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 a81d6b59aa92..372652ee4264 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ executors: class: description: The Resource class type: enum - enum: ['small', 'medium', 'large', 'xlarge'] + enum: ['small', 'medium', 'medium+', 'large', 'xlarge'] default: 'medium' working_directory: /tmp/storybook docker: @@ -19,7 +19,7 @@ executors: class: description: The Resource class type: enum - enum: ['small', 'medium', 'large', 'xlarge'] + enum: ['small', 'medium', 'medium+', 'large', 'xlarge'] default: 'medium' working_directory: /tmp/storybook docker: @@ -32,7 +32,7 @@ executors: class: description: The Resource class type: enum - enum: ['small', 'medium', 'large', 'xlarge'] + enum: ['small', 'medium', 'medium+', 'large', 'xlarge'] default: 'medium' working_directory: /tmp/storybook docker: @@ -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" }} @@ -118,23 +118,9 @@ jobs: name: examples command: | yarn run-chromatics - packtracker: - executor: - class: medium - name: sb_node_14_browsers - steps: - - git-shallow-clone/checkout_advanced: - clone_options: '--depth 1 --verbose' - - attach_workspace: - at: . - - run: - name: Report webpack stats for manager of official storybook - command: | - cd examples/official-storybook - yarn packtracker examples: executor: - class: medium + class: medium+ name: sb_node_14_browsers parallelism: 17 steps: @@ -194,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: @@ -204,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' @@ -218,14 +204,35 @@ 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 destination: cypress + e2e-tests-sb-docs: + executor: + class: large + name: sb_cypress_8_node_14 + parallelism: 2 + steps: + - git-shallow-clone/checkout_advanced: + clone_options: '--depth 1 --verbose' + - attach_workspace: + at: . + - run: + name: Running local registry + command: yarn local-registry --port 6000 --open + background: true + - run: + name: Wait for registry + command: yarn wait-on http://localhost:6000 + - run: + name: Run smoke tests + command: yarn test:e2e-framework angular_modern_inline_rendering --test-runner --docs-mode + no_output_timeout: 5m cra-bench: executor: class: medium @@ -385,6 +392,8 @@ jobs: - run: name: Test command: yarn test --coverage --runInBand --ci + - store_test_results: + path: junit.xml - persist_to_workspace: root: . paths: @@ -418,9 +427,6 @@ workflows: - smoke-tests: requires: - build - - packtracker: - requires: - - build - unit-tests: requires: - build @@ -439,6 +445,9 @@ workflows: - e2e-tests-core: requires: - publish + - e2e-tests-sb-docs: + requires: + - publish - e2e-tests-pnp: requires: - publish diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 406ac232541e..82d2d3cbf468 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,7 +12,7 @@ If your answer is yes to any of these, please make sure to include it in your PR @@ -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/argtypes.md b/docs/api/argtypes.md index 64ae683a5188..75031481bc78 100644 --- a/docs/api/argtypes.md +++ b/docs/api/argtypes.md @@ -89,6 +89,24 @@ In particular, this would render a row with a modified description, a type displ 💡 As with other Storybook properties (e.g., args, decorators), you can also override ArgTypes per story basis. +#### Global `argTypes` + +You can also define arg types at the global level; they will apply to every component's stories unless you overwrite them. To do so, export the `argTypes` key in your `preview.js`: + + + + + + + +
+💡 If you define a global arg type for a story that does not have that arg (e.g. if there is no corresponding global arg definition), then the arg type will have no effect. +
+ #### Using argTypes in addons If you want to access the argTypes of the current component inside an addon, you can use the `useArgTypes` hook from the `@storybook/api` package: @@ -101,4 +119,4 @@ If you want to access the argTypes of the current component inside an addon, you ]} /> - \ No newline at end of file + diff --git a/docs/api/cli-options.md b/docs/api/cli-options.md index 9380c20d4e17..f8606d47cb69 100644 --- a/docs/api/cli-options.md +++ b/docs/api/cli-options.md @@ -18,10 +18,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 +32,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 +55,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/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/environment-variables.md b/docs/configure/environment-variables.md index 830c94e1cc2d..d6439226bb4d 100644 --- a/docs/configure/environment-variables.md +++ b/docs/configure/environment-variables.md @@ -69,6 +69,34 @@ You can also pass these environment variables when you are [building your Storyb Then they'll be hardcoded to the static version of your Storybook. + +### Using Storybook configuration + +Additionally, you can extend your Storybook configuration file (i.e., [`.storybook/main.js`](../configure/overview.md#configure-story-rendering)) and provide a configuration field that you can use to define specific variables (e.g., API URLs). For example: + + + + + + + +When Storybook loads, it will enable you to access them in your stories similar as you would do if you were working with an `env` file: + + + + + + + ### Using environment variables to choose the browser Storybook allows you to choose the browser you want to preview your stories. Either through a `.env` file entry or directly in your `storybook` script. @@ -83,4 +111,4 @@ The table below lists the available options:
💡 By default, Storybook will open a new Chrome window as part of its startup process. If you don't have Chrome installed, make sure to include one of the following options, or set your default browser accordingly. -
+
\ 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/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 dda42e4c3185..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' }}` |
@@ -300,6 +300,52 @@ 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 `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. + + + + + + + +Or consider a constraint where if the user sets one control value, it doesn't make sense for the user to be able to set another value. + + + + + + + +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..9bcea7bc34b6 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: @@ -134,65 +147,65 @@ We're only covering versions 5.3 and 5.0 as they were important milestones for S | 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) | +| 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](./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/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) |
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 +265,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 +277,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 +373,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 +411,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..cada685c43da 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: @@ -92,4 +93,4 @@ If all else fails, try asking for [help](https://storybook.js.org/support) -Now that you installed Storybook successfully, let’s take a look at a story that was written for us. +Now that you installed Storybook successfully, let’s take a look at a story that was written for us. \ No newline at end of file diff --git a/docs/get-started/setup.md b/docs/get-started/setup.md index 6db9c9907798..e6cd39d8b027 100644 --- a/docs/get-started/setup.md +++ b/docs/get-started/setup.md @@ -25,6 +25,7 @@ Pick a simple component from your project, like a Button, and write a `.stories. 'web-components/your-component.js.mdx', 'html/your-component.js.mdx', 'html/your-component.ts.mdx', + 'preact/your-component.js.mdx', ]} /> @@ -124,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/get-started/whats-a-story.md b/docs/get-started/whats-a-story.md index 274649bc2237..8425cc063cfc 100644 --- a/docs/get-started/whats-a-story.md +++ b/docs/get-started/whats-a-story.md @@ -58,6 +58,7 @@ The above story definition can be further improved to take advantage of [Storybo 'svelte/button-story-with-args.mdx.mdx', 'html/button-story-with-args.js.mdx', 'html/button-story-with-args.ts.mdx', + 'preact/button-story-with-args.js.mdx', ]} /> 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-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/button-story-project-args-theme.js.mdx b/docs/snippets/common/button-story-project-args-theme.js.mdx new file mode 100644 index 000000000000..da897c5a7829 --- /dev/null +++ b/docs/snippets/common/button-story-project-args-theme.js.mdx @@ -0,0 +1,9 @@ +```js +// preview.js + +// All stories expect a theme arg +export const argTypes = { theme: { control: { options: ['light', 'dark'] } } }; + +// The default value of the theme arg to all stories +export const args = { theme: 'light' }; +``` 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 new file mode 100644 index 000000000000..58ecafb7128c --- /dev/null +++ b/docs/snippets/common/component-story-conditional-controls-mutual-exclusion.js.mdx @@ -0,0 +1,19 @@ +```js +// Button.stories.js +import { Button } from './Button'; +export default { + component: Button, + title: 'Button', + argTypes: { + // button can be passed a label or an image, not both + label: { + control: 'text', + if: { arg: 'image', truthy: false }, + }, + image: { + control: { type: 'select', options: ['foo.jpg', 'bar.jpg'] }, + 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 new file mode 100644 index 000000000000..2eba20f71e3e --- /dev/null +++ b/docs/snippets/common/component-story-conditional-controls-toggle.js.mdx @@ -0,0 +1,16 @@ +```js +// Button.stories.js +import { Button } from './Button'; +export default { + component: Button, + title: 'Button', + argTypes: { + label: { control: 'text' }, // always shows + advanced: { control: 'boolean' }, + // below are only included when advanced is true + 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-disable-controls.js.mdx b/docs/snippets/common/component-story-disable-controls.js.mdx index 4bbcdaccf3ac..b1a054880605 100644 --- a/docs/snippets/common/component-story-disable-controls.js.mdx +++ b/docs/snippets/common/component-story-disable-controls.js.mdx @@ -5,9 +5,9 @@ import { YourComponent } from './YourComponent'; export default { /* 👇 The title prop is optional. - * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading - * to learn how to generate automatic titles - */ + * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ title: 'YourComponent', component: YourComponent, argTypes: { @@ -19,4 +19,4 @@ export default { }, }, }; -``` \ No newline at end of file +``` diff --git a/docs/snippets/common/component-story-disable-controls.mdx.mdx b/docs/snippets/common/component-story-disable-controls.mdx.mdx index 04f50ba86a62..52d04044e018 100644 --- a/docs/snippets/common/component-story-disable-controls.mdx.mdx +++ b/docs/snippets/common/component-story-disable-controls.mdx.mdx @@ -9,10 +9,10 @@ import { YourComponent } from './YourComponent' title="YourComponent" component={YourComponent} argTypes={{ - foo:{ - table:{ + foo: { + table: { disable: true, } } }} /> -``` \ No newline at end of file +``` 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/my-component-env-var-config.js.mdx b/docs/snippets/common/my-component-env-var-config.js.mdx new file mode 100644 index 000000000000..fc83a32f3b6b --- /dev/null +++ b/docs/snippets/common/my-component-env-var-config.js.mdx @@ -0,0 +1,23 @@ +```js +// MyComponent.stories.js|jsx|ts|tsx + +import { MyComponent } from './MyComponent'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'MyComponent', + component: MyComponent, +}; + +const Template = (args) => ({ + //👇 Your template goes here +}); + +export const Default = Template.bind({}); +Default.args = { + exampleProp: process.env.EXAMPLE_VAR, +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/my-component-env-var-config.mdx.mdx b/docs/snippets/common/my-component-env-var-config.mdx.mdx new file mode 100644 index 000000000000..beaf32a5d824 --- /dev/null +++ b/docs/snippets/common/my-component-env-var-config.mdx.mdx @@ -0,0 +1,23 @@ +```md + + +import { Canvas, Meta, Story } from '@storybook/addon-docs'; + +import { MyComponent } from './MyComponent'; + + + +export const Template = (args) => ({ + //👇 Your template goes here +}); + + + + {Template.bind({})} + + +``` \ No newline at end of file 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-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-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-env-field-config.js.mdx b/docs/snippets/common/storybook-main-env-field-config.js.mdx new file mode 100644 index 000000000000..a8bec07f7f1b --- /dev/null +++ b/docs/snippets/common/storybook-main-env-field-config.js.mdx @@ -0,0 +1,20 @@ +```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', + ], + /* + * 👇 The `config` argument contains all the other existing environment variables. + * Either configured in an `.env` file or configured on the command line. + */ + env: (config) => ({ + ...config, + EXAMPLE_VAR: 'An environment variable configured in Storybook', + }), +}; +``` \ 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/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/html/button-story-with-args.js.mdx b/docs/snippets/html/button-story-with-args.js.mdx index 3466f20cbcd8..60feb2014547 100644 --- a/docs/snippets/html/button-story-with-args.js.mdx +++ b/docs/snippets/html/button-story-with-args.js.mdx @@ -1,7 +1,7 @@ ```js export default { /* 👇 The title prop is optional. - * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading * to learn how to generate automatic titles */ title: 'Button', diff --git a/docs/snippets/html/button-story-with-args.ts.mdx b/docs/snippets/html/button-story-with-args.ts.mdx index e3f866a17886..3130fc260de7 100644 --- a/docs/snippets/html/button-story-with-args.ts.mdx +++ b/docs/snippets/html/button-story-with-args.ts.mdx @@ -3,7 +3,7 @@ import { Meta, StoryFn } from '@storybook/html'; export default { /* 👇 The title prop is optional. - * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading * to learn how to generate automatic titles */ title: 'Button', diff --git a/docs/snippets/html/your-component.js.mdx b/docs/snippets/html/your-component.js.mdx index b83ef27897a3..50e47094f092 100644 --- a/docs/snippets/html/your-component.js.mdx +++ b/docs/snippets/html/your-component.js.mdx @@ -6,7 +6,7 @@ import { createYourComponent } from './YourComponent'; // 👇 This default export determines where your story goes in the story list export default { /* 👇 The title prop is optional. - * See https://storybook.js.org/docsreact/configure/overview#configure-story-loading + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading * to learn how to generate automatic titles */ title: 'YourComponent', diff --git a/docs/snippets/html/your-component.ts.mdx b/docs/snippets/html/your-component.ts.mdx index b41050449f72..52dcbbdb7f48 100644 --- a/docs/snippets/html/your-component.ts.mdx +++ b/docs/snippets/html/your-component.ts.mdx @@ -7,7 +7,7 @@ import { createYourComponent } from './YourComponent'; //👇 This default export determines where your story goes in the story list export default { /* 👇 The title prop is optional. - * See https://storybook.js.org/docsreact/configure/overview#configure-story-loading + * See https://storybook.js.org/docs/html/configure/overview#configure-story-loading * to learn how to generate automatic titles */ title: 'YourComponent', diff --git a/docs/snippets/preact/button-story-with-args.js.mdx b/docs/snippets/preact/button-story-with-args.js.mdx new file mode 100644 index 000000000000..93b3a1b01943 --- /dev/null +++ b/docs/snippets/preact/button-story-with-args.js.mdx @@ -0,0 +1,26 @@ +```js +// Button.stories.js|jsx + +/** @jsx h */ +import { h } from 'preact'; + +import { Button } from './Button'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/preact/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Button', + component: Button, +} +//👇 We create a “template” of how args map to rendering +const Template = (args) => ; +}; +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 96f8e72c73f5..3ce0d3e243f7 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.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build": "react-scripts build", @@ -34,15 +34,15 @@ "typescript": "^3.9.7" }, "devDependencies": { - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-docs": "6.5.0-beta.2", "@storybook/addon-ie11": "0.0.7--canary.5e87b64.0", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/builder-webpack4": "6.5.0-alpha.48", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/builder-webpack4": "6.5.0-beta.2", "@storybook/preset-create-react-app": "^3.1.6", - "@storybook/react": "6.5.0-alpha.48", + "@storybook/react": "6.5.0-beta.2", "@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 4d4dbcb5c10b..ed0873477566 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.48", + "version": "6.5.0-beta.2", "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.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/ember": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-docs": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addon-viewport": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/ember": "6.5.0-beta.2", "@storybook/ember-cli-storybook": "^0.2.1", - "@storybook/source-loader": "6.5.0-alpha.48", + "@storybook/source-loader": "6.5.0-beta.2", "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..f12a7468d5f9 --- /dev/null +++ b/examples/external-docs/package.json @@ -0,0 +1,39 @@ +{ + "name": "@storybook/external-docs", + "version": "6.5.0-beta.2", + "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.2", + "@storybook/components": "6.5.0-beta.2", + "@storybook/csf": "0.0.2--canary.87bc651.0", + "@storybook/preview-web": "6.5.0-beta.2", + "@storybook/react": "6.5.0-beta.2", + "@storybook/store": "6.5.0-beta.2", + "@storybook/theming": "6.5.0-beta.2", + "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 e659510c66b2..5bafbc9fa68f 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.48", + "version": "6.5.0-beta.2", "private": true, "description": "", "keywords": [], @@ -13,23 +13,23 @@ "storybook": "start-storybook -p 9006 --no-manager-cache" }, "devDependencies": { - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/addon-jest": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-docs": "6.5.0-beta.2", + "@storybook/addon-jest": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", "@storybook/addon-postcss": "^2.0.0", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/client-api": "6.5.0-alpha.48", - "@storybook/core": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/html": "6.5.0-alpha.48", - "@storybook/source-loader": "6.5.0-alpha.48", + "@storybook/addon-storyshots": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addon-viewport": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/client-api": "6.5.0-beta.2", + "@storybook/core": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/html": "6.5.0-beta.2", + "@storybook/source-loader": "6.5.0-beta.2", "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..7e54ea978ab0 100644 --- a/examples/official-storybook/main.ts +++ b/examples/official-storybook/main.ts @@ -34,6 +34,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 eb6b9d83d9ba..e2a408d3e02e 100644 --- a/examples/official-storybook/package.json +++ b/examples/official-storybook/package.json @@ -1,44 +1,43 @@ { "name": "official-storybook", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build-storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true build-storybook -c ./", "debug": "cross-env NODE_OPTIONS=--inspect-brk STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 -c ./", "do-storyshots-puppeteer": "../../node_modules/.bin/jest --projects=./storyshots-puppeteer", "generate-addon-jest-testresults": "jest --config=tests/addon-jest.config.json --json --outputFile=stories/addon-jest.testresults.json", - "packtracker": "yarn storybook --smoke-test --webpack-stats-json /tmp --quiet && cross-env PT_PROJECT_TOKEN=1af1d41b-d737-41d4-ac00-53c8f3913b53 packtracker-upload --stats=/tmp/manager-stats.json", "storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 -c ./ --no-manager-cache", "storyshots-puppeteer": "yarn run build-storybook && yarn run do-storyshots-puppeteer" }, "devDependencies": { - "@packtracker/webpack-plugin": "^2.3.0", + "@emotion/jest": "^11.8.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/addon-interactions": "6.5.0-alpha.48", - "@storybook/addon-jest": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storyshots-puppeteer": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-toolbars": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/cli": "6.5.0-alpha.48", - "@storybook/components": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-docs": "6.5.0-beta.2", + "@storybook/addon-interactions": "6.5.0-beta.2", + "@storybook/addon-jest": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addon-storyshots": "6.5.0-beta.2", + "@storybook/addon-storyshots-puppeteer": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addon-toolbars": "6.5.0-beta.2", + "@storybook/addon-viewport": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/cli": "6.5.0-beta.2", + "@storybook/components": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", "@storybook/design-system": "^5.4.7", "@storybook/jest": "^0.0.5", - "@storybook/node-logger": "6.5.0-alpha.48", - "@storybook/react": "6.5.0-alpha.48", - "@storybook/router": "6.5.0-alpha.48", - "@storybook/source-loader": "6.5.0-alpha.48", + "@storybook/node-logger": "6.5.0-beta.2", + "@storybook/react": "6.5.0-beta.2", + "@storybook/router": "6.5.0-beta.2", + "@storybook/source-loader": "6.5.0-beta.2", "@storybook/testing-library": "^0.0.7", - "@storybook/theming": "6.5.0-alpha.48", + "@storybook/theming": "6.5.0-beta.2", "@testing-library/dom": "^7.31.2", "@testing-library/user-event": "^13.1.9", "chromatic": "^6.0.2", @@ -49,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-controls.stories.tsx b/examples/official-storybook/stories/addon-controls.stories.tsx index ec83aa20c377..6dea53b8f168 100644 --- a/examples/official-storybook/stories/addon-controls.stories.tsx +++ b/examples/official-storybook/stories/addon-controls.stories.tsx @@ -28,6 +28,40 @@ export default { ], }, }, + mutuallyExclusiveA: { control: 'text', if: { arg: 'mutuallyExclusiveB', truthy: false } }, + mutuallyExclusiveB: { control: 'text', if: { arg: 'mutuallyExclusiveA', truthy: false } }, + colorMode: { + control: 'boolean', + }, + dynamicText: { + if: { arg: 'colorMode', truthy: false }, + control: 'text', + }, + dynamicColor: { + if: { arg: 'colorMode' }, + control: 'color', + }, + advanced: { + control: 'boolean', + }, + margin: { + control: 'number', + if: { arg: 'advanced' }, + }, + padding: { + control: 'number', + if: { arg: 'advanced' }, + }, + cornerRadius: { + control: 'number', + if: { arg: 'advanced' }, + }, + someText: { control: 'text' }, + 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/loaders.stories.js b/examples/official-storybook/stories/core/loaders.stories.js index bea9cab24134..e18cdb9795a5 100644 --- a/examples/official-storybook/stories/core/loaders.stories.js +++ b/examples/official-storybook/stories/core/loaders.stories.js @@ -9,3 +9,17 @@ export const Story = (args, { loaded }) => (
Loaded Value is {JSON.stringify(loaded, null, 2)}
); Story.loaders = [async () => ({ storyValue: 3 })]; + +export const ZIndex = (args, { loaded }) => ( +
+ This story has a very high z-index +
+); diff --git a/examples/official-storybook/stories/core/rendering.stories.js b/examples/official-storybook/stories/core/rendering.stories.js index ab6e3cabd641..262249772252 100644 --- a/examples/official-storybook/stories/core/rendering.stories.js +++ b/examples/official-storybook/stories/core/rendering.stories.js @@ -53,3 +53,8 @@ ArgsChange.decorators = [ return ; }, ]; + +// Ensure that this story gets focus when browsed to +// see https://github.com/storybookjs/storybook/issues/16847 +// eslint-disable-next-line jsx-a11y/no-autofocus +export const AutoFocus = () => ; diff --git a/examples/preact-kitchen-sink/.storybook/main.js b/examples/preact-kitchen-sink/.storybook/main.js index 9ed640ccc25d..00fe14b079b5 100644 --- a/examples/preact-kitchen-sink/.storybook/main.js +++ b/examples/preact-kitchen-sink/.storybook/main.js @@ -23,6 +23,7 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], features: { diff --git a/examples/preact-kitchen-sink/package.json b/examples/preact-kitchen-sink/package.json index a413948ca89b..c0e5b4ffc39f 100644 --- a/examples/preact-kitchen-sink/package.json +++ b/examples/preact-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "preact-example", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", @@ -15,16 +15,16 @@ "devDependencies": { "@babel/core": "^7.12.10", "@babel/plugin-transform-runtime": "^7.12.10", - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/preact": "6.5.0-alpha.48", - "@storybook/source-loader": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addon-storyshots": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addon-viewport": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/preact": "6.5.0-beta.2", + "@storybook/source-loader": "6.5.0-beta.2", "@types/prop-types": "^15.7.3", "@types/react": "^17", "@types/react-dom": "^17", diff --git a/examples/react-ts-webpack4/main.ts b/examples/react-ts-webpack4/main.ts index 9f01df4c63e7..c02cde327601 100644 --- a/examples/react-ts-webpack4/main.ts +++ b/examples/react-ts-webpack4/main.ts @@ -19,6 +19,7 @@ const config: StorybookConfig = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, typescript: { check: true, diff --git a/examples/react-ts-webpack4/package.json b/examples/react-ts-webpack4/package.json index 0cafbf3dcd9c..dce65f74da2e 100644 --- a/examples/react-ts-webpack4/package.json +++ b/examples/react-ts-webpack4/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/example-react-ts-webpack4", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build-storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true build-storybook -c ./", @@ -8,10 +8,10 @@ "storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 -c ./ --no-manager-cache" }, "dependencies": { - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-essentials": "6.5.0-alpha.48", - "@storybook/builder-webpack4": "6.5.0-alpha.48", - "@storybook/react": "6.5.0-alpha.48", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-essentials": "6.5.0-beta.2", + "@storybook/builder-webpack4": "6.5.0-beta.2", + "@storybook/react": "6.5.0-beta.2", "@types/react": "^16.14.23", "@types/react-dom": "^16.9.14", "prop-types": "15.7.2", diff --git a/examples/react-ts/.storybook/main.ts b/examples/react-ts/.storybook/main.ts index 2e82165e7cea..dfe7322dde52 100644 --- a/examples/react-ts/.storybook/main.ts +++ b/examples/react-ts/.storybook/main.ts @@ -24,6 +24,7 @@ const config: StorybookConfig = { core: { builder: { name: 'webpack4' }, channelOptions: { allowFunction: false, maxDepth: 10 }, + disableTelemetry: true, }, features: { postcss: false, diff --git a/examples/react-ts/.storybook/manager.js b/examples/react-ts/.storybook/manager.js new file mode 100644 index 000000000000..ece01ccdfaee --- /dev/null +++ b/examples/react-ts/.storybook/manager.js @@ -0,0 +1,8 @@ +import { addons } from '@storybook/addons'; +import startCase from 'lodash/startCase'; + +addons.setConfig({ + sidebar: { + renderLabel: ({ name, type }) => (type === 'story' ? name : startCase(name)), + }, +}); diff --git a/examples/react-ts/.storybook/preview.tsx b/examples/react-ts/.storybook/preview.tsx new file mode 100644 index 000000000000..47aa5c189bfe --- /dev/null +++ b/examples/react-ts/.storybook/preview.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { ThemeProvider, convert, themes } from '@storybook/theming'; + +export const parameters = { + options: { + // storySortV6: (a, b) => ( + // a[1].kind === b[1].kind + // ? 0 + // : a[1].id.localeCompare(b[1].id, undefined, { numeric: true }); + // ), + // storySortV7: (a, b) => ( + // a.title === b.title + // ? 0 + // : a.id.localeCompare(b.id, undefined, { numeric: true }); + // ), + storySort: { + order: ['Examples', 'Docs', 'Demo'], + }, + }, +}; + +export const decorators = [ + (StoryFn) => ( + + + + ), +]; diff --git a/examples/react-ts/package.json b/examples/react-ts/package.json index c4cc06979a06..e580937929eb 100644 --- a/examples/react-ts/package.json +++ b/examples/react-ts/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/example-react-ts", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build-storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true build-storybook", @@ -18,19 +18,22 @@ "@babel/preset-env": "^7.12.11", "@babel/preset-react": "^7.12.10", "@babel/preset-typescript": "^7.12.7", - "@storybook/addon-essentials": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/cli": "6.5.0-alpha.48", - "@storybook/components": "6.5.0-alpha.48", - "@storybook/react": "6.5.0-alpha.48", - "@storybook/theming": "6.5.0-alpha.48", + "@storybook/addon-essentials": "6.5.0-beta.2", + "@storybook/addon-storyshots": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/cli": "6.5.0-beta.2", + "@storybook/components": "6.5.0-beta.2", + "@storybook/react": "6.5.0-beta.2", + "@storybook/theming": "6.5.0-beta.2", "@testing-library/dom": "^7.31.2", + "@testing-library/react": "12.1.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", + "lodash": "^4.17.21", "typescript": "^3.9.7", "webpack": "4" } diff --git a/examples/react-ts/src/AccountForm.stories.tsx b/examples/react-ts/src/AccountForm.stories.tsx index d670d64ee45a..1a4806881f06 100644 --- a/examples/react-ts/src/AccountForm.stories.tsx +++ b/examples/react-ts/src/AccountForm.stories.tsx @@ -1,11 +1,12 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* 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 { ComponentStoryObj, ComponentMeta } from '@storybook/react'; -import { screen } from '@testing-library/dom'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { AccountForm } from './AccountForm'; +import { AccountForm, AccountFormProps } from './AccountForm'; export default { // Title not needed due to CSF3 auto-title @@ -20,17 +21,19 @@ export default { // Standard.args = { passwordVerification: false }; // Standard.play = () => userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com'); -export const Standard: ComponentStoryObj = { +type Story = ComponentStoryObj; + +export const Standard: Story = { // render: (args: AccountFormProps) => , args: { passwordVerification: false }, }; -export const StandardEmailFilled = { +export const StandardEmailFilled: Story = { ...Standard, play: () => userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com'), }; -export const StandardEmailFailed = { +export const StandardEmailFailed: Story = { ...Standard, play: async () => { await userEvent.type(screen.getByTestId('email'), 'michael@chromatic.com.com@com'); @@ -39,41 +42,41 @@ export const StandardEmailFailed = { }, }; -export const StandardPasswordFailed = { +export const StandardPasswordFailed: Story = { ...Standard, - play: async () => { - await StandardEmailFilled.play(); + play: async (context) => { + await StandardEmailFilled.play!(context); await userEvent.type(screen.getByTestId('password1'), 'asdf'); await userEvent.click(screen.getByTestId('submit')); }, }; -export const StandardFailHover = { +export const StandardFailHover: Story = { ...StandardPasswordFailed, - play: async () => { - await StandardPasswordFailed.play(); + play: async (context) => { + await StandardPasswordFailed.play!(context); await sleep(100); await userEvent.hover(screen.getByTestId('password-error-info')); }, }; -export const Verification: ComponentStoryObj = { +export const Verification: Story = { args: { passwordVerification: true }, }; -export const VerificationPasssword1 = { +export const VerificationPasssword1: Story = { ...Verification, - play: async () => { - await StandardEmailFilled.play(); + play: async (context) => { + await StandardEmailFilled.play!(context); await userEvent.type(screen.getByTestId('password1'), 'asdfasdf'); await userEvent.click(screen.getByTestId('submit')); }, }; -export const VerificationPasswordMismatch = { +export const VerificationPasswordMismatch: Story = { ...Verification, - play: async () => { - await StandardEmailFilled.play(); + play: async (context) => { + await StandardEmailFilled.play!(context); await userEvent.type(screen.getByTestId('password1'), 'asdfasdf'); await userEvent.type(screen.getByTestId('password2'), 'asdf1234'); await userEvent.click(screen.getByTestId('submit')); @@ -82,10 +85,10 @@ export const VerificationPasswordMismatch = { const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); -export const VerificationSuccess = { +export const VerificationSuccess: Story = { ...Verification, - play: async () => { - await StandardEmailFilled.play(); + play: async (context) => { + await StandardEmailFilled.play!(context); await sleep(1000); await userEvent.type(screen.getByTestId('password1'), 'asdfasdf', { delay: 50 }); await sleep(1000); @@ -94,3 +97,13 @@ export const VerificationSuccess = { await userEvent.click(screen.getByTestId('submit')); }, }; + +export const StandardWithRenderFunction: Story = { + ...Standard, + render: (args: AccountFormProps) => ( +
+

This uses a custom render

+ +
+ ), +}; diff --git a/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap b/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap index 3926326cf9aa..f5a55042efc3 100644 --- a/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap +++ b/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Storyshots Demo/AccountForm Standard 1`] = ` -.emotion-15 { +.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; @@ -20,7 +20,7 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` border-radius: 7px; } -.emotion-2 { +.emotion-1 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -30,30 +30,30 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` -ms-flex-align: center; align-items: center; -webkit-box-pack: center; - -webkit-justify-content: center; -ms-flex-pack: center; + -webkit-justify-content: center; justify-content: center; } -.emotion-0 { +.emotion-2 { height: 40px; z-index: 10; margin-left: 32px; } -.emotion-1 { +.emotion-3 { height: 40px; z-index: 1; left: -32px; position: relative; } -.emotion-3 { +.emotion-4 { margin-top: 20px; text-align: center; } -.emotion-14 { +.emotion-5 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -63,26 +63,26 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` -ms-flex-align: flex-start; align-items: flex-start; -webkit-box-pack: center; - -webkit-justify-content: center; -ms-flex-pack: center; + -webkit-justify-content: center; justify-content: center; width: 350px; min-height: 189px; margin-top: 8px; } -.emotion-13 { +.emotion-6 { width: 100%; -webkit-align-self: flex-start; - -ms-flex-item-align: start; + -ms-flex-item-align: flex-start; align-self: flex-start; } -.emotion-13[aria-disabled="true"] { +.emotion-6[aria-disabled="true"] { opacity: 0.6; } -.emotion-6 { +.emotion-7 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -91,44 +91,45 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` -ms-flex-direction: column; flex-direction: column; -webkit-box-pack: stretch; - -webkit-justify-content: stretch; -ms-flex-pack: stretch; + -webkit-justify-content: stretch; justify-content: stretch; margin-bottom: 10px; } -.emotion-4 { +.emotion-8 { font-size: 13px; font-weight: 500; margin-bottom: 6px; } -.emotion-5 { +.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-5:focus { +.emotion-9:focus { box-shadow: rgb(30 167 253) 0px 0px 0px 1px inset; } -.emotion-5:active { +.emotion-9:active { box-shadow: rgb(30 167 253) 0px 0px 0px 1px inset; } -.emotion-5[aria-invalid="true"] { +.emotion-9[aria-invalid="true"] { box-shadow: rgb(255 68 0) 0px 0px 0px 1px inset; } -.emotion-12 { +.emotion-13 { -webkit-align-self: stretch; -ms-flex-item-align: stretch; align-self: stretch; @@ -138,17 +139,17 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` display: flex; -webkit-box-pack: justify; -webkit-justify-content: space-between; - -ms-flex-pack: justify; justify-content: space-between; margin-top: 24px; } -.emotion-10 { +.emotion-14 { 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; @@ -166,28 +167,29 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` box-shadow: rgb(30 167 253 / 10%) 0 0 0 1px inset; } -.emotion-10:focus { +.emotion-14:focus { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-10:active { +.emotion-14:active { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-10[aria-disabled="true"] { +.emotion-14[aria-disabled="true"] { cursor: default; } -.emotion-11 { +.emotion-15 { 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; @@ -203,31 +205,31 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` color: #1EA7FD; } -.emotion-11:focus { +.emotion-15:focus { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-11:active { +.emotion-15:active { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-11[aria-disabled="true"] { +.emotion-15[aria-disabled="true"] { cursor: default; }
@@ -262,7 +264,7 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = ` @@ -281,26 +283,26 @@ exports[`Storyshots Demo/AccountForm Standard 1`] = `

Create an account to join the Storybook community

`; -exports[`Storyshots Demo/AccountForm Verification 1`] = ` -.emotion-18 { +exports[`Storyshots Demo/AccountForm Standard With Render Function 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; @@ -1860,7 +1870,7 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` border-radius: 7px; } -.emotion-2 { +.emotion-1 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -1870,30 +1880,30 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` -ms-flex-align: center; align-items: center; -webkit-box-pack: center; - -webkit-justify-content: center; -ms-flex-pack: center; + -webkit-justify-content: center; justify-content: center; } -.emotion-0 { +.emotion-2 { height: 40px; z-index: 10; margin-left: 32px; } -.emotion-1 { +.emotion-3 { height: 40px; z-index: 1; left: -32px; position: relative; } -.emotion-3 { +.emotion-4 { margin-top: 20px; text-align: center; } -.emotion-17 { +.emotion-5 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -1903,26 +1913,26 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` -ms-flex-align: flex-start; align-items: flex-start; -webkit-box-pack: center; - -webkit-justify-content: center; -ms-flex-pack: center; + -webkit-justify-content: center; justify-content: center; width: 350px; min-height: 189px; margin-top: 8px; } -.emotion-16 { +.emotion-6 { width: 100%; -webkit-align-self: flex-start; - -ms-flex-item-align: start; + -ms-flex-item-align: flex-start; align-self: flex-start; } -.emotion-16[aria-disabled="true"] { +.emotion-6[aria-disabled="true"] { opacity: 0.6; } -.emotion-6 { +.emotion-7 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; @@ -1931,44 +1941,45 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` -ms-flex-direction: column; flex-direction: column; -webkit-box-pack: stretch; - -webkit-justify-content: stretch; -ms-flex-pack: stretch; + -webkit-justify-content: stretch; justify-content: stretch; margin-bottom: 10px; } -.emotion-4 { +.emotion-8 { font-size: 13px; font-weight: 500; margin-bottom: 6px; } -.emotion-5 { +.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-5:focus { +.emotion-9:focus { box-shadow: rgb(30 167 253) 0px 0px 0px 1px inset; } -.emotion-5:active { +.emotion-9:active { box-shadow: rgb(30 167 253) 0px 0px 0px 1px inset; } -.emotion-5[aria-invalid="true"] { +.emotion-9[aria-invalid="true"] { box-shadow: rgb(255 68 0) 0px 0px 0px 1px inset; } -.emotion-15 { +.emotion-13 { -webkit-align-self: stretch; -ms-flex-item-align: stretch; align-self: stretch; @@ -1978,17 +1989,17 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` display: flex; -webkit-box-pack: justify; -webkit-justify-content: space-between; - -ms-flex-pack: justify; justify-content: space-between; margin-top: 24px; } -.emotion-13 { +.emotion-14 { 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; @@ -2006,28 +2017,29 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` box-shadow: rgb(30 167 253 / 10%) 0 0 0 1px inset; } -.emotion-13:focus { +.emotion-14:focus { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-13:active { +.emotion-14:active { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-13[aria-disabled="true"] { +.emotion-14[aria-disabled="true"] { cursor: default; } -.emotion-14 { +.emotion-15 { 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; @@ -2043,104 +2055,479 @@ exports[`Storyshots Demo/AccountForm Verification 1`] = ` color: #1EA7FD; } -.emotion-14:focus { +.emotion-15:focus { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-14:active { +.emotion-15:active { -webkit-text-decoration: underline; text-decoration: underline; font-weight: 700; } -.emotion-14[aria-disabled="true"] { +.emotion-15[aria-disabled="true"] { cursor: default; } -
-
+

+ This uses a custom render +

+
- - - Storybook icon - - - - - - - - + Storybook icon + + + + + + + + + + Storybook + + + + + +
+

- - Storybook - - +

+ - + + +
+
+ + +
+
+ + +
+ +
+ + +`; + +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; +} + +
+
+ + + Storybook icon + + + + + + + + + + Storybook + + +

Create an account to join the Storybook community

`; @@ -3416,6 +3810,7 @@ exports[`Storyshots Docs/ButtonMdx Controls 1`] = ` `; @@ -3424,6 +3819,7 @@ exports[`Storyshots Examples / Button Basic 1`] = ` `; @@ -3432,6 +3828,7 @@ exports[`Storyshots Examples / Button CSF 2 Story With Play 1`] = ` `; @@ -3440,6 +3837,7 @@ exports[`Storyshots Examples / Button Process Env 1`] = ` `; @@ -3448,6 +3846,7 @@ exports[`Storyshots Examples / Button Story No Render 1`] = ` `; @@ -3458,6 +3857,7 @@ exports[`Storyshots Examples / Button Story With Play 1`] = ` `; @@ -3466,6 +3866,7 @@ exports[`Storyshots Examples / Button With Args 1`] = ` `; diff --git a/examples/react-ts/src/button.stories.tsx b/examples/react-ts/src/button.stories.tsx index 2c9d8151b200..9a6162285409 100644 --- a/examples/react-ts/src/button.stories.tsx +++ b/examples/react-ts/src/button.stories.tsx @@ -7,10 +7,23 @@ import { screen } from '@testing-library/dom'; import userEvent from '@testing-library/user-event'; import { Button } from './button'; +const icons = { + foo: () => <>Foo, + bar: () => <>Bar, +}; + export default { component: Button, title: 'Examples / Button', - argTypes: { onClick: { action: 'click ' } }, + argTypes: { + onClick: { action: 'click ' }, + icon: { + description: 'An icon, displayed to the left of the title.', + control: { type: 'select' }, + options: Object.keys(icons), + mapping: icons, + }, + }, // render: () => <>hohoho, } as Meta; diff --git a/examples/react-ts/src/button.tsx b/examples/react-ts/src/button.tsx index f3c9ee6b83ea..99dddad4e2f7 100644 --- a/examples/react-ts/src/button.tsx +++ b/examples/react-ts/src/button.tsx @@ -1,14 +1,19 @@ -import React, { ButtonHTMLAttributes } from 'react'; +import React, { ComponentType, ButtonHTMLAttributes } from 'react'; export interface ButtonProps extends ButtonHTMLAttributes { /** * A label to show on the button */ label: string; + + /** + * An icon to show on the left of the label + */ + icon?: ComponentType; } -export const Button = ({ label = 'Hello', ...props }: ButtonProps) => ( +export const Button = ({ label = 'Hello', icon: Icon, ...props }: ButtonProps) => ( ); diff --git a/examples/server-kitchen-sink/package.json b/examples/server-kitchen-sink/package.json index 47bd45bc0a2d..aae0ecafbb1d 100644 --- a/examples/server-kitchen-sink/package.json +++ b/examples/server-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "server-kitchen-sink", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "description": "", "keywords": [], @@ -14,13 +14,13 @@ "storybook": "SERVER_PORT=1137 start-storybook -p 9006 --quiet" }, "devDependencies": { - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/node-logger": "6.5.0-alpha.48", - "@storybook/server": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/node-logger": "6.5.0-beta.2", + "@storybook/server": "6.5.0-beta.2", "concurrently": "^5.3.0", "cors": "^2.8.5", "express": "~4.17.1", diff --git a/examples/standalone-preview/package.json b/examples/standalone-preview/package.json index 2aa7fa7372aa..aa935de75af4 100644 --- a/examples/standalone-preview/package.json +++ b/examples/standalone-preview/package.json @@ -1,15 +1,15 @@ { "name": "standalone-preview", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "storybook": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true start-storybook -p 9011 -c ../official-storybook --no-manager-cache --preview-url=http://localhost:1337/external-iframe.html", "storybook-preview": "cross-env PREVIEW_URL=external-iframe.html parcel ./storybook.html --port 1337" }, "devDependencies": { - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/cli": "6.5.0-alpha.48", - "@storybook/react": "6.5.0-alpha.48", + "@storybook/addon-docs": "6.5.0-beta.2", + "@storybook/cli": "6.5.0-beta.2", + "@storybook/react": "6.5.0-beta.2", "cross-env": "^7.0.3", "parcel": "2.0.1", "react": "16.14.0", diff --git a/examples/svelte-kitchen-sink/.storybook/main.js b/examples/svelte-kitchen-sink/.storybook/main.js index b916ff3157b5..11afcb807c2b 100644 --- a/examples/svelte-kitchen-sink/.storybook/main.js +++ b/examples/svelte-kitchen-sink/.storybook/main.js @@ -35,6 +35,7 @@ module.exports = { }, core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], }; diff --git a/examples/svelte-kitchen-sink/package.json b/examples/svelte-kitchen-sink/package.json index bece7da3e6ad..ebae47246c26 100644 --- a/examples/svelte-kitchen-sink/package.json +++ b/examples/svelte-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "svelte-example", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build-storybook": "build-storybook", @@ -10,20 +10,20 @@ "global": "^4.4.0" }, "devDependencies": { - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/addon-interactions": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-docs": "6.5.0-beta.2", + "@storybook/addon-interactions": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addon-storyshots": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addon-viewport": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", "@storybook/jest": "^0.0.5", - "@storybook/source-loader": "6.5.0-alpha.48", - "@storybook/svelte": "6.5.0-alpha.48", + "@storybook/source-loader": "6.5.0-beta.2", + "@storybook/svelte": "6.5.0-beta.2", "@storybook/testing-library": "^0.0.7", "svelte-jester": "1.3.0", "svelte-preprocess": "4.6.8" diff --git a/examples/vue-3-cli/.storybook/main.js b/examples/vue-3-cli/.storybook/main.js index 5ac709c776c1..f66cac46a255 100644 --- a/examples/vue-3-cli/.storybook/main.js +++ b/examples/vue-3-cli/.storybook/main.js @@ -7,6 +7,7 @@ module.exports = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, features: { buildStoriesJson: true, diff --git a/examples/vue-3-cli/package.json b/examples/vue-3-cli/package.json index d9959e17037f..ec7112b9a5ef 100644 --- a/examples/vue-3-cli/package.json +++ b/examples/vue-3-cli/package.json @@ -1,6 +1,6 @@ { "name": "vue-3-cli-example", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build": "vue-cli-service build", @@ -14,14 +14,14 @@ }, "devDependencies": { "@babel/core": "^7.12.10", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-essentials": "6.5.0-alpha.48", - "@storybook/addon-interactions": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-essentials": "6.5.0-beta.2", + "@storybook/addon-interactions": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addon-storyshots": "6.5.0-beta.2", "@storybook/jest": "^0.0.5", "@storybook/testing-library": "^0.0.7", - "@storybook/vue3": "6.5.0-alpha.48", + "@storybook/vue3": "6.5.0-beta.2", "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-typescript": "~4.5.0", "@vue/cli-service": "~4.5.0", diff --git a/examples/vue-cli/.storybook/main.js b/examples/vue-cli/.storybook/main.js index 969e1ce0af60..704468bef8c8 100644 --- a/examples/vue-cli/.storybook/main.js +++ b/examples/vue-cli/.storybook/main.js @@ -9,6 +9,7 @@ module.exports = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, features: { buildStoriesJson: true, diff --git a/examples/vue-cli/package.json b/examples/vue-cli/package.json index c792775d7046..7f52b9de1643 100644 --- a/examples/vue-cli/package.json +++ b/examples/vue-cli/package.json @@ -1,6 +1,6 @@ { "name": "vue-cli-example", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build": "vue-cli-service build", @@ -15,11 +15,11 @@ "vue-property-decorator": "^9.1.2" }, "devDependencies": { - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-essentials": "6.5.0-alpha.48", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-essentials": "6.5.0-beta.2", "@storybook/preset-scss": "^1.0.3", - "@storybook/source-loader": "6.5.0-alpha.48", - "@storybook/vue": "6.5.0-alpha.48", + "@storybook/source-loader": "6.5.0-beta.2", + "@storybook/vue": "6.5.0-beta.2", "@vue/cli-plugin-babel": "~4.3.1", "@vue/cli-plugin-typescript": "~4.3.1", "@vue/cli-service": "~4.3.1", diff --git a/examples/vue-kitchen-sink/.storybook/main.js b/examples/vue-kitchen-sink/.storybook/main.js index f28511d9d037..9bd6242565e8 100644 --- a/examples/vue-kitchen-sink/.storybook/main.js +++ b/examples/vue-kitchen-sink/.storybook/main.js @@ -14,6 +14,7 @@ module.exports = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, staticDirs: ['../public'], features: { diff --git a/examples/vue-kitchen-sink/package.json b/examples/vue-kitchen-sink/package.json index 25c3e4551c41..e057dd2ba7c2 100644 --- a/examples/vue-kitchen-sink/package.json +++ b/examples/vue-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "vue-example", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "scripts": { "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", @@ -14,21 +14,21 @@ }, "devDependencies": { "@babel/core": "^7.12.10", - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/addon-interactions": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", + "@storybook/addon-a11y": "6.5.0-beta.2", + "@storybook/addon-actions": "6.5.0-beta.2", + "@storybook/addon-backgrounds": "6.5.0-beta.2", + "@storybook/addon-controls": "6.5.0-beta.2", + "@storybook/addon-docs": "6.5.0-beta.2", + "@storybook/addon-interactions": "6.5.0-beta.2", + "@storybook/addon-links": "6.5.0-beta.2", + "@storybook/addon-storyshots": "6.5.0-beta.2", + "@storybook/addon-storysource": "6.5.0-beta.2", + "@storybook/addon-viewport": "6.5.0-beta.2", + "@storybook/addons": "6.5.0-beta.2", "@storybook/jest": "^0.0.5", - "@storybook/source-loader": "6.5.0-alpha.48", + "@storybook/source-loader": "6.5.0-beta.2", "@storybook/testing-library": "^0.0.7", - "@storybook/vue": "6.5.0-alpha.48", + "@storybook/vue": "6.5.0-beta.2", "@vue/babel-preset-jsx": "^1.2.4", "babel-loader": "^8.0.0", "cross-env": "^7.0.3", diff --git a/examples/web-components-kitchen-sink/.storybook/main.js b/examples/web-components-kitchen-sink/.storybook/main.js index 4c7f08ca0108..26cc0234a730 100644 --- a/examples/web-components-kitchen-sink/.storybook/main.js +++ b/examples/web-components-kitchen-sink/.storybook/main.js @@ -15,6 +15,7 @@ module.exports = { ], core: { builder: 'webpack4', + disableTelemetry: true, }, features: { interactionsDebugger: true, diff --git a/examples/web-components-kitchen-sink/package.json b/examples/web-components-kitchen-sink/package.json index eebc4089746f..f079f3b83aa7 100644 --- a/examples/web-components-kitchen-sink/package.json +++ b/examples/web-components-kitchen-sink/package.json @@ -1,6 +1,6 @@ { "name": "web-components-kitchen-sink", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "private": true, "description": "", "keywords": [], @@ -39,6 +39,7 @@ "@storybook/core-common": "portal:../../lib/core-common", "@storybook/core-events": "portal:../../lib/core-events", "@storybook/core-server": "portal:../../lib/core-server", + "@storybook/csf": "0.0.2--canary.4566f4d.1", "@storybook/csf-tools": "portal:../../lib/csf-tools", "@storybook/docs-tools": "portal:../../lib/docs-tools", "@storybook/jest": "^0.0.5", @@ -49,6 +50,7 @@ "@storybook/router": "portal:../../lib/router", "@storybook/source-loader": "portal:../../lib/source-loader", "@storybook/store": "portal:../../lib/store", + "@storybook/telemetry": "portal:../../lib/telemetry", "@storybook/testing-library": "^0.0.7", "@storybook/theming": "portal:../../lib/theming", "@storybook/ui": "portal:../../lib/ui", diff --git a/examples/web-components-kitchen-sink/yarn.lock b/examples/web-components-kitchen-sink/yarn.lock index 879e095c6a80..50498686a6ea 100644 --- a/examples/web-components-kitchen-sink/yarn.lock +++ b/examples/web-components-kitchen-sink/yarn.lock @@ -1600,7 +1600,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.14.0, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.8.4": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.0, @babel/runtime@npm:^7.8.4": version: 7.14.8 resolution: "@babel/runtime@npm:7.14.8" dependencies: @@ -1609,6 +1609,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.17.8": + version: 7.17.9 + resolution: "@babel/runtime@npm:7.17.9" + dependencies: + regenerator-runtime: ^0.13.4 + checksum: 758ce8855a75408555ed9d196c82c86350257765095a5d3e05df35875d1b0cd42223c6f62356f000b1e1efe8e345d6312c60ae98e8727a2a49909a656f0fd805 + languageName: node + linkType: hard + "@babel/template@npm:^7.12.7, @babel/template@npm:^7.14.5, @babel/template@npm:^7.3.3, @babel/template@npm:^7.7.0": version: 7.14.5 resolution: "@babel/template@npm:7.14.5" @@ -2114,14 +2123,14 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-a11y@portal:../../addons/a11y::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/theming": 6.5.0-beta.1 axe-core: ^4.2.0 core-js: ^3.8.2 global: ^4.4.0 @@ -2131,8 +2140,8 @@ __metadata: ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 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: optional: true @@ -2145,17 +2154,18 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-actions@portal:../../addons/actions::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/theming": 6.5.0-beta.1 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 @@ -2164,8 +2174,8 @@ __metadata: util-deprecate: ^1.0.2 uuid-browser: ^3.1.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: optional: true @@ -2178,13 +2188,13 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-backgrounds@portal:../../addons/backgrounds::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/theming": 6.5.0-beta.1 core-js: ^3.8.2 global: ^4.4.0 memoizerific: ^1.11.3 @@ -2192,8 +2202,8 @@ __metadata: ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 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: optional: true @@ -2206,21 +2216,21 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-controls@portal:../../addons/controls::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/node-logger": 6.5.0-alpha.47 - "@storybook/store": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/node-logger": 6.5.0-beta.1 + "@storybook/store": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 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: optional: true @@ -2237,46 +2247,41 @@ __metadata: "@babel/preset-env": ^7.12.11 "@jest/transform": ^26.6.2 "@mdx-js/react": ^1.6.22 - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/docs-tools": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/docs-tools": 6.5.0-beta.1 "@storybook/mdx1-csf": canary - "@storybook/node-logger": 6.5.0-alpha.47 - "@storybook/postinstall": 6.5.0-alpha.47 - "@storybook/preview-web": 6.5.0-alpha.47 - "@storybook/source-loader": 6.5.0-alpha.47 - "@storybook/store": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/node-logger": 6.5.0-beta.1 + "@storybook/postinstall": 6.5.0-beta.1 + "@storybook/preview-web": 6.5.0-beta.1 + "@storybook/source-loader": 6.5.0-beta.1 + "@storybook/store": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 + babel-loader: ^8.0.0 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 global: ^4.4.0 lodash: ^4.17.21 + regenerator-runtime: ^0.13.7 remark-external-links: ^8.0.0 remark-slug: ^6.0.0 ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 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 react: optional: true react-dom: optional: true - webpack: - optional: true languageName: node linkType: soft @@ -2310,11 +2315,11 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-links@portal:../../addons/links::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/router": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/router": 6.5.0-beta.1 "@types/qs": ^6.9.5 core-js: ^3.8.2 global: ^4.4.0 @@ -2323,8 +2328,8 @@ __metadata: regenerator-runtime: ^0.13.7 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: optional: true @@ -2338,13 +2343,13 @@ __metadata: resolution: "@storybook/addon-storyshots@portal:../../addons/storyshots/storyshots-core::locator=web-components-kitchen-sink%40workspace%3A." dependencies: "@jest/transform": ^26.6.2 - "@storybook/addons": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 "@storybook/babel-plugin-require-context-hook": 1.0.1 - "@storybook/client-api": 6.5.0-alpha.47 - "@storybook/core": 6.5.0-alpha.47 - "@storybook/core-client": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 + "@storybook/client-api": 6.5.0-beta.1 + "@storybook/core": 6.5.0-beta.1 + "@storybook/core-client": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@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 @@ -2369,8 +2374,8 @@ __metadata: 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: "*" @@ -2413,23 +2418,22 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-storysource@portal:../../addons/storysource::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/router": 6.5.0-alpha.47 - "@storybook/source-loader": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/router": 6.5.0-beta.1 + "@storybook/source-loader": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 core-js: ^3.8.2 estraverse: ^5.2.0 loader-utils: ^2.0.0 - prettier: ">=2.2.1 <=2.3.0" prop-types: ^15.7.2 react-syntax-highlighter: ^15.4.5 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: optional: true @@ -2442,20 +2446,20 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addon-viewport@portal:../../addons/viewport::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 core-js: ^3.8.2 global: ^4.4.0 memoizerific: ^1.11.3 prop-types: ^15.7.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: optional: true @@ -2468,20 +2472,20 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/addons@portal:../../lib/addons::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/api": 6.5.0-alpha.47 - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/router": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/api": 6.5.0-beta.1 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/router": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 "@types/webpack-env": ^1.16.0 core-js: ^3.8.2 global: ^4.4.0 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 languageName: node linkType: soft @@ -2489,13 +2493,13 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/api@portal:../../lib/api::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/router": 6.5.0-alpha.47 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/router": 6.5.0-beta.1 "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/theming": 6.5.0-beta.1 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 global: ^4.4.0 @@ -2507,8 +2511,8 @@ __metadata: ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 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 languageName: node linkType: soft @@ -2524,22 +2528,22 @@ __metadata: resolution: "@storybook/builder-webpack4@portal:../../lib/builder-webpack4::locator=web-components-kitchen-sink%40workspace%3A." dependencies: "@babel/core": ^7.12.10 - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/channel-postmessage": 6.5.0-alpha.47 - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/node-logger": 6.5.0-alpha.47 - "@storybook/preview-web": 6.5.0-alpha.47 - "@storybook/router": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/channel-postmessage": 6.5.0-beta.1 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/node-logger": 6.5.0-beta.1 + "@storybook/preview-web": 6.5.0-beta.1 + "@storybook/router": 6.5.0-beta.1 "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 - "@storybook/ui": 6.5.0-alpha.47 + "@storybook/store": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 + "@storybook/ui": 6.5.0-beta.1 "@types/node": ^14.0.10 || ^16.0.0 "@types/webpack": ^4.41.26 autoprefixer: ^9.8.6 @@ -2571,8 +2575,8 @@ __metadata: webpack-hot-middleware: ^2.25.1 webpack-virtual-modules: ^0.2.2 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: typescript: optional: true @@ -2583,9 +2587,9 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/channel-postmessage@portal:../../lib/channel-postmessage::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 core-js: ^3.8.2 global: ^4.4.0 qs: ^6.10.0 @@ -2597,8 +2601,8 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/channel-websocket@portal:../../lib/channel-websocket::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 core-js: ^3.8.2 global: ^4.4.0 telejson: ^5.3.3 @@ -2619,13 +2623,13 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/client-api@portal:../../lib/client-api::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/channel-postmessage": 6.5.0-alpha.47 - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/store": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/channel-postmessage": 6.5.0-beta.1 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/store": 6.5.0-beta.1 "@types/qs": ^6.9.5 "@types/webpack-env": ^1.16.0 core-js: ^3.8.2 @@ -2640,8 +2644,8 @@ __metadata: ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 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 languageName: node linkType: soft @@ -2658,14 +2662,14 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/components@portal:../../lib/components::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/theming": 6.5.0-beta.1 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 languageName: node linkType: soft @@ -2673,16 +2677,16 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/core-client@portal:../../lib/core-client::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/channel-postmessage": 6.5.0-alpha.47 - "@storybook/channel-websocket": 6.5.0-alpha.47 - "@storybook/client-api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/preview-web": 6.5.0-alpha.47 - "@storybook/store": 6.5.0-alpha.47 - "@storybook/ui": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/channel-postmessage": 6.5.0-beta.1 + "@storybook/channel-websocket": 6.5.0-beta.1 + "@storybook/client-api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/preview-web": 6.5.0-beta.1 + "@storybook/store": 6.5.0-beta.1 + "@storybook/ui": 6.5.0-beta.1 airbnb-js-shims: ^2.2.1 ansi-to-html: ^0.6.11 core-js: ^3.8.2 @@ -2694,8 +2698,8 @@ __metadata: unfetch: ^4.2.0 util-deprecate: ^1.0.2 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 webpack: "*" peerDependenciesMeta: typescript: @@ -2729,7 +2733,7 @@ __metadata: "@babel/preset-react": ^7.12.10 "@babel/preset-typescript": ^7.12.7 "@babel/register": ^7.12.1 - "@storybook/node-logger": 6.5.0-alpha.47 + "@storybook/node-logger": 6.5.0-beta.1 "@storybook/semver": ^7.3.2 "@types/node": ^14.0.10 || ^16.0.0 "@types/pretty-hrtime": ^1.0.0 @@ -2758,8 +2762,8 @@ __metadata: util-deprecate: ^1.0.2 webpack: 4 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: typescript: optional: true @@ -2779,16 +2783,17 @@ __metadata: resolution: "@storybook/core-server@portal:../../lib/core-server::locator=web-components-kitchen-sink%40workspace%3A." dependencies: "@discoveryjs/json-ext": ^0.5.3 - "@storybook/builder-webpack4": 6.5.0-alpha.47 - "@storybook/core-client": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/csf-tools": 6.5.0-alpha.47 - "@storybook/manager-webpack4": 6.5.0-alpha.47 - "@storybook/node-logger": 6.5.0-alpha.47 + "@storybook/builder-webpack4": 6.5.0-beta.1 + "@storybook/core-client": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/csf-tools": 6.5.0-beta.1 + "@storybook/manager-webpack4": 6.5.0-beta.1 + "@storybook/node-logger": 6.5.0-beta.1 "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.0-alpha.47 + "@storybook/store": 6.5.0-beta.1 + "@storybook/telemetry": 6.5.0-beta.1 "@types/node": ^14.0.10 || ^16.0.0 "@types/node-fetch": ^2.5.7 "@types/pretty-hrtime": ^1.0.0 @@ -2823,8 +2828,8 @@ __metadata: ws: ^8.2.3 x-default-browser: ^0.4.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: "@storybook/builder-webpack5": optional: true @@ -2839,11 +2844,11 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/core@portal:../../lib/core::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/core-client": 6.5.0-alpha.47 - "@storybook/core-server": 6.5.0-alpha.47 + "@storybook/core-client": 6.5.0-beta.1 + "@storybook/core-server": 6.5.0-beta.1 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 webpack: "*" peerDependenciesMeta: "@storybook/builder-webpack5": @@ -2866,7 +2871,7 @@ __metadata: "@babel/preset-env": ^7.12.11 "@babel/traverse": ^7.12.11 "@babel/types": ^7.12.11 - "@storybook/csf": 0.0.2--canary.87bc651.0 + "@storybook/csf": 0.0.2--canary.4566f4d.1 "@storybook/mdx1-csf": canary core-js: ^3.8.2 fs-extra: ^9.0.1 @@ -2881,12 +2886,12 @@ __metadata: languageName: node linkType: soft -"@storybook/csf@npm:0.0.2--canary.87bc651.0": - version: 0.0.2--canary.87bc651.0 - resolution: "@storybook/csf@npm:0.0.2--canary.87bc651.0" +"@storybook/csf@npm:0.0.2--canary.4566f4d.1": + version: 0.0.2--canary.4566f4d.1 + resolution: "@storybook/csf@npm:0.0.2--canary.4566f4d.1" dependencies: lodash: ^4.17.15 - checksum: 0e7c378b358666ddae637ffba4c4345bed0a2603138528cbc5049f416a62a74cd8ab917856d444bf0b7b3dc0ba52186456c24b21ccb1f028dc5cd43e7f2509dc + checksum: dc0fe9940a47fbba9762275083816953da07a188f0315a631c307716b16a7073586a4d229df6b177dfb4b01604667e2bb24c13d6bfcb137d2f4d306874a590f4 languageName: node linkType: hard @@ -2895,9 +2900,8 @@ __metadata: resolution: "@storybook/docs-tools@portal:../../lib/docs-tools::locator=web-components-kitchen-sink%40workspace%3A." dependencies: "@babel/core": ^7.12.10 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/node-logger": 6.5.0-alpha.47 - "@storybook/store": 6.5.0-alpha.47 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/store": 6.5.0-beta.1 core-js: ^3.8.2 doctrine: ^3.0.0 lodash: ^4.17.21 @@ -2912,12 +2916,12 @@ __metadata: "@babel/core": ^7.12.10 "@babel/plugin-transform-template-literals": ^7.12.1 "@babel/preset-react": ^7.12.10 - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/core-client": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/node-logger": 6.5.0-alpha.47 - "@storybook/theming": 6.5.0-alpha.47 - "@storybook/ui": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/core-client": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@storybook/node-logger": 6.5.0-beta.1 + "@storybook/theming": 6.5.0-beta.1 + "@storybook/ui": 6.5.0-beta.1 "@types/node": ^14.0.10 || ^16.0.0 "@types/webpack": ^4.41.26 babel-loader: ^8.0.0 @@ -2945,8 +2949,8 @@ __metadata: webpack-dev-middleware: ^3.7.3 webpack-virtual-modules: ^0.2.2 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: typescript: optional: true @@ -2996,12 +3000,12 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/preview-web@portal:../../lib/preview-web::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/channel-postmessage": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/store": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/channel-postmessage": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/store": 6.5.0-beta.1 ansi-to-html: ^0.6.11 core-js: ^3.8.2 global: ^4.4.0 @@ -3013,8 +3017,8 @@ __metadata: unfetch: ^4.2.0 util-deprecate: ^1.0.2 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 languageName: node linkType: soft @@ -3022,12 +3026,12 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/router@portal:../../lib/router::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/client-logger": 6.5.0-alpha.47 + "@storybook/client-logger": 6.5.0-beta.1 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 languageName: node linkType: soft @@ -3047,9 +3051,9 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/source-loader@portal:../../lib/source-loader::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 core-js: ^3.8.2 estraverse: ^5.2.0 global: ^4.4.0 @@ -3058,8 +3062,8 @@ __metadata: prettier: ">=2.2.1 <=2.3.0" 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 languageName: node linkType: soft @@ -3067,10 +3071,10 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/store@portal:../../lib/store::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 global: ^4.4.0 @@ -3083,8 +3087,26 @@ __metadata: ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 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 + languageName: node + linkType: soft + +"@storybook/telemetry@portal:../../lib/telemetry::locator=web-components-kitchen-sink%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@storybook/telemetry@portal:../../lib/telemetry::locator=web-components-kitchen-sink%40workspace%3A." + dependencies: + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + chalk: ^4.1.0 + core-js: ^3.8.2 + detect-package-manager: ^2.0.1 + fetch-retry: ^5.0.2 + fs-extra: ^9.0.1 + global: ^4.4.0 + isomorphic-unfetch: ^3.1.0 + nanoid: ^3.3.1 + read-pkg-up: ^7.0.1 languageName: node linkType: soft @@ -3092,12 +3114,12 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/theming@portal:../../lib/theming::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/client-logger": 6.5.0-alpha.47 + "@storybook/client-logger": 6.5.0-beta.1 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 languageName: node linkType: soft @@ -3105,21 +3127,21 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/ui@portal:../../lib/ui::locator=web-components-kitchen-sink%40workspace%3A." dependencies: - "@storybook/addons": 6.5.0-alpha.47 - "@storybook/api": 6.5.0-alpha.47 - "@storybook/channels": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/components": 6.5.0-alpha.47 - "@storybook/core-events": 6.5.0-alpha.47 - "@storybook/router": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/api": 6.5.0-beta.1 + "@storybook/channels": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/components": 6.5.0-beta.1 + "@storybook/core-events": 6.5.0-beta.1 + "@storybook/router": 6.5.0-beta.1 "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.0-alpha.47 + "@storybook/theming": 6.5.0-beta.1 core-js: ^3.8.2 regenerator-runtime: ^0.13.7 resolve-from: ^5.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 languageName: node linkType: soft @@ -3130,15 +3152,15 @@ __metadata: "@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.47 - "@storybook/client-api": 6.5.0-alpha.47 - "@storybook/client-logger": 6.5.0-alpha.47 - "@storybook/core": 6.5.0-alpha.47 - "@storybook/core-common": 6.5.0-alpha.47 - "@storybook/csf": 0.0.2--canary.87bc651.0 - "@storybook/docs-tools": 6.5.0-alpha.47 - "@storybook/preview-web": 6.5.0-alpha.47 - "@storybook/store": 6.5.0-alpha.47 + "@storybook/addons": 6.5.0-beta.1 + "@storybook/client-api": 6.5.0-beta.1 + "@storybook/client-logger": 6.5.0-beta.1 + "@storybook/core": 6.5.0-beta.1 + "@storybook/core-common": 6.5.0-beta.1 + "@storybook/csf": 0.0.2--canary.4566f4d.1 + "@storybook/docs-tools": 6.5.0-beta.1 + "@storybook/preview-web": 6.5.0-beta.1 + "@storybook/store": 6.5.0-beta.1 "@types/node": ^14.14.20 || ^16.0.0 "@types/webpack-env": ^1.16.0 babel-plugin-bundled-import-meta: ^0.3.1 @@ -5925,6 +5947,15 @@ __metadata: languageName: node linkType: hard +"detect-package-manager@npm:^2.0.1": + version: 2.0.1 + resolution: "detect-package-manager@npm:2.0.1" + dependencies: + execa: ^5.1.1 + checksum: 56ffd65228d1ff3ead5ea7f8ab951a517a29270de27510b790c9a8b77d4f36efbd61493e170ca77ee3dc13cbb5218583ce65b78ad14a59dc48565c9bcbbf3c71 + languageName: node + linkType: hard + "detect-port@npm:^1.3.0": version: 1.3.0 resolution: "detect-port@npm:1.3.0" @@ -6462,7 +6493,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0": +"execa@npm:^5.0.0, execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -6684,6 +6715,13 @@ __metadata: languageName: node linkType: hard +"fetch-retry@npm:^5.0.2": + version: 5.0.2 + resolution: "fetch-retry@npm:5.0.2" + checksum: 694fae18ceec4c88c508daf682fccbf1e0736fa679e95daad50946e003df7e261d9a4d36388f6f9eab2426d1796b4ee054ced904794f1edad3ffdc55b2d4b785 + languageName: node + linkType: hard + "figgy-pudding@npm:^3.5.1": version: 3.5.2 resolution: "figgy-pudding@npm:3.5.2" @@ -8374,6 +8412,16 @@ fsevents@^1.2.7: languageName: node linkType: hard +"isomorphic-unfetch@npm:^3.1.0": + version: 3.1.0 + resolution: "isomorphic-unfetch@npm:3.1.0" + dependencies: + node-fetch: ^2.6.1 + unfetch: ^4.2.0 + checksum: d3b61fca06304db692b7f76bdfd3a00f410e42cfa7403c3b250546bf71589d18cf2f355922f57198e4cc4a9872d3647b20397a5c3edf1a347c90d57c83cf2a89 + languageName: node + linkType: hard + "istanbul-lib-coverage@npm:^3.0.0": version: 3.0.0 resolution: "istanbul-lib-coverage@npm:3.0.0" @@ -10072,6 +10120,15 @@ fsevents@^1.2.7: languageName: node linkType: hard +"nanoid@npm:^3.3.1": + version: 3.3.3 + resolution: "nanoid@npm:3.3.3" + bin: + nanoid: bin/nanoid.cjs + checksum: d7ab68893cdb92dd2152d505e56571d571c65b71a9815f9dfb3c9a8cbf943fe43c9777d9a95a3b81ef01e442fec8409a84375c08f90a5753610a9f22672d953a + languageName: node + linkType: hard + "nanomatch@npm:^1.2.9": version: 1.2.13 resolution: "nanomatch@npm:1.2.13" @@ -10136,7 +10193,7 @@ fsevents@^1.2.7: languageName: node linkType: hard -"node-fetch@npm:^2.6.7": +"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" dependencies: @@ -10967,12 +11024,12 @@ fsevents@^1.2.7: languageName: node linkType: hard -"polished@npm:^4.0.5": - version: 4.1.3 - resolution: "polished@npm:4.1.3" +"polished@npm:^4.2.2": + version: 4.2.2 + resolution: "polished@npm:4.2.2" dependencies: - "@babel/runtime": ^7.14.0 - checksum: 8e5328057804b10ac37160d0f17a551276193b47193721a91d6bc7094fbbd73ad69ed0a9faf92a95011611e91df6c554548d0be53261aff4268497b8a258cf20 + "@babel/runtime": ^7.17.8 + checksum: 1d054d1fea18ac7d921ca91504ffcf1ef0f505eda6acbfec6e205a98ebfea80b658664995deb35907dabc5f75f287dc2894812503a8aed28285bb91f25cf7400 languageName: node linkType: hard diff --git a/jest.config.js b/jest.config.js index b0ddc913094d..3292f58155c4 100644 --- a/jest.config.js +++ b/jest.config.js @@ -77,15 +77,22 @@ module.exports = { '/generators/', '/dll/', '/__mocks__ /', + '/__mockdata__/', + '/__mocks-ng-workspace__/', '/__testfixtures__/', '^.*\\.stories\\.[jt]sx?$', + 'typings.d.ts$', ], globals: { DOCS_MODE: false, PREVIEW_URL: undefined, SNAPSHOT_OS: os.platform() === 'win32' ? 'windows' : 'posix', }, - snapshotSerializers: ['jest-emotion', 'enzyme-to-json/serializer', 'jest-serializer-html'], + snapshotSerializers: [ + '@emotion/jest/serializer', + 'enzyme-to-json/serializer', + 'jest-serializer-html', + ], coverageDirectory: 'coverage', setupFilesAfterEnv: ['./scripts/jest.init.ts'], coverageReporters: ['lcov'], @@ -95,4 +102,5 @@ module.exports = { modulePathIgnorePatterns: ['/dist/.*/__mocks__/'], moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'], watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'], + reporters: ['default', 'jest-junit'], }; diff --git a/lerna.json b/lerna.json index f49b7ce8aa5b..8589d8f71fcf 100644 --- a/lerna.json +++ b/lerna.json @@ -2,5 +2,5 @@ "npmClient": "yarn", "useWorkspaces": true, "registry": "https://registry.npmjs.org", - "version": "6.5.0-alpha.48" + "version": "6.5.0-beta.2" } diff --git a/lib/addons/package.json b/lib/addons/package.json index 291adcd04cb5..a85df145fe4b 100644 --- a/lib/addons/package.json +++ b/lib/addons/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addons", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook addons store", "keywords": [ "storybook" @@ -40,25 +40,25 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/api": "6.5.0-alpha.48", - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/router": "6.5.0-alpha.48", - "@storybook/theming": "6.5.0-alpha.48", + "@storybook/api": "6.5.0-beta.2", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.0-beta.2", + "@storybook/theming": "6.5.0-beta.2", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", "global": "^4.4.0", "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" }, "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/public_api.js" } diff --git a/lib/api/package.json b/lib/api/package.json index 7c3753f91d21..2f46918a6e9f 100644 --- a/lib/api/package.json +++ b/lib/api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/api", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Core Storybook API & Context", "keywords": [ "storybook" @@ -38,13 +38,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/router": "6.5.0-alpha.48", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/router": "6.5.0-beta.2", "@storybook/semver": "^7.3.2", - "@storybook/theming": "6.5.0-alpha.48", + "@storybook/theming": "6.5.0-beta.2", "core-js": "^3.8.2", "fast-deep-equal": "^3.1.3", "global": "^4.4.0", @@ -65,12 +65,12 @@ "qs": "^6.10.1" }, "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" }, "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/api/src/index.tsx b/lib/api/src/index.tsx index 41acc3cbace5..78ce1ffb15a3 100644 --- a/lib/api/src/index.tsx +++ b/lib/api/src/index.tsx @@ -11,6 +11,7 @@ import React, { useRef, } from 'react'; import mergeWith from 'lodash/mergeWith'; +import { Conditional } from '@storybook/csf'; import { STORY_CHANGED, @@ -25,6 +26,7 @@ import { createContext } from './context'; import Store, { Options } from './store'; import getInitialState from './initial-state'; import type { StoriesHash, Story, Root, Group } from './lib/stories'; +import type { ComposedRef, Refs } from './modules/refs'; import { isGroup, isRoot, isStory } from './lib/stories'; import * as provider from './modules/provider'; @@ -116,6 +118,7 @@ export interface ArgType { name?: string; description?: string; defaultValue?: any; + if?: Conditional; [key: string]: any; } @@ -328,7 +331,7 @@ export function useStorybookApi(): API { return api; } -export type { StoriesHash, Story, Root, Group }; +export type { StoriesHash, Story, Root, Group, ComposedRef, Refs }; export { ManagerConsumer as Consumer, ManagerProvider as Provider, isGroup, isRoot, isStory }; export interface EventMap { diff --git a/lib/api/src/lib/stories.ts b/lib/api/src/lib/stories.ts index f59305e130a5..e170f30410f3 100644 --- a/lib/api/src/lib/stories.ts +++ b/lib/api/src/lib/stories.ts @@ -1,3 +1,4 @@ +import memoize from 'memoizerific'; import React from 'react'; import deprecate from 'util-deprecate'; import dedent from 'ts-dedent'; @@ -25,6 +26,7 @@ const { FEATURES } = global; export type { StoryId }; export interface Root { + type: 'root'; id: StoryId; depth: 0; name: string; @@ -38,6 +40,7 @@ export interface Root { } export interface Group { + type: 'group' | 'component'; id: StoryId; depth: number; name: string; @@ -56,6 +59,7 @@ export interface Group { } export interface Story { + type: 'story' | 'docs'; id: StoryId; depth: number; parent: StoryId; @@ -233,6 +237,7 @@ export const transformStoriesRawToStoriesHash = ( if (root.length && index === 0) { list.push({ + type: 'root', id, name, depth: index, @@ -245,6 +250,7 @@ export const transformStoriesRawToStoriesHash = ( }); } else { list.push({ + type: 'group', id, name, parent, @@ -277,6 +283,7 @@ export const transformStoriesRawToStoriesHash = ( }); acc[item.id] = { + type: item.parameters?.docsOnly ? 'docs' : 'story', ...item, depth: rootAndGroups.length, parent: rootAndGroups[rootAndGroups.length - 1].id, @@ -297,7 +304,10 @@ export const transformStoriesRawToStoriesHash = ( const { children } = item; if (children) { const childNodes = children.map((id) => storiesHashOutOfOrder[id]) as (Story | Group)[]; - acc[item.id].isComponent = childNodes.every((childNode) => childNode.isLeaf); + if (childNodes.every((childNode) => childNode.isLeaf)) { + acc[item.id].isComponent = true; + acc[item.id].type = 'component'; + } childNodes.forEach((childNode) => addItem(acc, childNode)); } } @@ -327,3 +337,17 @@ export function isStory(item: Item): item is Story { } return false; } + +export const getComponentLookupList = memoize(1)((hash: StoriesHash) => { + return Object.entries(hash).reduce((acc, i) => { + const value = i[1]; + if (value.isComponent) { + acc.push([...i[1].children]); + } + return acc; + }, [] as StoryId[][]); +}); + +export const getStoriesLookupList = memoize(1)((hash: StoriesHash) => { + return Object.keys(hash).filter((k) => !(hash[k].children || Array.isArray(hash[k]))); +}); diff --git a/lib/api/src/modules/layout.ts b/lib/api/src/modules/layout.ts index 8a7fc3595165..a51ee56f0b37 100644 --- a/lib/api/src/modules/layout.ts +++ b/lib/api/src/modules/layout.ts @@ -136,7 +136,7 @@ export const init: ModuleFn = ({ store, provider, singleStory }) => { panelPosition: position, }, }), - { persistence: 'session' } + { persistence: 'permanent' } ); } @@ -147,7 +147,7 @@ export const init: ModuleFn = ({ store, provider, singleStory }) => { panelPosition: state.layout.panelPosition === 'right' ? 'bottom' : 'right', }, }), - { persistence: 'session' } + { persistence: 'permanent' } ); }, diff --git a/lib/api/src/modules/stories.ts b/lib/api/src/modules/stories.ts index 62b1bf358de3..70b3c5ba8800 100644 --- a/lib/api/src/modules/stories.ts +++ b/lib/api/src/modules/stories.ts @@ -1,6 +1,7 @@ import global from 'global'; import { toId, sanitize } from '@storybook/csf'; import { + PRELOAD_STORIES, STORY_PREPARED, UPDATE_STORY_ARGS, RESET_STORY_ARGS, @@ -22,7 +23,10 @@ import { isStory, isRoot, transformStoryIndexToStoriesHash, + getComponentLookupList, + getStoriesLookupList, } from '../lib/stories'; + import type { StoriesHash, Story, @@ -77,6 +81,12 @@ export interface SubAPI { updateStoryArgs(story: Story, newArgs: Args): void; resetStoryArgs: (story: Story, argNames?: string[]) => void; findLeafStoryId(StoriesHash: StoriesHash, storyId: StoryId): StoryId; + findSiblingStoryId( + storyId: StoryId, + hash: StoriesHash, + direction: Direction, + toSiblingGroup: boolean // when true, skip over leafs within the same group + ): StoryId; fetchStoryList: () => Promise; setStoryList: (storyList: StoryIndex) => Promise; updateStory: (storyId: StoryId, update: StoryUpdate, ref?: ComposedRef) => Promise; @@ -187,26 +197,7 @@ export const init: ModuleFn = ({ } const hash = refId ? refs[refId].stories || {} : storiesHash; - - const lookupList = Object.entries(hash).reduce((acc, i) => { - const value = i[1]; - if (value.isComponent) { - acc.push([...i[1].children]); - } - return acc; - }, []); - - const index = lookupList.findIndex((i) => i.includes(storyId)); - - // cannot navigate beyond fist or last - if (index === lookupList.length - 1 && direction > 0) { - return; - } - if (index === 0 && direction < 0) { - return; - } - - const result = lookupList[index + direction][0]; + const result = api.findSiblingStoryId(storyId, hash, direction, true); if (result) { api.selectStory(result, undefined, { ref: refId }); @@ -227,21 +218,7 @@ export const init: ModuleFn = ({ } const hash = story.refId ? refs[story.refId].stories : storiesHash; - - const lookupList = Object.keys(hash).filter( - (k) => !(hash[k].children || Array.isArray(hash[k])) - ); - const index = lookupList.indexOf(storyId); - - // cannot navigate beyond fist or last - if (index === lookupList.length - 1 && direction > 0) { - return; - } - if (index === 0 && direction < 0) { - return; - } - - const result = lookupList[index + direction]; + const result = api.findSiblingStoryId(storyId, hash, direction, false); if (result) { api.selectStory(result, undefined, { ref: refId }); @@ -332,6 +309,39 @@ export const init: ModuleFn = ({ const childStoryId = storiesHash[storyId].children[0]; return api.findLeafStoryId(storiesHash, childStoryId); }, + findSiblingStoryId(storyId, hash, direction, toSiblingGroup) { + if (toSiblingGroup) { + const lookupList = getComponentLookupList(hash); + const index = lookupList.findIndex((i) => i.includes(storyId)); + + // cannot navigate beyond fist or last + if (index === lookupList.length - 1 && direction > 0) { + return; + } + if (index === 0 && direction < 0) { + return; + } + + if (lookupList[index + direction]) { + // eslint-disable-next-line consistent-return + return lookupList[index + direction][0]; + } + return; + } + const lookupList = getStoriesLookupList(hash); + const index = lookupList.indexOf(storyId); + + // cannot navigate beyond fist or last + if (index === lookupList.length - 1 && direction > 0) { + return; + } + if (index === 0 && direction < 0) { + return; + } + + // eslint-disable-next-line consistent-return + return lookupList[index + direction]; + }, updateStoryArgs: (story, updatedArgs) => { const { id: storyId, refId } = story; fullAPI.emit(UPDATE_STORY_ARGS, { @@ -448,6 +458,36 @@ export const init: ModuleFn = ({ } }); + fullAPI.on(STORY_PREPARED, function handler({ id, ...update }) { + const { ref, sourceType } = getEventMetadata(this, fullAPI); + fullAPI.updateStory(id, { ...update, prepared: true }, ref); + + if (!ref) { + if (!store.getState().hasCalledSetOptions) { + const { options } = update.parameters; + checkDeprecatedOptionParameters(options); + fullAPI.setOptions(options); + store.setState({ hasCalledSetOptions: true }); + } + } else { + fullAPI.updateRef(ref.id, { ready: true }); + } + + if (sourceType === 'local') { + const { storyId, storiesHash } = store.getState(); + + // create a list of related stories to be preloaded + const toBePreloaded = Array.from( + new Set([ + api.findSiblingStoryId(storyId, storiesHash, 1, true), + api.findSiblingStoryId(storyId, storiesHash, -1, true), + ]) + ).filter(Boolean); + + fullAPI.emit(PRELOAD_STORIES, toBePreloaded); + } + }); + fullAPI.on(SET_STORIES, function handler(data: SetStoriesPayload) { const { ref } = getEventMetadata(this, fullAPI); const stories = data.v ? denormalizeStoryParameters(data) : data.stories; @@ -489,22 +529,6 @@ export const init: ModuleFn = ({ } ); - fullAPI.on(STORY_PREPARED, function handler({ id, ...update }) { - const { ref } = getEventMetadata(this, fullAPI); - fullAPI.updateStory(id, { ...update, prepared: true }, ref); - - if (!ref) { - if (!store.getState().hasCalledSetOptions) { - const { options } = update.parameters; - checkDeprecatedOptionParameters(options); - fullAPI.setOptions(options); - store.setState({ hasCalledSetOptions: true }); - } - } else { - fullAPI.updateRef(ref.id, { ready: true }); - } - }); - fullAPI.on( STORY_ARGS_UPDATED, function handleStoryArgsUpdated({ storyId, args }: { storyId: StoryId; args: Args }) { diff --git a/lib/api/src/tests/stories.test.js b/lib/api/src/tests/stories.test.js index a6158410708f..ad0bae5bef3b 100644 --- a/lib/api/src/tests/stories.test.js +++ b/lib/api/src/tests/stories.test.js @@ -85,8 +85,22 @@ describe('stories API', () => { }); const parameters = {}; const storiesHash = { - 'a--1': { kind: 'a', name: '1', parameters, path: 'a--1', id: 'a--1', args: {} }, - 'a--2': { kind: 'a', name: '2', parameters, path: 'a--2', id: 'a--2', args: {} }, + 'a--1': { + kind: 'a', + name: '1', + parameters, + path: 'a--1', + id: 'a--1', + args: {}, + }, + 'a--2': { + kind: 'a', + name: '2', + parameters, + path: 'a--2', + id: 'a--2', + args: {}, + }, 'b-c--1': { kind: 'b/c', name: '1', @@ -153,6 +167,7 @@ describe('stories API', () => { 'custom-id--1', ]); expect(storedStoriesHash.a).toMatchObject({ + type: 'component', id: 'a', children: ['a--1', 'a--2'], isRoot: false, @@ -160,6 +175,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['a--1']).toMatchObject({ + type: 'story', id: 'a--1', parent: 'a', kind: 'a', @@ -170,6 +186,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['a--2']).toMatchObject({ + type: 'story', id: 'a--2', parent: 'a', kind: 'a', @@ -180,6 +197,7 @@ describe('stories API', () => { }); expect(storedStoriesHash.b).toMatchObject({ + type: 'group', id: 'b', children: ['b-c', 'b-d', 'b-e'], isRoot: false, @@ -187,6 +205,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['b-c']).toMatchObject({ + type: 'component', id: 'b-c', parent: 'b', children: ['b-c--1'], @@ -195,6 +214,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['b-c--1']).toMatchObject({ + type: 'story', id: 'b-c--1', parent: 'b-c', kind: 'b/c', @@ -205,6 +225,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['b-d']).toMatchObject({ + type: 'component', id: 'b-d', parent: 'b', children: ['b-d--1', 'b-d--2'], @@ -213,6 +234,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['b-d--1']).toMatchObject({ + type: 'story', id: 'b-d--1', parent: 'b-d', kind: 'b/d', @@ -223,6 +245,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['b-d--2']).toMatchObject({ + type: 'story', id: 'b-d--2', parent: 'b-d', kind: 'b/d', @@ -233,6 +256,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['b-e']).toMatchObject({ + type: 'component', id: 'b-e', parent: 'b', children: ['custom-id--1'], @@ -241,6 +265,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['custom-id--1']).toMatchObject({ + type: 'story', id: 'custom-id--1', parent: 'b-e', kind: 'b/e', @@ -279,14 +304,17 @@ describe('stories API', () => { 'design-system-some-component--my-story', ]); expect(storedStoriesHash['design-system']).toMatchObject({ + type: 'root', isRoot: true, name: 'Design System', // root name originates from `kind`, so it gets trimmed }); expect(storedStoriesHash['design-system-some-component']).toMatchObject({ + type: 'component', isComponent: true, name: 'Some Component', // component name originates from `kind`, so it gets trimmed }); expect(storedStoriesHash['design-system-some-component--my-story']).toMatchObject({ + type: 'story', isLeaf: true, kind: ' Design System / Some Component ', // kind is kept as-is, because it may be used as identifier name: ' My Story ', // story name is kept as-is, because it's set directly on the story @@ -318,12 +346,14 @@ describe('stories API', () => { // We need exact key ordering, even if in theory JS doens't guarantee it expect(Object.keys(storedStoriesHash)).toEqual(['a', 'a-b', 'a-b--1']); expect(storedStoriesHash.a).toMatchObject({ + type: 'root', id: 'a', children: ['a-b'], isRoot: true, isComponent: false, }); expect(storedStoriesHash['a-b']).toMatchObject({ + type: 'component', id: 'a-b', parent: 'a', children: ['a-b--1'], @@ -331,6 +361,7 @@ describe('stories API', () => { isComponent: true, }); expect(storedStoriesHash['a-b--1']).toMatchObject({ + type: 'story', id: 'a-b--1', parent: 'a-b', kind: 'a/b', @@ -365,12 +396,14 @@ describe('stories API', () => { // We need exact key ordering, even if in theory JS doens't guarantee it expect(Object.keys(storedStoriesHash)).toEqual(['a', 'a--1']); expect(storedStoriesHash.a).toMatchObject({ + type: 'component', id: 'a', children: ['a--1'], isRoot: false, isComponent: true, }); expect(storedStoriesHash['a--1']).toMatchObject({ + type: 'story', id: 'a--1', parent: 'a', kind: 'a', @@ -401,6 +434,7 @@ describe('stories API', () => { // We need exact key ordering, even if in theory JS doens't guarantee it expect(Object.keys(storedStoriesHash)).toEqual(['a', 'a--1', 'a--2', 'b', 'b--1']); expect(storedStoriesHash.a).toMatchObject({ + type: 'component', id: 'a', children: ['a--1', 'a--2'], isRoot: false, @@ -408,6 +442,7 @@ describe('stories API', () => { }); expect(storedStoriesHash.b).toMatchObject({ + type: 'component', id: 'b', children: ['b--1'], isRoot: false, @@ -703,6 +738,38 @@ describe('stories API', () => { }); }); + describe('findSiblingStoryId', () => { + it('works forward', () => { + const navigate = jest.fn(); + const store = createMockStore(); + + const storyId = 'a--1'; + const { + api: { setStories, findSiblingStoryId }, + state, + } = initStories({ store, navigate, storyId, viewMode: 'story', provider }); + store.setState(state); + setStories(storiesHash); + + const result = findSiblingStoryId(storyId, storiesHash, 1, false); + expect(result).toBe('a--2'); + }); + it('works forward toSiblingGroup', () => { + const navigate = jest.fn(); + const store = createMockStore(); + + const storyId = 'a--1'; + const { + api: { setStories, findSiblingStoryId }, + state, + } = initStories({ store, navigate, storyId, viewMode: 'story', provider }); + store.setState(state); + setStories(storiesHash); + + const result = findSiblingStoryId(storyId, store.getState().storiesHash, 1, true); + expect(result).toBe('b-c--1'); + }); + }); describe('jumpToComponent', () => { it('works forward', () => { const navigate = jest.fn(); @@ -943,6 +1010,7 @@ describe('stories API', () => { 'component-b--story-3', ]); expect(storedStoriesHash['component-a']).toMatchObject({ + type: 'component', id: 'component-a', children: ['component-a--story-1', 'component-a--story-2'], isRoot: false, @@ -950,6 +1018,7 @@ describe('stories API', () => { }); expect(storedStoriesHash['component-a--story-1']).toMatchObject({ + type: 'story', id: 'component-a--story-1', parent: 'component-a', kind: 'Component A', @@ -994,21 +1063,25 @@ describe('stories API', () => { it('infers docs only if there is only one story and it has the name "Page"', async () => { mockStories.mockReset().mockReturnValue({ 'component-a--page': { + type: 'story', title: 'Component A', name: 'Page', // Called "Page" but not only story importPath: './path/to/component-a.ts', }, 'component-a--story-2': { + type: 'story', title: 'Component A', name: 'Story 2', importPath: './path/to/component-a.ts', }, 'component-b--page': { + type: 'docs', title: 'Component B', name: 'Page', // Page and only story importPath: './path/to/component-b.ts', }, 'component-c--story-4': { + type: 'story', title: 'Component c', name: 'Story 4', // Only story but not page importPath: './path/to/component-c.ts', @@ -1066,6 +1139,7 @@ describe('stories API', () => { const { storiesHash: storedStoriesHash } = store.getState(); expect(storedStoriesHash['component-a--story-1']).toMatchObject({ + type: 'story', id: 'component-a--story-1', parent: 'component-a', kind: 'Component A', diff --git a/lib/api/src/version.ts b/lib/api/src/version.ts index 293cfa444aed..58f7edd2a0bf 100644 --- a/lib/api/src/version.ts +++ b/lib/api/src/version.ts @@ -1 +1 @@ -export const version = '6.5.0-alpha.48'; +export const version = '6.5.0-beta.2'; diff --git a/lib/builder-webpack4/package.json b/lib/builder-webpack4/package.json index 10d0f55845b4..20113171a766 100644 --- a/lib/builder-webpack4/package.json +++ b/lib/builder-webpack4/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack4", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" @@ -40,22 +40,22 @@ }, "dependencies": { "@babel/core": "^7.12.10", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/api": "6.5.0-alpha.48", - "@storybook/channel-postmessage": "6.5.0-alpha.48", - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-api": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/components": "6.5.0-alpha.48", - "@storybook/core-common": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/node-logger": "6.5.0-alpha.48", - "@storybook/preview-web": "6.5.0-alpha.48", - "@storybook/router": "6.5.0-alpha.48", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/api": "6.5.0-beta.2", + "@storybook/channel-postmessage": "6.5.0-beta.2", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-api": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/components": "6.5.0-beta.2", + "@storybook/core-common": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/node-logger": "6.5.0-beta.2", + "@storybook/preview-web": "6.5.0-beta.2", + "@storybook/router": "6.5.0-beta.2", "@storybook/semver": "^7.3.2", - "@storybook/store": "6.5.0-alpha.48", - "@storybook/theming": "6.5.0-alpha.48", - "@storybook/ui": "6.5.0-alpha.48", + "@storybook/store": "6.5.0-beta.2", + "@storybook/theming": "6.5.0-beta.2", + "@storybook/ui": "6.5.0-beta.2", "@types/node": "^14.0.10 || ^16.0.0", "@types/webpack": "^4.41.26", "autoprefixer": "^9.8.6", @@ -95,8 +95,8 @@ "@types/webpack-virtual-modules": "^0.1.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": { "typescript": { @@ -106,6 +106,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/builder-webpack4/src/index.ts b/lib/builder-webpack4/src/index.ts index 2462012e12bf..db89a415581d 100644 --- a/lib/builder-webpack4/src/index.ts +++ b/lib/builder-webpack4/src/index.ts @@ -11,6 +11,19 @@ let compilation: ReturnType; let reject: (reason?: any) => void; type WebpackBuilder = Builder; +type Unpromise> = T extends Promise ? U : never; + +type BuilderStartOptions = Partial['0']>; +type BuilderStartResult = Unpromise>; +type StarterFunction = ( + options: BuilderStartOptions +) => AsyncGenerator; + +type BuilderBuildOptions = Partial['0']>; +type BuilderBuildResult = Unpromise>; +type BuilderFunction = ( + options: BuilderBuildOptions +) => AsyncGenerator; export const executor = { get: async (options: Options) => { @@ -48,11 +61,54 @@ export const makeStatsFromError: (err: string) => Stats = (err) => toJson: () => ({ warnings: [] as any[], errors: [err] }), } as any); -export const start: WebpackBuilder['start'] = async ({ startTime, options, router }) => { +let asyncIterator: ReturnType | ReturnType; + +export const bail: WebpackBuilder['bail'] = async () => { + if (asyncIterator) { + try { + // we tell the builder (that started) to stop ASAP and wait + await asyncIterator.throw(new Error()); + } catch (e) { + // + } + } + if (reject) { + reject(); + } + // we wait for the compiler to finish it's work, so it's command-line output doesn't interfere + return new Promise((res, rej) => { + if (process && compilation) { + try { + compilation.close(() => res()); + logger.warn('Force closed preview build'); + } catch (err) { + logger.warn('Unable to close preview build!'); + res(); + } + } else { + res(); + } + }); +}; + +/** + * This function is a generator so that we can abort it mid process + * in case of failure coming from other processes e.g. manager builder + * + * I am sorry for making you read about generators today :') + */ +const starter: StarterFunction = async function* starterGeneratorFn({ + startTime, + options, + router, +}) { const webpackInstance = await executor.get(options); + yield; const config = await getConfig(options); + yield; const compiler = webpackInstance(config); + if (!compiler) { const err = `${config.name}: missing webpack compiler at runtime!`; logger.error(err); @@ -64,6 +120,7 @@ export const start: WebpackBuilder['start'] = async ({ startTime, options, route } const { handler, modulesCount } = await useProgressReporting(router, startTime, options); + yield; new ProgressPlugin({ handler, modulesCount }).apply(compiler); const middlewareOptions: Parameters[1] = { @@ -86,6 +143,7 @@ export const start: WebpackBuilder['start'] = async ({ startTime, options, route waitUntilValid(ready); reject = stop; }); + yield; if (!stats) { throw new Error('no stats after building preview'); @@ -102,26 +160,18 @@ export const start: WebpackBuilder['start'] = async ({ startTime, options, route }; }; -export const bail: WebpackBuilder['bail'] = (e: Error) => { - if (reject) { - reject(); - } - if (process) { - try { - compilation.close(); - logger.warn('Force closed preview build'); - } catch (err) { - logger.warn('Unable to close preview build!'); - } - } - throw e; -}; - -export const build: WebpackBuilder['build'] = async ({ options, startTime }) => { +/** + * This function is a generator so that we can abort it mid process + * in case of failure coming from other processes e.g. manager builder + * + * I am sorry for making you read about generators today :') + */ +const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, options }) { const webpackInstance = await executor.get(options); - + yield; logger.info('=> Compiling preview..'); const config = await getConfig(options); + yield; const compiler = webpackInstance(config); if (!compiler) { @@ -129,8 +179,9 @@ export const build: WebpackBuilder['build'] = async ({ options, startTime }) => logger.error(err); return Promise.resolve(makeStatsFromError(err)); } + yield; - return new Promise((succeed, fail) => { + return new Promise((succeed, fail) => { compiler.run((error, stats) => { if (error || !stats || stats.hasErrors()) { logger.error('=> Failed to build the preview'); @@ -142,11 +193,22 @@ export const build: WebpackBuilder['build'] = async ({ options, startTime }) => } if (stats && (stats.hasErrors() || stats.hasWarnings())) { - const { warnings, errors } = stats.toJson(config.stats); + const { warnings = [], errors = [] } = stats.toJson( + typeof config.stats === 'string' + ? config.stats + : { + warnings: true, + errors: true, + ...(config.stats as Stats.ToStringOptionsObject), + } + ); errors.forEach((e: string) => logger.error(e)); warnings.forEach((e: string) => logger.error(e)); - return fail(stats); + + return options.debugWebpack + ? fail(stats) + : fail(new Error('=> Webpack failed, learn more with --debug-webpack')); } } @@ -155,10 +217,34 @@ export const build: WebpackBuilder['build'] = async ({ options, startTime }) => stats.toJson(config.stats).warnings.forEach((e: string) => logger.warn(e)); } - return succeed(stats); + return succeed(stats as webpackReal.Stats); }); }); }; +export const start = async (options: BuilderStartOptions) => { + asyncIterator = starter(options); + let result; + + do { + // eslint-disable-next-line no-await-in-loop + result = await asyncIterator.next(); + } while (!result.done); + + return result.value; +}; + +export const build = async (options: BuilderStartOptions) => { + asyncIterator = builder(options); + let result; + + do { + // eslint-disable-next-line no-await-in-loop + result = await asyncIterator.next(); + } while (!result.done); + + return result.value; +}; + export const corePresets = [require.resolve('./presets/preview-preset.js')]; export const overridePresets = [require.resolve('./presets/custom-webpack-preset.js')]; diff --git a/lib/builder-webpack4/templates/virtualModuleModernEntry.js.handlebars b/lib/builder-webpack4/templates/virtualModuleModernEntry.js.handlebars index dfa3f306fa61..73e29368f16d 100644 --- a/lib/builder-webpack4/templates/virtualModuleModernEntry.js.handlebars +++ b/lib/builder-webpack4/templates/virtualModuleModernEntry.js.handlebars @@ -1,6 +1,7 @@ import global from 'global'; -import { composeConfigs, PreviewWeb } from '@storybook/preview-web'; +import { PreviewWeb } from '@storybook/preview-web'; +import { composeConfigs } from '@storybook/store'; import { ClientApi } from '@storybook/client-api'; import { addons } from '@storybook/addons'; import createPostMessageChannel from '@storybook/channel-postmessage'; diff --git a/lib/builder-webpack5/package.json b/lib/builder-webpack5/package.json index 0eab9f641be9..9d22591e879d 100644 --- a/lib/builder-webpack5/package.json +++ b/lib/builder-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack5", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" @@ -40,21 +40,21 @@ }, "dependencies": { "@babel/core": "^7.12.10", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/api": "6.5.0-alpha.48", - "@storybook/channel-postmessage": "6.5.0-alpha.48", - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-api": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/components": "6.5.0-alpha.48", - "@storybook/core-common": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/node-logger": "6.5.0-alpha.48", - "@storybook/preview-web": "6.5.0-alpha.48", - "@storybook/router": "6.5.0-alpha.48", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/api": "6.5.0-beta.2", + "@storybook/channel-postmessage": "6.5.0-beta.2", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-api": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/components": "6.5.0-beta.2", + "@storybook/core-common": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/node-logger": "6.5.0-beta.2", + "@storybook/preview-web": "6.5.0-beta.2", + "@storybook/router": "6.5.0-beta.2", "@storybook/semver": "^7.3.2", - "@storybook/store": "6.5.0-alpha.48", - "@storybook/theming": "6.5.0-alpha.48", + "@storybook/store": "6.5.0-beta.2", + "@storybook/theming": "6.5.0-beta.2", "@types/node": "^14.0.10 || ^16.0.0", "babel-loader": "^8.0.0", "babel-plugin-named-exports-order": "^0.0.2", @@ -86,8 +86,8 @@ "@types/webpack-virtual-modules": "^0.1.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": { "typescript": { @@ -97,6 +97,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/builder-webpack5/src/index.ts b/lib/builder-webpack5/src/index.ts index 522c69c060d8..2d2a84c4646e 100644 --- a/lib/builder-webpack5/src/index.ts +++ b/lib/builder-webpack5/src/index.ts @@ -1,4 +1,4 @@ -import webpack, { Stats, Configuration, ProgressPlugin } from 'webpack'; +import webpack, { Stats, Configuration, ProgressPlugin, StatsOptions } from 'webpack'; import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; import { logger } from '@storybook/node-logger'; @@ -9,6 +9,30 @@ let compilation: ReturnType; let reject: (reason?: any) => void; type WebpackBuilder = Builder; +type Unpromise> = T extends Promise ? U : never; + +type BuilderStartOptions = Partial['0']>; +type BuilderStartResult = Unpromise>; +type StarterFunction = ( + options: BuilderStartOptions +) => AsyncGenerator; + +type BuilderBuildOptions = Partial['0']>; +type BuilderBuildResult = Unpromise>; +type BuilderFunction = ( + options: BuilderBuildOptions +) => AsyncGenerator; + +export const executor = { + get: async (options: Options) => { + const version = ((await options.presets.apply('webpackVersion')) || '5') as string; + const webpackInstance = + (await options.presets.apply<{ default: typeof webpack }>('webpackInstance'))?.default || + webpack; + checkWebpackVersion({ version }, '5', 'builder-webpack5'); + return webpackInstance; + }, +}; export const getConfig: WebpackBuilder['getConfig'] = async (options) => { const { presets } = options; @@ -28,22 +52,55 @@ export const getConfig: WebpackBuilder['getConfig'] = async (options) => { ) as any; }; -export const executor = { - get: async (options: Options) => { - const version = ((await options.presets.apply('webpackVersion')) || '5') as string; - const webpackInstance = - (await options.presets.apply<{ default: typeof webpack }>('webpackInstance'))?.default || - webpack; - checkWebpackVersion({ version }, '5', 'builder-webpack5'); - return webpackInstance; - }, +let asyncIterator: ReturnType | ReturnType; + +export const bail: WebpackBuilder['bail'] = async () => { + if (asyncIterator) { + try { + // we tell the builder (that started) to stop ASAP and wait + await asyncIterator.throw(new Error()); + } catch (e) { + // + } + } + + if (reject) { + reject(); + } + // we wait for the compiler to finish it's work, so it's command-line output doesn't interfere + return new Promise((res, rej) => { + if (process && compilation) { + try { + compilation.close(() => res()); + logger.warn('Force closed preview build'); + } catch (err) { + logger.warn('Unable to close preview build!'); + res(); + } + } else { + res(); + } + }); }; -export const start: WebpackBuilder['start'] = async ({ startTime, options, router }) => { +/** + * This function is a generator so that we can abort it mid process + * in case of failure coming from other processes e.g. preview builder + * + * I am sorry for making you read about generators today :') + */ +const starter: StarterFunction = async function* starterGeneratorFn({ + startTime, + options, + router, +}) { const webpackInstance = await executor.get(options); + yield; const config = await getConfig(options); + yield; const compiler = webpackInstance(config); + if (!compiler) { const err = `${config.name}: missing webpack compiler at runtime!`; logger.error(err); @@ -59,6 +116,7 @@ export const start: WebpackBuilder['start'] = async ({ startTime, options, route } const { handler, modulesCount } = await useProgressReporting(router, startTime, options); + yield; new ProgressPlugin({ handler, modulesCount }).apply(compiler); const middlewareOptions: Parameters[1] = { @@ -75,6 +133,7 @@ export const start: WebpackBuilder['start'] = async ({ startTime, options, route compilation.waitUntilValid(ready); reject = stop; }); + yield; if (!stats) { throw new Error('no stats after building preview'); @@ -91,28 +150,20 @@ export const start: WebpackBuilder['start'] = async ({ startTime, options, route }; }; -export const bail: WebpackBuilder['bail'] = (e: Error) => { - if (reject) { - reject(); - } - if (process) { - try { - compilation.close(); - logger.warn('Force closed preview build'); - } catch (err) { - logger.warn('Unable to close preview build!'); - } - } - throw e; -}; - -export const build: WebpackBuilder['build'] = async ({ options, startTime }) => { +/** + * This function is a generator so that we can abort it mid process + * in case of failure coming from other processes e.g. manager builder + * + * I am sorry for making you read about generators today :') + */ +const builder: BuilderFunction = async function* builderGeneratorFn({ startTime, options }) { const webpackInstance = await executor.get(options); - + yield; logger.info('=> Compiling preview..'); const config = await getConfig(options); + yield; - return new Promise((succeed, fail) => { + return new Promise((succeed, fail) => { const compiler = webpackInstance(config); compiler.run((error, stats) => { @@ -129,7 +180,15 @@ export const build: WebpackBuilder['build'] = async ({ options, startTime }) => } if (stats && (stats.hasErrors() || stats.hasWarnings())) { - const { warnings = [], errors = [] } = stats.toJson({ warnings: true, errors: true }); + const { warnings = [], errors = [] } = stats.toJson( + typeof config.stats === 'string' + ? config.stats + : { + warnings: true, + errors: true, + ...(config.stats as StatsOptions), + } + ); errors.forEach((e) => logger.error(e.message)); warnings.forEach((e) => logger.error(e.message)); @@ -162,5 +221,29 @@ export const build: WebpackBuilder['build'] = async ({ options, startTime }) => }); }; +export const start = async (options: BuilderStartOptions) => { + asyncIterator = starter(options); + let result; + + do { + // eslint-disable-next-line no-await-in-loop + result = await asyncIterator.next(); + } while (!result.done); + + return result.value; +}; + +export const build = async (options: BuilderStartOptions) => { + asyncIterator = builder(options); + let result; + + do { + // eslint-disable-next-line no-await-in-loop + result = await asyncIterator.next(); + } while (!result.done); + + return result.value; +}; + export const corePresets = [require.resolve('./presets/preview-preset.js')]; export const overridePresets = [require.resolve('./presets/custom-webpack-preset.js')]; diff --git a/lib/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars b/lib/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars index c7b3025c4b7a..30df5e4c4248 100644 --- a/lib/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars +++ b/lib/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars @@ -1,6 +1,7 @@ import global from 'global'; -import { composeConfigs, PreviewWeb } from '@storybook/preview-web'; +import { PreviewWeb } from '@storybook/preview-web'; +import { composeConfigs } from '@storybook/store'; import { ClientApi } from '@storybook/client-api'; import { addons } from '@storybook/addons'; import createPostMessageChannel from '@storybook/channel-postmessage'; diff --git a/lib/channel-postmessage/package.json b/lib/channel-postmessage/package.json index 76537b88f1a5..b7e7f1538803 100644 --- a/lib/channel-postmessage/package.json +++ b/lib/channel-postmessage/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channel-postmessage", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "", "keywords": [ "storybook" @@ -40,9 +40,9 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", "core-js": "^3.8.2", "global": "^4.4.0", "qs": "^6.10.0", @@ -51,6 +51,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/channel-websocket/package.json b/lib/channel-websocket/package.json index 9e7f443bb755..a4ebf12f0751 100644 --- a/lib/channel-websocket/package.json +++ b/lib/channel-websocket/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channel-websocket", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "", "keywords": [ "storybook" @@ -40,8 +40,8 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", "core-js": "^3.8.2", "global": "^4.4.0", "telejson": "^5.3.3" @@ -49,6 +49,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/channels/package.json b/lib/channels/package.json index 4247059d2006..8239b3e9fc74 100644 --- a/lib/channels/package.json +++ b/lib/channels/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channels", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "", "keywords": [ "storybook" @@ -47,6 +47,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/cli-sb/package.json b/lib/cli-sb/package.json index c40ab6e46193..2bab60861dc5 100644 --- a/lib/cli-sb/package.json +++ b/lib/cli-sb/package.json @@ -1,6 +1,6 @@ { "name": "sb", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook CLI", "keywords": [ "storybook" @@ -24,10 +24,10 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/cli": "6.5.0-alpha.48" + "@storybook/cli": "6.5.0-beta.2" }, "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762" + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061" } diff --git a/lib/cli-storybook/package.json b/lib/cli-storybook/package.json index 7fe9a0cd8705..4ce8af064a9b 100644 --- a/lib/cli-storybook/package.json +++ b/lib/cli-storybook/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook CLI", "keywords": [ "storybook" @@ -27,10 +27,10 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/cli": "6.5.0-alpha.48" + "@storybook/cli": "6.5.0-beta.2" }, "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762" + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061" } diff --git a/lib/cli/package.json b/lib/cli/package.json index 06f4e293a03f..2e36d755ec0e 100644 --- a/lib/cli/package.json +++ b/lib/cli/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/cli", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook's CLI - easiest method of adding storybook to your projects", "keywords": [ "cli", @@ -47,11 +47,12 @@ "dependencies": { "@babel/core": "^7.12.10", "@babel/preset-env": "^7.12.11", - "@storybook/codemod": "6.5.0-alpha.48", - "@storybook/core-common": "6.5.0-alpha.48", - "@storybook/csf-tools": "6.5.0-alpha.48", - "@storybook/node-logger": "6.5.0-alpha.48", + "@storybook/codemod": "6.5.0-beta.2", + "@storybook/core-common": "6.5.0-beta.2", + "@storybook/csf-tools": "6.5.0-beta.2", + "@storybook/node-logger": "6.5.0-beta.2", "@storybook/semver": "^7.3.2", + "@storybook/telemetry": "6.5.0-beta.2", "boxen": "^5.1.2", "chalk": "^4.1.0", "commander": "^6.2.1", @@ -75,7 +76,7 @@ "update-notifier": "^5.0.1" }, "devDependencies": { - "@storybook/client-api": "6.5.0-alpha.48", + "@storybook/client-api": "6.5.0-beta.2", "@types/cross-spawn": "^6.0.2", "@types/prompts": "^2.0.9", "@types/puppeteer-core": "^2.1.0", @@ -91,5 +92,5 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762" + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061" } diff --git a/lib/cli/scripts/generate-sb-packages-versions.js b/lib/cli/scripts/generate-sb-packages-versions.js index 0f181d64e0ad..aab6c42ccb0e 100755 --- a/lib/cli/scripts/generate-sb-packages-versions.js +++ b/lib/cli/scripts/generate-sb-packages-versions.js @@ -1,6 +1,7 @@ #!/usr/bin/env node const { readJson, writeFile } = require('fs-extra'); +const { exec } = require('child_process'); const path = require('path'); const globby = require('globby'); const semver = require('@storybook/semver'); @@ -47,6 +48,10 @@ const run = async () => { export default ${JSON.stringify(packageToVersionMap, null, 2)} ` ); + + exec(`yarn lint:js:cmd --fix ${path.join(__dirname, '..', 'src', 'versions.ts')}`, { + cwd: path.join(__dirname, '..', '..', '..'), + }); }; run().catch((e) => { diff --git a/lib/cli/src/add.test.ts b/lib/cli/src/add.test.ts index 261c6626b11b..d6632443ea49 100644 --- a/lib/cli/src/add.test.ts +++ b/lib/cli/src/add.test.ts @@ -9,13 +9,13 @@ import { describe('addStorybookAddonToFile should correctly register an Storybook addon', () => { test('to an empty array', () => { expect(addStorybookAddonToFile('addon-name', [], true)).toEqual([ - `import '${storybookAddonScope}addon-name/register';`, + `import '${storybookAddonScope}addon-name/manager';`, ]); }); test('to an empty file', () => { expect(addStorybookAddonToFile('addon-name', [''], true)).toEqual([ - `import '${storybookAddonScope}addon-name/register';`, + `import '${storybookAddonScope}addon-name/manager';`, '', ]); }); @@ -25,16 +25,16 @@ describe('addStorybookAddonToFile should correctly register an Storybook addon', addStorybookAddonToFile( 'addon-name', [ - "import '@storybook/addon-actions/register';", - "import '@storybook/addon-links/register';", + "import '@storybook/addon-actions/manager';", + "import '@storybook/addon-links/manager';", '', ], true ) ).toEqual([ - "import '@storybook/addon-actions/register';", - "import '@storybook/addon-links/register';", - `import '${storybookAddonScope}addon-name/register';`, + `import '${storybookAddonScope}addon-name/manager';`, + "import '@storybook/addon-actions/manager';", + "import '@storybook/addon-links/manager';", '', ]); }); @@ -44,8 +44,8 @@ describe('addStorybookAddonToFile should correctly register an Storybook addon', addStorybookAddonToFile( 'addon-name', [ - "import '@storybook/addon-links/register';", - "import '@storybook/addon-actions/register';", + "import '@storybook/addon-links/manager';", + "import '@storybook/addon-actions/manager';", '', '//some other stuff', '', @@ -55,9 +55,9 @@ describe('addStorybookAddonToFile should correctly register an Storybook addon', true ) ).toEqual([ - "import '@storybook/addon-links/register';", - "import '@storybook/addon-actions/register';", - `import '${storybookAddonScope}addon-name/register';`, + `import '${storybookAddonScope}addon-name/manager';`, + "import '@storybook/addon-links/manager';", + "import '@storybook/addon-actions/manager';", '', '//some other stuff', '', @@ -71,17 +71,17 @@ describe('addStorybookAddonToFile should correctly register an Storybook addon', addStorybookAddonToFile( 'addon-name', [ - "import '@storybook/addon-actions/register';", - "import '@storybook/addon-links/register';", - `import '${storybookAddonScope}addon-name/register';`, + "import '@storybook/addon-actions/manager';", + "import '@storybook/addon-links/manager';", + `import '${storybookAddonScope}addon-name/manager';`, '', ], true ) ).toEqual([ - "import '@storybook/addon-actions/register';", - "import '@storybook/addon-links/register';", - `import '${storybookAddonScope}addon-name/register';`, + "import '@storybook/addon-actions/manager';", + "import '@storybook/addon-links/manager';", + `import '${storybookAddonScope}addon-name/manager';`, '', ]); }); @@ -91,16 +91,16 @@ describe('addStorybookAddonToFile should correctly register an Storybook addon', addStorybookAddonToFile( 'addon-name', [ - "import '@storybook/addon-actions/register';", - "import '@storybook/addon-links/register';", + "import '@storybook/addon-actions/manager';", + "import '@storybook/addon-links/manager';", '', ], false ) ).toEqual([ - "import '@storybook/addon-actions/register';", - "import '@storybook/addon-links/register';", - `import 'addon-name/register';`, + `import 'addon-name/manager';`, + "import '@storybook/addon-actions/manager';", + "import '@storybook/addon-links/manager';", '', ]); }); diff --git a/lib/cli/src/add.ts b/lib/cli/src/add.ts index 300a23039668..f6fb63e3787b 100644 --- a/lib/cli/src/add.ts +++ b/lib/cli/src/add.ts @@ -79,7 +79,7 @@ export const addStorybookAddonToFile = ( isOfficialAddon: boolean ) => { const addonNameNoTag = addonName.split('@')[0]; - const alreadyRegistered = addonsFile.find((line) => line.includes(`${addonNameNoTag}/register`)); + const alreadyRegistered = addonsFile.find((line) => line.includes(`${addonNameNoTag}/manager`)); if (alreadyRegistered) { return addonsFile; @@ -93,7 +93,7 @@ export const addStorybookAddonToFile = ( return [ ...addonsFile.slice(0, latestImportIndex + 1), - `import '${getPackageName(addonNameNoTag, isOfficialAddon)}/register';`, + `import '${getPackageName(addonNameNoTag, isOfficialAddon)}/manager';`, ...addonsFile.slice(latestImportIndex + 1), ]; }; diff --git a/lib/cli/src/automigrate/fixes/builder-vite.test.ts b/lib/cli/src/automigrate/fixes/builder-vite.test.ts new file mode 100644 index 000000000000..aa21e490b8af --- /dev/null +++ b/lib/cli/src/automigrate/fixes/builder-vite.test.ts @@ -0,0 +1,52 @@ +/* eslint-disable no-underscore-dangle */ +import path from 'path'; +import { JsPackageManager } from '../../js-package-manager'; +import { builderVite } from './builder-vite'; + +// eslint-disable-next-line global-require, jest/no-mocks-import +jest.mock('fs-extra', () => require('../../../../../__mocks__/fs-extra')); + +const checkBuilderVite = async ({ packageJson = {}, main }) => { + // eslint-disable-next-line global-require + require('fs-extra').__setMockFiles({ + [path.join('.storybook', 'main.js')]: `module.exports = ${JSON.stringify(main)};`, + }); + const packageManager = { + retrievePackageJson: () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), + } as JsPackageManager; + return builderVite.check({ packageManager }); +}; + +describe('builder-vite fix', () => { + describe('storybook-builder-vite', () => { + it('using storybook-builder-vite', async () => { + const main = { core: { builder: 'storybook-builder-vite' } }; + await expect(checkBuilderVite({ main })).resolves.toMatchObject({ + builder: 'storybook-builder-vite', + }); + }); + it('using storybook-builder-vite with options', async () => { + const main = { core: { builder: { name: 'storybook-builder-vite', options: {} } } }; + await expect(checkBuilderVite({ main })).resolves.toMatchObject({ + builder: { + name: 'storybook-builder-vite', + options: {}, + }, + }); + }); + }); + describe('other builders', () => { + it('using @storybook/builder-vite', async () => { + const main = { core: { builder: { name: '@storybook/builder-vite', options: {} } } }; + await expect(checkBuilderVite({ main })).resolves.toBeFalsy(); + }); + it('using webpack5', async () => { + const main = { core: { builder: 'webpack5' } }; + await expect(checkBuilderVite({ main })).resolves.toBeFalsy(); + }); + it('no builder specified', async () => { + const main = {}; + await expect(checkBuilderVite({ main })).resolves.toBeFalsy(); + }); + }); +}); diff --git a/lib/cli/src/automigrate/fixes/builder-vite.ts b/lib/cli/src/automigrate/fixes/builder-vite.ts new file mode 100644 index 000000000000..9c8d382b7210 --- /dev/null +++ b/lib/cli/src/automigrate/fixes/builder-vite.ts @@ -0,0 +1,93 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; + +import { ConfigFile, readConfig, writeConfig } from '@storybook/csf-tools'; +import { getStorybookInfo } from '@storybook/core-common'; + +import { Fix } from '../types'; +import { PackageJson, writePackageJson } from '../../js-package-manager'; + +const logger = console; + +interface BuilderViteOptions { + builder: any; + main: ConfigFile; + packageJson: PackageJson; +} + +/** + * Is the user using 'storybook-builder-vite' in their project? + * + * If so, prompt them to upgrade to '@storybook/builder-vite'. + * + * - Add '@storybook/builder-vite' as dev dependency + * - Remove 'storybook-builder-vite' dependency + * - Add core.builder = '@storybook/builder-vite' to main.js + */ +export const builderVite: Fix = { + id: 'builder-vite', + + async check({ packageManager }) { + const packageJson = packageManager.retrievePackageJson(); + const { mainConfig } = getStorybookInfo(packageJson); + if (!mainConfig) { + logger.warn('Unable to find storybook main.js config'); + return null; + } + const main = await readConfig(mainConfig); + const builder = main.getFieldValue(['core', 'builder']); + const builderName = typeof builder === 'string' ? builder : builder?.name; + + if (builderName !== 'storybook-builder-vite') { + return null; + } + + return { builder, main, packageJson }; + }, + + prompt({ builder }) { + const builderFormatted = chalk.cyan(JSON.stringify(builder, null, 2)); + + return dedent` + We've detected you're using the community vite builder: ${builderFormatted} + + 'storybook-builder-vite' is deprecated and now located at ${chalk.cyan( + '@storybook/builder-vite' + )}. + + We can upgrade your project to use the new builder automatically. + + More info: ${chalk.yellow( + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vite-builder-renamed' + )} + `; + }, + + async run({ result: { builder, main, packageJson }, packageManager, dryRun }) { + const { dependencies = {}, devDependencies = {} } = packageJson; + + logger.info(`Removing existing 'storybook-builder-vite' dependency`); + if (!dryRun) { + delete dependencies['storybook-builder-vite']; + delete devDependencies['storybook-builder-vite']; + writePackageJson(packageJson); + } + + logger.info(`Adding '@storybook/builder-vite' as dev dependency`); + if (!dryRun) { + packageManager.addDependencies({ installAsDevDependencies: true }, [ + '@storybook/builder-vite', + ]); + } + + logger.info(`Updating main.js to use vite builder`); + if (!dryRun) { + const updatedBuilder = + typeof builder === 'string' + ? '@storybook/builder-vite' + : { name: '@storybook/builder-vite', options: builder.options }; + main.setFieldValue(['core', 'builder'], updatedBuilder); + await writeConfig(main); + } + }, +}; diff --git a/lib/cli/src/automigrate/fixes/eslint-plugin.ts b/lib/cli/src/automigrate/fixes/eslint-plugin.ts index dd6e9351066b..431038bc4133 100644 --- a/lib/cli/src/automigrate/fixes/eslint-plugin.ts +++ b/lib/cli/src/automigrate/fixes/eslint-plugin.ts @@ -1,9 +1,9 @@ import chalk from 'chalk'; import dedent from 'ts-dedent'; import { ConfigFile, readConfig, writeConfig } from '@storybook/csf-tools'; +import { getStorybookInfo } from '@storybook/core-common'; import { findEslintFile, SUPPORTED_ESLINT_EXTENSIONS } from '../helpers/getEslintInfo'; -import { getStorybookInfo } from '../helpers/getStorybookInfo'; import type { Fix } from '../types'; diff --git a/lib/cli/src/automigrate/fixes/index.ts b/lib/cli/src/automigrate/fixes/index.ts index 2a30b3725dce..8af1741b392f 100644 --- a/lib/cli/src/automigrate/fixes/index.ts +++ b/lib/cli/src/automigrate/fixes/index.ts @@ -3,7 +3,8 @@ import { webpack5 } from './webpack5'; import { angular12 } from './angular12'; import { mainjsFramework } from './mainjsFramework'; import { eslintPlugin } from './eslint-plugin'; +import { builderVite } from './builder-vite'; import { Fix } from '../types'; export * from '../types'; -export const fixes: Fix[] = [cra5, webpack5, angular12, mainjsFramework, eslintPlugin]; +export const fixes: Fix[] = [cra5, webpack5, angular12, mainjsFramework, eslintPlugin, builderVite]; diff --git a/lib/cli/src/automigrate/fixes/mainjsFramework.ts b/lib/cli/src/automigrate/fixes/mainjsFramework.ts index e074a9cd5857..15a67e3ac674 100644 --- a/lib/cli/src/automigrate/fixes/mainjsFramework.ts +++ b/lib/cli/src/automigrate/fixes/mainjsFramework.ts @@ -3,8 +3,8 @@ import dedent from 'ts-dedent'; import semver from '@storybook/semver'; import { ConfigFile, readConfig, writeConfig } from '@storybook/csf-tools'; +import { getStorybookInfo } from '@storybook/core-common'; -import { getStorybookInfo } from '../helpers/getStorybookInfo'; import { Fix } from '../types'; const logger = console; diff --git a/lib/cli/src/automigrate/fixes/webpack5.ts b/lib/cli/src/automigrate/fixes/webpack5.ts index 323c3a064fc7..de27e2914516 100644 --- a/lib/cli/src/automigrate/fixes/webpack5.ts +++ b/lib/cli/src/automigrate/fixes/webpack5.ts @@ -2,8 +2,8 @@ import chalk from 'chalk'; import dedent from 'ts-dedent'; import semver from '@storybook/semver'; import { ConfigFile, readConfig, writeConfig } from '@storybook/csf-tools'; +import { getStorybookInfo } from '@storybook/core-common'; import { Fix } from '../types'; -import { getStorybookInfo } from '../helpers/getStorybookInfo'; import { PackageJsonWithDepsAndDevDeps } from '../../js-package-manager'; const logger = console; diff --git a/lib/cli/src/detect.test.ts b/lib/cli/src/detect.test.ts index 7c3a30cbccdb..11303ab1436f 100644 --- a/lib/cli/src/detect.test.ts +++ b/lib/cli/src/detect.test.ts @@ -15,6 +15,9 @@ jest.mock('./js-package-manager', () => ({ jest.mock('fs', () => ({ existsSync: jest.fn(), + stat: jest.fn(), + lstat: jest.fn(), + access: jest.fn(), })); jest.mock('path', () => ({ diff --git a/lib/cli/src/detect.ts b/lib/cli/src/detect.ts index a3eaa416f8eb..a53dcfe00e39 100644 --- a/lib/cli/src/detect.ts +++ b/lib/cli/src/detect.ts @@ -1,5 +1,6 @@ import path from 'path'; import fs from 'fs'; +import findUp from 'find-up'; import { ProjectType, @@ -9,9 +10,12 @@ import { TemplateConfiguration, TemplateMatcher, unsupportedTemplate, + CoreBuilder, } from './project_types'; -import { getBowerJson } from './helpers'; -import { PackageJson, readPackageJson } from './js-package-manager'; +import { getBowerJson, paddedLog } from './helpers'; +import { PackageJson, readPackageJson, JsPackageManager } from './js-package-manager'; + +const viteConfigFiles = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs']; const hasDependency = ( packageJson: PackageJson, @@ -86,7 +90,7 @@ const getFrameworkPreset = ( return matcherFunction(matcher) ? preset : null; }; -export function detectFrameworkPreset(packageJson = {}) { +export function detectFrameworkPreset(packageJson = {} as PackageJson) { const result = [...supportedTemplates, unsupportedTemplate].find((framework) => { return getFrameworkPreset(packageJson, framework) !== null; }); @@ -94,6 +98,51 @@ export function detectFrameworkPreset(packageJson = {}) { return result ? result.preset : ProjectType.UNDETECTED; } +/** + * Attempts to detect which builder to use, by searching for a vite config file. If one is found, the vite builder + * will be used, otherwise, webpack4 is the default. + * + * @returns CoreBuilder + */ +export function detectBuilder(packageManager: JsPackageManager) { + const viteConfig = findUp.sync(viteConfigFiles); + + if (viteConfig) { + paddedLog('Detected vite project, setting builder to @storybook/builder-vite'); + return CoreBuilder.Vite; + } + + try { + let out = ''; + if (packageManager.type === 'npm') { + try { + // npm <= v7 + out = packageManager.executeCommand('npm', ['ls', 'webpack']); + } catch (e2) { + // npm >= v8 + out = packageManager.executeCommand('npm', ['why', 'webpack']); + } + } else { + out = packageManager.executeCommand('yarn', ['why', 'webpack']); + } + + // if the user has BOTH webpack 4 and 5 installed already, we'll pick the safest options (4) + if (out.includes('webpack@4') || out.includes('webpack@npm:4')) { + return CoreBuilder.Webpack5; + } + + // the user has webpack 4 installed, but not 5 + if (out.includes('webpack@5') || out.includes('webpack@npm:5')) { + return CoreBuilder.Webpack5; + } + } catch (err) { + // + } + + // Fallback to webpack4 + return CoreBuilder.Webpack4; +} + export function isStorybookInstalled(dependencies: PackageJson | false, force?: boolean) { if (!dependencies) { return false; @@ -122,7 +171,12 @@ export function isStorybookInstalled(dependencies: PackageJson | false, force?: export function detectLanguage() { let language = SupportedLanguage.JAVASCRIPT; - const packageJson = readPackageJson(); + let packageJson; + try { + packageJson = readPackageJson(); + } catch (err) { + // + } const bowerJson = getBowerJson(); if (!packageJson && !bowerJson) { return language; @@ -136,7 +190,12 @@ export function detectLanguage() { } export function detect(options: { force?: boolean; html?: boolean } = {}) { - const packageJson = readPackageJson(); + let packageJson; + try { + packageJson = readPackageJson(); + } catch (err) { + // + } const bowerJson = getBowerJson(); if (!packageJson && !bowerJson) { diff --git a/lib/cli/src/frameworks/html/js/Header.js b/lib/cli/src/frameworks/html/js/Header.js index 80c413d022d5..925652350ede 100644 --- a/lib/cli/src/frameworks/html/js/Header.js +++ b/lib/cli/src/frameworks/html/js/Header.js @@ -26,6 +26,8 @@ export const createHeader = ({ user, onLogout, onLogin, onCreateAccount }) => { const account = document.createElement('div'); if (user) { + const welcomeMessage = `Welcome, ${user.name}!`; + account.innerHTML = welcomeMessage; account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout })); } else { account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin })); diff --git a/lib/cli/src/frameworks/html/js/Header.stories.js b/lib/cli/src/frameworks/html/js/Header.stories.js index f5f9ce67b81d..553f3f8760f2 100644 --- a/lib/cli/src/frameworks/html/js/Header.stories.js +++ b/lib/cli/src/frameworks/html/js/Header.stories.js @@ -2,6 +2,11 @@ import { createHeader } from './Header'; export default { title: 'Example/Header', + parameters: { + // More on Story layout: https://storybook.js.org/docs/html/configure/story-layout + layout: 'fullscreen', + }, + // More on argTypes: https://storybook.js.org/docs/html/api/argtypes argTypes: { onLogin: { action: 'onLogin' }, onLogout: { action: 'onLogout' }, @@ -13,7 +18,9 @@ const Template = (args) => createHeader(args); export const LoggedIn = Template.bind({}); LoggedIn.args = { - user: {}, + user: { + name: 'Jane Doe', + }, }; export const LoggedOut = Template.bind({}); diff --git a/lib/cli/src/frameworks/html/js/Page.js b/lib/cli/src/frameworks/html/js/Page.js index 1ea39188f2ef..a2b56d7cd5f6 100644 --- a/lib/cli/src/frameworks/html/js/Page.js +++ b/lib/cli/src/frameworks/html/js/Page.js @@ -1,11 +1,38 @@ import './page.css'; import { createHeader } from './Header'; -export const createPage = ({ user, onLogout, onLogin, onCreateAccount }) => { +export const createPage = () => { const article = document.createElement('article'); + let user = null; + let header = null; - const header = createHeader({ onLogin, onLogout, onCreateAccount, user }); + const rerenderHeader = () => { + const wrapper = document.getElementsByTagName('article')[0]; + wrapper.replaceChild(createHeaderElement(), wrapper.firstChild); + }; + + const onLogin = () => { + user = { name: 'Jane Doe' }; + rerenderHeader(); + }; + + const onLogout = () => { + user = null; + rerenderHeader(); + }; + + const onCreateAccount = () => { + user = { name: 'Jane Doe' }; + rerenderHeader(); + }; + + const createHeaderElement = () => { + return createHeader({ onLogin, onLogout, onCreateAccount, user }); + }; + + header = createHeaderElement(); article.appendChild(header); + const section = `

Pages in Storybook

diff --git a/lib/cli/src/frameworks/html/js/Page.stories.js b/lib/cli/src/frameworks/html/js/Page.stories.js index 33ccf9eb9406..3305bde25d9e 100644 --- a/lib/cli/src/frameworks/html/js/Page.stories.js +++ b/lib/cli/src/frameworks/html/js/Page.stories.js @@ -1,24 +1,23 @@ +import { within, userEvent } from '@storybook/testing-library'; import { createPage } from './Page'; -import * as HeaderStories from './Header.stories'; export default { title: 'Example/Page', - argTypes: { - onLogin: { action: 'onLogin' }, - onLogout: { action: 'onLogout' }, - onCreateAccount: { action: 'onCreateAccount' }, + parameters: { + // More on Story layout: https://storybook.js.org/docs/html/configure/story-layout + layout: 'fullscreen', }, }; -const Template = (args) => createPage(args); +const Template = () => createPage(); + +export const LoggedOut = Template.bind({}); export const LoggedIn = Template.bind({}); -LoggedIn.args = { - // More on composing args: https://storybook.js.org/docs/html/writing-stories/args#args-composition - ...HeaderStories.LoggedIn.args, -}; -export const LoggedOut = Template.bind({}); -LoggedOut.args = { - ...HeaderStories.LoggedOut.args, +// More on interaction testing: https://storybook.js.org/docs/html/writing-tests/interaction-testing +LoggedIn.play = async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = await canvas.getByRole('button', { name: /Log in/i }); + await userEvent.click(loginButton); }; diff --git a/lib/cli/src/frameworks/html/ts/Header.stories.ts b/lib/cli/src/frameworks/html/ts/Header.stories.ts index 476dfd5b89c4..a727dffbee22 100644 --- a/lib/cli/src/frameworks/html/ts/Header.stories.ts +++ b/lib/cli/src/frameworks/html/ts/Header.stories.ts @@ -3,6 +3,11 @@ import { createHeader, HeaderProps } from './Header'; export default { title: 'Example/Header', + parameters: { + // More on Story layout: https://storybook.js.org/docs/html/configure/story-layout + layout: 'fullscreen', + }, + // More on argTypes: https://storybook.js.org/docs/html/api/argtypes argTypes: { onLogin: { action: 'onLogin' }, onLogout: { action: 'onLogout' }, diff --git a/lib/cli/src/frameworks/html/ts/Header.ts b/lib/cli/src/frameworks/html/ts/Header.ts index f7ec96862742..94a31e6b5317 100644 --- a/lib/cli/src/frameworks/html/ts/Header.ts +++ b/lib/cli/src/frameworks/html/ts/Header.ts @@ -2,7 +2,7 @@ import './header.css'; import { createButton } from './Button'; export interface HeaderProps { - user?: {}; + user?: { name: string }; onLogin: () => void; onLogout: () => void; onCreateAccount: () => void; @@ -33,6 +33,8 @@ export const createHeader = ({ user, onLogout, onLogin, onCreateAccount }: Heade const account = document.createElement('div'); if (user) { + const welcomeMessage = `Welcome, ${user.name}!`; + account.innerHTML = welcomeMessage; account.appendChild(createButton({ size: 'small', label: 'Log out', onClick: onLogout })); } else { account.appendChild(createButton({ size: 'small', label: 'Log in', onClick: onLogin })); diff --git a/lib/cli/src/frameworks/html/ts/Page.stories.ts b/lib/cli/src/frameworks/html/ts/Page.stories.ts index 995905c126ae..bc7b6cdbe0e4 100644 --- a/lib/cli/src/frameworks/html/ts/Page.stories.ts +++ b/lib/cli/src/frameworks/html/ts/Page.stories.ts @@ -1,26 +1,24 @@ +import { within, userEvent } from '@storybook/testing-library'; import { Story, Meta } from '@storybook/html'; import { createPage } from './Page'; -import * as HeaderStories from './Header.stories'; -import { HeaderProps } from './Header'; export default { title: 'Example/Page', - argTypes: { - onLogin: { action: 'onLogin' }, - onLogout: { action: 'onLogout' }, - onCreateAccount: { action: 'onCreateAccount' }, + parameters: { + // More on Story layout: https://storybook.js.org/docs/html/configure/story-layout + layout: 'fullscreen', }, } as Meta; -const Template: Story = (args) => createPage(args); +const Template: Story = () => createPage(); + +export const LoggedOut = Template.bind({}); export const LoggedIn = Template.bind({}); -LoggedIn.args = { - // More on composing args: https://storybook.js.org/docs/html/writing-stories/args#args-composition - ...HeaderStories.LoggedIn.args, -}; -export const LoggedOut = Template.bind({}); -LoggedOut.args = { - ...HeaderStories.LoggedOut.args, +// More on interaction testing: https://storybook.js.org/docs/html/writing-tests/interaction-testing +LoggedIn.play = async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = await canvas.getByRole('button', { name: /Log in/i }); + await userEvent.click(loginButton); }; diff --git a/lib/cli/src/frameworks/html/ts/Page.ts b/lib/cli/src/frameworks/html/ts/Page.ts index bbccd64ada59..5c66149c82b5 100644 --- a/lib/cli/src/frameworks/html/ts/Page.ts +++ b/lib/cli/src/frameworks/html/ts/Page.ts @@ -1,18 +1,42 @@ import './page.css'; import { createHeader } from './Header'; -export interface PageProps { - user?: {}; - onLogin: () => void; - onLogout: () => void; - onCreateAccount: () => void; -} +type User = { + name: string; +}; -export const createPage = ({ user, onLogout, onLogin, onCreateAccount }: PageProps) => { +export const createPage = () => { const article = document.createElement('article'); + let user: User = null; + let header = null; + + const rerenderHeader = () => { + const wrapper = document.getElementsByTagName('article')[0]; + wrapper.replaceChild(createHeaderElement(), wrapper.firstChild); + }; + + const onLogin = () => { + user = { name: 'Jane Doe' }; + rerenderHeader(); + }; + + const onLogout = () => { + user = null; + rerenderHeader(); + }; - const header = createHeader({ onLogin, onLogout, onCreateAccount, user }); + const onCreateAccount = () => { + user = { name: 'Jane Doe' }; + rerenderHeader(); + }; + + const createHeaderElement = () => { + return createHeader({ onLogin, onLogout, onCreateAccount, user }); + }; + + header = createHeaderElement(); article.appendChild(header); + const section = `

Pages in Storybook

diff --git a/lib/cli/src/frameworks/preact/Header.jsx b/lib/cli/src/frameworks/preact/Header.jsx index f425ec15286d..06580039741c 100644 --- a/lib/cli/src/frameworks/preact/Header.jsx +++ b/lib/cli/src/frameworks/preact/Header.jsx @@ -29,7 +29,12 @@ export const Header = ({ user, onLogin, onLogout, onCreateAccount }) => (
{user ? ( -
{#if user} + + Welcome, {user.name}! +
+ Welcome, {{ user.name }}! diff --git a/lib/cli/src/frameworks/vue/Page.stories.js b/lib/cli/src/frameworks/vue/Page.stories.js index 296bf4485cd6..fd168a48d3fa 100644 --- a/lib/cli/src/frameworks/vue/Page.stories.js +++ b/lib/cli/src/frameworks/vue/Page.stories.js @@ -1,25 +1,27 @@ +import { within, userEvent } from '@storybook/testing-library'; + import MyPage from './Page'; -import * as HeaderStories from './Header.stories'; export default { title: 'Example/Page', component: MyPage, + parameters: { + // More on Story layout: https://storybook.js.org/docs/vue/configure/story-layout + layout: 'fullscreen', + }, }; -const Template = (args, { argTypes }) => ({ - props: Object.keys(argTypes), +const Template = () => ({ components: { MyPage }, - template: - '', + template: '', }); -export const LoggedIn = Template.bind({}); -LoggedIn.args = { - // More on composing args: https://storybook.js.org/docs/vue/writing-stories/args#args-composition - ...HeaderStories.LoggedIn.args, -}; - export const LoggedOut = Template.bind({}); -LoggedOut.args = { - ...HeaderStories.LoggedOut.args, + +// More on interaction testing: https://storybook.js.org/docs/vue/writing-tests/interaction-testing +export const LoggedIn = Template.bind({}); +LoggedIn.play = async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = await canvas.getByRole('button', { name: /Log in/i }); + await userEvent.click(loginButton); }; diff --git a/lib/cli/src/frameworks/vue/Page.vue b/lib/cli/src/frameworks/vue/Page.vue index 987b8b9f318f..5a45445ed909 100644 --- a/lib/cli/src/frameworks/vue/Page.vue +++ b/lib/cli/src/frameworks/vue/Page.vue @@ -67,21 +67,21 @@ export default { components: { MyHeader }, - props: { - user: { - type: Object, - }, + data() { + return { + user: null, + }; }, methods: { onLogin() { - this.$emit('onLogin'); + this.user = { name: 'Jane Doe' }; }, onLogout() { - this.$emit('onLogout'); + this.user = null; }, onCreateAccount() { - this.$emit('onCreateAccount'); + this.user = { name: 'Jane Doe' }; }, }, }; diff --git a/lib/cli/src/frameworks/vue3/Header.stories.js b/lib/cli/src/frameworks/vue3/Header.stories.js index eb7826516b69..8cda9abc0324 100644 --- a/lib/cli/src/frameworks/vue3/Header.stories.js +++ b/lib/cli/src/frameworks/vue3/Header.stories.js @@ -3,6 +3,10 @@ import MyHeader from './Header.vue'; export default { title: 'Example/Header', component: MyHeader, + parameters: { + // More on Story layout: https://storybook.js.org/docs/vue/configure/story-layout + layout: 'fullscreen', + }, }; const Template = (args) => ({ @@ -19,7 +23,9 @@ const Template = (args) => ({ export const LoggedIn = Template.bind({}); LoggedIn.args = { - user: {}, + user: { + name: 'Jane Doe', + }, }; export const LoggedOut = Template.bind({}); diff --git a/lib/cli/src/frameworks/vue3/Header.vue b/lib/cli/src/frameworks/vue3/Header.vue index eec3f73b6057..6ed4a66994ff 100644 --- a/lib/cli/src/frameworks/vue3/Header.vue +++ b/lib/cli/src/frameworks/vue3/Header.vue @@ -21,6 +21,7 @@

Acme

+ Welcome, {{ user.name }}! diff --git a/lib/cli/src/frameworks/vue3/Page.stories.js b/lib/cli/src/frameworks/vue3/Page.stories.js index 16ea39548276..ef6aeafe784d 100644 --- a/lib/cli/src/frameworks/vue3/Page.stories.js +++ b/lib/cli/src/frameworks/vue3/Page.stories.js @@ -1,30 +1,29 @@ +import { within, userEvent } from '@storybook/testing-library'; import MyPage from './Page.vue'; -import * as HeaderStories from './Header.stories'; export default { title: 'Example/Page', component: MyPage, + parameters: { + // More on Story layout: https://storybook.js.org/docs/vue/configure/story-layout + layout: 'fullscreen', + }, }; -const Template = (args) => ({ +const Template = () => ({ // Components used in your story `template` are defined in the `components` object components: { MyPage }, - // The story's `args` need to be mapped into the template through the `setup()` method - setup() { - // Story args can be mapped to keys in the returned object - return { user: args.user }; - }, - // Then, those values can be accessed directly in the template - template: '', -}); -export const LoggedIn = Template.bind({}); -LoggedIn.args = { - // More on composing args: https://storybook.js.org/docs/vue/writing-stories/args#args-composition - ...HeaderStories.LoggedIn.args, -}; + // Here we define the `template` + template: '', +}); export const LoggedOut = Template.bind({}); -LoggedOut.args = { - ...HeaderStories.LoggedOut.args, + +// More on interaction testing: https://storybook.js.org/docs/vue/writing-tests/interaction-testing +export const LoggedIn = Template.bind({}); +LoggedIn.play = async ({ canvasElement }) => { + const canvas = within(canvasElement); + const loginButton = await canvas.getByRole('button', { name: /Log in/i }); + await userEvent.click(loginButton); }; diff --git a/lib/cli/src/frameworks/vue3/Page.vue b/lib/cli/src/frameworks/vue3/Page.vue index f7f238422370..fc5a70d3f348 100644 --- a/lib/cli/src/frameworks/vue3/Page.vue +++ b/lib/cli/src/frameworks/vue3/Page.vue @@ -2,9 +2,9 @@
@@ -67,12 +67,22 @@ export default { components: { MyHeader }, - props: { - user: { - type: Object, - }, + data() { + return { + user: null + } }, - emits: ['login', 'logout', 'createAccount'], + methods: { + onLogin() { + this.user = { name: 'Jane Doe' }; + }, + onLogout() { + this.user = null; + }, + onCreateAccount() { + this.user = { name: 'Jane Doe' }; + }, + }, }; diff --git a/lib/cli/src/generate.ts b/lib/cli/src/generate.ts index 83d7b613497c..f363572de6ce 100644 --- a/lib/cli/src/generate.ts +++ b/lib/cli/src/generate.ts @@ -18,6 +18,15 @@ const pkg = sync({ cwd: __dirname }).packageJson; const logger = console; +program.option( + '--disable-telemetry', + 'disable sending telemetry data', + // default value is false, but if the user sets STORYBOOK_DISABLE_TELEMETRY, it can be true + process.env.STORYBOOK_DISABLE_TELEMETRY && process.env.STORYBOOK_DISABLE_TELEMETRY !== 'false' +); + +program.option('--enable-crash-reports', 'enable sending crash reports to telemetry data'); + program .command('init') .description('Initialize Storybook into your project.') diff --git a/lib/cli/src/generators/ANGULAR/index.ts b/lib/cli/src/generators/ANGULAR/index.ts index 4ac358bd3e87..934ceb6295d5 100644 --- a/lib/cli/src/generators/ANGULAR/index.ts +++ b/lib/cli/src/generators/ANGULAR/index.ts @@ -39,7 +39,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { const isWebpack5 = semver.gte(angularVersion, '12.0.0'); const updatedOptions = isWebpack5 ? { ...options, builder: CoreBuilder.Webpack5 } : options; - baseGenerator(packageManager, npmOptions, updatedOptions, 'angular', { + await baseGenerator(packageManager, npmOptions, updatedOptions, 'angular', { extraPackages: ['@compodoc/compodoc'], addScripts: false, }); diff --git a/lib/cli/src/generators/AURELIA/index.ts b/lib/cli/src/generators/AURELIA/index.ts index 1273aa2d5cb4..c2accccc8945 100644 --- a/lib/cli/src/generators/AURELIA/index.ts +++ b/lib/cli/src/generators/AURELIA/index.ts @@ -19,7 +19,7 @@ function addStorybookExcludeGlobToTsConfig() { const generator: Generator = async (packageManager, npmOptions, options) => { addStorybookExcludeGlobToTsConfig(); - baseGenerator(packageManager, npmOptions, options, 'aurelia', { + await baseGenerator(packageManager, npmOptions, options, 'aurelia', { extraPackages: ['aurelia'], }); copyTemplate(__dirname); diff --git a/lib/cli/src/generators/EMBER/index.ts b/lib/cli/src/generators/EMBER/index.ts index de4d2e9ef3e9..18b2c1a1e694 100644 --- a/lib/cli/src/generators/EMBER/index.ts +++ b/lib/cli/src/generators/EMBER/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'ember', { + await baseGenerator(packageManager, npmOptions, options, 'ember', { extraPackages: [ // babel-plugin-ember-modules-api-polyfill is a peerDep of @storybook/ember 'babel-plugin-ember-modules-api-polyfill', diff --git a/lib/cli/src/generators/HTML/index.ts b/lib/cli/src/generators/HTML/index.ts index 4781087d32bb..9f6b1ae2d347 100755 --- a/lib/cli/src/generators/HTML/index.ts +++ b/lib/cli/src/generators/HTML/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'html'); + await baseGenerator(packageManager, npmOptions, options, 'html'); }; export default generator; diff --git a/lib/cli/src/generators/METEOR/index.ts b/lib/cli/src/generators/METEOR/index.ts index c7894ddab8a1..945cb5b69616 100644 --- a/lib/cli/src/generators/METEOR/index.ts +++ b/lib/cli/src/generators/METEOR/index.ts @@ -3,7 +3,7 @@ import JSON5 from 'json5'; import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'react', { + await baseGenerator(packageManager, npmOptions, options, 'react', { extraPackages: ['react', 'react-dom', '@babel/preset-env', '@babel/preset-react'], staticDir: 'dist', }); diff --git a/lib/cli/src/generators/MITHRIL/index.ts b/lib/cli/src/generators/MITHRIL/index.ts index a693fddcd425..02c513e938b4 100644 --- a/lib/cli/src/generators/MITHRIL/index.ts +++ b/lib/cli/src/generators/MITHRIL/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'mithril'); + await baseGenerator(packageManager, npmOptions, options, 'mithril'); }; export default generator; diff --git a/lib/cli/src/generators/PREACT/index.ts b/lib/cli/src/generators/PREACT/index.ts index 2971849f2230..da2b5df84593 100644 --- a/lib/cli/src/generators/PREACT/index.ts +++ b/lib/cli/src/generators/PREACT/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'preact', { + await baseGenerator(packageManager, npmOptions, options, 'preact', { extraPackages: ['core-js'], }); }; diff --git a/lib/cli/src/generators/RAX/index.ts b/lib/cli/src/generators/RAX/index.ts index ddada20fe727..ad0f82027a53 100644 --- a/lib/cli/src/generators/RAX/index.ts +++ b/lib/cli/src/generators/RAX/index.ts @@ -18,7 +18,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { writePackageJson(packageJson); - baseGenerator(packageManager, npmOptions, options, 'rax', { + await baseGenerator(packageManager, npmOptions, options, 'rax', { extraPackages: ['rax'], }); }; diff --git a/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/addons.js b/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/addons.js index bc646c943eb4..c3f195bdf9ee 100644 --- a/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/addons.js +++ b/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/addons.js @@ -1,3 +1,3 @@ -import '@storybook/addon-actions/register'; -import '@storybook/addon-links/register'; -import '@storybook/addon-knobs/register'; +import '@storybook/addon-actions/manager'; +import '@storybook/addon-links/manager'; +import '@storybook/addon-knobs/manager'; diff --git a/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/rn-addons.js b/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/rn-addons.js index 4d30f923173b..18ce369c70b9 100644 --- a/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/rn-addons.js +++ b/lib/cli/src/generators/REACT_NATIVE/template-csf/storybook/rn-addons.js @@ -1,2 +1,2 @@ -import '@storybook/addon-ondevice-actions/register'; -import '@storybook/addon-ondevice-knobs/register'; +import '@storybook/addon-ondevice-actions/manager'; +import '@storybook/addon-ondevice-knobs/manager'; diff --git a/lib/cli/src/generators/RIOT/index.ts b/lib/cli/src/generators/RIOT/index.ts index 2c5c7f0ab5f9..44e066c4458a 100644 --- a/lib/cli/src/generators/RIOT/index.ts +++ b/lib/cli/src/generators/RIOT/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'riot', { + await baseGenerator(packageManager, npmOptions, options, 'riot', { extraPackages: ['riot-tag-loader'], }); }; diff --git a/lib/cli/src/generators/SERVER/index.ts b/lib/cli/src/generators/SERVER/index.ts index 0d9ae03fc2d3..8f7d65a7be86 100755 --- a/lib/cli/src/generators/SERVER/index.ts +++ b/lib/cli/src/generators/SERVER/index.ts @@ -2,7 +2,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; import { copyTemplate } from '../../helpers'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'server', { + await baseGenerator(packageManager, npmOptions, options, 'server', { extensions: ['json'], }); diff --git a/lib/cli/src/generators/SFC_VUE/index.ts b/lib/cli/src/generators/SFC_VUE/index.ts index 6bdc4a274dd7..a4940458fc59 100644 --- a/lib/cli/src/generators/SFC_VUE/index.ts +++ b/lib/cli/src/generators/SFC_VUE/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'vue'); + await baseGenerator(packageManager, npmOptions, options, 'vue'); }; export default generator; diff --git a/lib/cli/src/generators/VUE/index.ts b/lib/cli/src/generators/VUE/index.ts index c7a2549b8128..2f7ae9658960 100644 --- a/lib/cli/src/generators/VUE/index.ts +++ b/lib/cli/src/generators/VUE/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'vue', { + await baseGenerator(packageManager, npmOptions, options, 'vue', { extraPackages: ['vue-loader@^15.7.0'], }); }; diff --git a/lib/cli/src/generators/VUE3/index.ts b/lib/cli/src/generators/VUE3/index.ts index db9e4e4cab94..098a8f44b274 100644 --- a/lib/cli/src/generators/VUE3/index.ts +++ b/lib/cli/src/generators/VUE3/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'vue3', { + await baseGenerator(packageManager, npmOptions, options, 'vue3', { extraPackages: ['vue-loader@^16.0.0'], }); }; diff --git a/lib/cli/src/generators/WEBPACK_REACT/index.ts b/lib/cli/src/generators/WEBPACK_REACT/index.ts index 89494372f4b2..e7833641b92f 100644 --- a/lib/cli/src/generators/WEBPACK_REACT/index.ts +++ b/lib/cli/src/generators/WEBPACK_REACT/index.ts @@ -1,7 +1,7 @@ import { baseGenerator, Generator } from '../baseGenerator'; const generator: Generator = async (packageManager, npmOptions, options) => { - baseGenerator(packageManager, npmOptions, options, 'react'); + await baseGenerator(packageManager, npmOptions, options, 'react'); }; export default generator; diff --git a/lib/cli/src/generators/baseGenerator.ts b/lib/cli/src/generators/baseGenerator.ts index 926af379e361..1071db277dc2 100644 --- a/lib/cli/src/generators/baseGenerator.ts +++ b/lib/cli/src/generators/baseGenerator.ts @@ -1,4 +1,5 @@ import fse from 'fs-extra'; +import dedent from 'ts-dedent'; import { getStorybookBabelDependencies } from '@storybook/core-common'; import { NpmOptions } from '../NpmOptions'; import { SupportedLanguage, SupportedFrameworks, Builder, CoreBuilder } from '../project_types'; @@ -48,9 +49,11 @@ const defaultOptions: FrameworkOptions = { const builderDependencies = (builder: Builder) => { switch (builder) { case CoreBuilder.Webpack4: - return []; + return ['@storybook/builder-webpack4', '@storybook/manager-webpack4']; case CoreBuilder.Webpack5: return ['@storybook/builder-webpack5', '@storybook/manager-webpack5']; + case CoreBuilder.Vite: + return ['@storybook/builder-vite']; default: return [builder]; } @@ -59,7 +62,7 @@ const builderDependencies = (builder: Builder) => { const stripVersions = (addons: string[]) => addons.map((addon) => getPackageDetails(addon)[0]); const hasInteractiveStories = (framework: SupportedFrameworks) => - ['react', 'angular'].includes(framework); + ['react', 'angular', 'preact', 'svelte', 'vue', 'vue3', 'html'].includes(framework); export async function baseGenerator( packageManager: JsPackageManager, @@ -121,15 +124,28 @@ export async function baseGenerator( const versionedPackages = await packageManager.getVersionedPackages(...packages); + const coreBuilders = [CoreBuilder.Webpack4, CoreBuilder.Webpack5, CoreBuilder.Vite] as string[]; + const expandedBuilder = coreBuilders.includes(builder) + ? `@storybook/builder-${builder}` + : builder; const mainOptions = builder !== CoreBuilder.Webpack4 ? { core: { - builder, + builder: expandedBuilder, }, ...extraMain, } : extraMain; + + // Default vite builder to storyStoreV7 + if (expandedBuilder === '@storybook/builder-vite') { + mainOptions.features = { + ...mainOptions.features, + storyStoreV7: true, + }; + } + configure(framework, { framework: frameworkPackage, addons: [...addons, ...stripVersions(extraAddons)], @@ -141,6 +157,16 @@ export async function baseGenerator( copyComponents(framework, language); } + // FIXME: temporary workaround for https://github.com/storybookjs/storybook/issues/17516 + if (expandedBuilder === '@storybook/builder-vite') { + const previewHead = dedent` + + `; + await fse.writeFile(`.storybook/preview-head.html`, previewHead, { encoding: 'utf8' }); + } + const babelDependencies = addBabel ? await getBabelDependencies(packageManager, packageJson) : []; if (isNewFolder) { babelDependencies.push(...getStorybookBabelDependencies()); diff --git a/lib/cli/src/initiate.ts b/lib/cli/src/initiate.ts index e88673002ccd..3ba05abe5296 100644 --- a/lib/cli/src/initiate.ts +++ b/lib/cli/src/initiate.ts @@ -1,8 +1,9 @@ import { UpdateNotifier, Package } from 'update-notifier'; import chalk from 'chalk'; import prompts from 'prompts'; -import { detect, isStorybookInstalled, detectLanguage } from './detect'; -import { installableProjectTypes, ProjectType, Builder, CoreBuilder } from './project_types'; +import { telemetry } from '@storybook/telemetry'; +import { installableProjectTypes, ProjectType, Builder } from './project_types'; +import { detect, isStorybookInstalled, detectLanguage, detectBuilder } from './detect'; import { commandLog, codeLog, paddedLog } from './helpers'; import angularGenerator from './generators/ANGULAR'; import aureliaGenerator from './generators/AURELIA'; @@ -26,7 +27,7 @@ import preactGenerator from './generators/PREACT'; import svelteGenerator from './generators/SVELTE'; import raxGenerator from './generators/RAX'; import serverGenerator from './generators/SERVER'; -import { JsPackageManagerFactory, readPackageJson } from './js-package-manager'; +import { JsPackageManagerFactory, JsPackageManager } from './js-package-manager'; import { NpmOptions } from './NpmOptions'; import { automigrate } from './automigrate'; @@ -43,11 +44,14 @@ type CommandOptions = { builder?: Builder; linkable?: boolean; commonJs?: boolean; + disableTelemetry?: boolean; }; -const installStorybook = (projectType: ProjectType, options: CommandOptions): Promise => { - const packageManager = JsPackageManagerFactory.getPackageManager(options.useNpm); - +const installStorybook = ( + projectType: ProjectType, + packageManager: JsPackageManager, + options: CommandOptions +): Promise => { const npmOptions: NpmOptions = { installAsDevDependencies: true, skipInstall: options.skipInstall, @@ -57,7 +61,7 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr const generatorOptions = { language, - builder: options.builder || CoreBuilder.Webpack4, + builder: options.builder || detectBuilder(packageManager), linkable: !!options.linkable, commonJs: options.commonJs, }; @@ -92,7 +96,7 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr case ProjectType.UPDATE_PACKAGE_ORGANIZATIONS: return updateOrganisationsGenerator(packageManager, options.parser, npmOptions) .then(() => null) // commandLog doesn't like to see output - .then(commandLog('Upgrading your project to the new Storybook packages.')) + .then(commandLog('Upgrading your project to the new Storybook packages.\n')) .then(end); case ProjectType.REACT_SCRIPTS: @@ -102,7 +106,7 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr case ProjectType.REACT: return reactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "React" app')) + .then(commandLog('Adding Storybook support to your "React" app\n')) .then(end); case ProjectType.REACT_NATIVE: { @@ -120,7 +124,7 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr ]) as Promise<{ server: boolean }>) ) .then(({ server }) => reactNativeGenerator(packageManager, npmOptions, server)) - .then(commandLog('Adding Storybook support to your "React Native" app')) + .then(commandLog('Adding Storybook support to your "React Native" app\n')) .then(end) .then(() => { logger.log(chalk.red('NOTE: installation is not 100% automated.')); @@ -134,97 +138,97 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr case ProjectType.METEOR: return meteorGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Meteor" app')) + .then(commandLog('Adding Storybook support to your "Meteor" app\n')) .then(end); case ProjectType.WEBPACK_REACT: return webpackReactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Webpack React" app')) + .then(commandLog('Adding Storybook support to your "Webpack React" app\n')) .then(end); case ProjectType.REACT_PROJECT: return reactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "React" library')) + .then(commandLog('Adding Storybook support to your "React" library\n')) .then(end); case ProjectType.SFC_VUE: return sfcVueGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Single File Components Vue" app')) + .then(commandLog('Adding Storybook support to your "Single File Components Vue" app\n')) .then(end); case ProjectType.VUE: return vueGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Vue" app')) + .then(commandLog('Adding Storybook support to your "Vue" app\n')) .then(end); case ProjectType.VUE3: return vue3Generator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Vue 3" app')) + .then(commandLog('Adding Storybook support to your "Vue 3" app\n')) .then(end); case ProjectType.ANGULAR: return angularGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Angular" app')) + .then(commandLog('Adding Storybook support to your "Angular" app\n')) .then(end); case ProjectType.EMBER: return emberGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Ember" app')) + .then(commandLog('Adding Storybook support to your "Ember" app\n')) .then(end); case ProjectType.MITHRIL: return mithrilGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Mithril" app')) + .then(commandLog('Adding Storybook support to your "Mithril" app\n')) .then(end); case ProjectType.MARIONETTE: return marionetteGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Marionette.js" app')) + .then(commandLog('Adding Storybook support to your "Marionette.js" app\n')) .then(end); case ProjectType.MARKO: return markoGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Marko" app')) + .then(commandLog('Adding Storybook support to your "Marko" app\n')) .then(end); case ProjectType.HTML: return htmlGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "HTML" app')) + .then(commandLog('Adding Storybook support to your "HTML" app\n')) .then(end); case ProjectType.WEB_COMPONENTS: return webComponentsGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "web components" app')) + .then(commandLog('Adding Storybook support to your "web components" app\n')) .then(end); case ProjectType.RIOT: return riotGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "riot.js" app')) + .then(commandLog('Adding Storybook support to your "riot.js" app\n')) .then(end); case ProjectType.PREACT: return preactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Preact" app')) + .then(commandLog('Adding Storybook support to your "Preact" app\n')) .then(end); case ProjectType.SVELTE: return svelteGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Svelte" app')) + .then(commandLog('Adding Storybook support to your "Svelte" app\n')) .then(end); case ProjectType.RAX: return raxGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Rax" app')) + .then(commandLog('Adding Storybook support to your "Rax" app\n')) .then(end); case ProjectType.AURELIA: return aureliaGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Aurelia" app')) + .then(commandLog('Adding Storybook support to your "Aurelia" app\n')) .then(end); case ProjectType.SERVER: return serverGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Server" app')) + .then(commandLog('Adding Storybook support to your "Server" app\n')) .then(end); case ProjectType.UNSUPPORTED: @@ -247,7 +251,7 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr // Add a new line for the clear visibility. logger.log(); - return projectTypeInquirer(options); + return projectTypeInquirer(options, packageManager); } }; @@ -257,7 +261,10 @@ const installStorybook = (projectType: ProjectType, options: CommandOptions): Pr }); }; -const projectTypeInquirer = async (options: { yes?: boolean }) => { +const projectTypeInquirer = async ( + options: { yes?: boolean }, + packageManager: JsPackageManager +) => { const manualAnswer = options.yes ? true : await prompts([ @@ -280,15 +287,20 @@ const projectTypeInquirer = async (options: { yes?: boolean }) => { })), }, ]); - return installStorybook(frameworkAnswer.manualFramework, options); + return installStorybook(frameworkAnswer.manualFramework, packageManager, options); } return Promise.resolve(); }; export async function initiate(options: CommandOptions, pkg: Package): Promise { + const packageManager = JsPackageManagerFactory.getPackageManager(options.useNpm); const welcomeMessage = 'sb init - the simplest way to add a Storybook to your project.'; logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); + if (!options.disableTelemetry) { + telemetry('init'); + } + // Update notify code. new UpdateNotifier({ pkg, @@ -302,7 +314,7 @@ export async function initiate(options: CommandOptions, pkg: Package): Promise; - devDependencies?: Record; - peerDependencies?: Record; - scripts?: Record; - eslintConfig?: any; - type?: 'module'; -}; +import type { PackageJson } from '@storybook/core-common'; +export type { PackageJson } from '@storybook/core-common'; export type PackageJsonWithDepsAndDevDeps = PackageJson & Required>; diff --git a/lib/cli/src/js-package-manager/PackageJsonHelper.ts b/lib/cli/src/js-package-manager/PackageJsonHelper.ts index 17fa72935f0e..e013783745e4 100644 --- a/lib/cli/src/js-package-manager/PackageJsonHelper.ts +++ b/lib/cli/src/js-package-manager/PackageJsonHelper.ts @@ -1,11 +1,11 @@ import path from 'path'; import fs from 'fs'; -import { PackageJson } from './PackageJson'; +import type { PackageJson } from '@storybook/core-common'; -export function readPackageJson(): PackageJson | false { +export function readPackageJson(): PackageJson { const packageJsonPath = path.resolve('package.json'); if (!fs.existsSync(packageJsonPath)) { - return false; + throw new Error(`Could not read package.json file at ${packageJsonPath}`); } const jsonContent = fs.readFileSync(packageJsonPath, 'utf8'); diff --git a/lib/cli/src/project_types.ts b/lib/cli/src/project_types.ts index 71175d1005e3..b55a176da801 100644 --- a/lib/cli/src/project_types.ts +++ b/lib/cli/src/project_types.ts @@ -81,6 +81,7 @@ export const SUPPORTED_FRAMEWORKS: SupportedFrameworks[] = [ export enum CoreBuilder { Webpack4 = 'webpack4', Webpack5 = 'webpack5', + Vite = 'vite', } // The `& {}` bit allows for auto-complete, see: https://github.com/microsoft/TypeScript/issues/29729 diff --git a/lib/cli/src/repro-generators/configs.ts b/lib/cli/src/repro-generators/configs.ts index 7c8a80610aba..c5f7b5e52739 100644 --- a/lib/cli/src/repro-generators/configs.ts +++ b/lib/cli/src/repro-generators/configs.ts @@ -1,4 +1,5 @@ -import { SupportedFrameworks } from '../project_types'; +import type { StorybookConfig } from '@storybook/core-common'; +import type { SupportedFrameworks } from '../project_types'; export interface Parameters { framework: SupportedFrameworks; @@ -14,6 +15,8 @@ export interface Parameters { additionalDeps?: string[]; /** Add typescript dependency and creates a tsconfig.json file */ typescript?: boolean; + /** Merge configurations to main.js before running the tests */ + mainOverrides?: Partial & Record; } const fromDeps = (...args: string[]): string => @@ -61,6 +64,19 @@ export const react: Parameters = { additionalDeps: ['prop-types'], }; +export const react_legacy_root_api: Parameters = { + framework: 'react', + name: 'react_legacy_root_api', + version: 'latest', + generator: fromDeps('react', 'react-dom'), + additionalDeps: ['prop-types'], + mainOverrides: { + reactOptions: { + legacyRootApi: true, + }, + }, +}; + export const react_typescript: Parameters = { framework: 'react', name: 'react_typescript', @@ -76,6 +92,13 @@ export const webpack_react: Parameters = { generator: fromDeps('react', 'react-dom', 'webpack@webpack-4'), }; +export const vite_react: Parameters = { + framework: 'react', + name: 'vite_react', + version: 'latest', + generator: 'npx -p create-vite@{{version}} create-vite {{appName}} --template react-ts', +}; + export const react_in_yarn_workspace: Parameters = { framework: 'react', name: 'react_in_yarn_workspace', @@ -129,6 +152,18 @@ export const angular13: Parameters = { version: '13.1.x', }; +export const angular_modern_inline_rendering: Parameters = { + ...baseAngular, + name: 'angular_modern_inline_rendering', + additionalDeps: ['jest', '@storybook/test-runner'], + mainOverrides: { + features: { + storyStoreV7: true, + modernInlineRender: true, + }, + }, +}; + export const angular: Parameters = baseAngular; // #endregion diff --git a/lib/cli/src/repro-generators/scripts.ts b/lib/cli/src/repro-generators/scripts.ts index 1b6c172c8a32..28efd6ce0d24 100644 --- a/lib/cli/src/repro-generators/scripts.ts +++ b/lib/cli/src/repro-generators/scripts.ts @@ -1,8 +1,9 @@ import path from 'path'; -import { writeJSON } from 'fs-extra'; +import { readJSON, writeJSON } from 'fs-extra'; import shell, { ExecOptions } from 'shelljs'; import chalk from 'chalk'; import { cra, cra_typescript } from './configs'; +import storybookVersions from '../versions'; const logger = console; @@ -70,6 +71,14 @@ export const exec = async ( }); }; +const addPackageResolutions = async ({ cwd }: Options) => { + logger.info(`🔢 Adding package resolutions:`); + const packageJsonPath = path.join(cwd, 'package.json'); + const packageJson = await readJSON(packageJsonPath); + packageJson.resolutions = storybookVersions; + await writeJSON(packageJsonPath, packageJson, { spaces: 2 }); +}; + const installYarn2 = async ({ cwd, pnp, name }: Options) => { const command = [ `yarn set version berry`, @@ -219,6 +228,9 @@ export const createAndInit = async ( logger.log(); await doTask(generate, { ...options, cwd: options.creationPath }); + if (e2e) { + await doTask(addPackageResolutions, options); + } await doTask(installYarn2, options); await doTask(configureYarn2ForE2E, options, e2e); await doTask(addTypescript, options, !!options.typescript); diff --git a/lib/cli/src/upgrade.ts b/lib/cli/src/upgrade.ts index 37661545f1d2..e656b994bdfb 100644 --- a/lib/cli/src/upgrade.ts +++ b/lib/cli/src/upgrade.ts @@ -1,4 +1,5 @@ import { sync as spawnSync } from 'cross-spawn'; +import { telemetry } from '@storybook/telemetry'; import semver from '@storybook/semver'; import { logger } from '@storybook/node-logger'; import { @@ -36,6 +37,16 @@ const excludeList = [ '@storybook/addon-console', '@storybook/csf', '@storybook/storybook-deployer', + '@storybook/addon-postcss', + '@storybook/react-docgen-typescript-plugin', + '@storybook/babel-plugin-require-context-hook', + '@storybook/builder-vite', + '@storybook/mdx1-csf', + '@storybook/mdx2-csf', + '@storybook/expect', + '@storybook/jest', + '@storybook/test-runner', + '@storybook/testing-library', ]; export const isCorePackage = (pkg: string) => pkg.startsWith('@storybook/') && @@ -129,12 +140,23 @@ interface UpgradeOptions { useNpm: boolean; dryRun: boolean; yes: boolean; + disableTelemetry: boolean; } -export const upgrade = async ({ prerelease, skipCheck, useNpm, dryRun, yes }: UpgradeOptions) => { +export const upgrade = async ({ + prerelease, + skipCheck, + useNpm, + dryRun, + yes, + ...options +}: UpgradeOptions) => { const packageManager = JsPackageManagerFactory.getPackageManager(useNpm); commandLog(`Checking for latest versions of '@storybook/*' packages`); + if (!options.disableTelemetry) { + telemetry('upgrade', { prerelease }); + } let flags = []; if (!dryRun) flags.push('--upgrade'); diff --git a/lib/cli/src/versions.ts b/lib/cli/src/versions.ts index e25fd8b3620d..9e22fcdd2af1 100644 --- a/lib/cli/src/versions.ts +++ b/lib/cli/src/versions.ts @@ -1,59 +1,60 @@ // auto generated file, do not edit export default { - "@storybook/addon-a11y": "6.5.0-alpha.48", - "@storybook/addon-actions": "6.5.0-alpha.48", - "@storybook/addon-backgrounds": "6.5.0-alpha.48", - "@storybook/addon-controls": "6.5.0-alpha.48", - "@storybook/addon-docs": "6.5.0-alpha.48", - "@storybook/addon-essentials": "6.5.0-alpha.48", - "@storybook/addon-interactions": "6.5.0-alpha.48", - "@storybook/addon-jest": "6.5.0-alpha.48", - "@storybook/addon-links": "6.5.0-alpha.48", - "@storybook/addon-measure": "6.5.0-alpha.48", - "@storybook/addon-outline": "6.5.0-alpha.48", - "@storybook/addon-storyshots": "6.5.0-alpha.48", - "@storybook/addon-storyshots-puppeteer": "6.5.0-alpha.48", - "@storybook/addon-storysource": "6.5.0-alpha.48", - "@storybook/addon-toolbars": "6.5.0-alpha.48", - "@storybook/addon-viewport": "6.5.0-alpha.48", - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/angular": "6.5.0-alpha.48", - "@storybook/api": "6.5.0-alpha.48", - "@storybook/builder-webpack4": "6.5.0-alpha.48", - "@storybook/builder-webpack5": "6.5.0-alpha.48", - "@storybook/channel-postmessage": "6.5.0-alpha.48", - "@storybook/channel-websocket": "6.5.0-alpha.48", - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/cli": "6.5.0-alpha.48", - "@storybook/client-api": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/codemod": "6.5.0-alpha.48", - "@storybook/components": "6.5.0-alpha.48", - "@storybook/core": "6.5.0-alpha.48", - "@storybook/core-client": "6.5.0-alpha.48", - "@storybook/core-common": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/core-server": "6.5.0-alpha.48", - "@storybook/csf-tools": "6.5.0-alpha.48", - "@storybook/docs-tools": "6.5.0-alpha.48", - "@storybook/ember": "6.5.0-alpha.48", - "@storybook/html": "6.5.0-alpha.48", - "@storybook/instrumenter": "6.5.0-alpha.48", - "@storybook/manager-webpack4": "6.5.0-alpha.48", - "@storybook/manager-webpack5": "6.5.0-alpha.48", - "@storybook/node-logger": "6.5.0-alpha.48", - "@storybook/postinstall": "6.5.0-alpha.48", - "@storybook/preact": "6.5.0-alpha.48", - "@storybook/preview-web": "6.5.0-alpha.48", - "@storybook/react": "6.5.0-alpha.48", - "@storybook/router": "6.5.0-alpha.48", - "@storybook/server": "6.5.0-alpha.48", - "@storybook/source-loader": "6.5.0-alpha.48", - "@storybook/store": "6.5.0-alpha.48", - "@storybook/svelte": "6.5.0-alpha.48", - "@storybook/theming": "6.5.0-alpha.48", - "@storybook/ui": "6.5.0-alpha.48", - "@storybook/vue": "6.5.0-alpha.48", - "@storybook/vue3": "6.5.0-alpha.48", - "@storybook/web-components": "6.5.0-alpha.48" -} \ No newline at end of file + '@storybook/addon-a11y': '6.5.0-beta.2', + '@storybook/addon-actions': '6.5.0-beta.2', + '@storybook/addon-backgrounds': '6.5.0-beta.2', + '@storybook/addon-controls': '6.5.0-beta.2', + '@storybook/addon-docs': '6.5.0-beta.2', + '@storybook/addon-essentials': '6.5.0-beta.2', + '@storybook/addon-interactions': '6.5.0-beta.2', + '@storybook/addon-jest': '6.5.0-beta.2', + '@storybook/addon-links': '6.5.0-beta.2', + '@storybook/addon-measure': '6.5.0-beta.2', + '@storybook/addon-outline': '6.5.0-beta.2', + '@storybook/addon-storyshots': '6.5.0-beta.2', + '@storybook/addon-storyshots-puppeteer': '6.5.0-beta.2', + '@storybook/addon-storysource': '6.5.0-beta.2', + '@storybook/addon-toolbars': '6.5.0-beta.2', + '@storybook/addon-viewport': '6.5.0-beta.2', + '@storybook/addons': '6.5.0-beta.2', + '@storybook/angular': '6.5.0-beta.2', + '@storybook/api': '6.5.0-beta.2', + '@storybook/builder-webpack4': '6.5.0-beta.2', + '@storybook/builder-webpack5': '6.5.0-beta.2', + '@storybook/channel-postmessage': '6.5.0-beta.2', + '@storybook/channel-websocket': '6.5.0-beta.2', + '@storybook/channels': '6.5.0-beta.2', + '@storybook/cli': '6.5.0-beta.2', + '@storybook/client-api': '6.5.0-beta.2', + '@storybook/client-logger': '6.5.0-beta.2', + '@storybook/codemod': '6.5.0-beta.2', + '@storybook/components': '6.5.0-beta.2', + '@storybook/core': '6.5.0-beta.2', + '@storybook/core-client': '6.5.0-beta.2', + '@storybook/core-common': '6.5.0-beta.2', + '@storybook/core-events': '6.5.0-beta.2', + '@storybook/core-server': '6.5.0-beta.2', + '@storybook/csf-tools': '6.5.0-beta.2', + '@storybook/docs-tools': '6.5.0-beta.2', + '@storybook/ember': '6.5.0-beta.2', + '@storybook/html': '6.5.0-beta.2', + '@storybook/instrumenter': '6.5.0-beta.2', + '@storybook/manager-webpack4': '6.5.0-beta.2', + '@storybook/manager-webpack5': '6.5.0-beta.2', + '@storybook/node-logger': '6.5.0-beta.2', + '@storybook/postinstall': '6.5.0-beta.2', + '@storybook/preact': '6.5.0-beta.2', + '@storybook/preview-web': '6.5.0-beta.2', + '@storybook/react': '6.5.0-beta.2', + '@storybook/router': '6.5.0-beta.2', + '@storybook/server': '6.5.0-beta.2', + '@storybook/source-loader': '6.5.0-beta.2', + '@storybook/store': '6.5.0-beta.2', + '@storybook/svelte': '6.5.0-beta.2', + '@storybook/telemetry': '6.5.0-beta.2', + '@storybook/theming': '6.5.0-beta.2', + '@storybook/ui': '6.5.0-beta.2', + '@storybook/vue': '6.5.0-beta.2', + '@storybook/vue3': '6.5.0-beta.2', + '@storybook/web-components': '6.5.0-beta.2', +}; diff --git a/lib/client-api/package.json b/lib/client-api/package.json index 9b33709a6b45..dfd22d320bb7 100644 --- a/lib/client-api/package.json +++ b/lib/client-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/client-api", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook Client API", "keywords": [ "storybook" @@ -40,13 +40,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/channel-postmessage": "6.5.0-alpha.48", - "@storybook/channels": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/store": "6.5.0-alpha.48", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/channel-postmessage": "6.5.0-beta.2", + "@storybook/channels": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/store": "6.5.0-beta.2", "@types/qs": "^6.9.5", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", @@ -62,12 +62,12 @@ "util-deprecate": "^1.0.2" }, "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" }, "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/client-logger/package.json b/lib/client-logger/package.json index 5b3670888a52..368ce3944482 100644 --- a/lib/client-logger/package.json +++ b/lib/client-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/client-logger", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "", "keywords": [ "storybook" @@ -46,6 +46,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/codemod/package.json b/lib/codemod/package.json index 723e4c33a65b..61916516db49 100644 --- a/lib/codemod/package.json +++ b/lib/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/codemod", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "A collection of codemod scripts written with JSCodeshift", "keywords": [ "storybook" @@ -43,9 +43,9 @@ "dependencies": { "@babel/types": "^7.12.11", "@mdx-js/mdx": "^1.6.22", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/csf-tools": "6.5.0-alpha.48", - "@storybook/node-logger": "6.5.0-alpha.48", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/csf-tools": "6.5.0-beta.2", + "@storybook/node-logger": "6.5.0-beta.2", "core-js": "^3.8.2", "cross-spawn": "^7.0.3", "globby": "^11.0.2", @@ -62,6 +62,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/components/html.js b/lib/components/html.js index 7a58bc516e1f..782e7707979c 100644 --- a/lib/components/html.js +++ b/lib/components/html.js @@ -1 +1,2 @@ -module.exports = require('./dist/cjs/html'); +// eslint-disable-next-line import/no-unresolved +export * from './dist/esm/html'; diff --git a/lib/components/package.json b/lib/components/package.json index 334922d8a7f4..8fb2dc993ece 100644 --- a/lib/components/package.json +++ b/lib/components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/components", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Core Storybook Components", "keywords": [ "storybook" @@ -40,17 +40,18 @@ "prepare": "ts-node ../../scripts/prebundle.ts" }, "dependencies": { - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/theming": "6.5.0-alpha.48", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/theming": "6.5.0-beta.2", + "@types/react-syntax-highlighter": "11.0.5", "core-js": "^3.8.2", + "react-syntax-highlighter": "^15.4.5", "regenerator-runtime": "^0.13.7" }, "devDependencies": { "@popperjs/core": "^2.6.0", "@types/color-convert": "^2.0.0", "@types/overlayscrollbars": "^1.12.0", - "@types/react-syntax-highlighter": "11.0.5", "color-convert": "^2.0.1", "css": "^3.0.0", "fast-deep-equal": "^3.1.3", @@ -60,25 +61,25 @@ "markdown-to-jsx": "^7.1.3", "memoizerific": "^1.11.3", "overlayscrollbars": "^1.13.1", - "polished": "^4.0.5", + "polished": "^4.2.2", + "prettier": ">=2.2.1 <=2.3.0", "prop-types": "^15.7.2", "qs": "^6.10.0", "react-colorful": "^5.1.2", "react-popper-tooltip": "^3.1.1", - "react-syntax-highlighter": "^15.4.5", "react-textarea-autosize": "^8.3.0", "ts-dedent": "^2.0.0", "ts-node": "^10.4.0", "util-deprecate": "^1.0.2" }, "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" }, "publishConfig": { "access": "public" }, "bundlerEntrypoint": "./src/index.ts", - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/components/src/Zoom/ZoomIFrame.tsx b/lib/components/src/Zoom/ZoomIFrame.tsx index 2c377edc8057..1c2f0735b5fa 100644 --- a/lib/components/src/Zoom/ZoomIFrame.tsx +++ b/lib/components/src/Zoom/ZoomIFrame.tsx @@ -29,7 +29,8 @@ export class ZoomIFrame extends Component { // this component renders an iframe, which gets updates via post-messages // never update this component, it will cause the iframe to refresh - return false; + // the only exception is when the url changes, which happens when the version changes + return nextProps.children.props.src !== this.props.children.props.src; } setIframeInnerZoom(scale: number) { diff --git a/lib/components/src/blocks/ArgsTable/ArgValue.tsx b/lib/components/src/blocks/ArgsTable/ArgValue.tsx index 6d77e88954bb..a7e92a2b6e5f 100644 --- a/lib/components/src/blocks/ArgsTable/ArgValue.tsx +++ b/lib/components/src/blocks/ArgsTable/ArgValue.tsx @@ -77,7 +77,7 @@ const Detail = styled.div<{ width: string }>(({ theme, width }) => ({ minWidth: 200, maxWidth: 800, padding: 15, - // Dont remove the mono fontFamily here even if it seem useless, this is used by the browser to calculate the length of a "ch" unit. + // Don't remove the mono fontFamily here even if it seems useless, this is used by the browser to calculate the length of a "ch" unit. fontFamily: theme.typography.fonts.mono, fontSize: theme.typography.size.s1, // Most custom stylesheet will reset the box-sizing to "border-box" and will break the tooltip. diff --git a/lib/components/src/blocks/ArgsTable/ArgsTable.tsx b/lib/components/src/blocks/ArgsTable/ArgsTable.tsx index faabe0e11c24..58fc17afeb3e 100644 --- a/lib/components/src/blocks/ArgsTable/ArgsTable.tsx +++ b/lib/components/src/blocks/ArgsTable/ArgsTable.tsx @@ -2,10 +2,11 @@ import React, { FC } from 'react'; import pickBy from 'lodash/pickBy'; import { styled, ignoreSsrWarning } from '@storybook/theming'; import { opacify, transparentize, darken, lighten } from 'polished'; +import { includeConditionalArg } from '@storybook/csf'; import { Icons } from '../../icon/icon'; import { ArgRow } from './ArgRow'; import { SectionRow } from './SectionRow'; -import { ArgType, ArgTypes, Args } from './types'; +import { ArgType, ArgTypes, Args, Globals } from './types'; import { EmptyBlock } from '../EmptyBlock'; import { Link } from '../../typography/link/link'; import { ResetWrapper } from '../../typography/ResetWrapper'; @@ -270,6 +271,7 @@ export interface ArgsTableOptionProps { export interface ArgsTableDataProps { rows: ArgTypes; args?: Args; + globals?: Globals; } export interface ArgsTableErrorProps { @@ -395,10 +397,13 @@ export const ArgsTable: FC = (props) => { sort = 'none', } = props; const isLoading = 'isLoading' in props; - const { rows, args } = 'rows' in props ? props : argsTableLoadingData; + const { rows, args, globals } = 'rows' in props ? props : argsTableLoadingData; const groups = groupRows( - pickBy(rows, (row) => !row?.table?.disable), + pickBy( + rows, + (row) => !row?.table?.disable && includeConditionalArg(row, args || {}, globals || {}) + ), sort ); diff --git a/lib/components/src/blocks/ArgsTable/types.ts b/lib/components/src/blocks/ArgsTable/types.ts index 4b8a3fa4941c..5b97d7cb8053 100644 --- a/lib/components/src/blocks/ArgsTable/types.ts +++ b/lib/components/src/blocks/ArgsTable/types.ts @@ -1,3 +1,5 @@ +import type { Conditional } from '@storybook/csf'; + export interface JsDocParam { name: string; description?: string; @@ -32,6 +34,7 @@ export interface ArgType { name?: string; description?: string; defaultValue?: any; + if?: Conditional; [key: string]: any; } @@ -42,3 +45,5 @@ export interface ArgTypes { export interface Args { [key: string]: any; } + +export type Globals = { [name: string]: any }; diff --git a/lib/components/src/blocks/DocsPage.stories.tsx b/lib/components/src/blocks/DocsPage.stories.tsx index efbd4030a1b9..499a13fe6cb2 100644 --- a/lib/components/src/blocks/DocsPage.stories.tsx +++ b/lib/components/src/blocks/DocsPage.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Global, css } from '@emotion/core'; +import { Global, css } from '@emotion/react'; import { Title, Subtitle, DocsPageWrapper } from './DocsPage'; import { ArgsTable, Source, Description } from './index'; diff --git a/lib/components/src/blocks/Source.tsx b/lib/components/src/blocks/Source.tsx index d8c0d6e73dcf..c71429c020e5 100644 --- a/lib/components/src/blocks/Source.tsx +++ b/lib/components/src/blocks/Source.tsx @@ -1,5 +1,5 @@ -import React, { FunctionComponent } from 'react'; -import { styled, ThemeProvider, convert, themes } from '@storybook/theming'; +import React, { ComponentProps, FunctionComponent } from 'react'; +import { styled, ThemeProvider, convert, themes, ignoreSsrWarning } from '@storybook/theming'; import { EmptyBlock } from './EmptyBlock'; import { SyntaxHighlighter } from '../syntaxhighlighter/lazy-syntaxhighlighter'; @@ -31,7 +31,7 @@ interface SourceErrorProps { interface SourceCodeProps { language?: string; code?: string; - format?: boolean; + format?: ComponentProps['format']; dark?: boolean; } @@ -52,7 +52,7 @@ const SourceSkeletonPlaceholder = styled.div<{}>(({ theme }) => ({ marginTop: 1, width: '60%', - '&:first-child': { + [`&:first-child${ignoreSsrWarning}`]: { margin: 0, }, })); diff --git a/lib/components/src/controls/Date.test.ts b/lib/components/src/controls/Date.test.ts new file mode 100644 index 000000000000..08ad139676df --- /dev/null +++ b/lib/components/src/controls/Date.test.ts @@ -0,0 +1,22 @@ +import { parseDate, parseTime, formatDate, formatTime } from './Date'; + +describe('Date control', () => { + it.each([ + // name, input, expected + ['same date', '2022-01-01', '2022-01-01'], + ['month and day not padded with zeros', '2022-1-1', '2022-01-01'], + ['different year', '1900-10-1', '1900-10-01'], + ])('parse and format date: %s', (name, input, expected) => { + expect(formatDate(parseDate(input))).toBe(expected); + }); + + it.each([ + // name, input, expected + ['same time', '12:00', '12:00'], + ['hours not padded with a zero', '1:00', '01:00'], + ['minutes not padded with a zero', '01:0', '01:00'], + ['different minutes', '01:30', '01:30'], + ])('parse and format time: %s', (name, input, expected) => { + expect(formatTime(parseTime(input))).toBe(expected); + }); +}); diff --git a/lib/components/src/controls/Date.tsx b/lib/components/src/controls/Date.tsx index b8ddcebff979..81247bccfa4f 100644 --- a/lib/components/src/controls/Date.tsx +++ b/lib/components/src/controls/Date.tsx @@ -5,14 +5,14 @@ import { Form } from '../form'; import { ControlProps, DateValue, DateConfig } from './types'; import { getControlId } from './helpers'; -const parseDate = (value: string) => { +export const parseDate = (value: string) => { const [year, month, day] = value.split('-'); const result = new Date(); result.setFullYear(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)); return result; }; -const parseTime = (value: string) => { +export const parseTime = (value: string) => { const [hours, minutes] = value.split(':'); const result = new Date(); result.setHours(parseInt(hours, 10)); @@ -20,7 +20,7 @@ const parseTime = (value: string) => { return result; }; -const formatDate = (value: Date | number) => { +export const formatDate = (value: Date | number) => { const date = new Date(value); const year = `000${date.getFullYear()}`.slice(-4); const month = `0${date.getMonth() + 1}`.slice(-2); @@ -28,7 +28,7 @@ const formatDate = (value: Date | number) => { return `${year}-${month}-${day}`; }; -const formatTime = (value: Date | number) => { +export const formatTime = (value: Date | number) => { const date = new Date(value); const hours = `0${date.getHours()}`.slice(-2); const minutes = `0${date.getMinutes()}`.slice(-2); @@ -52,6 +52,10 @@ const FlexSpaced = styled.div(({ theme }) => ({ }, 'input:first-of-type': { marginLeft: 0, + flexGrow: 4, + }, + 'input:last-of-type': { + flexGrow: 3, }, })); diff --git a/lib/components/src/controls/Object.tsx b/lib/components/src/controls/Object.tsx index ff57f8ae79e6..b8c18b0c0155 100644 --- a/lib/components/src/controls/Object.tsx +++ b/lib/components/src/controls/Object.tsx @@ -244,7 +244,7 @@ const getCustomStyleFunction: (theme: Theme) => JsonTreeProps['getStyle'] = (the }); export const ObjectControl: FC = ({ name, value, onChange }) => { - const theme = useTheme(); + const theme = useTheme(); const data = useMemo(() => value && cloneDeep(value), [value]); const hasData = data !== null && data !== undefined; diff --git a/lib/components/src/controls/helpers.test.ts b/lib/components/src/controls/helpers.test.ts index 14faa7a53256..c902a025507e 100644 --- a/lib/components/src/controls/helpers.test.ts +++ b/lib/components/src/controls/helpers.test.ts @@ -6,7 +6,7 @@ describe('getControlId', () => { ['lower case', 'some-id', 'control-some-id'], ['upper case', 'SOME-ID', 'control-SOME-ID'], ['all valid characters', 'some_weird-:custom.id', 'control-some_weird-:custom.id'], - ])('%s', (a, input, expected) => { + ])('%s', (name, input, expected) => { expect(getControlId(input)).toBe(expected); }); }); @@ -17,7 +17,7 @@ describe('getControlSetterButtonId', () => { ['lower case', 'some-id', 'set-some-id'], ['upper case', 'SOME-ID', 'set-SOME-ID'], ['all valid characters', 'some_weird-:custom.id', 'set-some_weird-:custom.id'], - ])('%s', (a, input, expected) => { + ])('%s', (name, input, expected) => { expect(getControlSetterButtonId(input)).toBe(expected); }); }); diff --git a/lib/components/src/index.ts b/lib/components/src/index.ts index 885b3edb087b..8aa89b5953a0 100644 --- a/lib/components/src/index.ts +++ b/lib/components/src/index.ts @@ -32,6 +32,7 @@ export { Badge } from './Badge/Badge'; export { Link } from './typography/link/link'; export { DocumentWrapper } from './typography/DocumentWrapper'; export type { + SyntaxHighlighterFormatTypes, SyntaxHighlighterProps, SyntaxHighlighterRendererProps, } from './syntaxhighlighter/syntaxhighlighter-types'; diff --git a/lib/components/src/syntaxhighlighter/formatter.test.js b/lib/components/src/syntaxhighlighter/formatter.test.js deleted file mode 100644 index 9c5543fef74f..000000000000 --- a/lib/components/src/syntaxhighlighter/formatter.test.js +++ /dev/null @@ -1,90 +0,0 @@ -import dedent from 'ts-dedent'; - -import { formatter } from './formatter'; - -test('handles empty string', () => { - const input = ''; - const result = formatter(input); - - expect(result).toBe(input); -}); - -test('handles single line', () => { - const input = 'console.log("hello world")'; - const result = formatter(input); - - expect(result).toBe(input); -}); - -test('does not transform correct code', () => { - const input = dedent` - console.log("hello"); - console.log("world"); - `; - const result = formatter(input); - - expect(result).toBe(input); -}); - -test('does transform incorrect code', () => { - const input = ` - console.log("hello"); - console.log("world"); - `; - const result = formatter(input); - - expect(result).toBe(`console.log("hello"); -console.log("world");`); -}); - -test('more indentations - skip first line', () => { - const input = ` - test('handles empty string', () => { - const input = ''; - const result = formatter(input); - - expect(result).toBe(input); - }); - `; - const result = formatter(input); - - expect(result).toBe(`test('handles empty string', () => { - const input = ''; - const result = formatter(input); - - expect(result).toBe(input); -});`); -}); - -test('more indentations - code on first line', () => { - const input = `// some comment - test('handles empty string', () => { - const input = ''; - const result = formatter(input); - - expect(result).toBe(input); - }); - `; - const result = formatter(input); - - expect(result).toBe(`// some comment -test('handles empty string', () => { - const input = ''; - const result = formatter(input); - - expect(result).toBe(input); -});`); -}); - -test('removes whitespace in empty line completely', () => { - const input = ` - console.log("hello"); - - console.log("world"); - `; - const result = formatter(input); - - expect(result).toBe(`console.log("hello"); - -console.log("world");`); -}); diff --git a/lib/components/src/syntaxhighlighter/formatter.test.ts b/lib/components/src/syntaxhighlighter/formatter.test.ts new file mode 100644 index 000000000000..9546e098fe93 --- /dev/null +++ b/lib/components/src/syntaxhighlighter/formatter.test.ts @@ -0,0 +1,109 @@ +import dedent from 'ts-dedent'; + +import { formatter } from './formatter'; + +describe('dedent', () => { + test('handles empty string', () => { + const input = ''; + const result = formatter(true, input); + + expect(result).toBe(input); + }); + + test('handles single line', () => { + const input = 'console.log("hello world")'; + const result = formatter(true, input); + + expect(result).toBe(input); + }); + + test('does not transform correct code', () => { + const input = dedent` + console.log("hello"); + console.log("world"); + `; + const result = formatter(true, input); + + expect(result).toBe(input); + }); + + test('does transform incorrect code', () => { + const input = ` + console.log("hello"); + console.log("world"); + `; + const result = formatter(true, input); + + expect(result).toBe(`console.log("hello"); +console.log("world");`); + }); + + test('more indentations - skip first line', () => { + const input = ` + test('handles empty string', () => { + const input = ''; + const result = formatter(input); + + expect(result).toBe(input); + }); + `; + const result = formatter(true, input); + + expect(result).toBe(`test('handles empty string', () => { + const input = ''; + const result = formatter(input); + + expect(result).toBe(input); +});`); + }); + + test('more indentations - code on first line', () => { + const input = `// some comment + test('handles empty string', () => { + const input = ''; + const result = formatter(input); + + expect(result).toBe(input); + }); + `; + const result = formatter(true, input); + + expect(result).toBe(`// some comment +test('handles empty string', () => { + const input = ''; + const result = formatter(input); + + expect(result).toBe(input); +});`); + }); + + test('removes whitespace in empty line completely', () => { + const input = ` + console.log("hello"); + + console.log("world"); + `; + const result = formatter(true, input); + + expect(result).toBe(`console.log("hello"); + +console.log("world");`); + }); +}); + +describe('prettier (babel)', () => { + test('handles empty string', () => { + const input = ''; + const result = formatter('angular', input); + + expect(result).toBe(input); + }); + + test('handles single line', () => { + const input = 'console.log("hello world")'; + const result = formatter('angular', input); + console.log({ result }); + + expect(result).toBe(input); + }); +}); diff --git a/lib/components/src/syntaxhighlighter/formatter.ts b/lib/components/src/syntaxhighlighter/formatter.ts index dceeae48d0ad..6b00dbe5fb3e 100644 --- a/lib/components/src/syntaxhighlighter/formatter.ts +++ b/lib/components/src/syntaxhighlighter/formatter.ts @@ -1,4 +1,23 @@ import memoize from 'memoizerific'; + +import prettierHtml from 'prettier/parser-html'; +import prettier from 'prettier/standalone'; import dedent from 'ts-dedent'; +import { SyntaxHighlighterFormatTypes } from './syntaxhighlighter-types'; + +export const formatter = memoize(2)((type: SyntaxHighlighterFormatTypes, source: string) => { + if (type === false) { + return source; + } + if (type === 'dedent' || type === true) { + return dedent(source); + } -export const formatter = memoize(2)((code: string) => dedent(code)); + return prettier + .format(source, { + parser: type, + plugins: [prettierHtml], + htmlWhitespaceSensitivity: 'ignore', + }) + .trim(); +}); diff --git a/lib/components/src/syntaxhighlighter/lazy-syntaxhighlighter.tsx b/lib/components/src/syntaxhighlighter/lazy-syntaxhighlighter.tsx index 76c50138e95e..87abd83af2f4 100644 --- a/lib/components/src/syntaxhighlighter/lazy-syntaxhighlighter.tsx +++ b/lib/components/src/syntaxhighlighter/lazy-syntaxhighlighter.tsx @@ -1,9 +1,25 @@ import React, { ComponentProps, Suspense, lazy } from 'react'; const LazySyntaxHighlighter = lazy(() => import('./syntaxhighlighter')); +const LazySyntaxHighlighterWithFormatter = lazy(async () => { + const [{ SyntaxHighlighter }, { formatter }] = await Promise.all([ + import('./syntaxhighlighter'), + import('./formatter'), + ]); + + return { + default: (props: ComponentProps) => ( + + ), + }; +}); export const SyntaxHighlighter = (props: ComponentProps) => ( }> - + {props.format !== false ? ( + + ) : ( + + )} ); diff --git a/lib/components/src/syntaxhighlighter/syntaxhighlighter-types.ts b/lib/components/src/syntaxhighlighter/syntaxhighlighter-types.ts index bc33ab7f9f86..dfd948afb183 100644 --- a/lib/components/src/syntaxhighlighter/syntaxhighlighter-types.ts +++ b/lib/components/src/syntaxhighlighter/syntaxhighlighter-types.ts @@ -1,3 +1,4 @@ +import type { BuiltInParserName } from 'prettier'; import type { ReactNode } from 'react'; export interface SyntaxHighlighterRendererProps { @@ -6,12 +7,33 @@ export interface SyntaxHighlighterRendererProps { useInlineStyles: boolean; } -export interface SyntaxHighlighterProps { +export interface SyntaxHighlighterCustomProps { language: string; copyable?: boolean; bordered?: boolean; padded?: boolean; - format?: boolean; + format?: SyntaxHighlighterFormatTypes; + formatter?: (type: SyntaxHighlighterFormatTypes, source: string) => string; className?: string; renderer?: (props: SyntaxHighlighterRendererProps) => ReactNode; } + +export type SyntaxHighlighterFormatTypes = boolean | 'dedent' | BuiltInParserName; + +// these are copied from the `react-syntax-highlighter` package +// the reason these a COPIED is the types for this package are defining modules by filename +// which will not match one we've localized type-definitions +type lineTagPropsFunction = (lineNumber: number) => React.HTMLProps; +export interface SyntaxHighlighterBaseProps { + language?: string; + style?: any; + customStyle?: any; + lineProps?: lineTagPropsFunction | React.HTMLProps; + codeTagProps?: React.HTMLProps; + useInlineStyles?: boolean; + showLineNumbers?: boolean; + startingLineNumber?: number; + lineNumberStyle?: any; +} + +export type SyntaxHighlighterProps = SyntaxHighlighterBaseProps & SyntaxHighlighterCustomProps; diff --git a/lib/components/src/syntaxhighlighter/syntaxhighlighter.tsx b/lib/components/src/syntaxhighlighter/syntaxhighlighter.tsx index 667c49ad6729..92bd3bf6517b 100644 --- a/lib/components/src/syntaxhighlighter/syntaxhighlighter.tsx +++ b/lib/components/src/syntaxhighlighter/syntaxhighlighter.tsx @@ -1,10 +1,4 @@ -import React, { - ClipboardEvent, - ComponentProps, - FunctionComponent, - MouseEvent, - useState, -} from 'react'; +import React, { ClipboardEvent, FunctionComponent, MouseEvent, useCallback, useState } from 'react'; import { logger } from '@storybook/client-logger'; import { styled } from '@storybook/theming'; import global from 'global'; @@ -39,7 +33,6 @@ import ReactSyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism-ligh import { ActionBar } from '../ActionBar/ActionBar'; import { ScrollArea } from '../ScrollArea/ScrollArea'; -import { formatter } from './formatter'; import type { SyntaxHighlighterProps } from './syntaxhighlighter-types'; const { navigator, document, window: globalWindow } = global; @@ -138,17 +131,16 @@ export interface SyntaxHighlighterState { copied: boolean; } -type ReactSyntaxHighlighterProps = ComponentProps; +// copied from @types/react-syntax-highlighter/index.d.ts -type Props = SyntaxHighlighterProps & ReactSyntaxHighlighterProps; - -export const SyntaxHighlighter: FunctionComponent = ({ +export const SyntaxHighlighter: FunctionComponent = ({ children, language = 'jsx', copyable = false, bordered = false, padded = false, format = true, + formatter = null, className = null, showLineNumbers = false, ...rest @@ -157,22 +149,25 @@ export const SyntaxHighlighter: FunctionComponent = ({ return null; } - const highlightableCode = format ? formatter(children) : children.trim(); + const highlightableCode = formatter ? formatter(format, children) : children.trim(); const [copied, setCopied] = useState(false); - const onClick = (e: MouseEvent | ClipboardEvent) => { - e.preventDefault(); + const onClick = useCallback( + (e: MouseEvent | ClipboardEvent) => { + e.preventDefault(); - const selectedText = globalWindow.getSelection().toString(); - const textToCopy = e.type !== 'click' && selectedText ? selectedText : highlightableCode; + const selectedText = globalWindow.getSelection().toString(); + const textToCopy = e.type !== 'click' && selectedText ? selectedText : highlightableCode; - copyToClipboard(textToCopy) - .then(() => { - setCopied(true); - globalWindow.setTimeout(() => setCopied(false), 1500); - }) - .catch(logger.error); - }; + copyToClipboard(textToCopy) + .then(() => { + setCopied(true); + globalWindow.setTimeout(() => setCopied(false), 1500); + }) + .catch(logger.error); + }, + [] + ); return ( diff --git a/lib/core-client/package.json b/lib/core-client/package.json index 8722f8f48ca6..959ef7075a41 100644 --- a/lib/core-client/package.json +++ b/lib/core-client/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-client", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" @@ -40,16 +40,16 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.5.0-alpha.48", - "@storybook/channel-postmessage": "6.5.0-alpha.48", - "@storybook/channel-websocket": "6.5.0-alpha.48", - "@storybook/client-api": "6.5.0-alpha.48", - "@storybook/client-logger": "6.5.0-alpha.48", - "@storybook/core-events": "6.5.0-alpha.48", - "@storybook/csf": "0.0.2--canary.87bc651.0", - "@storybook/preview-web": "6.5.0-alpha.48", - "@storybook/store": "6.5.0-alpha.48", - "@storybook/ui": "6.5.0-alpha.48", + "@storybook/addons": "6.5.0-beta.2", + "@storybook/channel-postmessage": "6.5.0-beta.2", + "@storybook/channel-websocket": "6.5.0-beta.2", + "@storybook/client-api": "6.5.0-beta.2", + "@storybook/client-logger": "6.5.0-beta.2", + "@storybook/core-events": "6.5.0-beta.2", + "@storybook/csf": "0.0.2--canary.4566f4d.1", + "@storybook/preview-web": "6.5.0-beta.2", + "@storybook/store": "6.5.0-beta.2", + "@storybook/ui": "6.5.0-beta.2", "airbnb-js-shims": "^2.2.1", "ansi-to-html": "^0.6.11", "core-js": "^3.8.2", @@ -62,8 +62,8 @@ "util-deprecate": "^1.0.2" }, "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", "webpack": "*" }, "peerDependenciesMeta": { @@ -74,6 +74,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/core-client/src/preview/start.test.ts b/lib/core-client/src/preview/start.test.ts index 48fc6f35aba7..7b6d60121091 100644 --- a/lib/core-client/src/preview/start.test.ts +++ b/lib/core-client/src/preview/start.test.ts @@ -10,6 +10,7 @@ import { } from '@storybook/preview-web/dist/cjs/PreviewWeb.mockdata'; // @ts-ignore import { WebView } from '@storybook/preview-web/dist/cjs/WebView'; +import { setGlobalRender } from '@storybook/client-api'; import { start } from './start'; @@ -52,9 +53,9 @@ beforeEach(() => { describe('start', () => { describe('when configure is called with storiesOf only', () => { it('loads and renders the first story correctly', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi @@ -150,7 +151,7 @@ describe('start', () => { 'component-a--story-one' ); - expect(render).toHaveBeenCalledWith( + expect(renderToDOM).toHaveBeenCalledWith( expect.objectContaining({ id: 'component-a--story-one', }), @@ -159,9 +160,9 @@ describe('start', () => { }); it('sends over docs only stories', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi @@ -212,9 +213,9 @@ describe('start', () => { }); it('deals with stories with "default" name', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('default', jest.fn()); @@ -226,9 +227,9 @@ describe('start', () => { }); it('deals with stories with camel-cased names', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi @@ -242,9 +243,9 @@ describe('start', () => { }); it('deals with stories with spaces in the name', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi @@ -262,9 +263,9 @@ describe('start', () => { // https://github.com/storybookjs/storybook/issues/16303 it('deals with stories with numeric names', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('story0', jest.fn()); @@ -276,9 +277,9 @@ describe('start', () => { }); it('deals with storiesOf from the same file twice', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('default', jest.fn()); @@ -300,9 +301,9 @@ describe('start', () => { }); it('allows global metadata via client-api', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); const loader = jest.fn(async () => ({ val: 'loaded' })); const decorator = jest.fn(); @@ -317,7 +318,7 @@ describe('start', () => { expect(loader).toHaveBeenCalled(); expect(decorator).toHaveBeenCalled(); - expect(render).toHaveBeenCalledWith( + expect(renderToDOM).toHaveBeenCalledWith( expect.objectContaining({ storyContext: expect.objectContaining({ parameters: expect.objectContaining({ @@ -331,9 +332,9 @@ describe('start', () => { }); it('allows setting compomnent/args/argTypes via a parameter', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); const component = {}; configure('test', () => { @@ -352,7 +353,7 @@ describe('start', () => { await waitForRender(); - expect(render).toHaveBeenCalledWith( + expect(renderToDOM).toHaveBeenCalledWith( expect.objectContaining({ storyContext: expect.objectContaining({ component, @@ -370,9 +371,9 @@ describe('start', () => { }); it('supports forceRerender()', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); - const { configure, clientApi, forceReRender } = start(render); + const { configure, clientApi, forceReRender } = start(renderToDOM); configure('test', () => { clientApi.storiesOf('Component A', { id: 'file1' } as NodeModule).add('default', jest.fn()); @@ -389,9 +390,9 @@ describe('start', () => { }); it('supports HMR when a story file changes', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); - const { configure, clientApi, forceReRender } = start(render); + const { configure, clientApi, forceReRender } = start(renderToDOM); let disposeCallback: () => void; const module = { @@ -425,9 +426,9 @@ describe('start', () => { }); it('re-emits SET_STORIES when a story is added', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); - const { configure, clientApi, forceReRender } = start(render); + const { configure, clientApi, forceReRender } = start(renderToDOM); let disposeCallback: () => void; const module = { @@ -510,9 +511,9 @@ describe('start', () => { }); it('re-emits SET_STORIES when a story file is removed', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); - const { configure, clientApi, forceReRender } = start(render); + const { configure, clientApi, forceReRender } = start(renderToDOM); let disposeCallback: () => void; const moduleB = { @@ -636,9 +637,9 @@ describe('start', () => { describe('when configure is called with CSF only', () => { it('loads and renders the first story correctly', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure } = start(render); + const { configure } = start(renderToDOM); configure('test', () => [componentCExports]); await waitForRender(); @@ -701,7 +702,7 @@ describe('start', () => { 'component-c--story-one' ); - expect(render).toHaveBeenCalledWith( + expect(renderToDOM).toHaveBeenCalledWith( expect.objectContaining({ id: 'component-c--story-one', }), @@ -710,7 +711,7 @@ describe('start', () => { }); it('supports HMR when a story file changes', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); let disposeCallback: (data: object) => void; const module = { @@ -724,7 +725,7 @@ describe('start', () => { }, }; - const { configure } = start(render); + const { configure } = start(renderToDOM); configure('test', () => [componentCExports], module as any); await waitForRender(); @@ -754,7 +755,7 @@ describe('start', () => { }); it('re-emits SET_STORIES when a story is added', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); let disposeCallback: (data: object) => void; const module = { @@ -767,7 +768,7 @@ describe('start', () => { }, }, }; - const { configure } = start(render); + const { configure } = start(renderToDOM); configure('test', () => [componentCExports], module as any); await waitForRender(); @@ -851,7 +852,7 @@ describe('start', () => { }); it('re-emits SET_STORIES when a story file is removed', async () => { - const render = jest.fn(({ storyFn }) => storyFn()); + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); let disposeCallback: (data: object) => void; const module = { @@ -864,7 +865,7 @@ describe('start', () => { }, }, }; - const { configure } = start(render); + const { configure } = start(renderToDOM); configure( 'test', () => [componentCExports, { default: { title: 'Component D' }, StoryFour: jest.fn() }], @@ -1002,14 +1003,46 @@ describe('start', () => { "v": 2, } `); + + await waitForRender(); + }); + + it('allows you to override the render function in project annotations', async () => { + const renderToDOM = jest.fn(({ storyFn }) => storyFn()); + const frameworkRender = jest.fn(); + + const { configure } = start(renderToDOM, { render: frameworkRender }); + + const projectRender = jest.fn(); + setGlobalRender(projectRender); + configure('test', () => { + return [ + { + default: { + title: 'Component A', + component: jest.fn(), + }, + StoryOne: {}, + }, + ]; + }); + + await waitForRender(); + expect(mockChannel.emit).toHaveBeenCalledWith( + Events.STORY_RENDERED, + 'component-a--story-one' + ); + + expect(frameworkRender).not.toHaveBeenCalled(); + expect(projectRender).toHaveBeenCalled(); }); }); describe('when configure is called with a combination', () => { it('loads and renders the first story correctly', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure, clientApi } = start(render); + const { configure, clientApi } = start(renderToDOM); configure('test', () => { clientApi .storiesOf('Component A', { id: 'file1' } as NodeModule) @@ -1145,7 +1178,7 @@ describe('start', () => { 'component-a--story-one' ); - expect(render).toHaveBeenCalledWith( + expect(renderToDOM).toHaveBeenCalledWith( expect.objectContaining({ id: 'component-a--story-one', }), @@ -1268,9 +1301,9 @@ describe('start', () => { StoryOne: jest.fn(), }; it('loads and renders the first story correctly', async () => { - const render = jest.fn(); + const renderToDOM = jest.fn(); - const { configure } = start(render); + const { configure } = start(renderToDOM); configure('test', () => [componentDExports]); await waitForEvents([Events.SET_STORIES]); diff --git a/lib/core-client/src/preview/start.ts b/lib/core-client/src/preview/start.ts index 8ce0ec1810a2..0ee26eb30e78 100644 --- a/lib/core-client/src/preview/start.ts +++ b/lib/core-client/src/preview/start.ts @@ -2,12 +2,11 @@ import global from 'global'; import deprecate from 'util-deprecate'; import { ClientApi } from '@storybook/client-api'; import { PreviewWeb } from '@storybook/preview-web'; -import type { WebProjectAnnotations } from '@storybook/preview-web'; import type { AnyFramework, ArgsStoryFn } from '@storybook/csf'; import createChannel from '@storybook/channel-postmessage'; import { addons } from '@storybook/addons'; import Events from '@storybook/core-events'; -import type { Path } from '@storybook/store'; +import type { Path, WebProjectAnnotations } from '@storybook/store'; import { Loadable } from './types'; import { executeLoadableForChanges } from './executeLoadable'; @@ -118,8 +117,8 @@ export function start( ); return { - ...clientApi.facade.projectAnnotations, render, + ...clientApi.facade.projectAnnotations, renderToDOM, applyDecorators: decorateStory, }; diff --git a/lib/core-common/package.json b/lib/core-common/package.json index ae599536055d..0b33cbe55873 100644 --- a/lib/core-common/package.json +++ b/lib/core-common/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-common", - "version": "6.5.0-alpha.48", + "version": "6.5.0-beta.2", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" @@ -62,7 +62,7 @@ "@babel/preset-react": "^7.12.10", "@babel/preset-typescript": "^7.12.7", "@babel/register": "^7.12.1", - "@storybook/node-logger": "6.5.0-alpha.48", + "@storybook/node-logger": "6.5.0-beta.2", "@storybook/semver": "^7.3.2", "@types/node": "^14.0.10 || ^16.0.0", "@types/pretty-hrtime": "^1.0.0", @@ -100,8 +100,8 @@ "mock-fs": "^4.13.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": { "typescript": { @@ -111,6 +111,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "5f3afb8cf4389c16be11a6e5099e902d16a82762", + "gitHead": "b42ccab2b3f9d4f1f8f862242a5e4af0d3306061", "sbmodern": "dist/modern/index.js" } diff --git a/lib/core-common/src/index.ts b/lib/core-common/src/index.ts index ccdb8fbae13e..0414b1dd2d32 100644 --- a/lib/core-common/src/index.ts +++ b/lib/core-common/src/index.ts @@ -11,6 +11,9 @@ export * from './utils/interpret-require'; export * from './utils/load-custom-babel-config'; export * from './utils/load-custom-presets'; export * from './utils/load-custom-webpack-config'; +export * from './utils/load-main-config'; +export * from './utils/get-storybook-configuration'; +export * from './utils/get-storybook-info'; export * from './utils/load-manager-or-addons-file'; export * from './utils/load-preview-or-config-file'; export * from './utils/log-config'; diff --git a/lib/core-common/src/presets.test.ts b/lib/core-common/src/presets.test.ts index d9a26cbf12a2..ac19e6becbd1 100644 --- a/lib/core-common/src/presets.test.ts +++ b/lib/core-common/src/presets.test.ts @@ -17,28 +17,45 @@ jest.mock('@storybook/node-logger', () => ({ }, })); -jest.mock('resolve-from', () => (l: any, name: string) => { +jest.mock('./utils/safeResolve', () => { const KNOWN_FILES = [ + '@storybook/react', + '@storybook/addon-actions/manager', '@storybook/addon-actions/register', './local/preset', './local/addons', '/absolute/preset', '/absolute/addons', + '@storybook/addon-docs', + '@storybook/addon-cool', '@storybook/addon-docs/preset', + '@storybook/addon-interactions/preset', '@storybook/addon-essentials', + '@storybook/addon-knobs/manager', '@storybook/addon-knobs/register', '@storybook/addon-notes/register-panel', '@storybook/preset-create-react-app', '@storybook/preset-typescript', 'addon-bar/preset.js', + 'addon-bar', 'addon-baz/register.js', 'addon-foo/register.js', ]; - if (KNOWN_FILES.includes(name)) { - return name; - } - throw new Error(`cannot resolve ${name}`); + return { + safeResolveFrom: jest.fn((l: any, name: string) => { + if (KNOWN_FILES.includes(name)) { + return name; + } + return undefined; + }), + safeResolve: jest.fn((name: string) => { + if (KNOWN_FILES.includes(name)) { + return name; + } + return undefined; + }), + }; }); describe('presets', () => { @@ -388,12 +405,21 @@ describe('resolveAddonName', () => { it('should resolve managerEntries', () => { expect(resolveAddonName({}, '@storybook/addon-actions/register')).toEqual({ name: '@storybook/addon-actions/register', - type: 'managerEntries', + managerEntries: ['@storybook/addon-actions/register'], + type: 'virtual', + }); + }); + + it('should resolve managerEntries from new /manager path', () => { + expect(resolveAddonName({}, '@storybook/addon-actions/manager')).toEqual({ + name: '@storybook/addon-actions/manager', + managerEntries: ['@storybook/addon-actions/manager'], + type: 'virtual', }); }); it('should resolve presets', () => { - expect(resolveAddonName({}, '@storybook/addon-docs')).toEqual({ + expect(resolveAddonName({}, '@storybook/addon-docs/preset')).toEqual({ name: '@storybook/addon-docs/preset', type: 'presets', }); @@ -417,7 +443,12 @@ describe('loadPreset', () => { mockPreset('@storybook/addon-docs/preset', {}); mockPreset('@storybook/addon-actions/register', {}); mockPreset('addon-foo/register.js', {}); - mockPreset('addon-bar/preset', {}); + mockPreset('@storybook/addon-cool', {}); + mockPreset('@storybook/addon-interactions/preset', {}); + mockPreset('addon-bar', { + addons: ['@storybook/addon-cool'], + presets: ['@storybook/addon-interactions/preset'], + }); mockPreset('addon-baz/register.js', {}); mockPreset('@storybook/addon-notes/register-panel', {}); @@ -427,10 +458,10 @@ describe('loadPreset', () => { const loaded = loadPreset( { name: '', - type: 'managerEntries', + type: 'virtual', framework: '@storybook/react', presets: ['@storybook/preset-typescript'], - addons: ['@storybook/addon-docs'], + addons: ['@storybook/addon-docs/preset'], }, 0, {} @@ -447,6 +478,11 @@ describe('loadPreset', () => { "options": Object {}, "preset": Object {}, }, + Object { + "name": "@storybook/react", + "options": Object {}, + "preset": Object {}, + }, Object { "name": "@storybook/addon-docs/preset", "options": Object {}, @@ -455,14 +491,14 @@ describe('loadPreset', () => { Object { "name": Object { "addons": Array [ - "@storybook/addon-docs", + "@storybook/addon-docs/preset", ], "framework": "@storybook/react", "name": "", "presets": Array [ "@storybook/preset-typescript", ], - "type": "managerEntries", + "type": "virtual", }, "options": Object {}, "preset": Object {}, @@ -475,14 +511,14 @@ describe('loadPreset', () => { const loaded = loadPreset( { name: '', - type: 'managerEntries', + type: 'virtual', presets: ['@storybook/preset-typescript'], addons: [ - '@storybook/addon-docs', + '@storybook/addon-docs/preset', '@storybook/addon-actions/register', 'addon-foo/register.js', 'addon-bar', - 'addon-baz/register.tsx', + 'addon-baz/register.js', '@storybook/addon-notes/register-panel', ], }, @@ -501,34 +537,43 @@ describe('loadPreset', () => { preset: {}, }, { - name: '@storybook/addon-actions/register_additionalManagerEntries', + name: '@storybook/addon-actions/register', options: {}, preset: { managerEntries: ['@storybook/addon-actions/register'], }, }, { - name: 'addon-foo/register.js_additionalManagerEntries', + name: 'addon-foo/register.js', options: {}, preset: { managerEntries: ['addon-foo/register.js'], }, }, - // should be there, but some file mocking problem is causing it to not resolve - // { - // name: 'addon-bar', - // options: {}, - // preset: {}, - // }, { - name: 'addon-baz/register.tsx_additionalManagerEntries', + name: '@storybook/addon-interactions/preset', + options: {}, + preset: {}, + }, + { + name: '@storybook/addon-cool', + options: {}, + preset: {}, + }, + { + name: 'addon-bar', + options: {}, + preset: {}, + }, + { + name: 'addon-baz/register.js', options: {}, preset: { - managerEntries: ['addon-baz/register.tsx'], + managerEntries: ['addon-baz/register.js'], }, }, { - name: '@storybook/addon-notes/register-panel_additionalManagerEntries', + name: '@storybook/addon-notes/register-panel', options: {}, preset: { managerEntries: ['@storybook/addon-notes/register-panel'], @@ -538,15 +583,15 @@ describe('loadPreset', () => { name: { presets: ['@storybook/preset-typescript'], addons: [ - '@storybook/addon-docs', + '@storybook/addon-docs/preset', '@storybook/addon-actions/register', 'addon-foo/register.js', 'addon-bar', - 'addon-baz/register.tsx', + 'addon-baz/register.js', '@storybook/addon-notes/register-panel', ], name: '', - type: 'managerEntries', + type: 'virtual', }, options: {}, preset: {}, diff --git a/lib/core-common/src/presets.ts b/lib/core-common/src/presets.ts index fdc8f48da238..24093df15337 100644 --- a/lib/core-common/src/presets.ts +++ b/lib/core-common/src/presets.ts @@ -1,7 +1,6 @@ import dedent from 'ts-dedent'; import { resolve } from 'path'; import { logger } from '@storybook/node-logger'; -import resolveFrom from 'resolve-from'; import { CLIOptions, LoadedPreset, @@ -12,6 +11,7 @@ import { } from './types'; import { loadCustomPresets } from './utils/load-custom-presets'; import { serverRequire } from './utils/interpret-require'; +import { safeResolve, safeResolveFrom } from './utils/safeResolve'; const isObject = (val: unknown): val is Record => val != null && typeof val === 'object' && Array.isArray(val) === false; @@ -45,8 +45,8 @@ function resolvePresetFunction( * Parse an addon into either a managerEntries or a preset. Throw on invalid input. * * Valid inputs: - * - '@storybook/addon-actions/register' - * => { type: 'managerEntries', item } + * - '@storybook/addon-actions/manager' + * => { type: 'virtual', item } * * - '@storybook/addon-docs/preset' * => { type: 'presets', item } @@ -57,68 +57,95 @@ function resolvePresetFunction( * - { name: '@storybook/addon-docs(/preset)?', options: { ... } } * => { type: 'presets', item: { name: '@storybook/addon-docs/preset', options } } */ -export const resolveAddonName = (configDir: string, name: string) => { - let path; - - if (name.startsWith('.')) { - path = resolveFrom(configDir, name); - } else if (name.startsWith('/')) { - path = name; - } else if (name.match(/\/(preset|register(-panel)?)(\.(js|ts|tsx|jsx))?$/)) { - path = name; - } +interface ResolvedAddonPreset { + type: 'presets'; + name: string; +} +interface ResolvedAddonVirtual { + type: 'virtual'; + name: string; + managerEntries?: string[]; + previewAnnotations?: string[]; + presets?: (string | { name: string; options?: any })[]; +} - // when user provides full path, we don't need to do anything - if (path) { +export const resolveAddonName = ( + configDir: string, + name: string, + options: any +): ResolvedAddonPreset | ResolvedAddonVirtual => { + const r = name.startsWith('/') ? safeResolve : safeResolveFrom.bind(null, configDir); + const resolved = r(name); + + if (name.match(/\/(manager|register(-panel)?)(\.(js|ts|tsx|jsx))?$/)) { return { - name: path, - // Accept `register`, `register.js`, `require.resolve('foo/register'), `register-panel` - type: path.match(/register(-panel)?(\.(js|ts|tsx|jsx))?$/) ? 'managerEntries' : 'presets', + type: 'virtual', + name, + managerEntries: [resolved], + }; + } + if (name.match(/\/(preset)(\.(js|ts|tsx|jsx))?$/)) { + return { + type: 'presets', + name: resolved, }; } - try { + const path = name; + + // when user provides full path, we don't need to do anything! + const managerFile = safeResolve(`${path}/manager`); + const registerFile = safeResolve(`${path}/register`) || safeResolve(`${path}/register-panel`); + const previewFile = safeResolve(`${path}/preview`); + const presetFile = safeResolve(`${path}/preset`); + + if (!(managerFile || previewFile) && presetFile) { return { - name: resolveFrom(configDir, `${name}/preset`), type: 'presets', + name: presetFile, }; - // eslint-disable-next-line no-empty - } catch (err) {} + } + + if (managerFile || registerFile || previewFile || presetFile) { + const managerEntries = []; + + if (managerFile) { + managerEntries.push(managerFile); + } + // register file is the old way of registering addons + if (!managerFile && registerFile && !presetFile) { + managerEntries.push(registerFile); + } - try { return { - name: resolveFrom(configDir, `${name}/register`), - type: 'managerEntries', + type: 'virtual', + name: path, + ...(managerEntries.length ? { managerEntries } : {}), + ...(previewFile ? { previewAnnotations: [previewFile] } : {}), + ...(presetFile ? { presets: [{ name: presetFile, options }] } : {}), }; - // eslint-disable-next-line no-empty - } catch (err) {} + } return { - name: resolveFrom(configDir, name), type: 'presets', + name: resolved, }; }; const map = ({ configDir }: InterPresetOptions) => (item: any) => { + const options = isObject(item) ? item.options || undefined : undefined; + const name = isObject(item) ? item.name : item; try { - if (isObject(item)) { - const { name } = resolveAddonName(configDir, item.name); - return { ...item, name }; - } - const { name, type } = resolveAddonName(configDir, item); - if (type === 'managerEntries') { - return { - name: `${name}_additionalManagerEntries`, - type, - managerEntries: [name], - }; - } - return resolveAddonName(configDir, name); + const resolved = resolveAddonName(configDir, name, options); + return { + ...(options ? { options } : {}), + ...resolved, + }; } catch (err) { logger.error( - `Addon value should end in /register OR it should be a valid preset https://storybook.js.org/docs/react/addons/writing-presets/\n${item}` + `Addon value should end in /manager or /preview or /register OR it should be a valid preset https://storybook.js.org/docs/react/addons/writing-presets/\n${item}` ); } return undefined; @@ -135,7 +162,7 @@ function interopRequireDefault(filePath: string) { } function getContent(input: any) { - if (input.type === 'managerEntries') { + if (input.type === 'virtual') { const { type, name, ...rest } = input; return rest; } diff --git a/lib/core-common/src/types.ts b/lib/core-common/src/types.ts index 371878343cb5..b3ca1000ff06 100644 --- a/lib/core-common/src/types.ts +++ b/lib/core-common/src/types.ts @@ -50,6 +50,28 @@ export interface CoreConfig { builder: BuilderConfig; disableWebpackDefaults?: boolean; channelOptions?: Partial; + /** + * Disables the generation of project.json, a file containing Storybook metadata + */ + disableProjectJson?: boolean; + /** + * Disables Storybook telemetry + * @see https://storybook.js.org/telemetry + */ + disableTelemetry?: boolean; + /** + * Enable crash reports to be sent to Storybook telemetry + * @see https://storybook.js.org/telemetry + */ + enableCrashReports?: boolean; + /** + * enable CORS headings to run document in a "secure context" + * see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements + * This enables these headers in development-mode: + * Cross-Origin-Opener-Policy: same-origin + * Cross-Origin-Embedder-Policy: require-corp + */ + crossOriginIsolated?: boolean; } interface DirectoryMapping { @@ -133,6 +155,11 @@ export interface PackageJson { version: string; dependencies?: Record; devDependencies?: Record; + peerDependencies?: Record; + scripts?: Record; + eslintConfig?: Record; + type?: 'module'; + [key: string]: any; } // TODO: This could be exported to the outside world and used in `options.ts` file of each `@storybook/APP` @@ -157,6 +184,8 @@ export interface CLIOptions { ignorePreview?: boolean; previewUrl?: string; forceBuildPreview?: boolean; + disableTelemetry?: boolean; + enableCrashReports?: boolean; host?: string; /** * @deprecated Use 'staticDirs' Storybook Configuration option instead @@ -412,6 +441,13 @@ export interface StorybookConfig { /** * Add additional scripts to run in the preview a la `.storybook/preview.js` + * + * @deprecated use `previewAnnotations` or `/preview.js` file instead */ config?: (entries: Entry[], options: Options) => Entry[]; + + /** + * Add additional scripts to run in the preview a la `.storybook/preview.js` + */ + previewAnnotations?: (entries: Entry[], options: Options) => Entry[]; } diff --git a/lib/core-common/src/utils/file-cache.ts b/lib/core-common/src/utils/file-cache.ts index 56c2ea240049..2f810b927a34 100644 --- a/lib/core-common/src/utils/file-cache.ts +++ b/lib/core-common/src/utils/file-cache.ts @@ -31,7 +31,7 @@ export class FileSystemCache { } getSync(key: string, defaultValue?: any): any | typeof defaultValue { - this.internal.getSync(key, defaultValue); + return this.internal.getSync(key, defaultValue); } set(key: string, value: any): Promise<{ path: string }> { diff --git a/lib/cli/src/automigrate/helpers/getStorybookConfiguration.test.ts b/lib/core-common/src/utils/get-storybook-configuration.test.ts similarity index 92% rename from lib/cli/src/automigrate/helpers/getStorybookConfiguration.test.ts rename to lib/core-common/src/utils/get-storybook-configuration.test.ts index 47c57eeba423..e6a460acdf90 100644 --- a/lib/cli/src/automigrate/helpers/getStorybookConfiguration.test.ts +++ b/lib/core-common/src/utils/get-storybook-configuration.test.ts @@ -1,4 +1,4 @@ -import { getStorybookConfiguration } from './getStorybookConfiguration'; +import { getStorybookConfiguration } from './get-storybook-configuration'; describe('getStorybookConfiguration', () => { it('handles short names', () => { diff --git a/lib/cli/src/automigrate/helpers/getStorybookConfiguration.ts b/lib/core-common/src/utils/get-storybook-configuration.ts similarity index 91% rename from lib/cli/src/automigrate/helpers/getStorybookConfiguration.ts rename to lib/core-common/src/utils/get-storybook-configuration.ts index 98529af472b0..a1dd17c1ffc2 100644 --- a/lib/cli/src/automigrate/helpers/getStorybookConfiguration.ts +++ b/lib/core-common/src/utils/get-storybook-configuration.ts @@ -9,6 +9,10 @@ export function getStorybookConfiguration( shortName: string, longName: string ) { + if (!storybookScript) { + return null; + } + const parts = storybookScript.split(/[\s='"]+/); let index = parts.indexOf(longName); if (index === -1) { diff --git a/lib/cli/src/automigrate/helpers/getStorybookInfo.ts b/lib/core-common/src/utils/get-storybook-info.ts similarity index 87% rename from lib/cli/src/automigrate/helpers/getStorybookInfo.ts rename to lib/core-common/src/utils/get-storybook-info.ts index ef6b3efd9d08..000f37bcff08 100644 --- a/lib/cli/src/automigrate/helpers/getStorybookInfo.ts +++ b/lib/core-common/src/utils/get-storybook-info.ts @@ -1,7 +1,7 @@ import path from 'path'; import fse from 'fs-extra'; -import { PackageJsonWithDepsAndDevDeps } from '../../js-package-manager'; -import { getStorybookConfiguration } from './getStorybookConfiguration'; +import { getStorybookConfiguration } from './get-storybook-configuration'; +import { PackageJson } from '../types'; interface StorybookInfo { framework: string; @@ -32,7 +32,7 @@ const viewLayers: Record = { const logger = console; const findDependency = ( - { dependencies, devDependencies, peerDependencies }: PackageJsonWithDepsAndDevDeps, + { dependencies, devDependencies, peerDependencies }: PackageJson, predicate: (entry: [string, string]) => string ) => [ Object.entries(dependencies || {}).find(predicate), @@ -40,7 +40,7 @@ const findDependency = ( Object.entries(peerDependencies || {}).find(predicate), ]; -const getFrameworkInfo = (packageJson: PackageJsonWithDepsAndDevDeps) => { +const getFrameworkInfo = (packageJson: PackageJson) => { // Pull the viewlayer from dependencies in package.json const [dep, devDep, peerDep] = findDependency(packageJson, ([key]) => viewLayers[key]); const [pkg, version] = dep || devDep || peerDep || []; @@ -70,7 +70,7 @@ const findConfigFile = (prefix: string, configDir: string) => { return extension ? `${filePrefix}.${extension}` : null; }; -const getConfigInfo = (packageJson: PackageJsonWithDepsAndDevDeps) => { +const getConfigInfo = (packageJson: PackageJson) => { let configDir = '.storybook'; const storybookScript = packageJson.scripts?.storybook; if (storybookScript) { @@ -86,7 +86,7 @@ const getConfigInfo = (packageJson: PackageJsonWithDepsAndDevDeps) => { }; }; -export const getStorybookInfo = (packageJson: PackageJsonWithDepsAndDevDeps) => { +export const getStorybookInfo = (packageJson: PackageJson) => { const frameworkInfo = getFrameworkInfo(packageJson); const configInfo = getConfigInfo(packageJson); diff --git a/lib/core-common/src/utils/load-main-config.ts b/lib/core-common/src/utils/load-main-config.ts new file mode 100644 index 000000000000..67b294e33275 --- /dev/null +++ b/lib/core-common/src/utils/load-main-config.ts @@ -0,0 +1,10 @@ +import path from 'path'; +import { serverRequire } from './interpret-require'; +import { validateConfigurationFiles } from './validate-configuration-files'; +import { StorybookConfig } from '../types'; + +export function loadMainConfig({ configDir }: { configDir: string }): StorybookConfig { + validateConfigurationFiles(configDir); + + return serverRequire(path.resolve(configDir, 'main')); +} diff --git a/lib/core-common/src/utils/notify-telemetry.ts b/lib/core-common/src/utils/notify-telemetry.ts new file mode 100644 index 000000000000..53b291b4b6a8 --- /dev/null +++ b/lib/core-common/src/utils/notify-telemetry.ts @@ -0,0 +1,31 @@ +import chalk from 'chalk'; +import { cache } from './cache'; + +const TELEMETRY_KEY_NOTIFY_DATE = 'telemetry-notification-date'; + +const logger = console; + +export const notifyTelemetry = async () => { + const telemetryNotifyDate = await cache.get(TELEMETRY_KEY_NOTIFY_DATE, null); + // The end-user has already been notified about our telemetry integration. We + // don't need to constantly annoy them about it. + // We will re-inform users about the telemetry if significant changes are + // ever made. + if (telemetryNotifyDate) { + return; + } + + cache.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now().toString()); + + logger.log( + `${chalk.magenta.bold( + 'Attention' + )}: Storybook now collects completely anonymous telemetry regarding usage.` + ); + logger.log(`This information is used to shape Storybook's roadmap and prioritize features.`); + logger.log( + `You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:` + ); + logger.log(chalk.cyan('https://storybook.js.org/telemetry')); + logger.log(); +}; diff --git a/lib/core-common/src/utils/safeResolve.ts b/lib/core-common/src/utils/safeResolve.ts new file mode 100644 index 000000000000..a1d5684e45b5 --- /dev/null +++ b/lib/core-common/src/utils/safeResolve.ts @@ -0,0 +1,17 @@ +import resolveFrom from 'resolve-from'; + +export const safeResolveFrom = (path: string, file: string) => { + try { + return resolveFrom(path, file); + } catch (e) { + return undefined; + } +}; + +export const safeResolve = (file: string) => { + try { + return require.resolve(file); + } catch (e) { + return undefined; + } +}; diff --git a/lib/core-common/templates/base-preview-head.html b/lib/core-common/templates/base-preview-head.html index 1014b3161e85..45c0c3032dac 100644 --- a/lib/core-common/templates/base-preview-head.html +++ b/lib/core-common/templates/base-preview-head.html @@ -1,6 +1,17 @@