diff --git a/.storybook/babel.plugin.js b/.storybook/babel.plugin.js new file mode 100644 index 0000000000000..4babb454038e5 --- /dev/null +++ b/.storybook/babel.plugin.js @@ -0,0 +1,39 @@ +/** + * This Babel plugin adds `context.parameters.fullSource` property to Storybook stories, + * which contains source of of the file where story is present. + * It’s utilized by Export to CodeSandbox. + * @param {import('@babel/core')} babel + * @returns {import('@babel/core').PluginObj} + */ +module.exports = function (babel) { + const { types: t } = babel; + + return { + name: 'literal-replacer', + visitor: { + MemberExpression(path) { + if ( + t.isIdentifier(path.node.property) && + t.isIdentifier(path.node.object) && + path.node.property.name === 'parameters' && + path.parentPath.isAssignmentExpression() + ) { + const storyName = path.node.object.name; + const expression = t.expressionStatement( + t.assignmentExpression( + '=', + t.memberExpression( + t.memberExpression(t.identifier(storyName), t.identifier('parameters')), + t.identifier('fullSource'), + ), + t.identifier('__STORY__'), + ), + ); + const expressionStatement = path.findParent(p => p.isExpressionStatement()); + expressionStatement.insertAfter(expression); + path.stop(); + } + }, + }, + }; +}; diff --git a/.storybook/main.js b/.storybook/main.js index 30c501933e30d..7cc3b60e5db18 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -39,6 +39,7 @@ module.exports = /** @type {Omit} */ ({ '@storybook/addon-a11y', '@storybook/addon-knobs/preset', 'storybook-addon-performance', + 'storybook-addon-export-to-codesandbox', ], webpackFinal: config => { const tsPaths = new TsconfigPathsPlugin({ @@ -51,6 +52,17 @@ module.exports = /** @type {Omit} */ ({ if (config.module && config.module.rules) { overrideDefaultBabelLoader(/** @type {import("webpack").RuleSetRule[]} */ (config.module.rules)); + + config.module.rules.unshift({ + test: /\.stories\.tsx$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + plugins: [require('storybook-addon-export-to-codesandbox').babelPlugin], + }, + }, + }); } return config; diff --git a/.storybook/preview.js b/.storybook/preview.js index fef17237e88a9..44efcd08be4c7 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,5 +1,6 @@ import { withFluentProvider, withStrictMode } from '@fluentui/react-storybook'; import 'cypress-storybook/react'; +import dedent from 'dedent'; /** @type {NonNullable} */ export const decorators = [withFluentProvider, withStrictMode]; @@ -15,4 +16,24 @@ export const parameters = { excludeDecorators: true, }, }, + exportToCodeSandbox: { + requiredDependencies: { + 'react-dom': 'latest', // for React + 'react-scripts': 'latest', // necessary when using typescript in CodeSandbox + '@fluentui/react-components': '^9.0.0-alpha', // necessary for FluentProvider + }, + indexTsx: dedent` + import * as ReactDOM from 'react-dom'; + import { FluentProvider, webLightTheme } from '@fluentui/react-components'; + import { STORY_NAME as Example } from './example'; + // + // You can edit this example in "example.tsx". + // + ReactDOM.render( + + + , + document.getElementById('root'), + );`, + }, }; diff --git a/change/@fluentui-react-button-d1f817e2-ff90-495f-bdc9-27c91f7931ef.json b/change/@fluentui-react-button-d1f817e2-ff90-495f-bdc9-27c91f7931ef.json new file mode 100644 index 0000000000000..01b59364b3cc0 --- /dev/null +++ b/change/@fluentui-react-button-d1f817e2-ff90-495f-bdc9-27c91f7931ef.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "update stories structure to make them exportable to CodeSandbox", + "packageName": "@fluentui/react-button", + "email": "peter@draxler.ml", + "dependentChangeType": "none" +} diff --git a/change/@fluentui-react-components-ac6ea616-3cc3-4a01-ae02-aa2fb02937fe.json b/change/@fluentui-react-components-ac6ea616-3cc3-4a01-ae02-aa2fb02937fe.json new file mode 100644 index 0000000000000..3222ecdc1dc48 --- /dev/null +++ b/change/@fluentui-react-components-ac6ea616-3cc3-4a01-ae02-aa2fb02937fe.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "Add export to CodeSandbox for stories", + "packageName": "@fluentui/react-components", + "email": "peter@draxler.ml", + "dependentChangeType": "none" +} diff --git a/change/@fluentui-react-menu-96293a65-1e66-4664-8c63-955229640ba0.json b/change/@fluentui-react-menu-96293a65-1e66-4664-8c63-955229640ba0.json new file mode 100644 index 0000000000000..f4d4da4b995f6 --- /dev/null +++ b/change/@fluentui-react-menu-96293a65-1e66-4664-8c63-955229640ba0.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "export to codesandbox", + "packageName": "@fluentui/react-menu", + "email": "peter@draxler.ml", + "dependentChangeType": "patch" +} diff --git a/package.json b/package.json index a5408e8774d87..769fcab93f07f 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,7 @@ "@testing-library/react-hooks": "5.0.3", "@types/babel__helper-plugin-utils": "7.10.0", "@types/copy-webpack-plugin": "6.4.0", + "@types/dedent": "latest", "@types/enhanced-resolve": "3.0.7", "@types/eslint": "7.2.13", "@types/express": "4.17.2", @@ -231,7 +232,8 @@ "webpack-merge": "5.7.3", "workspace-tools": "0.16.2", "yargs": "13.3.2", - "yargs-parser": "13.1.2" + "yargs-parser": "13.1.2", + "storybook-addon-export-to-codesandbox": "0.5.1" }, "license": "MIT", "workspaces": { diff --git a/yarn.lock b/yarn.lock index 456021c61b646..9e4c8442bb459 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4368,6 +4368,11 @@ resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-1.0.10.tgz#d338c7feac93a98a32aac875d1100f92c7b61f4f" integrity sha512-aKf62rRQafDQmSiv1NylKhIMmznsjRN+MnXRXTqHoqm0U/UZzVpdrtRnSIfdiLS616OuC1soYeX1dBg2n1u8Xw== +"@types/dedent@latest": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@types/dedent/-/dedent-0.7.0.tgz#155f339ca404e6dd90b9ce46a3f78fd69ca9b050" + integrity sha512-EGlKlgMhnLt/cM4DbUSafFdrkeJoC9Mvnj0PUCU7tFmTjMjNRT957kXCx0wYm3JuEq4o4ZsS5vG+NlkM2DMd2A== + "@types/deep-assign@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@types/deep-assign/-/deep-assign-0.1.1.tgz#c10aa2d6202774015f5820ed303b82ab3b0bde9b" @@ -7327,6 +7332,11 @@ binary@^0.3.0: buffers "~0.1.1" chainsaw "~0.1.0" +binaryextensions@^2.1.2: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22" + integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg== + bl@^1.0.0: version "1.2.3" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" @@ -8535,6 +8545,20 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +codesandbox-import-util-types@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/codesandbox-import-util-types/-/codesandbox-import-util-types-2.2.3.tgz#b354b2f732ad130e119ebd9ead3bda3be5981a54" + integrity sha512-Qj00p60oNExthP2oR3vvXmUGjukij+rxJGuiaKM6tyUmSyimdZsqHI/TUvFFClAffk9s7hxGnQgWQ8KCce27qQ== + +codesandbox-import-utils@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/codesandbox-import-utils/-/codesandbox-import-utils-2.2.3.tgz#f7b4801245b381cb8c90fe245e336624e19b6c84" + integrity sha512-ymtmcgZKU27U+nM2qUb21aO8Ut/u2S9s6KorOgG81weP+NA0UZkaHKlaRqbLJ9h4i/4FLvwmEXYAnTjNmp6ogg== + dependencies: + codesandbox-import-util-types "^2.2.3" + istextorbinary "^2.2.1" + lz-string "^1.4.4" + codesandboxer@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/codesandboxer/-/codesandboxer-1.0.3.tgz#a2530a15eb9395f2c6f25e4b8064063dfb7b12f9" @@ -10621,6 +10645,14 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" +editions@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.1.tgz#3bc9962f1978e801312fbd0aebfed63b49bfe698" + integrity sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA== + dependencies: + errlop "^2.0.0" + semver "^6.3.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -10906,6 +10938,11 @@ err-code@^1.0.0: resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= +errlop@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b" + integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw== + errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" @@ -15303,6 +15340,15 @@ istanbul@^0.4.5: which "^1.1.1" wordwrap "^1.0.0" +istextorbinary@^2.2.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab" + integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA== + dependencies: + binaryextensions "^2.1.2" + editions "^2.2.0" + textextensions "^2.5.0" + isurl@^1.0.0-alpha5: version "1.0.0" resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" @@ -23258,6 +23304,13 @@ store2@^2.12.0: resolved "https://registry.yarnpkg.com/store2/-/store2-2.12.0.tgz#e1f1b7e1a59b6083b2596a8d067f6ee88fd4d3cf" integrity sha512-7t+/wpKLanLzSnQPX8WAcuLCCeuSHoWdQuh9SB3xD0kNOM38DNf+0Oa+wmvxmYueRzkmh6IcdKFtvTa+ecgPDw== +storybook-addon-export-to-codesandbox@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/storybook-addon-export-to-codesandbox/-/storybook-addon-export-to-codesandbox-0.5.1.tgz#828490c522baa705e36a6d5f2cb73184634ba1a8" + integrity sha512-uNb751qS0AF1UJpoHW0iZMWP+2I6MMo8wdxGUQ1QbaXkvMEtGeYo9bcz2fT4uBJ4Vhd1YSbzUzdfiK6VBdFyzg== + dependencies: + codesandbox-import-utils "^2.2.3" + storybook-addon-outline@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/storybook-addon-outline/-/storybook-addon-outline-1.4.1.tgz#0a1b262b9c65df43fc63308a1fdbd4283c3d9458" @@ -24090,6 +24143,11 @@ text-table@0.2.0, text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +textextensions@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4" + integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ== + thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"