diff --git a/.github/workflows/cron-weekly.yml b/.github/workflows/cron-weekly.yml index 8dafd4e99c27..898d10ace803 100644 --- a/.github/workflows/cron-weekly.yml +++ b/.github/workflows/cron-weekly.yml @@ -16,4 +16,9 @@ jobs: use-quiet-mode: 'yes' # output full HTTP info for broken links use-verbose-mode: 'yes' - config-file: '.github/workflows/markdown-link-check-config.json' + config-file: '.github/workflows/markdown-link-check-config.json' + # Notify to Discord channel on failure + - name: Send Discord Notification + if: failure() # Only run this step if previous steps failed + run: | + 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 }} diff --git a/.github/workflows/prepare-patch-release.yml b/.github/workflows/prepare-patch-release.yml index 5cdc1ba44fcf..91be3acf6f92 100644 --- a/.github/workflows/prepare-patch-release.yml +++ b/.github/workflows/prepare-patch-release.yml @@ -33,7 +33,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version-file: '.nvmrc' + node-version-file: ".nvmrc" - name: Cache dependencies uses: actions/cache@v3 @@ -89,7 +89,7 @@ jobs: yarn release:pick-patches - name: Cancel when no patches to pick - if: steps.pick-patches.outputs.pr-count == '0' && steps.pick-patches.outputs.pr-count != null + if: steps.pick-patches.outputs.no-patch-prs == 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # From https://stackoverflow.com/a/75809743 @@ -123,7 +123,7 @@ jobs: run: | yarn release:write-changelog ${{ steps.versions.outputs.next }} --unpicked-patches --verbose - - name: 'Commit changes to branch: version-patch-from-${{ steps.versions.outputs.current }}' + - name: "Commit changes to branch: version-patch-from-${{ steps.versions.outputs.current }}" working-directory: . run: | git config --global user.name 'storybook-bot' @@ -185,4 +185,4 @@ jobs: DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} uses: Ilshidur/action-discord@master with: - 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 }}' + 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 }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index ee61820d6939..39e2411abc61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +## 7.6.16 + +- Addon Themes: Make type generic less strict - [#26042](https://github.com/storybookjs/storybook/pull/26042), thanks [@yannbf](https://github.com/yannbf)! +- 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! + +## 7.6.15 + +This release accidentally didn't contain anything. + +## 7.6.14 + +- Core: Fix boolean `true` args in URL getting ignored - [#25950](https://github.com/storybookjs/storybook/pull/25950), thanks [@JReinhold](https://github.com/JReinhold)! + +## 7.6.13 + +- Next.js: Fix frameworkOptions resolution - [#25907](https://github.com/storybookjs/storybook/pull/25907), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- React Native: Fix init fails when package is already installed - [#25908](https://github.com/storybookjs/storybook/pull/25908), thanks [@dannyhw](https://github.com/dannyhw)! +- React Native: Remove watcher from init - [#25895](https://github.com/storybookjs/storybook/pull/25895), thanks [@dannyhw](https://github.com/dannyhw)! +- Webpack: Update StorybookConfig import in core-webpack types.ts - [#25740](https://github.com/storybookjs/storybook/pull/25740), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! + +## 7.6.12 + +- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)! + +## 7.6.11 + +- CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)! +- Codemods: Add support for multiple file extensions in runCodemod function - [#25708](https://github.com/storybookjs/storybook/pull/25708), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! + ## 7.6.10 - CLI: Fix existing version detection in `upgrade` - [#25642](https://github.com/storybookjs/storybook/pull/25642), thanks [@JReinhold](https://github.com/JReinhold)! diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 9458340d6ff9..e7d6ae22d03b 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,75 @@ +## 8.0.0-beta.3 + +- Addon-actions: Add spy to action for explicit actions - [#26033](https://github.com/storybookjs/storybook/pull/26033), thanks [@kasperpeulen](https://github.com/kasperpeulen)! +- Addon-themes: Make type generic less strict - [#26042](https://github.com/storybookjs/storybook/pull/26042), thanks [@yannbf](https://github.com/yannbf)! +- 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)! +- CLI: Refactor to add autoblockers - [#25934](https://github.com/storybookjs/storybook/pull/25934), thanks [@ndelangen](https://github.com/ndelangen)! +- Codemod: Migrate to test package - [#25958](https://github.com/storybookjs/storybook/pull/25958), thanks [@kasperpeulen](https://github.com/kasperpeulen)! +- 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)! +- Test: Bump user-event to 14.5.2 - [#25889](https://github.com/storybookjs/storybook/pull/25889), thanks [@kasperpeulen](https://github.com/kasperpeulen)! + +## 8.0.0-beta.2 + +- Core: Fix boolean `true` args in URL getting ignored - [#25950](https://github.com/storybookjs/storybook/pull/25950), thanks [@JReinhold](https://github.com/JReinhold)! +- Core: Move @types packages to dev deps in core-common - [#25387](https://github.com/storybookjs/storybook/pull/25387), thanks [@kyletsang](https://github.com/kyletsang)! +- Maintenance: Rename testing-utils paths to portable-stories - [#25888](https://github.com/storybookjs/storybook/pull/25888), thanks [@yannbf](https://github.com/yannbf)! +- 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)! +- UI: Fix `display=true` warning in console - [#25951](https://github.com/storybookjs/storybook/pull/25951), thanks [@JReinhold](https://github.com/JReinhold)! +- 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)! +- 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)! + +## 8.0.0-beta.1 + +- 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)! +- Core: Fix React peer dependency warnings - [#25926](https://github.com/storybookjs/storybook/pull/25926), thanks [@JReinhold](https://github.com/JReinhold)! +- 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)! +- Next.js: Fix frameworkOptions resolution - [#25907](https://github.com/storybookjs/storybook/pull/25907), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- React Native: Fix init fails when package is already installed - [#25908](https://github.com/storybookjs/storybook/pull/25908), thanks [@dannyhw](https://github.com/dannyhw)! +- React Native: Remove watcher from init - [#25895](https://github.com/storybookjs/storybook/pull/25895), thanks [@dannyhw](https://github.com/dannyhw)! +- Test: Fix jest-dom matcher type imports - [#25869](https://github.com/storybookjs/storybook/pull/25869), thanks [@alitas](https://github.com/alitas)! +- UI: Fix overlapping on the ref button in the sidebar - [#25914](https://github.com/storybookjs/storybook/pull/25914), thanks [@cdedreuille](https://github.com/cdedreuille)! +- 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)! + +## 8.0.0-beta.0 + +- CLI: Add Visual Tests addon to `init` - [#25850](https://github.com/storybookjs/storybook/pull/25850), thanks [@shilman](https://github.com/shilman)! +- CLI: Upgrade boxen library - [#25713](https://github.com/storybookjs/storybook/pull/25713), thanks [@yannbf](https://github.com/yannbf)! +- UI: Fix custom tabs not showing in the manager - [#25792](https://github.com/storybookjs/storybook/pull/25792), thanks [@ndelangen](https://github.com/ndelangen)! + +## 8.0.0-alpha.17 + +- CLI: Fix add command for non monorepo deps - [#25791](https://github.com/storybookjs/storybook/pull/25791), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- 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)! +- 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)! +- UI: Fix sidebar top and bottom addons not showing - [#25825](https://github.com/storybookjs/storybook/pull/25825), thanks [@ndelangen](https://github.com/ndelangen)! +- Webpack: Update StorybookConfig import in core-webpack types.ts - [#25740](https://github.com/storybookjs/storybook/pull/25740), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! + +## 8.0.0-alpha.16 + +- CLI: Fix `upgrade` detecting the wrong version of existing Storybooks - [#25752](https://github.com/storybookjs/storybook/pull/25752), thanks [@JReinhold](https://github.com/JReinhold)! +- CLI: Update init for react native v7 - [#25780](https://github.com/storybookjs/storybook/pull/25780), thanks [@dannyhw](https://github.com/dannyhw)! +- UI: Improve how the addon panel work on mobile - [#25787](https://github.com/storybookjs/storybook/pull/25787), thanks [@cdedreuille](https://github.com/cdedreuille)! + +## 8.0.0-alpha.15 + +- Next.js: Add logger statements for compiler selection - [#25755](https://github.com/storybookjs/storybook/pull/25755), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- React-Native: Fixes for v8 compatibility - [#25678](https://github.com/storybookjs/storybook/pull/25678), thanks [@shilman](https://github.com/shilman)! +- UI: Remove use of React.FC in components - [#25588](https://github.com/storybookjs/storybook/pull/25588), thanks [@ShaunEvening](https://github.com/ShaunEvening)! +- 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)! +- Vue3: Introduce portable stories API - [#25443](https://github.com/storybookjs/storybook/pull/25443), thanks [@yannbf](https://github.com/yannbf)! + +## 8.0.0-alpha.14 + +- Addons: Remove Node.js internal aliasing for Node builds - [#25712](https://github.com/storybookjs/storybook/pull/25712), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- Automigration: Add removeReactDependency fix to allFixes array - [#25717](https://github.com/storybookjs/storybook/pull/25717), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- Codemods: Add support for multiple file extensions in runCodemod function - [#25708](https://github.com/storybookjs/storybook/pull/25708), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- Next.js: Add webpack aliases for OpenTelemetry API - [#25652](https://github.com/storybookjs/storybook/pull/25652), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! +- UI: Remove `defaultProps` from `Link` component - [#25619](https://github.com/storybookjs/storybook/pull/25619), thanks [@tsvanharen](https://github.com/tsvanharen)! + +## 8.0.0-alpha.13 + +- Next.js: Fix SWC mode activation - [#25670](https://github.com/storybookjs/storybook/pull/25670), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)! + ## 8.0.0-alpha.12 - Blocks: Fix Controls block not having controls - [#25663](https://github.com/storybookjs/storybook/pull/25663), thanks [@JReinhold](https://github.com/JReinhold)! diff --git a/CODEOWNERS b/CODEOWNERS index 2e23565e1f5a..9d8ca4f6c5b9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,97 +1,97 @@ # Code Owners # Root -.github/ @JReinhold @yannbf @vanessayuenn -.circleci/ @yannbf @kasperpeulen -.yarnrc.yml @ndelangen @JReinhold +# .github/ @JReinhold @yannbf @vanessayuenn +# .circleci/ @yannbf @kasperpeulen +# .yarnrc.yml @ndelangen @JReinhold # Docs -/docs/ @kylegach @jonniebigodes +# /docs/ @kylegach @jonniebigodes # Scripts -/scripts/ @ndelangen @kasperpeulen -/scripts/release/ @jreinhold @ndelangen @kasperpeulen +# /scripts/ @ndelangen @kasperpeulen +# /scripts/release/ @jreinhold @ndelangen @kasperpeulen # Addons -/code/addons/a11y/ @ndelangen @yannbf -/code/addons/actions/ @ndelangen @yannbf -/code/addons/backgrounds/ @yannbf @ndelangen -/code/addons/controls/ @kasperpeulen @ndelangen -/code/addons/docs/ @JReinhold @kasperpeulen -/code/addons/essentials/ @valentinpalkovic @ndelangen -/code/addons/gfm/ @ndelangen @valentinpalkovic -/code/addons/highlight/ @yannbf @valentinpalkovic -/code/addons/interactions/ @yannbf @ndelangen -/code/addons/jest/ @ndelangen -/code/addons/links/ @yannbf @JReinhold -/code/addons/measure/ @yannbf @valentinpalkovic -/code/addons/outline/ @yannbf @valentinpalkovic -/code/addons/storysource/ @ndelangen -/code/addons/themes/ @JReinhold @Integrayshaun -/code/addons/toolbars/ @ndelangen @JReinhold -/code/addons/viewport/ @yannbf @ndelangen +# /code/addons/a11y/ @ndelangen @yannbf +# /code/addons/actions/ @ndelangen @yannbf +# /code/addons/backgrounds/ @yannbf @ndelangen +# /code/addons/controls/ @kasperpeulen @ndelangen +# /code/addons/docs/ @JReinhold @kasperpeulen +# /code/addons/essentials/ @valentinpalkovic @ndelangen +# /code/addons/gfm/ @ndelangen @valentinpalkovic +# /code/addons/highlight/ @yannbf @valentinpalkovic +# /code/addons/interactions/ @yannbf @ndelangen +# /code/addons/jest/ @ndelangen +# /code/addons/links/ @yannbf @JReinhold +# /code/addons/measure/ @yannbf @valentinpalkovic +# /code/addons/outline/ @yannbf @valentinpalkovic +# /code/addons/storysource/ @ndelangen +# /code/addons/themes/ @JReinhold @yannbf +# /code/addons/toolbars/ @ndelangen @JReinhold +# /code/addons/viewport/ @yannbf @ndelangen # Builder -/code/builders/builder-manager/ @ndelangen @valentinpalkovic -/code/builders/builder-vite/ @JReinhold @valentinpalkovic @IanVS -/code/builders/builder-webpack5/ @ndelangen @valentinpalkovic +# /code/builders/builder-manager/ @ndelangen @valentinpalkovic +# /code/builders/builder-vite/ @JReinhold @valentinpalkovic @IanVS +# /code/builders/builder-webpack5/ @ndelangen @valentinpalkovic # Frameworks -/code/frameworks/angular/ @valentinpalkovic @yannbf -/code/frameworks/html-vite/ @kasperpeulen @JReinhold -/code/frameworks/html-webpack5/ @kasperpeulen @JReinhold -/code/frameworks/nextjs/ @valentinpalkovic @kasperpeulen @yannbf -/code/frameworks/react-vite/ @valentinpalkovic @kasperpeulen -/code/frameworks/react-webpack5/ @valentinpalkovic @kasperpeulen -/code/frameworks/svelte-vite/ @kasperpeulen @JReinhold -/code/frameworks/svelte-webpack5/ @kasperpeulen @JReinhold -/code/frameworks/sveltekit/ @kasperpeulen @JReinhold -/code/frameworks/vue3-vite/ @kasperpeulen @yannbf @JReinhold -/code/frameworks/vue3-webpack5/ @kasperpeulen @yannbf @JReinhold -/code/frameworks/web-components-vite/ @kasperpeulen @JReinhold -/code/frameworks/web-components-webpack5/ @kasperpeulen @JReinhold +# /code/frameworks/angular/ @valentinpalkovic @yannbf +# /code/frameworks/html-vite/ @kasperpeulen @JReinhold +# /code/frameworks/html-webpack5/ @kasperpeulen @JReinhold +# /code/frameworks/nextjs/ @valentinpalkovic @kasperpeulen @yannbf +# /code/frameworks/react-vite/ @valentinpalkovic @kasperpeulen +# /code/frameworks/react-webpack5/ @valentinpalkovic @kasperpeulen +# /code/frameworks/svelte-vite/ @kasperpeulen @JReinhold +# /code/frameworks/svelte-webpack5/ @kasperpeulen @JReinhold +# /code/frameworks/sveltekit/ @kasperpeulen @JReinhold +# /code/frameworks/vue3-vite/ @kasperpeulen @yannbf @JReinhold +# /code/frameworks/vue3-webpack5/ @kasperpeulen @yannbf @JReinhold +# /code/frameworks/web-components-vite/ @kasperpeulen @JReinhold +# /code/frameworks/web-components-webpack5/ @kasperpeulen @JReinhold # Lib -/code/lib/channels/ @ndelangen @kasperpeulen -/code/lib/cli/ @yannbf @valentinpalkovic @ndelangen -/code/lib/cli-sb/ @yannbf @valentinpalkovic @ndelangen -/code/lib/cli-storybook/ @yannbf @valentinpalkovic @ndelangen -/code/lib/client-logger/ @ndelangen @yannbf -/code/lib/codemod/ @kasperpeulen @ndelangen -/code/lib/core-common/ @ndelangen @yannbf -/code/lib/core-events/ @ndelangen @kasperpeulen -/code/lib/core-server/ @ndelangen @JReinhold @tmeasday @shilman -/code/lib/core-webpack/ @valentinpalkovic @ndelangen -/code/lib/csf-plugin/ @ndelangen @valentinpalkovic -/code/lib/csf-tools/ @kasperpeulen @shilman -/code/lib/docs-tools/ @JReinhold @shilman -/code/lib/instrumenter/ @yannbf @kasperpeulen -/code/lib/manager-api/ @ndelangen @valentinpalkovic @kasperpeulen -/code/lib/node-logger/ @yannbf @ndelangen -/code/lib/preview/ @ndelangen @kasperpeulen -/code/lib/preview-api/ @yannbf @ndelangen @tmeasday -/code/lib/react-dom-shim/ @ndelangen @valentinpalkovic @tmeasday -/code/lib/router/ @ndelangen @JReinhold -/code/lib/telemetry/ @shilman @yannbf @ndelangen -/code/lib/theming/ @cdedreuille @ndelangen @JReinhold -/code/lib/types/ @kasperpeulen @ndelangen +# /code/lib/channels/ @ndelangen @kasperpeulen +# /code/lib/cli/ @yannbf @valentinpalkovic @ndelangen +# /code/lib/cli-sb/ @yannbf @valentinpalkovic @ndelangen +# /code/lib/cli-storybook/ @yannbf @valentinpalkovic @ndelangen +# /code/lib/client-logger/ @ndelangen @yannbf +# /code/lib/codemod/ @kasperpeulen @ndelangen +# /code/lib/core-common/ @ndelangen @yannbf +# /code/lib/core-events/ @ndelangen @kasperpeulen +# /code/lib/core-server/ @ndelangen @JReinhold @tmeasday @shilman +# /code/lib/core-webpack/ @valentinpalkovic @ndelangen +# /code/lib/csf-plugin/ @ndelangen @valentinpalkovic +# /code/lib/csf-tools/ @kasperpeulen @shilman +# /code/lib/docs-tools/ @JReinhold @shilman +# /code/lib/instrumenter/ @yannbf @kasperpeulen +# /code/lib/manager-api/ @ndelangen @valentinpalkovic @kasperpeulen +# /code/lib/node-logger/ @yannbf @ndelangen +# /code/lib/preview/ @ndelangen @kasperpeulen +# /code/lib/preview-api/ @yannbf @ndelangen @tmeasday +# /code/lib/react-dom-shim/ @ndelangen @valentinpalkovic @tmeasday +# /code/lib/router/ @ndelangen @JReinhold +# /code/lib/telemetry/ @shilman @yannbf @ndelangen +# /code/lib/theming/ @cdedreuille @ndelangen @JReinhold +# /code/lib/types/ @kasperpeulen @ndelangen # Presets -/code/presets/create-react-app/ @valentinpalkovic @ndelangen +# /code/presets/create-react-app/ @valentinpalkovic @ndelangen # Renderers -/code/renderers/html/ @kasperpeulen @JReinhold -/code/renderers/react/ @valentinpalkovic @kasperpeulen -/code/renderers/server/ @shilman @valentinpalkovic -/code/renderers/svelte/ @JReinhold @kasperpeulen -/code/renderers/vue3/ @kasperpeulen @JReinhold -/code/renderers/web-components/ @kasperpeulen @JReinhold +# /code/renderers/html/ @kasperpeulen @JReinhold +# /code/renderers/react/ @valentinpalkovic @kasperpeulen +# /code/renderers/server/ @shilman @valentinpalkovic +# /code/renderers/svelte/ @JReinhold @kasperpeulen +# /code/renderers/vue3/ @kasperpeulen @JReinhold +# /code/renderers/web-components/ @kasperpeulen @JReinhold # UI -/code/ui/.storybook/ @JReinhold @cdedreuille -/code/ui/blocks/ @JReinhold @cdedreuille -/code/ui/components/ @cdedreuille @JReinhold -/code/ui/manager/ @ndelangen @JReinhold @cdedreuille @tmeasday +# /code/ui/.storybook/ @JReinhold @cdedreuille +# /code/ui/blocks/ @JReinhold @cdedreuille +# /code/ui/components/ @cdedreuille @JReinhold +# /code/ui/manager/ @ndelangen @JReinhold @cdedreuille @tmeasday # E2E -/code/e2e-tests/ @yannbf @valentinpalkovic +# /code/e2e-tests/ @yannbf @valentinpalkovic diff --git a/LICENSE b/LICENSE index c9c6515841ac..c471193f579c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017 Kadira Inc. +Copyright (c) 2024 Storybook Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MIGRATION.md b/MIGRATION.md index 3a1b66b23c5b..77d77356d46e 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,11 +1,20 @@

Migration

- [From version 7.x to 8.0.0](#from-version-7x-to-800) + - [Type change in `composeStories` API](#type-change-in-composestories-api) + - [Tab addons are now routed to a query parameter](#tab-addons-are-now-routed-to-a-query-parameter) - [Default keyboard shortcuts changed](#default-keyboard-shortcuts-changed) - [Manager addons are now rendered with React 18](#manager-addons-are-now-rendered-with-react-18) - [Removal of `storiesOf`-API](#removal-of-storiesof-api) - [Removed deprecated shim packages](#removed-deprecated-shim-packages) - [Framework-specific Vite plugins have to be explicitly added](#framework-specific-vite-plugins-have-to-be-explicitly-added) + - [For React:](#for-react) + - [For Vue:](#for-vue) + - [For Svelte (without Sveltekit):](#for-svelte-without-sveltekit) + - [For Preact:](#for-preact) + - [For Solid:](#for-solid) + - [For Qwik:](#for-qwik) + - [TurboSnap Vite plugin is no longer needed](#turbosnap-vite-plugin-is-no-longer-needed) - [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) - [MDX related changes](#mdx-related-changes) - [MDX is upgraded to v3](#mdx-is-upgraded-to-v3) @@ -19,7 +28,6 @@ - [Dropping support for Yarn 1](#dropping-support-for-yarn-1) - [Dropping support for Node.js 16](#dropping-support-for-nodejs-16) - [Autotitle breaking fixes](#autotitle-breaking-fixes) - - [React v18 in the manager UI (including addons)](#react-v18-in-the-manager-ui-including-addons) - [Storyshots has been removed](#storyshots-has-been-removed) - [UI layout state has changed shape](#ui-layout-state-has-changed-shape) - [New UI and props for Button and IconButton components](#new-ui-and-props-for-button-and-iconbutton-components) @@ -27,6 +35,8 @@ - [Removed postinstall](#removed-postinstall) - [Removed stories.json](#removed-storiesjson) - [Removed `sb babelrc` command](#removed-sb-babelrc-command) + - [Changed interfaces for `@storybook/router` components](#changed-interfaces-for-storybookrouter-components) + - [Extract no longer batches](#extract-no-longer-batches) - [Framework-specific changes](#framework-specific-changes) - [React](#react) - [`react-docgen` component analysis by default](#react-docgen-component-analysis-by-default) @@ -34,6 +44,8 @@ - [Require Next.js 13.5 and up](#require-nextjs-135-and-up) - [Automatic SWC mode detection](#automatic-swc-mode-detection) - [RSC config moved to React renderer](#rsc-config-moved-to-react-renderer) + - [Vue](#vue) + - [Require Vue 3 and up](#require-vue-3-and-up) - [Angular](#angular) - [Require Angular 15 and up](#require-angular-15-and-up) - [Svelte](#svelte) @@ -70,19 +82,20 @@ - [`createChannel` from `@storybook/postmessage` and `@storybook/channel-websocket`](#createchannel-from-storybookpostmessage-and-storybookchannel-websocket) - [StoryStore and methods deprecated](#storystore-and-methods-deprecated) - [Addon author changes](#addon-author-changes) + - [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) - [Removed `config` preset](#removed-config-preset-1) - [From version 7.5.0 to 7.6.0](#from-version-750-to-760) - - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated) - - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated) - - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated) - - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop) - - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react) + - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated) + - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated) + - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated) + - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop) + - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react) - [From version 7.4.0 to 7.5.0](#from-version-740-to-750) - - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated) - - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers) + - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated) + - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers) - [From version 7.0.0 to 7.2.0](#from-version-700-to-720) - - [Addon API is more type-strict](#addon-api-is-more-type-strict) - - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated) + - [Addon API is more type-strict](#addon-api-is-more-type-strict) + - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated) - [From version 6.5.x to 7.0.0](#from-version-65x-to-700) - [7.0 breaking changes](#70-breaking-changes) - [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below) @@ -108,12 +121,13 @@ - [Deploying build artifacts](#deploying-build-artifacts) - [Dropped support for file URLs](#dropped-support-for-file-urls) - [Serving with nginx](#serving-with-nginx) - - [Ignore story files from node_modules](#ignore-story-files-from-node_modules) + - [Ignore story files from node\_modules](#ignore-story-files-from-node_modules) - [7.0 Core changes](#70-core-changes) - [7.0 feature flags removed](#70-feature-flags-removed) - [Story context is prepared before for supporting fine grained updates](#story-context-is-prepared-before-for-supporting-fine-grained-updates) - [Changed decorator order between preview.js and addons/frameworks](#changed-decorator-order-between-previewjs-and-addonsframeworks) - [Dark mode detection](#dark-mode-detection) + - [`addons.setConfig` should now be imported from `@storybook/manager-api`.](#addonssetconfig-should-now-be-imported-from-storybookmanager-api) - [7.0 core addons changes](#70-core-addons-changes) - [Removed auto injection of @storybook/addon-actions decorator](#removed-auto-injection-of-storybookaddon-actions-decorator) - [Addon-backgrounds: Removed deprecated grid parameter](#addon-backgrounds-removed-deprecated-grid-parameter) @@ -121,7 +135,7 @@ - [Addon-interactions: Interactions debugger is now default](#addon-interactions-interactions-debugger-is-now-default) - [7.0 Vite changes](#70-vite-changes) - [Vite builder uses Vite config automatically](#vite-builder-uses-vite-config-automatically) - - [Vite cache moved to node_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) + - [Vite cache moved to node\_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) - [7.0 Webpack changes](#70-webpack-changes) - [Webpack4 support discontinued](#webpack4-support-discontinued) - [Babel mode v7 exclusively](#babel-mode-v7-exclusively) @@ -171,7 +185,7 @@ - [Dropped addon-docs manual babel configuration](#dropped-addon-docs-manual-babel-configuration) - [Dropped addon-docs manual configuration](#dropped-addon-docs-manual-configuration) - [Autoplay in docs](#autoplay-in-docs) - - [Removed STORYBOOK_REACT_CLASSES global](#removed-storybook_react_classes-global) + - [Removed STORYBOOK\_REACT\_CLASSES global](#removed-storybook_react_classes-global) - [7.0 Deprecations and default changes](#70-deprecations-and-default-changes) - [storyStoreV7 enabled by default](#storystorev7-enabled-by-default) - [`Story` type deprecated](#story-type-deprecated) @@ -386,6 +400,29 @@ ## From version 7.x to 8.0.0 +### Type change in `composeStories` API + +There 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: + +```ts +const { Primary } = composeStories(stories) + +// before +await Primary.play(...) + +// after +await Primary.play?.(...) // if you don't care whether the play function exists +await Primary.play!(...) // if you want a runtime error when the play function does not exist +``` + +There 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. + +### Tab addons are now routed to a query parameter + +The URL of a tab used to be: `http://localhost:6006/?path=/my-addon-tab/my-story`. + +The new URL of a tab is `http://localhost:6006/?path=/story/my-story&tab=my-addon-tab`. + ### Default keyboard shortcuts changed The 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. @@ -432,23 +469,88 @@ In Storybook 7, these packages existed for backwards compatibility, but were mar - `@storybook/store` - this package has been merged into `@storybook/preview-api`. - `@storybook/api` - this package has been replaced with `@storybook/manager-api`. -This section explains the rationale, and the required changed you might have to make: [New Addons API](#new-addons-api) +These sections explain the rationale, and the required changes you might have to make: + +- [New Addons API](#new-addons-api) +- [`addons.setConfig` should now be imported from `@storybook/manager-api`.](#addonssetconfig-should-now-be-imported-from-storybookmanager-api) ### Framework-specific Vite plugins have to be explicitly added In Storybook 7, we would automatically add frameworks-specific Vite plugins, e.g. `@vitejs/plugin-react` if not installed. In Storybook 8 those plugins have to be added explicitly in the user's `vite.config.ts`: +#### For React: + ```ts import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; -// https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], }); ``` +#### For Vue: + +```ts +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; + +export default defineConfig({ + plugins: [vue()], +}); +``` + +#### For Svelte (without Sveltekit): + +```ts +import { defineConfig } from "vite"; +import svelte from "@sveltejs/vite-plugin-svelte"; + +export default defineConfig({ + plugins: [svelte()], +}); +``` + +#### For Preact: + +```ts +import { defineConfig } from "vite"; +import preact from "@preact/preset-vite"; + +export default defineConfig({ + plugins: [preact()], +}); +``` + +#### For Solid: + +```ts +import { defineConfig } from "vite"; +import solid from "vite-plugin-solid"; + +export default defineConfig({ + plugins: [solid()], +}); +``` + +#### For Qwik: + +```ts +import { defineConfig } from "vite"; +import qwik from "vite-plugin-qwik"; + +export default defineConfig({ + plugins: [qwik()], +}); +``` + +### TurboSnap Vite plugin is no longer needed + +At least in build mode, `builder-vite` now supports the `--webpack-stats-json` flag and will output `preview-stats.json`. + +This means https://github.com/IanVS/vite-plugin-turbosnap is no longer necessary, and duplicative, and the plugin will automatically be removed if found. + ### Implicit actions can not be used during rendering (for example in the play function) In Storybook 7, we inferred if the component accepts any action props, @@ -629,13 +731,6 @@ export default { Alternatively, 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/7.0/vue/configure/sidebar-and-urls#processing-custom-titles) to generate the titles dynamically. -#### React v18 in the manager UI (including addons) - -Storybook 7 used React 16 in the manager. In Storybook 8 this is upgraded to react v18. -Addons that inject UI into panels, tools, etc. are possibly affected by this. - -Addon authors are advised to upgrade to react v18. - #### Storyshots has been removed Storyshots was an addon for Storybook which allowed users to turn their stories into automated snapshot tests. @@ -705,6 +800,14 @@ From version 8.0 onwards, Storybook is compiler-agnostic and does not depend on The 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. +#### Changed interfaces for `@storybook/router` components + +The `hideOnly` prop has been removed from the `` component in `@storybook/router`. If needed this can be implemented manually with the `` component. + +#### Extract no longer batches + +`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. + ### Framework-specific changes #### React @@ -744,6 +847,12 @@ Storybook 7.6 introduced a new feature flag, `experimentalNextRSC`, to enable Re These 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. +#### Vue + +##### Require Vue 3 and up + +Starting in 8.0, Storybook requires Vue 3 and up. + #### Angular ##### Require Angular 15 and up @@ -1053,6 +1162,46 @@ Note that both these methods require initialization, so you should await `previe ### Addon author changes +#### Tab addons cannot manually route, Tool addons can filter their visibility via tabId + +The TAB type addons now should no longer specify the `match` or `route` property. + +Instead storybook will automatically show the addon's rendered content when the query parameter `tab` is set to the addon's ID. + +Example: + +```tsx +import { addons, types } from "@storybook/manager-api"; + +addons.register("my-addon", () => { + addons.add("my-addon/tab", { + type: types.TAB, + title: "My Addon", + render: () =>
Hello World
, + }); +}); +``` + +Tool type addon will now receive the `tabId` property passed to their `match` function. +That way they can chose to show/hide their content based on the current tab. + +When the canvas is shown, the `tabId` will be set to `undefined`. + +Example: + +```tsx +import { addons, types } from "@storybook/manager-api"; + +addons.register("my-addon", () => { + addons.add("my-addon/tool", { + type: types.TOOL, + title: "My Addon", + match: ({ tabId }) => tabId === "my-addon/tab", + render: () =>
👀
, + }); +}); +``` + #### Removed `config` preset In 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. @@ -1435,7 +1584,7 @@ Storybook uses `react` in a variety of docs-related packages. In the past, we've To upgrade manually, add any version of `react` and `react-dom` as devDependencies using your package manager of choice, e.g. ``` -npm add react react-dom --dev +npm add react react-dom --save-dev ``` #### start-storybook / build-storybook binaries removed @@ -1884,6 +2033,19 @@ Earlier versions used the light theme by default, so if you don't set a theme an To learn more about theming, read our [documentation](https://storybook.js.org/docs/react/configure/theming). +#### `addons.setConfig` should now be imported from `@storybook/manager-api`. + +The previous package, `@storybook/addons`, is now deprecated and will be removed in 8.0. + +```diff +- import { addons } from '@storybook/addons'; ++ import { addons } from '@storybook/manager-api'; + +addons.setConfig({ + // ... +}) +``` + ### 7.0 core addons changes #### Removed auto injection of @storybook/addon-actions decorator diff --git a/README.md b/README.md index bf45664b938f..829b319ec96f 100644 --- a/README.md +++ b/README.md @@ -97,10 +97,10 @@ For additional help, share your issue in [the repo's GitHub Discussions](https:/ ### Supported Frameworks | Renderer | Demo | | -| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | +|----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| | [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) | | [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/) | -| [Vue](code/renderers/vue) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/vue/latest?style=flat-square&color=blue&label)](https://next--630513346a8e284ae244d415.chromatic.com/) | [![Vue](https://img.shields.io/npm/dm/@storybook/vue?style=flat-square&color=eee)](code/renderers/vue) | +| [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/) | | [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) | | [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) | | [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) | diff --git a/code/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch b/code/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch index ea5e834a06df..9a1b74e203bd 100644 --- a/code/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch +++ b/code/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch @@ -1,10 +1,10 @@ diff --git a/dist/index.js b/dist/index.js -index 974d6b26f626024fc9904908100c9ecaa54f43e1..5be2d35267e7f0525c6588758dbebe72599f88a9 100644 +index 974d6b26f626024fc9904908100c9ecaa54f43e1..5d9d92a0796e02630ccdd1174d4fd25e016d2b06 100644 --- a/dist/index.js +++ b/dist/index.js -@@ -6,31 +6,37 @@ import { processError } from '@vitest/utils/error'; +@@ -6,28 +6,35 @@ import { processError } from '@vitest/utils/error'; import { util } from 'chai'; - + const MATCHERS_OBJECT = Symbol.for("matchers-object"); -const JEST_MATCHERS_OBJECT = Symbol.for("$$jest-matchers-object"); +// Patched this symbol for storybook, so that @storybook/test can be used in a jest environment as well. @@ -12,17 +12,14 @@ index 974d6b26f626024fc9904908100c9ecaa54f43e1..5be2d35267e7f0525c6588758dbebe72 +const JEST_MATCHERS_OBJECT = Symbol.for("$$jest-matchers-object-storybook"); const GLOBAL_EXPECT = Symbol.for("expect-global"); const ASYMMETRIC_MATCHERS_OBJECT = Symbol.for("asymmetric-matchers-object"); - + if (!Object.prototype.hasOwnProperty.call(globalThis, MATCHERS_OBJECT)) { const globalState = /* @__PURE__ */ new WeakMap(); - const matchers = /* @__PURE__ */ Object.create(null); - const assymetricMatchers = /* @__PURE__ */ Object.create(null); +- const assymetricMatchers = /* @__PURE__ */ Object.create(null); Object.defineProperty(globalThis, MATCHERS_OBJECT, { get: () => globalState }); -+ Object.defineProperty(globalThis, ASYMMETRIC_MATCHERS_OBJECT, { -+ get: () => assymetricMatchers -+ }); +} +if (!Object.prototype.hasOwnProperty.call(globalThis, JEST_MATCHERS_OBJECT)) { + const matchers = /* @__PURE__ */ Object.create(null); @@ -34,15 +31,14 @@ index 974d6b26f626024fc9904908100c9ecaa54f43e1..5be2d35267e7f0525c6588758dbebe72 matchers }) }); -- Object.defineProperty(globalThis, ASYMMETRIC_MATCHERS_OBJECT, { -- get: () => assymetricMatchers -- }); ++} ++if (!Object.prototype.hasOwnProperty.call(globalThis, ASYMMETRIC_MATCHERS_OBJECT)) { ++ const assymetricMatchers = /* @__PURE__ */ Object.create(null); + Object.defineProperty(globalThis, ASYMMETRIC_MATCHERS_OBJECT, { + get: () => assymetricMatchers + }); } + function getState(expect) { return globalThis[MATCHERS_OBJECT].get(expect); } -+ - function setState(state, expect) { - const map = globalThis[MATCHERS_OBJECT]; - const current = map.get(expect) || {}; diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index 7c770dea5645..9d59b4555ccb 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", @@ -60,7 +60,7 @@ "@storybook/client-logger": "workspace:*", "@storybook/components": "workspace:*", "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.3", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/theming": "workspace:*", diff --git a/code/addons/a11y/src/components/Report/Item.tsx b/code/addons/a11y/src/components/Report/Item.tsx index 2d34ee58d745..1830a10771fc 100644 --- a/code/addons/a11y/src/components/Report/Item.tsx +++ b/code/addons/a11y/src/components/Report/Item.tsx @@ -1,7 +1,6 @@ import React, { Fragment, useState } from 'react'; import { styled } from '@storybook/theming'; -import { Icons } from '@storybook/components'; import type { Result } from 'axe-core'; import { Info } from './Info'; @@ -11,6 +10,7 @@ import { Tags } from './Tags'; import type { RuleType } from '../A11YPanel'; import HighlightToggle from './HighlightToggle'; +import { ChevronSmallDownIcon } from '@storybook/icons'; const Wrapper = styled.div(({ theme }) => ({ display: 'flex', @@ -21,10 +21,7 @@ const Wrapper = styled.div(({ theme }) => ({ }, })); -const Icon = styled(Icons)({ - height: 10, - width: 10, - minWidth: 10, +const Icon = styled(ChevronSmallDownIcon)({ marginRight: 10, transition: 'transform 0.1s ease-in-out', verticalAlign: 'inherit', @@ -75,7 +72,6 @@ export const Item = (props: ItemProps) => { onToggle(!open)} role="button"> { addons.add(PANEL_ID, { title: '', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => , }); diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index d3b15dcf94fc..cb6d14cdabd8 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", diff --git a/code/addons/actions/src/runtime/action.ts b/code/addons/actions/src/runtime/action.ts index f6779d1a1a64..a647a8eb0d1b 100644 --- a/code/addons/actions/src/runtime/action.ts +++ b/code/addons/actions/src/runtime/action.ts @@ -103,6 +103,7 @@ export function action(name: string, options: ActionOptions = {}): HandlerFuncti channel.emit(EVENT_ID, actionDisplayToEmit); }; handler.isAction = true; + handler.implicit = options.implicit; return handler; } diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json index b26a5b945b72..fc57826dd378 100644 --- a/code/addons/backgrounds/package.json +++ b/code/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", @@ -53,13 +53,13 @@ }, "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.3", "memoizerific": "^1.11.3", "ts-dedent": "^2.0.0" }, "devDependencies": { "@storybook/client-logger": "workspace:*", "@storybook/components": "workspace:*", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/theming": "workspace:*", diff --git a/code/addons/backgrounds/src/manager.tsx b/code/addons/backgrounds/src/manager.tsx index ecd36b0bb618..cef974b6551b 100644 --- a/code/addons/backgrounds/src/manager.tsx +++ b/code/addons/backgrounds/src/manager.tsx @@ -9,7 +9,7 @@ addons.register(ADDON_ID, () => { addons.add(ADDON_ID, { title: 'Backgrounds', type: types.TOOL, - match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)), + match: ({ viewMode, tabId }) => !!(viewMode && viewMode.match(/^(story|docs)$/)) && !tabId, render: () => ( diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json index dc2a5da414f2..1c16d2c0a1a2 100644 --- a/code/addons/controls/package.json +++ b/code/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", diff --git a/code/addons/docs/README.md b/code/addons/docs/README.md index 9495cf2c1508..216893fb7070 100644 --- a/code/addons/docs/README.md +++ b/code/addons/docs/README.md @@ -12,7 +12,7 @@ Storybook Docs transforms your Storybook stories into world-class component docu **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. -Just like Storybook, Docs supports every major view layer including React, Vue, Angular, HTML, Web components, Svelte, and many more. +Just like Storybook, Docs supports every major view layer including React, Vue 3, Angular, HTML, Web components, Svelte, and many more. Read on to learn more: @@ -113,7 +113,7 @@ export default { ### Be sure to check framework specific installation needs - [React](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/react) (covered here) -- [Vue](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/vue) +- [Vue 3](https://github.com/storybookjs/storybook/blob/next/code/addons/docs/vue3) - [Angular](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/angular) - [Ember](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/ember) - [Web Components](https://github.com/storybookjs/storybook/tree/next/code/addons/docs/web-components) diff --git a/code/addons/docs/common/README.md b/code/addons/docs/common/README.md index 1195d287d444..4a43dfe641de 100644 --- a/code/addons/docs/common/README.md +++ b/code/addons/docs/common/README.md @@ -2,7 +2,7 @@ Storybook Docs transforms your Storybook stories into world-class component documentation. Docs supports [all web frameworks that Storybook supports](../README.md#framework-support). -Popular frameworks like [React](../react/README.md)/[Vue](../vue/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. +Popular 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. - [Installation](#installation) - [DocsPage](#docspage) diff --git a/code/addons/docs/docs/docspage.md b/code/addons/docs/docs/docspage.md index 3fef9898f955..5e89251c2ede 100644 --- a/code/addons/docs/docs/docspage.md +++ b/code/addons/docs/docs/docspage.md @@ -23,7 +23,7 @@ Like `addon-info`, `DocsPage` provides sensible defaults, meaning it adds docume However, `DocsPage` brings the following improvements: -- It supports all frameworks that Storybook supports, including React, Vue, Angular and [many others](../README.md#framework-support). +- It supports all frameworks that Storybook supports, including React, Vue 3, Angular and [many others](../README.md#framework-support). - It generates better documentation that can be used as a standalone docs site, independently of Storybook. - It supports better configuration, so you can capture project specific information with ease. - It's built to work with [`MDX`](./mdx.md) when you need more control of your documentation. diff --git a/code/addons/docs/docs/faq.md b/code/addons/docs/docs/faq.md index 5710640cc092..895098b7ad31 100644 --- a/code/addons/docs/docs/faq.md +++ b/code/addons/docs/docs/faq.md @@ -9,7 +9,7 @@ You've read the [Storybook Docs README](../README.md). You're already familiar w ## Does Docs support framework X? -Docs 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, Angular, Ember, Svelte, and others. +Docs 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. ## How does Docs interact with existing addons? @@ -44,6 +44,6 @@ This is [Component Story Format (CSF)](https://medium.com/storybookjs/component- ## More resources - References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md) -- 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) +- 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) - 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) - Example: [Storybook Design System](https://github.com/storybookjs/design-system) diff --git a/code/addons/docs/docs/mdx.md b/code/addons/docs/docs/mdx.md index 50039fd7fa6e..3f251fd9a9e5 100644 --- a/code/addons/docs/docs/mdx.md +++ b/code/addons/docs/docs/mdx.md @@ -195,6 +195,6 @@ Be sure to update your Storybook config file to load `.stories.mdx` stories, as ## More resources - References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md) -- 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) +- 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) - 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) - Example: [Storybook Design System](https://github.com/storybookjs/design-system) diff --git a/code/addons/docs/docs/multiframework.md b/code/addons/docs/docs/multiframework.md index 7959f79ef426..070d94089b00 100644 --- a/code/addons/docs/docs/multiframework.md +++ b/code/addons/docs/docs/multiframework.md @@ -13,7 +13,7 @@ Storybook Docs [provides basic support for all non-RN Storybook view layers](../ Your framework might need framework-specific configuration. This could include adding extra webpack loaders or global decorators/story parameters. -Addon-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 `..//{preset,config}.[tj]sx?`, where `` is the framework identifier, e.g. `vue`, `angular`, `react`, etc. +Addon-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 `..//{preset,config}.[tj]sx?`, where `` is the framework identifier, e.g. `vue3`, `angular`, `react`, etc. For 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). @@ -162,6 +162,6 @@ This configures the `jsxDecorator` to be run on every story. ## More resources - References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md) -- 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) +- 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) - 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) - Example: [Storybook Design System](https://github.com/storybookjs/design-system) diff --git a/code/addons/docs/docs/props-tables.md b/code/addons/docs/docs/props-tables.md index cdc704e2bd65..8dd5e8f7a285 100644 --- a/code/addons/docs/docs/props-tables.md +++ b/code/addons/docs/docs/props-tables.md @@ -18,7 +18,7 @@ Storybook Docs automatically generates props tables for components in supported ## Usage -For framework-specific setup instructions, see the framework's README: [React](../react/README.md), [Vue](../vue/README.md), [Angular](../angular/README.md), [Web Components](../web-components/README.md), [Ember](../ember/README.md). +For 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). ### DocsPage @@ -228,7 +228,7 @@ This package relies on a variety of sub-packages to extract property information | Framework | Underlying library | Docs | Open issues | | -------------- | ---------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 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) | -| Vue | `vue-docgen-api` | [Docs](../vue/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+vue%22) | +| 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) | | 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) | | 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) | | 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) | @@ -236,6 +236,6 @@ This package relies on a variety of sub-packages to extract property information ## More resources - References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md) -- 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) +- 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) - 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) - Example: [Storybook Design System](https://github.com/storybookjs/design-system) diff --git a/code/addons/docs/docs/recipes.md b/code/addons/docs/docs/recipes.md index df2892df89e4..ca03815ce2dd 100644 --- a/code/addons/docs/docs/recipes.md +++ b/code/addons/docs/docs/recipes.md @@ -352,6 +352,6 @@ There is also an webpack loader package that extracts descriptions from jsdoc co ## More resources - References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md) -- 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) +- 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) - 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) - Example: [Storybook Design System](https://github.com/storybookjs/design-system) diff --git a/code/addons/docs/docs/theming.md b/code/addons/docs/docs/theming.md index a570ba61073a..6f66a2d37267 100644 --- a/code/addons/docs/docs/theming.md +++ b/code/addons/docs/docs/theming.md @@ -92,6 +92,6 @@ addParameters({ ## More resources - References: [README](../README.md) / [DocsPage](docspage.md) / [MDX](mdx.md) / [FAQ](faq.md) / [Recipes](recipes.md) / [Theming](theming.md) / [Props](props-tables.md) -- 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) +- 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) - 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) - Example: [Storybook Design System](https://github.com/storybookjs/design-system) diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index d601c8bf30ad..b4a139a5f8b4 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", @@ -111,9 +111,10 @@ "@storybook/react-dom-shim": "workspace:*", "@storybook/theming": "workspace:*", "@storybook/types": "workspace:*", + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", "fs-extra": "^11.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", "rehype-external-links": "^3.0.0", "rehype-slug": "^6.0.0", "ts-dedent": "^2.0.0" @@ -122,6 +123,8 @@ "@mdx-js/mdx": "^3.0.0", "@rollup/pluginutils": "^5.0.2", "@storybook/test": "workspace:*", + "react": "^18.2.0", + "react-dom": "^18.2.0", "typescript": "^5.3.2", "vite": "^4.0.4" }, diff --git a/code/addons/docs/src/preset.ts b/code/addons/docs/src/preset.ts index ae79832240d1..68c7efb39f8b 100644 --- a/code/addons/docs/src/preset.ts +++ b/code/addons/docs/src/preset.ts @@ -138,16 +138,24 @@ export const viteFinal = async (config: any, options: Options) => { const { mdxPlugin } = await import('./plugins/mdx-plugin'); // Use the resolvedReact preset to alias react and react-dom to either the users version or the version shipped with addon-docs - const { react, reactDom } = await getResolvedReact(options); + const { react, reactDom, mdx } = await getResolvedReact(options); - const reactAliasPlugin = { - name: 'storybook:react-alias', + const packageDeduplicationPlugin = { + name: 'storybook:package-deduplication', enforce: 'pre', config: () => ({ resolve: { alias: { react, 'react-dom': reactDom, + '@mdx-js/react': mdx, + /** + * The following aliases are used to ensure a single instance of these packages are used in situations where they are duplicated + * The packages will be duplicated by the package manager when the user has react installed with another version than 18.2.0 + */ + '@storybook/theming': dirname(require.resolve('@storybook/theming')), + '@storybook/components': dirname(require.resolve('@storybook/components')), + '@storybook/blocks': dirname(require.resolve('@storybook/blocks')), }, }, }), @@ -155,7 +163,7 @@ export const viteFinal = async (config: any, options: Options) => { // add alias plugin early to ensure any other plugins that also add the aliases will override this // eg. the preact vite plugin adds its own aliases - plugins.unshift(reactAliasPlugin); + plugins.unshift(packageDeduplicationPlugin); plugins.push(mdxPlugin(options)); return config; diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json index 4891f0ad942c..22794fd4ce9b 100644 --- a/code/addons/essentials/package.json +++ b/code/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json index a37d18622182..03d674a63778 100644 --- a/code/addons/gfm/package.json +++ b/code/addons/gfm/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-mdx-gfm", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "GitHub Flavored Markdown in Storybook", "keywords": [ "addon", diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index 75183aa3f9ef..c70c356a70a6 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-highlight", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Highlight DOM nodes within your stories", "keywords": [ "storybook-addons", diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index a616a3bb272c..5a47c37f3d55 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", @@ -30,6 +30,7 @@ }, "./manager": "./dist/manager.js", "./preview": "./dist/preview.js", + "./preset": "./dist/preset.js", "./register.js": "./dist/manager.js", "./package.json": "./package.json" }, @@ -49,7 +50,6 @@ }, "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.3", "@storybook/types": "workspace:*", "jest-mock": "^27.0.6", "polished": "^4.2.2", @@ -61,6 +61,7 @@ "@storybook/components": "workspace:*", "@storybook/core-common": "workspace:*", "@storybook/core-events": "workspace:*", + "@storybook/icons": "^1.2.5", "@storybook/instrumenter": "workspace:*", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", diff --git a/code/addons/interactions/src/components/List.tsx b/code/addons/interactions/src/components/List.tsx index 8c420d37102a..75db1d21d99e 100644 --- a/code/addons/interactions/src/components/List.tsx +++ b/code/addons/interactions/src/components/List.tsx @@ -1,6 +1,6 @@ import React, { Fragment, useState } from 'react'; import { styled, themes, convert } from '@storybook/theming'; -import { Icons, type IconsProps } from '@storybook/components'; +import { ChevronSmallDownIcon } from '@storybook/icons'; const ListWrapper = styled.ul({ listStyle: 'none', @@ -18,10 +18,7 @@ const Wrapper = styled.div({ }, }); -const Icon = styled(Icons)({ - height: 10, - width: 10, - minWidth: 10, +const Icon = styled(ChevronSmallDownIcon)({ color: convert(themes.light).textMutedColor, marginRight: 10, transition: 'transform 0.1s ease-in-out', @@ -68,7 +65,6 @@ export const ListItem: React.FC = ({ item }) => { onToggle(!open)} role="button"> (({ theme, status }) => { - const color = { - [CallStates.DONE]: theme.color.positive, - [CallStates.ERROR]: theme.color.negative, - [CallStates.ACTIVE]: theme.color.secondary, - [CallStates.WAITING]: transparentize(0.5, gray[500]), - }[status]; - return { - width: status === CallStates.WAITING ? 6 : 12, - height: status === CallStates.WAITING ? 6 : 12, - color, - justifySelf: 'center', - }; +const WarningContainer = styled.div({ + width: 14, + height: 14, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', }); -export const StatusIcon: React.FC = ({ status, className }) => { - const icon = { - [CallStates.DONE]: 'check', - [CallStates.ERROR]: 'stopalt', - [CallStates.ACTIVE]: 'play', - [CallStates.WAITING]: 'circle', - }[status] as IconsProps['icon']; - return ( - - ); +export const StatusIcon: React.FC = ({ status }) => { + const theme = useTheme(); + + switch (status) { + case CallStates.DONE: { + return ; + } + case CallStates.ERROR: { + return ; + } + case CallStates.ACTIVE: { + return ; + } + case CallStates.WAITING: { + return ( + + + + ); + } + default: { + return null; + } + } }; diff --git a/code/addons/interactions/src/preview.ts b/code/addons/interactions/src/preview.ts index d751cbf7bc58..e0cc0aeae87a 100644 --- a/code/addons/interactions/src/preview.ts +++ b/code/addons/interactions/src/preview.ts @@ -1,11 +1,11 @@ -/* eslint-disable no-underscore-dangle */ import type { - Args, - LoaderFunction, + ArgsEnhancer, PlayFunction, PlayFunctionContext, + Renderer, StepLabel, } from '@storybook/types'; +import { fn, isMockFunction } from '@storybook/test'; import { instrument } from '@storybook/instrumenter'; export const { step: runStep } = instrument( @@ -16,26 +16,47 @@ export const { step: runStep } = instrument( { intercept: true } ); -const instrumentSpies: LoaderFunction = ({ initialArgs }) => { - const argTypesWithAction = Object.entries(initialArgs).filter( - ([, value]) => - typeof value === 'function' && - '_isMockFunction' in value && - value._isMockFunction && - !value._instrumented - ); - - return argTypesWithAction.reduce((acc, [key, value]) => { - const instrumented = instrument({ [key]: () => value }, { retain: true })[key]; - acc[key] = instrumented(); - // this enhancer is being called multiple times - - value._instrumented = true; - return acc; - }, {} as Args); +const traverseArgs = (value: unknown, depth = 0, key?: string): any => { + // Make sure to not get in infinite loops with self referencing args + if (depth > 5) return value; + if (value == null) return value; + if (isMockFunction(value)) { + // Makes sure we get the arg name in the interactions panel + if (key) value.mockName(key); + return value; + } + + // wrap explicit actions in a spy + if ( + typeof value === 'function' && + 'isAction' in value && + value.isAction && + !('implicit' in value && value.implicit) + ) { + const mock = fn(value as any); + if (key) mock.mockName(key); + return mock; + } + + if (Array.isArray(value)) { + depth++; + return value.map((item) => traverseArgs(item, depth)); + } + + if (typeof value === 'object' && value.constructor === Object) { + depth++; + // We have to mutate the original object for this to survive HMR. + for (const [k, v] of Object.entries(value)) { + (value as Record)[k] = traverseArgs(v, depth, k); + } + return value; + } + return value; }; -export const argsEnhancers = [instrumentSpies]; +const wrapActionsInSpyFns: ArgsEnhancer = ({ initialArgs }) => traverseArgs(initialArgs); + +export const argsEnhancers = [wrapActionsInSpyFns]; export const parameters = { throwPlayFunctionExceptions: false, diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json index abbda076ab5b..879b5dabff75 100644 --- a/code/addons/jest/package.json +++ b/code/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "React storybook addon that show component jest report", "keywords": [ "addon", @@ -62,6 +62,7 @@ "@storybook/client-logger": "workspace:*", "@storybook/components": "workspace:*", "@storybook/core-events": "workspace:*", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/theming": "workspace:*", diff --git a/code/addons/jest/src/components/Result.tsx b/code/addons/jest/src/components/Result.tsx index d50fa6f34a1a..61bacd9e6af7 100644 --- a/code/addons/jest/src/components/Result.tsx +++ b/code/addons/jest/src/components/Result.tsx @@ -1,8 +1,8 @@ import React, { Fragment, useState } from 'react'; import { styled, themes, convert } from '@storybook/theming'; -import { Icons } from '@storybook/components'; // eslint-disable-next-line import/no-named-as-default import Message from './Message'; +import { ChevronSmallDownIcon } from '@storybook/icons'; const Wrapper = styled.div<{ status: string }>(({ theme, status }) => ({ display: 'flex', @@ -30,10 +30,7 @@ const HeaderBar = styled.div<{ status: string }>(({ theme, status }) => ({ }, })); -const Icon = styled(Icons)(({ theme }) => ({ - height: 10, - width: 10, - minWidth: 10, +const Icon = styled(ChevronSmallDownIcon)(({ theme }) => ({ color: theme.textMutedColor, marginRight: 10, transition: 'transform 0.1s ease-in-out', @@ -66,7 +63,6 @@ export function Result(props: ResultProps) { {status === `failed` ? ( { addons.add(TOOL_ID, { type: types.TOOL, title: 'Measure', - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => , }); }); diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json index 544b749f4157..ac06e9f2783a 100644 --- a/code/addons/outline/package.json +++ b/code/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", @@ -55,13 +55,13 @@ }, "dependencies": { "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.3", "ts-dedent": "^2.0.0" }, "devDependencies": { "@storybook/client-logger": "workspace:*", "@storybook/components": "workspace:*", "@storybook/core-events": "workspace:*", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/types": "workspace:*", diff --git a/code/addons/outline/src/manager.tsx b/code/addons/outline/src/manager.tsx index 384ea24c07c6..3c80679a5fc9 100644 --- a/code/addons/outline/src/manager.tsx +++ b/code/addons/outline/src/manager.tsx @@ -8,7 +8,7 @@ addons.register(ADDON_ID, () => { addons.add(ADDON_ID, { title: 'Outline', type: types.TOOL, - match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)), + match: ({ viewMode, tabId }) => !!(viewMode && viewMode.match(/^(story|docs)$/)) && !tabId, render: () => , }); }); diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json index 0f48c582d1f1..8be3f92b9d91 100644 --- a/code/addons/storysource/package.json +++ b/code/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", diff --git a/code/addons/themes/README.md b/code/addons/themes/README.md index 55bc748fd48f..c529f8a60258 100644 --- a/code/addons/themes/README.md +++ b/code/addons/themes/README.md @@ -27,6 +27,7 @@ For tool-specific setup, check out the recipes below - [`@emotion/styled`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/emotion.md) - [`@mui/material`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/material-ui.md) - [`bootstrap`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/bootstrap.md) +- [`postcss`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/postcss.md) - [`styled-components`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/styled-components.md) - [`tailwind`](https://github.com/storybookjs/storybook/tree/next/code/addons/themes/docs/getting-started/tailwind.md) - [`vuetify@3.x`](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#writing-a-custom-decorator) diff --git a/code/addons/themes/docs/getting-started/bootstrap.md b/code/addons/themes/docs/getting-started/bootstrap.md index fd0a59d6fdce..41673332bba5 100644 --- a/code/addons/themes/docs/getting-started/bootstrap.md +++ b/code/addons/themes/docs/getting-started/bootstrap.md @@ -2,8 +2,6 @@ ## 📦 Install addon - - To get started, **install the package** as a dev dependency. yarn: diff --git a/code/addons/themes/docs/getting-started/emotion.md b/code/addons/themes/docs/getting-started/emotion.md index 1671b93b3583..7c44c20fc3d1 100644 --- a/code/addons/themes/docs/getting-started/emotion.md +++ b/code/addons/themes/docs/getting-started/emotion.md @@ -2,8 +2,6 @@ ## 📦 Install addon - - To get started, **install the package** as a dev dependency. yarn: diff --git a/code/addons/themes/docs/getting-started/material-ui.md b/code/addons/themes/docs/getting-started/material-ui.md index 1b88fae1451a..3c6209205161 100644 --- a/code/addons/themes/docs/getting-started/material-ui.md +++ b/code/addons/themes/docs/getting-started/material-ui.md @@ -2,8 +2,6 @@ ## 📦 Install addon - - To get started, **install the package** as a dev dependency. yarn: diff --git a/code/addons/themes/docs/getting-started/postcss.md b/code/addons/themes/docs/getting-started/postcss.md new file mode 100644 index 000000000000..d6ce1c8f02b1 --- /dev/null +++ b/code/addons/themes/docs/getting-started/postcss.md @@ -0,0 +1,114 @@ +# 🏁 Getting started with `postcss` + +## 📦 Install addon + +To get started, **install the package** as a dev dependency + +yarn: + +```zsh +yarn add -D @storybook/addon-themes postcss-dark-theme-class +``` + +npm: + +```zsh +npm install -D @storybook/addon-themes postcss-dark-theme-class +``` + +pnpm: + +```zsh +pnpm add -D @storybook/addon-themes postcss-dark-theme-class +``` + +## 🧩 Register Addon + +Now, **include the addon** in your `.storybook/main.js` file. + +```diff +module.exports = { + stories: [ + "../stories/**/*.stories.mdx", + "../stories/**/*.stories.@(js|jsx|ts|tsx)", + ], + addons: [ + "@storybook/addon-essentials", ++ "@storybook/addon-themes" + ], +}; +``` + +## 🏷️ Add class to `prefers-color-scheme` media + +CSS 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. + +Check your project for existing PostCSS config: `postcss.config.js` in the project root, `"postcss"` section in `package.json` or postcss in bundle config. + +Add plugin to the list. + +```diff +module.exports = { + plugins: [ ++ require('postcss-dark-theme-class'), + require('autoprefixer') + ] +} +``` + +Use `prefers-color-scheme` media in your CSS: + +```css +:root { + --text-color: black; +} +@media (prefers-color-scheme: dark) { + html { + --text-color: white; + } +} +``` + +## 🥾 Import your CSS + +To give your stories access to styles, import them into your `.storybook/preview.js` file. + +```diff +import { Preview } from "@storybook/your-renderer"; + ++import "../src/index.css"; + +const preview: Preview = { + parameters: { /* ... */ }, +}; + +export default preview; +``` + +## 🎨 Provide your theme(s) + +To 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. + +```diff +-import { Preview } from "@storybook/your-renderer"; ++import { Preview, Renderer } from "@storybook/your-renderer"; ++import { withThemeByClassName } from "@storybook/addon-themes"; + +import "../src/index.css"; + + +const preview: Preview = { + parameters: { /* ... */ }, ++ decorators: [ ++ withThemeByClassName({ ++ themes: { ++ light: "is-light", ++ dark: "is-dark", ++ }, ++ defaultTheme: "light", ++ }), ++ ] +}; + +export default preview; +``` diff --git a/code/addons/themes/docs/getting-started/styled-components.md b/code/addons/themes/docs/getting-started/styled-components.md index e5e31361f121..d844dfe4af3b 100644 --- a/code/addons/themes/docs/getting-started/styled-components.md +++ b/code/addons/themes/docs/getting-started/styled-components.md @@ -2,8 +2,6 @@ ## 📦 Install addon - - To get started, **install the package** as a dev dependency. yarn: diff --git a/code/addons/themes/docs/getting-started/tailwind.md b/code/addons/themes/docs/getting-started/tailwind.md index c5475c621550..e4b95a823e52 100644 --- a/code/addons/themes/docs/getting-started/tailwind.md +++ b/code/addons/themes/docs/getting-started/tailwind.md @@ -2,8 +2,6 @@ ## 📦 Install addon - - To get started, **install the package** as a dev dependency. yarn: diff --git a/code/addons/themes/package.json b/code/addons/themes/package.json index f6536c7bb828..e58c37701697 100644 --- a/code/addons/themes/package.json +++ b/code/addons/themes/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-themes", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Switch between multiple themes for you components in Storybook", "keywords": [ "css", @@ -59,7 +59,7 @@ "@storybook/client-logger": "workspace:*", "@storybook/components": "workspace:*", "@storybook/core-events": "workspace:*", - "@storybook/icons": "^1.2.3", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/theming": "workspace:*", diff --git a/code/addons/themes/src/decorators/class-name.decorator.tsx b/code/addons/themes/src/decorators/class-name.decorator.tsx index ccbe4fbf7f31..0306c5ea9912 100644 --- a/code/addons/themes/src/decorators/class-name.decorator.tsx +++ b/code/addons/themes/src/decorators/class-name.decorator.tsx @@ -13,7 +13,8 @@ const DEFAULT_ELEMENT_SELECTOR = 'html'; const classStringToArray = (classString: string) => classString.split(' ').filter(Boolean); -export const withThemeByClassName = ({ +// TODO check with @kasperpeulen: change the types so they can be correctly inferred from context e.g. any> +export const withThemeByClassName = ({ themes, defaultTheme, parentSelector = DEFAULT_ELEMENT_SELECTOR, diff --git a/code/addons/themes/src/decorators/data-attribute.decorator.tsx b/code/addons/themes/src/decorators/data-attribute.decorator.tsx index 546885db8d62..4009fd9073a0 100644 --- a/code/addons/themes/src/decorators/data-attribute.decorator.tsx +++ b/code/addons/themes/src/decorators/data-attribute.decorator.tsx @@ -12,7 +12,8 @@ export interface DataAttributeStrategyConfiguration { const DEFAULT_ELEMENT_SELECTOR = 'html'; const DEFAULT_DATA_ATTRIBUTE = 'data-theme'; -export const withThemeByDataAttribute = ({ +// TODO check with @kasperpeulen: change the types so they can be correctly inferred from context e.g. any> +export const withThemeByDataAttribute = ({ themes, defaultTheme, parentSelector = DEFAULT_ELEMENT_SELECTOR, diff --git a/code/addons/themes/src/decorators/provider.decorator.tsx b/code/addons/themes/src/decorators/provider.decorator.tsx index 6063034eb859..0466a29e6ac8 100644 --- a/code/addons/themes/src/decorators/provider.decorator.tsx +++ b/code/addons/themes/src/decorators/provider.decorator.tsx @@ -16,7 +16,8 @@ export interface ProviderStrategyConfiguration { const pluckThemeFromKeyPairTuple = ([_, themeConfig]: [string, Theme]): Theme => themeConfig; -export const withThemeFromJSXProvider = ({ +// TODO check with @kasperpeulen: change the types so they can be correctly inferred from context e.g. any> +export const withThemeFromJSXProvider = ({ Provider, GlobalStyles, defaultTheme, diff --git a/code/addons/themes/src/manager.tsx b/code/addons/themes/src/manager.tsx index 2fba5bd29a4b..f67c21c0b99c 100644 --- a/code/addons/themes/src/manager.tsx +++ b/code/addons/themes/src/manager.tsx @@ -7,7 +7,7 @@ addons.register(ADDON_ID, () => { addons.add(THEME_SWITCHER_ID, { title: 'Themes', type: types.TOOL, - match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)), + match: ({ viewMode, tabId }) => !!(viewMode && viewMode.match(/^(story|docs)$/)) && !tabId, render: ThemeSwitcher, paramKey: PARAM_KEY, }); diff --git a/code/addons/toolbars/README.md b/code/addons/toolbars/README.md index 560966c094ce..dcb9b9c4deef 100644 --- a/code/addons/toolbars/README.md +++ b/code/addons/toolbars/README.md @@ -42,4 +42,4 @@ The primary difference between the two packages is that `addon-toolbars` makes u - **Ergonomics**. Global args are easy to consume [in stories](https://storybook.js.org/docs/react/essentials/toolbars-and-globals#consuming-globals-from-within-a-story), in [Storybook Docs](https://github.com/storybookjs/storybook/tree/next/code/addons/docs), or even in other addons. -* **Framework compatibility**. Args are completely framework-independent, so `addon-toolbars` is compatible with React, Vue, Angular, etc. out of the box with no framework logic needed in the addon. +* **Framework compatibility**. Args are completely framework-independent, so `addon-toolbars` is compatible with React, Vue 3, Angular, etc. out of the box with no framework logic needed in the addon. diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json index 443561cf56ae..87101fc2d444 100644 --- a/code/addons/toolbars/package.json +++ b/code/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", diff --git a/code/addons/toolbars/src/components/ToolbarMenuButton.tsx b/code/addons/toolbars/src/components/ToolbarMenuButton.tsx index f7d297be6b93..b095b0fb3e24 100644 --- a/code/addons/toolbars/src/components/ToolbarMenuButton.tsx +++ b/code/addons/toolbars/src/components/ToolbarMenuButton.tsx @@ -10,6 +10,10 @@ interface ToolbarMenuButtonProps { onClick?: () => void; } +// We can't remove the Icons component just yet because there's no way for now to import icons +// in the preview directly. Before having a better solution, we are going to keep the Icons component +// for now and remove the deprecated warning. + export const ToolbarMenuButton: FC = ({ active, title, @@ -19,7 +23,7 @@ export const ToolbarMenuButton: FC = ({ }) => { return ( - {icon && } + {icon && } {title ? `\xa0${title}` : null} ); diff --git a/code/addons/toolbars/src/manager.tsx b/code/addons/toolbars/src/manager.tsx index c87d3fbf2d80..f1edac1d2fd5 100644 --- a/code/addons/toolbars/src/manager.tsx +++ b/code/addons/toolbars/src/manager.tsx @@ -7,7 +7,7 @@ addons.register(ADDON_ID, () => addons.add(ADDON_ID, { title: ADDON_ID, type: types.TOOL, - match: () => true, + match: ({ tabId }) => !tabId, render: () => , }) ); diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json index 54a6128ab55a..f5c3b0622880 100644 --- a/code/addons/viewport/package.json +++ b/code/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", @@ -55,7 +55,7 @@ "@storybook/components": "workspace:*", "@storybook/core-events": "workspace:*", "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.3", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/theming": "workspace:*", diff --git a/code/addons/viewport/src/manager.tsx b/code/addons/viewport/src/manager.tsx index e42e3fba40e1..973df25422c4 100644 --- a/code/addons/viewport/src/manager.tsx +++ b/code/addons/viewport/src/manager.tsx @@ -9,7 +9,7 @@ addons.register(ADDON_ID, () => { addons.add(ADDON_ID, { title: 'viewport / media-queries', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => , }); }); diff --git a/code/builders/builder-manager/package.json b/code/builders/builder-manager/package.json index a7e9b74eb21b..02f7b800666e 100644 --- a/code/builders/builder-manager/package.json +++ b/code/builders/builder-manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-manager", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook manager builder", "keywords": [ "storybook" diff --git a/code/builders/builder-vite/README.md b/code/builders/builder-vite/README.md index 1e5026e36443..18a2e0ec6df3 100644 --- a/code/builders/builder-vite/README.md +++ b/code/builders/builder-vite/README.md @@ -27,7 +27,7 @@ When installing Storybook, use the `--builder=vite` flag if you do not have a `v The builder supports both development mode in Storybook and building a static production version. -Your `vite.config` file will be used by Storybook. If you need to customize the vite config for Storybook, you have two choices: +Your `vite.config` file will be used by Storybook. If you need to customize the Vite config for Storybook, you have two choices: 1. Set values in your `vite.config` conditionally, based on an environment variable, for example. 2. Add a `viteFinal` config to your `.storybook/main.js` file. See [Customize Vite config](#customize-vite-config) for details. @@ -44,12 +44,12 @@ npx storybook@latest init --builder vite && npm run storybook ### Migration from webpack / CRA 1. Install `vite` and `@storybook/builder-vite` -2. Remove any explicit project dependencies on `webpack`, `react-scripts`, and any other webpack plugins or loaders. +2. Remove any explicit project dependencies on `webpack`, `react-scripts`, and any other Webpack plugins or loaders. 3. 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. -4. Choose a vite-based Storybook "framework" to set in the `framework` option of your `.storybook/main.js` file. -5. Remove storybook webpack cache (`rm -rf node_modules/.cache`) -6. Update your `/public/index.html` file for vite (be sure there are no `%PUBLIC_URL%` inside it, which is a CRA variable) -7. 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. +4. Choose a Vite-based Storybook "framework" to set in the `framework` option of your `.storybook/main.js` file. +5. Remove Storybook Webpack cache (`rm -rf node_modules/.cache`) +6. Update your `/public/index.html` file for Vite (be sure there are no `%PUBLIC_URL%` inside it, which is a CRA variable) +7. 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. 8. If you are using `@storybook/addon-interactions`, 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: ```html @@ -58,9 +58,9 @@ npx storybook@latest init --builder vite && npm run storybook ``` -9. Start up your storybook using the same `yarn storybook` or `npm run storybook` commands you are used to. +9. Start up your Storybook using the same `yarn storybook` or `npm run storybook` commands you are used to. -For other details about the differences between vite and webpack projects, be sure to read through the [vite documentation](https://vitejs.dev/). +For other details about the differences between Vite and Webpack projects, be sure to read through the [Vite documentation](https://vitejs.dev/). ### Customize Vite config @@ -105,7 +105,7 @@ const config = { export default config; ``` -The `viteFinal` function will give you `config` which is the combination of your project's vite config and the builder's own Vite config. +The `viteFinal` function will give you `config` which is the combination of your project's Vite config and the builder's own Vite config. You can tweak this as you want, for example to set up aliases, add new plugins etc. The `configType` variable will be either `"DEVELOPMENT"` or `"PRODUCTION"`. @@ -133,7 +133,7 @@ See [Customize Vite config](#customize-vite-config) for details about using `vit ### React Docgen -Docgen 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, and React, and there are two docgen options when using react, `react-docgen` and `react-docgen-typescript`. You can learn more about the pros/cons of each in [this gist](https://gist.github.com/shilman/036313ffa3af52ca986b375d90ea46b0). By default, if we find a `typescript` dependency in your `package.json` file, we will assume you're using typescript and will choose `react-docgen-typescript`. You can change this by setting the `typescript.reactDocgen` option in your `.storybook/main.js` file: +Docgen 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) setting in `.storybook/main.js`. ```javascript export default { @@ -149,7 +149,7 @@ If you're using TypeScript, we encourage you to experiment and see which option The builder will by default enable Vite's [server.fs.strict](https://vitejs.dev/config/#server-fs-strict) option, for increased security. The default project `root` is set to the parent directory of the -storybook configuration directory. This can be overridden in viteFinal. +Storybook configuration directory. This can be overridden in [viteFinal](https://storybook.js.org/docs/api/main-config-vite-final). ## Known issues @@ -158,7 +158,8 @@ storybook configuration directory. This can be overridden in viteFinal. ## Contributing The Vite builder cannot build itself. -Are you willing to contribute? We are especially looking for Vue and Svelte experts, as the current maintainers are react users. + +Are you willing to contribute? We are especially looking for Vue and Svelte experts, as the current maintainers are React users. Have a look at the GitHub issues with the `vite` label for known bugs. If you find any new bugs, feel free to create an issue or send a pull request! diff --git a/code/builders/builder-vite/input/iframe.html b/code/builders/builder-vite/input/iframe.html index dd976d6c4ab4..7720ef6b9482 100644 --- a/code/builders/builder-vite/input/iframe.html +++ b/code/builders/builder-vite/input/iframe.html @@ -1,44 +1,66 @@ - + + + + Storybook + - - - Storybook - + + + + + - - - - - + + + - // We do this so that "module && module.hot" etc. in Storybook source code - // doesn't fail (it will simply be disabled) - window.module = undefined; - window.global = window; - - - - - - -
-
- - - - - \ No newline at end of file + + +
+
+ + + + diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json index 86e2f412c145..f10e112debd4 100644 --- a/code/builders/builder-vite/package.json +++ b/code/builders/builder-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-vite", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "A plugin to run and build Storybooks with Vite", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme", "bugs": { @@ -57,7 +57,8 @@ "express": "^4.17.3", "find-cache-dir": "^3.0.0", "fs-extra": "^11.1.0", - "magic-string": "^0.30.0" + "magic-string": "^0.30.0", + "ts-dedent": "^2.0.0" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/code/builders/builder-vite/src/build.ts b/code/builders/builder-vite/src/build.ts index ccf9f9476a5f..1cd14d1b2d8d 100644 --- a/code/builders/builder-vite/src/build.ts +++ b/code/builders/builder-vite/src/build.ts @@ -1,7 +1,17 @@ import type { Options } from '@storybook/types'; -import { commonConfig } from './vite-config'; +import { logger } from '@storybook/node-logger'; +import dedent from 'ts-dedent'; +import { commonConfig } from './vite-config'; import { sanitizeEnvVars } from './envs'; +import type { WebpackStatsPlugin } from './plugins'; +import type { InlineConfig } from 'vite'; +import { hasVitePlugins } from './utils/has-vite-plugins'; +import { withoutVitePlugins } from './utils/without-vite-plugins'; + +function findPlugin(config: InlineConfig, name: string) { + return config.plugins?.find((p) => p && 'name' in p && p.name === name); +} export async function build(options: Options) { const { build: viteBuild, mergeConfig } = await import('vite'); @@ -28,5 +38,21 @@ export async function build(options: Options) { }).build; const finalConfig = await presets.apply('viteFinal', config, options); + + const turbosnapPluginName = 'rollup-plugin-turbosnap'; + const hasTurbosnapPlugin = + finalConfig.plugins && (await hasVitePlugins(finalConfig.plugins, [turbosnapPluginName])); + if (hasTurbosnapPlugin) { + logger.warn(dedent`Found '${turbosnapPluginName}' which is now included by default in Storybook 8. + Removing from your plugins list. Ensure you pass \`--webpack-stats-json\` to generate stats. + + For more information, see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#turbosnap-vite-plugin-is-no-longer-needed`); + + finalConfig.plugins = await withoutVitePlugins(finalConfig.plugins, [turbosnapPluginName]); + } + await viteBuild(await sanitizeEnvVars(options, finalConfig)); + + const statsPlugin = findPlugin(finalConfig, 'rollup-plugin-webpack-stats') as WebpackStatsPlugin; + return statsPlugin?.storybookGetStats(); } diff --git a/code/builders/builder-vite/src/plugins/index.ts b/code/builders/builder-vite/src/plugins/index.ts index 68e540908dc6..bc72dc8755d5 100644 --- a/code/builders/builder-vite/src/plugins/index.ts +++ b/code/builders/builder-vite/src/plugins/index.ts @@ -3,3 +3,4 @@ export * from './strip-story-hmr-boundaries'; export * from './code-generator-plugin'; export * from './csf-plugin'; export * from './external-globals-plugin'; +export * from './webpack-stats-plugin'; diff --git a/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts new file mode 100644 index 000000000000..affb130c07e1 --- /dev/null +++ b/code/builders/builder-vite/src/plugins/webpack-stats-plugin.ts @@ -0,0 +1,116 @@ +// This plugin is a direct port of https://github.com/IanVS/vite-plugin-turbosnap + +import type { BuilderStats } from '@storybook/types'; +import path from 'path'; +import type { Plugin } from 'vite'; + +/* + * Reason, Module are copied from chromatic types + * https://github.com/chromaui/chromatic-cli/blob/145a5e295dde21042e96396c7e004f250d842182/bin-src/types.ts#L265-L276 + */ +interface Reason { + moduleName: string; +} +interface Module { + id: string | number; + name: string; + modules?: Array>; + reasons?: Reason[]; +} + +type WebpackStatsPluginOptions = { + workingDir: string; +}; + +/** + * Strips off query params added by rollup/vite to ids, to make paths compatible for comparison with git. + */ +function stripQueryParams(filePath: string): string { + return filePath.split('?')[0]; +} + +/** + * We only care about user code, not node_modules, vite files, or (most) virtual files. + */ +function isUserCode(moduleName: string) { + return Boolean( + moduleName && + !moduleName.startsWith('vite/') && + !moduleName.startsWith('\x00') && + !moduleName.startsWith('\u0000') && + moduleName !== 'react/jsx-runtime' && + !moduleName.match(/node_modules\//) + ); +} + +export type WebpackStatsPlugin = Plugin & { storybookGetStats: () => BuilderStats }; + +export function pluginWebpackStats({ workingDir }: WebpackStatsPluginOptions): WebpackStatsPlugin { + /** + * Convert an absolute path name to a path relative to the vite root, with a starting `./` + */ + function normalize(filename: string) { + // Do not try to resolve virtual files + if (filename.startsWith('/virtual:')) { + return filename; + } + // Otherwise, we need them in the format `./path/to/file.js`. + else { + const relativePath = path.relative(workingDir, stripQueryParams(filename)); + // This seems hacky, got to be a better way to add a `./` to the start of a path. + return `./${relativePath}`; + } + } + + /** + * Helper to create Reason objects out of a list of string paths + */ + function createReasons(importers?: readonly string[]): Reason[] { + return (importers || []).map((i) => ({ moduleName: normalize(i) })); + } + + /** + * Helper function to build a `Module` given a filename and list of files that import it + */ + function createStatsMapModule(filename: string, importers?: readonly string[]): Module { + return { + id: filename, + name: filename, + reasons: createReasons(importers), + }; + } + + const statsMap = new Map(); + + return { + name: 'storybook:rollup-plugin-webpack-stats', + // We want this to run after the vite build plugins (https://vitejs.dev/guide/api-plugin.html#plugin-ordering) + enforce: 'post', + moduleParsed: function (mod) { + if (isUserCode(mod.id)) { + mod.importedIds + .concat(mod.dynamicallyImportedIds) + .filter((name) => isUserCode(name)) + .forEach((depIdUnsafe) => { + const depId = normalize(depIdUnsafe); + if (statsMap.has(depId)) { + const m = statsMap.get(depId); + if (m) { + m.reasons = (m.reasons ?? []) + .concat(createReasons([mod.id])) + .filter((r) => r.moduleName !== depId); + statsMap.set(depId, m); + } + } else { + statsMap.set(depId, createStatsMapModule(depId, [mod.id])); + } + }); + } + }, + + storybookGetStats() { + const stats = { modules: Array.from(statsMap.values()) }; + return { ...stats, toJson: () => stats }; + }, + }; +} diff --git a/code/builders/builder-vite/src/vite-config.ts b/code/builders/builder-vite/src/vite-config.ts index 2383ebd6e5e5..4a1c2fb3ee44 100644 --- a/code/builders/builder-vite/src/vite-config.ts +++ b/code/builders/builder-vite/src/vite-config.ts @@ -20,6 +20,7 @@ import { injectExportOrderPlugin, stripStoryHMRBoundary, externalGlobalsPlugin, + pluginWebpackStats, } from './plugins'; import type { BuilderOptions } from './types'; @@ -112,6 +113,7 @@ export async function pluginConfig(options: Options) { }, }, await externalGlobalsPlugin(externals), + pluginWebpackStats({ workingDir: process.cwd() }), ] as PluginOption[]; // TODO: framework doesn't exist, should move into framework when/if built diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index e600a0dc9424..f9973efbd8ef 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack5", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/builders/builder-webpack5/src/types.ts b/code/builders/builder-webpack5/src/types.ts index 6e55f145ca22..38621af56274 100644 --- a/code/builders/builder-webpack5/src/types.ts +++ b/code/builders/builder-webpack5/src/types.ts @@ -3,11 +3,12 @@ import type { Options, BuilderResult as BuilderResultBase, StorybookConfig, + TypescriptOptions as WebpackTypescriptOptions, } from '@storybook/core-webpack'; import type ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; -type TypeScriptOptionsBase = Required['typescript']; +type TypeScriptOptionsBase = Partial; /** * Options for TypeScript usage within Storybook. @@ -19,7 +20,7 @@ export interface TypescriptOptions extends TypeScriptOptionsBase { checkOptions?: ConstructorParameters[0]; } -export interface StorybookConfigWebpack extends Pick { +export interface StorybookConfigWebpack extends Omit { /** * Modify or return a custom Webpack config after the Storybook's default configuration * has run (mostly used by addons). diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index 32b0690e9c14..2b15ffc53fb9 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.", "keywords": [ "storybook", diff --git a/code/frameworks/angular/src/builders/build-storybook/index.ts b/code/frameworks/angular/src/builders/build-storybook/index.ts index abe8fbd6a060..81d6b2689c2a 100644 --- a/code/frameworks/angular/src/builders/build-storybook/index.ts +++ b/code/frameworks/angular/src/builders/build-storybook/index.ts @@ -49,6 +49,7 @@ export type StorybookBuilderOptions = JsonObject & { | 'configDir' | 'loglevel' | 'quiet' + | 'test' | 'webpackStatsJson' | 'disableTelemetry' | 'debugWebpack' @@ -87,6 +88,7 @@ const commandBuilder: BuilderHandlerFn = ( configDir, docs, loglevel, + test, outputDir, quiet, enableProdMode = true, @@ -104,6 +106,7 @@ const commandBuilder: BuilderHandlerFn = ( ...(docs ? { docs } : {}), loglevel, outputDir, + test, quiet, enableProdMode, disableTelemetry, diff --git a/code/frameworks/angular/src/preset.ts b/code/frameworks/angular/src/preset.ts index da3bb0192f0d..139b5477110e 100644 --- a/code/frameworks/angular/src/preset.ts +++ b/code/frameworks/angular/src/preset.ts @@ -22,7 +22,7 @@ export const previewAnnotations: PresetProperty<'previewAnnotations'> = (entries return annotations; }; -export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { +export const core: PresetProperty<'core'> = async (config, options) => { const framework = await options.presets.apply('framework'); return { @@ -34,7 +34,7 @@ export const core: PresetProperty<'core', StorybookConfig> = async (config, opti }; }; -export const typescript: PresetProperty<'typescript', StorybookConfig> = async (config) => { +export const typescript: PresetProperty<'typescript'> = async (config) => { return { ...config, skipCompiler: true, diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index de2e289d1f32..0da35b6230cc 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember", "bugs": { diff --git a/code/frameworks/ember/src/preset.ts b/code/frameworks/ember/src/preset.ts index 9de2b1ab35c0..7f0a07ce7cbb 100644 --- a/code/frameworks/ember/src/preset.ts +++ b/code/frameworks/ember/src/preset.ts @@ -43,7 +43,7 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig, }; }; -export const core: PresetProperty<'core', StorybookConfig> = async (config, options) => { +export const core: PresetProperty<'core'> = async (config, options) => { const framework = await options.presets.apply('framework'); return { diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index b80903daff3f..53c979465eae 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-vite", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/html-vite/src/preset.ts b/code/frameworks/html-vite/src/preset.ts index 4ae871b6e589..965ba77956a0 100644 --- a/code/frameworks/html-vite/src/preset.ts +++ b/code/frameworks/html-vite/src/preset.ts @@ -1,12 +1,11 @@ import type { PresetProperty } from '@storybook/types'; import { dirname, join } from 'path'; -import type { StorybookConfig } from './types'; function getAbsolutePath(value: I): I { return dirname(require.resolve(join(value, 'package.json'))) as any; } -export const core: PresetProperty<'core', StorybookConfig> = { +export const core: PresetProperty<'core'> = { builder: getAbsolutePath('@storybook/builder-vite'), renderer: getAbsolutePath('@storybook/html'), }; diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index c51d2a247d61..34e9a2c4683e 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-webpack5", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/nextjs/README.md b/code/frameworks/nextjs/README.md index 23f637900ac3..87019027ca9a 100644 --- a/code/frameworks/nextjs/README.md +++ b/code/frameworks/nextjs/README.md @@ -1,1055 +1,6 @@ -# Storybook for Next.js +# Storybook for Next.js -## Table of Contents - -- [Supported Features](#supported-features) -- [Requirements](#requirements) -- [Getting Started](#getting-started) - - [In a project without Storybook](#in-a-project-without-storybook) - - [In a project with Storybook](#in-a-project-with-storybook) - - [Automatic migration](#automatic-migration) - - [Manual migration](#manual-migration) -- [Documentation](#documentation) - - [Options](#options) - - [Next.js's Image Component](#nextjss-image-component) - - [Local Images](#local-images) - - [Remote Images](#remote-images) - - [Next.js Font Optimization](#nextjs-font-optimization) - - [next/font/google](#nextfontgoogle) - - [next/font/local](#nextfontlocal) - - [Not supported features of next/font](#not-supported-features-of-nextfont) - - [Mocking fonts during testing](#mocking-fonts-during-testing) - - [Next.js Routing](#nextjs-routing) - - [Overriding defaults](#overriding-defaults) - - [Global Defaults](#global-defaults) - - [Default Router](#default-router) - - [Actions Integration Caveats](#actions-integration-caveats) - - [Next.js Navigation](#nextjs-navigation) - - [Set `nextjs.appDirectory` to `true`](#set-nextjsappdirectory-to-true) - - [Overriding defaults](#overriding-defaults-1) - - [Global Defaults](#global-defaults-1) - - [`useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hook](#useselectedlayoutsegment-useselectedlayoutsegments-and-useparams-hook) - - [Default Navigation Context](#default-navigation-context) - - [Actions Integration Caveats](#actions-integration-caveats-1) - - [Next.js Head](#nextjs-head) - - [Sass/Scss](#sassscss) - - [Css/Sass/Scss Modules](#csssassscss-modules) - - [Styled JSX](#styled-jsx) - - [Postcss](#postcss) - - [Absolute Imports](#absolute-imports) - - [Runtime Config](#runtime-config) - - [Custom Webpack Config](#custom-webpack-config) - - [Typescript](#typescript) - - [Experimental React Server Components (RSC)](#experimental-react-server-components-rsc) - - [Notes for Yarn v2 and v3 users](#notes-for-yarn-v2-and-v3-users) - - [FAQ](#faq) - - [Stories for pages/components which fetch data](#stories-for-pagescomponents-which-fetch-data) - - [Statically imported images won't load](#statically-imported-images-wont-load) - - [Module not found: Error: Can't resolve `package name`](#module-not-found-error-cant-resolve-package-name) - - [What if I'm using the Vite builder?](#what-if-im-using-the-vite-builder) -- [Acknowledgements](#acknowledgements) - -## Supported Features - -👉 [Next.js's Image Component](#nextjss-image-component) - -👉 [Next.js Font Optimization](#nextjs-font-optimization) - -👉 [Next.js Routing (next/router)](#nextjs-routing) - -👉 [Next.js Head (next/head)](#nextjs-head) - -👉 [Next.js Navigation (next/navigation)](#nextjs-navigation) - -👉 [Sass/Scss](#sassscss) - -👉 [Css/Sass/Scss Modules](#csssassscss-modules) - -👉 [Styled JSX](#styled-jsx) - -👉 [Postcss](#postcss) - -👉 [Absolute Imports](#absolute-imports) - -👉 [Runtime Config](#runtime-config) - -👉 [Custom Webpack Config](#custom-webpack-config) - -👉 [Typescript](#typescript) (already supported out of the box by Storybook) - -## Requirements - -- [Next.js](https://nextjs.org/) >= 12.x -- [Storybook](https://storybook.js.org/) >= 7.x - -## Getting Started - -### In a project without Storybook - -Follow the prompts after running this command in your Next.js project's root directory: - -```bash -npx storybook@latest init -``` - -[More on getting started with Storybook](https://storybook.js.org/docs/react/get-started/install) - -### In a project with Storybook - -This framework is designed to work with Storybook 7. If you’re not already using v7, upgrade with this command: - -```bash -npx storybook@latest upgrade -``` - -#### Automatic migration - -When running the `upgrade` command above, you should get a prompt asking you to migrate to `@storybook/nextjs`, which should handle everything for you. In case that auto-migration does not work for your project, refer to the manual migration below. - -#### Manual migration - -Install the framework: - -```bash -yarn add --dev @storybook/nextjs -``` - -Update your `main.js` to change the framework property: - -```js -// .storybook/main.js -export default { - // ... - framework: { - // name: '@storybook/react-webpack5', // Remove this - name: '@storybook/nextjs', // Add this - }, -}; -``` - -If you were using Storybook plugins to integrate with Next.js, those are no longer necessary when using this framework and can be removed: - -```js -// .storybook/main.js -export default { - // ... - addons: [ - // ... - // These can both be removed - // 'storybook-addon-next', - // 'storybook-addon-next-router', - ], -}; -``` - -## Documentation - -### Options - -You can be pass an options object for additional configuration if needed. - -For example: - -```js -// .storybook/main.js -import * as path from 'path'; - -export default { - // ... - framework: { - name: '@storybook/nextjs', - options: { - image: { - loading: 'eager', - }, - nextConfigPath: path.resolve(__dirname, '../next.config.js'), - }, - }, -}; -``` - -- `image`: Props to pass to every instance of `next/image` -- `nextConfigPath`: The absolute path to the `next.config.js` - -### Next.js's Image Component - -[next/image](https://nextjs.org/docs/api-reference/next/image) is [notoriously difficult](https://github.com/vercel/next.js/issues/18393) to get working with Storybook. This framework allows you to use Next.js's `Image` component with no configuration! - -#### Local Images - -[Local images](https://nextjs.org/docs/basic-features/image-optimization#local-images) work just fine! Keep in mind that this feature was [only added in Next.js v11](https://nextjs.org/blog/next-11#automatic-size-detection-local-images). - -```js -import Image from 'next/image'; -import profilePic from '../public/me.png'; - -function Home() { - return ( - <> -

My Homepage

- Picture of the author -

Welcome to my homepage!

- - ); -} -``` - -#### Remote Images - -[Remote images](https://nextjs.org/docs/basic-features/image-optimization#remote-images) also work just fine! - -```js -import Image from 'next/image'; - -export default function Home() { - return ( - <> -

My Homepage

- Picture of the author -

Welcome to my homepage!

- - ); -} -``` - -### Next.js Font Optimization - -[next/font](https://nextjs.org/docs/basic-features/font-optimization) is partially supported in Storybook. The packages `next/font/google` and `next/font/local` are supported. - -#### next/font/google - -You don't have to do anything. `next/font/google` is supported out of the box. - -#### next/font/local - -For local fonts you have to define the [src](https://nextjs.org/docs/api-reference/next/font#src) property. -The path is relative to the directory where the font loader function is called. - -If the following component defines your localFont like this: - -```js -// src/components/MyComponent.js -import localFont from 'next/font/local'; - -const localRubikStorm = localFont({ src: './fonts/RubikStorm-Regular.ttf' }); -``` - -You have to tell Storybook where the `fonts` directory is located. 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. - -```js -// .storybook/main.js -export default { - ... - "staticDirs": [ - { - from: '../src/components/fonts', - to: 'src/components/fonts' - } - ], -} -``` - -#### Not supported features of next/font - -The following features are not supported (yet). Support for these features might be planned for the future: - -- [Support font loaders configuration in next.config.js](https://nextjs.org/docs/basic-features/font-optimization#specifying-a-subset) -- [fallback](https://nextjs.org/docs/api-reference/next/font#fallback) option -- [adjustFontFallback](https://nextjs.org/docs/api-reference/next/font#adjustfontfallback) option -- [preload](https://nextjs.org/docs/api-reference/next/font#preload) option gets ignored. Storybook handles Font loading its own way. -- [display](https://nextjs.org/docs/api-reference/next/font#display) option gets ignored. All fonts are loaded with display set to "block" to make Storybook load the font properly. - -#### Mocking fonts during testing - -Occasionally 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. - -For example, using [GitHub Actions](https://www.chromatic.com/docs/github-actions): - -```shell - - uses: chromaui/action@v1 - env: - #👇 the location of mocked fonts to use - NEXT_FONT_GOOGLE_MOCKED_RESPONSES: ${{ github.workspace }}/mocked-google-fonts.js - with: - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - token: ${{ secrets.GITHUB_TOKEN }} -``` - -Your mocked fonts will look something like this: - -```js -// mocked-google-fonts.js -//👇 Mocked responses of google fonts with the URL as the key -module.exports = { - 'https://fonts.googleapis.com/css?family=Inter:wght@400;500;600;800&display=block': ` - /* cyrillic-ext */ - @font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - font-display: block; - src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZJhiJ-Ek-_EeAmM.woff2) format('woff2'); - unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; - } - /* more font declarations go here */ - /* latin */ - @font-face { - font-family: 'Inter'; - font-style: normal; - font-weight: 400; - font-display: block; - src: url(https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiJ-Ek-_EeA.woff2) format('woff2'); - 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; - }`, -}; -``` - -### Next.js Routing - -[Next.js's router](https://nextjs.org/docs/routing/introduction) is automatically stubbed for you so that when the router is interacted with, all of its interactions are automatically logged to the Actions ctions panel if you have the [Storybook actions addon](https://storybook.js.org/docs/react/essentials/actions). - -> When using Next.js 13+, you should only use `next/router` in the `pages` directory. In the `app` directory, it is necessary to use `next/navigation`. - -#### Overriding defaults - -Per-story overrides can be done by adding a `nextjs.router` property onto the story [parameters](https://storybook.js.org/docs/react/writing-stories/parameters). The framework will shallowly merge whatever you put here into the router. - -```js -// SomeComponentThatUsesTheRouter.stories.js -import SomeComponentThatUsesTheRouter from './SomeComponentThatUsesTheRouter'; - -export default { - component: SomeComponentThatUsesTheRouter, -}; - -// If you have the actions addon, -// you can interact with the links and see the route change events there -export const Example = { - parameters: { - nextjs: { - router: { - pathname: '/profile/[id]', - asPath: '/profile/1', - query: { - id: '1', - }, - }, - }, - }, -}; -``` - -#### Global Defaults - -Global defaults can be set in [preview.js](https://storybook.js.org/docs/react/configure/#configure-story-rendering) and will be shallowly merged with the default router. - -```js -// .storybook/preview.js - -export const parameters = { - nextjs: { - router: { - pathname: '/some-default-path', - asPath: '/some-default-path', - query: {}, - }, - }, -}; -``` - -#### Default Router - -The default values on the stubbed router are as follows (see [globals](https://storybook.js.org/docs/react/essentials/toolbars-and-globals#globals) for more details on how globals work) - -```ts -const defaultRouter = { - push(...args) { - action('nextRouter.push')(...args); - return Promise.resolve(true); - }, - replace(...args) { - action('nextRouter.replace')(...args); - return Promise.resolve(true); - }, - reload(...args) { - action('nextRouter.reload')(...args); - }, - back(...args) { - action('nextRouter.back')(...args); - }, - forward() { - action('nextRouter.forward')(); - }, - prefetch(...args) { - action('nextRouter.prefetch')(...args); - return Promise.resolve(); - }, - beforePopState(...args) { - action('nextRouter.beforePopState')(...args); - }, - events: { - on(...args) { - action('nextRouter.events.on')(...args); - }, - off(...args) { - action('nextRouter.events.off')(...args); - }, - emit(...args) { - action('nextRouter.events.emit')(...args); - }, - }, - // The locale should be configured [globally](https://storybook.js.org/docs/react/essentials/toolbars-and-globals#globals) - locale: globals?.locale, - asPath: '/', - basePath: '/', - isFallback: false, - isLocaleDomain: false, - isReady: true, - isPreview: false, - route: '/', - pathname: '/', - query: {}, -}; -``` - -#### Actions Integration Caveats - -If you override a function, you lose the automatic actions integration and have to build it out yourself. - -```js -// .storybook/preview.js - -export const parameters = { - nextjs: { - router: { - push() { - // The default implementation that logs the action into the Actions panel is lost - }, - }, - }, -}; -``` - -Doing this yourself looks something like this (make sure you install the `@storybook/addon-actions` package): - -```js -// .storybook/preview.js -import { action } from '@storybook/addon-actions'; - -export const parameters = { - nextjs: { - router: { - push(...args) { - // Custom logic can go here - // This logs to the Actions panel - action('nextRouter.push')(...args); - // Return whatever you want here - return Promise.resolve(true); - }, - }, - }, -}; -``` - -### Next.js Navigation - -> Please note that [next/navigation](https://beta.nextjs.org/docs/upgrade-guide#step-5-migrating-routing-hooks) can only be used in components/pages in the `app` directory of Next.js 13+. - -#### Set `nextjs.appDirectory` to `true` - -If your story imports components that use `next/navigation`, you need to set the parameter `nextjs.appDirectory` to `true` in your Story: - -```js -// SomeComponentThatUsesTheRouter.stories.js -import SomeComponentThatUsesTheNavigation from './SomeComponentThatUsesTheNavigation'; - -export default { - component: SomeComponentThatUsesTheNavigation, -}; - -export const Example = { - parameters: { - nextjs: { - appDirectory: true, - }, - }, -}, -``` - -If 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 [preview.js](https://storybook.js.org/docs/react/configure/#configure-story-rendering) file to apply it to all stories. - -```js -// .storybook/preview.js - -export const parameters = { - nextjs: { - appDirectory: true, - }, -}; -``` - -The parameter `nextjs.appDirectory` defaults to `false` if not set. - -#### Overriding defaults - -Per-story overrides can be done by adding a `nextjs.navigation` property onto the story [parameters](https://storybook.js.org/docs/react/writing-stories/parameters). The framework will shallowly merge whatever you put here into the router. - -```js -// SomeComponentThatUsesTheNavigation.stories.js -import SomeComponentThatUsesTheNavigation from './SomeComponentThatUsesTheNavigation'; - -export default { - component: SomeComponentThatUsesTheNavigation, -}; - -// If you have the actions addon, -// you can interact with the links and see the route change events there -export const Example = { - parameters: { - nextjs: { - appDirectory: true, - navigation: { - pathname: '/profile', - query: { - user: '1', - }, - }, - }, - }, -}; -``` - -#### Global Defaults - -Global defaults can be set in [preview.js](https://storybook.js.org/docs/react/configure/#configure-story-rendering) and will be shallowly merged with the default router. - -```js -// .storybook/preview.js - -export const parameters = { - nextjs: { - appDirectory: true, - navigation: { - pathname: '/some-default-path', - }, - }, -}; -``` - -#### `useSelectedLayoutSegment` `useSelectedLayoutSegments` and `useParams` hook - -The `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. - -```js -// SomeComponentThatUsesTheNavigation.stories.js -import SomeComponentThatUsesTheNavigation from './SomeComponentThatUsesTheNavigation'; - -export default { - component: SomeComponentThatUsesTheNavigation, - parameters: { - nextjs: { - appDirectory: true, - navigation: { - segments: ['dashboard', 'analytics'] - }, - }, - }, -}; - -export const Example = {}; - -// SomeComponentThatUsesTheNavigation.js -import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation'; - -export default function SomeComponentThatUsesTheNavigation() { - const segment = useSelectedLayoutSegment(); // dashboard - const segments = useSelectedLayoutSegments(); // ["dashboard", "analytics"] - const params = useParams(); // {} - ... -} -``` - -To use `useParams`, you have to use a two string elements array for a segment, the first array element is the param key and the second array element is the param value. - -```js -// SomeComponentThatUsesParams.stories.js -import SomeComponentThatUsesParams from './SomeComponentThatUsesParams'; - -export default { - component: SomeComponentThatUsesParams, - parameters: { - nextjs: { - appDirectory: true, - navigation: { - segments: [ - ['slug', 'hello'], - ['framework', 'nextjs'], - ] - }, - }, - }, -}; - -export const Example = {}; - -// SomeComponentThatUsesParams.js -import { useSelectedLayoutSegment, useSelectedLayoutSegments, useParams } from 'next/navigation'; - -export default function SomeComponentThatUsesParams() { - const segment = useSelectedLayoutSegment(); // hello - const segments = useSelectedLayoutSegments(); // ["hello", "nextjs"] - const params = useParams(); // { slug: "hello", framework: "nextjs" } - ... -} -``` - -The default value of `nextjs.navigation.segments` is `[]` if not set. - -#### Default Navigation Context - -The default values on the stubbed navigation context are as follows: - -```ts -const defaultNavigationContext = { - push(...args) { - action('nextNavigation.push')(...args); - }, - replace(...args) { - action('nextNavigation.replace')(...args); - }, - forward(...args) { - action('nextNavigation.forward')(...args); - }, - back(...args) { - action('nextNavigation.back')(...args); - }, - prefetch(...args) { - action('nextNavigation.prefetch')(...args); - }, - refresh: () => { - action('nextNavigation.refresh')(); - }, - pathname: '/', - query: {}, -}; -``` - -#### Actions Integration Caveats - -If you override a function, you lose the automatic action tab integration and have to build it out yourself. - -```js -// .storybook/preview.js - -export const parameters = { - nextjs: { - appDirectory: true, - navigation: { - push() { - // The default implementation that logs the action into the Actions panel is lost - }, - }, - }, -}; -``` - -Doing this yourself looks something like this (make sure you install the `@storybook/addon-actions` package): - -```js -// .storybook/preview.js -import { action } from '@storybook/addon-actions'; - -export const parameters = { - nextjs: { - appDirectory: true, - navigation: { - push(...args) { - // Custom logic can go here - // This logs to the Actions panel - action('nextNavigation.push')(...args); - // Return whatever you want here - return Promise.resolve(true); - }, - }, - }, -}; -``` - -### Next.js Head - -[next/head](https://nextjs.org/docs/api-reference/next/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. - -### Sass/Scss - -[Global sass/scss stylesheets](https://nextjs.org/docs/basic-features/built-in-css-support#sass-support) are supported without any additional configuration as well. Just import them into [preview.js](https://storybook.js.org/docs/react/configure/#configure-story-rendering) - -```js -import '../styles/globals.scss'; -``` - -This will automatically include any of your [custom sass configurations](https://nextjs.org/docs/basic-features/built-in-css-support#customizing-sass-options) in your `next.config.js` file. - -```js -// next.config.js -import * as path from 'path'; - -export default { - // Any options here are included in Sass compilation for your stories - sassOptions: { - includePaths: [path.join(__dirname, 'styles')], - }, -}; -``` - -### Css/Sass/Scss Modules - -[css modules](https://nextjs.org/docs/basic-features/built-in-css-support#adding-component-level-css) work as expected. - -```js -// This import works just fine in Storybook now -import styles from './Button.module.css'; -// sass/scss is also supported -// import styles from './Button.module.scss' -// import styles from './Button.module.sass' - -export function Button() { - return ( - - ); -} -``` - -### Styled JSX - -The built in CSS-in-JS solution for Next.js is [styled-jsx](https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js), and this framework supports that out of the box too, zero config. - -```js -// This works just fine in Storybook now -function HelloWorld() { - return ( -
- Hello world -

scoped!

- - -
- ); -} - -export default HelloWorld; -``` - -You can use your own babel config too. This is an example of how you can customize styled-jsx. - -```json -// .babelrc or whatever config file you use -{ - "presets": [ - [ - "next/babel", - { - "styled-jsx": { - "plugins": ["@styled-jsx/plugin-sass"] - } - } - ] - ] -} -``` - -### Postcss - -Next.js lets you [customize postcss config](https://nextjs.org/docs/advanced-features/customizing-postcss-config#default-behavior). Thus this framework will automatically handle your postcss config for you. - -This allows for cool things like zero config tailwindcss! (See [Next.js' example](https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss)) - -### Absolute Imports - -Goodbye `../`! Absolute imports from the root directory work just fine. - -```js -// All good! -import Button from 'components/button'; -// Also good! -import styles from 'styles/HomePage.module.css'; - -export default function HomePage() { - return ( - <> -

Hello World

- + + +`; + +exports[`Renders CSF2StoryWithLocale story 1`] = ` + +
+
+

+ locale: undefined +

+ +
+
+ +`; + +exports[`Renders CSF3Button story 1`] = ` + +
+ +
+ +`; + +exports[`Renders CSF3ButtonWithRender story 1`] = ` + +
+
+

+ I am a custom render function +

+ +
+
+ +`; + +exports[`Renders CSF3InputFieldFilled story 1`] = ` + +
+ +
+ +`; + +exports[`Renders CSF3Primary story 1`] = ` + +
+ +
+ +`; diff --git a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts new file mode 100644 index 000000000000..4c541e1c4536 --- /dev/null +++ b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts @@ -0,0 +1,138 @@ +/// ; +import { it, expect, vi, describe } from 'vitest'; +import { render, screen } from '@testing-library/vue'; +import { addons } from '@storybook/preview-api'; +import { expectTypeOf } from 'expect-type'; +import type { Meta } from '@storybook/vue3'; + +import * as stories from './Button.stories'; +import type Button from './Button.vue'; +import { composeStories, composeStory, setProjectAnnotations } from '../../portable-stories'; + +// example with composeStories, returns an object with all stories composed with args/decorators +const { CSF3Primary } = composeStories(stories); + +// example with composeStory, returns a single story composed with args/decorators +const Secondary = composeStory(stories.CSF2Secondary, stories.default); + +it('renders primary button', () => { + render(CSF3Primary({ label: 'Hello world' })); + const buttonElement = screen.getByText(/Hello world/i); + expect(buttonElement).toBeInTheDocument(); +}); + +it('reuses args from composed story', () => { + render(Secondary()); + const buttonElement = screen.getByRole('button'); + expect(buttonElement.textContent).toEqual(Secondary.args.label); +}); + +it('myClickEvent handler is called', async () => { + const myClickEventSpy = vi.fn(); + render(Secondary({ onMyClickEvent: myClickEventSpy })); + const buttonElement = screen.getByRole('button'); + buttonElement.click(); + expect(myClickEventSpy).toHaveBeenCalled(); +}); + +it('reuses args from composeStories', () => { + const { getByText } = render(CSF3Primary()); + const buttonElement = getByText(/foo/i); + expect(buttonElement).toBeInTheDocument(); +}); + +describe('projectAnnotations', () => { + it('renders with default projectAnnotations', () => { + const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default); + const { getByText } = render(WithEnglishText()); + const buttonElement = getByText('Hello!'); + expect(buttonElement).toBeInTheDocument(); + }); + + it('renders with custom projectAnnotations via composeStory params', () => { + const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, { + globalTypes: { locale: { defaultValue: 'pt' } } as any, + }); + const { getByText } = render(WithPortugueseText()); + const buttonElement = getByText('Olá!'); + expect(buttonElement).toBeInTheDocument(); + }); + + it('renders with custom projectAnnotations via setProjectAnnotations', () => { + setProjectAnnotations([{ parameters: { injected: true } }]); + const Story = composeStory(stories.CSF2StoryWithLocale, stories.default); + expect(Story.parameters?.injected).toBe(true); + }); +}); + +describe('CSF3', () => { + it('renders with inferred globalRender', () => { + const Primary = composeStory(stories.CSF3Button, stories.default); + + render(Primary({ label: 'Hello world' })); + const buttonElement = screen.getByText(/Hello world/i); + expect(buttonElement).toBeInTheDocument(); + }); + + it('renders with custom render function', () => { + const Primary = composeStory(stories.CSF3ButtonWithRender, stories.default); + + render(Primary()); + expect(screen.getByTestId('custom-render')).toBeInTheDocument(); + }); + + it('renders with play function', async () => { + const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); + + const { container } = render(CSF3InputFieldFilled()); + + await CSF3InputFieldFilled.play!({ canvasElement: container as HTMLElement }); + + const input = screen.getByTestId('input') as HTMLInputElement; + expect(input.value).toEqual('Hello world!'); + }); +}); + +// common in addons that need to communicate between manager and preview +it('should pass with decorators that need addons channel', () => { + const PrimaryWithChannels = composeStory(stories.CSF3Primary, stories.default, { + decorators: [ + (StoryFn: any) => { + addons.getChannel(); + return StoryFn(); + }, + ], + }); + render(PrimaryWithChannels({ label: 'Hello world' })); + const buttonElement = screen.getByText(/Hello world/i); + expect(buttonElement).not.toBeNull(); +}); + +describe('ComposeStories types', () => { + it('Should support typescript operators', () => { + type ComposeStoriesParam = Parameters[0]; + + expectTypeOf({ + ...stories, + default: stories.default as Meta, + }).toMatchTypeOf(); + + expectTypeOf({ + ...stories, + default: stories.default satisfies Meta, + }).toMatchTypeOf(); + }); +}); + +// Batch snapshot testing +const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName, Story]); +it.each(testCases)('Renders %s story', async (_storyName, Story) => { + if (typeof Story === 'string' || _storyName === 'CSF2StoryWithParamsAndDecorator') { + return; + } + + await new Promise((resolve) => setTimeout(resolve, 0)); + + const tree = await render(Story()); + expect(tree.baseElement).toMatchSnapshot(); +}); diff --git a/code/renderers/vue3/src/docs/sourceDecorator.test.ts b/code/renderers/vue3/src/docs/sourceDecorator.test.ts index 0a97bd9884f9..d695d7979c37 100644 --- a/code/renderers/vue3/src/docs/sourceDecorator.test.ts +++ b/code/renderers/vue3/src/docs/sourceDecorator.test.ts @@ -286,6 +286,10 @@ describe('Vue3: sourceDecorator->attributeSoure()', () => { it('normal html attribute should not convert to vue event directive', () => { expect(attributeSource('on-click', () => {})).toMatchInlineSnapshot(`on-click='()=>({})'`); }); + it('The value undefined or empty string must not be returned.', () => { + expect(attributeSource('icon', undefined)).toMatchInlineSnapshot(`icon=""`); + expect(attributeSource('icon', '')).toMatchInlineSnapshot(`icon=""`); + }); it('htmlEventAttributeToVueEventAttribute onEv => v-on:', () => { const htmlEventAttributeToVueEventAttribute = (attribute: string) => { return htmlEventToVueEvent(attribute); diff --git a/code/renderers/vue3/src/docs/utils.ts b/code/renderers/vue3/src/docs/utils.ts index 707feb46e58f..b4e502952dfd 100644 --- a/code/renderers/vue3/src/docs/utils.ts +++ b/code/renderers/vue3/src/docs/utils.ts @@ -24,9 +24,9 @@ const htmlEventAttributeToVueEventAttribute = (key: string) => { }; const directiveSource = (key: string, value: unknown) => - key.includes('on') + key.toLowerCase().startsWith('on') ? `${htmlEventAttributeToVueEventAttribute(key)}='()=>({})'` - : `${key}="${value}"`; + : `${key}="${value || ''}"`; const attributeSource = (key: string, value: unknown, dynamic?: boolean) => // convert html event key to vue event key diff --git a/code/renderers/vue3/src/index.ts b/code/renderers/vue3/src/index.ts index 83d5e6cdd65b..87e6074fb708 100644 --- a/code/renderers/vue3/src/index.ts +++ b/code/renderers/vue3/src/index.ts @@ -2,8 +2,9 @@ import './globals'; -export * from './public-types'; export { setup } from './render'; +export * from './public-types'; +export * from './portable-stories'; // optimization: stop HMR propagation in webpack try { diff --git a/code/renderers/vue3/src/portable-stories.ts b/code/renderers/vue3/src/portable-stories.ts new file mode 100644 index 000000000000..4e009b25d672 --- /dev/null +++ b/code/renderers/vue3/src/portable-stories.ts @@ -0,0 +1,117 @@ +import { + composeStory as originalComposeStory, + composeStories as originalComposeStories, + setProjectAnnotations as originalSetProjectAnnotations, +} from '@storybook/preview-api'; +import type { + Args, + ProjectAnnotations, + StoryAnnotationsOrFn, + Store_CSFExports, + StoriesWithPartialProps, +} from '@storybook/types'; + +import * as defaultProjectAnnotations from './render'; +import type { Meta } from './public-types'; +import type { VueRenderer } from './types'; + +/** Function that sets the globalConfig of your Storybook. The global config is the preview module of your .storybook folder. + * + * It should be run a single time, so that your global config (e.g. decorators) is applied to your stories when using `composeStories` or `composeStory`. + * + * Example: + *```jsx + * // setup.js (for jest) + * import { setProjectAnnotations } from '@storybook/vue3'; + * import projectAnnotations from './.storybook/preview'; + * + * setProjectAnnotations(projectAnnotations); + *``` + * + * @param projectAnnotations - e.g. (import projectAnnotations from '../.storybook/preview') + */ +export function setProjectAnnotations( + projectAnnotations: ProjectAnnotations | ProjectAnnotations[] +) { + originalSetProjectAnnotations(projectAnnotations); +} + +/** + * Function that will receive a story along with meta (e.g. a default export from a .stories file) + * and optionally projectAnnotations e.g. (import * from '../.storybook/preview) + * and will return a composed component that has all args/parameters/decorators/etc combined and applied to it. + * + * + * It's very useful for reusing a story in scenarios outside of Storybook like unit testing. + * + * Example: + *```jsx + * import { render } from '@testing-library/vue'; + * import { composeStory } from '@storybook/vue3'; + * import Meta, { Primary as PrimaryStory } from './Button.stories'; + * + * const Primary = composeStory(PrimaryStory, Meta); + * + * test('renders primary button with Hello World', () => { + * const { getByText } = render(Primary({label: "Hello world"})); + * expect(getByText(/Hello world/i)).not.toBeNull(); + * }); + *``` + * + * @param story + * @param componentAnnotations - e.g. (import Meta from './Button.stories') + * @param [projectAnnotations] - e.g. (import * as projectAnnotations from '../.storybook/preview') this can be applied automatically if you use `setProjectAnnotations` in your setup files. + * @param [exportsName] - in case your story does not contain a name and you want it to have a name. + */ +export function composeStory( + story: StoryAnnotationsOrFn, + componentAnnotations: Meta, + projectAnnotations?: ProjectAnnotations, + exportsName?: string +) { + return originalComposeStory( + story as StoryAnnotationsOrFn, + componentAnnotations, + projectAnnotations, + defaultProjectAnnotations, + exportsName + ); +} + +/** + * Function that will receive a stories import (e.g. `import * as stories from './Button.stories'`) + * and optionally projectAnnotations (e.g. `import * from '../.storybook/preview`) + * and will return an object containing all the stories passed, but now as a composed component that has all args/parameters/decorators/etc combined and applied to it. + * + * + * It's very useful for reusing stories in scenarios outside of Storybook like unit testing. + * + * Example: + *```jsx + * import { render } from '@testing-library/vue'; + * import { composeStories } from '@storybook/vue3'; + * import * as stories from './Button.stories'; + * + * const { Primary, Secondary } = composeStories(stories); + * + * test('renders primary button with Hello World', () => { + * const { getByText } = render(Primary({label: "Hello world"})); + * expect(getByText(/Hello world/i)).not.toBeNull(); + * }); + *``` + * + * @param csfExports - e.g. (import * as stories from './Button.stories') + * @param [projectAnnotations] - e.g. (import * as projectAnnotations from '../.storybook/preview') this can be applied automatically if you use `setProjectAnnotations` in your setup files. + */ +export function composeStories>( + csfExports: TModule, + projectAnnotations?: ProjectAnnotations +) { + // @ts-expect-error Deep down TRenderer['canvasElement'] resolves to canvasElement: unknown but VueRenderer uses WebRenderer where canvasElement is HTMLElement, so the types clash + const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory); + + return composedStories as unknown as Omit< + StoriesWithPartialProps, + keyof Store_CSFExports + >; +} diff --git a/code/renderers/web-components/package.json b/code/renderers/web-components/package.json index 69345af8cc3e..10394c503b82 100644 --- a/code/renderers/web-components/package.json +++ b/code/renderers/web-components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook web-components renderer", "keywords": [ "lit", diff --git a/code/ui/.storybook/preview.tsx b/code/ui/.storybook/preview.tsx index 8d2bfc9aa908..1054d62a5d59 100644 --- a/code/ui/.storybook/preview.tsx +++ b/code/ui/.storybook/preview.tsx @@ -11,7 +11,6 @@ import { useTheme, } from '@storybook/theming'; import { useArgs, DocsContext as DocsContextProps } from '@storybook/preview-api'; -import { Symbols } from '@storybook/components'; import type { PreviewWeb } from '@storybook/preview-api'; import type { ReactRenderer } from '@storybook/react'; import type { Channel } from '@storybook/channels'; diff --git a/code/ui/blocks/package.json b/code/ui/blocks/package.json index 2b6d8028aabd..5719ea26e0be 100644 --- a/code/ui/blocks/package.json +++ b/code/ui/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/blocks", - "version": "8.0.0-alpha.12", + "version": "8.0.0-beta.3", "description": "Storybook Doc Blocks", "keywords": [ "storybook" @@ -51,7 +51,7 @@ "@storybook/csf": "^0.1.2", "@storybook/docs-tools": "workspace:*", "@storybook/global": "^5.0.0", - "@storybook/icons": "^1.2.3", + "@storybook/icons": "^1.2.5", "@storybook/manager-api": "workspace:*", "@storybook/preview-api": "workspace:*", "@storybook/theming": "workspace:*", @@ -78,6 +78,14 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + }, "publishConfig": { "access": "public" }, diff --git a/code/ui/blocks/src/components/ArgsTable/ArgValue.tsx b/code/ui/blocks/src/components/ArgsTable/ArgValue.tsx index 131aab285a1b..7d549c5f45a7 100644 --- a/code/ui/blocks/src/components/ArgsTable/ArgValue.tsx +++ b/code/ui/blocks/src/components/ArgsTable/ArgValue.tsx @@ -3,8 +3,9 @@ import React, { useState } from 'react'; import memoize from 'memoizerific'; import uniq from 'lodash/uniq.js'; import { styled } from '@storybook/theming'; -import { WithTooltipPure, Icons, SyntaxHighlighter, codeCommon } from '@storybook/components'; +import { WithTooltipPure, SyntaxHighlighter, codeCommon } from '@storybook/components'; import type { PropSummaryValue } from './types'; +import { ChevronSmallDownIcon, ChevronSmallUpIcon } from '@storybook/icons'; interface ArgValueProps { value?: PropSummaryValue; @@ -86,10 +87,11 @@ const Detail = styled.div<{ width: string }>(({ theme, width }) => ({ }, })); -const ArrowIcon = styled(Icons)({ - height: 10, - width: 10, - minWidth: 10, +const ChevronUpIcon = styled(ChevronSmallUpIcon)({ + marginLeft: 4, +}); + +const ChevronDownIcon = styled(ChevronSmallDownIcon)({ marginLeft: 4, }); @@ -176,7 +178,7 @@ const ArgSummary: FC = ({ value, initialExpandedArgs }) => { > {summaryAsString} - + {isOpen ? : } ); diff --git a/code/ui/blocks/src/components/ArgsTable/SectionRow.tsx b/code/ui/blocks/src/components/ArgsTable/SectionRow.tsx index b23f225584db..450075b56aa7 100644 --- a/code/ui/blocks/src/components/ArgsTable/SectionRow.tsx +++ b/code/ui/blocks/src/components/ArgsTable/SectionRow.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react'; import React, { useState } from 'react'; import { transparentize, lighten } from 'polished'; import { styled } from '@storybook/theming'; -import { Icons } from '@storybook/components'; +import { ChevronDownIcon, ChevronRightIcon } from '@storybook/icons'; type Level = 'section' | 'subsection'; @@ -14,7 +14,21 @@ export interface SectionRowProps { colSpan: number; } -const ExpanderIcon = styled(Icons)(({ theme }) => ({ +const ExpanderIconDown = styled(ChevronDownIcon)(({ theme }) => ({ + marginRight: 8, + marginLeft: -10, + marginTop: -2, // optical alignment + height: 12, + width: 12, + color: + theme.base === 'light' + ? transparentize(0.25, theme.color.defaultText) + : transparentize(0.3, theme.color.defaultText), + border: 'none', + display: 'inline-block', +})); + +const ExpanderIconRight = styled(ChevronRightIcon)(({ theme }) => ({ marginRight: 8, marginLeft: -10, marginTop: -2, // optical alignment @@ -100,7 +114,6 @@ export const SectionRow: FC = ({ // @ts-expect-error (Converted from ts-ignore) const itemCount = children?.length || 0; const caption = level === 'subsection' ? `${itemCount} item${itemCount !== 1 ? 's' : ''}` : ''; - const icon = expanded ? 'arrowdown' : 'arrowright'; const helperText = `${expanded ? 'Hide' : 'Show'} ${ level === 'subsection' ? itemCount : label @@ -114,7 +127,7 @@ export const SectionRow: FC = ({ {helperText} - + {expanded ? : } {label} diff --git a/code/ui/blocks/src/components/IconGallery.stories.tsx b/code/ui/blocks/src/components/IconGallery.stories.tsx index b14417402fdd..0dc183e79311 100644 --- a/code/ui/blocks/src/components/IconGallery.stories.tsx +++ b/code/ui/blocks/src/components/IconGallery.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Icons as ExampleIcon } from '@storybook/components'; import { IconItem, IconGallery } from './IconGallery'; +import { AddIcon, FaceHappyIcon, HomeIcon, SubtractIcon } from '@storybook/icons'; export default { component: IconGallery, @@ -9,16 +9,16 @@ export default { export const DefaultStyle = () => ( - + - + - + - + example diff --git a/code/ui/blocks/src/controls/Color.tsx b/code/ui/blocks/src/controls/Color.tsx index c9bf13a526c9..ff2eae90a49b 100644 --- a/code/ui/blocks/src/controls/Color.tsx +++ b/code/ui/blocks/src/controls/Color.tsx @@ -4,10 +4,11 @@ import { HexColorPicker, HslaStringColorPicker, RgbaStringColorPicker } from 're import convert from 'color-convert'; import throttle from 'lodash/throttle.js'; import { styled } from '@storybook/theming'; -import { TooltipNote, WithTooltip, Form, Icons } from '@storybook/components'; +import { TooltipNote, WithTooltip, Form } from '@storybook/components'; import type { ControlProps, ColorValue, ColorConfig, PresetColor } from './types'; import { getControlId } from './helpers'; +import { MarkupIcon } from '@storybook/icons'; const Wrapper = styled.div({ position: 'relative', @@ -74,7 +75,7 @@ const Input = styled(Form.Input)(({ theme }) => ({ fontFamily: theme.typography.fonts.base, })); -const ToggleIcon = styled(Icons)(({ theme }) => ({ +const ToggleIcon = styled(MarkupIcon)(({ theme }) => ({ position: 'absolute', zIndex: 1, top: 6, @@ -358,7 +359,7 @@ export const ColorControl: FC = ({ onFocus={(e: FocusEvent) => e.target.select()} placeholder="Choose color..." /> - {value ? : null} + {value ? : null}
); }; diff --git a/code/ui/blocks/src/controls/Object.tsx b/code/ui/blocks/src/controls/Object.tsx index c6b94fc23951..d6c4d2328af0 100644 --- a/code/ui/blocks/src/controls/Object.tsx +++ b/code/ui/blocks/src/controls/Object.tsx @@ -3,8 +3,8 @@ import cloneDeep from 'lodash/cloneDeep.js'; import type { ComponentProps, SyntheticEvent, FC, FocusEvent } from 'react'; import React, { useCallback, useMemo, useState, useEffect, useRef } from 'react'; import { styled, useTheme, type Theme } from '@storybook/theming'; -import { Form, Icons, IconButton, Button } from '@storybook/components'; -import { EyeCloseIcon, EyeIcon } from '@storybook/icons'; +import { Form, IconButton, Button } from '@storybook/components'; +import { AddIcon, EyeCloseIcon, EyeIcon, SubtractIcon } from '@storybook/icons'; import { JsonTree, getObjectType } from './react-editable-json-tree'; import { getControlId, getControlSetterButtonId } from './helpers'; import type { ControlProps, ObjectValue, ObjectConfig } from './types'; @@ -133,7 +133,7 @@ const ButtonInline = styled.button<{ primary?: boolean }>(({ theme, primary }) = order: primary ? 'initial' : 9, })); -const ActionIcon = styled(Icons)<{ disabled?: boolean }>(({ theme, icon, disabled }) => ({ +const ActionAddIcon = styled(AddIcon)<{ disabled?: boolean }>(({ theme, disabled }) => ({ display: 'inline-block', verticalAlign: 'middle', width: 15, @@ -142,11 +142,22 @@ const ActionIcon = styled(Icons)<{ disabled?: boolean }>(({ theme, icon, disable marginLeft: 5, cursor: disabled ? 'not-allowed' : 'pointer', color: theme.textMutedColor, - '&:hover': disabled - ? {} - : { - color: icon === 'subtract' ? theme.color.negative : theme.color.ancillary, - }, + '&:hover': disabled ? {} : { color: theme.color.ancillary }, + 'svg + &': { + marginLeft: 0, + }, +})); + +const ActionSubstractIcon = styled(SubtractIcon)<{ disabled?: boolean }>(({ theme, disabled }) => ({ + display: 'inline-block', + verticalAlign: 'middle', + width: 15, + height: 15, + padding: 3, + marginLeft: 5, + cursor: disabled ? 'not-allowed' : 'pointer', + color: theme.textMutedColor, + '&:hover': disabled ? {} : { color: theme.color.negative }, 'svg + &': { marginLeft: 0, }, @@ -309,8 +320,8 @@ export const ObjectControl: FC = ({ name, value, onChange }) => { Save } - plusMenuElement={} - minusMenuElement={} + plusMenuElement={} + minusMenuElement={} inputElement={(_: any, __: any, ___: any, key: string) => key ? : } diff --git a/code/ui/blocks/src/controls/options/Select.tsx b/code/ui/blocks/src/controls/options/Select.tsx index e2f9835a7c47..574c604b180b 100644 --- a/code/ui/blocks/src/controls/options/Select.tsx +++ b/code/ui/blocks/src/controls/options/Select.tsx @@ -3,12 +3,12 @@ import React from 'react'; import { styled } from '@storybook/theming'; import type { CSSObject } from '@storybook/theming'; import { logger } from '@storybook/client-logger'; -import { Icons } from '@storybook/components'; import type { ControlProps, OptionsSelection, NormalizedOptionsConfig } from '../types'; import { selectedKey, selectedKeys, selectedValues } from './helpers'; import { getControlId } from '../helpers'; +import { ChevronSmallDownIcon } from '@storybook/icons'; const styleResets: CSSObject = { // resets @@ -102,7 +102,7 @@ const SingleSelect: FC = ({ name, value, options, onChange }) => { return ( - +
- } + slotMain={} slotSidebar={ setMobileAboutOpen((state) => !state)} />} slotPanel={} slotPages={pages.map(({ id, render: Content }) => ( diff --git a/code/ui/manager/src/components/layout/Layout.stories.tsx b/code/ui/manager/src/components/layout/Layout.stories.tsx index aea6f4a1a5f2..6c291c5f2fe8 100644 --- a/code/ui/manager/src/components/layout/Layout.stories.tsx +++ b/code/ui/manager/src/components/layout/Layout.stories.tsx @@ -7,6 +7,7 @@ import type { Meta, StoryObj } from '@storybook/react'; import { fn } from '@storybook/test'; import { Layout } from './Layout'; import { LayoutProvider } from './LayoutProvider'; +import { LocationProvider } from '@storybook/router'; import MobileNavigationStoriesMeta from '../mobile/navigation/MobileNavigation.stories'; const PlaceholderBlock = styled.div({ @@ -60,6 +61,7 @@ const meta = { slotPanel: , slotPages: , setManagerLayoutState: fn(), + hasTab: false, }, parameters: { theme: 'light', @@ -67,7 +69,11 @@ const meta = { }, decorators: [ MobileNavigationStoriesMeta.decorators[0] as any, - (storyFn) => {storyFn()}, + (storyFn) => ( + + {storyFn()} + + ), ], render: (args) => { const [managerLayoutState, setManagerLayoutState] = useState(args.managerLayoutState); diff --git a/code/ui/manager/src/components/layout/Layout.tsx b/code/ui/manager/src/components/layout/Layout.tsx index 726b535e7f37..a17636ceadbd 100644 --- a/code/ui/manager/src/components/layout/Layout.tsx +++ b/code/ui/manager/src/components/layout/Layout.tsx @@ -6,6 +6,7 @@ import { MobileNavigation } from '../mobile/navigation/MobileNavigation'; import { MEDIA_DESKTOP_BREAKPOINT } from '../../constants'; import { useLayout } from './LayoutProvider'; import { Notifications } from '../../container/Notifications'; +import { Match } from '@storybook/router'; interface InternalLayoutState { isDragging: boolean; @@ -25,6 +26,7 @@ interface Props { slotSidebar?: React.ReactNode; slotPanel?: React.ReactNode; slotPages?: React.ReactNode; + hasTab: boolean; } const MINIMUM_CONTENT_WIDTH_PX = 100; @@ -44,10 +46,12 @@ const useLayoutSyncingState = ({ managerLayoutState, setManagerLayoutState, isDesktop, + hasTab, }: { managerLayoutState: Props['managerLayoutState']; setManagerLayoutState: Props['setManagerLayoutState']; isDesktop: boolean; + hasTab: boolean; }) => { // ref to keep track of previous managerLayoutState, to check if the props change const prevManagerLayoutStateRef = React.useRef(managerLayoutState); @@ -95,7 +99,7 @@ const useLayoutSyncingState = ({ const isPagesShown = managerLayoutState.viewMode !== 'story' && managerLayoutState.viewMode !== 'docs'; - const isPanelShown = managerLayoutState.viewMode === 'story'; + const isPanelShown = managerLayoutState.viewMode === 'story' && !hasTab; const { panelResizerRef, sidebarResizerRef } = useDragging({ setState: setInternalDraggingSizeState, @@ -119,7 +123,7 @@ const useLayoutSyncingState = ({ }; }; -export const Layout = ({ managerLayoutState, setManagerLayoutState, ...slots }: Props) => { +export const Layout = ({ managerLayoutState, setManagerLayoutState, hasTab, ...slots }: Props) => { const { isDesktop, isMobile } = useLayout(); const { @@ -132,7 +136,7 @@ export const Layout = ({ managerLayoutState, setManagerLayoutState, ...slots }: showPages, showPanel, isDragging, - } = useLayoutSyncingState({ managerLayoutState, setManagerLayoutState, isDesktop }); + } = useLayoutSyncingState({ managerLayoutState, setManagerLayoutState, isDesktop, hasTab }); return ( {showPages && {slots.slotPages}} - {slots.slotMain} + + {({ match }) => {slots.slotMain}} + {isDesktop && ( <> @@ -171,8 +178,8 @@ export const Layout = ({ managerLayoutState, setManagerLayoutState, ...slots }: ); }; -const LayoutContainer = styled.div( - ({ navSize, rightPanelWidth, bottomPanelHeight, viewMode, panelPosition }) => { +const LayoutContainer = styled.div( + ({ navSize, rightPanelWidth, bottomPanelHeight, viewMode, panelPosition, showPanel }) => { return { width: '100%', height: ['100vh', '100dvh'], // This array is a special Emotion syntax to set a fallback if 100dvh is not supported @@ -186,7 +193,7 @@ const LayoutContainer = styled.div( gridTemplateColumns: `minmax(0, ${navSize}px) minmax(${MINIMUM_CONTENT_WIDTH_PX}px, 1fr) minmax(0, ${rightPanelWidth}px)`, gridTemplateRows: `1fr minmax(0, ${bottomPanelHeight}px)`, gridTemplateAreas: (() => { - if (viewMode === 'docs') { + if (viewMode === 'docs' || !showPanel) { // remove panel in docs viewMode return `"sidebar content content" "sidebar content content"`; @@ -210,11 +217,12 @@ const SidebarContainer = styled.div(({ theme }) => ({ borderRight: `1px solid ${theme.color.border}`, })); -const ContentContainer = styled.div(({ theme }) => ({ +const ContentContainer = styled.div<{ shown: boolean }>(({ theme, shown }) => ({ flex: 1, position: 'relative', backgroundColor: theme.background.content, - display: 'grid', // This is needed to make the content container fill the available space + display: shown ? 'grid' : 'none', // This is needed to make the content container fill the available space + overflow: 'auto', [MEDIA_DESKTOP_BREAKPOINT]: { flex: 'auto', diff --git a/code/ui/manager/src/components/mobile/navigation/MobileAddonsDrawer.tsx b/code/ui/manager/src/components/mobile/navigation/MobileAddonsDrawer.tsx index b05dff4c3d25..7c0027d610bc 100644 --- a/code/ui/manager/src/components/mobile/navigation/MobileAddonsDrawer.tsx +++ b/code/ui/manager/src/components/mobile/navigation/MobileAddonsDrawer.tsx @@ -1,59 +1,21 @@ import type { FC, ReactNode } from 'react'; -import React, { useRef } from 'react'; +import React from 'react'; import { styled } from '@storybook/theming'; -import { Transition } from 'react-transition-group'; -import type { TransitionStatus } from 'react-transition-group/Transition'; -import { useLayout } from '../../layout/LayoutProvider'; interface MobileAddonsDrawerProps { children: ReactNode; } -const TRANSITION_DURATION = 200; - -const Container = styled.div<{ state: TransitionStatus }>(({ theme, state }) => ({ - position: 'fixed', +const Container = styled.div(({ theme }) => ({ + position: 'relative', boxSizing: 'border-box', width: '100%', background: theme.background.content, - height: '50%', - bottom: 0, - left: 0, + height: '42vh', zIndex: 11, - transition: `all ${TRANSITION_DURATION}ms ease-in-out`, overflow: 'hidden', - borderTop: `1px solid ${theme.appBorderColor}`, - transform: `${(() => { - switch (state) { - case 'entering': - case 'entered': - return 'translateY(0)'; - case 'exiting': - case 'exited': - return 'translateY(100%)'; - default: - return 'translateY(0)'; - } - })()}`, })); export const MobileAddonsDrawer: FC = ({ children }) => { - const { isMobilePanelOpen } = useLayout(); - const containerRef = useRef(null); - - return ( - - {(state) => ( - - {children} - - )} - - ); + return {children}; }; diff --git a/code/ui/manager/src/components/mobile/navigation/MobileNavigation.tsx b/code/ui/manager/src/components/mobile/navigation/MobileNavigation.tsx index 7174b8bd6a2e..47b7587019f8 100644 --- a/code/ui/manager/src/components/mobile/navigation/MobileNavigation.tsx +++ b/code/ui/manager/src/components/mobile/navigation/MobileNavigation.tsx @@ -35,40 +35,50 @@ const useFullStoryName = () => { }; export const MobileNavigation: FC = ({ menu, panel, showPanel }) => { - const { isMobileMenuOpen, setMobileMenuOpen, setMobilePanelOpen } = useLayout(); + const { isMobileMenuOpen, isMobilePanelOpen, setMobileMenuOpen, setMobilePanelOpen } = + useLayout(); const fullStoryName = useFullStoryName(); return ( {menu} - {panel} - - {showPanel && ( - setMobilePanelOpen(true)} title="Open addon panel"> - - + {isMobilePanelOpen ? ( + {panel} + ) : ( + )} ); }; const Container = styled.div(({ theme }) => ({ - display: 'flex', - alignItems: 'center', - justifyContent: 'space-between', bottom: 0, left: 0, width: '100%', - height: 40, zIndex: 10, background: theme.barBg, - padding: '0 6px', borderTop: `1px solid ${theme.appBorderColor}`, })); +const Nav = styled.div({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + width: '100%', + height: 40, + padding: '0 6px', +}); + const Button = styled.button(({ theme }) => ({ all: 'unset', display: 'flex', diff --git a/code/ui/manager/src/components/preview/Preview.mockdata.tsx b/code/ui/manager/src/components/preview/Preview.mockdata.tsx deleted file mode 100644 index 29d72ec355a2..000000000000 --- a/code/ui/manager/src/components/preview/Preview.mockdata.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { types } from '@storybook/manager-api'; -import type { API, State } from '@storybook/manager-api'; -import type { Addon_BaseType, Addon_Collection } from '@storybook/types'; -import type { PreviewProps } from './utils/types'; - -const addonNotes: Addon_BaseType = { - id: 'notes', - type: types.TAB, - title: 'Notes', - route: ({ storyId }) => `/info/${storyId}`, - match: ({ viewMode }) => viewMode === 'info', - render: () => null, -}; - -const mockAPI: Partial = { - on: (a, b) => () => {}, - emit: () => {}, - off: () => {}, - getElements: (type) => - type === types.TAB ? ({ notes: addonNotes } as Addon_Collection) : {}, -}; - -export const previewProps: PreviewProps = { - id: 'string', - storyId: 'story--id', - api: mockAPI as API, - entry: { - tags: [], - type: 'story', - id: 'story--id', - parent: 'root', - depth: 1, - title: 'kind', - name: 'story name', - importPath: './story.stories.tsx', - prepared: true, - parameters: { - fileName: '', - options: {}, - }, - args: {}, - }, - path: 'string', - viewMode: 'story', - location: {} as any as State['location'], - baseUrl: 'http://example.com', - queryParams: {}, - options: { - showTabs: true, - showToolbar: true, - }, - withLoader: false, - description: '', - refs: {}, -}; diff --git a/code/ui/manager/src/components/preview/Preview.stories.tsx b/code/ui/manager/src/components/preview/Preview.stories.tsx deleted file mode 100644 index 0a639c9db64e..000000000000 --- a/code/ui/manager/src/components/preview/Preview.stories.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import React from 'react'; - -import { parsePath, createPath } from 'history'; -import type { Combo, StoryEntry } from '@storybook/manager-api'; -import { Provider as ManagerProvider, Consumer } from '@storybook/manager-api'; -import { Location, BaseLocationProvider } from '@storybook/router'; - -import { ThemeProvider, ensure as ensureTheme, themes } from '@storybook/theming'; - -import type { Decorator } from '@storybook/react'; -import { Preview } from './Preview'; - -import { PrettyFakeProvider } from '../../FakeProvider'; -import { previewProps } from './Preview.mockdata'; -import { LayoutProvider } from '../layout/LayoutProvider'; - -const provider = new PrettyFakeProvider(); -const staticNavigator = { - createHref(to: any) { - return typeof to === 'string' ? to : createPath(to); - }, - - push() {}, - - replace() {}, - - go() {}, - - back() {}, - - forward() {}, -}; - -export default { - title: 'Preview', - component: Preview, - parameters: { - layout: 'fullscreen', - theme: 'light', - }, - decorators: [ - ((StoryFn, c) => { - const locationProp = parsePath('/?path=/story/story--id'); - - const location = { - pathname: locationProp.pathname || '/', - search: locationProp.search || '', - hash: locationProp.hash || '', - // @ts-expect-error (invalid input) - state: null, - key: 'default', - }; - - return ( - - - {(locationData) => ( - {}} - > - - - - - - - )} - - - ); - }) as Decorator, - ], -}; - -export const NoTabs = () => ( - - {({ api }: Combo) => { - return ( - ({}) }} - entry={{ - ...(previewProps.entry as StoryEntry), - parameters: { previewTabs: { canvas: { hidden: true } } }, - }} - /> - ); - }} - -); - -export const HideFullscreen = () => ( - - {({ api }: Combo) => { - return ( - ({}) }} - entry={{ - ...(previewProps.entry as StoryEntry), - parameters: { toolbar: { fullscreen: { hidden: true } } }, - }} - /> - ); - }} - -); - -export const HideAllDefaultTools = () => ( - - {({ api }: Combo) => { - return ( - ({}) }} - entry={{ - ...(previewProps.entry as StoryEntry), - parameters: { - toolbar: { - title: { hidden: true }, - remount: { hidden: true }, - zoom: { hidden: true }, - eject: { hidden: true }, - copy: { hidden: true }, - fullscreen: { hidden: true }, - }, - }, - }} - /> - ); - }} - -); - -export const WithCanvasTab = () => ( - - {({ api }: Combo) => { - return ({}) }} />; - }} - -); - -export const WithTabs = () => ; - -export const WithTabsHidden = () => ( - - {({ api }: Combo) => { - return ( - ({}) }} - /> - ); - }} - -); diff --git a/code/ui/manager/src/components/preview/Preview.tsx b/code/ui/manager/src/components/preview/Preview.tsx index 3130cccb3c19..49c77ba6a125 100644 --- a/code/ui/manager/src/components/preview/Preview.tsx +++ b/code/ui/manager/src/components/preview/Preview.tsx @@ -1,26 +1,22 @@ import type { FC } from 'react'; -import React, { Fragment, useMemo, useEffect, useRef, useState } from 'react'; +import React, { Fragment, useEffect, useRef, useState } from 'react'; import { Helmet } from 'react-helmet-async'; import { global } from '@storybook/global'; -import { type API, Consumer, type Combo, merge, addons, types } from '@storybook/manager-api'; -import type { Addon_BaseType } from '@storybook/types'; +import { Consumer, type Combo, merge, addons, types } from '@storybook/manager-api'; +import type { Addon_BaseType, Addon_WrapperType } from '@storybook/types'; import { PREVIEW_BUILDER_PROGRESS, SET_CURRENT_STORY } from '@storybook/core-events'; import { Loader } from '@storybook/components'; -import { Location } from '@storybook/router'; import * as S from './utils/components'; import { ZoomProvider, ZoomConsumer } from './tools/zoom'; -import { defaultWrappers, ApplyWrappers } from './Wrappers'; +import { ApplyWrappers } from './Wrappers'; import { ToolbarComp } from './Toolbar'; import { FramesRenderer } from './FramesRenderer'; import type { PreviewProps } from './utils/types'; -const getWrappers = (getFn: API['getElements']) => Object.values(getFn(types.PREVIEW)); -const getTabs = (getFn: API['getElements']) => Object.values(getFn(types.TAB)); - const canvasMapper = ({ state, api }: Combo) => ({ storyId: state.storyId, refId: state.refId, @@ -31,10 +27,9 @@ const canvasMapper = ({ state, api }: Combo) => ({ entry: api.getData(state.storyId, state.refId), previewInitialized: state.previewInitialized, refs: state.refs, - active: !!(state.viewMode && state.viewMode.match(/^(story|docs)$/)), }); -const createCanvasTab = (): Addon_BaseType => ({ +export const createCanvasTab = (): Addon_BaseType => ({ id: 'canvas', type: types.TAB, title: 'Canvas', @@ -43,19 +38,6 @@ const createCanvasTab = (): Addon_BaseType => ({ render: () => null, }); -const useTabs = (getElements: API['getElements'], entry: PreviewProps['entry']) => { - const canvasTab = useMemo(() => createCanvasTab(), []); - const tabsFromConfig = useMemo(() => getTabs(getElements), [getElements]); - - return useMemo(() => { - if (entry?.type === 'story' && entry.parameters) { - return filterTabs([canvasTab, ...tabsFromConfig], entry.parameters); - } - - return [canvasTab, ...tabsFromConfig]; - }, [entry, ...tabsFromConfig]); -}; - const Preview = React.memo(function Preview(props) { const { api, @@ -67,34 +49,39 @@ const Preview = React.memo(function Preview(props) { description, baseUrl, withLoader = true, + tools, + toolsExtra, + tabs, + wrappers, + tabId, } = props; - const { getElements } = api; - const tabs = useTabs(getElements, entry); + const tabContent = tabs.find((tab) => tab.id === tabId)?.render; const shouldScale = viewMode === 'story'; - const { showToolbar, showTabs = true } = options; - const visibleTabsInToolbar = showTabs ? tabs : []; + const { showToolbar } = options; const previousStoryId = useRef(storyId); useEffect(() => { if (entry && viewMode) { // Don't emit the event on first ("real") render, only when entry changes - if (storyId !== previousStoryId.current) { - previousStoryId.current = storyId; + if (storyId === previousStoryId.current) { + return; + } - if (viewMode.match(/docs|story/)) { - const { refId, id } = entry; - api.emit(SET_CURRENT_STORY, { - storyId: id, - viewMode, - options: { target: refId }, - }); - } + previousStoryId.current = storyId; + + if (viewMode.match(/docs|story/)) { + const { refId, id } = entry; + api.emit(SET_CURRENT_STORY, { + storyId: id, + viewMode, + options: { target: refId }, + }); } } - }, [entry, viewMode]); + }, [entry, viewMode, storyId, api]); return ( @@ -107,22 +94,18 @@ const Preview = React.memo(function Preview(props) { - - {tabs.map(({ render: Render, match, ...t }, i) => { - // @ts-expect-error (Converted from ts-ignore) - const key = t.id || t.key || i; - return ( - - {(lp) => } - - ); - })} + {tabContent && {tabContent({ active: true })}} + + + @@ -132,10 +115,12 @@ const Preview = React.memo(function Preview(props) { export { Preview }; -const Canvas: FC<{ withLoader: boolean; baseUrl: string; children?: never }> = ({ - baseUrl, - withLoader, -}) => { +const Canvas: FC<{ + withLoader: boolean; + baseUrl: string; + children?: never; + wrappers: Addon_WrapperType[]; +}> = ({ baseUrl, withLoader, wrappers }) => { return ( {({ @@ -146,15 +131,9 @@ const Canvas: FC<{ withLoader: boolean; baseUrl: string; children?: never }> = ( refId, viewMode, queryParams, - getElements, previewInitialized, - active, }) => { const id = 'canvas'; - const wrappers = useMemo( - () => [...defaultWrappers, ...getWrappers(getElements)], - [getElements, ...defaultWrappers] - ); const [progress, setProgress] = useState(undefined); useEffect(() => { @@ -187,13 +166,7 @@ const Canvas: FC<{ withLoader: boolean; baseUrl: string; children?: never }> = ( )} - + {customCanvas ? ( customCanvas(storyId, viewMode, id, baseUrl, scale, queryParams) ) : ( @@ -219,7 +192,7 @@ const Canvas: FC<{ withLoader: boolean; baseUrl: string; children?: never }> = ( ); }; -function filterTabs(panels: Addon_BaseType[], parameters: Record) { +export function filterTabs(panels: Addon_BaseType[], parameters?: Record | undefined) { const { previewTabs } = addons.getConfig(); const parametersTabs = parameters ? parameters.previewTabs : undefined; diff --git a/code/ui/manager/src/components/preview/Toolbar.tsx b/code/ui/manager/src/components/preview/Toolbar.tsx index b09d8f3e2a57..f46f3489790f 100644 --- a/code/ui/manager/src/components/preview/Toolbar.tsx +++ b/code/ui/manager/src/components/preview/Toolbar.tsx @@ -1,5 +1,4 @@ -import type { FunctionComponent } from 'react'; -import React, { Fragment, useMemo } from 'react'; +import React, { Fragment } from 'react'; import { styled } from '@storybook/theming'; @@ -16,17 +15,13 @@ import { types, } from '@storybook/manager-api'; -import { Location, type RenderData } from '@storybook/router'; import { Addon_TypesEnum, type Addon_BaseType } from '@storybook/types'; import { CloseIcon, ExpandIcon } from '@storybook/icons'; import { zoomTool } from './tools/zoom'; -import * as S from './utils/components'; - import type { PreviewProps } from './utils/types'; import { copyTool } from './tools/copy'; import { ejectTool } from './tools/eject'; -import { menuTool } from './tools/menu'; import { addonsTool } from './tools/addons'; import { remountTool } from './tools/remount'; import { useLayout } from '../layout/LayoutProvider'; @@ -73,12 +68,10 @@ export const fullScreenTool: Addon_BaseType = { }, }; -const tabsMapper = ({ state }: Combo) => ({ - viewMode: state.docsOnly, - storyId: state.storyId, +const tabsMapper = ({ api, state }: Combo) => ({ + navigate: api.navigate, path: state.path, - location: state.location, - refId: state.refId, + applyQueryParams: api.applyQueryParams, }); export const createTabsTool = (tabs: Addon_BaseType[]): Addon_BaseType => ({ @@ -91,16 +84,21 @@ export const createTabsTool = (tabs: Addon_BaseType[]): Addon_BaseType => ({ {tabs - .filter((p) => !p.hidden) - .map((t, index) => { - const to = t.route(rp); - const isActive = rp.path === to; + .filter(({ hidden }) => !hidden) + .map((tab, index) => { + const tabIdToApply = tab.id === 'canvas' ? undefined : tab.id; + const isActive = rp.path.includes(`tab=${tab.id}`); return ( - - - {t.title as any} - - + { + rp.applyQueryParams({ tab: tabIdToApply }); + }} + key={tab.id || `tab-${index}`} + > + {tab.title as any} + ); })} @@ -119,73 +117,56 @@ export const defaultToolsExtra: Addon_BaseType[] = [ copyTool, ]; -const useTools = ( - getElements: API['getElements'], - tabs: Addon_BaseType[], - viewMode: PreviewProps['viewMode'], - entry: PreviewProps['entry'], - location: PreviewProps['location'], - path: PreviewProps['path'] -) => { - const toolsFromConfig = useMemo( - () => getTools(getElements), - [getElements, getTools(getElements).length] - ); - const toolsExtraFromConfig = useMemo(() => getToolsExtra(getElements), [getElements]); - - const tools = useMemo( - () => [...defaultTools, ...toolsFromConfig], - [defaultTools, toolsFromConfig] - ); - const toolsExtra = useMemo( - () => [...defaultToolsExtra, ...toolsExtraFromConfig], - [defaultToolsExtra, toolsExtraFromConfig] - ); - - return useMemo(() => { - return ['story', 'docs'].includes(entry?.type) - ? filterTools(tools, toolsExtra, tabs, { - viewMode, - entry, - location, - path, - }) - : { left: tools, right: toolsExtra }; - }, [viewMode, entry, location, path, tools, toolsExtra, tabs]); -}; - export interface ToolData { isShown: boolean; tabs: Addon_BaseType[]; + tools: Addon_BaseType[]; + tabId: string; + toolsExtra: Addon_BaseType[]; api: API; - entry: LeafEntry; } -export const ToolRes: FunctionComponent = React.memo( - function ToolRes({ api, entry, tabs, isShown, location, path, viewMode }) { - const { left, right } = useTools(api.getElements, tabs, viewMode, entry, location, path); - - return left || right ? ( - - - - - - - - - - - ) : null; - } -); - -export const ToolbarComp = React.memo(function ToolbarComp(props) { - return ( - - {({ location, path, viewMode }) => } - - ); +export const ToolbarComp = React.memo(function ToolbarComp({ + isShown, + tools, + toolsExtra, + tabs, + tabId, + api, +}) { + return tabs || tools || toolsExtra ? ( + + + + {tabs.length > 1 ? ( + + + {tabs.map((tab, index) => { + return ( + { + api.applyQueryParams({ tab: tab.id === 'canvas' ? undefined : tab.id }); + }} + key={tab.id || `tab-${index}`} + > + {tab.title as any} + + ); + })} + + + + ) : null} + + + + + + + + ) : null; }); export const Tools = React.memo<{ list: Addon_BaseType[] }>(function Tools({ list }) { @@ -199,55 +180,38 @@ export const Tools = React.memo<{ list: Addon_BaseType[] }>(function Tools({ lis ); }); -function toolbarItemHasBeenExcluded(item: Partial, entry: LeafEntry) { - const parameters = entry.type === 'story' && entry.prepared ? entry.parameters : {}; +function toolbarItemHasBeenExcluded(item: Partial, entry: LeafEntry | undefined) { + const parameters = entry?.type === 'story' && entry?.prepared ? entry?.parameters : {}; const toolbarItemsFromStoryParameters = 'toolbar' in parameters ? parameters.toolbar : undefined; const { toolbar: toolbarItemsFromAddonsConfig } = addons.getConfig(); const toolbarItems = merge(toolbarItemsFromAddonsConfig, toolbarItemsFromStoryParameters); - return toolbarItems ? !!toolbarItems[item.id]?.hidden : false; + return toolbarItems ? !!toolbarItems[item?.id]?.hidden : false; } -export function filterTools( +export function filterToolsSide( tools: Addon_BaseType[], - toolsExtra: Addon_BaseType[], - tabs: Addon_BaseType[], - { - viewMode, - entry, - location, - path, - }: { - viewMode: State['viewMode']; - entry: PreviewProps['entry']; - location: State['location']; - path: State['path']; - } + entry: PreviewProps['entry'], + viewMode: State['viewMode'], + location: State['location'], + path: State['path'], + tabId: string ) { - const toolsLeft = [ - menuTool, - tabs.filter((p) => !p.hidden).length > 1 && createTabsTool(tabs), - ...tools, - ]; - const toolsRight = [...toolsExtra]; - const filter = (item: Partial) => item && (!item.match || item.match({ - storyId: entry.id, - refId: entry.refId, + storyId: entry?.id, + refId: entry?.refId, viewMode, location, path, + tabId, })) && !toolbarItemHasBeenExcluded(item, entry); - const left = toolsLeft.filter(filter); - const right = toolsRight.filter(filter); - - return { left, right }; + return tools.filter(filter); } const Toolbar = styled.div<{ shown: boolean }>(({ theme, shown }) => ({ diff --git a/code/ui/manager/src/components/preview/Wrappers.tsx b/code/ui/manager/src/components/preview/Wrappers.tsx index 80640a9875fa..b70385e928fd 100644 --- a/code/ui/manager/src/components/preview/Wrappers.tsx +++ b/code/ui/manager/src/components/preview/Wrappers.tsx @@ -9,14 +9,13 @@ export const ApplyWrappers: FC> = ({ wrappers, id, storyId, - active, children, }) => { return ( {wrappers.reduceRight( (acc, wrapper, index) => ( - + ), children )} @@ -28,10 +27,6 @@ export const defaultWrappers: Addon_WrapperType[] = [ { id: 'iframe-wrapper', type: Addon_TypesEnum.PREVIEW, - render: (p) => ( - - ), + render: (p) => {p.children}, }, ]; diff --git a/code/ui/manager/src/components/preview/tools/addons.tsx b/code/ui/manager/src/components/preview/tools/addons.tsx index 5af0f4bf7040..956a327ed840 100644 --- a/code/ui/manager/src/components/preview/tools/addons.tsx +++ b/code/ui/manager/src/components/preview/tools/addons.tsx @@ -16,7 +16,7 @@ export const addonsTool: Addon_BaseType = { title: 'addons', id: 'addons', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => ( {({ isVisible, toggle, singleStory, panelPosition }) => diff --git a/code/ui/manager/src/components/preview/tools/copy.tsx b/code/ui/manager/src/components/preview/tools/copy.tsx index f06e926c0290..59d72f3de850 100644 --- a/code/ui/manager/src/components/preview/tools/copy.tsx +++ b/code/ui/manager/src/components/preview/tools/copy.tsx @@ -28,7 +28,7 @@ export const copyTool: Addon_BaseType = { title: 'copy', id: 'copy', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => ( {({ baseUrl, storyId, queryParams }) => diff --git a/code/ui/manager/src/components/preview/tools/eject.tsx b/code/ui/manager/src/components/preview/tools/eject.tsx index e8c65f8fd29b..41c091ccc582 100644 --- a/code/ui/manager/src/components/preview/tools/eject.tsx +++ b/code/ui/manager/src/components/preview/tools/eject.tsx @@ -24,7 +24,7 @@ export const ejectTool: Addon_BaseType = { title: 'eject', id: 'eject', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => ( {({ baseUrl, storyId, queryParams }) => diff --git a/code/ui/manager/src/components/preview/tools/remount.tsx b/code/ui/manager/src/components/preview/tools/remount.tsx index af85a43af246..ecc178a41677 100644 --- a/code/ui/manager/src/components/preview/tools/remount.tsx +++ b/code/ui/manager/src/components/preview/tools/remount.tsx @@ -34,7 +34,7 @@ export const remountTool: Addon_BaseType = { title: 'remount', id: 'remount', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: () => ( {({ remount, storyId, api }) => { diff --git a/code/ui/manager/src/components/preview/tools/zoom.tsx b/code/ui/manager/src/components/preview/tools/zoom.tsx index e38cb99e0526..cffe05ac4d0e 100644 --- a/code/ui/manager/src/components/preview/tools/zoom.tsx +++ b/code/ui/manager/src/components/preview/tools/zoom.tsx @@ -97,6 +97,6 @@ export const zoomTool: Addon_BaseType = { title: 'zoom', id: 'zoom', type: types.TOOL, - match: ({ viewMode }) => viewMode === 'story', + match: ({ viewMode, tabId }) => viewMode === 'story' && !tabId, render: ZoomToolRenderer, }; diff --git a/code/ui/manager/src/components/preview/utils/components.ts b/code/ui/manager/src/components/preview/utils/components.ts index b5b446aec116..a8c2d9b30f98 100644 --- a/code/ui/manager/src/components/preview/utils/components.ts +++ b/code/ui/manager/src/components/preview/utils/components.ts @@ -16,6 +16,21 @@ export const FrameWrap = styled.div({ background: 'transparent', flex: 1, }); +export const CanvasWrap = styled.div<{ show: boolean }>( + { + alignContent: 'center', + alignItems: 'center', + justifyContent: 'center', + justifyItems: 'center', + overflow: 'auto', + gridTemplateColumns: '100%', + gridTemplateRows: '100%', + position: 'relative', + width: '100%', + height: '100%', + }, + ({ show }) => ({ display: show ? 'grid' : 'none' }) +); export const UnstyledLink = styled(Link)({ color: 'inherit', diff --git a/code/ui/manager/src/components/preview/utils/types.tsx b/code/ui/manager/src/components/preview/utils/types.tsx index 90ae75246019..7b0e60caefb5 100644 --- a/code/ui/manager/src/components/preview/utils/types.tsx +++ b/code/ui/manager/src/components/preview/utils/types.tsx @@ -1,6 +1,6 @@ import type { ReactElement } from 'react'; import type { State, API, LeafEntry } from '@storybook/manager-api'; -import type { Addon_WrapperType, API_ViewMode, StoryId } from '@storybook/types'; +import type { Addon_BaseType, Addon_WrapperType, API_ViewMode, StoryId } from '@storybook/types'; export interface PreviewProps { api: API; @@ -13,13 +13,16 @@ export interface PreviewProps { showToolbar: boolean; }; id?: string; - path: string; - location: State['location']; queryParams: State['customQueryParams']; customCanvas?: CustomCanvasRenderer; description: string; baseUrl: string; withLoader: boolean; + tabs: Addon_BaseType[]; + tools: Addon_BaseType[]; + toolsExtra: Addon_BaseType[]; + tabId: string | undefined; + wrappers: Addon_WrapperType[]; } export interface ApplyWrappersProps { @@ -27,7 +30,6 @@ export interface ApplyWrappersProps { viewMode: State['viewMode']; id: string; storyId: StoryId; - active: boolean; } export type CustomCanvasRenderer = ( diff --git a/code/ui/manager/src/components/sidebar/RefIndicator.tsx b/code/ui/manager/src/components/sidebar/RefIndicator.tsx index 14cc4089369b..f0c8b4259a52 100644 --- a/code/ui/manager/src/components/sidebar/RefIndicator.tsx +++ b/code/ui/manager/src/components/sidebar/RefIndicator.tsx @@ -3,12 +3,20 @@ import type { FC, MouseEventHandler } from 'react'; import React, { useMemo, useCallback, forwardRef } from 'react'; import type { TooltipLinkListLink } from '@storybook/components'; -import { Icons, WithTooltip, Spaced, TooltipLinkList } from '@storybook/components'; -import { styled } from '@storybook/theming'; +import { WithTooltip, Spaced, TooltipLinkList } from '@storybook/components'; +import { styled, useTheme } from '@storybook/theming'; import { transparentize } from 'polished'; import { useStorybookApi } from '@storybook/manager-api'; -import { ChevronDownIcon, GlobeIcon } from '@storybook/icons'; +import { + AlertIcon, + ChevronDownIcon, + DocumentIcon, + GlobeIcon, + LightningIcon, + LockIcon, + TimeIcon, +} from '@storybook/icons'; import type { RefType } from './types'; import type { getStateType } from '../../utils/tree'; @@ -115,22 +123,6 @@ export const MessageWrapper = styled.div({ overflow: 'hidden', }); -const BlueIcon = styled(Icons)(({ theme }) => ({ - color: theme.color.secondary, -})); - -const YellowIcon = styled(Icons)(({ theme }) => ({ - color: theme.color.gold, -})); - -const RedIcon = styled(Icons)(({ theme }) => ({ - color: theme.color.negative, -})); - -const GreenIcon = styled(Icons)(({ theme }) => ({ - color: theme.color.green, -})); - const Version = styled.div(({ theme }) => ({ display: 'flex', alignItems: 'center', @@ -243,19 +235,24 @@ const ReadyMessage: FC<{ url: string; componentCount: number; leafCount: number; -}> = ({ url, componentCount, leafCount }) => ( - - -
- View external Storybook +}> = ({ url, componentCount, leafCount }) => { + const theme = useTheme(); + + return ( + +
- Explore {componentCount} components and {leafCount} stories in a new browser tab. + View external Storybook +
+ Explore {componentCount} components and {leafCount} stories in a new browser tab. +
-
-
-); + + ); +}; const LoginRequiredMessage: FC = ({ loginUrl, id }) => { + const theme = useTheme(); const open = useCallback((e) => { e.preventDefault(); const childWindow = globalWindow.open(loginUrl, `storybook_auth_${id}`, 'resizable,scrollbars'); @@ -273,7 +270,7 @@ const LoginRequiredMessage: FC = ({ loginUrl, id }) => { return ( - +
Log in required
You need to authenticate to view this Storybook's components.
@@ -282,45 +279,64 @@ const LoginRequiredMessage: FC = ({ loginUrl, id }) => { ); }; -const ReadDocsMessage: FC = () => ( - - -
- Read Composition docs -
Learn how to combine multiple Storybooks into one.
-
-
-); +const ReadDocsMessage: FC = () => { + const theme = useTheme(); -const ErrorOccurredMessage: FC<{ url: string }> = ({ url }) => ( - - -
- Something went wrong -
This external Storybook didn't load. Debug it in a new tab now.
-
-
-); + return ( + + +
+ Read Composition docs +
Learn how to combine multiple Storybooks into one.
+
+
+ ); +}; -const LoadingMessage: FC<{ url: string }> = ({ url }) => ( - - -
- Please wait -
This Storybook is loading.
-
-
-); +const ErrorOccurredMessage: FC<{ url: string }> = ({ url }) => { + const theme = useTheme(); -const PerformanceDegradedMessage: FC = () => ( - - -
- Reduce lag -
Learn how to speed up Composition performance.
-
-
-); + return ( + + +
+ Something went wrong +
This external Storybook didn't load. Debug it in a new tab now.
+
+
+ ); +}; + +const LoadingMessage: FC<{ url: string }> = ({ url }) => { + const theme = useTheme(); + + return ( + + +
+ Please wait +
This Storybook is loading.
+
+
+ ); +}; + +const PerformanceDegradedMessage: FC = () => { + const theme = useTheme(); + + return ( + + +
+ Reduce lag +
Learn how to speed up Composition performance.
+
+
+ ); +}; diff --git a/code/ui/manager/src/components/sidebar/Refs.tsx b/code/ui/manager/src/components/sidebar/Refs.tsx index 04f90148f7b8..1cd5c6c7a5a0 100644 --- a/code/ui/manager/src/components/sidebar/Refs.tsx +++ b/code/ui/manager/src/components/sidebar/Refs.tsx @@ -67,6 +67,7 @@ const CollapseButton = styled.button(({ theme }) => ({ gap: 6, alignItems: 'center', cursor: 'pointer', + overflow: 'hidden', '&:focus': { borderColor: theme.color.secondary, diff --git a/code/ui/manager/src/components/sidebar/Search.tsx b/code/ui/manager/src/components/sidebar/Search.tsx index 525337b8b2aa..cbbecc8264a6 100644 --- a/code/ui/manager/src/components/sidebar/Search.tsx +++ b/code/ui/manager/src/components/sidebar/Search.tsx @@ -20,6 +20,7 @@ import { isSearchResult, isExpandType } from './types'; import { scrollIntoView, searchItem } from '../../utils/tree'; import { getGroupStatus, getHighestStatus } from '../../utils/status'; +import { useLayout } from '../layout/LayoutProvider'; const { document } = global; @@ -288,6 +289,7 @@ export const Search = React.memo<{ }, [inputRef, selectStory, showAllComponents] ); + const { isMobile } = useLayout(); return ( @@ -359,7 +361,7 @@ export const Search = React.memo<{ {/* @ts-expect-error (TODO) */} - {enableShortcuts && !isOpen && ( + {!isMobile && enableShortcuts && !isOpen && ( {searchShortcut === '⌘ K' ? ( <> diff --git a/code/ui/manager/src/container/Preview.tsx b/code/ui/manager/src/container/Preview.tsx index 9fcf7a4a8819..91e78d45f0c4 100644 --- a/code/ui/manager/src/container/Preview.tsx +++ b/code/ui/manager/src/container/Preview.tsx @@ -1,10 +1,64 @@ import { global } from '@storybook/global'; +import type { Addon_BaseType, Addon_Collection, Addon_WrapperType } from '@storybook/types'; +import { Addon_TypesEnum } from '@storybook/types'; +import type { ComponentProps } from 'react'; import React from 'react'; -import type { Combo, StoriesHash } from '@storybook/manager-api'; +import memoizerific from 'memoizerific'; + +import type { State, StoriesHash } from '@storybook/manager-api'; import { Consumer } from '@storybook/manager-api'; -import { Preview } from '../components/preview/Preview'; +import { Preview, createCanvasTab, filterTabs } from '../components/preview/Preview'; +import { defaultWrappers } from '../components/preview/Wrappers'; +import { filterToolsSide, fullScreenTool } from '../components/preview/Toolbar'; +import { menuTool } from '../components/preview/tools/menu'; +import { remountTool } from '../components/preview/tools/remount'; +import { zoomTool } from '../components/preview/tools/zoom'; +import type { PreviewProps } from '../components/preview/utils/types'; +import { addonsTool } from '../components/preview/tools/addons'; +import { copyTool } from '../components/preview/tools/copy'; +import { ejectTool } from '../components/preview/tools/eject'; + +const defaultTabs = [createCanvasTab()]; +const defaultTools = [menuTool, remountTool, zoomTool]; +const defaultToolsExtra = [addonsTool, fullScreenTool, ejectTool, copyTool]; + +const emptyTabsList: Addon_BaseType[] = []; + +type FilterProps = [ + entry: PreviewProps['entry'], + viewMode: State['viewMode'], + location: State['location'], + path: State['path'], + tabId: string, +]; + +// memoization to return the same array every time, unless something relevant changes +const memoizedTabs = memoizerific(1)( + ( + _, + tabElements: Addon_Collection, + parameters: Record | undefined, + showTabs: boolean + ) => + showTabs + ? filterTabs([...defaultTabs, ...Object.values(tabElements)], parameters) + : emptyTabsList +); +const memoizedTools = memoizerific(1)( + (_, toolElements: Addon_Collection, filterProps: FilterProps) => + filterToolsSide([...defaultTools, ...Object.values(toolElements)], ...filterProps) +); +const memoizedExtra = memoizerific(1)( + (_, extraElements: Addon_Collection, filterProps: FilterProps) => + filterToolsSide([...defaultToolsExtra, ...Object.values(extraElements)], ...filterProps) +); + +const memoizedWrapper = memoizerific(1)((_, previewElements: Addon_Collection) => [ + ...defaultWrappers, + ...Object.values(previewElements), +]); const { PREVIEW_URL } = global; @@ -22,22 +76,59 @@ const getDescription = (item: Item) => { return item?.name ? `${item.name} ⋅ Storybook` : 'Storybook'; }; -const mapper = ({ api, state }: Combo) => { +const mapper = ({ + api, + state, +}: Parameters['filter']>[0]): Omit< + ComponentProps, + 'withLoader' | 'id' +> => { const { layout, location, customQueryParams, storyId, refs, viewMode, path, refId } = state; const entry = api.getData(storyId, refId); + const tabsList = Object.values(api.getElements(Addon_TypesEnum.TAB)); + const wrapperList = Object.values(api.getElements(Addon_TypesEnum.PREVIEW)); + const toolsList = Object.values(api.getElements(Addon_TypesEnum.TOOL)); + const toolsExtraList = Object.values(api.getElements(Addon_TypesEnum.TOOLEXTRA)); + + const tabId = api.getQueryParam('tab'); + + const tools = memoizedTools(toolsList.length, api.getElements(Addon_TypesEnum.TOOL), [ + entry, + viewMode, + location, + path, + tabId, + ]) as Addon_BaseType[]; + const toolsExtra = memoizedExtra( + toolsExtraList.length, + api.getElements(Addon_TypesEnum.TOOLEXTRA), + [entry, viewMode, location, path, tabId] + ) as Addon_BaseType[]; + return { api, entry, options: layout, description: getDescription(entry), viewMode, - path, refs, storyId, baseUrl: PREVIEW_URL || 'iframe.html', queryParams: customQueryParams, - location, + tools: tools, + toolsExtra: toolsExtra, + tabs: memoizedTabs( + tabsList.length, + api.getElements(Addon_TypesEnum.TAB), + entry ? entry.parameters : undefined, + layout.showTabs + ) as Addon_BaseType[], + wrappers: memoizedWrapper( + wrapperList.length, + api.getElements(Addon_TypesEnum.PREVIEW) + ) as Addon_WrapperType[], + tabId: tabId, }; }; diff --git a/code/ui/manager/src/container/Sidebar.tsx b/code/ui/manager/src/container/Sidebar.tsx index 7eec79fc83c3..21d9cf09ef6c 100755 --- a/code/ui/manager/src/container/Sidebar.tsx +++ b/code/ui/manager/src/container/Sidebar.tsx @@ -45,9 +45,9 @@ const Sidebar = React.memo(function Sideber({ onMenuClick }: SidebarProps) { const bottomItems = api.getElements(Addon_TypesEnum.experimental_SIDEBAR_BOTTOM); const topItems = api.getElements(Addon_TypesEnum.experimental_SIDEBAR_TOP); // eslint-disable-next-line react-hooks/exhaustive-deps - const bottom = useMemo(() => Object.values(bottomItems), [...Object.values(bottomItems)]); + const bottom = useMemo(() => Object.values(bottomItems), [Object.keys(bottomItems).join('')]); // eslint-disable-next-line react-hooks/exhaustive-deps - const top = useMemo(() => Object.values(topItems), [...Object.values(topItems)]); + const top = useMemo(() => Object.values(topItems), [Object.keys(topItems).join('')]); return { title: name, diff --git a/code/ui/manager/src/index.tsx b/code/ui/manager/src/index.tsx index d97a382f35c7..2af0ac508db7 100644 --- a/code/ui/manager/src/index.tsx +++ b/code/ui/manager/src/index.tsx @@ -72,7 +72,11 @@ const Main: FC<{ provider: Provider }> = ({ provider }) => { diff --git a/code/ui/manager/src/settings/shortcuts.tsx b/code/ui/manager/src/settings/shortcuts.tsx index dc02ff9166b0..3af815c72cc1 100644 --- a/code/ui/manager/src/settings/shortcuts.tsx +++ b/code/ui/manager/src/settings/shortcuts.tsx @@ -7,8 +7,9 @@ import { shortcutToHumanString, shortcutMatchesShortcut, } from '@storybook/manager-api'; -import { Button, Form, Icons } from '@storybook/components'; +import { Button, Form } from '@storybook/components'; import SettingsFooter from './SettingsFooter'; +import { CheckIcon } from '@storybook/icons'; const Header = styled.header(({ theme }) => ({ marginBottom: 20, @@ -80,7 +81,7 @@ export const Fade = keyframes` 50% { opacity: 1; } `; -export const SuccessIcon = styled(Icons)<{ valid: string }>( +const SuccessIcon = styled(CheckIcon)<{ valid: string }>( ({ valid, theme }) => valid === 'valid' ? { @@ -283,7 +284,7 @@ class ShortcutsScreen extends Component - + )); diff --git a/code/ui/manager/src/utils/status.tsx b/code/ui/manager/src/utils/status.tsx index c5ab041663fd..db8d580820f4 100644 --- a/code/ui/manager/src/utils/status.tsx +++ b/code/ui/manager/src/utils/status.tsx @@ -1,13 +1,13 @@ import React from 'react'; -import { Icons } from '@storybook/components'; import type { ReactElement } from 'react'; import type { API_HashEntry, API_StatusState, API_StatusValue } from '@storybook/types'; import { styled } from '@storybook/theming'; import { getDescendantIds } from './tree'; +import { CircleIcon } from '@storybook/icons'; -const SmallIcons = styled(Icons)({ +const SmallIcons = styled(CircleIcon)({ // specificity hack '&&&': { width: 6, @@ -24,10 +24,10 @@ const LoadingIcons = styled(SmallIcons)(({ theme: { animation, color, base } }) export const statusPriority: API_StatusValue[] = ['unknown', 'pending', 'success', 'warn', 'error']; export const statusMapping: Record = { unknown: [null, null], - pending: [, 'currentColor'], - success: [, 'currentColor'], - warn: [, '#A15C20'], - error: [, 'brown'], + pending: [, 'currentColor'], + success: [, 'currentColor'], + warn: [, '#A15C20'], + error: [, 'brown'], }; export const getHighestStatus = (statuses: API_StatusValue[]): API_StatusValue => { diff --git a/code/vitest-setup.ts b/code/vitest-setup.ts index 4c1d82c78407..98a40b698bbb 100644 --- a/code/vitest-setup.ts +++ b/code/vitest-setup.ts @@ -1,5 +1,5 @@ import '@testing-library/jest-dom/vitest'; -import { vi } from 'vitest'; +import { vi, expect } from 'vitest'; import { dedent } from 'ts-dedent'; @@ -16,6 +16,7 @@ const ignoreList = [ error.message.match( /React will try to recreate this component tree from scratch using the error boundary you provided/ ), + (error: any) => error.message.includes('Lit is in dev mode. Not recommended for production!'), ]; const throwMessage = (type: any, message: any) => { diff --git a/code/vitest.workspace.ts b/code/vitest.workspace.ts index fda0ab58e871..9adcc717f753 100644 --- a/code/vitest.workspace.ts +++ b/code/vitest.workspace.ts @@ -12,10 +12,26 @@ export default defineWorkspace([ 'renderers/*/vitest.config.ts', ]); +/** + * CircleCI reports the wrong number of threads to Node.js, so we need to set it manually. + * Unit tests are running with the xlarge resource class, which has 8 vCPUs. + * @see https://jahed.dev/2022/11/20/fixing-node-js-multi-threading-on-circleci/ + * @see https://vitest.dev/config/#pooloptions-threads-maxthreads + * @see https://circleci.com/docs/configuration-reference/#x86 + * @see .circleci/config.yml#L214 + */ +const threadCount = process.env.CI ? 8 : undefined; + export const vitestCommonConfig = defineConfig({ test: { clearMocks: true, - setupFiles: [resolve('./vitest-setup.ts')], + setupFiles: [resolve(__dirname, './vitest-setup.ts')], globals: true, + poolOptions: { + threads: { + minThreads: threadCount, + maxThreads: threadCount, + }, + }, }, }); diff --git a/code/yarn.lock b/code/yarn.lock index 658e3dd2ca3c..86f09cd405d2 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -24,10 +24,10 @@ __metadata: languageName: node linkType: hard -"@adobe/css-tools@npm:^4.3.1": - version: 4.3.2 - resolution: "@adobe/css-tools@npm:4.3.2" - checksum: 296a03dd29f227c60500d2da8c7f64991fecf1d8b456ce2b4adb8cec7363d9c08b5b03f1463673fc8cbfe54b538745588e7a13c736d2dd14a80c01a20f127f39 +"@adobe/css-tools@npm:^4.3.2": + version: 4.3.3 + resolution: "@adobe/css-tools@npm:4.3.3" + checksum: e76e712df713964b87cdf2aca1f0477f19bebd845484d5fcba726d3ec7782366e2f26ec8cb2dcfaf47081a5c891987d8a9f5c3f30d11e1eb3c1848adc27fcb24 languageName: node linkType: hard @@ -522,26 +522,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.15": - version: 7.23.7 - resolution: "@babel/helper-create-class-features-plugin@npm:7.23.7" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-member-expression-to-functions": "npm:^7.23.0" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.20" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - semver: "npm:^6.3.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: f594e99f97211bda5530756712751c1c4ce6063bb376f1f38cc540309a086bd0f4b62aff969ddb29e7310e936c2d3745934a2b292c4710be8112e57fbe3f3381 - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.23.5": +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.15, @babel/helper-create-class-features-plugin@npm:^7.23.5": version: 7.23.5 resolution: "@babel/helper-create-class-features-plugin@npm:7.23.5" dependencies: @@ -770,7 +751,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.11.5, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.4, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.3, @babel/parser@npm:^7.23.5, @babel/parser@npm:^7.23.6, @babel/parser@npm:^7.4.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.11.5, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.4, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.5, @babel/parser@npm:^7.23.6, @babel/parser@npm:^7.4.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": version: 7.23.6 resolution: "@babel/parser@npm:7.23.6" bin: @@ -1181,21 +1162,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.23.2": - version: 7.23.7 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.7" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-remap-async-to-generator": "npm:^7.22.20" - "@babel/plugin-syntax-async-generators": "npm:^7.8.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 63d314edc9fbeaf2700745ca0e19bf9840e87f2d7d1f6c5638e06d2aec3e7418d0d7493ed09087e2fe369cc15e9d96c113fb2cd367cb5e3ff922e3712c27b7d4 - languageName: node - linkType: hard - -"@babel/plugin-transform-async-generator-functions@npm:^7.23.4": +"@babel/plugin-transform-async-generator-functions@npm:^7.23.2, @babel/plugin-transform-async-generator-functions@npm:^7.23.4": version: 7.23.4 resolution: "@babel/plugin-transform-async-generator-functions@npm:7.23.4" dependencies: @@ -1282,25 +1249,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.22.15": - version: 7.23.8 - resolution: "@babel/plugin-transform-classes@npm:7.23.8" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-compilation-targets": "npm:^7.23.6" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.20" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - globals: "npm:^11.1.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 227ac5166501e04d9e7fbd5eda6869b084ffa4af6830ac12544ac6ea14953ca00eb1762b0df9349c0f6c8d2a799385910f558066cd0fb85b9ca437b1131a6043 - languageName: node - linkType: hard - -"@babel/plugin-transform-classes@npm:^7.23.5": +"@babel/plugin-transform-classes@npm:^7.22.15, @babel/plugin-transform-classes@npm:^7.23.5": version: 7.23.5 resolution: "@babel/plugin-transform-classes@npm:7.23.5" dependencies: @@ -2271,25 +2220,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.4.5": - version: 7.23.2 - resolution: "@babel/traverse@npm:7.23.2" - dependencies: - "@babel/code-frame": "npm:^7.22.13" - "@babel/generator": "npm:^7.23.0" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/parser": "npm:^7.23.0" - "@babel/types": "npm:^7.23.0" - debug: "npm:^4.1.0" - globals: "npm:^11.1.0" - checksum: d096c7c4bab9262a2f658298a3c630ae4a15a10755bb257ae91d5ab3e3b2877438934859c8d34018b7727379fe6b26c4fa2efc81cf4c462a7fe00caf79fa02ff - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.23.7": +"@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.7, @babel/traverse@npm:^7.4.5": version: 7.23.7 resolution: "@babel/traverse@npm:7.23.7" dependencies: @@ -2307,7 +2238,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.4, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.3, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.2, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.4, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.6, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.2, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": version: 7.23.6 resolution: "@babel/types@npm:7.23.6" dependencies: @@ -2801,20 +2732,13 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.5.1": +"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" checksum: c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4 languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.6.1": - version: 4.9.1 - resolution: "@eslint-community/regexpp@npm:4.9.1" - checksum: d0e1bd1a37cb2cb6bbac88dfe97b62b412d4b6ea3a4bb1c4e1e503be03125063db5d80999cef9728f57b19b49979aa902ac68182bcf5f80dfce6fa9a9d34eee1 - languageName: node - linkType: hard - "@eslint/eslintrc@npm:^1.0.5": version: 1.4.1 resolution: "@eslint/eslintrc@npm:1.4.1" @@ -3734,72 +3658,72 @@ __metadata: languageName: node linkType: hard -"@next/env@npm:14.0.4": - version: 14.0.4 - resolution: "@next/env@npm:14.0.4" - checksum: 59b893d30aea0556379a24f6e4eac830677feb149bd8416b72383ea2600ce194fa22a79b2dd86e0b295c4a8f0702e461f48edaff1ac9173eddef42a4cce7fd98 +"@next/env@npm:14.1.0": + version: 14.1.0 + resolution: "@next/env@npm:14.1.0" + checksum: f45ce1e3dad87cdbddc58b06bd411f44a6d21dfc2c344d02a5e1b07f56fbc9a39e192c0b0917df9f2e9e4e2156306a8c78f173ca4b53932c2793e67797462a23 languageName: node linkType: hard -"@next/swc-darwin-arm64@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-darwin-arm64@npm:14.0.4" +"@next/swc-darwin-arm64@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-darwin-arm64@npm:14.1.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@next/swc-darwin-x64@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-darwin-x64@npm:14.0.4" +"@next/swc-darwin-x64@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-darwin-x64@npm:14.1.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@next/swc-linux-arm64-gnu@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-arm64-gnu@npm:14.0.4" +"@next/swc-linux-arm64-gnu@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-linux-arm64-gnu@npm:14.1.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-arm64-musl@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-arm64-musl@npm:14.0.4" +"@next/swc-linux-arm64-musl@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-linux-arm64-musl@npm:14.1.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@next/swc-linux-x64-gnu@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-x64-gnu@npm:14.0.4" +"@next/swc-linux-x64-gnu@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-linux-x64-gnu@npm:14.1.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@next/swc-linux-x64-musl@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-linux-x64-musl@npm:14.0.4" +"@next/swc-linux-x64-musl@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-linux-x64-musl@npm:14.1.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@next/swc-win32-arm64-msvc@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-win32-arm64-msvc@npm:14.0.4" +"@next/swc-win32-arm64-msvc@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-win32-arm64-msvc@npm:14.1.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@next/swc-win32-ia32-msvc@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-win32-ia32-msvc@npm:14.0.4" +"@next/swc-win32-ia32-msvc@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-win32-ia32-msvc@npm:14.1.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@next/swc-win32-x64-msvc@npm:14.0.4": - version: 14.0.4 - resolution: "@next/swc-win32-x64-msvc@npm:14.0.4" +"@next/swc-win32-x64-msvc@npm:14.1.0": + version: 14.1.0 + resolution: "@next/swc-win32-x64-msvc@npm:14.1.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -4293,6 +4217,13 @@ __metadata: languageName: node linkType: hard +"@one-ini/wasm@npm:0.1.1": + version: 0.1.1 + resolution: "@one-ini/wasm@npm:0.1.1" + checksum: 54700e055037f1a63bfcc86d24822203b25759598c2c3e295d1435130a449108aebc119c9c2e467744767dbe0b6ab47a182c61aa1071ba7368f5e20ab197ba65 + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -4789,7 +4720,7 @@ __metadata: "@storybook/client-logger": "workspace:*" "@storybook/components": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/theming": "workspace:*" @@ -4836,7 +4767,7 @@ __metadata: "@storybook/client-logger": "workspace:*" "@storybook/components": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/theming": "workspace:*" @@ -4912,6 +4843,7 @@ __metadata: "@storybook/test": "workspace:*" "@storybook/theming": "workspace:*" "@storybook/types": "workspace:*" + "@types/react": "npm:^16.8.0 || ^17.0.0 || ^18.0.0" fs-extra: "npm:^11.1.0" react: "npm:^18.2.0" react-dom: "npm:^18.2.0" @@ -4967,7 +4899,7 @@ __metadata: "@storybook/core-common": "workspace:*" "@storybook/core-events": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/instrumenter": "workspace:*" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" @@ -4993,6 +4925,7 @@ __metadata: "@storybook/components": "workspace:*" "@storybook/core-events": "workspace:*" "@storybook/global": "npm:^5.0.0" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/theming": "workspace:*" @@ -5048,7 +4981,7 @@ __metadata: "@storybook/components": "workspace:*" "@storybook/core-events": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/types": "workspace:*" @@ -5067,7 +5000,7 @@ __metadata: "@storybook/components": "workspace:*" "@storybook/core-events": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/types": "workspace:*" @@ -5107,7 +5040,7 @@ __metadata: "@storybook/client-logger": "workspace:*" "@storybook/components": "workspace:*" "@storybook/core-events": "workspace:*" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/theming": "workspace:*" @@ -5140,7 +5073,7 @@ __metadata: "@storybook/components": "workspace:*" "@storybook/core-events": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/theming": "workspace:*" @@ -5258,7 +5191,7 @@ __metadata: "@storybook/csf": "npm:^0.1.2" "@storybook/docs-tools": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/preview-api": "workspace:*" "@storybook/test": "workspace:*" @@ -5280,6 +5213,11 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true languageName: unknown linkType: soft @@ -5329,6 +5267,7 @@ __metadata: glob: "npm:^10.0.0" magic-string: "npm:^0.30.0" slash: "npm:^5.0.0" + ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" vite: "npm:^4.0.4" peerDependencies: @@ -5431,7 +5370,7 @@ __metadata: "@types/util-deprecate": "npm:^1.0.0" "@yarnpkg/fslib": "npm:2.10.3" "@yarnpkg/libzip": "npm:2.3.0" - boxen: "npm:^5.1.2" + boxen: "npm:^7.1.1" chalk: "npm:^4.1.0" commander: "npm:^6.2.1" cross-spawn: "npm:^7.0.3" @@ -5516,7 +5455,7 @@ __metadata: "@storybook/client-logger": "workspace:*" "@storybook/csf": "npm:^0.1.2" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/test": "workspace:*" "@storybook/theming": "workspace:*" "@storybook/types": "workspace:*" @@ -5624,7 +5563,7 @@ __metadata: "@types/semver": "npm:^7.3.4" "@types/ws": "npm:^8" better-opn: "npm:^3.0.2" - boxen: "npm:^5.1.2" + boxen: "npm:^7.1.1" chalk: "npm:^4.1.0" cli-table3: "npm:^0.6.1" compression: "npm:^1.7.4" @@ -5632,7 +5571,7 @@ __metadata: express: "npm:^4.17.3" fs-extra: "npm:^11.1.0" globby: "npm:^11.0.2" - ip: "npm:^2.0.0" + ip: "npm:^2.0.1" lodash: "npm:^4.17.21" node-fetch: "npm:^3.3.1" open: "npm:^8.4.0" @@ -5849,13 +5788,13 @@ __metadata: languageName: unknown linkType: soft -"@storybook/icons@npm:^1.2.3": - version: 1.2.3 - resolution: "@storybook/icons@npm:1.2.3" +"@storybook/icons@npm:^1.2.5": + version: 1.2.5 + resolution: "@storybook/icons@npm:1.2.5" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 510878cc80a844eb5b83460be8e71890743fb9fd70afb3cc46658d3324574d6389542a5dd078c5f613741193d0ac1ff7d2d83b33e447ee0fc1c3699d255ba225 + checksum: 089622af6de4ab82624d894fbe43688a0eb72f15e6bb8fc19c54fb9f9d7312ce7caf34acebcbd63319dbaef129d8547bc23a5600955d04f6034355e7d82dcfa1 languageName: node linkType: hard @@ -5943,7 +5882,7 @@ __metadata: "@storybook/components": "workspace:*" "@storybook/core-events": "workspace:*" "@storybook/global": "npm:^5.0.0" - "@storybook/icons": "npm:^1.2.3" + "@storybook/icons": "npm:^1.2.5" "@storybook/manager-api": "workspace:*" "@storybook/router": "workspace:*" "@storybook/test": "workspace:*" @@ -6017,7 +5956,7 @@ __metadata: fs-extra: "npm:^11.1.0" image-size: "npm:^1.0.0" loader-utils: "npm:^3.2.1" - next: "npm:^14.0.2" + next: "npm:^14.1.0" node-polyfill-webpack-plugin: "npm:^2.0.1" pnp-webpack-plugin: "npm:^1.7.0" postcss: "npm:^8.4.21" @@ -6481,7 +6420,7 @@ __metadata: "@typescript-eslint/experimental-utils": "npm:^5.62.0" "@typescript-eslint/parser": "npm:^6.18.1" "@vitejs/plugin-react": "npm:^3.0.1" - "@vitest/coverage-v8": "npm:^1.0.1" + "@vitest/coverage-v8": "npm:^1.2.2" chromatic: "npm:7.1.0" concurrently: "npm:^5.3.0" cross-env: "npm:^7.0.3" @@ -6492,7 +6431,7 @@ __metadata: eslint: "npm:^8.56.0" eslint-import-resolver-typescript: "npm:^3.6.1" eslint-plugin-local-rules: "portal:../scripts/eslint-plugin-local-rules" - eslint-plugin-storybook: "npm:^0.6.15" + eslint-plugin-storybook: "npm:^0.8.0" fs-extra: "npm:^11.1.0" github-release-from-changelog: "npm:^2.1.1" glob: "npm:^10.0.0" @@ -6518,7 +6457,7 @@ __metadata: util: "npm:^0.12.4" vite: "npm:^4.0.0" vite-plugin-turbosnap: "npm:^1.0.1" - vitest: "npm:^1.0.1" + vitest: "npm:^1.2.2" wait-on: "npm:^7.0.1" dependenciesMeta: ejs: @@ -6707,8 +6646,8 @@ __metadata: "@storybook/instrumenter": "workspace:*" "@storybook/preview-api": "workspace:*" "@testing-library/dom": "npm:^9.3.1" - "@testing-library/jest-dom": "npm:^6.1.3" - "@testing-library/user-event": "npm:14.3.0" + "@testing-library/jest-dom": "npm:^6.4.0" + "@testing-library/user-event": "npm:^14.5.2" "@vitest/expect": "npm:1.1.3" "@vitest/spy": "npm:^1.1.3" chai: "npm:^4.3.7" @@ -6752,6 +6691,11 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true languageName: unknown linkType: soft @@ -6813,6 +6757,7 @@ __metadata: "@storybook/global": "npm:^5.0.0" "@storybook/preview-api": "workspace:*" "@storybook/types": "workspace:*" + "@testing-library/vue": "npm:^8.0.0" "@types/prettier": "npm:^3.0.0" "@vitejs/plugin-vue": "npm:^4.4.0" "@vue/compiler-core": "npm:^3.0.0" @@ -6952,7 +6897,7 @@ __metadata: languageName: node linkType: hard -"@testing-library/dom@npm:^9.0.0, @testing-library/dom@npm:^9.3.1": +"@testing-library/dom@npm:^9.0.0, @testing-library/dom@npm:^9.3.1, @testing-library/dom@npm:^9.3.3": version: 9.3.3 resolution: "@testing-library/dom@npm:9.3.3" dependencies: @@ -6968,33 +6913,36 @@ __metadata: languageName: node linkType: hard -"@testing-library/jest-dom@npm:^6.1.3, @testing-library/jest-dom@npm:^6.1.4": - version: 6.1.5 - resolution: "@testing-library/jest-dom@npm:6.1.5" +"@testing-library/jest-dom@npm:^6.1.4, @testing-library/jest-dom@npm:^6.4.0": + version: 6.4.0 + resolution: "@testing-library/jest-dom@npm:6.4.0" dependencies: - "@adobe/css-tools": "npm:^4.3.1" + "@adobe/css-tools": "npm:^4.3.2" "@babel/runtime": "npm:^7.9.2" aria-query: "npm:^5.0.0" chalk: "npm:^3.0.0" css.escape: "npm:^1.5.1" - dom-accessibility-api: "npm:^0.5.6" + dom-accessibility-api: "npm:^0.6.3" lodash: "npm:^4.17.15" redent: "npm:^3.0.0" peerDependencies: "@jest/globals": ">= 28" + "@types/bun": "*" "@types/jest": ">= 28" jest: ">= 28" vitest: ">= 0.32" peerDependenciesMeta: "@jest/globals": optional: true + "@types/bun": + optional: true "@types/jest": optional: true jest: optional: true vitest: optional: true - checksum: f3643a56fcd970b5c7e8fd10faf3c4817d8ab0e74fb1198d726643bdc5ac675ceaac3b0068c5b4fbad254470e8f98ed50028741de875a29ceaa2f854570979c9 + checksum: 6b7eba9ca388986a721fb12f84adf0f5534bf7ec5851982023a889c4a0afac6e9e91291bdac39e1f59a05adefd7727e30463d98b21c3da32fbfec229ccb11ef1 languageName: node linkType: hard @@ -7025,21 +6973,35 @@ __metadata: languageName: node linkType: hard -"@testing-library/user-event@npm:14.3.0": - version: 14.3.0 - resolution: "@testing-library/user-event@npm:14.3.0" +"@testing-library/user-event@npm:^14.4.0, @testing-library/user-event@npm:^14.4.3": + version: 14.5.1 + resolution: "@testing-library/user-event@npm:14.5.1" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: 8a0e708709f2510287568dff668bc7d6f5c4e7e17407452b7aa0fcf74732dccf511c63fc76ac514d753cb1f0586c1def59ba7f5245a9523715d37a8f198745d3 + checksum: 1e00d6ead23377885b906db6e46e259161a0efb4138f7527481d7435f3c8f65cb7e3eab2900e2ac1886fa6dd03416e773a3a60dea87a9a2086a7127dee315f6f languageName: node linkType: hard -"@testing-library/user-event@npm:^14.4.0, @testing-library/user-event@npm:^14.4.3": - version: 14.5.1 - resolution: "@testing-library/user-event@npm:14.5.1" +"@testing-library/user-event@npm:^14.5.2": + version: 14.5.2 + resolution: "@testing-library/user-event@npm:14.5.2" peerDependencies: "@testing-library/dom": ">=7.21.4" - checksum: 1e00d6ead23377885b906db6e46e259161a0efb4138f7527481d7435f3c8f65cb7e3eab2900e2ac1886fa6dd03416e773a3a60dea87a9a2086a7127dee315f6f + checksum: 68a0c2aa28a3c8e6eb05cafee29705438d7d8a9427423ce5064d44f19c29e89b5636de46dd2f28620fb10abba75c67130185bbc3aa23ac1163a227a5f36641e1 + languageName: node + linkType: hard + +"@testing-library/vue@npm:^8.0.0": + version: 8.0.1 + resolution: "@testing-library/vue@npm:8.0.1" + dependencies: + "@babel/runtime": "npm:^7.23.2" + "@testing-library/dom": "npm:^9.3.3" + "@vue/test-utils": "npm:^2.4.1" + peerDependencies: + "@vue/compiler-sfc": ">= 3" + vue: ">= 3" + checksum: 1a65435fed6b020de1b704eec02cebfacf5bc8052c23bbcb19eea1300f5e60e9d112c4c99bd02aaabbeee2f7da9431dff4f61a38c0e2ced968fa865d2b65b68e languageName: node linkType: hard @@ -7587,14 +7549,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.13 - resolution: "@types/json-schema@npm:7.0.13" - checksum: 446fe6722899333ff647b5853fdcc9f039156d56abe517166154d3578d641841cc869f61e8b7822c24a1daeb7dfbd4fdcea84bf07c0858e2f9cca415e2ca8dd4 - languageName: node - linkType: hard - -"@types/json-schema@npm:^7.0.12": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" checksum: a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db @@ -7731,12 +7686,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:>= 8, @types/node@npm:>=10.0.0": - version: 20.10.3 - resolution: "@types/node@npm:20.10.3" +"@types/node@npm:*, @types/node@npm:>= 8, @types/node@npm:>=10.0.0, @types/node@npm:^20.0.0": + version: 20.11.1 + resolution: "@types/node@npm:20.11.1" dependencies: undici-types: "npm:~5.26.4" - checksum: 7c8a0327a29d68a0bb152ae30e8c4738638515dd599064821c9d0c1884a1efa103021cd8f8c91e690cd56b0602bb6fe0e6651a5df2337bdc85e0c0f66054b2ce + checksum: f665cdce28b0b6e57338d1f74e0599ee9b10eac74cff729921c8f473807398e9aba2f8cf74c74a4d3dfbc2d616c73267da7de3003ed3c8152ea366bf4c96a91a languageName: node linkType: hard @@ -7749,15 +7704,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^20.0.0": - version: 20.11.1 - resolution: "@types/node@npm:20.11.1" - dependencies: - undici-types: "npm:~5.26.4" - checksum: f665cdce28b0b6e57338d1f74e0599ee9b10eac74cff729921c8f473807398e9aba2f8cf74c74a4d3dfbc2d616c73267da7de3003ed3c8152ea366bf4c96a91a - languageName: node - linkType: hard - "@types/normalize-package-data@npm:^2.4.0": version: 2.4.2 resolution: "@types/normalize-package-data@npm:2.4.2" @@ -7913,6 +7859,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^16.8.0 || ^17.0.0 || ^18.0.0": + version: 18.2.55 + resolution: "@types/react@npm:18.2.55" + dependencies: + "@types/prop-types": "npm:*" + "@types/scheduler": "npm:*" + csstype: "npm:^3.0.2" + checksum: 6b1c73beafbbc582dc54ffd92b3779f6d850e8f6b5ce5d04b31e9498a3d77bfc416bb08f0d8d63ab4f4649ccd6639996472416871c01c74a528b16a55faeaf38 + languageName: node + linkType: hard + "@types/resolve@npm:^1.20.2": version: 1.20.3 resolution: "@types/resolve@npm:1.20.3" @@ -8345,7 +8302,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.45.0": +"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.62.0": version: 5.62.0 resolution: "@typescript-eslint/utils@npm:5.62.0" dependencies: @@ -8461,9 +8418,9 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-v8@npm:^1.0.1": - version: 1.0.4 - resolution: "@vitest/coverage-v8@npm:1.0.4" +"@vitest/coverage-v8@npm:^1.2.2": + version: 1.2.2 + resolution: "@vitest/coverage-v8@npm:1.2.2" dependencies: "@ampproject/remapping": "npm:^2.2.1" "@bcoe/v8-coverage": "npm:^0.2.3" @@ -8473,25 +8430,14 @@ __metadata: istanbul-lib-source-maps: "npm:^4.0.1" istanbul-reports: "npm:^3.1.6" magic-string: "npm:^0.30.5" - magicast: "npm:^0.3.2" + magicast: "npm:^0.3.3" picocolors: "npm:^1.0.0" std-env: "npm:^3.5.0" test-exclude: "npm:^6.0.0" v8-to-istanbul: "npm:^9.2.0" peerDependencies: vitest: ^1.0.0 - checksum: e4fb7e7f818a320dcef451193a6aba7b4173a3246695fb5c7b406251c860e10a02f41c3a9678301d6d14e9453bef16de5624658bc3abc11775c708bb20f15ace - languageName: node - linkType: hard - -"@vitest/expect@npm:1.0.4": - version: 1.0.4 - resolution: "@vitest/expect@npm:1.0.4" - dependencies: - "@vitest/spy": "npm:1.0.4" - "@vitest/utils": "npm:1.0.4" - chai: "npm:^4.3.10" - checksum: a5f3d0ab334938cd70f4d2b44205885532d3d24466617a3c4a230378b6cfa0b5de5f5d9ce80e48508c3cc02dfde1f064ea1126912d7e9f46e18b305b41417f2a + checksum: 90e3cfdc7d36df86f95b4bc372851dbf0a9e78ca9d80177674ebb30cf5dff1e786660016aa7e369bd30ac7d1d3edc18d7ab0f6ccfdc9cdfe04ada0e0b5d5911a languageName: node linkType: hard @@ -8506,45 +8452,47 @@ __metadata: languageName: node linkType: hard +"@vitest/expect@npm:1.2.2": + version: 1.2.2 + resolution: "@vitest/expect@npm:1.2.2" + dependencies: + "@vitest/spy": "npm:1.2.2" + "@vitest/utils": "npm:1.2.2" + chai: "npm:^4.3.10" + checksum: 920e80b956d9d5ef7909cbe2bf883c8556da11c5123ea037396cb672d7038116c9773bd36915a3df7be2ffd76b661d5a6487e7e5ded78f39e2500cb36ae81e59 + languageName: node + linkType: hard + "@vitest/expect@patch:@vitest/expect@npm%3A1.1.3#~/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch": version: 1.1.3 - resolution: "@vitest/expect@patch:@vitest/expect@npm%3A1.1.3#~/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch::version=1.1.3&hash=5d51c9" + resolution: "@vitest/expect@patch:@vitest/expect@npm%3A1.1.3#~/.yarn/patches/@vitest-expect-npm-1.1.3-2062bf533f.patch::version=1.1.3&hash=8fb073" dependencies: "@vitest/spy": "npm:1.1.3" "@vitest/utils": "npm:1.1.3" chai: "npm:^4.3.10" - checksum: 426287f864f58b05b1c4689bc87b4ef2ca7b3316a22e8e42d94ee9c125cbc0caf294618c9a1201a8ddf8ab68ce1ab194d1e34589f7d608906a3dc679074cfe22 + checksum: c3bbcae82050b7e92438c85e679ef2cb09162dc5638a10b3f0b5a8fc5600dfb0be578a244d84012ae2f1715748189393ac0fc72b891efff3503338221795ebe5 languageName: node linkType: hard -"@vitest/runner@npm:1.0.4": - version: 1.0.4 - resolution: "@vitest/runner@npm:1.0.4" +"@vitest/runner@npm:1.2.2": + version: 1.2.2 + resolution: "@vitest/runner@npm:1.2.2" dependencies: - "@vitest/utils": "npm:1.0.4" + "@vitest/utils": "npm:1.2.2" p-limit: "npm:^5.0.0" pathe: "npm:^1.1.1" - checksum: 4e60471997cbac61c2b7f5e8c701a7459ed51177c709f27c53ffa1e889097782132d21ed816c10cf3bf5dadf82e973c65d6e2210f77aba19f8be9d5e9a1a1002 + checksum: 25a9c03cca5b40738fe606757b14ee9d60d25193115b4674e3cc402c2b2c3844d234902d48bfa7646cb205455ea27891fef96733e033a570b85fe74ed29ff81c languageName: node linkType: hard -"@vitest/snapshot@npm:1.0.4": - version: 1.0.4 - resolution: "@vitest/snapshot@npm:1.0.4" +"@vitest/snapshot@npm:1.2.2": + version: 1.2.2 + resolution: "@vitest/snapshot@npm:1.2.2" dependencies: magic-string: "npm:^0.30.5" pathe: "npm:^1.1.1" pretty-format: "npm:^29.7.0" - checksum: 77fc4a7b74f4bce56bfa7ff5bfefa5d9a7511988d3e7e7fc798a877325ed3db4a3252fa343adff1c77482bc18e69f7279290d165fe5688d8f63a4266d2d716a8 - languageName: node - linkType: hard - -"@vitest/spy@npm:1.0.4": - version: 1.0.4 - resolution: "@vitest/spy@npm:1.0.4" - dependencies: - tinyspy: "npm:^2.2.0" - checksum: dece5db1aabc667a549d6e0a382d338fa0bfee684aadf4695d0633e1e30e11ad244d0be2163238598e615dfea683b73b2b095e89cc4854a2a2d6cb528c4bfca8 + checksum: 0f8a69a289aa6466c7dd56f8327190d56a0bc7ad10412127de001c94784f6dba5e5bccb757def21f565f4efa3e00c307b92e8b6c302f11fc57889b743ba18a95 languageName: node linkType: hard @@ -8557,14 +8505,12 @@ __metadata: languageName: node linkType: hard -"@vitest/utils@npm:1.0.4": - version: 1.0.4 - resolution: "@vitest/utils@npm:1.0.4" +"@vitest/spy@npm:1.2.2": + version: 1.2.2 + resolution: "@vitest/spy@npm:1.2.2" dependencies: - diff-sequences: "npm:^29.6.3" - loupe: "npm:^2.3.7" - pretty-format: "npm:^29.7.0" - checksum: 4a87f98b9192f544a6d52232ed1605ac9a6d7418e35de40b4ef36d0d0f6905112a9a21f1393e16f47838e67992399958d524e6b99f6a3583c0a0527fa7557e49 + tinyspy: "npm:^2.2.0" + checksum: 5480048d26c0d82b524317552fbdcc05fed6ea626d887620647826453a344798a360f2a75af477512a1569b1b6c918eae62338e8b35575f875fc2d7ef51419f3 languageName: node linkType: hard @@ -8580,6 +8526,18 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:1.2.2": + version: 1.2.2 + resolution: "@vitest/utils@npm:1.2.2" + dependencies: + diff-sequences: "npm:^29.6.3" + estree-walker: "npm:^3.0.3" + loupe: "npm:^2.3.7" + pretty-format: "npm:^29.7.0" + checksum: 32449cb7eca8ecea56e0fce280c9770f65fa6b60bbba73be06ca2891096818899b4b3220bd3c815df8beb4266034db394fcf235e4de8959cce686b8b360948d1 + languageName: node + linkType: hard + "@vitest/utils@npm:^0.34.6": version: 0.34.7 resolution: "@vitest/utils@npm:0.34.7" @@ -8643,7 +8601,7 @@ __metadata: languageName: node linkType: hard -"@vue/compiler-core@npm:3.4.5": +"@vue/compiler-core@npm:3.4.5, @vue/compiler-core@npm:^3.0.0": version: 3.4.5 resolution: "@vue/compiler-core@npm:3.4.5" dependencies: @@ -8656,18 +8614,6 @@ __metadata: languageName: node linkType: hard -"@vue/compiler-core@npm:^3.0.0": - version: 3.3.13 - resolution: "@vue/compiler-core@npm:3.3.13" - dependencies: - "@babel/parser": "npm:^7.23.5" - "@vue/shared": "npm:3.3.13" - estree-walker: "npm:^2.0.2" - source-map-js: "npm:^1.0.2" - checksum: d0544ef5c12adb1f25523349dfb5468ee59928892c8476c491b66806840ab7de7a2c15b943ae3805dc8adcfd1a88435db08b97a0d23977eafe7e448a2a001754 - languageName: node - linkType: hard - "@vue/compiler-dom@npm:3.0.0": version: 3.0.0 resolution: "@vue/compiler-dom@npm:3.0.0" @@ -8909,13 +8855,6 @@ __metadata: languageName: node linkType: hard -"@vue/shared@npm:3.3.13": - version: 3.3.13 - resolution: "@vue/shared@npm:3.3.13" - checksum: 8f49e0ee51f7f1edce16aa7a97b5a7a36d8cf36dfd03c9dba194b6eb0e9685eb71335f0a2b17af17753b742fa2346f96ec371a3c0a56677a4e7eeb0f13426a56 - languageName: node - linkType: hard - "@vue/shared@npm:3.4.5, @vue/shared@npm:^3.3.0": version: 3.4.5 resolution: "@vue/shared@npm:3.4.5" @@ -8923,6 +8862,22 @@ __metadata: languageName: node linkType: hard +"@vue/test-utils@npm:^2.4.1": + version: 2.4.1 + resolution: "@vue/test-utils@npm:2.4.1" + dependencies: + js-beautify: "npm:1.14.9" + vue-component-type-helpers: "npm:1.8.4" + peerDependencies: + "@vue/server-renderer": ^3.0.1 + vue: ^3.0.1 + peerDependenciesMeta: + "@vue/server-renderer": + optional: true + checksum: b3e88b84468c610a62dcea51d5ae089ea299192dd1fc787d69e78c76316b8425cbf1f035a05ab9043cad043c800823df7d76652224bfa713db8d0cf9ec8abb9c + languageName: node + linkType: hard + "@vue/typescript@npm:1.8.15": version: 1.8.15 resolution: "@vue/typescript@npm:1.8.15" @@ -9231,13 +9186,20 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.3.0": +"acorn-walk@npm:^8.1.1": version: 8.3.1 resolution: "acorn-walk@npm:8.3.1" checksum: a23d2f7c6b6cad617f4c77f14dfeb062a239208d61753e9ba808d916c550add92b39535467d2e6028280761ac4f5a904cc9df21530b84d3f834e3edef74ddde5 languageName: node linkType: hard +"acorn-walk@npm:^8.3.2": + version: 8.3.2 + resolution: "acorn-walk@npm:8.3.2" + checksum: 7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52 + languageName: node + linkType: hard + "acorn@npm:^7.1.1, acorn@npm:^7.4.1": version: 7.4.1 resolution: "acorn@npm:7.4.1" @@ -9385,7 +9347,7 @@ __metadata: languageName: node linkType: hard -"ansi-align@npm:^3.0.0": +"ansi-align@npm:^3.0.1": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" dependencies: @@ -10400,19 +10362,19 @@ __metadata: languageName: node linkType: hard -"boxen@npm:^5.1.2": - version: 5.1.2 - resolution: "boxen@npm:5.1.2" +"boxen@npm:^7.1.1": + version: 7.1.1 + resolution: "boxen@npm:7.1.1" dependencies: - ansi-align: "npm:^3.0.0" - camelcase: "npm:^6.2.0" - chalk: "npm:^4.1.0" - cli-boxes: "npm:^2.2.1" - string-width: "npm:^4.2.2" - type-fest: "npm:^0.20.2" - widest-line: "npm:^3.1.0" - wrap-ansi: "npm:^7.0.0" - checksum: 71f31c2eb3dcacd5fce524ae509e0cc90421752e0bfbd0281fd3352871d106c462a0f810c85f2fdb02f3a9fab2d7a84e9718b4999384d651b76104ebe5d2c024 + ansi-align: "npm:^3.0.1" + camelcase: "npm:^7.0.1" + chalk: "npm:^5.2.0" + cli-boxes: "npm:^3.0.0" + string-width: "npm:^5.1.2" + type-fest: "npm:^2.13.0" + widest-line: "npm:^4.0.1" + wrap-ansi: "npm:^8.1.0" + checksum: 3a9891dc98ac40d582c9879e8165628258e2c70420c919e70fff0a53ccc7b42825e73cda6298199b2fbc1f41f5d5b93b492490ad2ae27623bed3897ddb4267f8 languageName: node linkType: hard @@ -11136,10 +11098,10 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.2.0": - version: 6.3.0 - resolution: "camelcase@npm:6.3.0" - checksum: 0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 +"camelcase@npm:^7.0.1": + version: 7.0.1 + resolution: "camelcase@npm:7.0.1" + checksum: 3adfc9a0e96d51b3a2f4efe90a84dad3e206aaa81dfc664f1bd568270e1bf3b010aad31f01db16345b4ffe1910e16ab411c7273a19a859addd1b98ef7cf4cfbd languageName: node linkType: hard @@ -11154,13 +11116,20 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001406, caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": +"caniuse-lite@npm:^1.0.30001538, caniuse-lite@npm:^1.0.30001565": version: 1.0.30001570 resolution: "caniuse-lite@npm:1.0.30001570" checksum: e47230d2016edea56e002fa462a5289f697b48dcfbf703fb01aecc6c98ad4ecaf945ab23c253cb7af056c2d05f266e4e4cbebf45132100e2c9367439cb95b95b languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001579": + version: 1.0.30001581 + resolution: "caniuse-lite@npm:1.0.30001581" + checksum: 34b048156514eab5932212807428905cbecdef918f7c3d2153d5e8b6885d929e5c0b649f9e135cb1e03e413fbad8e00d1f24ed04cbcca52adc660ef98cad9032 + languageName: node + linkType: hard + "case-sensitive-paths-webpack-plugin@npm:^2.4.0": version: 2.4.0 resolution: "case-sensitive-paths-webpack-plugin@npm:2.4.0" @@ -11200,7 +11169,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:5.3.0, chalk@npm:^5.0.0, chalk@npm:^5.3.0": +"chalk@npm:5.3.0, chalk@npm:^5.0.0, chalk@npm:^5.2.0, chalk@npm:^5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" checksum: 8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 @@ -11444,10 +11413,10 @@ __metadata: languageName: node linkType: hard -"cli-boxes@npm:^2.2.1": - version: 2.2.1 - resolution: "cli-boxes@npm:2.2.1" - checksum: 6111352edbb2f62dbc7bfd58f2d534de507afed7f189f13fa894ce5a48badd94b2aa502fda28f1d7dd5f1eb456e7d4033d09a76660013ef50c7f66e7a034f050 +"cli-boxes@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-boxes@npm:3.0.0" + checksum: 4db3e8fbfaf1aac4fb3a6cbe5a2d3fa048bee741a45371b906439b9ffc821c6e626b0f108bdcd3ddf126a4a319409aedcf39a0730573ff050fdd7b6731e99fb9 languageName: node linkType: hard @@ -11754,6 +11723,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^10.0.0": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 + languageName: node + linkType: hard + "commander@npm:^2.18.0, commander@npm:^2.19.0, commander@npm:^2.2.0, commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -11879,6 +11855,16 @@ __metadata: languageName: node linkType: hard +"config-chain@npm:^1.1.13": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" + dependencies: + ini: "npm:^1.3.4" + proto-list: "npm:~1.2.1" + checksum: 39d1df18739d7088736cc75695e98d7087aea43646351b028dfabd5508d79cf6ef4c5bcd90471f52cd87ae470d1c5490c0a8c1a292fbe6ee9ff688061ea0963e + languageName: node + linkType: hard + "confusing-browser-globals@npm:^1.0.10": version: 1.0.11 resolution: "confusing-browser-globals@npm:1.0.11" @@ -12989,6 +12975,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.6.3": + version: 0.6.3 + resolution: "dom-accessibility-api@npm:0.6.3" + checksum: 10bee5aa514b2a9a37c87cd81268db607a2e933a050074abc2f6fa3da9080ebed206a320cbc123567f2c3087d22292853bdfdceaffdd4334ffe2af9510b29360 + languageName: node + linkType: hard + "dom-converter@npm:^0.2.0": version: 0.2.0 resolution: "dom-converter@npm:0.2.0" @@ -13215,6 +13208,20 @@ __metadata: languageName: node linkType: hard +"editorconfig@npm:^1.0.3": + version: 1.0.4 + resolution: "editorconfig@npm:1.0.4" + dependencies: + "@one-ini/wasm": "npm:0.1.1" + commander: "npm:^10.0.0" + minimatch: "npm:9.0.1" + semver: "npm:^7.5.3" + bin: + editorconfig: bin/editorconfig + checksum: ed6985959d7b34a56e1c09bef118758c81c969489b768d152c93689fce8403b0452462e934f665febaba3478eebc0fd41c0a36100783eaadf6d926c4abc87a3d + languageName: node + linkType: hard + "ee-first@npm:1.1.1": version: 1.1.1 resolution: "ee-first@npm:1.1.1" @@ -14205,17 +14212,17 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-storybook@npm:^0.6.15": - version: 0.6.15 - resolution: "eslint-plugin-storybook@npm:0.6.15" +"eslint-plugin-storybook@npm:^0.8.0": + version: 0.8.0 + resolution: "eslint-plugin-storybook@npm:0.8.0" dependencies: "@storybook/csf": "npm:^0.0.1" - "@typescript-eslint/utils": "npm:^5.45.0" - requireindex: "npm:^1.1.0" + "@typescript-eslint/utils": "npm:^5.62.0" + requireindex: "npm:^1.2.0" ts-dedent: "npm:^2.2.0" peerDependencies: eslint: ">=6" - checksum: c61f5f2af72b614c30e8b36644672cfa25ca28e963e5e6cfab438f0cb287a6270f875a2dd8cd600a04c9864b9c549e269d95ea8da88c412e2b868fcd6a3605a4 + checksum: c76f6decdd4c826cd6a8bb613085e0cde804f4648093a0464a39867cc0ba4e1d34be15ff91eed827730da5efbbf55ae5e71af648bb0b461946d5e41384669ab8 languageName: node linkType: hard @@ -16024,7 +16031,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.1": +"glob@npm:^8.0.1, glob@npm:^8.1.0": version: 8.1.0 resolution: "glob@npm:8.1.0" dependencies: @@ -16044,16 +16051,7 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0": - version: 13.22.0 - resolution: "globals@npm:13.22.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: e7fda8fe048a3b4fdfb95602b7dcd87d719f4b3797a6ba7f43e50fe148cfe20edfd3abeb16cc301caf679ca0f3e059b561e2d5060f2133f20f52c85bb16ac394 - languageName: node - linkType: hard - -"globals@npm:^13.6.0": +"globals@npm:^13.19.0, globals@npm:^13.6.0": version: 13.24.0 resolution: "globals@npm:13.24.0" dependencies: @@ -17208,7 +17206,7 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.5, ini@npm:~1.3.0": +"ini@npm:^1.3.4, ini@npm:^1.3.5, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a @@ -17279,6 +17277,13 @@ __metadata: languageName: node linkType: hard +"ip@npm:^2.0.1": + version: 2.0.1 + resolution: "ip@npm:2.0.1" + checksum: cab8eb3e88d0abe23e4724829621ec4c4c5cb41a7f936a2e626c947128c1be16ed543448d42af7cca95379f9892bfcacc1ccd8d09bc7e8bea0e86d492ce33616 + languageName: node + linkType: hard + "ipaddr.js@npm:1.9.1": version: 1.9.1 resolution: "ipaddr.js@npm:1.9.1" @@ -18300,6 +18305,22 @@ __metadata: languageName: node linkType: hard +"js-beautify@npm:1.14.9": + version: 1.14.9 + resolution: "js-beautify@npm:1.14.9" + dependencies: + config-chain: "npm:^1.1.13" + editorconfig: "npm:^1.0.3" + glob: "npm:^8.1.0" + nopt: "npm:^6.0.0" + bin: + css-beautify: js/bin/css-beautify.js + html-beautify: js/bin/html-beautify.js + js-beautify: js/bin/js-beautify.js + checksum: be7b968a15fef3b3f906b3f043538aebbe5ce0db60b3b44b9532c93d05790078011b8cf66c9b00b28fdd49ba3b15b098babb22fb4ae75fcf2b7814a6ad4ce12f + languageName: node + linkType: hard + "js-stringify@npm:^1.0.2": version: 1.0.2 resolution: "js-stringify@npm:1.0.2" @@ -18921,20 +18942,13 @@ __metadata: languageName: node linkType: hard -"lines-and-columns@npm:^2.0.3": +"lines-and-columns@npm:^2.0.3, lines-and-columns@npm:~2.0.3": version: 2.0.4 resolution: "lines-and-columns@npm:2.0.4" checksum: 4db28bf065cd7ad897c0700f22d3d0d7c5ed6777e138861c601c496d545340df3fc19e18bd04ff8d95a246a245eb55685b82ca2f8c2ca53a008e9c5316250379 languageName: node linkType: hard -"lines-and-columns@npm:~2.0.3": - version: 2.0.3 - resolution: "lines-and-columns@npm:2.0.3" - checksum: 09525c10010a925b7efe858f1dd3184eeac34f0a9bc34993075ec490efad71e948147746b18e9540279cc87cd44085b038f986903db3de65ffe96d38a7b91c4c - languageName: node - linkType: hard - "lint-staged@npm:^13.2.2": version: 13.3.0 resolution: "lint-staged@npm:13.3.0" @@ -19438,14 +19452,14 @@ __metadata: languageName: node linkType: hard -"magicast@npm:^0.3.2": - version: 0.3.2 - resolution: "magicast@npm:0.3.2" +"magicast@npm:^0.3.3": + version: 0.3.3 + resolution: "magicast@npm:0.3.3" dependencies: - "@babel/parser": "npm:^7.23.3" - "@babel/types": "npm:^7.23.3" + "@babel/parser": "npm:^7.23.6" + "@babel/types": "npm:^7.23.6" source-map-js: "npm:^1.0.2" - checksum: cd157b250d962ccdb313f250509220f10ad63f673d88a0a001d201fd2b2dae90c6c65c4e9b6ce164f05c25c400139715edce750e3e2f41b5a249e29225d6c4fb + checksum: 2eeba19545ac4328433be817bd81fcfa8a517ec67599260541e13ce5ce18b27ff8830f1b87d54a1392d408d1b96e44938bf026920f0110edbdfecc96980919b3 languageName: node linkType: hard @@ -20885,6 +20899,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:9.0.1": + version: 9.0.1 + resolution: "minimatch@npm:9.0.1" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: aa043eb8822210b39888a5d0d28df0017b365af5add9bd522f180d2a6962de1cbbf1bdeacdb1b17f410dc3336bc8d76fb1d3e814cdc65d00c2f68e01f0010096 + languageName: node + linkType: hard + "minimatch@npm:9.0.3, minimatch@npm:^9.0.0, minimatch@npm:^9.0.1, minimatch@npm:^9.0.3": version: 9.0.3 resolution: "minimatch@npm:9.0.3" @@ -21267,27 +21290,26 @@ __metadata: languageName: node linkType: hard -"next@npm:^14.0.2": - version: 14.0.4 - resolution: "next@npm:14.0.4" +"next@npm:^14.1.0": + version: 14.1.0 + resolution: "next@npm:14.1.0" dependencies: - "@next/env": "npm:14.0.4" - "@next/swc-darwin-arm64": "npm:14.0.4" - "@next/swc-darwin-x64": "npm:14.0.4" - "@next/swc-linux-arm64-gnu": "npm:14.0.4" - "@next/swc-linux-arm64-musl": "npm:14.0.4" - "@next/swc-linux-x64-gnu": "npm:14.0.4" - "@next/swc-linux-x64-musl": "npm:14.0.4" - "@next/swc-win32-arm64-msvc": "npm:14.0.4" - "@next/swc-win32-ia32-msvc": "npm:14.0.4" - "@next/swc-win32-x64-msvc": "npm:14.0.4" + "@next/env": "npm:14.1.0" + "@next/swc-darwin-arm64": "npm:14.1.0" + "@next/swc-darwin-x64": "npm:14.1.0" + "@next/swc-linux-arm64-gnu": "npm:14.1.0" + "@next/swc-linux-arm64-musl": "npm:14.1.0" + "@next/swc-linux-x64-gnu": "npm:14.1.0" + "@next/swc-linux-x64-musl": "npm:14.1.0" + "@next/swc-win32-arm64-msvc": "npm:14.1.0" + "@next/swc-win32-ia32-msvc": "npm:14.1.0" + "@next/swc-win32-x64-msvc": "npm:14.1.0" "@swc/helpers": "npm:0.5.2" busboy: "npm:1.6.0" - caniuse-lite: "npm:^1.0.30001406" + caniuse-lite: "npm:^1.0.30001579" graceful-fs: "npm:^4.2.11" postcss: "npm:8.4.31" styled-jsx: "npm:5.1.1" - watchpack: "npm:2.4.0" peerDependencies: "@opentelemetry/api": ^1.1.0 react: ^18.2.0 @@ -21319,7 +21341,7 @@ __metadata: optional: true bin: next: dist/bin/next - checksum: e6c829fd473d8c3605b2b62d15e1bf41e9d90cf59a2c213b4adeadff2846999bc9a653ffef18f6aa13cc9f5d6de02469c222acf5a4184901a4690a4504bd468f + checksum: dbb1ef8d22eec29a9127d28ed46eb34f14e3f7f7b4e4b91dc96027feb4d9ead554a804275484d9a54026e6e55d632d3997561e598c1fb8e8956e77614f39765f languageName: node linkType: hard @@ -23481,6 +23503,13 @@ __metadata: languageName: node linkType: hard +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: b9179f99394ec8a68b8afc817690185f3b03933f7b46ce2e22c1930dc84b60d09f5ad222beab4e59e58c6c039c7f7fcf620397235ef441a356f31f9744010e12 + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" @@ -24956,7 +24985,7 @@ __metadata: languageName: node linkType: hard -"requireindex@npm:^1.1.0, requireindex@npm:^1.2.0": +"requireindex@npm:^1.2.0": version: 1.2.0 resolution: "requireindex@npm:1.2.0" checksum: 7fb42aed73bf8de9acc4d6716cf07acc7fbe180e58729433bafcf702e76e7bb10e54f8266c06bfec62d752e0ac14d50e8758833de539e6f4e2cd642077866153 @@ -26617,7 +26646,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.2, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -27313,7 +27342,7 @@ __metadata: languageName: node linkType: hard -"terser@npm:5.24.0, terser@npm:^5.16.8": +"terser@npm:5.24.0": version: 5.24.0 resolution: "terser@npm:5.24.0" dependencies: @@ -27327,7 +27356,7 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.10.0": +"terser@npm:^5.10.0, terser@npm:^5.16.8": version: 5.26.0 resolution: "terser@npm:5.26.0" dependencies: @@ -27420,10 +27449,10 @@ __metadata: languageName: node linkType: hard -"tinypool@npm:^0.8.1": - version: 0.8.1 - resolution: "tinypool@npm:0.8.1" - checksum: d965c057a1866c9d83716f4e434f7be18b2a067ed3b32cc2de3b3bf34ca1756ac1c35bd04433e2086c8cc2afa75b328e4b17baa6b4e6292dba2ce31cc76770e0 +"tinypool@npm:^0.8.2": + version: 0.8.2 + resolution: "tinypool@npm:0.8.2" + checksum: 8998626614172fc37c394e9a14e701dc437727fc6525488a4d4fd42044a4b2b59d6f076d750cbf5c699f79c58dd4e40599ab09e2f1ae0df4b23516b98c9c3055 languageName: node linkType: hard @@ -28817,9 +28846,9 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:1.0.4": - version: 1.0.4 - resolution: "vite-node@npm:1.0.4" +"vite-node@npm:1.2.2": + version: 1.2.2 + resolution: "vite-node@npm:1.2.2" dependencies: cac: "npm:^6.7.14" debug: "npm:^4.3.4" @@ -28828,7 +28857,7 @@ __metadata: vite: "npm:^5.0.0" bin: vite-node: vite-node.mjs - checksum: 3be4f8045a2c39afb57fdf83450791f872b10f883728eb58495640eed8d370f062a8bf25622afd005be8b375a1b4ac5731ca4fa0ae7c962742acf8f904f7748a + checksum: 39a5b9d9c806a012aab208eee0f59e4e12446ec19a4cf149a6459e7ff86491c289e189fda4f55a63b7e37d713f5edbda0e9efed95af4f7ebefa6d39eee093c0b languageName: node linkType: hard @@ -28971,16 +29000,16 @@ __metadata: languageName: node linkType: hard -"vitest@npm:^1.0.1": - version: 1.0.4 - resolution: "vitest@npm:1.0.4" - dependencies: - "@vitest/expect": "npm:1.0.4" - "@vitest/runner": "npm:1.0.4" - "@vitest/snapshot": "npm:1.0.4" - "@vitest/spy": "npm:1.0.4" - "@vitest/utils": "npm:1.0.4" - acorn-walk: "npm:^8.3.0" +"vitest@npm:^1.2.2": + version: 1.2.2 + resolution: "vitest@npm:1.2.2" + dependencies: + "@vitest/expect": "npm:1.2.2" + "@vitest/runner": "npm:1.2.2" + "@vitest/snapshot": "npm:1.2.2" + "@vitest/spy": "npm:1.2.2" + "@vitest/utils": "npm:1.2.2" + acorn-walk: "npm:^8.3.2" cac: "npm:^6.7.14" chai: "npm:^4.3.10" debug: "npm:^4.3.4" @@ -28992,9 +29021,9 @@ __metadata: std-env: "npm:^3.5.0" strip-literal: "npm:^1.3.0" tinybench: "npm:^2.5.1" - tinypool: "npm:^0.8.1" + tinypool: "npm:^0.8.2" vite: "npm:^5.0.0" - vite-node: "npm:1.0.4" + vite-node: "npm:1.2.2" why-is-node-running: "npm:^2.2.2" peerDependencies: "@edge-runtime/vm": "*" @@ -29018,7 +29047,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 401cd3f7bc716269ed2e4d6304b3377a3957370f9ca1565d0fb328b3eb0017ba627e0357ccf7bf29126750ef312cc9e5319af8b5cfa87c3f746732480bebb813 + checksum: 085cb62146191b32dc98fac1a5b0de6d1c63c44cc1e7946a7d38309dd4135539432ec27b4bfad38ce79736688a0ce20d9b93f58de4ce4a41677cb3c5ca6ad980 languageName: node linkType: hard @@ -29077,6 +29106,13 @@ __metadata: languageName: node linkType: hard +"vue-component-type-helpers@npm:1.8.4": + version: 1.8.4 + resolution: "vue-component-type-helpers@npm:1.8.4" + checksum: b18ffe06e4834e6df2ff08ec1ddff19eb730b6b68a40727f937eb80fcb20bf523c1f8f0884ac17e5d72f4612f34da9dbd4aba9659a34f89e70c73e7e5f818de9 + languageName: node + linkType: hard + "vue-component-type-helpers@npm:latest": version: 1.8.15 resolution: "vue-component-type-helpers@npm:1.8.15" @@ -29278,7 +29314,7 @@ __metadata: languageName: node linkType: hard -"watchpack@npm:2.4.0, watchpack@npm:^2.2.0, watchpack@npm:^2.4.0": +"watchpack@npm:^2.2.0, watchpack@npm:^2.4.0": version: 2.4.0 resolution: "watchpack@npm:2.4.0" dependencies: @@ -29716,12 +29752,12 @@ __metadata: languageName: node linkType: hard -"widest-line@npm:^3.1.0": - version: 3.1.0 - resolution: "widest-line@npm:3.1.0" +"widest-line@npm:^4.0.1": + version: 4.0.1 + resolution: "widest-line@npm:4.0.1" dependencies: - string-width: "npm:^4.0.0" - checksum: b1e623adcfb9df35350dd7fc61295d6d4a1eaa65a406ba39c4b8360045b614af95ad10e05abf704936ed022569be438c4bfa02d6d031863c4166a238c301119f + string-width: "npm:^5.0.1" + checksum: 7da9525ba45eaf3e4ed1a20f3dcb9b85bd9443962450694dae950f4bdd752839747bbc14713522b0b93080007de8e8af677a61a8c2114aa553ad52bde72d0f9c languageName: node linkType: hard @@ -29850,22 +29886,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.13.0, ws@npm:^8.2.3": - version: 8.15.0 - resolution: "ws@npm:8.15.0" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: b778a405b2589ffbf549323e2f404f1f72e372a049d332d2f0b1f33057e9fbb14a05aa474cb156e4584b418cd95edf4297c0ca5263d6519e8009064bf8e0b80d - languageName: node - linkType: hard - -"ws@npm:^8.14.2": +"ws@npm:^8.13.0, ws@npm:^8.14.2, ws@npm:^8.2.3": version: 8.15.1 resolution: "ws@npm:8.15.1" peerDependencies: diff --git a/docs/addons/addon-migration-guide.md b/docs/addons/addon-migration-guide.md index b4547353b98f..8d0087b4fb4a 100644 --- a/docs/addons/addon-migration-guide.md +++ b/docs/addons/addon-migration-guide.md @@ -1,8 +1,8 @@ --- -title: Addon migration guide for Storybook 7.0 +title: Addon migration guide for Storybook 8.0 --- -Storybook 7 is our first major release in over two years. While Storybook’s addon API has not changed much in the past couple of years, addons require several changes for compatibility with Storybook 7. This guide will walk you through the upgrade process. +We deeply appreciate the dedication and effort addon creators put into keeping the Storybook ecosystem vibrant and up-to-date. As Storybook evolves to version 8.0, bringing new features and improvements, this guide is here to assist you in migrating your addons from 7.x to 8.0. If you need to migrate your addon from an earlier version of Storybook, please first refer to the [Addon migration guide for Storybook 7.0](https://storybook.js.org/docs/7.6/addons/addon-migration-guide). @@ -10,68 +10,57 @@ As we gather feedback from the community, we’ll update this page. We also have -## Dependencies +## Updating dependencies -The first thing to do is upgrade any Storybook dependencies in your project. We release the next version of all our packages on the `next` npm tag, so the easiest thing is to reference that in your `package.json`: +Begin by updating your Storybook dependencies. Use the `next` tag for pre-release versions, `latest` for the most recent stable release, or specify the version directly. ```json { "dependencies": { - "@storybook/client-logger": "next" + "@storybook/client-logger": "next" // or "latest", or "^8.0.0" } } ``` -If you'd rather depend on the latest version of Storybook, you can use the `latest` tag: +## Key changes for addons -```json -{ - "dependencies": { - "@storybook/client-logger": "latest" - } -} -``` +Here are the essential changes in version 8.0 that impact addon development. Please check the [full migration note](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-7x-to-800) for an exhaustive list of changes in 8.0. -Or use a version specifier: +### Node.js 16 support dropped -```json -{ - "dependencies": { - "@storybook/client-logger": "^7.0.0" - } -} -``` +Please upgrade your addon to Node.js 18, as support for Node.js 16 has ended. -## Breaking changes +### React 18 for manager UI -### `@storybook/addons` has been split into `@storybook/manager-api` and `@storybook/preview-api` +UI injected into panels, tools, etc. by addons is now rendered with React 18. Also note that the `key` prop is no longer passed to the render function. -The default export from `@storybook/addons` can now be used via named imports from `@storybook/manager-api` and `@storybook/preview-api`, depending on which environment you need the API from. The manager is the Storybook UI and includes your addon's Addon Panel. While the preview is used to render stories and includes your addon's decorators. +### @storybook/components deprecations -You 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`. If you use any of these packages, please import what you need from `@storybook/preview-api` instead. +`Icons` component from `@storybook/components` is now deprecated in favor of [`@storybook/icons`](https://github.com/storybookjs/icons). Additionally, various `Button` component props are also deprecated, with alternatives provided. -### Some components were moved from `@storybook/components` to a new package `@storybook/blocks` +### Storybook layout state API changes -Components like `ColorControl`, `ColorPalette`, `ArgsTable`, `ArgRow`, `TabbedArgsTable`, `SectionRow`, `Source`, AND `Code` were moved into a new package. In Storybook 7.0, they should be imported from `@storybook/blocks` instead. +If you're customizing the Storybook UI configuration with `addons.setConfig({...})`, be aware of [the changes to the layout state API](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#ui-layout-state-has-changed-shape). -```js -// import { ColorControl } from '@storybook/components'; -import { ColorControl } from '@storybook/blocks'; -``` +### Removal of deprecated features -## Deprecations and detailed migrations +Deprecated packages and APIs from 7.0 are now removed in 8.0.Consult the [full migration notes](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecations-which-are-now-removed) for details. Most notably for addons, the removal of the `@storybook/addons` now necessitates a switch to `@storybook/preview-api` and `@storybook/manager-api`. -We’ve also deprecated a few packages and APIs in 7.0. After you’ve made your addon working with 7.0, make sure to check the browser console in a Storybook running your addon. If you’re using deprecated packages, you should see warnings that link to migration instructions. +### Babel-loader removed from webpack -There are more technical details available in the [migration notes for addon authors](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#specific-instructions-for-addon-creators). +Storybook 8 [removes babel-loader from the webpack5 builder](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#removed-babelcore-and-babel-loader-from-storybookbuilder-webpack5). If your addon's preset overrides the `babel()` method, it will break if your users are using SWC to compile their files (which is the new default for Webpack 5-based Storybook projects). -Finally, for an exhaustive list of noteworthy changes in 7.0, check [the full migration notes](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#from-version-65x-to-700). +To solve for both Babel and SWC, the most robust approach is to create an [unplugin](https://github.com/unjs/unplugin) that will work with both Webpack and Vite builders. That will give you full control to run Babel (or whatever you want) on stories and components as they are loaded. -## Releasing +As a workaround, update your documentation to tell users to opt-in to Babel support. This should fix your addon in their project, at the cost of performance: + +```sh +npx storybook@latest add @storybook/addon-webpack5-compiler-babel +``` -You should release a new major version of this addon that supports Storybook 7. If you want to continue making changes that support Storybook 6, you should release a minor or a patch of the previous major version. +## Releasing -We also recommend releasing your own addon using the `next` tag to test it out in projects. +Release a new major version of your addon for Storybook 8.0. We recommend you to continue supporting 7.x with minor or patch versions. We also recommend releasing your own addon using the `next` tag to test it out in projects. ## Support diff --git a/docs/addons/addon-types.md b/docs/addons/addon-types.md index f46e4f41ff03..481640bec3ae 100644 --- a/docs/addons/addon-types.md +++ b/docs/addons/addon-types.md @@ -46,6 +46,10 @@ Use this boilerplate code to add a new `button` to Storybook's Toolbar: +The `match` property allows you to conditionally render your toolbar addon, [based on the current view](./writing-addons.md#conditionally-render-the-addon). + +
+ The `icon` element used in the example loads the icons from the `@storybook/components` package. See [here](../faq.md#what-icons-are-available-for-my-toolbar-or-my-addon) for the list of available icons that you can use.
diff --git a/docs/addons/install-addons.md b/docs/addons/install-addons.md index 33859546e2ea..b12cc34e1186 100644 --- a/docs/addons/install-addons.md +++ b/docs/addons/install-addons.md @@ -2,111 +2,79 @@ title: 'Install addons' --- -Storybook has [hundreds of reusable addons](https://storybook.js.org/addons) that are packaged as NPM modules. Let's walk through how to extend Storybook by installing and registering addons. +Storybook 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. -### Using addons +## Automatic installation -With the exception of preset addons, all addons have the same installation process: install and register. +Storybook includes a [`storybook add`](../api/cli-options.md#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. -For example, to include accessibility testing in Storybook, run the following command to install the necessary addon: +Run 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. -Next, update [`.storybook/main.js|ts`](../configure/index.md#configure-story-rendering) to the following: + - - - - - - - - -Addons may also require addon-specific configuration. Read their respective READMEs. +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. -Now when you run Storybook the accessibility testing addon will be enabled. - -![Storybook addon installed and registered](./storybook-addon-installed-registered.png) - -### Using preset addons +### Manual installation -Storybook preset addons are grouped collections of specific `babel`, `webpack` and `addons` configurations for distinct use cases. Each one with its own set of instructions. Preset addons have a three-step installation process: install, register and optionally configuration. +Storybook addons are always added through the [`addons`](../api/main-config-addons.md) configuration array in [`.storybook/main.js|ts`](../configure/index.md). The following example shows how to manually add the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) to Storybook. -For example, to use SCSS styling, run the following command to install the addon and the required dependencies: +Run the following command with your package manager of choice to install the addon. - - -Use the Webpack 5 snippet only if your framework already includes support for this version. Otherwise, use the Webpack 4 snippet. - - - -Next, update [`.storybook/main.js|ts`](../configure/index.md#configure-story-rendering) to the following: +Next, update `.storybook/main.js|ts` to the following: -Now when you run Storybook it will configure itself to use SCSS styling. No further configuration is needed. - -#### Optional configuration +When you run Storybook, the accessibility testing addon will be enabled. -Most preset addons can also take additional parameters. The most common use cases are: +![Storybook addon installed and registered](./storybook-addon-installed-registered.png) -- Addon configuration -- Webpack loader configuration +### Removing addons -Consider the following example: +To 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.md)) or opt-in to do it automatically via the CLI with the [`remove`](../api/cli-options.md#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: - - - -Preset addons may also have addon-specific configurations. Read their respective READMEs. - - - -Now, when Storybook starts up, it will update webpack's CSS loader to use modules and adjust how styling is defined. diff --git a/docs/addons/writing-addons.md b/docs/addons/writing-addons.md index dd99775dbdd5..a8fc35a4042e 100644 --- a/docs/addons/writing-addons.md +++ b/docs/addons/writing-addons.md @@ -97,11 +97,13 @@ Going through the code blocks in sequence: // src/Tool.tsx import { useGlobals, useStorybookApi } from '@storybook/manager-api'; - -import { Icons, IconButton } from '@storybook/components'; +import { IconButton } from '@storybook/components'; +import { LightningIcon } from '@storybook/icons'; ``` -The [`useGlobals`](./addons-api.md#useglobals) and [`useStorybookApi`](./addons-api.md#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. The `Icons` and `IconButtons` components from the [`@storybook/components`](https://www.npmjs.com/package/@storybook/components) package render the icons and buttons in the toolbar. +The [`useGlobals`](./addons-api.md#useglobals) and [`useStorybookApi`](./addons-api.md#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. + +The `IconButton` or `Button` component from the [`@storybook/components`](https://www.npmjs.com/package/@storybook/components) package 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. ```ts // src/Tool.tsx @@ -129,12 +131,7 @@ export const Tool = memo(function MyAddonSelector() { }, [toggleMyTool, api]); return ( - + ); @@ -155,7 +152,14 @@ Moving onto the manager, here we register the addon with Storybook using a uniqu -Notice the `match` property. It allows you to control the view mode where the addon is visible. If you only want to show it in a single mode, you must adjust the property to match the specific mode you aim for. In this case, it will be available in both story and documentation. +### Conditionally render the addon + +Notice the `match` property. It allows you to control the view mode (story or docs) and tab (the story canvas or [custom tabs](./addon-types.md#tabs)) where the toolbar addon is visible. For example: + +- `({ tabId }) => tabId === 'my-addon/tab'` will show your addon when viewing the tab with the ID `my-addon/tab`. +- `({ viewMode }) => viewMode === 'story'` will show your addon when viewing a story in the canvas. +- `({ viewMode }) => viewMode === 'docs'` will show your addon when viewing the documentation for a component. +- `({ 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`). Run the `start` script to build and start Storybook and verify that the addon is registered correctly and showing in the UI. diff --git a/docs/api/arg-types.md b/docs/api/arg-types.md index 555462c1354f..ed9f66b4cdd0 100644 --- a/docs/api/arg-types.md +++ b/docs/api/arg-types.md @@ -16,13 +16,13 @@ If you are using the Storybook [docs](../writing-docs/index.md) addon (installed To do so, Storybook uses various static analysis tools depending on your framework. -| Framework | Static analysis tool | -| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -| React | [react-docgen](https://github.com/reactjs/react-docgen) or [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript) | -| Vue | [vue-docgen-api](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api) | -| Angular | [compodoc](https://compodoc.app/) | -| WebComponents | [custom-element.json](https://github.com/webcomponents/custom-elements-json) | -| Ember | [YUI doc](https://github.com/ember-learn/ember-cli-addon-docs-yuidoc#documenting-components) | +| Framework | Static analysis tool | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| React | [react-docgen](https://github.com/reactjs/react-docgen) (default) or [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript) | +| Vue | [vue-docgen-api](https://github.com/vue-styleguidist/vue-styleguidist/tree/dev/packages/vue-docgen-api) | +| Angular | [compodoc](https://compodoc.app/) | +| WebComponents | [custom-element.json](https://github.com/webcomponents/custom-elements-json) | +| Ember | [YUI doc](https://github.com/ember-learn/ember-cli-addon-docs-yuidoc#documenting-components) | The data structure of `argTypes` is designed to match the output of the these tools. Properties specified manually will override what is inferred. diff --git a/docs/api/cli-options.md b/docs/api/cli-options.md index ee164e45e499..ad8292dfad31 100644 --- a/docs/api/cli-options.md +++ b/docs/api/cli-options.md @@ -14,9 +14,15 @@ Storybook collects completely anonymous data to help us improve user experience. All of the following documentation is available in the CLI by running `storybook --help`. + + +Passing options to these commands works slightly differently if you're using npm instead of Yarn. You must prefix all of your options with `--`. For example, `npm run storybook build -- -o ./path/to/build --quiet`. + + + ### `dev` -Compiles and serves a development build of your Storybook that reflects your source code changes in the browser in real time. Should be run from the root of your project. +Compiles 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. ```shell storybook dev [options] @@ -52,7 +58,7 @@ With the release of Storybook 8, the `-s` CLI flag was removed. We recommend usi ### `build` -Compiles your Storybook instance so it can be [deployed](../sharing/publish-storybook.md). Should be run from the root of your project. +Compiles your Storybook instance so it can be [deployed](../sharing/publish-storybook.md). It should be run from the root of your project. ```shell storybook build [options] @@ -74,8 +80,152 @@ Options include: | `--disable-telemetry` | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.md).
`storybook build --disable-telemetry` | | `--test` | Optimize Storybook's production build for performance and tests by removing unnecessary features with the `test` option. Learn more [here](../api/main-config-build.md).
`storybook build --test` | - + + +### `init` + +Installs and initializes the specified version (e.g., `@latest`, `@8`, `@next`) of Storybook into your project. Read more in the [installation guide](../get-started/install.md). + +```shell +storybook[@version] init [options] +``` + +For example, `storybook@latest init` will install the latest version of Storybook into your project. + +Options include: + +| Option | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `-b`, `--builder` | Defines the [builder](../builders/index.md) to use for your Storybook instance
`storybook init --builder webpack5` | +| `-f`,`--force` | Forcefully installs Storybook into your project, prompting you to overwrite existing files
`storybook init --force` | +| `-s`, `--skip-install` | Skips the dependency installation step. Used only when you need to configure Storybook manually
`storybook init --skip-install` | +| `-t`, `--type` | Defines the [framework](../configure/frameworks.md) to use for your Storybook instance
`storybook init --type solid` | +| `-y`, `--yes` | Skips interactive prompts and automatically installs Storybook per specified version
`storybook init --yes` | +| `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook init --package-manager pnpm` | +| `--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
`storybook init --use-pnp` | + +### `add` + +Installs a Storybook addon and configures your project for it. Read more in the [addon installation guide](../addons/install-addons.md). + +```shell +storybook add [addon] [options] +``` + +Options include: + +| Option | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook add [addon] --package-manager pnpm` | +| `-s`, `--skip-postinstall` | Skips post-install configuration. Used only when you need to configure the addon yourself
`storybook add [addon] --skip-postinstall` | + +### `remove` + +Deletes a Storybook addon from your project. Read more in the [addon installation guide](../addons/install-addons.md#removing-addons). + +```shell +storybook remove [addon] [options] +``` + +Options include: + +| Option | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--package-manager` | Sets the package manager to use when removing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook remove [addon]--package-manager pnpm` | + +### `upgrade` + +Upgrades your Storybook instance to the specified version (e.g., `@latest`, `@8`, `@next`). Read more in the [upgrade guide](../configure/upgrading.md). + +```shell +storybook[@version] upgrade [options] +``` + +For example, `storybook@latest upgrade --dry-run` will perform a dry run (no actual changes) of upgrading your project to the latest version of Storybook. + +Options include: + +| Option | Description | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `-c`, `--config-dir` | Directory where to load Storybook configurations from
`storybook upgrade --config-dir .storybook` | +| `-n`, `--dry-run` | Checks for version upgrades without installing them
`storybook upgrade --dry-run` | +| `-s`, `--skip-check` | Skips the migration check step during the upgrade process
`storybook upgrade --skip-check` | +| `-y`, `--yes` | Skips interactive prompts and automatically upgrades Storybook to the latest version
`storybook upgrade --yes` | +| `--package-manager` | Sets the package manager to use when installing the addon.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook upgrade --package-manager pnpm` | + +### `doctor` + +Performs 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](../configure/upgrading.md#verifying-the-upgrade) Storybook versions. + +```shell +storybook doctor [options] +``` + +Options include: + +| Option | Description | +| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `-c`, `--config-dir` | Directory where to load Storybook configurations from
`storybook doctor --config-dir .storybook` | +| `--package-manager` | Sets the package manager to use when running the health check.
Available package managers include `npm`, `yarn`, and `pnpm`
`storybook doctor --package-manager pnpm` | + +### `info` + +Reports useful debugging information about your environment. Helpful in providing information when opening an issue or a discussion. + +```shell +storybook info +``` + +Example output: + +```shell +Storybook Environment Info: + + System: + OS: macOS 14.2 + CPU: (8) arm64 Apple M3 + Shell: 5.9 - /bin/zsh + Binaries: + Node: 18.19.0 - ~/.nvm/versions/node/v18.19.0/bin/node + npm: 10.2.3 - ~/.nvm/versions/node/v18.19.0/bin/npm <----- active + Browsers: + Chrome: 120.0.6099.199 + npmPackages: + @storybook/addon-essentials: ^7.6.6 => 7.6.6 + @storybook/addon-interactions: ^7.6.6 => 7.6.6 + @storybook/addon-links: ^7.6.6 => 7.6.6 + @storybook/addon-onboarding: ^1.0.10 => 1.0.10 + @storybook/blocks: ^7.6.6 => 7.6.6 + @storybook/preset-create-react-app: ^7.6.6 => 7.6.6 + @storybook/react: ^7.6.6 => 7.6.6 + @storybook/react-webpack5: ^7.6.6 => 7.6.6 + @storybook/test: ^7.6.6 => 7.6.6 + storybook: ^7.6.6 => 7.6.6 + npmGlobalPackages: + chromatic: ^10.2.0 => 10.2.0 +``` + +### `sandbox` + +Generates 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/frameworks.md). Useful for reproducing bugs when opening an issue or a discussion. + +```shell +storybook[@version] sandbox [framework-filter] [options] +``` + +For example, `storybook@next sandbox` will generated sandboxes using the newest pre-release version of Storybook. + +The `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. + +Options include: + +| Option | Description | +| --------------------------- | ---------------------------------------------------------------------------------------------------- | +| `-o`, `--output [dir-name]` | Configures the location of the sandbox project
`storybook sandbox --output /my-sandbox-project` | +| `--no-init` | Generates a sandbox project without without initializing Storybook
`storybook sandbox --no-init` | + + -If you're using npm instead of yarn to publish Storybook, the commands work slightly different. For example, `npm run storybook build -- -o ./path/to/build`. +If you're looking for a hosted version of the available sandboxes, see [storybook.new](https://storybook.new). diff --git a/docs/api/csf.md b/docs/api/csf.md index d5ed3eb7ec40..5ddbab04d894 100644 --- a/docs/api/csf.md +++ b/docs/api/csf.md @@ -8,14 +8,12 @@ Component Story Format (CSF) is the recommended way to [write stories](../writin -If you are writing stories in the older `storiesOf()` syntax, you can find documentation in an [advanced README](https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/docs/storiesOf.md). +If you have stories written in the older `storiesOf()` syntax, it was removed in Storybook 8.0 and is no longer maintained. We recommend migrating your stories to CSF. See the [migration guide](../migration-guide.md#storiesof-to-csf) for more information. In 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). -CSF is supported in all frameworks except React Native, where you should use the [storiesOf API](https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/docs/storiesOf.md) instead. - ## Default export The 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.md#sorting-stories)), [decorators](../writing-stories/decorators.md), and [parameters](../writing-stories/parameters.md). @@ -108,8 +106,6 @@ Consider Storybook’s ["Button" example](../writing-stories/index.md#defining-s paths={[ 'react/button-story-click-handler.js.mdx', 'react/button-story-click-handler.ts.mdx', - 'vue/button-story-click-handler.2.js.mdx', - 'vue/button-story-click-handler.2.ts.mdx', 'vue/button-story-click-handler.3.js.mdx', 'vue/button-story-click-handler.3.ts.mdx', 'svelte/button-story-click-handler.js.mdx', @@ -134,8 +130,6 @@ Now consider the same example, re-written with args: paths={[ 'react/button-story-click-handler-args.js.mdx', 'react/button-story-click-handler-args.ts.mdx', - 'vue/button-story-click-handler-args.2.js.mdx', - 'vue/button-story-click-handler-args.2.ts.mdx', 'vue/button-story-click-handler-args.3.js.mdx', 'vue/button-story-click-handler-args.3.ts.mdx', 'angular/button-story-click-handler-args.ts.mdx', @@ -318,8 +312,6 @@ In CSF 2, the named exports are always functions that instantiate a component, a paths={[ 'react/csf-2-example-starter.js.mdx', 'react/csf-2-example-starter.ts.mdx', - 'vue/csf-2-example-starter.2.js.mdx', - 'vue/csf-2-example-starter.2.ts.mdx', 'vue/csf-2-example-starter.3.js.mdx', 'vue/csf-2-example-starter.3.ts.mdx', 'angular/csf-2-example-starter.ts.mdx', @@ -404,8 +396,6 @@ Let's start with a simple CSF 2 story function: paths={[ 'react/csf-2-example-story.js.mdx', 'react/csf-2-example-story.ts.mdx', - 'vue/csf-2-example-story.2.js.mdx', - 'vue/csf-2-example-story.2.ts.mdx', 'vue/csf-2-example-story.3.js.mdx', 'vue/csf-2-example-story.3.ts.mdx', 'angular/csf-2-example-story.ts.mdx', @@ -428,8 +418,6 @@ Now, let's rewrite it as a story object in CSF 3 with an explicit `render` funct paths={[ 'react/csf-3-example-render.js.mdx', 'react/csf-3-example-render.ts.mdx', - 'vue/csf-3-example-render.2.js.mdx', - 'vue/csf-3-example-render.2.ts.mdx', 'vue/csf-3-example-render.3.js.mdx', 'vue/csf-3-example-render.3.ts.mdx', 'angular/csf-3-example-render.ts.mdx', diff --git a/docs/api/doc-block-canvas.md b/docs/api/doc-block-canvas.md index 4deda4611680..ad84f57929bc 100644 --- a/docs/api/doc-block-canvas.md +++ b/docs/api/doc-block-canvas.md @@ -203,51 +203,3 @@ Type: `boolean` Default: `parameters.docs.canvas.withToolbar` Determines whether to render a toolbar containing tools to interact with the story. - -### `children` - -(⛔️ **Deprecated**) - -Type: `React.ReactNode` - -Expects only [Story](./doc-block-story.md) children. Reference the story with the `of` prop instead. - -### `columns` - -(⛔️ **Deprecated**) - -Type: `number` - -Splits the stories based on the number of defined columns. Multiple stories are not supported. - -### `isColumn` - -(⛔️ **Deprecated**) - -Type: `boolean` - -Displays the stories one above the other. Multiple stories are not supported. - -### `mdxSource` - -(⛔️ **Deprecated**) - -Type: `string` - -Provides source to display. Use [`source.code`](#source) instead. - -### `withSource` - -(⛔️ **Deprecated**) - -Type: `'open' | 'closed' | 'none'` - -Controls the source code block visibility. Use [`sourceState`](#sourcestate) instead. - -### `withToolbar` - -(⛔️ **Deprecated**) - -Type: `boolean` - -Sets the Canvas toolbar visibility. Use [`story.withToolbar`](#story) instead. diff --git a/docs/api/doc-block-markdown.md b/docs/api/doc-block-markdown.md index 8e05ca60d08a..e37ba196ee97 100644 --- a/docs/api/doc-block-markdown.md +++ b/docs/api/doc-block-markdown.md @@ -24,6 +24,8 @@ import { Button } from "@storybook/design-system"; ```md + + // DON'T do this, will error import ReadMe from './README.md'; // DO this, will work diff --git a/docs/api/index.md b/docs/api/index.md index 168f0d0456a4..60edd614c32c 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -82,7 +82,7 @@ An overview of all available API references for Storybook. Parameters - Parameters are static metadata used to configure your stories addons in Storybook. They are specified at the story, meta (component), project (global) levels. + Parameters are static metadata used to configure your stories addons in Storybook. They are specified at the story, meta (component), project (global) levels. diff --git a/docs/api/main-config-config.md b/docs/api/main-config-config.md deleted file mode 100644 index 326f28f9ace7..000000000000 --- a/docs/api/main-config-config.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: 'config' ---- - -(⛔️ **Deprecated**) - -Parent: [main.js|ts configuration](./main-config.md) - -Type: `string[] | ((config: string[], options: Options) => string[] | Promise)` - -Add additional scripts to run in the story preview. Deprecated in favor of [`previewAnnotations`](./main-config-preview-annotations.md). diff --git a/docs/api/main-config-swc.md b/docs/api/main-config-swc.md index 0a102bf0cf13..2bb867033572 100644 --- a/docs/api/main-config-swc.md +++ b/docs/api/main-config-swc.md @@ -6,7 +6,7 @@ Parent: [main.js|ts configuration](./main-config.md) Type: `(config: swc.Options, options: Options) => swc.Options | Promise` -Customize Storybook's [SWC](https://swc.rs/) setup. +Customize 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/frameworks.md), except Angular, Create React App, Ember.js and Next.js. diff --git a/docs/api/main-config-typescript.md b/docs/api/main-config-typescript.md index ae25c4fb308a..9af77907c54c 100644 --- a/docs/api/main-config-typescript.md +++ b/docs/api/main-config-typescript.md @@ -6,15 +6,32 @@ Parent: [main.js|ts configuration](./main-config.md) Type: + + ```ts { check?: boolean; checkOptions?: CheckOptions; reactDocgen?: 'react-docgen' | 'react-docgen-typescript' | false; reactDocgenTypescriptOptions?: ReactDocgenTypescriptOptions; + skipCompiler?: boolean; } ``` + + + + +```ts +{ + check?: boolean; + checkOptions?: CheckOptions; + skipCompiler?: boolean; +} +``` + + + Configures how Storybook handles [TypeScript files](../configure/typescript.md). ## `check` @@ -49,6 +66,8 @@ Options to pass to `fork-ts-checker-webpack-plugin`, if [enabled](#check). See [ + + ## `reactDocgen` Type: `'react-docgen' | 'react-docgen-typescript' | false` @@ -58,13 +77,13 @@ Default: - `false`: if `@storybook/react` is not installed - `'react-docgen'`: if `@storybook/react` is installed -Only available for React Storybook projects. Configure 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. +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. @@ -74,18 +93,20 @@ Only available for React Storybook projects. Configure which library, if any, St Type: `ReactDocgenTypescriptOptions` -Only available for React Storybook projects. Options to pass to react-docgen-typescript-plugin if react-docgen-typescript is enabled. See [docs for available options](https://github.com/hipstersmoothie/react-docgen-typescript-plugin). +Configures the options to pass to `react-docgen-typescript-plugin` if `react-docgen-typescript` is enabled. See [docs for available options](https://github.com/hipstersmoothie/react-docgen-typescript-plugin). + + ## `skipCompiler` Type: `boolean` diff --git a/docs/api/main-config.md b/docs/api/main-config.md index 51fc0888aff4..a9013268e45c 100644 --- a/docs/api/main-config.md +++ b/docs/api/main-config.md @@ -47,4 +47,3 @@ An object to configure Storybook containing the following properties: - [`typescript`](./main-config-typescript.md) - [`viteFinal`](./main-config-vite-final.md) - [`webpackFinal`](./main-config-webpack-final.md) -- [`config`](./main-config-config.md) (⛔️ Deprecated) diff --git a/docs/api/parameters.md b/docs/api/parameters.md index 53174e387492..506dc051b3df 100644 --- a/docs/api/parameters.md +++ b/docs/api/parameters.md @@ -2,7 +2,7 @@ title: 'Parameters' --- -Parameters are static metadata used to configure your [stories](../get-started/whats-a-story.md) and [addons](../addons/introduction.md) in Storybook. They are specified at the story, meta (component), project (global) levels. +Parameters are static metadata used to configure your [stories](../get-started/whats-a-story.md) and [addons](../addons/index.md) in Storybook. They are specified at the story, meta (component), project (global) levels. ## Story parameters @@ -36,7 +36,7 @@ Parameters specified at the story level apply to that story only. They are defin
-Parameter's specified in a [CSF](../writing-stories/introduction.md#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` (default export): +Parameter's specified in a [CSF](../writing-stories/index.md#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` (default export): @@ -145,7 +145,7 @@ See [the guide](../writing-stories/naming-components-and-hierarchy/#sorting-stor ### Essential addons -All other parameters are contributed by addons. The [essential addon's](../addons/essentials.md) parameters are documented on their individual pages: +All other parameters are contributed by addons. The [essential addon's](../essentials/index.md) parameters are documented on their individual pages: - [Actions](../essentials/actions.md#parameters) - [Backgrounds](../essentials/backgrounds.md#parameters) diff --git a/docs/builders/vite.md b/docs/builders/vite.md index e8d722777e7d..a254e7b5f7a0 100644 --- a/docs/builders/vite.md +++ b/docs/builders/vite.md @@ -114,7 +114,7 @@ If you need to override it, you can use the `viteFinal` function and adjust it. ### ArgTypes are not generated automatically -Currently, [automatic argType inference](../api/arg-types.md#automatic-argtype-inference) is only available for React, Vue3 and Svelte (JSDocs only). With React, the Vite builder defaults to `react-docgen-typescript` if TypeScript is listed as a dependency. If you run into any issues, you can revert to `react-docgen` by updating your Storybook configuration file as follows: +Currently, [automatic argType inference](../api/arg-types.md#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: diff --git a/docs/configure/compilers.md b/docs/configure/compilers.md index 803237b8b725..2019398344c1 100644 --- a/docs/configure/compilers.md +++ b/docs/configure/compilers.md @@ -6,18 +6,7 @@ Javascript compilers are essential in optimizing and transforming code, enhancin ## SWC -SWC 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.md), except Angular, it will automatically use SWC as its default, providing you with faster loading time. However, if you're upgrading from a previous version of Storybook, you may need to opt-in to use SWC by adjusting your Storybook configuration file (i.e., `.storybook/main.js|ts`) as follows: - - - - - - +SWC 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.md), except Angular, Create React App, Ember.js and Next.js, it will automatically use SWC as its default, providing you with faster loading time. diff --git a/docs/configure/frameworks-feature-support.md b/docs/configure/frameworks-feature-support.md index 498d984cabec..7ae41614e248 100644 --- a/docs/configure/frameworks-feature-support.md +++ b/docs/configure/frameworks-feature-support.md @@ -10,51 +10,51 @@ Below is a comprehensive table of what’s supported in which framework integrat Core frameworks have dedicated maintainers or contributors who are responsible for maintaining the integration. As such, you can use most Storybook features in these frameworks. -| | React | Vue | Angular | Web Components | -| ----------------------------------------------------------------------------------------- | ----- | --- | ------- | -------------- | -| **Essentials** | | | | | -| [Actions](../essentials/actions.md) | ✅ | ✅ | ✅ | ✅ | -| [Backgrounds](../essentials/backgrounds.md) | ✅ | ✅ | ✅ | ✅ | -| [Docs](../writing-docs/index.md) | ✅ | ✅ | ✅ | ✅ | -| [Viewport](../essentials/viewport.md) | ✅ | ✅ | ✅ | ✅ | -| [Controls](../essentials/controls.md) | ✅ | ✅ | ✅ | ✅ | -| [Measure](../essentials/measure-and-outline.md#measure-addon) | ✅ | ✅ | ✅ | ✅ | -| [Outline](../essentials/measure-and-outline.md#outline-addon) | ✅ | ✅ | ✅ | ✅ | -| **Addons** | | | | | -| [A11y](../writing-tests/accessibility-testing.md) | ✅ | ✅ | ✅ | ✅ | -| [Interactions](../writing-tests/interaction-testing.md) | ✅ | ✅ | ✅ | ✅ | -| [Test runner](../writing-tests/test-runner.md) | ✅ | ✅ | ✅ | ✅ | -| [Test coverage](../writing-tests/test-coverage.md) | ✅ | ✅ | ✅ | ✅ | -| [CSS resources](https://github.com/storybookjs/addon-cssresources) | ✅ | ✅ | ✅ | ✅ | -| [Design assets](https://github.com/storybookjs/addon-design-assets) | ✅ | ✅ | ✅ | ✅ | -| [Events](https://github.com/storybookjs/addon-events) | ✅ | ✅ | ✅ | ✅ | -| [Google analytics](https://github.com/storybookjs/addon-google-analytics) | ✅ | ✅ | ✅ | ✅ | -| [GraphQL](https://github.com/storybookjs/addon-graphql) | ✅ | | ✅ | | -| [Jest](https://github.com/storybookjs/storybook/tree/next/code/addons/jest) | ✅ | ✅ | ✅ | ✅ | -| [Links](https://github.com/storybookjs/storybook/tree/next/code/addons/links) | ✅ | ✅ | ✅ | ✅ | -| [Queryparams](https://github.com/storybookjs/addon-queryparams) | ✅ | ✅ | ✅ | ✅ | -| [Storysource](https://github.com/storybookjs/storybook/tree/next/code/addons/storysource) | ✅ | ✅ | ✅ | ✅ | -| **Docs** | | | | | -| [CSF Stories](../api/csf.md) | ✅ | ✅ | ✅ | ✅ | -| [Autodocs](../writing-docs/autodocs.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - ArgTypes](../api/doc-block-argtypes.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Canvas](../api/doc-block-canvas.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - ColorPalette](../api/doc-block-colorpalette.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Controls](../api/doc-block-controls.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Description](../api/doc-block-description.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - IconGallery](../api/doc-block-icongallery.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Markdown](../api/doc-block-markdown.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Meta](../api/doc-block-meta.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Primary](../api/doc-block-primary.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Source](../api/doc-block-source.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Story](../api/doc-block-story.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Stories](../api/doc-block-stories.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Subtitle](../api/doc-block-subtitle.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Title](../api/doc-block-title.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Typeset](../api/doc-block-typeset.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - Unstyled](../api/doc-block-unstyled.md) | ✅ | ✅ | ✅ | ✅ | -| [Doc Blocks - UseOf](../api/doc-block-useof.md) | ✅ | ✅ | ✅ | ✅ | -| Inline stories | ✅ | ✅ | ✅ | ✅ | +| | React | Vue 3 | Angular | Web Components | +| ----------------------------------------------------------------------------------------- | ----- | ----- | ------- | -------------- | +| **Essentials** | | | | | +| [Actions](../essentials/actions.md) | ✅ | ✅ | ✅ | ✅ | +| [Backgrounds](../essentials/backgrounds.md) | ✅ | ✅ | ✅ | ✅ | +| [Docs](../writing-docs/index.md) | ✅ | ✅ | ✅ | ✅ | +| [Viewport](../essentials/viewport.md) | ✅ | ✅ | ✅ | ✅ | +| [Controls](../essentials/controls.md) | ✅ | ✅ | ✅ | ✅ | +| [Measure](../essentials/measure-and-outline.md#measure-addon) | ✅ | ✅ | ✅ | ✅ | +| [Outline](../essentials/measure-and-outline.md#outline-addon) | ✅ | ✅ | ✅ | ✅ | +| **Addons** | | | | | +| [A11y](../writing-tests/accessibility-testing.md) | ✅ | ✅ | ✅ | ✅ | +| [Interactions](../writing-tests/interaction-testing.md) | ✅ | ✅ | ✅ | ✅ | +| [Test runner](../writing-tests/test-runner.md) | ✅ | ✅ | ✅ | ✅ | +| [Test coverage](../writing-tests/test-coverage.md) | ✅ | ✅ | ✅ | ✅ | +| [CSS resources](https://github.com/storybookjs/addon-cssresources) | ✅ | ✅ | ✅ | ✅ | +| [Design assets](https://github.com/storybookjs/addon-design-assets) | ✅ | ✅ | ✅ | ✅ | +| [Events](https://github.com/storybookjs/addon-events) | ✅ | ✅ | ✅ | ✅ | +| [Google analytics](https://github.com/storybookjs/addon-google-analytics) | ✅ | ✅ | ✅ | ✅ | +| [GraphQL](https://github.com/storybookjs/addon-graphql) | ✅ | | ✅ | | +| [Jest](https://github.com/storybookjs/storybook/tree/next/code/addons/jest) | ✅ | ✅ | ✅ | ✅ | +| [Links](https://github.com/storybookjs/storybook/tree/next/code/addons/links) | ✅ | ✅ | ✅ | ✅ | +| [Queryparams](https://github.com/storybookjs/addon-queryparams) | ✅ | ✅ | ✅ | ✅ | +| [Storysource](https://github.com/storybookjs/storybook/tree/next/code/addons/storysource) | ✅ | ✅ | ✅ | ✅ | +| **Docs** | | | | | +| [CSF Stories](../api/csf.md) | ✅ | ✅ | ✅ | ✅ | +| [Autodocs](../writing-docs/autodocs.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - ArgTypes](../api/doc-block-argtypes.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Canvas](../api/doc-block-canvas.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - ColorPalette](../api/doc-block-colorpalette.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Controls](../api/doc-block-controls.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Description](../api/doc-block-description.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - IconGallery](../api/doc-block-icongallery.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Markdown](../api/doc-block-markdown.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Meta](../api/doc-block-meta.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Primary](../api/doc-block-primary.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Source](../api/doc-block-source.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Story](../api/doc-block-story.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Stories](../api/doc-block-stories.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Subtitle](../api/doc-block-subtitle.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Title](../api/doc-block-title.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Typeset](../api/doc-block-typeset.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - Unstyled](../api/doc-block-unstyled.md) | ✅ | ✅ | ✅ | ✅ | +| [Doc Blocks - UseOf](../api/doc-block-useof.md) | ✅ | ✅ | ✅ | ✅ | +| Inline stories | ✅ | ✅ | ✅ | ✅ | ## Community frameworks @@ -110,8 +110,8 @@ Community frameworks have fewer contributors which means they may not be as up t To 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 -| Feature | Status | -| -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [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.md) instead. | -| [Storyshots](../writing-tests/snapshot-testing.md) | 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](../writing-tests/storyshots-migration-guide.md) for the available alternatives. | -| [`StoriesOf`](https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/docs/storiesOf.md) | The `storiesOf` API was officially deprecated with the release of Storybook 7.5 and is no longer actively maintained. We recommend using the [CSF API](../api/csf.md) instead for writing stories.
See the [migration guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storystorev6-and-storiesof-is-deprecated) for more information. | +| Feature | Status | +| -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [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.md) instead. | +| [Storyshots](../writing-tests/snapshot-testing.md) | 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](../writing-tests/storyshots-migration-guide.md) for the available alternatives. | +| [`StoriesOf`](https://github.com/storybookjs/storybook/blob/next/code/lib/preview-api/docs/storiesOf.md) | 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.md) instead for writing stories.
See the [migration guide](../migration-guide.md#storiesof-to-csf) for more information. | diff --git a/docs/configure/frameworks.md b/docs/configure/frameworks.md index 6c38d3f7abc3..67191e8d2311 100644 --- a/docs/configure/frameworks.md +++ b/docs/configure/frameworks.md @@ -12,10 +12,10 @@ You start by [installing](../get-started/install.md) Storybook into an existing Storybook 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. -| Builder | Framework | -| ------- | ------------------------------------------------------------------------ | -| Webpack | React, Angular, Vue, Web Components, NextJS, HTML, Ember, Preact, Svelte | -| Vite | React, Vue, Web Components, HTML, Svelte, SvelteKit, Qwik, Solid | +| Builder | Framework | +| ------- | -------------------------------------------------------------------------- | +| Webpack | React, Angular, Vue 3, Web Components, NextJS, HTML, Ember, Preact, Svelte | +| Vite | React, Vue 3, Web Components, HTML, Svelte, SvelteKit, Qwik, Solid | ### What about feature support? diff --git a/docs/configure/images-and-assets.md b/docs/configure/images-and-assets.md index 3ff5ad2f899d..77ffed4231db 100644 --- a/docs/configure/images-and-assets.md +++ b/docs/configure/images-and-assets.md @@ -16,8 +16,6 @@ Afterward, you can use any asset in your stories: paths={[ 'react/component-story-static-asset-with-import.js.mdx', 'react/component-story-static-asset-with-import.ts.mdx', - 'vue/component-story-static-asset-with-import.2.js.mdx', - 'vue/component-story-static-asset-with-import.2.ts.mdx', 'vue/component-story-static-asset-with-import.3.js.mdx', 'vue/component-story-static-asset-with-import.3.ts.mdx', 'angular/component-story-static-asset-with-import.ts.mdx', diff --git a/docs/configure/telemetry.md b/docs/configure/telemetry.md index 859d339a7fb0..ff3298ac86fd 100644 --- a/docs/configure/telemetry.md +++ b/docs/configure/telemetry.md @@ -8,7 +8,7 @@ Storybook collects completely anonymous data to help us improve user experience. Hundreds of thousands of developers use Storybook daily to build, test, and document components. Storybook is framework agnostic and integrates with the front-end ecosystem: -- **JavaScript frameworks** such as [React](https://reactjs.org/), [Vue](https://vuejs.org/), [Svelte](https://svelte.dev/) and [Solid](https://www.solidjs.com/) +- **JavaScript frameworks** such as [React](https://reactjs.org/), [Vue 3](https://vuejs.org/), [Svelte](https://svelte.dev/) and [Solid](https://www.solidjs.com/) - **Libraries** such as [Styled-Components](https://styled-components.com/), [Tailwind](https://tailwindcss.com/), [Redux](https://redux.js.org/) - **Design tools** such as [Figma](https://figma.com/), [Sketch](https://www.sketch.com/), [Zeplin](https://zeplin.io/) and [InVision](https://www.invisionapp.com/) - **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) @@ -31,7 +31,7 @@ Specifically, we track the following information in our telemetry events: - Storybook version. - Storybook metadata: - Language (e.g., TypeScript, JavaScript). - - Supported view layers (e.g., React, Vue, Angular, Svelte). + - Supported view layers (e.g., React, Vue 3, Angular, Svelte). - Builder (e.g., Webpack5, Vite). - Meta framework (e.g., [Next](https://nextjs.org/), [Gatsby](https://www.gatsbyjs.com/), [CRA](https://create-react-app.dev/)). - [Addons](https://storybook.js.org/integrations) (e.g., [Essentials](../essentials/index.md), [Accessibility](https://storybook.js.org/addons/@storybook/addon-a11y/)). diff --git a/docs/configure/typescript.md b/docs/configure/typescript.md index eb789ed833e7..cbbfccd4833d 100644 --- a/docs/configure/typescript.md +++ b/docs/configure/typescript.md @@ -28,20 +28,50 @@ See the Vite builder [TypeScript documentation](https://github.com/storybookjs/b ### Extending the default configuration -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` and `ngx-template-loader` for Angular, `react-docgen-typescript-plugin` for React). If you need to customize the default configuration for a specific use case scenario, refer to the [`config.typescript` API reference](../api/main-config-typescript.md). + -The above example extends the baseline configuration to remove existing props from third-party libraries. Useful if you want to document only your components. However, if you need to include them, you can do so by adjusting your configuration as follows: +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. + +| Option | Description | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `check` | Available for Webpack-based projects.
Enables type checking within Storybook
`typescript: { check: true },` | +| `checkOptions` | Requires the `check` option to be enabled.
Configures the [`fork-ts-checker-webpack-plugin`](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin) plugin
`typescript: { checkOptions:{},},` | +| `skipCompiler` | Disables parsing Typescript files through the compiler
`typescript: { skipCompiler:false,},` | + +
+ + + +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. + +| Option | Description | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `check` | Available for Webpack-based projects.
Enables type checking within Storybook
`typescript: { check: true },` | +| `checkOptions` | Requires the `check` option to be enabled.
Configures the [`fork-ts-checker-webpack-plugin`](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin) plugin
`typescript: { checkOptions: {},},` | +| `reactDocgen` | Configures the TypeScript parser used by Storybook.
Available options: `react-docgen` (default), `react-docgen-typescript`,` false`
`typescript: { reactDocgen: 'react-docgen'},` | +| `reactDocgenTypescriptOptions` | Requires the `reactDocgen`option to be `react-docgen-typescript`.
Configures the `react-docgen-typescript-plugin` plugin per builder
`typescript: { reactDocgen: 'react-docgen-typescript', reactDocgenTypescriptOptions: {},},` | +| `skipCompiler` | Disables parsing Typescript files through the compiler
`typescript: { skipCompiler:false,},` | + +
+ + + +Additional options are available for the `typescript` configuration option. See the [`config.typescript` API reference](../api/main-config-typescript.md) for more information. + + + ## Write stories with TypeScript Storybook 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: @@ -92,6 +122,45 @@ Now, when you define a story or update an existing one, you'll automatically get Out 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). + + ### The TypeScript auto-completion is not working on my editor If you're using Vue single file components and TypeScript, you can add both [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) and the [TypeScript Vue Plugin](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) 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. + + + + + +### Storybook doesn't create the required types for external packages + +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: + + + + + + + + +### The types are not being generated for my component + +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: + + + + + + + +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)). + + diff --git a/docs/configure/upgrading.md b/docs/configure/upgrading.md index c5e57d8d714e..c29b34b86ed8 100644 --- a/docs/configure/upgrading.md +++ b/docs/configure/upgrading.md @@ -16,16 +16,22 @@ To help ease the pain of keeping Storybook up-to-date, we provide a command-line paths={[ 'common/storybook-upgrade.npm.js.mdx', 'common/storybook-upgrade.pnpm.js.mdx', - 'common/storybook-upgrade.yarn.js.mdx' + 'common/storybook-upgrade.yarn.js.mdx', ]} /> -After running the command the script will: +The `upgrade` command will use whichever version you specify. For example: -- Upgrade all Storybook packages in your project to the latest stable version -- Run the relevant [automigrations](../migration-guide.md#automatic-upgrade) factoring in the [breaking changes](../migration-guide.md#major-breaking-changes) between your current version and the latest stable version +- `storybook@latest upgrade` will upgrade to the latest version +- `storybook@7.6.10 upgrade` will upgrade to `7.6.10` +- `storybook@7 upgrade` will upgrade to the newest `7.x.x` version + +After running the command, the script will: + +- Upgrade all Storybook packages in your project to the specified version +- Run the relevant [automigrations](../migration-guide.md#automatic-upgrade) factoring in the [breaking changes](../migration-guide.md#major-breaking-changes) between your current version and the specified version @@ -33,9 +39,25 @@ In addition to running the command, we also recommend checking the [MIGRATION.md +### Verifying the upgrade + +To help you verify that the upgrade was completed and that your project is still working as expected, the Storybook CLI provides the [`doctor`](../api/cli-options.md#doctor) command that allows you to do a health check on your project for common issues that might arise after an upgrade, such as duplicated dependencies, incompatible addons or mismatched versions. To perform the health check, run the following command with your package manager of choice: + + + + + + + ## Automigrate script -Storybook upgrades are not the only thing to consider: changes in the ecosystem also present challenges. For example, lots of frameworks ([Angular 12](https://angular.io/guide/updating-to-version-12#breaking-changes-in-angular-version-12), [Create React App v5](https://github.com/facebook/create-react-app/pull/11201), [NextJS](https://nextjs.org/docs/upgrading#webpack-5)) have recently migrated from [Webpack 4 to Webpack 5](https://webpack.js.org/migrate/5/), so even if you don't upgrade your Storybook version, you might need to update your configuration accordingly. That's what Automigrate is for: +Storybook 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: @@ -43,7 +65,7 @@ Storybook upgrades are not the only thing to consider: changes in the ecosystem paths={[ 'common/storybook-automigrate.npm.js.mdx', 'common/storybook-automigrate.pnpm.js.mdx', - 'common/storybook-automigrate.yarn.js.mdx' + 'common/storybook-automigrate.yarn.js.mdx', ]} /> @@ -69,6 +91,12 @@ To upgrade to the latest pre-release: +The `upgrade` command will use whichever version you specify. For example: + +- `storybook@next upgrade` will upgrade to the newest pre-release version +- `storybook@8.0.0-beta.1 upgrade` will upgrade to `8.0.0-beta.1` +- `storybook@8 upgrade` will upgrade to the newest `8.x` version + If you'd like to downgrade to a stable version, manually edit the package version numbers in your `package.json` and re-install. @@ -76,3 +104,25 @@ If you'd like to downgrade to a stable version, manually edit the package versio Storybook collects completely anonymous data to help us improve user experience. Participation is optional, and you may [opt-out](../configure/telemetry.md#how-to-opt-out) if you'd not like to share any information. + + + +## Troubleshooting + +### Storybook doesn't upgrade to the latest version when using Vue 2 + +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: + + + + + + + + diff --git a/docs/contribute/code.md b/docs/contribute/code.md index b9d246e2119a..5e8d229ae582 100644 --- a/docs/contribute/code.md +++ b/docs/contribute/code.md @@ -108,7 +108,7 @@ Adding a story or set of generic stories to our suite helps you test your work. Assuming you're working on one of the [Essential addons](../essentials/index.md), 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. -If you're modifying something related to a specific renderer (e.g., React, Vue, etc.), it will also have a similar `template/stories` directory in which you'll need to add your stories. +If 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. ### Add tests diff --git a/docs/contribute/framework.md b/docs/contribute/framework.md index f72a7eae9500..f54e19bae401 100644 --- a/docs/contribute/framework.md +++ b/docs/contribute/framework.md @@ -2,7 +2,7 @@ title: 'Contributing a Storybook framework' --- -A 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.md) (Webpack, Vite) plus renderer (React, Angular, Vue, web components, etc). +A 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.md) (Webpack, Vite) plus renderer (React, Angular, Vue 3, web components, etc). For 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. @@ -88,7 +88,7 @@ Because a framework is a node package, it must contain a `package.json` file. He "test": "..." }, "dependencies": { - "@storybook/addons": "^7.0.0", + "@storybook/manager-api": "^7.0.0", "@storybook/core-common": "^7.0.0", "@storybook/node-logger": "^7.0.0", "@storybook/": "^7.0.0", diff --git a/docs/contribute/new-snippets.md b/docs/contribute/new-snippets.md index ca07ff4bfa79..5bc09d844ab4 100644 --- a/docs/contribute/new-snippets.md +++ b/docs/contribute/new-snippets.md @@ -10,7 +10,7 @@ Storybook maintains code snippets for a [variety of frameworks](../configure/fra We welcome community contributions to the code snippets. Here's a matrix of the frameworks we have snippets for. Help us add snippets for your favorite framework. -| React | Vue | Angular | Web Components | Svelte | Solid | Ember | HTML | Preact | +| React | Vue 3 | Angular | Web Components | Svelte | Solid | Ember | HTML | Preact | | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ----- | ---- | ------ | | [✅](https://github.com/storybookjs/storybook/tree/next/docs/snippets/react) | [✅](https://github.com/storybookjs/storybook/tree/next/docs/snippets/vue) | [✅](https://github.com/storybookjs/storybook/tree/next/docs/snippets/angular) | [✅](https://github.com/storybookjs/storybook/tree/next/docs/snippets/web-components) | [✅](https://github.com/storybookjs/storybook/tree/next/docs/snippets/svelte) | [✅](https://github.com/storybookjs/storybook/tree/next/docs/snippets/solid) | ❌ | ❌ | ❌ | @@ -48,7 +48,6 @@ Browse the documentation and look for the code snippets you're willing to contri 'react/your-component.js.mdx', 'react/your-component.ts.mdx', 'angular/your-component.ts.mdx', - 'vue/your-component.2.js.mdx', 'vue/your-component.3.js.mdx', 'svelte/your-component.js.mdx', 'web-components/your-component.js.mdx', @@ -72,7 +71,6 @@ Create the file `ember/your-component.js.mdx`, similar to the other frameworks, 'react/your-component.js.mdx', 'react/your-component.ts.mdx', 'angular/your-component.ts.mdx', - 'vue/your-component.2.js.mdx', 'vue/your-component.3.js.mdx', 'svelte/your-component.js.mdx', 'web-components/your-component.js.mdx', diff --git a/docs/essentials/controls.md b/docs/essentials/controls.md index fcd5ea7f6333..60c950c34d29 100644 --- a/docs/essentials/controls.md +++ b/docs/essentials/controls.md @@ -31,7 +31,49 @@ If you have stories in the older pre-Storybook 6 style, check the [args & contro -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 default export of your story file, and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) for your component using [Compodoc](https://compodoc.app/) if you opt-in to use it, including first-class support for Angular's `inputs`, `outputs`, `properties`, `methods` and `view/content child/children`. +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. + +Run the following command to install the tooling. + + + + + + + +Update your `angular.json` file to include the following configuration to include it in the Storybook's inbuilt builder configuration. + + + + + + + + +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. + + + + + + + + +When you set the `component` annotation of the default export of your story file, it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) for your component. @@ -45,9 +87,57 @@ By default, Storybook will choose a control for each arg based on its initial va + + +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. + +Update your `ember-cli-build.js` configuration file to include the adapter. + + + + + + + +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. + + + + + + + + + +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. + + + +When you set the `component` annotation of the default export of your story file, it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) for your component. + + + + + + + + + -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 default export of your story file and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) for your component using [`react-docgen`](https://github.com/reactjs/react-docgen) or [`react-docgen-typescript`](https://github.com/styleguidist/react-docgen-typescript) for TypeScript. +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 default export of your story file, and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) 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. @@ -79,7 +169,38 @@ By default, Storybook will choose a control for each arg based on its initial va - + + +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. + + + + + + + + +When you set the `component` annotation of the default export of your story file, it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) for your component. + + + + + + + + + + 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 default export of your story file, and it will be used to infer the controls and auto-generate the matching [`argTypes`](../api/arg-types.md) for your component provided by the framework you've chosen to use. @@ -87,17 +208,16 @@ By default, Storybook will choose a control for each arg based on its initial va + + 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). @@ -163,10 +283,10 @@ This replaces the input with a radio group for a more intuitive experience. Controls 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`: -| Control | Default regex | Description | -| :-------: | :--------------------------------------: | :-------------------------------------------------------: | +| Control | Default regex | Description | +| --------- | ---------------------------------------- | --------------------------------------------------------- | | **color** | /(background|color)$/i | Will display a color picker UI for the args that match it | -| **date** | `/Date$/` | Will display a date picker UI for the args that match it | +| **date** | `/Date$/` | Will display a date picker UI for the args that match it | If 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: @@ -195,8 +315,6 @@ Until now, we only used auto-generated controls based on the component for which paths={[ 'react/page-story-slots.js.mdx', 'react/page-story-slots.ts.mdx', - 'vue/page-story-slots.2.js.mdx', - 'vue/page-story-slots.2.ts.mdx', 'vue/page-story-slots.3.js.mdx', 'vue/page-story-slots.3.ts.mdx', 'angular/page-story-slots.ts.mdx', @@ -223,9 +341,9 @@ Using `argTypes`, you can change the display and behavior of each control. ### Dealing with complex values -When 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 addon) and the preview (your story). +When 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., Controls addon) and the preview (your story). -One way to deal with this is to use primitive values (e.g., strings) as arg values and add a custom `render` function to convert these values to their complex counterpart before rendering. It isn't the nicest way to do it (see below), but certainly the most flexible. +One 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. @@ -284,7 +402,7 @@ As shown above, you can configure individual controls with the “control" annot | **number** | `number` | Provides a numeric input to include the range of all possible values.
`argTypes: { even: { control: { type: 'number', min:1, max:30, step: 2 } }}` | | | `range` | Provides a range slider component to include all possible values.
`argTypes: { odd: { control: { type: 'range', min: 1, max: 30, step: 3 } }}` | | **object** | `object` | Provides a JSON-based editor component to handle the object's values.
Also allows edition in raw mode.
`argTypes: { user: { control: 'object' }}` | -| **array** | `object` | Provides a JSON-based editor component to handle the values of the array.
Also allows edition in raw mode.
`argTypes: { odd: { control: 'object' }}` | +| **array** | `object` | Provides a JSON-based editor component to handle the array's values.
Also allows edition in raw mode.
`argTypes: { odd: { control: 'object' }}` | | | `file` | Provides a file input component that returns an array of URLs.
Can be further customized to accept specific file types.
`argTypes: { avatar: { control: { type: 'file', accept: '.png' } }}` | | **enum** | `radio` | Provides a set of radio buttons based on the available options.
`argTypes: { contact: { control: 'radio', options: ['email', 'phone', 'mail'] }}` | | | `inline-radio` | Provides a set of inlined radio buttons based on the available options.
`argTypes: { contact: { control: 'inline-radio', options: ['email', 'phone', 'mail'] }}` | @@ -514,117 +632,13 @@ It may also contain at most one of the following operators: If no operator is provided, that is equivalent to `{ truthy: true }`. - + ## Troubleshooting ### Controls are not automatically generated for my component -Out of the box, 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. However, in some cases, this may not be enough, and you may need to provide additional information to Storybook. To solve this, you can opt-in to use [Compodoc](https://compodoc.app/), a documentation generator for Angular applications that can extract the metadata of your components and generate the required argTypes and controls for your stories. - -Run the following command to install the tooling. - - - - - - - -Update your `angular.json` file to include the following configuration to include it in the Storybook's inbuilt builder configuration. - - - - - - - - -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. - - - - - - - - - - - - -## Troubleshooting - -### Controls are not automatically generated for my component - -Out of the box, 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. However, in some cases, this may not be enough, and you may need to provide additional information to Storybook. To solve this, you can 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) for newer versions and configure it in your Storybook UI configuration file (i.e., `.storybook/preview.js|ts`) to enable it. - - - - - - - - - - - - -## Troubleshooting - -### Controls are not automatically generated for my component - -Out of the box, 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) addon. However, in some cases, this may not be enough, and you may need to customize your project configuration to provide additional information to Storybook to generate the required argTypes and controls for your stories. - -Update your `ember-cli-build.js` configuration file to include the addon. - - - - - - - - -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. - - - - - - - - - - -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. - - +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). @@ -652,13 +666,7 @@ Specifies which properties to exclude from the Controls addon panel. Any propert Type: `boolean` -Show the full documentation, including description and default value, for each property in the Controls addon panel. See [usage example](#show-full-documentation-for-each-property), above. - -#### `hideNoControlsWarning` - -Type: `boolean` - -Hide the warning that appears when no controls are defined for a story. See [usage example](#hide-nocontrols-warning), above. +Show the full documentation for each property in the Controls addon panel, including the description and default value. See [usage example](#show-full-documentation-for-each-property), above. #### `include` @@ -670,7 +678,7 @@ Specifies which properties to include in the Controls addon panel. Any propertie Type: `(string | { color: string; title?: string })[]` -Specify preset color swatches for the color picker control. Color value many be any valid CSS color. See [usage example](#specify-initial-preset-color-swatches), above. +Specify 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. #### `sort` diff --git a/docs/essentials/viewport.md b/docs/essentials/viewport.md index b601ad531c7e..d58b033ea101 100644 --- a/docs/essentials/viewport.md +++ b/docs/essentials/viewport.md @@ -176,9 +176,9 @@ Update your story through [parameters](../writing-stories/parameters.md) to incl ### Keyboard shortcuts -- Previous viewport: shift + v -- Next viewport: v -- Reset viewport: alt + v +- Previous viewport: alt + shift + v +- Next viewport: alt + v +- Reset viewport: alt + control + v If you need, you can edit them on the shortcuts page. @@ -231,7 +231,7 @@ Specify the available viewports. The key is used to reference the viewport and t This addon contributes the following exports to Storybook: ```js -import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from '@storybook/addon-viewports'; +import { INITIAL_VIEWPORTS, MINIMAL_VIEWPORTS } from '@storybook/addon-viewport'; ``` #### `INITIAL_VIEWPORTS` diff --git a/docs/faq.md b/docs/faq.md index 55840449c2fa..6e6ce176787a 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -19,9 +19,9 @@ Here are some answers to frequently asked questions. If you have a question, you - [Is it possible to browse the documentation for past versions of Storybook?](#is-it-possible-to-browse-the-documentation-for-past-versions-of-storybook) - [What icons are available for my toolbar or my addon?](#what-icons-are-available-for-my-toolbar-or-my-addon) - [I see a "No Preview" error with a Storybook production build](#i-see-a-no-preview-error-with-a-storybook-production-build) -- [Can I use Storybook with Vue 3?](#can-i-use-storybook-with-vue-3) +- [Can I use Storybook with Vue 2?](#can-i-use-storybook-with-vue-2) - [Why aren't my code blocks highlighted with Storybook MDX](#why-arent-my-code-blocks-highlighted-with-storybook-mdx) -- [Why aren't my MDX 2 stories working in Storybook?](#why-arent-my-mdx-2-stories-working-in-storybook) +- [Why aren't my MDX stories working in Storybook?](#why-arent-my-mdx-stories-working-in-storybook) - [Why are my mocked GraphQL queries failing with Storybook's MSW addon?](#why-are-my-mocked-graphql-queries-failing-with-storybooks-msw-addon) - [Can I use other GraphQL providers with Storybook's MSW addon?](#can-i-use-other-graphql-providers-with-storybooks-msw-addon) - [Can I mock GraphQL mutations with Storybook's MSW addon?](#can-i-mock-graphql-mutations-with-storybooks-msw-addon) @@ -329,7 +329,6 @@ We're only covering versions 5.3 and 5.0 as they were important milestones for S | | `main.js` configuration/typescript | [See current documentation](./api/main-config-typescript.md) | Non existing feature or undocumented | Non existing feature or undocumented | | | `main.js` configuration/viteFinal | [See current documentation](./api/main-config-vite-final.md) | Non existing feature or undocumented | Non existing feature or undocumented | | | `main.js` configuration/webpackFinal | [See current documentation](./api/main-config-webpack-final.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | `main.js` configuration/config | [See current documentation](./api/main-config-config.md) | Non existing feature or undocumented | Non existing feature or undocumented | | | Frameworks | [See current documentation](./api/new-frameworks.md) | Non existing feature or undocumented | Non existing feature or undocumented | | | CLI options | [See current documentation](./api/cli-options.md) | [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) | @@ -363,17 +362,29 @@ Suppose you don't want to run the command above frequently. Add `http-server` as
-## Can I use Storybook with Vue 3? +## Can I use Storybook with Vue 2? -Yes, with the release of version 6.2, Storybook now includes support for Vue 3. See the [install page](./get-started/install.md) for instructions. +Vue 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: + + + + + + ## Why aren't my code blocks highlighted with Storybook MDX Out 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 and 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. -## Why aren't my MDX 2 stories working in Storybook? +## Why aren't my MDX stories working in Storybook? -MDX 2 introduced some changes to how the code is rendered. For example, if you enabled it in your Storybook and you have the following code block: +MDX can be picky about how your code is formatted with line breaks. This is especially true with code blocks. For example, this will break: ``` + + + ); +} + +export default HelloWorld; +``` + +You can use your own babel config too. This is an example of how you can customize styled-jsx. + +```json +// .babelrc (or whatever config file you use) +{ + "presets": [ + [ + "next/babel", + { + "styled-jsx": { + "plugins": ["@styled-jsx/plugin-sass"] + } + } + ] + ] +} +``` + +## PostCSS + +Next.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. + +This allows for cool things like zero-config Tailwind! (See [Next.js' example](https://github.com/vercel/next.js/tree/canary/examples/with-tailwindcss)) + +## Absolute imports + +[Absolute imports](https://nextjs.org/docs/pages/building-your-application/configuring/absolute-imports-and-module-aliases#absolute-imports) from the root directory are supported. + +```jsx +// index.js +// All good! +import Button from 'components/button'; +// Also good! +import styles from 'styles/HomePage.module.css'; + +export default function HomePage() { + return ( + <> +

Hello World

+