diff --git a/.babelrc.js b/.babelrc.js index 5af9a9046c5d..b00deb2d4c20 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -55,7 +55,7 @@ module.exports = { '@babel/plugin-syntax-dynamic-import', ['@babel/plugin-proposal-object-rest-spread', { loose: true, useBuiltIns: true }], 'babel-plugin-macros', - ['emotion', { sourceMap: true, autoLabel: true }], + ['@emotion', { sourceMap: true, autoLabel: 'always' }], ], env: { test: withTests, @@ -90,7 +90,7 @@ module.exports = { ['@babel/plugin-proposal-private-property-in-object', { loose: true }], ['@babel/plugin-proposal-class-properties', { loose: true }], 'babel-plugin-macros', - ['emotion', { sourceMap: true, autoLabel: true }], + ['@emotion', { sourceMap: true, autoLabel: 'always' }], 'babel-plugin-add-react-displayname', ], env: { @@ -125,7 +125,7 @@ module.exports = { ], ], plugins: [ - 'emotion', + '@emotion', 'babel-plugin-macros', '@babel/plugin-transform-arrow-functions', '@babel/plugin-transform-shorthand-properties', diff --git a/.circleci/config.yml b/.circleci/config.yml index 63e5e7a61ec2..372652ee4264 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -92,7 +92,7 @@ jobs: command: yarn install --immutable - run: name: Bootstrap - command: yarn bootstrap --core + command: yarn bootstrap --build --manager - save_cache: name: Save Yarn cache key: build-yarn-2-cache-v3--{{ checksum "yarn.lock" }} @@ -180,7 +180,7 @@ jobs: name: Wait for registry command: yarn wait-on http://localhost:6000 - run: - name: Run E2E tests + name: Run E2E (extended) tests command: yarn test:e2e-framework --clean --all --skip angular11 --skip angular --skip angular12 --skip vue3 --skip web_components_typescript --skip cra --skip react no_output_timeout: 5m - store_artifacts: @@ -190,7 +190,7 @@ jobs: executor: class: large name: sb_cypress_8_node_14 - parallelism: 2 + parallelism: 8 steps: - git-shallow-clone/checkout_advanced: clone_options: '--depth 1 --verbose' @@ -204,10 +204,10 @@ jobs: name: Wait for registry command: yarn wait-on http://localhost:6000 - run: - name: Run E2E tests + name: Run E2E (core) tests # Do not test CRA here because it's done in PnP part # TODO: Remove `web_components_typescript` as soon as Lit 2 stable is released - command: yarn test:e2e-framework vue3 angular130 angular13 angular12 angular11 web_components_typescript web_components_lit2 react + command: yarn test:e2e-framework vue3 angular130 angular13 angular12 angular11 web_components_typescript web_components_lit2 react react_legacy_root_api vite_react no_output_timeout: 5m - store_artifacts: path: /tmp/cypress-record @@ -392,6 +392,8 @@ jobs: - run: name: Test command: yarn test --coverage --runInBand --ci + - store_test_results: + path: junit.xml - persist_to_workspace: root: . paths: diff --git a/.gitignore b/.gitignore index 423ff6ec3edc..c0b4b25e9d31 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ tsconfig.tsbuildinfo lib/manager-webpack4/prebuilt lib/manager-webpack5/prebuilt examples/angular-cli/addon-jest.testresults.json +junit.xml # Yarn stuff /**/.yarn/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 89a122c9c123..5bbc932a15cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,301 @@ +## 6.5.0-beta.7 (May 9, 2022) + +### Features + +- CSF3: Add title prefix support for stories with custom titles ([#17724](https://github.com/storybookjs/storybook/pull/17724)) + +### Bug Fixes + +- Components: Fix race conditions in SyntaxHighlighter ([#18158](https://github.com/storybookjs/storybook/pull/18158)) + +### Maintenance + +- API: Deprecate isToolshown, rename to showToolbar ([#18131](https://github.com/storybookjs/storybook/pull/18131)) + +## 6.5.0-beta.6 (May 6, 2022) + +### Bug Fixes + +- Controls: Fix undefined args handling ([#18135](https://github.com/storybookjs/storybook/pull/18135)) + +### Maintenance + +- CLI: Update Introduction.stories.mdx template to be MDX2-friendly ([#18141](https://github.com/storybookjs/storybook/pull/18141)) + +### Dependency Upgrades + +- Remove jest from cli peerDependencies ([#18149](https://github.com/storybookjs/storybook/pull/18149)) + +## 6.5.0-beta.5 (May 4, 2022) + +### Bug Fixes + +- Core: Fix anonymous ID generation ([#18133](https://github.com/storybookjs/storybook/pull/18133)) + +## 6.5.0-beta.4 (May 4, 2022) + +### Features + +- UI: Add a parent level toolbar exclusion key for tabs ([#18106](https://github.com/storybookjs/storybook/pull/18106)) +- Addon-a11y: Display a11y issues number in addon tab title ([#17983](https://github.com/storybookjs/storybook/pull/17983)) + +### Bug Fixes + +- Addon-docs: Fix Canvas block CURRENT_SELECTION handling ([#18130](https://github.com/storybookjs/storybook/pull/18130)) +- Telemetry: Add safecheck for crash reports ([#18129](https://github.com/storybookjs/storybook/pull/18129)) +- Addon-a11y: Fix a11y params > element use ([#17989](https://github.com/storybookjs/storybook/pull/17989)) + +## 6.5.0-beta.3 (May 4, 2022) + +### Bug Fixes + +- UI: Externalize `react-syntax-highlighter` from components ([#18127](https://github.com/storybookjs/storybook/pull/18127)) + +## 6.5.0-beta.2 (May 2, 2022) + +### Features + +- Core: Add optional telemetry and crash reporting ([#18046](https://github.com/storybookjs/storybook/pull/18046)) + +### Bug Fixes + +- Controls: Fix URL deserialization for argTypes with mapping ([#18124](https://github.com/storybookjs/storybook/pull/18124)) +- Core: Fix telemetry project root detection ([#18125](https://github.com/storybookjs/storybook/pull/18125)) +- React: Fix version detection for older versions of `react-dom` ([#18105](https://github.com/storybookjs/storybook/pull/18105)) +- CLI: Add non-monorepo testing tools to exclude lists ([#18092](https://github.com/storybookjs/storybook/pull/18092)) + +### Maintenance + +- Examples: Update example to restore 6.4 auto-title behavior in UI ([#18109](https://github.com/storybookjs/storybook/pull/18109)) +- CLI: Remove git.io URL ([#18070](https://github.com/storybookjs/storybook/pull/18070)) +- UI: Make panel position a persistent preference ([#18036](https://github.com/storybookjs/storybook/pull/18036)) + +### Dependency Upgrades + +- React: Fix jest-specific-snapshot dev dependency ([#18095](https://github.com/storybookjs/storybook/pull/18095)) + +## 6.5.0-beta.1 (April 28, 2022) + +### Features + +- Toolbars: Add dynamicTitle option ([#17789](https://github.com/storybookjs/storybook/pull/17789)) +- Angular: Add webpackStatsJson to angular-builder ([#18001](https://github.com/storybookjs/storybook/pull/18001)) +- CLI/Vue: add interactions to vue cli template ([#18021](https://github.com/storybookjs/storybook/pull/18021)) +- CLI/HTML: Add interactions to cli template ([#18014](https://github.com/storybookjs/storybook/pull/18014)) + +### Bug Fixes + +- CSF: Re-apply TArgs to render type ([#18075](https://github.com/storybookjs/storybook/pull/18075)) +- CLI: await generators for proper install ([#18053](https://github.com/storybookjs/storybook/pull/18053)) +- Core: Fix story index for CSF default exports as TS vars ([#18054](https://github.com/storybookjs/storybook/pull/18054)) +- Core: Fix single-story hoisting regression for auto-title changes ([#18052](https://github.com/storybookjs/storybook/pull/18052)) + +## 6.5.0-beta.0 (April 24, 2022) + +### Features + +- CLI/Vue3: add interactions to vue3 cli template ([#18031](https://github.com/storybookjs/storybook/pull/18031)) +- CLI/Svelte: add interactions to cli template ([#17993](https://github.com/storybookjs/storybook/pull/17993)) +- UI: Move the "Rerun interactions" button to Subnav ([#17647](https://github.com/storybookjs/storybook/pull/17647)) + +## 6.5.0-alpha.64 (April 18, 2022) + +### Features + +- CLI/Preact: add interactions to cli template ([#17984](https://github.com/storybookjs/storybook/pull/17984)) + +### Bug Fixes + +- Interactions: Fix show length of object value on MethodCall ([#17649](https://github.com/storybookjs/storybook/pull/17649)) +- React: Fix React 18 react-dom/client dynamic import syntax ([#17987](https://github.com/storybookjs/storybook/pull/17987)) +- Svelte: Fix webpack5/babelModeV7 ([#17939](https://github.com/storybookjs/storybook/pull/17939)) + +### Maintenance + +- Examples: Remove stories from deprecated `options`/`queryparams` addons ([#17977](https://github.com/storybookjs/storybook/pull/17977)) +- Chore: Format versions.ts file using repo config ([#17963](https://github.com/storybookjs/storybook/pull/17963)) + +## 6.5.0-alpha.63 (April 14, 2022) + +### Bug Fixes + +- Theming: Re-export correct bundled file ([#17956](https://github.com/storybookjs/storybook/pull/17956)) +- Core: Support react-dom/client dom hack on Windows machines ([#17946](https://github.com/storybookjs/storybook/pull/17946)) + +### Maintenance + +- CI: set parallelism of nx to 2 ([#17878](https://github.com/storybookjs/storybook/pull/17878)) + +### Dependency Upgrades + +- Run `prebundle` script without `browser: true` in Rollup config ([#17947](https://github.com/storybookjs/storybook/pull/17947)) + +## 6.4.22 (April 14, 2022) + +### Maintenance + +- Core: Avoid framework imports from core/client ([#17875](https://github.com/storybookjs/storybook/pull/17875)) + +## 6.5.0-alpha.62 (April 13, 2022) + +Test publish with npm 2FA enabled for addon-jest + +## 6.5.0-alpha.61 (April 11, 2022) + +### Features + +- UI: Add URL parameters to SB to tweak visible UI ([#17891](https://github.com/storybookjs/storybook/pull/17891)) + +### Maintenance + +- Core: Followup changing CJS entrypoints to ESM ([#17927](https://github.com/storybookjs/storybook/pull/17927)) + +### Dependency Upgrades + +- Export `createCache` from `@storybook/theming` ([#17929](https://github.com/storybookjs/storybook/pull/17929)) + +## 6.4.21 (April 9, 2022) + +### Bug Fixes + +- Angular: Do not use default for includePaths ([#17876](https://github.com/storybookjs/storybook/pull/17876)) +- Controls: Fix date control width in addons panel ([#17780](https://github.com/storybookjs/storybook/pull/17780)) +- CLI: Preserve quote style in automigrate ([#17858](https://github.com/storybookjs/storybook/pull/17858)) +- CLI: Update the exclude list for upgrade warnings ([#17909](https://github.com/storybookjs/storybook/pull/17909)) + +## 6.5.0-alpha.60 (April 9, 2022) + +### Features + +- Core: Add story preloading to optimize lazy compilation ([#17903](https://github.com/storybookjs/storybook/pull/17903)) + +### Bug Fixes + +- UI: Fix pseudo class potential unsafe warning ([#17911](https://github.com/storybookjs/storybook/pull/17911)) +- Core: Fix user-supplied project-level `render` in v6 store ([#17885](https://github.com/storybookjs/storybook/pull/17885)) + +### Dependency Upgrades + +- Upgrade polished to 4.2.2 ([#17913](https://github.com/storybookjs/storybook/pull/17913)) +- Bump min vue-loader dependency version ([#17912](https://github.com/storybookjs/storybook/pull/17912)) + +## 6.5.0-alpha.59 (April 7, 2022) + +### Maintenance + +- CLI: Update the exclude list for upgrade warnings ([#17909](https://github.com/storybookjs/storybook/pull/17909)) +- Examples: Added an external-docs example to show the basic use case ([#17807](https://github.com/storybookjs/storybook/pull/17807)) + +### Dependency Upgrades + +- Migration to Emotion 11 ([#17640](https://github.com/storybookjs/storybook/pull/17640)) + +## 6.5.0-alpha.58 (April 7, 2022) + +### Features + +- CLI: Add webpack4/5 auto-detection ([#17908](https://github.com/storybookjs/storybook/pull/17908)) +- React: Add support for react18's new root API ([#17215](https://github.com/storybookjs/storybook/pull/17215)) + +### Bug Fixes + +- UI: Fix canvas as initialActive for fullscreen mode in mobile ([#17906](https://github.com/storybookjs/storybook/pull/17906)) +- UI: Fix mobile fullscreen UI ([#17873](https://github.com/storybookjs/storybook/pull/17873)) + +### Maintenance + +- Core: Avoid framework imports from core/client ([#17875](https://github.com/storybookjs/storybook/pull/17875)) +- Webpack: Make manager and preview build processes cancelable ([#17809](https://github.com/storybookjs/storybook/pull/17809)) +- Build: Add vite-react to e2e tests ([#17871](https://github.com/storybookjs/storybook/pull/17871)) +- CLI: Upgrade vue3 template to use webpack5 builder ([#17896](https://github.com/storybookjs/storybook/pull/17896)) +- Build: Exclude @storybook/builder-vite from verdaccio ([#17897](https://github.com/storybookjs/storybook/pull/17897)) + +## 6.5.0-alpha.57 (April 6, 2022) + +### Bug Fixes + +- Svelte: Fix dynamic source snippets ([#17866](https://github.com/storybookjs/storybook/pull/17866)) +- Angular: Do not use default for includePaths ([#17876](https://github.com/storybookjs/storybook/pull/17876)) + +### Maintenance + +- Addon-docs: assume links starting with "https://" are external ([#17819](https://github.com/storybookjs/storybook/pull/17819)) + +### Dependency Upgrades + +- Unify CSF version ([#17895](https://github.com/storybookjs/storybook/pull/17895)) + +## 6.5.0-alpha.56 (April 5, 2022) + +### Features + +- Controls: Rework conditional controls with globals, queries ([#17883](https://github.com/storybookjs/storybook/pull/17883)) +- UI: Add Brand target config option ([#17814](https://github.com/storybookjs/storybook/pull/17814)) + +### Bug Fixes + +- Controls: Fix date control width in addons panel ([#17780](https://github.com/storybookjs/storybook/pull/17780)) + +### Maintenance + +- Core: Update some references to use ESM rather than CJS ([#17868](https://github.com/storybookjs/storybook/pull/17868)) +- Build: Upgrade from deprecated circleci docker img ([#17832](https://github.com/storybookjs/storybook/pull/17832)) +- Build: Parallel e2e (this might be expensive) ([#17842](https://github.com/storybookjs/storybook/pull/17842)) +- Build: Add junit summary for CircleCI ([#17867](https://github.com/storybookjs/storybook/pull/17867)) + +## 6.5.0-alpha.55 (April 3, 2022) + +### Features + +- CLI: Detect vite project, use vite builder automatically ([#17860](https://github.com/storybookjs/storybook/pull/17860)) +- CLI: Default new vite projects to storyStoreV7 ([#17859](https://github.com/storybookjs/storybook/pull/17859)) + +### Bug Fixes + +- Core: Restore preview-web composeConfigs export ([#17861](https://github.com/storybookjs/storybook/pull/17861)) +- CLI: Preserve quote style in automigrate ([#17858](https://github.com/storybookjs/storybook/pull/17858)) + +## 6.4.20 (April 1, 2022) + +### Bug Fixes + +- CLI: Fix vite/jest issue with mocked global ([#17830](https://github.com/storybookjs/storybook/pull/17830)) +- Angular: Fix multiple calls of Input setter ([#17633](https://github.com/storybookjs/storybook/pull/17633)) +- Web-components: Fix CSS class usage in CLI template ([#17702](https://github.com/storybookjs/storybook/pull/17702)) +- UI: Fix composition support in safari ([#17679](https://github.com/storybookjs/storybook/pull/17679)) +- Addon-docs: DocsPage story order should match the index ([#17669](https://github.com/storybookjs/storybook/pull/17669)) +- Core: Fix core.builder check ([#17606](https://github.com/storybookjs/storybook/pull/17606)) + +### Maintenance + +- CLI: Add automigration to `@storybook/builder-vite` ([#17829](https://github.com/storybookjs/storybook/pull/17829)) + +## 6.5.0-alpha.54 (April 1, 2022) + +### Dependency Upgrades + +- React: Update react and react-dom peerDeps for React18 ([#17853](https://github.com/storybookjs/storybook/pull/17853)) + +## 6.5.0-alpha.53 (April 1, 2022) + +### Features + +- Core: Add simplified manager.js/preview.js API for addons ([#17755](https://github.com/storybookjs/storybook/pull/17755)) +- Core/React: Add testing utilities ([#17282](https://github.com/storybookjs/storybook/pull/17282)) + +### Bug Fixes + +- Addon-docs: Fix dependencies for yarn pnp ([#17705](https://github.com/storybookjs/storybook/pull/17705)) +- Webpack: Expand version ranges of webpack in the apps ([#17834](https://github.com/storybookjs/storybook/pull/17834)) +- CLI: Fix vite/jest issue with mocked global ([#17830](https://github.com/storybookjs/storybook/pull/17830)) + +### Maintenance + +- Build: Remove packtracker ([#17841](https://github.com/storybookjs/storybook/pull/17841)) +- Build: Swap order of e2e tests around ([#17840](https://github.com/storybookjs/storybook/pull/17840)) +- Build: Add weekly check for broken markdown links ([#17799](https://github.com/storybookjs/storybook/pull/17799)) +- Build: Switch to use medium+ ([#17837](https://github.com/storybookjs/storybook/pull/17837)) + ## 6.5.0-alpha.52 (March 31, 2022) ### Bug Fixes @@ -156,6 +454,21 @@ - Build: Fix CRA repro generator and e2e test in PnP mode ([#17375](https://github.com/storybookjs/storybook/pull/17375)) - UI: Add a custom title story for heading component ([#17487](https://github.com/storybookjs/storybook/pull/17487)) +## 6.4.19 (February 12, 2022) + +### Features + +- CLI/React: Add interactions to cli template ([#17345](https://github.com/storybookjs/storybook/pull/17345)) +- CLI/Angular: Add interactions to cli template ([#17437](https://github.com/storybookjs/storybook/pull/17437)) + +### Bug Fixes + +- Core/CLI: Add `extract` function to `PreviewWeb` and use it in `sb extract` if available ([#17447](https://github.com/storybookjs/storybook/pull/17447)) +- Core: Ensure we show an error when `configure()` throws ([#17435](https://github.com/storybookjs/storybook/pull/17435)) +- Core: Fix `useParameter` with nullish coalescing ([#17327](https://github.com/storybookjs/storybook/pull/17327)) +- Addon-links: Fix export statement in react.d.ts ([#17434](https://github.com/storybookjs/storybook/pull/17434)) +- Addon-docs: Fix typo in ArgsTable tooltip ([#17404](https://github.com/storybookjs/storybook/pull/17404)) + ## 6.5.0-alpha.39 (February 11, 2022) ### Features diff --git a/MIGRATION.md b/MIGRATION.md index 6cfcc02433c1..98e966e483b5 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,12 +1,17 @@

Migration

- [From version 6.4.x to 6.5.0](#from-version-64x-to-650) + - [React18 new root API](#react18-new-root-api) + - [Renamed isToolshown to showToolbar](#renamed-istoolshown-to-showtoolbar) + - [Deprecated register.js](#deprecated-registerjs) + - [Dropped support for addon-actions addDecorators](#dropped-support-for-addon-actions-adddecorators) - [Vite builder renamed](#vite-builder-renamed) - [Docs framework refactor for React](#docs-framework-refactor-for-react) - [Opt-in MDX2 support](#opt-in-mdx2-support) - [CSF3 auto-title improvements](#csf3-auto-title-improvements) - [Auto-title filename case](#auto-title-filename-case) - [Auto-title redundant filename](#auto-title-redundant-filename) + - [Auto-title always prefixes](#auto-title-always-prefixes) - [From version 6.3.x to 6.4.0](#from-version-63x-to-640) - [Automigrate](#automigrate) - [CRA5 upgrade](#cra5-upgrade) @@ -197,6 +202,53 @@ ## From version 6.4.x to 6.5.0 +### React18 new root API + +React 18 introduces a [new root API](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-client-rendering-apis). Starting in 6.5, Storybook for React will auto-detect your react version and use the new root API automatically if you're on React18. + +If you wish to opt out of the new root API, set the `reactOptions.legacyRootApi` flag in your `.storybook/main.js` config: + +```js +module.exports = { + reactOptions: { legacyRootApi: true }, +}; +``` + +### Renamed isToolshown to showToolbar + +Storybook's [manager API](docs/addons/addons-api.md) has deprecated the `isToolshown` option (to show/hide the toolbar) and renamed it to `showToolbar` for consistency with other similar UI options. + +Example: + +```js +// .storybook/manager.js +import { addons } from '@storybook/addons'; + +addons.setConfig({ + showToolbar: false, +}); +``` + +### Deprecated register.js + +In ancient versions of Storybook, addons were registered by referring to `addon-name/register.js`. This is going away in SB7.0. Instead you should just add `addon-name` to the `addons` array in `.storybook/main.js`. + +Before: + +```js +module.exports = { addons: ['my-addon/register.js'] }; +``` + +After: + +```js +module.exports = { addons: ['my-addon'] }; +``` + +### Dropped support for addon-actions addDecorators + +Prior to SB6.5, `addon-actions` provided an option called `addDecorators`. In SB6.5, decorators are applied always. This is technically a breaking change, so if this affects you please file an issue in Github and we can consider reverting this in a patch release. + ### Vite builder renamed SB6.5 renames Storybook's [Vite builder](https://github.com/storybookjs/builder-vite) from `storybook-builder-vite` to `@storybook/builder-vite`. This move is part of a larger effort to improve Vite support in Storybook. @@ -253,6 +305,19 @@ This might be considered a breaking change. However, we feel justified to releas 1. We consider it a bug in the initial auto-title implementation 2. CSF3 and the auto-title feature are experimental, and we reserve the right to make breaking changes outside of semver (tho we try to avoid it) +If you want to restore the old titles in the UI, you can customize your sidebar with the following code snippet in `.storybook/manager.js`: + +```js +import { addons } from '@storybook/addons'; +import startCase from 'lodash/startCase'; + +addons.setConfig({ + sidebar: { + renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)), + }, +}); +``` + #### Auto-title redundant filename The heuristic failed in the common scenario in which each component gets its own directory, e.g. `atoms/Button/Button.stories.js`, which would result in the redundant title `Atoms/Button/Button`. Alternatively, `atoms/Button/index.stories.js` would result in `Atoms/Button/Index`. @@ -266,6 +331,35 @@ Since CSF3 is experimental, we are introducing this technically breaking change export default { title: 'Atoms/Button/Button' }; ``` +#### Auto-title always prefixes + +When the user provides a `prefix` in their `main.js` `stories` field, it now prefixes all titles to matching stories, whereas in 6.4 and earlier it only prefixed auto-titles. + +Consider the following example: + +```js +// main.js +module.exports = { + stories: [{ directory: '../src', titlePrefix: 'Custom' }] +} + +// ../src/NoTitle.stories.js +export default { component: Foo }; + +// ../src/Title.stories.js +export default { component: Bar, title: 'Bar' } +``` + +In 6.4, the final titles would be: + +- `NoTitle.stories.js` => `Custom/NoTitle` +- `Title.stories.js` => `Bar` + +In 6.5, the final titles would be: + +- `NoTitle.stories.js` => `Custom/NoTitle` +- `Title.stories.js` => `Custom/Bar` + ## From version 6.3.x to 6.4.0 ### Automigrate @@ -279,7 +373,9 @@ For example, if you're in a webpack5 project but still use Storybook's default w You can run the existing suite of automigrations to see which ones apply to your project. This won't update any files unless you accept the changes: ``` + npx sb@next automigrate + ``` The automigration suite also runs when you create a new project (`sb init`) or when you update storybook (`sb upgrade`). @@ -289,7 +385,9 @@ The automigration suite also runs when you create a new project (`sb init`) or w Storybook 6.3 supports CRA5 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to upgrade the configuration. You can do this automatically by running: ``` + npx sb@next automigrate + ``` Or you can do the following steps manually to force Storybook to use webpack 5 for building your project: diff --git a/__mocks__/fs-extra.js b/__mocks__/fs-extra.js index 349ffb2b4c7f..ebe0d6c11d36 100644 --- a/__mocks__/fs-extra.js +++ b/__mocks__/fs-extra.js @@ -15,6 +15,7 @@ function __setMockFiles(newMockFiles) { const readFile = async (filePath) => mockFiles[filePath]; const readFileSync = (filePath = '') => mockFiles[filePath]; const existsSync = (filePath) => !!mockFiles[filePath]; +const readJsonSync = (filePath = '') => JSON.parse(mockFiles[filePath]); const lstatSync = (filePath) => ({ isFile: () => !!mockFiles[filePath], }); @@ -23,6 +24,7 @@ const lstatSync = (filePath) => ({ fs.__setMockFiles = __setMockFiles; fs.readFile = readFile; fs.readFileSync = readFileSync; +fs.readJsonSync = readJsonSync; fs.existsSync = existsSync; fs.lstatSync = lstatSync; diff --git a/addons/a11y/README.md b/addons/a11y/README.md index 9a1fa782d570..14f3b309de6c 100755 --- a/addons/a11y/README.md +++ b/addons/a11y/README.md @@ -47,7 +47,7 @@ When Axe reports accessibility violations in stories, there are multiple ways to At the Story level, override rules using `parameters.a11y.config.rules`. ```js -export const InputWithoutAutofill = () => ; +export const InputWithoutAutofill = () => ; InputWithoutAutofill.parameters = { a11y: { diff --git a/addons/a11y/manager.js b/addons/a11y/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/a11y/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/a11y/package.json b/addons/a11y/package.json index 9ca8339ae18d..7ff19118c8d6 100644 --- a/addons/a11y/package.json +++ b/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", @@ -45,14 +45,14 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/channels": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/channels": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.0-beta.7", "axe-core": "^4.2.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -67,8 +67,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -81,7 +81,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Accessibility", diff --git a/addons/a11y/preset.js b/addons/a11y/preset.js deleted file mode 100644 index fc6884de55c6..000000000000 --- a/addons/a11y/preset.js +++ /dev/null @@ -1,13 +0,0 @@ -function managerEntries(entry = []) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -function config(entry = []) { - return [ - ...entry, - require.resolve('./dist/esm/a11yRunner'), - require.resolve('./dist/esm/a11yHighlight'), - ]; -} - -module.exports = { managerEntries, config }; diff --git a/addons/a11y/preview.js b/addons/a11y/preview.js new file mode 100644 index 000000000000..e726cab5a1b6 --- /dev/null +++ b/addons/a11y/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preview'; diff --git a/addons/a11y/register.js b/addons/a11y/register.js index f209c0eb3703..2d916bea61a0 100755 --- a/addons/a11y/register.js +++ b/addons/a11y/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/a11y/src/a11yRunner.ts b/addons/a11y/src/a11yRunner.ts index 8a9463116a64..1f4fd7ddeab6 100644 --- a/addons/a11y/src/a11yRunner.ts +++ b/addons/a11y/src/a11yRunner.ts @@ -15,11 +15,6 @@ let active = false; // Holds latest story we requested a run let activeStoryId: string | undefined; -const getElement = () => { - const storyRoot = document.getElementById('story-root'); - return storyRoot ? storyRoot.childNodes : document.getElementById('root'); -}; - /** * Handle A11yContext events. * Because the event are sent without manual check, we split calls @@ -39,15 +34,16 @@ const run = async (storyId: string) => { if (!active) { active = true; channel.emit(EVENTS.RUNNING); - const axe = await import('axe-core'); + const axe = (await import('axe-core')).default; - const { element = getElement(), config, options = {} } = input; + const { element = '#root', config, options = {} } = input; + const htmlElement = document.querySelector(element); axe.reset(); if (config) { axe.configure(config); } - const result = await axe.run(element, options); + const result = await axe.run(htmlElement, options); // It's possible that we requested a new run on a different story. // Unfortunately, axe doesn't support a cancel method to abort current run. // We check if the story we run against is still the current one, diff --git a/addons/a11y/src/addDecorator.ts b/addons/a11y/src/addDecorator.ts deleted file mode 100644 index 95dc140b157a..000000000000 --- a/addons/a11y/src/addDecorator.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { withA11y } from '.'; - -export const decorators = [withA11y]; diff --git a/addons/a11y/src/components/A11YPanel.test.tsx b/addons/a11y/src/components/A11YPanel.test.tsx index 744e7e418b8b..7c366377b12d 100644 --- a/addons/a11y/src/components/A11YPanel.test.tsx +++ b/addons/a11y/src/components/A11YPanel.test.tsx @@ -63,6 +63,7 @@ describe('A11YPanel', () => { mockedApi.useStorybookState.mockReset(); mockedApi.useAddonState.mockReset(); + mockedApi.useAddonState.mockImplementation((_, defaultState) => React.useState(defaultState)); mockedApi.useChannel.mockReturnValue(jest.fn()); mockedApi.useParameter.mockReturnValue({ manual: false }); const state: Partial = { storyId: 'jest' }; diff --git a/addons/a11y/src/components/A11yContext.test.tsx b/addons/a11y/src/components/A11yContext.test.tsx index 5d4e7003f149..a70ced0368a6 100644 --- a/addons/a11y/src/components/A11yContext.test.tsx +++ b/addons/a11y/src/components/A11yContext.test.tsx @@ -53,11 +53,13 @@ describe('A11YPanel', () => { beforeEach(() => { mockedApi.useChannel.mockReset(); mockedApi.useStorybookState.mockReset(); + mockedApi.useAddonState.mockReset(); + mockedApi.useAddonState.mockImplementation((_, defaultState) => React.useState(defaultState)); mockedApi.useChannel.mockReturnValue(jest.fn()); - const state: Partial = { storyId }; + const storyState: Partial = { storyId }; // Lazy to mock entire state - mockedApi.useStorybookState.mockReturnValue(state as any); + mockedApi.useStorybookState.mockReturnValue(storyState as any); }); it('should render children', () => { diff --git a/addons/a11y/src/components/A11yContext.tsx b/addons/a11y/src/components/A11yContext.tsx index 5061f5623d47..bd3c378f2659 100644 --- a/addons/a11y/src/components/A11yContext.tsx +++ b/addons/a11y/src/components/A11yContext.tsx @@ -1,11 +1,11 @@ import * as React from 'react'; import { themes, convert } from '@storybook/theming'; import { Result } from 'axe-core'; -import { useChannel, useStorybookState } from '@storybook/api'; +import { useChannel, useStorybookState, useAddonState } from '@storybook/api'; import { STORY_CHANGED, STORY_RENDERED } from '@storybook/core-events'; -import { EVENTS } from '../constants'; +import { ADDON_ID, EVENTS } from '../constants'; -interface Results { +export interface Results { passes: Result[]; violations: Result[]; incomplete: Result[]; @@ -52,7 +52,7 @@ const defaultResult = { }; export const A11yContextProvider: React.FC = ({ active, ...props }) => { - const [results, setResults] = React.useState(defaultResult); + const [results, setResults] = useAddonState(ADDON_ID, defaultResult); const [tab, setTab] = React.useState(0); const [highlighted, setHighlighted] = React.useState([]); const { storyId } = useStorybookState(); diff --git a/addons/a11y/src/manager.test.tsx b/addons/a11y/src/manager.test.tsx new file mode 100644 index 000000000000..92ef7866313d --- /dev/null +++ b/addons/a11y/src/manager.test.tsx @@ -0,0 +1,55 @@ +import { addons } from '@storybook/addons'; +import * as api from '@storybook/api'; +import { PANEL_ID } from './constants'; +import './manager'; + +jest.mock('@storybook/api'); +jest.mock('@storybook/addons'); +const mockedApi = api as unknown as jest.Mocked; +mockedApi.getAddonState = jest.fn(); +const mockedAddons = addons as jest.Mocked; +const registrationImpl = mockedAddons.register.mock.calls[0][1]; + +describe('A11yManager', () => { + it('should register the panels', () => { + // when + registrationImpl(mockedApi); + + // then + expect(mockedAddons.add.mock.calls).toHaveLength(2); + expect(mockedAddons.add).toHaveBeenCalledWith(PANEL_ID, expect.anything()); + + const panel = mockedAddons.add.mock.calls + .map(([_, def]) => def) + .find(({ type }) => type === 'panel'); + const tool = mockedAddons.add.mock.calls + .map(([_, def]) => def) + .find(({ type }) => type === 'tool'); + expect(panel).toBeDefined(); + expect(tool).toBeDefined(); + }); + + it('should compute title with no issues', () => { + // given + mockedApi.getAddonState.mockImplementation(() => undefined); + registrationImpl(api as unknown as api.API); + const title = mockedAddons.add.mock.calls + .map(([_, def]) => def) + .find(({ type }) => type === 'panel').title as Function; + + // when / then + expect(title()).toBe('Accessibility'); + }); + + it('should compute title with issues', () => { + // given + mockedApi.getAddonState.mockImplementation(() => ({ violations: [{}], incomplete: [{}, {}] })); + registrationImpl(mockedApi); + const title = mockedAddons.add.mock.calls + .map(([_, def]) => def) + .find(({ type }) => type === 'panel').title as Function; + + // when / then + expect(title()).toBe('Accessibility (3)'); + }); +}); diff --git a/addons/a11y/src/register.tsx b/addons/a11y/src/manager.tsx similarity index 59% rename from addons/a11y/src/register.tsx rename to addons/a11y/src/manager.tsx index 69cb77a7fbf4..ce24d1c9cafd 100644 --- a/addons/a11y/src/register.tsx +++ b/addons/a11y/src/manager.tsx @@ -3,9 +3,9 @@ import { addons, types } from '@storybook/addons'; import { ADDON_ID, PANEL_ID, PARAM_KEY } from './constants'; import { VisionSimulator } from './components/VisionSimulator'; import { A11YPanel } from './components/A11YPanel'; -import { A11yContextProvider } from './components/A11yContext'; +import { A11yContextProvider, Results } from './components/A11yContext'; -addons.register(ADDON_ID, () => { +addons.register(ADDON_ID, (api) => { addons.add(PANEL_ID, { title: '', type: types.TOOL, @@ -14,7 +14,13 @@ addons.register(ADDON_ID, () => { }); addons.add(PANEL_ID, { - title: 'Accessibility', + title() { + const addonState: Results = api?.getAddonState(ADDON_ID); + const violationsNb = addonState?.violations?.length || 0; + const incompleteNb = addonState?.incomplete?.length || 0; + const totalNb = violationsNb + incompleteNb; + return totalNb !== 0 ? `Accessibility (${totalNb})` : 'Accessibility'; + }, type: types.PANEL, render: ({ active = true, key }) => ( diff --git a/addons/a11y/src/preview.tsx b/addons/a11y/src/preview.tsx new file mode 100644 index 000000000000..146feb51f50f --- /dev/null +++ b/addons/a11y/src/preview.tsx @@ -0,0 +1,2 @@ +import './a11yRunner'; +import './a11yHighlight'; diff --git a/addons/actions/manager.js b/addons/actions/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/actions/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/actions/package.json b/addons/actions/package.json index 9cd0c88bd81d..8919d656a2ef 100644 --- a/addons/actions/package.json +++ b/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", @@ -41,17 +41,18 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "fast-deep-equal": "^3.1.3", "global": "^4.4.0", "lodash": "^4.17.21", - "polished": "^4.0.5", + "polished": "^4.2.2", "prop-types": "^15.7.2", "react-inspector": "^5.1.0", "regenerator-runtime": "^0.13.7", @@ -65,8 +66,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -79,7 +80,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Actions", diff --git a/addons/actions/preset.js b/addons/actions/preset.js deleted file mode 100644 index ba70abe968e6..000000000000 --- a/addons/actions/preset.js +++ /dev/null @@ -1,16 +0,0 @@ -function managerEntries(entry, options) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -function config(entry = [], { addDecorator = true } = {}) { - const actionConfig = []; - if (addDecorator) { - actionConfig.push(require.resolve('./dist/esm/preset/addDecorator')); - } - return [...entry, ...actionConfig, require.resolve('./dist/esm/preset/addArgs')]; -} - -module.exports = { - managerEntries, - config, -}; diff --git a/addons/actions/preview.js b/addons/actions/preview.js new file mode 100644 index 000000000000..7817e1d278d2 --- /dev/null +++ b/addons/actions/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preset/preview'; diff --git a/addons/actions/register.js b/addons/actions/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/actions/register.js +++ b/addons/actions/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/actions/src/register.tsx b/addons/actions/src/manager.tsx similarity index 100% rename from addons/actions/src/register.tsx rename to addons/actions/src/manager.tsx diff --git a/addons/actions/src/preset/preview.tsx b/addons/actions/src/preset/preview.tsx new file mode 100644 index 000000000000..117c34f7196b --- /dev/null +++ b/addons/actions/src/preset/preview.tsx @@ -0,0 +1,2 @@ +export * from './addDecorator'; +export * from './addArgs'; diff --git a/addons/actions/src/preview/action.ts b/addons/actions/src/preview/action.ts index 53a5c3971577..c8af13de05d1 100644 --- a/addons/actions/src/preview/action.ts +++ b/addons/actions/src/preview/action.ts @@ -25,7 +25,7 @@ const serializeArg = (a: T) => { ); e.persist(); const viewDescriptor = Object.getOwnPropertyDescriptor(e, 'view'); - // dont send the entire window object over. + // don't send the entire window object over. const view: unknown = viewDescriptor?.value; if (typeof view === 'object' && view?.constructor.name === 'Window') { Object.defineProperty(e, 'view', { diff --git a/addons/backgrounds/manager.js b/addons/backgrounds/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/backgrounds/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/backgrounds/package.json b/addons/backgrounds/package.json index ee741e49d59c..a0834445b540 100644 --- a/addons/backgrounds/package.json +++ b/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", @@ -45,13 +45,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "global": "^4.4.0", "memoizerific": "^1.11.3", @@ -63,8 +63,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -77,7 +77,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Backgrounds", diff --git a/addons/backgrounds/preset.js b/addons/backgrounds/preset.js deleted file mode 100644 index a80aaefb5b30..000000000000 --- a/addons/backgrounds/preset.js +++ /dev/null @@ -1,16 +0,0 @@ -function config(entry = []) { - return [ - ...entry, - require.resolve('./dist/esm/preset/addDecorator'), - require.resolve('./dist/esm/preset/addParameter'), - ]; -} - -function managerEntries(entry = [], options) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -module.exports = { - managerEntries, - config, -}; diff --git a/addons/backgrounds/preview.js b/addons/backgrounds/preview.js new file mode 100644 index 000000000000..e726cab5a1b6 --- /dev/null +++ b/addons/backgrounds/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preview'; diff --git a/addons/backgrounds/register.js b/addons/backgrounds/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/backgrounds/register.js +++ b/addons/backgrounds/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/backgrounds/src/decorators/index.ts b/addons/backgrounds/src/decorators/index.ts deleted file mode 100644 index cf4a28890479..000000000000 --- a/addons/backgrounds/src/decorators/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './withBackground'; -export * from './withGrid'; diff --git a/addons/backgrounds/src/register.tsx b/addons/backgrounds/src/manager.tsx similarity index 100% rename from addons/backgrounds/src/register.tsx rename to addons/backgrounds/src/manager.tsx diff --git a/addons/backgrounds/src/preset/addDecorator.tsx b/addons/backgrounds/src/preset/addDecorator.tsx deleted file mode 100644 index 93ccff632339..000000000000 --- a/addons/backgrounds/src/preset/addDecorator.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { withGrid, withBackground } from '../decorators'; - -export const decorators = [withGrid, withBackground]; diff --git a/addons/backgrounds/src/preset/addParameter.tsx b/addons/backgrounds/src/preview.tsx similarity index 58% rename from addons/backgrounds/src/preset/addParameter.tsx rename to addons/backgrounds/src/preview.tsx index ceb1d3b41203..cc67d00f6318 100644 --- a/addons/backgrounds/src/preset/addParameter.tsx +++ b/addons/backgrounds/src/preview.tsx @@ -1,3 +1,7 @@ +import { withBackground } from './decorators/withBackground'; +import { withGrid } from './decorators/withGrid'; + +export const decorators = [withGrid, withBackground]; export const parameters = { backgrounds: { grid: { diff --git a/addons/controls/README.md b/addons/controls/README.md index 81751a70a35b..372d453b6a58 100644 --- a/addons/controls/README.md +++ b/addons/controls/README.md @@ -48,7 +48,7 @@ If you are somehow tied to knobs or prefer the knobs interface, we are happy to ### How do I migrate from addon-knobs? -If you're already using [Storybook Knobs](https://github.com/storybookjs/storybook/tree/main/addons/knobs) you should consider migrating to Controls. +If you're already using [Storybook Knobs](https://github.com/storybookjs/addon-knobs) you should consider migrating to Controls. You're probably using it for something that can be satisfied by one of the cases [described above](#writing-stories). diff --git a/addons/controls/manager.js b/addons/controls/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/controls/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/controls/package.json b/addons/controls/package.json index e30b70865099..9cfb0ce95e93 100644 --- a/addons/controls/package.json +++ b/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", @@ -25,8 +25,8 @@ "url": "https://opencollective.com/storybook" }, "license": "MIT", - "main": "dist/cjs/register.js", - "module": "dist/esm/register.js", + "main": "dist/cjs/manager.js", + "module": "dist/esm/manager.js", "types": "dist/ts3.9/index.d.ts", "typesVersions": { "<3.8": { @@ -45,22 +45,22 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/node-logger": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/node-logger": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "lodash": "^4.17.21", "ts-dedent": "^2.0.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -73,8 +73,8 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", - "sbmodern": "dist/modern/register.js", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", + "sbmodern": "dist/modern/manager.js", "storybook": { "displayName": "Controls", "icon": "https://user-images.githubusercontent.com/263385/101991669-479cc600-3c7c-11eb-93d9-38b67e8371f2.png", diff --git a/addons/controls/preset.js b/addons/controls/preset.js deleted file mode 100644 index 3dd9b66d3aa7..000000000000 --- a/addons/controls/preset.js +++ /dev/null @@ -1,8 +0,0 @@ -function managerEntries(entry = [], options) { - // eslint-disable-next-line global-require - const { checkDocsLoaded } = require('./dist/cjs/preset/checkDocsLoaded'); - checkDocsLoaded(options.configDir); - return [...entry, require.resolve('./dist/esm/register')]; -} - -module.exports = { managerEntries }; diff --git a/addons/controls/register.js b/addons/controls/register.js index 681a5d09dcec..2d916bea61a0 100644 --- a/addons/controls/register.js +++ b/addons/controls/register.js @@ -1 +1,6 @@ -import './dist/esm/register'; +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/controls/src/ControlsPanel.tsx b/addons/controls/src/ControlsPanel.tsx index 66b052a75186..6d74c4576235 100644 --- a/addons/controls/src/ControlsPanel.tsx +++ b/addons/controls/src/ControlsPanel.tsx @@ -1,5 +1,12 @@ import React, { FC } from 'react'; -import { ArgTypes, useArgs, useArgTypes, useParameter, useStorybookState } from '@storybook/api'; +import { + ArgTypes, + useArgs, + useGlobals, + useArgTypes, + useParameter, + useStorybookState, +} from '@storybook/api'; import { ArgsTable, NoControlsWarning, PresetColor, SortType } from '@storybook/components'; import { PARAM_KEY } from './constants'; @@ -13,6 +20,7 @@ interface ControlsParameters { export const ControlsPanel: FC = () => { const [args, updateArgs, resetArgs] = useArgs(); + const [globals] = useGlobals(); const rows = useArgTypes(); const isArgsStory = useParameter('__isArgsStory', false); const { @@ -41,6 +49,7 @@ export const ControlsPanel: FC = () => { compact: !expanded && hasControls, rows: withPresetColors, args, + globals, updateArgs, resetArgs, inAddonPanel: true, diff --git a/addons/controls/src/register.tsx b/addons/controls/src/manager.tsx similarity index 100% rename from addons/controls/src/register.tsx rename to addons/controls/src/manager.tsx diff --git a/addons/docs/docs/faq.md b/addons/docs/docs/faq.md index 8030502baf12..5710640cc092 100644 --- a/addons/docs/docs/faq.md +++ b/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/storybooks/storybook/tree/next/app/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, Angular, Ember, Svelte, and others. ## How does Docs interact with existing addons? diff --git a/addons/docs/docs/multiframework.md b/addons/docs/docs/multiframework.md index 967d14c90130..a70a59d14533 100644 --- a/addons/docs/docs/multiframework.md +++ b/addons/docs/docs/multiframework.md @@ -53,8 +53,6 @@ export interface ArgType { name?: string; description?: string; defaultValue?: any; - addIf?: string; - removeIf?: string; [key: string]: any; } diff --git a/addons/docs/manager.js b/addons/docs/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/docs/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/docs/package.json b/addons/docs/package.json index 7a9f29cfbbdf..2243b15c0e20 100644 --- a/addons/docs/package.json +++ b/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", @@ -59,20 +59,21 @@ "@babel/preset-env": "^7.12.11", "@jest/transform": "^26.6.2", "@mdx-js/react": "^1.6.22", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", "@storybook/mdx1-csf": "canary", - "@storybook/node-logger": "6.5.0-alpha.52", - "@storybook/postinstall": "6.5.0-alpha.52", - "@storybook/preview-web": "6.5.0-alpha.52", - "@storybook/source-loader": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/node-logger": "6.5.0-beta.7", + "@storybook/postinstall": "6.5.0-beta.7", + "@storybook/preview-web": "6.5.0-beta.7", + "@storybook/source-loader": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", + "babel-loader": "^8.0.0", "core-js": "^3.8.2", "fast-deep-equal": "^3.1.3", "global": "^4.4.0", @@ -86,23 +87,14 @@ "devDependencies": { "@babel/core": "^7.12.10", "@storybook/mdx2-csf": "canary", - "@types/util-deprecate": "^1.0.0", - "babel-loader": "^8.0.0", - "webpack": "4" + "@types/util-deprecate": "^1.0.0" }, "peerDependencies": { "@storybook/mdx2-csf": "*", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0", - "webpack": "*" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { - "@storybook/builder-webpack4": { - "optional": true - }, - "@storybook/builder-webpack5": { - "optional": true - }, "@storybook/mdx2-csf": { "optional": true }, @@ -111,15 +103,12 @@ }, "react-dom": { "optional": true - }, - "webpack": { - "optional": true } }, "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Docs", diff --git a/addons/docs/preset.js b/addons/docs/preset.js index c318823dc33a..e45ac5b4cec0 100644 --- a/addons/docs/preset.js +++ b/addons/docs/preset.js @@ -1,16 +1 @@ -const { findDistEsm } = require('@storybook/core-common'); -const { webpack } = require('./dist/cjs/frameworks/common/preset'); - -function managerEntries(entry = [], options) { - return [...entry, findDistEsm(__dirname, 'register')]; -} - -function config(entry = [], options = {}) { - return [findDistEsm(__dirname, 'frameworks/common/config'), ...entry]; -} - -module.exports = { - webpack, - managerEntries, - config, -}; +module.exports = require('./dist/cjs/preset'); diff --git a/addons/docs/preview.js b/addons/docs/preview.js new file mode 100644 index 000000000000..e726cab5a1b6 --- /dev/null +++ b/addons/docs/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preview'; diff --git a/addons/docs/register.js b/addons/docs/register.js index 980200ade086..2d916bea61a0 100644 --- a/addons/docs/register.js +++ b/addons/docs/register.js @@ -1,2 +1,6 @@ -/* eslint-disable import/extensions */ -require('./dist/esm/register.js'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/docs/src/blocks/ArgsTable.tsx b/addons/docs/src/blocks/ArgsTable.tsx index 56f0e8edba3a..d30792f387b0 100644 --- a/addons/docs/src/blocks/ArgsTable.tsx +++ b/addons/docs/src/blocks/ArgsTable.tsx @@ -11,7 +11,7 @@ import { ArgTypesExtractor } from '@storybook/docs-tools'; import { addons } from '@storybook/addons'; import { filterArgTypes, PropDescriptor } from '@storybook/store'; import Events from '@storybook/core-events'; -import { StrictArgTypes, Args } from '@storybook/csf'; +import { StrictArgTypes, Args, Globals } from '@storybook/csf'; import { DocsContext, DocsContextProps } from './DocsContext'; import { Component, CURRENT_SELECTION, PRIMARY_STORY } from './types'; @@ -42,18 +42,20 @@ type StoryProps = BaseProps & { type ArgsTableProps = BaseProps | OfProps | ComponentsProps | StoryProps; -const useArgs = ( - storyId: string, - context: DocsContextProps -): [Args, (args: Args) => void, (argNames?: string[]) => void] => { - const channel = addons.getChannel(); - +const getContext = (storyId: string, context: DocsContextProps) => { const story = context.storyById(storyId); if (!story) { throw new Error(`Unknown story: ${storyId}`); } + return context.getStoryContext(story); +}; - const storyContext = context.getStoryContext(story); +const useArgs = ( + storyId: string, + context: DocsContextProps +): [Args, (args: Args) => void, (argNames?: string[]) => void] => { + const channel = addons.getChannel(); + const storyContext = getContext(storyId, context); const [args, setArgs] = useState(storyContext.args); useEffect(() => { @@ -76,6 +78,22 @@ const useArgs = ( return [args, updateArgs, resetArgs]; }; +const useGlobals = (storyId: string, context: DocsContextProps): [Globals] => { + const channel = addons.getChannel(); + const storyContext = getContext(storyId, context); + const [globals, setGlobals] = useState(storyContext.globals); + + useEffect(() => { + const cb = (changed: { globals: Globals }) => { + setGlobals(changed.globals); + }; + channel.on(Events.GLOBALS_UPDATED, cb); + return () => channel.off(Events.GLOBALS_UPDATED, cb); + }, []); + + return [globals]; +}; + export const extractComponentArgTypes = ( component: Component, { id, storyById }: DocsContextProps, @@ -162,13 +180,14 @@ export const StoryTable: FC< const story = useStory(storyId, context); // eslint-disable-next-line prefer-const let [args, updateArgs, resetArgs] = useArgs(storyId, context); + const [globals] = useGlobals(storyId, context); if (!story) return ; const argTypes = filterArgTypes(story.argTypes, include, exclude); const mainLabel = getComponentName(component) || 'Story'; - let tabs = { [mainLabel]: { rows: argTypes, args, updateArgs, resetArgs } } as Record< + let tabs = { [mainLabel]: { rows: argTypes, args, globals, updateArgs, resetArgs } } as Record< string, PureArgsTableProps >; diff --git a/addons/docs/src/blocks/Canvas.tsx b/addons/docs/src/blocks/Canvas.tsx index bf5362857f0c..a1217e48939d 100644 --- a/addons/docs/src/blocks/Canvas.tsx +++ b/addons/docs/src/blocks/Canvas.tsx @@ -11,6 +11,7 @@ import { DocsContext, DocsContextProps } from './DocsContext'; import { SourceContext, SourceContextProps } from './SourceContainer'; import { getSourceProps, SourceState } from './Source'; import { useStories } from './useStory'; +import { CURRENT_SELECTION } from './types'; export { SourceState }; @@ -53,7 +54,10 @@ const getPreviewProps = ( ); const sourceProps = getSourceProps({ ids: targetIds }, docsContext, sourceContext); if (!sourceState) sourceState = sourceProps.state; - const stories = useStories(targetIds, docsContext); + const storyIds = targetIds.map((targetId) => + targetId === CURRENT_SELECTION ? docsContext.id : targetId + ); + const stories = useStories(storyIds, docsContext); isLoading = stories.some((s) => !s); return { diff --git a/addons/docs/src/blocks/mdx.tsx b/addons/docs/src/blocks/mdx.tsx index 3dbc6746ee99..953bd22266b3 100644 --- a/addons/docs/src/blocks/mdx.tsx +++ b/addons/docs/src/blocks/mdx.tsx @@ -91,7 +91,7 @@ export const AnchorMdx: FC = (props) => { } // Links to other pages of SB should use the base URL of the top level iframe instead of the base URL of the preview iframe. - if (target !== '_blank') { + if (target !== '_blank' && !href.startsWith('https://')) { return ( (await import('../../blocks')).DocsContainer, - getPage: async () => (await import('../../blocks')).DocsPage, - iframeHeight: 100, - }, -}; diff --git a/addons/docs/src/register.ts b/addons/docs/src/manager.ts similarity index 100% rename from addons/docs/src/register.ts rename to addons/docs/src/manager.ts diff --git a/addons/docs/src/frameworks/common/preset.ts b/addons/docs/src/preset.ts similarity index 89% rename from addons/docs/src/frameworks/common/preset.ts rename to addons/docs/src/preset.ts index ab7f02c19766..b6cb10d7e2b1 100644 --- a/addons/docs/src/frameworks/common/preset.ts +++ b/addons/docs/src/preset.ts @@ -3,7 +3,7 @@ import remarkSlug from 'remark-slug'; import remarkExternalLinks from 'remark-external-links'; import global from 'global'; -import type { BuilderConfig, Options } from '@storybook/core-common'; +import type { Options } from '@storybook/core-common'; import { logger } from '@storybook/node-logger'; // for frameworks that are not working with react, we need to configure @@ -38,16 +38,7 @@ export async function webpack( typeof createCompiler >[0] */ ) { - const { builder = 'webpack4' } = await options.presets.apply<{ - builder: BuilderConfig; - }>('core', {} as any); - - const builderName = typeof builder === 'string' ? builder : builder.name; - const resolvedBabelLoader = require.resolve('babel-loader', { - paths: builderName.match(/^webpack(4|5)$/) - ? [require.resolve(`@storybook/builder-${builderName}`)] - : [builderName], - }); + const resolvedBabelLoader = require.resolve('babel-loader'); const { module = {} } = webpackConfig; diff --git a/addons/docs/src/preview.ts b/addons/docs/src/preview.ts new file mode 100644 index 000000000000..a6269505f285 --- /dev/null +++ b/addons/docs/src/preview.ts @@ -0,0 +1,6 @@ +export const parameters = { + docs: { + getContainer: async () => (await import('./blocks')).DocsContainer, + getPage: async () => (await import('./blocks')).DocsPage, + }, +}; diff --git a/addons/essentials/package.json b/addons/essentials/package.json index 12c984685eb4..f8fb8f1c8e78 100644 --- a/addons/essentials/package.json +++ b/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", @@ -39,25 +39,25 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-backgrounds": "6.5.0-alpha.52", - "@storybook/addon-controls": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", - "@storybook/addon-measure": "6.5.0-alpha.52", - "@storybook/addon-outline": "6.5.0-alpha.52", - "@storybook/addon-toolbars": "6.5.0-alpha.52", - "@storybook/addon-viewport": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/node-logger": "6.5.0-alpha.52", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-backgrounds": "6.5.0-beta.7", + "@storybook/addon-controls": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", + "@storybook/addon-measure": "6.5.0-beta.7", + "@storybook/addon-outline": "6.5.0-beta.7", + "@storybook/addon-toolbars": "6.5.0-beta.7", + "@storybook/addon-viewport": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/node-logger": "6.5.0-beta.7", "core-js": "^3.8.2", "regenerator-runtime": "^0.13.7", "ts-dedent": "^2.0.0" }, "devDependencies": { "@babel/core": "^7.12.10", - "@storybook/vue": "6.5.0-alpha.52", + "@storybook/vue": "6.5.0-beta.7", "@types/jest": "^26.0.16", "@types/webpack-env": "^1.16.0" }, @@ -120,6 +120,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js" } diff --git a/addons/essentials/src/index.ts b/addons/essentials/src/index.ts index 7441e9fb9160..7b5bc79e3741 100644 --- a/addons/essentials/src/index.ts +++ b/addons/essentials/src/index.ts @@ -1,4 +1,4 @@ -import path, { join } from 'path'; +import path, { dirname, join } from 'path'; import { logger } from '@storybook/node-logger'; import { serverRequire } from '@storybook/core-common'; @@ -50,12 +50,7 @@ export function addons(options: PresetOptions = {}) { // as it's done in `lib/core/src/server/presets.js`. .map((addon) => { try { - return require.resolve(join(addon, 'preset')); - // eslint-disable-next-line no-empty - } catch (err) {} - - try { - return require.resolve(join(addon, 'register')); + return dirname(require.resolve(join(addon, 'package.json'))); // eslint-disable-next-line no-empty } catch (err) {} diff --git a/addons/interactions/manager.js b/addons/interactions/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/interactions/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/interactions/package.json b/addons/interactions/package.json index 7bc44f9abd94..eb4d8ed424a0 100644 --- a/addons/interactions/package.json +++ b/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", @@ -21,8 +21,8 @@ "url": "https://opencollective.com/storybook" }, "license": "MIT", - "main": "dist/cjs/register.js", - "module": "dist/esm/register.js", + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", "types": "dist/ts3.9/index.d.ts", "typesVersions": { "<3.8": { @@ -41,18 +41,20 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/instrumenter": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@devtools-ds/object-inspector": "^1.1.2", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/instrumenter": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "global": "^4.4.0", "jest-mock": "^27.0.6", - "polished": "^4.0.5", + "polished": "^4.2.2", "ts-dedent": "^2.2.0" }, "devDependencies": { @@ -61,8 +63,8 @@ "formik": "^2.2.9" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -75,7 +77,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Interactions", diff --git a/addons/interactions/preset.js b/addons/interactions/preset.js index d7d7f8fd24f9..fb325c5b170b 100644 --- a/addons/interactions/preset.js +++ b/addons/interactions/preset.js @@ -1,15 +1,10 @@ -function config(entry = []) { - return [...entry, require.resolve('./dist/esm/preset/argsEnhancers')]; -} +const { checkActionsLoaded } = require('./dist/cjs/preset/checkActionsLoaded'); -function managerEntries(entry = [], options) { - // eslint-disable-next-line global-require - const { checkActionsLoaded } = require('./dist/cjs/preset/checkActionsLoaded'); +function previewAnnotations(entry = [], options) { checkActionsLoaded(options.configDir); - return [...entry, require.resolve('./dist/esm/register')]; + return entry; } module.exports = { - config, - managerEntries, + previewAnnotations, }; diff --git a/addons/interactions/preview.js b/addons/interactions/preview.js new file mode 100644 index 000000000000..7817e1d278d2 --- /dev/null +++ b/addons/interactions/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preset/preview'; diff --git a/addons/interactions/register.js b/addons/interactions/register.js index 681a5d09dcec..2d916bea61a0 100644 --- a/addons/interactions/register.js +++ b/addons/interactions/register.js @@ -1 +1,6 @@ -import './dist/esm/register'; +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/interactions/src/Panel.tsx b/addons/interactions/src/Panel.tsx index e290d5d453ba..4693f8577991 100644 --- a/addons/interactions/src/Panel.tsx +++ b/addons/interactions/src/Panel.tsx @@ -2,7 +2,7 @@ import global from 'global'; import * as React from 'react'; import ReactDOM from 'react-dom'; import { useChannel, useParameter, StoryId } from '@storybook/api'; -import { STORY_RENDER_PHASE_CHANGED } from '@storybook/core-events'; +import { STORY_RENDER_PHASE_CHANGED, FORCE_REMOUNT } from '@storybook/core-events'; import { AddonPanel, Link, Placeholder } from '@storybook/components'; import { EVENTS, Call, CallStates, ControlStates, LogItem } from '@storybook/instrumenter'; import { styled } from '@storybook/theming'; @@ -17,6 +17,7 @@ export interface Controls { goto: (args: any) => void; next: (args: any) => void; end: (args: any) => void; + rerun: (args: any) => void; } interface AddonPanelProps { @@ -34,6 +35,8 @@ interface InteractionsPanelProps { calls: Map; endRef?: React.Ref; onScrollToEnd?: () => void; + isRerunAnimating: boolean; + setIsRerunAnimating: React.Dispatch>; } const INITIAL_CONTROL_STATES = { @@ -65,6 +68,8 @@ export const AddonPanelPure: React.FC = React.memo( isPlaying, onScrollToEnd, endRef, + isRerunAnimating, + setIsRerunAnimating, ...panelProps }) => ( @@ -78,6 +83,8 @@ export const AddonPanelPure: React.FC = React.memo( } storyFileName={fileName} onScrollToEnd={onScrollToEnd} + isRerunAnimating={isRerunAnimating} + setIsRerunAnimating={setIsRerunAnimating} /> )} {interactions.map((call) => ( @@ -110,6 +117,7 @@ export const Panel: React.FC = (props) => { const [storyId, setStoryId] = React.useState(); const [controlStates, setControlStates] = React.useState(INITIAL_CONTROL_STATES); const [isPlaying, setPlaying] = React.useState(false); + const [isRerunAnimating, setIsRerunAnimating] = React.useState(false); const [scrollTarget, setScrollTarget] = React.useState(); // Calls are tracked in a ref so we don't needlessly rerender. @@ -154,6 +162,10 @@ export const Panel: React.FC = (props) => { goto: (callId: string) => emit(EVENTS.GOTO, { storyId, callId }), next: () => emit(EVENTS.NEXT, { storyId }), end: () => emit(EVENTS.END, { storyId }), + rerun: () => { + setIsRerunAnimating(true); + emit(FORCE_REMOUNT, { storyId }); + }, }), [storyId] ); @@ -181,6 +193,8 @@ export const Panel: React.FC = (props) => { isPlaying={isPlaying} endRef={endRef} onScrollToEnd={scrollTarget && scrollToTarget} + isRerunAnimating={isRerunAnimating} + setIsRerunAnimating={setIsRerunAnimating} {...props} /> diff --git a/addons/interactions/src/Tool.tsx b/addons/interactions/src/Tool.tsx deleted file mode 100644 index cf07bd7b9b0d..000000000000 --- a/addons/interactions/src/Tool.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { ComponentProps, useState } from 'react'; -import { useChannel, useStorybookApi } from '@storybook/api'; -import { Icons, IconButton } from '@storybook/components'; -import { FORCE_REMOUNT } from '@storybook/core-events'; -import { styled } from '@storybook/theming'; -import { TOOL_ID } from './constants'; - -interface AnimatedButtonProps { - animating?: boolean; -} - -const StyledAnimatedIconButton = styled(IconButton)< - AnimatedButtonProps & ComponentProps ->(({ theme, animating, disabled }) => ({ - opacity: disabled ? 0.5 : 1, - svg: { - animation: animating && `${theme.animation.rotate360} 1000ms ease-out`, - }, -})); - -export const Tool = () => { - const { id: storyId } = useStorybookApi().getCurrentStoryData() || {}; - const emit = useChannel({}); - const [isAnimating, setIsAnimating] = useState(false); - const animateAndReplay = () => { - if (!storyId) return; - setIsAnimating(true); - emit(FORCE_REMOUNT, { storyId }); - }; - - return ( - setIsAnimating(false)} - animating={isAnimating} - disabled={!storyId} - > - - - ); -}; diff --git a/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx b/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx index 0ee5b32d843a..9619a228b507 100644 --- a/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx +++ b/addons/interactions/src/components/AccountForm/addon-interactions.stories.tsx @@ -179,7 +179,7 @@ export const Verification: CSF3Story = { argTypes: { onSubmit: { action: 'clicked' } }, }; -export const VerificationPasssword1: CSF3Story = { +export const VerificationPassword: CSF3Story = { ...Verification, play: async (context) => { const canvas = within(context.canvasElement); diff --git a/addons/interactions/src/components/MatcherResult.tsx b/addons/interactions/src/components/MatcherResult.tsx index ba75519f627b..cf52a920ae42 100644 --- a/addons/interactions/src/components/MatcherResult.tsx +++ b/addons/interactions/src/components/MatcherResult.tsx @@ -29,15 +29,17 @@ const StyledReceived = styled.span(({ theme }) => ({ export const Received = ({ value, parsed }: { value: any; parsed?: boolean }) => parsed ? ( - + ) : ( {value} ); export const Expected = ({ value, parsed }: { value: any; parsed?: boolean }) => { if (parsed) { - if (typeof value === 'string' && value.startsWith('called with')) return <>{value}; - return ; + if (typeof value === 'string' && value.startsWith('called with')) { + return <>{value}; + } + return ; } return {value}; }; diff --git a/addons/interactions/src/components/MethodCall.stories.tsx b/addons/interactions/src/components/MethodCall.stories.tsx index a2d09b71d6cc..feda43c8ff5c 100644 --- a/addons/interactions/src/components/MethodCall.stories.tsx +++ b/addons/interactions/src/components/MethodCall.stories.tsx @@ -42,7 +42,20 @@ export const Args = () => ( i)} /> - + + + 123, + asyncFn: async () => 'hello', + }} + showObjectInspector + /> diff --git a/addons/interactions/src/components/MethodCall.tsx b/addons/interactions/src/components/MethodCall.tsx index 724bf3963e27..10a3bf2c0f47 100644 --- a/addons/interactions/src/components/MethodCall.tsx +++ b/addons/interactions/src/components/MethodCall.tsx @@ -1,3 +1,4 @@ +import { ObjectInspector } from '@devtools-ds/object-inspector'; import { Call, CallRef, ElementRef } from '@storybook/instrumenter'; import { useTheme } from '@storybook/theming'; import React, { Fragment, ReactElement } from 'react'; @@ -91,11 +92,17 @@ const interleave = (nodes: ReactElement[], separator: ReactElement) => export const Node = ({ value, nested, + showObjectInspector, callsById, ...props }: { value: any; nested?: boolean; + /** + * Shows an object inspector instead of just printing the object. + * Only available for Objects + */ + showObjectInspector?: boolean; callsById?: Map; [props: string]: any; }) => { @@ -131,7 +138,7 @@ export const Node = ({ value.constructor?.name !== 'Object': return ; case Object.prototype.toString.call(value) === '[object Object]': - return ; + return ; default: return ; } @@ -199,14 +206,37 @@ export const ArrayNode = ({ value, nested = false }: { value: any[]; nested?: bo ); }; -export const ObjectNode = ({ value, nested = false }: { value: object; nested?: boolean }) => { +export const ObjectNode = ({ + showInspector, + value, + nested = false, +}: { + showInspector?: boolean; + value: object; + nested?: boolean; +}) => { + const isDarkMode = useTheme().base === 'dark'; const colors = useThemeColors(); + + if (showInspector) { + return ( + <> + + + ); + } + if (nested) { return {'{…}'}; } const nodelist = interleave( Object.entries(value) - .slice(0, 1) + .slice(0, 2) .map(([k, v]) => ( {k}: diff --git a/addons/interactions/src/components/Subnav/Subnav.tsx b/addons/interactions/src/components/Subnav/Subnav.tsx index e35b133fbf69..9b371cce947c 100644 --- a/addons/interactions/src/components/Subnav/Subnav.tsx +++ b/addons/interactions/src/components/Subnav/Subnav.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ComponentProps } from 'react'; import { Button, IconButton, @@ -37,6 +37,8 @@ export interface SubnavProps { status: Call['status']; storyFileName?: string; onScrollToEnd?: () => void; + isRerunAnimating: boolean; + setIsRerunAnimating: React.Dispatch>; } const StyledButton = styled(Button)(({ theme }) => ({ @@ -90,12 +92,27 @@ const JumpToEndButton = styled(StyledButton)({ lineHeight: '12px', }); +interface AnimatedButtonProps { + animating?: boolean; +} + +const RerunButton = styled(StyledIconButton)< + AnimatedButtonProps & ComponentProps +>(({ theme, animating, disabled }) => ({ + opacity: disabled ? 0.5 : 1, + svg: { + animation: animating && `${theme.animation.rotate360} 200ms ease-out`, + }, +})); + export const Subnav: React.FC = ({ controls, controlStates, status, storyFileName, onScrollToEnd, + isRerunAnimating, + setIsRerunAnimating, }) => { const buttonText = status === CallStates.ERROR ? 'Scroll to error' : 'Scroll to end'; @@ -135,6 +152,19 @@ export const Subnav: React.FC = ({ + + }> + setIsRerunAnimating(false)} + animating={isRerunAnimating} + disabled={isRerunAnimating} + > + + + {storyFileName && ( diff --git a/addons/interactions/src/constants.ts b/addons/interactions/src/constants.ts index 945e500e2269..3c723e93852c 100644 --- a/addons/interactions/src/constants.ts +++ b/addons/interactions/src/constants.ts @@ -1,3 +1,2 @@ export const ADDON_ID = 'storybook/interactions'; -export const TOOL_ID = `${ADDON_ID}/tool`; export const PANEL_ID = `${ADDON_ID}/panel`; diff --git a/addons/interactions/src/register.tsx b/addons/interactions/src/manager.tsx similarity index 54% rename from addons/interactions/src/register.tsx rename to addons/interactions/src/manager.tsx index 836f74a17db9..454945d6c44a 100644 --- a/addons/interactions/src/register.tsx +++ b/addons/interactions/src/manager.tsx @@ -1,17 +1,9 @@ import { addons, types } from '@storybook/addons'; -import { ADDON_ID, TOOL_ID, PANEL_ID } from './constants'; -import { Tool } from './Tool'; +import { ADDON_ID, PANEL_ID } from './constants'; import { Panel } from './Panel'; addons.register(ADDON_ID, () => { - addons.add(TOOL_ID, { - type: types.TOOL, - title: 'Restart', - match: ({ viewMode }) => viewMode === 'story', - render: Tool, - }); - addons.add(PANEL_ID, { type: types.PANEL, title: 'Interactions', diff --git a/addons/interactions/src/preset/argsEnhancers.ts b/addons/interactions/src/preset/preview.ts similarity index 100% rename from addons/interactions/src/preset/argsEnhancers.ts rename to addons/interactions/src/preset/preview.ts diff --git a/addons/jest/manager.js b/addons/jest/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/jest/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/jest/package.json b/addons/jest/package.json index 6f4e7613da6f..122e7ec5aa72 100644 --- a/addons/jest/package.json +++ b/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "React storybook addon that show component jest report", "keywords": [ "addon", @@ -47,11 +47,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "global": "^4.4.0", "react-sizeme": "^3.0.1", @@ -62,8 +63,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -76,7 +77,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Jest", diff --git a/addons/jest/register.js b/addons/jest/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/jest/register.js +++ b/addons/jest/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/jest/src/register.tsx b/addons/jest/src/manager.tsx similarity index 100% rename from addons/jest/src/register.tsx rename to addons/jest/src/manager.tsx diff --git a/addons/links/README.md b/addons/links/README.md index 4fa4c342921e..b8e1d7e4e5ef 100644 --- a/addons/links/README.md +++ b/addons/links/README.md @@ -55,7 +55,8 @@ With that, you can link an event in a component to any story in the Storybook. You can also pass a function instead for any of above parameter. That function accepts arguments emitted by the event and it should return a string: ```js -import { LinkTo, linkTo } from '@storybook/addon-links'; +import { linkTo } from '@storybook/addon-links'; +import LinkTo from '@storybook/addon-links/react'; export default { title: 'Select', diff --git a/addons/links/manager.js b/addons/links/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/links/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/links/package.json b/addons/links/package.json index 17efcd9ac141..7bab938858d0 100644 --- a/addons/links/package.json +++ b/addons/links/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-links", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", @@ -41,11 +41,11 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/router": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.0-beta.7", "@types/qs": "^6.9.5", "core-js": "^3.8.2", "global": "^4.4.0", @@ -58,8 +58,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -72,7 +72,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Links", diff --git a/addons/links/preset.js b/addons/links/preset.js deleted file mode 100644 index 2b5ed5ac00d6..000000000000 --- a/addons/links/preset.js +++ /dev/null @@ -1,13 +0,0 @@ -function managerEntries(entry = []) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -function config(entry = [], { addDecorator = true } = {}) { - const linkConfig = []; - if (addDecorator) { - linkConfig.push(require.resolve('./dist/esm/preset/addDecorator')); - } - return [...entry, ...linkConfig]; -} - -module.exports = { managerEntries, config }; diff --git a/addons/links/preview.js b/addons/links/preview.js new file mode 100644 index 000000000000..e726cab5a1b6 --- /dev/null +++ b/addons/links/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preview'; diff --git a/addons/links/react.js b/addons/links/react.js index 835dd0388e29..d0e3270119d6 100644 --- a/addons/links/react.js +++ b/addons/links/react.js @@ -1 +1,3 @@ -module.exports = require('./dist/cjs/react'); +import LinkTo from './dist/esm/react'; + +export default LinkTo; diff --git a/addons/links/register.js b/addons/links/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/links/register.js +++ b/addons/links/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/links/src/index.ts b/addons/links/src/index.ts index 239fae7ba1a8..a41227513de1 100644 --- a/addons/links/src/index.ts +++ b/addons/links/src/index.ts @@ -14,7 +14,7 @@ export function LinkTo(): null { return null; } -export { linkTo, hrefTo, withLinks, navigate } from './preview'; +export { linkTo, hrefTo, withLinks, navigate } from './utils'; if (module && module.hot && module.hot.decline) { module.hot.decline(); diff --git a/addons/links/src/register.ts b/addons/links/src/manager.ts similarity index 100% rename from addons/links/src/register.ts rename to addons/links/src/manager.ts diff --git a/addons/links/src/preset/addDecorator.ts b/addons/links/src/preset/addDecorator.ts deleted file mode 100644 index ff68743b1a37..000000000000 --- a/addons/links/src/preset/addDecorator.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { withLinks } from '../index'; - -export const decorators = [withLinks]; diff --git a/addons/links/src/preview.ts b/addons/links/src/preview.ts index 3082bedc09bc..1527786e81af 100644 --- a/addons/links/src/preview.ts +++ b/addons/links/src/preview.ts @@ -1,91 +1,3 @@ -import global from 'global'; -import qs from 'qs'; -import { addons, makeDecorator } from '@storybook/addons'; -import { STORY_CHANGED, SELECT_STORY } from '@storybook/core-events'; -import type { StoryId, StoryName, ComponentTitle } from '@storybook/csf'; -import { toId } from '@storybook/csf'; -import { PARAM_KEY } from './constants'; +import { withLinks } from './index'; -const { document, HTMLElement } = global; - -interface ParamsId { - storyId: StoryId; -} -interface ParamsCombo { - kind?: ComponentTitle; - story?: StoryName; -} - -export const navigate = (params: ParamsId | ParamsCombo) => - addons.getChannel().emit(SELECT_STORY, params); - -export const hrefTo = (title: ComponentTitle, name: StoryName): Promise => { - return new Promise((resolve) => { - const { location } = document; - const query = qs.parse(location.search, { ignoreQueryPrefix: true }); - const existingId = [].concat(query.id)[0]; - const titleToLink = title || existingId.split('--', 2)[0]; - const id = toId(titleToLink, name); - const url = `${location.origin + location.pathname}?${qs.stringify( - { ...query, id }, - { encode: false } - )}`; - - resolve(url); - }); -}; - -const valueOrCall = (args: string[]) => (value: string | ((...args: string[]) => string)) => - typeof value === 'function' ? value(...args) : value; - -export const linkTo = - (idOrTitle: string, nameInput?: string | ((...args: any[]) => string)) => - (...args: any[]) => { - const resolver = valueOrCall(args); - const title = resolver(idOrTitle); - const name = resolver(nameInput); - - if (title?.match(/--/) && !name) { - navigate({ storyId: title }); - } else { - navigate({ kind: title, story: name }); - } - }; - -const linksListener = (e: Event) => { - const { target } = e; - if (!(target instanceof HTMLElement)) { - return; - } - const element = target as HTMLElement; - const { sbKind: kind, sbStory: story } = element.dataset; - if (kind || story) { - e.preventDefault(); - navigate({ kind, story }); - } -}; - -let hasListener = false; - -const on = () => { - if (!hasListener) { - hasListener = true; - document.addEventListener('click', linksListener); - } -}; -const off = () => { - if (hasListener) { - hasListener = false; - document.removeEventListener('click', linksListener); - } -}; - -export const withLinks = makeDecorator({ - name: 'withLinks', - parameterName: PARAM_KEY, - wrapper: (getStory, context) => { - on(); - addons.getChannel().once(STORY_CHANGED, off); - return getStory(context); - }, -}); +export const decorators = [withLinks]; diff --git a/addons/links/src/react/components/link.tsx b/addons/links/src/react/components/link.tsx index fccca70d04a5..aa6207eff75c 100644 --- a/addons/links/src/react/components/link.tsx +++ b/addons/links/src/react/components/link.tsx @@ -1,6 +1,6 @@ import React, { MouseEvent, PureComponent, ReactNode } from 'react'; -import { navigate, hrefTo } from '../../preview'; +import { navigate, hrefTo } from '../../utils'; // FIXME: copied from Typography.Link. Code is duplicated to // avoid emotion dependency which breaks React 15.x back-compat diff --git a/addons/links/src/preview.test.ts b/addons/links/src/utils.test.ts similarity index 97% rename from addons/links/src/preview.test.ts rename to addons/links/src/utils.test.ts index f5dd3af355f1..fb2126018bf6 100644 --- a/addons/links/src/preview.test.ts +++ b/addons/links/src/utils.test.ts @@ -1,7 +1,7 @@ import { addons } from '@storybook/addons'; import { SELECT_STORY } from '@storybook/core-events'; -import { linkTo, hrefTo } from './preview'; +import { linkTo, hrefTo } from './utils'; jest.mock('@storybook/addons'); jest.mock('global', () => ({ diff --git a/addons/links/src/utils.ts b/addons/links/src/utils.ts new file mode 100644 index 000000000000..3082bedc09bc --- /dev/null +++ b/addons/links/src/utils.ts @@ -0,0 +1,91 @@ +import global from 'global'; +import qs from 'qs'; +import { addons, makeDecorator } from '@storybook/addons'; +import { STORY_CHANGED, SELECT_STORY } from '@storybook/core-events'; +import type { StoryId, StoryName, ComponentTitle } from '@storybook/csf'; +import { toId } from '@storybook/csf'; +import { PARAM_KEY } from './constants'; + +const { document, HTMLElement } = global; + +interface ParamsId { + storyId: StoryId; +} +interface ParamsCombo { + kind?: ComponentTitle; + story?: StoryName; +} + +export const navigate = (params: ParamsId | ParamsCombo) => + addons.getChannel().emit(SELECT_STORY, params); + +export const hrefTo = (title: ComponentTitle, name: StoryName): Promise => { + return new Promise((resolve) => { + const { location } = document; + const query = qs.parse(location.search, { ignoreQueryPrefix: true }); + const existingId = [].concat(query.id)[0]; + const titleToLink = title || existingId.split('--', 2)[0]; + const id = toId(titleToLink, name); + const url = `${location.origin + location.pathname}?${qs.stringify( + { ...query, id }, + { encode: false } + )}`; + + resolve(url); + }); +}; + +const valueOrCall = (args: string[]) => (value: string | ((...args: string[]) => string)) => + typeof value === 'function' ? value(...args) : value; + +export const linkTo = + (idOrTitle: string, nameInput?: string | ((...args: any[]) => string)) => + (...args: any[]) => { + const resolver = valueOrCall(args); + const title = resolver(idOrTitle); + const name = resolver(nameInput); + + if (title?.match(/--/) && !name) { + navigate({ storyId: title }); + } else { + navigate({ kind: title, story: name }); + } + }; + +const linksListener = (e: Event) => { + const { target } = e; + if (!(target instanceof HTMLElement)) { + return; + } + const element = target as HTMLElement; + const { sbKind: kind, sbStory: story } = element.dataset; + if (kind || story) { + e.preventDefault(); + navigate({ kind, story }); + } +}; + +let hasListener = false; + +const on = () => { + if (!hasListener) { + hasListener = true; + document.addEventListener('click', linksListener); + } +}; +const off = () => { + if (hasListener) { + hasListener = false; + document.removeEventListener('click', linksListener); + } +}; + +export const withLinks = makeDecorator({ + name: 'withLinks', + parameterName: PARAM_KEY, + wrapper: (getStory, context) => { + on(); + addons.getChannel().once(STORY_CHANGED, off); + return getStory(context); + }, +}); diff --git a/addons/measure/manager.js b/addons/measure/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/measure/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/measure/package.json b/addons/measure/package.json index fd10abe4b9ec..96abbc0ec6e5 100644 --- a/addons/measure/package.json +++ b/addons/measure/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-measure", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Inspect layouts by visualizing the box model", "keywords": [ "storybook-addons", @@ -44,12 +44,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", "core-js": "^3.8.2", "global": "^4.4.0" }, @@ -57,8 +57,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -71,7 +71,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Measure", diff --git a/addons/measure/preset.js b/addons/measure/preset.js deleted file mode 100644 index 459bbb650ccd..000000000000 --- a/addons/measure/preset.js +++ /dev/null @@ -1,12 +0,0 @@ -function config(entry = []) { - return [...entry, require.resolve('./dist/esm/preset/addDecorator')]; -} - -function managerEntries(entry = [], options) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -module.exports = { - managerEntries, - config, -}; diff --git a/addons/measure/preview.js b/addons/measure/preview.js new file mode 100644 index 000000000000..e726cab5a1b6 --- /dev/null +++ b/addons/measure/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preview'; diff --git a/addons/measure/register.js b/addons/measure/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/measure/register.js +++ b/addons/measure/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/measure/src/register.tsx b/addons/measure/src/manager.tsx similarity index 100% rename from addons/measure/src/register.tsx rename to addons/measure/src/manager.tsx diff --git a/addons/measure/src/preset/addDecorator.tsx b/addons/measure/src/preview.tsx similarity index 51% rename from addons/measure/src/preset/addDecorator.tsx rename to addons/measure/src/preview.tsx index 8aabbd42a2da..c1433b927efa 100644 --- a/addons/measure/src/preset/addDecorator.tsx +++ b/addons/measure/src/preview.tsx @@ -1,5 +1,5 @@ -import { withMeasure } from '../withMeasure'; -import { PARAM_KEY } from '../constants'; +import { withMeasure } from './withMeasure'; +import { PARAM_KEY } from './constants'; export const decorators = [withMeasure]; diff --git a/addons/outline/manager.js b/addons/outline/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/outline/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/outline/package.json b/addons/outline/package.json index 6504042bfff9..ec59c1f4fb06 100644 --- a/addons/outline/package.json +++ b/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", @@ -47,12 +47,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", "core-js": "^3.8.2", "global": "^4.4.0", "regenerator-runtime": "^0.13.7", @@ -62,8 +62,8 @@ "@types/webpack-env": "^1.16.0" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -76,7 +76,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Outline", diff --git a/addons/outline/preset.js b/addons/outline/preset.js deleted file mode 100644 index 459bbb650ccd..000000000000 --- a/addons/outline/preset.js +++ /dev/null @@ -1,12 +0,0 @@ -function config(entry = []) { - return [...entry, require.resolve('./dist/esm/preset/addDecorator')]; -} - -function managerEntries(entry = [], options) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -module.exports = { - managerEntries, - config, -}; diff --git a/addons/outline/preview.js b/addons/outline/preview.js new file mode 100644 index 000000000000..7817e1d278d2 --- /dev/null +++ b/addons/outline/preview.js @@ -0,0 +1 @@ +export * from './dist/esm/preset/preview'; diff --git a/addons/outline/register.js b/addons/outline/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/outline/register.js +++ b/addons/outline/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/outline/src/register.tsx b/addons/outline/src/manager.tsx similarity index 100% rename from addons/outline/src/register.tsx rename to addons/outline/src/manager.tsx diff --git a/addons/outline/src/preset/addDecorator.tsx b/addons/outline/src/preset/preview.tsx similarity index 100% rename from addons/outline/src/preset/addDecorator.tsx rename to addons/outline/src/preset/preview.tsx diff --git a/addons/storyshots/storyshots-core/README.md b/addons/storyshots/storyshots-core/README.md index 05a9d2fcdc3f..30404b8b2f8a 100644 --- a/addons/storyshots/storyshots-core/README.md +++ b/addons/storyshots/storyshots-core/README.md @@ -66,7 +66,7 @@ If you still need to configure jest you can use the resources mentioned below: **NOTE**: if you are using Storybook 5.3's `main.js` to list story files, this is no longer needed. -Sometimes it's useful to configure Storybook with Webpack's require.context feature. You could be loading stories [one of two ways](https://storybook.js.org/docs/react/writing-stories/loading-stories). +Sometimes it's useful to configure Storybook with Webpack's require.context feature. You could be loading stories [one of two ways](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/basics/writing-stories/index.md#loading-stories). 1. If you're using the `storiesOf` API, you can integrate it this way: diff --git a/addons/storyshots/storyshots-core/package.json b/addons/storyshots/storyshots-core/package.json index f9ae8b29c029..df4171e6691c 100644 --- a/addons/storyshots/storyshots-core/package.json +++ b/addons/storyshots/storyshots-core/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storyshots", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Take a code snapshot of every story automatically with Jest", "keywords": [ "addon", @@ -45,13 +45,13 @@ }, "dependencies": { "@jest/transform": "^26.6.2", - "@storybook/addons": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", "@storybook/babel-plugin-require-context-hook": "1.0.1", - "@storybook/client-api": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-client": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", + "@storybook/client-api": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-client": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", "@types/glob": "^7.1.3", "@types/jest": "^26.0.16", "@types/jest-specific-snapshot": "^0.5.3", @@ -69,15 +69,15 @@ "devDependencies": { "@angular/core": "^11.2.0", "@angular/platform-browser-dynamic": "^11.2.0", - "@storybook/addon-docs": "6.5.0-alpha.52", - "@storybook/angular": "6.5.0-alpha.52", - "@storybook/react": "6.5.0-alpha.52", - "@storybook/vue": "6.5.0-alpha.52", - "@storybook/vue3": "6.5.0-alpha.52", + "@emotion/jest": "^11.8.0", + "@storybook/addon-docs": "6.5.0-beta.7", + "@storybook/angular": "6.5.0-beta.7", + "@storybook/react": "6.5.0-beta.7", + "@storybook/vue": "6.5.0-beta.7", + "@storybook/vue3": "6.5.0-beta.7", "babel-loader": "^8.0.0", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.1", - "jest-emotion": "^10.0.32", "jest-preset-angular": "^8.3.2", "jest-vue-preprocessor": "^1.7.1", "rxjs": "^6.6.3", @@ -94,8 +94,8 @@ "jest-preset-angular": "*", "jest-vue-preprocessor": "*", "preact": "^10.5.13", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", "rxjs": "*", "svelte": "*", "vue": "*", @@ -151,7 +151,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "storybook": { "displayName": "Storyshots", "icon": "https://user-images.githubusercontent.com/263385/101991676-48cdf300-3c7c-11eb-8aa1-944dab6ab29b.png", diff --git a/addons/storyshots/storyshots-core/stories/storyshot.enzyme.test.js b/addons/storyshots/storyshots-core/stories/storyshot.enzyme.test.js index ef3fb2f198cb..96e285722d44 100644 --- a/addons/storyshots/storyshots-core/stories/storyshot.enzyme.test.js +++ b/addons/storyshots/storyshots-core/stories/storyshot.enzyme.test.js @@ -1,12 +1,9 @@ import path from 'path'; import { mount } from 'enzyme'; -import { createSerializer as enzymeSerializer } from 'enzyme-to-json'; -import { createSerializer as emotionSerializer } from 'jest-emotion'; import initStoryshots from '../dist/ts3.9'; initStoryshots({ framework: 'react', configPath: path.join(__dirname, '..', '.storybook'), renderer: mount, - snapshotSerializers: [enzymeSerializer(), emotionSerializer()], }); diff --git a/addons/storyshots/storyshots-puppeteer/README.md b/addons/storyshots/storyshots-puppeteer/README.md index 9c793d56f0a5..c2b6ab49566b 100644 --- a/addons/storyshots/storyshots-puppeteer/README.md +++ b/addons/storyshots/storyshots-puppeteer/README.md @@ -8,13 +8,13 @@ Add the following modules into your app. npm install @storybook/addon-storyshots-puppeteer puppeteer --save-dev ``` -⚠️ As of Storybook 5.3 `puppeteer` is no more included in addon dependencies and must be added to your project directly. +⚠️ As of Storybook 5.3 `puppeteer` is no longer included in the addon dependencies and must be added to your project directly. ## Configure Storyshots for Puppeteer tests ⚠️ **React-native** is **not supported** by this test function. -When willing to run Puppeteer tests for your stories, you have two options: +When running Puppeteer tests for your stories, you have two options: - Have a storybook running (ie. accessible via http(s), for instance using `npm run storybook`) - Have a static build of the storybook (for instance, using `npm run build-storybook`) diff --git a/addons/storyshots/storyshots-puppeteer/package.json b/addons/storyshots/storyshots-puppeteer/package.json index d9937de85c99..e5e36b90ebd2 100644 --- a/addons/storyshots/storyshots-puppeteer/package.json +++ b/addons/storyshots/storyshots-puppeteer/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storyshots-puppeteer", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Image snapshots addition to StoryShots based on puppeteer", "keywords": [ "addon", @@ -41,19 +41,19 @@ }, "dependencies": { "@axe-core/puppeteer": "^4.2.0", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/node-logger": "6.5.0-alpha.52", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/node-logger": "6.5.0-beta.7", "@types/jest-image-snapshot": "^4.1.3", "core-js": "^3.8.2", "jest-image-snapshot": "^4.3.0", "regenerator-runtime": "^0.13.7" }, "devDependencies": { - "@storybook/csf": "0.0.2--canary.507502b.0", + "@storybook/csf": "0.0.2--canary.4566f4d.1", "@types/puppeteer": "^5.4.0" }, "peerDependencies": { - "@storybook/addon-storyshots": "6.5.0-alpha.52", + "@storybook/addon-storyshots": "6.5.0-beta.7", "puppeteer": "^2.0.0 || ^3.0.0" }, "peerDependenciesMeta": { @@ -64,5 +64,5 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65" + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74" } diff --git a/addons/storysource/package.json b/addons/storysource/package.json index 9d3d1de43ab7..84d8e1830b9d 100644 --- a/addons/storysource/package.json +++ b/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", @@ -41,13 +41,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/router": "6.5.0-alpha.52", - "@storybook/source-loader": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/router": "6.5.0-beta.7", + "@storybook/source-loader": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "estraverse": "^5.2.0", "loader-utils": "^2.0.0", @@ -60,8 +60,8 @@ "@types/react-syntax-highlighter": "^11.0.5" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -74,7 +74,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Storysource", diff --git a/addons/storysource/preset.js b/addons/storysource/preset.js index 9a53f8d68228..9ffb6ac993f5 100644 --- a/addons/storysource/preset.js +++ b/addons/storysource/preset.js @@ -25,7 +25,7 @@ function webpack(webpackConfig = {}, options = {}) { } function managerEntries(entry = []) { - return [...entry, require.resolve('./dist/esm/register')]; + return [...entry, require.resolve('./dist/esm/manager')]; } module.exports = { webpack, managerEntries }; diff --git a/addons/storysource/register.js b/addons/storysource/register.js index f209c0eb3703..4e287d25b151 100644 --- a/addons/storysource/register.js +++ b/addons/storysource/register.js @@ -1 +1 @@ -require('./dist/esm/register'); +import './dist/esm/manager'; diff --git a/addons/storysource/src/register.tsx b/addons/storysource/src/manager.tsx similarity index 100% rename from addons/storysource/src/register.tsx rename to addons/storysource/src/manager.tsx diff --git a/addons/toolbars/manager.js b/addons/toolbars/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/toolbars/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/toolbars/package.json b/addons/toolbars/package.json index 98ab2dfc9e98..f793bc755271 100644 --- a/addons/toolbars/package.json +++ b/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", @@ -25,9 +25,9 @@ "url": "https://opencollective.com/storybook" }, "license": "MIT", - "main": "dist/cjs/register.js", - "module": "dist/esm/register.js", - "types": "dist/ts3.9/register.d.ts", + "main": "dist/cjs/manager.js", + "module": "dist/esm/manager.js", + "types": "dist/ts3.9/manager.d.ts", "typesVersions": { "<3.8": { "dist/ts3.9/*": [ @@ -45,16 +45,17 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "regenerator-runtime": "^0.13.7" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -67,8 +68,8 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", - "sbmodern": "dist/modern/register.js", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", + "sbmodern": "dist/modern/manager.js", "storybook": { "displayName": "Toolbars", "icon": "https://user-images.githubusercontent.com/263385/101991677-48cdf300-3c7c-11eb-93b4-19b0e3366959.png", diff --git a/addons/toolbars/preset.js b/addons/toolbars/preset.js deleted file mode 100644 index 656f27562a44..000000000000 --- a/addons/toolbars/preset.js +++ /dev/null @@ -1,5 +0,0 @@ -function managerEntries(entry = []) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -module.exports = { managerEntries }; diff --git a/addons/toolbars/register.js b/addons/toolbars/register.js index 681a5d09dcec..2d916bea61a0 100644 --- a/addons/toolbars/register.js +++ b/addons/toolbars/register.js @@ -1 +1,6 @@ -import './dist/esm/register'; +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/toolbars/src/components/ToolbarMenuList.tsx b/addons/toolbars/src/components/ToolbarMenuList.tsx index 0f5bef8764fa..ae921689ad89 100644 --- a/addons/toolbars/src/components/ToolbarMenuList.tsx +++ b/addons/toolbars/src/components/ToolbarMenuList.tsx @@ -3,7 +3,7 @@ import { useGlobals } from '@storybook/api'; import { WithTooltip, TooltipLinkList } from '@storybook/components'; import { ToolbarMenuButton } from './ToolbarMenuButton'; import { withKeyboardCycle, WithKeyboardCycleProps } from '../hoc/withKeyboardCycle'; -import { getSelectedIcon } from '../utils/get-selected-icon'; +import { getSelectedIcon, getSelectedTitle } from '../utils/get-selected'; import { ToolbarMenuProps } from '../types'; import { ToolbarMenuListItem } from './ToolbarMenuListItem'; @@ -22,7 +22,7 @@ export const ToolbarMenuList: FC = withKeyboardCycle( id, name, description, - toolbar: { icon: _icon, items, title: _title, showName, preventDynamicIcon }, + toolbar: { icon: _icon, items, title: _title, showName, preventDynamicIcon, dynamicTitle }, }) => { const [globals, updateGlobals] = useGlobals(); @@ -40,6 +40,10 @@ export const ToolbarMenuList: FC = withKeyboardCycle( title = name; } + if (dynamicTitle) { + title = getSelectedTitle({ currentValue, items }) || title; + } + const handleItemClick = useCallback( (value: string) => { updateGlobals({ [id]: value }); diff --git a/addons/toolbars/src/register.tsx b/addons/toolbars/src/manager.tsx similarity index 100% rename from addons/toolbars/src/register.tsx rename to addons/toolbars/src/manager.tsx diff --git a/addons/toolbars/src/types.ts b/addons/toolbars/src/types.ts index 372302a33e5c..078e007e6220 100644 --- a/addons/toolbars/src/types.ts +++ b/addons/toolbars/src/types.ts @@ -33,6 +33,8 @@ export interface NormalizedToolbarConfig { shortcuts?: ToolbarShortcuts; /** @deprecated "name" no longer dual purposes as title - use "title" if a title is wanted */ showName?: boolean; + /** Change title based on selected value */ + dynamicTitle?: boolean; } export type NormalizedToolbarArgType = ArgType & { diff --git a/addons/toolbars/src/utils/get-selected-icon.ts b/addons/toolbars/src/utils/get-selected-icon.ts deleted file mode 100644 index fb0e201e14d2..000000000000 --- a/addons/toolbars/src/utils/get-selected-icon.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ToolbarItem } from '../types'; - -interface GetSelectedIconProps { - currentValue: string | null; - items: ToolbarItem[]; -} - -export const getSelectedIcon = ({ currentValue, items }: GetSelectedIconProps) => { - const selectedItem = currentValue != null && items.find((item) => item.value === currentValue); - const selectedIcon = selectedItem && selectedItem.icon; - - return selectedIcon; -}; diff --git a/addons/toolbars/src/utils/get-selected.ts b/addons/toolbars/src/utils/get-selected.ts new file mode 100644 index 000000000000..245f0b9fe04a --- /dev/null +++ b/addons/toolbars/src/utils/get-selected.ts @@ -0,0 +1,21 @@ +import { ToolbarItem } from '../types'; + +interface GetSelectedItemProps { + currentValue: string | null; + items: ToolbarItem[]; +} + +export const getSelectedItem = ({ currentValue, items }: GetSelectedItemProps) => { + const selectedItem = currentValue != null && items.find((item) => item.value === currentValue); + return selectedItem; +}; + +export const getSelectedIcon = ({ currentValue, items }: GetSelectedItemProps) => { + const selectedItem = getSelectedItem({ currentValue, items }); + return selectedItem?.icon; +}; + +export const getSelectedTitle = ({ currentValue, items }: GetSelectedItemProps) => { + const selectedItem = getSelectedItem({ currentValue, items }); + return selectedItem?.title; +}; diff --git a/addons/viewport/manager.js b/addons/viewport/manager.js new file mode 100644 index 000000000000..4e287d25b151 --- /dev/null +++ b/addons/viewport/manager.js @@ -0,0 +1 @@ +import './dist/esm/manager'; diff --git a/addons/viewport/package.json b/addons/viewport/package.json index 0a9bc78586fb..bae7cc8f1724 100644 --- a/addons/viewport/package.json +++ b/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", @@ -42,12 +42,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "core-js": "^3.8.2", "global": "^4.4.0", "memoizerific": "^1.11.3", @@ -55,8 +55,8 @@ "regenerator-runtime": "^0.13.7" }, "peerDependencies": { - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "react": { @@ -69,7 +69,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/preview.js", "storybook": { "displayName": "Viewport", diff --git a/addons/viewport/preset.js b/addons/viewport/preset.js deleted file mode 100644 index 656f27562a44..000000000000 --- a/addons/viewport/preset.js +++ /dev/null @@ -1,5 +0,0 @@ -function managerEntries(entry = []) { - return [...entry, require.resolve('./dist/esm/register')]; -} - -module.exports = { managerEntries }; diff --git a/addons/viewport/register.js b/addons/viewport/register.js index f209c0eb3703..2d916bea61a0 100644 --- a/addons/viewport/register.js +++ b/addons/viewport/register.js @@ -1 +1,6 @@ -require('./dist/esm/register'); +import { once } from '@storybook/client-logger'; +import './manager'; + +once.warn( + 'register.js is deprecated see https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#deprecated-registerjs' +); diff --git a/addons/viewport/src/register.tsx b/addons/viewport/src/manager.tsx similarity index 100% rename from addons/viewport/src/register.tsx rename to addons/viewport/src/manager.tsx diff --git a/app/angular/README.md b/app/angular/README.md index 24e320e7b728..f18b4cdfb590 100644 --- a/app/angular/README.md +++ b/app/angular/README.md @@ -19,5 +19,5 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/angular/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/angular/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/angular/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. diff --git a/app/angular/package.json b/app/angular/package.json index 8c5864ca9adf..3c1702baeaa8 100644 --- a/app/angular/package.json +++ b/app/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Angular: Develop Angular Components in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -45,17 +45,17 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/node-logger": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/node-logger": "6.5.0-beta.7", "@storybook/semver": "^7.3.2", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/react": "^16.14.23", "@types/react-dom": "^16.9.14", @@ -137,5 +137,5 @@ "access": "public" }, "builders": "dist/ts3.9/builders/builders.json", - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65" + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74" } diff --git a/app/angular/src/builders/build-storybook/index.spec.ts b/app/angular/src/builders/build-storybook/index.spec.ts index 2eb9cb922d56..c396c9cc6d9c 100644 --- a/app/angular/src/builders/build-storybook/index.spec.ts +++ b/app/angular/src/builders/build-storybook/index.spec.ts @@ -84,6 +84,7 @@ describe('Build Storybook Builder', () => { outputDir: 'storybook-static', mode: 'static', tsConfig: './storybook/tsconfig.ts', + webpackStatsJson: false, }); }); @@ -109,6 +110,34 @@ describe('Build Storybook Builder', () => { outputDir: 'storybook-static', mode: 'static', tsConfig: 'path/to/tsConfig.json', + webpackStatsJson: false, + }); + }); + + it('should build storybook with webpack stats.json', async () => { + const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', { + tsConfig: 'path/to/tsConfig.json', + compodoc: false, + webpackStatsJson: true, + }); + + const output = await run.result; + + await run.stop(); + + expect(output.success).toBeTruthy(); + expect(cpSpawnMock.spawn).not.toHaveBeenCalledWith(); + expect(buildStandaloneMock).toHaveBeenCalledWith({ + angularBrowserTarget: null, + angularBuilderContext: expect.any(Object), + angularBuilderOptions: {}, + configDir: '.storybook', + loglevel: undefined, + quiet: false, + outputDir: 'storybook-static', + mode: 'static', + tsConfig: 'path/to/tsConfig.json', + webpackStatsJson: true, }); }); @@ -162,6 +191,7 @@ describe('Build Storybook Builder', () => { outputDir: 'storybook-static', mode: 'static', tsConfig: './storybook/tsconfig.ts', + webpackStatsJson: false, }); }); @@ -188,6 +218,7 @@ describe('Build Storybook Builder', () => { outputDir: 'storybook-static', mode: 'static', tsConfig: 'path/to/tsConfig.json', + webpackStatsJson: false, }); }); }); diff --git a/app/angular/src/builders/build-storybook/index.ts b/app/angular/src/builders/build-storybook/index.ts index 1995b4efa568..462efad1bd4b 100644 --- a/app/angular/src/builders/build-storybook/index.ts +++ b/app/angular/src/builders/build-storybook/index.ts @@ -31,7 +31,7 @@ export type StorybookBuilderOptions = JsonObject & { } & Pick< // makes sure the option exists CLIOptions, - 'outputDir' | 'configDir' | 'loglevel' | 'quiet' | 'docs' + 'outputDir' | 'configDir' | 'loglevel' | 'quiet' | 'docs' | 'webpackStatsJson' >; export type StorybookBuilderOutput = JsonObject & BuilderOutput & {}; @@ -62,6 +62,7 @@ function commandBuilder( loglevel, outputDir, quiet, + webpackStatsJson, } = options; const standaloneOptions: StandaloneOptions = { @@ -77,6 +78,7 @@ function commandBuilder( ...(styles ? { styles } : {}), }, tsConfig, + webpackStatsJson, }; return standaloneOptions; }), diff --git a/app/angular/src/builders/build-storybook/schema.json b/app/angular/src/builders/build-storybook/schema.json index d20f55765ebf..2fa4edad3f2d 100644 --- a/app/angular/src/builders/build-storybook/schema.json +++ b/app/angular/src/builders/build-storybook/schema.json @@ -52,6 +52,11 @@ "type": "string" } }, + "webpackStatsJson": { + "type": "boolean", + "description": "Write Webpack Stats JSON to disk", + "default": false + }, "styles": { "type": "array", "description": "Global styles to be included in the build.", @@ -69,8 +74,7 @@ "type": "array", "items": { "type": "string" - }, - "default": [] + } } }, "additionalProperties": false, diff --git a/app/angular/src/builders/start-storybook/schema.json b/app/angular/src/builders/start-storybook/schema.json index 9911fe8e7bed..3c78f907bdd1 100644 --- a/app/angular/src/builders/start-storybook/schema.json +++ b/app/angular/src/builders/start-storybook/schema.json @@ -96,8 +96,7 @@ "type": "array", "items": { "type": "string" - }, - "default": [] + } } }, "additionalProperties": false, diff --git a/app/angular/src/builders/utils/build-standalone-errors-handler.ts b/app/angular/src/builders/utils/build-standalone-errors-handler.ts index d912c0163126..126ad4836c26 100644 --- a/app/angular/src/builders/utils/build-standalone-errors-handler.ts +++ b/app/angular/src/builders/utils/build-standalone-errors-handler.ts @@ -21,11 +21,11 @@ export const buildStandaloneErrorHandler = (error: any): any => { logger.line(); return error.close ? dedent` - FATAL broken build!, will close the process, - Fix the error below and restart storybook. - ` + FATAL broken build!, will close the process, + Fix the error below and restart storybook. + ` : dedent` - Broken build, fix the error above. - You may need to refresh the browser. - `; + Broken build, fix the error above. + You may need to refresh the browser. + `; }; diff --git a/app/angular/src/client/preview/index.ts b/app/angular/src/client/preview/index.ts index e37a283bd466..e2d014eeecec 100644 --- a/app/angular/src/client/preview/index.ts +++ b/app/angular/src/client/preview/index.ts @@ -1,6 +1,6 @@ /* eslint-disable prefer-destructuring */ import type { ClientStoryApi, Loadable } from '@storybook/addons'; -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import './globals'; import { renderToDOM, render } from './render'; import decorateStory from './decorateStory'; diff --git a/app/angular/src/server/framework-preset-angular-cli.test.ts b/app/angular/src/server/framework-preset-angular-cli.test.ts index fa356f688eb4..b5e1b86eee2b 100644 --- a/app/angular/src/server/framework-preset-angular-cli.test.ts +++ b/app/angular/src/server/framework-preset-angular-cli.test.ts @@ -766,8 +766,8 @@ const newWebpackConfiguration = ( bail: false, devtool: 'cheap-module-source-map', entry: [ - '/Users/joe/storybook/lib/core-server/dist/cjs/globals/polyfills.js', - '/Users/joe/storybook/lib/core-server/dist/cjs/globals/globals.js', + '/Users/joe/storybook/lib/core-server/dist/esm/globals/polyfills.js', + '/Users/joe/storybook/lib/core-server/dist/esm/globals/globals.js', '/Users/joe/storybook/examples/angular-cli/.storybook/storybook-init-framework-entry.js', '/Users/joe/storybook/addons/docs/dist/esm/frameworks/common/config.js-generated-other-entry.js', '/Users/joe/storybook/addons/docs/dist/esm/frameworks/angular/config.js-generated-other-entry.js', @@ -797,9 +797,6 @@ const newWebpackConfiguration = ( modules: ['node_modules'], mainFields: ['browser', 'main'], alias: { - '@emotion/core': '/Users/joe/storybook/node_modules/@emotion/core', - '@emotion/styled': '/Users/joe/storybook/node_modules/@emotion/styled', - 'emotion-theming': '/Users/joe/storybook/node_modules/emotion-theming', '@storybook/addons': '/Users/joe/storybook/lib/addons', '@storybook/api': '/Users/joe/storybook/lib/api', '@storybook/channels': '/Users/joe/storybook/lib/channels', diff --git a/app/angular/src/server/framework-preset-angular-docs.ts b/app/angular/src/server/framework-preset-angular-docs.ts index 314ef6039f3f..1c2cac0c15eb 100644 --- a/app/angular/src/server/framework-preset-angular-docs.ts +++ b/app/angular/src/server/framework-preset-angular-docs.ts @@ -2,7 +2,7 @@ import path from 'path'; import { StorybookConfig } from '@storybook/core-common'; import { hasDocsOrControls } from '@storybook/docs-tools'; -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, path.join(__dirname, '../../../dist/ts3.9/client/docs/config')]; }; diff --git a/app/angular/src/server/preset.ts b/app/angular/src/server/preset.ts index ab7d7dd63059..65dc2fa28dc0 100644 --- a/app/angular/src/server/preset.ts +++ b/app/angular/src/server/preset.ts @@ -1,6 +1,6 @@ import type { StorybookConfig } from '@storybook/core-common'; -export const config: StorybookConfig['config'] = (entries = []) => [ +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entries = []) => [ ...entries, require.resolve('../client/preview/config'), ]; diff --git a/app/ember/README.md b/app/ember/README.md index ee45d9a87eb3..95b842a85ad8 100644 --- a/app/ember/README.md +++ b/app/ember/README.md @@ -19,8 +19,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/ember/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/ember/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/ember/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. ## Docs diff --git a/app/ember/package.json b/app/ember/package.json index 517ac9ef9c6c..62251b7203fa 100644 --- a/app/ember/package.json +++ b/app/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/main/app/ember", "bugs": { @@ -42,10 +42,10 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "core-js": "^3.8.2", "global": "^4.4.0", "react": "16.14.0", @@ -66,6 +66,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/ember/src/client/preview/index.ts b/app/ember/src/client/preview/index.ts index b2642044a9f8..b85ad89f9751 100644 --- a/app/ember/src/client/preview/index.ts +++ b/app/ember/src/client/preview/index.ts @@ -1,4 +1,4 @@ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import './globals'; import { renderToDOM } from './render'; diff --git a/app/ember/src/server/framework-preset-babel-ember.ts b/app/ember/src/server/framework-preset-babel-ember.ts index 85bb723bee7b..da857b38fada 100644 --- a/app/ember/src/server/framework-preset-babel-ember.ts +++ b/app/ember/src/server/framework-preset-babel-ember.ts @@ -48,6 +48,6 @@ export function babel(config: TransformOptions, options: Options): TransformOpti }; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/ember/src/server/framework-preset-ember-docs.ts b/app/ember/src/server/framework-preset-ember-docs.ts index c2e6f69be8f2..2cdcc56e7cb8 100644 --- a/app/ember/src/server/framework-preset-ember-docs.ts +++ b/app/ember/src/server/framework-preset-ember-docs.ts @@ -2,7 +2,7 @@ import type { StorybookConfig } from '@storybook/core-common'; import { findDistEsm } from '@storybook/core-common'; import { hasDocsOrControls } from '@storybook/docs-tools'; -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/html/README.md b/app/html/README.md index 223ecd19e5b9..3fa757d3a7f5 100644 --- a/app/html/README.md +++ b/app/html/README.md @@ -21,5 +21,5 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/html/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/html/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/html/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. diff --git a/app/html/package.json b/app/html/package.json index 0340281e266a..fb267feff28d 100644 --- a/app/html/package.json +++ b/app/html/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -45,13 +45,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/preview-web": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/preview-web": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", @@ -76,6 +76,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/html/src/client/preview/index.ts b/app/html/src/client/preview/index.ts index 7838f55b09ff..decfcb1ee96e 100644 --- a/app/html/src/client/preview/index.ts +++ b/app/html/src/client/preview/index.ts @@ -1,5 +1,5 @@ /* eslint-disable prefer-destructuring */ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import type { ClientStoryApi, Loadable } from '@storybook/addons'; import { HtmlFramework } from './types-6-0'; diff --git a/app/html/src/server/framework-preset-html-docs.ts b/app/html/src/server/framework-preset-html-docs.ts index c2e6f69be8f2..2cdcc56e7cb8 100644 --- a/app/html/src/server/framework-preset-html-docs.ts +++ b/app/html/src/server/framework-preset-html-docs.ts @@ -2,7 +2,7 @@ import type { StorybookConfig } from '@storybook/core-common'; import { findDistEsm } from '@storybook/core-common'; import { hasDocsOrControls } from '@storybook/docs-tools'; -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/html/src/server/framework-preset-html.ts b/app/html/src/server/framework-preset-html.ts index 10b69f8fafdc..481086898273 100644 --- a/app/html/src/server/framework-preset-html.ts +++ b/app/html/src/server/framework-preset-html.ts @@ -11,6 +11,6 @@ export function webpack(config: Configuration) { return config; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/preact/README.md b/app/preact/README.md index 886a1a134b13..2bbdd89def68 100644 --- a/app/preact/README.md +++ b/app/preact/README.md @@ -19,8 +19,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/preact/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/preact/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/preact/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. ## Docs diff --git a/app/preact/package.json b/app/preact/package.json index 361b184be3e0..45d51bacd322 100644 --- a/app/preact/package.json +++ b/app/preact/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" @@ -46,11 +46,11 @@ }, "dependencies": { "@babel/plugin-transform-react-jsx": "^7.12.12", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", @@ -76,6 +76,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/preact/src/client/preview/index.ts b/app/preact/src/client/preview/index.ts index b15e21d72ee2..922e284a6e9c 100644 --- a/app/preact/src/client/preview/index.ts +++ b/app/preact/src/client/preview/index.ts @@ -1,5 +1,5 @@ /* eslint-disable prefer-destructuring */ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import type { ClientStoryApi, Loadable } from '@storybook/addons'; import './globals'; diff --git a/app/preact/src/server/framework-preset-preact.ts b/app/preact/src/server/framework-preset-preact.ts index 034cd1f4f729..9a50492d3480 100644 --- a/app/preact/src/server/framework-preset-preact.ts +++ b/app/preact/src/server/framework-preset-preact.ts @@ -29,6 +29,6 @@ export function webpackFinal(config: Configuration): Configuration { }; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/react/README.md b/app/react/README.md index 2e7e11dcbfe7..60379031702d 100644 --- a/app/react/README.md +++ b/app/react/README.md @@ -19,8 +19,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/react/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/react/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/react/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. Here are some featured storybooks that you can reference to see how Storybook works: diff --git a/app/react/package.json b/app/react/package.json index 7abb34ad66f7..39ebb7de709a 100644 --- a/app/react/package.json +++ b/app/react/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -49,16 +49,16 @@ "@babel/preset-flow": "^7.12.1", "@babel/preset-react": "^7.12.10", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/node-logger": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/node-logger": "6.5.0-beta.7", "@storybook/react-docgen-typescript-plugin": "1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0", "@storybook/semver": "^7.3.2", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/store": "6.5.0-beta.7", "@types/estree": "^0.0.51", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", @@ -69,6 +69,7 @@ "babel-plugin-react-docgen": "^4.2.1", "core-js": "^3.8.2", "escodegen": "^2.0.0", + "fs-extra": "^9.0.1", "global": "^4.4.0", "html-tags": "^3.1.0", "lodash": "^4.17.21", @@ -83,13 +84,13 @@ }, "devDependencies": { "@types/util-deprecate": "^1.0.0", + "jest-specific-snapshot": "^4.0.0", "webpack": "4" }, "peerDependencies": { "@babel/core": "^7.11.5", - "jest-specific-snapshot": "^4.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", "require-from-string": "^2.0.2" }, "peerDependenciesMeta": { @@ -118,6 +119,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/react/src/client/index.ts b/app/react/src/client/index.ts index 54de76c85858..141f7e7f43fc 100644 --- a/app/react/src/client/index.ts +++ b/app/react/src/client/index.ts @@ -9,6 +9,7 @@ export { raw, forceReRender, } from './preview'; +export * from './testing'; export * from './preview/types-6-3'; diff --git a/app/react/src/client/preview/index.tsx b/app/react/src/client/preview/index.tsx index 4f47993c6719..9847e6da2046 100644 --- a/app/react/src/client/preview/index.tsx +++ b/app/react/src/client/preview/index.tsx @@ -1,5 +1,5 @@ /* eslint-disable prefer-destructuring */ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import { ClientStoryApi, Loadable } from '@storybook/addons'; import './globals'; diff --git a/app/react/src/client/preview/render.tsx b/app/react/src/client/preview/render.tsx index 1a5e10e556ba..94db184a3b6b 100644 --- a/app/react/src/client/preview/render.tsx +++ b/app/react/src/client/preview/render.tsx @@ -6,8 +6,10 @@ import React, { StrictMode, Fragment, } from 'react'; -import ReactDOM from 'react-dom'; -import { RenderContext } from '@storybook/store'; +import ReactDOM, { version as reactDomVersion } from 'react-dom'; +import type { Root as ReactRoot } from 'react-dom/client'; + +import type { RenderContext } from '@storybook/store'; import { ArgsStoryFn } from '@storybook/csf'; import { StoryContext } from './types'; @@ -15,6 +17,9 @@ import { ReactFramework } from './types-6-0'; const { FRAMEWORK_OPTIONS } = global; +// A map of all rendered React 18 nodes +const nodes = new Map(); + export const render: ArgsStoryFn = (args, context) => { const { id, component: Component } = context; if (!Component) { @@ -26,10 +31,56 @@ export const render: ArgsStoryFn = (args, context) => { return ; }; -const renderElement = async (node: ReactElement, el: Element) => - new Promise((resolve) => { - ReactDOM.render(node, el, () => resolve(null)); +const renderElement = async (node: ReactElement, el: Element) => { + // Create Root Element conditionally for new React 18 Root Api + const root = await getReactRoot(el); + + return new Promise((resolve) => { + if (root) { + root.render(node); + setTimeout(() => { + resolve(null); + }, 0); + } else { + ReactDOM.render(node, el, () => resolve(null)); + } }); +}; + +const canUseNewReactRootApi = + reactDomVersion && (reactDomVersion.startsWith('18') || reactDomVersion.startsWith('0.0.0')); + +const shouldUseNewRootApi = FRAMEWORK_OPTIONS?.legacyRootApi !== true; + +const isUsingNewReactRootApi = shouldUseNewRootApi && canUseNewReactRootApi; + +const unmountElement = (el: Element) => { + const root = nodes.get(el); + if (root && isUsingNewReactRootApi) { + root.unmount(); + nodes.delete(el); + } else { + ReactDOM.unmountComponentAtNode(el); + } +}; + +const getReactRoot = async (el: Element): Promise => { + if (!isUsingNewReactRootApi) { + return null; + } + + let root = nodes.get(el); + + if (!root) { + // eslint-disable-next-line import/no-unresolved + const reactDomClient = (await import('react-dom/client')).default; + root = reactDomClient.createRoot(el); + + nodes.set(el, root); + } + + return root; +}; class ErrorBoundary extends ReactComponent<{ showException: (err: Error) => void; @@ -92,7 +143,7 @@ export async function renderToDOM( // https://github.com/storybookjs/react-storybook/issues/81 // (This is not the case when we change args or globals to the story however) if (forceRemount) { - ReactDOM.unmountComponentAtNode(domElement); + unmountElement(domElement); } await renderElement(element, domElement); diff --git a/app/react/src/client/testing/index.ts b/app/react/src/client/testing/index.ts new file mode 100644 index 000000000000..8099a10b9ff8 --- /dev/null +++ b/app/react/src/client/testing/index.ts @@ -0,0 +1,129 @@ +import { + composeStory as originalComposeStory, + composeStories as originalComposeStories, + setProjectAnnotations as originalSetProjectAnnotations, + CSFExports, + ComposedStory, + StoriesWithPartialProps, +} from '@storybook/store'; +import { ProjectAnnotations, Args } from '@storybook/csf'; +import { once } from '@storybook/client-logger'; + +import { render } from '../preview/render'; +import type { Meta, ReactFramework } from '../preview/types-6-0'; + +/** 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/react'; + * import * as projectAnnotations from './.storybook/preview'; + * + * setProjectAnnotations(projectAnnotations); + *``` + * + * @param projectAnnotations - e.g. (import * as projectAnnotations from '../.storybook/preview') + */ +export function setProjectAnnotations( + projectAnnotations: ProjectAnnotations | ProjectAnnotations[] +) { + originalSetProjectAnnotations(projectAnnotations); +} + +/** Preserved for users migrating from `@storybook/testing-react`. + * + * @deprecated Use setProjectAnnotations instead + */ +export function setGlobalConfig( + projectAnnotations: ProjectAnnotations | ProjectAnnotations[] +) { + once.warn(`setGlobalConfig is deprecated. Use setProjectAnnotations instead.`); + setProjectAnnotations(projectAnnotations); +} + +// This will not be necessary once we have auto preset loading +const defaultProjectAnnotations: ProjectAnnotations = { + render, +}; + +/** + * 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/react'; + * import { composeStory } from '@storybook/react'; + * import Meta, { Primary as PrimaryStory } from './Button.stories'; + * + * const Primary = composeStory(PrimaryStory, Meta); + * + * test('renders primary button with Hello World', () => { + * const { getByText } = render(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: ComposedStory, + componentAnnotations: Meta, + projectAnnotations?: ProjectAnnotations, + exportsName?: string +) { + return originalComposeStory( + story, + 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/react'; + * import { composeStories } from '@storybook/react'; + * import * as stories from './Button.stories'; + * + * const { Primary, Secondary } = composeStories(stories); + * + * test('renders primary button with Hello World', () => { + * const { getByText } = render(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 +) { + const composedStories = originalComposeStories(csfExports, projectAnnotations, composeStory); + + return composedStories as unknown as Omit< + StoriesWithPartialProps, + keyof CSFExports + >; +} diff --git a/app/react/src/server/framework-preset-react-docs.ts b/app/react/src/server/framework-preset-react-docs.ts index 723cf49a9f29..98f9c12145b9 100644 --- a/app/react/src/server/framework-preset-react-docs.ts +++ b/app/react/src/server/framework-preset-react-docs.ts @@ -58,7 +58,7 @@ export async function webpackFinal(config: Configuration, options: Options) { }; } -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/react/src/server/framework-preset-react-dom-hack.ts b/app/react/src/server/framework-preset-react-dom-hack.ts new file mode 100644 index 000000000000..f9893d37c85a --- /dev/null +++ b/app/react/src/server/framework-preset-react-dom-hack.ts @@ -0,0 +1,22 @@ +import { readJSON } from 'fs-extra'; +import { Configuration, IgnorePlugin } from 'webpack'; + +// this is a hack to allow importing react-dom/client even when it's not available +// this should be removed once we drop support for react-dom < 18 + +export async function webpackFinal(config: Configuration) { + const reactDomPkg = await readJSON(require.resolve('react-dom/package.json')); + + return { + ...config, + plugins: [ + ...config.plugins, + reactDomPkg.version.startsWith('18') || reactDomPkg.version.startsWith('0.0.0') + ? null + : new IgnorePlugin({ + resourceRegExp: /react-dom\/client$/, + contextRegExp: /(app\/react|app\\react|@storybook\/react|@storybook\\react)/, // TODO this needs to work for both in our MONOREPO and in the user's NODE_MODULES + }), + ].filter(Boolean), + }; +} diff --git a/app/react/src/server/framework-preset-react.ts b/app/react/src/server/framework-preset-react.ts index 3fb207b1d263..7559e61a9251 100644 --- a/app/react/src/server/framework-preset-react.ts +++ b/app/react/src/server/framework-preset-react.ts @@ -87,6 +87,7 @@ export async function webpackFinal(config: Configuration, options: Options) { ...config, plugins: [ ...config.plugins, + // Storybook uses webpack-hot-middleware https://github.com/storybookjs/storybook/issues/14114 new ReactRefreshWebpackPlugin({ overlay: { diff --git a/app/react/src/server/preset.ts b/app/react/src/server/preset.ts index b0807877e886..081c6073e26b 100644 --- a/app/react/src/server/preset.ts +++ b/app/react/src/server/preset.ts @@ -1,13 +1,14 @@ import { findDistEsm } from '@storybook/core-common'; import type { StorybookConfig } from '@storybook/core-common'; -export const config: StorybookConfig['config'] = (entries = []) => [ +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entries = []) => [ ...entries, findDistEsm(__dirname, 'client/preview/config'), ]; export const addons: StorybookConfig['addons'] = [ require.resolve('./framework-preset-react'), + require.resolve('./framework-preset-react-dom-hack'), require.resolve('./framework-preset-cra'), require.resolve('./framework-preset-react-docs'), ]; diff --git a/app/react/src/typings.d.ts b/app/react/src/typings.d.ts index 4ff88fa9018c..cd1929c868b2 100644 --- a/app/react/src/typings.d.ts +++ b/app/react/src/typings.d.ts @@ -1,2 +1,44 @@ declare module '@storybook/semver'; declare module 'global'; + +// TODO: Replace, as soon as @types/react-dom 17.0.14 is used +// Source: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/fb0f14b7a35cde26ffaa82e7536c062e593e9ae6/types/react-dom/client.d.ts +declare module 'react-dom/client' { + +import React = require('react'); + export interface HydrationOptions { + onHydrated?(suspenseInstance: Comment): void; + onDeleted?(suspenseInstance: Comment): void; + /** + * Prefix for `useId`. + */ + identifierPrefix?: string; + onRecoverableError?: (error: unknown) => void; + } + + export interface RootOptions { + /** + * Prefix for `useId`. + */ + identifierPrefix?: string; + onRecoverableError?: (error: unknown) => void; + } + + export interface Root { + render(children: React.ReactChild | Iterable): void; + unmount(): void; + } + + /** + * Replaces `ReactDOM.render` when the `.render` method is called and enables Concurrent Mode. + * + * @see https://reactjs.org/docs/concurrent-mode-reference.html#createroot + */ + export function createRoot(container: Element | Document | DocumentFragment | Comment, options?: RootOptions): Root; + + export function hydrateRoot( + container: Element | Document | DocumentFragment | Comment, + initialChildren: React.ReactChild | Iterable, + options?: HydrationOptions, + ): Root; +} diff --git a/app/react/types/index.ts b/app/react/types/index.ts index 587c0a51088c..f2f6ac0a2fed 100644 --- a/app/react/types/index.ts +++ b/app/react/types/index.ts @@ -7,5 +7,13 @@ export interface StorybookConfig extends BaseConfig { reactOptions?: { fastRefresh?: boolean; strictMode?: boolean; + /** + * Use React's legacy root API to mount components + * @description + * React has introduced a new root API with React 18.x to enable a whole set of new features (e.g. concurrent features) + * If this flag is true, the legacy Root API is used to mount components to make it easier to migrate step by step to React 18. + * @default false + */ + legacyRootApi?: boolean; }; } diff --git a/app/server/README.md b/app/server/README.md index 3421377c873e..28e5e50205aa 100644 --- a/app/server/README.md +++ b/app/server/README.md @@ -230,7 +230,7 @@ Just like CSF stories we can define `argTypes` to specify the controls used in t ## Addon compatibility -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/react/configure/storybook-addons) and a great API to customize as you wish. As some addons assume the story is rendered in JS, they may not work with `@storybook/server` (yet!). +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. As some addons assume the story is rendered in JS, they may not work with `@storybook/server` (yet!). Many addons that act on the manager side (such as `backgrounds` and `viewport`) will work out of the box with `@storybook/server` -- you can configure them with parameters written on the server as usual. diff --git a/app/server/package.json b/app/server/package.json index bae2883c0911..4e0533a96861 100644 --- a/app/server/package.json +++ b/app/server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -45,15 +45,15 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/api": "6.5.0-alpha.52", - "@storybook/client-api": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/node-logger": "6.5.0-alpha.52", - "@storybook/preview-web": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/api": "6.5.0-beta.7", + "@storybook/client-api": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/node-logger": "6.5.0-beta.7", + "@storybook/preview-web": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", @@ -76,6 +76,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/server/src/client/preview/index.ts b/app/server/src/client/preview/index.ts index 4bedb816a6c2..9395dfb98109 100644 --- a/app/server/src/client/preview/index.ts +++ b/app/server/src/client/preview/index.ts @@ -1,4 +1,4 @@ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import type { ClientStoryApi, Loadable } from '@storybook/addons'; import './globals'; diff --git a/app/server/src/server/framework-preset-server.ts b/app/server/src/server/framework-preset-server.ts index ddde3f77f7d5..f4f552890b79 100644 --- a/app/server/src/server/framework-preset-server.ts +++ b/app/server/src/server/framework-preset-server.ts @@ -19,6 +19,6 @@ export function webpack(config: Configuration) { return config; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/svelte/README.md b/app/svelte/README.md index fcb7b786e567..49bbb60840e3 100644 --- a/app/svelte/README.md +++ b/app/svelte/README.md @@ -19,8 +19,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/svelte/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/svelte/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/svelte/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. ## TODOs diff --git a/app/svelte/package.json b/app/svelte/package.json index 7169bc17e072..60c70a449e5c 100644 --- a/app/svelte/package.json +++ b/app/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -46,14 +46,14 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/node-logger": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/node-logger": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "core-js": "^3.8.2", "global": "^4.4.0", "loader-utils": "^2.0.0", @@ -83,6 +83,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/svelte/src/client/docs/sourceDecorator.ts b/app/svelte/src/client/docs/sourceDecorator.ts index d449523197b5..11bbeffaec02 100644 --- a/app/svelte/src/client/docs/sourceDecorator.ts +++ b/app/svelte/src/client/docs/sourceDecorator.ts @@ -1,4 +1,5 @@ import { addons, useEffect } from '@storybook/addons'; +import { once } from '@storybook/client-logger'; import type { ArgTypes, Args, StoryContext, AnyFramework } from '@storybook/csf'; import { SourceType, SNIPPET_RENDERED } from '@storybook/docs-tools'; @@ -160,12 +161,16 @@ export const sourceDecorator = (storyFn: any, context: StoryContext { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/svelte/src/server/framework-preset-svelte.ts b/app/svelte/src/server/framework-preset-svelte.ts index a9bec1dc6109..c3cf144bc72e 100644 --- a/app/svelte/src/server/framework-preset-svelte.ts +++ b/app/svelte/src/server/framework-preset-svelte.ts @@ -1,6 +1,7 @@ import { findDistEsm } from '@storybook/core-common'; import type { Options, StorybookConfig } from '@storybook/core-common'; import type { Configuration } from 'webpack'; +import type { TransformOptions } from '@babel/core'; export async function webpack(config: Configuration, options: Options): Promise { const { preprocess = undefined, loader = {} } = await options.presets.apply( @@ -33,6 +34,14 @@ export async function webpack(config: Configuration, options: Options): Promise< }; } -export const config: StorybookConfig['config'] = (entry = []) => { +export async function babelDefault(config: TransformOptions): Promise { + return { + ...config, + presets: [...(config?.presets || [])], + plugins: [...(config?.plugins || [])], + }; +} + +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/vue/README.md b/app/vue/README.md index 169efbeee115..33ae491f8f41 100644 --- a/app/vue/README.md +++ b/app/vue/README.md @@ -23,8 +23,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/vue/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/vue/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/vue/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. ## Vue Notes diff --git a/app/vue/package.json b/app/vue/package.json index d48cfb082fa0..deaa9dd26752 100644 --- a/app/vue/package.json +++ b/app/vue/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Vue: Develop Vue Component in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -45,13 +45,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", @@ -86,6 +86,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/vue/src/client/preview/index.ts b/app/vue/src/client/preview/index.ts index 7002a27b58b9..0d894499697c 100644 --- a/app/vue/src/client/preview/index.ts +++ b/app/vue/src/client/preview/index.ts @@ -1,5 +1,5 @@ /* eslint-disable prefer-destructuring */ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import type { ClientStoryApi, Loadable } from '@storybook/addons'; import './globals'; diff --git a/app/vue/src/server/framework-preset-vue-docs.ts b/app/vue/src/server/framework-preset-vue-docs.ts index 478196fa0d8f..984fa07c49c5 100644 --- a/app/vue/src/server/framework-preset-vue-docs.ts +++ b/app/vue/src/server/framework-preset-vue-docs.ts @@ -30,7 +30,7 @@ export function webpackFinal(webpackConfig: any = {}, options: Options) { return webpackConfig; } -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/vue/src/server/framework-preset-vue.ts b/app/vue/src/server/framework-preset-vue.ts index 5ca2341d674f..8656d8d35060 100644 --- a/app/vue/src/server/framework-preset-vue.ts +++ b/app/vue/src/server/framework-preset-vue.ts @@ -45,6 +45,6 @@ export async function webpack(config: Configuration, { presets }: Options) { return config; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/vue3/README.md b/app/vue3/README.md index 0d85c31aa0eb..b0fafaff0295 100644 --- a/app/vue3/README.md +++ b/app/vue3/README.md @@ -19,8 +19,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/vue3/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/vue3/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/vue/sharing/publish-storybook) of your Storybook and deploy it anywhere you want. ## Extending the Vue application diff --git a/app/vue3/package.json b/app/vue3/package.json index 8ce75714e27d..3ff0ed3d0bd3 100644 --- a/app/vue3/package.json +++ b/app/vue3/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" @@ -45,12 +45,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", @@ -63,7 +63,7 @@ "ts-loader": "^8.0.14", "vue-docgen-api": "^4.44.15", "vue-docgen-loader": "^1.5.0", - "vue-loader": "^16.0.0", + "vue-loader": "^16.4.1", "webpack": ">=4.0.0 <6.0.0" }, "devDependencies": { @@ -83,6 +83,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/vue3/src/client/preview/index.ts b/app/vue3/src/client/preview/index.ts index f37473e1329e..912dc4bf7919 100644 --- a/app/vue3/src/client/preview/index.ts +++ b/app/vue3/src/client/preview/index.ts @@ -1,5 +1,5 @@ import type { App } from 'vue'; -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import type { ClientStoryApi, Loadable } from '@storybook/addons'; import './globals'; diff --git a/app/vue3/src/server/framework-preset-vue3-docs.ts b/app/vue3/src/server/framework-preset-vue3-docs.ts index 34e755af3f17..b97af76f15ff 100644 --- a/app/vue3/src/server/framework-preset-vue3-docs.ts +++ b/app/vue3/src/server/framework-preset-vue3-docs.ts @@ -31,7 +31,7 @@ export function webpackFinal(webpackConfig: any = {}, options: Options) { return webpackConfig; } -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/vue3/src/server/framework-preset-vue3.ts b/app/vue3/src/server/framework-preset-vue3.ts index 0db63e4cd193..fb4dc76a2886 100644 --- a/app/vue3/src/server/framework-preset-vue3.ts +++ b/app/vue3/src/server/framework-preset-vue3.ts @@ -48,6 +48,6 @@ export function webpack(config: Configuration): Configuration { }; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/app/web-components/README.md b/app/web-components/README.md index 5de2c1130fcc..e07aad25f2bb 100644 --- a/app/web-components/README.md +++ b/app/web-components/README.md @@ -21,8 +21,8 @@ For more information visit: [storybook.js.org](https://storybook.js.org) --- -Storybook also comes with a lot of [addons](https://storybook.js.org/docs/web-components/configure/storybook-addons) and a great API to customize as you wish. -You can also build a [static version](https://storybook.js.org/docs/web-components/workflows/publish-storybook) of your storybook and deploy it anywhere you want. +Storybook also comes with a lot of [addons](https://storybook.js.org/addons) and a great API to customize as you wish. +You can also build a [static version](https://storybook.js.org/docs/web-components/sharing/publish-storybook) of your storybook and deploy it anywhere you want. # Hot Module Reloading (HMR) diff --git a/app/web-components/package.json b/app/web-components/package.json index db9b12b2a614..fd8943d8dbfb 100644 --- a/app/web-components/package.json +++ b/app/web-components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.", "keywords": [ "lit-html", @@ -50,15 +50,15 @@ "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/preset-env": "^7.12.11", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/client-api": "6.5.0-alpha.52", - "@storybook/client-logger": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-common": "6.5.0-alpha.52", - "@storybook/csf": "0.0.2--canary.507502b.0", - "@storybook/docs-tools": "6.5.0-alpha.52", - "@storybook/preview-web": "6.5.0-alpha.52", - "@storybook/store": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/client-api": "6.5.0-beta.7", + "@storybook/client-logger": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-common": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/docs-tools": "6.5.0-beta.7", + "@storybook/preview-web": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", "@types/node": "^14.14.20 || ^16.0.0", "@types/webpack-env": "^1.16.0", "babel-plugin-bundled-import-meta": "^0.3.1", @@ -82,6 +82,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "863b3811b24a4703645a09286059bc6d95bd2e65", + "gitHead": "14bb6d241c888cc3be6adba94c3e3a1ceddadf74", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/web-components/src/client/preview/index.ts b/app/web-components/src/client/preview/index.ts index aeb08b3bc3da..ef8fe1cc37e4 100644 --- a/app/web-components/src/client/preview/index.ts +++ b/app/web-components/src/client/preview/index.ts @@ -1,5 +1,5 @@ /* eslint-disable prefer-destructuring */ -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import type { ClientStoryApi, Loadable } from '@storybook/addons'; import './globals'; diff --git a/app/web-components/src/server/framework-preset-web-components-docs.ts b/app/web-components/src/server/framework-preset-web-components-docs.ts index 507496e74073..31ccb922f3f1 100644 --- a/app/web-components/src/server/framework-preset-web-components-docs.ts +++ b/app/web-components/src/server/framework-preset-web-components-docs.ts @@ -1,7 +1,7 @@ import { findDistEsm, StorybookConfig } from '@storybook/core-common'; import { hasDocsOrControls } from '@storybook/docs-tools'; -export const config: StorybookConfig['config'] = (entry = [], options) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = [], options) => { if (!hasDocsOrControls(options)) return entry; return [...entry, findDistEsm(__dirname, 'client/docs/config')]; }; diff --git a/app/web-components/src/server/framework-preset-web-components.ts b/app/web-components/src/server/framework-preset-web-components.ts index 44e273ff8f3c..19c537420947 100644 --- a/app/web-components/src/server/framework-preset-web-components.ts +++ b/app/web-components/src/server/framework-preset-web-components.ts @@ -41,6 +41,6 @@ export function webpack(config: Configuration, options: Options) { return config; } -export const config: StorybookConfig['config'] = (entry = []) => { +export const previewAnnotations: StorybookConfig['previewAnnotations'] = (entry = []) => { return [...entry, findDistEsm(__dirname, 'client/preview/config')]; }; diff --git a/cypress/generated/addon-interactions.spec.ts b/cypress/generated/addon-interactions.spec.ts index d66349525aae..95d0b59c172d 100644 --- a/cypress/generated/addon-interactions.spec.ts +++ b/cypress/generated/addon-interactions.spec.ts @@ -30,4 +30,28 @@ describe('addon-interactions', () => { onlyOn('react', () => { it('should have interactions', test); }); + + onlyOn('vite_react', () => { + it('should have interactions', test); + }); + + onlyOn('preact', () => { + it('should have interactions', test); + }); + + onlyOn('html', () => { + it('should have interactions', test); + }); + + onlyOn('svelte', () => { + it('should have interactions', test); + }); + + onlyOn('vue3', () => { + it('should have interactions', test); + }); + + onlyOn('vue', () => { + it('should have interactions', test); + }); }); diff --git a/docs/addons/addon-catalog.md b/docs/addons/addon-catalog.md index 62b4b1f39b07..372d9ce7dbbc 100644 --- a/docs/addons/addon-catalog.md +++ b/docs/addons/addon-catalog.md @@ -2,9 +2,9 @@ title: 'Add to the addon catalog' --- -Storybook addons are listed in the [catalog](/addons) and distributed via npm. The catalog is populated by querying npm's registry for Storybook-specific metadata in `package.json`. +Storybook addons are listed in the [catalog](https://storybook.js.org/addons/) and distributed via npm. The catalog is populated by querying npm's registry for Storybook-specific metadata in `package.json`. -Add your addon to the catalog by publishing an npm package that follows these requirements: +Add your addon to the catalog by publishing a npm package that follows these requirements: - `package.json` with [module information](./writing-addons.md#get-started) and [addon metadata](#addon-metadata) - `README.md` file with installation and configuration instructions diff --git a/docs/addons/addon-knowledge-base.md b/docs/addons/addon-knowledge-base.md index acb9c2a8fd54..2e174ca405fd 100644 --- a/docs/addons/addon-knowledge-base.md +++ b/docs/addons/addon-knowledge-base.md @@ -70,7 +70,7 @@ Complementing the components, also included is a set of UI primitives. Use the c | Component | Source | Story | | ------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | -| Color Pallette (see note below) | [See implementation](https://github.com/storybookjs/storybook/tree/master/lib/components/src/Colors) | [See story](https://5a375b97f4b14f0020b0cda3-wbeulgbetj.chromatic.com/?path=/story/basics-colorpalette--page) | +| Color Palette (see note below) | [See implementation](https://github.com/storybookjs/storybook/tree/master/lib/components/src/Colors) | [See story](https://5a375b97f4b14f0020b0cda3-wbeulgbetj.chromatic.com/?path=/story/basics-colorpalette--page) | | Icon | [See implementation](https://github.com/storybookjs/storybook/blob/master/lib/components/src/icon/icons.tsx) | [See story](https://5a375b97f4b14f0020b0cda3-wbeulgbetj.chromatic.com/?path=/story/basics-icon--labels) | | Typography | [See implementation](https://github.com/storybookjs/storybook/tree/master/lib/components/src/typography) | [See story](https://5a375b97f4b14f0020b0cda3-wbeulgbetj.chromatic.com/?path=/story/basics-typography--all) | diff --git a/docs/addons/addons-api.md b/docs/addons/addons-api.md index 26decd0e386b..5c0e5b2a6463 100644 --- a/docs/addons/addons-api.md +++ b/docs/addons/addons-api.md @@ -362,7 +362,7 @@ The following table details how to use the API values: | **showPanel** | Boolean | Display panel that shows addon configurations | `true` | | **panelPosition** | String/Object | Where to show the addon panel | `bottom` or `right` | | **enableShortcuts** | Boolean | Enable/disable shortcuts | `true` | -| **isToolshown** | Boolean | Show/hide tool bar | `true` | +| **showToolbar** | Boolean | Show/hide tool bar | `true` | | **theme** | Object | Storybook Theme, see next section | `undefined` | | **selectedPanel** | String | Id to select an addon panel | `storybook/actions/panel` | | **initialActive** | String | Select the default active tab on Mobile | `sidebar` or `canvas` or `addons` | diff --git a/docs/addons/configure-addons.md b/docs/addons/configure-addons.md index fcf6dd3263be..d68f9c40d997 100644 --- a/docs/addons/configure-addons.md +++ b/docs/addons/configure-addons.md @@ -10,9 +10,9 @@ Presets offload the burden of configuration from user to the addon. Preset optio For example, many libraries require that the app be wrapped by a `Provider` which _provides_ data to components down the tree. Presets can describe behavior like adding wrappers automatically, without users having to do any manual configuration. If a user installs an addon that has Presets, the addon can instruct Storybook to wrap all stories in `Provider`. This allows folks to start using your library with Storybook, with just 1 line of config! -For more on presets, see: [Write a preset addon](./writing-presets) +For more on presets, see: [Write a preset addon](./writing-presets.md) -The mechanism for wrapping each story is referred to as a Storybook [decorator](../writing-stories/decorators). They allow you to augment stories with extra rendering functionality or by providing data. +The mechanism for wrapping each story is referred to as a Storybook [decorator](../writing-stories/decorators.md). They allow you to augment stories with extra rendering functionality or by providing data. ## Parameters @@ -20,7 +20,7 @@ Parameters are available in the browser and are great for configuring addon beha For example, the [Pseudo States addon](https://storybook.js.org/addons/storybook-addon-pseudo-states) uses parameters to enable the various pseudo-states. Users can provide global defaults and then override them at the story level. -Use the [`useParameter`](./addons-api#useparameter) hook to access the parameter values within your addon. +Use the [`useParameter`](./addons-api.md#useparameter) hook to access the parameter values within your addon. ```js export const Hover = () => ; @@ -33,6 +33,6 @@ Channels enable two-way communication between the manager and the preview pane, For example, the [Actions addon](https://storybook.js.org/addons/@storybook/addon-actions) captures user events and displays their data in a panel. -Use the [`useChannel`](./addons-api#usechannel) hook to access the channel data within your addon. +Use the [`useChannel`](./addons-api.md#usechannel) hook to access the channel data within your addon. For a complete example, check out [storybookjs/addon-kit/withRoundTrip.ts](https://github.com/storybookjs/addon-kit/blob/main/src/withRoundTrip.ts) diff --git a/docs/addons/introduction.md b/docs/addons/introduction.md index f043fc24299c..3ec5dbf1ae93 100644 --- a/docs/addons/introduction.md +++ b/docs/addons/introduction.md @@ -22,7 +22,7 @@ The **Preview** area is an `iframe` where your stories are rendered. ![Storybook detailed window](./manager-preview.jpg) -Because both elements run in their own separate `iframes`, they use a communication channel to keep in synch. For example when you select a story in the Manager a event is dispatched across the channel notifying the Preview to render the story. +Because both elements run in their own separate `iframes`, they use a communication channel to keep in sync. For example when you select a story in the Manager an event is dispatched across the channel notifying the Preview to render the story. ## Anatomy of an addon @@ -32,10 +32,10 @@ Storybook addons allow you to extend what's already possible with Storybook, eve [UI-based addons](./addon-types.md#ui-based-addons) focus on customizing Storybook's user interface to extend your development workflow. Examples of UI-based addons include: [Controls](../essentials/controls.md), [Docs](../writing-docs/introduction.md) and [Accessibility](https://github.com/storybookjs/storybook/tree/master/addons/a11y). -[Learn how to write an addon »](./writing-addons) +[Learn how to write an addon »](./writing-addons.md) ### Preset addons [Preset addons](./addon-types.md#preset-addons) help you integrate Storybook with other technologies and libraries. Examples of preset addons are: [preset-scss](https://github.com/storybookjs/presets/tree/master/packages/preset-scss) and [preset-create-react-app](https://github.com/storybookjs/presets/tree/master/packages/preset-create-react-app). -[Learn how to write a preset addon »](./writing-presets) +[Learn how to write a preset addon »](./writing-presets.md) diff --git a/docs/addons/writing-presets.md b/docs/addons/writing-presets.md index ab9198c5f783..c8215c390354 100644 --- a/docs/addons/writing-presets.md +++ b/docs/addons/writing-presets.md @@ -2,7 +2,7 @@ title: 'Write a preset addon' --- -[Storybook preset addons](./addon-types.md#preset-addons) are grouped collections of `babel`, `webpack`, and `addons` configurations that support specific use cases in Storybook, such as typescript or MDX support. +[Storybook preset addons](./addon-types.md#preset-addons) are grouped collections of `babel`, `webpack`, and `addons` configurations that support specific use cases in Storybook, such as TypeScript or MDX support. This doc covers the [presets API](#presets-api) and how to use the presets mechanism for [advanced configuration](#advanced-configuration). @@ -10,7 +10,7 @@ This doc covers the [presets API](#presets-api) and how to use the presets mecha A preset is a set of hooks that is called by Storybook on initialization and can override configurations for `babel`, `webpack`, `addons`, and `entries`. -Each configuration has a similar signature, accepting a base configuration object and options, as in this webpack example: +Each configuration has a similar signature, accepting a base configuration object and options, as in this Webpack example: @@ -46,7 +46,7 @@ For example, Storybook's Mihtril support uses plugins internally and here's how ### Webpack -The webpack functions `webpack`, `webpackFinal`, and `managerWebpack` configure webpack. +The Webpack functions `webpack`, `webpackFinal`, and `managerWebpack` configure Webpack. All functions take a [webpack4 configuration object](https://webpack.js.org/configuration/). @@ -62,11 +62,11 @@ For example, here is how Storybook automatically adopts `create-react-app`'s con -- `webpack` is applied to the preview config after it has been initialized by storybook +- `webpack` is applied to the preview config after it has been initialized by Storybook - `webpackFinal` is applied to the preview config after all user presets have been applied - `managerWebpack` is applied to the manager config -As of Storybook 6.3, Storybook can run with either `webpack4` or `webpack5` builder. If your addon needs to know which version of Webpack it's running inside, the version and the actual webpack instance itself are both available inside your preset: +As of Storybook 6.3, Storybook can run with either `webpack4` or `webpack5` builder. If your addon needs to know which version of Webpack it's running inside, the version and the actual Webpack instance itself are both available inside your preset: @@ -81,7 +81,7 @@ As of Storybook 6.3, Storybook can run with either `webpack4` or `webpack5` buil ### Manager entries -The addon config `managerEntries` allows you to add addons to Storybook from within a preset. For addons that require custom webpack/babel configuration, it is easier to install the preset, and it will take care of everything. +The addon config `managerEntries` allows you to add addons to Storybook from within a preset. For addons that require custom Webpack/Babel configuration, it is easier to install the preset, and it will take care of everything. For example, the Storysource preset contains the following code: @@ -176,9 +176,9 @@ Entries are the place to register entry points for the preview. For example it c ## Advanced Configuration -The presets API is also more powerful than the [standard configuration options](../configure/webpack.md#extending-storybooks-webpack-config) available in Storybook, so it's also possible to use presets for more advanced configuration without actually publishing a preset yourself. +The presets API is also more powerful than the [standard configuration options](../builders/webpack.md#extending-storybooks-webpack-config) available in Storybook, so it's also possible to use presets for more advanced configuration without actually publishing a preset yourself. -For example, some users want to configure the webpack for Storybook's UI and addons ([issue](https://github.com/storybookjs/storybook/issues/4995)), but this is not possible using [standard webpack configuration](../configure/webpack.md#default-configuration) (it used to be possible before SB4.1). However, you can achieve this with a private preset. +For example, some users want to configure the Webpack for Storybook's UI and addons ([issue](https://github.com/storybookjs/storybook/issues/4995)), but this is not possible using [standard Webpack configuration](../builders/webpack.md#default-configuration) (it used to be possible before SB4.1). However, you can achieve this with a private preset. If it doesn't exist yet, create a file `.storybook/main.js`: @@ -196,7 +196,7 @@ If it doesn't exist yet, create a file `.storybook/main.js`: It's also possible to programmatically modify the preview head/body HTML using a preset, similar to the way `preview-head.html`/`preview-body.html` can be used to [configure story rendering](../configure/story-rendering.md). The `previewHead` and `previewBody` functions accept a string, which is the existing head/body, and return a modified string. -For example, the following snippet adds a style tag to the preview head programatically: +For example, the following snippet adds a style tag to the preview head programmatically: @@ -210,7 +210,7 @@ For example, the following snippet adds a style tag to the preview head programa Similarly, the `managerHead` can be used to modify the surrounding "manager" UI, analogous to `manager-head.html`. -Finally, the preview's main page _template_ can also be overridden using the `previewMainTemplate`, which should return a reference to a file containing an `.ejs` template that gets interpolated with some environment variables. For an example, see the [Storybook's default template](https://github.com/storybookjs/storybook/blob/next/lib/core-common/src/templates/index.ejs). +Finally, the preview's main page _template_ can also be overridden using the `previewMainTemplate`, which should return a reference to a file containing an `.ejs` template that gets interpolated with some environment variables. For an example, see the [Storybook's default template](https://github.com/storybookjs/storybook/blob/next/lib/core-common/templates/index.ejs). ## Sharing advanced configuration diff --git a/docs/api/cli-options.md b/docs/api/cli-options.md index 9380c20d4e17..ae567dd69631 100644 --- a/docs/api/cli-options.md +++ b/docs/api/cli-options.md @@ -4,6 +4,10 @@ title: 'CLI options' Storybook comes with two CLI utilities: `start-storybook` and `build-storybook`. +
+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. +
+ Pass these commands the following options to alter Storybook's behavior. ## start-storybook @@ -18,10 +22,10 @@ Usage: start-storybook [options] | `-V`, `--version` | Output the version number
`start-storybook -V` | | `-p`, `--port [number]` | Port to run Storybook
`start-storybook -p 9009` | | `-h`, `--host [string]` | Host to run Storybook
`start-storybook -h my-host.com` | -| `-s`, `--static-dir` | **Deprecated** [see note](#static-dir-deprecation). Directory where to load static files from, comma-separated list
`start-storybook -s public` | +| `-s`, `--static-dir` | **Deprecated** [see note](#static-dir-deprecation). Directory where to load static files from, comma-separated list
`start-storybook -s public` | | `-c`, `--config-dir [dir-name]` | Directory where to load Storybook configurations from
`start-storybook -c .storybook` | -| `--https` | Serve Storybook over HTTPS. Note: You must provide your own certificate information.
`start-storybook --https` | -| `--ssl-ca` | Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)
`start-storybook --ssl-ca my-certificate` | +| `--https` | Serve Storybook over HTTPS. Note: You must provide your own certificate information
`start-storybook --https` | +| `--ssl-ca` | Provide an SSL certificate authority. (Optional with --https, required if using a self-signed certificate)
`start-storybook --ssl-ca my-certificate` | | `--ssl-cert` | Provide an SSL certificate. (Required with --https)
`start-storybook --ssl-cert my-ssl-certificate` | | `--ssl-key` | Provide an SSL key. (Required with --https)
`start-storybook --ssl-key my-ssl-key` | | `--smoke-test` | Exit after successful start
`start-storybook --smoke-test` | @@ -32,7 +36,8 @@ Usage: start-storybook [options] | `--debug-webpack` | Display final webpack configurations for debugging purposes
`start-storybook --debug-webpack` | | `--webpack-stats-json` | Write Webpack Stats JSON to disk
`start-storybook --webpack-stats-json /tmp/webpack-stats` | | `--docs` | Starts Storybook in documentation mode. Learn more about it in [here](../writing-docs/build-documentation.md#preview-storybooks-documentation)
`start-storybook --docs` | -| `--no-manager-cache` | Disables Storybook's manager caching mechanism. See note below.
`start-storybook --no-manager-cache` | +| `--no-manager-cache` | Disables Storybook's manager caching mechanism. See note below
`start-storybook --no-manager-cache` | +| `--disable-telemetry` | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.md)
`start-storybook --disable-telemetry` |
💡 The flag --no-manager-cache disables the internal caching of Storybook and can severely impact your Storybook loading time, so only use it when you need to refresh Storybook's UI, such as when editing themes. @@ -54,15 +59,16 @@ Usage: build-storybook [options] | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-h`, `--help` | Output usage information
`build-storybook --help` | | `-V`, `--version` | Output the version number
`build-storybook -V` | -| `-s`, `--static-dir` | **Deprecated** [see note](#static-dir-deprecation). Directory where to load static files from, comma-separated list
`build-storybook -s public` | +| `-s`, `--static-dir` | **Deprecated** [see note](#static-dir-deprecation).
Directory where to load static files from, comma-separated list
`build-storybook -s public` | | `-o`, `--output-dir [dir-name]` | Directory where to store built files
`build-storybook -o /my-deployed-storybook` | | `-c`, `--config-dir [dir-name]` | Directory where to load Storybook configurations from
`build-storybook -c .storybook` | -| `--loglevel [level]` | Controls level of logging during build. Can be one of: [silly, verbose, info (default), warn, error, silent]
`build-storybook --loglevel warn` | +| `--loglevel [level]` | Controls level of logging during build.
Available options: `silly`, `verbose`, `info` (default), `warn`, `error`, `silent`
`build-storybook --loglevel warn` | | `--quiet` | Suppress verbose build output
`build-storybook --quiet` | | `--no-dll` | Do not use dll reference (no-op)
`build-storybook --no-dll` | | `--debug-webpack` | Display final webpack configurations for debugging purposes
`build-storybook --debug-webpack` | | `--webpack-stats-json` | Write Webpack Stats JSON to disk
`build-storybook --webpack-stats-json /my-storybook/webpack-stats` | | `--docs` | Builds Storybook in documentation mode. Learn more about it in [here](../writing-docs/build-documentation.md#publish-storybooks-documentation)
`build-storybook --docs` | +| `--disable-telemetry` | Disables Storybook's telemetry. Learn more about it [here](../configure/telemetry.md).
`build-storybook --disable-telemetry` |
💡 If you're using npm instead of yarn to publish Storybook, the commands work slightly different. For example, npm run build-storybook -- -o ./path/to/build. diff --git a/docs/builders/builder-api.md b/docs/builders/builder-api.md new file mode 100644 index 000000000000..1ac4563f86a8 --- /dev/null +++ b/docs/builders/builder-api.md @@ -0,0 +1,163 @@ +--- +title: 'Builder API' +--- + +Storybook is architected to support multiple builders, including [Webpack](https://webpack.js.org/), [Vite](https://vitejs.dev/), and [ESBuild](https://esbuild.github.io/). The builder API is the set of interfaces you can use to add a new builder to Storybook. + +![Storybook builders](./storybook-builders.png) + +## How do builders work? + +In Storybook, a builder is responsible for compiling your components and stories into JS bundles that run in the browser. A builder also provides a development server for interactive development and a production mode for optimized bundles. + +To opt into a builder, the user must add it as a dependency and then edit their configuration file (`.storybook/main.js`) to enable it. For example, with the Vite builder: + + + + + + + + + + + + + +## Builder API + +In Storybook, every builder must implement the following [API](https://github.com/storybookjs/storybook/blob/next/lib/core-common/src/types.ts#L170-L189), exposing the following configuration options and entry points: + + + + + + + +In development mode, the `start` API call is responsible for initializing the development server to monitor the file system for changes (for example, components and stories) then execute a hot module reload in the browser. +It also provides a **bail** function to allow the running process to end gracefully, either via user input or error. + +In production, the `build` API call is responsible for generating a static Storybook build, storing it by default in the `storybook-static` directory if no additional configuration is provided. The generated output should contain everything the user needs to view its Storybook by opening either the `index.html` or `iframe.html` in a browser with no other processes running. + +## Implementation + +Under the hood, a builder is responsible for serving/building the preview `iframe`, which has its own set of requirements. To fully support Storybook, including the [Essential addons](../writing-stories/introduction.md) that ship with Storybook, it must consider the following. + +### Import stories + +The `stories` configuration field enables story loading in Storybook. It defines an array of file globs containing the physical location of the component's stories. The builder must be able to load those files and monitor them for changes and update the UI accordingly. + +### Provide configuration options + +By default, Storybook's configuration is handled in a dedicated file (`storybook/main.js|ts`), giving the user the option to customize it to suit its needs. The builder should also provide its own configuration support through additional fields or some other builder-appropriate mechanism. For example: + + + + + + + +### Handle preview.js exports + +The [`preview.js`](../configure/overview.md#configure-story-rendering) configuration file allows users to control how the story renders in the UI. This is provided via the [decorators](../writing-stories/decorators.md) named export. When Storybook starts, it converts these named exports into internal API calls via virtual module entry, for example, `addDecorator()`. The builder must also provide a similar implementation. For example: + + + + + + + +### MDX support + +[Storybook's Docs](../writing-docs/introduction.md) includes the ability to author stories/documentation in MDX using a Webpack loader. The builder must also know how to interpret MDX and invoke Storybook's special extensions. For example: + + + + + + + +### Generate source code snippets + +Storybook annotates components and stories with additional metadata related to their inputs to automatically generate interactive controls and documentation. Currently, this is provided via Webpack loaders/plugins. The builder must re-implement this to support those features. + +### Generate a static build + +One of Storybook's core features it's the ability to generate a static build that can be [published](../sharing/publish-storybook.md) to a web hosting service. The builder must also be able to provide a similar mechanism. For example: + + + + + + + +### Development server integration + +By default, when Storybook starts in development mode, it relies on its internal development server. The builder needs to be able to integrate with it. For example: + + + + + + + +### Shutdown the development server + +The builder must provide a way to stop the development server once the process terminates; this can be via user input or error. For example: + + + + + + + +### HMR support + +While running in development mode, the builder's development server must be able to reload the page once a change happens, either in a story, component, or helper function. + +### More information + +This area is under rapid development, so the documented is still in progress and subject to change. If you are interested in writing your builder, we encourage you to check [webpack](https://github.com/storybookjs/storybook/tree/next/lib/builder-webpack4), [Vite](https://github.com/storybookjs/builder-vite), and Modern Web's [dev-server-storybook](https://github.com/modernweb-dev/web/blob/master/packages/dev-server-storybook/src/serve/storybookPlugin.ts) source code. In addition, we have a wonderful contributor community on [Storybook Discord](https://discord.gg/storybook) if you have questions. Ping us in the [#contributing](https://discord.com/channels/486522875931656193/839297503446695956) channel. + +#### Learn more about builders + +- [Vite builder](./vite.md) for bundling with Vite +- [Webpack builder](./webpack.md) for bundling with Webpack +- Builder API for building a Storybook builder \ No newline at end of file diff --git a/docs/builders/overview.md b/docs/builders/overview.md new file mode 100644 index 000000000000..f7395953f7e4 --- /dev/null +++ b/docs/builders/overview.md @@ -0,0 +1,24 @@ +--- +title: 'Builders' +--- + +Storybook, at its core, is powered by builders such as Webpack and Vite. These builders spin up a development environment, compile your code—Javascript, CSS, and MDX—into an executable bundle and update the browser in real-time. + +![Storybook builder overview](./storybook-builder-workflow.png) + +## CLI basics + +Before diving into setting up Storybook's builders, let's look at how the CLI configures them. When you initialize Storybook (via `npx sb init`), the CLI automatically detects which builder to use based on your application. For example, if you're working with Vite, it will install the Vite builder. If you're working with Webpack, it installs the Webpack builder based on your current version. + +Additionally, you can also provide a flag to Storybook's CLI and specify the builder you want to use: + +```shell +npx sb init --builder +``` + +## Manual setup + +Storybook uses the Webpack 4 builder by default if you don't specify one. If you want to use a different builder in your application, these docs detail how you can set up Storybook's supported builders. + +- [**Vite builder**](./vite.md) for bundling your stories with Vite with near-instant HMR. +- [**Webpack**](./webpack.md) for bundling your stories with Webpack with improved performance \ No newline at end of file diff --git a/docs/builders/storybook-builder-workflow.png b/docs/builders/storybook-builder-workflow.png new file mode 100644 index 000000000000..7cfceb815bea Binary files /dev/null and b/docs/builders/storybook-builder-workflow.png differ diff --git a/docs/builders/storybook-builders.png b/docs/builders/storybook-builders.png new file mode 100644 index 000000000000..ab61ec37bf46 Binary files /dev/null and b/docs/builders/storybook-builders.png differ diff --git a/docs/builders/vite.md b/docs/builders/vite.md new file mode 100644 index 000000000000..b4fff2f197b1 --- /dev/null +++ b/docs/builders/vite.md @@ -0,0 +1,136 @@ +--- +title: 'Vite' +--- + +Storybook Vite builder bundles your components and stories with [Vite](https://vitejs.dev/), a fast ESM bundler. + +- For applications built with Vite: it allows reusing the existing configuration in Storybook. +- For applications built with Webpack: it provides faster startup and refresh times, with the disadvantage that your component's execution environment differs from your application. + +## Setup + +If you ran `npx sb init` to include Storybook in your Vite application, the builder is already installed and configured for you. If you want, you can also opt into it manually. + +Run the following command to install the builder. + + + + + + + +Update your Storybook configuration (in `.storybook/main.js|ts`) to include the builder. + + + + + + + +## Configuration + +Out of the box, Storybook's Vite builder includes a set of configuration defaults for the supported frameworks. You can also fine-tune them or override them to match your existing configuration as, by default, the builder does not read your `vite.config.js` file. For example, if you need to set up aliasing, you can adjust your Storybook configuration file (`.storybook/main.js|ts`) and provide the following: + + + + + + + +The asynchronous function`viteFinal` receives a `config` object with the default builder configuration and returns the updated configuration with the defined alias. + +You can also override the builder's configuration based on the environment. For instance, if you need to provide a custom configuration for development purposes and another for production, you can extend the default configuration as follows: + + + + + + + +### Svelte configuration + +If you're working with Svelte's Vite plugin ([`vite-plugin-svelte`](https://github.com/sveltejs/vite-plugin-svelte/tree/main/packages/vite-plugin-svelte)), you can extend your existing configuration and include an additional `SvelteOptions` object to customize it. For example: + + + + + + + +### TypeScript + +If you need, you can also configure Storybook's Vite builder using TypeScript. Rename your `.storybook/main.js` to `.storybook/main.ts` and adjust it as follows: + + + + + + + +--- + +## Troubleshooting + +### Prebundle errors + +Vite automatically restarts and begins the prebundling process if it detects a new dependency. This pattern breaks with Storybook and throws confusing error messages. If you see the following message in your terminal: + +```shell +[vite] new dependencies found: +``` + +Update your `viteFinal` configuration and include the new dependencies as follows: + + + + + + + +### Working directory not being detected + +By default, the Vite builder enables Vite's [`server.fs.strict`](https://vitejs.dev/config/#server-fs-strict) option for increased security, defining the project's `root` to Storybook's configuration directory +If you need to override it, you can use the `viteFinal` function and adjust it. + +### HMR seems flaky + +Saving a component story does not initiate a hot module replacement. Instead, a complete reload happens. You can update your component file or save it to see the changes in effect. + +### ArgTypes are not generated automatically + +Storybook’s [automatic argType inference](https://storybook.js.org/docs/react/api/argtypes#automatic-argtype-inference) is currently only available for React TypeScript projects. The builder will include additional framework support in future releases. + +#### Learn more about builders + +- Vite builder for bundling with Vite +- [Webpack builder](./webpack.md) for bundling with Webpack +- [Builder API](./builder-api.md) for building a Storybook builder \ No newline at end of file diff --git a/docs/builders/webpack.md b/docs/builders/webpack.md new file mode 100644 index 000000000000..a2571d22ea0c --- /dev/null +++ b/docs/builders/webpack.md @@ -0,0 +1,203 @@ +--- +title: 'Webpack' +--- + +Storybook displays your components in a custom web application built using [Webpack](https://webpack.js.org/). Webpack is a complex tool, but our default configuration is intended to cover most use cases. [Addons](https://storybook.js.org/addons/) are also available that extend the configuration for other everyday use cases. + +You can customize Storybook's Webpack setup by providing a `webpackFinal` field in [`.storybook/main.js`](../configure/overview.md#configure-your-storybook-project) file. + +The value should be an async function that receives a Webpack config and eventually returns a Webpack config. + +### Default configuration + +By default, Storybook's Webpack configuration will allow you to: + +#### Import images and other static files + +You can import images and other local files and have them built into the Storybook: + + + + + + + +#### Import JSON as JavaScript + +You can import `.json` files and have them expanded to a JavaScript object: + + + + + + + +If you want to know the exact details of the Webpack config, the best way is to run either of the following: + +```shell + +## Development mode +yarn start-storybook --debug-webpack + +## Production mode +yarn build-storybook --debug-webpack +``` + +### Code splitting + +Starting with Storybook 6.4, [code splitting](https://v4.webpack.js.org/guides/code-splitting/) is supported through a configuration flag. Update your Storybook configuration and add the `storyStoreV7` flag: + + + + + + + +When you start your Storybook, you'll see an improvement in loading times. Read more about it in the [announcement post](https://storybook.js.org/blog/storybook-on-demand-architecture/) and the [configuration documentation](../configure/overview.md#configure-your-storybook-project). + +### Webpack 5 + +Storybook builds your project with Webpack 4 by default. If your project uses Webpack 5, you can opt into the Webpack 5 builder by installing the required dependencies (i.e., `@storybook/builder-webpack5`, `@storybook/manager-webpack5`) and update your Storybook configuration as follows: + + + + + + + +Once you are using Webpack 5, you can further opt into some features to optimize your build: + +#### Lazy Compilation + +Storybook supports Webpack's experimental [lazy compilation](https://webpack.js.org/configuration/experiments/#experimentslazycompilation) feature, via the `lazyCompilation` builder flag: + + + + + + + +This feature applies in development mode, and will mean your Storybook will start up faster, at the cost of slightly slower browsing time when you change stories. + +#### Filesystem Caching + +Storybook supports Webpack's [filesystem caching](https://webpack.js.org/configuration/cache/#cachetype) feature, via the `fsCache` builder flag: + + + + + + + +This feature will mean build output is cached between runs of Storybook, speeding up subsequent startup times. + +### Extending Storybook’s Webpack config + +To extend the above configuration, use the `webpackFinal` field of [`.storybook/main.js`](../configure/overview.md#configure-your-storybook-project). + +The value should export a `function`, which will receive the default config as its first argument. The second argument is an options object from Storybook, and this will have information about where config came from, whether we're in production or development mode, etc. + +For example, if you wanted to add [Sass](https://sass-lang.com/) support, you can adjust your configuration as such: + + + + + + + +Storybook uses the config returned from the above function to render your components in Storybook's "preview" iframe. Note that Storybook has an entirely separate Webpack config for its UI (also referred to as the "manager"), so the customizations you make only apply to the rendering of your stories, i.e., you can completely replace `config.module.rules` if you want. + +Nevertheless, edit `config` with care. Make sure to preserve the following config options: + +- **entry** +- **output** + +Furthermore, `config` requires the `HtmlWebpackplugin` to generate the preview page, so rather than overwriting `config.plugins` you should probably append to it (or overwrite it with care), see [the following issue](https://github.com/storybookjs/storybook/issues/6020) for examples on how to handle this: + + + + + + + +Finally, if your custom Webpack config uses a loader that does not explicitly include specific file extensions via the `test` property, in that case, it is necessary to `exclude` the `.ejs` file extension from that loader. + +If you're using a non-standard Storybook config directory, you should put `main.js` there instead of `.storybook` and update the `include` path to ensure it resolves to your project root. + +### Using your existing config + +Suppose you have an existing Webpack config for your project and want to reuse this app's configuration. In that case, you can import your main Webpack config into Storybook's [`.storybook/main.js`](../configure/overview.md#configure-your-storybook-project) and merge both: + +The following code snippet shows how you can replace the loaders from Storybook with the ones from your app's `webpack.config.js`: + + + + + + + +
+ +💡 Projects initialized via generators (e.g, Vue CLI) may require that you import their own Webpack config file (i.e., /projectRoot/node_modules/@vue/cli-service/webpack.config.js) to use a certain feature with Storybook. For other generators, make sure to check the documentation for instructions. + +
+ +### TypeScript Module Resolution + +When working with TypeScript projects, the default Webpack configuration may fail to resolve module aliases defined in your [`tsconfig` file](https://www.typescriptlang.org/tsconfig). To work around this issue you may use [`tsconfig-paths-webpack-plugin`](https://github.com/dividab/tsconfig-paths-webpack-plugin#tsconfig-paths-webpack-plugin) while [extending Storybook's Webpack config](#extending-storybooks-webpack-config) like: + + + + + + + +
+ +#### Learn more about builders + +- [Vite builder](./vite.md) for bundling with Vite +- [Webpack builder](./webpack.md) for bundling with Webpack +- [Builder API](./builder-api.md) for building a Storybook builder \ No newline at end of file diff --git a/docs/configure/babel.md b/docs/configure/babel.md index aa6d23031050..a1af175354ef 100644 --- a/docs/configure/babel.md +++ b/docs/configure/babel.md @@ -18,7 +18,7 @@ It has three different modes: Storybook works with evergreen browsers by default. -If you want to run Storybook in IE11, make sure to [disable](../essentials/introduction#disabling-addons) the docs-addon that is part of `@storybook/addon-essentials`, as this currently [causes issues in IE11](https://github.com/storybookjs/storybook/issues/8884). +If you want to run Storybook in IE11, make sure to [disable](../essentials/introduction.md#disabling-addons) the docs-addon that is part of `@storybook/addon-essentials`, as this currently [causes issues in IE11](https://github.com/storybookjs/storybook/issues/8884). Here are some key features of Storybook's Babel configurations. @@ -38,7 +38,7 @@ You can also place a `.storybook/.babelrc` file to use a unique configuration fo ### Custom configuration -If you need, you can customize the default Babel configuration used by Storybook. Update your [`.storybook/main.js`](./overview#configure-your-storybook-project) and add the `babel` field with the options you want to use: +If you need, you can customize the default Babel configuration used by Storybook. Update your [`.storybook/main.js`](./overview.md#configure-your-storybook-project) and add the `babel` field with the options you want to use: diff --git a/docs/configure/features-and-behavior.md b/docs/configure/features-and-behavior.md index 42d791c02226..d936e062d962 100644 --- a/docs/configure/features-and-behavior.md +++ b/docs/configure/features-and-behavior.md @@ -23,7 +23,7 @@ The following table details how to use the API values: | **showPanel** | Boolean | Display panel that shows addon configurations | `true` | | **panelPosition** | String/Object | Where to show the addon panel | `bottom` or `right` | | **enableShortcuts** | Boolean | Enable/disable shortcuts | `true` | -| **isToolshown** | Boolean | Show/hide tool bar | `true` | +| **showToolbar** | Boolean | Show/hide tool bar | `true` | | **theme** | Object | Storybook Theme, see next section | `undefined` | | **selectedPanel** | String | Id to select an addon panel | `storybook/actions/panel` | | **initialActive** | String | Select the default active tab on Mobile | `sidebar` or `canvas` or `addons` | @@ -54,4 +54,5 @@ You can use URL parameters to configure some of the available features: | **isFullscreen** | `full` | `true` | | **showNav** | `nav` | `false` | | **showPanel** | `panel` | `false`, `right`, `bottom` | -| **selectedPanel** | `addonPanel` | Any panel ID | \ No newline at end of file +| **selectedPanel** | `addonPanel` | Any panel ID | +| **showTabs** | `tabs` | `true` | \ No newline at end of file diff --git a/docs/configure/images-and-assets.md b/docs/configure/images-and-assets.md index 779a8c7bb3f6..8049a22db88a 100644 --- a/docs/configure/images-and-assets.md +++ b/docs/configure/images-and-assets.md @@ -127,4 +127,4 @@ In this case, you need to have all your images and media files with relative pat If you load static content via importing, this is automatic, and you do not have to do anything. -Suppose you are serving assets in a [static directory](#serving-static-files-via-storybook) along with your Storybook. In that case, you need to use relative paths to load images or use the base element. +Suppose you are serving assets in a [static directory](#serving-static-files-via-storybook-configuration) along with your Storybook. In that case, you need to use relative paths to load images or use the base element. diff --git a/docs/configure/overview.md b/docs/configure/overview.md index 493b5f1150a9..462d88bc3cd6 100644 --- a/docs/configure/overview.md +++ b/docs/configure/overview.md @@ -27,7 +27,7 @@ The main configuration file is `main.js`. This file controls the Storybook serve The `main.js` configuration file is a [preset](../addons/addon-types.md) and, as such, has a powerful interface, but the key fields within it are: - `stories` - an array of globs that indicates the [location of your story files](#configure-story-loading), relative to `main.js`. -- `addons` - a list of the [addons](/addons) you are using. +- `addons` - a list of the [addons](https://storybook.js.org/addons/) you are using. - `webpackFinal` - custom [webpack configuration](./webpack.md#extending-storybooks-webpack-config). - `babel` - custom [babel configuration](./babel.md). - `framework` - framework specific configurations to help the loading and building process. diff --git a/docs/configure/storybook-addons.md b/docs/configure/storybook-addons.md index 55b33eac648d..21233c31bf3e 100644 --- a/docs/configure/storybook-addons.md +++ b/docs/configure/storybook-addons.md @@ -22,4 +22,4 @@ There are many, many Storybook addons, but they can be roughly categorized into - **Essential** addons are core-team developed addons that are considered a part of the out-of-the-box user experience. These ship by default with new Storybook installations. - **Core** addons are developed by the core team. They are kept in sync with the development of Storybook itself and written in idiomatic ways as templates for other addons. They can be found within the [Storybook monorepo](https://github.com/storybookjs/storybook/tree/next/addons). -- **Community** addons are addons written by the massive Storybook community. They can be found on our [website](/addons), [GitHub](https://github.com/), and [npm](https://www.npmjs.com/). \ No newline at end of file +- **Community** addons are addons written by the massive Storybook community. They can be found on our [website](https://storybook.js.org/addons/), [GitHub](https://github.com/), and [npm](https://www.npmjs.com/). \ No newline at end of file diff --git a/docs/configure/styling-and-css.md b/docs/configure/styling-and-css.md index f45208957370..2253874499fb 100644 --- a/docs/configure/styling-and-css.md +++ b/docs/configure/styling-and-css.md @@ -10,7 +10,7 @@ CSS-in-JS libraries are designed to use basic JavaScript, and they often work in ### Importing CSS files -If your component files import their CSS, Storybook's webpack configuration will work out of the box. The noticeable exception to this is if you're using a CSS precompiler. In this case, you can either install and configure a Storybook preset (e.g., [SCSS preset](https://github.com/storybookjs/presets/tree/master/packages/preset-scss)), or customize [Storybook's webpack configuration](./webpack#extending-storybooks-webpack-config) and include the appropriate loader. +If your component files import their CSS, Storybook's webpack configuration will work out of the box. The noticeable exception to this is if you're using a CSS precompiler. In this case, you can either install and configure a Storybook preset (e.g., [SCSS preset](https://github.com/storybookjs/presets/tree/master/packages/preset-scss)), or customize [Storybook's webpack configuration](./webpack.md#extending-storybooks-webpack-config) and include the appropriate loader. @@ -18,4 +18,4 @@ To use your CSS in all stories, you import it in [`.storybook/preview.js`](./ove ### Adding webfonts -If you need webfonts to be available, you may need to add some code to the [`.storybook/preview-head.html`](./story-rendering.md#adding-to-head) file. We recommend including any assets with your Storybook if possible, in which case you likely want to configure the [static file location](./images-and-assets#serving-static-files-via-storybook). \ No newline at end of file +If you need webfonts to be available, you may need to add some code to the [`.storybook/preview-head.html`](./story-rendering.md#adding-to-head) file. We recommend including any assets with your Storybook if possible, in which case you likely want to configure the [static file location](./images-and-assets.md#serving-static-files-via-storybook-configuration). \ No newline at end of file diff --git a/docs/configure/telemetry.md b/docs/configure/telemetry.md new file mode 100644 index 000000000000..72c66d0b8aed --- /dev/null +++ b/docs/configure/telemetry.md @@ -0,0 +1,174 @@ +--- +title: 'Telemetry' +--- + +Storybook collects completely anonymous data to help us improve user experience. Participation in this anonymous program is optional, and you may opt-out if you'd not like to share any information. + +## Why is telemetry collected? + +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/), and [Svelte](https://svelte.dev/) +- **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) + +In the past, our improvement process relied on manually gathering feedback. But with a growing userbase and the need to support a wide variety of integrations, we need a more accurate method for gauging Storybook usage and pain points. + +These telemetry data help us (the maintainers) to prioritize the highest impact projects. That allows us to keep up with trends in the front-end ecosystem and verify that our community's hard work achieves the intended result. + +## What is being collected? + +We collect general usage details, including command invocation, Storybook version, addons, and the view layer. + +Specifically, we track the following information in our telemetry events: + +- Timestamp of the occurrence. +- Command invoked (e.g., `init`, `upgrade`, `start-storybook`). +- Storybook unique identifier: One-way hash generated during Storybook installation process. +- One way hash of the IP address where the event occurred for spam detection. +- Story count. +- Storybook version. +- Storybook metadata: + - Language (e.g., TypeScript, JavaScript). + - Supported view layers (e.g., React, Vue, Angular, Svelte). + - Builder (e.g., Webpack4, Webpack5, Vite). + - Meta framework (e.g., [Next](https://nextjs.org/), [Gatsby](https://www.gatsbyjs.com/), [CRA](https://create-react-app.dev/)). + - [Addons](/addons) (e.g., [Essentials](../essentials/introduction), [Accessibility](https://storybook.js.org/addons/@storybook/addon-a11y/)). + - [Feature flags](./overview.md#feature-flags) (e.g., `buildStoriesJson`). +- Whether the command was invoked on CI or not. + +Access to the raw data is highly controlled, limited to select members of Storybook's core team who maintain the telemetry. We cannot identify individual users from the dataset: it is anonymized and untraceable back to the user. + +## What about sensitive information? + +We take your privacy and our security very seriously. We perform additional steps to ensure that secure data (e.g., environment variables or other forms of sensitive data) **do not** make their way into our analytics. You can view all the information we collect by setting the `STORYBOOK_TELEMETRY_DEBUG` to `1` to print out the information gathered. For example: + + + + + + + +Will generate the following output: + +```json +{ + "anonymousId": "8bcfdfd5f9616a1923dd92adf89714331b2d18693c722e05152a47f8093392bb", + "eventType": "start", + "payload": { + "storyIndex": { + "storyCount": 4, + "version": 3 + } + }, + "inCI": false, + "metadata": { + "generatedAt": 1648233198722, + "builder": { + "name": "webpack4" + }, + "hasCustomBabel": false, + "hasCustomWebpack": true, + "hasStaticDirs": true, + "hasStorybookEslint": false, + "refCount": 0, + "metaFramework": { + "name": "CRA", + "packageName": "react-scripts", + "version": "4.0.3" + }, + "features": { + "buildStoriesJson": true + }, + "storybookVersion": "6.5.0", + "language": "typescript", + "storybookPackages": { + "@storybook/addons": { + "version": "6.5.0" + }, + "@storybook/builder-webpack4": { + "version": "6.5.0" + }, + "@storybook/react": { + "version": "6.5.0" + } + }, + "framework": { + "name": "react" + }, + "addons": { + "@storybook/preset-create-react-app": { + "version": "3.2.0" + }, + "@storybook/addon-ie11": { + "version": "0.0.7--canary.5e87b64.0" + }, + "@storybook/addon-essentials": { + "options": { + "viewport": false + }, + "version": "6.5.0" + } + } + } +} +``` + +## Will this data be shared? + +The data we collect is anonymous, not traceable to the source, and only meaningful in aggregate form. No data we collect is personally identifiable. +In the future, we plan to share relevant data with the community through public dashboards (or similar data representation formats). + +## How to opt-out + +You may opt-out of the telemetry by setting Storybook's configuration element `disableTelemetry` to `true`, using the `--disable-telemetry` flag, or setting the environment variable`STORYBOOK_DISABLE_TELEMETRY` to `1`. For example: + + + + + + + +## Crash reports (disabled by default) + +In addition to general usage telemetry, you may also choose to share crash reports. Storybook will then sanitize the error object (removing all user paths) and append it to the telemetry event. To enable crash reporting, you can set the `enableCrashReports` configuration element to `true`, using the `--enable-crash-reports` flag, or set the `STORYBOOK_ENABLE_CRASH_REPORTS` environment variable to `1`. For example: + + + + + + + +Generates the following item in the telemetry event: + + + + + + diff --git a/docs/configure/theming.md b/docs/configure/theming.md index e2928d0826cd..55e8118bb38f 100644 --- a/docs/configure/theming.md +++ b/docs/configure/theming.md @@ -32,7 +32,7 @@ When setting a theme, set a complete theme object. The theme is replaced, not co ## Theming docs -[Storybook Docs](../writing-docs/introduction) uses the same theme system as Storybook’s UI but is themed independently from the main UI. +[Storybook Docs](../writing-docs/introduction.md) uses the same theme system as Storybook’s UI but is themed independently from the main UI. Supposing you have a Storybook theme defined for the main UI in [`.storybook/manager.js`](./overview.md#configure-story-rendering): @@ -85,6 +85,7 @@ Above, we're creating a new theme that will: - Use Storybook's `light` theme as a baseline. - Replace Storybook's logo in the sidebar with our own (defined in the brandImage variable). - Add custom branding information. +- Set the brand link to open in the same window (as opposed to a new one), via the `target` attribute. Finally, we'll need to import the theme into Storybook. Create a new file called `manager.js` in your `.storybook` directory and add the following: @@ -226,4 +227,4 @@ Or with template literals: ]} /> - \ No newline at end of file + diff --git a/docs/configure/upgrading.md b/docs/configure/upgrading.md index 4cc4322328e4..5cd1f7cdf0e1 100644 --- a/docs/configure/upgrading.md +++ b/docs/configure/upgrading.md @@ -18,7 +18,7 @@ This upgrades all of the Storybook packages in your project to the latest stable
-In addition to running the command, we also recommend checking the [MIGRATION.md file](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md), for the detailed log of relevant changes and deprecations that might affect your upgrade. +In addition to running the command, we also recommend checking the [MIGRATION.md file](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md), for the detailed log of relevant changes and deprecations that might affect your upgrade.
@@ -42,4 +42,8 @@ To upgrade to the latest pre-release: npx sb@next upgrade --prerelease ``` -If you'd like to downgrade to a stable version, manually edit the package version numbers in your `package.json` and re-install. \ No newline at end of file +If you'd like to downgrade to a stable version, manually edit the package version numbers in your `package.json` and re-install. + +
+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. +
diff --git a/docs/configure/webpack.md b/docs/configure/webpack.md index d86127a6ae25..c156547d953e 100644 --- a/docs/configure/webpack.md +++ b/docs/configure/webpack.md @@ -2,7 +2,7 @@ title: 'Webpack' --- -Storybook displays your components in a custom web application built using [Webpack](https://webpack.js.org/). Webpack is a complex tool, but our default configuration is intended to cover most use cases. [Addons](/addons) are also available that extend the configuration for other everyday use cases. +Storybook displays your components in a custom web application built using [Webpack](https://webpack.js.org/). Webpack is a complex tool, but our default configuration is intended to cover most use cases. [Addons](https://storybook.js.org/addons/) are also available that extend the configuration for other everyday use cases. You can customize Storybook's webpack setup by providing a `webpackFinal` field in [`.storybook/main.js`](./overview.md#configure-your-storybook-project) file. @@ -69,7 +69,7 @@ When you start your Storybook, you'll see an improvement in loading times. Read ### Webpack 5 -Storybook builds your project with Webpack 4 by default. If your project uses Webpack 5, you can opt into the Webpack 5 builder by installing the `@storybook/builder-webpack5` package, and opting in in your `main.js`: +Storybook builds your project with Webpack 4 by default. If your project uses Webpack 5, you can opt into the Webpack 5 builder by installing the required dependencies (i.e., `@storybook/builder-webpack5`, `@storybook/manager-webpack5`) and update your Storybook configuration as follows: diff --git a/docs/contribute/code.md b/docs/contribute/code.md index b6c92a5560ee..9a1f4fada5b6 100644 --- a/docs/contribute/code.md +++ b/docs/contribute/code.md @@ -59,7 +59,9 @@ yarn build When asked if you want to start the build in `watch` mode, answer **yes** to develop in interactive mode. Afterward, choose which packages you want to build. For example, if you're going to work on a feature for `@storybook/addon-docs`, you might want to select `@storybook/addon-docs` and `@storybook/components`.
-💡 Build's `watch' mode is great for interactive development. However, for performance reasons it only transpiles your code and doesn't execute the TypeScript compiler. If something isn't working as expected, try running `build` WITHOUT watch mode: it will re-generate TypeScript types and also perform type checking for you. + +💡 Build's `watch` mode is great for interactive development. However, for performance reasons it only transpiles your code and doesn't execute the TypeScript compiler. If something isn't working as expected, try running `build` WITHOUT watch mode: it will re-generate TypeScript types and also perform type checking for you. +
![Storybook package selector](./storybook-build-packages-selection-optimized.png) @@ -144,14 +146,14 @@ npx sb@next link --local /path/to/local-repro-directory ```
-💡 The `sb link` command relies on `yarn 2` linking under the hood. It requires that the local repro is using `yarn 2`, which will be the case if you're using the [`sb repro` command](./how-to-reproduce) per our contributing guidelines. If you are trying to link to a non-`yarn 2` project, linking will fail. +💡 The sb link command relies on yarn 2 linking under the hood. It requires that the local repro is using yarn 2, which will be the case if you're using the [sb repro command](./how-to-reproduce) per our contributing guidelines. If you are trying to link to a non-yarn 2 project, linking will fail.
## Troubleshooting
-`yarn build --all --watch` watches everything but is resource-intensive +yarn build --all --watch watches everything but is resource-intensive It's troublesome to know which packages you're going to change ahead of time, and watching all of them can be highly demanding, even on modern machines. If you're working on a powerful enough machine, you can use `yarn build --all --watch` instead of `yarn build`. diff --git a/docs/contribute/how-to-contribute.md b/docs/contribute/how-to-contribute.md index 546b0b9ccd34..894cb309f598 100644 --- a/docs/contribute/how-to-contribute.md +++ b/docs/contribute/how-to-contribute.md @@ -12,8 +12,8 @@ In the interest of fostering an open and welcoming environment, we as contributo - [**Code**](./code.md): Features, bug fixes, dependency updates - [**Docs**](./documentation-updates.md): Typos, clarifications -- [**Integrations**](./../api/new-frameworks): Integrate Storybook with your favorite library -- [**Addons**](./../addons/introduction): Build an addon and share it with the community +- [**Integrations**](./../api/new-frameworks.md): Integrate Storybook with your favorite library +- [**Addons**](./../addons/introduction.md): Build an addon and share it with the community - [**Examples**](https://github.com/storybookjs/storybook/tree/next/examples/official-storybook): Add an example/test for a feature ## Not sure how to get started? diff --git a/docs/contribute/how-to-reproduce.md b/docs/contribute/how-to-reproduce.md index 1372a8205290..ebc2ae7f39f3 100644 --- a/docs/contribute/how-to-reproduce.md +++ b/docs/contribute/how-to-reproduce.md @@ -50,7 +50,7 @@ If everything worked as it should, you should have a fully functional Storybook Before adding code, install and configure any necessary packages. For example, if you run into a problem with a CSS framework (e.g., [Tailwind](https://tailwindcss.com/)), you should install and configure it. -Install and configure any Storybook [addons](/addons) that relate to the issue (e.g.,`@storybook/addon-a11y`). +Install and configure any Storybook [addons](https://storybook.js.org/addons/) that relate to the issue (e.g.,`@storybook/addon-a11y`). ## Add stories diff --git a/docs/contribute/new-snippets.md b/docs/contribute/new-snippets.md index c6b51f6dcde9..84e4a91439b2 100644 --- a/docs/contribute/new-snippets.md +++ b/docs/contribute/new-snippets.md @@ -110,7 +110,7 @@ yarn start:skip-addons ```
-💡 During the start process if there's an issue with the the documentation, the process will stop and you'll get a notification. +💡 During the start process if there's an issue with the documentation, the process will stop and you'll get a notification.
Open a browser window to `http://localhost:8000`, click the Docs link, and select your framework from the dropdown. diff --git a/docs/essentials/controls.md b/docs/essentials/controls.md index 305653acedfd..5da997b1fc61 100644 --- a/docs/essentials/controls.md +++ b/docs/essentials/controls.md @@ -11,7 +11,7 @@ Storybook Controls gives you a graphical UI to interact with a component's argum /> -Controls does not require any modification to your components. Stories for controls are: +Controls do not require any modification to your components. Stories for controls are: - Convenient. Auto-generate controls based on React/Vue/Angular/etc. components. - Portable. Reuse your interactive stories in documentation, tests, and even in designs. @@ -180,7 +180,7 @@ The Controls addon can be configured in two ways: ### Annotation -As shown above, you can configure individual controls with the “control" annotation in the [argTypes](../api/argtypes) field of either a component or story. Below is a condensed example and table featuring all available controls. +As shown above, you can configure individual controls with the “control" annotation in the [argTypes](../api/argtypes.md) field of either a component or story. Below is a condensed example and table featuring all available controls. | Data Type | Control | Description | | ----------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -197,7 +197,7 @@ As shown above, you can configure individual controls with the “control" annot | | `select` | Provides a drop-down list component to handle single value selection. `argTypes: { age: { control: 'select', options: [20, 30, 40, 50] }}` | | | `multi-select` | Provides a drop-down list that allows multiple selected values. `argTypes: { countries: { control: 'multi-select', options: ['USA', 'Canada', 'Mexico'] }}` | | **string** | `text` | Provides a freeform text input.
`argTypes: { label: { control: 'text' }}` | -| | `color` | Provides a color picker component to handle color values.
Can be additionally configured to include a set of color presets.
`argTypes: { color: { control: { type: 'color', presetsColors: ['red', 'green']} }}` | +| | `color` | Provides a color picker component to handle color values.
Can be additionally configured to include a set of color presets.
`argTypes: { color: { control: { type: 'color', presetColors: ['red', 'green']} }}` | | | `date` | Provides a datepicker component to handle date selection. `argTypes: { startDate: { control: 'date' }}` |
@@ -302,7 +302,7 @@ paths={[ ### Conditional controls -In some cases, it's useful to be able to conditionally exclude a control based on the value of another control. Controls supports basic versions of these use cases with the `addIf` and `removeIf` options, which can take a boolean value, or a string which can refer to the value of another arg. +In some cases, it's useful to be able to conditionally exclude a control based on the value of another control. Controls supports basic versions of these use cases with the `if`, which can takes a simple query object to determine whether to include the control. Consider a collection of "advanced" settings that are only visible when the user toggles an "advanced" toggle. @@ -328,6 +328,24 @@ Or consider a constraint where if the user sets one control value, it doesn't ma +The query object must contain either an `arg` or `global` target: + +| field | type | meaning | +| ------ | ------ | ----------------------------- | +| arg | string | The ID of the arg to test. | +| global | string | The ID of the global to test. | + +It may also contain at most one of the following operators: + +| operator | type | meaning | +| -------- | ------- | ---------------------------------------------------- | +| truthy | boolean | Is the target value truthy? | +| exists | boolean | Is the target value defined? | +| eq | any | Is the target value equal to the provided value? | +| neq | any | Is the target value NOT equal to the provided value? | + +If no operator is provided, that is equivalent to `{ truthy: true }`. + ## Hide NoControls warning If you don't plan to handle the control args inside your Story, you can remove the warning with: diff --git a/docs/essentials/introduction.md b/docs/essentials/introduction.md index db59851a0415..4d84463a8e9e 100644 --- a/docs/essentials/introduction.md +++ b/docs/essentials/introduction.md @@ -32,7 +32,7 @@ Update your Storybook configuration (in [`.storybook/main.js`](../configure/over diff --git a/docs/faq.md b/docs/faq.md index 9c5934ea7830..1976efce092f 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -83,6 +83,20 @@ module.exports = { 💡 Fast Refresh only works in development mode with React 16.10 or higher.
+### How do I setup the new React Context Root API with Storybook? + +If your installed React Version equals or is higher than 18.0.0, the new React Root API is automatically used and the newest React [concurrent features](https://reactjs.org/docs/concurrent-mode-intro.html) can be used. + +You can opt-out from the new React Root API by setting the following property in your `.storybook/main.js` file: + +```js +module.exports = { + reactOptions: { + legacyRootApi: true, + }, +}; +``` + ### Why is there no addons channel? A common error is that an addon tries to access the "channel", but the channel is not set. It can happen in a few different cases: @@ -97,7 +111,6 @@ A common error is that an addon tries to access the "channel", but the channel i 2. In React Native, it's a special case documented in [#1192](https://github.com/storybookjs/storybook/issues/1192) - ### Why aren't Controls visible in the Canvas panel but visible in the Docs panel? If you're adding Storybook's dependencies manually, make sure you include the [`@storybook/addon-controls`](https://www.npmjs.com/package/@storybook/addon-controls) dependency in your project and reference it in your `.storybook/main.js` as follows: @@ -132,67 +145,73 @@ With the release of version 6.0, we updated our documentation as well. That does We're only covering versions 5.3 and 5.0 as they were important milestones for Storybook. If you want to go back in time a little more, you'll have to check the specific release in the monorepo. -| Section | Page | Current Location | Version 5.3 location | Version 5.0 location | -|------------------|-------------------------------------------|------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| -| Get started | Install | [See current documentation](../get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | -| | What's a story | [See current documentation](../get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | -| | Browse Stories | [See current documentation](../get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | -| | Setup | [See current documentation](../get-started/setup.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | -| Write stories | Introduction | [See current documentation](../writing-stories/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Parameters | [See current documentation](../writing-stories/parameters.md) | See versioned documentation here | Non existing feature or undocumented | -| | Decorators | [See current documentation](../writing-stories/decorators.md) | See versioned documentation here | See versioned documentation here | -| | Naming components and hierarchy | [See current documentation](../writing-stories/naming-components-and-hierarchy.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | -| | Build pages and screens | [See current documentation](../writing-stories/build-pages-with-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Stories for multiple components | [See current documentation](../writing-stories/stories-for-multiple-components.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Write docs | DocsPage | [See current documentation](../writing-docs/docs-page.md) | See versioned addon documentation | Non existing feature or undocumented | -| | MDX | [See current documentation](../writing-docs/mdx.md) | See versioned addon documentation | Non existing feature or undocumented | -| | Doc Blocks/Argstable | [See current documentation](../writing-docs/doc-block-argstable.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Canvas | [See current documentation](../writing-docs/doc-block-canvas.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Color Palette | [See current documentation](../doc-block-colorpalette.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Description | [See current documentation](../writing-docs/doc-block-description.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Icon Gallery | [See current documentation](../writing-docs/doc-block-icongallery.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Source | [See current documentation](../writing-docs/doc-block-source.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Story | [See current documentation](../writing-docs/doc-block-story.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Doc Blocks/Typeset | [See current documentation](../writing-docs/doc-block-typeset.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | -| | Preview and build docs | [See current documentation](../writing-docs/build-documentation.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Testing | Visual tests | [See current documentation](../writing-tests/visual-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing) | -| | Accessibility tests | [See current documentation](../writing-tests/accessibility-testing.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Interaction tests | [See current documentation](../writing-tests/interaction-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing) | -| | Snapshot tests | [See current documentation](../writing-tests/snapshot-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing) | -| | Import stories in tests | [See current documentation](../writing-tests/importing-stories-in-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | -| Sharing | Publish Storybook | [See current documentation](../sharing/publish-storybook.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook) | -| | Embed | [See current documentation](../sharing/embed.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Composition | [See current documentation](../sharing/storybook-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Package Composition | [See current documentation](../sharing/package-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| Essential addons | Controls | [See current documentation](../essentials/controls.md) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs) | -| | Actions | [See current documentation](../essentials/actions.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions) | -| | Viewport | [See current documentation](../essentials/viewport.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport) | -| | Backgrounds | [See current documentation](../essentials/backgrounds.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds) | -| | Toolbars and globals | [See current documentation](../essentials/toolbars-and-globals.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide) | Non existing feature or undocumented | -| Configure | Overview | [See current documentation](../configure/overview.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview) | [See versioned documentation](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/basics/writing-stories) | -| | Integration/Webpack | [See current documentation](../configure/webpack.md) | See versioned documentation | See versioned documentation | -| | Integration/Babel | [See current documentation](../configure/babel.md) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config) | -| | Integration/Typescript | [See current documentation](../configure/typescript.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config) | -| | Integration/Styling and CSS | [See current documentation](../configure/styling-and-css.md) | See versioned documentation | See versioned documentation | -| | Integration/Images and assets | [See current documentation](../configure/images-and-assets.md) | See versioned documentation | See versioned documentation | -| | Story rendering | [See current documentation](../configure/story-rendering.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags) | -| | Story Layout | [See current documentation](../configure/story-layout.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | User Interface/Features and behavior | [See current documentation](../configure/features-and-behavior.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | -| | User Interface/Theming | [See current documentation](../configure/theming.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming) | -| | User Interface/Sidebar & URLS | [See current documentation](../configure/sidebar-and-urls.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | -| | Environment variables | [See current documentation](../configure/environment-variables.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars) | -| Addons | Introduction | [See current documentation](../addons/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Install addons | [See current documentation](../addons/install-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/blob/release/5.3/docs/src/pages/addons/using-addons/) | [See versioned documentation](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/addons/using-addons/) | -| | Writing Addons | [See current documentation](../addons/writing-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Writing Presets | [See current documentation](../addons/writing-presets.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets) | Non existing feature or undocumented | -| | Addons Knowledge Base | [See current documentation](../addons/addon-knowledge-base.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | -| | Types of addons | [See current documentation](../addons/addon-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | -| | Addons API | [See current documentation](../addons/addons-api.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api) | -| API | Stories/Component Story Format | [See current documentation](../api/csf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format) | Non existing feature or undocumented | -| | Stories/MDX syntax | [See current documentation](../api/mdx.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/mdx-syntax) | Non existing feature or undocumented | -| | Stories/StoriesOF format (see note below) | [See current documentation](../../lib/core/docs/storiesOf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/storiesof-api) | 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) | + +| Section | Page | Current Location | Version 5.3 location | Version 5.0 location | +|------------------|-------------------------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| Get started | Install | [See current documentation](./get-started/install.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides/quick-start-guide) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides/quick-start-guide) | +| | What's a story | [See current documentation](./get-started/whats-a-story.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | +| | Browse Stories | [See current documentation](./get-started/browse-stories.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/blob/release/5.0/docs/src/pages/guides) | +| | Setup | [See current documentation](./get-started/setup.md) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/guides) | [See versioned documentation for your framework](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/guides) | +| Write stories | Introduction | [See current documentation](./writing-stories/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Parameters | [See current documentation](./writing-stories/parameters.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#parameters) | Non existing feature or undocumented | +| | Decorators | [See current documentation](./writing-stories/decorators.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories/index.md#decorators) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories/index.md#using-decorators) | +| | Naming components and hierarchy | [See current documentation](./writing-stories/naming-components-and-hierarchy.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/writing-stories) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Build pages and screens | [See current documentation](./writing-stories/build-pages-with-storybook.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Stories for multiple components | [See current documentation](./writing-stories/stories-for-multiple-components.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Write docs | DocsPage | [See current documentation](./writing-docs/docs-page.md) | See versioned addon documentation | Non existing feature or undocumented | +| | MDX | [See current documentation](./writing-docs/mdx.md) | See versioned addon documentation | Non existing feature or undocumented | +| | Doc Blocks/Argstable | [See current documentation](./writing-docs/doc-block-argstable.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Canvas | [See current documentation](./writing-docs/doc-block-canvas.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Color Palette | [See current documentation](./writing-docs/doc-block-colorpalette.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Description | [See current documentation](./writing-docs/doc-block-description.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Icon Gallery | [See current documentation](./writing-docs/doc-block-icongallery.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Source | [See current documentation](./writing-docs/doc-block-source.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Story | [See current documentation](./writing-docs/doc-block-story.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Doc Blocks/Typeset | [See current documentation](./writing-docs/doc-block-typeset.md) | [See versioned addon documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/docs/) | Non existing feature or undocumented | +| | Preview and build docs | [See current documentation](./writing-docs/build-documentation.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Testing | Visual tests | [See current documentation](./writing-tests/visual-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/automated-visual-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/automated-visual-testing) | +| | Accessibility tests | [See current documentation](./writing-tests/accessibility-testing.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Interaction tests | [See current documentation](./writing-tests/interaction-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/interaction-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/interaction-testing) | +| | Snapshot tests | [See current documentation](./writing-tests/snapshot-testing.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/structural-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/structural-testing) | +| | Import stories in tests | [See current documentation](./writing-tests/importing-stories-in-tests.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/testing/react-ui-testing) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/testing/react-ui-testing) | +| Sharing | Publish Storybook | [See current documentation](./sharing/publish-storybook.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/exporting-storybook) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/exporting-storybook) | +| | Embed | [See current documentation](./sharing/embed.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Composition | [See current documentation](./sharing/storybook-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Package Composition | [See current documentation](./sharing/package-composition.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Essential addons | Controls | [See current documentation](./essentials/controls.md) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/knobs) | Controls are specific to version 6.0 see [Knobs versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/knobs) | +| | Actions | [See current documentation](./essentials/actions.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/actions) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/actions) | +| | Viewport | [See current documentation](./essentials/viewport.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/viewport) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/viewport) | +| | Backgrounds | [See current documentation](./essentials/backgrounds.md) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/addons/backgrounds) | [See addon versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/addons/backgrounds) | +| | Toolbars and globals | [See current documentation](./essentials/toolbars-and-globals.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/basics/toolbar-guide) | Non existing feature or undocumented | +| Configure | Overview | [See current documentation](./configure/overview.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/overview) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/basics/writing-stories) | +| | Integration/Babel | [See current documentation](./configure/babel.md) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-babel-config) | See versioned documentation here and [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-babel-config) | +| | Integration/Typescript | [See current documentation](./configure/typescript.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/typescript-config) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/typescript-config) | +| | Integration/Styling and CSS | [See current documentation](./configure/styling-and-css.md) | See versioned documentation | See versioned documentation | +| | Integration/Images and assets | [See current documentation](./configure/images-and-assets.md) | See versioned documentation | See versioned documentation | +| | Story rendering | [See current documentation](./configure/story-rendering.md) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-head-tags) and [here](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/add-custom-body) | See versioned documentation [here](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/add-custom-head-tags) | +| | Story Layout | [See current documentation](./configure/story-layout.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | User Interface/Features and behavior | [See current documentation](./configure/features-and-behavior.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | +| | User Interface/Theming | [See current documentation](./configure/theming.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/theming) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/theming) | +| | User Interface/Sidebar & URLS | [See current documentation](./configure/sidebar-and-urls.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/options-parameter) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/options-parameter) | +| | Environment variables | [See current documentation](./configure/environment-variables.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/env-vars) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/env-vars) | +| Builders | Introduction | [See current documentation](./builders/overview.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Vite | [See current documentation](./builders/vite.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Webpack | [See current documentation](./builders/webpack.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/configurations/custom-webpack-config/index.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/configurations/custom-webpack-config/index.md) | +| | Builder API | [See current documentation](./builders/builder-api.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| Addons | Introduction | [See current documentation](./addons/introduction.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Install addons | [See current documentation](./addons/install-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/using-addons/) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/using-addons/) | +| | Writing Addons | [See current documentation](./addons/writing-addons.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Writing Presets | [See current documentation](./addons/writing-presets.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/presets/writing-presets) | Non existing feature or undocumented | +| | Addons Knowledge Base | [See current documentation](./addons/addon-knowledge-base.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/writing-addons) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/writing-addons) | +| | Types of addons | [See current documentation](./addons/addon-types.md) | Non existing feature or undocumented | Non existing feature or undocumented | +| | Addons API | [See current documentation](./addons/addons-api.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/addons/api) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.0/docs/src/pages/addons/api) | +| API | Stories/Component Story Format | [See current documentation](./api/csf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/component-story-format) | Non existing feature or undocumented | +| | Stories/MDX syntax | [See current documentation](./api/mdx.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/mdx-syntax) | Non existing feature or undocumented | +| | Stories/StoriesOF format (see note below) | [See current documentation](../lib/core/docs/storiesOf.md) | [See versioned documentation](https://github.com/storybookjs/storybook/tree/release/5.3/docs/src/pages/formats/storiesof-api) | 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) | + +
With the release of version 5.3, we've updated how you can write your stories more compactly and easily. It doesn't mean that the storiesOf format has been removed. For the time being, we're still supporting it, and we have documentation for it. But be advised that this is bound to change in the future.
@@ -252,7 +271,7 @@ Suppose you don't want to run the command above frequently. Add http-serve ### Can I use Storybook with Vue 3? -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. +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. ### Is snapshot testing with Storyshots supported for Vue 3? @@ -264,7 +283,7 @@ See our documentation on how to customize the [Storyshots configuration](./snaps ### Why are my MDX stories not working in IE11? -Currently there's an issue when using MDX stories with IE11. This issue does not apply to [DocsPage](../writing-docs/docs-page.md). If you're interested in helping us fix this issue, read our Contribution guidelines and submit a pull request. +Currently there's an issue when using MDX stories with IE11. This issue does not apply to [DocsPage](./writing-docs/docs-page.md). If you're interested in helping us fix this issue, read our Contribution guidelines and submit a pull request. ### Why are my mocked GraphQL queries failing with Storybook's MSW addon? @@ -360,12 +379,10 @@ export default meta; Although valid, it introduces additional boilerplate code to the story definition. Instead, we're working towards implementing a safer mechanism based on what's currently being discussed in the following [issue](https://github.com/microsoft/TypeScript/issues/7481). Once the feature is released, we'll migrate our existing examples and documentation accordingly. - ## Why is Storybook's source loader returning undefined with curried functions? This is a known issue with Storybook. If you're interested in getting it fixed, open an issue with a [working reproduction](./contribute/how-to-reproduce) so that it can be triaged and fixed in future releases. - ## Why are my args no longer displaying the default values? Before version 6.3, unset args were set to the `argTypes.defaultValue` if specified or inferred from the component's properties (e.g., React's prop types, Angular inputs, Vue props). Starting with version 6.3, Storybook no longer infers default values but instead defines the arg's value as `undefined` when unset, allowing the framework to supply its default value. @@ -400,4 +417,4 @@ export default { }, }, }; -``` \ No newline at end of file +``` diff --git a/docs/get-started/conclusion.md b/docs/get-started/conclusion.md index 79d662b19f48..074d4dd09a48 100644 --- a/docs/get-started/conclusion.md +++ b/docs/get-started/conclusion.md @@ -8,4 +8,4 @@ If you’d like to learn workflows for building app UIs with Storybook, check ou - [How to write stories](../writing-stories/introduction.md) - [How to document components and design systems](../writing-docs/introduction.md) -- [View example Storybooks from leading companies](./examples.md) +- [View example Storybooks from leading companies](https://storybook.js.org/showcase) diff --git a/docs/get-started/install.md b/docs/get-started/install.md index 7c24707d5429..7daf4ffda386 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -41,6 +41,7 @@ The command above will make the following changes to your local environment: - 🛠 Setup the necessary scripts to run and build Storybook. - 🛠 Add the default Storybook configuration. - 📝 Add some boilerplate stories to get you started. +- 📡 Set up telemetry to help us improve Storybook. Read more about it [here](../configure/telemetry.md). Depending on your framework, first, build your app and then check that everything worked by running: @@ -88,6 +89,10 @@ Below are some of the most common installation issues and instructions on how to +
+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. +
+ If all else fails, try asking for [help](https://storybook.js.org/support)
diff --git a/docs/get-started/setup.md b/docs/get-started/setup.md index 792a7365c445..2959e5685ddd 100644 --- a/docs/get-started/setup.md +++ b/docs/get-started/setup.md @@ -42,20 +42,20 @@ Storybook comes with a permissive [default configuration](../configure/overview. Your project may have additional requirements before components can be rendered in isolation. This warrants customizing configuration further. There are three broad categories of configuration you might need.
-Build configuration like webpack and Babel +Build configuration like Webpack and Babel If you see errors on the CLI when you run the `yarn storybook` command, you likely need to make changes to Storybook’s build configuration. Here are some things to try: - [Presets](../addons/addon-types.md) bundle common configurations for various technologies into Storybook. In particular, presets exist for Create React App, SCSS and Ant Design. - Specify a custom [Babel configuration](../configure/babel.md#custom-babel-config) for Storybook. Storybook automatically tries to use your project’s config if it can. -- Adjust the [webpack configuration](../configure/webpack.md) that Storybook uses. Try patching in your own configuration if needed. +- Adjust the [Webpack configuration](../builders/webpack.md) that Storybook uses. Try patching in your own configuration if needed.
Runtime configuration -If Storybook builds but you see an error immediately when connecting to it in the browser, in that case, chances are one of your input files is not compiling/transpiling correctly to be interpreted by the browser. Storybook supports modern browsers and IE11, but you may need to check the Babel and webpack settings (see above) to ensure your component code works correctly. +If Storybook builds but you see an error immediately when connecting to it in the browser, in that case, chances are one of your input files is not compiling/transpiling correctly to be interpreted by the browser. Storybook supports modern browsers and IE11, but you may need to check the Babel and Webpack settings (see above) to ensure your component code works correctly.
@@ -104,7 +104,7 @@ If you are using CSS-in-JS, chances are your styles are working because they’r
@import CSS into components -Storybook allows you to import CSS files in your components directly. But in some cases you may need to [tweak its webpack configuration](../configure/webpack.md#extendingstorybooks-webpack-config). Angular components require [a special import](../configure/styling-and-css.md#importing-css-files). +Storybook allows you to import CSS files in your components directly. But in some cases you may need to [tweak its Webpack configuration](../builders/webpack.md#extendingstorybooks-webpack-config). Angular components require [a special import](../configure/styling-and-css.md#importing-css-files).
@@ -125,7 +125,7 @@ Alternatively, if you want to inject a CSS link tag to the `` directly (or
Load fonts or images from a local directory -If you're referencing fonts or images from a local directory, you'll need to configure the Storybook script to [serve the static files](../configure/images-and-assets). +If you're referencing fonts or images from a local directory, you'll need to configure the Storybook script to [serve the static files](../configure/images-and-assets.md).
diff --git a/docs/sharing/design-addon-panel.png b/docs/sharing/design-addon-panel.png new file mode 100644 index 000000000000..fdb6a4b52e19 Binary files /dev/null and b/docs/sharing/design-addon-panel.png differ diff --git a/docs/sharing/design-integrations.md b/docs/sharing/design-integrations.md new file mode 100644 index 000000000000..48f87006987a --- /dev/null +++ b/docs/sharing/design-integrations.md @@ -0,0 +1,174 @@ +--- +title: 'Design integrations' +--- + +Storybook integrates with design tools to speed up your development workflow. That helps you debug inconsistencies earlier in the design process, discover existing components to reuse, and compare designs to stories. + +## Figma + +[Figma](https://www.figma.com/) is a collaborative UI design tool that allows multiple people to work on the same design simultaneously in the browser. There are two ways to integrate Storybook and Figma. + +- [**Embed Storybook in Figma**](#embed-storybook-in-figma-with-the-plugin) +- [**Embed Figma in Storybook**](#embed-figma-in-storybook-with-the-addon) + +### Embed Storybook in Figma with the plugin + +[Storybook Connect](https://www.figma.com/community/plugin/1056265616080331589/Storybook-Connect) is a Figma plugin that allows you to embed component stories in Figma. It’s powered by [Storybook embeds](./embed.md) and [Chromatic](https://www.chromatic.com/), a publishing tool created by the Storybook team. + + + +#### Install plugin + +Before we begin, you must have a Storybook [published to Chromatic](./publish-storybook.md#publish-storybook-with-chromatic). It provides the index, versions, and access control that back the plugin. + +Go to [Storybook Connect](https://www.figma.com/community/plugin/1056265616080331589/Storybook-Connect) to install the plugin. + +In Figma, open the command palette (in Mac OS, use `Command + /`, in Windows use `Control + /`) and type `Storybook Connect` to enable it. + +![Figma palette Storybook connect](./figma-plugin-open-in-figma.png) + +Follow the instructions to connect and authenticate with Chromatic. + +#### Link stories to Figma components + +Link stories to Figma components, variants, and instances. + +Go to a story in a Storybook published on Chromatic. Make sure it’s on the branch you want to link. Then copy the URL to the story. + +In Figma, select the component, open the plugin, and paste the URL. + +![Story linked in Figma](./figma-plugin-paste-url.png) + +Chromatic will automatically update your linked stories to reflect the most recent Storybook published on the branch you linked. That means the link persists even as you push new code. + +
+💡 The plugin does not support linking stories to Figma layers. +
+ +#### View stories in Figma + +Once they're connected, you'll be able to view the story by clicking the link in the sidebar. Click "View story". Alternatively, open the plugin by using the command palette (in Mac OS, use `Command + /`, in Windows, use `Control + /`), then type `Storybook Connect`. + +![Figma sidebar with story link](./figma-plugin-sidebar.png) + +### Embed Figma in Storybook with the addon + +[Design addon](https://storybook.js.org/addons/storybook-addon-designs) allows you to embed Figma files and prototypes in Storybook. + +![Storybook addon figma](./storybook-figma-addon.png) + +#### Install design addon + +Run the following command to install the addon. + + + + + + + +Update your Storybook configuration (in `.storybook/main.js|ts`) to include the addon. + + + + + + + +#### Link Figma components to stories + +In Figma, open the file you want to embed in Storybook. You can embed files, prototypes, components, and frames. + +- Embed a file or prototype, click the "Share" button to generate a unique URL for the file then click "Copy link". + +- Embed a component or frame check "Link to selected frame" in the Share dialog. Or right click on the frame and go to "Copy/Paste as" » "Copy link". + +In Storybook, add a new [parameter](../writing-stories/parameters.md) named `design` to your story and paste the Figma URL. For example: + + + + + + + +#### View designs in Storybook + +Click the "Design" tab in the addon panel to view the embedded Figma design. + +![Design addon panel](./design-addon-panel.png) + +## Zeplin + +[Zeplin](https://zeplin.io/) is a design tool that generates styleguides from [Sketch](https://www.sketch.com/), [Figma](https://www.figma.com/), and [Adobe XD](https://www.adobe.com/en/products/xd.html). + +Use the [Zeplin addon](https://storybook.js.org/addons/storybook-zeplin) to connect Storybook. The addon displays designs from Zeplin alongside the currently selected story. It includes convenient tooling to overlay the design image atop the live component. + +Zeplin's native app also supports [links to published Storybooks](https://support.zeplin.io/en/articles/5674596-connecting-your-storybook-instance-with-zeplin). + +![Zeplin Storybook addon](./storybook-zeplin-addon.png) + +## Zeroheight + +[Zeroheight](https://zeroheight.com/) is a collaborative styleguide generator for design systems. It showcases design, code, brand, and copywriting documentation in one place. Users can easily edit that documentation with a WYSIWYG editor. + +Zeroheight integrates with [Storybook](https://zeroheight.com/3xlwst8/p/507ba7-storybook), enabling you to embed stories alongside your design specs. + +![Zeroheight Storybook integration](./storybook-zeroheight.gif) + +## UXPin + +[UXPin](https://www.uxpin.com/) is an interactive design tool that uses production code to generate prototypes. + +UXPin allows you to [use interactive stories](https://www.uxpin.com/docs/merge/storybook-integration/) to design user flows. + + + +## InVision Design System Manager + +[InVision DSM](https://www.invisionapp.com/design-system-manager) is a design system documentation tool. It helps design teams consolidate UX principles, user interface design, and design tokens in a shared workspace. + +InVision allows you to embed [Storybook](https://support.invisionapp.com/hc/en-us/articles/360028388192-Publishing-Storybook-to-DSM) in your design system documentation. + +![Invision DSM Storybook integration](./storybook-invision-dsm.gif) + +## Adobe XD + +[Adobe XD](https://www.adobe.com/products/xd.html) is a UI and UX design tool for creating wireframes, interactive designs, and prototypes. + +Integrate Adobe XD with Storybook using the [design addon](https://storybook.js.org/addons/storybook-addon-designs/). You can [embed design specs](https://helpx.adobe.com/xd/help/publish-design-specs.html) alongside stories by following these [instructions](https://pocka.github.io/storybook-addon-designs/?path=/story/docs-iframe-readme--page). + +## Build your own integration + +Extend and customize Storybook by building an integration. Integrate with lower-level Storybook APIs or bootstrap an addon to customize Storybook's UI and behavior. + +- [Addon documentation](../addons/introduction.md) +- [Create an addon tutorial](https://storybook.js.org/tutorials/create-an-addon/) diff --git a/docs/sharing/figma-plugin-open-in-figma.png b/docs/sharing/figma-plugin-open-in-figma.png new file mode 100644 index 000000000000..9c699609c207 Binary files /dev/null and b/docs/sharing/figma-plugin-open-in-figma.png differ diff --git a/docs/sharing/figma-plugin-open-story.mp4 b/docs/sharing/figma-plugin-open-story.mp4 new file mode 100644 index 000000000000..354a5355af47 Binary files /dev/null and b/docs/sharing/figma-plugin-open-story.mp4 differ diff --git a/docs/sharing/figma-plugin-paste-url.png b/docs/sharing/figma-plugin-paste-url.png new file mode 100644 index 000000000000..a9484c11c3e8 Binary files /dev/null and b/docs/sharing/figma-plugin-paste-url.png differ diff --git a/docs/sharing/figma-plugin-sidebar.png b/docs/sharing/figma-plugin-sidebar.png new file mode 100644 index 000000000000..9cf9c13265cc Binary files /dev/null and b/docs/sharing/figma-plugin-sidebar.png differ diff --git a/docs/sharing/storybook-composition.md b/docs/sharing/storybook-composition.md index 88284c846a0b..ba12b5276a9c 100644 --- a/docs/sharing/storybook-composition.md +++ b/docs/sharing/storybook-composition.md @@ -65,7 +65,7 @@ You can also compose Storybooks based on the current development environment (e.
-💡 Similar to the other fields available in Storybook’s configuration file, the `refs` field can also be a function that accepts a config parameter containing Storybook’s configuration object. Check the [webpack documentation](../configure/webpack.md#extending-storybooks-webpack-config) to learn more about it. +💡 Similar to the other fields available in Storybook’s configuration file, the `refs` field can also be a function that accepts a config parameter containing Storybook’s configuration object. Check the [Webpack documentation](../builders/webpack.md#extending-storybooks-webpack-config) to learn more about it.
diff --git a/docs/sharing/storybook-figma-addon.png b/docs/sharing/storybook-figma-addon.png new file mode 100644 index 000000000000..f6924a72b90d Binary files /dev/null and b/docs/sharing/storybook-figma-addon.png differ diff --git a/docs/sharing/storybook-invision-dsm.gif b/docs/sharing/storybook-invision-dsm.gif new file mode 100644 index 000000000000..adaf18d8d021 Binary files /dev/null and b/docs/sharing/storybook-invision-dsm.gif differ diff --git a/docs/sharing/storybook-uxpin.mp4 b/docs/sharing/storybook-uxpin.mp4 new file mode 100644 index 000000000000..e9a8d4750ff3 Binary files /dev/null and b/docs/sharing/storybook-uxpin.mp4 differ diff --git a/docs/sharing/storybook-zeplin-addon.png b/docs/sharing/storybook-zeplin-addon.png new file mode 100644 index 000000000000..d334ac147894 Binary files /dev/null and b/docs/sharing/storybook-zeplin-addon.png differ diff --git a/docs/sharing/storybook-zeroheight.gif b/docs/sharing/storybook-zeroheight.gif new file mode 100644 index 000000000000..4ec641641307 Binary files /dev/null and b/docs/sharing/storybook-zeroheight.gif differ diff --git a/docs/snippets/angular/button-story-with-blue-args.mdx.mdx b/docs/snippets/angular/button-story-with-blue-args.mdx.mdx index 423d9de4a6b7..15b10326a495 100644 --- a/docs/snippets/angular/button-story-with-blue-args.mdx.mdx +++ b/docs/snippets/angular/button-story-with-blue-args.mdx.mdx @@ -20,5 +20,5 @@ import { Button } from './button.component'; }} /> - + ``` \ No newline at end of file diff --git a/docs/snippets/angular/component-story-figma-integration.mdx.mdx b/docs/snippets/angular/component-story-figma-integration.mdx.mdx new file mode 100644 index 000000000000..85939ccf81a0 --- /dev/null +++ b/docs/snippets/angular/component-story-figma-integration.mdx.mdx @@ -0,0 +1,27 @@ +```md + + +import { Canvas, Meta, Story } from '@storybook/addon-docs'; + +import { withDesign } from 'storybook-addon-designs'; + +import { MyComponent } from './MyComponent.component'; + + + +export const Template = () => ({ props: {} }); + + + + {Template.bind({})} + + +``` \ No newline at end of file diff --git a/docs/snippets/angular/component-story-figma-integration.ts.mdx b/docs/snippets/angular/component-story-figma-integration.ts.mdx new file mode 100644 index 000000000000..eb0e2565f611 --- /dev/null +++ b/docs/snippets/angular/component-story-figma-integration.ts.mdx @@ -0,0 +1,29 @@ +```ts +// MyComponent.stories.ts + +import { Story, Meta } from '@storybook/angular/'; + +import { withDesign } from 'storybook-addon-designs'; + +import { MyComponent } from './MyComponent.component'; + +// More on default export: https://storybook.js.org/docs/angular/writing-stories/introduction#default-export +export default { + title: 'FigmaExample', + component: MyComponent, + decorators: [withDesign], +} as Meta; + +// More on component templates: https://storybook.js.org/docs/angular/writing-stories/introduction#using-args +const Template: Story = () => ({ + props: {}, +}); + +export const Example = Template.bind({}); +Example.parameters = { + design: { + type: 'figma', + url: 'https://www.figma.com/file/Sample-File', + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/angular/login-form-with-play-function.mdx.mdx b/docs/snippets/angular/login-form-with-play-function.mdx.mdx index 03e662a852a8..31443143cd7d 100644 --- a/docs/snippets/angular/login-form-with-play-function.mdx.mdx +++ b/docs/snippets/angular/login-form-with-play-function.mdx.mdx @@ -5,6 +5,8 @@ import { Canvas, Meta, Story } from '@storybook/addon-docs'; import { within, userEvent } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import { LoginForm } from './LoginForm.component'; @@ -13,7 +15,7 @@ export const Template = (args) => ({ props: args }); - {Template.bind(())} + {Template.bind({})} ({ props: args }); // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); + // See https://storybook.js.org/docs/angular/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); }}> {Template.bind({})} - ``` \ No newline at end of file diff --git a/docs/snippets/angular/login-form-with-play-function.ts.mdx b/docs/snippets/angular/login-form-with-play-function.ts.mdx index 276e1d785a2e..48df0db4da3c 100644 --- a/docs/snippets/angular/login-form-with-play-function.ts.mdx +++ b/docs/snippets/angular/login-form-with-play-function.ts.mdx @@ -5,6 +5,8 @@ import { Meta, Story } from '@storybook/angular'; import { userEvent, within } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import { LoginForm } from './LoginForm.component'; export default { @@ -27,14 +29,19 @@ FilledForm.play = async ({ canvasElement }) => { // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); // See https://storybook.js.org/docs/angular/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); }; ``` \ No newline at end of file diff --git a/docs/snippets/angular/my-component-play-function-with-delay.mdx.mdx b/docs/snippets/angular/my-component-play-function-with-delay.mdx.mdx index 20b6d5cc2a49..6ed819ac2e70 100644 --- a/docs/snippets/angular/my-component-play-function-with-delay.mdx.mdx +++ b/docs/snippets/angular/my-component-play-function-with-delay.mdx.mdx @@ -16,7 +16,7 @@ export const Template = (args) => ({ props: args }); play={async () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -28,4 +28,4 @@ export const Template = (args) => ({ props: args }); }} > {Template.bind({})} -``` \ No newline at end of file +``` diff --git a/docs/snippets/angular/my-component-play-function-with-delay.ts.mdx b/docs/snippets/angular/my-component-play-function-with-delay.ts.mdx index c0bdc9307061..084f43dd360d 100644 --- a/docs/snippets/angular/my-component-play-function-with-delay.ts.mdx +++ b/docs/snippets/angular/my-component-play-function-with-delay.ts.mdx @@ -23,7 +23,7 @@ const Template: Story = (args) => ({ export const DelayedStory: Story = Template.bind({}); DelayedStory.play = () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -33,4 +33,4 @@ DelayedStory.play = () => { delay: 100, }); }; -``` \ No newline at end of file +``` diff --git a/docs/snippets/common/args-usage-with-addons.js.mdx b/docs/snippets/common/args-usage-with-addons.js.mdx index 7c1ccf730efd..77d833352065 100644 --- a/docs/snippets/common/args-usage-with-addons.js.mdx +++ b/docs/snippets/common/args-usage-with-addons.js.mdx @@ -1,5 +1,5 @@ ```js -// your-addon/register.js +// your-addon/manager.js import { useArgs } from '@storybook/api'; diff --git a/docs/snippets/common/component-cypress-test.js.mdx b/docs/snippets/common/component-cypress-test.js.mdx index 03d9db2866a7..8de26d698793 100644 --- a/docs/snippets/common/component-cypress-test.js.mdx +++ b/docs/snippets/common/component-cypress-test.js.mdx @@ -8,7 +8,7 @@ describe('Login Form', () => { cy.visit('/iframe.html?id=components-login-form--example'); cy.get('#login-form').within(() => { cy.log('**enter the email**'); - cy.get('#email').should('have.value', 'your-own-emailaddress@provider.com'); + cy.get('#email').should('have.value', 'email@provider.com'); cy.log('**enter password**'); cy.get('#password').should('have.value', 'a-random-password'); }); diff --git a/docs/snippets/common/component-playwright-test.js.mdx b/docs/snippets/common/component-playwright-test.js.mdx index d9d195f40967..0e0e83b99a43 100644 --- a/docs/snippets/common/component-playwright-test.js.mdx +++ b/docs/snippets/common/component-playwright-test.js.mdx @@ -7,7 +7,7 @@ test('Login Form inputs', async ({ page }) => { await page.goto('http://localhost:6006/iframe.html?id=components-login-form--example'); const email = await page.inputValue('#email'); const password = await page.inputValue('#password'); - await expect(email).toBe('your-own-emailaddress@provider.com'); + await expect(email).toBe('email@provider.com'); await expect(password).toBe('a-random-password'); }); ``` \ No newline at end of file diff --git a/docs/snippets/common/component-story-conditional-controls-mutual-exclusion.js.mdx b/docs/snippets/common/component-story-conditional-controls-mutual-exclusion.js.mdx index 86b3c15aaccc..58ecafb7128c 100644 --- a/docs/snippets/common/component-story-conditional-controls-mutual-exclusion.js.mdx +++ b/docs/snippets/common/component-story-conditional-controls-mutual-exclusion.js.mdx @@ -6,10 +6,13 @@ export default { title: 'Button', argTypes: { // button can be passed a label or an image, not both - label: { control: 'text', removeIf: 'image' }, + label: { + control: 'text', + if: { arg: 'image', truthy: false }, + }, image: { control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] }, - removeIf: 'label', + if: { arg: 'label', truthy: false }, }, }, }; diff --git a/docs/snippets/common/component-story-conditional-controls-toggle.js.mdx b/docs/snippets/common/component-story-conditional-controls-toggle.js.mdx index 9f46bf6e4acb..2eba20f71e3e 100644 --- a/docs/snippets/common/component-story-conditional-controls-toggle.js.mdx +++ b/docs/snippets/common/component-story-conditional-controls-toggle.js.mdx @@ -8,9 +8,9 @@ export default { label: { control: 'text' }, // always shows advanced: { control: 'boolean' }, // below are only included when advanced is true - margin: { control: 'number', addIf: 'advanced' }, - padding: { control: 'number', addIf: 'advanced' }, - cornerRadius: { control: 'number', addIf: 'advanced' }, + margin: { control: 'number', if: { arg: 'advanced' } }, + padding: { control: 'number', if: { arg: 'advanced' } }, + cornerRadius: { control: 'number', if: { arg: 'advanced' } }, }, }; ``` diff --git a/docs/snippets/common/component-story-custom-source.js.mdx b/docs/snippets/common/component-story-custom-source.js.mdx index ae09a7eb6291..a1bc4291717c 100644 --- a/docs/snippets/common/component-story-custom-source.js.mdx +++ b/docs/snippets/common/component-story-custom-source.js.mdx @@ -12,7 +12,7 @@ export default { component: Button, }; -export const Template = (args) => ({ +const Template = (args) => ({ //👇 Your template goes here }); diff --git a/docs/snippets/common/component-story-mdx-dedent.mdx.mdx b/docs/snippets/common/component-story-mdx-dedent.mdx.mdx index 8d377271a76e..d66d3d240e56 100644 --- a/docs/snippets/common/component-story-mdx-dedent.mdx.mdx +++ b/docs/snippets/common/component-story-mdx-dedent.mdx.mdx @@ -10,7 +10,7 @@ import dedent from 'ts-dedent'; -``` \ No newline at end of file +``` diff --git a/docs/snippets/common/my-addon-initial-panel-state.js.mdx b/docs/snippets/common/my-addon-initial-panel-state.js.mdx index 72c6f1e7cb00..8009d61ac4fd 100644 --- a/docs/snippets/common/my-addon-initial-panel-state.js.mdx +++ b/docs/snippets/common/my-addon-initial-panel-state.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/src/register.js +// /my-addon/src/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-a11y-install.npm.js.mdx b/docs/snippets/common/storybook-a11y-install.npm.js.mdx new file mode 100644 index 000000000000..933ac6105d46 --- /dev/null +++ b/docs/snippets/common/storybook-a11y-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/addon-a11y --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-a11y-install.yarn.js.mdx b/docs/snippets/common/storybook-a11y-install.yarn.js.mdx new file mode 100644 index 000000000000..41e5bf35360e --- /dev/null +++ b/docs/snippets/common/storybook-a11y-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/addon-a11y +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-a11y-register.js.mdx b/docs/snippets/common/storybook-a11y-register.js.mdx index 26837cd8cdd5..4c6401ea169a 100644 --- a/docs/snippets/common/storybook-a11y-register.js.mdx +++ b/docs/snippets/common/storybook-a11y-register.js.mdx @@ -2,11 +2,10 @@ // .storybook/main.js module.exports = { - stories:[], - addons:[ - '@storybook/addon-links', - '@storybook/addon-essentials', - '@storybook/preset-create-react-app', + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + // Other Storybook addons '@storybook/addon-a11y', //👈 The a11y addon goes here + ], }; -``` +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-a11y-register.ts.mdx b/docs/snippets/common/storybook-a11y-register.ts.mdx new file mode 100644 index 000000000000..73137a1bf616 --- /dev/null +++ b/docs/snippets/common/storybook-a11y-register.ts.mdx @@ -0,0 +1,16 @@ +```ts +// .storybook/main.ts + +// Imports Storybook's configuration API +import type { StorybookConfig } from '@storybook/core-common'; + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + // Other Storybook addons + '@storybook/addon-a11y', //👈 The a11y addon goes here + ], +}; + +module.exports = config; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-change-panel.js.mdx b/docs/snippets/common/storybook-addon-change-panel.js.mdx index 8e4794320c1e..fc9f821e60c4 100644 --- a/docs/snippets/common/storybook-addon-change-panel.js.mdx +++ b/docs/snippets/common/storybook-addon-change-panel.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/src/register.js +// /my-addon/src/manager.js import { useParameter } from '@storybook/api'; diff --git a/docs/snippets/common/storybook-addon-disable-addon.js.mdx b/docs/snippets/common/storybook-addon-disable-addon.js.mdx index b8dc0b43b88e..f74d563d5366 100644 --- a/docs/snippets/common/storybook-addon-disable-addon.js.mdx +++ b/docs/snippets/common/storybook-addon-disable-addon.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register(ADDON_ID, () => { addons.add(PANEL_ID, { diff --git a/docs/snippets/common/storybook-addon-interactions-addon-full-install.npm.js.mdx b/docs/snippets/common/storybook-addon-interactions-addon-full-install.npm.js.mdx new file mode 100644 index 000000000000..027dc24430bf --- /dev/null +++ b/docs/snippets/common/storybook-addon-interactions-addon-full-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/testing-library @storybook/jest @storybook/addon-interactions --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-interactions-addon-full-install.yarn.js.mdx b/docs/snippets/common/storybook-addon-interactions-addon-full-install.yarn.js.mdx new file mode 100644 index 000000000000..d4e583095882 --- /dev/null +++ b/docs/snippets/common/storybook-addon-interactions-addon-full-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/testing-library @storybook/jest @storybook/addon-interactions +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-panel-example.js.mdx b/docs/snippets/common/storybook-addon-panel-example.js.mdx index 5f3898b61c67..29d8a1ab9d46 100644 --- a/docs/snippets/common/storybook-addon-panel-example.js.mdx +++ b/docs/snippets/common/storybook-addon-panel-example.js.mdx @@ -1,5 +1,5 @@ ```js -// addon-panel/register.js +// addon-panel/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addon-panel-initial.js.mdx b/docs/snippets/common/storybook-addon-panel-initial.js.mdx index fb4b80e7cff0..9f9e6b6c05f0 100644 --- a/docs/snippets/common/storybook-addon-panel-initial.js.mdx +++ b/docs/snippets/common/storybook-addon-panel-initial.js.mdx @@ -1,5 +1,5 @@ ```js -// .storybook/my-addon/register.js +// .storybook/my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addon-tab-example.js.mdx b/docs/snippets/common/storybook-addon-tab-example.js.mdx index bbfddd9627cd..dcfa1b41f92b 100644 --- a/docs/snippets/common/storybook-addon-tab-example.js.mdx +++ b/docs/snippets/common/storybook-addon-tab-example.js.mdx @@ -1,5 +1,5 @@ ```js -// addon-tab/register.js +// addon-tab/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addon-toolbar-example.js.mdx b/docs/snippets/common/storybook-addon-toolbar-example.js.mdx index 37ca2cfb2713..869c9df49ad4 100644 --- a/docs/snippets/common/storybook-addon-toolbar-example.js.mdx +++ b/docs/snippets/common/storybook-addon-toolbar-example.js.mdx @@ -1,5 +1,5 @@ ```js -// addon-toolbar/register.js +// addon-toolbar/manager.js import React from "react"; diff --git a/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx b/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx index 415edea16fd7..6f5f9e3845aa 100644 --- a/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx +++ b/docs/snippets/common/storybook-addons-api-disablequeryparams.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { api.setQueryParams({ diff --git a/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx b/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx index 76513f992911..0c324ddd0d24 100644 --- a/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx +++ b/docs/snippets/common/storybook-addons-api-getqueryparam.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { api.getQueryParam('bbc'); diff --git a/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx b/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx index e7e9f13fe831..39321b7f1958 100644 --- a/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx +++ b/docs/snippets/common/storybook-addons-api-geturlstate.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { const href = api.getUrlState({ diff --git a/docs/snippets/common/storybook-addons-api-imports.js.mdx b/docs/snippets/common/storybook-addons-api-imports.js.mdx index eb2af57b1a9a..e44d88ab048f 100644 --- a/docs/snippets/common/storybook-addons-api-imports.js.mdx +++ b/docs/snippets/common/storybook-addons-api-imports.js.mdx @@ -1,5 +1,5 @@ ```js -// .storybook/my-addon/register.js +// .storybook/my-addon/manager.js import { addons } from '@storybook/addons'; ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx b/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx index 2f69823954b9..3c9617bfa19e 100644 --- a/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx +++ b/docs/snippets/common/storybook-addons-api-makedecorator.js.mdx @@ -1,5 +1,5 @@ ```js -// .storybook/my-addon/register.js +// .storybook/my-addon/manager.js import { makeDecorator } from '@storybook/addons'; diff --git a/docs/snippets/common/storybook-addons-api-on.js.mdx b/docs/snippets/common/storybook-addons-api-on.js.mdx index aa2e706c51c6..ac86c5e43918 100644 --- a/docs/snippets/common/storybook-addons-api-on.js.mdx +++ b/docs/snippets/common/storybook-addons-api-on.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { api.on('some-event', (eventData) => console.log(eventData)); diff --git a/docs/snippets/common/storybook-addons-api-register.js.mdx b/docs/snippets/common/storybook-addons-api-register.js.mdx index 009b2ea7e660..3c044eebd8c4 100644 --- a/docs/snippets/common/storybook-addons-api-register.js.mdx +++ b/docs/snippets/common/storybook-addons-api-register.js.mdx @@ -1,5 +1,5 @@ ```js -// .storybook/my-addon/register.js +// .storybook/my-addon/manager.js import { addons } from '@storybook/addons'; diff --git a/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx b/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx index 24b46cc3191b..46c89f25fa43 100644 --- a/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx +++ b/docs/snippets/common/storybook-addons-api-selectincurrentkind.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { api.selectInCurrentKind('Basic'); diff --git a/docs/snippets/common/storybook-addons-api-selectstory.js.mdx b/docs/snippets/common/storybook-addons-api-selectstory.js.mdx index bd1314b7ec4f..4af2f91bc3ad 100644 --- a/docs/snippets/common/storybook-addons-api-selectstory.js.mdx +++ b/docs/snippets/common/storybook-addons-api-selectstory.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { api.selectStory('Button', 'Basic'); diff --git a/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx b/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx index 988482dbd3ad..bbfaa727b722 100644 --- a/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx +++ b/docs/snippets/common/storybook-addons-api-setqueryparams.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js addons.register('my-organisation/my-addon', (api) => { api.setQueryParams({ diff --git a/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx b/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx index c0800d6d301b..6d6db143ba12 100644 --- a/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useaddonstate.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addons-api-useapi.js.mdx b/docs/snippets/common/storybook-addons-api-useapi.js.mdx index f88c1c1524a2..f6c05424dc6a 100644 --- a/docs/snippets/common/storybook-addons-api-useapi.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useapi.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addons-api-usechannel.js.mdx b/docs/snippets/common/storybook-addons-api-usechannel.js.mdx index 7184c752dc05..f017c5cfccb0 100644 --- a/docs/snippets/common/storybook-addons-api-usechannel.js.mdx +++ b/docs/snippets/common/storybook-addons-api-usechannel.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addons-api-useglobal.js.mdx b/docs/snippets/common/storybook-addons-api-useglobal.js.mdx index 94f5a8b83313..ad33aef34253 100644 --- a/docs/snippets/common/storybook-addons-api-useglobal.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useglobal.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addons-api-useparameter.js.mdx b/docs/snippets/common/storybook-addons-api-useparameter.js.mdx index 3c496cbb2a09..fdbc74301782 100644 --- a/docs/snippets/common/storybook-addons-api-useparameter.js.mdx +++ b/docs/snippets/common/storybook-addons-api-useparameter.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx b/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx index 62f1605af9f1..4e1515a3b6b3 100644 --- a/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx +++ b/docs/snippets/common/storybook-addons-api-usestorybookstate.js.mdx @@ -1,5 +1,5 @@ ```js -// /my-addon/register.js +// /my-addon/manager.js import React from 'react'; diff --git a/docs/snippets/common/storybook-argtypes-with-addon.js.mdx b/docs/snippets/common/storybook-argtypes-with-addon.js.mdx index 3187d5e6f3a4..f34c4859bfb9 100644 --- a/docs/snippets/common/storybook-argtypes-with-addon.js.mdx +++ b/docs/snippets/common/storybook-argtypes-with-addon.js.mdx @@ -1,5 +1,5 @@ ```js -// .storybook/my-addon/register.js +// .storybook/my-addon/manager.js import { useArgTypes } from '@storybook/api'; diff --git a/docs/snippets/common/storybook-builder-api-build-server.ts.mdx b/docs/snippets/common/storybook-builder-api-build-server.ts.mdx new file mode 100644 index 000000000000..28f40b3d394f --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-build-server.ts.mdx @@ -0,0 +1,36 @@ +```ts +// build.ts + +import { build as viteBuild } from 'vite'; +import { stringifyProcessEnvs } from './envs'; +import { commonConfig } from './vite-config'; + +import type { EnvsRaw, ExtendedOptions } from './types'; + +export async function build(options: ExtendedOptions) { + const { presets } = options; + + const baseConfig = await commonConfig(options, 'build'); + const config = { + ...baseConfig, + build: { + outDir: options.outputDir, + emptyOutDir: false, + sourcemap: true, + }, + }; + + const finalConfig = await presets.apply('viteFinal', config, options); + + const envsRaw = await presets.apply>('env'); + // Stringify env variables after getting `envPrefix` from the final config + const envs = stringifyProcessEnvs(envsRaw, finalConfig.envPrefix); + // Update `define` + finalConfig.define = { + ...finalConfig.define, + ...envs, + }; + + await viteBuild(finalConfig); +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-builder-api-configuration-options.ts.mdx b/docs/snippets/common/storybook-builder-api-configuration-options.ts.mdx new file mode 100644 index 000000000000..6e802781ee3a --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-configuration-options.ts.mdx @@ -0,0 +1,36 @@ +```ts +// vite-server.ts + +import { stringifyProcessEnvs } from './envs'; +import { getOptimizeDeps } from './optimizeDeps'; +import { commonConfig } from './vite-config'; + +import type { EnvsRaw, ExtendedOptions } from './types'; + +export async function createViteServer(options: ExtendedOptions, devServer: Server) { + const { port, presets } = options; + + // Defines the baseline config. + const baseConfig = await commonConfig(options, 'development'); + const defaultConfig = { + ...baseConfig, + server: { + middlewareMode: true, + hmr: { + port, + server: devServer, + }, + fs: { + strict: true, + }, + }, + optimizeDeps: await getOptimizeDeps(baseConfig, options), + }; + + const finalConfig = await presets.apply('viteFinal', defaultConfig, options); + + const envsRaw = await presets.apply>('env'); + + // Remainder implementation +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-builder-api-dev-server.ts.mdx b/docs/snippets/common/storybook-builder-api-dev-server.ts.mdx new file mode 100644 index 000000000000..a4731e6d7799 --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-dev-server.ts.mdx @@ -0,0 +1,14 @@ +```ts +// server.ts + +import { createServer } from 'vite'; + +export async function createViteServer(options: ExtendedOptions, devServer: Server) { + // Remainder server configuration + + // Creates the server. + return createServer({ + // The server configuration goes here + }); +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-builder-api-interface.ts.mdx b/docs/snippets/common/storybook-builder-api-interface.ts.mdx new file mode 100644 index 000000000000..d8cbd038c15b --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-interface.ts.mdx @@ -0,0 +1,22 @@ +```ts +export interface Builder { + start: (args: { + options: Options; + startTime: ReturnType; + router: Router; + server: Server; + }) => Promise; + bail: (e?: Error) => Promise; + }>; + build: (arg: { + options: Options; + startTime: ReturnType; + }) => Promise; + bail: (e?: Error) => Promise; + getConfig: (options: Options) => Promise; + corePresets?: string[]; + overridePresets?: string[]; +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-builder-api-mdx.ts.mdx b/docs/snippets/common/storybook-builder-api-mdx.ts.mdx new file mode 100644 index 000000000000..e9591db2ad4f --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-mdx.ts.mdx @@ -0,0 +1,20 @@ +```ts +// mdx-plugin.ts + +import mdx from 'vite-plugin-mdx'; + +import { createCompiler } from '@storybook/csf-tools/mdx'; + +export function mdxPlugin() { + return mdx((filename) => { + const compilers = []; + + if (filename.endsWith('stories.mdx') || filename.endsWith('story.mdx')) { + compilers.push(createCompiler({})); + } + return { + compilers, + }; + }); +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-builder-api-preview-exports.ts.mdx b/docs/snippets/common/storybook-builder-api-preview-exports.ts.mdx new file mode 100644 index 000000000000..0fd6743bacd1 --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-preview-exports.ts.mdx @@ -0,0 +1,82 @@ +```ts +// codegen-iframe-script.ts + +import { virtualPreviewFile, virtualStoriesFile } from './virtual-file-names'; +import { transformAbsPath } from './utils/transform-abs-path'; +import type { ExtendedOptions } from './types'; + +export async function generateIframeScriptCode(options: ExtendedOptions) { + const { presets, frameworkPath, framework } = options; + const frameworkImportPath = frameworkPath || `@storybook/${framework}`; + + const presetEntries = await presets.apply('config', [], options); + const configEntries = [...presetEntries].filter(Boolean); + + const absoluteFilesToImport = (files: string[], name: string) => + files + .map((el, i) => `import ${name ? `* as ${name}_${i} from ` : ''}'${transformAbsPath(el)}'`) + .join('\n'); + + const importArray = (name: string, length: number) => + new Array(length).fill(0).map((_, i) => `${name}_${i}`); + + const code = ` + // Ensure that the client API is initialized by the framework before any other iframe code + // is loaded. That way our client-apis can assume the existence of the API+store + import { configure } from '${frameworkImportPath}'; + + import { + addDecorator, + addParameters, + addArgTypesEnhancer, + addArgsEnhancer, + setGlobalRender + } from '@storybook/client-api'; + import { logger } from '@storybook/client-logger'; + ${absoluteFilesToImport(configEntries, 'config')} + import * as preview from '${virtualPreviewFile}'; + import { configStories } from '${virtualStoriesFile}'; + + const configs = [${importArray('config', configEntries.length) + .concat('preview.default') + .join(',')}].filter(Boolean) + + configs.forEach(config => { + Object.keys(config).forEach((key) => { + const value = config[key]; + switch (key) { + case 'args': + case 'argTypes': { + return logger.warn('Invalid args/argTypes in config, ignoring.', JSON.stringify(value)); + } + case 'decorators': { + return value.forEach((decorator) => addDecorator(decorator, false)); + } + case 'parameters': { + return addParameters({ ...value }, false); + } + case 'render': { + return setGlobalRender(value) + } + case 'globals': + case 'globalTypes': { + const v = {}; + v[key] = value; + return addParameters(v, false); + } + case 'decorateStory': + case 'renderToDOM': { + return null; + } + default: { + // eslint-disable-next-line prefer-template + return console.log(key + ' was not supported :( !'); + } + } + }); + }) + configStories(configure); + `.trim(); + return code; +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-builder-api-shutdown-server.ts.mdx b/docs/snippets/common/storybook-builder-api-shutdown-server.ts.mdx new file mode 100644 index 000000000000..03144c66ca7d --- /dev/null +++ b/docs/snippets/common/storybook-builder-api-shutdown-server.ts.mdx @@ -0,0 +1,24 @@ +```ts +// index.ts + +import { createViteServer } from './vite-server'; + +export const start: ViteBuilder['start'] = async ({ options, server: devServer }) => { + // Remainder implementation goes here + + const server = await createViteServer(options as ExtendedOptions, devServer); + async function bail(e?: Error): Promise { + try { + return await server.close(); + } catch (err) { + console.warn('unable to close the server'); + } + throw e; + } + + return { + bail, + totalTime: process.hrtime(startTime), + }; +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-client-preview.ts.mdx b/docs/snippets/common/storybook-client-preview.ts.mdx index 436d862dc8ac..765d8d1ab341 100644 --- a/docs/snippets/common/storybook-client-preview.ts.mdx +++ b/docs/snippets/common/storybook-client-preview.ts.mdx @@ -1,7 +1,7 @@ ```ts // your-framework/src/client/preview/index.ts -import { start } from '@storybook/core/client'; +import { start } from '@storybook/core'; import './globals'; diff --git a/docs/snippets/common/storybook-config-layout.js.mdx b/docs/snippets/common/storybook-config-layout.js.mdx index 550254d31dd3..c36446aebea2 100644 --- a/docs/snippets/common/storybook-config-layout.js.mdx +++ b/docs/snippets/common/storybook-config-layout.js.mdx @@ -9,7 +9,7 @@ addons.setConfig({ showPanel: true, panelPosition: 'bottom', enableShortcuts: true, - isToolshown: true, + showToolbar: true, theme: undefined, selectedPanel: undefined, initialActive: 'sidebar', @@ -18,11 +18,11 @@ addons.setConfig({ collapsedRoots: ['other'], }, toolbar: { - title: { hidden: false, }, - zoom: { hidden: false, }, - eject: { hidden: false, }, - copy: { hidden: false, }, - fullscreen: { hidden: false, }, + title: { hidden: false }, + zoom: { hidden: false }, + eject: { hidden: false }, + copy: { hidden: false }, + fullscreen: { hidden: false }, }, }); -``` \ No newline at end of file +``` diff --git a/docs/snippets/common/storybook-disable-telemetry-env.env-var.js.mdx b/docs/snippets/common/storybook-disable-telemetry-env.env-var.js.mdx new file mode 100644 index 000000000000..9ed1c3e5430d --- /dev/null +++ b/docs/snippets/common/storybook-disable-telemetry-env.env-var.js.mdx @@ -0,0 +1,3 @@ +```shell +STORYBOOK_DISABLE_TELEMETRY=1 yarn storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-disable-telemetry-flag.npm.js.mdx b/docs/snippets/common/storybook-disable-telemetry-flag.npm.js.mdx new file mode 100644 index 000000000000..81212a40c93a --- /dev/null +++ b/docs/snippets/common/storybook-disable-telemetry-flag.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run storybook -- --disable-telemetry +``` diff --git a/docs/snippets/common/storybook-disable-telemetry-flag.yarn.js.mdx b/docs/snippets/common/storybook-disable-telemetry-flag.yarn.js.mdx new file mode 100644 index 000000000000..c9e70448cefa --- /dev/null +++ b/docs/snippets/common/storybook-disable-telemetry-flag.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn storybook --disable-telemetry +``` diff --git a/docs/snippets/common/storybook-figma-addon-install.npm.js.mdx b/docs/snippets/common/storybook-figma-addon-install.npm.js.mdx new file mode 100644 index 000000000000..2ef0c42eee1f --- /dev/null +++ b/docs/snippets/common/storybook-figma-addon-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install --save-dev storybook-addon-designs +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-figma-addon-install.yarn.js.mdx b/docs/snippets/common/storybook-figma-addon-install.yarn.js.mdx new file mode 100644 index 000000000000..2c11db47977a --- /dev/null +++ b/docs/snippets/common/storybook-figma-addon-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add -D storybook-addon-designs +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-disable-telemetry.main-js.js.mdx b/docs/snippets/common/storybook-main-disable-telemetry.main-js.js.mdx new file mode 100644 index 000000000000..c7786a174244 --- /dev/null +++ b/docs/snippets/common/storybook-main-disable-telemetry.main-js.js.mdx @@ -0,0 +1,18 @@ +```js +// .storybook/main.js + +module.exports = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/preset-create-react-app', + ], + framework: '@storybook/react', + core: { + builder: 'webpack5', + disableTelemetry: true, // 👈 Disables telemetry + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-disable-telemetry.main-ts.ts.mdx b/docs/snippets/common/storybook-main-disable-telemetry.main-ts.ts.mdx new file mode 100644 index 000000000000..1f707e2d95e7 --- /dev/null +++ b/docs/snippets/common/storybook-main-disable-telemetry.main-ts.ts.mdx @@ -0,0 +1,23 @@ +```ts +// .storybook/main.ts + +// Imports Storybook's configuration API +import type { StorybookConfig } from '@storybook/core-common'; + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/preset-create-react-app', + ], + framework: '@storybook/react', + core: { + builder: 'webpack5', + disableTelemetry: true, // 👈 Disables telemetry + }, +}; + +module.exports = config; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-enable-interactive-debugger.js.mdx b/docs/snippets/common/storybook-main-enable-interactive-debugger.js.mdx new file mode 100644 index 000000000000..d1c4064fa142 --- /dev/null +++ b/docs/snippets/common/storybook-main-enable-interactive-debugger.js.mdx @@ -0,0 +1,14 @@ +```js +// .storybook/main.js|ts + +module.exports = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + // Other Storybook addons + '@storybook/addon-interactions', // 👈 Addon is registered here + ], + features: { + interactionsDebugger: true, // 👈 Enable playback controls + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-figma-addon-register.js.mdx b/docs/snippets/common/storybook-main-figma-addon-register.js.mdx new file mode 100644 index 000000000000..de68b73dcacc --- /dev/null +++ b/docs/snippets/common/storybook-main-figma-addon-register.js.mdx @@ -0,0 +1,11 @@ +```js +// .storybook/main.js|ts + +module.exports = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + // Other Storybook addons + 'storybook-addon-designs', // 👈 Addon is registered here + ], +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-register-addon.js.mdx b/docs/snippets/common/storybook-main-register-addon.js.mdx index 0f587017ee85..675a1d62c08a 100644 --- a/docs/snippets/common/storybook-main-register-addon.js.mdx +++ b/docs/snippets/common/storybook-main-register-addon.js.mdx @@ -2,6 +2,6 @@ // .storybook/main.js module.exports = { - addons: ['path/to/register.js'], + addons: ['path/to/manager.js'], }; ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-register-essentials-addon.js.mdx b/docs/snippets/common/storybook-main-register-essentials-addon.js.mdx new file mode 100644 index 000000000000..8c20f79bb8e8 --- /dev/null +++ b/docs/snippets/common/storybook-main-register-essentials-addon.js.mdx @@ -0,0 +1,8 @@ +```js +// .storybook/main.js + +module.exports = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], +}; +``` diff --git a/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx b/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx index 4a913b4f8aa3..18fa46acdf1f 100644 --- a/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx +++ b/docs/snippets/common/storybook-main-register-presets-managerentry.js.mdx @@ -3,7 +3,6 @@ module.exports = { addons: [ - '@storybook/addon-storysource/register', // A managerEntry registered here, in this case from the storysource addon. '@storybook/addon-docs/preset', // A preset registered here, in this case from the addon-docs addon. ], }; diff --git a/docs/snippets/common/storybook-main-use-manager-entries.js.mdx b/docs/snippets/common/storybook-main-use-manager-entries.js.mdx index 5bbaa228a809..024799320379 100644 --- a/docs/snippets/common/storybook-main-use-manager-entries.js.mdx +++ b/docs/snippets/common/storybook-main-use-manager-entries.js.mdx @@ -2,6 +2,6 @@ // .storybook/main.js module.exports = { - managerEntries: ['@storybook/addon-storysource/register'], + managerEntries: ['some-storybook-addon/entry-point.js'], }; ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-webpack5-fsCache.mdx b/docs/snippets/common/storybook-main-webpack5-fsCache.js.mdx similarity index 97% rename from docs/snippets/common/storybook-main-webpack5-fsCache.mdx rename to docs/snippets/common/storybook-main-webpack5-fsCache.js.mdx index 622152ccfc46..9ea2077caa93 100644 --- a/docs/snippets/common/storybook-main-webpack5-fsCache.mdx +++ b/docs/snippets/common/storybook-main-webpack5-fsCache.js.mdx @@ -11,4 +11,4 @@ module.exports = { }, }, }; -``` +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx b/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx index fb0cd405ac72..65d78e77448b 100644 --- a/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx +++ b/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx @@ -12,6 +12,8 @@ export const globalTypes = { items: ['light', 'dark'], // Property that specifies if the name of the item will be displayed showName: true, + // Change title based on selected value + dynamicTitle: true, }, }, }; diff --git a/docs/snippets/common/storybook-run-dev.npm.js.mdx b/docs/snippets/common/storybook-run-dev.npm.js.mdx index 0a952c1b61cc..8f7f525b9a59 100644 --- a/docs/snippets/common/storybook-run-dev.npm.js.mdx +++ b/docs/snippets/common/storybook-run-dev.npm.js.mdx @@ -1,4 +1,3 @@ ```shell -# Starts Storybook in development mode npm run storybook ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-run-dev.yarn.js.mdx b/docs/snippets/common/storybook-run-dev.yarn.js.mdx index c93bf22abb92..137dc51f4c21 100644 --- a/docs/snippets/common/storybook-run-dev.yarn.js.mdx +++ b/docs/snippets/common/storybook-run-dev.yarn.js.mdx @@ -1,4 +1,3 @@ ```shell -# Starts Storybook in development mode yarn storybook ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-storysource-manager-entries.js.mdx b/docs/snippets/common/storybook-storysource-manager-entries.js.mdx index 5e792ec1d298..e9c5dec6d95e 100644 --- a/docs/snippets/common/storybook-storysource-manager-entries.js.mdx +++ b/docs/snippets/common/storybook-storysource-manager-entries.js.mdx @@ -1,7 +1,5 @@ ```js // storysource/preset.js -export function managerEntries(entry = []) { - return [...entry, require.resolve('@storybook/addon-storysource/register')]; -} +/* nothing needed */ ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-crash-report-event.js.mdx b/docs/snippets/common/storybook-telemetry-crash-report-event.js.mdx new file mode 100644 index 000000000000..88d98f5c6bb3 --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-crash-report-event.js.mdx @@ -0,0 +1,13 @@ +```js +{ + stack: 'Error: Your button is not working\n' + + ' at Object. ($SNIP/test.js:39:27)\n' + + ' at Module._compile (node:internal/modules/cjs/loader:1103:14)\n' + + ' at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)\n' + + ' at Module.load (node:internal/modules/cjs/loader:981:32)\n' + + ' at Function.Module._load (node:internal/modules/cjs/loader:822:12)\n' + + ' at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)\n' + + ' at node:internal/main/run_main_module:17:47', + message: 'Your button is not working' +} +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-main-enable-crash-reports.main-js.js.mdx b/docs/snippets/common/storybook-telemetry-main-enable-crash-reports.main-js.js.mdx new file mode 100644 index 000000000000..c1e3d032880e --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-main-enable-crash-reports.main-js.js.mdx @@ -0,0 +1,18 @@ +```js +// .storybook/main.js + +module.exports = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/preset-create-react-app', + ], + framework: '@storybook/react', + core: { + builder: 'webpack5', + enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-main-enable-crash-reports.main-ts.ts.mdx b/docs/snippets/common/storybook-telemetry-main-enable-crash-reports.main-ts.ts.mdx new file mode 100644 index 000000000000..7ce3bba1a827 --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-main-enable-crash-reports.main-ts.ts.mdx @@ -0,0 +1,23 @@ +```ts +// .storybook/main.ts + +// Imports Storybook's configuration API +import type { StorybookConfig } from '@storybook/core-common'; + +const config: StorybookConfig = { + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + '@storybook/addon-interactions', + '@storybook/preset-create-react-app', + ], + framework: '@storybook/react', + core: { + builder: 'webpack5', + enableCrashReports: true, // 👈 Appends the crash reports to the telemetry events + }, +}; + +module.exports = config; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-preview-event.npm.js.mdx b/docs/snippets/common/storybook-telemetry-preview-event.npm.js.mdx new file mode 100644 index 000000000000..eab8893ec86f --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-preview-event.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +STORYBOOK_TELEMETRY_DEBUG=1 npm run storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-preview-event.yarn.js.mdx b/docs/snippets/common/storybook-telemetry-preview-event.yarn.js.mdx new file mode 100644 index 000000000000..fdb9d20be615 --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-preview-event.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +STORYBOOK_TELEMETRY_DEBUG=1 yarn storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.env-var.js.mdx b/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.env-var.js.mdx new file mode 100644 index 000000000000..41b65f194069 --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.env-var.js.mdx @@ -0,0 +1,3 @@ +```shell +STORYBOOK_ENABLE_CRASH_REPORTS=1 yarn storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.npm.js.mdx b/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.npm.js.mdx new file mode 100644 index 000000000000..b0fc399a5408 --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run storybook -- --enable-crash-reports +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.yarn.js.mdx b/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.yarn.js.mdx new file mode 100644 index 000000000000..71876f939367 --- /dev/null +++ b/docs/snippets/common/storybook-telemetry-storybook-enable-crash-reports.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn storybook --enable-crash-reports +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-a11y-config.js.mdx b/docs/snippets/common/storybook-test-runner-a11y-config.js.mdx new file mode 100644 index 000000000000..22bf4552fe90 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-a11y-config.js.mdx @@ -0,0 +1,23 @@ +```js +// .storybook/test-runner.js + +const { injectAxe, checkA11y } = require('axe-playwright'); + +/* +* See https://storybook.js.org/docs/react/writing-tests/test-runner#test-hook-api-experimental +* to learn more about the test-runner hooks API. +*/ +module.exports = { + async preRender(page) { + await injectAxe(page); + }, + async postRender(page) { + await checkA11y(page, '#root', { + detailedReport: true, + detailedReportOptions: { + html: true, + }, + }); + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-a11y-config.ts.mdx b/docs/snippets/common/storybook-test-runner-a11y-config.ts.mdx new file mode 100644 index 000000000000..aed751c49a9b --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-a11y-config.ts.mdx @@ -0,0 +1,27 @@ +```ts +// .storybook/test-runner.ts + +import { injectAxe, checkA11y } from 'axe-playwright'; + +import type { TestRunnerConfig } from '@storybook/test-runner'; + +/* +* See https://storybook.js.org/docs/react/writing-tests/test-runner#test-hook-api-experimental +* to learn more about the test-runner hooks API. +*/ +const a11yConfig: TestRunnerConfig = { + async preRender(page) { + await injectAxe(page); + }, + async postRender(page) { + await checkA11y(page, '#root', { + detailedReport: true, + detailedReportOptions: { + html: true, + }, + }); + }, +}; + +module.exports = a11yConfig; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-axe-playwright.npm.js.mdx b/docs/snippets/common/storybook-test-runner-axe-playwright.npm.js.mdx new file mode 100644 index 000000000000..aecfe3f9f414 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-axe-playwright.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install axe-playwright --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-axe-playwright.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-axe-playwright.yarn.js.mdx new file mode 100644 index 000000000000..e2d8d43da865 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-axe-playwright.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev axe-playwright +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-disable-stories-json.npm.js.mdx b/docs/snippets/common/storybook-test-runner-disable-stories-json.npm.js.mdx new file mode 100644 index 000000000000..79ae4ca39232 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-disable-stories-json.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run test-storybook -- --no-stories-json +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-disable-stories-json.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-disable-stories-json.yarn.js.mdx new file mode 100644 index 000000000000..141d6375fa63 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-disable-stories-json.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn test-storybook --no-stories-json +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute-with-flags.npm.js.mdx b/docs/snippets/common/storybook-test-runner-execute-with-flags.npm.js.mdx new file mode 100644 index 000000000000..88667dfad959 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute-with-flags.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run test-storybook -- --watch +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute-with-flags.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-execute-with-flags.yarn.js.mdx new file mode 100644 index 000000000000..7f4617721424 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute-with-flags.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn test-storybook --watch +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute-with-url.env-var.js.mdx b/docs/snippets/common/storybook-test-runner-execute-with-url.env-var.js.mdx new file mode 100644 index 000000000000..abc722730ba3 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute-with-url.env-var.js.mdx @@ -0,0 +1,3 @@ +```shell +TARGET_URL=https://the-storybook-url-here.com yarn test-storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute-with-url.npm.js.mdx b/docs/snippets/common/storybook-test-runner-execute-with-url.npm.js.mdx new file mode 100644 index 000000000000..9b3b6020ba60 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute-with-url.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run test-storybook -- --url https://the-storybook-url-here.com +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute-with-url.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-execute-with-url.yarn.js.mdx new file mode 100644 index 000000000000..af9b66dc11a4 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute-with-url.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn test-storybook --url https://the-storybook-url-here.com +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute.npm.js.mdx b/docs/snippets/common/storybook-test-runner-execute.npm.js.mdx new file mode 100644 index 000000000000..345a549b73d0 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run test-storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-execute.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-execute.yarn.js.mdx new file mode 100644 index 000000000000..0e90b9012b2b --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-execute.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn test-storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-hooks-example.js.mdx b/docs/snippets/common/storybook-test-runner-hooks-example.js.mdx new file mode 100644 index 000000000000..85f2437a74a0 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-hooks-example.js.mdx @@ -0,0 +1,24 @@ +```js +// .storybook/test-runner.js + +module.exports = { + // Hook that is executed before the test runner starts running tests + setup() { + // Add your configuration here. + }, + /* Hook to execute before a story is rendered. + * The page argument is the Playwright's page object for the story. + * The context argument is a Storybook object containing the story's id, title, and name. + */ + async preRender(page, context) { + // Add your configuration here. + }, + /* Hook to execute after a story is rendered. + * The page argument is the Playwright's page object for the story + * The context argument is a Storybook object containing the story's id, title, and name. + */ + async postRender(page, context) { + // Add your configuration here. + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-hooks-example.ts.mdx b/docs/snippets/common/storybook-test-runner-hooks-example.ts.mdx new file mode 100644 index 000000000000..bdc01f0f8c8b --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-hooks-example.ts.mdx @@ -0,0 +1,28 @@ +```ts +// .storybook/test-runner.ts + +import type { TestRunnerConfig } from '@storybook/test-runner'; + +const config: TestRunnerConfig = { + // Hook that is executed before the test runner starts running tests + setup() { + // Add your configuration here. + }, + /* Hook to execute before a story is rendered. + * The page argument is the Playwright's page object for the story. + * The context argument is a Storybook object containing the story's id, title, and name. + */ + async preRender(page, context) { + // Add your configuration here. + }, + /* Hook to execute after a story is rendered. + * The page argument is the Playwright's page object for the story + * The context argument is a Storybook object containing the story's id, title, and name. + */ + async postRender(page, context) { + // Add your configuration here. + }, +}; + +module.exports = config; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-install.npm.js.mdx b/docs/snippets/common/storybook-test-runner-install.npm.js.mdx new file mode 100644 index 000000000000..90f046c3ec62 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/test-runner jest --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx new file mode 100644 index 000000000000..3221e525779e --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/test-runner jest +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-local-build-workflow.yml.mdx b/docs/snippets/common/storybook-test-runner-local-build-workflow.yml.mdx new file mode 100644 index 000000000000..ce8e8658aaa5 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-local-build-workflow.yml.mdx @@ -0,0 +1,26 @@ +```yml +# .github/workflows/storybook-tests.yml + +name: 'Storybook Tests' +on: push +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '14.x' + - name: Install dependencies + run: yarn + - name: Install Playwright + run: npx playwright install --with-deps + - name: Build Storybook + run: yarn build-storybook --quiet + - name: Serve Storybook and run tests + run: | + npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \ + "npx http-server storybook-static --port 6006 --silent" \ + "npx wait-on tcp:6006 && yarn test-storybook" +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-with-deploy-event-workflow.yml.mdx b/docs/snippets/common/storybook-test-runner-with-deploy-event-workflow.yml.mdx new file mode 100644 index 000000000000..4a8705f7ec19 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-with-deploy-event-workflow.yml.mdx @@ -0,0 +1,24 @@ +```yml +# .github/workflows/storybook-tests.yml + +name: Storybook Tests +on: deployment_status +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + if: github.event.deployment_status.state == 'success' + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: '14.x' + - name: Install dependencies + run: yarn + - name: Install Playwright + run: npx playwright install --with-deps + - name: Run Storybook tests + run: yarn test-storybook + env: + TARGET_URL: '${{ github.event.deployment_status.target_url }}' +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-with-stories-json.npm.js.mdx b/docs/snippets/common/storybook-test-runner-with-stories-json.npm.js.mdx new file mode 100644 index 000000000000..0199d36a8ba6 --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-with-stories-json.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run test-storybook -- --stories-json +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-with-stories-json.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-with-stories-json.yarn.js.mdx new file mode 100644 index 000000000000..8a5bf7838bda --- /dev/null +++ b/docs/snippets/common/storybook-test-runner-with-stories-json.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn test-storybook --stories-json +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-testing-addon-install.npm.js.mdx b/docs/snippets/common/storybook-testing-addon-install.npm.js.mdx new file mode 100644 index 000000000000..f49ff3a0f3fb --- /dev/null +++ b/docs/snippets/common/storybook-testing-addon-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install --save-dev @storybook/testing-( react | vue | vue3 | angular) +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-testing-addon-install.yarn.js.mdx b/docs/snippets/common/storybook-testing-addon-install.yarn.js.mdx new file mode 100644 index 000000000000..4b6378ec00d9 --- /dev/null +++ b/docs/snippets/common/storybook-testing-addon-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/testing-( react | vue | vue3 | angular ) +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-theme-example-variables.ts.mdx b/docs/snippets/common/storybook-theme-example-variables.ts.mdx index 5fcafab87256..6c3be843f097 100644 --- a/docs/snippets/common/storybook-theme-example-variables.ts.mdx +++ b/docs/snippets/common/storybook-theme-example-variables.ts.mdx @@ -8,5 +8,6 @@ export default create({ brandTitle: 'My custom storybook', brandUrl: 'https://example.com', brandImage: 'https://place-hold.it/350x150', + brandTarget: '_self', }); -``` \ No newline at end of file +``` diff --git a/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx b/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx new file mode 100644 index 000000000000..d34ce2dc5052 --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx @@ -0,0 +1,20 @@ +```js +// .storybook/main.js|ts + +module.exports = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + core: { + builder: '@storybook/builder-vite', + }, + async viteFinal(config, { configType }) { + // Return the updated configuration + return mergeConfig(config, { + // Adds a new alias + resolve: { + alias: { exampleAlias: 'something' }, + }, + }); + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-config-env.js.mdx b/docs/snippets/common/storybook-vite-builder-config-env.js.mdx new file mode 100644 index 000000000000..a3dbee8895aa --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-config-env.js.mdx @@ -0,0 +1,24 @@ +```js +// .storybook/main.js|ts + +const { mergeConfig } = require('vite'); + +module.exports = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + core: { + builder: '@storybook/builder-vite', + }, + async viteFinal(config, { configType }) { + if (configType === 'DEVELOPMENT') { + // Your development configuration goes here + } + if (configType === 'PRODUCTION') { + // Your production configuration goes here. + } + return mergeConfig(config, { + // Your environment configuration here + }); + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-error-optimized.js.mdx b/docs/snippets/common/storybook-vite-builder-error-optimized.js.mdx new file mode 100644 index 000000000000..cc7883900911 --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-error-optimized.js.mdx @@ -0,0 +1,18 @@ +```js +// .storybook/main.js|ts + +module.exports = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + core: { + builder: '@storybook/builder-vite', + }, + async viteFinal(config, { configType }) { + config.optimizeDeps.include = [ + ...(config.optimizeDeps?.include ?? []), + // Other dependencies go here + ]; + return config; + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-install.npm.js.mdx b/docs/snippets/common/storybook-vite-builder-install.npm.js.mdx new file mode 100644 index 000000000000..e4d64958fb9a --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/builder-vite --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-install.yarn.js.mdx b/docs/snippets/common/storybook-vite-builder-install.yarn.js.mdx new file mode 100644 index 000000000000..ff51b902c057 --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/builder-vite +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-register.js.mdx b/docs/snippets/common/storybook-vite-builder-register.js.mdx new file mode 100644 index 000000000000..6ae400a96a42 --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-register.js.mdx @@ -0,0 +1,11 @@ +```js +// .storybook/main.js|ts + +module.exports = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + core: { + builder: '@storybook/builder-vite', // 👈 The builder enabled here. + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-svelte-plugin.js.mdx b/docs/snippets/common/storybook-vite-builder-svelte-plugin.js.mdx new file mode 100644 index 000000000000..3ec43e4e035e --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-svelte-plugin.js.mdx @@ -0,0 +1,24 @@ +```js +// .storybook/main.js|ts + +const preprocess = require('svelte-preprocess'); + +module.exports = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + core: { + builder: '@storybook/builder-vite', + }, + async viteFinal(config, { configType }) { + // Customize the Vite config here + return config; + }, + svelteOptions: { + preprocess: preprocess({ + typescript: true, + postcss: true, + sourceMap: true, + }), + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-vite-builder-ts-configure.ts.mdx b/docs/snippets/common/storybook-vite-builder-ts-configure.ts.mdx new file mode 100644 index 000000000000..3948e084d949 --- /dev/null +++ b/docs/snippets/common/storybook-vite-builder-ts-configure.ts.mdx @@ -0,0 +1,19 @@ +```ts +// .storybook/main.ts + +import type { StorybookViteConfig } from '@storybook/builder-vite'; + +const config: StorybookViteConfig = { + stories: ['../stories/**/*.stories.mdx', '../stories/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + core: { + builder: '@storybook/builder-vite', + }, + async viteFinal(config, options) { + // Add your configuration here + return config; + }, +}; + +export default config; +``` \ No newline at end of file diff --git a/docs/snippets/common/your-theme.js.mdx b/docs/snippets/common/your-theme.js.mdx index 24f9771bad36..4858c332aa17 100644 --- a/docs/snippets/common/your-theme.js.mdx +++ b/docs/snippets/common/your-theme.js.mdx @@ -37,5 +37,6 @@ export default create({ brandTitle: 'My custom storybook', brandUrl: 'https://example.com', brandImage: 'https://place-hold.it/350x150', + brandTarget: '_self', }); -``` \ No newline at end of file +``` diff --git a/docs/snippets/react/accessibility-testing-with-jest-axe.js.mdx b/docs/snippets/react/accessibility-testing-with-jest-axe.js.mdx deleted file mode 100644 index 73946a456b30..000000000000 --- a/docs/snippets/react/accessibility-testing-with-jest-axe.js.mdx +++ /dev/null @@ -1,23 +0,0 @@ -```js -// MyComponent.test.js - -import { render } from '@testing-library/react'; - -import { composeStories } from '@storybook/testing-react'; - -import { axe, toHaveNoViolations } from 'jest-axe'; - -import * as MyComponentStories from './MyComponent.stories'; - -const { Accessible } = composeStories(MyComponentStories); - -expect.extend(toHaveNoViolations); - -test('Example accessiblity test', async () => { - const { container } = render(); - - const AxeResults = await axe(container); - - expect(AxeResults).toHaveNoViolations(); -}); -``` \ No newline at end of file diff --git a/docs/snippets/react/button-story-with-blue-args.mdx.mdx b/docs/snippets/react/button-story-with-blue-args.mdx.mdx index f9f69d188f71..7c5e3c682781 100644 --- a/docs/snippets/react/button-story-with-blue-args.mdx.mdx +++ b/docs/snippets/react/button-story-with-blue-args.mdx.mdx @@ -20,5 +20,5 @@ import { Button } from './Button'; }} /> - + ``` \ No newline at end of file diff --git a/docs/snippets/react/component-story-figma-integration.js.mdx b/docs/snippets/react/component-story-figma-integration.js.mdx new file mode 100644 index 000000000000..57ecc2750431 --- /dev/null +++ b/docs/snippets/react/component-story-figma-integration.js.mdx @@ -0,0 +1,27 @@ +```js +// MyComponent.stories.js|jsx + +import React from 'react'; + +import { withDesign } from 'storybook-addon-designs'; + +import { MyComponent } from './MyComponent'; + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +export default { + title: 'FigmaExample', + component: MyComponent, + decorators: [withDesign], +}; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +const Template = () => ; + +export const Example = Template.bind({}); +Example.parameters = { + design: { + type: 'figma', + url: 'https://www.figma.com/file/Sample-File', + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/react/component-story-figma-integration.mdx.mdx b/docs/snippets/react/component-story-figma-integration.mdx.mdx new file mode 100644 index 000000000000..455cb3a10eaa --- /dev/null +++ b/docs/snippets/react/component-story-figma-integration.mdx.mdx @@ -0,0 +1,27 @@ +```md + + +import { Canvas, Meta, Story } from '@storybook/addon-docs'; + +import { withDesign } from 'storybook-addon-designs'; + +import { MyComponent } from './MyComponent'; + + + +export const Template = () => ; + + + + {Template.bind({})} + + +``` \ No newline at end of file diff --git a/docs/snippets/react/component-story-figma-integration.ts.mdx b/docs/snippets/react/component-story-figma-integration.ts.mdx new file mode 100644 index 000000000000..1b54ea82e143 --- /dev/null +++ b/docs/snippets/react/component-story-figma-integration.ts.mdx @@ -0,0 +1,29 @@ +```ts +// MyComponent.stories.ts|tsx + +import React from 'react'; + +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import { withDesign } from 'storybook-addon-designs'; + +import { MyComponent } from './MyComponent'; + +// More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export +export default { + title: 'FigmaExample', + component: MyComponent, + decorators: [withDesign], +} as ComponentMeta; + +// More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args +const Template: ComponentStory = () => ; + +export const Example = Template.bind({}); +Example.parameters = { + design: { + type: 'figma', + url: 'https://www.figma.com/file/Sample-File', + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/react/document-screen-fetch.js.mdx b/docs/snippets/react/document-screen-fetch.js.mdx index 160069be7840..86f04def6814 100644 --- a/docs/snippets/react/document-screen-fetch.js.mdx +++ b/docs/snippets/react/document-screen-fetch.js.mdx @@ -22,7 +22,7 @@ function useFetchData() { }) .then((res) => res.json()) .then((data) => { - setStatus('sucess'); + setStatus('success'); setData(data); }) .catch(() => { diff --git a/docs/snippets/react/login-form-with-play-function.js.mdx b/docs/snippets/react/login-form-with-play-function.js.mdx index 01d5427e4283..ca6e59d02331 100644 --- a/docs/snippets/react/login-form-with-play-function.js.mdx +++ b/docs/snippets/react/login-form-with-play-function.js.mdx @@ -5,6 +5,8 @@ import React from 'react'; import { within, userEvent } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import { LoginForm } from './LoginForm'; export default { @@ -25,14 +27,19 @@ FilledForm.play = async ({ canvasElement }) => { // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); // See https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); }; -``` +``` \ No newline at end of file diff --git a/docs/snippets/react/login-form-with-play-function.mdx.mdx b/docs/snippets/react/login-form-with-play-function.mdx.mdx index 2593c723fb15..327a8ae55c42 100644 --- a/docs/snippets/react/login-form-with-play-function.mdx.mdx +++ b/docs/snippets/react/login-form-with-play-function.mdx.mdx @@ -5,6 +5,8 @@ import { Canvas, Meta, Story } from '@storybook/addon-docs'; import { within, userEvent } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import { LoginForm } from './LoginForm'; @@ -22,16 +24,22 @@ export const Template = (args) => ; // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); - // See https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel - await userEvent.click(canvas.getByRole('button')); - }}> - {Template.bind({})} + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); + + // See https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel + await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); + }}> + {Template.bind({})} ``` diff --git a/docs/snippets/react/login-form-with-play-function.ts.mdx b/docs/snippets/react/login-form-with-play-function.ts.mdx index df528c066cf8..05b3e8395739 100644 --- a/docs/snippets/react/login-form-with-play-function.ts.mdx +++ b/docs/snippets/react/login-form-with-play-function.ts.mdx @@ -7,6 +7,8 @@ import { ComponentStory, ComponentMeta } from '@storybook/react'; import { within, userEvent } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import { LoginForm } from './LoginForm'; export default { @@ -27,14 +29,19 @@ FilledForm.play = async ({ canvasElement }) => { // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); // See https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); }; ``` \ No newline at end of file diff --git a/docs/snippets/react/my-component-play-function-with-delay.js.mdx b/docs/snippets/react/my-component-play-function-with-delay.js.mdx index 434cd2304a6b..ffda0d5edec1 100644 --- a/docs/snippets/react/my-component-play-function-with-delay.js.mdx +++ b/docs/snippets/react/my-component-play-function-with-delay.js.mdx @@ -22,7 +22,7 @@ export const DelayedStory = Template.bind({}); DelayedStory.play = async () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -32,4 +32,4 @@ DelayedStory.play = async () => { delay: 100, }); }; -``` \ No newline at end of file +``` diff --git a/docs/snippets/react/my-component-play-function-with-delay.mdx.mdx b/docs/snippets/react/my-component-play-function-with-delay.mdx.mdx index 44dd26e7fd96..56ab5df2ebcc 100644 --- a/docs/snippets/react/my-component-play-function-with-delay.mdx.mdx +++ b/docs/snippets/react/my-component-play-function-with-delay.mdx.mdx @@ -16,7 +16,7 @@ export const Template = (args) => ; play={async () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -28,4 +28,4 @@ export const Template = (args) => ; }}> {Template.bind({})} -``` \ No newline at end of file +``` diff --git a/docs/snippets/react/my-component-play-function-with-delay.ts.mdx b/docs/snippets/react/my-component-play-function-with-delay.ts.mdx index 93ce662baabd..0d806f32d210 100644 --- a/docs/snippets/react/my-component-play-function-with-delay.ts.mdx +++ b/docs/snippets/react/my-component-play-function-with-delay.ts.mdx @@ -24,7 +24,7 @@ export const DelayedStory = Template.bind({}); DelayedStory.play = async () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -34,4 +34,4 @@ DelayedStory.play = async () => { delay: 100, }); }; -``` \ No newline at end of file +``` diff --git a/docs/snippets/react/storybook-testing-addon-optional-config.js.mdx b/docs/snippets/react/storybook-testing-addon-optional-config.js.mdx index 60b244c3ff40..9bc7bbd7a6ba 100644 --- a/docs/snippets/react/storybook-testing-addon-optional-config.js.mdx +++ b/docs/snippets/react/storybook-testing-addon-optional-config.js.mdx @@ -1,5 +1,5 @@ ```js -// setupTests.js +// setupFile.js import { setGlobalConfig } from '@storybook/testing-react'; @@ -7,4 +7,4 @@ import { setGlobalConfig } from '@storybook/testing-react'; import * as globalStorybookConfig from './.storybook/preview'; setGlobalConfig(globalStorybookConfig); -``` \ No newline at end of file +``` diff --git a/docs/snippets/svelte/button-story-with-blue-args.mdx.mdx b/docs/snippets/svelte/button-story-with-blue-args.mdx.mdx index 68046a1c382a..c6d410ddc632 100644 --- a/docs/snippets/svelte/button-story-with-blue-args.mdx.mdx +++ b/docs/snippets/svelte/button-story-with-blue-args.mdx.mdx @@ -3,7 +3,7 @@ import { Meta } from '@storybook/addon-docs'; -import Button from './Button.svelte'; +import Button from './Button.svelte'; - + ``` \ No newline at end of file diff --git a/docs/snippets/svelte/component-story-figma-integration.js.mdx b/docs/snippets/svelte/component-story-figma-integration.js.mdx new file mode 100644 index 000000000000..a509ab634c30 --- /dev/null +++ b/docs/snippets/svelte/component-story-figma-integration.js.mdx @@ -0,0 +1,28 @@ +```js +// MyComponent.stories.js + +import { withDesign } from 'storybook-addon-designs'; + +import MyComponent from './MyComponent.svelte'; + +// More on default export: https://storybook.js.org/docs/svelte/writing-stories/introduction#default-export +export default { + title: 'FigmaExample', + component: { MyComponent }, + decorators: [withDesign], +}; + +// More on component templates: https://storybook.js.org/docs/svelte/writing-stories/introduction#using-args +const Template = () => ({ + props: {}, + Component: MyComponent, +}); + +export const Example = Template.bind({}); +Example.parameters = { + design: { + type: 'figma', + url: 'https://www.figma.com/file/Sample-File', + }, +}; +``` \ No newline at end of file diff --git a/docs/snippets/svelte/component-story-figma-integration.mdx.mdx b/docs/snippets/svelte/component-story-figma-integration.mdx.mdx new file mode 100644 index 000000000000..3dcfbcfd35e0 --- /dev/null +++ b/docs/snippets/svelte/component-story-figma-integration.mdx.mdx @@ -0,0 +1,34 @@ +```md + + +import { Canvas, Meta, Story } from '@storybook/addon-docs'; + +import { withDesign } from 'storybook-addon-designs'; + +import MyComponent from './MyComponent.svelte'; + + + +export const Template = () => ({ + props: {}, + Component: MyComponent, +}); + + + + {Template.bind({})} + + +``` \ No newline at end of file diff --git a/docs/snippets/svelte/login-form-with-play-function.js.mdx b/docs/snippets/svelte/login-form-with-play-function.js.mdx index e49f2f000811..e06ea2235a84 100644 --- a/docs/snippets/svelte/login-form-with-play-function.js.mdx +++ b/docs/snippets/svelte/login-form-with-play-function.js.mdx @@ -3,6 +3,8 @@ import { within, userEvent } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import LoginForm from './LoginForm.svelte'; export default { @@ -26,14 +28,19 @@ FilledForm.play = async ({ canvasElement }) => { // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); + // 👇 Simulate interactions with the component + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); // See https://storybook.js.org/docs/svelte/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); }; ``` \ No newline at end of file diff --git a/docs/snippets/svelte/login-form-with-play-function.mdx.mdx b/docs/snippets/svelte/login-form-with-play-function.mdx.mdx index b6545bb4cd51..8f5e3441bf6c 100644 --- a/docs/snippets/svelte/login-form-with-play-function.mdx.mdx +++ b/docs/snippets/svelte/login-form-with-play-function.mdx.mdx @@ -5,6 +5,8 @@ import { Canvas, Meta, Story } from '@storybook/addon-docs'; import { within, userEvent } from '@storybook/testing-library'; +import { expect } from '@storybook/jest'; + import LoginForm from './LoginForm.svelte'; @@ -22,19 +24,23 @@ export const Template = (args) => ({ { - // Starts querying the component from its root element const canvas = within(canvasElement); - await userEvent.type(canvas.getByTestId('email'), 'email@provider.com', { - delay: 100, - }); - await userEvent.type(canvas.getByTestId('password'), 'a-random-password', { - delay: 100, - }); + // 👇 Simulate interactions + await userEvent.type(canvas.getByTestId('email'), 'email@provider.com'); + + await userEvent.type(canvas.getByTestId('password'), 'a-random-password'); // See https://storybook.js.org/docs/svelte/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel await userEvent.click(canvas.getByRole('button')); + + // 👇 Assert DOM structure + await expect( + canvas.getByText( + 'Everything is perfect. Your account is ready and we should probably get you started!' + ) + ).toBeInTheDocument(); }}> {Template.bind({})} diff --git a/docs/snippets/svelte/my-component-play-function-with-delay.js.mdx b/docs/snippets/svelte/my-component-play-function-with-delay.js.mdx index 2c84dca6544a..47ce8d030ca1 100644 --- a/docs/snippets/svelte/my-component-play-function-with-delay.js.mdx +++ b/docs/snippets/svelte/my-component-play-function-with-delay.js.mdx @@ -23,7 +23,7 @@ export const DelayedStory = Template.bind({}); DelayedStory.play = async () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -33,4 +33,4 @@ DelayedStory.play = async () => { delay: 100, }); }; -``` \ No newline at end of file +``` diff --git a/docs/snippets/svelte/my-component-play-function-with-delay.mdx.mdx b/docs/snippets/svelte/my-component-play-function-with-delay.mdx.mdx index 79f0fee163c0..2706786d7110 100644 --- a/docs/snippets/svelte/my-component-play-function-with-delay.mdx.mdx +++ b/docs/snippets/svelte/my-component-play-function-with-delay.mdx.mdx @@ -19,7 +19,7 @@ export const Template = (args) => ({ play={async () => { const exampleElement= screen.getByLabelText('example-element'); - // The delay option set the ammount of milliseconds between characters being typed + // The delay option set the amount of milliseconds between characters being typed await userEvent.type(exampleElement, 'random string', { delay: 100, }); @@ -31,4 +31,4 @@ export const Template = (args) => ({ }}> {Template.bind({})} -``` \ No newline at end of file +``` diff --git a/docs/snippets/vue/accessibility-testing-with-jest-axe.js.mdx b/docs/snippets/vue/accessibility-testing-with-jest-axe.js.mdx deleted file mode 100644 index bb64b8201590..000000000000 --- a/docs/snippets/vue/accessibility-testing-with-jest-axe.js.mdx +++ /dev/null @@ -1,23 +0,0 @@ -```js -// MyComponent.test.js - -import { render } from '@testing-library/vue'; - -import { composeStories } from '@storybook/testing-vue'; - -import { axe, toHaveNoViolations } from 'jest-axe'; - -import * as MyComponentStories from './MyComponent.stories'; - -const { Accessible } = composeStories(MyComponentStories); - -expect.extend(toHaveNoViolations); - -test('Example accessiblity test', async () => { - const { container } = render(Accessible()); - - const AxeResults = await axe(container); - - expect(AxeResults).toHaveNoViolations(); -}); -``` \ No newline at end of file diff --git a/docs/snippets/vue/badge-story-starter-example.mdx.mdx b/docs/snippets/vue/badge-story-starter-example.mdx.mdx index 1905cd91cac4..3b228d2840a9 100644 --- a/docs/snippets/vue/badge-story-starter-example.mdx.mdx +++ b/docs/snippets/vue/badge-story-starter-example.mdx.mdx @@ -76,4 +76,4 @@ with unique URLs and isolated snapshot tests. }} -``` +``` \ No newline at end of file diff --git a/docs/snippets/vue/badge-story.mdx-2.mdx.mdx b/docs/snippets/vue/badge-story.mdx-2.mdx.mdx index fb34bac4968d..32ed8f0726b5 100644 --- a/docs/snippets/vue/badge-story.mdx-2.mdx.mdx +++ b/docs/snippets/vue/badge-story.mdx-2.mdx.mdx @@ -69,4 +69,4 @@ with unique URLs, which is great for review and testing. {Template.bind({})} -``` +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-group-story.2.js.mdx b/docs/snippets/vue/button-group-story.2.js.mdx index 73edf3359698..a083bfbce036 100644 --- a/docs/snippets/vue/button-group-story.2.js.mdx +++ b/docs/snippets/vue/button-group-story.2.js.mdx @@ -1,5 +1,5 @@ ```js -//ButtonGroup.stories.js +// ButtonGroup.stories.js import ButtonGroup from './ButtonGroup.vue'; diff --git a/docs/snippets/vue/button-group-story.3.js.mdx b/docs/snippets/vue/button-group-story.3.js.mdx index fba028c49219..6197ffd73ae4 100644 --- a/docs/snippets/vue/button-group-story.3.js.mdx +++ b/docs/snippets/vue/button-group-story.3.js.mdx @@ -1,5 +1,5 @@ ```js -//ButtonGroup.stories.js +// ButtonGroup.stories.js import ButtonGroup from './ButtonGroup.vue'; diff --git a/docs/snippets/vue/button-group-story.ts-2.ts.mdx b/docs/snippets/vue/button-group-story.ts-2.ts.mdx new file mode 100644 index 000000000000..d0e1eb3adadc --- /dev/null +++ b/docs/snippets/vue/button-group-story.ts-2.ts.mdx @@ -0,0 +1,31 @@ +```ts +// ButtonGroup.stories.ts + +import ButtonGroup from './ButtonGroup.vue'; + +import { Meta, StoryFn } from '@storybook/vue'; + +//👇 Imports the Button stories +import * as ButtonStories from './Button.stories'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/vue/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'ButtonGroup', + component: ButtonGroup, +} as Meta; + +const Template: StoryFn = (args, { argTypes }) => ({ + components: { ButtonGroup }, + props: Object.keys(argTypes), + template: '', +}); + +export const Pair = Template.bind({}); +Pair.args = { + buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }], + orientation: 'horizontal', +}; +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-group-story.ts-3.ts.mdx b/docs/snippets/vue/button-group-story.ts-3.ts.mdx new file mode 100644 index 000000000000..91b68cc272f6 --- /dev/null +++ b/docs/snippets/vue/button-group-story.ts-3.ts.mdx @@ -0,0 +1,33 @@ +```ts +// ButtonGroup.stories.ts + +import ButtonGroup from './ButtonGroup.vue'; + +import { Meta, StoryFn } from '@storybook/vue3'; + +//👇 Imports the Button stories +import * as ButtonStories from './Button.stories'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/vue/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'ButtonGroup', + component: ButtonGroup, +} as Meta; + +const Template: StoryFn = (args) => ({ + components: { ButtonGroup }, + setup() { + return { args }; + }, + template: '', +}); + +export const Pair = Template.bind({}); +Pair.args = { + buttons: [{ ...ButtonStories.Primary.args }, { ...ButtonStories.Secondary.args }], + orientation: 'horizontal', +}; +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-story-component-decorator.ts-2.ts.mdx b/docs/snippets/vue/button-story-component-decorator.ts-2.ts.mdx new file mode 100644 index 000000000000..37a6ec4b52f0 --- /dev/null +++ b/docs/snippets/vue/button-story-component-decorator.ts-2.ts.mdx @@ -0,0 +1,17 @@ +```ts +// Button.stories.ts + +import Button from './Button.vue'; + +import { Meta } from '@storybook/vue'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/vue/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + component: Button, + decorators: [() => ({ template: '
' })], +} as Meta; +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-story-component-decorator.ts-3.ts.mdx b/docs/snippets/vue/button-story-component-decorator.ts-3.ts.mdx new file mode 100644 index 000000000000..bc4678319e93 --- /dev/null +++ b/docs/snippets/vue/button-story-component-decorator.ts-3.ts.mdx @@ -0,0 +1,17 @@ +```ts +// Button.stories.ts + +import Button from './Button.vue'; + +import { Meta } from '@storybook/vue3'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/vue/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + component: Button, + decorators: [() => ({ template: '
' })], +} as Meta; +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-story-default-export-with-component.ts-2.ts.mdx b/docs/snippets/vue/button-story-default-export-with-component.ts-2.ts.mdx new file mode 100644 index 000000000000..3203b13bc70a --- /dev/null +++ b/docs/snippets/vue/button-story-default-export-with-component.ts-2.ts.mdx @@ -0,0 +1,16 @@ +```ts +// Button.stories.ts + +import Button from './Button.vue'; + +import { Meta } from '@storybook/vue'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/vue/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + component: Button, +} as Meta; +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-story-default-export-with-component.ts-3.ts.mdx b/docs/snippets/vue/button-story-default-export-with-component.ts-3.ts.mdx new file mode 100644 index 000000000000..afc5e65c7954 --- /dev/null +++ b/docs/snippets/vue/button-story-default-export-with-component.ts-3.ts.mdx @@ -0,0 +1,16 @@ +```ts +// Button.stories.ts + +import Button from './Button.vue'; + +import { Meta } from '@storybook/vue3'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/vue/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + component: Button, +} as Meta; +``` \ No newline at end of file diff --git a/docs/snippets/vue/button-story-rename-story.js.mdx b/docs/snippets/vue/button-story-rename-story.js.mdx index 1b87c6bc4b53..95750d3d6c82 100644 --- a/docs/snippets/vue/button-story-rename-story.js.mdx +++ b/docs/snippets/vue/button-story-rename-story.js.mdx @@ -17,4 +17,4 @@ export const Primary = () => ({ template: '
\ No newline at end of file +
diff --git a/docs/writing-stories/play-function.md b/docs/writing-stories/play-function.md index 4538ffa37318..cef5c1be9920 100644 --- a/docs/writing-stories/play-function.md +++ b/docs/writing-stories/play-function.md @@ -6,7 +6,7 @@ title: 'Play function' ## Setup the interactions addon -We recommend installing Storybook's [`addon-interactions`](/addons/@storybook/addon-interactions/) before you start writing stories with the `play` function. It's the perfect complement for it, including a handy set of UI controls to allow you command over the execution flow. At any time, you can pause, resume, rewind, and step through each interaction. Also providing you with an easy-to-use debugger for potential issues. +We recommend installing Storybook's [`addon-interactions`](https://storybook.js.org/addons/@storybook/addon-interactions) before you start writing stories with the `play` function. It's the perfect complement for it, including a handy set of UI controls to allow you command over the execution flow. At any time, you can pause, resume, rewind, and step through each interaction. Also providing you with an easy-to-use debugger for potential issues. Run the following command to install the addon and the required dependencies. @@ -210,4 +210,4 @@ By default, each interaction you write inside your `play` function will be execu -Applying these changes to your stories can provide a performance boost and improved error handling with [`addon-interactions`](/addons/@storybook/addon-interactions/). +Applying these changes to your stories can provide a performance boost and improved error handling with [`addon-interactions`](https://storybook.js.org/addons/@storybook/addon-interactions). diff --git a/docs/writing-tests/accessibility-testing.md b/docs/writing-tests/accessibility-testing.md index cc14cd06abef..9dcae06f0404 100644 --- a/docs/writing-tests/accessibility-testing.md +++ b/docs/writing-tests/accessibility-testing.md @@ -6,29 +6,37 @@ Accessibility is the practice of making websites inclusive to all. That means su Accessibility tests audit the rendered DOM against a set of heuristics based on [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) rules and other industry-accepted best practices. They act as the first line of QA to catch blatant accessibility violations. -Storybook’s official [a11y addon](https://storybook.js.org/addons/@storybook/addon-a11y) runs accessibility audits while you’re developing components to give you a fast feedback loop. It's powered by Deque's [axe-core](https://github.com/dequelabs/axe-core), which automatically catches up to [57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/). - ![Accessibility testing](./accessibility-testing-storybook.gif) -## Setup a11y addon +## Accessibility checks with a11y addon + +Storybook provides an official [a11y addon](https://storybook.js.org/addons/@storybook/addon-a11y). Powered by Deque's [axe-core](https://github.com/dequelabs/axe-core), which automatically catches up to [57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/). + +### Set up the a11y addon + +If you want to check accessibility for your stories using the [addon](https://storybook.js.org/addons/@storybook/addon-a11y/), you'll need to install it and add it to your Storybook. -To enable accessibility testing with Storybook, you'll need to install the [`@storybook/addon-a11y`](https://storybook.js.org/addons/@storybook/addon-a11y/) addon. Run the following command: +Run the following command to install the addon. -```shell -# With npm -npm install @storybook/addon-a11y --save-dev + + + -# With yarn -yarn add --dev @storybook/addon-a11y -``` + -Update your Storybook configuration (in `.storybook/main.js`) to include the accessibility addon: +Update your Storybook configuration (in `.storybook/main.js|ts`) to include the accessibility addon. @@ -73,7 +81,7 @@ Cycling through both stories, you will see that the `Inaccessible` story contain ### Configure -Out of the box, Storybook's accessibility addon includes a set of accessibility rules that cover most issues. You can also fine tune the [addon configuration](https://github.com/storybookjs/storybook/tree/next/addons/a11y#parameters) or override [Axe's ruleset](https://github.com/storybookjs/storybook/tree/next/addons/a11y#handling-failing-rules) to best suit your needs. +Out of the box, Storybook's accessibility addon includes a set of accessibility rules that cover most issues. You can also fine-tune the [addon configuration](https://github.com/storybookjs/storybook/tree/next/addons/a11y#parameters) or override [Axe's ruleset](https://github.com/storybookjs/storybook/tree/next/addons/a11y#handling-failing-rules) to best suit your needs. #### Global a11y configuration @@ -148,37 +156,65 @@ Disable accessibility testing for stories or components by adding the following -## Automate accessibility tests with Jest +## Automate accessibility tests with test runner + +The most accurate way to check accessibility is manually on real devices. However, you can use automated tools to catch common accessibility issues. For example, [Axe](https://www.deque.com/axe/), on average, catches upwards to [57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/) automatically. + +These tools work by auditing the rendered DOM against heuristics based on [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) rules and other industry-accepted best practices. You can then integrate these tools into your test automation pipeline using the Storybook [test runner](./test-runner.md#test-hook-api-experimental) and [axe-playwright](https://github.com/abhinaba-ghosh/axe-playwright). + +### Setup -Accessibility testing with Storybook shortens the feedback loop which means you fix issues faster. Reuse stories in a Jest test and run an accessibility audit on them using the the [jest-axe integration](https://github.com/nickcolley/jest-axe). That also unlocks the ability to integrate accessibility tests into your functional testing pipeline. +To enable accessibility testing with the test runner, you will need to take additional steps to set it up properly. Detailed below is our recommendation to configure and execute them. -For example, include the following test file to run an accessibility test on a story: +Run the following command to install the required dependencies. -When you execute your test script, it will run the accessibility audit along with any interaction tests you might have. +Add a new [configuration file](./test-runner.md#test-hook-api-experimental) inside your Storybook directory with the following inside: + + + + + + + +
+ +💡 `preRender` and `postRender` are convenient hooks that allow you to extend the test runner's default configuration. They are **experimental** and subject to changes. Read more about them [here](./test-runner.md#test-hook-api-experimental). + +
+ +When you execute the test runner (for example, with `yarn test-storybook`), it will run the accessibility audit and any [interaction tests](./interaction-testing.md) you might have configured for each component story. + +It starts checking for issues by traversing the DOM tree starting from the story's root element and generates a detailed report based on the issues it encountered. -![Accessibility testing with Jest Axe Core](./jest-accessibility-testing-optimized.png) +![Accessibility testing with the test runner](./test-runner-a11y-optimized.png) --- #### What’s the difference between browser-based and linter-based accessibility tests? -Browser-based accessibility tests, like found in Storybook, evaluates the rendered DOM because that gives you the highest accuracy. Auditing code that hasn't been compiled yet is one step removed from the real thing so you won't catch everything the user might experience. +Browser-based accessibility tests, like those found in Storybook, evaluate the rendered DOM because that gives you the highest accuracy. Auditing code that hasn't been compiled yet is one step removed from the real thing, so you won't catch everything the user might experience. #### Learn about other UI tests +- [Test runner](./test-runner.md) to automate test execution - [Visual tests](./visual-testing.md) for appearance - Accessibility tests for accessibility - [Interaction tests](./interaction-testing.md) for user behavior simulation - [Snapshot tests](./snapshot-testing.md) for rendering errors and warnings -- [Import stories in other tests](./importing-stories-in-tests.md) for other tools +- [Import stories in other tests](./importing-stories-in-tests.md) for other tools \ No newline at end of file diff --git a/docs/writing-tests/addon-interaction-example-optimized.mp4 b/docs/writing-tests/addon-interaction-example-optimized.mp4 index dbbafa57d051..c2b34091be68 100644 Binary files a/docs/writing-tests/addon-interaction-example-optimized.mp4 and b/docs/writing-tests/addon-interaction-example-optimized.mp4 differ diff --git a/docs/writing-tests/addon-interactions-playback-controls-optimized.mp4 b/docs/writing-tests/addon-interactions-playback-controls-optimized.mp4 new file mode 100644 index 000000000000..2afbd10562bb Binary files /dev/null and b/docs/writing-tests/addon-interactions-playback-controls-optimized.mp4 differ diff --git a/docs/writing-tests/importing-stories-in-tests.md b/docs/writing-tests/importing-stories-in-tests.md index 1f3caa31803b..d076be34b058 100644 --- a/docs/writing-tests/importing-stories-in-tests.md +++ b/docs/writing-tests/importing-stories-in-tests.md @@ -21,13 +21,22 @@ Storybook has test addons for core frameworks React, Vue (2,3), and Angular. Thi Run the following command to add Storybook's testing addon into your environment: -```shell -# With npm, don't forget to select only your framework -npm install --save-dev @storybook/testing-( react | vue | vue3 | angular) + + + -# With yarn, don't forget to select only your framework -yarn add --dev @storybook/testing-( react | vue | vue3 | angular ) -``` + + +
+ +💡 When running the command to install the addon, don't forget to select **only** your framework. + +
### Optional configuration @@ -60,7 +69,7 @@ Update your test script to include the configuration file: ## Example with Testing Library -[Testing Library](https://testing-library.com/) is a suite of helper libraries for browser-based interaction tests. With [Component Story Format](../api/csf.md), your stories are reusable with Testing Library. Each named export (i.e., a story) is renderable within your testing setup. +[Testing Library](https://testing-library.com/) is a suite of helper libraries for browser-based interaction tests. With [Component Story Format](../api/csf.md), your stories are reusable with Testing Library. Each named export (story) is renderable within your testing setup.
@@ -88,7 +97,7 @@ Once the test runs, it loads the story and renders it. [Testing Library](https:/ ## Example with Cypress -[Cypress](https://www.cypress.io/) is an end-to-end testing framework. It enables you to test a complete instance of your application by simulating user behavior. With Component Story Format, your stories are reusable with Cypress. Each named export (i.e., a story) is renderable within your testing setup. +[Cypress](https://www.cypress.io/) is an end-to-end testing framework. It enables you to test a complete instance of your application by simulating user behavior. With Component Story Format, your stories are reusable with Cypress. Each named export (in other words, a story) is renderable within your testing setup. An example of an end-to-end test with Cypress and Storybook is testing a login component for the correct inputs. For example, if you had the following story: @@ -130,7 +139,7 @@ When Cypress runs your test, it loads Storybook's isolated iframe and checks if ## Example with Playwright -[Playwright](https://playwright.dev/) is a browser automation tool and end-to-end testing framework from Microsoft. It offers cross-browser automation, mobile testing with device emulation, and headless testing. With Component Story Format, your stories are reusable with Playwright. Each named export (i.e., a story) is renderable within your testing setup. +[Playwright](https://playwright.dev/) is a browser automation tool and end-to-end testing framework from Microsoft. It offers cross-browser automation, mobile testing with device emulation, and headless testing. With Component Story Format, your stories are reusable with Playwright. Each named export (in other words, a story) is renderable within your testing setup. A real-life scenario of user flow testing with Playwright would be how to test a login form for validity. For example, if you had the following story already created: @@ -171,8 +180,9 @@ Once you execute Playwright, it opens a new browser window, loads Storybook's is #### Learn about other UI tests +- [Test runner](./test-runner.md) to automate test execution - [Visual tests](./visual-testing.md) for appearance - [Accessibility tests](./accessibility-testing.md) for accessibility - [Interaction tests](./interaction-testing.md) for user behavior simulation - [Snapshot tests](./snapshot-testing.md) for rendering errors and warnings -- Import stories in other tests for other tools +- Import stories in other tests for other tools \ No newline at end of file diff --git a/docs/writing-tests/interaction-testing.md b/docs/writing-tests/interaction-testing.md index 2fb63362a629..1b86c56dfc01 100644 --- a/docs/writing-tests/interaction-testing.md +++ b/docs/writing-tests/interaction-testing.md @@ -6,17 +6,51 @@ As you build more complex UIs like pages, components become responsible for more In a nutshell, you start by supplying the appropriate props for the initial state of a component. Then simulate user behavior such as clicks and form entries. Finally, check whether the UI and component state update correctly. +In Storybook, this familiar workflow happens in your browser. That makes it easier to debug failures because you're running tests in the same environment as you develop components: the browser. + ![Storybook interaction testing](./storybook-interaction-tests.gif) -## Setup interactions addon +## How does component testing in Storybook work? -You can set up interaction testing in Storybook using the `play` function and [`@storybook/addon-interactions`](https://storybook.js.org/addons/@storybook/addon-interactions/). +You start by writing a [**story**](../writing-stories/introduction.md) to set up the component's initial state. Then simulate user behavior using the **play** function. Finally, use the **test-runner** to confirm that the component renders correctly and that your interaction tests with the **play** function pass. Additionally, you can automate test execution via the [command line](./test-runner.md#cli-options) or in your [CI environment](./test-runner.md#set-up-ci-to-run-tests). - The [`play`](../writing-stories/play-function.md) function is a small snippet of code that runs after a story finishes rendering. You can use this to test user workflows. +- The test is written using Storybook-instrumented versions of [Jest](https://jestjs.io/) and [Testing Library](https://testing-library.com/). +- [`@storybook/addon-interactions`](https://storybook.js.org/addons/@storybook/addon-interactions/) visualizes the test in Storybook and provides a playback interface for convenient browser-based debugging. +- [`@storybook/test-runner`](https://github.com/storybookjs/test-runner) is a standalone utility—powered by [Jest](https://jestjs.io/) and [Playwright](https://playwright.dev/)—that executes all of your interactions tests and catches broken stories. + +## Set up the interactions addon + +To enable interaction testing with Storybook, you'll need to take additional steps to set it up properly. We recommend you go through the [test runner documentation](./test-runner.md) before proceeding with the rest of the required configuration. + +Run the following command to install the interactions addon and related dependencies. + + + + + + + +Update your Storybook configuration (in `.storybook/main.js|ts`) to include the interactions addon and enable playback controls for debugging. + + + + -- [`@storybook/addon-interactions`](/addons/@storybook/addon-interactions/) includes helper utilities and a playback interface that simulates user behavior in the browser. It’s powered Testing Library and includes convenient instrumentation for debugging. + + +## Write an interaction test -Here's an example of how to set up interaction testing in Storybook with the `play` function: +The test itself is defined inside a `play` function connected to a story. Here's an example of how to set up an interaction test with Storybook and the `play` function: @@ -49,7 +83,7 @@ Once the story loads in the UI, it simulates the user's behavior and verifies th ## API for user-events -Under the hood, Storybook’s interaction addon mirrors Testing Library’s `user-events` API. If you’re familiar with [Testing Library](https://testing-library.com/) you should be at home in Storybook. +Under the hood, Storybook’s interaction addon mirrors Testing Library’s [`user-events`](https://testing-library.com/docs/user-event/intro/) API. If you’re familiar with [Testing Library](https://testing-library.com/), you should be at home in Storybook. Below is an abridged API for user-event. For more, check out the [official user-event docs](https://testing-library.com/docs/ecosystem-user-event/). @@ -65,6 +99,17 @@ Below is an abridged API for user-event. For more, check out the [official user- | `type` | Writes text inside inputs, or textareas
`userEvent.type(await within(canvasElement).getByRole('my-input'),'Some text');` | | `unhover` | Unhovers out of element
`userEvent.unhover(await within(canvasElement).getByLabelText(/Example/i));` | +### Interactive debugger + +If you check your interactions panel, you'll see the step-by-step flow. It also offers a handy set of UI controls to pause, resume, rewind, and step through each interaction. + + + ### Permalinks for reproductions The `play` function is executed after the story is rendered. If there’s an error, it’ll be shown in the interaction addon panel to help with debugging. @@ -75,6 +120,33 @@ Since Storybook is a webapp, anyone with the URL can reproduce the error with th Streamline interaction testing further by automatically [publishing Storybook](../sharing/publish-storybook.md) in pull requests. That gives teams a universal reference point to test and debug stories. +## Execute tests with the test-runner + +Storybook only runs the interaction test when you're viewing a story. Therefore, you'd have to go through each story to run all your checks. As your Storybook grows, it becomes unrealistic to review each change manually. Storybook [test-runner](https://github.com/storybookjs/test-runner) automates the process by running all tests for you. To execute the test-runner, open a new terminal window and run the following command: + + + + + + + +![Interaction test with test runner](./storybook-interaction-test-runner-loginform-optimized.png) + +
+ +💡 If you need, you can provide additional flags to the test-runner. Read the [documentation](./test-runner.md#cli-options) to learn more. + +
+ +## Automate + +Once you're ready to push your code into a pull request, you'll want to automatically run all your checks using a Continuous Integration (CI) service before merging it. Read our [documentation](./test-runner.md#set-up-ci-to-run-tests) for a detailed guide on setting up a CI environment to run tests. + --- #### What’s the difference between interaction tests and visual tests? @@ -83,8 +155,9 @@ Interaction tests can be expensive to maintain when applied wholesale to every c #### Learn about other UI tests +- [Test runner](./test-runner.md) to automate test execution - [Visual tests](./visual-testing.md) for appearance - [Accessibility tests](accessibility-testing.md) for accessibility - Interaction tests for user behavior simulation - [Snapshot tests](./snapshot-testing.md) for rendering errors and warnings -- [Import stories in other tests](./importing-stories-in-tests.md) for other tools +- [Import stories in other tests](./importing-stories-in-tests.md) for other tools \ No newline at end of file diff --git a/docs/writing-tests/introduction.md b/docs/writing-tests/introduction.md index 776ed827f50d..334a684c9d2d 100644 --- a/docs/writing-tests/introduction.md +++ b/docs/writing-tests/introduction.md @@ -10,10 +10,13 @@ That means stories are a pragmatic starting point for your UI testing strategy. The simplest testing method is manual “spot checking”. You run Storybook locally, then eyeball every story to verify its appearance and behavior. [Publish](../sharing/publish-storybook.md) your Storybook online to share reproductions and get teammates involved. -Storybook also comes with tools, test runners, and handy integrations with the larger JavaScript ecosystem to expand your UI test coverage. These docs detail how you can use Storybook for UI testing. +To test a component in isolation, you often have to mock data, dependencies, or even network requests. Check out our guide on [mocking in Storybook](../writing-stories/build-pages-with-storybook.md#mocking-connected-components) for more info. +Storybook also comes with tools, [a test runner](./test-runner.md), and [handy integrations](./importing-stories-in-tests.md) with the larger JavaScript ecosystem to expand your UI test coverage. These docs detail how you can use Storybook for UI testing. + +- [**Test runner**](./test-runner.md) to automatically test your entire Storybook and catch broken stories. - [**Visual tests**](./visual-testing.md) capture a screenshot of every story then compare it against baselines to detect appearance and integration issues - [**Accessibility tests**](./accessibility-testing.md) catch usability issues related to visual, hearing, mobility, cognitive, speech, or neurological disabilities - [**Interaction tests**](./interaction-testing.md) verify component functionality by simulating user behaviour, firing events, and ensuring that state is updated as expected - [**Snapshot tests**](./snapshot-testing.md) detect changes in the rendered markup to surface rendering errors or warnings -- [**Import stories in other tests**](./importing-stories-in-tests.md) to QA even more UI characteristics +- [**Import stories in other tests**](./importing-stories-in-tests.md) to QA even more UI characteristics \ No newline at end of file diff --git a/docs/writing-tests/jest-accessibility-testing-optimized.png b/docs/writing-tests/jest-accessibility-testing-optimized.png deleted file mode 100644 index b8f3925cb5d6..000000000000 Binary files a/docs/writing-tests/jest-accessibility-testing-optimized.png and /dev/null differ diff --git a/docs/writing-tests/snapshot-testing.md b/docs/writing-tests/snapshot-testing.md index 895b2ffa4b5a..242c1f00885f 100644 --- a/docs/writing-tests/snapshot-testing.md +++ b/docs/writing-tests/snapshot-testing.md @@ -64,7 +64,7 @@ npm i -D @storybook/addon-storyshots-puppeteer puppeteer yarn add @storybook/addon-storyshots-puppeteer puppeteer ``` -Next, update your test file (e.g., `storybook.test.js`) to the following: +Next, update your test file (for example, `storybook.test.js`) to the following: @@ -110,8 +110,9 @@ Visual tests capture images of stories and compare them against image baselines. #### Learn about other UI tests +- [Test runner](./test-runner.md) to automate test execution - [Visual tests](./visual-testing.md) for appearance - [Accessibility tests](./accessibility-testing.md) for accessibility - [Interaction tests](./interaction-testing.md) for user behavior simulation - Snapshot tests for rendering errors and warnings -- [Import stories in other tests](./importing-stories-in-tests.md) for other tools +- [Import stories in other tests](./importing-stories-in-tests.md) for other tools \ No newline at end of file diff --git a/docs/writing-tests/storybook-interaction-test-runner-loginform-optimized.png b/docs/writing-tests/storybook-interaction-test-runner-loginform-optimized.png new file mode 100644 index 000000000000..ce2f360da358 Binary files /dev/null and b/docs/writing-tests/storybook-interaction-test-runner-loginform-optimized.png differ diff --git a/docs/writing-tests/test-runner-a11y-optimized.png b/docs/writing-tests/test-runner-a11y-optimized.png new file mode 100644 index 000000000000..00a937460df2 Binary files /dev/null and b/docs/writing-tests/test-runner-a11y-optimized.png differ diff --git a/docs/writing-tests/test-runner.md b/docs/writing-tests/test-runner.md new file mode 100644 index 000000000000..5502adfbcd15 --- /dev/null +++ b/docs/writing-tests/test-runner.md @@ -0,0 +1,305 @@ +--- +title: 'Test runner' +--- + +Storybook test runner turns all of your stories into executable tests. It is powered by [Jest](https://jestjs.io/) and [Playwright](https://playwright.dev/). + +- For those [without a play function](../writing-stories/introduction.md): it verifies whether the story renders without any errors. +- For those [with a play function](../writing-stories/play-function.md): it also checks for errors in the play function and that all assertions passed. + +These tests run in a live browser and can be executed via the [command line](#cli-options) or your [CI server](#set-up-ci-to-run-tests). + +## Setup + +The test-runner is a standalone, framework-agnostic utility that runs parallel to your Storybook. You will need to take some additional steps to set it up properly. Detailed below is our recommendation to configure and execute it. + +Run the following command to install it and the required dependencies. + + + + + + + +Update your `package.json` scripts and enable the test runner. + +```json +{ + "scripts": { + "test-storybook": "test-storybook" + } +} +``` + +Start your Storybook with: + + + + + + + +
+💡 Storybook's test runner requires either a locally running Storybook instance or a published Storybook to run all the existing tests. +
+ +Finally, open a new terminal window and run the test-runner with: + + + + + + + +## Configure + +Test runner offers zero-config support for Storybook. However, you can run `test-storybook --eject` for more fine-grained control. It generates a `test-runner-jest.config.js` file at the root of your project, which you can modify. Additionally, you can extend the generated configuration file and provide [testEnvironmentOptions](https://github.com/playwright-community/jest-playwright#configuration) as the test runner also uses [jest-playwright](https://github.com/playwright-community/jest-playwright) under the hood. + +### CLI Options + +The test-runner is powered by [Jest](https://jestjs.io/) and accepts a subset of its [CLI options](https://jestjs.io/docs/cli) (for example, `--watch`, `--maxWorkers`). +If you're already using any of those flags in your project, you should be able to migrate them into Storybook's test-runner without any issues. Listed below are all the available flags and examples of using them. + +| Options | Description | +| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| `--help` | Output usage information
`test-storybook --help` | +| `-s`, `--stories-json` | Run in stories json mode. Automatically detected (requires a compatible Storybook)
`test-storybook --stories-json` | +| `--no-stories-json` | Disables stories json mode
`test-storybook --no-stories-json` | +| `-c`, `--config-dir [dir-name]` | Directory where to load Storybook configurations from
`test-storybook -c .storybook` | +| `--watch` | Run in watch mode
`test-storybook --watch` | +| `--url` | Define the URL to run tests in. Useful for custom Storybook URLs
`test-storybook --url http://the-storybook-url-here.com` | +| `--browsers` | Define browsers to run tests in. One or multiple of: chromium, firefox, webkit
`test-storybook --browsers firefox chromium` | +| `--maxWorkers [amount]` | Specifies the maximum number of workers the worker-pool will spawn for running tests
`test-storybook --maxWorkers=2` | +| `--no-cache` | Disable the cache
`test-storybook --no-cache` | +| `--clearCache` | Deletes the Jest cache directory and then exits without running tests
`test-storybook --clearCache` | +| `--verbose` | Display individual test results with the test suite hierarchy
`test-storybook --verbose` | +| `-u`, `--updateSnapshot` | Use this flag to re-record every snapshot that fails during this test run
`test-storybook -u` | +| `--eject` | Creates a local configuration file to override defaults of the test-runner
`test-storybook --eject` | + + + + + + + +### Run tests against a deployed Storybook + +By default, the test-runner assumes that you're running it against a locally served Storybook on port `6006`. If you want to define a target URL to run against deployed Storybooks, you can use the `--url` flag or set the `TARGET_URL` environment variable. For example: + + + + + + + +## Set up CI to run tests + +You can also configure the test-runner to run tests on a CI environment. Documented below are some recipes to help you get started. + +### Run against deployed Storybooks via Github Actions deployment + +If you're publishing your Storybook with services such as [Vercel](https://vercel.com/) or [Netlify](https://www.netlify.com/), they emit a `deployment_status` event in GitHub Actions. You can use it and set the `deployment_status.target_url` as the `TARGET_URL` environment variable. Here's how: + + + + + + + +
+ +💡 The published Storybook must be publicly available for this example to work. We recommend running the test server using the recipe [below](#run-against-non-deployed-storybooks) if it requires authentication. + +
+ +### Run against non-deployed Storybooks + +You can use your CI provider (for example, [GitHub Actions](https://github.com/features/actions), [GitLab Pipelines](https://docs.gitlab.com/ee/ci/pipelines/), [CircleCI](https://circleci.com/)) to build and run the test runner against your built Storybook. Here's a recipe that relies on third-party libraries, that is to say, [concurrently](https://www.npmjs.com/package/concurrently), [http-server](https://www.npmjs.com/package/http-server), and [wait-on](https://www.npmjs.com/package/wait-on) to build Storybook and run tests with the test-runner. + + + + + + + +
+ +💡 By default Storybook outputs the [build](../sharing/publish-storybook.md#build-storybook-as-a-static-web-application) to the `storybook-static` directory. If you're using a different build directory, you'll need to adjust the recipe accordingly. + +
+ +### What's the difference between Chromatic and Test runner? + +The test-runner is a generic testing tool that can run locally or on CI and be configured or extended to run all kinds of tests. + +[Chromatic](https://www.chromatic.com/) is a cloud-based service that runs [visual](./visual-testing.md) and [interaction tests](./interaction-testing.md) (and soon accessibility tests) without setting up the test runner. It also syncs with your git provider and manages access control for private projects. + +However, you might want to pair the test runner and Chromatic in some cases. + +- Use it locally and Chromatic on your CI. +- Use Chromatic for visual and interaction tests and run other custom tests using the test runner. + +## Advanced configuration + +### Test hook API (experimental) + +The test-runner renders a story and executes its [play function](../writing-stories/play-function.md) if one exists. However, certain behaviors are impossible to achieve via the play function, which executes in the browser. For example, if you want the test-runner to take visual snapshots for you, this is possible via Playwright/Jest but must be executed in Node. + +The test-runner exports test hooks that can be overridden globally to enable use cases like visual or DOM snapshots. These hooks give you access to the test lifecycle _before_ and _after_ the story is rendered. +Listed below are the available hooks and an overview of how to use them. + +| Hook | Description | +| ------------ | ----------------------------------------------------------------------------- | +| `setup` | Executes once before all the tests run
`setup() {}` | +| `preRender` | Executes before a story is rendered
`async preRender(page, context) {}` | +| `postRender` | Executes after the story is rendered
`async postRender(page, context) {}` | + +
+ +💡 These test hooks are experimental and may be subject to breaking changes. We encourage you to test as much as possible within the story's [play function](../writing-stories/play-function.md). + +
+ +To enable the hooks API, you'll need to add a new configuration file inside your Storybook directory and set them up as follows: + + + + + + + +
+ +💡 Except for the `setup` function, all other functions run asynchronously. Both `preRender` and `postRender` functions include two additional arguments, a [Playwright page](https://playwright.dev/docs/pages) and a context object which contains the `id`, `title`, and the `name` of the story. + +
+ +When the test-runner executes, your existing tests will go through the following lifecycle: + +- The `setup` function is executed before all the tests run. +- The context object is generated containing the required information. +- Playwright navigates to the story's page. +- The `preRender` function is executed. +- The story is rendered, and any existing `play` functions are executed. +- The `postRender` function is executed. + +### Stories.json mode + +The test-runner transforms your story files into tests when testing a local Storybook. For a remote Storybook, it uses the Storybook's [stories.json](../configure/overview.md#feature-flags) file (a static index of all the stories) to run the tests. + +#### Why? + +Suppose you run into a situation where the local and remote Storybooks appear out of sync, or you might not even have access to the code. In that case, the `stories.json` file is guaranteed to be the most accurate representation of the deployed Storybook you are testing. To test a local Storybook using this feature, use the `--stories-json` flag as follows: + + + + + + + +
+ +💡 The `stories.json` mode is not compatible with watch mode. + +
+ +If you need to disable it, use the `--no-stories-json` flag: + + + + + + + +#### How do I check if my Storybook has a `stories.json` file? + +Stories.json mode requires a `stories.json` file. Open a browser window and navigate to your deployed Storybook instance (for example, `https://your-storybook-url-here.com/stories.json`). You should see a JSON file that starts with a `"v": 3` key, immediately followed by another key called "stories", which contains a map of story IDs to JSON objects. If that is the case, your Storybook supports [stories.json mode](../configure/overview.md#feature-flags). + +--- + +## Troubleshooting + +### The test runner seems flaky and keeps timing out + +If your tests time out with the following message: + +```shell +Timeout - Async callback was not invoked within the 15000 ms timeout specified by jest.setTimeout +``` + +It might be that Playwright couldn't handle testing the number of stories you have in your project. Perhaps you have a large number of stories, or your CI environment has a really low RAM configuration. In such cases, you should limit the number of workers that run in parallel by adjusting your command as follows: + +```json +{ + "scripts": { + "test-storybook:ci": "yarn test-storybook --maxWorkers=2" + } +} +``` + +### The error output in the CLI is too short + +By default, the test runner truncates error outputs at 1000 characters, and you can check the full output directly in Storybook in the browser. However, if you want to change that limit, you can do so by setting the `DEBUG_PRINT_LIMIT` environment variable to a number of your choosing, for example, `DEBUG_PRINT_LIMIT=5000 yarn test-storybook`. + +### Run the test runner in other CI environments + +As the test runner is based on Playwright, you might need to use specific docker images or other configurations depending on your CI setup. In that case, you can refer to the [Playwright CI docs](https://playwright.dev/docs/ci) for more information. + +#### Learn about other UI tests + +- Test runner to automate test execution +- [Visual tests](./visual-testing.md) for appearance +- [Accessibility tests](./accessibility-testing.md) for accessibility +- [Interaction tests](./interaction-testing.md) for user behavior simulation +- [Snapshot tests](./snapshot-testing.md) for rendering errors and warnings +- [Import stories in other tests](./importing-stories-in-tests.md) for other tools \ No newline at end of file diff --git a/docs/writing-tests/visual-testing.md b/docs/writing-tests/visual-testing.md index 8ead581bbe4c..a5336a3854a0 100644 --- a/docs/writing-tests/visual-testing.md +++ b/docs/writing-tests/visual-testing.md @@ -50,7 +50,7 @@ View it online at https://www.chromatic.com/build?appId=...&number=1. 💡 Before running Chromatic's CLI ensure you have at least two commits added to the repository to prevent build failures, as Chromatic relies on a full Git history graph to establish the baselines. Read more about baselines in Chromatic's documentation
-When Chromatic finishes, it should have successfully deployed your Storybook and established the baselines (i.e., starting point) for all your component's stories. Additionally, providing you with a link to the published Storybook that you can share with your team to gather feedback. +When Chromatic finishes, it should have successfully deployed your Storybook and established the baselines, that is to say, the starting point for all your component's stories. Additionally, providing you with a link to the published Storybook that you can share with your team to gather feedback. ![Chromatic project first build](./chromatic-first-build-optimized.png) @@ -74,8 +74,9 @@ Snapshot tests compare the rendered markup of every story against known baseline #### Learn about other UI tests +- [Test runner](./test-runner.md) to automate test execution - Visual tests for appearance - [Accessibility tests](./accessibility-testing.md) for accessibility - [Interaction tests](./interaction-testing.md) for user behavior simulation - [Snapshot tests](./snapshot-testing.md) for rendering errors and warnings -- [Import stories in other tests](./importing-stories-in-tests.md) for other tools +- [Import stories in other tests](./importing-stories-in-tests.md) for other tools \ No newline at end of file diff --git a/examples/angular-cli/.storybook/main.js b/examples/angular-cli/.storybook/main.js index 8af67f228e3b..5b3bd5b5bcce 100644 --- a/examples/angular-cli/.storybook/main.js +++ b/examples/angular-cli/.storybook/main.js @@ -16,6 +16,7 @@ module.exports = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, angularOptions: { enableIvy: true, diff --git a/examples/angular-cli/package.json b/examples/angular-cli/package.json index ee505cf78f77..cd872e88dd2b 100644 --- a/examples/angular-cli/package.json +++ b/examples/angular-cli/package.json @@ -1,6 +1,6 @@ { "name": "angular-cli", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "license": "MIT", "scripts": { @@ -39,21 +39,21 @@ "@angular/compiler-cli": "^11.2.14", "@angular/elements": "^11.2.14", "@compodoc/compodoc": "^1.1.18", - "@storybook/addon-a11y": "6.5.0-alpha.52", - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-backgrounds": "6.5.0-alpha.52", - "@storybook/addon-controls": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", - "@storybook/addon-interactions": "6.5.0-alpha.52", - "@storybook/addon-jest": "6.5.0-alpha.52", - "@storybook/addon-links": "6.5.0-alpha.52", - "@storybook/addon-storyshots": "6.5.0-alpha.52", - "@storybook/addon-storysource": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/angular": "6.5.0-alpha.52", + "@storybook/addon-a11y": "6.5.0-beta.7", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-backgrounds": "6.5.0-beta.7", + "@storybook/addon-controls": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", + "@storybook/addon-interactions": "6.5.0-beta.7", + "@storybook/addon-jest": "6.5.0-beta.7", + "@storybook/addon-links": "6.5.0-beta.7", + "@storybook/addon-storyshots": "6.5.0-beta.7", + "@storybook/addon-storysource": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/angular": "6.5.0-beta.7", "@storybook/babel-plugin-require-context-hook": "1.0.1", "@storybook/jest": "^0.0.5", - "@storybook/source-loader": "6.5.0-alpha.52", + "@storybook/source-loader": "6.5.0-beta.7", "@storybook/testing-library": "^0.0.7", "@types/core-js": "^2.5.4", "@types/jest": "^26.0.16", diff --git a/examples/cra-kitchen-sink/.storybook/main.js b/examples/cra-kitchen-sink/.storybook/main.js index 486f57474131..6d285cb4917a 100644 --- a/examples/cra-kitchen-sink/.storybook/main.js +++ b/examples/cra-kitchen-sink/.storybook/main.js @@ -32,6 +32,7 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], features: { diff --git a/examples/cra-kitchen-sink/package.json b/examples/cra-kitchen-sink/package.json index 4ebed6868a09..5eb92f17d1d8 100644 --- a/examples/cra-kitchen-sink/package.json +++ b/examples/cra-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "cra-kitchen-sink", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "scripts": { "build": "react-scripts build", @@ -11,7 +11,7 @@ "test": "react-scripts test --env=jsdom" }, "dependencies": { - "@storybook/client-logger": "6.5.0-alpha.52", + "@storybook/client-logger": "6.5.0-beta.7", "global": "^4.4.0", "prop-types": "^15.7.2", "react": "16.14.0", @@ -21,19 +21,19 @@ }, "devDependencies": { "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@storybook/addon-a11y": "6.5.0-alpha.52", - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-backgrounds": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", + "@storybook/addon-a11y": "6.5.0-beta.7", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-backgrounds": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", "@storybook/addon-ie11": "0.0.7--canary.5e87b64.0", - "@storybook/addon-jest": "6.5.0-alpha.52", - "@storybook/addon-links": "6.5.0-alpha.52", - "@storybook/addon-storyshots": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/builder-webpack4": "6.5.0-alpha.52", + "@storybook/addon-jest": "6.5.0-beta.7", + "@storybook/addon-links": "6.5.0-beta.7", + "@storybook/addon-storyshots": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/builder-webpack4": "6.5.0-beta.7", "@storybook/preset-create-react-app": "^3.1.6", - "@storybook/react": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/react": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "webpack": "4" }, "storybook": { diff --git a/examples/cra-react15/.storybook/main.js b/examples/cra-react15/.storybook/main.js index 76fdcb43fa94..1f0d64a52bdf 100644 --- a/examples/cra-react15/.storybook/main.js +++ b/examples/cra-react15/.storybook/main.js @@ -20,6 +20,7 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], }; diff --git a/examples/cra-react15/package.json b/examples/cra-react15/package.json index 0d67c14b3d0f..ec7dbc8186f8 100644 --- a/examples/cra-react15/package.json +++ b/examples/cra-react15/package.json @@ -1,6 +1,6 @@ { "name": "cra-react15", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "scripts": { "build": "react-scripts build", @@ -19,14 +19,14 @@ "react-scripts": "3.4.4" }, "devDependencies": { - "@storybook/addon-actions": "6.5.0-alpha.52", + "@storybook/addon-actions": "6.5.0-beta.7", "@storybook/addon-ie11": "0.0.7--canary.5e87b64.0", - "@storybook/addon-links": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/builder-webpack4": "6.5.0-alpha.52", + "@storybook/addon-links": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/builder-webpack4": "6.5.0-beta.7", "@storybook/preset-create-react-app": "^3.1.6", - "@storybook/react": "6.5.0-alpha.52", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/react": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "babel-core": "6", "babel-runtime": "6", "webpack": "4" diff --git a/examples/cra-ts-essentials/.storybook/main.js b/examples/cra-ts-essentials/.storybook/main.ts similarity index 71% rename from examples/cra-ts-essentials/.storybook/main.js rename to examples/cra-ts-essentials/.storybook/main.ts index 97a4e0a2b0ff..651ca6c6bc74 100644 --- a/examples/cra-ts-essentials/.storybook/main.js +++ b/examples/cra-ts-essentials/.storybook/main.ts @@ -1,6 +1,8 @@ +import type { StorybookConfig } from '@storybook/react/types'; + const path = require('path'); -module.exports = { +const mainConfig: StorybookConfig = { stories: ['../src/**/*.stories.@(tsx|mdx)'], addons: [ '@storybook/preset-create-react-app', @@ -13,9 +15,9 @@ module.exports = { }, ], logLevel: 'debug', - webpackFinal: (config) => { + webpackFinal: async (config) => { // add monorepo root as a valid directory to import modules from - config.resolve.plugins.forEach((p) => { + config.resolve?.plugins?.forEach((p: any) => { if (Array.isArray(p.appSrcs)) { p.appSrcs.push(path.join(__dirname, '..', '..', '..')); } @@ -24,9 +26,12 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], features: { buildStoriesJson: true, }, }; + +module.exports = mainConfig; diff --git a/examples/cra-ts-essentials/.storybook/preview.js b/examples/cra-ts-essentials/.storybook/preview.js deleted file mode 100644 index 305c8eb0be14..000000000000 --- a/examples/cra-ts-essentials/.storybook/preview.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; - -export const decorators = [ - (StoryFn, { globals: { locale = 'en' } }) => ( - <> -
{locale}
- - - ), -]; - -export const globalTypes = { - locale: { - name: 'Locale', - description: 'Internationalization locale', - defaultValue: 'en', - toolbar: { - icon: 'globe', - items: [ - { value: 'en', right: '🇺🇸', title: 'English' }, - { value: 'es', right: '🇪🇸', title: 'Español' }, - { value: 'zh', right: '🇨🇳', title: '中文' }, - { value: 'kr', right: '🇰🇷', title: '한국어' }, - ], - }, - }, -}; diff --git a/examples/cra-ts-essentials/.storybook/preview.tsx b/examples/cra-ts-essentials/.storybook/preview.tsx new file mode 100644 index 000000000000..2fdf6346b211 --- /dev/null +++ b/examples/cra-ts-essentials/.storybook/preview.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import type { DecoratorFn } from '@storybook/react'; +import { ThemeProvider, convert, themes } from '@storybook/theming'; + +export const decorators: DecoratorFn[] = [ + (StoryFn, { globals: { locale } }) => ( + <> +
Locale: {locale}
+ + + ), + (StoryFn) => ( + + + + ), +]; + +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, +}; + +export const globalTypes = { + locale: { + name: 'Locale', + description: 'Internationalization locale', + defaultValue: 'en', + toolbar: { + dynamicTitle: true, + icon: 'globe', + items: [ + { value: 'en', right: '🇺🇸', title: 'English' }, + { value: 'es', right: '🇪🇸', title: 'Español' }, + { value: 'zh', right: '🇨🇳', title: '中文' }, + { value: 'kr', right: '🇰🇷', title: '한국어' }, + ], + }, + }, + theme: { + name: 'Theme', + description: 'Global theme for components', + toolbar: { + dynamicTitle: true, + icon: 'circlehollow', + title: 'Theme', + items: [ + { value: 'light', icon: 'circlehollow', title: 'Light' }, + { value: 'dark', icon: 'circle', title: 'Dark' }, + { value: 'side-by-side', icon: 'sidebar', title: 'Side by side' }, + { value: 'stacked', icon: 'bottombar', title: 'Stacked' }, + ], + }, + }, +}; diff --git a/examples/cra-ts-essentials/package.json b/examples/cra-ts-essentials/package.json index 192ed77b03f5..411b05ca4168 100644 --- a/examples/cra-ts-essentials/package.json +++ b/examples/cra-ts-essentials/package.json @@ -1,6 +1,6 @@ { "name": "cra-ts-essentials", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "scripts": { "build": "react-scripts build", @@ -8,7 +8,7 @@ "eject": "react-scripts eject", "start": "react-scripts start", "storybook": "start-storybook -p 9009 --no-manager-cache", - "test": "react-scripts test" + "test": "SKIP_PREFLIGHT_CHECK=true react-scripts test" }, "browserslist": { "production": [ @@ -23,10 +23,13 @@ ] }, "dependencies": { + "@storybook/components": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", "@types/jest": "^26.0.16", "@types/node": "^14.14.20 || ^16.0.0", "@types/react": "^16.14.23", - "@types/react-dom": "^16.9.14", + "@types/react-dom": "16.9.14", + "formik": "2.2.9", "global": "^4.4.0", "react": "16.14.0", "react-dom": "16.14.0", @@ -34,12 +37,13 @@ "typescript": "^3.9.7" }, "devDependencies": { - "@storybook/addon-essentials": "6.5.0-alpha.52", + "@storybook/addon-essentials": "6.5.0-beta.7", "@storybook/addon-ie11": "0.0.7--canary.5e87b64.0", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/builder-webpack4": "6.5.0-alpha.52", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/builder-webpack4": "6.5.0-beta.7", "@storybook/preset-create-react-app": "^3.1.6", - "@storybook/react": "6.5.0-alpha.52", + "@storybook/react": "6.5.0-beta.7", + "@storybook/testing-library": "^0.0.9", "webpack": "4" }, "storybook": { diff --git a/examples/cra-ts-essentials/src/setupTests.ts b/examples/cra-ts-essentials/src/setupTests.ts new file mode 100644 index 000000000000..e65a5923ef0f --- /dev/null +++ b/examples/cra-ts-essentials/src/setupTests.ts @@ -0,0 +1,4 @@ +import { setProjectAnnotations } from '@storybook/react'; +import * as projectAnnotations from '../.storybook/preview'; + +setProjectAnnotations(projectAnnotations); diff --git a/examples/cra-ts-essentials/src/stories/0-Welcome.stories.tsx b/examples/cra-ts-essentials/src/stories/0-Welcome.stories.tsx index 9920a416e1ff..ec39dbbe4813 100644 --- a/examples/cra-ts-essentials/src/stories/0-Welcome.stories.tsx +++ b/examples/cra-ts-essentials/src/stories/0-Welcome.stories.tsx @@ -1,12 +1,15 @@ import React from 'react'; import { linkTo } from '@storybook/addon-links'; import { Welcome } from '@storybook/react/demo'; +import type { ComponentMeta, ComponentStory } from '@storybook/react'; export default { title: 'Welcome', component: Welcome, -}; +} as ComponentMeta; -export const ToStorybook = () => ; +export const ToStorybook: ComponentStory = () => ( + +); ToStorybook.storyName = 'to Storybook'; diff --git a/examples/cra-ts-essentials/src/stories/1-Button.stories.tsx b/examples/cra-ts-essentials/src/stories/1-Button.stories.tsx index e952509a9012..c3d83e4544a7 100644 --- a/examples/cra-ts-essentials/src/stories/1-Button.stories.tsx +++ b/examples/cra-ts-essentials/src/stories/1-Button.stories.tsx @@ -1,13 +1,14 @@ import React from 'react'; import { Button } from '@storybook/react/demo'; +import type { ComponentStory, ComponentMeta } from '@storybook/react'; export default { title: 'Button', component: Button, argTypes: { onClick: { action: 'clicked' } }, -}; +} as ComponentMeta; -const Template = (args: any) => ; +}; +CSF2StoryWithLocale.storyName = 'WithLocale'; + +export const CSF2StoryWithParamsAndDecorator: CSF2Story = (args) => { + return + ); +}; diff --git a/examples/cra-ts-essentials/src/stories/testing-react/components/__snapshots__/internals.test.tsx.snap b/examples/cra-ts-essentials/src/stories/testing-react/components/__snapshots__/internals.test.tsx.snap new file mode 100644 index 000000000000..dd0a3d4183fb --- /dev/null +++ b/examples/cra-ts-essentials/src/stories/testing-react/components/__snapshots__/internals.test.tsx.snap @@ -0,0 +1,127 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Renders CSF2Secondary story 1`] = ` + +
+
+ Locale: + en +
+ +
+ +`; + +exports[`Renders CSF2StoryWithLocale story 1`] = ` + +
+
+ Locale: + en +
+ +
+ +`; + +exports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = ` + +
+
+ Locale: + en +
+ +
+ +`; + +exports[`Renders CSF3Button story 1`] = ` + +
+
+ Locale: + en +
+ +
+ +`; + +exports[`Renders CSF3ButtonWithRender story 1`] = ` + +
+
+ Locale: + en +
+
+

+ I am a custom render function +

+ +
+
+ +`; + +exports[`Renders CSF3InputFieldFilled story 1`] = ` + +
+
+ Locale: + en +
+ +
+ +`; + +exports[`Renders CSF3Primary story 1`] = ` + +
+
+ Locale: + en +
+ +
+ +`; diff --git a/examples/cra-ts-essentials/src/stories/testing-react/components/button.css b/examples/cra-ts-essentials/src/stories/testing-react/components/button.css new file mode 100644 index 000000000000..dc91dc76370b --- /dev/null +++ b/examples/cra-ts-essentials/src/stories/testing-react/components/button.css @@ -0,0 +1,30 @@ +.storybook-button { + font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: 700; + border: 0; + border-radius: 3em; + cursor: pointer; + display: inline-block; + line-height: 1; +} +.storybook-button--primary { + color: white; + background-color: #1ea7fd; +} +.storybook-button--secondary { + color: #333; + background-color: transparent; + box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; +} +.storybook-button--small { + font-size: 12px; + padding: 10px 16px; +} +.storybook-button--medium { + font-size: 14px; + padding: 11px 20px; +} +.storybook-button--large { + font-size: 16px; + padding: 12px 24px; +} diff --git a/examples/cra-ts-essentials/src/stories/testing-react/components/internals.test.tsx b/examples/cra-ts-essentials/src/stories/testing-react/components/internals.test.tsx new file mode 100644 index 000000000000..5fbdae1697d0 --- /dev/null +++ b/examples/cra-ts-essentials/src/stories/testing-react/components/internals.test.tsx @@ -0,0 +1,100 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import React from 'react'; +import addons from '@storybook/addons'; +import { render, screen } from '@testing-library/react'; + +import { composeStories, composeStory } from '@storybook/react'; + +import * as stories from './Button.stories'; + +import * as globalConfig from '../../../../.storybook/preview'; + +const { CSF2StoryWithParamsAndDecorator } = composeStories(stories); + +test('returns composed args including default values from argtypes', () => { + expect(CSF2StoryWithParamsAndDecorator.args).toEqual({ + ...stories.CSF2StoryWithParamsAndDecorator.args, + label: stories.default.argTypes!.label!.defaultValue, + }); +}); + +test('returns composed parameters from story', () => { + expect(CSF2StoryWithParamsAndDecorator.parameters).toEqual( + expect.objectContaining({ + ...stories.CSF2StoryWithParamsAndDecorator.parameters, + ...globalConfig.parameters, + }) + ); +}); + +// common in addons that need to communicate between manager and preview +test('should pass with decorators that need addons channel', () => { + const PrimaryWithChannels = composeStory(stories.CSF3Primary, stories.default, { + decorators: [ + (StoryFn: any) => { + addons.getChannel(); + return ; + }, + ], + }); + render(Hello world); + const buttonElement = screen.getByText(/Hello world/i); + expect(buttonElement).not.toBeNull(); +}); + +describe('Unsupported formats', () => { + test('should throw error if story is undefined', () => { + const UnsupportedStory = () =>
hello world
; + UnsupportedStory.story = { parameters: {} }; + + const UnsupportedStoryModule: any = { + default: {}, + UnsupportedStory: undefined, + }; + + expect(() => { + composeStories(UnsupportedStoryModule); + }).toThrow(); + }); +}); + +describe('non-story exports', () => { + test('should filter non-story exports with excludeStories', () => { + const StoryModuleWithNonStoryExports = { + default: { + title: 'Some/Component', + excludeStories: /.*Data/, + }, + LegitimateStory: () =>
hello world
, + mockData: {}, + }; + + const result = composeStories(StoryModuleWithNonStoryExports); + expect(Object.keys(result)).not.toContain('mockData'); + }); + + test('should filter non-story exports with includeStories', () => { + const StoryModuleWithNonStoryExports = { + default: { + title: 'Some/Component', + includeStories: /.*Story/, + }, + LegitimateStory: () =>
hello world
, + mockData: {}, + }; + + const result = composeStories(StoryModuleWithNonStoryExports); + expect(Object.keys(result)).not.toContain('mockData'); + }); +}); + +// Batch snapshot testing +const testCases = Object.values(composeStories(stories)).map((Story) => [ + // The ! is necessary in Typescript only, as the property is part of a partial type + Story.storyName!, + Story, +]); +test.each(testCases)('Renders %s story', async (_storyName, Story) => { + const tree = await render(); + expect(tree.baseElement).toMatchSnapshot(); +}); diff --git a/examples/cra-ts-essentials/tsconfig.json b/examples/cra-ts-essentials/tsconfig.json index 450e0014a4ea..4e81ac32da5f 100644 --- a/examples/cra-ts-essentials/tsconfig.json +++ b/examples/cra-ts-essentials/tsconfig.json @@ -6,7 +6,7 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true, "jsx": "react", - "module": "commonjs", + "module": "esnext", "skipLibCheck": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, @@ -18,9 +18,17 @@ "lib": [ "es2017", "dom" - ] + ], + "allowJs": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true }, "include": [ "src" ] -} \ No newline at end of file +} diff --git a/examples/cra-ts-kitchen-sink/.storybook/localAddon/register.tsx b/examples/cra-ts-kitchen-sink/.storybook/localAddon/manager.tsx similarity index 100% rename from examples/cra-ts-kitchen-sink/.storybook/localAddon/register.tsx rename to examples/cra-ts-kitchen-sink/.storybook/localAddon/manager.tsx diff --git a/examples/cra-ts-kitchen-sink/.storybook/main.ts b/examples/cra-ts-kitchen-sink/.storybook/main.ts index 048a7f5cefae..2c81ab345cf0 100644 --- a/examples/cra-ts-kitchen-sink/.storybook/main.ts +++ b/examples/cra-ts-kitchen-sink/.storybook/main.ts @@ -12,7 +12,7 @@ module.exports = { '@storybook/addon-actions', '@storybook/addon-links', '@storybook/addon-a11y', - './localAddon/register.tsx', + './localAddon/manager.tsx', './localAddon/preset.ts', ], webpackFinal: (config: Configuration) => { @@ -28,6 +28,7 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], features: { diff --git a/examples/cra-ts-kitchen-sink/package.json b/examples/cra-ts-kitchen-sink/package.json index 587cb509df51..0a29c42afb29 100644 --- a/examples/cra-ts-kitchen-sink/package.json +++ b/examples/cra-ts-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "cra-ts-kitchen-sink", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "scripts": { "build": "react-scripts build", @@ -34,15 +34,15 @@ "typescript": "^3.9.7" }, "devDependencies": { - "@storybook/addon-a11y": "6.5.0-alpha.52", - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", + "@storybook/addon-a11y": "6.5.0-beta.7", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", "@storybook/addon-ie11": "0.0.7--canary.5e87b64.0", - "@storybook/addon-links": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/builder-webpack4": "6.5.0-alpha.52", + "@storybook/addon-links": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/builder-webpack4": "6.5.0-beta.7", "@storybook/preset-create-react-app": "^3.1.6", - "@storybook/react": "6.5.0-alpha.52", + "@storybook/react": "6.5.0-beta.7", "@types/enzyme": "^3.10.8", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.9.1", diff --git a/examples/ember-cli/.storybook/main.js b/examples/ember-cli/.storybook/main.js index c58025c3fd1c..071ec0e45ae4 100644 --- a/examples/ember-cli/.storybook/main.js +++ b/examples/ember-cli/.storybook/main.js @@ -28,6 +28,7 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../ember-output'], features: { diff --git a/examples/ember-cli/package.json b/examples/ember-cli/package.json index fcff35aa5dec..bfccd912a416 100644 --- a/examples/ember-cli/package.json +++ b/examples/ember-cli/package.json @@ -1,6 +1,6 @@ { "name": "ember-example", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "scripts": { "build": "ember build --output-path ember-output", @@ -17,18 +17,18 @@ "devDependencies": { "@babel/core": "^7.12.10", "@ember/optional-features": "^2.0.0", - "@storybook/addon-a11y": "6.5.0-alpha.52", - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-backgrounds": "6.5.0-alpha.52", - "@storybook/addon-controls": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", - "@storybook/addon-links": "6.5.0-alpha.52", - "@storybook/addon-storysource": "6.5.0-alpha.52", - "@storybook/addon-viewport": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/ember": "6.5.0-alpha.52", + "@storybook/addon-a11y": "6.5.0-beta.7", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-backgrounds": "6.5.0-beta.7", + "@storybook/addon-controls": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", + "@storybook/addon-links": "6.5.0-beta.7", + "@storybook/addon-storysource": "6.5.0-beta.7", + "@storybook/addon-viewport": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/ember": "6.5.0-beta.7", "@storybook/ember-cli-storybook": "^0.2.1", - "@storybook/source-loader": "6.5.0-alpha.52", + "@storybook/source-loader": "6.5.0-beta.7", "babel-loader": "^8.0.0", "broccoli-asset-rev": "^3.0.0", "cross-env": "^7.0.3", diff --git a/examples/external-docs/.babelrc b/examples/external-docs/.babelrc new file mode 100644 index 000000000000..202d425a099e --- /dev/null +++ b/examples/external-docs/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-typescript" + ] +} diff --git a/examples/external-docs/README.md b/examples/external-docs/README.md new file mode 100644 index 000000000000..5fe025e663f0 --- /dev/null +++ b/examples/external-docs/README.md @@ -0,0 +1,3 @@ +# Storybook External Docs Example + +This example demostrates using Stories in an app built outside of SB's build process. diff --git a/examples/external-docs/package.json b/examples/external-docs/package.json new file mode 100644 index 000000000000..40a7d6f1682e --- /dev/null +++ b/examples/external-docs/package.json @@ -0,0 +1,39 @@ +{ + "name": "@storybook/external-docs", + "version": "6.5.0-beta.7", + "private": true, + "scripts": { + "build-storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true build-storybook -c ./src/.storybook", + "debug": "cross-env NODE_OPTIONS=--inspect-brk STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011", + "sb": "node ../../lib/cli/bin/index.js", + "start": "SKIP_PREFLIGHT_CHECK=true react-scripts start", + "storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 --no-manager-cache -c ./src/.storybook" + }, + "dependencies": { + "@storybook/addon-essentials": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/preview-web": "6.5.0-beta.7", + "@storybook/react": "6.5.0-beta.7", + "@storybook/store": "6.5.0-beta.7", + "@storybook/theming": "6.5.0-beta.7", + "formik": "^2.2.9", + "prop-types": "15.7.2", + "react": "16.14.0", + "react-dom": "16.14.0", + "react-scripts": "^4.0.2" + }, + "devDependencies": { + "@babel/preset-env": "^7.12.11", + "@babel/preset-react": "^7.12.10", + "@babel/preset-typescript": "^7.12.7", + "@testing-library/dom": "^7.31.2", + "@testing-library/user-event": "^13.1.9", + "@types/babel__preset-env": "^7", + "@types/react": "^16.14.23", + "@types/react-dom": "^16.9.14", + "cross-env": "^7.0.3", + "typescript": "^3.9.7", + "webpack": "4" + } +} diff --git a/examples/external-docs/public/favicon.ico b/examples/external-docs/public/favicon.ico new file mode 100644 index 000000000000..c2c86b859eaa Binary files /dev/null and b/examples/external-docs/public/favicon.ico differ diff --git a/examples/external-docs/public/index.html b/examples/external-docs/public/index.html new file mode 100644 index 000000000000..c240d2ca8b0f --- /dev/null +++ b/examples/external-docs/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/examples/external-docs/public/logo192.png b/examples/external-docs/public/logo192.png new file mode 100644 index 000000000000..fbdb05d4eb6b Binary files /dev/null and b/examples/external-docs/public/logo192.png differ diff --git a/examples/external-docs/public/logo512.png b/examples/external-docs/public/logo512.png new file mode 100644 index 000000000000..917458c29a82 Binary files /dev/null and b/examples/external-docs/public/logo512.png differ diff --git a/examples/external-docs/public/manifest.json b/examples/external-docs/public/manifest.json new file mode 100644 index 000000000000..080d6c77ac21 --- /dev/null +++ b/examples/external-docs/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/examples/external-docs/public/robots.txt b/examples/external-docs/public/robots.txt new file mode 100644 index 000000000000..01b0f9a10733 --- /dev/null +++ b/examples/external-docs/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/examples/external-docs/src/.storybook/main.ts b/examples/external-docs/src/.storybook/main.ts new file mode 100644 index 000000000000..0465288c69ca --- /dev/null +++ b/examples/external-docs/src/.storybook/main.ts @@ -0,0 +1,34 @@ +import type { StorybookConfig } from '@storybook/react/types'; + +const config: StorybookConfig = { + stories: [ + { + directory: '../components', + titlePrefix: 'Demo', + }, + ], + logLevel: 'debug', + addons: ['@storybook/addon-essentials'], + typescript: { + check: true, + checkOptions: {}, + reactDocgenTypescriptOptions: { + propFilter: (prop) => ['label', 'disabled'].includes(prop.name), + }, + }, + core: { + builder: { name: 'webpack4' }, + channelOptions: { allowFunction: false, maxDepth: 10 }, + }, + features: { + postcss: false, + // modernInlineRender: true, + storyStoreV7: !global.navigator?.userAgent?.match?.('jsdom'), + buildStoriesJson: true, + babelModeV7: true, + warnOnLegacyHierarchySeparator: false, + previewMdx2: true, + }, + framework: '@storybook/react', +}; +module.exports = config; diff --git a/examples/react-ts/.storybook/preview.js b/examples/external-docs/src/.storybook/preview.js similarity index 100% rename from examples/react-ts/.storybook/preview.js rename to examples/external-docs/src/.storybook/preview.js diff --git a/examples/external-docs/src/SecondStoriesPage.tsx b/examples/external-docs/src/SecondStoriesPage.tsx new file mode 100644 index 000000000000..e3b3bc3c2014 --- /dev/null +++ b/examples/external-docs/src/SecondStoriesPage.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { DocsProvider, Meta, Story } from './blocks'; + +import meta, { Standard } from './components/AccountForm.stories'; + +export default () => ( + +
+ + + +
+
+); diff --git a/examples/external-docs/src/StoriesPage.tsx b/examples/external-docs/src/StoriesPage.tsx new file mode 100644 index 000000000000..75cd6b9126c8 --- /dev/null +++ b/examples/external-docs/src/StoriesPage.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { DocsProvider, Meta, Story } from './blocks'; + +import meta, { WithArgs, Basic } from './components/button.stories'; +import EmojiMeta, { WithArgs as EmojiWithArgs } from './components/emoji-button.stories'; + +export default () => ( + +
+ + + + + + +
+
+); diff --git a/examples/external-docs/src/blocks.tsx b/examples/external-docs/src/blocks.tsx new file mode 100644 index 000000000000..9a4281a209d7 --- /dev/null +++ b/examples/external-docs/src/blocks.tsx @@ -0,0 +1,171 @@ +import React, { createContext, useContext, useRef, useEffect } from 'react'; + +import { Preview } from '@storybook/preview-web'; +import { Path, ModuleExports, StoryIndex } from '@storybook/store'; +import { toId, AnyFramework, ComponentTitle, StoryId } from '@storybook/csf'; + +// @ts-ignore +import * as reactAnnotations from '@storybook/react/dist/esm/client/preview/config'; +// @ts-ignore +import * as previewAnnotations from './.storybook/preview'; + +type StoryExport = any; +type MetaExport = any; +type ExportName = string; + +const projectAnnotations = { + ...reactAnnotations, + ...previewAnnotations, +}; + +const DocsContext = createContext<{ + setMeta: (meta: MetaExport) => void; + addStory: (story: StoryExport, storyMeta?: MetaExport) => void; + renderStory: (story: StoryExport, element: HTMLElement) => void; +}>({ + setMeta: () => {}, + addStory: () => {}, + renderStory: () => {}, +}); + +export const DocsProvider: React.FC = ({ children }) => { + let pageMeta: MetaExport; + const setMeta = (m: MetaExport) => { + pageMeta = m; + }; + + let nextImportPath = 0; + const importPaths = new Map(); + const getImportPath = (meta: MetaExport) => { + if (!importPaths.has(meta)) { + importPaths.set(meta, `importPath-${nextImportPath}`); + nextImportPath += 1; + } + return importPaths.get(meta) as Path; + }; + + let nextTitle = 0; + const titles = new Map(); + const getTitle = (meta: MetaExport) => { + if (!titles.has(meta)) { + titles.set(meta, `title-${nextTitle}`); + nextTitle += 1; + } + return titles.get(meta); + }; + + let nextExportName = 0; + const exportNames = new Map(); + const getExportName = (story: StoryExport) => { + if (!exportNames.has(story)) { + exportNames.set(story, `export-${nextExportName}`); + nextExportName += 1; + } + return exportNames.get(story) as ExportName; + }; + + const storyIds = new Map(); + + const storyIndex: StoryIndex = { v: 3, stories: {} }; + const knownCsfFiles: Record = {}; + + const addStory = (storyExport: StoryExport, storyMeta?: MetaExport) => { + const meta = storyMeta || pageMeta; + const importPath: Path = getImportPath(meta); + const title: ComponentTitle = meta.title || getTitle(meta); + + const exportName = getExportName(storyExport); + const storyId = toId(title, exportName); + storyIds.set(storyExport, storyId); + + if (!knownCsfFiles[importPath]) { + knownCsfFiles[importPath] = { + default: meta, + }; + } + knownCsfFiles[importPath][exportName] = storyExport; + + storyIndex.stories[storyId] = { + id: storyId, + importPath, + title, + name: 'Name', + }; + }; + + let previewPromise: Promise>; + const getPreview = () => { + const importFn = (importPath: Path) => { + console.log(knownCsfFiles, importPath); + return Promise.resolve(knownCsfFiles[importPath]); + }; + + if (!previewPromise) { + previewPromise = (async () => { + // @ts-ignore + // eslint-disable-next-line no-undef + if (window.preview) { + // @ts-ignore + // eslint-disable-next-line no-undef + (window.preview as PreviewWeb).onStoriesChanged({ + importFn, + storyIndex, + }); + } else { + const preview = new Preview(); + await preview.initialize({ + getStoryIndex: () => storyIndex, + importFn, + getProjectAnnotations: () => projectAnnotations, + }); + // @ts-ignore + // eslint-disable-next-line no-undef + window.preview = preview; + } + + // @ts-ignore + // eslint-disable-next-line no-undef + return window.preview; + })(); + } + + return previewPromise; + }; + + const renderStory = async (storyExport: any, element: HTMLElement) => { + const preview = await getPreview(); + + const storyId = storyIds.get(storyExport); + if (!storyId) throw new Error(`Didn't find story id '${storyId}'`); + const story = await preview.storyStore.loadStory({ storyId }); + + console.log({ story }); + + preview.renderStoryToElement(story, element); + }; + + return ( + + {children} + + ); +}; + +export function Meta({ of }: { of: any }) { + const { setMeta } = useContext(DocsContext); + setMeta(of); + return null; +} + +export function Story({ of, meta }: { of: any; meta?: any }) { + const { addStory, renderStory } = useContext(DocsContext); + + addStory(of, meta); + + const ref = useRef(null); + useEffect(() => { + if (ref.current) renderStory(of, ref.current); + }); + + return
; +} diff --git a/examples/external-docs/src/components/AccountForm.stories.tsx b/examples/external-docs/src/components/AccountForm.stories.tsx new file mode 100644 index 000000000000..46fe06ff649c --- /dev/null +++ b/examples/external-docs/src/components/AccountForm.stories.tsx @@ -0,0 +1,95 @@ +/* eslint-disable storybook/await-interactions */ +/* eslint-disable storybook/use-storybook-testing-library */ +// @TODO: use addon-interactions and remove the rule disable above +import { ComponentStoryObj, ComponentMeta } from '@storybook/react'; +import { screen } from '@testing-library/dom'; +import userEvent from '@testing-library/user-event'; +import { AccountForm } from './AccountForm'; + +export default { + // Title not needed due to CSF3 auto-title + // title: 'Demo/AccountForm', + component: AccountForm, + parameters: { + layout: 'centered', + }, +} as ComponentMeta; + +// export const Standard = (args: any) => ; +// Standard.args = { passwordVerification: false }; +// Standard.play = () => userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com'); + +export const Standard: ComponentStoryObj = { + // render: (args: AccountFormProps) => , + args: { passwordVerification: false }, +}; + +export const StandardEmailFilled = { + ...Standard, + play: () => userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com'), +}; + +export const StandardEmailFailed = { + ...Standard, + play: async () => { + await userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com.com@com'); + await userEvent.type(screen.getByTestId('password1'), 'testpasswordthatwontfail'); + await userEvent.click(screen.getByTestId('submit')); + }, +}; + +export const StandardPasswordFailed = { + ...Standard, + play: async () => { + await StandardEmailFilled.play(); + await userEvent.type(screen.getByTestId('password1'), 'asdf'); + await userEvent.click(screen.getByTestId('submit')); + }, +}; + +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +export const StandardFailHover = { + ...StandardPasswordFailed, + play: async () => { + await StandardPasswordFailed.play(); + await sleep(100); + await userEvent.hover(screen.getByTestId('password-error-info')); + }, +}; + +export const Verification: ComponentStoryObj = { + args: { passwordVerification: true }, +}; + +export const VerificationPasssword1 = { + ...Verification, + play: async () => { + await StandardEmailFilled.play(); + await userEvent.type(screen.getByTestId('password1'), 'asdfasdf'); + await userEvent.click(screen.getByTestId('submit')); + }, +}; + +export const VerificationPasswordMismatch = { + ...Verification, + play: async () => { + await StandardEmailFilled.play(); + await userEvent.type(screen.getByTestId('password1'), 'asdfasdf'); + await userEvent.type(screen.getByTestId('password2'), 'asdf1234'); + await userEvent.click(screen.getByTestId('submit')); + }, +}; + +export const VerificationSuccess = { + ...Verification, + play: async () => { + await StandardEmailFilled.play(); + await sleep(1000); + await userEvent.type(screen.getByTestId('password1'), 'asdfasdf', { delay: 50 }); + await sleep(1000); + await userEvent.type(screen.getByTestId('password2'), 'asdfasdf', { delay: 50 }); + await sleep(1000); + await userEvent.click(screen.getByTestId('submit')); + }, +}; diff --git a/examples/external-docs/src/components/AccountForm.tsx b/examples/external-docs/src/components/AccountForm.tsx new file mode 100644 index 000000000000..d5e612931ac7 --- /dev/null +++ b/examples/external-docs/src/components/AccountForm.tsx @@ -0,0 +1,552 @@ +import { keyframes, styled } from '@storybook/theming'; +import { + ErrorMessage, + Field as FormikInput, + Form as FormikForm, + Formik, + FormikProps, +} from 'formik'; +import React, { FC, HTMLAttributes, useCallback, useState } from 'react'; +import { Icons, WithTooltip } from '@storybook/components'; + +const errorMap = { + email: { + required: { + normal: 'Please enter your email address', + tooltip: + 'We do require an email address and a password as a minimum in order to be able to create an account for you to log in with', + }, + format: { + normal: 'Please enter a correctly formatted email address', + tooltip: + 'Your email address is formatted incorrectly and is not correct - please double check for misspelling', + }, + }, + password: { + required: { + normal: 'Please enter a password', + tooltip: 'A password is requried to create an account', + }, + length: { + normal: 'Please enter a password of minimum 6 characters', + tooltip: + 'For security reasons we enforce a password length of minimum 6 characters - but have no other requirements', + }, + }, + verifiedPassword: { + required: { + normal: 'Please verify your password', + tooltip: + 'Verification of your password is required to ensure no errors in the spelling of the password', + }, + match: { + normal: 'Your passwords do not match', + tooltip: + 'Your verification password has to match your password to make sure you have not misspelled', + }, + }, +}; + +// https://emailregex.com/ +const email99RegExp = new RegExp( + // eslint-disable-next-line no-useless-escape + /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ +); + +export interface AccountFormResponse { + success: boolean; +} + +export interface AccountFormValues { + email: string; + password: string; +} + +interface FormValues extends AccountFormValues { + verifiedPassword: string; +} + +interface FormErrors { + email?: string; + emailTooltip?: string; + password?: string; + passwordTooltip?: string; + verifiedPassword?: string; + verifiedPasswordTooltip?: string; +} + +export type AccountFormProps = { + passwordVerification?: boolean; + onSubmit?: (values: AccountFormValues) => void; + onTransactionStart?: (values: AccountFormValues) => void; + onTransactionEnd?: (values: AccountFormResponse) => void; +}; + +export const AccountForm: FC = ({ + passwordVerification, + onSubmit, + onTransactionStart, + onTransactionEnd, +}) => { + const [state, setState] = useState({ + transacting: false, + transactionSuccess: false, + transactionFailure: false, + }); + + const handleFormSubmit = useCallback( + async ({ email, password }: FormValues, { setSubmitting, resetForm }) => { + if (onSubmit) { + onSubmit({ email, password }); + } + + if (onTransactionStart) { + onTransactionStart({ email, password }); + } + + setSubmitting(true); + + setState({ + ...state, + transacting: true, + }); + + await new Promise((r) => setTimeout(r, 2100)); + + const success = Math.random() < 1; + + if (onTransactionEnd) { + onTransactionEnd({ success }); + } + + setSubmitting(false); + resetForm({ values: { email: '', password: '', verifiedPassword: '' } }); + + setState({ + ...state, + transacting: false, + transactionSuccess: success === true, + transactionFailure: success === false, + }); + }, + [setState, onTransactionEnd, onTransactionStart] + ); + + return ( + + + + Storybook icon + + + + + + + + <title>Storybook + + + + + + {!state.transactionSuccess && !state.transactionFailure && ( + Create an account to join the Storybook community + )} + + {state.transactionSuccess && !state.transactionFailure && ( + +

+ Everything is perfect. Your account is ready and we should probably get you started! +

+

So why don't you get started then?

+ { + setState({ + transacting: false, + transactionSuccess: false, + transactionFailure: false, + }); + }} + > + Go back + +
+ )} + {state.transactionFailure && !state.transactionSuccess && ( + +

What a mess, this API is not working

+

+ Someone should probably have a stern talking to about this, but it won't be me - coz + I'm gonna head out into the nice weather +

+ { + setState({ + transacting: false, + transactionSuccess: false, + transactionFailure: false, + }); + }} + > + Go back + +
+ )} + {!state.transactionSuccess && !state.transactionFailure && ( + { + const errors: FormErrors = {}; + + if (!email) { + errors.email = errorMap.email.required.normal; + errors.emailTooltip = errorMap.email.required.tooltip; + } else { + const validEmail = email.match(email99RegExp); + + if (validEmail === null) { + errors.email = errorMap.email.format.normal; + errors.emailTooltip = errorMap.email.format.tooltip; + } + } + + if (!password) { + errors.password = errorMap.password.required.normal; + errors.passwordTooltip = errorMap.password.required.tooltip; + } else if (password.length < 6) { + errors.password = errorMap.password.length.normal; + errors.passwordTooltip = errorMap.password.length.tooltip; + } + + if (passwordVerification && !verifiedPassword) { + errors.verifiedPassword = errorMap.verifiedPassword.required.normal; + errors.verifiedPasswordTooltip = errorMap.verifiedPassword.required.tooltip; + } else if (passwordVerification && password !== verifiedPassword) { + errors.verifiedPassword = errorMap.verifiedPassword.match.normal; + errors.verifiedPasswordTooltip = errorMap.verifiedPassword.match.tooltip; + } + + return errors; + }} + > + {({ errors: _errors, isSubmitting, dirty }: FormikProps) => { + const errors = _errors as FormErrors; + + return ( +
+ + + + {({ field }: { field: HTMLAttributes }) => ( + <> + + {errors.email && ( + {errors.emailTooltip}} + > + + + + + + )} + + )} + + + + + + {({ field }: { field: HTMLAttributes }) => ( + + )} + + {errors.password && ( + {errors.passwordTooltip}}> + + + + + + )} + + {passwordVerification && ( + + + + {({ field }: { field: HTMLAttributes }) => ( + + )} + + {errors.verifiedPassword && ( + {errors.verifiedPasswordTooltip}} + > + + + + + + )} + + )} + + + Create Account + + + Reset + + +
+ ); + }} +
+ )} +
+
+ ); +}; + +const Wrapper = styled.section(({ theme }) => ({ + fontFamily: theme.typography.fonts.base, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + width: 450, + padding: 32, + backgroundColor: theme.background.content, + borderRadius: 7, +})); + +const Brand = styled.div({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', +}); + +const Title = styled.svg({ + height: 40, + zIndex: 1, + left: -32, + position: 'relative', +}); + +const logoAnimation = keyframes({ + '0': { + transform: 'rotateY(0deg)', + transformOrigin: '50% 5% 0', + }, + '100%': { + transform: 'rotateY(360deg)', + transformOrigin: '50% 5% 0', + }, +}); + +interface LogoProps { + transacting: boolean; +} + +const Logo = styled.svg( + ({ transacting }) => + transacting && { + animation: `${logoAnimation} 1250ms both infinite`, + }, + { height: 40, zIndex: 10, marginLeft: 32 } +); + +const Introduction = styled.p({ + marginTop: 20, + textAlign: 'center', +}); + +const Content = styled.div({ + display: 'flex', + alignItems: 'flex-start', + justifyContent: 'center', + width: 350, + minHeight: 189, + marginTop: 8, +}); + +const Presentation = styled.div({ + textAlign: 'center', +}); + +const Form = styled(FormikForm)({ + width: '100%', + alignSelf: 'flex-start', + '&[aria-disabled="true"]': { + opacity: 0.6, + }, +}); + +const FieldWrapper = styled.div({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'stretch', + marginBottom: 10, +}); + +const Label = styled.label({ + fontSize: 13, + fontWeight: 500, + marginBottom: 6, +}); + +const Input = styled.input(({ theme }) => ({ + fontSize: 14, + color: theme.color.defaultText, + padding: '10px 15px', + borderRadius: 4, + appearance: 'none', + outline: 'none', + border: '0 none', + boxShadow: 'rgb(0 0 0 / 10%) 0px 0px 0px 1px inset', + '&:focus': { + boxShadow: 'rgb(30 167 253) 0px 0px 0px 1px inset', + }, + '&:active': { + boxShadow: 'rgb(30 167 253) 0px 0px 0px 1px inset', + }, + '&[aria-invalid="true"]': { + boxShadow: 'rgb(255 68 0) 0px 0px 0px 1px inset', + }, +})); + +const ErrorWrapper = styled.div({ + display: 'flex', + alignItems: 'flex-start', + fontSize: 11, + marginTop: 6, + cursor: 'help', +}); + +const ErrorIcon = styled(Icons)(({ theme }) => ({ + fill: theme.color.defaultText, + opacity: 0.8, + marginRight: 6, + marginLeft: 2, + marginTop: 1, +})); + +const ErrorTooltip = styled.div(({ theme }) => ({ + fontFamily: theme.typography.fonts.base, + fontSize: 13, + padding: 8, + maxWidth: 350, +})); + +const Actions = styled.div({ + alignSelf: 'stretch', + display: 'flex', + justifyContent: 'space-between', + marginTop: 24, +}); + +const Error = styled(ErrorMessage)({}); + +interface ButtonProps { + dirty?: boolean; +} + +const Button = styled.button({ + backgroundColor: 'transparent', + border: '0 none', + outline: 'none', + appearance: 'none', + fontWeight: 500, + fontSize: 12, + flexBasis: '50%', + cursor: 'pointer', + padding: '11px 16px', + borderRadius: 4, + textTransform: 'uppercase', + '&:focus': { + textDecoration: 'underline', + fontWeight: 700, + }, + '&:active': { + textDecoration: 'underline', + fontWeight: 700, + }, + '&[aria-disabled="true"]': { + cursor: 'default', + }, +}); + +const Submit = styled(Button)(({ theme, dirty }) => ({ + marginRight: 8, + backgroundColor: theme.color.secondary, + color: theme.color.inverseText, + opacity: dirty ? 1 : 0.6, + boxShadow: 'rgb(30 167 253 / 10%) 0 0 0 1px inset', +})); + +const Reset = styled(Button)(({ theme }) => ({ + marginLeft: 8, + boxShadow: 'rgb(30 167 253) 0 0 0 1px inset', + color: theme.color.secondary, +})); diff --git a/examples/external-docs/src/components/button.stories.tsx b/examples/external-docs/src/components/button.stories.tsx new file mode 100644 index 000000000000..7005dc92658b --- /dev/null +++ b/examples/external-docs/src/components/button.stories.tsx @@ -0,0 +1,42 @@ +/* eslint-disable storybook/await-interactions */ +/* eslint-disable storybook/use-storybook-testing-library */ +// @TODO: use addon-interactions and remove the rule disable above +import React from 'react'; +import { Meta, ComponentStory } from '@storybook/react'; +import { screen } from '@testing-library/dom'; +import userEvent from '@testing-library/user-event'; +import { Button } from './button'; + +export default { + component: Button, + title: 'Examples / Button', + argTypes: { onClick: { action: 'click ' } }, + // render: () => <>hohoho, +} as Meta; + +export const WithArgs: ComponentStory = (args) => +); diff --git a/examples/external-docs/src/components/emoji-button.stories.tsx b/examples/external-docs/src/components/emoji-button.stories.tsx new file mode 100644 index 000000000000..9fdbd03f2c22 --- /dev/null +++ b/examples/external-docs/src/components/emoji-button.stories.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { EmojiButton } from './emoji-button'; + +export default { component: EmojiButton, title: 'Examples / Emoji Button' }; + +export const WithArgs = (args: any) => ; +WithArgs.args = { label: 'With args' }; +export const Basic = () => ; diff --git a/examples/external-docs/src/components/emoji-button.tsx b/examples/external-docs/src/components/emoji-button.tsx new file mode 100644 index 000000000000..f38ee88a0dd2 --- /dev/null +++ b/examples/external-docs/src/components/emoji-button.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +export const EmojiButton = ({ label, ...props }: { label: string }) => ( + +); + +EmojiButton.propTypes = { + /** + * A label to show on the button + */ + label: PropTypes.string, +}; + +EmojiButton.defaultProps = { + label: 'Hello', +}; diff --git a/examples/external-docs/src/index.tsx b/examples/external-docs/src/index.tsx new file mode 100644 index 000000000000..ec04c046a889 --- /dev/null +++ b/examples/external-docs/src/index.tsx @@ -0,0 +1,24 @@ +/* global document */ + +import React, { useState } from 'react'; +import ReactDOM from 'react-dom'; +import StoriesPage from './StoriesPage'; +import SecondStoriesPage from './SecondStoriesPage'; + +const Router = ({ routes }: { routes: (() => JSX.Element)[] }) => { + const [routeNumber, setRoute] = useState(0); + const Route = routes[routeNumber]; + + console.log(routeNumber); + return ( +
+ + {/* eslint-disable-next-line react/button-has-type */} + +
+ ); +}; + +const App = () => ; + +ReactDOM.render(, document.getElementById('root')); diff --git a/examples/external-docs/src/react-app-env.d.ts b/examples/external-docs/src/react-app-env.d.ts new file mode 100644 index 000000000000..6431bc5fc6b2 --- /dev/null +++ b/examples/external-docs/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/external-docs/tsconfig.json b/examples/external-docs/tsconfig.json new file mode 100644 index 000000000000..dc08a84bc28a --- /dev/null +++ b/examples/external-docs/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "esModuleInterop": true, + "jsx": "react", + "skipLibCheck": true, + "strict": true, + "target": "es5", + "lib": [ + "dom", + "esnext" + ], + "allowJs": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "include": [ "src/*"] +} diff --git a/examples/html-kitchen-sink/.storybook/main.js b/examples/html-kitchen-sink/.storybook/main.js index 9a7f974f2c16..4fd3c2957c12 100644 --- a/examples/html-kitchen-sink/.storybook/main.js +++ b/examples/html-kitchen-sink/.storybook/main.js @@ -23,6 +23,7 @@ module.exports = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, features: { buildStoriesJson: true, diff --git a/examples/html-kitchen-sink/package.json b/examples/html-kitchen-sink/package.json index 9f33d79cc6e3..f324cf24be3b 100644 --- a/examples/html-kitchen-sink/package.json +++ b/examples/html-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "html-kitchen-sink", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "description": "", "keywords": [], @@ -13,23 +13,23 @@ "storybook": "start-storybook -p 9006 --no-manager-cache" }, "devDependencies": { - "@storybook/addon-a11y": "6.5.0-alpha.52", - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-backgrounds": "6.5.0-alpha.52", - "@storybook/addon-controls": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", - "@storybook/addon-jest": "6.5.0-alpha.52", - "@storybook/addon-links": "6.5.0-alpha.52", + "@storybook/addon-a11y": "6.5.0-beta.7", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-backgrounds": "6.5.0-beta.7", + "@storybook/addon-controls": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", + "@storybook/addon-jest": "6.5.0-beta.7", + "@storybook/addon-links": "6.5.0-beta.7", "@storybook/addon-postcss": "^2.0.0", - "@storybook/addon-storyshots": "6.5.0-alpha.52", - "@storybook/addon-storysource": "6.5.0-alpha.52", - "@storybook/addon-viewport": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/client-api": "6.5.0-alpha.52", - "@storybook/core": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", - "@storybook/html": "6.5.0-alpha.52", - "@storybook/source-loader": "6.5.0-alpha.52", + "@storybook/addon-storyshots": "6.5.0-beta.7", + "@storybook/addon-storysource": "6.5.0-beta.7", + "@storybook/addon-viewport": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/client-api": "6.5.0-beta.7", + "@storybook/core": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", + "@storybook/html": "6.5.0-beta.7", + "@storybook/source-loader": "6.5.0-beta.7", "autoprefixer": "^10.0.1", "eventemitter3": "^4.0.7", "format-json": "^1.0.3", diff --git a/examples/official-storybook/components/addon-measure/ShadowRoot.js b/examples/official-storybook/components/addon-measure/ShadowRoot.js index 665257cf6d6d..d0587b88d307 100644 --- a/examples/official-storybook/components/addon-measure/ShadowRoot.js +++ b/examples/official-storybook/components/addon-measure/ShadowRoot.js @@ -1,9 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; // eslint-disable-next-line import/no-extraneous-dependencies -import { drawSelectedElement } from '@storybook/addon-measure/dist/cjs/box-model/visualizer'; +import { drawSelectedElement } from '@storybook/addon-measure/dist/esm/box-model/visualizer'; // eslint-disable-next-line import/no-extraneous-dependencies -import { init, destroy } from '@storybook/addon-measure/dist/cjs/box-model/canvas'; +import { init, destroy } from '@storybook/addon-measure/dist/esm/box-model/canvas'; export const ShadowRoot = ({ label = 'Hello from shadow DOM', drawMode = 'ROOT' }) => { const ref = React.useRef(); diff --git a/examples/official-storybook/components/addon-measure/Visualization.js b/examples/official-storybook/components/addon-measure/Visualization.js index bcd10d6a3d1b..6ae319f75f69 100644 --- a/examples/official-storybook/components/addon-measure/Visualization.js +++ b/examples/official-storybook/components/addon-measure/Visualization.js @@ -1,9 +1,9 @@ import React, { useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; // eslint-disable-next-line import/no-extraneous-dependencies -import { drawSelectedElement } from '@storybook/addon-measure/dist/cjs/box-model/visualizer'; +import { drawSelectedElement } from '@storybook/addon-measure/dist/esm/box-model/visualizer'; // eslint-disable-next-line import/no-extraneous-dependencies -import { init, destroy } from '@storybook/addon-measure/dist/cjs/box-model/canvas'; +import { init, destroy } from '@storybook/addon-measure/dist/esm/box-model/canvas'; export const Visualization = ({ render }) => { const element = useRef(null); diff --git a/examples/official-storybook/main.ts b/examples/official-storybook/main.ts index 846261c69e77..0f3115a2d5a4 100644 --- a/examples/official-storybook/main.ts +++ b/examples/official-storybook/main.ts @@ -4,6 +4,10 @@ import type { StorybookConfig } from '@storybook/react/types'; const config: StorybookConfig = { stories: [ + { + directory: './stories/title', + titlePrefix: 'Custom Prefix', + }, // FIXME: Breaks e2e tests './intro.stories.mdx', '../../lib/ui/src/**/*.stories.@(js|tsx|mdx)', '../../lib/components/src/**/*.stories.@(js|tsx|mdx)', @@ -34,6 +38,7 @@ const config: StorybookConfig = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, logLevel: 'debug', features: { diff --git a/examples/official-storybook/package.json b/examples/official-storybook/package.json index b8510d7cddd5..2fb99d9b1f9e 100644 --- a/examples/official-storybook/package.json +++ b/examples/official-storybook/package.json @@ -1,6 +1,6 @@ { "name": "official-storybook", - "version": "6.5.0-alpha.52", + "version": "6.5.0-beta.7", "private": true, "scripts": { "build-storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true build-storybook -c ./", @@ -11,32 +11,33 @@ "storyshots-puppeteer": "yarn run build-storybook && yarn run do-storyshots-puppeteer" }, "devDependencies": { + "@emotion/jest": "^11.8.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@storybook/addon-a11y": "6.5.0-alpha.52", - "@storybook/addon-actions": "6.5.0-alpha.52", - "@storybook/addon-backgrounds": "6.5.0-alpha.52", - "@storybook/addon-controls": "6.5.0-alpha.52", - "@storybook/addon-docs": "6.5.0-alpha.52", - "@storybook/addon-interactions": "6.5.0-alpha.52", - "@storybook/addon-jest": "6.5.0-alpha.52", - "@storybook/addon-links": "6.5.0-alpha.52", - "@storybook/addon-storyshots": "6.5.0-alpha.52", - "@storybook/addon-storyshots-puppeteer": "6.5.0-alpha.52", - "@storybook/addon-storysource": "6.5.0-alpha.52", - "@storybook/addon-toolbars": "6.5.0-alpha.52", - "@storybook/addon-viewport": "6.5.0-alpha.52", - "@storybook/addons": "6.5.0-alpha.52", - "@storybook/cli": "6.5.0-alpha.52", - "@storybook/components": "6.5.0-alpha.52", - "@storybook/core-events": "6.5.0-alpha.52", + "@storybook/addon-a11y": "6.5.0-beta.7", + "@storybook/addon-actions": "6.5.0-beta.7", + "@storybook/addon-backgrounds": "6.5.0-beta.7", + "@storybook/addon-controls": "6.5.0-beta.7", + "@storybook/addon-docs": "6.5.0-beta.7", + "@storybook/addon-interactions": "6.5.0-beta.7", + "@storybook/addon-jest": "6.5.0-beta.7", + "@storybook/addon-links": "6.5.0-beta.7", + "@storybook/addon-storyshots": "6.5.0-beta.7", + "@storybook/addon-storyshots-puppeteer": "6.5.0-beta.7", + "@storybook/addon-storysource": "6.5.0-beta.7", + "@storybook/addon-toolbars": "6.5.0-beta.7", + "@storybook/addon-viewport": "6.5.0-beta.7", + "@storybook/addons": "6.5.0-beta.7", + "@storybook/cli": "6.5.0-beta.7", + "@storybook/components": "6.5.0-beta.7", + "@storybook/core-events": "6.5.0-beta.7", "@storybook/design-system": "^5.4.7", "@storybook/jest": "^0.0.5", - "@storybook/node-logger": "6.5.0-alpha.52", - "@storybook/react": "6.5.0-alpha.52", - "@storybook/router": "6.5.0-alpha.52", - "@storybook/source-loader": "6.5.0-alpha.52", + "@storybook/node-logger": "6.5.0-beta.7", + "@storybook/react": "6.5.0-beta.7", + "@storybook/router": "6.5.0-beta.7", + "@storybook/source-loader": "6.5.0-beta.7", "@storybook/testing-library": "^0.0.7", - "@storybook/theming": "6.5.0-alpha.52", + "@storybook/theming": "6.5.0-beta.7", "@testing-library/dom": "^7.31.2", "@testing-library/user-event": "^13.1.9", "chromatic": "^6.0.2", @@ -47,7 +48,6 @@ "express": "^4.17.1", "format-json": "^1.0.3", "global": "^4.4.0", - "jest-emotion": "^10.0.32", "lodash": "^4.17.21", "paths.macro": "^3.0.1", "prop-types": "^15.7.2", diff --git a/examples/official-storybook/stories/addon-a11y/parameters.stories.js b/examples/official-storybook/stories/addon-a11y/parameters.stories.js new file mode 100644 index 000000000000..77c2a22f57b6 --- /dev/null +++ b/examples/official-storybook/stories/addon-a11y/parameters.stories.js @@ -0,0 +1,38 @@ +import React from 'react'; +import BaseButton from '../../components/BaseButton'; + +export default { + title: 'Addons/A11y/Parameters', + component: BaseButton, + parameters: { + options: { selectedPanel: 'storybook/a11y/panel' }, + }, +}; + +export const ElementId = () => ( + <> +

+ The a11y.element parameter is set to the Insufficient contrast{' '} + section.{' '} +

+ +
+ No discernable button text +

This a11y violation should not be reported, as this section is not scanned.

+ +
+
+ Insufficient contrast +

This a11y issue (incomplete) should be reported.

+ +
+ +); +ElementId.parameters = { + a11y: { + element: '#insufficient-contrast', + }, +}; diff --git a/examples/official-storybook/stories/addon-controls.stories.tsx b/examples/official-storybook/stories/addon-controls.stories.tsx index 9550d612193f..6dea53b8f168 100644 --- a/examples/official-storybook/stories/addon-controls.stories.tsx +++ b/examples/official-storybook/stories/addon-controls.stories.tsx @@ -28,17 +28,17 @@ export default { ], }, }, - mutuallyExclusiveA: { control: 'text', removeIf: 'mutuallyExclusiveB' }, - mutuallyExclusiveB: { control: 'text', removeIf: 'mutuallyExclusiveA' }, + mutuallyExclusiveA: { control: 'text', if: { arg: 'mutuallyExclusiveB', truthy: false } }, + mutuallyExclusiveB: { control: 'text', if: { arg: 'mutuallyExclusiveA', truthy: false } }, colorMode: { control: 'boolean', }, dynamicText: { - removeIf: 'colorMode', + if: { arg: 'colorMode', truthy: false }, control: 'text', }, dynamicColor: { - addIf: 'colorMode', + if: { arg: 'colorMode' }, control: 'color', }, advanced: { @@ -46,19 +46,22 @@ export default { }, margin: { control: 'number', - addIf: 'advanced', + if: { arg: 'advanced' }, }, padding: { control: 'number', - addIf: 'advanced', + if: { arg: 'advanced' }, }, cornerRadius: { control: 'number', - addIf: 'advanced', + if: { arg: 'advanced' }, }, someText: { control: 'text' }, - subText: { control: 'text', addIf: 'someText' }, - anotherText: { control: 'text', addIf: 'someText' }, + subText: { control: 'text', if: { arg: 'someText' } }, + ifThemeExists: { control: 'text', if: { global: 'theme' } }, + ifThemeNotExists: { control: 'text', if: { global: 'theme', exists: false } }, + ifLightTheme: { control: 'text', if: { global: 'theme', eq: 'light' } }, + ifNotLightTheme: { control: 'text', if: { global: 'theme', neq: 'light' } }, }, parameters: { chromatic: { disable: true }, diff --git a/examples/official-storybook/stories/addon-options.stories.js b/examples/official-storybook/stories/addon-options.stories.js deleted file mode 100644 index 0ee37459418e..000000000000 --- a/examples/official-storybook/stories/addon-options.stories.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -export default { - title: 'Addons/Options', -}; - -export const SettingName = () => ( -
This story should have changed the name of the storybook
-); - -SettingName.storyName = 'setting name'; - -SettingName.parameters = { - options: { - name: 'Custom Storybook', - }, -}; - -export const HidingAddonPanel = () => ( -
This story should have changed hidden the addons panel
-); - -HidingAddonPanel.storyName = 'hiding addon panel'; - -HidingAddonPanel.parameters = { - options: { - showPanel: false, - }, -}; diff --git a/examples/official-storybook/stories/addon-queryparams.stories.js b/examples/official-storybook/stories/addon-queryparams.stories.js deleted file mode 100644 index 4b0cd74f7b00..000000000000 --- a/examples/official-storybook/stories/addon-queryparams.stories.js +++ /dev/null @@ -1,27 +0,0 @@ -import global from 'global'; -import React from 'react'; - -const { document } = global; - -export default { - title: 'Addons/QueryParams', - - parameters: { - query: { - mock: true, - }, - }, -}; - -export const MockIsTrue = () => ( -
This story should have an extra url query param: {document.location.search}
-); - -MockIsTrue.storyName = 'mock is true'; - -export const MockIs4 = () => ( -
This story should have an extra url query param: {document.location.search}
-); - -MockIs4.storyName = 'mock is 4'; -MockIs4.parameters = { query: { mock: 4 } }; diff --git a/examples/official-storybook/stories/core/args.stories.js b/examples/official-storybook/stories/core/args.stories.js index 1a1bb9ee72a1..4ee37b44f996 100644 --- a/examples/official-storybook/stories/core/args.stories.js +++ b/examples/official-storybook/stories/core/args.stories.js @@ -64,3 +64,23 @@ DifferentSet.args = { foo: 'bar', bar: 2, }; + +export const TestUndefinedArgs = Template.bind({}); +TestUndefinedArgs.args = { + first: 'Bob', + last: 'Miller', + foo: 'bar', +}; +TestUndefinedArgs.argTypes = { + first: { + control: { type: 'select' }, + options: ['Bob', 'Alice'], + }, + last: { + control: { type: 'select' }, + options: ['Miller', 'Meyer'], + }, + foo: { + control: { type: 'text' }, + }, +}; diff --git a/examples/official-storybook/stories/title/AutoTitle.stories.js b/examples/official-storybook/stories/title/AutoTitle.stories.js new file mode 100644 index 000000000000..3a2b02502232 --- /dev/null +++ b/examples/official-storybook/stories/title/AutoTitle.stories.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { Form } from '@storybook/components'; + +const { Button } = Form; + +export default { + // Title not needed due to CSF3 auto-title + // title: 'AutoTitle', + component: Button, +}; + +export const Basic = () => + +
+ + + + +`; + +exports[`Storyshots Demo/AccountForm Verification 1`] = ` +.emotion-0 { + font-family: "Nunito Sans",-apple-system,".SFNSText-Regular","San Francisco",BlinkMacSystemFont,"Segoe UI","Helvetica Neue",Helvetica,Arial,sans-serif; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 450px; + padding: 32px; + background-color: #FFFFFF; + border-radius: 7px; +} + +.emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; +} + +.emotion-2 { + height: 40px; + z-index: 10; + margin-left: 32px; +} + +.emotion-3 { + height: 40px; + z-index: 1; + left: -32px; + position: relative; +} + +.emotion-4 { + margin-top: 20px; + text-align: center; +} + +.emotion-5 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + width: 350px; + min-height: 189px; + margin-top: 8px; +} + +.emotion-6 { + width: 100%; + -webkit-align-self: flex-start; + -ms-flex-item-align: flex-start; + align-self: flex-start; +} + +.emotion-6[aria-disabled="true"] { + opacity: 0.6; +} + +.emotion-7 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: stretch; + -ms-flex-pack: stretch; + -webkit-justify-content: stretch; + justify-content: stretch; + margin-bottom: 10px; +} + +.emotion-8 { + font-size: 13px; + font-weight: 500; + margin-bottom: 6px; +} + +.emotion-9 { + font-size: 14px; + color: #333333; + padding: 10px 15px; + border-radius: 4px; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + outline: none; + border: 0 none; + box-shadow: rgb(0 0 0 / 10%) 0px 0px 0px 1px inset; +} + +.emotion-9:focus { + box-shadow: rgb(30 167 253) 0px 0px 0px 1px inset; +} + +.emotion-9:active { + box-shadow: rgb(30 167 253) 0px 0px 0px 1px inset; +} + +.emotion-9[aria-invalid="true"] { + box-shadow: rgb(255 68 0) 0px 0px 0px 1px inset; +} + +.emotion-16 { + -webkit-align-self: stretch; + -ms-flex-item-align: stretch; + align-self: stretch; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + margin-top: 24px; +} + +.emotion-17 { + background-color: transparent; + border: 0 none; + outline: none; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + font-weight: 500; + font-size: 12px; + -webkit-flex-basis: 50%; + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + cursor: pointer; + padding: 11px 16px; + border-radius: 4px; + text-transform: uppercase; + margin-right: 8px; + background-color: #1EA7FD; + color: #FFFFFF; + opacity: 0.6; + box-shadow: rgb(30 167 253 / 10%) 0 0 0 1px inset; +} + +.emotion-17:focus { + -webkit-text-decoration: underline; + text-decoration: underline; + font-weight: 700; +} + +.emotion-17:active { + -webkit-text-decoration: underline; + text-decoration: underline; + font-weight: 700; +} + +.emotion-17[aria-disabled="true"] { + cursor: default; +} + +.emotion-18 { + background-color: transparent; + border: 0 none; + outline: none; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + font-weight: 500; + font-size: 12px; + -webkit-flex-basis: 50%; + -ms-flex-preferred-size: 50%; + flex-basis: 50%; + cursor: pointer; + padding: 11px 16px; + border-radius: 4px; + text-transform: uppercase; + margin-left: 8px; + box-shadow: rgb(30 167 253) 0 0 0 1px inset; + color: #1EA7FD; +} + +.emotion-18:focus { + -webkit-text-decoration: underline; + text-decoration: underline; + font-weight: 700; +} + +.emotion-18:active { + -webkit-text-decoration: underline; + text-decoration: underline; + font-weight: 700; +} + +.emotion-18[aria-disabled="true"] { + cursor: default; +} + +
+
@@ -2102,7 +2659,7 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` @@ -2121,26 +2678,26 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = `

Create an account to join the Storybook community

`; -exports[`Storyshots Docs/ButtonMdx Basic 1`] = ` - -`; - -exports[`Storyshots Docs/ButtonMdx Controls 1`] = ` - -`; - -exports[`Storyshots Examples / Button Basic 1`] = ` +exports[`Storyshots Demo/Examples / Button Basic 1`] = ` `; -exports[`Storyshots Examples / Button CSF 2 Story With Play 1`] = ` +exports[`Storyshots Demo/Examples / Button CSF 2 Story With Play 1`] = ` `; -exports[`Storyshots Examples / Button Process Env 1`] = ` +exports[`Storyshots Demo/Examples / Button Process Env 1`] = ` `; -exports[`Storyshots Examples / Button Story No Render 1`] = ` +exports[`Storyshots Demo/Examples / Button Story No Render 1`] = ` `; -exports[`Storyshots Examples / Button Story Object 1`] = `"hahaha"`; +exports[`Storyshots Demo/Examples / Button Story Object 1`] = `"hahaha"`; -exports[`Storyshots Examples / Button Story With Play 1`] = ` +exports[`Storyshots Demo/Examples / Button Story With Play 1`] = ` `; -exports[`Storyshots Examples / Button With Args 1`] = ` +exports[`Storyshots Demo/Examples / Button With Args 1`] = ` `; -exports[`Storyshots Examples / Emoji Button Basic 1`] = ` +exports[`Storyshots Demo/Examples / Emoji Button Basic 1`] = ` `; -exports[`Storyshots Examples / Emoji Button With Args 1`] = ` +exports[`Storyshots Demo/Examples / Emoji Button With Args 1`] = ` ); diff --git a/examples/react-ts/src/title/AutoTitle.stories.js b/examples/react-ts/src/title/AutoTitle.stories.js new file mode 100644 index 000000000000..e912d9560606 --- /dev/null +++ b/examples/react-ts/src/title/AutoTitle.stories.js @@ -0,0 +1,12 @@ +import React from 'react'; +import { Form } from '@storybook/components'; + +const { Button } = Form; + +export default { + // Title not needed due to CSF3 auto-title + // title: 'AutoTitle', + component: Button, +}; + +export const Basic = () =>