diff --git a/.circleci/config.yml b/.circleci/config.yml index b5259168ea40..445608a1fc38 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -198,7 +198,7 @@ jobs: command: yarn test:e2e-framework --clean --all --skip angular11 --skip angular --skip vue3 --skip web_components_typescript --skip cra no_output_timeout: 5m - store_artifacts: - path: /tmp/storybook/cypress + path: /tmp/cypress-record destination: cypress e2e-tests-core: executor: @@ -224,7 +224,7 @@ jobs: command: yarn test:e2e-framework vue3 angular angular11 web_components_typescript web_components_lit2 no_output_timeout: 5m - store_artifacts: - path: /tmp/storybook/cypress + path: /tmp/cypress-record destination: cypress cra-bench: executor: @@ -271,7 +271,7 @@ jobs: name: run e2e tests command: yarn test:e2e-framework --pnp sfcVue cra - store_artifacts: - path: /tmp/storybook/cypress + path: /tmp/cypress-record destination: cypress e2e-tests-examples: executor: @@ -293,7 +293,7 @@ jobs: name: cypress run command: yarn test:e2e-examples - store_artifacts: - path: /tmp/storybook/cypress + path: /tmp/cypress-record destination: cypress smoke-tests: executor: diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml index f8a75e7201a2..43ea60fc73dd 100644 --- a/.github/workflows/tests-unit.yml +++ b/.github/workflows/tests-unit.yml @@ -7,19 +7,15 @@ jobs: name: Core Unit Tests runs-on: ubuntu-latest steps: - - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - uses: actions/checkout@v2 - - name: Cache node modules - uses: actions/cache@v2 - with: - path: node_modules - key: yarn-2-cache-v1-${{ hashFiles('**/yarn.lock') }} - - name: install, bootstrap - run: | - yarn install --immutable - yarn bootstrap --core - - name: test - run: | - yarn test --runInBand --ci + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: "12.x" + cache: yarn + - name: install, bootstrap + run: | + yarn install --immutable + yarn bootstrap --core + - name: test + run: | + yarn test --runInBand --ci diff --git a/CHANGELOG.md b/CHANGELOG.md index 15c0247a7085..7a7e69c4205f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,112 @@ +## 6.4.0-alpha.17 (July 15, 2021) + +### Features + +- Types: Export BaseStoryFn and BaseStoryObject ([#15592](https://github.com/storybookjs/storybook/pull/15592)) +- Addon-docs: Add transparency support to color swatch ([#14439](https://github.com/storybookjs/storybook/pull/14439)) + +## 6.4.0-alpha.16 (July 13, 2021) + +### Features + +- Addon-backgrounds: Respect user's reduced motion settings ([#13711](https://github.com/storybookjs/storybook/pull/13711)) +- CSF: Add CSF3 typings ([#15558](https://github.com/storybookjs/storybook/pull/15558)) + +### Bug Fixes + +- Angular: Fix actions argType auto generation ([#15563](https://github.com/storybookjs/storybook/pull/15563)) + +## 6.4.0-alpha.15 (July 13, 2021) + +### Bug Fixes + +- Controls: Fix color matching behavior for non-string types ([#15549](https://github.com/storybookjs/storybook/pull/15549)) +- UI: Fix toggle button for custom theming ([#15449](https://github.com/storybookjs/storybook/pull/15449)) + +### Maintenance + +- Build: Fix `publish` step on CircleCI ([#15556](https://github.com/storybookjs/storybook/pull/15556)) +- Examples: Add no-manager-cache to all examples ([#15546](https://github.com/storybookjs/storybook/pull/15546)) +- Official-storybook: Add example of embedding story object in MDX ([#15533](https://github.com/storybookjs/storybook/pull/15533)) + +## 6.4.0-alpha.14 (July 11, 2021) + +### Features + +- Web-components: Dynamic source snippets ([#15337](https://github.com/storybookjs/storybook/pull/15337)) + +### Maintenance + +- Essentials: Add measure addon to monorepo ([#15545](https://github.com/storybookjs/storybook/pull/15545)) + +## 6.4.0-alpha.13 (July 9, 2021) + +### Bug Fixes + +- Addon-docs/Angular: Add unique id to Angular stories ([#15501](https://github.com/storybookjs/storybook/pull/15501)) +- Composition: Fix refs ordering ([#15527](https://github.com/storybookjs/storybook/pull/15527)) + +### Maintenance + +- Essentials: Add outline addon to monorepo ([#15526](https://github.com/storybookjs/storybook/pull/15526)) +- Build: Fix cache setup in GitHub Actions workflow ([#15523](https://github.com/storybookjs/storybook/pull/15523)) + +## 6.3.4 (July 8, 2021) + +### Maintenance + +- Addon-docs: Cache DocsContext on window to prevent duplication ([#15428](https://github.com/storybookjs/storybook/pull/15428)) + +## 6.3.3 (July 7, 2021) + +### Bug Fixes + +- Webpack5: Quit process after finishing a static build ([#15483](https://github.com/storybookjs/storybook/pull/15483)) +- Addon-docs/Angular: Fix numeric args default value handling ([#15491](https://github.com/storybookjs/storybook/pull/15491)) +- Angular: Fix circular reference not being handled in moduleMetadata ([#15410](https://github.com/storybookjs/storybook/pull/15410)) +- Core: Fix double rebuilds by removing aggregateTimeout ([#15372](https://github.com/storybookjs/storybook/pull/15372)) +- CLI: Fix NPM typo ([#15461](https://github.com/storybookjs/storybook/pull/15461)) + +## 6.4.0-alpha.12 (July 7, 2021) + +### Bug Fixes + +- Webpack5: Quit process after finishing a static build ([#15483](https://github.com/storybookjs/storybook/pull/15483)) +- Addon-docs/Angular: Fix numeric args default value handling ([#15491](https://github.com/storybookjs/storybook/pull/15491)) + +### Maintenance + +- Angular: Make Ivy work by default in the angular-cli example ([#15280](https://github.com/storybookjs/storybook/pull/15280)) +- Official-storybook: Fix shortcut for navigating to previous language ([#15489](https://github.com/storybookjs/storybook/pull/15489)) +- Addon-docs: Add docs to standalone example ([#7848](https://github.com/storybookjs/storybook/pull/7848)) +- Build: Update Yarn cache setup in GitHub Actions workflow ([#15480](https://github.com/storybookjs/storybook/pull/15480)) + +## 6.4.0-alpha.11 (July 3, 2021) + +### Bug Fixes + +- UI: Fix sidebar toggle in fullscreen mode ([#15459](https://github.com/storybookjs/storybook/pull/15459)) +- Angular: Fix circular reference not being handled in moduleMetadata ([#15410](https://github.com/storybookjs/storybook/pull/15410)) + +### Maintenance + +- Addon-a11y: Reverse help and description labels in accordion ([#15466](https://github.com/storybookjs/storybook/pull/15466)) + +## 6.4.0-alpha.10 (July 2, 2021) + +### Features + +- UI: Display menu icon on the toolbar when the sidebar is collapsed ([#15369](https://github.com/storybookjs/storybook/pull/15369)) + +### Bug Fixes + +- Core: Fix double rebuilds by removing aggregateTimeout ([#15372](https://github.com/storybookjs/storybook/pull/15372)) +- CLI: Fix NPM typo ([#15461](https://github.com/storybookjs/storybook/pull/15461)) + +### Maintenance + +- Addon-docs: Cache DocsContext on window to prevent duplication ([#15428](https://github.com/storybookjs/storybook/pull/15428)) + ## 6.3.2 (June 30, 2021) ### Bug Fixes diff --git a/MIGRATION.md b/MIGRATION.md index ca2578e6b7b6..9426f71bf721 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -4,10 +4,10 @@ - [Webpack 5 manager build](#webpack-5-manager-build) - [Angular 12 upgrade](#angular-12-upgrade) - [Lit support](#lit-support) + - [No longer inferring default values of args](#no-longer-inferring-default-values-of-args) - [6.3 deprecations](#63-deprecations) - [Deprecated addon-knobs](#deprecated-addon-knobs) - [Deprecated scoped blocks imports](#deprecated-scoped-blocks-imports) - - [Deprecated `argType.defaultValue`](#deprecated-argtypedefaultvalue) - [Deprecated layout URL params](#deprecated-layout-url-params) - [From version 6.1.x to 6.2.0](#from-version-61x-to-620) - [MDX pattern tweaked](#mdx-pattern-tweaked) @@ -176,6 +176,14 @@ yarn add @storybook/manager-webpack5 --dev npm install @storybook/manager-webpack5 --save-dev ``` +Because Storybook uses `webpack@4` as the default, it's possible for the wrong version of webpack to get hoisted by your package manager. If you receive an error that looks like you might be using the wrong version of webpack, install `webpack@5` explicitly as a dev dependency to force it to be hoisted: + +```shell +yarn add webpack@5 --dev +# Or +npm install webpack@5 --save-dev +``` + ### Angular 12 upgrade Storybook 6.3 supports Angular 12 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to do the following steps to force Storybook to use webpack 5 for building your project: @@ -204,34 +212,13 @@ To do so, it relies on helpers added in the latest minor versions of `lit-html`/ According to the package manager you are using, it can be handled automatically when updating Storybook or can require to manually update the versions and regenerate the lockfile. -### 6.3 deprecations - -#### Deprecated addon-knobs - -We are replacing `@storybook/addon-knobs` with `@storybook/addon-controls`. - -- [Rationale & discussion](https://github.com/storybookjs/storybook/discussions/15060) -- [Migration notes](https://github.com/storybookjs/storybook/blob/next/addons/controls/README.md#how-do-i-migrate-from-addon-knobs) - -#### Deprecated scoped blocks imports - -In 6.3, we changed doc block imports from `@storybook/addon-docs/blocks` to `@storybook/addon-docs`. This makes it possible for bundlers to automatically choose the ESM or CJS version of the library depending on the context. - -To update your code, you should be able to global replace `@storybook/addon-docs/blocks` with `@storybook/addon-docs`. Example: - -```js -// before -import { Meta, Story } from '@storybook/addon-docs/blocks'; - -// after -import { Meta, Story } from '@storybook/addon-docs'; -``` - -#### Deprecated `argType.defaultValue` +### No longer inferring default values of args Previously, unset `args` were set to the `argType.defaultValue` if set or inferred from the component's prop types (etc.). In 6.3 we no longer infer default values and instead set arg values to `undefined` when unset, allowing the framework to supply the default value. -If you were using `argType.defaultValue` to fix issues with the above inference, it should no longer be necessary, you can remove that code. If you were using it to set a default value for an arg, there is a simpler way; simply set a value for the arg at the component level: +If you were using `argType.defaultValue` to fix issues with the above inference, it should no longer be necessary, you can remove that code. + +If you were using `argType.defaultValue` or relying on inference to set a default value for an arg, you should now set a value for the arg at the component level: ```js export default { @@ -255,6 +242,29 @@ export default { }; ``` +### 6.3 deprecations + +#### Deprecated addon-knobs + +We are replacing `@storybook/addon-knobs` with `@storybook/addon-controls`. + +- [Rationale & discussion](https://github.com/storybookjs/storybook/discussions/15060) +- [Migration notes](https://github.com/storybookjs/storybook/blob/next/addons/controls/README.md#how-do-i-migrate-from-addon-knobs) + +#### Deprecated scoped blocks imports + +In 6.3, we changed doc block imports from `@storybook/addon-docs/blocks` to `@storybook/addon-docs`. This makes it possible for bundlers to automatically choose the ESM or CJS version of the library depending on the context. + +To update your code, you should be able to global replace `@storybook/addon-docs/blocks` with `@storybook/addon-docs`. Example: + +```js +// before +import { Meta, Story } from '@storybook/addon-docs/blocks'; + +// after +import { Meta, Story } from '@storybook/addon-docs'; +``` + #### Deprecated layout URL params Several URL params to control the manager layout have been deprecated and will be removed in 7.0: diff --git a/addons/a11y/package.json b/addons/a11y/package.json index 633647506235..b72f932802c7 100644 --- a/addons/a11y/package.json +++ b/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", @@ -11,13 +11,13 @@ "verify", "test" ], - "homepage": "https://github.com/storybookjs/storybook#readme", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/a11y", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, "repository": { "type": "git", - "url": "git+https://github.com/storybookjs/storybook.git", + "url": "https://github.com/storybookjs/storybook.git", "directory": "addons/a11y" }, "funding": { @@ -45,14 +45,14 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/channels": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/client-logger": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/channels": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "axe-core": "^4.2.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -81,7 +81,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Accessibility", diff --git a/addons/a11y/src/components/Report/Info.tsx b/addons/a11y/src/components/Report/Info.tsx index 743a617c02f4..0a8434e96dbf 100644 --- a/addons/a11y/src/components/Report/Info.tsx +++ b/addons/a11y/src/components/Report/Info.tsx @@ -7,7 +7,7 @@ const Wrapper = styled.div({ padding: 12, marginBottom: 10, }); -const Help = styled.p({ +const Description = styled.p({ margin: '0 0 12px', }); const Link = styled.a({ @@ -24,7 +24,7 @@ interface InfoProps { export const Info: FunctionComponent = ({ item }) => { return ( - {item.help} + {item.description} More info... diff --git a/addons/a11y/src/components/Report/Item.tsx b/addons/a11y/src/components/Report/Item.tsx index 815aa0a176b7..d00cffda1ce2 100644 --- a/addons/a11y/src/components/Report/Item.tsx +++ b/addons/a11y/src/components/Report/Item.tsx @@ -82,7 +82,7 @@ export const Item = (props: ItemProps) => { transform: `rotate(${open ? 0 : -90}deg)`, }} /> - {item.description} + {item.help} diff --git a/addons/actions/package.json b/addons/actions/package.json index e0ea3d243bf6..ca084ec50d39 100644 --- a/addons/actions/package.json +++ b/addons/actions/package.json @@ -1,13 +1,13 @@ { "name": "@storybook/addon-actions", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", "essentials", "data-state" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/actions", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/actions", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -41,12 +41,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "fast-deep-equal": "^3.1.3", "global": "^4.4.0", @@ -78,7 +78,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Actions", diff --git a/addons/backgrounds/package.json b/addons/backgrounds/package.json index 19db457cc687..2b092acb0480 100644 --- a/addons/backgrounds/package.json +++ b/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", @@ -10,7 +10,7 @@ "essentials", "design" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/backgrounds", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/backgrounds", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,12 +45,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-logger": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "global": "^4.4.0", "memoizerific": "^1.11.3", @@ -76,7 +76,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Backgrounds", diff --git a/addons/backgrounds/src/decorators/withBackground.ts b/addons/backgrounds/src/decorators/withBackground.ts index defad6f99c71..26ce596afc29 100644 --- a/addons/backgrounds/src/decorators/withBackground.ts +++ b/addons/backgrounds/src/decorators/withBackground.ts @@ -1,7 +1,12 @@ import { StoryFn as StoryFunction, StoryContext, useMemo, useEffect } from '@storybook/addons'; import { PARAM_KEY as BACKGROUNDS_PARAM_KEY } from '../constants'; -import { clearStyles, addBackgroundStyle, getBackgroundColorByName } from '../helpers'; +import { + clearStyles, + addBackgroundStyle, + getBackgroundColorByName, + isReduceMotionEnabled, +} from '../helpers'; export const withBackground = (StoryFn: StoryFunction, context: StoryContext) => { const { globals, parameters } = context; @@ -29,10 +34,11 @@ export const withBackground = (StoryFn: StoryFunction, context: StoryContext) => context.viewMode === 'docs' ? `#anchor--${context.id} .docs-story` : '.sb-show-main'; const backgroundStyles = useMemo(() => { + const transitionStyle = 'transition: background-color 0.3s;'; return ` ${selector} { background: ${selectedBackgroundColor} !important; - transition: background-color 0.3s; + ${isReduceMotionEnabled() ? '' : transitionStyle} } `; }, [selectedBackgroundColor, selector]); diff --git a/addons/backgrounds/src/helpers/index.ts b/addons/backgrounds/src/helpers/index.ts index 3b1d00f237f5..9b35c8acea87 100644 --- a/addons/backgrounds/src/helpers/index.ts +++ b/addons/backgrounds/src/helpers/index.ts @@ -5,7 +5,12 @@ import { logger } from '@storybook/client-logger'; import { Background } from '../types'; -const { document } = global; +const { document, window } = global; + +export const isReduceMotionEnabled = () => { + const prefersReduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + return prefersReduceMotion.matches; +}; export const getBackgroundColorByName = ( currentSelectedValue: string, diff --git a/addons/controls/package.json b/addons/controls/package.json index 5fbb6962f989..4df03eeb8b74 100644 --- a/addons/controls/package.json +++ b/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", @@ -45,12 +45,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/node-logger": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/node-logger": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "ts-dedent": "^2.0.0" }, @@ -69,7 +69,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/register.js", "storybook": { "displayName": "Controls", diff --git a/addons/docs/package.json b/addons/docs/package.json index 50ab2d05d887..479971625de0 100644 --- a/addons/docs/package.json +++ b/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", @@ -10,7 +10,7 @@ "essentials", "organize" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/docs", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/docs", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -63,20 +63,20 @@ "@mdx-js/loader": "^1.6.22", "@mdx-js/mdx": "^1.6.22", "@mdx-js/react": "^1.6.22", - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/builder-webpack4": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/client-logger": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/builder-webpack4": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", "@storybook/csf": "0.0.1", - "@storybook/csf-tools": "6.4.0-alpha.9", - "@storybook/node-logger": "6.4.0-alpha.9", - "@storybook/postinstall": "6.4.0-alpha.9", - "@storybook/source-loader": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/csf-tools": "6.4.0-alpha.17", + "@storybook/node-logger": "6.4.0-alpha.17", + "@storybook/postinstall": "6.4.0-alpha.17", + "@storybook/source-loader": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "acorn": "^7.4.1", "acorn-jsx": "^5.3.1", "acorn-walk": "^7.2.0", @@ -89,6 +89,7 @@ "js-string-escape": "^1.0.1", "loader-utils": "^2.0.0", "lodash": "^4.17.20", + "nanoid": "^3.1.23", "p-limit": "^3.1.0", "prettier": "~2.2.1", "prop-types": "^15.7.2", @@ -104,10 +105,10 @@ "@babel/core": "^7.12.10", "@emotion/core": "^10.1.1", "@emotion/styled": "^10.0.27", - "@storybook/angular": "6.4.0-alpha.9", - "@storybook/react": "6.4.0-alpha.9", - "@storybook/vue": "6.4.0-alpha.9", - "@storybook/web-components": "6.4.0-alpha.9", + "@storybook/angular": "6.4.0-alpha.17", + "@storybook/react": "6.4.0-alpha.17", + "@storybook/vue": "6.4.0-alpha.17", + "@storybook/web-components": "6.4.0-alpha.17", "@types/cross-spawn": "^6.0.2", "@types/doctrine": "^0.0.3", "@types/enzyme": "^3.10.8", @@ -137,10 +138,10 @@ "zone.js": "^0.11.3" }, "peerDependencies": { - "@storybook/angular": "6.4.0-alpha.9", - "@storybook/vue": "6.4.0-alpha.9", - "@storybook/vue3": "6.4.0-alpha.9", - "@storybook/web-components": "6.4.0-alpha.9", + "@storybook/angular": "6.4.0-alpha.17", + "@storybook/vue": "6.4.0-alpha.17", + "@storybook/vue3": "6.4.0-alpha.17", + "@storybook/web-components": "6.4.0-alpha.17", "lit": "^2.0.0-rc.1", "lit-html": "^1.4.1 || ^2.0.0-rc.3", "react": "^16.8.0 || ^17.0.0", @@ -191,7 +192,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Docs", diff --git a/addons/docs/src/blocks/DocsContext.ts b/addons/docs/src/blocks/DocsContext.ts index 0556b6304e39..9f66a2588552 100644 --- a/addons/docs/src/blocks/DocsContext.ts +++ b/addons/docs/src/blocks/DocsContext.ts @@ -1,4 +1,5 @@ import { Context, createContext } from 'react'; +import { window as globalWindow } from 'global'; export interface DocsContextProps { id?: string; @@ -17,4 +18,15 @@ export interface DocsContextProps { forceRender?: () => void; } -export const DocsContext: Context = createContext({}); +// We add DocsContext to window. The reason is that in case DocsContext.ts is +// imported multiple times (maybe once directly, and another time from a minified bundle) +// we will have multiple DocsContext definitions - leading to lost context in +// the React component tree. +// This was specifically a problem with the Vite builder. +/* eslint-disable no-underscore-dangle */ +if (globalWindow.__DOCS_CONTEXT__ === undefined) { + globalWindow.__DOCS_CONTEXT__ = createContext({}); + globalWindow.__DOCS_CONTEXT__.displayName = 'DocsContext'; +} + +export const DocsContext: Context = globalWindow.__DOCS_CONTEXT__; diff --git a/addons/docs/src/frameworks/angular/__testfixtures__/doc-button/argtypes.snapshot b/addons/docs/src/frameworks/angular/__testfixtures__/doc-button/argtypes.snapshot index 70866177760b..19fcc9ec96f7 100644 --- a/addons/docs/src/frameworks/angular/__testfixtures__/doc-button/argtypes.snapshot +++ b/addons/docs/src/frameworks/angular/__testfixtures__/doc-button/argtypes.snapshot @@ -14,7 +14,7 @@ Object { }, }, "type": Object { - "name": "void", + "name": "string", }, }, "_value": Object { @@ -30,7 +30,7 @@ Object { }, }, "type": Object { - "name": "void", + "name": "string", }, }, "accent": Object { @@ -129,7 +129,7 @@ Object { }, }, "type": Object { - "name": "void", + "name": "string", }, }, "isDisabled": Object { @@ -225,7 +225,7 @@ Object { }, }, "type": Object { - "name": "void", + "name": "object", }, }, "protectedMethod": Object { diff --git a/addons/docs/src/frameworks/angular/compodoc.ts b/addons/docs/src/frameworks/angular/compodoc.ts index a3418ed4c26d..8d76ee810ba3 100644 --- a/addons/docs/src/frameworks/angular/compodoc.ts +++ b/addons/docs/src/frameworks/angular/compodoc.ts @@ -112,7 +112,9 @@ const displaySignature = (item: Method): string => { const extractTypeFromValue = (defaultValue: any) => { const valueType = typeof defaultValue; - return defaultValue || valueType === 'boolean' || valueType === 'string' ? valueType : null; + return defaultValue || valueType === 'number' || valueType === 'boolean' || valueType === 'string' + ? valueType + : null; }; const extractEnumValues = (compodocType: any) => { @@ -188,7 +190,7 @@ export const extractArgTypesFromData = (componentData: Class | Directive | Injec const section = mapItemToSection(key, item); const defaultValue = isMethod(item) ? undefined : extractDefaultValue(item as Property); const type = - isMethod(item) || section !== 'inputs' + isMethod(item) || (section !== 'inputs' && section !== 'properties') ? { name: 'void' } : extractType(item as Property, defaultValue); const action = section === 'outputs' ? { action: item.name } : {}; @@ -215,9 +217,9 @@ export const extractArgTypesFromData = (componentData: Class | Directive | Injec }); const SECTIONS = [ + 'properties', 'inputs', 'outputs', - 'properties', 'methods', 'view child', 'view children', diff --git a/addons/docs/src/frameworks/angular/prepareForInline.ts b/addons/docs/src/frameworks/angular/prepareForInline.ts index ae9de532bdb2..fc9e4f0ab26c 100644 --- a/addons/docs/src/frameworks/angular/prepareForInline.ts +++ b/addons/docs/src/frameworks/angular/prepareForInline.ts @@ -1,5 +1,6 @@ import React from 'react'; import pLimit from 'p-limit'; +import { nanoid } from 'nanoid'; import { IStory, StoryContext } from '@storybook/angular'; import { rendererFactory } from '@storybook/angular/renderer'; @@ -18,7 +19,7 @@ export const prepareForInline = (storyFn: StoryFn, { id, parameters }: S } return limit(async () => { - const renderer = await rendererFactory.getRendererInstance(id, node); + const renderer = await rendererFactory.getRendererInstance(`${id}-${nanoid(10)}`, node); await renderer.render({ forced: false, parameters, diff --git a/addons/docs/src/frameworks/web-components/config.js b/addons/docs/src/frameworks/web-components/config.js deleted file mode 100644 index b931d4e826d2..000000000000 --- a/addons/docs/src/frameworks/web-components/config.js +++ /dev/null @@ -1,29 +0,0 @@ -/* global window */ -import React from 'react'; -import { render } from 'lit-html'; -import { extractArgTypes, extractComponentDescription } from './custom-elements'; - -export const parameters = { - docs: { - extractArgTypes, - extractComponentDescription, - inlineStories: true, - prepareForInline: (storyFn) => { - class Story extends React.Component { - constructor(props) { - super(props); - this.wrapperRef = React.createRef(); - } - - componentDidMount() { - render(storyFn(), this.wrapperRef.current); - } - - render() { - return React.createElement('div', { ref: this.wrapperRef }); - } - } - return React.createElement(Story); - }, - }, -}; diff --git a/addons/docs/src/frameworks/web-components/config.ts b/addons/docs/src/frameworks/web-components/config.ts new file mode 100644 index 000000000000..30273896e170 --- /dev/null +++ b/addons/docs/src/frameworks/web-components/config.ts @@ -0,0 +1,19 @@ +import { extractArgTypes, extractComponentDescription } from './custom-elements'; +import { sourceDecorator } from './sourceDecorator'; +import { prepareForInline } from './prepareForInline'; +import { SourceType } from '../../shared'; + +export const decorators = [sourceDecorator]; + +export const parameters = { + docs: { + extractArgTypes, + extractComponentDescription, + inlineStories: true, + prepareForInline, + source: { + type: SourceType.DYNAMIC, + language: 'html', + }, + }, +}; diff --git a/addons/docs/src/frameworks/web-components/prepareForInline.ts b/addons/docs/src/frameworks/web-components/prepareForInline.ts new file mode 100644 index 000000000000..715bdb8afef6 --- /dev/null +++ b/addons/docs/src/frameworks/web-components/prepareForInline.ts @@ -0,0 +1,19 @@ +import type { StoryFn } from '@storybook/addons'; +import React from 'react'; +import { render } from 'lit-html'; + +export const prepareForInline = (storyFn: StoryFn) => { + class Story extends React.Component { + wrapperRef = React.createRef(); + + componentDidMount(): void { + render(storyFn(), this.wrapperRef.current); + } + + render(): React.ReactElement { + return React.createElement('div', { ref: this.wrapperRef }); + } + } + + return (React.createElement(Story) as unknown) as React.CElement<{}, React.Component>; +}; diff --git a/addons/docs/src/frameworks/web-components/sourceDecorator.test.ts b/addons/docs/src/frameworks/web-components/sourceDecorator.test.ts new file mode 100644 index 000000000000..4c2c49851045 --- /dev/null +++ b/addons/docs/src/frameworks/web-components/sourceDecorator.test.ts @@ -0,0 +1,100 @@ +import { html } from 'lit-html'; +import { styleMap } from 'lit-html/directives/style-map'; +import { addons, StoryContext } from '@storybook/addons'; +import { sourceDecorator } from './sourceDecorator'; +import { SNIPPET_RENDERED } from '../../shared'; + +jest.mock('@storybook/addons'); +const mockedAddons = addons as jest.Mocked; + +expect.addSnapshotSerializer({ + print: (val: any) => val, + test: (val) => typeof val === 'string', +}); + +const makeContext = (name: string, parameters: any, args: any, extra?: object): StoryContext => ({ + id: `lit-test--${name}`, + kind: 'js-text', + name, + parameters, + args, + argTypes: {}, + globals: {}, + ...extra, +}); + +describe('sourceDecorator', () => { + let mockChannel: { on: jest.Mock; emit?: jest.Mock }; + beforeEach(() => { + mockedAddons.getChannel.mockReset(); + + mockChannel = { on: jest.fn(), emit: jest.fn() }; + mockedAddons.getChannel.mockReturnValue(mockChannel as any); + }); + + it('should render dynamically for args stories', () => { + const storyFn = (args: any) => html`
args story
`; + const context = makeContext('args', { __isArgsStory: true }, {}); + sourceDecorator(storyFn, context); + expect(mockChannel.emit).toHaveBeenCalledWith( + SNIPPET_RENDERED, + 'lit-test--args', + '
args story
' + ); + }); + + it('should skip dynamic rendering for no-args stories', () => { + const storyFn = () => html`
classic story
`; + const context = makeContext('classic', {}, {}); + sourceDecorator(storyFn, context); + expect(mockChannel.emit).not.toHaveBeenCalled(); + }); + + it('should use the originalStoryFn if excludeDecorators is set', () => { + const storyFn = (args: any) => html`
args story
`; + const decoratedStoryFn = (args: any) => html` +
${storyFn(args)}
+ `; + const context = makeContext( + 'args', + { + __isArgsStory: true, + docs: { + source: { + excludeDecorators: true, + }, + }, + }, + {}, + { originalStoryFn: storyFn } + ); + sourceDecorator(decoratedStoryFn, context); + expect(mockChannel.emit).toHaveBeenCalledWith( + SNIPPET_RENDERED, + 'lit-test--args', + '
args story
' + ); + }); + + it('allows the snippet output to be modified by transformSource', () => { + const storyFn = (args: any) => html`
args story
`; + const transformSource = (dom: string) => `

${dom}

`; + const docs = { transformSource }; + const context = makeContext('args', { __isArgsStory: true, docs }, {}); + sourceDecorator(storyFn, context); + expect(mockChannel.emit).toHaveBeenCalledWith( + SNIPPET_RENDERED, + 'lit-test--args', + '

args story

' + ); + }); + + it('provides the story context to transformSource', () => { + const storyFn = (args: any) => html`
args story
`; + const transformSource = jest.fn((x) => x); + const docs = { transformSource }; + const context = makeContext('args', { __isArgsStory: true, docs }, {}); + sourceDecorator(storyFn, context); + expect(transformSource).toHaveBeenCalledWith('
args story
', context); + }); +}); diff --git a/addons/docs/src/frameworks/web-components/sourceDecorator.ts b/addons/docs/src/frameworks/web-components/sourceDecorator.ts new file mode 100644 index 000000000000..d1ab37f8ec2e --- /dev/null +++ b/addons/docs/src/frameworks/web-components/sourceDecorator.ts @@ -0,0 +1,39 @@ +/* global window */ +import { render } from 'lit-html'; +import { addons, StoryContext, StoryFn } from '@storybook/addons'; +import { SNIPPET_RENDERED, SourceType } from '../../shared'; + +function skipSourceRender(context: StoryContext) { + const sourceParams = context?.parameters.docs?.source; + const isArgsStory = context?.parameters.__isArgsStory; + + // always render if the user forces it + if (sourceParams?.type === SourceType.DYNAMIC) { + return false; + } + + // never render if the user is forcing the block to render code, or + // if the user provides code, or if it's not an args story. + return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE; +} + +function applyTransformSource(source: string, context: StoryContext): string { + const { transformSource } = context.parameters.docs ?? {}; + if (typeof transformSource !== 'function') return source; + return transformSource(source, context); +} + +export function sourceDecorator(storyFn: StoryFn, context: StoryContext) { + const story = context?.parameters.docs?.source?.excludeDecorators + ? context.originalStoryFn(context.args) + : storyFn(); + + if (!skipSourceRender(context)) { + const container = window.document.createElement('div'); + render(story, container); + const source = applyTransformSource(container.innerHTML.replace(//g, ''), context); + if (source) addons.getChannel().emit(SNIPPET_RENDERED, context.id, source); + } + + return story; +} diff --git a/addons/essentials/package.json b/addons/essentials/package.json index 1b4e84329f91..98d2aa8c43a9 100644 --- a/addons/essentials/package.json +++ b/addons/essentials/package.json @@ -1,13 +1,13 @@ { "name": "@storybook/addon-essentials", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", "essentials", "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/essentials", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/essentials", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -39,31 +39,31 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addon-actions": "6.4.0-alpha.9", - "@storybook/addon-backgrounds": "6.4.0-alpha.9", - "@storybook/addon-controls": "6.4.0-alpha.9", - "@storybook/addon-docs": "6.4.0-alpha.9", - "@storybook/addon-measure": "^2.0.0", - "@storybook/addon-toolbars": "6.4.0-alpha.9", - "@storybook/addon-viewport": "6.4.0-alpha.9", - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/node-logger": "6.4.0-alpha.9", + "@storybook/addon-actions": "6.4.0-alpha.17", + "@storybook/addon-backgrounds": "6.4.0-alpha.17", + "@storybook/addon-controls": "6.4.0-alpha.17", + "@storybook/addon-docs": "6.4.0-alpha.17", + "@storybook/addon-measure": "6.4.0-alpha.17", + "@storybook/addon-outline": "6.4.0-alpha.17", + "@storybook/addon-toolbars": "6.4.0-alpha.17", + "@storybook/addon-viewport": "6.4.0-alpha.17", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/node-logger": "6.4.0-alpha.17", "core-js": "^3.8.2", "regenerator-runtime": "^0.13.7", - "storybook-addon-outline": "^1.4.1", "ts-dedent": "^2.0.0" }, "devDependencies": { "@babel/core": "^7.12.10", - "@storybook/vue": "6.4.0-alpha.9", + "@storybook/vue": "6.4.0-alpha.17", "@types/jest": "^26.0.16", "@types/webpack-env": "^1.16.0" }, "peerDependencies": { "@babel/core": "^7.9.6", - "@storybook/vue": "6.4.0-alpha.9", - "@storybook/web-components": "6.4.0-alpha.9", + "@storybook/vue": "6.4.0-alpha.17", + "@storybook/web-components": "6.4.0-alpha.17", "babel-loader": "^8.0.0", "lit-html": "^1.4.1 || ^2.0.0-rc.3", "react": "^16.8.0 || ^17.0.0", @@ -93,6 +93,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js" } diff --git a/addons/essentials/src/index.ts b/addons/essentials/src/index.ts index b281ec05be15..7cf3bc35170b 100644 --- a/addons/essentials/src/index.ts +++ b/addons/essentials/src/index.ts @@ -39,7 +39,7 @@ export function addons(options: PresetOptions = {}) { return ( ['docs', 'controls', 'actions', 'backgrounds', 'viewport', 'toolbars', 'measure', 'outline'] .filter((key) => (options as any)[key] !== false) - .map((key) => (key === 'outline' ? `storybook-addon-${key}` : `@storybook/addon-${key}`)) + .map((key) => `@storybook/addon-${key}`) .filter((addon) => !checkInstalled(addon, main)) // Use `require.resolve` to ensure Yarn PnP compatibility // Files of various addons should be resolved in the context of `addon-essentials` as they are listed as deps here diff --git a/addons/jest/package.json b/addons/jest/package.json index 112fa987f3c2..b05e72dbedcc 100644 --- a/addons/jest/package.json +++ b/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "React storybook addon that show component jest report", "keywords": [ "addon", @@ -12,7 +12,7 @@ "unit-testing", "test" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/jest", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/jest", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -47,11 +47,11 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "global": "^4.4.0", "react-sizeme": "^3.0.1", @@ -76,7 +76,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Jest", diff --git a/addons/links/README.md b/addons/links/README.md index 1f4b5346e446..c512695b275d 100644 --- a/addons/links/README.md +++ b/addons/links/README.md @@ -143,4 +143,4 @@ It accepts all the props the `a` element does, plus `story` and `kind`. It the ` ``` -To implement such a component for another framework, you need to add special handling for `click` event on native `a` element. See [`RoutedLink` sources](https://github.com/storybookjs/storybook/blob/main/addons/links/src/react/components/RoutedLink.js#L20-L24) for reference. +To implement such a component for another framework, you need to add special handling for `click` event on native `a` element. See [`RoutedLink` sources](https://github.com/storybookjs/storybook/blob/main/addons/links/src/react/components/RoutedLink.tsx) for reference. diff --git a/addons/links/package.json b/addons/links/package.json index bcf71c9e0462..149ebd0a5dde 100644 --- a/addons/links/package.json +++ b/addons/links/package.json @@ -1,13 +1,13 @@ { "name": "@storybook/addon-links", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", "storybook", "organize" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/links", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/links", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -41,11 +41,11 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/client-logger": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", "@storybook/csf": "0.0.1", - "@storybook/router": "6.4.0-alpha.9", + "@storybook/router": "6.4.0-alpha.17", "@types/qs": "^6.9.5", "core-js": "^3.8.2", "global": "^4.4.0", @@ -72,7 +72,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Links", diff --git a/addons/links/src/react/components/RoutedLink.tsx b/addons/links/src/react/components/RoutedLink.tsx index 2c5ede5f1d33..7fbf75157ba4 100644 --- a/addons/links/src/react/components/RoutedLink.tsx +++ b/addons/links/src/react/components/RoutedLink.tsx @@ -1,6 +1,6 @@ import React from 'react'; -// NOTE: this is a copy of `lib/components/src/navigation/RoutedLink.js`. +// NOTE: this is a copy of `lib/components/src/navigation/RoutedLink.tsx`. // It's duplicated here because that copy has an explicit dependency on // React 16.3+, which breaks older versions of React running in the preview. // The proper DRY solution is to create a new package that doesn't depend diff --git a/addons/measure/README.md b/addons/measure/README.md new file mode 100644 index 000000000000..99638a461da3 --- /dev/null +++ b/addons/measure/README.md @@ -0,0 +1,33 @@ +# Storybook Addon Measure + +Storybook addon for inspecting layouts and visualizing the box model. + +1. Press the m key to enable the addon: + +2. Hover over a DOM node + +3. Storybook will display the dimensions of the selected element—margin, padding, border, width and height—in pixels. + +![](https://user-images.githubusercontent.com/42671/119589961-dff9b380-bda1-11eb-9550-7ae28bc70bf4.gif) + +## Usage + +This addon requires Storybook 6.3 or later. Measure is part of [essentials](https://storybook.js.org/docs/react/essentials/introduction) and so is installed in all new Storybooks by default. If you need to add it to your Storybook, you can run: + +```sh +npm i -D @storybook/addon-measure +``` + +Add `"@storybook/addon-measure"` to the addons array in your `.storybook/main.js`: + +```js +module.exports = { + addons: ['@storybook/addon-measure'], +}; +``` + +### Inspiration + +- [Inspx](https://github.com/raunofreiberg/inspx) by Rauno Freiberg +- [Aaron Westbrook's script](https://gist.github.com/awestbro/e668c12662ad354f02a413205b65fce7) +- [Visbug](https://visbug.web.app/) from the Chrome team diff --git a/addons/measure/package.json b/addons/measure/package.json new file mode 100644 index 000000000000..5dc89df8958f --- /dev/null +++ b/addons/measure/package.json @@ -0,0 +1,82 @@ +{ + "name": "@storybook/addon-measure", + "version": "6.4.0-alpha.17", + "description": "Inspect layouts by visualizing the box model", + "keywords": [ + "storybook-addons", + "essentials", + "style", + "CSS", + "design" + ], + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/measure", + "bugs": { + "url": "https://github.com/storybookjs/storybook/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/storybookjs/storybook.git", + "directory": "addons/measure" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "license": "MIT", + "author": "winkerVSbecks", + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "types": "dist/ts3.9/index.d.ts", + "typesVersions": { + "<3.8": { + "*": [ + "dist/ts3.4/*" + ] + } + }, + "files": [ + "dist/**/*", + "README.md", + "*.js", + "*.d.ts" + ], + "scripts": { + "prepare": "node ../../scripts/prepare.js" + }, + "dependencies": { + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "core-js": "^3.8.2", + "global": "^4.4.0" + }, + "devDependencies": { + "@types/webpack-env": "^1.16.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + }, + "publishConfig": { + "access": "public" + }, + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", + "sbmodern": "dist/modern/index.js", + "storybook": { + "displayName": "Measure", + "unsupportedFrameworks": [ + "react-native" + ], + "icon": "https://user-images.githubusercontent.com/42671/119589951-dbcd9600-bda1-11eb-9227-078f3cfc1e74.png" + } +} diff --git a/addons/measure/preset.js b/addons/measure/preset.js new file mode 100644 index 000000000000..459bbb650ccd --- /dev/null +++ b/addons/measure/preset.js @@ -0,0 +1,12 @@ +function config(entry = []) { + return [...entry, require.resolve('./dist/esm/preset/addDecorator')]; +} + +function managerEntries(entry = [], options) { + return [...entry, require.resolve('./dist/esm/register')]; +} + +module.exports = { + managerEntries, + config, +}; diff --git a/addons/measure/register.js b/addons/measure/register.js new file mode 100644 index 000000000000..f209c0eb3703 --- /dev/null +++ b/addons/measure/register.js @@ -0,0 +1 @@ +require('./dist/esm/register'); diff --git a/addons/measure/src/Tool.tsx b/addons/measure/src/Tool.tsx new file mode 100644 index 000000000000..86edabf47e46 --- /dev/null +++ b/addons/measure/src/Tool.tsx @@ -0,0 +1,39 @@ +import React, { useCallback, useEffect } from 'react'; +import { useGlobals, useStorybookApi } from '@storybook/api'; +import { Icons, IconButton } from '@storybook/components'; +import { TOOL_ID, ADDON_ID } from './constants'; + +export const Tool = () => { + const [globals, updateGlobals] = useGlobals(); + const { measureEnabled } = globals; + const api = useStorybookApi(); + + const toggleMeasure = useCallback( + () => + updateGlobals({ + measureEnabled: !measureEnabled, + }), + [updateGlobals, measureEnabled] + ); + + useEffect(() => { + api.setAddonShortcut(ADDON_ID, { + label: 'Toggle Measure [M]', + defaultShortcut: ['M'], + actionName: 'measure', + showInMenu: false, + action: toggleMeasure, + }); + }, [toggleMeasure, api]); + + return ( + + + + ); +}; diff --git a/addons/measure/src/box-model/canvas.ts b/addons/measure/src/box-model/canvas.ts new file mode 100644 index 000000000000..08387ec05a64 --- /dev/null +++ b/addons/measure/src/box-model/canvas.ts @@ -0,0 +1,97 @@ +/* eslint-disable no-param-reassign */ +import global from 'global'; + +interface Size { + width: number; + height: number; +} + +interface CanvasState { + canvas?: HTMLCanvasElement; + context?: CanvasRenderingContext2D; + width?: number; + height?: number; +} + +function getDocumentWidthAndHeight() { + const container = global.document.documentElement; + + const height = Math.max(container.scrollHeight, container.offsetHeight); + const width = Math.max(container.scrollWidth, container.offsetWidth); + return { width, height }; +} + +function createCanvas(): CanvasState { + const canvas = global.document.createElement('canvas'); + canvas.id = 'storybook-addon-measure'; + const context = canvas.getContext('2d'); + // Set canvas width & height + const { width, height } = getDocumentWidthAndHeight(); + setCanvasWidthAndHeight(canvas, context, { width, height }); + // Position canvas + canvas.style.position = 'absolute'; + canvas.style.left = '0'; + canvas.style.top = '0'; + canvas.style.zIndex = '100000'; + // Disable any user interactions + canvas.style.pointerEvents = 'none'; + global.document.body.appendChild(canvas); + + return { canvas, context, width, height }; +} + +function setCanvasWidthAndHeight( + canvas: HTMLCanvasElement, + context: CanvasRenderingContext2D, + { width, height }: Size +) { + canvas.style.width = `${width}px`; + canvas.style.height = `${height}px`; + + // Scale + const scale = global.window.devicePixelRatio; + canvas.width = Math.floor(width * scale); + canvas.height = Math.floor(height * scale); + + // Normalize coordinate system to use css pixels. + context.scale(scale, scale); +} + +let state: CanvasState = {}; + +export function init() { + if (!state.canvas) { + state = createCanvas(); + } +} + +export function clear() { + if (state.context) { + state.context.clearRect(0, 0, state.width, state.height); + } +} + +export function draw(callback: (context: CanvasRenderingContext2D) => void) { + clear(); + callback(state.context); +} + +export function rescale() { + // First reset so that the canvas size doesn't impact the container size + setCanvasWidthAndHeight(state.canvas, state.context, { width: 0, height: 0 }); + + const { width, height } = getDocumentWidthAndHeight(); + setCanvasWidthAndHeight(state.canvas, state.context, { width, height }); + + // update state + state.width = width; + state.height = height; +} + +export function destroy() { + if (state.canvas) { + clear(); + state.canvas.parentNode.removeChild(state.canvas); + state = {}; + } +} diff --git a/addons/measure/src/box-model/labels.ts b/addons/measure/src/box-model/labels.ts new file mode 100644 index 000000000000..80bbf440c92e --- /dev/null +++ b/addons/measure/src/box-model/labels.ts @@ -0,0 +1,308 @@ +/* eslint-disable operator-assignment */ +/* eslint-disable no-param-reassign */ +type LabelType = 'margin' | 'padding' | 'border' | 'content'; +type LabelPosition = 'top' | 'right' | 'bottom' | 'left' | 'center'; +type Direction = 'top' | 'right' | 'bottom' | 'left'; + +export interface Label { + type: LabelType; + text: number | string; + position: LabelPosition; +} + +export type LabelStack = Label[]; + +interface RectSize { + w: number; + h: number; +} + +interface Coordinate { + x: number; + y: number; +} + +interface Rect extends RectSize, Coordinate {} + +interface RoundedRect extends Rect { + r: number; +} + +const colors = { + margin: '#f6b26b', + border: '#ffe599', + padding: '#93c47d', + content: '#6fa8dc', + text: '#232020', +}; + +const labelPadding = 6; + +function roundedRect(context: CanvasRenderingContext2D, { x, y, w, h, r }: RoundedRect) { + x = x - w / 2; + y = y - h / 2; + + if (w < 2 * r) r = w / 2; + if (h < 2 * r) r = h / 2; + + context.beginPath(); + context.moveTo(x + r, y); + context.arcTo(x + w, y, x + w, y + h, r); + context.arcTo(x + w, y + h, x, y + h, r); + context.arcTo(x, y + h, x, y, r); + context.arcTo(x, y, x + w, y, r); + context.closePath(); +} + +function positionCoordinate( + position: LabelPosition, + { padding, border, width, height, top, left }: ElementMeasurements +): Coordinate { + const contentWidth = width - border.left - border.right - padding.left - padding.right; + const contentHeight = height - padding.top - padding.bottom - border.top - border.bottom; + + let x = left + border.left + padding.left; + let y = top + border.top + padding.top; + + if (position === 'top') { + x += contentWidth / 2; + } else if (position === 'right') { + x += contentWidth; + y += contentHeight / 2; + } else if (position === 'bottom') { + x += contentWidth / 2; + y += contentHeight; + } else if (position === 'left') { + y += contentHeight / 2; + } else if (position === 'center') { + x += contentWidth / 2; + y += contentHeight / 2; + } + + return { x, y }; +} + +/** + * Offset the label based on how many layers appear before it + * For example: + * margin labels will shift further outwards if there are + * padding labels + */ +function offset( + type: LabelType, + position: LabelPosition, + { margin, border, padding }: ElementMeasurements, + labelPaddingSize: number, + external: boolean +) { + let shift = (dir: Direction) => 0; + let offsetX = 0; + let offsetY = 0; + + // If external labels then push them to the edge of the band + // else keep them centred + const locationMultiplier = external ? 1 : 0.5; + // Account for padding within the label + const labelPaddingShift = external ? labelPaddingSize * 2 : 0; + + if (type === 'padding') { + shift = (dir: Direction) => padding[dir] * locationMultiplier + labelPaddingShift; + } else if (type === 'border') { + shift = (dir: Direction) => padding[dir] + border[dir] * locationMultiplier + labelPaddingShift; + } else if (type === 'margin') { + shift = (dir: Direction) => + padding[dir] + border[dir] + margin[dir] * locationMultiplier + labelPaddingShift; + } + + if (position === 'top') { + offsetY = -shift('top'); + } else if (position === 'right') { + offsetX = shift('right'); + } else if (position === 'bottom') { + offsetY = shift('bottom'); + } else if (position === 'left') { + offsetX = -shift('left'); + } + + return { offsetX, offsetY }; +} + +function collide(a: Rect, b: Rect) { + return ( + Math.abs(a.x - b.x) < Math.abs(a.w + b.w) / 2 && Math.abs(a.y - b.y) < Math.abs(a.h + b.h) / 2 + ); +} + +function overlapAdjustment(position: LabelPosition, currentRect: Rect, prevRect: Rect) { + if (position === 'top') { + currentRect.y = prevRect.y - prevRect.h - labelPadding; + } else if (position === 'right') { + currentRect.x = prevRect.x + prevRect.w / 2 + labelPadding + currentRect.w / 2; + } else if (position === 'bottom') { + currentRect.y = prevRect.y + prevRect.h + labelPadding; + } else if (position === 'left') { + currentRect.x = prevRect.x - prevRect.w / 2 - labelPadding - currentRect.w / 2; + } + + return { x: currentRect.x, y: currentRect.y }; +} + +function textWithRect( + context: CanvasRenderingContext2D, + type: LabelType, + { x, y, w, h }: Rect, + text: number | string +) { + roundedRect(context, { x, y, w, h, r: 3 }); + context.fillStyle = `${colors[type]}dd`; + context.fill(); + context.strokeStyle = colors[type]; + context.stroke(); + + context.fillStyle = colors.text; + context.fillText(text as string, x, y); + + roundedRect(context, { x, y, w, h, r: 3 }); + context.fillStyle = `${colors[type]}dd`; + context.fill(); + context.strokeStyle = colors[type]; + context.stroke(); + + context.fillStyle = colors.text; + context.fillText(text as string, x, y); + + return { x, y, w, h }; +} + +function configureText(context: CanvasRenderingContext2D, text: number | string): RectSize { + context.font = '600 12px monospace'; + context.textBaseline = 'middle'; + context.textAlign = 'center'; + + const metrics = context.measureText(text as string); + const actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent; + + const w = metrics.width + labelPadding * 2; + const h = actualHeight + labelPadding * 2; + + return { w, h }; +} + +function drawLabel( + context: CanvasRenderingContext2D, + measurements: ElementMeasurements, + { type, position = 'center', text }: Label, + prevRect: Rect, + external = false +) { + let { x, y } = positionCoordinate(position, measurements); + const { offsetX, offsetY } = offset(type, position, measurements, labelPadding + 1, external); + + // Shift coordinate to center within + // the band of measurement + x += offsetX; + y += offsetY; + + const { w, h } = configureText(context, text); + + // Adjust for overlap + if (prevRect && collide({ x, y, w, h }, prevRect)) { + const adjusted = overlapAdjustment(position, { x, y, w, h }, prevRect); + x = adjusted.x; + y = adjusted.y; + } + + return textWithRect(context, type, { x, y, w, h }, text); +} + +function floatingOffset(alignment: FloatingAlignment, { w, h }: RectSize) { + const deltaW = w * 0.5 + labelPadding; + const deltaH = h * 0.5 + labelPadding; + + return { + offsetX: (alignment.x === 'left' ? -1 : 1) * deltaW, + offsetY: (alignment.y === 'top' ? -1 : 1) * deltaH, + }; +} + +export function drawFloatingLabel( + context: CanvasRenderingContext2D, + measurements: ElementMeasurements, + { type, text }: Label +) { + const { floatingAlignment, extremities } = measurements; + + let x = extremities[floatingAlignment.x]; + let y = extremities[floatingAlignment.y]; + + const { w, h } = configureText(context, text); + + const { offsetX, offsetY } = floatingOffset(floatingAlignment, { + w, + h, + }); + + x += offsetX; + y += offsetY; + + return textWithRect(context, type, { x, y, w, h }, text); +} + +function drawStack( + context: CanvasRenderingContext2D, + measurements: ElementMeasurements, + stack: LabelStack, + external: boolean +) { + const rects: Rect[] = []; + + stack.forEach((l, idx) => { + // Move the centred label to floating in external mode + const rect = + external && l.position === 'center' + ? drawFloatingLabel(context, measurements, l) + : drawLabel(context, measurements, l, rects[idx - 1], external); + rects[idx] = rect; + }); +} + +interface GroupedLabelStacks { + top?: LabelStack; + right?: LabelStack; + bottom?: LabelStack; + left?: LabelStack; + center?: LabelStack; +} + +export function labelStacks( + context: CanvasRenderingContext2D, + measurements: ElementMeasurements, + labels: LabelStack, + externalLabels: boolean +) { + const stacks = labels.reduce((acc, l) => { + if (!Object.prototype.hasOwnProperty.call(acc, l.position)) { + acc[l.position] = []; + } + + acc[l.position].push(l); + + return acc; + }, {}); + + if (stacks.top) { + drawStack(context, measurements, stacks.top, externalLabels); + } + if (stacks.right) { + drawStack(context, measurements, stacks.right, externalLabels); + } + if (stacks.bottom) { + drawStack(context, measurements, stacks.bottom, externalLabels); + } + if (stacks.left) { + drawStack(context, measurements, stacks.left, externalLabels); + } + if (stacks.center) { + drawStack(context, measurements, stacks.center, externalLabels); + } +} diff --git a/addons/measure/src/box-model/visualizer.ts b/addons/measure/src/box-model/visualizer.ts new file mode 100644 index 000000000000..97ac7791bb73 --- /dev/null +++ b/addons/measure/src/box-model/visualizer.ts @@ -0,0 +1,308 @@ +/* eslint-disable operator-assignment */ +/** + * Based on https://gist.github.com/awestbro/e668c12662ad354f02a413205b65fce7 + */ +import global from 'global'; +import { draw } from './canvas'; +import { labelStacks, Label, LabelStack } from './labels'; + +const colors = { + margin: '#f6b26ba8', + border: '#ffe599a8', + padding: '#93c47d8c', + content: '#6fa8dca8', +}; + +const SMALL_NODE_SIZE = 30; + +function pxToNumber(px: string): number { + return parseInt(px.replace('px', ''), 10); +} + +function round(value: number): number | string { + return Number.isInteger(value) ? value : value.toFixed(2); +} + +function filterZeroValues(labels: LabelStack): LabelStack { + return labels.filter((l) => l.text !== 0 && l.text !== '0'); +} + +function floatingAlignment(extremities: Extremities): FloatingAlignment { + const windowExtremities = { + top: global.window.scrollY, + bottom: global.window.scrollY + global.window.innerHeight, + left: global.window.scrollX, + right: global.window.scrollX + global.window.innerWidth, + }; + + const distances = { + top: Math.abs(windowExtremities.top - extremities.top), + bottom: Math.abs(windowExtremities.bottom - extremities.bottom), + left: Math.abs(windowExtremities.left - extremities.left), + right: Math.abs(windowExtremities.right - extremities.right), + }; + + return { + x: distances.left > distances.right ? 'left' : 'right', + y: distances.top > distances.bottom ? 'top' : 'bottom', + }; +} + +function measureElement(element: HTMLElement): ElementMeasurements { + const style = global.getComputedStyle(element); + // eslint-disable-next-line prefer-const + let { top, left, right, bottom, width, height } = element.getBoundingClientRect(); + + const { + marginTop, + marginBottom, + marginLeft, + marginRight, + paddingTop, + paddingBottom, + paddingLeft, + paddingRight, + borderBottomWidth, + borderTopWidth, + borderLeftWidth, + borderRightWidth, + } = style; + + top = top + global.window.scrollY; + left = left + global.window.scrollX; + bottom = bottom + global.window.scrollY; + right = right + global.window.scrollX; + + const margin = { + top: pxToNumber(marginTop), + bottom: pxToNumber(marginBottom), + left: pxToNumber(marginLeft), + right: pxToNumber(marginRight), + }; + + const padding = { + top: pxToNumber(paddingTop), + bottom: pxToNumber(paddingBottom), + left: pxToNumber(paddingLeft), + right: pxToNumber(paddingRight), + }; + + const border = { + top: pxToNumber(borderTopWidth), + bottom: pxToNumber(borderBottomWidth), + left: pxToNumber(borderLeftWidth), + right: pxToNumber(borderRightWidth), + }; + + const extremities = { + top: top - margin.top, + bottom: bottom + margin.bottom, + left: left - margin.left, + right: right + margin.right, + }; + + return { + margin, + padding, + border, + top, + left, + bottom, + right, + width, + height, + extremities, + floatingAlignment: floatingAlignment(extremities), + }; +} + +function drawMargin( + context: CanvasRenderingContext2D, + { margin, width, height, top, left, bottom, right }: Dimensions +): LabelStack { + // Draw Margin + const marginHeight = height + margin.bottom + margin.top; + + context.fillStyle = colors.margin; + // Top margin rect + context.fillRect(left, top - margin.top, width, margin.top); + // Right margin rect + context.fillRect(right, top - margin.top, margin.right, marginHeight); + // Bottom margin rect + context.fillRect(left, bottom, width, margin.bottom); + // Left margin rect + context.fillRect(left - margin.left, top - margin.top, margin.left, marginHeight); + + const marginLabels: LabelStack = [ + { + type: 'margin', + text: round(margin.top), + position: 'top', + }, + { + type: 'margin', + text: round(margin.right), + position: 'right', + }, + { + type: 'margin', + text: round(margin.bottom), + position: 'bottom', + }, + { + type: 'margin', + text: round(margin.left), + position: 'left', + }, + ]; + + return filterZeroValues(marginLabels); +} + +function drawPadding( + context: CanvasRenderingContext2D, + { padding, border, width, height, top, left, bottom, right }: Dimensions +): LabelStack { + const paddingWidth = width - border.left - border.right; + const paddingHeight = height - padding.top - padding.bottom - border.top - border.bottom; + + context.fillStyle = colors.padding; + // Top padding rect + context.fillRect(left + border.left, top + border.top, paddingWidth, padding.top); + // Right padding rect + context.fillRect( + right - padding.right - border.right, + top + padding.top + border.top, + padding.right, + paddingHeight + ); + // Bottom padding rect + context.fillRect( + left + border.left, + bottom - padding.bottom - border.bottom, + paddingWidth, + padding.bottom + ); + // Left padding rect + context.fillRect(left + border.left, top + padding.top + border.top, padding.left, paddingHeight); + + const paddingLabels: LabelStack = [ + { + type: 'padding', + text: padding.top, + position: 'top', + }, + { + type: 'padding', + text: padding.right, + position: 'right', + }, + { + type: 'padding', + text: padding.bottom, + position: 'bottom', + }, + { + type: 'padding', + text: padding.left, + position: 'left', + }, + ]; + + return filterZeroValues(paddingLabels); +} + +function drawBorder( + context: CanvasRenderingContext2D, + { border, width, height, top, left, bottom, right }: Dimensions +): Label[] { + const borderHeight = height - border.top - border.bottom; + + context.fillStyle = colors.border; + // Top border rect + context.fillRect(left, top, width, border.top); + // Bottom border rect + context.fillRect(left, bottom - border.bottom, width, border.bottom); + // Left border rect + context.fillRect(left, top + border.top, border.left, borderHeight); + // Right border rect + context.fillRect(right - border.right, top + border.top, border.right, borderHeight); + + const borderLabels: LabelStack = [ + { + type: 'border', + text: border.top, + position: 'top', + }, + { + type: 'border', + text: border.right, + position: 'right', + }, + { + type: 'border', + text: border.bottom, + position: 'bottom', + }, + { + type: 'border', + text: border.left, + position: 'left', + }, + ]; + + return filterZeroValues(borderLabels); +} + +function drawContent( + context: CanvasRenderingContext2D, + { padding, border, width, height, top, left }: Dimensions +): LabelStack { + const contentWidth = width - border.left - border.right - padding.left - padding.right; + const contentHeight = height - padding.top - padding.bottom - border.top - border.bottom; + + context.fillStyle = colors.content; + // content rect + context.fillRect( + left + border.left + padding.left, + top + border.top + padding.top, + contentWidth, + contentHeight + ); + + // Dimension label + return [ + { + type: 'content', + position: 'center', + text: `${round(contentWidth)} x ${round(contentHeight)}`, + }, + ]; +} + +function drawBoxModel(element: HTMLElement) { + return (context: CanvasRenderingContext2D) => { + if (element && context) { + const measurements = measureElement(element); + + const marginLabels = drawMargin(context, measurements); + const paddingLabels = drawPadding(context, measurements); + const borderLabels = drawBorder(context, measurements); + const contentLabels = drawContent(context, measurements); + + const externalLabels = + measurements.width <= SMALL_NODE_SIZE * 3 || measurements.height <= SMALL_NODE_SIZE; + + labelStacks( + context, + measurements, + [...contentLabels, ...paddingLabels, ...borderLabels, ...marginLabels], + externalLabels + ); + } + }; +} + +export function drawSelectedElement(element: HTMLElement) { + draw(drawBoxModel(element)); +} diff --git a/addons/measure/src/constants.ts b/addons/measure/src/constants.ts new file mode 100644 index 000000000000..3375eac3e939 --- /dev/null +++ b/addons/measure/src/constants.ts @@ -0,0 +1,9 @@ +export const ADDON_ID = 'storybook/measure-addon'; +export const TOOL_ID = `${ADDON_ID}/tool`; +export const PARAM_KEY = 'measureEnabled'; + +export const EVENTS = { + RESULT: `${ADDON_ID}/result`, + REQUEST: `${ADDON_ID}/request`, + CLEAR: `${ADDON_ID}/clear`, +}; diff --git a/addons/measure/src/index.ts b/addons/measure/src/index.ts new file mode 100644 index 000000000000..644402abb41c --- /dev/null +++ b/addons/measure/src/index.ts @@ -0,0 +1,6 @@ +if (module && module.hot && module.hot.decline) { + module.hot.decline(); +} + +// make it work with --isolatedModules +export default {}; diff --git a/addons/measure/src/preset/addDecorator.tsx b/addons/measure/src/preset/addDecorator.tsx new file mode 100644 index 000000000000..8aabbd42a2da --- /dev/null +++ b/addons/measure/src/preset/addDecorator.tsx @@ -0,0 +1,8 @@ +import { withMeasure } from '../withMeasure'; +import { PARAM_KEY } from '../constants'; + +export const decorators = [withMeasure]; + +export const globals = { + [PARAM_KEY]: false, +}; diff --git a/addons/measure/src/register.tsx b/addons/measure/src/register.tsx new file mode 100644 index 000000000000..162e7ce43ecd --- /dev/null +++ b/addons/measure/src/register.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { addons, types } from '@storybook/addons'; + +import { ADDON_ID, TOOL_ID } from './constants'; +import { Tool } from './Tool'; + +addons.register(ADDON_ID, () => { + addons.add(TOOL_ID, { + type: types.TOOL, + title: 'Measure', + match: ({ viewMode }) => viewMode === 'story', + render: () => , + }); +}); diff --git a/addons/measure/src/typings.d.ts b/addons/measure/src/typings.d.ts new file mode 100644 index 000000000000..4a8ad58bf897 --- /dev/null +++ b/addons/measure/src/typings.d.ts @@ -0,0 +1,51 @@ +declare module 'global'; + +interface Margin { + top: number; + bottom: number; + left: number; + right: number; +} + +interface Padding { + top: number; + bottom: number; + left: number; + right: number; +} + +interface Border { + top: number; + bottom: number; + left: number; + right: number; +} + +interface Dimensions { + margin: Margin; + padding: Padding; + border: Border; + width: number; + height: number; + top: number; + left: number; + bottom: number; + right: number; +} + +interface Extremities { + top: number; + bottom: number; + left: number; + right: number; +} + +interface FloatingAlignment { + x: 'left' | 'right'; + y: 'top' | 'bottom'; +} + +interface ElementMeasurements extends Dimensions { + extremities: Extremities; + floatingAlignment: FloatingAlignment; +} diff --git a/addons/measure/src/util.ts b/addons/measure/src/util.ts new file mode 100644 index 000000000000..afb07d91299d --- /dev/null +++ b/addons/measure/src/util.ts @@ -0,0 +1,28 @@ +import global from 'global'; + +export const deepElementFromPoint = (x: number, y: number) => { + const element = global.document.elementFromPoint(x, y); + + const crawlShadows = (node: Element): Element => { + if (node && node.shadowRoot) { + const nestedElement = node.shadowRoot.elementFromPoint(x, y); + + // Nested node is same as the root one + if (node.isEqualNode(nestedElement)) { + return node; + } + // The nested node has shadow DOM too so continue crawling + if (nestedElement.shadowRoot) { + return crawlShadows(nestedElement); + } + // No more shadow DOM + return nestedElement; + } + + return node; + }; + + const shadowElement = crawlShadows(element); + + return shadowElement || element; +}; diff --git a/addons/measure/src/withMeasure.ts b/addons/measure/src/withMeasure.ts new file mode 100644 index 000000000000..64711e69a5e4 --- /dev/null +++ b/addons/measure/src/withMeasure.ts @@ -0,0 +1,63 @@ +/* eslint-env browser */ +import { StoryFn as StoryFunction, StoryContext, useEffect } from '@storybook/addons'; +import { drawSelectedElement } from './box-model/visualizer'; +import { init, rescale, destroy } from './box-model/canvas'; +import { deepElementFromPoint } from './util'; + +let nodeAtPointerRef; +const pointer = { x: 0, y: 0 }; + +function findAndDrawElement(x: number, y: number) { + nodeAtPointerRef = deepElementFromPoint(x, y); + drawSelectedElement(nodeAtPointerRef); +} + +export const withMeasure = (StoryFn: StoryFunction, context: StoryContext) => { + const { measureEnabled } = context.globals; + + useEffect(() => { + const onMouseMove = (event: MouseEvent) => { + window.requestAnimationFrame(() => { + event.stopPropagation(); + pointer.x = event.clientX; + pointer.y = event.clientY; + }); + }; + + document.addEventListener('mousemove', onMouseMove); + + return () => { + document.removeEventListener('mousemove', onMouseMove); + }; + }, []); + + useEffect(() => { + const onMouseOver = (event: MouseEvent) => { + window.requestAnimationFrame(() => { + event.stopPropagation(); + findAndDrawElement(event.clientX, event.clientY); + }); + }; + + const onResize = () => { + window.requestAnimationFrame(() => { + rescale(); + }); + }; + + if (measureEnabled) { + document.addEventListener('mouseover', onMouseOver); + init(); + window.addEventListener('resize', onResize); + // Draw the element below the pointer when first enabled + findAndDrawElement(pointer.x, pointer.y); + } + + return () => { + window.removeEventListener('resize', onResize); + destroy(); + }; + }, [measureEnabled]); + + return StoryFn(); +}; diff --git a/addons/measure/tsconfig.json b/addons/measure/tsconfig.json new file mode 100644 index 000000000000..d1ee4fc75941 --- /dev/null +++ b/addons/measure/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["webpack-env"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "src/**/*.test.*", + "src/**/tests/**/*", + "src/**/__tests__/**/*", + "src/**/*.stories.*", + "src/**/*.mockdata.*", + "src/**/__testfixtures__/**" + ] +} diff --git a/addons/outline/README.md b/addons/outline/README.md new file mode 100644 index 000000000000..c94df715d438 --- /dev/null +++ b/addons/outline/README.md @@ -0,0 +1,23 @@ +# Storybook Addon Outline + +Storybook Addon Outline can be used for visually debugging CSS layout and alignment inside the preview in [Storybook](https://storybook.js.org). Based on [Pesticide](https://github.com/mrmrs/pesticide), it draws outlines around every single element in the preview pane. + +![React Storybook Screenshot](https://user-images.githubusercontent.com/42671/98158421-dada2300-1ea8-11eb-8619-af1e7018e1ec.png) + +## Usage + +Requires Storybook 6.1 or later. Outline is part of [essentials](https://storybook.js.org/docs/react/essentials/introduction) and so is installed in all new Storybooks by default. If you need to add it to your Storybook, you can run: + +```sh +npm i -D @storybook/addon-outline +``` + +Then, add following content to [`.storybook/main.js`](https://storybook.js.org/docs/react/configure/overview#configure-your-storybook-project): + +```js +module.exports = { + addons: ['@storybook/addon-outline'], +}; +``` + +You can now click on the outline button in the toolbar to toggle the outlines. diff --git a/addons/outline/package.json b/addons/outline/package.json new file mode 100644 index 000000000000..b6362e2684f9 --- /dev/null +++ b/addons/outline/package.json @@ -0,0 +1,87 @@ +{ + "name": "@storybook/addon-outline", + "version": "6.4.0-alpha.17", + "description": "Outline all elements with CSS to help with layout placement and alignment", + "keywords": [ + "storybook-addons", + "essentials", + "outline", + "css", + "layout", + "debug", + "storybook-addon", + "style" + ], + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/outline", + "bugs": { + "url": "https://github.com/storybookjs/storybook/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/storybookjs/storybook.git", + "directory": "addons/outline" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "license": "MIT", + "author": "winkerVSbecks", + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "types": "dist/ts3.9/index.d.ts", + "typesVersions": { + "<3.8": { + "*": [ + "dist/ts3.4/*" + ] + } + }, + "files": [ + "dist/**/*", + "README.md", + "*.js", + "*.d.ts" + ], + "scripts": { + "prepare": "node ../../scripts/prepare.js" + }, + "dependencies": { + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "core-js": "^3.8.2", + "global": "^4.4.0", + "regenerator-runtime": "^0.13.7", + "ts-dedent": "^2.0.0" + }, + "devDependencies": { + "@types/webpack-env": "^1.16.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + }, + "publishConfig": { + "access": "public" + }, + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", + "sbmodern": "dist/modern/index.js", + "storybook": { + "displayName": "Outline", + "unsupportedFrameworks": [ + "react-native" + ], + "icon": "https://user-images.githubusercontent.com/263385/101991674-48355c80-3c7c-11eb-9686-f684e755fcdd.png" + } +} diff --git a/addons/outline/preset.js b/addons/outline/preset.js new file mode 100644 index 000000000000..459bbb650ccd --- /dev/null +++ b/addons/outline/preset.js @@ -0,0 +1,12 @@ +function config(entry = []) { + return [...entry, require.resolve('./dist/esm/preset/addDecorator')]; +} + +function managerEntries(entry = [], options) { + return [...entry, require.resolve('./dist/esm/register')]; +} + +module.exports = { + managerEntries, + config, +}; diff --git a/addons/outline/register.js b/addons/outline/register.js new file mode 100644 index 000000000000..f209c0eb3703 --- /dev/null +++ b/addons/outline/register.js @@ -0,0 +1 @@ +require('./dist/esm/register'); diff --git a/addons/outline/src/OutlineSelector.tsx b/addons/outline/src/OutlineSelector.tsx new file mode 100644 index 000000000000..9a91fba9cd6d --- /dev/null +++ b/addons/outline/src/OutlineSelector.tsx @@ -0,0 +1,29 @@ +import React, { memo, useCallback } from 'react'; +import { useGlobals } from '@storybook/api'; +import { Icons, IconButton } from '@storybook/components'; +import { PARAM_KEY } from './constants'; + +export const OutlineSelector = memo(() => { + const [globals, updateGlobals] = useGlobals(); + + const isActive = globals[PARAM_KEY] || false; + + const toggleOutline = useCallback( + () => + updateGlobals({ + [PARAM_KEY]: !isActive, + }), + [isActive] + ); + + return ( + + + + ); +}); diff --git a/addons/outline/src/constants.ts b/addons/outline/src/constants.ts new file mode 100644 index 000000000000..1da3648c98ee --- /dev/null +++ b/addons/outline/src/constants.ts @@ -0,0 +1,2 @@ +export const ADDON_ID = 'storybook/outline'; +export const PARAM_KEY = 'outline'; diff --git a/addons/outline/src/helpers.ts b/addons/outline/src/helpers.ts new file mode 100644 index 000000000000..569a80e21d7b --- /dev/null +++ b/addons/outline/src/helpers.ts @@ -0,0 +1,27 @@ +import global from 'global'; + +export const clearStyles = (selector: string | string[]) => { + const selectors = Array.isArray(selector) ? selector : [selector]; + selectors.forEach(clearStyle); +}; + +const clearStyle = (selector: string | string[]) => { + const element = global.document.getElementById(selector); + if (element && element.parentElement) { + element.parentElement.removeChild(element); + } +}; + +export const addOutlineStyles = (selector: string, css: string) => { + const existingStyle = global.document.getElementById(selector); + if (existingStyle) { + if (existingStyle.innerHTML !== css) { + existingStyle.innerHTML = css; + } + } else { + const style = global.document.createElement('style'); + style.setAttribute('id', selector); + style.innerHTML = css; + global.document.head.appendChild(style); + } +}; diff --git a/addons/outline/src/index.ts b/addons/outline/src/index.ts new file mode 100644 index 000000000000..644402abb41c --- /dev/null +++ b/addons/outline/src/index.ts @@ -0,0 +1,6 @@ +if (module && module.hot && module.hot.decline) { + module.hot.decline(); +} + +// make it work with --isolatedModules +export default {}; diff --git a/addons/outline/src/outlineCSS.ts b/addons/outline/src/outlineCSS.ts new file mode 100644 index 000000000000..94bbeee73570 --- /dev/null +++ b/addons/outline/src/outlineCSS.ts @@ -0,0 +1,403 @@ +import dedent from 'ts-dedent'; + +/* + From pesticide v1.3.0 . @mrmrs . MIT +*/ +export default function outlineCSS(selector: string) { + return dedent/* css */ ` + ${selector} body { + outline: 1px solid #2980b9 !important; + } + + ${selector} article { + outline: 1px solid #3498db !important; + } + + ${selector} nav { + outline: 1px solid #0088c3 !important; + } + + ${selector} aside { + outline: 1px solid #33a0ce !important; + } + + ${selector} section { + outline: 1px solid #66b8da !important; + } + + ${selector} header { + outline: 1px solid #99cfe7 !important; + } + + ${selector} footer { + outline: 1px solid #cce7f3 !important; + } + + ${selector} h1 { + outline: 1px solid #162544 !important; + } + + ${selector} h2 { + outline: 1px solid #314e6e !important; + } + + ${selector} h3 { + outline: 1px solid #3e5e85 !important; + } + + ${selector} h4 { + outline: 1px solid #449baf !important; + } + + ${selector} h5 { + outline: 1px solid #c7d1cb !important; + } + + ${selector} h6 { + outline: 1px solid #4371d0 !important; + } + + ${selector} main { + outline: 1px solid #2f4f90 !important; + } + + ${selector} address { + outline: 1px solid #1a2c51 !important; + } + + ${selector} div { + outline: 1px solid #036cdb !important; + } + + ${selector} p { + outline: 1px solid #ac050b !important; + } + + ${selector} hr { + outline: 1px solid #ff063f !important; + } + + ${selector} pre { + outline: 1px solid #850440 !important; + } + + ${selector} blockquote { + outline: 1px solid #f1b8e7 !important; + } + + ${selector} ol { + outline: 1px solid #ff050c !important; + } + + ${selector} ul { + outline: 1px solid #d90416 !important; + } + + ${selector} li { + outline: 1px solid #d90416 !important; + } + + ${selector} dl { + outline: 1px solid #fd3427 !important; + } + + ${selector} dt { + outline: 1px solid #ff0043 !important; + } + + ${selector} dd { + outline: 1px solid #e80174 !important; + } + + ${selector} figure { + outline: 1px solid #ff00bb !important; + } + + ${selector} figcaption { + outline: 1px solid #bf0032 !important; + } + + ${selector} table { + outline: 1px solid #00cc99 !important; + } + + ${selector} caption { + outline: 1px solid #37ffc4 !important; + } + + ${selector} thead { + outline: 1px solid #98daca !important; + } + + ${selector} tbody { + outline: 1px solid #64a7a0 !important; + } + + ${selector} tfoot { + outline: 1px solid #22746b !important; + } + + ${selector} tr { + outline: 1px solid #86c0b2 !important; + } + + ${selector} th { + outline: 1px solid #a1e7d6 !important; + } + + ${selector} td { + outline: 1px solid #3f5a54 !important; + } + + ${selector} col { + outline: 1px solid #6c9a8f !important; + } + + ${selector} colgroup { + outline: 1px solid #6c9a9d !important; + } + + ${selector} button { + outline: 1px solid #da8301 !important; + } + + ${selector} datalist { + outline: 1px solid #c06000 !important; + } + + ${selector} fieldset { + outline: 1px solid #d95100 !important; + } + + ${selector} form { + outline: 1px solid #d23600 !important; + } + + ${selector} input { + outline: 1px solid #fca600 !important; + } + + ${selector} keygen { + outline: 1px solid #b31e00 !important; + } + + ${selector} label { + outline: 1px solid #ee8900 !important; + } + + ${selector} legend { + outline: 1px solid #de6d00 !important; + } + + ${selector} meter { + outline: 1px solid #e8630c !important; + } + + ${selector} optgroup { + outline: 1px solid #b33600 !important; + } + + ${selector} option { + outline: 1px solid #ff8a00 !important; + } + + ${selector} output { + outline: 1px solid #ff9619 !important; + } + + ${selector} progress { + outline: 1px solid #e57c00 !important; + } + + ${selector} select { + outline: 1px solid #e26e0f !important; + } + + ${selector} textarea { + outline: 1px solid #cc5400 !important; + } + + ${selector} details { + outline: 1px solid #33848f !important; + } + + ${selector} summary { + outline: 1px solid #60a1a6 !important; + } + + ${selector} command { + outline: 1px solid #438da1 !important; + } + + ${selector} menu { + outline: 1px solid #449da6 !important; + } + + ${selector} del { + outline: 1px solid #bf0000 !important; + } + + ${selector} ins { + outline: 1px solid #400000 !important; + } + + ${selector} img { + outline: 1px solid #22746b !important; + } + + ${selector} iframe { + outline: 1px solid #64a7a0 !important; + } + + ${selector} embed { + outline: 1px solid #98daca !important; + } + + ${selector} object { + outline: 1px solid #00cc99 !important; + } + + ${selector} param { + outline: 1px solid #37ffc4 !important; + } + + ${selector} video { + outline: 1px solid #6ee866 !important; + } + + ${selector} audio { + outline: 1px solid #027353 !important; + } + + ${selector} source { + outline: 1px solid #012426 !important; + } + + ${selector} canvas { + outline: 1px solid #a2f570 !important; + } + + ${selector} track { + outline: 1px solid #59a600 !important; + } + + ${selector} map { + outline: 1px solid #7be500 !important; + } + + ${selector} area { + outline: 1px solid #305900 !important; + } + + ${selector} a { + outline: 1px solid #ff62ab !important; + } + + ${selector} em { + outline: 1px solid #800b41 !important; + } + + ${selector} strong { + outline: 1px solid #ff1583 !important; + } + + ${selector} i { + outline: 1px solid #803156 !important; + } + + ${selector} b { + outline: 1px solid #cc1169 !important; + } + + ${selector} u { + outline: 1px solid #ff0430 !important; + } + + ${selector} s { + outline: 1px solid #f805e3 !important; + } + + ${selector} small { + outline: 1px solid #d107b2 !important; + } + + ${selector} abbr { + outline: 1px solid #4a0263 !important; + } + + ${selector} q { + outline: 1px solid #240018 !important; + } + + ${selector} cite { + outline: 1px solid #64003c !important; + } + + ${selector} dfn { + outline: 1px solid #b4005a !important; + } + + ${selector} sub { + outline: 1px solid #dba0c8 !important; + } + + ${selector} sup { + outline: 1px solid #cc0256 !important; + } + + ${selector} time { + outline: 1px solid #d6606d !important; + } + + ${selector} code { + outline: 1px solid #e04251 !important; + } + + ${selector} kbd { + outline: 1px solid #5e001f !important; + } + + ${selector} samp { + outline: 1px solid #9c0033 !important; + } + + ${selector} var { + outline: 1px solid #d90047 !important; + } + + ${selector} mark { + outline: 1px solid #ff0053 !important; + } + + ${selector} bdi { + outline: 1px solid #bf3668 !important; + } + + ${selector} bdo { + outline: 1px solid #6f1400 !important; + } + + ${selector} ruby { + outline: 1px solid #ff7b93 !important; + } + + ${selector} rt { + outline: 1px solid #ff2f54 !important; + } + + ${selector} rp { + outline: 1px solid #803e49 !important; + } + + ${selector} span { + outline: 1px solid #cc2643 !important; + } + + ${selector} br { + outline: 1px solid #db687d !important; + } + + ${selector} wbr { + outline: 1px solid #db175b !important; + }`; +} diff --git a/addons/outline/src/preset/addDecorator.tsx b/addons/outline/src/preset/addDecorator.tsx new file mode 100644 index 000000000000..1abee6e575c6 --- /dev/null +++ b/addons/outline/src/preset/addDecorator.tsx @@ -0,0 +1,8 @@ +import { withOutline } from '../withOutline'; +import { PARAM_KEY } from '../constants'; + +export const decorators = [withOutline]; + +export const globals = { + [PARAM_KEY]: false, +}; diff --git a/addons/outline/src/register.tsx b/addons/outline/src/register.tsx new file mode 100644 index 000000000000..3f3f96ae3b06 --- /dev/null +++ b/addons/outline/src/register.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { addons, types } from '@storybook/addons'; + +import { ADDON_ID } from './constants'; +import { OutlineSelector } from './OutlineSelector'; + +addons.register(ADDON_ID, () => { + addons.add(ADDON_ID, { + title: 'Outline', + type: types.TOOL, + match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)), + render: () => , + }); +}); diff --git a/addons/outline/src/typings.d.ts b/addons/outline/src/typings.d.ts new file mode 100644 index 000000000000..2f4eb9cf4fd9 --- /dev/null +++ b/addons/outline/src/typings.d.ts @@ -0,0 +1 @@ +declare module 'global'; diff --git a/addons/outline/src/withOutline.ts b/addons/outline/src/withOutline.ts new file mode 100644 index 000000000000..391967c96abb --- /dev/null +++ b/addons/outline/src/withOutline.ts @@ -0,0 +1,33 @@ +import { StoryFn as StoryFunction, StoryContext, useMemo, useEffect } from '@storybook/addons'; + +import { clearStyles, addOutlineStyles } from './helpers'; +import { PARAM_KEY } from './constants'; +import outlineCSS from './outlineCSS'; + +export const withOutline = (StoryFn: StoryFunction, context: StoryContext) => { + const { globals } = context; + const isActive = globals[PARAM_KEY] === true; + const isInDocs = context.viewMode === 'docs'; + + const outlineStyles = useMemo(() => { + const selector = isInDocs ? `#anchor--${context.id} .docs-story` : '.sb-show-main'; + + return outlineCSS(selector); + }, [context]); + + useEffect(() => { + const selectorId = isInDocs ? `addon-outline-docs-${context.id}` : `addon-outline`; + + if (!isActive) { + clearStyles(selectorId); + } else { + addOutlineStyles(selectorId, outlineStyles); + } + + return () => { + clearStyles(selectorId); + }; + }, [isActive, outlineStyles, context]); + + return StoryFn(); +}; diff --git a/addons/outline/tsconfig.json b/addons/outline/tsconfig.json new file mode 100644 index 000000000000..d1ee4fc75941 --- /dev/null +++ b/addons/outline/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["webpack-env"] + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "src/**/*.test.*", + "src/**/tests/**/*", + "src/**/__tests__/**/*", + "src/**/*.stories.*", + "src/**/*.mockdata.*", + "src/**/__testfixtures__/**" + ] +} diff --git a/addons/storyshots/storyshots-core/package.json b/addons/storyshots/storyshots-core/package.json index cc81750d1124..6b01c4fe4f0f 100644 --- a/addons/storyshots/storyshots-core/package.json +++ b/addons/storyshots/storyshots-core/package.json @@ -1,13 +1,13 @@ { "name": "@storybook/addon-storyshots", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Take a code snapshot of every story automatically with Jest", "keywords": [ "addon", "storybook", "test" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/storyshots/storyshots-core", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,10 +45,10 @@ }, "dependencies": { "@jest/transform": "^26.6.2", - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "@types/glob": "^7.1.3", "@types/jest": "^26.0.16", "@types/jest-specific-snapshot": "^0.5.3", @@ -67,11 +67,11 @@ "devDependencies": { "@angular/core": "^11.2.0", "@angular/platform-browser-dynamic": "^11.2.0", - "@storybook/addon-docs": "6.4.0-alpha.9", - "@storybook/angular": "6.4.0-alpha.9", - "@storybook/react": "6.4.0-alpha.9", - "@storybook/vue": "6.4.0-alpha.9", - "@storybook/vue3": "6.4.0-alpha.9", + "@storybook/addon-docs": "6.4.0-alpha.17", + "@storybook/angular": "6.4.0-alpha.17", + "@storybook/react": "6.4.0-alpha.17", + "@storybook/vue": "6.4.0-alpha.17", + "@storybook/vue3": "6.4.0-alpha.17", "babel-loader": "^8.2.2", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.1", @@ -149,7 +149,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "storybook": { "displayName": "Storyshots", "icon": "https://user-images.githubusercontent.com/263385/101991676-48cdf300-3c7c-11eb-8aa1-944dab6ab29b.png", diff --git a/addons/storyshots/storyshots-puppeteer/package.json b/addons/storyshots/storyshots-puppeteer/package.json index 7689f59f39f0..10741d53fc99 100644 --- a/addons/storyshots/storyshots-puppeteer/package.json +++ b/addons/storyshots/storyshots-puppeteer/package.json @@ -1,12 +1,12 @@ { "name": "@storybook/addon-storyshots-puppeteer", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Image snapshots addition to StoryShots based on puppeteer", "keywords": [ "addon", "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-puppeteer", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/storyshots/storyshots-puppeteer", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -42,7 +42,7 @@ "dependencies": { "@axe-core/puppeteer": "^4.2.0", "@storybook/csf": "0.0.1", - "@storybook/node-logger": "6.4.0-alpha.9", + "@storybook/node-logger": "6.4.0-alpha.17", "@types/jest-image-snapshot": "^4.1.3", "core-js": "^3.8.2", "jest-image-snapshot": "^4.3.0", @@ -53,7 +53,7 @@ "@types/puppeteer": "^5.4.0" }, "peerDependencies": { - "@storybook/addon-storyshots": "6.4.0-alpha.9", + "@storybook/addon-storyshots": "6.4.0-alpha.17", "puppeteer": "^2.0.0 || ^3.0.0" }, "peerDependenciesMeta": { @@ -64,5 +64,5 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde" + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73" } diff --git a/addons/storysource/package.json b/addons/storysource/package.json index 37ef907fad04..83b835121ebe 100644 --- a/addons/storysource/package.json +++ b/addons/storysource/package.json @@ -1,13 +1,13 @@ { "name": "@storybook/addon-storysource", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", "storybook", "code" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/storysource", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/storysource", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -41,13 +41,13 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-logger": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/router": "6.4.0-alpha.9", - "@storybook/source-loader": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/router": "6.4.0-alpha.17", + "@storybook/source-loader": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "estraverse": "^5.2.0", "loader-utils": "^2.0.0", @@ -75,7 +75,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/index.js", "storybook": { "displayName": "Storysource", diff --git a/addons/toolbars/package.json b/addons/toolbars/package.json index 209321a416fc..1cf300fb6254 100644 --- a/addons/toolbars/package.json +++ b/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", @@ -45,11 +45,11 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "regenerator-runtime": "^0.13.7" }, @@ -68,7 +68,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/register.js", "storybook": { "displayName": "Toolbars", diff --git a/addons/viewport/package.json b/addons/viewport/package.json index 78d6c38086fa..6e69b44634cf 100644 --- a/addons/viewport/package.json +++ b/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", @@ -8,7 +8,7 @@ "style", "essentials" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/addons/viewport", + "homepage": "https://github.com/storybookjs/storybook/tree/main/addons/viewport", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -42,12 +42,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-logger": "6.4.0-alpha.9", - "@storybook/components": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", - "@storybook/theming": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-logger": "6.4.0-alpha.17", + "@storybook/components": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "@storybook/theming": "6.4.0-alpha.17", "core-js": "^3.8.2", "global": "^4.4.0", "memoizerific": "^1.11.3", @@ -69,7 +69,7 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/preview.js", "storybook": { "displayName": "Viewport", diff --git a/app/angular/package.json b/app/angular/package.json index 6c9c90c27f8a..20483664ac62 100644 --- a/app/angular/package.json +++ b/app/angular/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/angular", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Angular: Develop Angular Components in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/angular", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/angular", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,12 +45,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", - "@storybook/core-events": "6.4.0-alpha.9", - "@storybook/node-logger": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", + "@storybook/core-events": "6.4.0-alpha.17", + "@storybook/node-logger": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "autoprefixer": "^9.8.6", "core-js": "^3.8.2", @@ -65,6 +65,7 @@ "regenerator-runtime": "^0.13.7", "sass-loader": "^10.1.0", "strip-json-comments": "3.1.1", + "telejson": "^5.3.2", "ts-dedent": "^2.0.0", "ts-loader": "^8.0.14", "tsconfig-paths-webpack-plugin": "^3.3.0", @@ -128,5 +129,5 @@ "access": "public" }, "builders": "dist/ts3.9/builders/builders.json", - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde" + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73" } diff --git a/app/angular/src/client/preview/angular-beta/AbstractRenderer.ts b/app/angular/src/client/preview/angular-beta/AbstractRenderer.ts index 8260f8856244..8dbaaf5b1c41 100644 --- a/app/angular/src/client/preview/angular-beta/AbstractRenderer.ts +++ b/app/angular/src/client/preview/angular-beta/AbstractRenderer.ts @@ -3,6 +3,7 @@ import { enableProdMode, NgModule, PlatformRef } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BehaviorSubject, Subject } from 'rxjs'; +import { stringify } from 'telejson'; import { ICollection, StoryFnAngularReturnType } from '../types'; import { Parameters } from '../types-6-0'; import { createStorybookModule, getStorybookModuleMetadata } from './StorybookModule'; @@ -160,7 +161,7 @@ export abstract class AbstractRenderer { const currentStoryRender = { storyFnAngular, - moduleMetadataSnapshot: JSON.stringify(moduleMetadata), + moduleMetadataSnapshot: stringify(moduleMetadata), }; this.previousStoryRenderInfo = currentStoryRender; diff --git a/app/angular/src/client/preview/angular-beta/RendererFactory.test.ts b/app/angular/src/client/preview/angular-beta/RendererFactory.test.ts index f3f3233b73cd..754cc894fc70 100644 --- a/app/angular/src/client/preview/angular-beta/RendererFactory.test.ts +++ b/app/angular/src/client/preview/angular-beta/RendererFactory.test.ts @@ -1,4 +1,4 @@ -import { Component, getPlatform } from '@angular/core'; +import { Component, getPlatform, ɵresetJitOptions } from '@angular/core'; import { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { Parameters } from '../types-6-0'; @@ -26,6 +26,10 @@ describe('RendererFactory', () => { afterEach(() => { jest.clearAllMocks(); + + // Necessary to avoid this error "Provided value for `preserveWhitespaces` can not be changed once it has been set." : + // Source: https://github.com/angular/angular/commit/e342ffd855ffeb8af7067b42307ffa320d82177e#diff-92b125e532cc22977b46a91f068d6d7ea81fd61b772842a4a0212f1cfd875be6R28 + ɵresetJitOptions(); }); describe('CanvasRenderer', () => { @@ -65,7 +69,9 @@ describe('RendererFactory', () => { targetDOMNode: rootTargetDOMNode, }); - expect(document.body.getElementsByTagName('my-story')[0].innerHTML).toBe('🦊'); + expect(document.body.getElementsByTagName('my-story')[0].innerHTML).toBe( + '🦊' + ); }); describe('when forced=true', () => { diff --git a/app/angular/src/client/preview/angular-beta/RendererService.test.ts b/app/angular/src/client/preview/angular-beta/RendererService.test.ts index 802ac6039382..d404a287ab23 100644 --- a/app/angular/src/client/preview/angular-beta/RendererService.test.ts +++ b/app/angular/src/client/preview/angular-beta/RendererService.test.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, ɵresetJitOptions } from '@angular/core'; import { platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { Parameters } from '../types-6-0'; @@ -18,6 +18,10 @@ describe('RendererService', () => { afterEach(() => { jest.clearAllMocks(); + + // Necessary to avoid this error "Provided value for `preserveWhitespaces` can not be changed once it has been set." : + // Source: https://github.com/angular/angular/commit/e342ffd855ffeb8af7067b42307ffa320d82177e#diff-92b125e532cc22977b46a91f068d6d7ea81fd61b772842a4a0212f1cfd875be6R28 + ɵresetJitOptions(); }); it('should initialize', () => { @@ -53,10 +57,33 @@ describe('RendererService', () => { }); expect(document.body.getElementsByTagName('storybook-wrapper')[0].innerHTML).toBe( - '🦊' + '🦊' ); }); + it('should handle circular reference in moduleMetadata', async () => { + class Thing { + token: Thing; + + constructor() { + this.token = this; + } + } + const token = new Thing(); + + await rendererService.render({ + storyFnAngular: { + template: '🦊', + props: {}, + moduleMetadata: { providers: [{ provide: 'foo', useValue: token }] }, + }, + forced: false, + parameters: {} as any, + }); + + expect(document.body.getElementsByTagName('storybook-wrapper')[0].innerHTML).toBe('🦊'); + }); + describe('when forced=true', () => { beforeEach(async () => { // Init first render diff --git a/app/angular/src/client/preview/angular-beta/RendererService.ts b/app/angular/src/client/preview/angular-beta/RendererService.ts index 58144ac66a26..9909cf0f24ae 100644 --- a/app/angular/src/client/preview/angular-beta/RendererService.ts +++ b/app/angular/src/client/preview/angular-beta/RendererService.ts @@ -3,6 +3,7 @@ import { enableProdMode, NgModule, PlatformRef } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BehaviorSubject, Subject } from 'rxjs'; +import { stringify } from 'telejson'; import { ICollection, StoryFnAngularReturnType } from '../types'; import { Parameters } from '../types-6-0'; import { createStorybookModule, getStorybookModuleMetadata } from './StorybookModule'; @@ -154,7 +155,7 @@ export class RendererService { this.currentStoryRender = { storyFnAngular, - moduleMetadataSnapshot: JSON.stringify(moduleMetadata), + moduleMetadataSnapshot: stringify(moduleMetadata), }; if ( diff --git a/app/angular/src/server/build.ts b/app/angular/src/server/build.ts index d8abf06a4396..fe1ed4fb11e3 100644 --- a/app/angular/src/server/build.ts +++ b/app/angular/src/server/build.ts @@ -1,4 +1,13 @@ import { buildStatic } from '@storybook/core/server'; +import { logger } from '@storybook/node-logger'; import options from './options'; -buildStatic(options); +async function build() { + try { + await buildStatic(options); + } catch (error) { + logger.error(error); + } +} + +build(); diff --git a/app/ember/package.json b/app/ember/package.json index 59135776c25c..93406a5f039a 100644 --- a/app/ember/package.json +++ b/app/ember/package.json @@ -1,8 +1,8 @@ { "name": "@storybook/ember", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/ember", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/ember", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -43,8 +43,8 @@ }, "dependencies": { "@ember/test-helpers": "^2.1.4", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "core-js": "^3.8.2", "global": "^4.4.0", "react": "16.14.0", @@ -65,6 +65,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/html/package.json b/app/html/package.json index 3c84b8b0e2e5..c84ac7bb7261 100644 --- a/app/html/package.json +++ b/app/html/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/html", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/html", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/html", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,10 +45,10 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -68,6 +68,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/preact/package.json b/app/preact/package.json index 0e531be6f016..aa4e2569522a 100644 --- a/app/preact/package.json +++ b/app/preact/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/preact", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/preact", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/preact", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -46,9 +46,9 @@ }, "dependencies": { "@babel/plugin-transform-react-jsx": "^7.12.12", - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -72,6 +72,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/react/package.json b/app/react/package.json index 44ce65b3d888..3ab2e3c7a92a 100644 --- a/app/react/package.json +++ b/app/react/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/react", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/react", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/react", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -49,10 +49,10 @@ "@babel/preset-flow": "^7.12.1", "@babel/preset-react": "^7.12.10", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", - "@storybook/node-logger": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", + "@storybook/node-logger": "6.4.0-alpha.17", "@storybook/react-docgen-typescript-plugin": "1.0.2-canary.253f8c1.0", "@storybook/semver": "^7.3.2", "@types/webpack-env": "^1.16.0", @@ -71,7 +71,7 @@ "webpack": "4" }, "devDependencies": { - "@storybook/client-api": "6.4.0-alpha.9", + "@storybook/client-api": "6.4.0-alpha.17", "@types/node": "^14.14.20", "@types/prompts": "^2.0.9" }, @@ -94,6 +94,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/react/src/client/preview/index.tsx b/app/react/src/client/preview/index.tsx index 64d40bd005b8..cc9b300fc51a 100644 --- a/app/react/src/client/preview/index.tsx +++ b/app/react/src/client/preview/index.tsx @@ -10,11 +10,6 @@ import { Story } from './types-6-3'; const framework = 'react'; -const globalRender: Story = (args, { parameters }) => { - const Component = parameters.component; - return ; -}; - interface ClientApi extends ClientStoryApi { setAddon(addon: any): void; configure(loader: Loadable, module: NodeModule): void; @@ -24,6 +19,11 @@ interface ClientApi extends ClientStoryApi { raw: () => any; // todo add type } +const globalRender: Story = (args, { parameters }) => { + const Component = parameters.component; + return ; +}; + const api = start(render); api.clientApi.globalRender = globalRender; diff --git a/app/server/package.json b/app/server/package.json index b5e0e01a5f00..d2788a49b044 100644 --- a/app/server/package.json +++ b/app/server/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/server", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/server", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/server", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,12 +45,12 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/api": "6.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", - "@storybook/node-logger": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/api": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", + "@storybook/node-logger": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -72,6 +72,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/svelte/package.json b/app/svelte/package.json index 0e54f2598cfe..713989b190e7 100644 --- a/app/svelte/package.json +++ b/app/svelte/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/svelte", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/svelte", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/svelte", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,9 +45,9 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "core-js": "^3.8.2", "global": "^4.4.0", "react": "16.14.0", @@ -73,6 +73,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/vue/package.json b/app/vue/package.json index 35497bb286c5..86ae37b69fe7 100644 --- a/app/vue/package.json +++ b/app/vue/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/vue", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Vue: Develop Vue Component in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/vue", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/vue", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,9 +45,9 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -81,6 +81,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/vue3/package.json b/app/vue3/package.json index e8eccb38842b..6386ab1f6f05 100644 --- a/app/vue3/package.json +++ b/app/vue3/package.json @@ -1,11 +1,11 @@ { "name": "@storybook/vue3", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/vue3", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/vue3", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -45,9 +45,9 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/addons": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "core-js": "^3.8.2", "global": "^4.4.0", @@ -79,6 +79,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/app/web-components/package.json b/app/web-components/package.json index be050bf3057c..79add56423f4 100644 --- a/app/web-components/package.json +++ b/app/web-components/package.json @@ -1,13 +1,13 @@ { "name": "@storybook/web-components", - "version": "6.4.0-alpha.9", + "version": "6.4.0-alpha.17", "description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.", "keywords": [ "lit-html", "storybook", "web-components" ], - "homepage": "https://github.com/storybookjs/storybook/tree/master/app/web-components", + "homepage": "https://github.com/storybookjs/storybook/tree/main/app/web-components", "bugs": { "url": "https://github.com/storybookjs/storybook/issues" }, @@ -50,10 +50,10 @@ "@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.4.0-alpha.9", - "@storybook/client-api": "6.4.0-alpha.9", - "@storybook/core": "6.4.0-alpha.9", - "@storybook/core-common": "6.4.0-alpha.9", + "@storybook/addons": "6.4.0-alpha.17", + "@storybook/client-api": "6.4.0-alpha.17", + "@storybook/core": "6.4.0-alpha.17", + "@storybook/core-common": "6.4.0-alpha.17", "@types/webpack-env": "^1.16.0", "babel-plugin-bundled-import-meta": "^0.3.1", "core-js": "^3.8.2", @@ -76,6 +76,6 @@ "publishConfig": { "access": "public" }, - "gitHead": "b9b9f9484bfe3cb9f259c26bc71e7635362addde", + "gitHead": "3afa39c64e2efe01e567ce8946e80586d77a8b73", "sbmodern": "dist/modern/client/index.js" } diff --git a/docs/addons/configure-addons.md b/docs/addons/configure-addons.md index 3a84cd600ff2..fcf6dd3263be 100644 --- a/docs/addons/configure-addons.md +++ b/docs/addons/configure-addons.md @@ -35,4 +35,4 @@ For example, the [Actions addon](https://storybook.js.org/addons/@storybook/addo Use the [`useChannel`](./addons-api#usechannel) hook to access the channel data within your addon. -For a complete example, check out [storybookjs/addon-kit/withRoundTrip.js](https://github.com/storybookjs/addon-kit/blob/main/src/withRoundTrip.js) +For a complete example, check out [storybookjs/addon-kit/withRoundTrip.ts](https://github.com/storybookjs/addon-kit/blob/main/src/withRoundTrip.ts) diff --git a/docs/addons/writing-presets.md b/docs/addons/writing-presets.md index 7a8bb72b70e4..c77ff7a926a7 100644 --- a/docs/addons/writing-presets.md +++ b/docs/addons/writing-presets.md @@ -66,6 +66,20 @@ For example, here is how Storybook automatically adopts `create-react-app`'s con - `webpackFinal` is applied to the preview config after all user presets have been applied - `managerWebpack` is applied to the manager config +As of Storybook 6.3, Storybook can run with either `webpack4` or `webpack5` builder. If your addon needs to know which version of Webpack it's running inside, the version and the actual webpack instance itself are both available inside your preset: + +```js +// .storybook/main.js + +export function webpackFinal(config, { presets }) { + const version = await presets.apply('webpackVersion'); + const instance = (await presets.apply('webpackInstance'))?.default; + + logger.info(`=> Running in webpack ${version}: ${instance}`); + return config; +} +``` + ### Manager entries The addon config `managerEntries` allows you to add addons to Storybook from within a preset. For addons that require custom webpack/babel configuration, it is easier to install the preset, and it will take care of everything. diff --git a/docs/api/cli-options.md b/docs/api/cli-options.md index 5b6a3b45c439..003e7013c824 100644 --- a/docs/api/cli-options.md +++ b/docs/api/cli-options.md @@ -34,7 +34,7 @@ Usage: start-storybook [options] | --no-manager-cache | Disables Storybook's manager caching mechanism. See note below. | `start-storybook --no-manager-cache` |
-💡 NOTE: The flag --no-manager-cache disables the internal caching of Storybook and can serverely impact your Storybook loading time, so only use it when you need to refresh Storybook's UI, such as when editing themes. +💡 NOTE: 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.
## build-storybook diff --git a/docs/configure/theming.md b/docs/configure/theming.md index 15ee2eeb47d3..076b170cc0d2 100644 --- a/docs/configure/theming.md +++ b/docs/configure/theming.md @@ -98,20 +98,6 @@ Finally, we'll need to import the theme into Storybook. Create a new file called - -Adjust your `storybook` script in your package.json and include the [`--no-manager-cache`](../api/cli-options.md#start-storybook) flag. For instance: - -```json -{ - "scripts":{ - "storybook": "start-storybook -p 6006 --no-manager-cache", - }, -} -``` -
-💡 Note: Once you've finished configuring your theme, you can remove the --no-manager-cacheflag from the storybook script at will. Leaving it in can severely impact loading times. -
- Now your custom theme will replace Storybook's default theme, and you'll see a similar set of changes in the UI. ![Storybook starter theme](./storybook-starter-custom-theme.png) diff --git a/docs/contribute/code.md b/docs/contribute/code.md index f21c6238c81b..fd73f64cf261 100644 --- a/docs/contribute/code.md +++ b/docs/contribute/code.md @@ -101,7 +101,7 @@ yarn test ```
-💡 Storybook uses jest as part of the testing suite, if you notice that the snapshot tests fail you can re-run and update them with yarn test --update. +💡 Storybook uses jest as part of the testing suite, if you notice that the snapshot tests fail you can re-run and update them with yarn test -u.
Doing this prevents last-minute bugs and is also a great way to get your contribution merged faster once you submit your pull request. Failing to do so will lead to one of the maintainers mark the pull request with the **Work in Progress** label until all tests pass. diff --git a/docs/essentials/auto-generated-controls/react.mdx b/docs/essentials/auto-generated-controls/react.mdx index bf2f23322192..ab1b01981cfd 100644 --- a/docs/essentials/auto-generated-controls/react.mdx +++ b/docs/essentials/auto-generated-controls/react.mdx @@ -1,6 +1,8 @@ To use auto-detected controls with React, you must fill in the `component` field in your story metadata: ```ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx + import { Button } from './Button'; export default { diff --git a/docs/essentials/introduction.md b/docs/essentials/introduction.md index 8a466018730a..96356b3b135d 100644 --- a/docs/essentials/introduction.md +++ b/docs/essentials/introduction.md @@ -29,6 +29,8 @@ npm install --save-dev @storybook/addon-essentials Update your Storybook configuration (in `.storybook/main.js`) to include the essentials addon. ```js +// .storybook/main.js + module.exports = { addons: ['@storybook/addon-essentials'], }; diff --git a/docs/essentials/toolbars-and-globals.md b/docs/essentials/toolbars-and-globals.md index 04cb76024e21..901a23a758ad 100644 --- a/docs/essentials/toolbars-and-globals.md +++ b/docs/essentials/toolbars-and-globals.md @@ -6,9 +6,9 @@ Storybook ships with toolbar items to control the [viewport](./viewport.md) and ## Globals -Globals in Storybook represent “global” (as in not story-specific) inputs to the rendering of the story. As they aren’t specific to the story, they aren’t passed in the `args` argument to the story function (although they are accessible as `context.globals`), but typically you use them in decorators which apply to all stories. +Globals in Storybook represent “global” (as in not story-specific) inputs to the rendering of the story. As they aren’t specific to the story, they aren’t passed in the `args` argument to the story function (although they are accessible as `context.globals`), but typically you use them in decorators, which apply to all stories. -When the globals change, the story re-renders and the decorators rerun with the new values. The easiest way to change globals is to create a toolbar item for them. +When the globals change, the story re-renders, and the decorators rerun with the new values. The easiest way to change globals is to create a toolbar item for them. ## Global types and the toolbar annotation @@ -34,7 +34,7 @@ When you start your Storybook, you should see a new dropdown in your toolbar wit ## Create a decorator -We have a `global` defined, let's wire it up! We can consume our new `theme` global in a decorator using the `context.globals.theme` value. +We have a `global` implemented. Let's wire it up! We can consume our new `theme` global in a decorator using the `context.globals.theme` value. For example, suppose you are using `styled-components`. You can add a theme provider decorator to your [`.storybook/preview.js`](../configure/overview.md#configure-story-rendering) config: @@ -76,7 +76,7 @@ The icon element used in the examples loads the icons from the @storybook/addon-toolbars addon is required to use toolbars. The toolbars addon is included by default in @storybook/addon-essentials. -By adding the configuration element `right`, the text will be displayed on the right side in the toolbar menu, once you connect it to a decorator. +By adding the configuration element `right`, the text will be displayed on the right side in the toolbar menu once you connect it to a decorator. Here's a list of the configuration options available. @@ -84,15 +84,15 @@ Here's a list of the configuration options available. | --------- | :----: | :-------------------------------------------------------------: | :------: | | **value** | String | The string value of the menu that gets set in the globals | Yes | | **title** | String | The main text of the title | Yes | -| **left** | String | A string that gets shown in left side of the menu | No | -| **right** | String | A string that gets shown in right side of the menu | No | +| **left** | String | A string that gets shown on the left side of the menu | No | +| **right** | String | A string that gets displayed on the right side of the menu | No | | **icon** | String | An icon that gets shown in the toolbar if this item is selected | No | ## Consuming globals from within a story We recommend consuming globals from within a decorator and define a global setting for all stories. -But we're aware that sometimes it's more useful to use toolbar options in a per-story basis. +But we're aware that sometimes it's more beneficial to use toolbar options on a per-story basis. Using the example above, you can modify any story to retrieve the **Locale** `global` from the story context: @@ -100,8 +100,15 @@ Using the example above, you can modify any story to retrieve the **Locale** `gl @@ -115,7 +122,11 @@ In Storybook 6.0, if you set the global option `passArgsFirst: false` for backwa @@ -125,7 +136,7 @@ In Storybook 6.0, if you set the global option `passArgsFirst: false` for backwa ## Consuming globals from within an addon -If you're working on a Storybook addon and you need to retrieve globals. You can do so, the `@storybook/api` package provides a hook for this scenario, you can use the [`useGlobals()`](../addons/addons-api.md#useglobals) hook to retrieve any globals you want. +If you're working on a Storybook addon and you need to retrieve globals, you can do so. The `@storybook/api` package provides a hook for this scenario. You can use the [`useGlobals()`](../addons/addons-api.md#useglobals) hook to retrieve any globals you want. Using the ThemeProvider example above, you could expand it to display which current theme is being shown inside a panel like so: @@ -141,7 +152,7 @@ Using the ThemeProvider example above, you could expand it to display which curr ## Updating globals from within an addon -If you're working on a Storybook addon that needs to update the global and refreshes the UI, you can do so. As mentioned previously, the `@storybook/api` package provides the necessary hook for this scenario. You can use the `updateGlobals` function to update any global values you want. +If you're working on a Storybook addon that needs to update the global and refreshes the UI, you can do so. As mentioned previously, the `@storybook/api` package provides the necessary hook for this scenario. You can use the `updateGlobals` function to update any global values you want. Also, you can use the `@storybook/addons` and `@storybook/core-events` packages together to trigger the refresh. @@ -155,4 +166,4 @@ For example, if you were working on a [toolbar addon](../addons/addon-types.md#t ]} /> - + \ No newline at end of file diff --git a/docs/frameworks.js b/docs/frameworks.js index 9f07c78632bb..1a12aeb18d17 100644 --- a/docs/frameworks.js +++ b/docs/frameworks.js @@ -111,7 +111,7 @@ module.exports = { }, { name: 'Dynamic source', - supported: ['react', 'vue', 'angular', 'svelte'], + supported: ['react', 'vue', 'angular', 'svelte', 'web-components'], path: 'writing-docs/doc-blocks#source', }, { diff --git a/docs/get-started/install.md b/docs/get-started/install.md index cc74c44f4f3f..5e58f7bc799c 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -29,6 +29,7 @@ title: 'Install Storybook' Storybook needs to be installed into a project that is already setup with a framework. It will not work on an empty project. There are many ways to bootstrap an app in a given framework including: +- 📦 [Create an Angular Workspace](https://angular.io/cli/new) - 📦 [Create React App](https://reactjs.org/docs/create-a-new-react-app.html) - 📦 [Vue CLI](https://cli.vuejs.org/) - 📦 [Ember CLI](https://guides.emberjs.com/release/getting-started/quick-start/) diff --git a/docs/snippets/angular/apollo-module.mock-apollo-module.ts.mdx b/docs/snippets/angular/apollo-module.mock-apollo-module.ts.mdx new file mode 100644 index 000000000000..a4ff6cb2d888 --- /dev/null +++ b/docs/snippets/angular/apollo-module.mock-apollo-module.ts.mdx @@ -0,0 +1,39 @@ +```ts +// mock-graphql.module.ts + +import { NgModule } from '@angular/core'; +import { APOLLO_OPTIONS } from 'apollo-angular'; +import { ApolloClientOptions, InMemoryCache } from '@apollo/client/core'; +import { HttpLink } from 'apollo-angular/http'; + +// See here for docs https://apollo-angular.com/docs/get-started + +const uri = 'https://your-graphql-endpoint'; +export function createApollo(httpLink: HttpLink): ApolloClientOptions { + return { + link: httpLink.create({ uri }), + cache: new InMemoryCache(), + defaultOptions: { + watchQuery: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, + query: { + fetchPolicy: 'no-cache', + errorPolicy: 'all', + }, + }, + }; +} + +@NgModule({ + providers: [ + { + provide: APOLLO_OPTIONS, + useFactory: createApollo, + deps: [HttpLink], + }, + ], +}) +export class MockGraphQLModule {} +``` diff --git a/docs/snippets/angular/document-screen-fetch.ts.mdx b/docs/snippets/angular/document-screen-fetch.ts.mdx new file mode 100644 index 000000000000..ccaddf887db9 --- /dev/null +++ b/docs/snippets/angular/document-screen-fetch.ts.mdx @@ -0,0 +1,48 @@ +```ts +// YourPage.component.ts + +import { Component, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +@Component({ + selector: 'document-screen', + template: ` +
+

There was an error fetching the data!

+

Loading...

+
+ + + + +
+
+ `, +}) +export default class DocumentScreen implements OnInit { + user: any = { id: 0, name: 'Some User' }; + + document: any = { id: 0, title: 'Some Title' }; + + subdocuments: any = []; + + error = false; + loading = true; + + constructor(private http: HttpClient) {} + + ngOnInit() { + this.http.get('https://your-restful-endpoint').subscribe({ + next: (data) => { + this.loading = false; + this.user = data.user; + this.document = data.document; + this.documents.data.subdocuments; + }, + error: (error) => { + this.error = true; + }, + }); + } +} +``` diff --git a/docs/snippets/angular/document-screen-with-graphql.ts.mdx b/docs/snippets/angular/document-screen-with-graphql.ts.mdx new file mode 100644 index 000000000000..be521f486212 --- /dev/null +++ b/docs/snippets/angular/document-screen-with-graphql.ts.mdx @@ -0,0 +1,69 @@ +```ts +// YourPage.component.ts + +import { Component, OnInit } from '@angular/core'; +import { Apollo } from 'apollo-angular'; +import gql from 'graphql-tag'; + +@Component({ + selector: 'document-screen', + template: ` +
Loading...
+
There was an error fetching the data!
+
+ + + + +
+ `, +}) +export class SampleGraphqlComponent implements OnInit { + user: any = { id: 0, name: 'Some User' }; + + document: any = { id: 0, title: 'Some Title' }; + + subdocuments: any = []; + + error = ''; + loading = true; + + constructor(private apollo: Apollo) {} + ngOnInit() { + this.apollo + .watchQuery({ + query: gql` + query AllInfoQuery { + user { + userID + name + } + document { + id + userID + title + brief + status + } + subdocuments { + id + userID + title + content + status + } + } + `, + }) + .valueChanges.subscribe((result: any) => { + this.user = result?.data?.user; + this.document = result?.data?.document; + this.subdocuments = result?.data?.subdocuments; + this.loading = result.loading; + + // Errors is an array and we're getting the first item only + this.error = result.errors[0].message; + }); + } +} +``` diff --git a/docs/snippets/angular/documentscreen-story-msw-graphql-query.ts.mdx b/docs/snippets/angular/documentscreen-story-msw-graphql-query.ts.mdx new file mode 100644 index 000000000000..16849250c632 --- /dev/null +++ b/docs/snippets/angular/documentscreen-story-msw-graphql-query.ts.mdx @@ -0,0 +1,106 @@ +```ts +// YourPage.stories.ts + +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; + +import { Story, Meta, moduleMetadata } from '@storybook/angular'; + +import { graphql } from 'msw'; + +import DocumentScreen from './YourPage.component'; +import DocumentList from './DocumentList.component'; +import DocumentHeader from './DocumentHeader.component'; +import PageLayout from './PageLayout.component'; + +import { MockGraphQLModule } from './mock-graphql.module'; + +export default { + component: DocumentScreen, + decorators: [ + moduleMetadata({ + declarations: [DocumentList, DocumentHeader, PageLayout], + imports: [CommonModule, HttpClientModule, MockGraphQLModule], + }), + ], + title: 'Mock GraphQL query with Storybook and MSW', +} as Meta; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate: Story = (args) => ({ + props: args, +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res(ctx.data(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + graphql.query('AllInfoQuery', (req, res, ctx) => { + return res( + ctx.delay(800), + ctx.errors([ + { + message: 'Access denied', + }, + ]) + ); + }), + ], +}; +``` diff --git a/docs/snippets/angular/documentscreen-story-msw-rest-request.ts.mdx b/docs/snippets/angular/documentscreen-story-msw-rest-request.ts.mdx new file mode 100644 index 000000000000..5ae41166c1b6 --- /dev/null +++ b/docs/snippets/angular/documentscreen-story-msw-rest-request.ts.mdx @@ -0,0 +1,97 @@ +```ts +// YourPage.stories.ts + +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; + +import { Story, Meta, moduleMetadata } from '@storybook/angular'; + +import { rest } from 'msw'; + +import DocumentScreen from './YourPage.component'; +import DocumentList from './DocumentList.component'; +import DocumentHeader from './DocumentHeader.component'; +import PageLayout from './PageLayout.component'; + +export default { + component: DocumentScreen, + decorators: [ + moduleMetadata({ + declarations: [DocumentList, DocumentHeader, PageLayout], + imports: [CommonModule, HttpClientModule], + }), + ], + title: 'Mock Rest request with Storybook and MSW', +} as Meta; + +//👇The mocked data that will be used in the story +const TestData = { + user: { + userID: 1, + name: 'Someone', + }, + document: { + id: 1, + userID: 1, + title: 'Something', + brief: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + status: 'approved', + }, + subdocuments: [ + { + id: 1, + userID: 1, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 2, + userID: 1, + title: 'Something else', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'awaiting review', + }, + { + id: 3, + userID: 2, + title: 'Another document', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + { + id: 4, + userID: 2, + title: 'Something', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + status: 'approved', + }, + ], +}; + +const PageTemplate: Story = (args) => ({ + props: args, +}); + +export const MockedSuccess = PageTemplate.bind({}); +MockedSuccess.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.json(TestData)); + }), + ], +}; + +export const MockedError = PageTemplate.bind({}); +MockedError.parameters = { + msw: [ + rest.get('https://your-restful-endpoint', (_req, res, ctx) => { + return res(ctx.delay(800), ctx.status(403)); + }), + ], +}; +``` diff --git a/docs/snippets/angular/loader-story.mdx.mdx b/docs/snippets/angular/loader-story.mdx.mdx new file mode 100644 index 000000000000..e1f84461b134 --- /dev/null +++ b/docs/snippets/angular/loader-story.mdx.mdx @@ -0,0 +1,28 @@ +```md + + +import { Meta, Story } from '@storybook/addon-docs/blocks'; + +import TodoItem from './TodoItem'; + +import fetch from 'node-fetch'; + + + + ({ + todo: await ( + await fetch("https://jsonplaceholder.typicode.com/todos/1") + ).json(), + }), + ]} +> + {(args, { loaded: { todo } }) => ({ + props: { + todo: todo, + }, + })} + +``` \ No newline at end of file diff --git a/docs/snippets/angular/loader-story.ts.mdx b/docs/snippets/angular/loader-story.ts.mdx new file mode 100644 index 000000000000..837cd804a9a5 --- /dev/null +++ b/docs/snippets/angular/loader-story.ts.mdx @@ -0,0 +1,37 @@ +```ts +// TodoItem.stories.ts + +import { moduleMetadata, Story, Meta } from '@storybook/angular'; + +import fetch from 'node-fetch'; + +import { CommonModule } from '@angular/common'; + +import TodoItem from './TodoItem'; + +export default { + component: TodoItem, + decorators: [ + moduleMetadata({ + declarations: [TodoItem], + imports: [CommonModule], + }), + ], + title: 'Examples/Loader', +} as Meta; + +export const Primary = (args, { loaded: { todo } }) => { + return { + props: { + args, + todo, + }, + }; +}; + +Primary.loaders = [ + async () => ({ + todo: await (await fetch('https://jsonplaceholder.typicode.com/todos/1')).json(), + }), +]; +``` \ No newline at end of file diff --git a/docs/snippets/angular/my-component-story-use-globaltype-backwards-compat.ts.mdx b/docs/snippets/angular/my-component-story-use-globaltype-backwards-compat.ts.mdx new file mode 100644 index 000000000000..d2fe8932164c --- /dev/null +++ b/docs/snippets/angular/my-component-story-use-globaltype-backwards-compat.ts.mdx @@ -0,0 +1,10 @@ +```ts +// MyComponent.stories.ts + +export const StoryWithLocale = ({ globals: { locale } }) => { + const caption = getCaptionForLocale(locale); + return { + template: `

${caption}

`, + }; +}; +``` \ No newline at end of file diff --git a/docs/snippets/angular/my-component-story-use-globaltype.mdx.mdx b/docs/snippets/angular/my-component-story-use-globaltype.mdx.mdx new file mode 100644 index 000000000000..eb1fd520ddc1 --- /dev/null +++ b/docs/snippets/angular/my-component-story-use-globaltype.mdx.mdx @@ -0,0 +1,23 @@ +```md + + +export const getCaptionForLocale = (locale) => { + switch(locale) { + case 'es': return 'Hola!'; + case 'fr': return 'Bonjour!'; + case 'kr': return '안녕하세요!'; + case 'zh': return '你好!'; + default: + return 'Hello!'; + } +}; + + + {(args, { globals: { locale } }) => { + const caption = getCaptionForLocale(locale); + return { + template: `

${caption}

`, + }; + }} +
+``` \ No newline at end of file diff --git a/docs/snippets/angular/my-component-story-use-globaltype.ts.mdx b/docs/snippets/angular/my-component-story-use-globaltype.ts.mdx new file mode 100644 index 000000000000..505764d13be0 --- /dev/null +++ b/docs/snippets/angular/my-component-story-use-globaltype.ts.mdx @@ -0,0 +1,25 @@ +```ts +// MyComponent.stories.ts + +const getCaptionForLocale = (locale) => { + switch (locale) { + case 'es': + return 'Hola!'; + case 'fr': + return 'Bonjour!'; + case 'kr': + return '안녕하세요!'; + case 'zh': + return '你好!'; + default: + return 'Hello!'; + } +}; + +export const StoryWithLocale = (args, { globals: { locale } }) => { + const caption = getCaptionForLocale(locale); + return { + template: `

${caption}

`, + }; +}; +``` \ No newline at end of file diff --git a/docs/snippets/common/badge-story-custom-argtypes.js.mdx b/docs/snippets/common/badge-story-custom-argtypes.js.mdx index 4dd612f905e0..7ffb54787e47 100644 --- a/docs/snippets/common/badge-story-custom-argtypes.js.mdx +++ b/docs/snippets/common/badge-story-custom-argtypes.js.mdx @@ -1,5 +1,5 @@ ```js -// Badge.stories.js | Badge.stories.ts +// Badge.stories.js | Badge.stories.jsx | Badge.stories.ts | Badge.stories.tsx export default { component: Badge, diff --git a/docs/snippets/common/button-group-story-subcomponents.js.mdx b/docs/snippets/common/button-group-story-subcomponents.js.mdx index 1522fe77d830..27c2aa1d48f6 100644 --- a/docs/snippets/common/button-group-story-subcomponents.js.mdx +++ b/docs/snippets/common/button-group-story-subcomponents.js.mdx @@ -1,5 +1,5 @@ ```js -// ButtonGroup.stories.js +// ButtonGroup.stories.js | ButtonGroup.stories.jsx import { Button, ButtonGroup } from '../ButtonGroup'; diff --git a/docs/snippets/common/button-group-story-subcomponents.ts.mdx b/docs/snippets/common/button-group-story-subcomponents.ts.mdx index 53da77dce0a9..d5657305d92a 100644 --- a/docs/snippets/common/button-group-story-subcomponents.ts.mdx +++ b/docs/snippets/common/button-group-story-subcomponents.ts.mdx @@ -1,5 +1,5 @@ ```ts -// ButtonGroup.stories.ts +// ButtonGroup.stories.ts | ButtonGroup.stories.tsx import { Meta } from '@storybook/react/types-6-0'; diff --git a/docs/snippets/common/button-story-action-event-handle.js.mdx b/docs/snippets/common/button-story-action-event-handle.js.mdx index f40b1655e1cb..653e01aef496 100644 --- a/docs/snippets/common/button-story-action-event-handle.js.mdx +++ b/docs/snippets/common/button-story-action-event-handle.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-argtypes-with-categories.js.mdx b/docs/snippets/common/button-story-argtypes-with-categories.js.mdx index 716aec51d730..cf247036634e 100644 --- a/docs/snippets/common/button-story-argtypes-with-categories.js.mdx +++ b/docs/snippets/common/button-story-argtypes-with-categories.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-argtypes-with-subcategories.js.mdx b/docs/snippets/common/button-story-argtypes-with-subcategories.js.mdx index 9bba6a872970..62e7cf67ebb9 100644 --- a/docs/snippets/common/button-story-argtypes-with-subcategories.js.mdx +++ b/docs/snippets/common/button-story-argtypes-with-subcategories.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-controls-primary-variant.js.mdx b/docs/snippets/common/button-story-controls-primary-variant.js.mdx index 8a5d6615f6f3..f36addd2d26d 100644 --- a/docs/snippets/common/button-story-controls-primary-variant.js.mdx +++ b/docs/snippets/common/button-story-controls-primary-variant.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx const Primary = Template.bind({}); Primary.args = { diff --git a/docs/snippets/common/button-story-controls-radio-group.js.mdx b/docs/snippets/common/button-story-controls-radio-group.js.mdx index fa59e415b90a..1806575b7996 100644 --- a/docs/snippets/common/button-story-controls-radio-group.js.mdx +++ b/docs/snippets/common/button-story-controls-radio-group.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-default-export.js.mdx b/docs/snippets/common/button-story-default-export.js.mdx index deb7867e2ef1..ec2b02425fd7 100644 --- a/docs/snippets/common/button-story-default-export.js.mdx +++ b/docs/snippets/common/button-story-default-export.js.mdx @@ -1,7 +1,7 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { - title: 'Button' -} + title: 'Button', +}; ``` \ No newline at end of file diff --git a/docs/snippets/common/button-story-disable-addon.js.mdx b/docs/snippets/common/button-story-disable-addon.js.mdx index e413e812141c..84656a63b51e 100644 --- a/docs/snippets/common/button-story-disable-addon.js.mdx +++ b/docs/snippets/common/button-story-disable-addon.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-disable-docspage-component.js.mdx b/docs/snippets/common/button-story-disable-docspage-component.js.mdx index 08d0f98ad4f0..9acd2461f7ba 100644 --- a/docs/snippets/common/button-story-disable-docspage-component.js.mdx +++ b/docs/snippets/common/button-story-disable-docspage-component.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx import { Button } from './Button'; diff --git a/docs/snippets/common/button-story-docs-code-type.js.mdx b/docs/snippets/common/button-story-docs-code-type.js.mdx index 10357521bce4..c4130f7d16f2 100644 --- a/docs/snippets/common/button-story-docs-code-type.js.mdx +++ b/docs/snippets/common/button-story-docs-code-type.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', @@ -10,7 +10,7 @@ export default { parameters: { docs: { source: { - type: 'code' + type: 'code', } } } diff --git a/docs/snippets/common/button-story-docspage-with-custom-component.js.mdx b/docs/snippets/common/button-story-docspage-with-custom-component.js.mdx index cc24230dd019..1cfd5c698d85 100644 --- a/docs/snippets/common/button-story-docspage-with-custom-component.js.mdx +++ b/docs/snippets/common/button-story-docspage-with-custom-component.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx import { Button } from './Button'; diff --git a/docs/snippets/common/button-story-docspage-with-mdx.js.mdx b/docs/snippets/common/button-story-docspage-with-mdx.js.mdx index a75971cf2d92..e81d979d98cf 100644 --- a/docs/snippets/common/button-story-docspage-with-mdx.js.mdx +++ b/docs/snippets/common/button-story-docspage-with-mdx.js.mdx @@ -1,6 +1,5 @@ ```js - -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx import { Button } from './Button'; diff --git a/docs/snippets/common/button-story-grouped.js.mdx b/docs/snippets/common/button-story-grouped.js.mdx index e08768ce609c..94c157e22f0d 100644 --- a/docs/snippets/common/button-story-grouped.js.mdx +++ b/docs/snippets/common/button-story-grouped.js.mdx @@ -1,7 +1,7 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { - title: 'Design System/Atoms/Button' -} + title: 'Design System/Atoms/Button', +}; ``` \ No newline at end of file diff --git a/docs/snippets/common/button-story-hide-nocontrols-warning.js.mdx b/docs/snippets/common/button-story-hide-nocontrols-warning.js.mdx index dbabf7734b1e..bee9dd999ac9 100644 --- a/docs/snippets/common/button-story-hide-nocontrols-warning.js.mdx +++ b/docs/snippets/common/button-story-hide-nocontrols-warning.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const Large = Template.bind({}); diff --git a/docs/snippets/common/button-story-hoisted.js.mdx b/docs/snippets/common/button-story-hoisted.js.mdx index 1facba381002..f47bd55e388b 100644 --- a/docs/snippets/common/button-story-hoisted.js.mdx +++ b/docs/snippets/common/button-story-hoisted.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx import { Button as ButtonComponent } from './Button'; diff --git a/docs/snippets/common/button-story-matching-argtypes.js.mdx b/docs/snippets/common/button-story-matching-argtypes.js.mdx index c3e034294ec3..d2b13c760c9a 100644 --- a/docs/snippets/common/button-story-matching-argtypes.js.mdx +++ b/docs/snippets/common/button-story-matching-argtypes.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-onclick-action-argtype.js.mdx b/docs/snippets/common/button-story-onclick-action-argtype.js.mdx index b43af8fd9dca..4b6fd2c0735e 100644 --- a/docs/snippets/common/button-story-onclick-action-argtype.js.mdx +++ b/docs/snippets/common/button-story-onclick-action-argtype.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/button-story-primary-composition.js.mdx b/docs/snippets/common/button-story-primary-composition.js.mdx index 63332e4c58ea..17aaf25b50f3 100644 --- a/docs/snippets/common/button-story-primary-composition.js.mdx +++ b/docs/snippets/common/button-story-primary-composition.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx const Primary = ButtonStory.bind({}); Primary.args = { diff --git a/docs/snippets/common/button-story-primary-long-name.js.mdx b/docs/snippets/common/button-story-primary-long-name.js.mdx index 8c6473ff8512..265e78970bf2 100644 --- a/docs/snippets/common/button-story-primary-long-name.js.mdx +++ b/docs/snippets/common/button-story-primary-long-name.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const PrimaryLongName = Template.bind({}); diff --git a/docs/snippets/common/button-story-remix-docspage.js.mdx b/docs/snippets/common/button-story-remix-docspage.js.mdx index f081164723dd..3543dff88f8e 100644 --- a/docs/snippets/common/button-story-remix-docspage.js.mdx +++ b/docs/snippets/common/button-story-remix-docspage.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx import React from 'react'; diff --git a/docs/snippets/common/button-story-remix-docspage.ts.mdx b/docs/snippets/common/button-story-remix-docspage.ts.mdx index ed56362b453e..0fc74186b286 100644 --- a/docs/snippets/common/button-story-remix-docspage.ts.mdx +++ b/docs/snippets/common/button-story-remix-docspage.ts.mdx @@ -1,5 +1,5 @@ ```ts -// Button.stories.tsx +// Button.stories.ts | Button.stories.tsx import React from 'react'; diff --git a/docs/snippets/common/button-story-with-parameters.js.mdx b/docs/snippets/common/button-story-with-parameters.js.mdx index 6d825b6920da..0664a5d6e430 100644 --- a/docs/snippets/common/button-story-with-parameters.js.mdx +++ b/docs/snippets/common/button-story-with-parameters.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const Primary = Template.bind({}); Primary.args ={ diff --git a/docs/snippets/common/checkbox-story-csf.js.mdx b/docs/snippets/common/checkbox-story-csf.js.mdx index bd693ded4c3f..4a114f056add 100644 --- a/docs/snippets/common/checkbox-story-csf.js.mdx +++ b/docs/snippets/common/checkbox-story-csf.js.mdx @@ -1,11 +1,11 @@ ```js -// Checkbox.stories.js +// Checkbox.stories.js | Checkbox.stories.jsx import { Checkbox } from './Checkbox'; export default { - title: 'MDX/Checkbox', - component: Checkbox + title: 'MDX/Checkbox', + component: Checkbox, }; const Template = (args) => diff --git a/docs/snippets/common/checkbox-story-grouped.js.mdx b/docs/snippets/common/checkbox-story-grouped.js.mdx index 9d9a5febc842..86c94be35218 100644 --- a/docs/snippets/common/checkbox-story-grouped.js.mdx +++ b/docs/snippets/common/checkbox-story-grouped.js.mdx @@ -1,7 +1,7 @@ ```js -// Checkbox.stories.js | Checkbox.stories.ts +// Checkbox.stories.js | Checkbox.stories.jsx | Checkbox.stories.ts | Checkbox.stories.tsx export default { - title: 'Design System/Atoms/Checkbox' -} + title: 'Design System/Atoms/Checkbox', +}; ``` \ No newline at end of file diff --git a/docs/snippets/common/component-story-csf-argstable-customization.js.mdx b/docs/snippets/common/component-story-csf-argstable-customization.js.mdx index 5ec147578992..cb343482cbec 100644 --- a/docs/snippets/common/component-story-csf-argstable-customization.js.mdx +++ b/docs/snippets/common/component-story-csf-argstable-customization.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/component-story-csf-description.js.mdx b/docs/snippets/common/component-story-csf-description.js.mdx index a4072d78927c..846e38ef6da0 100644 --- a/docs/snippets/common/component-story-csf-description.js.mdx +++ b/docs/snippets/common/component-story-csf-description.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'CustomDescription', diff --git a/docs/snippets/common/component-story-custom-args-mapping.js.mdx b/docs/snippets/common/component-story-custom-args-mapping.js.mdx index e10a61d9eb7c..c80bbf2f0862 100644 --- a/docs/snippets/common/component-story-custom-args-mapping.js.mdx +++ b/docs/snippets/common/component-story-custom-args-mapping.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx import { Button } from './button'; import { ArrowUp, ArrowDown, ArrowLeft, ArrowRight } from './icons'; diff --git a/docs/snippets/common/component-story-custom-source.js.mdx b/docs/snippets/common/component-story-custom-source.js.mdx index 353c4e972595..44ea73c129a2 100644 --- a/docs/snippets/common/component-story-custom-source.js.mdx +++ b/docs/snippets/common/component-story-custom-source.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const CustomSource = () => Template.bind({}); diff --git a/docs/snippets/common/component-story-disable-controls-alt.js.mdx b/docs/snippets/common/component-story-disable-controls-alt.js.mdx index 7778a6fab407..9d208e4b5447 100644 --- a/docs/snippets/common/component-story-disable-controls-alt.js.mdx +++ b/docs/snippets/common/component-story-disable-controls-alt.js.mdx @@ -1,5 +1,5 @@ ```js -// YourComponent.stories.js | YourComponent.stories.ts +// YourComponent.stories.js | YourComponent.stories.jsx | YourComponent.stories.ts | YourComponent.stories.tsx import { YourComponent } from './your-component' diff --git a/docs/snippets/common/component-story-disable-controls-regex.js.mdx b/docs/snippets/common/component-story-disable-controls-regex.js.mdx index a9f303658197..f2c55298d61e 100644 --- a/docs/snippets/common/component-story-disable-controls-regex.js.mdx +++ b/docs/snippets/common/component-story-disable-controls-regex.js.mdx @@ -1,5 +1,5 @@ ```js -// YourComponent.stories.js | YourComponent.stories.ts +// YourComponent.stories.js | YourComponent.stories.jsx | YourComponent.stories.ts | YourComponent.stories.tsx ArrayInclude = Template.bind({}) ArrayInclude.parameters = { controls: { include: ['foo', 'bar'] } }; diff --git a/docs/snippets/common/component-story-disable-controls.js.mdx b/docs/snippets/common/component-story-disable-controls.js.mdx index 818ea786e7bf..02494573a959 100644 --- a/docs/snippets/common/component-story-disable-controls.js.mdx +++ b/docs/snippets/common/component-story-disable-controls.js.mdx @@ -1,5 +1,5 @@ ```js -// YourComponent.stories.js | YourComponent.stories.ts +// YourComponent.stories.js | YourComponent.stories.jsx | YourComponent.stories.ts | YourComponent.stories.tsx import { YourComponent } from './your-component' diff --git a/docs/snippets/common/component-story-dynamic-title.js.mdx b/docs/snippets/common/component-story-dynamic-title.js.mdx index 47d464d21335..7a0d96736792 100644 --- a/docs/snippets/common/component-story-dynamic-title.js.mdx +++ b/docs/snippets/common/component-story-dynamic-title.js.mdx @@ -1,5 +1,5 @@ ```js -// MyComponent.stories.js | MyComponent.stories.ts +// MyComponent.stories.js | MyComponent.stories.jsx | MyComponent.stories.ts | MyComponent.stories.tsx import base from 'paths.macro'; diff --git a/docs/snippets/common/component-story-mdx-argstable-block.mdx.mdx b/docs/snippets/common/component-story-mdx-argstable-block-for-component.mdx.mdx similarity index 100% rename from docs/snippets/common/component-story-mdx-argstable-block.mdx.mdx rename to docs/snippets/common/component-story-mdx-argstable-block-for-component.mdx.mdx diff --git a/docs/snippets/common/component-story-mdx-argstable-block-for-story.mdx.mdx b/docs/snippets/common/component-story-mdx-argstable-block-for-story.mdx.mdx new file mode 100644 index 000000000000..8808665b07a1 --- /dev/null +++ b/docs/snippets/common/component-story-mdx-argstable-block-for-story.mdx.mdx @@ -0,0 +1,15 @@ +```md + + +import { ArgsTable } from '@storybook/addon-docs'; +import { MyComponent } from './MyComponent'; + +# My Component! + + + + {(args) => } + + + +``` diff --git a/docs/snippets/common/component-story-sort-controls.js.mdx b/docs/snippets/common/component-story-sort-controls.js.mdx index 6a816951b85a..65f4ee7f9ae6 100644 --- a/docs/snippets/common/component-story-sort-controls.js.mdx +++ b/docs/snippets/common/component-story-sort-controls.js.mdx @@ -1,5 +1,5 @@ ```js -// YourComponent.stories.js | YourComponent.stories.ts +// YourComponent.stories.js | YourComponent.stories.jsx | YourComponent.stories.ts | YourComponent.stories.tsx import { YourComponent } from './your-component' diff --git a/docs/snippets/common/custom-docs-page.ts-component.ts.mdx b/docs/snippets/common/custom-docs-page.ts-component.ts.mdx index af66d57a8e2b..402274308b79 100644 --- a/docs/snippets/common/custom-docs-page.ts-component.ts.mdx +++ b/docs/snippets/common/custom-docs-page.ts-component.ts.mdx @@ -3,7 +3,7 @@ import React from 'react'; -export const CustomDocumentationComponent: React.FC<{}> = () => { +export const CustomDocumentationComponent: React.VFC<{}> = () => { return (

Replacing DocsPage with a custom component

diff --git a/docs/snippets/common/foo-bar-baz-story.js.mdx b/docs/snippets/common/foo-bar-baz-story.js.mdx index 3e87aad910f8..5815debcec68 100644 --- a/docs/snippets/common/foo-bar-baz-story.js.mdx +++ b/docs/snippets/common/foo-bar-baz-story.js.mdx @@ -1,5 +1,5 @@ ```js -// FooBar.stories.js | FooBar.stories.ts +// FooBar.stories.js | FooBar.stories.jsx | FooBar.stories.ts | FooBar.stories.tsx export default { title: 'Foo/Bar', diff --git a/docs/snippets/common/gizmo-story-controls-customization.js.mdx b/docs/snippets/common/gizmo-story-controls-customization.js.mdx index 1b090b4d1403..36501155756d 100644 --- a/docs/snippets/common/gizmo-story-controls-customization.js.mdx +++ b/docs/snippets/common/gizmo-story-controls-customization.js.mdx @@ -1,5 +1,5 @@ ```js -// Gizmo.stories.js | Gizmo.stories.ts +// Gizmo.stories.js | Gizmo.stories.jsx | Gizmo.stories.ts | Gizmo.stories.tsx export default { title: 'Gizmo', diff --git a/docs/snippets/common/my-component-story-import-json.js.mdx b/docs/snippets/common/my-component-story-import-json.js.mdx index 9265c9d195ce..56b0e6431166 100644 --- a/docs/snippets/common/my-component-story-import-json.js.mdx +++ b/docs/snippets/common/my-component-story-import-json.js.mdx @@ -1,5 +1,5 @@ ```js -// MyComponent.stories.js | MyComponent.stories.ts +// MyComponent.stories.js | MyComponent.stories.jsx | MyComponent.stories.ts | MyComponent.stories.tsx // This will automatically be parsed to the contents of `data.json` import data from './data.json'; diff --git a/docs/snippets/common/my-component-story-import-static-asset.js.mdx b/docs/snippets/common/my-component-story-import-static-asset.js.mdx index 816ad32dc8b1..8aa950ac4c07 100644 --- a/docs/snippets/common/my-component-story-import-static-asset.js.mdx +++ b/docs/snippets/common/my-component-story-import-static-asset.js.mdx @@ -1,5 +1,5 @@ ```js -// MyComponent.stories.js | MyComponent.stories.ts +// MyComponent.stories.js | MyComponent.stories.jsx | MyComponent.stories.ts | MyComponent.stories.tsx // This will include './static/image.png' in the bundle. // And return a path to be included in a src attribute diff --git a/docs/snippets/common/my-component-story-mandatory-export.js.mdx b/docs/snippets/common/my-component-story-mandatory-export.js.mdx index 4ec694947a11..3aa3727adb73 100644 --- a/docs/snippets/common/my-component-story-mandatory-export.js.mdx +++ b/docs/snippets/common/my-component-story-mandatory-export.js.mdx @@ -1,5 +1,5 @@ ```js -// MyComponent.story.js +// MyComponent.story.js | MyComponent.story.jsx | MyComponent.story.ts | MyComponent.story.tsx import MyComponent from './MyComponent'; diff --git a/docs/snippets/common/my-component-story-with-storyname.js.mdx b/docs/snippets/common/my-component-story-with-storyname.js.mdx index 1b02fba82219..612c7e0478a2 100644 --- a/docs/snippets/common/my-component-story-with-storyname.js.mdx +++ b/docs/snippets/common/my-component-story-with-storyname.js.mdx @@ -1,5 +1,5 @@ ```js -// MyComponent.stories.js +// MyComponent.story.js | MyComponent.story.jsx | MyComponent.story.ts | MyComponent.story.tsx export const Simple = () => ; diff --git a/docs/snippets/common/my-component-story.js.mdx b/docs/snippets/common/my-component-story.js.mdx index 7bef33659bc4..0adef68983c9 100644 --- a/docs/snippets/common/my-component-story.js.mdx +++ b/docs/snippets/common/my-component-story.js.mdx @@ -1,5 +1,5 @@ ```js -// MyComponent.stories.js | MyComponent.stories.ts +// MyComponent.stories.js | MyComponent.stories.jsx | MyComponent.stories.ts | MyComponent.stories.tsx import { MyComponent } from './MyComponent'; diff --git a/docs/snippets/common/other-foo-bar-story.js.mdx b/docs/snippets/common/other-foo-bar-story.js.mdx index 65ba2e3bac9c..482d8a60e39b 100644 --- a/docs/snippets/common/other-foo-bar-story.js.mdx +++ b/docs/snippets/common/other-foo-bar-story.js.mdx @@ -1,5 +1,5 @@ ```js -// FooBar.stories.js | FooBar.stories.ts +// FooBar.stories.js | FooBar.stories.jsx | FooBar.stories.ts | FooBar.stories.tsx export default { title: 'OtherFoo/Bar', diff --git a/docs/snippets/common/storybook-addon-backgrounds-configure-backgrounds.js.mdx b/docs/snippets/common/storybook-addon-backgrounds-configure-backgrounds.js.mdx index 7db76a4ecf58..77d4cd2084a8 100644 --- a/docs/snippets/common/storybook-addon-backgrounds-configure-backgrounds.js.mdx +++ b/docs/snippets/common/storybook-addon-backgrounds-configure-backgrounds.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx // To apply a set of backgrounds to all stories of Button: export default { diff --git a/docs/snippets/common/storybook-addon-backgrounds-configure-grid.js.mdx b/docs/snippets/common/storybook-addon-backgrounds-configure-grid.js.mdx index 12af04ed3de0..6f321c920850 100644 --- a/docs/snippets/common/storybook-addon-backgrounds-configure-grid.js.mdx +++ b/docs/snippets/common/storybook-addon-backgrounds-configure-grid.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx // To apply a grid to all stories of Button: export default { diff --git a/docs/snippets/common/storybook-addon-backgrounds-disable-backgrounds.js.mdx b/docs/snippets/common/storybook-addon-backgrounds-disable-backgrounds.js.mdx index 114e733b8d5a..6ff2e2b676a1 100644 --- a/docs/snippets/common/storybook-addon-backgrounds-disable-backgrounds.js.mdx +++ b/docs/snippets/common/storybook-addon-backgrounds-disable-backgrounds.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const Large = Template.bind({}); Large.parameters = { diff --git a/docs/snippets/common/storybook-addon-backgrounds-disable-grid.js.mdx b/docs/snippets/common/storybook-addon-backgrounds-disable-grid.js.mdx index 32191fc1cd16..2946c92062b9 100644 --- a/docs/snippets/common/storybook-addon-backgrounds-disable-grid.js.mdx +++ b/docs/snippets/common/storybook-addon-backgrounds-disable-grid.js.mdx @@ -1,11 +1,11 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const Large = Template.bind({}); Large.parameters = { backgrounds: { grid: { - disable: true + disable: true, } } }; diff --git a/docs/snippets/common/storybook-addon-backgrounds-override-background-color.js.mdx b/docs/snippets/common/storybook-addon-backgrounds-override-background-color.js.mdx index 7b3832caa637..c11b02c7a26e 100644 --- a/docs/snippets/common/storybook-addon-backgrounds-override-background-color.js.mdx +++ b/docs/snippets/common/storybook-addon-backgrounds-override-background-color.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const Large = Template.bind({}); Large.parameters = { diff --git a/docs/snippets/common/storybook-component-layout-param.js.mdx b/docs/snippets/common/storybook-component-layout-param.js.mdx index d1f4ba54cede..36098b96b765 100644 --- a/docs/snippets/common/storybook-component-layout-param.js.mdx +++ b/docs/snippets/common/storybook-component-layout-param.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx import Button from './Button'; diff --git a/docs/snippets/common/storybook-customize-argtypes.js.mdx b/docs/snippets/common/storybook-customize-argtypes.js.mdx index 38972b03a1b6..7a45d3876c17 100644 --- a/docs/snippets/common/storybook-customize-argtypes.js.mdx +++ b/docs/snippets/common/storybook-customize-argtypes.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export default { title: 'Button', diff --git a/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx b/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx index 42e775d4df3a..fb0cd405ac72 100644 --- a/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx +++ b/docs/snippets/common/storybook-preview-configure-globaltypes.js.mdx @@ -11,8 +11,8 @@ export const globalTypes = { // Array of plain string values or MenuItem shape (see below) items: ['light', 'dark'], // Property that specifies if the name of the item will be displayed - showName: True, + showName: true, }, }, }; -``` \ No newline at end of file +``` diff --git a/docs/snippets/svelte/storybook-preview-global-loader.js.mdx b/docs/snippets/common/storybook-preview-global-loader.js.mdx similarity index 54% rename from docs/snippets/svelte/storybook-preview-global-loader.js.mdx rename to docs/snippets/common/storybook-preview-global-loader.js.mdx index 8c10b6a19050..2b7d8f057d48 100644 --- a/docs/snippets/svelte/storybook-preview-global-loader.js.mdx +++ b/docs/snippets/common/storybook-preview-global-loader.js.mdx @@ -5,7 +5,7 @@ import fetch from 'node-fetch'; export const loaders = [ async () => ({ - currentUser: (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(), + currentUser: await (await fetch('https://jsonplaceholder.typicode.com/users/1')).json(), }), ]; ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-story-layout-param.js.mdx b/docs/snippets/common/storybook-story-layout-param.js.mdx index d39352bab539..66669c9585ec 100644 --- a/docs/snippets/common/storybook-story-layout-param.js.mdx +++ b/docs/snippets/common/storybook-story-layout-param.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js | Button.stories.ts +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const WithLayout = Template.bind({}); WithLayout.parameters = { diff --git a/docs/snippets/preact/button-test.js.mdx b/docs/snippets/preact/button-test.js.mdx new file mode 100644 index 000000000000..2c1889942549 --- /dev/null +++ b/docs/snippets/preact/button-test.js.mdx @@ -0,0 +1,17 @@ +```js +// Button.test.js + +import { h } from 'preact'; + +import { render, screen } from '@testing-library/preact'; + +import '@testing-library/jest-dom/extend-expect'; + +//👇 Imports a specific story for the test +import { Primary } from './Button.stories'; + +it('renders the button in the primary state', () => { + render(); + expect(screen.getByRole('button')).toHaveTextContent('Primary'); +}); +``` diff --git a/docs/snippets/react/app-story-with-mock.js.mdx b/docs/snippets/react/app-story-with-mock.js.mdx index d39a3953d2c6..db4426bd71b5 100644 --- a/docs/snippets/react/app-story-with-mock.js.mdx +++ b/docs/snippets/react/app-story-with-mock.js.mdx @@ -1,5 +1,5 @@ ```js -// App.stories.js +// App.stories.js | App.stories.jsx | App.stories.ts | App.stories.tsx import React from 'react'; diff --git a/docs/snippets/react/button-component-with-proptypes.js.mdx b/docs/snippets/react/button-component-with-proptypes.js.mdx index a89b0a8fe460..c0ed93eee7ac 100644 --- a/docs/snippets/react/button-component-with-proptypes.js.mdx +++ b/docs/snippets/react/button-component-with-proptypes.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.js +// Button.js | Button.jsx import React from 'react'; diff --git a/docs/snippets/react/button-component-with-proptypes.ts.mdx b/docs/snippets/react/button-component-with-proptypes.ts.mdx index 8d36c40cb46f..9086f82d0201 100644 --- a/docs/snippets/react/button-component-with-proptypes.ts.mdx +++ b/docs/snippets/react/button-component-with-proptypes.ts.mdx @@ -1,5 +1,5 @@ ```ts -// Button.tsx +// Button.ts | Button.tsx import React from 'react'; diff --git a/docs/snippets/react/button-group-story.js.mdx b/docs/snippets/react/button-group-story.js.mdx index 68509b2b1728..7b033e48af4c 100644 --- a/docs/snippets/react/button-group-story.js.mdx +++ b/docs/snippets/react/button-group-story.js.mdx @@ -1,5 +1,5 @@ ```js -// ButtonGroup.stories.js +// ButtonGroup.stories.js | ButtonGroup.stories.jsx import React from 'react'; diff --git a/docs/snippets/react/button-group-story.ts.mdx b/docs/snippets/react/button-group-story.ts.mdx index cfb2f5281292..b6bcf985a34f 100644 --- a/docs/snippets/react/button-group-story.ts.mdx +++ b/docs/snippets/react/button-group-story.ts.mdx @@ -1,5 +1,5 @@ ```ts -// ButtonGroup.stories.tsx +// ButtonGroup.stories.ts | ButtonGroup.stories.tsx import React from 'react'; diff --git a/docs/snippets/react/button-implementation.js.mdx b/docs/snippets/react/button-implementation.js.mdx index 45135e517751..b45bca83ecde 100644 --- a/docs/snippets/react/button-implementation.js.mdx +++ b/docs/snippets/react/button-implementation.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.js +// Button.js | Button.jsx import React from 'react'; diff --git a/docs/snippets/react/button-implementation.ts.mdx b/docs/snippets/react/button-implementation.ts.mdx index 34ff8b42a2b0..8d406fcfb038 100644 --- a/docs/snippets/react/button-implementation.ts.mdx +++ b/docs/snippets/react/button-implementation.ts.mdx @@ -1,5 +1,5 @@ ```ts -// Button.ts +// Button.ts | Button.tsx import React from 'react'; diff --git a/docs/snippets/react/button-story-click-handler-args.js.mdx b/docs/snippets/react/button-story-click-handler-args.js.mdx index e9ceab29ccca..e35cfba2a78e 100644 --- a/docs/snippets/react/button-story-click-handler-args.js.mdx +++ b/docs/snippets/react/button-story-click-handler-args.js.mdx @@ -1,5 +1,5 @@ ```js -// Button.stories.js +// Button.stories.js | Button.stories.jsx | Button.stories.ts | Button.stories.tsx export const Text = ({ label, onClick }) =>