Skip to content

Commit 8952fa6

Browse files
authored
Storybook/Export to CodeSandbox (#19583)
Adds a "Open in CodeSandbox" button to stories in Storybook in Docs mode.
1 parent 586adc8 commit 8952fa6

8 files changed

Lines changed: 154 additions & 1 deletion

.storybook/babel.plugin.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* This Babel plugin adds `context.parameters.fullSource` property to Storybook stories,
3+
* which contains source of of the file where story is present.
4+
* It’s utilized by Export to CodeSandbox.
5+
* @param {import('@babel/core')} babel
6+
* @returns {import('@babel/core').PluginObj}
7+
*/
8+
module.exports = function (babel) {
9+
const { types: t } = babel;
10+
11+
return {
12+
name: 'literal-replacer',
13+
visitor: {
14+
MemberExpression(path) {
15+
if (
16+
t.isIdentifier(path.node.property) &&
17+
t.isIdentifier(path.node.object) &&
18+
path.node.property.name === 'parameters' &&
19+
path.parentPath.isAssignmentExpression()
20+
) {
21+
const storyName = path.node.object.name;
22+
const expression = t.expressionStatement(
23+
t.assignmentExpression(
24+
'=',
25+
t.memberExpression(
26+
t.memberExpression(t.identifier(storyName), t.identifier('parameters')),
27+
t.identifier('fullSource'),
28+
),
29+
t.identifier('__STORY__'),
30+
),
31+
);
32+
const expressionStatement = path.findParent(p => p.isExpressionStatement());
33+
expressionStatement.insertAfter(expression);
34+
path.stop();
35+
}
36+
},
37+
},
38+
};
39+
};

.storybook/main.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ module.exports = /** @type {Omit<StorybookConfig,'typescript'|'babel'>} */ ({
3939
'@storybook/addon-a11y',
4040
'@storybook/addon-knobs/preset',
4141
'storybook-addon-performance',
42+
'storybook-addon-export-to-codesandbox',
4243
],
4344
webpackFinal: config => {
4445
const tsPaths = new TsconfigPathsPlugin({
@@ -51,6 +52,17 @@ module.exports = /** @type {Omit<StorybookConfig,'typescript'|'babel'>} */ ({
5152

5253
if (config.module && config.module.rules) {
5354
overrideDefaultBabelLoader(/** @type {import("webpack").RuleSetRule[]} */ (config.module.rules));
55+
56+
config.module.rules.unshift({
57+
test: /\.stories\.tsx$/,
58+
exclude: /node_modules/,
59+
use: {
60+
loader: 'babel-loader',
61+
options: {
62+
plugins: [require('storybook-addon-export-to-codesandbox').babelPlugin],
63+
},
64+
},
65+
});
5466
}
5567

5668
return config;

.storybook/preview.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { withFluentProvider, withStrictMode } from '@fluentui/react-storybook';
22
import 'cypress-storybook/react';
3+
import dedent from 'dedent';
34

45
/** @type {NonNullable<import('@storybook/react').Story['decorators']>} */
56
export const decorators = [withFluentProvider, withStrictMode];
@@ -15,4 +16,24 @@ export const parameters = {
1516
excludeDecorators: true,
1617
},
1718
},
19+
exportToCodeSandbox: {
20+
requiredDependencies: {
21+
'react-dom': 'latest', // for React
22+
'react-scripts': 'latest', // necessary when using typescript in CodeSandbox
23+
'@fluentui/react-components': '^9.0.0-alpha', // necessary for FluentProvider
24+
},
25+
indexTsx: dedent`
26+
import * as ReactDOM from 'react-dom';
27+
import { FluentProvider, webLightTheme } from '@fluentui/react-components';
28+
import { STORY_NAME as Example } from './example';
29+
//
30+
// You can edit this example in "example.tsx".
31+
//
32+
ReactDOM.render(
33+
<FluentProvider theme={webLightTheme}>
34+
<Example />
35+
</FluentProvider>,
36+
document.getElementById('root'),
37+
);`,
38+
},
1839
};
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "none",
3+
"comment": "update stories structure to make them exportable to CodeSandbox",
4+
"packageName": "@fluentui/react-button",
5+
"email": "[email protected]",
6+
"dependentChangeType": "none"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "none",
3+
"comment": "Add export to CodeSandbox for stories",
4+
"packageName": "@fluentui/react-components",
5+
"email": "[email protected]",
6+
"dependentChangeType": "none"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "export to codesandbox",
4+
"packageName": "@fluentui/react-menu",
5+
"email": "[email protected]",
6+
"dependentChangeType": "patch"
7+
}

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
"@testing-library/react-hooks": "5.0.3",
116116
"@types/babel__helper-plugin-utils": "7.10.0",
117117
"@types/copy-webpack-plugin": "6.4.0",
118+
"@types/dedent": "latest",
118119
"@types/enhanced-resolve": "3.0.7",
119120
"@types/eslint": "7.2.13",
120121
"@types/express": "4.17.2",
@@ -231,7 +232,8 @@
231232
"webpack-merge": "5.7.3",
232233
"workspace-tools": "0.16.2",
233234
"yargs": "13.3.2",
234-
"yargs-parser": "13.1.2"
235+
"yargs-parser": "13.1.2",
236+
"storybook-addon-export-to-codesandbox": "0.5.1"
235237
},
236238
"license": "MIT",
237239
"workspaces": {

yarn.lock

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4368,6 +4368,11 @@
43684368
resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.0.10.tgz#d338c7feac93a98a32aac875d1100f92c7b61f4f"
43694369
integrity sha512-aKf62rRQafDQmSiv1NylKhIMmznsjRN+MnXRXTqHoqm0U/UZzVpdrtRnSIfdiLS616OuC1soYeX1dBg2n1u8Xw==
43704370

4371+
"@types/dedent@latest":
4372+
version "0.7.0"
4373+
resolved "https://registry.yarnpkg.com/@types/dedent/-/dedent-0.7.0.tgz#155f339ca404e6dd90b9ce46a3f78fd69ca9b050"
4374+
integrity sha512-EGlKlgMhnLt/cM4DbUSafFdrkeJoC9Mvnj0PUCU7tFmTjMjNRT957kXCx0wYm3JuEq4o4ZsS5vG+NlkM2DMd2A==
4375+
43714376
"@types/deep-assign@^0.1.1":
43724377
version "0.1.1"
43734378
resolved "https://registry.yarnpkg.com/@types/deep-assign/-/deep-assign-0.1.1.tgz#c10aa2d6202774015f5820ed303b82ab3b0bde9b"
@@ -7327,6 +7332,11 @@ binary@^0.3.0:
73277332
buffers "~0.1.1"
73287333
chainsaw "~0.1.0"
73297334

7335+
binaryextensions@^2.1.2:
7336+
version "2.3.0"
7337+
resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22"
7338+
integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==
7339+
73307340
bl@^1.0.0:
73317341
version "1.2.3"
73327342
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7"
@@ -8535,6 +8545,20 @@ code-point-at@^1.0.0:
85358545
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
85368546
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
85378547

8548+
codesandbox-import-util-types@^2.2.3:
8549+
version "2.2.3"
8550+
resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-2.2.3.tgz#b354b2f732ad130e119ebd9ead3bda3be5981a54"
8551+
integrity sha512-Qj00p60oNExthP2oR3vvXmUGjukij+rxJGuiaKM6tyUmSyimdZsqHI/TUvFFClAffk9s7hxGnQgWQ8KCce27qQ==
8552+
8553+
codesandbox-import-utils@^2.2.3:
8554+
version "2.2.3"
8555+
resolved "https://registry.yarnpkg.com/codesandbox-import-utils/-/codesandbox-import-utils-2.2.3.tgz#f7b4801245b381cb8c90fe245e336624e19b6c84"
8556+
integrity sha512-ymtmcgZKU27U+nM2qUb21aO8Ut/u2S9s6KorOgG81weP+NA0UZkaHKlaRqbLJ9h4i/4FLvwmEXYAnTjNmp6ogg==
8557+
dependencies:
8558+
codesandbox-import-util-types "^2.2.3"
8559+
istextorbinary "^2.2.1"
8560+
lz-string "^1.4.4"
8561+
85388562
codesandboxer@^1.0.3:
85398563
version "1.0.3"
85408564
resolved "https://registry.yarnpkg.com/codesandboxer/-/codesandboxer-1.0.3.tgz#a2530a15eb9395f2c6f25e4b8064063dfb7b12f9"
@@ -10621,6 +10645,14 @@ [email protected]:
1062110645
dependencies:
1062210646
safe-buffer "^5.0.1"
1062310647

10648+
editions@^2.2.0:
10649+
version "2.3.1"
10650+
resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.1.tgz#3bc9962f1978e801312fbd0aebfed63b49bfe698"
10651+
integrity sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==
10652+
dependencies:
10653+
errlop "^2.0.0"
10654+
semver "^6.3.0"
10655+
1062410656
1062510657
version "1.1.1"
1062610658
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -10906,6 +10938,11 @@ err-code@^1.0.0:
1090610938
resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960"
1090710939
integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=
1090810940

10941+
errlop@^2.0.0:
10942+
version "2.2.0"
10943+
resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b"
10944+
integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==
10945+
1090910946
errno@^0.1.3, errno@~0.1.7:
1091010947
version "0.1.7"
1091110948
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@@ -15303,6 +15340,15 @@ istanbul@^0.4.5:
1530315340
which "^1.1.1"
1530415341
wordwrap "^1.0.0"
1530515342

15343+
istextorbinary@^2.2.1:
15344+
version "2.6.0"
15345+
resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab"
15346+
integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==
15347+
dependencies:
15348+
binaryextensions "^2.1.2"
15349+
editions "^2.2.0"
15350+
textextensions "^2.5.0"
15351+
1530615352
isurl@^1.0.0-alpha5:
1530715353
version "1.0.0"
1530815354
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
@@ -23258,6 +23304,13 @@ store2@^2.12.0:
2325823304
resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf"
2325923305
integrity sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw==
2326023306

23307+
23308+
version "0.5.1"
23309+
resolved "https://registry.yarnpkg.com/storybook-addon-export-to-codesandbox/-/storybook-addon-export-to-codesandbox-0.5.1.tgz#828490c522baa705e36a6d5f2cb73184634ba1a8"
23310+
integrity sha512-uNb751qS0AF1UJpoHW0iZMWP+2I6MMo8wdxGUQ1QbaXkvMEtGeYo9bcz2fT4uBJ4Vhd1YSbzUzdfiK6VBdFyzg==
23311+
dependencies:
23312+
codesandbox-import-utils "^2.2.3"
23313+
2326123314
storybook-addon-outline@^1.4.1:
2326223315
version "1.4.1"
2326323316
resolved "https://registry.yarnpkg.com/storybook-addon-outline/-/storybook-addon-outline-1.4.1.tgz#0a1b262b9c65df43fc63308a1fdbd4283c3d9458"
@@ -24090,6 +24143,11 @@ [email protected], text-table@^0.2.0:
2409024143
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
2409124144
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
2409224145

24146+
textextensions@^2.5.0:
24147+
version "2.6.0"
24148+
resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4"
24149+
integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==
24150+
2409324151
thenify-all@^1.0.0:
2409424152
version "1.6.0"
2409524153
resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"

0 commit comments

Comments
 (0)