From e729092d7c260289a20daafc2452ad2b40b056da Mon Sep 17 00:00:00 2001 From: Andy Wilson <31218527+The-Code-Monkey@users.noreply.github.com> Date: Fri, 6 May 2022 10:52:43 +0100 Subject: [PATCH 01/69] security: update x-default-browser --- lib/core-client/src/typings.d.ts | 1 - lib/core-server/package.json | 4 +-- yarn.lock | 58 ++++++++++++++------------------ 3 files changed, 28 insertions(+), 35 deletions(-) diff --git a/lib/core-client/src/typings.d.ts b/lib/core-client/src/typings.d.ts index 0a7386c391b..67ea5135824 100644 --- a/lib/core-client/src/typings.d.ts +++ b/lib/core-client/src/typings.d.ts @@ -6,6 +6,5 @@ declare module 'pnp-webpack-plugin'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module 'x-default-browser'; declare module '@storybook/ui'; diff --git a/lib/core-server/package.json b/lib/core-server/package.json index 61d89bf4ab7..a03df017f1b 100644 --- a/lib/core-server/package.json +++ b/lib/core-server/package.json @@ -39,6 +39,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { + "@aw-web-design/x-default-browser": "1.2.0", "@discoveryjs/json-ext": "^0.5.3", "@storybook/builder-webpack4": "6.5.0-beta.6", "@storybook/core-client": "6.5.0-beta.6", @@ -82,8 +83,7 @@ "util-deprecate": "^1.0.2", "watchpack": "^2.2.0", "webpack": "4", - "ws": "^8.2.3", - "x-default-browser": "^0.4.0" + "ws": "^8.2.3" }, "devDependencies": { "@storybook/builder-webpack5": "6.5.0-beta.6", diff --git a/yarn.lock b/yarn.lock index b381d54adcc..4fc155e48b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -375,6 +375,17 @@ __metadata: languageName: node linkType: hard +"@aw-web-design/x-default-browser@npm:1.2.0": + version: 1.2.0 + resolution: "@aw-web-design/x-default-browser@npm:1.2.0" + dependencies: + default-browser-id: 3.0.0 + bin: + xdb: dist/esm/bin/x-default-browser.js + checksum: deacfedfe90b63bd31f9d835d90504b8d1af68728e3594b7a1011b3253689343073b0b855bf19a301eda7ee87d6706f7802c7293051c1d366e4457b86dcb0490 + languageName: node + linkType: hard + "@axe-core/puppeteer@npm:^4.2.0": version: 4.4.0 resolution: "@axe-core/puppeteer@npm:4.4.0" @@ -7655,6 +7666,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/core-server@workspace:lib/core-server" dependencies: + "@aw-web-design/x-default-browser": 1.2.0 "@discoveryjs/json-ext": ^0.5.3 "@storybook/builder-webpack4": 6.5.0-beta.6 "@storybook/builder-webpack5": 6.5.0-beta.6 @@ -7705,7 +7717,6 @@ __metadata: watchpack: ^2.2.0 webpack: 4 ws: ^8.2.3 - x-default-browser: ^0.4.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -14763,7 +14774,7 @@ __metadata: languageName: node linkType: hard -"big-integer@npm:^1.6.7": +"big-integer@npm:^1.6.44": version: 1.6.51 resolution: "big-integer@npm:1.6.51" checksum: c8139662d57f8833a44802f4b65be911679c569535ea73c5cfd3c1c8994eaead1b84b6f63e1db63833e4d4cacb6b6a9e5522178113dfdc8e4c81ed8436f1e8cc @@ -14993,12 +15004,12 @@ __metadata: languageName: node linkType: hard -"bplist-parser@npm:^0.1.0": - version: 0.1.1 - resolution: "bplist-parser@npm:0.1.1" +"bplist-parser@npm:^0.2.0": + version: 0.2.0 + resolution: "bplist-parser@npm:0.2.0" dependencies: - big-integer: ^1.6.7 - checksum: cd50206f956e74f6e46cb5ed14be5eb00b2e14676ea3dd36703470715177a2770fc22032eca63a36adb3b56a1e51138a95bb0fc6849a78c21e92caeedf219ea7 + big-integer: ^1.6.44 + checksum: ce79c69e0f6efe506281e7c84e3712f7d12978991675b6e3a58a295b16f13ca81aa9b845c335614a545e0af728c8311b6aa3142af76ba1cb616af9bbac5c4a9f languageName: node linkType: hard @@ -19254,16 +19265,13 @@ __metadata: languageName: node linkType: hard -"default-browser-id@npm:^1.0.4": - version: 1.0.4 - resolution: "default-browser-id@npm:1.0.4" +"default-browser-id@npm:3.0.0": + version: 3.0.0 + resolution: "default-browser-id@npm:3.0.0" dependencies: - bplist-parser: ^0.1.0 - meow: ^3.1.0 - untildify: ^2.0.0 - bin: - default-browser-id: cli.js - checksum: a00a2ab66beab70490b4d76258a1f2eadfadca6414bf67ab78aa25b33dc3de0c4c813bb8f204271aa7a08281c39474487db0229e325112456464fb97a0522a8a + bplist-parser: ^0.2.0 + untildify: ^4.0.0 + checksum: 8db3ab882eb3e1e8b59d84c8641320e6c66d8eeb17eb4bb848b7dd549b1e6fd313988e4a13542e95fbaeff03f6e9dedc5ad191ad4df7996187753eb0d45c00b7 languageName: node linkType: hard @@ -31675,7 +31683,7 @@ __metadata: languageName: node linkType: hard -"meow@npm:^3.1.0, meow@npm:^3.3.0": +"meow@npm:^3.3.0": version: 3.7.0 resolution: "meow@npm:3.7.0" dependencies: @@ -45110,7 +45118,7 @@ __metadata: languageName: node linkType: hard -"untildify@npm:^2.0.0, untildify@npm:^2.1.0": +"untildify@npm:^2.1.0": version: 2.1.0 resolution: "untildify@npm:2.1.0" dependencies: @@ -47672,20 +47680,6 @@ __metadata: languageName: node linkType: hard -"x-default-browser@npm:^0.4.0": - version: 0.4.0 - resolution: "x-default-browser@npm:0.4.0" - dependencies: - default-browser-id: ^1.0.4 - dependenciesMeta: - default-browser-id: - optional: true - bin: - x-default-browser: bin/x-default-browser.js - checksum: a19e42ffeab19560ea05a423561f5b3b82bb3a5878dc932cfd0847fadc5890b8b685d6b39e2356c8304b3943f5a7120ba4b233365d686ff8f9bf2499ce11f052 - languageName: node - linkType: hard - "xdg-basedir@npm:^4.0.0": version: 4.0.0 resolution: "xdg-basedir@npm:4.0.0" From 4a20068b897923cf2f24321e587a7219854ba4e9 Mon Sep 17 00:00:00 2001 From: Andy Wilson <31218527+The-Code-Monkey@users.noreply.github.com> Date: Fri, 6 May 2022 12:36:45 +0100 Subject: [PATCH 02/69] fix: hopefully all works well as had to implement async --- lib/core-client/src/typings.d.ts | 3 +- lib/core-server/src/utils/open-in-browser.ts | 32 +++++++++++--------- lib/core-server/typings.d.ts | 1 - lib/manager-webpack4/typings.d.ts | 1 - lib/manager-webpack5/typings.d.ts | 1 - 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/lib/core-client/src/typings.d.ts b/lib/core-client/src/typings.d.ts index 67ea5135824..5ac3ee603b6 100644 --- a/lib/core-client/src/typings.d.ts +++ b/lib/core-client/src/typings.d.ts @@ -6,5 +6,4 @@ declare module 'pnp-webpack-plugin'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module '@storybook/ui'; - +declare module '@storybook/ui'; \ No newline at end of file diff --git a/lib/core-server/src/utils/open-in-browser.ts b/lib/core-server/src/utils/open-in-browser.ts index daa5938b3f0..ff46b6678fb 100644 --- a/lib/core-server/src/utils/open-in-browser.ts +++ b/lib/core-server/src/utils/open-in-browser.ts @@ -1,25 +1,27 @@ import { logger } from '@storybook/node-logger'; import betterOpn from 'better-opn'; // betterOpn alias used because also loading open import open from 'open'; -import getDefaultBrowser from 'x-default-browser'; +import getDefaultBrowser from '@aw-web-design/x-default-browser'; import dedent from 'ts-dedent'; -export function openInBrowser(address: string) { - getDefaultBrowser(async (err: any, res: any) => { - try { - if (res.isChrome || res.isChromium) { - // We use betterOpn for Chrome because it is better at handling which chrome tab - // or window the preview loads in. - betterOpn(address); - } else { - await open(address); - } - } catch (error) { - logger.error(dedent` +export async function openInBrowser(address: string) { + await getDefaultBrowser.then((fn) => + fn(async (err: any, res: any) => { + try { + if (res.isChrome || res.isChromium) { + // We use betterOpn for Chrome because it is better at handling which chrome tab + // or window the preview loads in. + betterOpn(address); + } else { + await open(address); + } + } catch (error) { + logger.error(dedent` Could not open ${address} inside a browser. If you're running this command inside a docker container or on a CI, you need to pass the '--ci' flag to prevent opening a browser by default. `); - } - }); + } + }) + ); } diff --git a/lib/core-server/typings.d.ts b/lib/core-server/typings.d.ts index eeb489a5e71..a70d4619ac7 100644 --- a/lib/core-server/typings.d.ts +++ b/lib/core-server/typings.d.ts @@ -7,7 +7,6 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module 'x-default-browser'; declare module '@storybook/ui'; declare module '@discoveryjs/json-ext'; declare module 'watchpack'; diff --git a/lib/manager-webpack4/typings.d.ts b/lib/manager-webpack4/typings.d.ts index 894b889ada8..4519e450b9e 100644 --- a/lib/manager-webpack4/typings.d.ts +++ b/lib/manager-webpack4/typings.d.ts @@ -7,5 +7,4 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module 'x-default-browser'; declare module '@storybook/ui'; diff --git a/lib/manager-webpack5/typings.d.ts b/lib/manager-webpack5/typings.d.ts index 70fcabe6c3b..41985534004 100644 --- a/lib/manager-webpack5/typings.d.ts +++ b/lib/manager-webpack5/typings.d.ts @@ -6,5 +6,4 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module 'x-default-browser'; declare module '@storybook/ui'; From b98527fde4ad54d95bbf5be8c6fd0c80f1ed007c Mon Sep 17 00:00:00 2001 From: Andy Wilson <31218527+The-Code-Monkey@users.noreply.github.com> Date: Fri, 6 May 2022 13:06:33 +0100 Subject: [PATCH 03/69] Rename open-in-browser.ts to open-in-browser.cts --- .../src/utils/{open-in-browser.ts => open-in-browser.cts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/core-server/src/utils/{open-in-browser.ts => open-in-browser.cts} (100%) diff --git a/lib/core-server/src/utils/open-in-browser.ts b/lib/core-server/src/utils/open-in-browser.cts similarity index 100% rename from lib/core-server/src/utils/open-in-browser.ts rename to lib/core-server/src/utils/open-in-browser.cts From 07dda492af3e5a33c6f134dfbcf2b83f4b80f84c Mon Sep 17 00:00:00 2001 From: Andy Wilson <31218527+The-Code-Monkey@users.noreply.github.com> Date: Fri, 6 May 2022 15:03:41 +0100 Subject: [PATCH 04/69] fix: package to newer version --- lib/core-client/src/typings.d.ts | 1 + lib/core-server/package.json | 2 +- lib/core-server/src/utils/open-in-browser.ts | 36 +++++++++--------- lib/core-server/typings.d.ts | 1 + lib/manager-webpack4/typings.d.ts | 1 + lib/manager-webpack5/typings.d.ts | 1 + yarn.lock | 40 +++----------------- 7 files changed, 28 insertions(+), 54 deletions(-) diff --git a/lib/core-client/src/typings.d.ts b/lib/core-client/src/typings.d.ts index 5ac3ee603b6..bce6e8953b9 100644 --- a/lib/core-client/src/typings.d.ts +++ b/lib/core-client/src/typings.d.ts @@ -6,4 +6,5 @@ declare module 'pnp-webpack-plugin'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; +declare module '@aw-web-design/x-default-browser'; declare module '@storybook/ui'; \ No newline at end of file diff --git a/lib/core-server/package.json b/lib/core-server/package.json index a03df017f1b..868ea2096c8 100644 --- a/lib/core-server/package.json +++ b/lib/core-server/package.json @@ -39,7 +39,7 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@aw-web-design/x-default-browser": "1.2.0", + "@aw-web-design/x-default-browser": "1.4.0", "@discoveryjs/json-ext": "^0.5.3", "@storybook/builder-webpack4": "6.5.0-beta.6", "@storybook/core-client": "6.5.0-beta.6", diff --git a/lib/core-server/src/utils/open-in-browser.ts b/lib/core-server/src/utils/open-in-browser.ts index ff46b6678fb..82ab966a1f4 100644 --- a/lib/core-server/src/utils/open-in-browser.ts +++ b/lib/core-server/src/utils/open-in-browser.ts @@ -4,24 +4,22 @@ import open from 'open'; import getDefaultBrowser from '@aw-web-design/x-default-browser'; import dedent from 'ts-dedent'; -export async function openInBrowser(address: string) { - await getDefaultBrowser.then((fn) => - fn(async (err: any, res: any) => { - try { - if (res.isChrome || res.isChromium) { - // We use betterOpn for Chrome because it is better at handling which chrome tab - // or window the preview loads in. - betterOpn(address); - } else { - await open(address); - } - } catch (error) { - logger.error(dedent` - Could not open ${address} inside a browser. If you're running this command inside a - docker container or on a CI, you need to pass the '--ci' flag to prevent opening a - browser by default. - `); +export function openInBrowser(address: string) { + getDefaultBrowser(async (err: any, res: any) => { + try { + if (res.isChrome || res.isChromium) { + // We use betterOpn for Chrome because it is better at handling which chrome tab + // or window the preview loads in. + betterOpn(address); + } else { + await open(address); } - }) - ); + } catch (error) { + logger.error(dedent` + Could not open ${address} inside a browser. If you're running this command inside a + docker container or on a CI, you need to pass the '--ci' flag to prevent opening a + browser by default. + `); + } + }); } diff --git a/lib/core-server/typings.d.ts b/lib/core-server/typings.d.ts index a70d4619ac7..b539c76578d 100644 --- a/lib/core-server/typings.d.ts +++ b/lib/core-server/typings.d.ts @@ -7,6 +7,7 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; +declare module '@aw-web-design/x-default-browser'; declare module '@storybook/ui'; declare module '@discoveryjs/json-ext'; declare module 'watchpack'; diff --git a/lib/manager-webpack4/typings.d.ts b/lib/manager-webpack4/typings.d.ts index 4519e450b9e..6c5e278ef73 100644 --- a/lib/manager-webpack4/typings.d.ts +++ b/lib/manager-webpack4/typings.d.ts @@ -7,4 +7,5 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; +declare module '@aw-web-design/x-default-browser'; declare module '@storybook/ui'; diff --git a/lib/manager-webpack5/typings.d.ts b/lib/manager-webpack5/typings.d.ts index 41985534004..febd3228fce 100644 --- a/lib/manager-webpack5/typings.d.ts +++ b/lib/manager-webpack5/typings.d.ts @@ -6,4 +6,5 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; +declare module '@aw-web-design/x-default-browser'; declare module '@storybook/ui'; diff --git a/yarn.lock b/yarn.lock index 4fc155e48b1..2cada94c542 100644 --- a/yarn.lock +++ b/yarn.lock @@ -375,14 +375,12 @@ __metadata: languageName: node linkType: hard -"@aw-web-design/x-default-browser@npm:1.2.0": - version: 1.2.0 - resolution: "@aw-web-design/x-default-browser@npm:1.2.0" - dependencies: - default-browser-id: 3.0.0 +"@aw-web-design/x-default-browser@npm:1.4.0": + version: 1.4.0 + resolution: "@aw-web-design/x-default-browser@npm:1.4.0" bin: - xdb: dist/esm/bin/x-default-browser.js - checksum: deacfedfe90b63bd31f9d835d90504b8d1af68728e3594b7a1011b3253689343073b0b855bf19a301eda7ee87d6706f7802c7293051c1d366e4457b86dcb0490 + x-default-browser: bin/x-default-browser.js + checksum: 1e21253f5af8c9050a511bd4a8342e079f30f662caaa3155afa77474ce12ff014fe4d04859528ccddffd30fb6a4df60acebccc7b657b1639092516e50bb09a6c languageName: node linkType: hard @@ -7666,7 +7664,7 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/core-server@workspace:lib/core-server" dependencies: - "@aw-web-design/x-default-browser": 1.2.0 + "@aw-web-design/x-default-browser": 1.4.0 "@discoveryjs/json-ext": ^0.5.3 "@storybook/builder-webpack4": 6.5.0-beta.6 "@storybook/builder-webpack5": 6.5.0-beta.6 @@ -14774,13 +14772,6 @@ __metadata: languageName: node linkType: hard -"big-integer@npm:^1.6.44": - version: 1.6.51 - resolution: "big-integer@npm:1.6.51" - checksum: c8139662d57f8833a44802f4b65be911679c569535ea73c5cfd3c1c8994eaead1b84b6f63e1db63833e4d4cacb6b6a9e5522178113dfdc8e4c81ed8436f1e8cc - languageName: node - linkType: hard - "big.js@npm:^3.1.3": version: 3.2.0 resolution: "big.js@npm:3.2.0" @@ -15004,15 +14995,6 @@ __metadata: languageName: node linkType: hard -"bplist-parser@npm:^0.2.0": - version: 0.2.0 - resolution: "bplist-parser@npm:0.2.0" - dependencies: - big-integer: ^1.6.44 - checksum: ce79c69e0f6efe506281e7c84e3712f7d12978991675b6e3a58a295b16f13ca81aa9b845c335614a545e0af728c8311b6aa3142af76ba1cb616af9bbac5c4a9f - languageName: node - linkType: hard - "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -19265,16 +19247,6 @@ __metadata: languageName: node linkType: hard -"default-browser-id@npm:3.0.0": - version: 3.0.0 - resolution: "default-browser-id@npm:3.0.0" - dependencies: - bplist-parser: ^0.2.0 - untildify: ^4.0.0 - checksum: 8db3ab882eb3e1e8b59d84c8641320e6c66d8eeb17eb4bb848b7dd549b1e6fd313988e4a13542e95fbaeff03f6e9dedc5ad191ad4df7996187753eb0d45c00b7 - languageName: node - linkType: hard - "default-gateway@npm:^4.2.0": version: 4.2.0 resolution: "default-gateway@npm:4.2.0" From 5f9a806bbf7d23898e0161d2d219cfe51fd63181 Mon Sep 17 00:00:00 2001 From: Andy Wilson <31218527+The-Code-Monkey@users.noreply.github.com> Date: Fri, 6 May 2022 15:04:37 +0100 Subject: [PATCH 05/69] fix: package to newer version --- .../src/utils/{open-in-browser.cts => open-in-browser.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/core-server/src/utils/{open-in-browser.cts => open-in-browser.ts} (100%) diff --git a/lib/core-server/src/utils/open-in-browser.cts b/lib/core-server/src/utils/open-in-browser.ts similarity index 100% rename from lib/core-server/src/utils/open-in-browser.cts rename to lib/core-server/src/utils/open-in-browser.ts From 94c5203cec3f52ee7996c913fe154e5229eed10e Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 17 May 2022 17:04:47 +0100 Subject: [PATCH 06/69] Broken links checker tweaks --- .../workflows/markdown-link-check-config.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/markdown-link-check-config.json b/.github/workflows/markdown-link-check-config.json index df6db06fff2..af45ab47887 100644 --- a/.github/workflows/markdown-link-check-config.json +++ b/.github/workflows/markdown-link-check-config.json @@ -14,6 +14,22 @@ }, { "pattern": "https://stackblitz.com/*" + }, + { + "pattern": "https://*.chromatic.com" + }, + { + "pattern": "https://www.chromatic.com/build?*" + }, + { + "pattern": "http://*.nodeca.com" + }, + { + "pattern": "http://definitelytyped.org/*" + }, + { + "pattern": "https://yoursite.com/*" } - ] + ], + "aliveStatusCodes": [429, 200] } \ No newline at end of file From ef4e9e4363035f94c2491272e1c2cac169eaacd7 Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 17 May 2022 19:13:02 +0100 Subject: [PATCH 07/69] marks documents to avoid links checkers. --- MIGRATION.md | 2 ++ RELEASES.md | 5 ++--- examples/README.md | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 6b7fd72703e..0c010f2f40b 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -360,6 +360,7 @@ In 6.5, the final titles would be: - `NoTitle.stories.js` => `Custom/NoTitle` - `Title.stories.js` => `Custom/Bar` + ## From version 6.3.x to 6.4.0 ### Automigrate @@ -2881,3 +2882,4 @@ If you **are** using these addons, it takes two steps to migrate: import { action } from '@storybook/addon-actions'; import { linkTo } from '@storybook/addon-links'; ``` + \ No newline at end of file diff --git a/RELEASES.md b/RELEASES.md index 0d98bf5f873..88557cf2fbe 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -81,12 +81,11 @@ there gathering upvotes and "me too" comments. We need a way to make sure that these bugs get addressed. For every non-PATCH release, we nominate a small number of bugs that must be -addressed before a release can go out by adding them to the milestone. For example, here's a list of blocking bugs [for the 3.2 milestone](https://github.com/storybookjs/storybook/milestone/3). +addressed before a release can go out by adding them to the milestone. For example, here's a list of blocking bugs [for the 6.5 milestone](https://github.com/storybookjs/storybook/milestone/75). Adding bugs to the milestone helps people looking for good ways to contribute, or to understand what is blocking the release so they can actually do something -about it. Discussion about which bugs are critical happens in the `#maintenance` -channel [in our Slack](https://now-examples-slackin-rrirkqohko.now.sh/) [![Storybook Slack](https://now-examples-slackin-rrirkqohko.now.sh/badge.svg)](https://now-examples-slackin-rrirkqohko.now.sh/) +about it. Discussion about which bugs are critical happens in the [`#maintenance` channel](https://discord.com/channels/486522875931656193/490070912448724992) in our Discord Server If you're experiencing a bug, the best way to make sure that it gets attention is to upvote it by adding a "thumbs-up" reaction in Github. This way important diff --git a/examples/README.md b/examples/README.md index aa9276df9c6..e78c93b724d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -22,6 +22,7 @@ Live examples of these: - [Ember](https://storybookjs.netlify.com/ember-cli/) - [Preact](https://storybookjs.netlify.com/preact-kitchen-sink/) + ### 5.0 - [React Official](https://release-5-0--storybooks-official.netlify.com/) @@ -37,3 +38,4 @@ Live examples of these: - [React Official](https://release-3-4--storybooks-official.netlify.com) - [Vue](https://release-3-4--storybooks-vue.netlify.com/) - [Angular](https://release-3-4--storybooks-angular.netlify.com/) + \ No newline at end of file From 2bbc30c1c7b774dd378a702f096c5f15a80ddeb5 Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 17 May 2022 19:26:21 +0100 Subject: [PATCH 08/69] adds missing pattern --- .github/workflows/markdown-link-check-config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/markdown-link-check-config.json b/.github/workflows/markdown-link-check-config.json index af45ab47887..8ae064afbbe 100644 --- a/.github/workflows/markdown-link-check-config.json +++ b/.github/workflows/markdown-link-check-config.json @@ -29,6 +29,9 @@ }, { "pattern": "https://yoursite.com/*" + }, + { + "pattern": "https://my-specific-domain.com" } ], "aliveStatusCodes": [429, 200] From 38767d7a2cfcd6ffaa81776558d7b1c9a65a555c Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 17 May 2022 21:10:46 -0500 Subject: [PATCH 09/69] Update mdx.md Adds a recipe for creating a Changelog story, which seems like a pretty common MDX-only docs use case. --- docs/writing-docs/mdx.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/writing-docs/mdx.md b/docs/writing-docs/mdx.md index 1da98f82ec2..f081ca9a212 100644 --- a/docs/writing-docs/mdx.md +++ b/docs/writing-docs/mdx.md @@ -211,6 +211,37 @@ Write your documentation as you usually would, and your existing SCSS code block +### Creating a Changelog story + +One common use case for MDX-only docs stories is importing a project's `CHANGELOG.md` into an MDX story, so that users can easily refer to the CHANGELOG via a documentation node in Storybook. + +First, ensure that `transcludeMarkdown` is set to `true` in `main.js`: + +```js +addons: [ + "@storybook/addon-links", + "@storybook/addon-essentials", + // set transcludeMarkdown to true + { + name: "@storybook/addon-docs", + options: { transcludeMarkdown: true }, + }, +] +``` + +Then, import the markdown and treat the imported file as a component in the MDX file: + +```mdx +import { Meta } from "@storybook/addon-docs"; + +import Changelog from "../CHANGELOG.md"; + + + + +``` +![Changelog markdown in an MDX story](https://user-images.githubusercontent.com/9900326/168942693-b3954bed-0369-4eb5-a4ed-634ebb7575fa.png) + ## Linking to other stories and pages When writing MDX, you may want to provide links to other stories or documentation pages and sections. You can use the `path` query string. @@ -276,4 +307,4 @@ Update your Storybook configuration (in `.storybook/main.js|ts`) and add the `pr ]} /> - \ No newline at end of file + From 3aa19fee07679044ece9f6e6b8c9307855fbc773 Mon Sep 17 00:00:00 2001 From: Matt Oliver Date: Wed, 18 May 2022 21:17:06 -0500 Subject: [PATCH 10/69] adds optimized png and moves snippets to snippets folder --- .../common/mdx-changelog-stories.mdx.mdx | 12 +++++++++++ ...book-main-enable-transcludemarkdown.js.mdx | 20 ++++++++++++++++++ ...og-mdx-md-transcludemarkdown-optimized.png | Bin 0 -> 38411 bytes docs/writing-docs/mdx.md | 20 ++++++++---------- 4 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 docs/snippets/common/mdx-changelog-stories.mdx.mdx create mode 100644 docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx create mode 100644 docs/writing-docs/changelog-mdx-md-transcludemarkdown-optimized.png diff --git a/docs/snippets/common/mdx-changelog-stories.mdx.mdx b/docs/snippets/common/mdx-changelog-stories.mdx.mdx new file mode 100644 index 00000000000..502faa40e3a --- /dev/null +++ b/docs/snippets/common/mdx-changelog-stories.mdx.mdx @@ -0,0 +1,12 @@ +```md + + + +import { Meta } from "@storybook/addon-docs"; + +import Changelog from "../CHANGELOG.md"; + + + + +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx b/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx new file mode 100644 index 00000000000..ab8a8a2b063 --- /dev/null +++ b/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx @@ -0,0 +1,20 @@ +// .storybook/main.js|ts + +module.exports = { + stories: [ + //👇 Changes the load order of our stories. First loads the Changelog page + '../src/Changelog.stories.mdx', + '../stories/**/*.stories.mdx', + '../stories/**/*.stories.@(js|jsx|ts|tsx)' + ], + addons: [ + '@storybook/addon-links', + '@storybook/addon-essentials', + { + name: '@storybook/addon-docs', + options: { + transcludeMarkdown: true, //👈 Set transcludeMarkdown to true + }, + }, + ], +}; \ No newline at end of file diff --git a/docs/writing-docs/changelog-mdx-md-transcludemarkdown-optimized.png b/docs/writing-docs/changelog-mdx-md-transcludemarkdown-optimized.png new file mode 100644 index 0000000000000000000000000000000000000000..fe83633f16d1acbc3820b22f0c8e7d8c08582f5c GIT binary patch literal 38411 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 literal 0 HcmV?d00001 diff --git a/docs/writing-docs/mdx.md b/docs/writing-docs/mdx.md index f081ca9a212..54296197645 100644 --- a/docs/writing-docs/mdx.md +++ b/docs/writing-docs/mdx.md @@ -217,17 +217,15 @@ One common use case for MDX-only docs stories is importing a project's `CHANGELO First, ensure that `transcludeMarkdown` is set to `true` in `main.js`: -```js -addons: [ - "@storybook/addon-links", - "@storybook/addon-essentials", - // set transcludeMarkdown to true - { - name: "@storybook/addon-docs", - options: { transcludeMarkdown: true }, - }, -] -``` + + + + + Then, import the markdown and treat the imported file as a component in the MDX file: From 0d21b966c9691fdf70f8740a767d096fc7521509 Mon Sep 17 00:00:00 2001 From: Aaron Reisman Date: Wed, 18 May 2022 20:48:30 -0700 Subject: [PATCH 11/69] Update get-monorepo-type.ts Fixes issues when no package.json exists at the root of a repo --- lib/telemetry/src/get-monorepo-type.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/telemetry/src/get-monorepo-type.ts b/lib/telemetry/src/get-monorepo-type.ts index 30aae5eadc7..9f49ce41cdf 100644 --- a/lib/telemetry/src/get-monorepo-type.ts +++ b/lib/telemetry/src/get-monorepo-type.ts @@ -27,6 +27,8 @@ export const getMonorepoType = (): MonorepoType => { if (monorepoType) { return monorepoType; } + + if (!fs.existsSync(path.join(projectRootPath, 'package.json'))) return undefined; const packageJson = fs.readJsonSync(path.join(projectRootPath, 'package.json')) as PackageJson; From d01674b7028e2f5bf6a68d235c187574af812397 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 19 May 2022 22:03:51 +0800 Subject: [PATCH 12/69] Revert "security: update x-default-browser" --- lib/core-client/src/typings.d.ts | 5 +- lib/core-server/package.json | 4 +- lib/core-server/src/utils/open-in-browser.ts | 10 ++-- lib/core-server/typings.d.ts | 2 +- lib/manager-webpack4/typings.d.ts | 2 +- lib/manager-webpack5/typings.d.ts | 2 +- yarn.lock | 58 ++++++++++++++++---- 7 files changed, 59 insertions(+), 24 deletions(-) diff --git a/lib/core-client/src/typings.d.ts b/lib/core-client/src/typings.d.ts index bce6e8953b9..0a7386c391b 100644 --- a/lib/core-client/src/typings.d.ts +++ b/lib/core-client/src/typings.d.ts @@ -6,5 +6,6 @@ declare module 'pnp-webpack-plugin'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module '@aw-web-design/x-default-browser'; -declare module '@storybook/ui'; \ No newline at end of file +declare module 'x-default-browser'; +declare module '@storybook/ui'; + diff --git a/lib/core-server/package.json b/lib/core-server/package.json index 13937a1201c..af967ab9206 100644 --- a/lib/core-server/package.json +++ b/lib/core-server/package.json @@ -39,7 +39,6 @@ "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@aw-web-design/x-default-browser": "1.4.0", "@discoveryjs/json-ext": "^0.5.3", "@storybook/builder-webpack4": "6.5.0-rc.1", "@storybook/core-client": "6.5.0-rc.1", @@ -83,7 +82,8 @@ "util-deprecate": "^1.0.2", "watchpack": "^2.2.0", "webpack": "4", - "ws": "^8.2.3" + "ws": "^8.2.3", + "x-default-browser": "^0.4.0" }, "devDependencies": { "@storybook/builder-webpack5": "6.5.0-rc.1", diff --git a/lib/core-server/src/utils/open-in-browser.ts b/lib/core-server/src/utils/open-in-browser.ts index 82ab966a1f4..daa5938b3f0 100644 --- a/lib/core-server/src/utils/open-in-browser.ts +++ b/lib/core-server/src/utils/open-in-browser.ts @@ -1,7 +1,7 @@ import { logger } from '@storybook/node-logger'; import betterOpn from 'better-opn'; // betterOpn alias used because also loading open import open from 'open'; -import getDefaultBrowser from '@aw-web-design/x-default-browser'; +import getDefaultBrowser from 'x-default-browser'; import dedent from 'ts-dedent'; export function openInBrowser(address: string) { @@ -16,10 +16,10 @@ export function openInBrowser(address: string) { } } catch (error) { logger.error(dedent` - Could not open ${address} inside a browser. If you're running this command inside a - docker container or on a CI, you need to pass the '--ci' flag to prevent opening a - browser by default. - `); + Could not open ${address} inside a browser. If you're running this command inside a + docker container or on a CI, you need to pass the '--ci' flag to prevent opening a + browser by default. + `); } }); } diff --git a/lib/core-server/typings.d.ts b/lib/core-server/typings.d.ts index b539c76578d..eeb489a5e71 100644 --- a/lib/core-server/typings.d.ts +++ b/lib/core-server/typings.d.ts @@ -7,7 +7,7 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module '@aw-web-design/x-default-browser'; +declare module 'x-default-browser'; declare module '@storybook/ui'; declare module '@discoveryjs/json-ext'; declare module 'watchpack'; diff --git a/lib/manager-webpack4/typings.d.ts b/lib/manager-webpack4/typings.d.ts index 6c5e278ef73..894b889ada8 100644 --- a/lib/manager-webpack4/typings.d.ts +++ b/lib/manager-webpack4/typings.d.ts @@ -7,5 +7,5 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module '@aw-web-design/x-default-browser'; +declare module 'x-default-browser'; declare module '@storybook/ui'; diff --git a/lib/manager-webpack5/typings.d.ts b/lib/manager-webpack5/typings.d.ts index febd3228fce..70fcabe6c3b 100644 --- a/lib/manager-webpack5/typings.d.ts +++ b/lib/manager-webpack5/typings.d.ts @@ -6,5 +6,5 @@ declare module '@storybook/theming/paths'; declare module '@storybook/ui/paths'; declare module 'better-opn'; declare module 'open'; -declare module '@aw-web-design/x-default-browser'; +declare module 'x-default-browser'; declare module '@storybook/ui'; diff --git a/yarn.lock b/yarn.lock index 80f5dc4700b..4168f11cab6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -375,15 +375,6 @@ __metadata: languageName: node linkType: hard -"@aw-web-design/x-default-browser@npm:1.4.0": - version: 1.4.0 - resolution: "@aw-web-design/x-default-browser@npm:1.4.0" - bin: - x-default-browser: bin/x-default-browser.js - checksum: 1e21253f5af8c9050a511bd4a8342e079f30f662caaa3155afa77474ce12ff014fe4d04859528ccddffd30fb6a4df60acebccc7b657b1639092516e50bb09a6c - languageName: node - linkType: hard - "@axe-core/puppeteer@npm:^4.2.0": version: 4.4.0 resolution: "@axe-core/puppeteer@npm:4.4.0" @@ -7664,7 +7655,6 @@ __metadata: version: 0.0.0-use.local resolution: "@storybook/core-server@workspace:lib/core-server" dependencies: - "@aw-web-design/x-default-browser": 1.4.0 "@discoveryjs/json-ext": ^0.5.3 "@storybook/builder-webpack4": 6.5.0-rc.1 "@storybook/builder-webpack5": 6.5.0-rc.1 @@ -7715,6 +7705,7 @@ __metadata: watchpack: ^2.2.0 webpack: 4 ws: ^8.2.3 + x-default-browser: ^0.4.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -14772,6 +14763,13 @@ __metadata: languageName: node linkType: hard +"big-integer@npm:^1.6.7": + version: 1.6.51 + resolution: "big-integer@npm:1.6.51" + checksum: c8139662d57f8833a44802f4b65be911679c569535ea73c5cfd3c1c8994eaead1b84b6f63e1db63833e4d4cacb6b6a9e5522178113dfdc8e4c81ed8436f1e8cc + languageName: node + linkType: hard + "big.js@npm:^3.1.3": version: 3.2.0 resolution: "big.js@npm:3.2.0" @@ -14995,6 +14993,15 @@ __metadata: languageName: node linkType: hard +"bplist-parser@npm:^0.1.0": + version: 0.1.1 + resolution: "bplist-parser@npm:0.1.1" + dependencies: + big-integer: ^1.6.7 + checksum: cd50206f956e74f6e46cb5ed14be5eb00b2e14676ea3dd36703470715177a2770fc22032eca63a36adb3b56a1e51138a95bb0fc6849a78c21e92caeedf219ea7 + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -19247,6 +19254,19 @@ __metadata: languageName: node linkType: hard +"default-browser-id@npm:^1.0.4": + version: 1.0.4 + resolution: "default-browser-id@npm:1.0.4" + dependencies: + bplist-parser: ^0.1.0 + meow: ^3.1.0 + untildify: ^2.0.0 + bin: + default-browser-id: cli.js + checksum: a00a2ab66beab70490b4d76258a1f2eadfadca6414bf67ab78aa25b33dc3de0c4c813bb8f204271aa7a08281c39474487db0229e325112456464fb97a0522a8a + languageName: node + linkType: hard + "default-gateway@npm:^4.2.0": version: 4.2.0 resolution: "default-gateway@npm:4.2.0" @@ -31655,7 +31675,7 @@ __metadata: languageName: node linkType: hard -"meow@npm:^3.3.0": +"meow@npm:^3.1.0, meow@npm:^3.3.0": version: 3.7.0 resolution: "meow@npm:3.7.0" dependencies: @@ -45106,7 +45126,7 @@ __metadata: languageName: node linkType: hard -"untildify@npm:^2.1.0": +"untildify@npm:^2.0.0, untildify@npm:^2.1.0": version: 2.1.0 resolution: "untildify@npm:2.1.0" dependencies: @@ -47668,6 +47688,20 @@ __metadata: languageName: node linkType: hard +"x-default-browser@npm:^0.4.0": + version: 0.4.0 + resolution: "x-default-browser@npm:0.4.0" + dependencies: + default-browser-id: ^1.0.4 + dependenciesMeta: + default-browser-id: + optional: true + bin: + x-default-browser: bin/x-default-browser.js + checksum: a19e42ffeab19560ea05a423561f5b3b82bb3a5878dc932cfd0847fadc5890b8b685d6b39e2356c8304b3943f5a7120ba4b233365d686ff8f9bf2499ce11f052 + languageName: node + linkType: hard + "xdg-basedir@npm:^4.0.0": version: 4.0.0 resolution: "xdg-basedir@npm:4.0.0" From 741df67ae1828481f30aefbfc4aad4e1c7ff02c7 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 19 May 2022 17:26:51 +0200 Subject: [PATCH 13/69] chore: fix jest 27 in angular e2e modern inline rendering config --- lib/cli/src/repro-generators/configs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cli/src/repro-generators/configs.ts b/lib/cli/src/repro-generators/configs.ts index c5f7b5e5273..24181973670 100644 --- a/lib/cli/src/repro-generators/configs.ts +++ b/lib/cli/src/repro-generators/configs.ts @@ -155,7 +155,7 @@ export const angular13: Parameters = { export const angular_modern_inline_rendering: Parameters = { ...baseAngular, name: 'angular_modern_inline_rendering', - additionalDeps: ['jest', '@storybook/test-runner'], + additionalDeps: ['jest@27', '@storybook/test-runner'], mainOverrides: { features: { storyStoreV7: true, From 89dc4f10e41e7205406101582c356d50ceed4dc0 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Fri, 20 May 2022 15:32:08 +0800 Subject: [PATCH 14/69] Webpack5: Apply named exports order logic for stories only --- .../src/server/framework-preset-react-docs.ts | 1 + .../src/presets/preview-preset.ts | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/react/src/server/framework-preset-react-docs.ts b/app/react/src/server/framework-preset-react-docs.ts index 98f9c12145b..1e9a1e74cfb 100644 --- a/app/react/src/server/framework-preset-react-docs.ts +++ b/app/react/src/server/framework-preset-react-docs.ts @@ -19,6 +19,7 @@ export async function babel(config: TransformOptions, options: Options) { return { ...config, overrides: [ + ...(config?.overrides || []), { test: reactDocgen === 'react-docgen' ? /\.(mjs|tsx?|jsx?)$/ : /\.(mjs|jsx?)$/, plugins: [ diff --git a/lib/builder-webpack5/src/presets/preview-preset.ts b/lib/builder-webpack5/src/presets/preview-preset.ts index b1810716b2b..fdd31c435ca 100644 --- a/lib/builder-webpack5/src/presets/preview-preset.ts +++ b/lib/builder-webpack5/src/presets/preview-preset.ts @@ -20,8 +20,13 @@ export const entries = async (_: unknown, options: any) => { return result; }; -export const babel = async (config: any, options: any) => { - // FIXME: Add this to overrides to only apply to story files - config.plugins.push('babel-plugin-named-exports-order'); - return config; -}; +export const babel = async (config: any, options: any) => ({ + ...config, + overrides: [ + ...(config?.overrides || []), + { + test: /\.(story|stories).*$/, + plugins: [require.resolve('babel-plugin-named-exports-order')], + }, + ], +}); From 55932e1e461bee0ddeec76993218b459d2eb3306 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 20 May 2022 11:07:06 +0200 Subject: [PATCH 15/69] fix: use correct framework version in telemetry --- lib/core-common/src/utils/get-storybook-info.ts | 3 ++- lib/telemetry/src/storybook-metadata.ts | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/core-common/src/utils/get-storybook-info.ts b/lib/core-common/src/utils/get-storybook-info.ts index 000f37bcff0..0729ac2ca9e 100644 --- a/lib/core-common/src/utils/get-storybook-info.ts +++ b/lib/core-common/src/utils/get-storybook-info.ts @@ -6,6 +6,7 @@ import { PackageJson } from '../types'; interface StorybookInfo { framework: string; version: string; + frameworkPackage: string; configDir?: string; mainConfig?: string; previewConfig?: string; @@ -57,7 +58,7 @@ const getFrameworkInfo = (packageJson: PackageJson) => { ); } - return { framework, version }; + return { framework, version, frameworkPackage: pkg }; }; const validConfigExtensions = ['ts', 'js', 'tsx', 'jsx', 'mjs', 'cjs']; diff --git a/lib/telemetry/src/storybook-metadata.ts b/lib/telemetry/src/storybook-metadata.ts index ec288805c3c..0a82e61f436 100644 --- a/lib/telemetry/src/storybook-metadata.ts +++ b/lib/telemetry/src/storybook-metadata.ts @@ -187,9 +187,13 @@ export const computeStorybookMetadata = async ({ const hasStorybookEslint = !!allDependencies['eslint-plugin-storybook']; const storybookInfo = getStorybookInfo(packageJson); + + const storybookVersion = + storybookPackages[storybookInfo.frameworkPackage]?.version || storybookInfo.version; + return { ...metadata, - storybookVersion: storybookInfo.version, + storybookVersion, language, storybookPackages, framework: { From f59e1db766383e1f36fcddcfc181bd1dad909a44 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 20 May 2022 19:00:09 +0200 Subject: [PATCH 16/69] fix: add vue3 webpack5 automigration --- MIGRATION.md | 29 ++++- lib/cli/src/automigrate/fixes/index.ts | 11 +- lib/cli/src/automigrate/fixes/vue3.test.ts | 139 +++++++++++++++++++++ lib/cli/src/automigrate/fixes/vue3.ts | 60 +++++++++ 4 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 lib/cli/src/automigrate/fixes/vue3.test.ts create mode 100644 lib/cli/src/automigrate/fixes/vue3.ts diff --git a/MIGRATION.md b/MIGRATION.md index 6b7fd72703e..68f32edbddb 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,6 +1,7 @@

Migration

- [From version 6.4.x to 6.5.0](#from-version-64x-to-650) + - [Vue 3 upgrade](#vue-3-upgrade) - [React18 new root API](#react18-new-root-api) - [Renamed isToolshown to showToolbar](#renamed-istoolshown-to-showtoolbar) - [Deprecated register.js](#deprecated-registerjs) @@ -202,6 +203,10 @@ ## From version 6.4.x to 6.5.0 +### Vue 3 upgrade + +Storybook 6.5 supports Vue 3 out of the box when you install it fresh. However, if you're upgrading your project from a previous version, you'll need to [follow the steps for opting-in to webpack 5](#webpack-5). + ### React18 new root API React 18 introduces a [new root API](https://reactjs.org/blog/2022/03/08/react-18-upgrade-guide.html#updates-to-client-rendering-apis). Starting in 6.5, Storybook for React will auto-detect your react version and use the new root API automatically if you're on React18. @@ -748,7 +753,29 @@ The `--static-dir` flag has been deprecated and will be removed in Storybook 7.0 ### Webpack 5 -Storybook 6.3 brings opt-in support for building both your project and the manager UI with webpack 5. To do so: +Storybook 6.3 brings opt-in support for building both your project and the manager UI with webpack 5. To do so, there are two ways: + +1 - Upgrade command + +If you're upgrading your Storybook version, run this command, which will both upgrade your dependencies but also detect whether you should migrate to webpack5 builders and apply the changes automatically: + +```shell +npx storybook upgrade +``` + +2 - Automigrate command + +If you don't want to change your Storybook version but want Storybook to detect whether you should migrate to webpack5 builders and apply the changes automatically: + +```shell +npx storybook automigrate +``` + +3 - Manually + +If either methods did not work or you just want to proceed manually, do the following steps: + +Install the dependencies: ```shell yarn add @storybook/builder-webpack5 @storybook/manager-webpack5 --dev diff --git a/lib/cli/src/automigrate/fixes/index.ts b/lib/cli/src/automigrate/fixes/index.ts index 8af1741b392..566162243ed 100644 --- a/lib/cli/src/automigrate/fixes/index.ts +++ b/lib/cli/src/automigrate/fixes/index.ts @@ -1,10 +1,19 @@ import { cra5 } from './cra5'; import { webpack5 } from './webpack5'; import { angular12 } from './angular12'; +import { vue3 } from './vue3'; import { mainjsFramework } from './mainjsFramework'; import { eslintPlugin } from './eslint-plugin'; import { builderVite } from './builder-vite'; import { Fix } from '../types'; export * from '../types'; -export const fixes: Fix[] = [cra5, webpack5, angular12, mainjsFramework, eslintPlugin, builderVite]; +export const fixes: Fix[] = [ + cra5, + webpack5, + angular12, + vue3, + mainjsFramework, + eslintPlugin, + builderVite, +]; diff --git a/lib/cli/src/automigrate/fixes/vue3.test.ts b/lib/cli/src/automigrate/fixes/vue3.test.ts new file mode 100644 index 00000000000..92da39e82fa --- /dev/null +++ b/lib/cli/src/automigrate/fixes/vue3.test.ts @@ -0,0 +1,139 @@ +/* eslint-disable no-underscore-dangle */ +import path from 'path'; +import { JsPackageManager } from '../../js-package-manager'; +import { vue3 } from './vue3'; + +// eslint-disable-next-line global-require, jest/no-mocks-import +jest.mock('fs-extra', () => require('../../../../../__mocks__/fs-extra')); + +const checkCra5 = async ({ packageJson, main }) => { + // eslint-disable-next-line global-require + require('fs-extra').__setMockFiles({ + [path.join('.storybook', 'main.js')]: `module.exports = ${JSON.stringify(main)};`, + }); + const packageManager = { + retrievePackageJson: () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), + } as JsPackageManager; + return vue3.check({ packageManager }); +}; + +describe('vue3 fix', () => { + describe('sb < 6.3', () => { + describe('vue3 dependency', () => { + const packageJson = { + dependencies: { '@storybook/vue': '^6.2.0', vue: '^3.0.0' }, + }; + it('should fail', async () => { + await expect( + checkCra5({ + packageJson, + main: {}, + }) + ).rejects.toThrow(); + }); + }); + describe('no vue dependency', () => { + const packageJson = { dependencies: { '@storybook/vue': '^6.2.0' } }; + it('should no-op', async () => { + await expect( + checkCra5({ + packageJson, + main: {}, + }) + ).resolves.toBeFalsy(); + }); + }); + }); + describe('sb 6.3 - 7.0', () => { + describe('vue3 dependency', () => { + const packageJson = { + dependencies: { '@storybook/vue': '^6.3.0', vue: '^3.0.0' }, + }; + describe('webpack5 builder', () => { + it('should no-op', async () => { + await expect( + checkCra5({ + packageJson, + main: { core: { builder: 'webpack5' } }, + }) + ).resolves.toBeFalsy(); + }); + }); + describe('custom builder', () => { + it('should no-op', async () => { + await expect( + checkCra5({ + packageJson, + main: { core: { builder: 'storybook-builder-vite' } }, + }) + ).resolves.toBeFalsy(); + }); + }); + describe('webpack4 builder', () => { + it('should add webpack5 builder', async () => { + await expect( + checkCra5({ + packageJson, + main: { core: { builder: 'webpack4' } }, + }) + ).resolves.toMatchObject({ + vueVersion: '^3.0.0', + storybookVersion: '^6.3.0', + }); + }); + }); + describe('no builder', () => { + it('should add webpack5 builder', async () => { + await expect( + checkCra5({ + packageJson, + main: {}, + }) + ).resolves.toMatchObject({ + vueVersion: '^3.0.0', + storybookVersion: '^6.3.0', + }); + }); + }); + }); + describe('no vue dependency', () => { + it('should no-op', async () => { + await expect( + checkCra5({ + packageJson: {}, + main: {}, + }) + ).resolves.toBeFalsy(); + }); + }); + describe('vue2 dependency', () => { + it('should no-op', async () => { + await expect( + checkCra5({ + packageJson: { + dependencies: { + vue: '2', + }, + }, + main: {}, + }) + ).resolves.toBeFalsy(); + }); + }); + }); + describe('sb 7.0+', () => { + describe('vue3 dependency', () => { + const packageJson = { + dependencies: { '@storybook/vue': '^7.0.0-alpha.0', vue: '^3.0.0' }, + }; + it('should no-op', async () => { + await expect( + checkCra5({ + packageJson, + main: {}, + }) + ).resolves.toBeFalsy(); + }); + }); + }); +}); diff --git a/lib/cli/src/automigrate/fixes/vue3.ts b/lib/cli/src/automigrate/fixes/vue3.ts new file mode 100644 index 00000000000..15a066432db --- /dev/null +++ b/lib/cli/src/automigrate/fixes/vue3.ts @@ -0,0 +1,60 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; +import semver from '@storybook/semver'; +import { ConfigFile } from '@storybook/csf-tools'; +import { Fix } from '../types'; +import { webpack5 } from './webpack5'; + +interface Vue3RunOptions { + vueVersion: string; + storybookVersion: string; + main: ConfigFile; +} + +/** + * Is the user upgrading to Vue3? + * + * If so: + * - Run webpack5 fix + */ +export const vue3: Fix = { + id: 'vue3', + + async check({ packageManager }) { + const packageJson = packageManager.retrievePackageJson(); + const { dependencies, devDependencies } = packageJson; + const vueVersion = dependencies.vue || devDependencies.vue; + const vueCoerced = semver.coerce(vueVersion)?.version; + + if (!vueCoerced || semver.lt(vueCoerced, '3.0.0')) { + return null; + } + + const builderInfo = await webpack5.checkWebpack5Builder(packageJson); + return builderInfo ? { vueVersion, ...builderInfo } : null; + }, + + prompt({ vueVersion, storybookVersion }) { + const vueFormatted = chalk.cyan(`Vue ${vueVersion}`); + const sbFormatted = chalk.cyan(`Storybook ${storybookVersion}`); + return dedent` + We've detected you are running ${vueFormatted} with Storybook. + ${sbFormatted} runs webpack4 by default, which is incompatible. + + In order to work with your version of Vue, we need to install Storybook's ${chalk.cyan( + 'webpack5 builder' + )}. + + More info: ${chalk.yellow( + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#vue3-upgrade' + )} + `; + }, + + async run(options) { + return webpack5.run({ + ...options, + result: { webpackVersion: null, ...options.result }, + }); + }, +}; From 885d79d0e8f7441dd50785ba3695285d5cb648bd Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 23 May 2022 07:55:05 +0200 Subject: [PATCH 17/69] fix typo in tests --- .../src/automigrate/fixes/angular12.test.ts | 20 +++++++++---------- lib/cli/src/automigrate/fixes/vue3.test.ts | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/cli/src/automigrate/fixes/angular12.test.ts b/lib/cli/src/automigrate/fixes/angular12.test.ts index c00b4518405..9ef4c8ad186 100644 --- a/lib/cli/src/automigrate/fixes/angular12.test.ts +++ b/lib/cli/src/automigrate/fixes/angular12.test.ts @@ -6,7 +6,7 @@ import { angular12 } from './angular12'; // eslint-disable-next-line global-require, jest/no-mocks-import jest.mock('fs-extra', () => require('../../../../../__mocks__/fs-extra')); -const checkCra5 = async ({ packageJson, main }) => { +const checkAngular12 = async ({ packageJson, main }) => { // eslint-disable-next-line global-require require('fs-extra').__setMockFiles({ [path.join('.storybook', 'main.js')]: `module.exports = ${JSON.stringify(main)};`, @@ -25,7 +25,7 @@ describe('angular12 fix', () => { }; it('should fail', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: {}, }) @@ -36,7 +36,7 @@ describe('angular12 fix', () => { const packageJson = { dependencies: { '@storybook/react': '^6.2.0' } }; it('should no-op', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: {}, }) @@ -52,7 +52,7 @@ describe('angular12 fix', () => { describe('webpack5 builder', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: { core: { builder: 'webpack5' } }, }) @@ -62,7 +62,7 @@ describe('angular12 fix', () => { describe('custom builder', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: { core: { builder: 'storybook-builder-vite' } }, }) @@ -72,7 +72,7 @@ describe('angular12 fix', () => { describe('webpack4 builder', () => { it('should add webpack5 builder', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: { core: { builder: 'webpack4' } }, }) @@ -85,7 +85,7 @@ describe('angular12 fix', () => { describe('no builder', () => { it('should add webpack5 builder', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: {}, }) @@ -99,7 +99,7 @@ describe('angular12 fix', () => { describe('no angular dependency', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson: {}, main: {}, }) @@ -109,7 +109,7 @@ describe('angular12 fix', () => { describe('angular11 dependency', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson: { dependencies: { '@angular/core': '11', @@ -128,7 +128,7 @@ describe('angular12 fix', () => { }; it('should no-op', async () => { await expect( - checkCra5({ + checkAngular12({ packageJson, main: {}, }) diff --git a/lib/cli/src/automigrate/fixes/vue3.test.ts b/lib/cli/src/automigrate/fixes/vue3.test.ts index 92da39e82fa..6fb5a71b17a 100644 --- a/lib/cli/src/automigrate/fixes/vue3.test.ts +++ b/lib/cli/src/automigrate/fixes/vue3.test.ts @@ -6,7 +6,7 @@ import { vue3 } from './vue3'; // eslint-disable-next-line global-require, jest/no-mocks-import jest.mock('fs-extra', () => require('../../../../../__mocks__/fs-extra')); -const checkCra5 = async ({ packageJson, main }) => { +const checkVue3 = async ({ packageJson, main }) => { // eslint-disable-next-line global-require require('fs-extra').__setMockFiles({ [path.join('.storybook', 'main.js')]: `module.exports = ${JSON.stringify(main)};`, @@ -25,7 +25,7 @@ describe('vue3 fix', () => { }; it('should fail', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: {}, }) @@ -36,7 +36,7 @@ describe('vue3 fix', () => { const packageJson = { dependencies: { '@storybook/vue': '^6.2.0' } }; it('should no-op', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: {}, }) @@ -52,7 +52,7 @@ describe('vue3 fix', () => { describe('webpack5 builder', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: { core: { builder: 'webpack5' } }, }) @@ -62,7 +62,7 @@ describe('vue3 fix', () => { describe('custom builder', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: { core: { builder: 'storybook-builder-vite' } }, }) @@ -72,7 +72,7 @@ describe('vue3 fix', () => { describe('webpack4 builder', () => { it('should add webpack5 builder', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: { core: { builder: 'webpack4' } }, }) @@ -85,7 +85,7 @@ describe('vue3 fix', () => { describe('no builder', () => { it('should add webpack5 builder', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: {}, }) @@ -99,7 +99,7 @@ describe('vue3 fix', () => { describe('no vue dependency', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkVue3({ packageJson: {}, main: {}, }) @@ -109,7 +109,7 @@ describe('vue3 fix', () => { describe('vue2 dependency', () => { it('should no-op', async () => { await expect( - checkCra5({ + checkVue3({ packageJson: { dependencies: { vue: '2', @@ -128,7 +128,7 @@ describe('vue3 fix', () => { }; it('should no-op', async () => { await expect( - checkCra5({ + checkVue3({ packageJson, main: {}, }) From 23c6ff7fb04eb1d3de1b4521105275317822bebf Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 23 May 2022 07:55:38 +0200 Subject: [PATCH 18/69] use sb in migration steps --- MIGRATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 68f32edbddb..79b479cc97b 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -760,7 +760,7 @@ Storybook 6.3 brings opt-in support for building both your project and the manag If you're upgrading your Storybook version, run this command, which will both upgrade your dependencies but also detect whether you should migrate to webpack5 builders and apply the changes automatically: ```shell -npx storybook upgrade +npx sb upgrade ``` 2 - Automigrate command @@ -768,7 +768,7 @@ npx storybook upgrade If you don't want to change your Storybook version but want Storybook to detect whether you should migrate to webpack5 builders and apply the changes automatically: ```shell -npx storybook automigrate +npx sb automigrate ``` 3 - Manually From 09910349f188ffd96db2bc0f916b8f6b2fce3fba Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Mon, 23 May 2022 19:56:52 +0800 Subject: [PATCH 19/69] MDX: Upgrade csf-mdx libraries --- addons/docs/package.json | 6 +++--- lib/csf-tools/package.json | 6 +++--- yarn.lock | 28 ++++++++++++++-------------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/addons/docs/package.json b/addons/docs/package.json index 09fe2b8368a..e974e4ac804 100644 --- a/addons/docs/package.json +++ b/addons/docs/package.json @@ -66,7 +66,7 @@ "@storybook/core-events": "6.5.0-rc.1", "@storybook/csf": "0.0.2--canary.4566f4d.1", "@storybook/docs-tools": "6.5.0-rc.1", - "@storybook/mdx1-csf": "canary", + "@storybook/mdx1-csf": "^0.0.1", "@storybook/node-logger": "6.5.0-rc.1", "@storybook/postinstall": "6.5.0-rc.1", "@storybook/preview-web": "6.5.0-rc.1", @@ -86,11 +86,11 @@ }, "devDependencies": { "@babel/core": "^7.12.10", - "@storybook/mdx2-csf": "canary", + "@storybook/mdx2-csf": "^0.0.3", "@types/util-deprecate": "^1.0.0" }, "peerDependencies": { - "@storybook/mdx2-csf": "*", + "@storybook/mdx2-csf": "^0.0.3", "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" }, diff --git a/lib/csf-tools/package.json b/lib/csf-tools/package.json index 732c9109f93..16b834cfa11 100644 --- a/lib/csf-tools/package.json +++ b/lib/csf-tools/package.json @@ -48,7 +48,7 @@ "@babel/traverse": "^7.12.11", "@babel/types": "^7.12.11", "@storybook/csf": "0.0.2--canary.4566f4d.1", - "@storybook/mdx1-csf": "canary", + "@storybook/mdx1-csf": "^0.0.1", "core-js": "^3.8.2", "fs-extra": "^9.0.1", "global": "^4.4.0", @@ -56,12 +56,12 @@ "ts-dedent": "^2.0.0" }, "devDependencies": { - "@storybook/mdx2-csf": "canary", + "@storybook/mdx2-csf": "^0.0.3", "@types/fs-extra": "^9.0.6", "js-yaml": "^3.14.1" }, "peerDependencies": { - "@storybook/mdx2-csf": "*" + "@storybook/mdx2-csf": "^0.0.3" }, "peerDependenciesMeta": { "@storybook/mdx2-csf": { diff --git a/yarn.lock b/yarn.lock index 4168f11cab6..fd9be8f2af5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6554,8 +6554,8 @@ __metadata: "@storybook/core-events": 6.5.0-rc.1 "@storybook/csf": 0.0.2--canary.4566f4d.1 "@storybook/docs-tools": 6.5.0-rc.1 - "@storybook/mdx1-csf": canary - "@storybook/mdx2-csf": canary + "@storybook/mdx1-csf": ^0.0.1 + "@storybook/mdx2-csf": ^0.0.3 "@storybook/node-logger": 6.5.0-rc.1 "@storybook/postinstall": 6.5.0-rc.1 "@storybook/preview-web": 6.5.0-rc.1 @@ -6574,7 +6574,7 @@ __metadata: ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 peerDependencies: - "@storybook/mdx2-csf": "*" + "@storybook/mdx2-csf": ^0.0.3 react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 peerDependenciesMeta: @@ -7751,8 +7751,8 @@ __metadata: "@babel/traverse": ^7.12.11 "@babel/types": ^7.12.11 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/mdx1-csf": canary - "@storybook/mdx2-csf": canary + "@storybook/mdx1-csf": ^0.0.1 + "@storybook/mdx2-csf": ^0.0.3 "@types/fs-extra": ^9.0.6 core-js: ^3.8.2 fs-extra: ^9.0.1 @@ -7761,7 +7761,7 @@ __metadata: regenerator-runtime: ^0.13.7 ts-dedent: ^2.0.0 peerDependencies: - "@storybook/mdx2-csf": "*" + "@storybook/mdx2-csf": ^0.0.3 peerDependenciesMeta: "@storybook/mdx2-csf": optional: true @@ -8166,9 +8166,9 @@ __metadata: languageName: unknown linkType: soft -"@storybook/mdx1-csf@npm:canary": - version: 0.0.1-canary.1.867dcd5.0 - resolution: "@storybook/mdx1-csf@npm:0.0.1-canary.1.867dcd5.0" +"@storybook/mdx1-csf@npm:^0.0.1": + version: 0.0.1 + resolution: "@storybook/mdx1-csf@npm:0.0.1" dependencies: "@babel/generator": ^7.12.11 "@babel/parser": ^7.12.11 @@ -8181,13 +8181,13 @@ __metadata: lodash: ^4.17.21 prettier: ">=2.2.1 <=2.3.0" ts-dedent: ^2.0.0 - checksum: bf3ea30731250cc945b9a3f18396ce308da6c29c7569ea5ae8eaf17a5b472255c1f618120f230d34e3013df3805f31fe2a254b2b2478f58c1472ae3288bd86a1 + checksum: c25a4ad1356ce65950483bd85f37ba93237149fd782360e3548a86dafd9753674ddebb03a8665ed78f99bc1533e87ba2a0605c2fc984a5ad19662fd4b930db78 languageName: node linkType: hard -"@storybook/mdx2-csf@npm:canary": - version: 0.0.1-canary.1.357011b.0 - resolution: "@storybook/mdx2-csf@npm:0.0.1-canary.1.357011b.0" +"@storybook/mdx2-csf@npm:^0.0.3": + version: 0.0.3 + resolution: "@storybook/mdx2-csf@npm:0.0.3" dependencies: "@babel/generator": ^7.12.11 "@babel/parser": ^7.12.11 @@ -8197,7 +8197,7 @@ __metadata: js-string-escape: ^1.0.1 loader-utils: ^2.0.0 lodash: ^4.17.21 - checksum: d478936e21773fdb7a182160d61aa951b71edde927c97e095a2557dce80f3f263ae91fe818491713ffe834034370189a2fa17d672275d881c841a2277bbf89d0 + checksum: 0bbf5d537930c8a592a371012fb9cc3cd88a5184ff3a6a40a04ccf1c702e6f2c79a57c61b13c772b24c42c4a7f5820e9d7cf933d16a78e08f6e24a6bb2171efc languageName: node linkType: hard From 2c488457395d60da7b4504eeb46d377013a0896f Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 23 May 2022 15:05:13 +0200 Subject: [PATCH 20/69] CLI: wait until deps are installed to automigrate --- lib/cli/src/initiate.ts | 183 ++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 93 deletions(-) diff --git a/lib/cli/src/initiate.ts b/lib/cli/src/initiate.ts index 3ba05abe529..2a41e4efdbc 100644 --- a/lib/cli/src/initiate.ts +++ b/lib/cli/src/initiate.ts @@ -66,21 +66,6 @@ const installStorybook = ( commonJs: options.commonJs, }; - const end = () => { - if (!options.skipInstall) { - packageManager.installDependencies(); - } - - logger.log('\nTo run your Storybook, type:\n'); - codeLog([packageManager.getRunStorybookCommand()]); - logger.log('\nFor more information visit:', chalk.cyan('https://storybook.js.org')); - - // Add a new line for the clear visibility. - logger.log(); - }; - - const REACT_NATIVE_REPO = 'https://github.com/storybookjs/react-native'; - const runGenerator: () => Promise = () => { switch (projectType) { case ProjectType.ALREADY_HAS_STORYBOOK: @@ -96,18 +81,17 @@ const installStorybook = ( case ProjectType.UPDATE_PACKAGE_ORGANIZATIONS: return updateOrganisationsGenerator(packageManager, options.parser, npmOptions) .then(() => null) // commandLog doesn't like to see output - .then(commandLog('Upgrading your project to the new Storybook packages.\n')) - .then(end); + .then(commandLog('Upgrading your project to the new Storybook packages.\n')); case ProjectType.REACT_SCRIPTS: - return reactScriptsGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Create React App" based project')) - .then(end); + return reactScriptsGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Create React App" based project') + ); case ProjectType.REACT: - return reactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "React" app\n')) - .then(end); + return reactGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "React" app\n') + ); case ProjectType.REACT_NATIVE: { return ( @@ -124,112 +108,103 @@ const installStorybook = ( ]) as Promise<{ server: boolean }>) ) .then(({ server }) => reactNativeGenerator(packageManager, npmOptions, server)) - .then(commandLog('Adding Storybook support to your "React Native" app\n')) - .then(end) - .then(() => { - logger.log(chalk.red('NOTE: installation is not 100% automated.')); - logger.log(`To quickly run Storybook, replace contents of your app entry with:\n`); - codeLog(["export {default} from './storybook';"]); - logger.log('\n For more in information, see the github readme:\n'); - logger.log(chalk.cyan(REACT_NATIVE_REPO)); - logger.log(); - }); + .then(commandLog('Adding Storybook support to your "React Native" app\n')); } case ProjectType.METEOR: - return meteorGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Meteor" app\n')) - .then(end); + return meteorGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Meteor" app\n') + ); case ProjectType.WEBPACK_REACT: - return webpackReactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Webpack React" app\n')) - .then(end); + return webpackReactGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Webpack React" app\n') + ); case ProjectType.REACT_PROJECT: - return reactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "React" library\n')) - .then(end); + return reactGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "React" library\n') + ); case ProjectType.SFC_VUE: - return sfcVueGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Single File Components Vue" app\n')) - .then(end); + return sfcVueGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Single File Components Vue" app\n') + ); case ProjectType.VUE: - return vueGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Vue" app\n')) - .then(end); + return vueGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Vue" app\n') + ); case ProjectType.VUE3: - return vue3Generator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Vue 3" app\n')) - .then(end); + return vue3Generator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Vue 3" app\n') + ); case ProjectType.ANGULAR: - return angularGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Angular" app\n')) - .then(end); + return angularGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Angular" app\n') + ); case ProjectType.EMBER: - return emberGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Ember" app\n')) - .then(end); + return emberGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Ember" app\n') + ); case ProjectType.MITHRIL: - return mithrilGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Mithril" app\n')) - .then(end); + return mithrilGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Mithril" app\n') + ); case ProjectType.MARIONETTE: - return marionetteGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Marionette.js" app\n')) - .then(end); + return marionetteGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Marionette.js" app\n') + ); case ProjectType.MARKO: - return markoGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Marko" app\n')) - .then(end); + return markoGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Marko" app\n') + ); case ProjectType.HTML: - return htmlGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "HTML" app\n')) - .then(end); + return htmlGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "HTML" app\n') + ); case ProjectType.WEB_COMPONENTS: - return webComponentsGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "web components" app\n')) - .then(end); + return webComponentsGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "web components" app\n') + ); case ProjectType.RIOT: - return riotGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "riot.js" app\n')) - .then(end); + return riotGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "riot.js" app\n') + ); case ProjectType.PREACT: - return preactGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Preact" app\n')) - .then(end); + return preactGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Preact" app\n') + ); case ProjectType.SVELTE: - return svelteGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Svelte" app\n')) - .then(end); + return svelteGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Svelte" app\n') + ); case ProjectType.RAX: - return raxGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Rax" app\n')) - .then(end); + return raxGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Rax" app\n') + ); case ProjectType.AURELIA: - return aureliaGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Aurelia" app\n')) - .then(end); + return aureliaGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Aurelia" app\n') + ); case ProjectType.SERVER: - return serverGenerator(packageManager, npmOptions, generatorOptions) - .then(commandLog('Adding Storybook support to your "Server" app\n')) - .then(end); + return serverGenerator(packageManager, npmOptions, generatorOptions).then( + commandLog('Adding Storybook support to your "Server" app\n') + ); case ProjectType.UNSUPPORTED: paddedLog(`We detected a project type that we don't support yet.`); @@ -294,7 +269,7 @@ const projectTypeInquirer = async ( export async function initiate(options: CommandOptions, pkg: Package): Promise { const packageManager = JsPackageManagerFactory.getPackageManager(options.useNpm); - const welcomeMessage = 'sb init - the simplest way to add a Storybook to your project.'; + const welcomeMessage = 'storybook init - the simplest way to add a Storybook to your project.'; logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); if (!options.disableTelemetry) { @@ -337,7 +312,6 @@ export async function initiate(options: CommandOptions, pkg: Package): Promise Date: Mon, 23 May 2022 22:47:27 +0800 Subject: [PATCH 21/69] Examples: Add MDX files back to react-ts --- examples/react-ts/.storybook/main.ts | 4 ++++ .../src/__snapshots__/storyshots.test.ts.snap | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/examples/react-ts/.storybook/main.ts b/examples/react-ts/.storybook/main.ts index 579583f50ad..752f85c6ac6 100644 --- a/examples/react-ts/.storybook/main.ts +++ b/examples/react-ts/.storybook/main.ts @@ -11,6 +11,10 @@ const config: StorybookConfig = { titlePrefix: 'Demo', files: '*.stories.(js|ts|tsx|mdx)', }, + { + directory: '../src/addon-docs', + files: '*.stories.mdx', + }, ], logLevel: 'debug', addons: [ diff --git a/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap b/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap index d5f828f6d87..409f2a8ab57 100644 --- a/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap +++ b/examples/react-ts/src/__snapshots__/storyshots.test.ts.snap @@ -4040,3 +4040,21 @@ exports[`Storyshots Demo/Examples / Emoji Button With Args 1`] = ` With args `; + +exports[`Storyshots Docs/ButtonMdx Basic 1`] = ` + +`; + +exports[`Storyshots Docs/ButtonMdx Controls 1`] = ` + +`; From 9afa130efa2ca77cd188bcc5d5fcaa164a58bc8a Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 23 May 2022 15:08:03 +0200 Subject: [PATCH 22/69] CLI: fix automigration --yes flag --- lib/cli/src/automigrate/index.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/cli/src/automigrate/index.ts b/lib/cli/src/automigrate/index.ts index ad2dd67d7c4..3913eab12dd 100644 --- a/lib/cli/src/automigrate/index.ts +++ b/lib/cli/src/automigrate/index.ts @@ -29,28 +29,31 @@ export const automigrate = async ({ fixId, dryRun, yes }: FixOptions = {}) => { boxen(message, { borderStyle: 'round', padding: 1, borderColor: '#F1618C' } as any) ); - const runAnswer = - yes || dryRun - ? { fix: false } - : await prompts([ - { - type: 'confirm', - name: 'fix', - message: `Do you want to run the '${chalk.cyan(f.id)}' fix on your project?`, - }, - ]); + let runAnswer: { fix: boolean }; + + if (dryRun) { + runAnswer = { fix: false }; + } else if (yes) { + runAnswer = { fix: true }; + } else { + runAnswer = await prompts({ + type: 'confirm', + name: 'fix', + message: `Do you want to run the '${chalk.cyan(f.id)}' fix on your project?`, + }); + } if (runAnswer.fix) { try { await f.run({ result, packageManager, dryRun }); - logger.info(`✅ fixed ${chalk.cyan(f.id)}`); + logger.info(`✅ ran ${chalk.cyan(f.id)} migration`); } catch (error) { - logger.info(`❌ error in ${chalk.cyan(f.id)}:`); + logger.info(`❌ error when running ${chalk.cyan(f.id)} migration:`); logger.info(error.message); logger.info(); } } else { - logger.info(`Skipping the ${chalk.cyan(f.id)} fix.`); + logger.info(`Skipping the ${chalk.cyan(f.id)} migration.`); logger.info(); logger.info( `If you change your mind, run '${chalk.cyan('npx storybook@next automigrate')}'` From eab88cc138ae74ce38aa060267fe5dfc243f17fb Mon Sep 17 00:00:00 2001 From: Alexey Ryabov Date: Mon, 23 May 2022 20:04:39 +0300 Subject: [PATCH 23/69] Fix open in browser doesn't work in WSL On Linux, `x-default-browser` requires `xdg-utils` to be installed to determine a default browser. So it fails when it's not installed. However, in WSL, we still can open a browser without it. Now it fallbacks to `open` when `x-default-browser` fails which makes it work on WSL without `xdg-utils`. --- lib/core-server/src/utils/open-in-browser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core-server/src/utils/open-in-browser.ts b/lib/core-server/src/utils/open-in-browser.ts index daa5938b3f0..bf98fbf9dd4 100644 --- a/lib/core-server/src/utils/open-in-browser.ts +++ b/lib/core-server/src/utils/open-in-browser.ts @@ -7,7 +7,7 @@ import dedent from 'ts-dedent'; export function openInBrowser(address: string) { getDefaultBrowser(async (err: any, res: any) => { try { - if (res.isChrome || res.isChromium) { + if (res && (res.isChrome || res.isChromium)) { // We use betterOpn for Chrome because it is better at handling which chrome tab // or window the preview loads in. betterOpn(address); From 2b7724aacace233926aa5dada7a297332c97a0ad Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 23 May 2022 19:07:10 +0200 Subject: [PATCH 24/69] CLI: improve texts for automigration --- lib/cli/src/automigrate/index.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/cli/src/automigrate/index.ts b/lib/cli/src/automigrate/index.ts index 3913eab12dd..26e9e23b041 100644 --- a/lib/cli/src/automigrate/index.ts +++ b/lib/cli/src/automigrate/index.ts @@ -18,11 +18,14 @@ export const automigrate = async ({ fixId, dryRun, yes }: FixOptions = {}) => { const packageManager = JsPackageManagerFactory.getPackageManager(); const filtered = fixId ? fixes.filter((f) => f.id === fixId) : fixes; + logger.info('🔎 checking possible migrations..'); + for (let i = 0; i < filtered.length; i += 1) { const f = fixes[i] as Fix; - logger.info(`🔎 checking '${chalk.cyan(f.id)}'`); const result = await f.check({ packageManager }); if (result) { + logger.info(`🔎 found a '${chalk.cyan(f.id)}' migration:`); + logger.info(); const message = f.prompt(result); logger.info( @@ -39,7 +42,7 @@ export const automigrate = async ({ fixId, dryRun, yes }: FixOptions = {}) => { runAnswer = await prompts({ type: 'confirm', name: 'fix', - message: `Do you want to run the '${chalk.cyan(f.id)}' fix on your project?`, + message: `Do you want to run the '${chalk.cyan(f.id)}' migration on your project?`, }); } @@ -61,4 +64,8 @@ export const automigrate = async ({ fixId, dryRun, yes }: FixOptions = {}) => { } } } + + logger.info(); + logger.info('✅ migration check successfully ran'); + logger.info(); }; From 84295cca2bef58f00f17e2be99bf82b5afd01dba Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Mon, 23 May 2022 18:26:26 +0100 Subject: [PATCH 25/69] removes outdated examples --- examples/README.md | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/examples/README.md b/examples/README.md index e78c93b724d..70c3ddc681b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,22 +20,4 @@ Live examples of these: - [HTML](https://storybookjs.netlify.com/html-kitchen-sink/) - [Svelte](https://storybookjs.netlify.com/svelte-kitchen-sink/) - [Ember](https://storybookjs.netlify.com/ember-cli/) -- [Preact](https://storybookjs.netlify.com/preact-kitchen-sink/) - - -### 5.0 - -- [React Official](https://release-5-0--storybooks-official.netlify.com/) -- [Vue](https://release-5-0--storybooks-vue.netlify.com/) -- [Angular](https://release-5-0--storybooks-angular.netlify.com/) -- [HTML](https://release-5-0--storybooks-html.netlify.com/) -- [Svelte](https://release-5-0--storybooks-svelte.netlify.com/) -- [Ember](https://release-5-0--storybooks-ember.netlify.com/) -- [Preact](https://release-5-0--storybooks-preact.netlify.com/) - -### 3.4 - -- [React Official](https://release-3-4--storybooks-official.netlify.com) -- [Vue](https://release-3-4--storybooks-vue.netlify.com/) -- [Angular](https://release-3-4--storybooks-angular.netlify.com/) - \ No newline at end of file +- [Preact](https://storybookjs.netlify.com/preact-kitchen-sink/) \ No newline at end of file From 7a2a78eca922f9492d4c8895544da259f2cf7099 Mon Sep 17 00:00:00 2001 From: Matt Oliver Date: Mon, 23 May 2022 16:21:05 -0500 Subject: [PATCH 26/69] update mdx.md with correct path to optimized example image --- docs/writing-docs/mdx.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/writing-docs/mdx.md b/docs/writing-docs/mdx.md index 54296197645..e7b8458293d 100644 --- a/docs/writing-docs/mdx.md +++ b/docs/writing-docs/mdx.md @@ -238,7 +238,7 @@ import Changelog from "../CHANGELOG.md"; ``` -![Changelog markdown in an MDX story](https://user-images.githubusercontent.com/9900326/168942693-b3954bed-0369-4eb5-a4ed-634ebb7575fa.png) +![Changelog markdown in an MDX story](./changelog-mdx-md-transcludemarkdown-optimized.png) ## Linking to other stories and pages From df72f45e35f08e73d6b84bdedb2bda4a0899de72 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Tue, 24 May 2022 11:05:28 +0800 Subject: [PATCH 27/69] CSF: Fix auto-title crash on file ID and show warning --- lib/store/src/autoTitle.ts | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/store/src/autoTitle.ts b/lib/store/src/autoTitle.ts index 0f2e268eb71..2e98306b7c7 100644 --- a/lib/store/src/autoTitle.ts +++ b/lib/store/src/autoTitle.ts @@ -1,4 +1,6 @@ import slash from 'slash'; +import dedent from 'ts-dedent'; +import { once } from '@storybook/client-logger'; // FIXME: types duplicated type from `core-common', to be // removed when we remove v6 back-compat. @@ -48,11 +50,24 @@ function pathJoin(paths: string[]): string { return paths.join('/').replace(slashes, '/'); } -export const userOrAutoTitleFromSpecifier = (fileName: string, entry: NormalizedStoriesSpecifier, userTitle?: string) => { +export const userOrAutoTitleFromSpecifier = ( + fileName: string | number, + entry: NormalizedStoriesSpecifier, + userTitle?: string +) => { const { directory, importPathMatcher, titlePrefix = '' } = entry || {}; // On Windows, backslashes are used in paths, which can cause problems here // slash makes sure we always handle paths with unix-style forward slash - const normalizedFileName = slash(fileName); + + if (typeof fileName === 'number') { + once.warn(dedent` + CSF Auto-title received a numeric fileName. This typically happens when + webpack is mis-configured in production mode. To force webpack to produce + filenames, set optimization.moduleIds = "named" in your webpack config. + `); + } + + const normalizedFileName = slash(String(fileName)); if (importPathMatcher.exec(normalizedFileName)) { if (!userTitle) { @@ -74,11 +89,15 @@ export const userOrAutoTitleFromSpecifier = (fileName: string, entry: Normalized return undefined; }; -export const userOrAutoTitle = (fileName: string, storiesEntries: NormalizedStoriesSpecifier[], userTitle?: string) => { +export const userOrAutoTitle = ( + fileName: string, + storiesEntries: NormalizedStoriesSpecifier[], + userTitle?: string +) => { for (let i = 0; i < storiesEntries.length; i += 1) { const title = userOrAutoTitleFromSpecifier(fileName, storiesEntries[i], userTitle); if (title) return title; } return userTitle || undefined; -}; \ No newline at end of file +}; From e77f583467d3426c058486523d011fea0eb09cf9 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Tue, 24 May 2022 12:25:49 +0200 Subject: [PATCH 28/69] fix: Do not delete .idea while doing the cleanup It also makes sure only root level directories are excluded Closes #18308 --- scripts/reset.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/reset.js b/scripts/reset.js index 3641cea9315..afbd4ee9b07 100644 --- a/scripts/reset.js +++ b/scripts/reset.js @@ -11,8 +11,8 @@ const cleaningProcess = spawn('git', [ 'clean', '-xdf', '-n', - '--exclude=".vscode"', - '--exclude=".idea"', + '--exclude="/.vscode"', + '--exclude="/.idea"', ]); cleaningProcess.stdout.on('data', (data) => { From 9b3584989411cc9eb05622e7005349eb42211df4 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Tue, 24 May 2022 13:37:45 +0200 Subject: [PATCH 29/69] Tweak the language in case when a users decides not to run the script --- scripts/bootstrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index fa1d07f49e3..21e029464a1 100755 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -203,7 +203,7 @@ function run() { if (sure) { return list; } - throw new Error('problem is between keyboard and chair'); + throw new Error('Cleanup canceled'); }); } return list; From 8bdb1cdcb990f65d8f3d4667a782bb5618984cb7 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Tue, 24 May 2022 13:48:12 +0200 Subject: [PATCH 30/69] feat: Add cleanup task to bootstrap that removes compiled /dist folders --- package.json | 2 + scripts/bootstrap.js | 11 +++- yarn.lock | 153 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 158 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index c1c7debbca8..0713dc02c53 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "build-storybooks": "cross-env STORYBOOK_DISPLAY_WARNING=true DISPLAY_WARNING=true node -r esm ./scripts/build-storybooks.js", "changelog": "pr-log --sloppy --cherry-pick", "changelog:next": "pr-log --sloppy --since-prerelease", + "clean:dist": "del **/dist", "coverage": "codecov", "danger": "danger", "generate-repros": "zx scripts/repros-generator/index.mjs", @@ -228,6 +229,7 @@ "core-js": "^3.21.1", "cross-env": "^7.0.3", "danger": "^10.6.2", + "del-cli": "^4.0.1", "detect-port": "^1.3.0", "downlevel-dts": "^0.6.0", "dts-bundle-generator": "^6.2.0", diff --git a/scripts/bootstrap.js b/scripts/bootstrap.js index 21e029464a1..c7c07e9abdc 100755 --- a/scripts/bootstrap.js +++ b/scripts/bootstrap.js @@ -76,6 +76,15 @@ function run() { }, order: 1, }), + cleanup: createTask({ + name: `Remove compiled dist directories ${chalk.gray('(cleanup)')}`, + defaultValue: false, + option: '--cleanup', + command: () => { + spawn('npm run clean:dist'); + }, + order: 0, + }), reset: createTask({ name: `Clean repository ${chalk.red('(reset)')}`, defaultValue: false, @@ -142,7 +151,7 @@ function run() { const groups = { main: ['core'], buildtasks: ['install', 'build', 'manager'], - devtasks: ['dev', 'registry', 'reset'], + devtasks: ['dev', 'registry', 'cleanup', 'reset'], }; Object.keys(tasks) diff --git a/yarn.lock b/yarn.lock index fd9be8f2af5..dfb5cd913b5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8542,6 +8542,7 @@ __metadata: cross-env: ^7.0.3 cypress: 8.7.0 danger: ^10.6.2 + del-cli: ^4.0.1 detect-port: ^1.3.0 downlevel-dts: ^0.6.0 dts-bundle-generator: ^6.2.0 @@ -16257,6 +16258,18 @@ __metadata: languageName: node linkType: hard +"camelcase-keys@npm:^7.0.0": + version: 7.0.2 + resolution: "camelcase-keys@npm:7.0.2" + dependencies: + camelcase: ^6.3.0 + map-obj: ^4.1.0 + quick-lru: ^5.1.1 + type-fest: ^1.2.1 + checksum: ae86a51168643e9e8a2f2c7bfa17850729979ec3dafc5253056a7d97931cbb0e3ef5b4185e59d54b7a56c54405dee2874b0c82033498d8626e512ff9034cb05c + languageName: node + linkType: hard + "camelcase@npm:5.3.1, camelcase@npm:^5.0.0, camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -16278,7 +16291,7 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^6.0.0, camelcase@npm:^6.1.0, camelcase@npm:^6.2.0": +"camelcase@npm:^6.0.0, camelcase@npm:^6.1.0, camelcase@npm:^6.2.0, camelcase@npm:^6.3.0": version: 6.3.0 resolution: "camelcase@npm:6.3.0" checksum: 0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 @@ -19150,6 +19163,13 @@ __metadata: languageName: node linkType: hard +"decamelize@npm:^5.0.0": + version: 5.0.1 + resolution: "decamelize@npm:5.0.1" + checksum: 3da71022bc1e85487810fa0833138effb599fa331ca21e179650e93a765d0c4dabeb1ecdd6ad1474fa0bacd2457953c63ea335afb6e53b35f2b4bf779514e2a3 + languageName: node + linkType: hard + "decimal.js@npm:^10.2.1": version: 10.3.1 resolution: "decimal.js@npm:10.3.1" @@ -19363,6 +19383,19 @@ __metadata: languageName: node linkType: hard +"del-cli@npm:^4.0.1": + version: 4.0.1 + resolution: "del-cli@npm:4.0.1" + dependencies: + del: ^6.0.0 + meow: ^10.1.0 + bin: + del: cli.js + del-cli: cli.js + checksum: 01d314de214e7d96159f99d385186d90a71e0494a9262d98b8da15d144a22b894e0fae4d99d7c707cf3a50990f0513263c0e5b5b72ce5ad92f1ab1c7140e0f70 + languageName: node + linkType: hard + "del@npm:^2.2.0": version: 2.2.2 resolution: "del@npm:2.2.2" @@ -19393,6 +19426,22 @@ __metadata: languageName: node linkType: hard +"del@npm:^6.0.0": + version: 6.1.0 + resolution: "del@npm:6.1.0" + dependencies: + globby: ^11.0.1 + graceful-fs: ^4.2.4 + is-glob: ^4.0.1 + is-path-cwd: ^2.2.0 + is-path-inside: ^3.0.2 + p-map: ^4.0.0 + rimraf: ^3.0.2 + slash: ^3.0.0 + checksum: ce93c194f774ce2dcde8fa4dc44d29bf528f8e8fd27f4e70da8ddea6e56fc1a6dc0631c589399186a1f635f94d0f54e9549f48b90186674b3c602b14c4b82132 + languageName: node + linkType: hard + "delayed-stream@npm:0.0.5": version: 0.0.5 resolution: "delayed-stream@npm:0.0.5" @@ -26148,6 +26197,13 @@ __metadata: languageName: node linkType: hard +"indent-string@npm:^5.0.0": + version: 5.0.0 + resolution: "indent-string@npm:5.0.0" + checksum: 8ee77b57d92e71745e133f6f444d6fa3ed503ad0e1bcd7e80c8da08b42375c07117128d670589725ed07b1978065803fa86318c309ba45415b7fe13e7f170220 + languageName: node + linkType: hard + "indexes-of@npm:^1.0.1": version: 1.0.1 resolution: "indexes-of@npm:1.0.1" @@ -26946,7 +27002,7 @@ __metadata: languageName: node linkType: hard -"is-path-cwd@npm:^2.0.0": +"is-path-cwd@npm:^2.0.0, is-path-cwd@npm:^2.2.0": version: 2.2.0 resolution: "is-path-cwd@npm:2.2.0" checksum: afce71533a427a759cd0329301c18950333d7589533c2c90205bd3fdcf7b91eb92d1940493190567a433134d2128ec9325de2fd281e05be1920fbee9edd22e0a @@ -31159,7 +31215,7 @@ __metadata: languageName: node linkType: hard -"map-obj@npm:^4.0.0": +"map-obj@npm:^4.0.0, map-obj@npm:^4.1.0": version: 4.3.0 resolution: "map-obj@npm:4.3.0" checksum: 1c19e1c88513c8abdab25c316367154c6a0a6a0f77e3e8c391bb7c0e093aefed293f539d026dc013d86219e5e4c25f23b0003ea588be2101ccd757bacc12d43b @@ -31675,6 +31731,26 @@ __metadata: languageName: node linkType: hard +"meow@npm:^10.1.0": + version: 10.1.2 + resolution: "meow@npm:10.1.2" + dependencies: + "@types/minimist": ^1.2.2 + camelcase-keys: ^7.0.0 + decamelize: ^5.0.0 + decamelize-keys: ^1.1.0 + hard-rejection: ^2.1.0 + minimist-options: 4.1.0 + normalize-package-data: ^3.0.2 + read-pkg-up: ^8.0.0 + redent: ^4.0.0 + trim-newlines: ^4.0.2 + type-fest: ^1.2.2 + yargs-parser: ^20.2.9 + checksum: 8b4332e7b80b79188c2082ada65b592180a33e24aee76d2574ce1fb1c7542e8c8b65300c14abdfde984c1bffea429bf0d13670e00db36b326a7fd6e22dab9c9a + languageName: node + linkType: hard + "meow@npm:^3.1.0, meow@npm:^3.3.0": version: 3.7.0 resolution: "meow@npm:3.7.0" @@ -32320,7 +32396,7 @@ __metadata: languageName: node linkType: hard -"min-indent@npm:^1.0.0": +"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": version: 1.0.1 resolution: "min-indent@npm:1.0.1" checksum: 7e207bd5c20401b292de291f02913230cb1163abca162044f7db1d951fa245b174dc00869d40dd9a9f32a885ad6a5f3e767ee104cf278f399cb4e92d3f582d5c @@ -33369,7 +33445,7 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^3.0.0": +"normalize-package-data@npm:^3.0.0, normalize-package-data@npm:^3.0.2": version: 3.0.3 resolution: "normalize-package-data@npm:3.0.3" dependencies: @@ -34717,7 +34793,7 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^5.0.0": +"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: @@ -37652,6 +37728,13 @@ __metadata: languageName: node linkType: hard +"quick-lru@npm:^5.1.1": + version: 5.1.1 + resolution: "quick-lru@npm:5.1.1" + checksum: a24cba5da8cec30d70d2484be37622580f64765fb6390a928b17f60cd69e8dbd32a954b3ff9176fa1b86d86ff2ba05252fae55dc4d40d0291c60412b0ad096da + languageName: node + linkType: hard + "quick-temp@npm:^0.1.2, quick-temp@npm:^0.1.3, quick-temp@npm:^0.1.5, quick-temp@npm:^0.1.8": version: 0.1.8 resolution: "quick-temp@npm:0.1.8" @@ -38643,6 +38726,17 @@ __metadata: languageName: node linkType: hard +"read-pkg-up@npm:^8.0.0": + version: 8.0.0 + resolution: "read-pkg-up@npm:8.0.0" + dependencies: + find-up: ^5.0.0 + read-pkg: ^6.0.0 + type-fest: ^1.0.1 + checksum: cf3905ccbe5cd602f23192cc7ca65ed17561bab117eadb9aed817441d5bfc6b9a11215c2a3e9505f501d046818f3c4180dbea61fa83c42083e0b4e407d5cc745 + languageName: node + linkType: hard + "read-pkg@npm:^1.0.0": version: 1.1.0 resolution: "read-pkg@npm:1.1.0" @@ -38699,6 +38793,18 @@ __metadata: languageName: node linkType: hard +"read-pkg@npm:^6.0.0": + version: 6.0.0 + resolution: "read-pkg@npm:6.0.0" + dependencies: + "@types/normalize-package-data": ^2.4.0 + normalize-package-data: ^3.0.2 + parse-json: ^5.2.0 + type-fest: ^1.0.1 + checksum: b51ee5eed75324f4fac34c9a40b5e4b403de4c532242be01959c9bbdb1ff9db1c6c2aefaba569622fec49d1ead866e97ba856ab145f6e11039b11f7bec1318ba + languageName: node + linkType: hard + "read@npm:1, read@npm:~1.0.1": version: 1.0.7 resolution: "read@npm:1.0.7" @@ -38909,6 +39015,16 @@ __metadata: languageName: node linkType: hard +"redent@npm:^4.0.0": + version: 4.0.0 + resolution: "redent@npm:4.0.0" + dependencies: + indent-string: ^5.0.0 + strip-indent: ^4.0.0 + checksum: a9b640c8f4b2b5b26a1a908706475ff404dd50a97d6f094bc3c59717be922622927cc7d601d4ae2857d897ad243fd979bd76d751a0481cee8be7024e5fb4c662 + languageName: node + linkType: hard + "redeyed@npm:~1.0.0": version: 1.0.1 resolution: "redeyed@npm:1.0.1" @@ -42556,6 +42672,15 @@ __metadata: languageName: node linkType: hard +"strip-indent@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-indent@npm:4.0.0" + dependencies: + min-indent: ^1.0.1 + checksum: 6b1fb4e22056867f5c9e7a6f3f45922d9a2436cac758607d58aeaac0d3b16ec40b1c43317de7900f1b8dd7a4107352fa47fb960f2c23566538c51e8585c8870e + languageName: node + linkType: hard + "strip-json-comments@npm:2.0.1, strip-json-comments@npm:^2.0.0, strip-json-comments@npm:~2.0.1": version: 2.0.1 resolution: "strip-json-comments@npm:2.0.1" @@ -43980,6 +44105,13 @@ __metadata: languageName: node linkType: hard +"trim-newlines@npm:^4.0.2": + version: 4.0.2 + resolution: "trim-newlines@npm:4.0.2" + checksum: 48d022e9d14f27cf8b71983691af61cd8ce511d159ed0962452d2fa23f58298398d905e1ff982566f9034f93df3ef676868c1c14d13bcd849e7500dbfbd6101b + languageName: node + linkType: hard + "trim-right@npm:^1.0.1": version: 1.0.1 resolution: "trim-right@npm:1.0.1" @@ -44406,6 +44538,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^1.0.1, type-fest@npm:^1.2.1, type-fest@npm:^1.2.2": + version: 1.4.0 + resolution: "type-fest@npm:1.4.0" + checksum: a3c0f4ee28ff6ddf800d769eafafcdeab32efa38763c1a1b8daeae681920f6e345d7920bf277245235561d8117dab765cb5f829c76b713b4c9de0998a5397141 + languageName: node + linkType: hard + "type-is@npm:~1.6.17, type-is@npm:~1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -47860,7 +47999,7 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:20.x, yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.3, yargs-parser@npm:^20.2.7": +"yargs-parser@npm:20.x, yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.3, yargs-parser@npm:^20.2.7, yargs-parser@npm:^20.2.9": version: 20.2.9 resolution: "yargs-parser@npm:20.2.9" checksum: 0685a8e58bbfb57fab6aefe03c6da904a59769bd803a722bb098bd5b0f29d274a1357762c7258fb487512811b8063fb5d2824a3415a0a4540598335b3b086c72 From d548cdf77359352c0ef2397e621b6cc33d91f205 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Wed, 25 May 2022 11:39:49 +0300 Subject: [PATCH 31/69] (docs) Updated Angular styles Nx docs --- .../configure/css-troubleshooting/angular.mdx | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/configure/css-troubleshooting/angular.mdx b/docs/configure/css-troubleshooting/angular.mdx index ab6674b7547..d9c6c7a81dd 100644 --- a/docs/configure/css-troubleshooting/angular.mdx +++ b/docs/configure/css-troubleshooting/angular.mdx @@ -42,7 +42,11 @@ Additionally, if you need Storybook specific styles that are separate from your ``` ### Nx with Angular 13 -If you're working with Storybook and [NX libraries](https://nx.dev/structure/library-types), you can extend your project's configuration (i.e., `project.json`) and provide the application's styles. For example: + +If you're working with Storybook and [Nx libraries](https://nx.dev/structure/library-types), +you can extend your project's configuration (i.e., `project.json`) and provide the application's styles. + +For earlier Nx versions (prior to `14.1.8`), your configuration would look like this: ```json "build-storybook": { @@ -56,11 +60,35 @@ If you're working with Storybook and [NX libraries](https://nx.dev/structure/lib }, "projectBuildConfig": "example-lib:build-storybook", "styles": ["apps/example-app/src/styles.scss"] + } + } +``` + +Starting with version `14.1.8`, Nx uses the Storybook builder directly, which means any configuration supplied to the builder also applies to the NX setup. If you're working with a library, you'll need to configure the styling options ( e.g., preprocessors) inside the `build-storybook` `options` configuration object. For example: + +```json + "storybook": { + "executor": "@storybook/angular:start-storybook", + "options": { + "configDir": "apps/example-lib/.storybook", + "browserTarget": "example-lib:build-storybook", + }, }, - "configurations": { - "ci": { - "quiet": true + "build-storybook": { + "executor": "@storybook/angular:build-storybook", + "outputs": ["{options.outputPath}"], + "options": { + "outputDir": "dist/storybook/example-lib", + "configDir": "apps/example-lib/.storybook", + "browserTarget": "example-lib:build-storybook", + "styles": [".storybook/custom-styles.scss"], + "stylePreprocessorOptions": { + "includePaths": [ + "libs/design-system/src/lib" + ] + } } } - } ``` + +When Nx runs, it will load Storybook's configuration and styling based on the `storybook`'s [`browserTarget`](https://nx.dev/storybook/extra-topics-for-angular-projects#setting-up-browsertarget). From 930499e6a0980b20639fba050ec454515cafd6f1 Mon Sep 17 00:00:00 2001 From: inokawa <48897392+inokawa@users.noreply.github.com> Date: Wed, 25 May 2022 23:24:04 +0900 Subject: [PATCH 32/69] Fix not working link in cli-options.md --- docs/api/cli-options.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api/cli-options.md b/docs/api/cli-options.md index ae567dd6963..6ca92991ce9 100644 --- a/docs/api/cli-options.md +++ b/docs/api/cli-options.md @@ -5,7 +5,9 @@ title: 'CLI options' Storybook comes with two CLI utilities: `start-storybook` and `build-storybook`.
+ Storybook collects completely anonymous data to help us improve user experience. Participation is optional, and you may [opt-out](../configure/telemetry.md#how-to-opt-out) if you'd not like to share any information. +
Pass these commands the following options to alter Storybook's behavior. From 0ecf7593d034ed746aec20dd721b7674e6c624da Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Wed, 25 May 2022 16:22:00 +0100 Subject: [PATCH 33/69] updates Build pages with MSW set up --- ...orybook-main-with-single-static-dir.js.mdx | 6 +- .../common/storybook-msw-generate.msw.js.mdx | 3 + .../common/storybook-msw-install.npm.js.mdx | 3 + .../common/storybook-msw-install.yarn.js.mdx | 3 + ...torybook-preview-register-msw-addon.js.mdx | 25 ++++++++ .../build-pages-with-storybook.md | 62 ++++++++++++++++--- 6 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 docs/snippets/common/storybook-msw-generate.msw.js.mdx create mode 100644 docs/snippets/common/storybook-msw-install.npm.js.mdx create mode 100644 docs/snippets/common/storybook-msw-install.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-preview-register-msw-addon.js.mdx diff --git a/docs/snippets/common/storybook-main-with-single-static-dir.js.mdx b/docs/snippets/common/storybook-main-with-single-static-dir.js.mdx index 51f72b251d8..12ca0636ba6 100644 --- a/docs/snippets/common/storybook-main-with-single-static-dir.js.mdx +++ b/docs/snippets/common/storybook-main-with-single-static-dir.js.mdx @@ -2,8 +2,8 @@ // .storybook/main.js module.exports = { - stories: [], - addons: [], - staticDirs: ['../public'], + stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'], + staticDirs: ['../public'], //👈 Configures the static asset folder in Storybook }; ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-msw-generate.msw.js.mdx b/docs/snippets/common/storybook-msw-generate.msw.js.mdx new file mode 100644 index 00000000000..413d5bf267e --- /dev/null +++ b/docs/snippets/common/storybook-msw-generate.msw.js.mdx @@ -0,0 +1,3 @@ +```shell +npx msw init public/ +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-msw-install.npm.js.mdx b/docs/snippets/common/storybook-msw-install.npm.js.mdx new file mode 100644 index 00000000000..2a8608ebb29 --- /dev/null +++ b/docs/snippets/common/storybook-msw-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install msw msw-storybook-addon --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-msw-install.yarn.js.mdx b/docs/snippets/common/storybook-msw-install.yarn.js.mdx new file mode 100644 index 00000000000..ff285f0d717 --- /dev/null +++ b/docs/snippets/common/storybook-msw-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev msw msw-storybook-addon +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-preview-register-msw-addon.js.mdx b/docs/snippets/common/storybook-preview-register-msw-addon.js.mdx new file mode 100644 index 00000000000..d1b97095311 --- /dev/null +++ b/docs/snippets/common/storybook-preview-register-msw-addon.js.mdx @@ -0,0 +1,25 @@ +```js +// .storybook/preview.js + +import { initialize, mswDecorator } from 'msw-storybook-addon'; + +/* + * Initializes MSW + * See https://github.com/mswjs/msw-storybook-addon#configuring-msw + * to learn how to customize it + */ +initialize(); + +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +}; + +// Provide the MSW addon decorator globally +export const decorators = [mswDecorator]; +``` \ No newline at end of file diff --git a/docs/writing-stories/build-pages-with-storybook.md b/docs/writing-stories/build-pages-with-storybook.md index 9ebd55d0e8e..9bced0a9b45 100644 --- a/docs/writing-stories/build-pages-with-storybook.md +++ b/docs/writing-stories/build-pages-with-storybook.md @@ -2,7 +2,7 @@ title: 'Building pages with Storybook' --- -Storybook helps you build any component, from small “atomic” components to composed pages. But as you move up the component hierarchy toward the level of pages, you end up dealing with more complexity. +Storybook helps you build any component, from small “atomic” components to composed pages. But as you move up the component hierarchy toward the page level, you deal with more complexity. There are many ways to build pages in Storybook. Here are common patterns and solutions. @@ -47,7 +47,7 @@ When you are building screens in this way, it is typical that the inputs of a co -In such cases it is natural to use [args composition](./args.md#args-composition) to build the stories for the page based on the stories of the sub-components: +In such cases, it is natural to use [args composition](./args.md#args-composition) to build the stories for the page based on the stories of the sub-components: @@ -72,13 +72,57 @@ If you need to render a connected component in Storybook, you can mock the netwo ### Mocking providers -If you are using a provider that supplies data via the context, you can wrap your story in a decorator that provides a mocked version of that provider. For example, in the [Screens](https://storybook.js.org/tutorials/intro-to-storybook/react/en/screen/) chapter of the Intro to Storybook tutorial, we mock a Redux provider with mock data. +Suppose you are using a provider that supplies data via the context. In that case, you can wrap your story in a decorator that provides a mocked version of that provider. For example, in the [Screens](https://storybook.js.org/tutorials/intro-to-storybook/react/en/screen/) chapter of the Intro to Storybook tutorial, we mock a Redux provider with mock data. ### Mocking API Services -Connected applications such as Twitter, Instagram, amongst others, are everywhere, consuming data either from REST or GraphQL endpoints. If you're working in an application that relies on either of these data providers, you can add Mock Service Worker (MSW) via [Storybook's MSW addon](https://storybook.js.org/addons/msw-storybook-addon) to mock data alongside your app and stories. +Connected applications such as Twitter, Instagram, amongst others, are everywhere, consuming data from REST or GraphQL endpoints. Suppose you're working in an application that relies on either of these data providers. In that case, you can add Mock Service Worker (MSW) via [Storybook's MSW addon](https://storybook.js.org/addons/msw-storybook-addon) to mock data alongside your app and stories. -[Mock Service Worker](https://mswjs.io/) is an API mocking library. It relies on service workers to capture network requests and provides mocked data in response. The MSW addon adds this functionality into Storybook, allowing you to mock API requests in your stories. +[Mock Service Worker](https://mswjs.io/) is an API mocking library. It relies on service workers to capture network requests and provides mocked data in response. The MSW addon adds this functionality into Storybook, allowing you to mock API requests in your stories. Below is an overview of how to set up and use the addon. + +Run the following commands to install MSW, the addon, and generate a mock service worker. + + + + + + + +
+ +💡 If you're working with Angular, you'll need to adjust the command to save the mock service worker file in a different directory (e.g., `src`). + +
+ +Update your `.storybook/preview.js` file and enable the addon via a [global decorator](./decorators.md#global-decorators). + + + + + + + +Finally, update your [`.storybook/main.js|ts`](../configure/overview.md#using-storybook-api) to allow Storybook to load the generated mock service worker file as follows: + + + + + + #### Mocking REST requests with MSW addon @@ -157,7 +201,7 @@ To test your screen with the GraphQL mocked data, you could write the following It is also possible to mock imports directly, as you might in a unit test, using Webpack’s aliasing. It's advantageous if your component makes network requests directly with third-party libraries. -We're going to use [isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch) as an example. +We'll use [isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch) as an example. Inside a directory called `__mocks__`, create a new file called `isomorphic-fetch.js` with the following code: @@ -223,7 +267,7 @@ Like the [import mocking](##mocking-imports) above, once you have a mock, you’ It's possible to avoid mocking the dependencies of connected "container" components entirely by passing them around via props or React context. However, it requires a strict split of the container and presentational component logic. For example, if you have a component responsible for data fetching logic and rendering DOM, it will need to be mocked as previously described. -It’s common to import and embed container components amongst presentational components. However, as we discovered earlier, to render them within Storybook, we’ll likely have to mock their dependencies or the imports themselves. +It’s common to import and embed container components amongst presentational components. However, as we discovered earlier, we’ll likely have to mock their dependencies or the imports to render them within Storybook. Not only can this quickly grow to become a tedious task, but it’s also challenging to mock container components that use local states. So, instead of importing containers directly, a solution to this problem is to create a React context that provides the container components. It allows you to freely embed container components as usual, at any level in the component hierarchy without worrying about subsequently mocking their dependencies; since we can swap out the containers themselves with their mocked presentational counterpart. @@ -238,7 +282,7 @@ ProfilePageContext.js
-It’s also often helpful to set up a “global” container context (perhaps named `GlobalContainerContext`) for container components that may be rendered on every page of your app and adding them to the top level of your application. While it’s possible to place every container within this global context, it should only provide globally required containers. +It’s also often helpful to set up a “global” container context (perhaps named `GlobalContainerContext`) for container components that may be rendered on every page of your app and add them to the top level of your application. While it’s possible to place every container within this global context, it should only provide globally required containers.
@@ -284,7 +328,7 @@ In the context of Storybook, instead of providing container components through c
-If the same context applies to all `ProfilePage` stories, we can also use a [decorator](./decorators.md). +If the same context applies to all `ProfilePage` stories, we can use a [decorator](./decorators.md).
From d001760cf5691644f412b6f7fe8deb686e95168a Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 25 May 2022 22:15:10 +0200 Subject: [PATCH 34/69] feat: bump ip to 2.0.0 --- lib/core-server/package.json | 2 +- yarn.lock | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/core-server/package.json b/lib/core-server/package.json index af967ab9206..1ad69bfb556 100644 --- a/lib/core-server/package.json +++ b/lib/core-server/package.json @@ -68,7 +68,7 @@ "fs-extra": "^9.0.1", "global": "^4.4.0", "globby": "^11.0.2", - "ip": "^1.1.5", + "ip": "^2.0.0", "lodash": "^4.17.21", "node-fetch": "^2.6.7", "open": "^8.4.0", diff --git a/yarn.lock b/yarn.lock index dfb5cd913b5..342557e467e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7689,7 +7689,7 @@ __metadata: fs-extra: ^9.0.1 global: ^4.4.0 globby: ^11.0.2 - ip: ^1.1.5 + ip: ^2.0.0 jest-specific-snapshot: ^4.0.0 lodash: ^4.17.21 node-fetch: ^2.6.7 @@ -26453,6 +26453,13 @@ __metadata: languageName: node linkType: hard +"ip@npm:^2.0.0": + version: 2.0.0 + resolution: "ip@npm:2.0.0" + checksum: 8d186cc5585f57372847ae29b6eba258c68862055e18a75cc4933327232cb5c107f89800ce29715d542eef2c254fbb68b382e780a7414f9ee7caf60b7a473958 + languageName: node + linkType: hard + "ipaddr.js@npm:1.9.1, ipaddr.js@npm:^1.9.0": version: 1.9.1 resolution: "ipaddr.js@npm:1.9.1" From 8fc24f2f180f403b8c7d2a5f03cddce807322265 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Fri, 27 May 2022 12:02:27 +0800 Subject: [PATCH 35/69] Addon-a11y: Skip flakey tests Also, this should use SB interaction testing --- addons/a11y/src/components/VisionSimulator.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/a11y/src/components/VisionSimulator.test.tsx b/addons/a11y/src/components/VisionSimulator.test.tsx index 51b41cdba5c..cb1d43ede51 100644 --- a/addons/a11y/src/components/VisionSimulator.test.tsx +++ b/addons/a11y/src/components/VisionSimulator.test.tsx @@ -30,7 +30,7 @@ describe('Vision Simulator', () => { await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); }); - it('should display tooltip on click', async () => { + it.skip('should display tooltip on click', async () => { // given render(); await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); From 6ca9090234a173e8a9d948e6332c3fb26aa203b2 Mon Sep 17 00:00:00 2001 From: Jimmy Somsanith Date: Fri, 27 May 2022 13:04:09 +0200 Subject: [PATCH 36/69] skip the flaky test --- addons/a11y/src/components/VisionSimulator.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/a11y/src/components/VisionSimulator.test.tsx b/addons/a11y/src/components/VisionSimulator.test.tsx index cb1d43ede51..e77de439208 100644 --- a/addons/a11y/src/components/VisionSimulator.test.tsx +++ b/addons/a11y/src/components/VisionSimulator.test.tsx @@ -30,7 +30,7 @@ describe('Vision Simulator', () => { await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); }); - it.skip('should display tooltip on click', async () => { + it('should display tooltip on click', async () => { // given render(); await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); @@ -45,7 +45,7 @@ describe('Vision Simulator', () => { ); }); - it('should set filter', async () => { + it.skip('should set filter', async () => { // given render(); await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); From 100450e9503222a3812d28b0d2d3b912e9c22be7 Mon Sep 17 00:00:00 2001 From: Chris Dillon Date: Fri, 27 May 2022 09:53:18 -0700 Subject: [PATCH 37/69] fix: Syntax error in vite builder docs Just a missing comma in the object. --- docs/snippets/common/storybook-vite-builder-aliasing.js.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx b/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx index af94f7ec987..223d5bb2a4a 100644 --- a/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx +++ b/docs/snippets/common/storybook-vite-builder-aliasing.js.mdx @@ -13,7 +13,7 @@ module.exports = { // Merge custom configuration into the default config return mergeConfig(config, { // Use the same "resolve" configuration as your app - resolve: (await import('../vite.config.js')).default.resolve + resolve: (await import('../vite.config.js')).default.resolve, // Add dependencies to pre-optimization optimizeDeps: { include: ['storybook-dark-mode'], From f7ff4b95dc8b1e344be2fc0e31ad90b3145812ce Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Fri, 27 May 2022 19:39:08 +0100 Subject: [PATCH 38/69] Updates jest snippets to address jest 28 --- docs/faq.md | 4 ++++ docs/snippets/common/storybook-test-runner-install.npm.js.mdx | 2 +- .../snippets/common/storybook-test-runner-install.yarn.js.mdx | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index a76ebab17e5..766f29ed4ad 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -472,3 +472,7 @@ export default { }, }; ``` + +### Why isn't Storybook's test runner working? + +There's an issue with Storybook's test runner and the latest version of Jest (i.e., version 28), which prevents it from running effectively. As a workaround, you can downgrade Jest to the previous stable version (i.e., version 27), and you'll be able to run it. See the following [issue](https://github.com/storybookjs/test-runner/issues/99) for more information. \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-install.npm.js.mdx b/docs/snippets/common/storybook-test-runner-install.npm.js.mdx index 90f046c3ec6..42ab4d4a456 100644 --- a/docs/snippets/common/storybook-test-runner-install.npm.js.mdx +++ b/docs/snippets/common/storybook-test-runner-install.npm.js.mdx @@ -1,3 +1,3 @@ ```shell -npm install @storybook/test-runner jest --save-dev +npm install @storybook/test-runner jest@27.5.1 --save-dev ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx index 3221e525779..53bfe1f72ff 100644 --- a/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx +++ b/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx @@ -1,3 +1,3 @@ ```shell -yarn add --dev @storybook/test-runner jest +yarn add --dev @storybook/test-runner jest@27.5.1 ``` \ No newline at end of file From 175ab5256a8b20b671b2be84eb2fbc28f2370e52 Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Fri, 27 May 2022 21:10:53 +0100 Subject: [PATCH 39/69] remove specific version --- docs/snippets/common/storybook-test-runner-install.npm.js.mdx | 2 +- docs/snippets/common/storybook-test-runner-install.yarn.js.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/snippets/common/storybook-test-runner-install.npm.js.mdx b/docs/snippets/common/storybook-test-runner-install.npm.js.mdx index 42ab4d4a456..50b39891c2b 100644 --- a/docs/snippets/common/storybook-test-runner-install.npm.js.mdx +++ b/docs/snippets/common/storybook-test-runner-install.npm.js.mdx @@ -1,3 +1,3 @@ ```shell -npm install @storybook/test-runner jest@27.5.1 --save-dev +npm install @storybook/test-runner jest@27 --save-dev ``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx b/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx index 53bfe1f72ff..79840bb5b1b 100644 --- a/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx +++ b/docs/snippets/common/storybook-test-runner-install.yarn.js.mdx @@ -1,3 +1,3 @@ ```shell -yarn add --dev @storybook/test-runner jest@27.5.1 +yarn add --dev @storybook/test-runner jest@27 ``` \ No newline at end of file From f3e932e2477afc7e24809061db35cf52c757c1cd Mon Sep 17 00:00:00 2001 From: inokawa <48897392+inokawa@users.noreply.github.com> Date: Sat, 28 May 2022 15:17:03 +0900 Subject: [PATCH 40/69] Fix link to typescript --- docs/builders/webpack.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/builders/webpack.md b/docs/builders/webpack.md index a2571d22ea0..768b4ab2ee9 100644 --- a/docs/builders/webpack.md +++ b/docs/builders/webpack.md @@ -193,11 +193,11 @@ When working with TypeScript projects, the default Webpack configuration may fai
-💡 Learn more about Storybook's built-in TypeScript support or see this issue for more information. +💡 Learn more about Storybook's built-in TypeScript support or see this issue for more information.
#### Learn more about builders - [Vite builder](./vite.md) for bundling with Vite - [Webpack builder](./webpack.md) for bundling with Webpack -- [Builder API](./builder-api.md) for building a Storybook builder \ No newline at end of file +- [Builder API](./builder-api.md) for building a Storybook builder From 8800d235a3f2ce281ebc0970074a77012ab9ad17 Mon Sep 17 00:00:00 2001 From: Jimmy Somsanith Date: Sat, 28 May 2022 13:19:51 +0200 Subject: [PATCH 41/69] Skip failiing test --- addons/a11y/src/components/VisionSimulator.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/a11y/src/components/VisionSimulator.test.tsx b/addons/a11y/src/components/VisionSimulator.test.tsx index e77de439208..9191e058db6 100644 --- a/addons/a11y/src/components/VisionSimulator.test.tsx +++ b/addons/a11y/src/components/VisionSimulator.test.tsx @@ -30,7 +30,7 @@ describe('Vision Simulator', () => { await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); }); - it('should display tooltip on click', async () => { + it.skip('should display tooltip on click', async () => { // given render(); await waitFor(() => expect(screen.getByTitle('Vision simulator')).toBeInTheDocument()); From dc497289e5c0127e6172f5a2c57f9a2ed2718d7f Mon Sep 17 00:00:00 2001 From: saseungmin Date: Sun, 29 May 2022 00:21:46 +0900 Subject: [PATCH 42/69] [Fix] Tyop in storybook-main-enable-transcludemarkdown.js.mdx - Fix to code snippets in "https://storybook.js.org/docs/7.0/react/writing-docs/mdx" - Fix typo storybook-main-enable-transcludemarkdown.js.mdx --- .../common/storybook-main-enable-transcludemarkdown.js.mdx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx b/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx index ab8a8a2b063..cb07d576345 100644 --- a/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx +++ b/docs/snippets/common/storybook-main-enable-transcludemarkdown.js.mdx @@ -1,3 +1,4 @@ +```js // .storybook/main.js|ts module.exports = { @@ -17,4 +18,5 @@ module.exports = { }, }, ], -}; \ No newline at end of file +}; +``` From 0c0a21b030ebf1329448a25d0a043a5c728de6a3 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 30 May 2022 09:42:03 +0200 Subject: [PATCH 43/69] chore: clean verdaccio cache when running locally --- scripts/run-registry.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/run-registry.ts b/scripts/run-registry.ts index 1c4a3807822..313c828afda 100755 --- a/scripts/run-registry.ts +++ b/scripts/run-registry.ts @@ -1,4 +1,5 @@ import { exec } from 'child_process'; +import { remove, pathExists } from 'fs-extra'; import chalk from 'chalk'; import path from 'path'; import program from 'commander'; @@ -176,6 +177,16 @@ const run = async () => { logger.log(`📐 reading version of storybook`); logger.log(`🚛 listing storybook packages`); + + if (!process.env.CI) { + // when running e2e locally, clear cache to avoid EPUBLISHCONFLICT errors + const verdaccioCache = path.resolve(__dirname, '..', '.verdaccio-cache'); + if (await pathExists(verdaccioCache)) { + logger.log(`🗑 cleaning up cache`); + await remove(verdaccioCache); + } + } + logger.log(`🎬 starting verdaccio (this takes ±5 seconds, so be patient)`); const [verdaccioServer, packages, version] = await Promise.all([ From 03c5026744a4988fdc3623c1494d6efe58ef786d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 30 May 2022 15:57:54 +0200 Subject: [PATCH 44/69] Turn off Emotion's warnings about potentially unsafe pseudo-selectors in SSR --- lib/ui/src/index.tsx | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/lib/ui/src/index.tsx b/lib/ui/src/index.tsx index b7a5ea06547..45ee6f86a45 100644 --- a/lib/ui/src/index.tsx +++ b/lib/ui/src/index.tsx @@ -7,13 +7,21 @@ import ReactDOM from 'react-dom'; import { Location, LocationProvider, useNavigate } from '@storybook/router'; import { Provider as ManagerProvider, Combo } from '@storybook/api'; -import { ThemeProvider, ensure as ensureTheme } from '@storybook/theming'; +import { + ThemeProvider, + ensure as ensureTheme, + CacheProvider, + createCache, +} from '@storybook/theming'; import { HelmetProvider } from 'react-helmet-async'; import App from './app'; import Provider from './provider'; +const emotionCache = createCache({ key: 'sto' }); +emotionCache.compat = true; + const { DOCS_MODE } = global; // @ts-ignore @@ -66,15 +74,17 @@ const Main: FC<{ provider: Provider }> = ({ provider }) => { : !state.storiesFailed && !state.storiesConfigured; return ( - - - + + + + + ); }} From 0facbafafc12ff72630f3414ba111d4b6f9dd2dc Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 30 May 2022 18:19:40 +0200 Subject: [PATCH 45/69] docs(README): update version badges --- README.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0472ab5a1ac..df9b875b9e3 100644 --- a/README.md +++ b/README.md @@ -51,8 +51,8 @@ It allows you to browse a component library, view the different states of each c

View README for:
- latest - next + latest + next

## Table of contents @@ -92,19 +92,19 @@ For additional help, join us in the [Storybook Discord](https://discord.gg/story ### Supported Frameworks -| Framework | Demo | | -| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| [React](app/react) | [v6.4.x](https://storybookjs.netlify.com/official-storybook/?path=/story/*) | [![React](https://img.shields.io/npm/dm/@storybook/react.svg)](app/react) | -| [Vue](app/vue) | [v6.4.x](https://storybookjs.netlify.com/vue-kitchen-sink/) | [![Vue](https://img.shields.io/npm/dm/@storybook/vue.svg)](app/vue) | -| [Angular](app/angular) | [v6.4.x](https://storybookjs.netlify.com/angular-cli/) | [![Angular](https://img.shields.io/npm/dm/@storybook/angular.svg)](app/angular) | -| [Web components](app/web-components) | [v6.4.x](https://storybookjs.netlify.com/web-components-kitchen-sink/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/web-components.svg)](app/web-components) | -| [React Native](https://github.com/storybookjs/react-native) | - | [![React Native](https://img.shields.io/npm/dm/@storybook/react-native.svg)](https://github.com/storybookjs/react-native) | -| [HTML](app/html) | [v6.4.x](https://storybookjs.netlify.com/html-kitchen-sink/) | [![HTML](https://img.shields.io/npm/dm/@storybook/html.svg)](app/html) | -| [Ember](app/ember) | [v6.4.x](https://storybookjs.netlify.com/ember-cli/) | [![Ember](https://img.shields.io/npm/dm/@storybook/ember.svg)](app/ember) | -| [Svelte](app/svelte) | [v6.4.x](https://storybookjs.netlify.com/svelte-kitchen-sink/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/svelte.svg)](app/svelte) | -| [Preact](app/preact) | [v6.4.x](https://storybookjs.netlify.com/preact-kitchen-sink/) | [![Preact](https://img.shields.io/npm/dm/@storybook/preact.svg)](app/preact) | -| [Marionette.js](https://github.com/storybookjs/marionette) | - | [![Marionette.js](https://img.shields.io/npm/dm/@storybook/marionette.svg)](https://github.com/storybookjs/marionette) | -| [Android, iOS, Flutter](https://github.com/storybookjs/native) | [v6.4.x](https://storybookjs.github.io/native/@storybook/native-flutter-example/index.html) | [![Native](https://img.shields.io/npm/dm/@storybook/native.svg)](https://github.com/storybookjs/native) | +| Framework | Demo | | +| -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| [React](app/react) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/react/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/official-storybook/?path=/story/*) | [![React](https://img.shields.io/npm/dm/@storybook/react?style=flat-square&color=eee)](app/react) | +| [Vue](app/vue) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/vue/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/vue-kitchen-sink/) | [![Vue](https://img.shields.io/npm/dm/@storybook/vue?style=flat-square&color=eee)](app/vue) | +| [Angular](app/angular) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/angular/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/angular-cli/) | [![Angular](https://img.shields.io/npm/dm/@storybook/angular?style=flat-square&color=eee)](app/angular) | +| [Web components](app/web-components) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/web-components/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/web-components-kitchen-sink/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/web-components?style=flat-square&color=eee)](app/web-components) | +| [React Native](https://github.com/storybookjs/react-native) | - | [![React Native](https://img.shields.io/npm/dm/@storybook/react-native?style=flat-square&color=eee)](https://github.com/storybookjs/react-native) | +| [HTML](app/html) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/html/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/html-kitchen-sink/) | [![HTML](https://img.shields.io/npm/dm/@storybook/html?style=flat-square&color=eee)](app/html) | +| [Ember](app/ember) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/ember/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/ember-cli/) | [![Ember](https://img.shields.io/npm/dm/@storybook/ember?style=flat-square&color=eee)](app/ember) | +| [Svelte](app/svelte) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/svelte/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/svelte-kitchen-sink/) | [![Svelte](https://img.shields.io/npm/dm/@storybook/svelte?style=flat-square&color=eee)](app/svelte) | +| [Preact](app/preact) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/preact/latest?style=flat-square&color=blue&label)](https://storybookjs.netlify.com/preact-kitchen-sink/) | [![Preact](https://img.shields.io/npm/dm/@storybook/preact?style=flat-square&color=eee)](app/preact) | +| [Marionette.js](https://github.com/storybookjs/marionette) | - | [![Marionette.js](https://img.shields.io/npm/dm/@storybook/marionette?style=flat-square&color=eee)](https://github.com/storybookjs/marionette) | +| [Android, iOS, Flutter](https://github.com/storybookjs/native) | [![Storybook demo](https://img.shields.io/npm/v/@storybook/native/latest?style=flat-square&color=blue&label)](https://storybookjs.github.io/native/@storybook/native-flutter-example/index.html) | [![Native](https://img.shields.io/npm/dm/@storybook/native?style=flat-square&color=eee)](https://github.com/storybookjs/native) | ### Sub Projects From ca86e9d3900a342d48a624d8584bd57f544ad0d5 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 31 May 2022 14:09:21 +1000 Subject: [PATCH 46/69] Drop `ignoreSsrWarning` workaround --- .../src/blocks/ArgsTable/ArgsTable.tsx | 16 ++++++++-------- lib/components/src/blocks/Source.tsx | 4 ++-- lib/components/src/spaced/Spaced.tsx | 6 +++--- lib/components/src/tabs/tabs.tsx | 5 +---- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/components/src/blocks/ArgsTable/ArgsTable.tsx b/lib/components/src/blocks/ArgsTable/ArgsTable.tsx index f5651b6f925..f353984140e 100644 --- a/lib/components/src/blocks/ArgsTable/ArgsTable.tsx +++ b/lib/components/src/blocks/ArgsTable/ArgsTable.tsx @@ -1,6 +1,6 @@ import React, { FC } from 'react'; import pickBy from 'lodash/pickBy'; -import { styled, ignoreSsrWarning } from '@storybook/theming'; +import { styled } from '@storybook/theming'; import { opacify, transparentize, darken, lighten } from 'polished'; import { includeConditionalArg } from '@storybook/csf'; import { once } from '@storybook/client-logger'; @@ -111,20 +111,20 @@ export const TableWrapper = styled.table<{ marginLeft: inAddonPanel ? 0 : 1, marginRight: inAddonPanel ? 0 : 1, - [`tr:first-child${ignoreSsrWarning}`]: { - [`td:first-child${ignoreSsrWarning}, th:first-child${ignoreSsrWarning}`]: { + [`tr:first-child`]: { + [`td:first-child, th:first-child`]: { borderTopLeftRadius: inAddonPanel ? 0 : theme.appBorderRadius, }, - [`td:last-child${ignoreSsrWarning}, th:last-child${ignoreSsrWarning}`]: { + [`td:last-child, th:last-child`]: { borderTopRightRadius: inAddonPanel ? 0 : theme.appBorderRadius, }, }, - [`tr:last-child${ignoreSsrWarning}`]: { - [`td:first-child${ignoreSsrWarning}, th:first-child${ignoreSsrWarning}`]: { + [`tr:last-child`]: { + [`td:first-child, th:first-child`]: { borderBottomLeftRadius: inAddonPanel ? 0 : theme.appBorderRadius, }, - [`td:last-child${ignoreSsrWarning}, th:last-child${ignoreSsrWarning}`]: { + [`td:last-child, th:last-child`]: { borderBottomRightRadius: inAddonPanel ? 0 : theme.appBorderRadius, }, }, @@ -172,7 +172,7 @@ export const TableWrapper = styled.table<{ : lighten(0.05, theme.background.content), } : { - [`&:not(:first-child${ignoreSsrWarning})`]: { + [`&:not(:first-child)`]: { borderTopWidth: 1, borderTopStyle: 'solid', borderTopColor: diff --git a/lib/components/src/blocks/Source.tsx b/lib/components/src/blocks/Source.tsx index c71429c020e..4d79f1807b0 100644 --- a/lib/components/src/blocks/Source.tsx +++ b/lib/components/src/blocks/Source.tsx @@ -1,5 +1,5 @@ import React, { ComponentProps, FunctionComponent } from 'react'; -import { styled, ThemeProvider, convert, themes, ignoreSsrWarning } from '@storybook/theming'; +import { styled, ThemeProvider, convert, themes } from '@storybook/theming'; import { EmptyBlock } from './EmptyBlock'; import { SyntaxHighlighter } from '../syntaxhighlighter/lazy-syntaxhighlighter'; @@ -52,7 +52,7 @@ const SourceSkeletonPlaceholder = styled.div<{}>(({ theme }) => ({ marginTop: 1, width: '60%', - [`&:first-child${ignoreSsrWarning}`]: { + [`&:first-child`]: { margin: 0, }, })); diff --git a/lib/components/src/spaced/Spaced.tsx b/lib/components/src/spaced/Spaced.tsx index 8ce2e6274b6..90460605a6a 100644 --- a/lib/components/src/spaced/Spaced.tsx +++ b/lib/components/src/spaced/Spaced.tsx @@ -1,5 +1,5 @@ import React, { FunctionComponent } from 'react'; -import { styled, ignoreSsrWarning } from '@storybook/theming'; +import { styled } from '@storybook/theming'; const toNumber = (input: any) => (typeof input === 'number' ? input : Number(input)); @@ -19,7 +19,7 @@ const Container = styled.div( marginLeft: col * theme.layoutMargin, verticalAlign: 'inherit', }, - [`& > *:first-child${ignoreSsrWarning}`]: { + [`& > *:first-child`]: { marginLeft: 0, }, } @@ -27,7 +27,7 @@ const Container = styled.div( '& > *': { marginTop: row * theme.layoutMargin, }, - [`& > *:first-child${ignoreSsrWarning}`]: { + [`& > *:first-child`]: { marginTop: 0, }, }, diff --git a/lib/components/src/tabs/tabs.tsx b/lib/components/src/tabs/tabs.tsx index 8152a883742..57065e9dfe9 100644 --- a/lib/components/src/tabs/tabs.tsx +++ b/lib/components/src/tabs/tabs.tsx @@ -15,9 +15,6 @@ import { Placeholder } from '../placeholder/placeholder'; import { FlexBar } from '../bar/bar'; import { TabButton } from '../bar/button'; -const ignoreSsrWarning = - '/* emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason */'; - export interface WrapperProps { bordered?: boolean; absolute?: boolean; @@ -87,7 +84,7 @@ const Content = styled.div( bottom: 0 + (bordered ? 1 : 0), top: 40 + (bordered ? 1 : 0), overflow: 'auto', - [`& > *:first-child${ignoreSsrWarning}`]: { + [`& > *:first-child`]: { position: 'absolute', left: 0 + (bordered ? 1 : 0), right: 0 + (bordered ? 1 : 0), From d42b8b76c4fb76d4e22edd311fe2d80564c595c9 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 31 May 2022 15:16:28 +1000 Subject: [PATCH 47/69] Fix lint warning in preview web test --- .../src/PreviewWeb.integration.test.ts | 5 +- lib/preview-web/src/PreviewWeb.test.ts | 437 +++++++++--------- 2 files changed, 221 insertions(+), 221 deletions(-) diff --git a/lib/preview-web/src/PreviewWeb.integration.test.ts b/lib/preview-web/src/PreviewWeb.integration.test.ts index 2e452c167c4..34b7434b8b2 100644 --- a/lib/preview-web/src/PreviewWeb.integration.test.ts +++ b/lib/preview-web/src/PreviewWeb.integration.test.ts @@ -76,8 +76,9 @@ describe('PreviewWeb', () => { const preview = new PreviewWeb(); const docsRoot = window.document.createElement('div'); - // @ts-ignore - preview.view.prepareForDocs.mockReturnValue(docsRoot); + ( + preview.view.prepareForDocs as any as jest.Mock + ).mockReturnValue(docsRoot); componentOneExports.default.parameters.docs.container.mockImplementationOnce(() => React.createElement('div', {}, 'INSIDE') ); diff --git a/lib/preview-web/src/PreviewWeb.test.ts b/lib/preview-web/src/PreviewWeb.test.ts index ba915bbf1bc..016a079e64f 100644 --- a/lib/preview-web/src/PreviewWeb.test.ts +++ b/lib/preview-web/src/PreviewWeb.test.ts @@ -1,7 +1,30 @@ import global from 'global'; import * as ReactDOM from 'react-dom'; import merge from 'lodash/merge'; -import Events, { IGNORED_EXCEPTION } from '@storybook/core-events'; +import Events, { + CONFIG_ERROR, + CURRENT_STORY_WAS_SET, + DOCS_RENDERED, + FORCE_REMOUNT, + FORCE_RE_RENDER, + GLOBALS_UPDATED, + IGNORED_EXCEPTION, + PREVIEW_KEYDOWN, + RESET_STORY_ARGS, + SET_CURRENT_STORY, + SET_GLOBALS, + STORY_ARGS_UPDATED, + STORY_CHANGED, + STORY_ERRORED, + STORY_MISSING, + STORY_PREPARED, + STORY_RENDERED, + STORY_SPECIFIED, + STORY_THREW_EXCEPTION, + STORY_UNCHANGED, + UPDATE_GLOBALS, + UPDATE_STORY_ARGS, +} from '@storybook/core-events'; import { logger } from '@storybook/client-logger'; import { addons, mockChannel as createMockChannel } from '@storybook/addons'; import type { AnyFramework } from '@storybook/csf'; @@ -100,10 +123,10 @@ beforeEach(() => { projectAnnotations.renderToDOM.mockReset(); projectAnnotations.render.mockClear(); projectAnnotations.decorators[0].mockClear(); - // @ts-ignore - ReactDOM.render.mockReset().mockImplementation((_: any, _2: any, cb: () => any) => cb()); - // @ts-ignore - logger.warn.mockClear(); + (ReactDOM.render as any as jest.Mock) + .mockReset() + .mockImplementation((_: any, _2: any, cb: () => any) => cb()); + (logger.warn as jest.Mock).mockClear(); mockStoryIndex.mockReset().mockReturnValue(storyIndex); addons.setChannel(mockChannel as any); @@ -126,7 +149,7 @@ describe('PreviewWeb', () => { ).rejects.toThrow(err); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, err); + expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, err); }); it('shows an error if the stories.json endpoint 500s', async () => { @@ -139,7 +162,7 @@ describe('PreviewWeb', () => { ); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error)); + expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, expect.any(Error)); }); it('sets globals from the URL', async () => { @@ -153,7 +176,7 @@ describe('PreviewWeb', () => { it('emits the SET_GLOBALS event', async () => { await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, { + expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, { globals: { a: 'b' }, globalTypes: {}, }); @@ -162,7 +185,7 @@ describe('PreviewWeb', () => { it('SET_GLOBALS sets globals and types even when undefined', async () => { await createAndRenderPreview({ getProjectAnnotations: () => ({ renderToDOM: jest.fn() }) }); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, { + expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, { globals: {}, globalTypes: {}, }); @@ -173,7 +196,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, { + expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, { globals: { a: 'c' }, globalTypes: {}, }); @@ -193,7 +216,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'url' }, }); @@ -234,7 +257,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_SPECIFIED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_SPECIFIED, { storyId: 'component-one--a', viewMode: 'story', }); @@ -245,7 +268,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, { + expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, { storyId: 'component-one--a', viewMode: 'story', }); @@ -258,7 +281,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'random'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'random'); }); it('tries again with a specifier if CSF file changes', async () => { @@ -267,7 +290,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--d'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--d'); mockChannel.emit.mockClear(); const newComponentOneExports = merge({}, componentOneExports, { @@ -295,7 +318,7 @@ describe('PreviewWeb', () => { }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_SPECIFIED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_SPECIFIED, { storyId: 'component-one--d', viewMode: 'story', }); @@ -311,9 +334,9 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--d'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--d'); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -343,7 +366,7 @@ describe('PreviewWeb', () => { }, }, }); - expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_SPECIFIED, { + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_SPECIFIED, { storyId: 'component-one--d', viewMode: 'story', }); @@ -355,7 +378,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); expect(preview.view.showNoPreview).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING); }); describe('in story viewMode', () => { @@ -375,7 +398,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, { id: 'component-one--a', parameters: { __isArgsStory: false, @@ -441,7 +464,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -454,7 +477,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -490,7 +513,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -503,7 +526,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({ message: error.title, stack: error.description, @@ -519,7 +542,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -534,7 +557,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); it('does not show error display if the render function throws IGNORED_EXCEPTION', async () => { @@ -548,10 +571,7 @@ describe('PreviewWeb', () => { await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith( - Events.STORY_THREW_EXCEPTION, - IGNORED_EXCEPTION - ); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, IGNORED_EXCEPTION); expect(preview.view.showErrorDisplay).not.toHaveBeenCalled(); }); }); @@ -568,7 +588,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a&viewMode=docs'; await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, { id: 'component-one--a', parameters: { __isArgsStory: false, @@ -607,7 +627,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.DOCS_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'component-one--a'); }); }); }); @@ -617,10 +637,10 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } }); + emitter.emit(UPDATE_GLOBALS, { globals: { foo: 'bar' } }); - await waitForEvents([Events.GLOBALS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.GLOBALS_UPDATED, { + await waitForEvents([GLOBALS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(GLOBALS_UPDATED, { globals: { a: 'b', foo: 'bar' }, initialGlobals: { a: 'b' }, }); @@ -630,7 +650,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } }); + emitter.emit(UPDATE_GLOBALS, { globals: { foo: 'bar' } }); expect(preview.storyStore.globals.get()).toEqual({ a: 'b', foo: 'bar' }); }); @@ -641,7 +661,7 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); projectAnnotations.renderToDOM.mockClear(); - emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } }); + emitter.emit(UPDATE_GLOBALS, { globals: { foo: 'bar' } }); await waitForRender(); expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith( @@ -660,10 +680,10 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } }); + emitter.emit(UPDATE_GLOBALS, { globals: { foo: 'bar' } }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); describe('in docs mode', () => { @@ -673,7 +693,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } }); + emitter.emit(UPDATE_GLOBALS, { globals: { foo: 'bar' } }); await waitForRender(); expect(ReactDOM.render).toHaveBeenCalledTimes(2); @@ -686,13 +706,13 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + await waitForEvents([STORY_ARGS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a', new: 'arg' }, }); @@ -702,7 +722,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -719,7 +739,7 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); projectAnnotations.renderToDOM.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -742,13 +762,13 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); describe('while story is still rendering', () => { @@ -768,7 +788,7 @@ describe('PreviewWeb', () => { ); componentOneExports.default.loaders[0].mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -822,7 +842,7 @@ describe('PreviewWeb', () => { await new PreviewWeb().initialize({ importFn, getProjectAnnotations }); await waitForRenderPhase('rendering'); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -857,7 +877,7 @@ describe('PreviewWeb', () => { it('works if it is called directly from inside non async renderToDOM', async () => { document.location.search = '?id=component-one--a'; projectAnnotations.renderToDOM.mockImplementationOnce(() => { - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -914,7 +934,7 @@ describe('PreviewWeb', () => { undefined // this is coming from view.prepareForStory, not super important ); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -947,7 +967,7 @@ describe('PreviewWeb', () => { (ReactDOM.render as jest.MockedFunction).mockClear(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -971,11 +991,11 @@ describe('PreviewWeb', () => { (ReactDOM.render as jest.MockedFunction).mockClear(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); + await waitForEvents([STORY_ARGS_UPDATED]); expect(ReactDOM.render).not.toHaveBeenCalled(); }); @@ -1003,7 +1023,7 @@ describe('PreviewWeb', () => { (ReactDOM.render as jest.MockedFunction).mockClear(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { new: 'arg' }, }); @@ -1040,26 +1060,26 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'new' }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + await waitForEvents([STORY_ARGS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'new' }, }); mockChannel.emit.mockClear(); - emitter.emit(Events.RESET_STORY_ARGS, { + emitter.emit(RESET_STORY_ARGS, { storyId: 'component-one--a', argNames: ['foo'], }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); + await waitForEvents([STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a' }, }); @@ -1071,14 +1091,14 @@ describe('PreviewWeb', () => { const onUpdateArgsSpy = jest.spyOn(preview, 'onUpdateArgs'); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'new', new: 'value' }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); + await waitForEvents([STORY_ARGS_UPDATED]); mockChannel.emit.mockClear(); - emitter.emit(Events.RESET_STORY_ARGS, { + emitter.emit(RESET_STORY_ARGS, { storyId: 'component-one--a', argNames: ['foo'], }); @@ -1096,8 +1116,8 @@ describe('PreviewWeb', () => { undefined // this is coming from view.prepareForStory, not super important ); - await waitForEvents([Events.STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + await waitForEvents([STORY_ARGS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a', new: 'value' }, }); @@ -1113,14 +1133,14 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const onUpdateArgsSpy = jest.spyOn(preview, 'onUpdateArgs'); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'new' }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); + await waitForEvents([STORY_ARGS_UPDATED]); mockChannel.emit.mockClear(); - emitter.emit(Events.RESET_STORY_ARGS, { + emitter.emit(RESET_STORY_ARGS, { storyId: 'component-one--a', }); @@ -1137,8 +1157,8 @@ describe('PreviewWeb', () => { undefined // this is coming from view.prepareForStory, not super important ); - await waitForEvents([Events.STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + await waitForEvents([STORY_ARGS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a' }, }); @@ -1154,14 +1174,14 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const onUpdateArgsSpy = jest.spyOn(preview, 'onUpdateArgs'); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'new', new: 'value' }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); + await waitForEvents([STORY_ARGS_UPDATED]); mockChannel.emit.mockClear(); - emitter.emit(Events.RESET_STORY_ARGS, { + emitter.emit(RESET_STORY_ARGS, { storyId: 'component-one--a', }); @@ -1178,8 +1198,8 @@ describe('PreviewWeb', () => { undefined // this is coming from view.prepareForStory, not super important ); - await waitForEvents([Events.STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + await waitForEvents([STORY_ARGS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a' }, }); @@ -1195,14 +1215,14 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); const onUpdateArgsSpy = jest.spyOn(preview, 'onUpdateArgs'); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: undefined }, }); - await waitForEvents([Events.STORY_ARGS_UPDATED]); + await waitForEvents([STORY_ARGS_UPDATED]); mockChannel.emit.mockClear(); - emitter.emit(Events.RESET_STORY_ARGS, { + emitter.emit(RESET_STORY_ARGS, { storyId: 'component-one--a', }); @@ -1219,8 +1239,8 @@ describe('PreviewWeb', () => { undefined // this is coming from view.prepareForStory, not super important ); - await waitForEvents([Events.STORY_ARGS_UPDATED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + await waitForEvents([STORY_ARGS_UPDATED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a' }, }); @@ -1239,7 +1259,7 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); projectAnnotations.renderToDOM.mockClear(); - emitter.emit(Events.FORCE_RE_RENDER); + emitter.emit(FORCE_RE_RENDER); await waitForRender(); expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith( @@ -1263,7 +1283,7 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); projectAnnotations.renderToDOM.mockClear(); - emitter.emit(Events.FORCE_REMOUNT, { storyId: 'component-one--a' }); + emitter.emit(FORCE_REMOUNT, { storyId: 'component-one--a' }); await waitForRender(); expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith( @@ -1292,7 +1312,7 @@ describe('PreviewWeb', () => { ); mockChannel.emit.mockClear(); - emitter.emit(Events.FORCE_REMOUNT, { storyId: 'component-one--a' }); + emitter.emit(FORCE_REMOUNT, { storyId: 'component-one--a' }); await waitForSetCurrentStory(); // Now let the renderToDOM call resolve @@ -1307,7 +1327,7 @@ describe('PreviewWeb', () => { expect(componentOneExports.a.play).toHaveBeenCalledTimes(1); await waitForRenderPhase('completed'); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); await waitForQuiescence(); }); @@ -1325,7 +1345,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1342,13 +1362,13 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, { + expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1358,15 +1378,15 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'random', viewMode: 'story', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_MISSING]); + await waitForEvents([STORY_MISSING]); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'random'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'random'); }); describe('if called before the preview is initialized', () => { @@ -1375,13 +1395,13 @@ describe('PreviewWeb', () => { // We intentionally are *not* awaiting here new PreviewWeb().initialize({ importFn, getProjectAnnotations }); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); - await waitForEvents([Events.STORY_RENDERED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, { + await waitForEvents([STORY_RENDERED]); + expect(mockChannel.emit).toHaveBeenCalledWith(CURRENT_STORY_WAS_SET, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1390,8 +1410,8 @@ describe('PreviewWeb', () => { '', 'pathname?id=component-one--b&viewMode=story' ); - expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--b'); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b'); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_MISSING, 'component-one--b'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b'); }); }); @@ -1400,14 +1420,14 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_UNCHANGED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_UNCHANGED, 'component-one--a'); + await waitForEvents([STORY_UNCHANGED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_UNCHANGED, 'component-one--a'); }); it('does NOT call renderToDOM', async () => { @@ -1415,7 +1435,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); projectAnnotations.renderToDOM.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -1448,11 +1468,11 @@ describe('PreviewWeb', () => { // We can't wait for the initialize function, as it waits for `renderSelection()` // which prepares, but it does emit `CURRENT_STORY_WAS_SET` right before that preview.initialize({ importFn, getProjectAnnotations }); - await waitForEvents([Events.CURRENT_STORY_WAS_SET]); + await waitForEvents([CURRENT_STORY_WAS_SET]); mockChannel.emit.mockClear(); projectAnnotations.renderToDOM.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -1477,7 +1497,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1494,7 +1514,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1508,14 +1528,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_CHANGED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--b'); + await waitForEvents([STORY_CHANGED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--b'); }); it('emits STORY_PREPARED', async () => { @@ -1523,14 +1543,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_PREPARED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, { + await waitForEvents([STORY_PREPARED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, { id: 'component-one--b', parameters: { __isArgsStory: false, @@ -1548,7 +1568,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1575,7 +1595,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1613,14 +1633,14 @@ describe('PreviewWeb', () => { }); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -1634,14 +1654,14 @@ describe('PreviewWeb', () => { ); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({ message: error.title, stack: error.description, @@ -1658,14 +1678,14 @@ describe('PreviewWeb', () => { ); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -1674,7 +1694,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1689,14 +1709,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b'); }); it('retains any arg changes', async () => { @@ -1704,7 +1724,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'updated' }, }); @@ -1714,7 +1734,7 @@ describe('PreviewWeb', () => { }); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1725,7 +1745,7 @@ describe('PreviewWeb', () => { }); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -1745,7 +1765,7 @@ describe('PreviewWeb', () => { await new PreviewWeb().initialize({ importFn, getProjectAnnotations }); await waitForRenderPhase('loading'); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1779,7 +1799,7 @@ describe('PreviewWeb', () => { await waitForRenderPhase('rendering'); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1798,11 +1818,8 @@ describe('PreviewWeb', () => { expect(componentOneExports.b.play).toHaveBeenCalled(); await waitForRenderPhase('completed'); - expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.STORY_RENDERED, - 'component-one--a' - ); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b'); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b'); await waitForQuiescence(); }); @@ -1827,7 +1844,7 @@ describe('PreviewWeb', () => { ); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1839,7 +1856,7 @@ describe('PreviewWeb', () => { await waitForSetCurrentStory(); await waitForRenderPhase('rendering'); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--b'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--b'); expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith( expect.objectContaining({ forceRemount: true, @@ -1853,14 +1870,11 @@ describe('PreviewWeb', () => { await waitForRenderPhase('playing'); await waitForRenderPhase('completed'); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--b'); // Final story rendered is not emitted for the first story await waitForQuiescence(); - expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.STORY_RENDERED, - 'component-one--a' - ); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); it('reloads page if playFunction fails to abort in time', async () => { @@ -1883,7 +1897,7 @@ describe('PreviewWeb', () => { ); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -1894,10 +1908,7 @@ describe('PreviewWeb', () => { await waitForSetCurrentStory(); expect(global.window.location.reload).toHaveBeenCalled(); - expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.STORY_CHANGED, - 'component-one--b' - ); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_CHANGED, 'component-one--b'); expect(projectAnnotations.renderToDOM).not.toHaveBeenCalledWith( expect.objectContaining({ storyContext: expect.objectContaining({ id: 'component-one--b' }), @@ -1913,7 +1924,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'docs', }); @@ -1930,7 +1941,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a'; const preview = await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'docs', }); @@ -1944,14 +1955,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'docs', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_CHANGED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a'); + await waitForEvents([STORY_CHANGED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a'); }); it('calls view.prepareForDocs', async () => { @@ -1959,7 +1970,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'docs', }); @@ -1974,7 +1985,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'docs', }); @@ -2002,14 +2013,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'docs', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.DOCS_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(DOCS_RENDERED, 'component-one--a'); }); }); @@ -2018,7 +2029,7 @@ describe('PreviewWeb', () => { document.location.search = '?id=component-one--a&viewMode=docs'; await createAndRenderPreview(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2036,7 +2047,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2052,14 +2063,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_CHANGED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a'); + await waitForEvents([STORY_CHANGED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a'); }); it('calls view.prepareForStory', async () => { @@ -2067,7 +2078,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2086,14 +2097,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); - await waitForEvents([Events.STORY_PREPARED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, { + await waitForEvents([STORY_PREPARED]); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, { id: 'component-one--a', parameters: { __isArgsStory: false, @@ -2111,7 +2122,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2138,7 +2149,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2176,14 +2187,14 @@ describe('PreviewWeb', () => { }); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -2197,14 +2208,14 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({ message: error.title, stack: error.description, @@ -2221,14 +2232,14 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -2237,7 +2248,7 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2252,14 +2263,14 @@ describe('PreviewWeb', () => { await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); await waitForSetCurrentStory(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); }); }); @@ -2277,13 +2288,13 @@ describe('PreviewWeb', () => { ); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error)); + expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, expect.any(Error)); mockChannel.emit.mockClear(); mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' }; preview.onStoryIndexChanged(); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); it('sets story args from the URL', async () => { @@ -2297,7 +2308,7 @@ describe('PreviewWeb', () => { ); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error)); + expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, expect.any(Error)); mockChannel.emit.mockClear(); mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' }; @@ -2327,10 +2338,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.STORY_UNCHANGED, - 'component-one--a' - ); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_UNCHANGED, 'component-one--a'); }); it('does not emit STORY_CHANGED', async () => { @@ -2341,7 +2349,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a'); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a'); }); it('emits STORY_PREPARED with new annotations', async () => { @@ -2352,7 +2360,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_PREPARED, { id: 'component-one--a', parameters: { __isArgsStory: false, @@ -2373,7 +2381,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'edited' }, }); @@ -2438,7 +2446,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'updated' }, }); @@ -2474,7 +2482,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -2491,7 +2499,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ERRORED, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({ message: error.title, stack: error.description, @@ -2511,7 +2519,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_THREW_EXCEPTION, error); expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error); }); @@ -2535,7 +2543,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); }); @@ -2575,7 +2583,7 @@ describe('PreviewWeb', () => { const preview = await createAndRenderPreview(); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -2585,7 +2593,7 @@ describe('PreviewWeb', () => { preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex }); mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2610,10 +2618,10 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); preview.onStoriesChanged({ importFn: newImportFn }); - await waitForEvents([Events.STORY_UNCHANGED]); + await waitForEvents([STORY_UNCHANGED]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_UNCHANGED, 'component-one--a'); - expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_UNCHANGED, 'component-one--a'); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_CHANGED, 'component-one--a'); }); it('clears preparing state', async () => { @@ -2623,7 +2631,7 @@ describe('PreviewWeb', () => { (preview.view.showMain as jest.Mock).mockClear(); mockChannel.emit.mockClear(); preview.onStoriesChanged({ importFn: newImportFn }); - await waitForEvents([Events.STORY_UNCHANGED]); + await waitForEvents([STORY_UNCHANGED]); expect(preview.view.showMain).toHaveBeenCalled(); }); @@ -2638,10 +2646,7 @@ describe('PreviewWeb', () => { await waitForQuiescence(); expect(projectAnnotations.renderToDOM).not.toHaveBeenCalled(); - expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.STORY_RENDERED, - 'component-one--a' - ); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); }); @@ -2667,7 +2672,7 @@ describe('PreviewWeb', () => { // Change A's args mockChannel.emit.mockClear(); - emitter.emit(Events.UPDATE_STORY_ARGS, { + emitter.emit(UPDATE_STORY_ARGS, { storyId: 'component-one--a', updatedArgs: { foo: 'updated' }, }); @@ -2675,7 +2680,7 @@ describe('PreviewWeb', () => { // Change to story B mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--b', viewMode: 'story', }); @@ -2693,7 +2698,7 @@ describe('PreviewWeb', () => { // Change back to Story A mockChannel.emit.mockClear(); - emitter.emit(Events.SET_CURRENT_STORY, { + emitter.emit(SET_CURRENT_STORY, { storyId: 'component-one--a', viewMode: 'story', }); @@ -2738,10 +2743,10 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex }); - await waitForEvents([Events.STORY_MISSING]); + await waitForEvents([STORY_MISSING]); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_MISSING, 'component-one--a'); }); it('does not re-render the story', async () => { @@ -2754,10 +2759,7 @@ describe('PreviewWeb', () => { await waitForQuiescence(); expect(projectAnnotations.renderToDOM).not.toHaveBeenCalled(); - expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.STORY_RENDERED, - 'component-one--a' - ); + expect(mockChannel.emit).not.toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); it('re-renders the story if it is readded', async () => { @@ -2766,12 +2768,12 @@ describe('PreviewWeb', () => { mockChannel.emit.mockClear(); preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex }); - await waitForEvents([Events.STORY_MISSING]); + await waitForEvents([STORY_MISSING]); mockChannel.emit.mockClear(); preview.onStoriesChanged({ importFn, storyIndex }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); }); }); @@ -2795,7 +2797,7 @@ describe('PreviewWeb', () => { preview.onGetProjectAnnotationsChanged({ getProjectAnnotations }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a'); + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-one--a'); }); it('sets globals from the URL', async () => { @@ -2834,7 +2836,7 @@ describe('PreviewWeb', () => { ).rejects.toThrow(err); expect(preview.view.showErrorDisplay).toHaveBeenCalled(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, err); + expect(mockChannel.emit).toHaveBeenCalledWith(CONFIG_ERROR, err); }); const newGlobalDecorator = jest.fn((s) => s()); @@ -2866,8 +2868,8 @@ describe('PreviewWeb', () => { preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations }); await waitForRender(); - await waitForEvents([Events.SET_GLOBALS]); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, { + await waitForEvents([SET_GLOBALS]); + expect(mockChannel.emit).toHaveBeenCalledWith(SET_GLOBALS, { globals: { a: 'edited' }, globalTypes: {}, }); @@ -2895,7 +2897,7 @@ describe('PreviewWeb', () => { preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations }); await waitForRender(); - expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, { + expect(mockChannel.emit).toHaveBeenCalledWith(STORY_ARGS_UPDATED, { storyId: 'component-one--a', args: { foo: 'a', global: 'added' }, }); @@ -2931,10 +2933,7 @@ describe('PreviewWeb', () => { target: { tagName: 'div', getAttribute: jest.fn().mockReturnValue(null) }, } as any); - expect(mockChannel.emit).toHaveBeenCalledWith( - Events.PREVIEW_KEYDOWN, - expect.objectContaining({}) - ); + expect(mockChannel.emit).toHaveBeenCalledWith(PREVIEW_KEYDOWN, expect.objectContaining({})); }); it('does not emit PREVIEW_KEYDOWN for input elements', async () => { @@ -2946,7 +2945,7 @@ describe('PreviewWeb', () => { } as any); expect(mockChannel.emit).not.toHaveBeenCalledWith( - Events.PREVIEW_KEYDOWN, + PREVIEW_KEYDOWN, expect.objectContaining({}) ); }); From fae35d32e6a4b561ecd8fb0b0a38806c3e37771f Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 31 May 2022 15:23:45 +1000 Subject: [PATCH 48/69] More updates in preview-web --- lib/preview-web/src/Preview.tsx | 33 ++++++++----- lib/preview-web/src/PreviewWeb.mockdata.ts | 21 +++++--- lib/preview-web/src/PreviewWeb.test.ts | 2 +- lib/preview-web/src/PreviewWeb.tsx | 57 ++++++++++++++-------- 4 files changed, 74 insertions(+), 39 deletions(-) diff --git a/lib/preview-web/src/Preview.tsx b/lib/preview-web/src/Preview.tsx index ab3f4be9118..2eae90f861b 100644 --- a/lib/preview-web/src/Preview.tsx +++ b/lib/preview-web/src/Preview.tsx @@ -1,7 +1,18 @@ import dedent from 'ts-dedent'; import global from 'global'; import { SynchronousPromise } from 'synchronous-promise'; -import Events from '@storybook/core-events'; +import { + CONFIG_ERROR, + FORCE_REMOUNT, + FORCE_RE_RENDER, + GLOBALS_UPDATED, + RESET_STORY_ARGS, + SET_GLOBALS, + STORY_ARGS_UPDATED, + STORY_INDEX_INVALIDATED, + UPDATE_GLOBALS, + UPDATE_STORY_ARGS, +} from '@storybook/core-events'; import { logger } from '@storybook/client-logger'; import { addons, Channel } from '@storybook/addons'; import { AnyFramework, StoryId, ProjectAnnotations, Args, Globals } from '@storybook/csf'; @@ -80,13 +91,13 @@ export class Preview { } setupListeners() { - this.serverChannel?.on(Events.STORY_INDEX_INVALIDATED, this.onStoryIndexChanged.bind(this)); + this.serverChannel?.on(STORY_INDEX_INVALIDATED, this.onStoryIndexChanged.bind(this)); - this.channel.on(Events.UPDATE_GLOBALS, this.onUpdateGlobals.bind(this)); - this.channel.on(Events.UPDATE_STORY_ARGS, this.onUpdateArgs.bind(this)); - this.channel.on(Events.RESET_STORY_ARGS, this.onResetArgs.bind(this)); - this.channel.on(Events.FORCE_RE_RENDER, this.onForceReRender.bind(this)); - this.channel.on(Events.FORCE_REMOUNT, this.onForceRemount.bind(this)); + this.channel.on(UPDATE_GLOBALS, this.onUpdateGlobals.bind(this)); + this.channel.on(UPDATE_STORY_ARGS, this.onUpdateArgs.bind(this)); + this.channel.on(RESET_STORY_ARGS, this.onResetArgs.bind(this)); + this.channel.on(FORCE_RE_RENDER, this.onForceReRender.bind(this)); + this.channel.on(FORCE_REMOUNT, this.onForceRemount.bind(this)); } getProjectAnnotationsOrRenderError( @@ -144,7 +155,7 @@ export class Preview { } emitGlobals() { - this.channel.emit(Events.SET_GLOBALS, { + this.channel.emit(SET_GLOBALS, { globals: this.storyStore.globals.get() || {}, globalTypes: this.storyStore.projectAnnotations.globalTypes || {}, }); @@ -227,7 +238,7 @@ export class Preview { await Promise.all(this.storyRenders.map((r) => r.rerender())); - this.channel.emit(Events.GLOBALS_UPDATED, { + this.channel.emit(GLOBALS_UPDATED, { globals: this.storyStore.globals.get(), initialGlobals: this.storyStore.globals.initialGlobals, }); @@ -238,7 +249,7 @@ export class Preview { await Promise.all(this.storyRenders.filter((r) => r.id === storyId).map((r) => r.rerender())); - this.channel.emit(Events.STORY_ARGS_UPDATED, { + this.channel.emit(STORY_ARGS_UPDATED, { storyId, args: this.storyStore.args.get(storyId), }); @@ -344,6 +355,6 @@ export class Preview { this.previewEntryError = err; logger.error(reason); logger.error(err); - this.channel.emit(Events.CONFIG_ERROR, err); + this.channel.emit(CONFIG_ERROR, err); } } diff --git a/lib/preview-web/src/PreviewWeb.mockdata.ts b/lib/preview-web/src/PreviewWeb.mockdata.ts index d33563686c1..ae2eadf8c70 100644 --- a/lib/preview-web/src/PreviewWeb.mockdata.ts +++ b/lib/preview-web/src/PreviewWeb.mockdata.ts @@ -1,5 +1,12 @@ import { EventEmitter } from 'events'; -import Events from '@storybook/core-events'; +import { + DOCS_RENDERED, + STORY_ERRORED, + STORY_MISSING, + STORY_RENDERED, + STORY_RENDER_PHASE_CHANGED, + STORY_THREW_EXCEPTION, +} from '@storybook/core-events'; import { StoryIndex } from '@storybook/store'; import { RenderPhase } from './PreviewWeb'; @@ -99,15 +106,15 @@ export const waitForEvents = ( // the async parts, so we need to listen for the "done" events export const waitForRender = () => waitForEvents([ - Events.STORY_RENDERED, - Events.DOCS_RENDERED, - Events.STORY_THREW_EXCEPTION, - Events.STORY_ERRORED, - Events.STORY_MISSING, + STORY_RENDERED, + DOCS_RENDERED, + STORY_THREW_EXCEPTION, + STORY_ERRORED, + STORY_MISSING, ]); export const waitForRenderPhase = (phase: RenderPhase) => - waitForEvents([Events.STORY_RENDER_PHASE_CHANGED], ({ newPhase }) => newPhase === phase); + waitForEvents([STORY_RENDER_PHASE_CHANGED], ({ newPhase }) => newPhase === phase); // A little trick to ensure that we always call the real `setTimeout` even when timers are mocked const realSetTimeout = setTimeout; diff --git a/lib/preview-web/src/PreviewWeb.test.ts b/lib/preview-web/src/PreviewWeb.test.ts index 016a079e64f..0b507fb35f8 100644 --- a/lib/preview-web/src/PreviewWeb.test.ts +++ b/lib/preview-web/src/PreviewWeb.test.ts @@ -1,7 +1,7 @@ import global from 'global'; import * as ReactDOM from 'react-dom'; import merge from 'lodash/merge'; -import Events, { +import { CONFIG_ERROR, CURRENT_STORY_WAS_SET, DOCS_RENDERED, diff --git a/lib/preview-web/src/PreviewWeb.tsx b/lib/preview-web/src/PreviewWeb.tsx index 417730034bd..e4fdb3c2d57 100644 --- a/lib/preview-web/src/PreviewWeb.tsx +++ b/lib/preview-web/src/PreviewWeb.tsx @@ -1,7 +1,24 @@ import deprecate from 'util-deprecate'; import dedent from 'ts-dedent'; import global from 'global'; -import Events, { IGNORED_EXCEPTION } from '@storybook/core-events'; +import { + CURRENT_STORY_WAS_SET, + IGNORED_EXCEPTION, + PRELOAD_STORIES, + PREVIEW_KEYDOWN, + SET_CURRENT_STORY, + SET_STORIES, + STORY_ARGS_UPDATED, + STORY_CHANGED, + STORY_ERRORED, + STORY_MISSING, + STORY_PREPARED, + STORY_RENDER_PHASE_CHANGED, + STORY_SPECIFIED, + STORY_THREW_EXCEPTION, + STORY_UNCHANGED, + UPDATE_QUERY_PARAMS, +} from '@storybook/core-events'; import { logger } from '@storybook/client-logger'; import { AnyFramework, StoryId, ProjectAnnotations, Args, Globals } from '@storybook/csf'; import type { @@ -64,9 +81,9 @@ export class PreviewWeb extends Preview) { @@ -87,7 +104,7 @@ export class PreviewWeb extends Preview { return super.initializeWithStoryIndex(storyIndex).then(() => { if (!global.FEATURES?.storyStoreV7) { - this.channel.emit(Events.SET_STORIES, this.storyStore.getSetStoriesPayload()); + this.channel.emit(SET_STORIES, this.storyStore.getSetStoriesPayload()); } return this.selectSpecifiedStory(); @@ -130,9 +147,9 @@ export class PreviewWeb extends Preview extends Preview extends Preview extends Preview extends Preview extends Preview extends Preview extends Preview extends Preview Date: Tue, 31 May 2022 15:25:10 +1000 Subject: [PATCH 49/69] Default selection to story --- lib/preview-web/src/PreviewWeb.test.ts | 17 +++++++++++++++++ lib/preview-web/src/PreviewWeb.tsx | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/preview-web/src/PreviewWeb.test.ts b/lib/preview-web/src/PreviewWeb.test.ts index 0b507fb35f8..8d58970be04 100644 --- a/lib/preview-web/src/PreviewWeb.test.ts +++ b/lib/preview-web/src/PreviewWeb.test.ts @@ -1415,6 +1415,23 @@ describe('PreviewWeb', () => { }); }); + describe('if called on a storybook without selection', () => { + it('sets viewMode to story by default', async () => { + await createAndRenderPreview(); + + emitter.emit(SET_CURRENT_STORY, { + storyId: 'component-one--b', + }); + await waitForSetCurrentStory(); + + expect(history.replaceState).toHaveBeenCalledWith( + {}, + '', + 'pathname?id=component-one--b&viewMode=story' + ); + }); + }); + describe('if the selection is unchanged', () => { it('emits STORY_UNCHANGED', async () => { document.location.search = '?id=component-one--a'; diff --git a/lib/preview-web/src/PreviewWeb.tsx b/lib/preview-web/src/PreviewWeb.tsx index e4fdb3c2d57..6c455bd2e93 100644 --- a/lib/preview-web/src/PreviewWeb.tsx +++ b/lib/preview-web/src/PreviewWeb.tsx @@ -200,7 +200,7 @@ export class PreviewWeb extends Preview Date: Tue, 31 May 2022 11:37:10 +0200 Subject: [PATCH 50/69] it goes green --- .circleci/config.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 372652ee426..12a8319c824 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -274,9 +274,10 @@ jobs: - run: name: Wait for registry command: yarn wait-on http://localhost:6000 - - run: - name: run e2e tests cra - command: yarn test:e2e-framework --pnp cra + # TODO: we disabled this one because it keeps failing, we should fix it, and enable it again! + # - run: + # name: run e2e tests cra + # command: yarn test:e2e-framework --pnp cra - run: name: run e2e tests vue command: yarn test:e2e-framework --pnp sfcVue From 223d4beaf7986f63793e3019e6c81eb5ad7bd7dc Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 31 May 2022 12:39:47 +0200 Subject: [PATCH 51/69] disable all pnp e2e tests for now, get it green --- .circleci/config.yml | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 12a8319c824..cd947ee9c6e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -265,32 +265,32 @@ jobs: steps: - git-shallow-clone/checkout_advanced: clone_options: '--depth 1 --verbose' - - attach_workspace: - at: . - - run: - name: Running local registry - command: yarn local-registry --port 6000 --open - background: true - - run: - name: Wait for registry - command: yarn wait-on http://localhost:6000 # TODO: we disabled this one because it keeps failing, we should fix it, and enable it again! + # - attach_workspace: + # at: . + # - run: + # name: Running local registry + # command: yarn local-registry --port 6000 --open + # background: true + # - run: + # name: Wait for registry + # command: yarn wait-on http://localhost:6000 # - run: # name: run e2e tests cra # command: yarn test:e2e-framework --pnp cra - - run: - name: run e2e tests vue - command: yarn test:e2e-framework --pnp sfcVue - - run: - name: prep artifacts - when: always - command: zip -r /tmp/storybook-e2e-testing-out.zip /tmp/storybook-e2e-testing - - store_artifacts: - path: /tmp/cypress-record - destination: cypress - - store_artifacts: - path: /tmp/storybook-e2e-testing-out.zip - destination: e2e + # - run: + # name: run e2e tests vue + # command: yarn test:e2e-framework --pnp sfcVue + # - run: + # name: prep artifacts + # when: always + # command: zip -r /tmp/storybook-e2e-testing-out.zip /tmp/storybook-e2e-testing + # - store_artifacts: + # path: /tmp/cypress-record + # destination: cypress + # - store_artifacts: + # path: /tmp/storybook-e2e-testing-out.zip + # destination: e2e e2e-tests-examples: executor: class: small From 294b1cc8eddc8c234939eb678d5a4c61c610d671 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 31 May 2022 13:06:09 +0200 Subject: [PATCH 52/69] Vue: export applyDecorators for storyStoreV7 --- app/vue/src/client/preview/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/vue/src/client/preview/config.ts b/app/vue/src/client/preview/config.ts index 036f51eba18..759c77b9abe 100644 --- a/app/vue/src/client/preview/config.ts +++ b/app/vue/src/client/preview/config.ts @@ -1,4 +1,4 @@ export { render, renderToDOM } from './render'; -export { decorateStory } from './decorateStory'; +export { decorateStory as applyDecorators } from './decorateStory'; export const parameters = { framework: 'vue' }; From fcb61e10a3fb0ef5c59137c09c7766699a309b14 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 31 May 2022 13:06:35 +0200 Subject: [PATCH 53/69] Vue3: export applyDecorators for storyStoreV7 --- app/vue3/src/client/preview/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/vue3/src/client/preview/config.ts b/app/vue3/src/client/preview/config.ts index 69f6b3b8683..589efca6a13 100644 --- a/app/vue3/src/client/preview/config.ts +++ b/app/vue3/src/client/preview/config.ts @@ -1,4 +1,4 @@ export { render, renderToDOM } from './render'; -export { decorateStory } from './decorateStory'; +export { decorateStory as applyDecorators } from './decorateStory'; export const parameters = { framework: 'vue3' }; From 68458171bffc4824c358fc242f4d2c721de16a06 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 31 May 2022 13:52:38 +0200 Subject: [PATCH 54/69] chore(storybook): upgrade vue examples to use storyStoreV7 --- examples/vue-3-cli/.storybook/main.js | 1 + examples/vue-cli/.storybook/main.js | 1 + examples/vue-kitchen-sink/.storybook/main.js | 1 + 3 files changed, 3 insertions(+) diff --git a/examples/vue-3-cli/.storybook/main.js b/examples/vue-3-cli/.storybook/main.js index 5858049fd74..0699c40dfc4 100644 --- a/examples/vue-3-cli/.storybook/main.js +++ b/examples/vue-3-cli/.storybook/main.js @@ -10,6 +10,7 @@ module.exports = { disableTelemetry: true, }, features: { + storyStoreV7: !global.navigator?.userAgent?.match?.('jsdom'), buildStoriesJson: true, channelOptions: { allowFunction: false, maxDepth: 10 }, }, diff --git a/examples/vue-cli/.storybook/main.js b/examples/vue-cli/.storybook/main.js index 742a7b1d5ab..e80616cd0d8 100644 --- a/examples/vue-cli/.storybook/main.js +++ b/examples/vue-cli/.storybook/main.js @@ -13,6 +13,7 @@ module.exports = { disableTelemetry: true, }, features: { + storyStoreV7: true, buildStoriesJson: true, }, }; diff --git a/examples/vue-kitchen-sink/.storybook/main.js b/examples/vue-kitchen-sink/.storybook/main.js index eb7979f07f2..6068e3c0408 100644 --- a/examples/vue-kitchen-sink/.storybook/main.js +++ b/examples/vue-kitchen-sink/.storybook/main.js @@ -20,5 +20,6 @@ module.exports = { staticDirs: ['../public'], features: { buildStoriesJson: true, + storyStoreV7: !global.navigator?.userAgent?.match?.('jsdom'), }, }; From 22fff177ae67952263afbc8c6c6430e7f76b4b27 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 31 May 2022 16:09:45 +0200 Subject: [PATCH 55/69] chore(vue-kitchen-sink): update example with older syntax --- examples/vue-kitchen-sink/.storybook/preview.js | 1 + examples/vue-kitchen-sink/src/stories/core.stories.js | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/vue-kitchen-sink/.storybook/preview.js b/examples/vue-kitchen-sink/.storybook/preview.js index 65ca5b85929..9f879a2bad5 100644 --- a/examples/vue-kitchen-sink/.storybook/preview.js +++ b/examples/vue-kitchen-sink/.storybook/preview.js @@ -10,4 +10,5 @@ export const parameters = { docs: { iframeHeight: '60px', }, + globalParameter: 'globalParameter', }; diff --git a/examples/vue-kitchen-sink/src/stories/core.stories.js b/examples/vue-kitchen-sink/src/stories/core.stories.js index 7f328fe356e..ab20c828681 100644 --- a/examples/vue-kitchen-sink/src/stories/core.stories.js +++ b/examples/vue-kitchen-sink/src/stories/core.stories.js @@ -1,15 +1,10 @@ -import { addParameters } from '@storybook/vue'; - -const globalParameter = 'globalParameter'; -const chapterParameter = 'chapterParameter'; +const componentParameter = 'componentParameter'; const storyParameter = 'storyParameter'; -addParameters({ globalParameter }); - export default { title: 'Core/Parameters', parameters: { - chapterParameter, + componentParameter, }, }; From ea2a136d4db5af0c1e508a72db1d897ab58e5909 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Tue, 31 May 2022 17:34:12 +0200 Subject: [PATCH 56/69] update snapshots --- .../src/stories/__snapshots__/core.stories.storyshot | 4 ++-- .../stories/__snapshots__/custom-decorators.stories.storyshot | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot b/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot index c6f10f6e74e..79adbe9aa5b 100644 --- a/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot +++ b/examples/vue-kitchen-sink/src/stories/__snapshots__/core.stories.storyshot @@ -8,9 +8,9 @@ exports[`Storyshots Core/Parameters passed to story 1`] = ` "docs": { "iframeHeight": "60px" }, - "framework": "vue", "globalParameter": "globalParameter", - "chapterParameter": "chapterParameter", + "framework": "vue", + "componentParameter": "componentParameter", "storyParameter": "storyParameter", "__isArgsStory": true, "__id": "core-parameters--passed-to-story", diff --git a/examples/vue-kitchen-sink/src/stories/__snapshots__/custom-decorators.stories.storyshot b/examples/vue-kitchen-sink/src/stories/__snapshots__/custom-decorators.stories.storyshot index 037ca9020ee..0be37ed065f 100644 --- a/examples/vue-kitchen-sink/src/stories/__snapshots__/custom-decorators.stories.storyshot +++ b/examples/vue-kitchen-sink/src/stories/__snapshots__/custom-decorators.stories.storyshot @@ -53,8 +53,8 @@ exports[`Storyshots Custom/Decorator for Vue With Data 1`] = ` "docs": { "iframeHeight": "60px" }, - "framework": "vue", "globalParameter": "globalParameter", + "framework": "vue", "__isArgsStory": true, "__id": "custom-decorator-for-vue--with-data", "args": {}, From 2a3ef9a3d20f69c8dd449f6a5a45aab236d27f79 Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 31 May 2022 18:19:16 +0100 Subject: [PATCH 57/69] Updates to docs for better UX --- docs/addons/writing-addons.md | 19 ++++++++--- docs/builders/webpack.md | 34 ++++++++++++++----- docs/contribute/code.md | 20 ++++++----- docs/contribute/new-snippets.md | 8 +++-- docs/essentials/interactions.md | 15 ++++---- docs/essentials/introduction.md | 29 +++++++++------- docs/sharing/publish-storybook.md | 18 ++++++---- .../build-storybook-production-mode.js.mdx | 7 ---- ...build-storybook-production-mode.npm.js.mdx | 3 ++ ...uild-storybook-production-mode.yarn.js.mdx | 3 ++ .../common/chromatic-install.npm.js.mdx | 3 ++ .../common/chromatic-install.yarn.js.mdx | 3 ++ ...storybook-addon-actions-install.npm.js.mdx | 3 ++ ...torybook-addon-actions-install.yarn.js.mdx | 3 ++ ...rybook-addon-essentials-install.npm.js.mdx | 3 ++ ...ybook-addon-essentials-install.yarn.js.mdx | 3 ++ ...rybook-addon-storyshots-install.npm.js.mdx | 3 ++ ...ybook-addon-storyshots-install.yarn.js.mdx | 3 ++ .../storybook-debug-webpack-dev.npm.js.mdx | 3 ++ .../storybook-debug-webpack-dev.yarn.js.mdx | 3 ++ .../storybook-debug-webpack-prod.npm.js.mdx | 3 ++ .../storybook-debug-webpack-prod.yarn.js.mdx | 3 ++ ...rite-addon-install-dependencies.npm.js.mdx | 3 ++ ...ite-addon-install-dependencies.yarn.js.mdx | 3 ++ docs/writing-stories/play-function.md | 15 ++++---- docs/writing-tests/snapshot-testing.md | 15 ++++---- docs/writing-tests/visual-testing.md | 17 ++++++---- 27 files changed, 171 insertions(+), 74 deletions(-) delete mode 100644 docs/snippets/common/build-storybook-production-mode.js.mdx create mode 100644 docs/snippets/common/build-storybook-production-mode.npm.js.mdx create mode 100644 docs/snippets/common/build-storybook-production-mode.yarn.js.mdx create mode 100644 docs/snippets/common/chromatic-install.npm.js.mdx create mode 100644 docs/snippets/common/chromatic-install.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-addon-actions-install.npm.js.mdx create mode 100644 docs/snippets/common/storybook-addon-actions-install.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-addon-essentials-install.npm.js.mdx create mode 100644 docs/snippets/common/storybook-addon-essentials-install.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-addon-storyshots-install.npm.js.mdx create mode 100644 docs/snippets/common/storybook-addon-storyshots-install.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-debug-webpack-dev.npm.js.mdx create mode 100644 docs/snippets/common/storybook-debug-webpack-dev.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-debug-webpack-prod.npm.js.mdx create mode 100644 docs/snippets/common/storybook-debug-webpack-prod.yarn.js.mdx create mode 100644 docs/snippets/common/storybook-write-addon-install-dependencies.npm.js.mdx create mode 100644 docs/snippets/common/storybook-write-addon-install-dependencies.yarn.js.mdx diff --git a/docs/addons/writing-addons.md b/docs/addons/writing-addons.md index 7b3079ad94a..1be4af5d445 100644 --- a/docs/addons/writing-addons.md +++ b/docs/addons/writing-addons.md @@ -50,13 +50,22 @@ Once you've gone through the prompts, your `package.json` should look like: ### Build system -We'll need to add the necessary dependencies and make some adjustments. Run the following commands: +We'll need to add the necessary dependencies and make some adjustments. Run the following command to install the required depedencies: + + + + + + + +Initialize a local Storybook instance to allow you to test your addon. ```shell -# Installs React and Babel CLI -yarn add react react-dom @babel/cli - -# Adds Storybook: npx sb init ``` diff --git a/docs/builders/webpack.md b/docs/builders/webpack.md index 768b4ab2ee9..fa5568bb6c5 100644 --- a/docs/builders/webpack.md +++ b/docs/builders/webpack.md @@ -40,16 +40,34 @@ You can import `.json` files and have them expanded to a JavaScript object: -If you want to know the exact details of the Webpack config, the best way is to run either of the following: +If you want to know the exact details of the Webpack config, the best way is to run either of the following commands: -```shell +For development mode: -## Development mode -yarn start-storybook --debug-webpack + -## Production mode -yarn build-storybook --debug-webpack -``` + + + + +For production mode: + + + + + + + ### Code splitting @@ -199,5 +217,5 @@ When working with TypeScript projects, the default Webpack configuration may fai #### Learn more about builders - [Vite builder](./vite.md) for bundling with Vite -- [Webpack builder](./webpack.md) for bundling with Webpack +- Webpack builder for bundling with Webpack - [Builder API](./builder-api.md) for building a Storybook builder diff --git a/docs/contribute/code.md b/docs/contribute/code.md index 9a1f4fada5b..f25714e4e71 100644 --- a/docs/contribute/code.md +++ b/docs/contribute/code.md @@ -6,13 +6,16 @@ Contribute a new feature or bug fix to [Storybook's monorepo](https://github.com ## Initial setup -First [fork](https://docs.github.com/en/github/getting-started-with-github/quickstart/fork-a-repo) the Storybook repository then clone and build your fork locally. Run the following commands: +Start by [forking](https://docs.github.com/en/github/getting-started-with-github/quickstart/fork-a-repo) the Storybook monorepo and cloning it locally. ```shell git clone https://github.com/your-username/storybook.git -cd storybook -yarn -yarn bootstrap --core +``` + +Navigate to the `storybook` directory and install the required dependencies with the following commands: + +```shell +yarn && yarn bootstrap --core ``` ## Run tests & examples @@ -28,8 +31,7 @@ yarn test Once the tests finish, check if the examples are working with the following commands: ```shell -cd examples/cra-ts-essentials -yarn storybook +cd examples/cra-ts-essentials && yarn storybook ```
@@ -106,7 +108,7 @@ Storybook's monorepo is set up to rely on end-to-end testing with [Cypress](http Before submitting your contribution, run the test suite one last time with: -```sh +```shell yarn test ``` @@ -133,7 +135,7 @@ We encourage bug reports to include reproductions. In the same way that it's pos To do so, run the following command in the root of the monorepo: -```sh +```shell npx sb@next link https://github.com/your-username/your-project.git ``` @@ -141,7 +143,7 @@ This command creates a project `../storybook-repros/your-project`, and automatic If you already have a reproduction on your local machine, you can similarly link it to your monorepo dev setup with the `--local` flag: -```sh +```shell npx sb@next link --local /path/to/local-repro-directory ``` diff --git a/docs/contribute/new-snippets.md b/docs/contribute/new-snippets.md index 84e4a91439b..35a88ea3683 100644 --- a/docs/contribute/new-snippets.md +++ b/docs/contribute/new-snippets.md @@ -89,11 +89,15 @@ Go through the rest of the documentation and repeat the process. Before submitting your contribution, we advise you to check your work against the Storybook website. Doing this prevents last-minute issues with the documentation and is also an excellent way for the maintainers to merge faster once you submit the pull request. However, failing to do so will lead one of the maintainers to notify you that your contribution has an issue. -Start by forking [frontpage repo](https://github.com/storybookjs/frontpage). Then, clone and install the dependencies with the following commands: +Start by forking [frontpage repo](https://github.com/storybookjs/frontpage) and cloning it locally. ```shell git clone https://github.com/your-username/frontpage.git -cd frontpage +``` + +Navigate to the `frontpage` directory and install the required dependencies with the following command: + +```shell yarn ``` diff --git a/docs/essentials/interactions.md b/docs/essentials/interactions.md index 4e1ca509917..a46bcc13b11 100644 --- a/docs/essentials/interactions.md +++ b/docs/essentials/interactions.md @@ -18,13 +18,16 @@ The interactions are written using a Storybook-instrumented version of [Testing Since Interactions is still experimental, it doesn't yet ship with Storybook by default. As such, you'll have to install it. You may also want to add our wrappers for Testing Library and Jest. -```shell -# With npm -npm install @storybook/addon-interactions @storybook/jest @storybook/testing-library --save-dev + -# With yarn -yarn add --dev @storybook/addon-interactions @storybook/jest @storybook/testing-library -``` + + + Next, update [`.storybook/main.js`](../configure/overview.md#configure-story-rendering) to the following: diff --git a/docs/essentials/introduction.md b/docs/essentials/introduction.md index ea508ccb541..bd2b6661e24 100644 --- a/docs/essentials/introduction.md +++ b/docs/essentials/introduction.md @@ -18,13 +18,16 @@ If you ran `sb init` to include Storybook in your project, the Essentials addon If you're upgrading from a previous Storybook version, you'll need to run the following command in your terminal: -```shell -#With npm -npm install -D @storybook/addon-essentials + -#With yarn -yarn add -D @storybook/addon-essentials -``` + + + Update your Storybook configuration (in [`.storybook/main.js`](../configure/overview.md#configure-story-rendering)) to include the Essentials addon. @@ -44,14 +47,16 @@ Essentials is "zero-config”. It comes with a recommended configuration out of If you need to reconfigure any of the [individual Essentials addons](https://storybook.js.org/addons/tag/essentials), install them manually by following the installation instructions, register them in your Storybook configuration file (i.e., [`.storybook/main.js`](../configure/overview.md#configure-story-rendering)) and adjust the configuration to suit your needs. For example: -```shell -#With npm -npm install -D @storybook/addon-actions + + -#With yarn -yarn add -D @storybook/addon-actions -``` + diff --git a/docs/sharing/publish-storybook.md b/docs/sharing/publish-storybook.md index f260dc6f99a..2e6794a0a92 100644 --- a/docs/sharing/publish-storybook.md +++ b/docs/sharing/publish-storybook.md @@ -21,7 +21,8 @@ First, we'll need to build Storybook as a static web application. The functional paths={[ 'angular/custom-build-script-production.script-for-builder.js.mdx', 'angular/build-storybook-production-mode.with-builder.js.mdx', - 'common/build-storybook-production-mode.js.mdx', + 'common/build-storybook-production-mode.yarn.js.mdx', + 'common/build-storybook-production-mode.npm.js.mdx', ]} /> @@ -49,13 +50,16 @@ To get started, sign up with your GitHub, GitLab, Bitbucket, or email and genera Next, install the [Chromatic CLI](https://www.npmjs.com/package/chromatic) package from npm: -```shell -# With npm -npm install --save-dev chromatic + -# With yarn -yarn add --dev chromatic -``` + + + Run the following command after the package finishes installing. Make sure that you replace `your-project-token` with your own project token. diff --git a/docs/snippets/common/build-storybook-production-mode.js.mdx b/docs/snippets/common/build-storybook-production-mode.js.mdx deleted file mode 100644 index 9bd298812fa..00000000000 --- a/docs/snippets/common/build-storybook-production-mode.js.mdx +++ /dev/null @@ -1,7 +0,0 @@ -```shell -# With yarn -yarn build-storybook - -# With npm -npm run build-storybook -``` \ No newline at end of file diff --git a/docs/snippets/common/build-storybook-production-mode.npm.js.mdx b/docs/snippets/common/build-storybook-production-mode.npm.js.mdx new file mode 100644 index 00000000000..15ee902eae4 --- /dev/null +++ b/docs/snippets/common/build-storybook-production-mode.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run build-storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/build-storybook-production-mode.yarn.js.mdx b/docs/snippets/common/build-storybook-production-mode.yarn.js.mdx new file mode 100644 index 00000000000..eda3dbd3ad9 --- /dev/null +++ b/docs/snippets/common/build-storybook-production-mode.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn build-storybook +``` \ No newline at end of file diff --git a/docs/snippets/common/chromatic-install.npm.js.mdx b/docs/snippets/common/chromatic-install.npm.js.mdx new file mode 100644 index 00000000000..08f68adbfcc --- /dev/null +++ b/docs/snippets/common/chromatic-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install chromatic --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/chromatic-install.yarn.js.mdx b/docs/snippets/common/chromatic-install.yarn.js.mdx new file mode 100644 index 00000000000..ef2232eb881 --- /dev/null +++ b/docs/snippets/common/chromatic-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev chromatic +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-actions-install.npm.js.mdx b/docs/snippets/common/storybook-addon-actions-install.npm.js.mdx new file mode 100644 index 00000000000..a693fd458d6 --- /dev/null +++ b/docs/snippets/common/storybook-addon-actions-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/addon-actions --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-actions-install.yarn.js.mdx b/docs/snippets/common/storybook-addon-actions-install.yarn.js.mdx new file mode 100644 index 00000000000..b1e52357c62 --- /dev/null +++ b/docs/snippets/common/storybook-addon-actions-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/addon-actions +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-essentials-install.npm.js.mdx b/docs/snippets/common/storybook-addon-essentials-install.npm.js.mdx new file mode 100644 index 00000000000..a693fd458d6 --- /dev/null +++ b/docs/snippets/common/storybook-addon-essentials-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/addon-actions --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-essentials-install.yarn.js.mdx b/docs/snippets/common/storybook-addon-essentials-install.yarn.js.mdx new file mode 100644 index 00000000000..7bc9cf52e94 --- /dev/null +++ b/docs/snippets/common/storybook-addon-essentials-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/addon-essentials +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-storyshots-install.npm.js.mdx b/docs/snippets/common/storybook-addon-storyshots-install.npm.js.mdx new file mode 100644 index 00000000000..1d4b6caf3ac --- /dev/null +++ b/docs/snippets/common/storybook-addon-storyshots-install.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install @storybook/addon-storyshots --save-dev +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-addon-storyshots-install.yarn.js.mdx b/docs/snippets/common/storybook-addon-storyshots-install.yarn.js.mdx new file mode 100644 index 00000000000..c847016ced6 --- /dev/null +++ b/docs/snippets/common/storybook-addon-storyshots-install.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add --dev @storybook/addon-storyshots +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-debug-webpack-dev.npm.js.mdx b/docs/snippets/common/storybook-debug-webpack-dev.npm.js.mdx new file mode 100644 index 00000000000..080af4a1deb --- /dev/null +++ b/docs/snippets/common/storybook-debug-webpack-dev.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run storybook -- --debug-webpack +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-debug-webpack-dev.yarn.js.mdx b/docs/snippets/common/storybook-debug-webpack-dev.yarn.js.mdx new file mode 100644 index 00000000000..8dbc7b2b49e --- /dev/null +++ b/docs/snippets/common/storybook-debug-webpack-dev.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn storybook --debug-webpack +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-debug-webpack-prod.npm.js.mdx b/docs/snippets/common/storybook-debug-webpack-prod.npm.js.mdx new file mode 100644 index 00000000000..5ca3edbb934 --- /dev/null +++ b/docs/snippets/common/storybook-debug-webpack-prod.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm run build-storybook -- --debug-webpack +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-debug-webpack-prod.yarn.js.mdx b/docs/snippets/common/storybook-debug-webpack-prod.yarn.js.mdx new file mode 100644 index 00000000000..1b2c9df5792 --- /dev/null +++ b/docs/snippets/common/storybook-debug-webpack-prod.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn build-storybook --debug-webpack +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-write-addon-install-dependencies.npm.js.mdx b/docs/snippets/common/storybook-write-addon-install-dependencies.npm.js.mdx new file mode 100644 index 00000000000..e196ab44437 --- /dev/null +++ b/docs/snippets/common/storybook-write-addon-install-dependencies.npm.js.mdx @@ -0,0 +1,3 @@ +```shell +npm install react react-dom @babel/cli +``` \ No newline at end of file diff --git a/docs/snippets/common/storybook-write-addon-install-dependencies.yarn.js.mdx b/docs/snippets/common/storybook-write-addon-install-dependencies.yarn.js.mdx new file mode 100644 index 00000000000..e81984d3e2a --- /dev/null +++ b/docs/snippets/common/storybook-write-addon-install-dependencies.yarn.js.mdx @@ -0,0 +1,3 @@ +```shell +yarn add react react-dom @babel/cli +``` \ No newline at end of file diff --git a/docs/writing-stories/play-function.md b/docs/writing-stories/play-function.md index cef5c1be992..0923ee57a2c 100644 --- a/docs/writing-stories/play-function.md +++ b/docs/writing-stories/play-function.md @@ -10,13 +10,16 @@ We recommend installing Storybook's [`addon-interactions`](https://storybook.js. Run the following command to install the addon and the required dependencies. -```shell -# With npm -npm install @storybook/addon-interactions @storybook/testing-library --save-dev + -# With yarn -yarn add --dev @storybook/addon-interactions @storybook/testing-library -``` + + + Update your Storybook configuration (in `.storybook/main.js`) to include the interactions addon. diff --git a/docs/writing-tests/snapshot-testing.md b/docs/writing-tests/snapshot-testing.md index 242c1f00885..1b90a05dfec 100644 --- a/docs/writing-tests/snapshot-testing.md +++ b/docs/writing-tests/snapshot-testing.md @@ -14,13 +14,16 @@ Storybook is a helpful tool for snapshot testing because every story is essentia Run the following command to install Storyshots: -```shell -# With npm -npm install @storybook/addon-storyshots --save-dev + -# With yarn -yarn add --dev @storybook/addon-storyshots -``` + + + Add a test file to your environment with the following contents to configure Storyshots: diff --git a/docs/writing-tests/visual-testing.md b/docs/writing-tests/visual-testing.md index a5336a3854a..bed00fbfcff 100644 --- a/docs/writing-tests/visual-testing.md +++ b/docs/writing-tests/visual-testing.md @@ -20,13 +20,18 @@ To get started, sign up with your [GitHub](https://github.com/), [GitLab](https: Next, install the [chromatic](https://www.npmjs.com/package/chromatic) CLI package from npm: -```shell -# With npm -npm install chromatic --save-dev + + + + + + -# With yarn -yarn add --dev chromatic -``` Run the following command after the package finishes installing: From 6020acdeba0c4b01a02752a14e0d275e8575878b Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Tue, 31 May 2022 18:36:56 +0100 Subject: [PATCH 58/69] Adds spacing to prevent issues with the link --- docs/get-started/install.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/get-started/install.md b/docs/get-started/install.md index be09b6b2a85..8c5fe9ae609 100644 --- a/docs/get-started/install.md +++ b/docs/get-started/install.md @@ -90,7 +90,9 @@ Below are some of the most common installation issues and instructions on how to
+ Storybook collects completely anonymous data to help us improve user experience. Participation is optional, and you may [opt-out](../configure/telemetry.md#how-to-opt-out) if you'd not like to share any information. +
If all else fails, try asking for [help](https://storybook.js.org/support) From 2317e6e43f31462288f240cf69d1ebf12f865082 Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Tue, 31 May 2022 13:51:46 -0400 Subject: [PATCH 59/69] Fix global argTypes definition docs --- docs/snippets/common/button-story-project-args-theme.js.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/snippets/common/button-story-project-args-theme.js.mdx b/docs/snippets/common/button-story-project-args-theme.js.mdx index da897c5a782..c3fd8bd5e66 100644 --- a/docs/snippets/common/button-story-project-args-theme.js.mdx +++ b/docs/snippets/common/button-story-project-args-theme.js.mdx @@ -2,7 +2,7 @@ // preview.js // All stories expect a theme arg -export const argTypes = { theme: { control: { options: ['light', 'dark'] } } }; +export const argTypes = { theme: { control: 'select', options: ['light', 'dark'] } }; // The default value of the theme arg to all stories export const args = { theme: 'light' }; From e5841e4210c0d641ccbcdd453b0b842694ac5ffe Mon Sep 17 00:00:00 2001 From: Stefanos Lignos Zivver Date: Thu, 26 May 2022 15:35:32 +0200 Subject: [PATCH 60/69] feat(cli): Add support for angular/cli@14.0.0 --- .../src/generators/ANGULAR/angular-helpers.ts | 32 ++++++++++++++++--- lib/cli/src/generators/ANGULAR/index.ts | 9 ++---- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/lib/cli/src/generators/ANGULAR/angular-helpers.ts b/lib/cli/src/generators/ANGULAR/angular-helpers.ts index bd9eecfa2ba..a1ab6d8f922 100644 --- a/lib/cli/src/generators/ANGULAR/angular-helpers.ts +++ b/lib/cli/src/generators/ANGULAR/angular-helpers.ts @@ -10,7 +10,7 @@ type TsConfig = { export function getAngularAppTsConfigPath() { const angularJson = readFileAsJson('angular.json', true); - const { defaultProject } = angularJson; + const defaultProject = getDefaultProjectName(angularJson); const tsConfigPath = angularJson.projects[defaultProject].architect.build.options.tsConfig; if (!tsConfigPath || !fs.existsSync(path.resolve(tsConfigPath))) { @@ -50,9 +50,33 @@ export function editStorybookTsConfig(tsconfigPath: string) { writeFileAsJson(tsconfigPath, tsConfigJson); } -export function isDefaultProjectSet() { - const angularJson = readFileAsJson('angular.json', true); - return angularJson && !!angularJson.defaultProject; +export function getDefaultProjectName(angularJson: any): string | undefined { + const { defaultProject, projects } = angularJson; + + if (projects?.storybook) { + return 'storybook'; + } + + if (defaultProject) { + return defaultProject; + } + + const firstProjectName = projects ? Object.keys(projects)[0] : undefined; + if (firstProjectName) { + return firstProjectName; + } + + return undefined; +} + +export function checkForProjects() { + const { projects } = readFileAsJson('angular.json', true); + + if (!projects || Object.keys(projects).length === 0) { + throw new Error( + 'Could not find a project in your Angular workspace. \nAdd a project and re-run the installation' + ); + } } export async function getBaseTsConfigName() { diff --git a/lib/cli/src/generators/ANGULAR/index.ts b/lib/cli/src/generators/ANGULAR/index.ts index 934ceb6295d..3ff3b1b4d85 100644 --- a/lib/cli/src/generators/ANGULAR/index.ts +++ b/lib/cli/src/generators/ANGULAR/index.ts @@ -1,7 +1,7 @@ import path from 'path'; import semver from '@storybook/semver'; import { - isDefaultProjectSet, + checkForProjects, editStorybookTsConfig, getAngularAppTsConfigJson, getAngularAppTsConfigPath, @@ -28,11 +28,8 @@ function editAngularAppTsConfig() { } const generator: Generator = async (packageManager, npmOptions, options) => { - if (!isDefaultProjectSet()) { - throw new Error( - 'Could not find a default project in your Angular workspace.\nSet a defaultProject in your angular.json and re-run the installation.' - ); - } + checkForProjects(); + const angularVersion = semver.coerce( packageManager.retrievePackageJson().dependencies['@angular/core'] )?.version; From fc2edfaa40485af9fe8d9cb59cb99ca4553a7798 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Wed, 1 Jun 2022 11:05:24 +0200 Subject: [PATCH 61/69] chore(vue-kitchen-sink): scope styles in App.vue --- examples/vue-kitchen-sink/src/App.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vue-kitchen-sink/src/App.vue b/examples/vue-kitchen-sink/src/App.vue index 06f14e40a8c..7695b522c01 100644 --- a/examples/vue-kitchen-sink/src/App.vue +++ b/examples/vue-kitchen-sink/src/App.vue @@ -30,7 +30,7 @@ export default { } -