Merge pull request #17515 from storybookjs/17514-mdx2-support

Addon-docs: MDX2 support
This commit is contained in:
Michael Shilman 2022-02-28 12:21:01 +08:00 committed by GitHub
commit f2858d3b4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1316 additions and 2806 deletions

View File

@ -1,6 +1,7 @@
<h1>Migration</h1>
- [From version 6.4.x to 6.5.0](#from-version-64x-to-650)
- [Opt-in MDX2 support](#opt-in-mdx2-support)
- [CSF3 auto-title redundant filename](#csf3-auto-title-redundant-filename)
- [From version 6.3.x to 6.4.0](#from-version-63x-to-640)
- [Automigrate](#automigrate)
@ -192,6 +193,24 @@
## From version 6.4.x to 6.5.0
### Opt-in MDX2 support
SB6.5 adds experimental opt-in support for MDXv2. To install:
```sh
yarn add @storybook/mdx2-csf -D
```
Then add the `previewMdx2` feature flag to your `.storybook/main.js` config:
```js
module.exports = {
features: {
previewMdx2: true,
},
};
```
### CSF3 auto-title redundant filename
SB 6.4 introduced experimental "auto-title", in which a story's location in the sidebar (aka `title`) can be automatically inferred from its location on disk. For example, the file `atoms/Button.stories.js` might result in the title `Atoms/Button`.

View File

@ -1,11 +1,8 @@
const path = require('path');
const mdx = require('@mdx-js/mdx');
const { ScriptTransformer } = require('@jest/transform');
const { dedent } = require('ts-dedent');
const { createCompiler } = require('@storybook/csf-tools/mdx');
const compilers = [createCompiler({})];
const { compileSync } = require('@storybook/mdx1-csf');
module.exports = {
process(src, filename, config, { instrument }) {
@ -13,7 +10,7 @@ module.exports = {
/* @jsx mdx */
import React from 'react'
import { mdx } from '@mdx-js/react'
${mdx.sync(src, { compilers, filepath: filename })}
${compileSync(src, { filepath: filename })}
`;
const extension = path.extname(filename);

View File

@ -1 +1 @@
module.exports = require('@storybook/csf-tools/mdx').createCompiler;
module.exports = require('@storybook/mdx1-csf').createCompiler;

View File

@ -61,8 +61,6 @@
"@babel/plugin-transform-react-jsx": "^7.12.12",
"@babel/preset-env": "^7.12.11",
"@jest/transform": "^26.6.2",
"@mdx-js/loader": "^1.6.22",
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@storybook/addons": "6.5.0-alpha.42",
"@storybook/api": "6.5.0-alpha.42",
@ -73,6 +71,7 @@
"@storybook/core-events": "6.5.0-alpha.42",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/csf-tools": "6.5.0-alpha.42",
"@storybook/mdx1-csf": "0.0.1-canary.1.0025c94.0",
"@storybook/node-logger": "6.5.0-alpha.42",
"@storybook/postinstall": "6.5.0-alpha.42",
"@storybook/preview-web": "6.5.0-alpha.42",
@ -88,7 +87,6 @@
"fast-deep-equal": "^3.1.3",
"global": "^4.4.0",
"html-tags": "^3.1.0",
"js-string-escape": "^1.0.1",
"loader-utils": "^2.0.0",
"lodash": "^4.17.21",
"nanoid": "^3.1.23",
@ -109,14 +107,13 @@
"@emotion/styled": "^10.0.27",
"@storybook/angular": "6.5.0-alpha.42",
"@storybook/html": "6.5.0-alpha.42",
"@storybook/mdx2-csf": "0.0.1-canary.1.357011b.0",
"@storybook/react": "6.5.0-alpha.42",
"@storybook/vue": "6.5.0-alpha.42",
"@storybook/web-components": "6.5.0-alpha.42",
"@types/cross-spawn": "^6.0.2",
"@types/doctrine": "^0.0.3",
"@types/enzyme": "^3.10.8",
"@types/estree": "^0.0.44",
"@types/jest": "^26.0.16",
"@types/loader-utils": "^2.0.0",
"@types/prop-types": "^15.7.3",
"@types/tmp": "^0.2.0",
@ -124,7 +121,6 @@
"babel-loader": "^8.0.0",
"babel-plugin-react-docgen": "^4.2.1",
"cross-spawn": "^7.0.3",
"fs-extra": "^9.0.1",
"jest": "^26.6.3",
"jest-specific-snapshot": "^4.0.0",
"lit-element": "^3.0.2",
@ -134,12 +130,27 @@
"styled-components": "^5.2.1",
"sveltedoc-parser": "4.1.0",
"tmp": "^0.2.1",
"tslib": "^2.1.0",
"vue": "^2.6.10",
"web-component-analyzer": "^1.1.6",
"webpack": "4",
"zone.js": "^0.11.3"
},
"peerDependencies": {
"@storybook/angular": "6.5.0-alpha.42",
"@storybook/html": "6.5.0-alpha.42",
"@storybook/mdx2-csf": "0.0.1-canary.1.357011b.0",
"@storybook/react": "6.5.0-alpha.42",
"@storybook/vue": "6.5.0-alpha.42",
"@storybook/vue3": "6.5.0-alpha.42",
"@storybook/web-components": "6.5.0-alpha.42",
"lit": "^2.0.0",
"lit-html": "^1.4.1 || ^2.0.0",
"react": "^16.8.0 || ^17.0.0",
"react-dom": "^16.8.0 || ^17.0.0",
"svelte": "^3.31.2",
"sveltedoc-parser": "^4.1.0",
"vue": "^2.6.10 || ^3.0.0",
"webpack": "*"
},
"peerDependenciesMeta": {
"@storybook/angular": {
"optional": true
@ -159,6 +170,9 @@
"@storybook/manager-webpack5": {
"optional": true
},
"@storybook/mdx2-csf": {
"optional": true
},
"@storybook/react": {
"optional": true
},

View File

@ -1,11 +1,12 @@
import path from 'path';
import remarkSlug from 'remark-slug';
import remarkExternalLinks from 'remark-external-links';
import global from 'global';
// @ts-ignore
import { createCompiler } from '@storybook/csf-tools/mdx';
import type { BuilderConfig, Options } from '@storybook/core-common';
const { log } = console;
// for frameworks that are not working with react, we need to configure
// the jsx to transpile mdx, for now there will be a flag for that
// for more complex solutions we can find alone that we need to add '@babel/plugin-transform-react-jsx'
@ -34,9 +35,9 @@ function createBabelOptions({ babelOptions, mdxBabelOptions, configureJSX }: Bab
export async function webpack(
webpackConfig: any = {},
options: Options &
BabelParams & { sourceLoaderOptions: any; transcludeMarkdown: boolean } & Parameters<
BabelParams & { sourceLoaderOptions: any; transcludeMarkdown: boolean } /* & Parameters<
typeof createCompiler
>[0]
>[0] */
) {
const { builder = 'webpack4' } = await options.presets.apply<{
builder: BuilderConfig;
@ -62,9 +63,17 @@ export async function webpack(
} = options;
const mdxLoaderOptions = {
skipCsf: true,
remarkPlugins: [remarkSlug, remarkExternalLinks],
};
const mdxVersion = global.FEATURES?.previewMdx2 ? 'MDX2' : 'MDX1';
log(`Addon-docs: using ${mdxVersion}`);
const mdxLoader = global.FEATURES?.previewMdx2
? require.resolve('@storybook/mdx2-csf/loader')
: require.resolve('@storybook/mdx1-csf/loader');
// set `sourceLoaderOptions` to `null` to disable for manual configuration
const sourceLoader = sourceLoaderOptions
? [
@ -89,7 +98,7 @@ export async function webpack(
options: createBabelOptions({ babelOptions, mdxBabelOptions, configureJSX }),
},
{
loader: require.resolve('@mdx-js/loader'),
loader: mdxLoader,
options: mdxLoaderOptions,
},
],
@ -123,11 +132,7 @@ export async function webpack(
options: createBabelOptions({ babelOptions, mdxBabelOptions, configureJSX }),
},
{
loader: require.resolve('@mdx-js/loader'),
options: {
compilers: [createCompiler(options)],
...mdxLoaderOptions,
},
loader: mdxLoader,
},
],
},
@ -140,7 +145,7 @@ export async function webpack(
options: createBabelOptions({ babelOptions, mdxBabelOptions, configureJSX }),
},
{
loader: require.resolve('@mdx-js/loader'),
loader: mdxLoader,
options: mdxLoaderOptions,
},
],

View File

@ -32,6 +32,7 @@ const config: StorybookConfig = {
buildStoriesJson: true,
babelModeV7: true,
warnOnLegacyHierarchySeparator: false,
previewMdx2: true,
},
framework: '@storybook/react',
};

View File

@ -3404,7 +3404,7 @@ exports[`Storyshots Demo/Account Form Verification Success 1`] = `
</section>
`;
exports[`Storyshots Docs/Button Basic 1`] = `
exports[`Storyshots Docs/ButtonMdx Basic 1`] = `
<button
type="button"
>
@ -3412,7 +3412,7 @@ exports[`Storyshots Docs/Button Basic 1`] = `
</button>
`;
exports[`Storyshots Docs/Button Controls 1`] = `
exports[`Storyshots Docs/ButtonMdx Controls 1`] = `
<button
type="button"
>

View File

@ -6,4 +6,4 @@ import { Meta, Canvas } from '@storybook/addon-docs';
## [Link](http://https://storybook.js.org/) in heading
This file is a documentation-only MDX file, i.e. it doesn't contain any `<Story>` definitions.
This file is a documentation-only MDX {1+1} file, i.e. it doesn't contain any `<Story>` definitions.

View File

@ -1,9 +1,9 @@
import { Meta, Story } from '@storybook/addon-docs';
import { Button } from '../button';
<Meta title="Docs/Button" component={Button} />
<Meta title="Docs/ButtonMdx" component={Button} />
# Button
# Button MDX
<Story name="Basic">
<Button label="Click me" />

View File

@ -1,58 +1,58 @@
// auto generated file, do not edit
export default {
"@storybook/addon-a11y": "6.5.0-alpha.42",
"@storybook/addon-actions": "6.5.0-alpha.42",
"@storybook/addon-backgrounds": "6.5.0-alpha.42",
"@storybook/addon-controls": "6.5.0-alpha.42",
"@storybook/addon-docs": "6.5.0-alpha.42",
"@storybook/addon-essentials": "6.5.0-alpha.42",
"@storybook/addon-interactions": "6.5.0-alpha.42",
"@storybook/addon-jest": "6.5.0-alpha.42",
"@storybook/addon-links": "6.5.0-alpha.42",
"@storybook/addon-measure": "6.5.0-alpha.42",
"@storybook/addon-outline": "6.5.0-alpha.42",
"@storybook/addon-storyshots": "6.5.0-alpha.42",
"@storybook/addon-storyshots-puppeteer": "6.5.0-alpha.42",
"@storybook/addon-storysource": "6.5.0-alpha.42",
"@storybook/addon-toolbars": "6.5.0-alpha.42",
"@storybook/addon-viewport": "6.5.0-alpha.42",
"@storybook/addons": "6.5.0-alpha.42",
"@storybook/angular": "6.5.0-alpha.42",
"@storybook/api": "6.5.0-alpha.42",
"@storybook/builder-webpack4": "6.5.0-alpha.42",
"@storybook/builder-webpack5": "6.5.0-alpha.42",
"@storybook/channel-postmessage": "6.5.0-alpha.42",
"@storybook/channel-websocket": "6.5.0-alpha.42",
"@storybook/channels": "6.5.0-alpha.42",
"@storybook/cli": "6.5.0-alpha.42",
"@storybook/client-api": "6.5.0-alpha.42",
"@storybook/client-logger": "6.5.0-alpha.42",
"@storybook/codemod": "6.5.0-alpha.42",
"@storybook/components": "6.5.0-alpha.42",
"@storybook/core": "6.5.0-alpha.42",
"@storybook/core-client": "6.5.0-alpha.42",
"@storybook/core-common": "6.5.0-alpha.42",
"@storybook/core-events": "6.5.0-alpha.42",
"@storybook/core-server": "6.5.0-alpha.42",
"@storybook/csf-tools": "6.5.0-alpha.42",
"@storybook/ember": "6.5.0-alpha.42",
"@storybook/html": "6.5.0-alpha.42",
"@storybook/instrumenter": "6.5.0-alpha.42",
"@storybook/manager-webpack4": "6.5.0-alpha.42",
"@storybook/manager-webpack5": "6.5.0-alpha.42",
"@storybook/node-logger": "6.5.0-alpha.42",
"@storybook/postinstall": "6.5.0-alpha.42",
"@storybook/preact": "6.5.0-alpha.42",
"@storybook/preview-web": "6.5.0-alpha.42",
"@storybook/react": "6.5.0-alpha.42",
"@storybook/router": "6.5.0-alpha.42",
"@storybook/server": "6.5.0-alpha.42",
"@storybook/source-loader": "6.5.0-alpha.42",
"@storybook/store": "6.5.0-alpha.42",
"@storybook/svelte": "6.5.0-alpha.42",
"@storybook/theming": "6.5.0-alpha.42",
"@storybook/ui": "6.5.0-alpha.42",
"@storybook/vue": "6.5.0-alpha.42",
"@storybook/vue3": "6.5.0-alpha.42",
"@storybook/web-components": "6.5.0-alpha.42"
}
'@storybook/addon-a11y': '6.5.0-alpha.42',
'@storybook/addon-actions': '6.5.0-alpha.42',
'@storybook/addon-backgrounds': '6.5.0-alpha.42',
'@storybook/addon-controls': '6.5.0-alpha.42',
'@storybook/addon-docs': '6.5.0-alpha.42',
'@storybook/addon-essentials': '6.5.0-alpha.42',
'@storybook/addon-interactions': '6.5.0-alpha.42',
'@storybook/addon-jest': '6.5.0-alpha.42',
'@storybook/addon-links': '6.5.0-alpha.42',
'@storybook/addon-measure': '6.5.0-alpha.42',
'@storybook/addon-outline': '6.5.0-alpha.42',
'@storybook/addon-storyshots': '6.5.0-alpha.42',
'@storybook/addon-storyshots-puppeteer': '6.5.0-alpha.42',
'@storybook/addon-storysource': '6.5.0-alpha.42',
'@storybook/addon-toolbars': '6.5.0-alpha.42',
'@storybook/addon-viewport': '6.5.0-alpha.42',
'@storybook/addons': '6.5.0-alpha.42',
'@storybook/angular': '6.5.0-alpha.42',
'@storybook/api': '6.5.0-alpha.42',
'@storybook/builder-webpack4': '6.5.0-alpha.42',
'@storybook/builder-webpack5': '6.5.0-alpha.42',
'@storybook/channel-postmessage': '6.5.0-alpha.42',
'@storybook/channel-websocket': '6.5.0-alpha.42',
'@storybook/channels': '6.5.0-alpha.42',
'@storybook/cli': '6.5.0-alpha.42',
'@storybook/client-api': '6.5.0-alpha.42',
'@storybook/client-logger': '6.5.0-alpha.42',
'@storybook/codemod': '6.5.0-alpha.42',
'@storybook/components': '6.5.0-alpha.42',
'@storybook/core': '6.5.0-alpha.42',
'@storybook/core-client': '6.5.0-alpha.42',
'@storybook/core-common': '6.5.0-alpha.42',
'@storybook/core-events': '6.5.0-alpha.42',
'@storybook/core-server': '6.5.0-alpha.42',
'@storybook/csf-tools': '6.5.0-alpha.42',
'@storybook/ember': '6.5.0-alpha.42',
'@storybook/html': '6.5.0-alpha.42',
'@storybook/instrumenter': '6.5.0-alpha.42',
'@storybook/manager-webpack4': '6.5.0-alpha.42',
'@storybook/manager-webpack5': '6.5.0-alpha.42',
'@storybook/node-logger': '6.5.0-alpha.42',
'@storybook/postinstall': '6.5.0-alpha.42',
'@storybook/preact': '6.5.0-alpha.42',
'@storybook/preview-web': '6.5.0-alpha.42',
'@storybook/react': '6.5.0-alpha.42',
'@storybook/router': '6.5.0-alpha.42',
'@storybook/server': '6.5.0-alpha.42',
'@storybook/source-loader': '6.5.0-alpha.42',
'@storybook/store': '6.5.0-alpha.42',
'@storybook/svelte': '6.5.0-alpha.42',
'@storybook/theming': '6.5.0-alpha.42',
'@storybook/ui': '6.5.0-alpha.42',
'@storybook/vue': '6.5.0-alpha.42',
'@storybook/vue3': '6.5.0-alpha.42',
'@storybook/web-components': '6.5.0-alpha.42',
};

View File

@ -373,6 +373,11 @@ export interface StorybookConfig {
* Will be removed in 7.0.
*/
warnOnLegacyHierarchySeparator?: boolean;
/**
* Preview MDX2 support, will become default in 7.0
*/
previewMdx2?: boolean;
};
/**

View File

@ -65,6 +65,7 @@
"detect-port": "^1.3.0",
"express": "^4.17.1",
"fs-extra": "^9.0.1",
"global": "^4.4.0",
"globby": "^11.0.2",
"ip": "^1.1.5",
"lodash": "^4.17.21",

View File

@ -388,16 +388,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -447,12 +438,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -406,16 +406,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -465,12 +456,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -310,16 +310,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -408,12 +399,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -309,16 +309,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -407,12 +398,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -326,16 +326,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -424,12 +415,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -325,16 +325,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -423,12 +414,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -343,16 +343,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -441,12 +432,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -342,16 +342,7 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"options": Object {
"compilers": Array [
[Function],
],
"remarkPlugins": Array [
[Function],
[Function],
],
},
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
},
],
},
@ -440,12 +431,13 @@ Object {
},
},
Object {
"loader": "NODE_MODULES/@mdx-js/loader/index.js",
"loader": "NODE_MODULES/@storybook/mdx1-csf/loader.js",
"options": Object {
"remarkPlugins": Array [
[Function],
[Function],
],
"skipCsf": true,
},
},
],

View File

@ -11,6 +11,7 @@ import {
} from '@storybook/core-common';
import dedent from 'ts-dedent';
import prompts from 'prompts';
import global from 'global';
import path from 'path';
import { storybookDevServer } from './dev-server';
@ -75,6 +76,7 @@ export async function buildDevStandalone(options: CLIOptions & LoadOptions & Bui
});
const features = await presets.apply<StorybookConfig['features']>('features');
global.FEATURES = features;
const fullOptions: Options = {
...options,

View File

@ -3,6 +3,7 @@ import cpy from 'cpy';
import fs from 'fs-extra';
import path from 'path';
import dedent from 'ts-dedent';
import global from 'global';
import { logger } from '@storybook/node-logger';
@ -92,6 +93,8 @@ export async function buildStaticStandalone(options: CLIOptions & LoadOptions &
}
const features = await presets.apply<StorybookConfig['features']>('features');
global.FEATURES = features;
if (features?.buildStoriesJson || features?.storyStoreV7) {
const directories = {
configDir: options.configDir,

View File

@ -90,7 +90,7 @@ const baseOptions = {
managerOnly, // production
docsMode: false,
cache,
configDir: path.resolve(`${__dirname}/../../../examples/react-ts/.storybook`),
configDir: path.resolve(`${__dirname}/../../../examples/cra-ts-essentials/.storybook`),
ci: true,
managerCache: false,
};
@ -254,10 +254,13 @@ describe('build cli flags', () => {
outputDir: `${__dirname}/storybook-static`,
};
it('--webpack-stats-json calls output-stats', async () => {
// eslint-disable-next-line jest/no-disabled-tests
it.skip('does not call output-stats', async () => {
await buildStaticStandalone(cliOptions);
expect(outputStats).not.toHaveBeenCalled();
});
it('--webpack-stats-json calls output-stats', async () => {
await buildStaticStandalone({ ...cliOptions, webpackStatsJson: '/tmp/dir' });
expect(outputStats).toHaveBeenCalledWith(
'/tmp/dir',

View File

@ -1,45 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf3 auto-title-docs-only.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<pre>
<code parentName=\\"pre\\" {...{}}>{\` import { Meta } from '@storybook/addon-docs';
<Meta />
# Auto-title Docs Only
Spme **markdown** here!
\`}</code>
</pre>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,46 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf3 auto-title.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta component={Button} mdxType=\\"Meta\\" />
<Story name=\\"Basic\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Basic</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const basic = () => <Button>Basic</Button>;
basic.storyName = 'Basic';
basic.parameters = { storySource: { source: '<Button>Basic</Button>' } };
const componentMeta = { component: Button, includeStories: ['basic'] };
const mdxStoryNameToKey = { Basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,77 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin component-args.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
args={{
a: 1,
b: 2,
}}
argTypes={{
a: {
name: 'A',
},
b: {
name: 'B',
},
}}
mdxType=\\"Meta\\"
/>
<h1>{\`Args\`}</h1>
<Story name=\\"component notes\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Component notes</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const componentNotes = () => <Button>Component notes</Button>;
componentNotes.storyName = 'component notes';
componentNotes.parameters = { storySource: { source: '<Button>Component notes</Button>' } };
const componentMeta = {
title: 'Button',
args: {
a: 1,
b: 2,
},
argTypes: {
a: {
name: 'A',
},
b: {
name: 'B',
},
},
includeStories: ['componentNotes'],
};
const mdxStoryNameToKey = { 'component notes': 'componentNotes' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,51 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin component-id.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" component={Button} id=\\"button-id\\" mdxType=\\"Meta\\" />
<Story name=\\"component notes\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Component notes</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const componentNotes = () => <Button>Component notes</Button>;
componentNotes.storyName = 'component notes';
componentNotes.parameters = { storySource: { source: '<Button>Component notes</Button>' } };
const componentMeta = {
title: 'Button',
id: 'button-id',
component: Button,
includeStories: ['componentNotes'],
};
const mdxStoryNameToKey = { 'component notes': 'componentNotes' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,54 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf3 component-render.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
component={Button}
render={(args) => <Button {...args} mdxType=\\"Button\\" />}
mdxType=\\"Meta\\"
/>
<Story name=\\"Basic\\" mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const basic = {};
basic.storyName = 'Basic';
basic.parameters = { storySource: { source: '{}' } };
const componentMeta = {
title: 'Button',
component: Button,
render: (args) => <Button {...args} />,
includeStories: ['basic'],
};
const mdxStoryNameToKey = { Basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,54 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf-imports.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Story, Meta, Canvas } from '@storybook/addon-docs';
import { Welcome, Button } from '@storybook/angular/demo';
import * as MyStories from './My.stories';
import { Other } from './Other.stories';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"MDX/CSF imports\\" mdxType=\\"Meta\\" />
<h1>{\`Stories from CSF imports\`}</h1>
<Story story={MyStories.Basic} name=\\"_Basic_\\" mdxType=\\"Story\\" />
<Canvas mdxType=\\"Canvas\\">
<Story story={Other} name=\\"_Other_\\" mdxType=\\"Story\\" />
</Canvas>
<Story name=\\"renamed\\" story={MyStories.Foo} mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const _Basic_ = MyStories.Basic;
export const _Other_ = Other;
export const _Foo_ = MyStories.Foo;
_Foo_.storyName = 'renamed';
const componentMeta = { title: 'MDX/CSF imports', includeStories: ['_Basic_', '_Other_', '_Foo_'] };
const mdxStoryNameToKey = { _Basic_: '_Basic_', _Other_: '_Other_', renamed: '_Foo_' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,80 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin decorators.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
decorators={[
(storyFn) => (
<div
style={{
backgroundColor: 'yellow',
}}
>
{storyFn()}
</div>
),
]}
mdxType=\\"Meta\\"
/>
<h1>{\`Decorated story\`}</h1>
<Story
name=\\"one\\"
decorators={[(storyFn) => <div className=\\"local\\">{storyFn()}</div>]}
mdxType=\\"Story\\"
>
<Button mdxType=\\"Button\\">One</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.storyName = 'one';
one.parameters = { storySource: { source: '<Button>One</Button>' } };
one.decorators = [(storyFn) => <div className=\\"local\\">{storyFn()}</div>];
const componentMeta = {
title: 'Button',
decorators: [
(storyFn) => (
<div
style={{
backgroundColor: 'yellow',
}}
>
{storyFn()}
</div>
),
],
includeStories: ['one'],
};
const mdxStoryNameToKey = { one: 'one' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,44 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf3 default-render.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" component={Button} mdxType=\\"Meta\\" />
<Story name=\\"Basic\\" mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const basic = {};
basic.storyName = 'Basic';
basic.parameters = { storySource: { source: '{}' } };
const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] };
const mdxStoryNameToKey = { Basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,46 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin docs-only.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"docs-only\\" mdxType=\\"Meta\\" />
<h1>{\`Documentation only\`}</h1>
<p>{\`This is a documentation-only MDX file which generates a dummy 'docsOnly: true' story.\`}</p>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const __page = () => {
throw new Error('Docs-only story');
};
__page.parameters = { docsOnly: true };
const componentMeta = { title: 'docs-only', includeStories: ['__page'] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,76 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin loaders.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
loaders={[
async () => ({
foo: 1,
}),
]}
mdxType=\\"Meta\\"
/>
<h1>{\`Story with loader\`}</h1>
<Story
name=\\"one\\"
loaders={[
async () => ({
bar: 2,
}),
]}
mdxType=\\"Story\\"
>
<Button mdxType=\\"Button\\">One</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.storyName = 'one';
one.parameters = { storySource: { source: '<Button>One</Button>' } };
one.loaders = [
async () => ({
bar: 2,
}),
];
const componentMeta = {
title: 'Button',
loaders: [
async () => ({
foo: 1,
}),
],
includeStories: ['one'],
};
const mdxStoryNameToKey = { one: 'one' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,44 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin meta-quotes-in-title.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Addons/Docs/what's in a title?\\" mdxType=\\"Meta\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const __page = () => {
throw new Error('Docs-only story');
};
__page.parameters = { docsOnly: true };
const componentMeta = { title: \\"Addons/Docs/what's in a title?\\", includeStories: ['__page'] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,58 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin non-story-exports.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
export const two = 2;
const layoutProps = {
two,
};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" mdxType=\\"Meta\\" />
<h1>{\`Story definition\`}</h1>
<Story name=\\"one\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">One</Button>
</Story>
<Story name=\\"hello story\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Hello button</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.storyName = 'one';
one.parameters = { storySource: { source: '<Button>One</Button>' } };
export const helloStory = () => <Button>Hello button</Button>;
helloStory.storyName = 'hello story';
helloStory.parameters = { storySource: { source: '<Button>Hello button</Button>' } };
const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] };
const mdxStoryNameToKey = { one: 'one', 'hello story': 'helloStory' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,78 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin parameters.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
component={Button}
parameters={{
notes: 'component notes',
}}
mdxType=\\"Meta\\"
/>
<Story name=\\"component notes\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Component notes</Button>
</Story>
<Story
name=\\"story notes\\"
parameters={{
notes: 'story notes',
}}
mdxType=\\"Story\\"
>
<Button mdxType=\\"Button\\">Story notes</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const componentNotes = () => <Button>Component notes</Button>;
componentNotes.storyName = 'component notes';
componentNotes.parameters = { storySource: { source: '<Button>Component notes</Button>' } };
export const storyNotes = () => <Button>Story notes</Button>;
storyNotes.storyName = 'story notes';
storyNotes.parameters = {
storySource: { source: '<Button>Story notes</Button>' },
...{
notes: 'story notes',
},
};
const componentMeta = {
title: 'Button',
parameters: {
notes: 'component notes',
},
component: Button,
includeStories: ['componentNotes', 'storyNotes'],
};
const mdxStoryNameToKey = { 'component notes': 'componentNotes', 'story notes': 'storyNotes' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,77 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin previews.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Canvas, Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta
title=\\"Button\\"
component={Button}
parameters={{
notes: 'component notes',
}}
mdxType=\\"Meta\\"
/>
<h1>{\`Canvas\`}</h1>
<p>{\`Canvases can contain normal components, stories, and story references\`}</p>
<Canvas mdxType=\\"Canvas\\">
<Button mdxType=\\"Button\\">Just a button</Button>
<Story name=\\"hello button\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Hello button</Button>
</Story>
<Story name=\\"two\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Two</Button>
</Story>
<Story id=\\"welcome--welcome\\" mdxType=\\"Story\\" />
</Canvas>
<p>{\`Canvas without a story\`}</p>
<Canvas mdxSource=\\"%0A%3CButton%3EJust%20a%20button%3C/Button%3E%0A\\" mdxType=\\"Canvas\\">
<Button mdxType=\\"Button\\">Just a button</Button>
</Canvas>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const helloButton = () => <Button>Hello button</Button>;
helloButton.storyName = 'hello button';
helloButton.parameters = { storySource: { source: '<Button>Hello button</Button>' } };
export const two = () => <Button>Two</Button>;
two.storyName = 'two';
two.parameters = { storySource: { source: '<Button>Two</Button>' } };
const componentMeta = {
title: 'Button',
parameters: {
notes: 'component notes',
},
component: Button,
includeStories: ['helloButton', 'two'],
};
const mdxStoryNameToKey = { 'hello button': 'helloButton', two: 'two' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,78 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-args.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
export const Template = (args) => <Button mdxType=\\"Button\\">Component notes</Button>;
const layoutProps = {
Template,
};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" mdxType=\\"Meta\\" />
<h1>{\`Args\`}</h1>
<Story
name=\\"component notes\\"
args={{
a: 1,
b: 2,
}}
argTypes={{
a: {
name: 'A',
},
b: {
name: 'B',
},
}}
mdxType=\\"Story\\"
>
{Template.bind({})}
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const componentNotes = Template.bind({});
componentNotes.storyName = 'component notes';
componentNotes.argTypes = {
a: {
name: 'A',
},
b: {
name: 'B',
},
};
componentNotes.args = {
a: 1,
b: 2,
};
componentNotes.parameters = { storySource: { source: 'args => <Button>Component notes</Button>' } };
const componentMeta = { title: 'Button', includeStories: ['componentNotes'] };
const mdxStoryNameToKey = { 'component notes': 'componentNotes' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,39 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-current.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Story } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<h1>{\`Current story\`}</h1>
<Story id=\\".\\" mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,46 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-def-text-only.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Text\\" mdxType=\\"Meta\\" />
<h1>{\`Story definition\`}</h1>
<Story name=\\"text\\" mdxType=\\"Story\\">
Plain text
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const text = () => 'Plain text';
text.storyName = 'text';
text.parameters = { storySource: { source: \\"'Plain text'\\" } };
const componentMeta = { title: 'Text', includeStories: ['text'] };
const mdxStoryNameToKey = { text: 'text' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,76 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-definitions.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" mdxType=\\"Meta\\" />
<h1>{\`Story definition\`}</h1>
<Story name=\\"one\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">One</Button>
</Story>
<Story name=\\"hello story\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">Hello button</Button>
</Story>
<Story name=\\"w/punctuation\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">with punctuation</Button>
</Story>
<Story name=\\"1 fine day\\" mdxType=\\"Story\\">
<Button mdxType=\\"Button\\">starts with number</Button>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const one = () => <Button>One</Button>;
one.storyName = 'one';
one.parameters = { storySource: { source: '<Button>One</Button>' } };
export const helloStory = () => <Button>Hello button</Button>;
helloStory.storyName = 'hello story';
helloStory.parameters = { storySource: { source: '<Button>Hello button</Button>' } };
export const wPunctuation = () => <Button>with punctuation</Button>;
wPunctuation.storyName = 'w/punctuation';
wPunctuation.parameters = { storySource: { source: '<Button>with punctuation</Button>' } };
export const _1FineDay = () => <Button>starts with number</Button>;
_1FineDay.storyName = '1 fine day';
_1FineDay.parameters = { storySource: { source: '<Button>starts with number</Button>' } };
const componentMeta = {
title: 'Button',
includeStories: ['one', 'helloStory', 'wPunctuation', '_1FineDay'],
};
const mdxStoryNameToKey = {
one: 'one',
'hello story': 'helloStory',
'w/punctuation': 'wPunctuation',
'1 fine day': '_1FineDay',
};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,60 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-function-var.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Meta, Story } from '@storybook/addon-docs';
export const basicFn = () => <Button mdxType=\\"Button\\" />;
const makeShortcode = (name) =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const Button = makeShortcode('Button');
const layoutProps = {
basicFn,
};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"story-function-var\\" mdxType=\\"Meta\\" />
<h1>{\`Button\`}</h1>
<p>{\`I can define a story with the function defined in CSF:\`}</p>
<Story name=\\"basic\\" mdxType=\\"Story\\">
{basicFn}
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const basic = assertIsFn(basicFn);
basic.storyName = 'basic';
basic.parameters = { storySource: { source: 'basicFn' } };
const componentMeta = { title: 'story-function-var', includeStories: ['basic'] };
const mdxStoryNameToKey = { basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,67 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-function.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
const makeShortcode = (name) =>
function MDXDefaultShortcode(props) {
console.warn(
'Component ' +
name +
' was not imported, exported, or provided by MDXProvider as global scope'
);
return <div {...props} />;
};
const Story = makeShortcode('Story');
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Story name=\\"function\\" height=\\"100px\\" mdxType=\\"Story\\">
{() => {
const btn = document.createElement('button');
btn.innerHTML = 'Hello Button';
btn.addEventListener('click', action('Click'));
return btn;
}}
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const functionStory = () => {
const btn = document.createElement('button');
btn.innerHTML = 'Hello Button';
btn.addEventListener('click', action('Click'));
return btn;
};
functionStory.storyName = 'function';
functionStory.parameters = {
storySource: {
source:
\\"() => {\\\\n const btn = document.createElement('button');\\\\n btn.innerHTML = 'Hello Button';\\\\n btn.addEventListener('click', action('Click'));\\\\n return btn;\\\\n}\\",
},
};
const componentMeta = { includeStories: ['functionStory'] };
const mdxStoryNameToKey = { function: 'functionStory' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,54 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-multiple-children.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Multiple\\" mdxType=\\"Meta\\" />
<h1>{\`Multiple children\`}</h1>
<Story name=\\"multiple children\\" mdxType=\\"Story\\">
<p>Hello Child #1</p>
<p>Hello Child #2</p>
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const multipleChildren = () => (
<>
<p>Hello Child #1</p>
<p>Hello Child #2</p>
</>
);
multipleChildren.storyName = 'multiple children';
multipleChildren.parameters = {
storySource: { source: '<p>Hello Child #1</p>\\\\n<p>Hello Child #2</p>' },
};
const componentMeta = { title: 'Multiple', includeStories: ['multipleChildren'] };
const mdxStoryNameToKey = { 'multiple children': 'multipleChildren' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,70 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-object.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Story, Meta } from '@storybook/addon-docs';
import { Welcome, Button } from '@storybook/angular/demo';
import { linkTo } from '@storybook/addon-links';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"MDX|Welcome\\" mdxType=\\"Meta\\" />
<h1>{\`Story object\`}</h1>
<Story name=\\"to storybook\\" height=\\"300px\\" mdxType=\\"Story\\">
{{
template:
'<storybook-welcome-component (showApp)=\\"showApp()\\"></storybook-welcome-component>',
props: {
showApp: linkTo('Button'),
},
moduleMetadata: {
declarations: [Welcome],
},
}}
</Story>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const toStorybook = () => ({
template: '<storybook-welcome-component (showApp)=\\"showApp()\\"></storybook-welcome-component>',
props: {
showApp: linkTo('Button'),
},
moduleMetadata: {
declarations: [Welcome],
},
});
toStorybook.storyName = 'to storybook';
toStorybook.parameters = {
storySource: {
source:
\\"{\\\\n template: '<storybook-welcome-component (showApp)=\\\\\\"showApp()\\\\\\"></storybook-welcome-component>',\\\\n props: {\\\\n showApp: linkTo('Button')\\\\n },\\\\n moduleMetadata: {\\\\n declarations: [Welcome]\\\\n }\\\\n}\\",
},
};
const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] };
const mdxStoryNameToKey = { 'to storybook': 'toStorybook' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,45 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf3 story-play.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" component={Button} mdxType=\\"Meta\\" />
<Story name=\\"Basic\\" play={() => console.log('play')} mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const basic = {};
basic.storyName = 'Basic';
basic.parameters = { storySource: { source: '{}' } };
basic.play = () => console.log('play');
const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] };
const mdxStoryNameToKey = { Basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,39 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin story-references.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Story } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<h1>{\`Story reference\`}</h1>
<Story id=\\"welcome--welcome\\" mdxType=\\"Story\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,49 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin csf3 story-render.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title=\\"Button\\" component={Button} mdxType=\\"Meta\\" />
<Story
name=\\"Basic\\"
render={(args) => <Button {...args} mdxType=\\"Button\\" />}
mdxType=\\"Story\\"
/>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const basic = {};
basic.storyName = 'Basic';
basic.parameters = { storySource: { source: '{}' } };
basic.render = (args) => <Button {...args} />;
const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] };
const mdxStoryNameToKey = { Basic: 'basic' };
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,45 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin title-template-string.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Meta, Story } from '@storybook/addon-docs';
import { titleFunction } from '../title-generators';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<Meta title={\`\${titleFunction('template')}\`} mdxType=\\"Meta\\" />
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
export const __page = () => {
throw new Error('Docs-only story');
};
__page.parameters = { docsOnly: true };
const componentMeta = { title: \`\${titleFunction('template')}\`, includeStories: ['__page'] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

View File

@ -1,40 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`docs-mdx-compiler-plugin vanilla.mdx 1`] = `
"/* @jsxRuntime classic */
/* @jsx mdx */
import { assertIsFn, AddContext } from '@storybook/addon-docs';
import { Button } from '@storybook/react/demo';
const layoutProps = {};
const MDXLayout = 'wrapper';
function MDXContent({ components, ...props }) {
return (
<MDXLayout {...layoutProps} {...props} components={components} mdxType=\\"MDXLayout\\">
<h1>{\`Hello MDX\`}</h1>
<p>{\`This is some random content.\`}</p>
<Button mdxType=\\"Button\\">Hello button</Button>
</MDXLayout>
);
}
MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
const mdxStoryNameToKey = {};
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => (
<AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}>
<MDXContent />
</AddContext>
),
};
export default componentMeta;
"
`;

21
lib/csf-tools/index.cjs Normal file
View File

@ -0,0 +1,21 @@
const { FEATURES } = require('global');
const fs = require('fs-extra');
const lib = require('./dist/cjs/index');
const readCsfOrMdx = async (fileName, options) => {
let code = (await fs.readFile(fileName, 'utf-8')).toString();
if (fileName.endsWith('.mdx')) {
const { compile } =
FEATURES && FEATURES.previewMdx2
? await import('@storybook/mdx2-csf')
: await import('@storybook/mdx1-csf');
code = await compile(code);
}
return lib.loadCsf(code, { ...options, fileName });
};
module.exports = {
readCsfOrMdx,
...lib,
};

4
lib/csf-tools/index.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
import { CsfFile, CsfOptions } from './dist/ts3.9/index.d';
export declare const readCsfOrMdx: (fileName: string, options: CsfOptions) => Promise<CsfFile>;
export * from './dist/ts3.9/index.d';

17
lib/csf-tools/index.mjs Normal file
View File

@ -0,0 +1,17 @@
import global from 'global';
import fs from 'fs-extra';
import { loadCsf } from './dist/esm/index';
export const readCsfOrMdx = async (fileName, options) => {
let code = (await fs.readFile(fileName, 'utf-8')).toString();
if (fileName.endsWith('.mdx')) {
const { compile } = global.FEATURES?.previewMdx2
? await import('@storybook/mdx2-csf')
: await import('@storybook/mdx1-csf');
code = await compile(code);
}
return loadCsf(code, { ...options, fileName });
};
export * from './dist/esm/index';

View File

@ -1 +1,2 @@
export * from './dist/ts3.9/mdx/index.d';
declare module '@mdx-js/loader';
export * from '@storybook/mdx1-csf';

View File

@ -1 +1 @@
module.exports = require('./dist/cjs/mdx');
module.exports = require('@storybook/mdx1-csf');

View File

@ -20,9 +20,9 @@
},
"license": "MIT",
"sideEffects": false,
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/ts3.9/index.d.ts",
"main": "index.cjs",
"module": "index.mjs",
"types": "index.d.ts",
"typesVersions": {
"<3.8": {
"dist/ts3.9/*": [
@ -47,21 +47,27 @@
"@babel/preset-env": "^7.12.11",
"@babel/traverse": "^7.12.11",
"@babel/types": "^7.12.11",
"@mdx-js/mdx": "^1.6.22",
"@storybook/csf": "0.0.2--canary.87bc651.0",
"@storybook/mdx1-csf": "0.0.1-canary.1.0025c94.0",
"core-js": "^3.8.2",
"fs-extra": "^9.0.1",
"global": "^4.4.0",
"js-string-escape": "^1.0.1",
"lodash": "^4.17.21",
"prettier": ">=2.2.1 <=2.3.0",
"regenerator-runtime": "^0.13.7",
"ts-dedent": "^2.0.0"
},
"devDependencies": {
"@storybook/mdx2-csf": "0.0.1-canary.1.357011b.0",
"@types/fs-extra": "^9.0.6",
"js-yaml": "^3.14.1"
},
"peerDependencies": {
"@storybook/mdx2-csf": "0.0.1-canary.1.357011b.0"
},
"peerDependenciesMeta": {
"@storybook/mdx2-csf": {
"optional": true
}
},
"publishConfig": {
"access": "public"
},

View File

@ -1,17 +1,3 @@
import fs from 'fs-extra';
import mdx from '@mdx-js/mdx';
import { loadCsf, CsfOptions } from './CsfFile';
import { createCompiler } from './mdx';
export const readCsfOrMdx = async (fileName: string, options: CsfOptions) => {
let code = (await fs.readFile(fileName, 'utf-8')).toString();
if (fileName.endsWith('.mdx')) {
code = await mdx(code, { compilers: [createCompiler({})] });
}
return loadCsf(code, { ...options, fileName });
};
export * from './CsfFile';
export * from './ConfigFile';
export * from './getStorySortParameter';

View File

@ -1 +0,0 @@
export * from './sb-mdx-plugin';

View File

@ -1,512 +0,0 @@
import 'jest-specific-snapshot';
import dedent from 'ts-dedent';
import path from 'path';
import mdx from '@mdx-js/mdx';
import prettier from 'prettier';
import { createCompiler } from './sb-mdx-plugin';
function generate(content) {
const code = mdx.sync(content, {
// filepath: filePath,
compilers: [createCompiler({})],
});
return prettier.format(code, {
parser: 'babel',
printWidth: 100,
tabWidth: 2,
bracketSpacing: true,
trailingComma: 'es5',
singleQuote: true,
});
}
const fixturesDir = path.join(__dirname, '..', '..', '__testfixtures__', 'mdx');
const snap = (prefix) => path.join(fixturesDir, `${prefix}.output.snapshot`);
describe('docs-mdx-compiler-plugin', () => {
it('component-args.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" args={{ a: 1, b: 2 }} argTypes={{ a: { name: 'A' }, b: { name: 'B' } }} />
# Args
<Story name="component notes">
<Button>Component notes</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('component-args'));
});
it('component-id.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} id="button-id" />
<Story name="component notes">
<Button>Component notes</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('component-id'));
});
it('csf-imports.mdx', () => {
expect(
generate(dedent`
import { Story, Meta, Canvas } from '@storybook/addon-docs';
import { Welcome, Button } from '@storybook/angular/demo';
import * as MyStories from './My.stories';
import { Other } from './Other.stories';
<Meta title="MDX/CSF imports" />
# Stories from CSF imports
<Story story={MyStories.Basic} />
<Canvas>
<Story story={Other} />
</Canvas>
<Story name="renamed" story={MyStories.Foo} />
`)
).toMatchSpecificSnapshot(snap('csf-imports'));
});
it('decorators.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta
title="Button"
decorators={[(storyFn) => <div style={{ backgroundColor: 'yellow' }}>{storyFn()}</div>]}
/>
# Decorated story
<Story name="one" decorators={[(storyFn) => <div className="local">{storyFn()}</div>]}>
<Button>One</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('decorators'));
});
it('docs-only.mdx', () => {
expect(
generate(dedent`
import { Meta } from '@storybook/addon-docs';
<Meta title="docs-only" />
# Documentation only
This is a documentation-only MDX file which generates a dummy 'docsOnly: true' story.
`)
).toMatchSpecificSnapshot(snap('docs-only'));
});
it('loaders.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" loaders={[async () => ({ foo: 1 })]} />
# Story with loader
<Story name="one" loaders={[async () => ({ bar: 2 })]}>
<Button>One</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('loaders'));
});
it('meta-quotes-in-title.mdx', () => {
expect(
generate(dedent`
import { Meta } from '@storybook/addon-docs';
<Meta title="Addons/Docs/what's in a title?" />
`)
).toMatchSpecificSnapshot(snap('meta-quotes-in-title'));
});
it('non-story-exports.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" />
# Story definition
<Story name="one">
<Button>One</Button>
</Story>
export const two = 2;
<Story name="hello story">
<Button>Hello button</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('non-story-exports'));
});
it('parameters.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} parameters={{ notes: 'component notes' }} />
<Story name="component notes">
<Button>Component notes</Button>
</Story>
<Story name="story notes" parameters={{ notes: 'story notes' }}>
<Button>Story notes</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('parameters'));
});
it('previews.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Canvas, Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} parameters={{ notes: 'component notes' }} />
# Canvas
Canvases can contain normal components, stories, and story references
<Canvas>
<Button>Just a button</Button>
<Story name="hello button">
<Button>Hello button</Button>
</Story>
<Story name="two">
<Button>Two</Button>
</Story>
<Story id="welcome--welcome" />
</Canvas>
Canvas without a story
<Canvas>
<Button>Just a button</Button>
</Canvas>
`)
).toMatchSpecificSnapshot(snap('previews'));
});
it('story-args.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" />
# Args
export const Template = (args) => <Button>Component notes</Button>;
<Story
name="component notes"
args={{ a: 1, b: 2 }}
argTypes={{ a: { name: 'A' }, b: { name: 'B' } }}
>
{Template.bind({})}
</Story>
`)
).toMatchSpecificSnapshot(snap('story-args'));
});
it('story-current.mdx', () => {
expect(
generate(dedent`
import { Story } from '@storybook/addon-docs';
# Current story
<Story id="." />
`)
).toMatchSpecificSnapshot(snap('story-current'));
});
it('story-def-text-only.mdx', () => {
expect(
generate(dedent`
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Text" />
# Story definition
<Story name="text">Plain text</Story>
`)
).toMatchSpecificSnapshot(snap('story-def-text-only'));
});
it('story-definitions.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" />
# Story definition
<Story name="one">
<Button>One</Button>
</Story>
<Story name="hello story">
<Button>Hello button</Button>
</Story>
<Story name="w/punctuation">
<Button>with punctuation</Button>
</Story>
<Story name="1 fine day">
<Button>starts with number</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('story-definitions'));
});
it('story-function-var.mdx', () => {
expect(
generate(dedent`
import { Meta, Story } from '@storybook/addon-docs';
<Meta title="story-function-var" />
export const basicFn = () => <Button />;
# Button
I can define a story with the function defined in CSF:
<Story name="basic">{basicFn}</Story>
`)
).toMatchSpecificSnapshot(snap('story-function-var'));
});
it('story-function.mdx', () => {
expect(
generate(dedent`
<Story name="function" height="100px">
{() => {
const btn = document.createElement('button');
btn.innerHTML = 'Hello Button';
btn.addEventListener('click', action('Click'));
return btn;
}}
</Story>
`)
).toMatchSpecificSnapshot(snap('story-function'));
});
it('story-multiple-children.mdx', () => {
expect(
generate(dedent`
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Multiple" />
# Multiple children
<Story name="multiple children">
<p>Hello Child #1</p>
<p>Hello Child #2</p>
</Story>
`)
).toMatchSpecificSnapshot(snap('story-multiple-children'));
});
it('story-object.mdx', () => {
expect(
generate(dedent`
import { Story, Meta } from '@storybook/addon-docs';
import { Welcome, Button } from '@storybook/angular/demo';
import { linkTo } from '@storybook/addon-links';
<Meta title="MDX|Welcome" />
# Story object
<Story name="to storybook" height="300px">
{{
template: '<storybook-welcome-component (showApp)="showApp()"></storybook-welcome-component>',
props: {
showApp: linkTo('Button'),
},
moduleMetadata: {
declarations: [Welcome],
},
}}
</Story>
`)
).toMatchSpecificSnapshot(snap('story-object'));
});
it('story-references.mdx', () => {
expect(
generate(dedent`
import { Story } from '@storybook/addon-docs';
# Story reference
<Story id="welcome--welcome" />
`)
).toMatchSpecificSnapshot(snap('story-references'));
});
it('title-template-string.mdx', () => {
expect(
generate(
[
"import { Meta, Story } from '@storybook/addon-docs';",
"import { titleFunction } from '../title-generators';",
'',
// eslint-disable-next-line no-template-curly-in-string
"<Meta title={`${titleFunction('template')}`} />",
].join('\n')
)
).toMatchSpecificSnapshot(snap('title-template-string'));
});
it('vanilla.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
# Hello MDX
This is some random content.
<Button>Hello button</Button>
`)
).toMatchSpecificSnapshot(snap('vanilla'));
});
it('errors on missing story props', async () => {
await expect(async () =>
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" />
# Bad story
<Story>
<Button>One</Button>
</Story>
`)
).rejects.toThrow('Expected a Story name, id, or story attribute');
});
describe('csf3', () => {
it('auto-title-docs-only.mdx', () => {
expect(
generate(dedent`
import { Meta } from '@storybook/addon-docs';
<Meta />
# Auto-title Docs Only
Spme **markdown** here!
`)
).toMatchSpecificSnapshot(snap('auto-title-docs-only'));
});
it('auto-title.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta component={Button} />
<Story name="Basic">
<Button>Basic</Button>
</Story>
`)
).toMatchSpecificSnapshot(snap('auto-title'));
});
it('default-render.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} />
<Story name="Basic" />
`)
).toMatchSpecificSnapshot(snap('default-render'));
});
it('component-render.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} render={(args) => <Button {...args} />} />
<Story name="Basic" />
`)
).toMatchSpecificSnapshot(snap('component-render'));
});
it('story-render.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} />
<Story name="Basic" render={(args) => <Button {...args} />} />
`)
).toMatchSpecificSnapshot(snap('story-render'));
});
it('story-play.mdx', () => {
expect(
generate(dedent`
import { Button } from '@storybook/react/demo';
import { Story, Meta } from '@storybook/addon-docs';
<Meta title="Button" component={Button} />
<Story name="Basic" play={() => console.log('play')} />
`)
).toMatchSpecificSnapshot(snap('story-play'));
});
});
});

View File

@ -1,521 +0,0 @@
import { toJSX } from '@mdx-js/mdx/mdx-hast-to-jsx';
import { parse, parseExpression } from '@babel/parser';
import * as t from '@babel/types';
import generate from '@babel/generator';
import camelCase from 'lodash/camelCase';
import jsStringEscape from 'js-string-escape';
// Defined in MDX2.0
interface MdxOptions {
filepath?: string;
skipExport?: boolean;
wrapExport?: string;
remarkPlugins?: any[];
rehypePlugins?: any[];
}
interface CompilerOptions {
filepath?: string;
}
interface Element {
type: string;
children: Element[];
value: string;
}
interface Context {
counter: number;
namedExports: Record<string, any>;
storyNameToKey: Record<string, string>;
root: Element;
}
type MetaExport = Record<string, any>;
// Generate the MDX as is, but append named exports for every
// story in the contents
const STORY_REGEX = /^<Story[\s>]/;
const CANVAS_REGEX = /^<(Preview|Canvas)[\s>]/;
const META_REGEX = /^<Meta[\s>]/;
const RESERVED =
/^(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|await|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$/;
function getAttr(elt: t.JSXOpeningElement, what: string): t.JSXAttribute['value'] | undefined {
const attr = (elt.attributes as t.JSXAttribute[]).find((n) => n.name.name === what);
return attr?.value;
}
const isReserved = (name: string) => RESERVED.exec(name);
const startsWithNumber = (name: string) => /^\d/.exec(name);
const sanitizeName = (name: string) => {
let key = camelCase(name);
if (startsWithNumber(key)) {
key = `_${key}`;
} else if (isReserved(key)) {
key = `${key}Story`;
}
return key;
};
const getStoryKey = (name: string, counter: number) =>
name ? sanitizeName(name) : `story${counter}`;
function genAttribute(key: string, element: t.JSXOpeningElement) {
const value = getAttr(element, key);
if (t.isJSXExpressionContainer(value)) {
const { code } = generate(value.expression, {});
return code;
}
return undefined;
}
function genImportStory(
ast: t.JSXElement,
storyDef: t.JSXExpressionContainer,
storyName: string,
context: Context
) {
const { code: story } = generate(storyDef.expression, {});
const storyKey = `_${story.split('.').pop()}_`;
const statements = [`export const ${storyKey} = ${story};`];
if (storyName) {
context.storyNameToKey[storyName] = storyKey;
statements.push(`${storyKey}.storyName = '${storyName}';`);
} else {
context.storyNameToKey[storyKey] = storyKey;
ast.openingElement.attributes.push(
t.jsxAttribute(t.jsxIdentifier('name'), t.stringLiteral(storyKey))
);
}
return {
[storyKey]: statements.join('\n'),
};
}
function getBodyPart(bodyNode: t.Node, context: Context) {
const body = t.isJSXExpressionContainer(bodyNode) ? bodyNode.expression : bodyNode;
let sourceBody = body;
if (
t.isCallExpression(body) &&
t.isMemberExpression(body.callee) &&
t.isIdentifier(body.callee.object) &&
t.isIdentifier(body.callee.property) &&
body.callee.property.name === 'bind' &&
(body.arguments.length === 0 ||
(body.arguments.length === 1 &&
t.isObjectExpression(body.arguments[0]) &&
body.arguments[0].properties.length === 0))
) {
const bound = body.callee.object.name;
const namedExport = context.namedExports[bound];
if (namedExport) {
sourceBody = namedExport;
}
}
const { code: storyCode } = generate(body, {});
const { code: sourceCode } = generate(sourceBody, {});
return { storyCode, sourceCode, body };
}
const idOrNull = (attr: t.JSXAttribute['value']) => (t.isStringLiteral(attr) ? attr.value : null);
const expressionOrNull = (attr: t.JSXAttribute['value']) =>
t.isJSXExpressionContainer(attr) ? attr.expression : null;
function genStoryExport(ast: t.JSXElement, context: Context) {
const storyName = idOrNull(getAttr(ast.openingElement, 'name'));
const storyId = idOrNull(getAttr(ast.openingElement, 'id'));
const storyRef = getAttr(ast.openingElement, 'story') as t.JSXExpressionContainer;
if (!storyId && !storyName && !storyRef) {
throw new Error('Expected a Story name, id, or story attribute');
}
// We don't generate exports for story references or the smart "current story"
if (storyId) {
return null;
}
if (storyRef) {
return genImportStory(ast, storyRef, storyName, context);
}
const statements = [];
const storyKey = getStoryKey(storyName, context.counter);
const bodyNodes = ast.children.filter((n) => !t.isJSXText(n));
let storyCode = null;
let sourceCode = null;
let storyVal = null;
if (!bodyNodes.length) {
if (ast.children.length > 0) {
// plain text node
const { code } = generate(ast.children[0], {});
storyCode = `'${code}'`;
sourceCode = storyCode;
storyVal = `() => (
${storyCode}
)`;
} else {
sourceCode = '{}';
storyVal = '{}';
}
} else {
const bodyParts = bodyNodes.map((bodyNode) => getBodyPart(bodyNode, context));
// if we have more than two children
// 1. Add line breaks
// 2. Enclose in <> ... </>
storyCode = bodyParts.map(({ storyCode: code }) => code).join('\n');
sourceCode = bodyParts.map(({ sourceCode: code }) => code).join('\n');
const storyReactCode = bodyParts.length > 1 ? `<>\n${storyCode}\n</>` : storyCode;
// keep track if an identifier or function call
// avoid breaking change for 5.3
const BIND_REGEX = /\.bind\(.*\)/;
if (bodyParts.length === 1) {
if (BIND_REGEX.test(bodyParts[0].storyCode)) {
storyVal = bodyParts[0].storyCode;
} else if (t.isIdentifier(bodyParts[0].body)) {
storyVal = `assertIsFn(${storyCode})`;
} else if (t.isArrowFunctionExpression(bodyParts[0].body)) {
storyVal = `(${storyCode})`;
} else {
storyVal = `() => (
${storyReactCode}
)`;
}
} else {
storyVal = `() => (
${storyReactCode}
)`;
}
}
statements.push(`export const ${storyKey} = ${storyVal};`);
// always preserve the name, since CSF exports can get modified by displayName
statements.push(`${storyKey}.storyName = '${storyName}';`);
const argTypes = genAttribute('argTypes', ast.openingElement);
if (argTypes) statements.push(`${storyKey}.argTypes = ${argTypes};`);
const args = genAttribute('args', ast.openingElement);
if (args) statements.push(`${storyKey}.args = ${args};`);
const parameters = expressionOrNull(getAttr(ast.openingElement, 'parameters'));
const source = jsStringEscape(sourceCode);
const sourceParam = `storySource: { source: '${source}' }`;
if (parameters) {
const { code: params } = generate(parameters, {});
statements.push(`${storyKey}.parameters = { ${sourceParam}, ...${params} };`);
} else {
statements.push(`${storyKey}.parameters = { ${sourceParam} };`);
}
const decorators = expressionOrNull(getAttr(ast.openingElement, 'decorators'));
if (decorators) {
const { code: decos } = generate(decorators, {});
statements.push(`${storyKey}.decorators = ${decos};`);
}
const loaders = expressionOrNull(getAttr(ast.openingElement, 'loaders'));
if (loaders) {
const { code: loaderCode } = generate(loaders, {});
statements.push(`${storyKey}.loaders = ${loaderCode};`);
}
const play = expressionOrNull(getAttr(ast.openingElement, 'play'));
if (play) {
const { code: playCode } = generate(play, {});
statements.push(`${storyKey}.play = ${playCode};`);
}
const render = expressionOrNull(getAttr(ast.openingElement, 'render'));
if (render) {
const { code: renderCode } = generate(render, {});
statements.push(`${storyKey}.render = ${renderCode};`);
}
context.storyNameToKey[storyName] = storyKey;
return {
[storyKey]: statements.join('\n'),
};
}
function genCanvasExports(ast: t.JSXElement, context: Context) {
const canvasExports = {};
for (let i = 0; i < ast.children.length; i += 1) {
const child = ast.children[i];
if (
t.isJSXElement(child) &&
t.isJSXIdentifier(child.openingElement.name) &&
child.openingElement.name.name === 'Story'
) {
const storyExport = genStoryExport(child, context);
const { code } = generate(child, {});
// @ts-ignore
child.value = code;
if (storyExport) {
Object.assign(canvasExports, storyExport);
context.counter += 1;
}
}
}
return canvasExports;
}
function genMeta(ast: t.JSXElement, options: CompilerOptions) {
const titleAttr = getAttr(ast.openingElement, 'title');
const idAttr = getAttr(ast.openingElement, 'id');
let title = null;
if (titleAttr) {
if (t.isStringLiteral(titleAttr)) {
title = "'".concat(jsStringEscape(titleAttr.value), "'");
} else if (t.isJSXExpressionContainer(titleAttr)) {
try {
// generate code, so the expression is evaluated by the CSF compiler
const { code } = generate(titleAttr.expression, {});
// remove the curly brackets at start and end of code
title = code.replace(/^\{(.+)\}$/, '$1');
} catch (e) {
// eat exception if title parsing didn't go well
// eslint-disable-next-line no-console
console.warn('Invalid title:', options.filepath);
title = undefined;
}
} else {
console.warn(`Unknown title attr: ${titleAttr.type}`);
}
}
const id = t.isStringLiteral(idAttr) ? `'${idAttr.value}'` : null;
const parameters = genAttribute('parameters', ast.openingElement);
const decorators = genAttribute('decorators', ast.openingElement);
const loaders = genAttribute('loaders', ast.openingElement);
const component = genAttribute('component', ast.openingElement);
const subcomponents = genAttribute('subcomponents', ast.openingElement);
const args = genAttribute('args', ast.openingElement);
const argTypes = genAttribute('argTypes', ast.openingElement);
const render = genAttribute('render', ast.openingElement);
return {
title,
id,
parameters,
decorators,
loaders,
component,
subcomponents,
args,
argTypes,
render,
};
}
function getExports(node: Element, context: Context, options: CompilerOptions) {
const { value, type } = node;
if (type === 'jsx') {
if (STORY_REGEX.exec(value)) {
// Single story
const ast = parseExpression(value, {
plugins: ['jsx'],
}) as unknown as t.JSXElement;
const storyExport = genStoryExport(ast, context);
const { code } = generate(ast, {});
// eslint-disable-next-line no-param-reassign
node.value = code;
return storyExport && { stories: storyExport };
}
if (CANVAS_REGEX.exec(value)) {
// Canvas/Preview, possibly containing multiple stories
const ast = parseExpression(value, { plugins: ['jsx'] }) as t.JSXElement;
const canvasExports = genCanvasExports(ast, context);
// We're overwriting the Canvas tag here with a version that
// has the `name` attribute (e.g. `<Story name="..." story={...} />`)
// even if the user didn't provide one. We need the name attribute when
// we render the node at runtime.
const { code } = generate(ast, {});
// eslint-disable-next-line no-param-reassign
node.value = code;
return { stories: canvasExports };
}
if (META_REGEX.exec(value)) {
const ast = parseExpression(value, { plugins: ['jsx'] }) as t.JSXElement;
return { meta: genMeta(ast, options) };
}
}
return null;
}
// insert `mdxStoryNameToKey` and `mdxComponentMeta` into the context so that we
// can reconstruct the Story ID dynamically from the `name` at render time
const wrapperJs = `
componentMeta.parameters = componentMeta.parameters || {};
componentMeta.parameters.docs = {
...(componentMeta.parameters.docs || {}),
page: () => <AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}><MDXContent /></AddContext>,
};
`.trim();
// Use this rather than JSON.stringify because `Meta`'s attributes
// are already valid code strings, so we want to insert them raw
// rather than add an extra set of quotes
function stringifyMeta(meta: object) {
let result = '{ ';
Object.entries(meta).forEach(([key, val]) => {
if (val) {
result += `${key}: ${val}, `;
}
});
result += ' }';
return result;
}
const hasStoryChild = (node: t.JSXElement): boolean => {
if (
node.openingElement &&
t.isJSXIdentifier(node.openingElement.name) &&
node.openingElement.name.name === 'Story'
) {
return !!node;
}
if (node.children && node.children.length > 0) {
return !!node.children.find((child: t.JSXElement) => hasStoryChild(child));
}
return false;
};
const getMdxSource = (children: t.Node[]) =>
encodeURI(children.map((el) => generate(el).code).join('\n'));
// Parse out the named exports from a node, where the key
// is the variable name and the value is the AST of the
// variable declaration initializer
const getNamedExports = (node: Element) => {
const namedExports: Record<string, t.Expression> = {};
const ast = parse(node.value, {
sourceType: 'module',
plugins: ['jsx'],
// FIXME!!! presets: ['env]
});
if (t.isFile(ast) && t.isProgram(ast.program) && ast.program.body.length === 1) {
const exported = ast.program.body[0];
if (
t.isExportNamedDeclaration(exported) &&
t.isVariableDeclaration(exported.declaration) &&
exported.declaration.declarations.length === 1
) {
const declaration = exported.declaration.declarations[0];
if (t.isVariableDeclarator(declaration) && t.isIdentifier(declaration.id)) {
const { name } = declaration.id;
namedExports[name] = declaration.init;
}
}
}
return namedExports;
};
function extractExports(root: Element, options: CompilerOptions) {
const namedExports = {};
root.children.forEach((child) => {
if (child.type === 'jsx') {
try {
const ast = parseExpression(child.value, { plugins: ['jsx'] }) as t.JSXElement;
if (
t.isJSXOpeningElement(ast.openingElement) &&
['Preview', 'Canvas'].includes((ast.openingElement.name as t.JSXIdentifier).name) &&
!hasStoryChild(ast)
) {
const canvasAst = ast.openingElement;
canvasAst.attributes.push(
t.jsxAttribute(
t.jsxIdentifier('mdxSource'),
t.stringLiteral(getMdxSource(ast.children))
)
);
}
const { code } = generate(ast, {});
// eslint-disable-next-line no-param-reassign
child.value = code;
} catch {
/** catch erroneous child.value string where the babel parseExpression makes exception
* https://github.com/mdx-js/mdx/issues/767
* eg <button>
* <div>hello world</div>
*
* </button>
* generates error
* 1. child.value =`<button>\n <div>hello world</div`
* 2. child.value =`\n`
* 3. child.value =`</button>`
*
*/
}
} else if (child.type === 'export') {
Object.assign(namedExports, getNamedExports(child));
}
});
// we're overriding default export
const storyExports = [];
const includeStories = [];
let metaExport: MetaExport | null = null;
const context: Context = {
counter: 0,
storyNameToKey: {},
root,
namedExports,
};
root.children.forEach((n) => {
const exports = getExports(n, context, options);
if (exports) {
const { stories, meta } = exports;
if (stories) {
Object.entries(stories).forEach(([key, story]) => {
includeStories.push(key);
storyExports.push(story);
});
}
if (meta) {
if (metaExport) {
throw new Error('Meta can only be declared once');
}
metaExport = meta;
}
}
});
if (metaExport) {
if (!storyExports.length) {
storyExports.push('export const __page = () => { throw new Error("Docs-only story"); };');
storyExports.push('__page.parameters = { docsOnly: true };');
includeStories.push('__page');
}
} else {
metaExport = {};
}
metaExport.includeStories = JSON.stringify(includeStories);
const defaultJsx = toJSX(root, {}, { ...options, skipExport: true });
const fullJsx = [
'import { assertIsFn, AddContext } from "@storybook/addon-docs";',
defaultJsx,
...storyExports,
`const componentMeta = ${stringifyMeta(metaExport)};`,
`const mdxStoryNameToKey = ${JSON.stringify(context.storyNameToKey)};`,
wrapperJs,
'export default componentMeta;',
].join('\n\n');
return fullJsx;
}
export function createCompiler(mdxOptions: MdxOptions) {
return function compiler(options: CompilerOptions = {}) {
this.Compiler = (root: Element) => extractExports(root, options);
};
}

View File

@ -1,4 +0,0 @@
declare module '@mdx-js/react';
declare module '@mdx-js/mdx';
declare module '@mdx-js/mdx/mdx-hast-to-jsx';
declare module 'js-string-escape';

View File

@ -1 +0,0 @@
declare module 'global';

View File

@ -63,6 +63,14 @@ packages:
access: $all
publish: $all
proxy: npmjs
'@storybook/mdx1-csf':
access: $all
publish: $all
proxy: npmjs
'@storybook/mdx2-csf':
access: $all
publish: $all
proxy: npmjs
# storybook packages are NOT proxied to global registry
# allowing us to republish any version during tests

1118
yarn.lock

File diff suppressed because it is too large Load Diff