diff --git a/.storybook/main.mjs b/.storybook/main.mjs index 081c708..77d0d96 100644 --- a/.storybook/main.mjs +++ b/.storybook/main.mjs @@ -31,7 +31,7 @@ export default { name: '@storybook/react-webpack5', options: {}, }, - stories: ['../**/*.mdx', '../**/*.stories.*'], + stories: ['../**/Introduction.mdx', '../**/*.mdx', '../**/*.stories.*'], storyIndexers: (indexers) => { // ? Extend js story indexer for mjs return indexers.map((indexer) => { diff --git a/README.md b/README.md index 43831bd..c0c364a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # @idesigncode/storybook-tools -A collection of tools & React components for use with Storybook. +A collection of ESM tools to document component implementation examples in Storybook. ## Documentation [![Storybook](https://cdn.jsdelivr.net/gh/storybookjs/brand@main/badge/badge-storybook.svg)](https://idesigncode-storybook-tools.netlify.app) @@ -9,7 +9,7 @@ Check out the [documentation](https://idesigncode-storybook-tools.netlify.app/) ## Installation ```shell -npm i @idesigncode/storybook-tools --save +npm i @idesigncode/storybook-tools --save-dev ``` ## Features diff --git a/__snapshots__/components-defaultvalue.test.js.snap b/__snapshots__/components-defaultvalue.test.js.snap index 4491d91..8bce214 100644 --- a/__snapshots__/components-defaultvalue.test.js.snap +++ b/__snapshots__/components-defaultvalue.test.js.snap @@ -7,7 +7,7 @@ exports[`Components/DefaultValue Automatic Type Source test 1`] = ` style="white-space: pre;" > - // Stories of Component.mjs + // Component.stories.mjs @@ -112,7 +112,7 @@ exports[`Components/DefaultValue Manual Type With Link Source test 1`] = ` style="white-space: pre;" > - // Stories of Component.mjs + // Component.stories.mjs @@ -346,7 +346,7 @@ exports[`Components/DefaultValue Ref Type Source test 1`] = ` style="white-space: pre;" > - // Stories of Component.mjs + // Component.stories.mjs diff --git a/__snapshots__/components-propstable.test.js.snap b/__snapshots__/components-propstable.test.js.snap index 0ccf1e5..a7581ee 100644 --- a/__snapshots__/components-propstable.test.js.snap +++ b/__snapshots__/components-propstable.test.js.snap @@ -818,7 +818,7 @@ exports[`Components/PropsTable Automatic Props Source test 1`] = ` style="white-space: pre;" > - // InputWithProps.mjs (the "example component") + // Input.example.mjs (the "example component") @@ -893,7 +893,7 @@ exports[`Components/PropsTable Automatic Props Source test 1`] = ` - InputWithProps + InputExample @@ -1145,7 +1145,7 @@ exports[`Components/PropsTable Automatic Props Source test 1`] = ` default - InputWithProps + InputExample ; @@ -1314,7 +1314,7 @@ exports[`Components/PropsTable Manual Type With Required Source test 1`] = ` style="white-space: pre;" > - // InputWithProps.mjs (the "example component") + // Input.example.mjs (the "example component") @@ -1389,7 +1389,7 @@ exports[`Components/PropsTable Manual Type With Required Source test 1`] = ` - InputWithProps + InputExample @@ -1806,7 +1806,7 @@ exports[`Components/PropsTable Manual Type With Required Source test 1`] = ` default - InputWithProps + InputExample ; @@ -2090,7 +2090,7 @@ exports[`Components/PropsTable Raw Import Displayed Source test 1`] = ` style="white-space: pre;" > - // Source code displayed by <Source code={InputWithPropsRaw} /> + // Source code displayed by <Source code={InputExampleRaw} /> @@ -2144,7 +2144,7 @@ exports[`Components/PropsTable Raw Import Displayed Source test 1`] = ` - InputWithProps + InputExample @@ -2350,7 +2350,7 @@ exports[`Components/PropsTable Raw Import Displayed Source test 1`] = ` default - InputWithProps + InputExample ; @@ -2372,7 +2372,7 @@ exports[`Components/PropsTable Raw Import test 1`] = ` style="white-space: pre;" > - // Stories of Input.mjs + // Input.stories.mjs @@ -2382,7 +2382,7 @@ exports[`Components/PropsTable Raw Import test 1`] = ` import - InputWithPropsRaw + InputExampleRaw from @@ -2390,7 +2390,7 @@ exports[`Components/PropsTable Raw Import test 1`] = ` - './InputWithProps.mjs?raw' + './Input.example.mjs?raw' ; @@ -2417,7 +2417,7 @@ exports[`Components/PropsTable Raw Import test 1`] = ` { - InputWithPropsRaw + InputExampleRaw } diff --git a/__snapshots__/components-source--component-example-raw-displayed-source.png b/__snapshots__/components-source--component-example-raw-displayed-source.png new file mode 100644 index 0000000..f056611 Binary files /dev/null and b/__snapshots__/components-source--component-example-raw-displayed-source.png differ diff --git a/__snapshots__/components-source--component-example-raw.png b/__snapshots__/components-source--component-example-raw.png new file mode 100644 index 0000000..c0bb8ff Binary files /dev/null and b/__snapshots__/components-source--component-example-raw.png differ diff --git a/__snapshots__/components-source--component-example.png b/__snapshots__/components-source--component-example.png new file mode 100644 index 0000000..acfb399 Binary files /dev/null and b/__snapshots__/components-source--component-example.png differ diff --git a/__snapshots__/components-source.test.js.snap b/__snapshots__/components-source.test.js.snap index e9912e4..58c8fad 100644 --- a/__snapshots__/components-source.test.js.snap +++ b/__snapshots__/components-source.test.js.snap @@ -42,7 +42,7 @@ exports[`Components/Source Code test 1`] = ` `; -exports[`Components/Source Component With Props Raw Displayed Source test 1`] = ` +exports[`Components/Source Component Example Raw Displayed Source test 1`] = `
     
 `;
 
-exports[`Components/Source Component With Props Raw test 1`] = `
+exports[`Components/Source Component Example Raw test 1`] = `
 
     
       
-        // Stories of Component.mjs
+        // Component.stories.mjs
       
       
       
@@ -139,7 +139,7 @@ exports[`Components/Source Component With Props Raw test 1`] = `
         import
       
       
-        ComponentWithPropsRaw
+        ComponentExampleRaw
       
       
         from
@@ -147,7 +147,7 @@ exports[`Components/Source Component With Props Raw test 1`] = `
       
       
       
-        './ComponentWithProps.mjs?raw'
+        './Component.example.mjs?raw'
       
       
         ;
@@ -197,7 +197,7 @@ exports[`Components/Source Component With Props Raw test 1`] = `
         {
       
       
-        ComponentWithPropsRaw
+        ComponentExampleRaw
       
       
         }
@@ -371,14 +371,14 @@ exports[`Components/Source Component With Props Raw test 1`] = `
 
`; -exports[`Components/Source Component With Props test 1`] = ` +exports[`Components/Source Component Example test 1`] = `
     
       
-        // ComponentWithProps.mjs (the "example component")
+        // Component.example.mjs (the "example component")
       
       
       
diff --git a/__snapshots__/configuration-webpack.test.js.snap b/__snapshots__/configuration-webpack.test.js.snap
index d3889ab..8f438b4 100644
--- a/__snapshots__/configuration-webpack.test.js.snap
+++ b/__snapshots__/configuration-webpack.test.js.snap
@@ -280,7 +280,7 @@ exports[`Configuration/Webpack Raw Import test 1`] = `
           style="white-space: pre;"
     >
       
-        // Stories of Component.mjs
+        // Component.stories.mjs
       
       
       
@@ -290,7 +290,7 @@ exports[`Configuration/Webpack Raw Import test 1`] = `
         import
       
       
-        ComponentWithPropsRaw
+        ComponentExampleRaw
       
       
         from
@@ -298,7 +298,7 @@ exports[`Configuration/Webpack Raw Import test 1`] = `
       
       
       
-        './ComponentWithProps.mjs?raw'
+        './Component.example.mjs?raw'
       
       
         ;
@@ -562,7 +562,7 @@ exports[`Configuration/Webpack Webpack Final Config test 1`] = `
       
       
       
-        // ? Enable correct display of dynamic source code in production
+        // ? Enable unminified display of props in production
       
       
       
diff --git a/package.json b/package.json
index e924ea8..928c0b4 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@idesigncode/storybook-tools",
   "version": "2.1.0",
-  "description": "A collection of tools & React components for use with Storybook.",
+  "description": "A collection of ESM tools to document component implementation examples in Storybook.",
   "keywords": [
     "react",
     "css",
diff --git a/src/storybookConfig.mjs b/src/storybookConfig.mjs
index b9bd02d..ee67fe8 100644
--- a/src/storybookConfig.mjs
+++ b/src/storybookConfig.mjs
@@ -12,7 +12,7 @@ export const webpackFinal = async (config) => {
     return rule;
   });
 
-  // ? Enable correct display of dynamic source code in production
+  // ? Enable unminified display of props in production
   config.optimization.minimizer.map((minimizer) => {
     minimizer.options.minimizer.options.compress = false;
     minimizer.options.minimizer.options.format = { comments: true };
diff --git a/stories/ComponentWithProps.mjs b/stories/Component.example.mjs
similarity index 95%
rename from stories/ComponentWithProps.mjs
rename to stories/Component.example.mjs
index db671f8..92c0cdb 100644
--- a/stories/ComponentWithProps.mjs
+++ b/stories/Component.example.mjs
@@ -7,7 +7,7 @@ export const Input = React.forwardRef((props, ref) => (
 ));
 Input.displayName = 'Input';
 
-const ComponentWithProps = () => {
+const ComponentExample = () => {
   const ref = React.useRef();
 
   return (
@@ -56,4 +56,4 @@ const ComponentWithProps = () => {
   );
 };
 
-export default ComponentWithProps;
+export default ComponentExample;
diff --git a/stories/DefaultValue.mdx b/stories/DefaultValue.mdx
index 84a8ff8..348f62b 100644
--- a/stories/DefaultValue.mdx
+++ b/stories/DefaultValue.mdx
@@ -5,7 +5,7 @@ import * as DefaultValueStories from './DefaultValue.stories.mjs';
 
 # DefaultValue
 
-A simple [MDX component](https://storybook.js.org/docs/react/writing-docs/mdx) that adds a table with details of a single prop's default value.
+A simple component that adds a table with details of a single prop's default value.
 
 
 
diff --git a/stories/DefaultValue.stories.mjs b/stories/DefaultValue.stories.mjs
index 93a05ff..c3f0b02 100644
--- a/stories/DefaultValue.stories.mjs
+++ b/stories/DefaultValue.stories.mjs
@@ -34,7 +34,7 @@ export const AutomaticTypeSource = {
     return (
       ),
diff --git a/stories/ImportPathReplacements.mdx b/stories/ImportPathReplacements.mdx
index fe1f486..905b13a 100644
--- a/stories/ImportPathReplacements.mdx
+++ b/stories/ImportPathReplacements.mdx
@@ -1,4 +1,5 @@
 import { Meta, Story } from '@storybook/addon-docs';
+import ImportPathReplacementsObject from './ImportPathReplacementsObject.mjs';
 import * as ImportPathReplacementsStories from './ImportPathReplacements.stories.mjs';
 
 
@@ -9,31 +10,17 @@ The [Source](/docs/components-source--docs) component can automatically display
 
 By default, this functionality is disabled unless `process.env.IMPORT_PATH_REPLACEMENTS` has a value - a stringified `{ key: value }` object:
 
-
-  
-    
-      
-      
-    
-    
-      
-      
-    
-  
-
`key` - A string to match within an import path. Also accepts `^` to prepend - relative paths. -
`value`A string to replace the matched `key` string.
- -> #### Note: -> -> - Import path replacements are performed in the order specified. -> - Matches may occur more than once within an import path. + To use import path replacements globally, you can add the configuration to an `.env` file or with [Storybook environment variables](https://storybook.js.org/docs/react/configure/environment-variables#using-storybook-configuration): +> #### Note: +> +> - Import path replacements are performed in the order specified. +> - Matches may occur more than once within an import path. +> > #### See also: > > - [Source](/docs/components-source--docs) - further information and examples of using import path replacements. diff --git a/stories/ImportPathReplacementsObject.mjs b/stories/ImportPathReplacementsObject.mjs new file mode 100644 index 0000000..453a369 --- /dev/null +++ b/stories/ImportPathReplacementsObject.mjs @@ -0,0 +1,30 @@ +import React from 'react'; + +const ImportPathReplacementsObject = () => ( + + + + + + + + + + + + + + + + +
Import path replacements object
+ key + + A string to match within an import path. Also accepts `^` to prepend + relative paths. +
+ value + A string to replace the matched `key` string.
+); + +export default ImportPathReplacementsObject; diff --git a/stories/InputWithProps.mjs b/stories/Input.example.mjs similarity index 88% rename from stories/InputWithProps.mjs rename to stories/Input.example.mjs index e4fbb3b..1ae31d0 100644 --- a/stories/InputWithProps.mjs +++ b/stories/Input.example.mjs @@ -2,7 +2,7 @@ import React from 'react'; import PropsTable from '../src/PropsTable.mjs'; import Input from './Input.mjs'; // preserve-path -const InputWithProps = (props) => { +const InputExample = (props) => { const [value, setValue] = React.useState(''); return ( @@ -17,4 +17,4 @@ const InputWithProps = (props) => { ); }; -export default InputWithProps; +export default InputExample; diff --git a/stories/Introduction.mdx b/stories/Introduction.mdx new file mode 100644 index 0000000..3eced69 --- /dev/null +++ b/stories/Introduction.mdx @@ -0,0 +1,50 @@ +import { Meta } from '@storybook/addon-docs'; +import Source from '../src/Source.mjs'; + + + +# Introduction + +To get started, let's first take a look at the suggested file structure: + + + +Using a separate file for each implementation "example component" allows us to: + +- Add state functionality (as you would in a real implementation). +- Define a variety of prop combinations. +- Import the functional example as the rendered component of a story. +- Import the file as raw source code (with some [Webpack](https://idesigncode-storybook-tools.netlify.app/?path=/docs/configuration-webpack--docs) configuration). + +Of course the file names and locations are just a suggestion - they are not required. + +## Components + +All components are designed to be used within [stories](https://storybook.js.org/docs/react/writing-stories/introduction) or directly in [Docs pages](https://storybook.js.org/docs/react/writing-docs/mdx). + +- [DefaultValue](/docs/components-propstable--docs) - a table detailing a single prop's default value. +- [PropsTable](/docs/components-propstable--docs) - automatically document static & "live-updating" props details. +- [Source](/docs/components-source--docs) - display a block of source code. + +These components are also compatible with [User Interaction](https://storybook.js.org/docs/react/writing-tests/interaction-testing), [DOM](https://jestjs.io/docs/snapshot-testing) & [Image](https://github.com/americanexpress/jest-image-snapshot) Snapshot tests. + +## Configuration + +The default themes and component styles can be imported with the [default CSS styles](https://idesigncode-storybook-tools.netlify.app/?path=/docs/configuration-css--docs). + +If are using Docs pages, you might also want to enable the light & dark mode theme functionality with the [DocsContainer](https://idesigncode-storybook-tools.netlify.app/?path=/docs/configuration-docscontainer--docs). + +Optionally, some further configuration is required for some of the more advanced functionality: + +- [Webpack](https://idesigncode-storybook-tools.netlify.app/?path=/docs/configuration-webpack--docs) - enables the "raw imports" and "unminified display of props" functionality. +- [Import Path Replacements](/docs/configuration-import-path-replacements--docs) - enables transforming file import paths displayed by the Source component. diff --git a/stories/PropsTable.mdx b/stories/PropsTable.mdx index 6f5da2c..64db2e0 100644 --- a/stories/PropsTable.mdx +++ b/stories/PropsTable.mdx @@ -7,8 +7,6 @@ import * as PropsTableStories from './PropsTable.stories.mjs'; Adds a table of props details automatically generated from the props given to a single child component. -Can be used within [stories](https://storybook.js.org/docs/react/writing-stories/introduction) or directly in [MDX pages](https://storybook.js.org/docs/react/writing-docs/mdx). - > #### Note: diff --git a/stories/PropsTable.stories.mjs b/stories/PropsTable.stories.mjs index 7fa6833..5ca6c03 100644 --- a/stories/PropsTable.stories.mjs +++ b/stories/PropsTable.stories.mjs @@ -6,10 +6,10 @@ import prettier from 'prettier/standalone'; import formatValueToString from '../src/formatValueToString.mjs'; import PropsTable from '../src/PropsTable.mjs'; import Source from '../src/Source.mjs'; +import ComponentExample from './Component.example.mjs'; import Component from './Component.mjs'; -import ComponentWithProps from './ComponentWithProps.mjs'; -import InputWithProps from './InputWithProps.mjs'; -import InputWithPropsRaw from './InputWithProps.mjs?raw'; +import InputExample from './Input.example.mjs'; +import InputExampleRaw from './Input.example.mjs?raw'; export default { title: 'Components/PropsTable', @@ -36,7 +36,7 @@ export const Props = { }, }; export const AutomaticProps = { - render: InputWithProps, + render: InputExample, play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); const input = canvas.getByDisplayValue(''); @@ -54,7 +54,7 @@ export const AutomaticProps = { }, }; -const InputWithPropsRawWithoutProps = InputWithPropsRaw +const InputExampleRawWithoutProps = InputExampleRaw // Remove "props" from example component .replace(/\s?{?\.*?props}?/gm, ''); @@ -62,8 +62,8 @@ export const AutomaticPropsSource = { render: () => ( @@ -74,25 +74,27 @@ export const RawImport = { render: () => ( `, + ``, ].join('\n')} importPathReplacements={false} /> ), }; -const InputWithPropsRawWithoutPropsComments = - InputWithPropsRawWithoutProps.replace(/( ( `, - ...InputWithPropsRawWithoutPropsComments, + `// Source code displayed by `, + ...InputExampleRawWithoutPropsComments, ].join('\n')} /> ), @@ -114,7 +116,7 @@ export const ManualTypeWithRequired = { }, hideChildren: true, }, - render: InputWithProps, + render: InputExample, }; export const ManualTypeWithRequiredSource = { @@ -127,8 +129,8 @@ export const ManualTypeWithRequiredSource = { ', `` ), @@ -145,5 +147,5 @@ export const ManualTypeWithRequiredSource = { }; export const AllPropTypes = { - render: ComponentWithProps, + render: ComponentExample, }; diff --git a/stories/Source.mdx b/stories/Source.mdx index 445df32..a37c77b 100644 --- a/stories/Source.mdx +++ b/stories/Source.mdx @@ -1,4 +1,5 @@ import { Meta, Story } from '@storybook/addon-docs'; +import ImportPathReplacementsObject from './ImportPathReplacementsObject.mjs'; import * as SourceStories from './Source.stories.mjs'; @@ -9,8 +10,6 @@ Adds a block of source code with "copy" functionality to the page. Similar to [Storybook's Source block](https://storybook.js.org/docs/react/api/doc-block-source) but with code replacement functionality for production-ready source code and image snapshot testing compatibility. -Can be used within [stories](https://storybook.js.org/docs/react/writing-stories/introduction) or directly in [MDX pages](https://storybook.js.org/docs/react/writing-docs/mdx). - ### Implementation: @@ -34,41 +33,24 @@ The `Source` component can automatically display all [file import paths](https:/ Please see [Import Path Replacements](/docs/configuration-import-path-replacements--docs) for setting global (default) configuration of all instances of `Source`. -Alternatively, you can override the global configuration by supplying a stringified `{ key: value }` object for `importPathReplacements` directly: - - - - - - - - - - - - -
`key` - A string to match within an import path. Also accepts `^` to prepend - relative paths. -
`value`A string to replace the matched `key` string.
+Alternatively, you can override the global configuration by supplying a stringified `{ key: value }` object for `importPathReplacements` directly. -> #### Note: -> -> - Import path replacements are performed in the order specified. -> - Matches may occur more than once within an import path. + For further control, you can also use the inline comment `// preserve-path` to opt-out of the import path replacement: - + - + - + You can also disable import path replacements on each instance of `Source` by setting `importPathReplacements` to `false`. > #### Note: > +> - Import path replacements are performed in the order specified. +> - Matches may occur more than once within an import path. > - Any use of the `// preserve-path` will be removed from the displayed source code of each `Source` that uses import path replacements. > > #### See also: diff --git a/stories/Source.stories.mjs b/stories/Source.stories.mjs index 9c3a15b..6f2eb81 100644 --- a/stories/Source.stories.mjs +++ b/stories/Source.stories.mjs @@ -65,25 +65,25 @@ const componentWithProps = [ `const notAnImport = '../src/notAnImport.mjs';`, ]; -export const ComponentWithProps = { +export const ComponentExample = { args: { code: [ - `// ComponentWithProps.mjs (the "example component")`, + `// Component.example.mjs (the "example component")`, ...componentWithProps, ].join('\n'), importPathReplacements: false, }, }; -export const ComponentWithPropsRaw = { +export const ComponentExampleRaw = { args: { code: [ - `// Stories of Component.mjs`, - `import ComponentWithPropsRaw from './ComponentWithProps.mjs?raw';`, + `// Component.stories.mjs`, + `import ComponentExampleRaw from './Component.example.mjs?raw';`, `import packageJson from '../package.json';`, ``, `