mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-07 07:21:17 +08:00
Merge remote-tracking branch 'origin/next' into valentin/remove-babel-from-webpack5-builder
This commit is contained in:
commit
10ad2a447e
893
.yarn/releases/yarn-4.0.0.cjs
generated
vendored
893
.yarn/releases/yarn-4.0.0.cjs
generated
vendored
File diff suppressed because one or more lines are too long
893
.yarn/releases/yarn-4.0.2.cjs
generated
vendored
Executable file
893
.yarn/releases/yarn-4.0.2.cjs
generated
vendored
Executable file
File diff suppressed because one or more lines are too long
@ -8,4 +8,4 @@ nodeLinker: node-modules
|
||||
|
||||
npmPublishAccess: public
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.0.0.cjs
|
||||
yarnPath: .yarn/releases/yarn-4.0.2.cjs
|
||||
|
@ -25,6 +25,7 @@ If you run `yarn start` and encounter the following error, try rerunning `yarn s
|
||||
```sh
|
||||
> NX ENOENT: no such file or directory, open 'storybook/code/node_modules/nx/package.json'
|
||||
```
|
||||
|
||||
If you are a Storybook contributor and still experience issues, it is recommended that you verify your local Storybook instance for any unintentional local changes. To do this, you can use the following command:
|
||||
|
||||
```sh
|
||||
@ -37,11 +38,11 @@ By executing this command, you will be able to see which untracked or ignored fi
|
||||
|
||||
If you have forked the repository, you should [disable Github Actions for your repo](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository) as many of them (e.g. pushing to sandbox) will fail without proper authorization. In your Github repo, go to Settings > Actions > General > set the Actions Permissions to **Disable actions**.
|
||||
|
||||
# Running against different sandbox templates
|
||||
## Running against different sandbox templates
|
||||
|
||||
You can also pick a specific template to use as your sandbox by running `yarn task`, which will prompt you to make further choices about which template you want and which task you want to run.
|
||||
|
||||
# Making code changes
|
||||
## Making code changes
|
||||
|
||||
If you want to make code changes to Storybook packages while running a sandbox, you'll need to do the following:
|
||||
|
||||
@ -56,10 +57,10 @@ yarn build --watch react core-server api addon-docs
|
||||
|
||||
3. If you are running the sandbox in "unlinked" mode you'll need to re-run the sandbox from the `publish` step to see the changes:
|
||||
|
||||
```
|
||||
```sh
|
||||
yarn task --task dev --template <your template> --start-from=publish
|
||||
```
|
||||
|
||||
# Contributing to Storybook
|
||||
## Contributing to Storybook
|
||||
|
||||
For further advice on how to contribute, please refer to our [NEW contributing guide on the Storybook website](https://storybook.js.org/docs/contribute).
|
||||
|
@ -1,6 +1,7 @@
|
||||
<h1>Migration</h1>
|
||||
|
||||
- [From version 7.x to 8.0.0](#from-version-7x-to-800)
|
||||
- [Removal of `storiesOf`-API](#removal-of-storiesof-api)
|
||||
- [Removed deprecated shim packages](#removed-deprecated-shim-packages)
|
||||
- [Framework-specific Vite plugins have to be explicitly added](#framework-specific-vite-plugins-have-to-be-explicitly-added)
|
||||
- [Implicit actions can not be used during rendering (for example in the play function)](#implicit-actions-can-not-be-used-during-rendering-for-example-in-the-play-function)
|
||||
@ -367,6 +368,14 @@
|
||||
|
||||
## From version 7.x to 8.0.0
|
||||
|
||||
### Removal of `storiesOf`-API
|
||||
|
||||
The `storiesOf` API has been removed in Storybook 8.0.
|
||||
|
||||
If you need to dynamically create stories, you will need to implement this via the experimental `experimental_indexers` [API](#storyindexers-is-replaced-with-experimental_indexers).
|
||||
|
||||
For migrating to CSF, see: [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated)
|
||||
|
||||
### Removed deprecated shim packages
|
||||
|
||||
In Storybook 7, these packages existed for backwards compatibility, but were marked as deprecated:
|
||||
|
@ -2,6 +2,8 @@ compressionLevel: 0
|
||||
|
||||
enableGlobalCache: true
|
||||
|
||||
installStatePath: ../.yarn/code-install-state.gz
|
||||
|
||||
logFilters:
|
||||
- code: YN0005
|
||||
level: discard
|
||||
@ -23,7 +25,6 @@ plugins:
|
||||
unsafeHttpWhitelist:
|
||||
- localhost
|
||||
|
||||
yarnPath: ../.yarn/releases/yarn-4.0.0.cjs
|
||||
installStatePath: '../.yarn/code-install-state.gz'
|
||||
yarnPath: ../.yarn/releases/yarn-4.0.2.cjs
|
||||
# Sometimes you get a "The remote archive doesn't match the expected checksum" error, uncommenting this line will fix it
|
||||
# checksumBehavior: 'update'
|
||||
|
@ -60,7 +60,7 @@
|
||||
"@storybook/client-logger": "workspace:*",
|
||||
"@storybook/components": "workspace:*",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/manager-api": "workspace:*",
|
||||
"@storybook/preview-api": "workspace:*",
|
||||
"@storybook/theming": "workspace:*",
|
||||
|
@ -53,7 +53,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"memoizerific": "^1.11.3",
|
||||
"ts-dedent": "^2.0.0"
|
||||
},
|
||||
|
@ -49,7 +49,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/types": "workspace:*",
|
||||
"jest-mock": "^27.0.6",
|
||||
"polished": "^4.2.2",
|
||||
|
@ -65,7 +65,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"tiny-invariant": "^1.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -55,7 +55,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"ts-dedent": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1 +1 @@
|
||||
import './dist/preset';
|
||||
require('./dist/preset');
|
||||
|
@ -59,7 +59,7 @@
|
||||
"@storybook/client-logger": "workspace:*",
|
||||
"@storybook/components": "workspace:*",
|
||||
"@storybook/core-events": "workspace:*",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/manager-api": "workspace:*",
|
||||
"@storybook/preview-api": "workspace:*",
|
||||
"@storybook/theming": "workspace:*",
|
||||
|
@ -55,7 +55,7 @@
|
||||
"@storybook/components": "workspace:*",
|
||||
"@storybook/core-events": "workspace:*",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/manager-api": "workspace:*",
|
||||
"@storybook/preview-api": "workspace:*",
|
||||
"@storybook/theming": "workspace:*",
|
||||
|
@ -1,48 +0,0 @@
|
||||
import { loadPreviewOrConfigFile } from '@storybook/core-common';
|
||||
import type { Options } from '@storybook/types';
|
||||
import slash from 'slash';
|
||||
import { listStories } from './list-stories';
|
||||
|
||||
const absoluteFilesToImport = async (
|
||||
files: string[],
|
||||
name: string,
|
||||
normalizePath: (id: string) => string
|
||||
) =>
|
||||
files
|
||||
.map((el, i) => `import ${name ? `* as ${name}_${i} from ` : ''}'/@fs/${normalizePath(el)}'`)
|
||||
.join('\n');
|
||||
|
||||
export async function generateVirtualStoryEntryCode(options: Options) {
|
||||
const { normalizePath } = await import('vite');
|
||||
const storyEntries = await listStories(options);
|
||||
const resolveMap = storyEntries.reduce<Record<string, string>>(
|
||||
(prev, entry) => ({ ...prev, [entry]: entry.replace(slash(process.cwd()), '.') }),
|
||||
{}
|
||||
);
|
||||
const modules = storyEntries.map((entry, i) => `${JSON.stringify(entry)}: story_${i}`).join(',');
|
||||
|
||||
return `
|
||||
${await absoluteFilesToImport(storyEntries, 'story', normalizePath)}
|
||||
|
||||
function loadable(key) {
|
||||
return {${modules}}[key];
|
||||
}
|
||||
|
||||
Object.assign(loadable, {
|
||||
keys: () => (${JSON.stringify(Object.keys(resolveMap))}),
|
||||
resolve: (key) => (${JSON.stringify(resolveMap)}[key])
|
||||
});
|
||||
|
||||
export function configStories(configure) {
|
||||
configure(loadable, { hot: import.meta.hot }, false);
|
||||
}
|
||||
`.trim();
|
||||
}
|
||||
|
||||
export async function generatePreviewEntryCode({ configDir }: Options) {
|
||||
const previewFile = loadPreviewOrConfigFile({ configDir });
|
||||
if (!previewFile) return '';
|
||||
|
||||
return `import * as preview from '${slash(previewFile)}';
|
||||
export default preview;`;
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
import { getRendererName } from '@storybook/core-common';
|
||||
import type { Options, PreviewAnnotation } from '@storybook/types';
|
||||
import { virtualPreviewFile, virtualStoriesFile } from './virtual-file-names';
|
||||
import { processPreviewAnnotation } from './utils/process-preview-annotation';
|
||||
|
||||
export async function generateIframeScriptCode(options: Options, projectRoot: string) {
|
||||
const { presets } = options;
|
||||
const rendererName = await getRendererName(options);
|
||||
|
||||
const previewAnnotations = await presets.apply<PreviewAnnotation[]>(
|
||||
'previewAnnotations',
|
||||
[],
|
||||
options
|
||||
);
|
||||
const configEntries = [...previewAnnotations]
|
||||
.filter(Boolean)
|
||||
.map((path) => processPreviewAnnotation(path, projectRoot));
|
||||
|
||||
const filesToImport = (files: string[], name: string) =>
|
||||
files.map((el, i) => `import ${name ? `* as ${name}_${i} from ` : ''}'${el}'`).join('\n');
|
||||
|
||||
const importArray = (name: string, length: number) =>
|
||||
new Array(length).fill(0).map((_, i) => `${name}_${i}`);
|
||||
|
||||
// noinspection UnnecessaryLocalVariableJS
|
||||
/** @todo Inline variable and remove `noinspection` */
|
||||
// language=JavaScript
|
||||
const code = `
|
||||
// Ensure that the client API is initialized by the framework before any other iframe code
|
||||
// is loaded. That way our client-apis can assume the existence of the API+store
|
||||
import { configure } from '${rendererName}';
|
||||
|
||||
import { logger } from '@storybook/client-logger';
|
||||
import * as previewApi from "@storybook/preview-api";
|
||||
${filesToImport(configEntries, 'config')}
|
||||
|
||||
import * as preview from '${virtualPreviewFile}';
|
||||
import { configStories } from '${virtualStoriesFile}';
|
||||
|
||||
const {
|
||||
addDecorator,
|
||||
addParameters,
|
||||
addLoader,
|
||||
addArgs,
|
||||
addArgTypes,
|
||||
addStepRunner,
|
||||
addArgTypesEnhancer,
|
||||
addArgsEnhancer,
|
||||
setGlobalRender,
|
||||
} = previewApi;
|
||||
|
||||
const configs = [${importArray('config', configEntries.length)
|
||||
.concat('preview.default')
|
||||
.join(',')}].filter(Boolean)
|
||||
|
||||
configs.map(config => config.default ? config.default : config).forEach(config => {
|
||||
Object.keys(config).forEach((key) => {
|
||||
const value = config[key];
|
||||
switch (key) {
|
||||
case 'args': {
|
||||
return addArgs(value);
|
||||
}
|
||||
case 'argTypes': {
|
||||
return addArgTypes(value);
|
||||
}
|
||||
case 'decorators': {
|
||||
return value.forEach((decorator) => addDecorator(decorator, false));
|
||||
}
|
||||
case 'loaders': {
|
||||
return value.forEach((loader) => addLoader(loader, false));
|
||||
}
|
||||
case 'parameters': {
|
||||
return addParameters({ ...value }, false);
|
||||
}
|
||||
case 'argTypesEnhancers': {
|
||||
return value.forEach((enhancer) => addArgTypesEnhancer(enhancer));
|
||||
}
|
||||
case 'argsEnhancers': {
|
||||
return value.forEach((enhancer) => addArgsEnhancer(enhancer))
|
||||
}
|
||||
case 'render': {
|
||||
return setGlobalRender(value)
|
||||
}
|
||||
case 'globals':
|
||||
case 'globalTypes': {
|
||||
const v = {};
|
||||
v[key] = value;
|
||||
return addParameters(v, false);
|
||||
}
|
||||
case 'decorateStory':
|
||||
case 'applyDecorators':
|
||||
case 'renderToDOM': // deprecated
|
||||
case 'renderToCanvas': {
|
||||
return null; // This key is not handled directly in v6 mode.
|
||||
}
|
||||
case 'runStep': {
|
||||
return addStepRunner(value);
|
||||
}
|
||||
default: {
|
||||
// eslint-disable-next-line prefer-template
|
||||
return console.log(key + ' was not supported :( !');
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
/* TODO: not quite sure what to do with this, to fix HMR
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept();
|
||||
}
|
||||
*/
|
||||
|
||||
configStories(configure);
|
||||
`.trim();
|
||||
return code;
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import type { Options } from '@storybook/types';
|
||||
import { logger } from '@storybook/node-logger';
|
||||
|
||||
import { listStories } from './list-stories';
|
||||
|
||||
@ -28,11 +27,7 @@ function toImportPath(relativePath: string) {
|
||||
async function toImportFn(stories: string[]) {
|
||||
const { normalizePath } = await import('vite');
|
||||
const objectEntries = stories.map((file) => {
|
||||
const ext = path.extname(file);
|
||||
const relativePath = normalizePath(path.relative(process.cwd(), file));
|
||||
if (!['.js', '.jsx', '.ts', '.tsx', '.mdx', '.svelte', '.vue'].includes(ext)) {
|
||||
logger.warn(`Cannot process ${ext} file with storyStoreV7: ${relativePath}`);
|
||||
}
|
||||
|
||||
return ` '${toImportPath(relativePath)}': async () => import('/@fs/${file}')`;
|
||||
});
|
||||
|
@ -69,7 +69,6 @@ export async function generateModernIframeScriptCode(options: Options, projectRo
|
||||
window.__STORYBOOK_PREVIEW__ = window.__STORYBOOK_PREVIEW__ || new PreviewWeb();
|
||||
|
||||
window.__STORYBOOK_STORY_STORE__ = window.__STORYBOOK_STORY_STORE__ || window.__STORYBOOK_PREVIEW__.storyStore;
|
||||
window.__STORYBOOK_CLIENT_API__ = window.__STORYBOOK_CLIENT_API__ || new ClientApi({ storyStore: window.__STORYBOOK_PREVIEW__.storyStore });
|
||||
window.__STORYBOOK_PREVIEW__.initialize({ importFn, getProjectAnnotations });
|
||||
|
||||
${generateHMRHandler(frameworkName)};
|
||||
|
@ -4,10 +4,8 @@ import * as fs from 'fs';
|
||||
import type { Plugin } from 'vite';
|
||||
import type { Options } from '@storybook/types';
|
||||
import { transformIframeHtml } from '../transform-iframe-html';
|
||||
import { generateIframeScriptCode } from '../codegen-iframe-script';
|
||||
import { generateModernIframeScriptCode } from '../codegen-modern-iframe-script';
|
||||
import { generateImportFnScriptCode } from '../codegen-importfn-script';
|
||||
import { generateVirtualStoryEntryCode, generatePreviewEntryCode } from '../codegen-entries';
|
||||
import { generateAddonSetupCode } from '../codegen-set-addon-channel';
|
||||
|
||||
import {
|
||||
@ -90,27 +88,16 @@ export function codeGeneratorPlugin(options: Options): Plugin {
|
||||
return undefined;
|
||||
},
|
||||
async load(id, config) {
|
||||
const storyStoreV7 = options.features?.storyStoreV7;
|
||||
if (id === virtualStoriesFile) {
|
||||
if (storyStoreV7) {
|
||||
return generateImportFnScriptCode(options);
|
||||
}
|
||||
return generateVirtualStoryEntryCode(options);
|
||||
return generateImportFnScriptCode(options);
|
||||
}
|
||||
|
||||
if (id === virtualAddonSetupFile) {
|
||||
return generateAddonSetupCode();
|
||||
}
|
||||
|
||||
if (id === virtualPreviewFile && !storyStoreV7) {
|
||||
return generatePreviewEntryCode(options);
|
||||
}
|
||||
|
||||
if (id === virtualFileId) {
|
||||
if (storyStoreV7) {
|
||||
return generateModernIframeScriptCode(options, projectRoot);
|
||||
}
|
||||
return generateIframeScriptCode(options, projectRoot);
|
||||
return generateModernIframeScriptCode(options, projectRoot);
|
||||
}
|
||||
|
||||
if (id === iframeId) {
|
||||
|
@ -1,16 +1,14 @@
|
||||
import type { Options, PreviewAnnotation } from '@storybook/types';
|
||||
import { join, resolve } from 'path';
|
||||
import {
|
||||
getBuilderOptions,
|
||||
getRendererName,
|
||||
handlebars,
|
||||
interpolate,
|
||||
loadPreviewOrConfigFile,
|
||||
normalizeStories,
|
||||
readTemplate,
|
||||
} from '@storybook/core-common';
|
||||
import type { Options, PreviewAnnotation } from '@storybook/types';
|
||||
import { isAbsolute, join, resolve } from 'path';
|
||||
import slash from 'slash';
|
||||
import { toImportFn, toRequireContextString } from '@storybook/core-webpack';
|
||||
import { toImportFn } from '@storybook/core-webpack';
|
||||
import type { BuilderOptions } from '../types';
|
||||
|
||||
export const getVirtualModules = async (options: Options) => {
|
||||
@ -37,79 +35,31 @@ export const getVirtualModules = async (options: Options) => {
|
||||
return entry.absolute;
|
||||
}
|
||||
|
||||
// TODO: Remove as soon as we drop support for disabled StoryStoreV7
|
||||
if (isAbsolute(entry)) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
return slash(entry);
|
||||
}
|
||||
),
|
||||
loadPreviewOrConfigFile(options),
|
||||
].filter(Boolean);
|
||||
|
||||
if (options.features?.storyStoreV7) {
|
||||
const storiesFilename = 'storybook-stories.js';
|
||||
const storiesPath = resolve(join(workingDir, storiesFilename));
|
||||
const storiesFilename = 'storybook-stories.js';
|
||||
const storiesPath = resolve(join(workingDir, storiesFilename));
|
||||
|
||||
const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;
|
||||
virtualModules[storiesPath] = toImportFn(stories, { needPipelinedImport });
|
||||
const configEntryPath = resolve(join(workingDir, 'storybook-config-entry.js'));
|
||||
virtualModules[configEntryPath] = handlebars(
|
||||
await readTemplate(
|
||||
require.resolve(
|
||||
'@storybook/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars'
|
||||
)
|
||||
),
|
||||
{
|
||||
storiesFilename,
|
||||
previewAnnotations,
|
||||
}
|
||||
// We need to double escape `\` for webpack. We may have some in windows paths
|
||||
).replace(/\\/g, '\\\\');
|
||||
entries.push(configEntryPath);
|
||||
} else {
|
||||
const rendererName = await getRendererName(options);
|
||||
|
||||
const rendererInitEntry = resolve(join(workingDir, 'storybook-init-renderer-entry.js'));
|
||||
virtualModules[rendererInitEntry] = `import '${slash(rendererName)}';`;
|
||||
entries.push(rendererInitEntry);
|
||||
|
||||
const entryTemplate = await readTemplate(
|
||||
require.resolve('@storybook/builder-webpack5/templates/virtualModuleEntry.template.js')
|
||||
);
|
||||
|
||||
previewAnnotations.forEach((previewAnnotationFilename: string | undefined) => {
|
||||
if (!previewAnnotationFilename) return;
|
||||
|
||||
// Ensure that relative paths end up mapped to a filename in the cwd, so a later import
|
||||
// of the `previewAnnotationFilename` in the template works.
|
||||
const entryFilename = previewAnnotationFilename.startsWith('.')
|
||||
? `${previewAnnotationFilename.replace(/(\w)(\/|\\)/g, '$1-')}-generated-config-entry.js`
|
||||
: `${previewAnnotationFilename}-generated-config-entry.js`;
|
||||
// NOTE: although this file is also from the `dist/cjs` directory, it is actually a ESM
|
||||
// file, see https://github.com/storybookjs/storybook/pull/16727#issuecomment-986485173
|
||||
virtualModules[entryFilename] = interpolate(entryTemplate, {
|
||||
previewAnnotationFilename,
|
||||
});
|
||||
entries.push(entryFilename);
|
||||
});
|
||||
if (stories.length > 0) {
|
||||
const storyTemplate = await readTemplate(
|
||||
require.resolve('@storybook/builder-webpack5/templates/virtualModuleStory.template.js')
|
||||
);
|
||||
// NOTE: this file has a `.cjs` extension as it is a CJS file (from `dist/cjs`) and runs
|
||||
// in the user's webpack mode, which may be strict about the use of require/import.
|
||||
// See https://github.com/storybookjs/storybook/issues/14877
|
||||
const storiesFilename = resolve(join(workingDir, `generated-stories-entry.cjs`));
|
||||
virtualModules[storiesFilename] = interpolate(storyTemplate, {
|
||||
rendererName,
|
||||
})
|
||||
// Make sure we also replace quotes for this one
|
||||
.replace("'{{stories}}'", stories.map(toRequireContextString).join(','));
|
||||
entries.push(storiesFilename);
|
||||
const needPipelinedImport = !!builderOptions.lazyCompilation && !isProd;
|
||||
virtualModules[storiesPath] = toImportFn(stories, { needPipelinedImport });
|
||||
const configEntryPath = resolve(join(workingDir, 'storybook-config-entry.js'));
|
||||
virtualModules[configEntryPath] = handlebars(
|
||||
await readTemplate(
|
||||
require.resolve(
|
||||
'@storybook/builder-webpack5/templates/virtualModuleModernEntry.js.handlebars'
|
||||
)
|
||||
),
|
||||
{
|
||||
storiesFilename,
|
||||
previewAnnotations,
|
||||
}
|
||||
}
|
||||
// We need to double escape `\` for webpack. We may have some in windows paths
|
||||
).replace(/\\/g, '\\\\');
|
||||
entries.push(configEntryPath);
|
||||
|
||||
return {
|
||||
virtualModules,
|
||||
|
@ -1,65 +0,0 @@
|
||||
/* eslint-disable import/no-unresolved */
|
||||
import {
|
||||
addDecorator,
|
||||
addParameters,
|
||||
addLoader,
|
||||
addArgs,
|
||||
addArgTypes,
|
||||
addStepRunner,
|
||||
addArgsEnhancer,
|
||||
addArgTypesEnhancer,
|
||||
setGlobalRender,
|
||||
} from '@storybook/preview-api';
|
||||
import * as previewAnnotations from '{{previewAnnotationFilename}}';
|
||||
|
||||
const config = previewAnnotations.default ?? previewAnnotations;
|
||||
|
||||
Object.keys(config).forEach((key) => {
|
||||
const value = config[key];
|
||||
switch (key) {
|
||||
case 'args': {
|
||||
return addArgs(value);
|
||||
}
|
||||
case 'argTypes': {
|
||||
return addArgTypes(value);
|
||||
}
|
||||
case 'decorators': {
|
||||
return value.forEach((decorator) => addDecorator(decorator, false));
|
||||
}
|
||||
case 'loaders': {
|
||||
return value.forEach((loader) => addLoader(loader, false));
|
||||
}
|
||||
case 'parameters': {
|
||||
return addParameters({ ...value }, false);
|
||||
}
|
||||
case 'argTypesEnhancers': {
|
||||
return value.forEach((enhancer) => addArgTypesEnhancer(enhancer));
|
||||
}
|
||||
case 'argsEnhancers': {
|
||||
return value.forEach((enhancer) => addArgsEnhancer(enhancer));
|
||||
}
|
||||
case 'render': {
|
||||
return setGlobalRender(value);
|
||||
}
|
||||
case 'globals':
|
||||
case 'globalTypes': {
|
||||
const v = {};
|
||||
v[key] = value;
|
||||
return addParameters(v, false);
|
||||
}
|
||||
case '__namedExportsOrder':
|
||||
case 'decorateStory':
|
||||
case 'renderToDOM': // deprecated
|
||||
case 'renderToCanvas': {
|
||||
return null; // This key is not handled directly in v6 mode.
|
||||
}
|
||||
case 'runStep': {
|
||||
return addStepRunner(value);
|
||||
}
|
||||
default: {
|
||||
return console.log(
|
||||
`Unknown key '${key}' exported by preview annotation file '{{previewAnnotationFilename}}'`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
@ -20,7 +20,6 @@ const preview = new PreviewWeb();
|
||||
window.__STORYBOOK_PREVIEW__ = preview;
|
||||
window.__STORYBOOK_STORY_STORE__ = preview.storyStore;
|
||||
window.__STORYBOOK_ADDONS_CHANNEL__ = channel;
|
||||
window.__STORYBOOK_CLIENT_API__ = new ClientApi({ storyStore: preview.storyStore });
|
||||
|
||||
preview.initialize({ importFn, getProjectAnnotations });
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
const { configure } = require('{{rendererName}}');
|
||||
|
||||
configure(['{{stories}}'], module, false);
|
@ -48,17 +48,6 @@ test.describe('addon-backgrounds', () => {
|
||||
});
|
||||
|
||||
test('button should appear for unattached .mdx files', async ({ page }) => {
|
||||
// SSv6 does not support .mdx files. There is a unattached stories.mdx file
|
||||
// at /docs/addons-docs-stories-mdx-unattached--docs, but these are functionally
|
||||
// really attached
|
||||
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
test.skip(
|
||||
// eslint-disable-next-line jest/valid-title
|
||||
templateName.includes('ssv6'),
|
||||
'Only run this test for Sandboxes with StoryStoreV7 enabled'
|
||||
);
|
||||
|
||||
const sbPage = new SbPage(page);
|
||||
|
||||
// We start on the introduction page by default.
|
||||
|
@ -1,9 +1,7 @@
|
||||
/* eslint-disable jest/no-disabled-tests */
|
||||
import { test, expect } from '@playwright/test';
|
||||
import process from 'process';
|
||||
|
||||
const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001';
|
||||
const templateName = process.env.STORYBOOK_TEMPLATE_NAME || '';
|
||||
|
||||
test.describe('JSON files', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
@ -11,11 +9,6 @@ test.describe('JSON files', () => {
|
||||
});
|
||||
|
||||
test('should have index.json', async ({ page }) => {
|
||||
test.skip(
|
||||
// eslint-disable-next-line jest/valid-title
|
||||
templateName.includes('ssv6'),
|
||||
'Only run this test for Sandboxes with StoryStoreV7 enabled'
|
||||
);
|
||||
const json = await page.evaluate(() => fetch('/index.json').then((res) => res.json()));
|
||||
|
||||
expect(json).toEqual({
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
import './globals';
|
||||
|
||||
// eslint-disable-next-line import/export
|
||||
export * from './public-api';
|
||||
// eslint-disable-next-line import/export
|
||||
export * from './public-types';
|
||||
|
||||
export type { StoryFnAngularReturnType as IStory } from './types';
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './public-types';
|
@ -31,7 +31,7 @@ export type Meta<TArgs = Args> = ComponentAnnotations<AngularRenderer, Transform
|
||||
export type StoryFn<TArgs = Args> = AnnotatedStoryFn<AngularRenderer, TransformEventType<TArgs>>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
1
code/frameworks/angular/src/typings.d.ts
vendored
1
code/frameworks/angular/src/typings.d.ts
vendored
@ -6,7 +6,6 @@ declare var NODE_ENV: string | undefined;
|
||||
declare var __STORYBOOK_ADDONS_CHANNEL__: any;
|
||||
declare var __STORYBOOK_ADDONS_PREVIEW: any;
|
||||
declare var __STORYBOOK_COMPODOC_JSON__: any;
|
||||
declare var __STORYBOOK_CLIENT_API__: any;
|
||||
declare var __STORYBOOK_PREVIEW__: any;
|
||||
declare var __STORYBOOK_STORY_STORE__: any;
|
||||
declare var CHANNEL_OPTIONS: any;
|
||||
|
@ -1 +0,0 @@
|
||||
import './globals';
|
@ -58,7 +58,7 @@
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18 || >=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -148,7 +148,7 @@
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -24,7 +24,7 @@ function Component() {
|
||||
name: 'Prefetch',
|
||||
},
|
||||
{
|
||||
// @ts-expect-error (a legacy nextjs api?)
|
||||
// @ts-expect-error (old API)
|
||||
cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),
|
||||
name: 'Push HTML',
|
||||
},
|
||||
@ -33,7 +33,7 @@ function Component() {
|
||||
name: 'Refresh',
|
||||
},
|
||||
{
|
||||
// @ts-expect-error (a legacy nextjs api?)
|
||||
// @ts-expect-error (old API)
|
||||
cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),
|
||||
name: 'Replace',
|
||||
},
|
||||
|
@ -60,7 +60,7 @@
|
||||
"vite": "^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -65,7 +65,7 @@
|
||||
"vite": "^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -68,7 +68,7 @@
|
||||
"vite": "^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18 || >=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -68,7 +68,7 @@
|
||||
"vite": "^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18 || >=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -62,7 +62,7 @@
|
||||
"vite": "^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18 || >=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -58,7 +58,7 @@
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18 || >=16"
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
@ -12,11 +12,7 @@ import type { JsPackageManager } from '../js-package-manager';
|
||||
import { getPackageDetails } from '../js-package-manager';
|
||||
import packageVersions from '../versions';
|
||||
import type { FrameworkOptions, GeneratorOptions } from './types';
|
||||
import {
|
||||
configureEslintPlugin,
|
||||
extractEslintInfo,
|
||||
suggestESLintPlugin,
|
||||
} from '../automigrate/helpers/eslintPlugin';
|
||||
import { configureEslintPlugin, extractEslintInfo } from '../automigrate/helpers/eslintPlugin';
|
||||
import { detectBuilder } from '../detect';
|
||||
|
||||
const logger = console;
|
||||
@ -173,14 +169,7 @@ const hasFrameworkTemplates = (framework?: SupportedFrameworks) =>
|
||||
export async function baseGenerator(
|
||||
packageManager: JsPackageManager,
|
||||
npmOptions: NpmOptions,
|
||||
{
|
||||
language,
|
||||
builder,
|
||||
pnp,
|
||||
frameworkPreviewParts,
|
||||
yes: skipPrompts,
|
||||
projectType,
|
||||
}: GeneratorOptions,
|
||||
{ language, builder, pnp, frameworkPreviewParts, projectType }: GeneratorOptions,
|
||||
renderer: SupportedRenderers,
|
||||
options: FrameworkOptions = defaultOptions,
|
||||
framework?: SupportedFrameworks
|
||||
@ -318,10 +307,8 @@ export async function baseGenerator(
|
||||
);
|
||||
|
||||
if (hasEslint && !isStorybookPluginInstalled) {
|
||||
if (skipPrompts || (await suggestESLintPlugin())) {
|
||||
depsToInstall.push('eslint-plugin-storybook');
|
||||
await configureEslintPlugin(eslintConfigFile ?? undefined, packageManager);
|
||||
}
|
||||
depsToInstall.push('eslint-plugin-storybook');
|
||||
await configureEslintPlugin(eslintConfigFile ?? undefined, packageManager);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
@ -66,7 +66,7 @@ export type Template = {
|
||||
inDevelopment?: boolean;
|
||||
/**
|
||||
* Some sandboxes might need extra modifications in the initialized Storybook,
|
||||
* such as extend main.js, for setting specific feature flags like storyStoreV7, etc.
|
||||
* such as extend main.js, for setting specific feature flags.
|
||||
*/
|
||||
modifications?: {
|
||||
skipTemplateStories?: boolean;
|
||||
|
@ -29,9 +29,6 @@ const config: StorybookConfig = {
|
||||
disableTelemetry: true,
|
||||
},
|
||||
logLevel: 'debug',
|
||||
features: {
|
||||
storyStoreV7: false,
|
||||
},
|
||||
framework: {
|
||||
name: '@storybook/react-webpack5',
|
||||
options: {
|
||||
|
@ -2,7 +2,7 @@ import chalk from 'chalk';
|
||||
import { copy, emptyDir, ensureDir } from 'fs-extra';
|
||||
import { dirname, join, relative, resolve } from 'path';
|
||||
import { global } from '@storybook/global';
|
||||
import { deprecate, logger } from '@storybook/node-logger';
|
||||
import { logger } from '@storybook/node-logger';
|
||||
import { getPrecedingUpgrade, telemetry } from '@storybook/telemetry';
|
||||
import type { BuilderOptions, CLIOptions, LoadOptions, Options } from '@storybook/types';
|
||||
import {
|
||||
@ -13,7 +13,6 @@ import {
|
||||
resolveAddonName,
|
||||
} from '@storybook/core-common';
|
||||
|
||||
import dedent from 'ts-dedent';
|
||||
import { outputStats } from './utils/output-stats';
|
||||
import { copyAllStaticFilesRelativeToMain } from './utils/copy-all-static-files';
|
||||
import { getBuilders } from './utils/get-builders';
|
||||
@ -102,13 +101,6 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption
|
||||
presets.apply('docs', {}),
|
||||
]);
|
||||
|
||||
if (features?.storyStoreV7 === false) {
|
||||
deprecate(
|
||||
dedent`storyStoreV6 is deprecated, please migrate to storyStoreV7 instead.
|
||||
- Refer to the migration guide at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storystorev6-and-storiesof-is-deprecated`
|
||||
);
|
||||
}
|
||||
|
||||
const fullOptions: Options = {
|
||||
...options,
|
||||
presets,
|
||||
@ -138,7 +130,7 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption
|
||||
|
||||
let initializedStoryIndexGenerator: Promise<StoryIndexGenerator | undefined> =
|
||||
Promise.resolve(undefined);
|
||||
if ((features?.buildStoriesJson || features?.storyStoreV7) && !options.ignorePreview) {
|
||||
if (!options.ignorePreview) {
|
||||
const workingDir = process.cwd();
|
||||
const directories = {
|
||||
configDir: options.configDir,
|
||||
@ -149,7 +141,6 @@ export async function buildStaticStandalone(options: BuildStaticStandaloneOption
|
||||
...directories,
|
||||
indexers,
|
||||
docs: docsOptions,
|
||||
storyStoreV7: !!features?.storyStoreV7,
|
||||
build,
|
||||
});
|
||||
|
||||
|
@ -5,9 +5,8 @@ import invariant from 'tiny-invariant';
|
||||
import type { Options } from '@storybook/types';
|
||||
|
||||
import { logConfig } from '@storybook/core-common';
|
||||
import { deprecate, logger } from '@storybook/node-logger';
|
||||
import { logger } from '@storybook/node-logger';
|
||||
|
||||
import dedent from 'ts-dedent';
|
||||
import { MissingBuilderError } from '@storybook/core-events/server-errors';
|
||||
import { getMiddleware } from './utils/middleware';
|
||||
import { getServerAddresses } from './utils/server-address';
|
||||
@ -38,13 +37,6 @@ export async function storybookDevServer(options: Options) {
|
||||
getServerChannel(server)
|
||||
);
|
||||
|
||||
if (features?.storyStoreV7 === false) {
|
||||
deprecate(
|
||||
dedent`storyStoreV6 is deprecated, please migrate to storyStoreV7 instead.
|
||||
- Refer to the migration guide at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storystorev6-and-storiesof-is-deprecated`
|
||||
);
|
||||
}
|
||||
|
||||
let indexError: Error | undefined;
|
||||
// try get index generator, if failed, send telemetry without storyCount, then rethrow the error
|
||||
const initializedStoryIndexGenerator: Promise<StoryIndexGenerator | undefined> =
|
||||
|
@ -187,8 +187,6 @@ export const previewAnnotations = async (base: any, options: Options) => {
|
||||
|
||||
export const features: PresetProperty<'features'> = async (existing) => ({
|
||||
...existing,
|
||||
buildStoriesJson: false,
|
||||
storyStoreV7: true,
|
||||
argTypeTargetsV7: true,
|
||||
legacyDecoratorFileOrder: false,
|
||||
disallowImplicitActionsInRenderV8: true,
|
||||
|
@ -43,7 +43,6 @@ const options: StoryIndexGeneratorOptions = {
|
||||
configDir: path.join(__dirname, '__mockdata__'),
|
||||
workingDir: path.join(__dirname, '__mockdata__'),
|
||||
indexers: [csfIndexer],
|
||||
storyStoreV7: true,
|
||||
docs: { defaultName: 'docs', autodocs: false },
|
||||
};
|
||||
|
||||
|
@ -49,7 +49,6 @@ type SpecifierStoriesCache = Record<Path, CacheEntry>;
|
||||
export type StoryIndexGeneratorOptions = {
|
||||
workingDir: Path;
|
||||
configDir: Path;
|
||||
storyStoreV7: boolean;
|
||||
indexers: Indexer[];
|
||||
docs: DocsOptions;
|
||||
build?: StorybookConfigRaw['build'];
|
||||
@ -346,11 +345,6 @@ export class StoryIndexGenerator {
|
||||
async extractDocs(specifier: NormalizedStoriesSpecifier, absolutePath: Path) {
|
||||
const relativePath = path.relative(this.options.workingDir, absolutePath);
|
||||
try {
|
||||
invariant(
|
||||
this.options.storyStoreV7,
|
||||
`You cannot use \`.mdx\` files without using \`storyStoreV7\`.`
|
||||
);
|
||||
|
||||
const normalizedPath = normalizeStoryPath(relativePath);
|
||||
const importPath = slash(normalizedPath);
|
||||
|
||||
@ -530,13 +524,9 @@ export class StoryIndexGenerator {
|
||||
async sortStories(entries: StoryIndex['entries']) {
|
||||
const sortableStories = Object.values(entries);
|
||||
|
||||
// Skip sorting if we're in v6 mode because we don't have
|
||||
// all the info we need here
|
||||
if (this.options.storyStoreV7) {
|
||||
const storySortParameter = await this.getStorySortParameter();
|
||||
const fileNameOrder = this.storyFileNames();
|
||||
sortStoriesV7(sortableStories, storySortParameter, fileNameOrder);
|
||||
}
|
||||
const storySortParameter = await this.getStorySortParameter();
|
||||
const fileNameOrder = this.storyFileNames();
|
||||
sortStoriesV7(sortableStories, storySortParameter, fileNameOrder);
|
||||
|
||||
return sortableStories.reduce((acc, item) => {
|
||||
acc[item.id] = item;
|
||||
|
@ -16,7 +16,6 @@ const options: StoryIndexGeneratorOptions = {
|
||||
configDir: path.join(__dirname, '..', '__mockdata__'),
|
||||
workingDir: path.join(__dirname, '..', '__mockdata__'),
|
||||
indexers: [],
|
||||
storyStoreV7: true,
|
||||
docs: { defaultName: 'docs', autodocs: false },
|
||||
};
|
||||
|
||||
|
@ -7,16 +7,11 @@ import { router } from './router';
|
||||
|
||||
export async function getStoryIndexGenerator(
|
||||
features: {
|
||||
buildStoriesJson?: boolean;
|
||||
storyStoreV7?: boolean;
|
||||
argTypeTargetsV7?: boolean;
|
||||
},
|
||||
options: Options,
|
||||
serverChannel: ServerChannel
|
||||
): Promise<StoryIndexGenerator | undefined> {
|
||||
if (!features?.buildStoriesJson && !features?.storyStoreV7) {
|
||||
return undefined;
|
||||
}
|
||||
const workingDir = process.cwd();
|
||||
const directories = {
|
||||
configDir: options.configDir,
|
||||
@ -32,7 +27,6 @@ export async function getStoryIndexGenerator(
|
||||
indexers: await indexers,
|
||||
docs: await docsOptions,
|
||||
workingDir,
|
||||
storyStoreV7: features.storyStoreV7 ?? false,
|
||||
});
|
||||
|
||||
const initializedStoryIndexGenerator = generator.initialize().then(() => generator);
|
||||
|
@ -45,7 +45,6 @@ const getInitializedStoryIndexGenerator = async (
|
||||
indexers: [csfIndexer],
|
||||
configDir: workingDir,
|
||||
workingDir,
|
||||
storyStoreV7: true,
|
||||
docs: { defaultName: 'docs', autodocs: false },
|
||||
...overrides,
|
||||
};
|
||||
@ -252,35 +251,6 @@ describe('useStoriesJson', () => {
|
||||
`);
|
||||
}, 20_000);
|
||||
|
||||
it('disallows .mdx files without storyStoreV7', async () => {
|
||||
const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;
|
||||
useStoriesJson({
|
||||
router,
|
||||
initializedStoryIndexGenerator: getInitializedStoryIndexGenerator({
|
||||
storyStoreV7: false,
|
||||
}),
|
||||
workingDir,
|
||||
serverChannel: mockServerChannel,
|
||||
normalizedStories,
|
||||
});
|
||||
|
||||
expect(use).toHaveBeenCalledTimes(1);
|
||||
const route = use.mock.calls[0][1];
|
||||
|
||||
await route(request, response);
|
||||
|
||||
expect(send).toHaveBeenCalledTimes(1);
|
||||
expect(send.mock.calls[0][0]).toMatchInlineSnapshot(`
|
||||
"Unable to index files:
|
||||
- ./src/docs2/ComponentReference.mdx: Invariant failed: You cannot use \`.mdx\` files without using \`storyStoreV7\`.
|
||||
- ./src/docs2/MetaOf.mdx: Invariant failed: You cannot use \`.mdx\` files without using \`storyStoreV7\`.
|
||||
- ./src/docs2/NoTitle.mdx: Invariant failed: You cannot use \`.mdx\` files without using \`storyStoreV7\`.
|
||||
- ./src/docs2/SecondMetaOf.mdx: Invariant failed: You cannot use \`.mdx\` files without using \`storyStoreV7\`.
|
||||
- ./src/docs2/Template.mdx: Invariant failed: You cannot use \`.mdx\` files without using \`storyStoreV7\`.
|
||||
- ./src/docs2/Title.mdx: Invariant failed: You cannot use \`.mdx\` files without using \`storyStoreV7\`."
|
||||
`);
|
||||
});
|
||||
|
||||
it('can handle simultaneous access', async () => {
|
||||
const mockServerChannel = { emit: vi.fn() } as any as ServerChannel;
|
||||
|
||||
|
@ -455,8 +455,7 @@ export class CsfFile {
|
||||
throw new Error(dedent`
|
||||
Unexpected \`storiesOf\` usage: ${formatLocation(node, self._fileName)}.
|
||||
|
||||
In SB7, we use the next-generation \`storyStoreV7\` by default, which does not support \`storiesOf\`.
|
||||
More info, with details about how to opt-out here: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storystorev7-enabled-by-default
|
||||
SB8 does not support \`storiesOf\`.
|
||||
`);
|
||||
}
|
||||
},
|
||||
|
@ -450,6 +450,31 @@ export default {
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('storysort satisfies inline', () => {
|
||||
expect(
|
||||
getStorySortParameter(dedent`
|
||||
enum ComponentGroups {
|
||||
General = 'General'
|
||||
}
|
||||
export default {
|
||||
parameters: {
|
||||
options: {
|
||||
storySort: {
|
||||
order: ['General'] satisfies ComponentGroups[]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
`)
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"order": [
|
||||
"General",
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
describe('unsupported', () => {
|
||||
it('bad default export', () => {
|
||||
|
@ -19,7 +19,9 @@ const getValue = (obj: t.ObjectExpression, key: string) => {
|
||||
return value;
|
||||
};
|
||||
|
||||
const parseValue = (expr: t.Expression): any => {
|
||||
const parseValue = (value: t.Expression): any => {
|
||||
const expr = stripTSModifiers(value);
|
||||
|
||||
if (t.isArrayExpression(expr)) {
|
||||
return (expr.elements as t.Expression[]).map((o) => {
|
||||
return parseValue(o);
|
||||
|
@ -58,7 +58,7 @@ import {
|
||||
import type { ComposedRef } from '../index';
|
||||
import type { ModuleFn } from '../lib/types';
|
||||
|
||||
const { FEATURES, fetch } = global;
|
||||
const { fetch } = global;
|
||||
const STORY_INDEX_PATH = './index.json';
|
||||
|
||||
type Direction = -1 | 1;
|
||||
@ -881,10 +881,8 @@ export const init: ModuleFn<SubAPI, SubState> = ({
|
||||
filters: config?.sidebar?.filters || {},
|
||||
},
|
||||
init: async () => {
|
||||
if (FEATURES?.storyStoreV7) {
|
||||
provider.channel?.on(STORY_INDEX_INVALIDATED, () => api.fetchIndex());
|
||||
await api.fetchIndex();
|
||||
}
|
||||
provider.channel?.on(STORY_INDEX_INVALIDATED, () => api.fetchIndex());
|
||||
await api.fetchIndex();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -39,7 +39,6 @@ vi.mock('@storybook/global', () => ({
|
||||
global: {
|
||||
...globalThis,
|
||||
fetch: vi.fn(() => ({ json: () => ({ v: 4, entries: mockGetEntries() }) })),
|
||||
FEATURES: { storyStoreV7: true },
|
||||
CONFIG_TYPE: 'DEVELOPMENT',
|
||||
},
|
||||
}));
|
||||
|
@ -10,34 +10,14 @@ The preview's job is:
|
||||
|
||||
3. Render the current selection to the web view in either story or docs mode.
|
||||
|
||||
## V7 Store vs Legacy (V6)
|
||||
|
||||
The story store is designed to load stories 'on demand', and will operate in this fashion if the `storyStoreV7` feature is enabled.
|
||||
|
||||
However, for back-compat reasons, in v6 mode, we need to load all stories, synchronously on bootup, emitting the `SET_STORIES` event.
|
||||
|
||||
In V7 mode we do not emit that event, instead preferring the `STORY_PREPARED` event, with the data for the single story being rendered.
|
||||
|
||||
## Initialization
|
||||
|
||||
The preview is `initialized` in two ways.
|
||||
|
||||
### V7 Mode:
|
||||
|
||||
- `importFn` - is an async `import()` function
|
||||
|
||||
- `getProjectAnnotations` - is a simple function that evaluations `preview.js` and addon config files and combines them. If it errors, the Preview will show the error.
|
||||
|
||||
- No `getStoryIndex` function is passed, instead the preview creates a `StoryIndexClient` that pulls `stories.json` from node and watches the event stream for invalidation events.
|
||||
|
||||
### V6 Mode
|
||||
|
||||
- `importFn` - is a simulated `import()` function, that is synchronous, see `client-api` for details.
|
||||
- `getProjectAnnotations` - also evaluates `preview.js` et al, but watches for calls to `setStories`, and passes them to the `ClientApi`
|
||||
- `getStoryIndex` is a local function (that must be called _after_ `getProjectAnnotations`) that gets the list of stories added.
|
||||
|
||||
See `client-api` for more details on this process.
|
||||
|
||||
## Story Rendering and interruptions
|
||||
|
||||
The Preview is split into three parts responsible for state management:
|
||||
|
@ -54,7 +54,6 @@
|
||||
"lodash": "^4.17.21",
|
||||
"memoizerific": "^1.11.3",
|
||||
"qs": "^6.10.0",
|
||||
"synchronous-promise": "^2.0.15",
|
||||
"ts-dedent": "^2.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
},
|
||||
|
@ -1,4 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/triple-slash-reference */
|
||||
/// <reference path="typings.d.ts" />
|
||||
|
||||
export * from './modules/client-api';
|
@ -1,4 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/triple-slash-reference */
|
||||
/// <reference path="typings.d.ts" />
|
||||
|
||||
export * from './modules/core-client';
|
@ -41,22 +41,6 @@ export { DocsContext } from './preview-web';
|
||||
*/
|
||||
export { simulatePageLoad, simulateDOMContentLoaded } from './preview-web';
|
||||
|
||||
/**
|
||||
* STORIES API
|
||||
*/
|
||||
export {
|
||||
addArgTypes,
|
||||
addArgTypesEnhancer,
|
||||
addArgs,
|
||||
addArgsEnhancer,
|
||||
addDecorator,
|
||||
addLoader,
|
||||
addParameters,
|
||||
addStepRunner,
|
||||
} from './client-api';
|
||||
export { getQueryParam, getQueryParams } from './client-api';
|
||||
export { setGlobalRender } from './client-api';
|
||||
|
||||
export {
|
||||
combineArgs,
|
||||
combineParameters,
|
||||
@ -83,8 +67,5 @@ export type { PropDescriptor } from './store';
|
||||
/**
|
||||
* STORIES API
|
||||
*/
|
||||
export { ClientApi } from './client-api';
|
||||
export { StoryStore } from './store';
|
||||
export { Preview, PreviewWeb, PreviewWithSelection, UrlStore, WebView } from './preview-web';
|
||||
export type { SelectionStore, View } from './preview-web';
|
||||
export { start } from './core-client';
|
||||
export { Preview, PreviewWeb } from './preview-web';
|
||||
|
@ -1,214 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import { dedent } from 'ts-dedent';
|
||||
import { global } from '@storybook/global';
|
||||
import type {
|
||||
Args,
|
||||
StepRunner,
|
||||
ArgTypes,
|
||||
Renderer,
|
||||
DecoratorFunction,
|
||||
Parameters,
|
||||
ArgTypesEnhancer,
|
||||
ArgsEnhancer,
|
||||
LoaderFunction,
|
||||
Globals,
|
||||
GlobalTypes,
|
||||
Path,
|
||||
ModuleImportFn,
|
||||
ModuleExports,
|
||||
} from '@storybook/types';
|
||||
import type { StoryStore } from '../../store';
|
||||
import { combineParameters, composeStepRunners, normalizeInputTypes } from '../../store';
|
||||
|
||||
import { StoryStoreFacade } from './StoryStoreFacade';
|
||||
|
||||
const warningAlternatives = {
|
||||
addDecorator: `Instead, use \`export const decorators = [];\` in your \`preview.js\`.`,
|
||||
addParameters: `Instead, use \`export const parameters = {};\` in your \`preview.js\`.`,
|
||||
addLoader: `Instead, use \`export const loaders = [];\` in your \`preview.js\`.`,
|
||||
addArgs: '',
|
||||
addArgTypes: '',
|
||||
addArgsEnhancer: '',
|
||||
addArgTypesEnhancer: '',
|
||||
addStepRunner: '',
|
||||
getGlobalRender: '',
|
||||
setGlobalRender: '',
|
||||
};
|
||||
|
||||
const checkMethod = (method: keyof typeof warningAlternatives) => {
|
||||
if (global.FEATURES?.storyStoreV7) {
|
||||
throw new Error(
|
||||
dedent`You cannot use \`${method}\` with the new Story Store.
|
||||
|
||||
${warningAlternatives[method]}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!global.__STORYBOOK_CLIENT_API__) {
|
||||
throw new Error(`Singleton client API not yet initialized, cannot call \`${method}\`.`);
|
||||
}
|
||||
};
|
||||
|
||||
export const addDecorator = (decorator: DecoratorFunction<Renderer>) => {
|
||||
checkMethod('addDecorator');
|
||||
global.__STORYBOOK_CLIENT_API__?.addDecorator(decorator);
|
||||
};
|
||||
|
||||
export const addParameters = (parameters: Parameters) => {
|
||||
checkMethod('addParameters');
|
||||
global.__STORYBOOK_CLIENT_API__?.addParameters(parameters);
|
||||
};
|
||||
|
||||
export const addLoader = (loader: LoaderFunction<Renderer>) => {
|
||||
checkMethod('addLoader');
|
||||
global.__STORYBOOK_CLIENT_API__?.addLoader(loader);
|
||||
};
|
||||
|
||||
export const addArgs = (args: Args) => {
|
||||
checkMethod('addArgs');
|
||||
global.__STORYBOOK_CLIENT_API__?.addArgs(args);
|
||||
};
|
||||
|
||||
export const addArgTypes = (argTypes: ArgTypes) => {
|
||||
checkMethod('addArgTypes');
|
||||
global.__STORYBOOK_CLIENT_API__?.addArgTypes(argTypes);
|
||||
};
|
||||
|
||||
export const addArgsEnhancer = (enhancer: ArgsEnhancer<Renderer>) => {
|
||||
checkMethod('addArgsEnhancer');
|
||||
global.__STORYBOOK_CLIENT_API__?.addArgsEnhancer(enhancer);
|
||||
};
|
||||
|
||||
export const addArgTypesEnhancer = (enhancer: ArgTypesEnhancer<Renderer>) => {
|
||||
checkMethod('addArgTypesEnhancer');
|
||||
global.__STORYBOOK_CLIENT_API__?.addArgTypesEnhancer(enhancer);
|
||||
};
|
||||
|
||||
export const addStepRunner = (stepRunner: StepRunner) => {
|
||||
checkMethod('addStepRunner');
|
||||
global.__STORYBOOK_CLIENT_API__?.addStepRunner(stepRunner);
|
||||
};
|
||||
|
||||
export const getGlobalRender = () => {
|
||||
checkMethod('getGlobalRender');
|
||||
return global.__STORYBOOK_CLIENT_API__?.facade.projectAnnotations.render;
|
||||
};
|
||||
|
||||
export const setGlobalRender = (render: StoryStoreFacade<any>['projectAnnotations']['render']) => {
|
||||
checkMethod('setGlobalRender');
|
||||
if (global.__STORYBOOK_CLIENT_API__) {
|
||||
global.__STORYBOOK_CLIENT_API__.facade.projectAnnotations.render = render;
|
||||
}
|
||||
};
|
||||
|
||||
export class ClientApi<TRenderer extends Renderer> {
|
||||
facade: StoryStoreFacade<TRenderer>;
|
||||
|
||||
storyStore?: StoryStore<TRenderer>;
|
||||
|
||||
onImportFnChanged?: ({ importFn }: { importFn: ModuleImportFn }) => void;
|
||||
|
||||
// If we don't get passed modules so don't know filenames, we can
|
||||
// just use numeric indexes
|
||||
|
||||
constructor({ storyStore }: { storyStore?: StoryStore<TRenderer> } = {}) {
|
||||
this.facade = new StoryStoreFacade();
|
||||
|
||||
this.storyStore = storyStore;
|
||||
}
|
||||
|
||||
importFn(path: Path) {
|
||||
return this.facade.importFn(path);
|
||||
}
|
||||
|
||||
getStoryIndex() {
|
||||
if (!this.storyStore) {
|
||||
throw new Error('Cannot get story index before setting storyStore');
|
||||
}
|
||||
return this.facade.getStoryIndex(this.storyStore);
|
||||
}
|
||||
|
||||
addDecorator = (decorator: DecoratorFunction<TRenderer>) => {
|
||||
this.facade.projectAnnotations.decorators?.push(decorator);
|
||||
};
|
||||
|
||||
addParameters = ({
|
||||
globals,
|
||||
globalTypes,
|
||||
...parameters
|
||||
}: Parameters & { globals?: Globals; globalTypes?: GlobalTypes }) => {
|
||||
this.facade.projectAnnotations.parameters = combineParameters(
|
||||
this.facade.projectAnnotations.parameters,
|
||||
parameters
|
||||
);
|
||||
if (globals) {
|
||||
this.facade.projectAnnotations.globals = {
|
||||
...this.facade.projectAnnotations.globals,
|
||||
...globals,
|
||||
};
|
||||
}
|
||||
if (globalTypes) {
|
||||
this.facade.projectAnnotations.globalTypes = {
|
||||
...this.facade.projectAnnotations.globalTypes,
|
||||
...normalizeInputTypes(globalTypes),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
addStepRunner = (stepRunner: StepRunner<TRenderer>) => {
|
||||
this.facade.projectAnnotations.runStep = composeStepRunners(
|
||||
[this.facade.projectAnnotations.runStep, stepRunner].filter(
|
||||
Boolean
|
||||
) as StepRunner<TRenderer>[]
|
||||
);
|
||||
};
|
||||
|
||||
addLoader = (loader: LoaderFunction<TRenderer>) => {
|
||||
this.facade.projectAnnotations.loaders?.push(loader);
|
||||
};
|
||||
|
||||
addArgs = (args: Args) => {
|
||||
this.facade.projectAnnotations.args = {
|
||||
...this.facade.projectAnnotations.args,
|
||||
...args,
|
||||
};
|
||||
};
|
||||
|
||||
addArgTypes = (argTypes: ArgTypes) => {
|
||||
this.facade.projectAnnotations.argTypes = {
|
||||
...this.facade.projectAnnotations.argTypes,
|
||||
...normalizeInputTypes(argTypes),
|
||||
};
|
||||
};
|
||||
|
||||
addArgsEnhancer = (enhancer: ArgsEnhancer<TRenderer>) => {
|
||||
this.facade.projectAnnotations.argsEnhancers?.push(enhancer);
|
||||
};
|
||||
|
||||
addArgTypesEnhancer = (enhancer: ArgTypesEnhancer<TRenderer>) => {
|
||||
this.facade.projectAnnotations.argTypesEnhancers?.push(enhancer);
|
||||
};
|
||||
|
||||
// Because of the API of `storiesOf().add()` we don't have a good "end" call for a
|
||||
// storiesOf file to finish adding stories, and us to load it into the facade as a
|
||||
// single psuedo-CSF file. So instead we just keep collecting the CSF files and load
|
||||
// them all into the facade at the end.
|
||||
_addedExports = {} as Record<Path, ModuleExports>;
|
||||
|
||||
_loadAddedExports() {
|
||||
Object.entries(this._addedExports).forEach(([fileName, fileExports]) =>
|
||||
this.facade.addStoriesFromExports(fileName, fileExports)
|
||||
);
|
||||
}
|
||||
|
||||
// @deprecated
|
||||
raw = () => {
|
||||
return this.storyStore?.raw();
|
||||
};
|
||||
|
||||
// @deprecated
|
||||
get _storyStore() {
|
||||
return this.storyStore;
|
||||
}
|
||||
}
|
@ -1,256 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import { global } from '@storybook/global';
|
||||
import { dedent } from 'ts-dedent';
|
||||
import { SynchronousPromise } from 'synchronous-promise';
|
||||
import { toId, isExportStory, storyNameFromExport } from '@storybook/csf';
|
||||
import type {
|
||||
IndexEntry,
|
||||
Renderer,
|
||||
ComponentId,
|
||||
DocsOptions,
|
||||
Parameters,
|
||||
Path,
|
||||
ModuleExports,
|
||||
NormalizedProjectAnnotations,
|
||||
NormalizedStoriesSpecifier,
|
||||
PreparedStory,
|
||||
StoryIndex,
|
||||
StoryId,
|
||||
} from '@storybook/types';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
import type { StoryStore } from '../../store';
|
||||
import { userOrAutoTitle, sortStoriesV6 } from '../../store';
|
||||
|
||||
export const AUTODOCS_TAG = 'autodocs';
|
||||
export const STORIES_MDX_TAG = 'stories-mdx';
|
||||
|
||||
export class StoryStoreFacade<TRenderer extends Renderer> {
|
||||
projectAnnotations: NormalizedProjectAnnotations<TRenderer>;
|
||||
|
||||
entries: Record<StoryId, IndexEntry & { componentId?: ComponentId }>;
|
||||
|
||||
csfExports: Record<Path, ModuleExports>;
|
||||
|
||||
constructor() {
|
||||
this.projectAnnotations = {
|
||||
loaders: [],
|
||||
decorators: [],
|
||||
parameters: {},
|
||||
argsEnhancers: [],
|
||||
argTypesEnhancers: [],
|
||||
args: {},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
this.entries = {};
|
||||
|
||||
this.csfExports = {};
|
||||
}
|
||||
|
||||
// This doesn't actually import anything because the client-api loads fully
|
||||
// on startup, but this is a shim after all.
|
||||
importFn(path: Path) {
|
||||
return SynchronousPromise.resolve().then(() => {
|
||||
const moduleExports = this.csfExports[path];
|
||||
if (!moduleExports) throw new Error(`Unknown path: ${path}`);
|
||||
return moduleExports;
|
||||
});
|
||||
}
|
||||
|
||||
getStoryIndex(store: StoryStore<TRenderer>) {
|
||||
const fileNameOrder = Object.keys(this.csfExports);
|
||||
const storySortParameter = this.projectAnnotations.parameters?.options?.storySort;
|
||||
|
||||
const storyEntries = Object.entries(this.entries);
|
||||
// Add the kind parameters and global parameters to each entry
|
||||
const sortableV6 = storyEntries.map(([storyId, { type, importPath, ...entry }]) => {
|
||||
const exports = this.csfExports[importPath];
|
||||
const csfFile = store.processCSFFileWithCache<TRenderer>(
|
||||
exports,
|
||||
importPath,
|
||||
exports.default.title
|
||||
);
|
||||
|
||||
let storyLike: PreparedStory<TRenderer>;
|
||||
if (type === 'story') {
|
||||
storyLike = store.storyFromCSFFile({ storyId, csfFile });
|
||||
} else {
|
||||
storyLike = {
|
||||
...entry,
|
||||
story: entry.name,
|
||||
kind: entry.title,
|
||||
componentId: toId(entry.componentId || entry.title),
|
||||
parameters: { fileName: importPath },
|
||||
} as any;
|
||||
}
|
||||
return [
|
||||
storyId,
|
||||
storyLike,
|
||||
csfFile.meta.parameters,
|
||||
this.projectAnnotations.parameters || {},
|
||||
] as [StoryId, PreparedStory<TRenderer>, Parameters, Parameters];
|
||||
});
|
||||
|
||||
// NOTE: the sortStoriesV6 version returns the v7 data format. confusing but more convenient!
|
||||
let sortedV7: IndexEntry[];
|
||||
|
||||
try {
|
||||
sortedV7 = sortStoriesV6(sortableV6, storySortParameter, fileNameOrder);
|
||||
} catch (err: any) {
|
||||
if (typeof storySortParameter === 'function') {
|
||||
throw new Error(dedent`
|
||||
Error sorting stories with sort parameter ${storySortParameter}:
|
||||
|
||||
> ${err.message}
|
||||
|
||||
Are you using a V7-style sort function in V6 compatibility mode?
|
||||
|
||||
More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#v7-style-story-sort
|
||||
`);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
const entries = sortedV7.reduce((acc, s) => {
|
||||
// We use the original entry we stored in `this.stories` because it is possible that the CSF file itself
|
||||
// exports a `parameters.fileName` which can be different and mess up our `importFn`.
|
||||
// NOTE: this doesn't actually change the story object, just the index.
|
||||
acc[s.id] = this.entries[s.id];
|
||||
return acc;
|
||||
}, {} as StoryIndex['entries']);
|
||||
|
||||
return { v: 4, entries };
|
||||
}
|
||||
|
||||
clearFilenameExports(fileName: Path) {
|
||||
if (!this.csfExports[fileName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear this module's stories from the storyList and existing exports
|
||||
Object.entries(this.entries).forEach(([id, { importPath }]) => {
|
||||
if (importPath === fileName) {
|
||||
delete this.entries[id];
|
||||
}
|
||||
});
|
||||
|
||||
// We keep this as an empty record so we can use it to maintain component order
|
||||
this.csfExports[fileName] = {};
|
||||
}
|
||||
|
||||
// NOTE: we could potentially share some of this code with the stories.json generation
|
||||
addStoriesFromExports(fileName: Path, fileExports: ModuleExports) {
|
||||
if (fileName.match(/\.mdx$/) && !fileName.match(/\.stories\.mdx$/)) {
|
||||
if (global.FEATURES?.storyStoreV7MdxErrors !== false) {
|
||||
throw new Error(dedent`
|
||||
Cannot index \`.mdx\` file (\`${fileName}\`) in \`storyStoreV7: false\` mode.
|
||||
|
||||
The legacy story store does not support new-style \`.mdx\` files. If the file above
|
||||
is not intended to be indexed (i.e. displayed as an entry in the sidebar), either
|
||||
exclude it from your \`stories\` glob, or add <Meta isTemplate /> to it.
|
||||
|
||||
If you wanted to index the file, you'll need to name it \`stories.mdx\` and stick to the
|
||||
legacy (6.x) MDX API, or use the new store.`);
|
||||
}
|
||||
}
|
||||
|
||||
// if the export haven't changed since last time we added them, this is a no-op
|
||||
if (this.csfExports[fileName] === fileExports) {
|
||||
return;
|
||||
}
|
||||
// OTOH, if they have changed, let's clear them out first
|
||||
this.clearFilenameExports(fileName);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { default: defaultExport, __namedExportsOrder, ...namedExports } = fileExports;
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { id: componentId, title, tags: componentTags = [] } = defaultExport || {};
|
||||
|
||||
const specifiers = (global.STORIES || []).map(
|
||||
(specifier: NormalizedStoriesSpecifier & { importPathMatcher: string }) => ({
|
||||
...specifier,
|
||||
importPathMatcher: new RegExp(specifier.importPathMatcher),
|
||||
})
|
||||
);
|
||||
|
||||
title = userOrAutoTitle(fileName, specifiers, title);
|
||||
|
||||
if (!title) {
|
||||
logger.info(
|
||||
`Unexpected default export without title in '${fileName}': ${JSON.stringify(
|
||||
fileExports.default
|
||||
)}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.csfExports[fileName] = {
|
||||
...fileExports,
|
||||
default: { ...defaultExport, title },
|
||||
};
|
||||
|
||||
let sortedExports = namedExports;
|
||||
|
||||
// prefer a user/loader provided `__namedExportsOrder` array if supplied
|
||||
// we do this as es module exports are always ordered alphabetically
|
||||
// see https://github.com/storybookjs/storybook/issues/9136
|
||||
if (Array.isArray(__namedExportsOrder)) {
|
||||
sortedExports = {};
|
||||
__namedExportsOrder.forEach((name) => {
|
||||
const namedExport = namedExports[name];
|
||||
if (namedExport) sortedExports[name] = namedExport;
|
||||
});
|
||||
}
|
||||
|
||||
const storyExports = Object.entries(sortedExports).filter(([key]) =>
|
||||
isExportStory(key, defaultExport)
|
||||
);
|
||||
|
||||
// NOTE: this logic is equivalent to the `extractStories` function of `StoryIndexGenerator`
|
||||
const docsOptions = (global.DOCS_OPTIONS || {}) as DocsOptions;
|
||||
const { autodocs } = docsOptions;
|
||||
const componentAutodocs = componentTags.includes(AUTODOCS_TAG);
|
||||
const autodocsOptedIn = autodocs === true || (autodocs === 'tag' && componentAutodocs);
|
||||
if (storyExports.length) {
|
||||
if (componentTags.includes(STORIES_MDX_TAG) || autodocsOptedIn) {
|
||||
const name = docsOptions.defaultName;
|
||||
const docsId = toId(componentId || title, name);
|
||||
this.entries[docsId] = {
|
||||
type: 'docs',
|
||||
id: docsId,
|
||||
title,
|
||||
name,
|
||||
importPath: fileName,
|
||||
...(componentId && { componentId }),
|
||||
tags: [
|
||||
...componentTags,
|
||||
'docs',
|
||||
...(autodocsOptedIn && !componentAutodocs ? [AUTODOCS_TAG] : []),
|
||||
],
|
||||
storiesImports: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
storyExports.forEach(([key, storyExport]: [string, any]) => {
|
||||
const exportName = storyNameFromExport(key);
|
||||
const id = storyExport.parameters?.__id || toId(componentId || title, exportName);
|
||||
const name =
|
||||
(typeof storyExport !== 'function' && storyExport.name) ||
|
||||
storyExport.storyName ||
|
||||
storyExport.story?.name ||
|
||||
exportName;
|
||||
|
||||
if (!storyExport.parameters?.docsOnly) {
|
||||
this.entries[id] = {
|
||||
type: 'story',
|
||||
id,
|
||||
name,
|
||||
title,
|
||||
importPath: fileName,
|
||||
...(componentId && { componentId }),
|
||||
tags: [...(storyExport.tags || componentTags), 'story'],
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
export {
|
||||
addArgs,
|
||||
addArgsEnhancer,
|
||||
addArgTypes,
|
||||
addArgTypesEnhancer,
|
||||
addDecorator,
|
||||
addLoader,
|
||||
addParameters,
|
||||
addStepRunner,
|
||||
ClientApi,
|
||||
setGlobalRender,
|
||||
} from './ClientApi';
|
||||
|
||||
export * from '../../store';
|
||||
|
||||
export * from './queryparams';
|
@ -1,17 +0,0 @@
|
||||
import { global } from '@storybook/global';
|
||||
import { parse } from 'qs';
|
||||
|
||||
export const getQueryParams = () => {
|
||||
const { document } = global;
|
||||
// document.location is not defined in react-native
|
||||
if (document && document.location && document.location.search) {
|
||||
return parse(document.location.search, { ignoreQueryPrefix: true });
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
export const getQueryParam = (key: string) => {
|
||||
const params = getQueryParams();
|
||||
|
||||
return params[key];
|
||||
};
|
@ -1,110 +0,0 @@
|
||||
/// <reference types="node" />
|
||||
/// <reference types="webpack-env" />
|
||||
|
||||
import { logger } from '@storybook/client-logger';
|
||||
import type { Path, ModuleExports } from '@storybook/types';
|
||||
|
||||
export interface RequireContext {
|
||||
keys: () => string[];
|
||||
(id: string): any;
|
||||
resolve(id: string): string;
|
||||
}
|
||||
|
||||
export type LoaderFunction = () => void | any[];
|
||||
|
||||
export type Loadable = RequireContext | RequireContext[] | LoaderFunction;
|
||||
|
||||
/**
|
||||
* Executes a Loadable (function that returns exports or require context(s))
|
||||
* and returns a map of filename => module exports
|
||||
*
|
||||
* @param loadable Loadable
|
||||
* @returns Map<Path, ModuleExports>
|
||||
*/
|
||||
export function executeLoadable(loadable: Loadable) {
|
||||
let reqs = null;
|
||||
// todo discuss / improve type check
|
||||
if (Array.isArray(loadable)) {
|
||||
reqs = loadable;
|
||||
} else if ((loadable as RequireContext).keys) {
|
||||
reqs = [loadable as RequireContext];
|
||||
}
|
||||
|
||||
let exportsMap = new Map<Path, ModuleExports>();
|
||||
if (reqs) {
|
||||
reqs.forEach((req) => {
|
||||
req.keys().forEach((filename: string) => {
|
||||
try {
|
||||
const fileExports = req(filename) as ModuleExports;
|
||||
exportsMap.set(
|
||||
typeof req.resolve === 'function' ? req.resolve(filename) : filename,
|
||||
fileExports
|
||||
);
|
||||
} catch (error: any) {
|
||||
const errorString =
|
||||
error.message && error.stack ? `${error.message}\n ${error.stack}` : error.toString();
|
||||
logger.error(`Unexpected error while loading ${filename}: ${errorString}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const exported = (loadable as LoaderFunction)();
|
||||
if (Array.isArray(exported) && exported.every((obj) => obj.default != null)) {
|
||||
exportsMap = new Map(
|
||||
exported.map((fileExports, index) => [`exports-map-${index}`, fileExports])
|
||||
);
|
||||
} else if (exported) {
|
||||
logger.warn(
|
||||
`Loader function passed to 'configure' should return void or an array of module exports that all contain a 'default' export. Received: ${JSON.stringify(
|
||||
exported
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return exportsMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a Loadable (function that returns exports or require context(s))
|
||||
* and compares it's output to the last time it was run (as stored on a node module)
|
||||
*
|
||||
* @param loadable Loadable
|
||||
* @param m NodeModule
|
||||
* @returns { added: Map<Path, ModuleExports>, removed: Map<Path, ModuleExports> }
|
||||
*/
|
||||
export function executeLoadableForChanges(loadable: Loadable, m?: NodeModule) {
|
||||
let lastExportsMap: ReturnType<typeof executeLoadable> =
|
||||
m?.hot?.data?.lastExportsMap || new Map();
|
||||
if (m?.hot?.dispose) {
|
||||
m.hot.accept();
|
||||
m.hot.dispose((data) => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
data.lastExportsMap = lastExportsMap;
|
||||
});
|
||||
}
|
||||
|
||||
const exportsMap = executeLoadable(loadable);
|
||||
const added = new Map<Path, ModuleExports>();
|
||||
Array.from(exportsMap.entries())
|
||||
// Ignore files that do not have a default export
|
||||
.filter(([, fileExports]) => !!fileExports.default)
|
||||
// Ignore exports that are equal (by reference) to last time, this means the file hasn't changed
|
||||
.filter(([fileName, fileExports]) => lastExportsMap.get(fileName) !== fileExports)
|
||||
.forEach(([fileName, fileExports]) => added.set(fileName, fileExports));
|
||||
|
||||
const removed = new Map<Path, ModuleExports>();
|
||||
Array.from(lastExportsMap.keys())
|
||||
.filter((fileName) => !exportsMap.has(fileName))
|
||||
.forEach((fileName) => {
|
||||
const value = lastExportsMap.get(fileName);
|
||||
if (value) {
|
||||
removed.set(fileName, value);
|
||||
}
|
||||
});
|
||||
|
||||
// Save the value for the dispose() call above
|
||||
lastExportsMap = exportsMap;
|
||||
|
||||
return { added, removed };
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import { ClientApi } from '../../client-api';
|
||||
import { StoryStore } from '../../store';
|
||||
import { start } from './start';
|
||||
|
||||
export { start, ClientApi, StoryStore };
|
@ -1,627 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
/**
|
||||
* @vitest-environment jsdom
|
||||
*/
|
||||
import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest';
|
||||
import { STORY_RENDERED, STORY_UNCHANGED, SET_INDEX, CONFIG_ERROR } from '@storybook/core-events';
|
||||
|
||||
import type { ModuleExports, Path } from '@storybook/types';
|
||||
import { global } from '@storybook/global';
|
||||
import { setGlobalRender } from '../../client-api';
|
||||
import {
|
||||
waitForRender,
|
||||
waitForEvents,
|
||||
waitForQuiescence,
|
||||
emitter,
|
||||
mockChannel,
|
||||
} from '../preview-web/PreviewWeb.mockdata';
|
||||
|
||||
import { start as realStart } from './start';
|
||||
import type { Loadable } from './executeLoadable';
|
||||
|
||||
vi.mock('@storybook/global', () => ({
|
||||
global: {
|
||||
...globalThis,
|
||||
window: globalThis,
|
||||
history: { replaceState: vi.fn() },
|
||||
document: {
|
||||
location: {
|
||||
pathname: 'pathname',
|
||||
search: '?id=*',
|
||||
},
|
||||
},
|
||||
DOCS_OPTIONS: {},
|
||||
},
|
||||
}));
|
||||
|
||||
// console.log(global);
|
||||
|
||||
vi.mock('@storybook/channels', () => ({
|
||||
createBrowserChannel: () => mockChannel,
|
||||
}));
|
||||
vi.mock('@storybook/client-logger');
|
||||
vi.mock('react-dom');
|
||||
|
||||
// for the auto-title test
|
||||
vi.mock('../../store', async (importOriginal) => {
|
||||
return {
|
||||
...(await importOriginal<typeof import('../../store')>()),
|
||||
userOrAutoTitle: (importPath: Path, specifier: any, userTitle?: string) =>
|
||||
userTitle || 'auto-title',
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../../preview-web', async (importOriginal) => {
|
||||
const actualPreviewWeb = await importOriginal<typeof import('../../preview-web')>();
|
||||
|
||||
class OverloadPreviewWeb extends actualPreviewWeb.PreviewWeb<any> {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// @ts-expect-error (incomplete)
|
||||
this.view = {
|
||||
...Object.fromEntries(
|
||||
Object.getOwnPropertyNames(this.view.constructor.prototype).map((key) => [key, vi.fn()])
|
||||
),
|
||||
prepareForDocs: vi.fn().mockReturnValue('docs-root'),
|
||||
prepareForStory: vi.fn().mockReturnValue('story-root'),
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
...actualPreviewWeb,
|
||||
PreviewWeb: OverloadPreviewWeb,
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockChannel.emit.mockClear();
|
||||
// Preview doesn't clean itself up as it isn't designed to ever be stopped :shrug:
|
||||
emitter.removeAllListeners();
|
||||
});
|
||||
|
||||
const start: typeof realStart = (...args) => {
|
||||
const result = realStart(...args);
|
||||
|
||||
const configure: typeof result['configure'] = (
|
||||
framework: string,
|
||||
loadable: Loadable,
|
||||
m?: NodeModule,
|
||||
disableBackwardCompatibility = false
|
||||
) => result.configure(framework, loadable, m, disableBackwardCompatibility);
|
||||
|
||||
return {
|
||||
...result,
|
||||
configure,
|
||||
};
|
||||
};
|
||||
afterEach(() => {
|
||||
// I'm not sure why this is required (it seems just afterEach is required really)
|
||||
mockChannel.emit.mockClear();
|
||||
});
|
||||
|
||||
function makeRequireContext(importMap: Record<Path, ModuleExports>) {
|
||||
const req = (path: Path) => importMap[path];
|
||||
req.keys = () => Object.keys(importMap);
|
||||
return req;
|
||||
}
|
||||
|
||||
describe('start', () => {
|
||||
beforeEach(() => {
|
||||
global.DOCS_OPTIONS = {};
|
||||
// @ts-expect-error (setting this to undefined is indeed what we want to do)
|
||||
global.__STORYBOOK_CLIENT_API__ = undefined;
|
||||
// @ts-expect-error (setting this to undefined is indeed what we want to do)
|
||||
global.__STORYBOOK_PREVIEW__ = undefined;
|
||||
// @ts-expect-error (setting this to undefined is indeed what we want to do)
|
||||
global.IS_STORYBOOK = undefined;
|
||||
});
|
||||
|
||||
const componentCExports = {
|
||||
default: {
|
||||
title: 'Component C',
|
||||
tags: ['component-tag', 'autodocs'],
|
||||
},
|
||||
StoryOne: {
|
||||
render: vi.fn(),
|
||||
tags: ['story-tag'],
|
||||
},
|
||||
StoryTwo: vi.fn(),
|
||||
};
|
||||
|
||||
describe('when configure is called with CSF only', () => {
|
||||
it('loads and renders the first story correctly', async () => {
|
||||
const renderToCanvas = vi.fn();
|
||||
|
||||
const { configure } = start(renderToCanvas);
|
||||
configure('test', () => [componentCExports]);
|
||||
|
||||
await waitForRender();
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"component-c--story-one": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-one",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story One",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"story-tag",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
"component-c--story-two": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-two",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story Two",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"component-tag",
|
||||
"autodocs",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
|
||||
await waitForRender();
|
||||
expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-c--story-one');
|
||||
|
||||
expect(renderToCanvas).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
id: 'component-c--story-one',
|
||||
}),
|
||||
'story-root'
|
||||
);
|
||||
});
|
||||
|
||||
it('supports HMR when a story file changes', async () => {
|
||||
const renderToCanvas = vi.fn(({ storyFn }) => storyFn());
|
||||
|
||||
let disposeCallback: (data: object) => void = () => {};
|
||||
const module = {
|
||||
id: 'file1',
|
||||
hot: {
|
||||
data: {},
|
||||
accept: vi.fn(),
|
||||
dispose(cb: () => void) {
|
||||
disposeCallback = cb;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { configure } = start(renderToCanvas);
|
||||
configure('test', () => [componentCExports], module as any);
|
||||
|
||||
await waitForRender();
|
||||
expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-c--story-one');
|
||||
expect(componentCExports.StoryOne.render).toHaveBeenCalled();
|
||||
expect(module.hot.accept).toHaveBeenCalled();
|
||||
expect(disposeCallback).toBeDefined();
|
||||
|
||||
mockChannel.emit.mockClear();
|
||||
disposeCallback(module.hot.data);
|
||||
const secondImplementation = vi.fn();
|
||||
configure(
|
||||
'test',
|
||||
() => [{ ...componentCExports, StoryOne: secondImplementation }],
|
||||
module as any
|
||||
);
|
||||
|
||||
await waitForRender();
|
||||
expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-c--story-one');
|
||||
expect(secondImplementation).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('re-emits SET_INDEX when a story is added', async () => {
|
||||
const renderToCanvas = vi.fn(({ storyFn }) => storyFn());
|
||||
|
||||
let disposeCallback: (data: object) => void = () => {};
|
||||
const module = {
|
||||
id: 'file1',
|
||||
hot: {
|
||||
data: {},
|
||||
accept: vi.fn(),
|
||||
dispose(cb: () => void) {
|
||||
disposeCallback = cb;
|
||||
},
|
||||
},
|
||||
};
|
||||
const { configure } = start(renderToCanvas);
|
||||
configure('test', () => [componentCExports], module as any);
|
||||
|
||||
await waitForRender();
|
||||
|
||||
mockChannel.emit.mockClear();
|
||||
disposeCallback(module.hot.data);
|
||||
configure('test', () => [{ ...componentCExports, StoryThree: vi.fn() }], module as any);
|
||||
|
||||
await waitForEvents([SET_INDEX]);
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"component-c--story-one": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-one",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story One",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"story-tag",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
"component-c--story-three": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-three",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story Three",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"component-tag",
|
||||
"autodocs",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
"component-c--story-two": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-two",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story Two",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"component-tag",
|
||||
"autodocs",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('re-emits SET_INDEX when a story file is removed', async () => {
|
||||
const renderToCanvas = vi.fn(({ storyFn }) => storyFn());
|
||||
|
||||
let disposeCallback: (data: object) => void = () => {};
|
||||
const module = {
|
||||
id: 'file1',
|
||||
hot: {
|
||||
data: {},
|
||||
accept: vi.fn(),
|
||||
dispose(cb: () => void) {
|
||||
disposeCallback = cb;
|
||||
},
|
||||
},
|
||||
};
|
||||
const { configure } = start(renderToCanvas);
|
||||
configure(
|
||||
'test',
|
||||
() => [componentCExports, { default: { title: 'Component D' }, StoryFour: vi.fn() }],
|
||||
module as any
|
||||
);
|
||||
|
||||
await waitForEvents([SET_INDEX]);
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"component-c--story-one": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-one",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story One",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"story-tag",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
"component-c--story-two": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-two",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story Two",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"component-tag",
|
||||
"autodocs",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
"component-d--story-four": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-d--story-four",
|
||||
"importPath": "exports-map-1",
|
||||
"initialArgs": {},
|
||||
"name": "Story Four",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-1",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"story",
|
||||
],
|
||||
"title": "Component D",
|
||||
"type": "story",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
await waitForRender();
|
||||
|
||||
mockChannel.emit.mockClear();
|
||||
disposeCallback(module.hot.data);
|
||||
configure('test', () => [componentCExports], module as any);
|
||||
|
||||
await waitForEvents([SET_INDEX]);
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"component-c--story-one": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-one",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story One",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"story-tag",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
"component-c--story-two": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "component-c--story-two",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story Two",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"component-tag",
|
||||
"autodocs",
|
||||
"story",
|
||||
],
|
||||
"title": "Component C",
|
||||
"type": "story",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
|
||||
await waitForEvents([STORY_UNCHANGED]);
|
||||
});
|
||||
|
||||
it('allows you to override the render function in project annotations', async () => {
|
||||
const renderToCanvas = vi.fn(({ storyFn }) => storyFn());
|
||||
const frameworkRender = vi.fn();
|
||||
|
||||
const { configure } = start(renderToCanvas, { render: frameworkRender });
|
||||
|
||||
const projectRender = vi.fn();
|
||||
setGlobalRender(projectRender);
|
||||
configure('test', () => {
|
||||
return [
|
||||
{
|
||||
default: {
|
||||
title: 'Component A',
|
||||
component: vi.fn(),
|
||||
},
|
||||
StoryOne: {},
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
await waitForRender();
|
||||
expect(mockChannel.emit).toHaveBeenCalledWith(STORY_RENDERED, 'component-a--story-one');
|
||||
|
||||
expect(frameworkRender).not.toHaveBeenCalled();
|
||||
expect(projectRender).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('docs', () => {
|
||||
beforeEach(() => {
|
||||
global.DOCS_OPTIONS = {};
|
||||
});
|
||||
|
||||
// NOTE: MDX files are only ever passed as CSF
|
||||
it('sends over docs only stories as entries', async () => {
|
||||
const renderToCanvas = vi.fn();
|
||||
|
||||
const { configure } = start(renderToCanvas);
|
||||
|
||||
configure(
|
||||
'test',
|
||||
makeRequireContext({
|
||||
'./Introduction.stories.mdx': {
|
||||
default: { title: 'Introduction', tags: ['stories-mdx'] },
|
||||
_Page: { name: 'Page', parameters: { docsOnly: true } },
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
await waitForEvents([SET_INDEX]);
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"introduction": {
|
||||
"id": "introduction",
|
||||
"importPath": "./Introduction.stories.mdx",
|
||||
"name": undefined,
|
||||
"parameters": {
|
||||
"fileName": "./Introduction.stories.mdx",
|
||||
"renderer": "test",
|
||||
},
|
||||
"storiesImports": [],
|
||||
"tags": [
|
||||
"stories-mdx",
|
||||
"docs",
|
||||
],
|
||||
"title": "Introduction",
|
||||
"type": "docs",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
|
||||
// Wait a second to let the docs "render" finish (and maybe throw)
|
||||
await waitForQuiescence();
|
||||
});
|
||||
|
||||
it('errors on .mdx files', async () => {
|
||||
const renderToCanvas = vi.fn();
|
||||
|
||||
const { configure } = start(renderToCanvas);
|
||||
|
||||
configure(
|
||||
'test',
|
||||
makeRequireContext({
|
||||
'./Introduction.mdx': {
|
||||
default: () => 'some mdx function',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
await waitForEvents([CONFIG_ERROR]);
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === CONFIG_ERROR)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
[Error: Cannot index \`.mdx\` file (\`./Introduction.mdx\`) in \`storyStoreV7: false\` mode.
|
||||
|
||||
The legacy story store does not support new-style \`.mdx\` files. If the file above
|
||||
is not intended to be indexed (i.e. displayed as an entry in the sidebar), either
|
||||
exclude it from your \`stories\` glob, or add <Meta isTemplate /> to it.
|
||||
|
||||
If you wanted to index the file, you'll need to name it \`stories.mdx\` and stick to the
|
||||
legacy (6.x) MDX API, or use the new store.]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('auto-title', () => {
|
||||
const componentDExports = {
|
||||
default: {
|
||||
component: 'Component D',
|
||||
},
|
||||
StoryOne: vi.fn(),
|
||||
};
|
||||
it('loads and renders the first story correctly', async () => {
|
||||
const renderToCanvas = vi.fn();
|
||||
|
||||
const { configure } = start(renderToCanvas);
|
||||
configure('test', () => [componentDExports]);
|
||||
|
||||
await waitForEvents([SET_INDEX]);
|
||||
expect(mockChannel.emit.mock.calls.find((call) => call[0] === SET_INDEX)?.[1])
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"auto-title--story-one": {
|
||||
"argTypes": {},
|
||||
"args": {},
|
||||
"id": "auto-title--story-one",
|
||||
"importPath": "exports-map-0",
|
||||
"initialArgs": {},
|
||||
"name": "Story One",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "exports-map-0",
|
||||
"renderer": "test",
|
||||
},
|
||||
"tags": [
|
||||
"story",
|
||||
],
|
||||
"title": "auto-title",
|
||||
"type": "story",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
|
||||
await waitForRender();
|
||||
});
|
||||
});
|
||||
});
|
@ -1,170 +0,0 @@
|
||||
/* eslint-disable no-underscore-dangle, @typescript-eslint/naming-convention */
|
||||
import { global } from '@storybook/global';
|
||||
import type { Renderer, ArgsStoryFn, Path, ProjectAnnotations } from '@storybook/types';
|
||||
import { createBrowserChannel } from '@storybook/channels';
|
||||
import { FORCE_RE_RENDER } from '@storybook/core-events';
|
||||
import { addons } from '../../addons';
|
||||
import { PreviewWeb } from '../../preview-web';
|
||||
import { ClientApi } from '../../client-api';
|
||||
|
||||
import { executeLoadableForChanges } from './executeLoadable';
|
||||
import type { Loadable } from './executeLoadable';
|
||||
|
||||
const { FEATURES } = global;
|
||||
|
||||
const removedApi = (name: string) => () => {
|
||||
throw new Error(`@storybook/client-api:${name} was removed in storyStoreV7.`);
|
||||
};
|
||||
|
||||
interface CoreClient_RendererImplementation<TRenderer extends Renderer> {
|
||||
/**
|
||||
* A function that applies decorators to a story.
|
||||
* @template TRenderer The type of renderer used by the Storybook client API.
|
||||
* @type {ProjectAnnotations<TRenderer>['applyDecorators']}
|
||||
*/
|
||||
decorateStory?: ProjectAnnotations<TRenderer>['applyDecorators'];
|
||||
/**
|
||||
* A function that renders a story with args.
|
||||
* @template TRenderer The type of renderer used by the Storybook client API.
|
||||
* @type {ArgsStoryFn<TRenderer>}
|
||||
*/
|
||||
render?: ArgsStoryFn<TRenderer>;
|
||||
}
|
||||
|
||||
interface CoreClient_ClientAPIFacade {
|
||||
/**
|
||||
* The old way of retrieving the list of stories at runtime.
|
||||
* @deprecated This method is deprecated and will be removed in a future version.
|
||||
*/
|
||||
raw: (...args: any[]) => never;
|
||||
}
|
||||
|
||||
interface CoreClient_StartReturnValue<TRenderer extends Renderer> {
|
||||
/**
|
||||
* Forces a re-render of all stories in the Storybook preview.
|
||||
* This function emits the `FORCE_RE_RENDER` event to the Storybook channel.
|
||||
* @deprecated This method is deprecated and will be removed in a future version.
|
||||
* @returns {void}
|
||||
*/
|
||||
forceReRender: () => void;
|
||||
/**
|
||||
* The old way of setting up storybook with runtime configuration.
|
||||
* @deprecated This method is deprecated and will be removed in a future version.
|
||||
* @returns {void}
|
||||
*/
|
||||
configure: any;
|
||||
/**
|
||||
* @deprecated This property is deprecated and will be removed in a future version.
|
||||
* @type {ClientApi<TRenderer> | CoreClient_ClientAPIFacade}
|
||||
*/
|
||||
clientApi: ClientApi<TRenderer> | CoreClient_ClientAPIFacade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the Storybook preview API.
|
||||
* @template TRenderer The type of renderer used by the Storybook client API.
|
||||
* @param {ProjectAnnotations<TRenderer>['renderToCanvas']} renderToCanvas A function that renders a story to a canvas.
|
||||
* @param {CoreClient_RendererImplementation<TRenderer>} [options] Optional configuration options for the renderer implementation.
|
||||
* @param {ProjectAnnotations<TRenderer>['applyDecorators']} [options.decorateStory] A function that applies decorators to a story.
|
||||
* @param {ArgsStoryFn<TRenderer>} [options.render] A function that renders a story with arguments.
|
||||
* @returns {CoreClient_StartReturnValue<TRenderer>} An object containing functions and objects related to the Storybook preview API.
|
||||
*/
|
||||
export function start<TRenderer extends Renderer>(
|
||||
renderToCanvas: ProjectAnnotations<TRenderer>['renderToCanvas'],
|
||||
{ decorateStory, render }: CoreClient_RendererImplementation<TRenderer> = {}
|
||||
): CoreClient_StartReturnValue<TRenderer> {
|
||||
if (global) {
|
||||
// To enable user code to detect if it is running in Storybook
|
||||
global.IS_STORYBOOK = true;
|
||||
}
|
||||
|
||||
if (FEATURES?.storyStoreV7) {
|
||||
return {
|
||||
forceReRender: removedApi('forceReRender'),
|
||||
configure: removedApi('configure'),
|
||||
clientApi: {
|
||||
raw: removedApi('raw'),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const channel = createBrowserChannel({ page: 'preview' });
|
||||
addons.setChannel(channel);
|
||||
|
||||
const clientApi = global?.__STORYBOOK_CLIENT_API__ || new ClientApi<TRenderer>();
|
||||
const preview = global?.__STORYBOOK_PREVIEW__ || new PreviewWeb<TRenderer>();
|
||||
let initialized = false;
|
||||
|
||||
const importFn = (path: Path) => clientApi.importFn(path);
|
||||
function onStoriesChanged() {
|
||||
const storyIndex = clientApi.getStoryIndex();
|
||||
preview.onStoriesChanged({ storyIndex, importFn });
|
||||
}
|
||||
|
||||
// These two bits are a bit ugly, but due to dependencies, `ClientApi` cannot have
|
||||
// direct reference to `PreviewWeb`, so we need to patch in bits
|
||||
clientApi.onImportFnChanged = onStoriesChanged;
|
||||
clientApi.storyStore = preview.storyStore;
|
||||
|
||||
if (global) {
|
||||
global.__STORYBOOK_CLIENT_API__ = clientApi;
|
||||
global.__STORYBOOK_ADDONS_CHANNEL__ = channel;
|
||||
global.__STORYBOOK_PREVIEW__ = preview;
|
||||
global.__STORYBOOK_STORY_STORE__ = preview.storyStore;
|
||||
}
|
||||
|
||||
return {
|
||||
forceReRender: () => channel.emit(FORCE_RE_RENDER),
|
||||
|
||||
clientApi,
|
||||
// This gets called each time the user calls configure (i.e. once per HMR)
|
||||
// The first time, it constructs the preview, subsequently it updates it
|
||||
configure(
|
||||
renderer: string,
|
||||
loadable: Loadable,
|
||||
m?: NodeModule,
|
||||
disableBackwardCompatibility = true
|
||||
) {
|
||||
if (disableBackwardCompatibility) {
|
||||
throw new Error('unexpected configure() call');
|
||||
}
|
||||
|
||||
clientApi.addParameters({ renderer });
|
||||
|
||||
// We need to run the `executeLoadableForChanges` function *inside* the `getProjectAnnotations
|
||||
// function in case it throws. So we also need to process its output there also
|
||||
const getProjectAnnotations = () => {
|
||||
const { added, removed } = executeLoadableForChanges(loadable, m);
|
||||
clientApi._loadAddedExports();
|
||||
|
||||
Array.from(added.entries()).forEach(([fileName, fileExports]) =>
|
||||
clientApi.facade.addStoriesFromExports(fileName, fileExports)
|
||||
);
|
||||
|
||||
Array.from(removed.entries()).forEach(([fileName]) =>
|
||||
clientApi.facade.clearFilenameExports(fileName)
|
||||
);
|
||||
|
||||
return {
|
||||
render,
|
||||
...clientApi.facade.projectAnnotations,
|
||||
renderToCanvas,
|
||||
applyDecorators: decorateStory,
|
||||
};
|
||||
};
|
||||
|
||||
if (!initialized) {
|
||||
preview.initialize({
|
||||
getStoryIndex: () => clientApi.getStoryIndex(),
|
||||
importFn,
|
||||
getProjectAnnotations,
|
||||
});
|
||||
initialized = true;
|
||||
} else {
|
||||
// TODO -- why don't we care about the new annotations?
|
||||
getProjectAnnotations();
|
||||
onStoriesChanged();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { dedent } from 'ts-dedent';
|
||||
import { global } from '@storybook/global';
|
||||
import { SynchronousPromise } from 'synchronous-promise';
|
||||
import {
|
||||
CONFIG_ERROR,
|
||||
FORCE_REMOUNT,
|
||||
@ -13,7 +12,7 @@ import {
|
||||
UPDATE_GLOBALS,
|
||||
UPDATE_STORY_ARGS,
|
||||
} from '@storybook/core-events';
|
||||
import { logger, deprecate } from '@storybook/client-logger';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
import type { Channel } from '@storybook/channels';
|
||||
import type {
|
||||
Renderer,
|
||||
@ -61,21 +60,14 @@ export class Preview<TRenderer extends Renderer> {
|
||||
previewEntryError?: Error;
|
||||
|
||||
constructor(protected channel: Channel = addons.getChannel()) {
|
||||
if (global.FEATURES?.storyStoreV7 && addons.hasServerChannel()) {
|
||||
if (addons.hasServerChannel()) {
|
||||
this.serverChannel = addons.getServerChannel();
|
||||
}
|
||||
this.storyStore = new StoryStore();
|
||||
}
|
||||
|
||||
// INITIALIZATION
|
||||
|
||||
// NOTE: the reason that the preview and store's initialization code is written in a promise
|
||||
// style and not `async-await`, and the use of `SynchronousPromise`s is in order to allow
|
||||
// storyshots to immediately call `raw()` on the store without waiting for a later tick.
|
||||
// (Even simple things like `Promise.resolve()` and `await` involve the callback happening
|
||||
// in the next promise "tick").
|
||||
// See the comment in `storyshots-core/src/api/index.ts` for more detail.
|
||||
initialize({
|
||||
async initialize({
|
||||
getStoryIndex,
|
||||
importFn,
|
||||
getProjectAnnotations,
|
||||
@ -93,9 +85,8 @@ export class Preview<TRenderer extends Renderer> {
|
||||
|
||||
this.setupListeners();
|
||||
|
||||
return this.getProjectAnnotationsOrRenderError(getProjectAnnotations).then(
|
||||
(projectAnnotations) => this.initializeWithProjectAnnotations(projectAnnotations)
|
||||
);
|
||||
const projectAnnotations = await this.getProjectAnnotationsOrRenderError(getProjectAnnotations);
|
||||
return this.initializeWithProjectAnnotations(projectAnnotations);
|
||||
}
|
||||
|
||||
setupListeners() {
|
||||
@ -107,57 +98,44 @@ export class Preview<TRenderer extends Renderer> {
|
||||
this.channel.on(FORCE_REMOUNT, this.onForceRemount.bind(this));
|
||||
}
|
||||
|
||||
getProjectAnnotationsOrRenderError(
|
||||
async getProjectAnnotationsOrRenderError(
|
||||
getProjectAnnotations: () => MaybePromise<ProjectAnnotations<TRenderer>>
|
||||
): Promise<ProjectAnnotations<TRenderer>> {
|
||||
return SynchronousPromise.resolve()
|
||||
.then(getProjectAnnotations)
|
||||
.then((projectAnnotations) => {
|
||||
if (projectAnnotations.renderToDOM)
|
||||
deprecate(`\`renderToDOM\` is deprecated, please rename to \`renderToCanvas\``);
|
||||
try {
|
||||
const projectAnnotations = await getProjectAnnotations();
|
||||
|
||||
this.renderToCanvas = projectAnnotations.renderToCanvas || projectAnnotations.renderToDOM;
|
||||
if (!this.renderToCanvas) {
|
||||
throw new Error(dedent`
|
||||
this.renderToCanvas = projectAnnotations.renderToCanvas;
|
||||
if (!this.renderToCanvas) {
|
||||
throw new Error(dedent`
|
||||
Expected your framework's preset to export a \`renderToCanvas\` field.
|
||||
|
||||
Perhaps it needs to be upgraded for Storybook 6.4?
|
||||
|
||||
More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-framework-field
|
||||
`);
|
||||
}
|
||||
return projectAnnotations;
|
||||
})
|
||||
.catch((err) => {
|
||||
// This is an error extracting the projectAnnotations (i.e. evaluating the previewEntries) and
|
||||
// needs to be show to the user as a simple error
|
||||
this.renderPreviewEntryError('Error reading preview.js:', err);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
return projectAnnotations;
|
||||
} catch (err) {
|
||||
// This is an error extracting the projectAnnotations (i.e. evaluating the previewEntries) and
|
||||
// needs to be show to the user as a simple error
|
||||
this.renderPreviewEntryError('Error reading preview.js:', err as Error);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// If initialization gets as far as project annotations, this function runs.
|
||||
initializeWithProjectAnnotations(projectAnnotations: ProjectAnnotations<TRenderer>) {
|
||||
async initializeWithProjectAnnotations(projectAnnotations: ProjectAnnotations<TRenderer>) {
|
||||
this.storyStore.setProjectAnnotations(projectAnnotations);
|
||||
|
||||
this.setInitialGlobals();
|
||||
|
||||
let storyIndexPromise: Promise<StoryIndex>;
|
||||
if (global.FEATURES?.storyStoreV7) {
|
||||
storyIndexPromise = this.getStoryIndexFromServer();
|
||||
} else {
|
||||
if (!this.getStoryIndex) {
|
||||
throw new Error('No `getStoryIndex` passed defined in v6 mode');
|
||||
}
|
||||
storyIndexPromise = SynchronousPromise.resolve().then(this.getStoryIndex);
|
||||
try {
|
||||
const storyIndex = await this.getStoryIndexFromServer();
|
||||
return this.initializeWithStoryIndex(storyIndex);
|
||||
} catch (err) {
|
||||
this.renderPreviewEntryError('Error loading story index:', err as Error);
|
||||
throw err;
|
||||
}
|
||||
|
||||
return storyIndexPromise
|
||||
.then((storyIndex: StoryIndex) => this.initializeWithStoryIndex(storyIndex))
|
||||
.catch((err) => {
|
||||
this.renderPreviewEntryError('Error loading story index:', err);
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
async setInitialGlobals() {
|
||||
@ -185,15 +163,11 @@ export class Preview<TRenderer extends Renderer> {
|
||||
}
|
||||
|
||||
// If initialization gets as far as the story index, this function runs.
|
||||
initializeWithStoryIndex(storyIndex: StoryIndex): PromiseLike<void> {
|
||||
initializeWithStoryIndex(storyIndex: StoryIndex): void {
|
||||
if (!this.importFn)
|
||||
throw new Error(`Cannot call initializeWithStoryIndex before initialization`);
|
||||
|
||||
return this.storyStore.initialize({
|
||||
storyIndex,
|
||||
importFn: this.importFn,
|
||||
cache: !global.FEATURES?.storyStoreV7,
|
||||
});
|
||||
this.storyStore.initialize({ storyIndex, importFn: this.importFn });
|
||||
}
|
||||
|
||||
// EVENT HANDLERS
|
||||
@ -212,7 +186,7 @@ export class Preview<TRenderer extends Renderer> {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.storyStore.setProjectAnnotations(projectAnnotations);
|
||||
this.storyStore.setProjectAnnotations(projectAnnotations);
|
||||
this.emitGlobals();
|
||||
}
|
||||
|
||||
@ -230,7 +204,7 @@ export class Preview<TRenderer extends Renderer> {
|
||||
|
||||
// This is the first time the story index worked, let's load it into the store
|
||||
if (!this.storyStore.storyIndex) {
|
||||
await this.initializeWithStoryIndex(storyIndex);
|
||||
this.initializeWithStoryIndex(storyIndex);
|
||||
}
|
||||
|
||||
// Update the store with the new stories.
|
||||
@ -368,9 +342,7 @@ export class Preview<TRenderer extends Renderer> {
|
||||
Do you have an error in your \`preview.js\`? Check your Storybook's browser console for errors.`);
|
||||
}
|
||||
|
||||
if (global.FEATURES?.storyStoreV7) {
|
||||
await this.storyStore.cacheAllCSFFiles();
|
||||
}
|
||||
await this.storyStore.cacheAllCSFFiles();
|
||||
|
||||
return this.storyStore.extract(options);
|
||||
}
|
||||
|
@ -47,9 +47,6 @@ vi.mock('@storybook/global', () => ({
|
||||
search: '?id=*',
|
||||
},
|
||||
},
|
||||
FEATURES: {
|
||||
storyStoreV7: true,
|
||||
},
|
||||
fetch: async () => ({ status: 200, json: async () => mockStoryIndex }),
|
||||
},
|
||||
}));
|
||||
@ -76,7 +73,7 @@ beforeEach(() => {
|
||||
vi.mocked(WebView.prototype).prepareForStory.mockReturnValue('story-element' as any);
|
||||
});
|
||||
|
||||
describe('PreviewWeb', () => {
|
||||
describe.skip('PreviewWeb', () => {
|
||||
describe('initial render', () => {
|
||||
it('renders story mode through the stack', async () => {
|
||||
const { DocsRenderer } = await import('@storybook/addon-docs');
|
||||
|
@ -69,10 +69,6 @@ vi.mock('@storybook/global', async (importOriginal) => ({
|
||||
search: '?id=*',
|
||||
},
|
||||
},
|
||||
FEATURES: {
|
||||
storyStoreV7: true,
|
||||
// xxx
|
||||
},
|
||||
fetch: async () => mockFetchResult,
|
||||
},
|
||||
}));
|
||||
@ -142,7 +138,7 @@ beforeEach(() => {
|
||||
vi.mocked(WebView.prototype).prepareForStory.mockReturnValue('story-element' as any);
|
||||
});
|
||||
|
||||
describe('PreviewWeb', () => {
|
||||
describe.skip('PreviewWeb', () => {
|
||||
describe('initialize', () => {
|
||||
it('shows an error if getProjectAnnotations throws', async () => {
|
||||
const err = new Error('meta error');
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { dedent } from 'ts-dedent';
|
||||
import { global } from '@storybook/global';
|
||||
import {
|
||||
CURRENT_STORY_WAS_SET,
|
||||
DOCS_PREPARED,
|
||||
PRELOAD_ENTRIES,
|
||||
PREVIEW_KEYDOWN,
|
||||
SET_CURRENT_STORY,
|
||||
SET_INDEX,
|
||||
STORY_ARGS_UPDATED,
|
||||
STORY_CHANGED,
|
||||
STORY_ERRORED,
|
||||
@ -115,14 +113,10 @@ export class PreviewWithSelection<TFramework extends Renderer> extends Preview<T
|
||||
}
|
||||
|
||||
// If initialization gets as far as the story index, this function runs.
|
||||
initializeWithStoryIndex(storyIndex: StoryIndex): PromiseLike<void> {
|
||||
return super.initializeWithStoryIndex(storyIndex).then(() => {
|
||||
if (!global.FEATURES?.storyStoreV7) {
|
||||
this.channel.emit(SET_INDEX, this.storyStore.getSetIndexPayload());
|
||||
}
|
||||
async initializeWithStoryIndex(storyIndex: StoryIndex): Promise<void> {
|
||||
await super.initializeWithStoryIndex(storyIndex);
|
||||
|
||||
return this.selectSpecifiedStory();
|
||||
});
|
||||
return this.selectSpecifiedStory();
|
||||
}
|
||||
|
||||
// Use the selection specifier to choose a story, then render it
|
||||
@ -204,10 +198,6 @@ export class PreviewWithSelection<TFramework extends Renderer> extends Preview<T
|
||||
}) {
|
||||
await super.onStoriesChanged({ importFn, storyIndex });
|
||||
|
||||
if (!global.FEATURES?.storyStoreV7) {
|
||||
this.channel.emit(SET_INDEX, await this.storyStore.getSetIndexPayload());
|
||||
}
|
||||
|
||||
if (this.selectionStore.selection) {
|
||||
await this.renderSelection();
|
||||
} else {
|
||||
@ -396,15 +386,13 @@ export class PreviewWithSelection<TFramework extends Renderer> extends Preview<T
|
||||
render.story
|
||||
);
|
||||
|
||||
if (global.FEATURES?.storyStoreV7) {
|
||||
this.channel.emit(STORY_PREPARED, {
|
||||
id: storyId,
|
||||
parameters,
|
||||
initialArgs,
|
||||
argTypes,
|
||||
args: unmappedArgs,
|
||||
});
|
||||
}
|
||||
this.channel.emit(STORY_PREPARED, {
|
||||
id: storyId,
|
||||
parameters,
|
||||
initialArgs,
|
||||
argTypes,
|
||||
args: unmappedArgs,
|
||||
});
|
||||
|
||||
// For v6 mode / compatibility
|
||||
// If the implementation changed, or args were persisted, the args may have changed,
|
||||
@ -412,8 +400,10 @@ export class PreviewWithSelection<TFramework extends Renderer> extends Preview<T
|
||||
if (implementationChanged || persistedArgs) {
|
||||
this.channel.emit(STORY_ARGS_UPDATED, { storyId, args: unmappedArgs });
|
||||
}
|
||||
} else if (global.FEATURES?.storyStoreV7) {
|
||||
if (!this.storyStore.projectAnnotations) throw new Error('Store not initialized');
|
||||
} else {
|
||||
if (!this.storyStore.projectAnnotations) {
|
||||
throw new Error('Store not initialized');
|
||||
}
|
||||
|
||||
// Default to the project parameters for MDX docs
|
||||
let { parameters } = this.storyStore.projectAnnotations;
|
||||
@ -467,9 +457,7 @@ export class PreviewWithSelection<TFramework extends Renderer> extends Preview<T
|
||||
Do you have an error in your \`preview.js\`? Check your Storybook's browser console for errors.`);
|
||||
}
|
||||
|
||||
if (global.FEATURES?.storyStoreV7) {
|
||||
await this.storyStore.cacheAllCSFFiles();
|
||||
}
|
||||
await this.storyStore.cacheAllCSFFiles();
|
||||
|
||||
return this.storyStore.extract(options);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ describe('StoryStore', () => {
|
||||
it('normalizes on initialization', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
expect(store.projectAnnotations!.globalTypes).toEqual({
|
||||
a: { name: 'a', type: { name: 'string' } },
|
||||
@ -99,7 +99,7 @@ describe('StoryStore', () => {
|
||||
it('normalizes on updateGlobalAnnotations', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
expect(store.projectAnnotations!.globalTypes).toEqual({
|
||||
@ -115,7 +115,7 @@ describe('StoryStore', () => {
|
||||
it('pulls the story via the importFn', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
importFn.mockClear();
|
||||
expect(await store.loadStory({ storyId: 'component-one--a' })).toMatchObject({
|
||||
@ -130,7 +130,7 @@ describe('StoryStore', () => {
|
||||
it('uses a cache', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
expect(processCSFFile).toHaveBeenCalledTimes(1);
|
||||
@ -158,7 +158,7 @@ describe('StoryStore', () => {
|
||||
const loadPromise = store.loadStory({ storyId: 'component-one--a' });
|
||||
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
expect(await loadPromise).toMatchObject({
|
||||
id: 'component-one--a',
|
||||
@ -175,7 +175,7 @@ describe('StoryStore', () => {
|
||||
it('busts the loadStory cache', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
expect(processCSFFile).toHaveBeenCalledTimes(1);
|
||||
@ -194,7 +194,7 @@ describe('StoryStore', () => {
|
||||
it('busts the loadStory cache if the importFn returns a new module', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
expect(processCSFFile).toHaveBeenCalledTimes(1);
|
||||
@ -216,7 +216,7 @@ describe('StoryStore', () => {
|
||||
it('busts the loadStory cache if the csf file no longer appears in the index', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
await store.loadStory({ storyId: 'component-one--a' });
|
||||
expect(processCSFFile).toHaveBeenCalledTimes(1);
|
||||
@ -235,7 +235,7 @@ describe('StoryStore', () => {
|
||||
it('reuses the cache if a story importPath has not changed', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
expect(processCSFFile).toHaveBeenCalledTimes(1);
|
||||
@ -267,7 +267,7 @@ describe('StoryStore', () => {
|
||||
it('imports with a new path for a story id if provided', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
await store.loadStory({ storyId: 'component-one--a' });
|
||||
expect(importFn).toHaveBeenCalledWith(storyIndex.entries['component-one--a'].importPath);
|
||||
@ -297,7 +297,7 @@ describe('StoryStore', () => {
|
||||
it('re-caches stories if the were cached already', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
await store.loadStory({ storyId: 'component-one--a' });
|
||||
@ -370,7 +370,7 @@ describe('StoryStore', () => {
|
||||
it('returns all the stories in the file', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const csfFile = await store.loadCSFFileByStoryId('component-one--a');
|
||||
const stories = store.componentStoriesFromCSFFile({ csfFile });
|
||||
@ -389,7 +389,7 @@ describe('StoryStore', () => {
|
||||
'component-one--a': storyIndex.entries['component-one--a'],
|
||||
},
|
||||
};
|
||||
store.initialize({ storyIndex: reversedIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex: reversedIndex, importFn });
|
||||
|
||||
const csfFile = await store.loadCSFFileByStoryId('component-one--a');
|
||||
const stories = store.componentStoriesFromCSFFile({ csfFile });
|
||||
@ -403,7 +403,7 @@ describe('StoryStore', () => {
|
||||
it('returns the args and globals correctly', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
|
||||
@ -416,7 +416,7 @@ describe('StoryStore', () => {
|
||||
it('returns the args and globals correctly when they change', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
|
||||
@ -432,7 +432,7 @@ describe('StoryStore', () => {
|
||||
it('can force initial args', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
|
||||
@ -446,7 +446,7 @@ describe('StoryStore', () => {
|
||||
it('returns the same hooks each time', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
|
||||
@ -463,7 +463,7 @@ describe('StoryStore', () => {
|
||||
it('cleans the hooks from the context', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
const story = await store.loadStory({ storyId: 'component-one--a' });
|
||||
|
||||
@ -478,7 +478,7 @@ describe('StoryStore', () => {
|
||||
it('imports *all* csf files', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
importFn.mockClear();
|
||||
const csfFiles = await store.loadAllCSFFiles();
|
||||
@ -498,7 +498,7 @@ describe('StoryStore', () => {
|
||||
});
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn: blockedImportFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn: blockedImportFn });
|
||||
|
||||
const promise = store.loadAllCSFFiles({ batchSize: 1 });
|
||||
expect(blockedImportFn).toHaveBeenCalledTimes(1);
|
||||
@ -513,7 +513,7 @@ describe('StoryStore', () => {
|
||||
it('throws if you have not called cacheAllCSFFiles', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
expect(() => store.extract()).toThrow(/Cannot call extract/);
|
||||
});
|
||||
@ -521,7 +521,7 @@ describe('StoryStore', () => {
|
||||
it('produces objects with functions and hooks stripped', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
expect(store.extract()).toMatchInlineSnapshot(`
|
||||
@ -658,7 +658,6 @@ describe('StoryStore', () => {
|
||||
store.initialize({
|
||||
storyIndex,
|
||||
importFn: docsOnlyImportFn,
|
||||
cache: false,
|
||||
});
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
@ -691,7 +690,6 @@ describe('StoryStore', () => {
|
||||
store.initialize({
|
||||
storyIndex: unnattachedStoryIndex,
|
||||
importFn,
|
||||
cache: false,
|
||||
});
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
@ -713,7 +711,7 @@ describe('StoryStore', () => {
|
||||
it('produces an array of stories', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
expect(store.raw()).toMatchInlineSnapshot(`
|
||||
@ -862,7 +860,7 @@ describe('StoryStore', () => {
|
||||
it('maps stories list to payload correctly', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
expect(store.getSetStoriesPayload()).toMatchInlineSnapshot(`
|
||||
@ -1002,7 +1000,7 @@ describe('StoryStore', () => {
|
||||
it('maps stories list to payload correctly', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
expect(store.getStoriesJsonData()).toMatchInlineSnapshot(`
|
||||
@ -1052,116 +1050,6 @@ describe('StoryStore', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSetIndexPayload', () => {
|
||||
it('add parameters/args to index correctly', async () => {
|
||||
const store = new StoryStore();
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
await store.cacheAllCSFFiles();
|
||||
|
||||
expect(store.getSetIndexPayload()).toMatchInlineSnapshot(`
|
||||
{
|
||||
"entries": {
|
||||
"component-one--a": {
|
||||
"argTypes": {
|
||||
"a": {
|
||||
"name": "a",
|
||||
"type": {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
"foo": {
|
||||
"name": "foo",
|
||||
"type": {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"args": {
|
||||
"foo": "a",
|
||||
},
|
||||
"id": "component-one--a",
|
||||
"importPath": "./src/ComponentOne.stories.js",
|
||||
"initialArgs": {
|
||||
"foo": "a",
|
||||
},
|
||||
"name": "A",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "./src/ComponentOne.stories.js",
|
||||
},
|
||||
"title": "Component One",
|
||||
"type": "story",
|
||||
},
|
||||
"component-one--b": {
|
||||
"argTypes": {
|
||||
"a": {
|
||||
"name": "a",
|
||||
"type": {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
"foo": {
|
||||
"name": "foo",
|
||||
"type": {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"args": {
|
||||
"foo": "b",
|
||||
},
|
||||
"id": "component-one--b",
|
||||
"importPath": "./src/ComponentOne.stories.js",
|
||||
"initialArgs": {
|
||||
"foo": "b",
|
||||
},
|
||||
"name": "B",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "./src/ComponentOne.stories.js",
|
||||
},
|
||||
"title": "Component One",
|
||||
"type": "story",
|
||||
},
|
||||
"component-two--c": {
|
||||
"argTypes": {
|
||||
"a": {
|
||||
"name": "a",
|
||||
"type": {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
"foo": {
|
||||
"name": "foo",
|
||||
"type": {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"args": {
|
||||
"foo": "c",
|
||||
},
|
||||
"id": "component-two--c",
|
||||
"importPath": "./src/ComponentTwo.stories.js",
|
||||
"initialArgs": {
|
||||
"foo": "c",
|
||||
},
|
||||
"name": "C",
|
||||
"parameters": {
|
||||
"__isArgsStory": false,
|
||||
"fileName": "./src/ComponentTwo.stories.js",
|
||||
},
|
||||
"title": "Component Two",
|
||||
"type": "story",
|
||||
},
|
||||
},
|
||||
"v": 4,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cacheAllCsfFiles', () => {
|
||||
describe('if the store is not yet initialized', () => {
|
||||
it('waits for initialization', async () => {
|
||||
@ -1171,7 +1059,7 @@ describe('StoryStore', () => {
|
||||
const cachePromise = store.cacheAllCSFFiles();
|
||||
|
||||
store.setProjectAnnotations(projectAnnotations);
|
||||
store.initialize({ storyIndex, importFn, cache: false });
|
||||
store.initialize({ storyIndex, importFn });
|
||||
|
||||
await expect(cachePromise).resolves.toEqual(undefined);
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import memoize from 'memoizerific';
|
||||
import type {
|
||||
IndexEntry,
|
||||
Renderer,
|
||||
API_PreparedStoryIndex,
|
||||
ComponentTitle,
|
||||
Parameters,
|
||||
Path,
|
||||
@ -24,7 +23,6 @@ import type {
|
||||
} from '@storybook/types';
|
||||
import mapValues from 'lodash/mapValues.js';
|
||||
import pick from 'lodash/pick.js';
|
||||
import { SynchronousPromise } from 'synchronous-promise';
|
||||
|
||||
import { HooksContext } from '../addons';
|
||||
import { StoryIndexStore } from './StoryIndexStore';
|
||||
@ -63,9 +61,9 @@ export class StoryStore<TRenderer extends Renderer> {
|
||||
|
||||
prepareStoryWithCache: typeof prepareStory;
|
||||
|
||||
initializationPromise: SynchronousPromise<void>;
|
||||
initializationPromise: Promise<void>;
|
||||
|
||||
// This *does* get set in the constructor but the semantics of `new SynchronousPromise` trip up TS
|
||||
// This *does* get set in the constructor but the semantics of `new Promise` trip up TS
|
||||
resolveInitializationPromise!: () => void;
|
||||
|
||||
constructor() {
|
||||
@ -80,7 +78,7 @@ export class StoryStore<TRenderer extends Renderer> {
|
||||
this.prepareStoryWithCache = memoize(STORY_CACHE_SIZE)(prepareStory) as typeof prepareStory;
|
||||
|
||||
// We cannot call `loadStory()` until we've been initialized properly. But we can wait for it.
|
||||
this.initializationPromise = new SynchronousPromise((resolve) => {
|
||||
this.initializationPromise = new Promise((resolve) => {
|
||||
this.resolveInitializationPromise = resolve;
|
||||
});
|
||||
}
|
||||
@ -100,19 +98,15 @@ export class StoryStore<TRenderer extends Renderer> {
|
||||
initialize({
|
||||
storyIndex,
|
||||
importFn,
|
||||
cache = false,
|
||||
}: {
|
||||
storyIndex?: StoryIndex;
|
||||
importFn: ModuleImportFn;
|
||||
cache?: boolean;
|
||||
}): Promise<void> {
|
||||
}): void {
|
||||
this.storyIndex = new StoryIndexStore(storyIndex);
|
||||
this.importFn = importFn;
|
||||
|
||||
// We don't need the cache to be loaded to call `loadStory`, we just need the index ready
|
||||
this.resolveInitializationPromise();
|
||||
|
||||
return cache ? this.cacheAllCSFFiles() : SynchronousPromise.resolve();
|
||||
}
|
||||
|
||||
// This means that one of the CSF files has changed.
|
||||
@ -142,18 +136,18 @@ export class StoryStore<TRenderer extends Renderer> {
|
||||
}
|
||||
|
||||
// To load a single CSF file to service a story we need to look up the importPath in the index
|
||||
loadCSFFileByStoryId(storyId: StoryId): Promise<CSFFile<TRenderer>> {
|
||||
async loadCSFFileByStoryId(storyId: StoryId): Promise<CSFFile<TRenderer>> {
|
||||
if (!this.storyIndex || !this.importFn)
|
||||
throw new Error(`loadCSFFileByStoryId called before initialization`);
|
||||
|
||||
const { importPath, title } = this.storyIndex.storyIdToEntry(storyId);
|
||||
return this.importFn(importPath).then((moduleExports) =>
|
||||
// We pass the title in here as it may have been generated by autoTitle on the server.
|
||||
this.processCSFFileWithCache(moduleExports, importPath, title)
|
||||
);
|
||||
const moduleExports = await this.importFn(importPath);
|
||||
|
||||
// We pass the title in here as it may have been generated by autoTitle on the server.
|
||||
return this.processCSFFileWithCache(moduleExports, importPath, title);
|
||||
}
|
||||
|
||||
loadAllCSFFiles({ batchSize = EXTRACT_BATCH_SIZE } = {}): Promise<
|
||||
async loadAllCSFFiles({ batchSize = EXTRACT_BATCH_SIZE } = {}): Promise<
|
||||
StoryStore<TRenderer>['cachedCSFFiles']
|
||||
> {
|
||||
if (!this.storyIndex) throw new Error(`loadAllCSFFiles called before initialization`);
|
||||
@ -163,41 +157,33 @@ export class StoryStore<TRenderer extends Renderer> {
|
||||
storyId,
|
||||
]);
|
||||
|
||||
const loadInBatches = (
|
||||
const loadInBatches = async (
|
||||
remainingImportPaths: typeof importPaths
|
||||
): Promise<{ importPath: Path; csfFile: CSFFile<TRenderer> }[]> => {
|
||||
if (remainingImportPaths.length === 0) return SynchronousPromise.resolve([]);
|
||||
if (remainingImportPaths.length === 0) return Promise.resolve([]);
|
||||
|
||||
const csfFilePromiseList = remainingImportPaths
|
||||
.slice(0, batchSize)
|
||||
.map(([importPath, storyId]) =>
|
||||
this.loadCSFFileByStoryId(storyId).then((csfFile) => ({
|
||||
importPath,
|
||||
csfFile,
|
||||
}))
|
||||
);
|
||||
.map(async ([importPath, storyId]) => ({
|
||||
importPath,
|
||||
csfFile: await this.loadCSFFileByStoryId(storyId),
|
||||
}));
|
||||
|
||||
return SynchronousPromise.all(csfFilePromiseList).then((firstResults) =>
|
||||
loadInBatches(remainingImportPaths.slice(batchSize)).then((restResults) =>
|
||||
firstResults.concat(restResults)
|
||||
)
|
||||
);
|
||||
const firstResults = await Promise.all(csfFilePromiseList);
|
||||
const restResults = await loadInBatches(remainingImportPaths.slice(batchSize));
|
||||
return firstResults.concat(restResults);
|
||||
};
|
||||
|
||||
return loadInBatches(importPaths).then((list) =>
|
||||
list.reduce((acc, { importPath, csfFile }) => {
|
||||
acc[importPath] = csfFile;
|
||||
return acc;
|
||||
}, {} as Record<Path, CSFFile<TRenderer>>)
|
||||
);
|
||||
const list = await loadInBatches(importPaths);
|
||||
return list.reduce((acc, { importPath, csfFile }) => {
|
||||
acc[importPath] = csfFile;
|
||||
return acc;
|
||||
}, {} as Record<Path, CSFFile<TRenderer>>);
|
||||
}
|
||||
|
||||
cacheAllCSFFiles(): Promise<void> {
|
||||
return this.initializationPromise.then(() =>
|
||||
this.loadAllCSFFiles().then((csfFiles) => {
|
||||
this.cachedCSFFiles = csfFiles;
|
||||
})
|
||||
);
|
||||
async cacheAllCSFFiles(): Promise<void> {
|
||||
await this.initializationPromise;
|
||||
this.cachedCSFFiles = await this.loadAllCSFFiles();
|
||||
}
|
||||
|
||||
preparedMetaFromCSFFile({ csfFile }: { csfFile: CSFFile<TRenderer> }): PreparedMeta<TRenderer> {
|
||||
@ -393,38 +379,6 @@ export class StoryStore<TRenderer extends Renderer> {
|
||||
};
|
||||
};
|
||||
|
||||
getSetIndexPayload(): API_PreparedStoryIndex {
|
||||
if (!this.storyIndex) throw new Error('getSetIndexPayload called before initialization');
|
||||
if (!this.cachedCSFFiles)
|
||||
throw new Error('Cannot call getSetIndexPayload() unless you call cacheAllCSFFiles() first');
|
||||
const { cachedCSFFiles } = this;
|
||||
|
||||
const stories = this.extract({ includeDocsOnly: true });
|
||||
|
||||
return {
|
||||
v: 4,
|
||||
entries: Object.fromEntries(
|
||||
Object.entries(this.storyIndex.entries).map(([id, entry]) => [
|
||||
id,
|
||||
stories[id]
|
||||
? {
|
||||
...entry,
|
||||
args: stories[id].initialArgs,
|
||||
initialArgs: stories[id].initialArgs,
|
||||
argTypes: stories[id].argTypes,
|
||||
parameters: stories[id].parameters,
|
||||
}
|
||||
: {
|
||||
...entry,
|
||||
parameters: this.preparedMetaFromCSFFile({
|
||||
csfFile: cachedCSFFiles[entry.importPath],
|
||||
}).parameters,
|
||||
},
|
||||
])
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
raw(): BoundStory<TRenderer>[] {
|
||||
return Object.values(this.extract())
|
||||
.map(({ id }: { id: StoryId }) => this.fromId(id))
|
||||
|
@ -177,6 +177,16 @@ describe('userOrAutoTitleFromSpecifier', () => {
|
||||
).toMatchInlineSnapshot(`to/button`);
|
||||
});
|
||||
|
||||
it('match with case-insensitive trailing duplicate', () => {
|
||||
expect(
|
||||
userOrAuto(
|
||||
'./path/to/button/Button.stories.js',
|
||||
normalizeStoriesEntry({ directory: './path' }, options),
|
||||
undefined
|
||||
)
|
||||
).toMatchInlineSnapshot(`to/Button`);
|
||||
});
|
||||
|
||||
it('match with trailing index', () => {
|
||||
expect(
|
||||
userOrAuto(
|
||||
|
@ -15,11 +15,12 @@ const sanitize = (parts: string[]) => {
|
||||
if (parts.length === 1) return [lastStripped];
|
||||
|
||||
const nextToLast = parts[parts.length - 2];
|
||||
if (lastStripped && nextToLast && lastStripped.toLowerCase() === nextToLast.toLowerCase()) {
|
||||
return [...parts.slice(0, -2), lastStripped];
|
||||
}
|
||||
|
||||
return lastStripped &&
|
||||
nextToLast &&
|
||||
(lastStripped === nextToLast ||
|
||||
/^(story|stories)([.][^.]+)$/i.test(last) ||
|
||||
/^index$/i.test(lastStripped))
|
||||
(/^(story|stories)([.][^.]+)$/i.test(last) || /^index$/i.test(lastStripped))
|
||||
? parts.slice(0, -1)
|
||||
: [...parts.slice(0, -1), lastStripped];
|
||||
};
|
||||
|
1
code/lib/preview-api/src/typings.d.ts
vendored
1
code/lib/preview-api/src/typings.d.ts
vendored
@ -19,7 +19,6 @@ declare var IS_STORYBOOK: boolean;
|
||||
// relevant framework instantiates them via `start.js`. The good news is this happens right away.
|
||||
declare var __STORYBOOK_ADDONS_CHANNEL__: any;
|
||||
declare var __STORYBOOK_ADDONS_PREVIEW: any;
|
||||
declare var __STORYBOOK_CLIENT_API__: import('./modules/client-api/ClientApi').ClientApi<any>;
|
||||
declare var __STORYBOOK_PREVIEW__: import('./modules/preview-web/PreviewWeb').PreviewWeb<any>;
|
||||
declare var __STORYBOOK_STORY_STORE__: any;
|
||||
declare var STORYBOOK_HOOKS_CONTEXT: any;
|
||||
|
@ -10,34 +10,14 @@ The preview's job is:
|
||||
|
||||
3. Render the current selection to the web view in either story or docs mode.
|
||||
|
||||
## V7 Store vs Legacy (V6)
|
||||
|
||||
The story store is designed to load stories 'on demand', and will operate in this fashion if the `storyStoreV7` feature is enabled.
|
||||
|
||||
However, for back-compat reasons, in v6 mode, we need to load all stories, synchronously on bootup, emitting the `SET_STORIES` event.
|
||||
|
||||
In V7 mode we do not emit that event, instead preferring the `STORY_PREPARED` event, with the data for the single story being rendered.
|
||||
|
||||
## Initialization
|
||||
|
||||
The preview is `initialized` in two ways.
|
||||
|
||||
### V7 Mode:
|
||||
|
||||
- `importFn` - is an async `import()` function
|
||||
|
||||
- `getProjectAnnotations` - is a simple function that evaluations `preview.js` and addon config files and combines them. If it errors, the Preview will show the error.
|
||||
|
||||
- No `getStoryIndex` function is passed, instead the preview creates a `StoryIndexClient` that pulls `stories.json` from node and watches the event stream for invalidation events.
|
||||
|
||||
### V6 Mode
|
||||
|
||||
- `importFn` - is a simulated `import()` function, that is synchronous, see `client-api` for details.
|
||||
- `getProjectAnnotations` - also evaluates `preview.js` et al, but watches for calls to `setStories`, and passes them to the `ClientApi`
|
||||
- `getStoryIndex` is a local function (that must be called _after_ `getProjectAnnotations`) that gets the list of stories added.
|
||||
|
||||
See `client-api` for more details on this process.
|
||||
|
||||
## Story Rendering and interruptions
|
||||
|
||||
The Preview is split into three parts responsible for state management:
|
||||
|
@ -313,9 +313,7 @@ describe('storybook-metadata', () => {
|
||||
});
|
||||
|
||||
it('should return user specified features', async () => {
|
||||
const features = {
|
||||
storyStoreV7: true,
|
||||
};
|
||||
const features = {};
|
||||
|
||||
const result = await computeStorybookMetadata({
|
||||
packageJson: packageJsonMock,
|
||||
|
@ -341,22 +341,6 @@ export interface StorybookConfigRaw {
|
||||
staticDirs?: (DirectoryMapping | string)[];
|
||||
logLevel?: string;
|
||||
features?: {
|
||||
/**
|
||||
* Build stories.json automatically on start/build
|
||||
*/
|
||||
buildStoriesJson?: boolean;
|
||||
|
||||
/**
|
||||
* Activate on demand story store
|
||||
*/
|
||||
storyStoreV7?: boolean;
|
||||
|
||||
/**
|
||||
* Do not throw errors if using `.mdx` files in SSv7
|
||||
* (for internal use in sandboxes)
|
||||
*/
|
||||
storyStoreV7MdxErrors?: boolean;
|
||||
|
||||
/**
|
||||
* Filter args with a "target" on the type from the render function (EXPERIMENTAL)
|
||||
*/
|
||||
|
@ -256,7 +256,7 @@
|
||||
"built": false
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@4.0.0",
|
||||
"packageManager": "yarn@4.0.2",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
|
@ -29,7 +29,7 @@ export type Meta<TArgs = Args> = ComponentAnnotations<HtmlRenderer, TArgs>;
|
||||
export type StoryFn<TArgs = Args> = AnnotatedStoryFn<HtmlRenderer, TArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@ export type Meta<TArgs = Args> = ComponentAnnotations<PreactRenderer, TArgs>;
|
||||
export type StoryFn<TArgs = Args> = AnnotatedStoryFn<PreactRenderer, TArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -37,7 +37,7 @@ export type StoryFn<TCmpOrArgs = Args> = [TCmpOrArgs] extends [ComponentType<any
|
||||
: AnnotatedStoryFn<ReactRenderer, TCmpOrArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -28,7 +28,7 @@ export type Meta<TArgs = Args> = ComponentAnnotations<ServerRenderer, TArgs>;
|
||||
export type StoryFn<TArgs = Args> = AnnotatedStoryFn<ServerRenderer, TArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -36,7 +36,7 @@ export type StoryFn<TCmpOrArgs = Args> = TCmpOrArgs extends SvelteComponentTyped
|
||||
: AnnotatedStoryFn<SvelteRenderer, TCmpOrArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
import './globals';
|
||||
|
||||
export * from './public-api';
|
||||
export * from './public-types';
|
||||
export { setup } from './render';
|
||||
|
||||
// optimization: stop HMR propagation in webpack
|
||||
try {
|
||||
|
@ -1 +0,0 @@
|
||||
export { setup } from './render';
|
@ -40,7 +40,7 @@ export type StoryFn<TCmpOrArgs = Args> = AnnotatedStoryFn<
|
||||
>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -29,7 +29,7 @@ export type Meta<TArgs = Args> = ComponentAnnotations<WebComponentsRenderer, TAr
|
||||
export type StoryFn<TArgs = Args> = AnnotatedStoryFn<WebComponentsRenderer, TArgs>;
|
||||
|
||||
/**
|
||||
* Story function that represents a CSFv3 component example.
|
||||
* Story object that represents a CSFv3 component example.
|
||||
*
|
||||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
|
||||
*/
|
||||
|
@ -51,7 +51,7 @@
|
||||
"@storybook/csf": "^0.1.2",
|
||||
"@storybook/docs-tools": "workspace:*",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/manager-api": "workspace:*",
|
||||
"@storybook/preview-api": "workspace:*",
|
||||
"@storybook/theming": "workspace:*",
|
||||
@ -60,7 +60,7 @@
|
||||
"color-convert": "^2.0.1",
|
||||
"dequal": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-to-jsx": "^7.1.8",
|
||||
"markdown-to-jsx": "7.3.2",
|
||||
"memoizerific": "^1.11.3",
|
||||
"polished": "^4.2.2",
|
||||
"react-colorful": "^5.1.2",
|
||||
|
@ -63,7 +63,7 @@
|
||||
"@storybook/client-logger": "workspace:*",
|
||||
"@storybook/csf": "^0.1.2",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/theming": "workspace:*",
|
||||
"@storybook/types": "workspace:*",
|
||||
"memoizerific": "^1.11.3",
|
||||
|
@ -79,7 +79,7 @@
|
||||
"@storybook/components": "workspace:*",
|
||||
"@storybook/core-events": "workspace:*",
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@storybook/icons": "^1.2.1",
|
||||
"@storybook/icons": "^1.2.3",
|
||||
"@storybook/manager-api": "workspace:*",
|
||||
"@storybook/router": "workspace:*",
|
||||
"@storybook/test": "workspace:*",
|
||||
@ -94,7 +94,7 @@
|
||||
"fs-extra": "^11.1.0",
|
||||
"fuse.js": "^3.6.1",
|
||||
"lodash": "^4.17.21",
|
||||
"markdown-to-jsx": "^7.1.8",
|
||||
"markdown-to-jsx": "7.3.2",
|
||||
"memoizerific": "^1.11.3",
|
||||
"polished": "^4.2.2",
|
||||
"qs": "^6.10.0",
|
||||
|
@ -18,8 +18,6 @@ import { FramesRenderer } from './FramesRenderer';
|
||||
|
||||
import type { PreviewProps } from './utils/types';
|
||||
|
||||
const { FEATURES } = global;
|
||||
|
||||
const getWrappers = (getFn: API['getElements']) => Object.values(getFn(types.PREVIEW));
|
||||
const getTabs = (getFn: API['getElements']) => Object.values(getFn(types.TAB));
|
||||
|
||||
@ -160,7 +158,7 @@ const Canvas: FC<{ withLoader: boolean; baseUrl: string; children?: never }> = (
|
||||
|
||||
const [progress, setProgress] = useState(undefined);
|
||||
useEffect(() => {
|
||||
if (FEATURES?.storyStoreV7 && global.CONFIG_TYPE === 'DEVELOPMENT') {
|
||||
if (global.CONFIG_TYPE === 'DEVELOPMENT') {
|
||||
try {
|
||||
const channel = addons.getServerChannel();
|
||||
|
||||
|
@ -9,7 +9,7 @@ import { CHANNEL_CREATED } from '@storybook/core-events';
|
||||
import Provider from './provider';
|
||||
import { renderStorybookUI } from './index';
|
||||
|
||||
const { FEATURES, CONFIG_TYPE } = global;
|
||||
const { CONFIG_TYPE } = global;
|
||||
|
||||
class ReactProvider extends Provider {
|
||||
private addons: AddonStore;
|
||||
@ -34,7 +34,7 @@ class ReactProvider extends Provider {
|
||||
this.channel = channel;
|
||||
global.__STORYBOOK_ADDONS_CHANNEL__ = channel;
|
||||
|
||||
if (FEATURES?.storyStoreV7 && CONFIG_TYPE === 'DEVELOPMENT') {
|
||||
if (CONFIG_TYPE === 'DEVELOPMENT') {
|
||||
this.serverChannel = this.channel;
|
||||
addons.setServerChannel(this.serverChannel);
|
||||
}
|
||||
|
331
code/yarn.lock
331
code/yarn.lock
@ -50,7 +50,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@angular-devkit/architect@npm:0.1700.5, @angular-devkit/architect@npm:^0.1700.5":
|
||||
"@angular-devkit/architect@npm:0.1700.5":
|
||||
version: 0.1700.5
|
||||
resolution: "@angular-devkit/architect@npm:0.1700.5"
|
||||
dependencies:
|
||||
@ -60,6 +60,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@angular-devkit/architect@npm:^0.1700.5":
|
||||
version: 0.1700.9
|
||||
resolution: "@angular-devkit/architect@npm:0.1700.9"
|
||||
dependencies:
|
||||
"@angular-devkit/core": "npm:17.0.9"
|
||||
rxjs: "npm:7.8.1"
|
||||
checksum: e740d7d6b9318fd6a1b1642fa62d182f7509a021d75835082aba693f0312b369742267b3a0748426f7bee5b7d93b4e2cd17b7f9323a451f7e650efeb8c0b394b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@angular-devkit/build-angular@npm:^17.0.5":
|
||||
version: 17.0.5
|
||||
resolution: "@angular-devkit/build-angular@npm:17.0.5"
|
||||
@ -181,7 +191,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@angular-devkit/core@npm:17.0.5, @angular-devkit/core@npm:^17.0.5":
|
||||
"@angular-devkit/core@npm:17.0.5":
|
||||
version: 17.0.5
|
||||
resolution: "@angular-devkit/core@npm:17.0.5"
|
||||
dependencies:
|
||||
@ -200,6 +210,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@angular-devkit/core@npm:17.0.9, @angular-devkit/core@npm:^17.0.5":
|
||||
version: 17.0.9
|
||||
resolution: "@angular-devkit/core@npm:17.0.9"
|
||||
dependencies:
|
||||
ajv: "npm:8.12.0"
|
||||
ajv-formats: "npm:2.1.1"
|
||||
jsonc-parser: "npm:3.2.0"
|
||||
picomatch: "npm:3.0.1"
|
||||
rxjs: "npm:7.8.1"
|
||||
source-map: "npm:0.7.4"
|
||||
peerDependencies:
|
||||
chokidar: ^3.5.2
|
||||
peerDependenciesMeta:
|
||||
chokidar:
|
||||
optional: true
|
||||
checksum: fb054e100d912fbf0c4570937993de706a71bb3338ad3cce57bf6a936ab1be1102f6c351024c1c18892d57ed80554305578593dc73ece37d74eb748f216c137c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@angular-devkit/schematics@npm:17.0.5":
|
||||
version: 17.0.5
|
||||
resolution: "@angular-devkit/schematics@npm:17.0.5"
|
||||
@ -525,7 +554,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/helper-define-polyfill-provider@npm:^0.4.3, @babel/helper-define-polyfill-provider@npm:^0.4.4":
|
||||
"@babel/helper-define-polyfill-provider@npm:^0.4.4":
|
||||
version: 0.4.4
|
||||
resolution: "@babel/helper-define-polyfill-provider@npm:0.4.4"
|
||||
dependencies:
|
||||
@ -701,13 +730,13 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@babel/helpers@npm:^7.23.2, @babel/helpers@npm:^7.23.7":
|
||||
version: 7.23.7
|
||||
resolution: "@babel/helpers@npm:7.23.7"
|
||||
version: 7.23.8
|
||||
resolution: "@babel/helpers@npm:7.23.8"
|
||||
dependencies:
|
||||
"@babel/template": "npm:^7.22.15"
|
||||
"@babel/traverse": "npm:^7.23.7"
|
||||
"@babel/types": "npm:^7.23.6"
|
||||
checksum: f74a61ad28a1bc1fdd9133ad571c07787b66d6db017c707b87c203b0cd06879cea8b33e9c6a8585765a4949efa5df3cc9e19b710fe867f11be38ee29fd4a0488
|
||||
checksum: d9fce49278a31aaa017a40c1fcdaa450999c49e33582cce8138058c58b1acbe3a2d2488f010f28e91dedf0d35795ea32f0ee18745bbb6c7f54052ae0fd7e6a3f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1218,22 +1247,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/plugin-transform-classes@npm:^7.22.15, @babel/plugin-transform-classes@npm:^7.23.5":
|
||||
version: 7.23.5
|
||||
resolution: "@babel/plugin-transform-classes@npm:7.23.5"
|
||||
"@babel/plugin-transform-classes@npm:^7.22.15, @babel/plugin-transform-classes@npm:^7.23.8":
|
||||
version: 7.23.8
|
||||
resolution: "@babel/plugin-transform-classes@npm:7.23.8"
|
||||
dependencies:
|
||||
"@babel/helper-annotate-as-pure": "npm:^7.22.5"
|
||||
"@babel/helper-compilation-targets": "npm:^7.22.15"
|
||||
"@babel/helper-compilation-targets": "npm:^7.23.6"
|
||||
"@babel/helper-environment-visitor": "npm:^7.22.20"
|
||||
"@babel/helper-function-name": "npm:^7.23.0"
|
||||
"@babel/helper-optimise-call-expression": "npm:^7.22.5"
|
||||
"@babel/helper-plugin-utils": "npm:^7.22.5"
|
||||
"@babel/helper-replace-supers": "npm:^7.22.20"
|
||||
"@babel/helper-split-export-declaration": "npm:^7.22.6"
|
||||
globals: "npm:^11.1.0"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.0.0-0
|
||||
checksum: 07988f52b4893151887d1ea6ff79e5fe834078c5731bd09babd5659edbbae21ea4e2de326a02443a63fd776b4c945da6177f07875b56fe66e0b7899e830a9e92
|
||||
checksum: 227ac5166501e04d9e7fbd5eda6869b084ffa4af6830ac12544ac6ea14953ca00eb1762b0df9349c0f6c8d2a799385910f558066cd0fb85b9ca437b1131a6043
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -1955,8 +1983,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@babel/preset-env@npm:^7.16.5, @babel/preset-env@npm:^7.23.2":
|
||||
version: 7.23.7
|
||||
resolution: "@babel/preset-env@npm:7.23.7"
|
||||
version: 7.23.8
|
||||
resolution: "@babel/preset-env@npm:7.23.8"
|
||||
dependencies:
|
||||
"@babel/compat-data": "npm:^7.23.5"
|
||||
"@babel/helper-compilation-targets": "npm:^7.23.6"
|
||||
@ -1991,7 +2019,7 @@ __metadata:
|
||||
"@babel/plugin-transform-block-scoping": "npm:^7.23.4"
|
||||
"@babel/plugin-transform-class-properties": "npm:^7.23.3"
|
||||
"@babel/plugin-transform-class-static-block": "npm:^7.23.4"
|
||||
"@babel/plugin-transform-classes": "npm:^7.23.5"
|
||||
"@babel/plugin-transform-classes": "npm:^7.23.8"
|
||||
"@babel/plugin-transform-computed-properties": "npm:^7.23.3"
|
||||
"@babel/plugin-transform-destructuring": "npm:^7.23.3"
|
||||
"@babel/plugin-transform-dotall-regex": "npm:^7.23.3"
|
||||
@ -2040,7 +2068,7 @@ __metadata:
|
||||
semver: "npm:^6.3.1"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.0.0-0
|
||||
checksum: ac9def873cec52ee02a550bde6e22eced16d1ae331bb8ebc82c03e4c91c12ac17e3e4027647e61612937bcc25ac46e71370aaf99dc2e85dbd11f7777ffeed54e
|
||||
checksum: e602ad954645f1a509644e3d2c72b3c63bdc2273c377e7a83b78f076eca215887ea3624ffc36aaad03deb9ac8acd89e247fd4562b96e0f2b679485e20d8ff25f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -2124,12 +2152,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime-corejs3@npm:^7.10.2":
|
||||
version: 7.23.7
|
||||
resolution: "@babel/runtime-corejs3@npm:7.23.7"
|
||||
version: 7.23.8
|
||||
resolution: "@babel/runtime-corejs3@npm:7.23.8"
|
||||
dependencies:
|
||||
core-js-pure: "npm:^3.30.2"
|
||||
regenerator-runtime: "npm:^0.14.0"
|
||||
checksum: 7230942b6dadddd68334283068f360323c6df205542811bd7e37384ebfc0b5dcc266470db99e5905a8c6e3bb9898f7f066dde145b33b560acd271118ed9b41b2
|
||||
checksum: 2ccc006308dc0afb88dab5b91380be3a644a7616b9e33b6039eeceb11080541d566e8c29d1e81495c3983990c6843cb872bb150dd6c0f23f85fa9eb8d1fe20c5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -2161,11 +2189,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
|
||||
version: 7.23.7
|
||||
resolution: "@babel/runtime@npm:7.23.7"
|
||||
version: 7.23.8
|
||||
resolution: "@babel/runtime@npm:7.23.8"
|
||||
dependencies:
|
||||
regenerator-runtime: "npm:^0.14.0"
|
||||
checksum: 3e304133ee55b0750e03e53cb4efb47fb2bdcdb5795f85bbffa10595196c34b9be60eb65bd6d833c87f49fc827f0365f86f95f51d85b188004d3128bb5129c93
|
||||
checksum: ba5e8fbb32ef04f6cab5e89c54a0497c2fde7b730595cc1af93496270314f13ff2c6a9360fdb2f0bdd4d6b376752ce3cf85642bd6b876969a6a62954934c2df8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -2467,15 +2495,15 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@emotion/serialize@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@emotion/serialize@npm:1.1.2"
|
||||
version: 1.1.3
|
||||
resolution: "@emotion/serialize@npm:1.1.3"
|
||||
dependencies:
|
||||
"@emotion/hash": "npm:^0.9.1"
|
||||
"@emotion/memoize": "npm:^0.8.1"
|
||||
"@emotion/unitless": "npm:^0.8.1"
|
||||
"@emotion/utils": "npm:^1.2.1"
|
||||
csstype: "npm:^3.0.2"
|
||||
checksum: d243e0e5abce8d2183d25a32ec89bf650ee741ebadb29e6405abde05d4e2ed446ba5b3f725a29833ad709d0d08f0a5c8d0532fdcd43f4b23d931d8b6d4f218c1
|
||||
checksum: 875241eafaa30e7d3b7cf9b585d8c1f224cbf627a674e87eb1d7662dafa76a8c8d67f14a79dbf7d1eaa017e9f68389962990fbcc699d5ad65035a1a047432a3f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -4621,7 +4649,7 @@ __metadata:
|
||||
"@storybook/client-logger": "workspace:*"
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/theming": "workspace:*"
|
||||
@ -4668,7 +4696,7 @@ __metadata:
|
||||
"@storybook/client-logger": "workspace:*"
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/theming": "workspace:*"
|
||||
@ -4799,7 +4827,7 @@ __metadata:
|
||||
"@storybook/core-common": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/instrumenter": "workspace:*"
|
||||
"@storybook/jest": "npm:next"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
@ -4881,7 +4909,7 @@ __metadata:
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/types": "workspace:*"
|
||||
@ -4900,7 +4928,7 @@ __metadata:
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/types": "workspace:*"
|
||||
@ -4940,7 +4968,7 @@ __metadata:
|
||||
"@storybook/client-logger": "workspace:*"
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/theming": "workspace:*"
|
||||
@ -4973,7 +5001,7 @@ __metadata:
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/theming": "workspace:*"
|
||||
@ -5092,7 +5120,7 @@ __metadata:
|
||||
"@storybook/csf": "npm:^0.1.2"
|
||||
"@storybook/docs-tools": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/preview-api": "workspace:*"
|
||||
"@storybook/test": "workspace:*"
|
||||
@ -5103,7 +5131,7 @@ __metadata:
|
||||
color-convert: "npm:^2.0.1"
|
||||
dequal: "npm:^2.0.2"
|
||||
lodash: "npm:^4.17.21"
|
||||
markdown-to-jsx: "npm:^7.1.8"
|
||||
markdown-to-jsx: "npm:7.3.2"
|
||||
memoizerific: "npm:^1.11.3"
|
||||
polished: "npm:^4.2.2"
|
||||
react-colorful: "npm:^5.1.2"
|
||||
@ -5362,7 +5390,7 @@ __metadata:
|
||||
"@storybook/client-logger": "workspace:*"
|
||||
"@storybook/csf": "npm:^0.1.2"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/test": "workspace:*"
|
||||
"@storybook/theming": "workspace:*"
|
||||
"@storybook/types": "workspace:*"
|
||||
@ -5693,7 +5721,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@storybook/icons@npm:^1.2.1":
|
||||
"@storybook/icons@npm:^1.2.3":
|
||||
version: 1.2.3
|
||||
resolution: "@storybook/icons@npm:1.2.3"
|
||||
peerDependencies:
|
||||
@ -5799,7 +5827,7 @@ __metadata:
|
||||
"@storybook/components": "workspace:*"
|
||||
"@storybook/core-events": "workspace:*"
|
||||
"@storybook/global": "npm:^5.0.0"
|
||||
"@storybook/icons": "npm:^1.2.1"
|
||||
"@storybook/icons": "npm:^1.2.3"
|
||||
"@storybook/manager-api": "workspace:*"
|
||||
"@storybook/router": "workspace:*"
|
||||
"@storybook/test": "workspace:*"
|
||||
@ -5814,7 +5842,7 @@ __metadata:
|
||||
fs-extra: "npm:^11.1.0"
|
||||
fuse.js: "npm:^3.6.1"
|
||||
lodash: "npm:^4.17.21"
|
||||
markdown-to-jsx: "npm:^7.1.8"
|
||||
markdown-to-jsx: "npm:7.3.2"
|
||||
memoizerific: "npm:^1.11.3"
|
||||
polished: "npm:^4.2.2"
|
||||
qs: "npm:^6.10.0"
|
||||
@ -6105,7 +6133,6 @@ __metadata:
|
||||
memoizerific: "npm:^1.11.3"
|
||||
qs: "npm:^6.10.0"
|
||||
slash: "npm:^5.0.0"
|
||||
synchronous-promise: "npm:^2.0.15"
|
||||
ts-dedent: "npm:^2.0.0"
|
||||
util-deprecate: "npm:^1.0.2"
|
||||
languageName: unknown
|
||||
@ -8184,7 +8211,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@urql/core@npm:>=4.1.0, @urql/core@npm:^4.1.0":
|
||||
"@urql/core@npm:>=4.1.0":
|
||||
version: 4.2.2
|
||||
resolution: "@urql/core@npm:4.2.2"
|
||||
dependencies:
|
||||
"@0no-co/graphql.web": "npm:^1.0.1"
|
||||
wonka: "npm:^6.3.2"
|
||||
checksum: f1db8f3ca6e0c8e6257a8eb5b7057959a47086a7390af1329ef509f04a6d15f4fb42f9e990bd519526abff504a5524b5b89babdff01d5d61d800ed23ca87c067
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@urql/core@npm:^4.1.0":
|
||||
version: 4.2.0
|
||||
resolution: "@urql/core@npm:4.2.0"
|
||||
dependencies:
|
||||
@ -8428,6 +8465,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-core@npm:3.4.5":
|
||||
version: 3.4.5
|
||||
resolution: "@vue/compiler-core@npm:3.4.5"
|
||||
dependencies:
|
||||
"@babel/parser": "npm:^7.23.6"
|
||||
"@vue/shared": "npm:3.4.5"
|
||||
entities: "npm:^4.5.0"
|
||||
estree-walker: "npm:^2.0.2"
|
||||
source-map-js: "npm:^1.0.2"
|
||||
checksum: 31a4a431d515eb9b3783bc50ac08af9ca32be703453ed80a569ac29a83e896d7d6f876803db24eea9df0fbe2fc7e7e0fdf51013a6f6897ca7feb685583ae04d3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-core@npm:^3.0.0":
|
||||
version: 3.3.13
|
||||
resolution: "@vue/compiler-core@npm:3.3.13"
|
||||
@ -8450,7 +8500,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-dom@npm:3.3.11, @vue/compiler-dom@npm:^3.2.0, @vue/compiler-dom@npm:^3.3.0":
|
||||
"@vue/compiler-dom@npm:3.3.11":
|
||||
version: 3.3.11
|
||||
resolution: "@vue/compiler-dom@npm:3.3.11"
|
||||
dependencies:
|
||||
@ -8460,6 +8510,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-dom@npm:3.4.5, @vue/compiler-dom@npm:^3.2.0, @vue/compiler-dom@npm:^3.3.0":
|
||||
version: 3.4.5
|
||||
resolution: "@vue/compiler-dom@npm:3.4.5"
|
||||
dependencies:
|
||||
"@vue/compiler-core": "npm:3.4.5"
|
||||
"@vue/shared": "npm:3.4.5"
|
||||
checksum: a2f8703792c97e4949d9ffce9de0d2d40a8d09d8412017c8f69fa4aab4f4dd46a2d10138bae3bdeab12fca4bf67d6a8e23114ca592f7d9a577f3b745fa7191a2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-sfc@npm:3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "@vue/compiler-sfc@npm:3.0.0"
|
||||
@ -8486,7 +8546,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-sfc@npm:3.3.11, @vue/compiler-sfc@npm:^3.2.0, @vue/compiler-sfc@npm:^3.2.33":
|
||||
"@vue/compiler-sfc@npm:3.3.11":
|
||||
version: 3.3.11
|
||||
resolution: "@vue/compiler-sfc@npm:3.3.11"
|
||||
dependencies:
|
||||
@ -8504,6 +8564,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-sfc@npm:^3.2.0, @vue/compiler-sfc@npm:^3.2.33":
|
||||
version: 3.4.5
|
||||
resolution: "@vue/compiler-sfc@npm:3.4.5"
|
||||
dependencies:
|
||||
"@babel/parser": "npm:^7.23.6"
|
||||
"@vue/compiler-core": "npm:3.4.5"
|
||||
"@vue/compiler-dom": "npm:3.4.5"
|
||||
"@vue/compiler-ssr": "npm:3.4.5"
|
||||
"@vue/shared": "npm:3.4.5"
|
||||
estree-walker: "npm:^2.0.2"
|
||||
magic-string: "npm:^0.30.5"
|
||||
postcss: "npm:^8.4.32"
|
||||
source-map-js: "npm:^1.0.2"
|
||||
checksum: fa3f0a64e2afa02836d188a9bb0314f51fd1b45bf8609d6fe401bee97edd492775dabf3da61d93a10a86a0eb2c794ef994cc2a7f8cd6b96de8a4ab0e52f6b126
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-ssr@npm:3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "@vue/compiler-ssr@npm:3.0.0"
|
||||
@ -8524,6 +8601,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/compiler-ssr@npm:3.4.5":
|
||||
version: 3.4.5
|
||||
resolution: "@vue/compiler-ssr@npm:3.4.5"
|
||||
dependencies:
|
||||
"@vue/compiler-dom": "npm:3.4.5"
|
||||
"@vue/shared": "npm:3.4.5"
|
||||
checksum: 4d62fb820e3794f44c16fc61d29544755a1398ced7ee11a38a67ad25b2e114bb0ae6e7066f0501103e31b88e04c49bbf82fbfb2a6735bbc9a186b579789ef906
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/language-core@npm:1.8.15":
|
||||
version: 1.8.15
|
||||
resolution: "@vue/language-core@npm:1.8.15"
|
||||
@ -8637,7 +8724,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/shared@npm:3.3.11, @vue/shared@npm:^3.3.0":
|
||||
"@vue/shared@npm:3.3.11":
|
||||
version: 3.3.11
|
||||
resolution: "@vue/shared@npm:3.3.11"
|
||||
checksum: 164b904ed6c5a6e9b0d4c6ac38a214770943d5b1196e8af7193f7f9f099706ffd7627e40c95a9b4de430ff7d3523a713c9236ef6e8ca48dd6865606efb7208f5
|
||||
@ -8651,6 +8738,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/shared@npm:3.4.5, @vue/shared@npm:^3.3.0":
|
||||
version: 3.4.5
|
||||
resolution: "@vue/shared@npm:3.4.5"
|
||||
checksum: 4bd4f6a6369ab02b8a01ac3b93fb5d580d3ea0e9781dd2be8ab676b50521733acbc85fac6b48bc9cd3704dc9237d6365148d287da51c07e1d0568d6c0f7742a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@vue/typescript@npm:1.8.15":
|
||||
version: 1.8.15
|
||||
resolution: "@vue/typescript@npm:1.8.15"
|
||||
@ -8959,14 +9053,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"acorn-walk@npm:^8.1.1":
|
||||
version: 8.2.0
|
||||
resolution: "acorn-walk@npm:8.2.0"
|
||||
checksum: dbe92f5b2452c93e960c5594e666dd1fae141b965ff2cb4a1e1d0381e3e4db4274c5ce4ffa3d681a86ca2a8d4e29d5efc0670a08e23fd2800051ea387df56ca2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"acorn-walk@npm:^8.3.0":
|
||||
"acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.3.0":
|
||||
version: 8.3.1
|
||||
resolution: "acorn-walk@npm:8.3.1"
|
||||
checksum: a23d2f7c6b6cad617f4c77f14dfeb062a239208d61753e9ba808d916c550add92b39535467d2e6028280761ac4f5a904cc9df21530b84d3f834e3edef74ddde5
|
||||
@ -9840,20 +9927,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-polyfill-corejs2@npm:^0.4.6":
|
||||
version: 0.4.6
|
||||
resolution: "babel-plugin-polyfill-corejs2@npm:0.4.6"
|
||||
dependencies:
|
||||
"@babel/compat-data": "npm:^7.22.6"
|
||||
"@babel/helper-define-polyfill-provider": "npm:^0.4.3"
|
||||
semver: "npm:^6.3.1"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
checksum: 64a98811f343492aa6970ab253760194e389c0417e5b830522f944009c1f0c78e1251975fd1b9869cd48cc4623111b20a3389cf6732a1d10ba0d19de6fa5114f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-polyfill-corejs2@npm:^0.4.7":
|
||||
"babel-plugin-polyfill-corejs2@npm:^0.4.6, babel-plugin-polyfill-corejs2@npm:^0.4.7":
|
||||
version: 0.4.7
|
||||
resolution: "babel-plugin-polyfill-corejs2@npm:0.4.7"
|
||||
dependencies:
|
||||
@ -9866,19 +9940,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-polyfill-corejs3@npm:^0.8.5":
|
||||
version: 0.8.6
|
||||
resolution: "babel-plugin-polyfill-corejs3@npm:0.8.6"
|
||||
dependencies:
|
||||
"@babel/helper-define-polyfill-provider": "npm:^0.4.3"
|
||||
core-js-compat: "npm:^3.33.1"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
checksum: 97d974c1dfbefdf27866e21a1ac757f6ab1626379b544d6f8ddb05f7bfa02173f8347b6140295b0f770394549f9321775d3048e466a9a02b99b88ad5f0346858
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-polyfill-corejs3@npm:^0.8.7":
|
||||
"babel-plugin-polyfill-corejs3@npm:^0.8.5, babel-plugin-polyfill-corejs3@npm:^0.8.7":
|
||||
version: 0.8.7
|
||||
resolution: "babel-plugin-polyfill-corejs3@npm:0.8.7"
|
||||
dependencies:
|
||||
@ -9890,18 +9952,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-polyfill-regenerator@npm:^0.5.3":
|
||||
version: 0.5.3
|
||||
resolution: "babel-plugin-polyfill-regenerator@npm:0.5.3"
|
||||
dependencies:
|
||||
"@babel/helper-define-polyfill-provider": "npm:^0.4.3"
|
||||
peerDependencies:
|
||||
"@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0
|
||||
checksum: cc32313b9ebbf1d7bedc33524a861136b9e5d3b6e9be317ac360a1c2a59ae5ed1b465a6c68b2715cdefb089780ddfb0c11f4a148e49827a947beee76e43da598
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"babel-plugin-polyfill-regenerator@npm:^0.5.4":
|
||||
"babel-plugin-polyfill-regenerator@npm:^0.5.3, babel-plugin-polyfill-regenerator@npm:^0.5.4":
|
||||
version: 0.5.4
|
||||
resolution: "babel-plugin-polyfill-regenerator@npm:0.5.4"
|
||||
dependencies:
|
||||
@ -11882,7 +11933,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cosmiconfig@npm:^8.2.0":
|
||||
"cosmiconfig@npm:^8.2.0, cosmiconfig@npm:^8.3.5":
|
||||
version: 8.3.6
|
||||
resolution: "cosmiconfig@npm:8.3.6"
|
||||
dependencies:
|
||||
@ -13338,7 +13389,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"entities@npm:^4.2.0, entities@npm:^4.3.0, entities@npm:^4.4.0":
|
||||
"entities@npm:^4.2.0, entities@npm:^4.3.0, entities@npm:^4.4.0, entities@npm:^4.5.0":
|
||||
version: 4.5.0
|
||||
resolution: "entities@npm:4.5.0"
|
||||
checksum: 5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250
|
||||
@ -15027,7 +15078,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.15.0":
|
||||
"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.14.0":
|
||||
version: 1.15.4
|
||||
resolution: "follow-redirects@npm:1.15.4"
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
checksum: 5f37ed9170c9eb19448c5418fdb0f2b73f644b5364834e70791a76ecc7db215246f9773bbef4852cfae4067764ffc852e047f744b661b0211532155b73556a6a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.15.0":
|
||||
version: 1.15.3
|
||||
resolution: "follow-redirects@npm:1.15.3"
|
||||
peerDependenciesMeta:
|
||||
@ -15502,7 +15563,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-func-name@npm:^2.0.0, get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2":
|
||||
"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "get-func-name@npm:2.0.2"
|
||||
checksum: 89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df
|
||||
@ -17669,14 +17730,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0":
|
||||
version: 3.2.0
|
||||
resolution: "istanbul-lib-coverage@npm:3.2.0"
|
||||
checksum: 10ecb00a50cac2f506af8231ce523ffa1ac1310db0435c8ffaabb50c1d72539906583aa13c84f8835dc103998b9989edc3c1de989d2e2a96a91a9ba44e5db6b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"istanbul-lib-coverage@npm:^3.2.2":
|
||||
"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0, istanbul-lib-coverage@npm:^3.2.2":
|
||||
version: 3.2.2
|
||||
resolution: "istanbul-lib-coverage@npm:3.2.2"
|
||||
checksum: 6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b
|
||||
@ -17981,12 +18035,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jiti@npm:^1.18.2":
|
||||
version: 1.20.0
|
||||
resolution: "jiti@npm:1.20.0"
|
||||
"jiti@npm:^1.18.2, jiti@npm:^1.20.0":
|
||||
version: 1.21.0
|
||||
resolution: "jiti@npm:1.21.0"
|
||||
bin:
|
||||
jiti: bin/jiti.js
|
||||
checksum: e71999db5e436d38c32ca713c3688b5da2a686f264584d927dcca80a4eaece83af7dd32c047524e74084bb11bdfa148f5f91b7e9a0044b4803feffe3c2c30dbc
|
||||
checksum: 7f361219fe6c7a5e440d5f1dba4ab763a5538d2df8708cdc22561cf25ea3e44b837687931fca7cdd8cdd9f567300e90be989dd1321650045012d8f9ed6aab07f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -19049,16 +19103,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^2.3.6":
|
||||
version: 2.3.6
|
||||
resolution: "loupe@npm:2.3.6"
|
||||
dependencies:
|
||||
get-func-name: "npm:^2.0.0"
|
||||
checksum: a974841ce94ef2a35aac7144e7f9e789e3887f82286cd9ffe7ff00f2ac9d117481989948657465e2b0b102f23136d89ae0a18fd4a32d9015012cd64464453289
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loupe@npm:^2.3.7":
|
||||
"loupe@npm:^2.3.6, loupe@npm:^2.3.7":
|
||||
version: 2.3.7
|
||||
resolution: "loupe@npm:2.3.7"
|
||||
dependencies:
|
||||
@ -19347,7 +19392,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"markdown-to-jsx@npm:^7.1.8":
|
||||
"markdown-to-jsx@npm:7.3.2":
|
||||
version: 7.3.2
|
||||
resolution: "markdown-to-jsx@npm:7.3.2"
|
||||
peerDependencies:
|
||||
@ -22983,7 +23028,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-loader@npm:7.3.3, postcss-loader@npm:^7.0.2":
|
||||
"postcss-loader@npm:7.3.3":
|
||||
version: 7.3.3
|
||||
resolution: "postcss-loader@npm:7.3.3"
|
||||
dependencies:
|
||||
@ -22997,6 +23042,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-loader@npm:^7.0.2":
|
||||
version: 7.3.4
|
||||
resolution: "postcss-loader@npm:7.3.4"
|
||||
dependencies:
|
||||
cosmiconfig: "npm:^8.3.5"
|
||||
jiti: "npm:^1.20.0"
|
||||
semver: "npm:^7.5.4"
|
||||
peerDependencies:
|
||||
postcss: ^7.0.0 || ^8.0.1
|
||||
webpack: ^5.0.0
|
||||
checksum: 1bf7614aeea9ad1f8ee6be3a5451576c059391688ea67f825aedc2674056369597faeae4e4a81fe10843884c9904a71403d9a54197e1f560e8fbb9e61f2a2680
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"postcss-modules-extract-imports@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "postcss-modules-extract-imports@npm:2.0.0"
|
||||
@ -23631,14 +23690,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"punycode@npm:^2.1.0, punycode@npm:^2.1.1":
|
||||
version: 2.3.0
|
||||
resolution: "punycode@npm:2.3.0"
|
||||
checksum: 8e6f7abdd3a6635820049e3731c623bbef3fedbf63bbc696b0d7237fdba4cefa069bc1fa62f2938b0fbae057550df7b5318f4a6bcece27f1907fc75c54160bee
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"punycode@npm:^2.3.1":
|
||||
"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "punycode@npm:2.3.1"
|
||||
checksum: 14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9
|
||||
@ -27124,13 +27176,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"synchronous-promise@npm:^2.0.15":
|
||||
version: 2.0.17
|
||||
resolution: "synchronous-promise@npm:2.0.17"
|
||||
checksum: 1babe643d8417789ef6e5a2f3d4b8abcda2de236acd09bbe2c98f6be82c0a2c92ed21a6e4f934845fa8de18b1435a9cba1e8c3d945032e8a532f076224c024b1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0, tapable@npm:^2.2.1":
|
||||
version: 2.2.1
|
||||
resolution: "tapable@npm:2.2.1"
|
||||
@ -27272,7 +27317,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"terser@npm:5.24.0, terser@npm:^5.10.0, terser@npm:^5.16.8":
|
||||
"terser@npm:5.24.0, terser@npm:^5.16.8":
|
||||
version: 5.24.0
|
||||
resolution: "terser@npm:5.24.0"
|
||||
dependencies:
|
||||
@ -27286,6 +27331,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"terser@npm:^5.10.0":
|
||||
version: 5.26.0
|
||||
resolution: "terser@npm:5.26.0"
|
||||
dependencies:
|
||||
"@jridgewell/source-map": "npm:^0.3.3"
|
||||
acorn: "npm:^8.8.2"
|
||||
commander: "npm:^2.20.0"
|
||||
source-map-support: "npm:~0.5.20"
|
||||
bin:
|
||||
terser: bin/terser
|
||||
checksum: 3906289c6bacd75804a47a583cdafefbd76c5edb39435369755c7b1592e57586fb2f4bddf6eb37a807d6e782171dbf0aa7bbdc80fd5b77b2f2b62196cac49b62
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"test-exclude@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "test-exclude@npm:6.0.0"
|
||||
@ -27896,11 +27955,11 @@ __metadata:
|
||||
|
||||
"typescript@patch:typescript@npm%3A^5.0.3#optional!builtin<compat/typescript>, typescript@patch:typescript@npm%3A^5.3.2#optional!builtin<compat/typescript>":
|
||||
version: 5.3.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin<compat/typescript>::version=5.3.3&hash=29ae49"
|
||||
resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin<compat/typescript>::version=5.3.3&hash=e012d7"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: e22df47df9b2b2f2617b8bf511a29aea3d177f9f7a0756818230a76b01cbd7da988bf55f9463aaa1a4c1ff90b80f8dc5676460d4e9dfc010572cbba59b822b0c
|
||||
checksum: 1d0a5f4ce496c42caa9a30e659c467c5686eae15d54b027ee7866744952547f1be1262f2d40de911618c242b510029d51d43ff605dba8fb740ec85ca2d3f9500
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -124,14 +124,14 @@ Provides HTML class(es) to the preview element, for custom styling.
|
||||
|
||||
### `layout`
|
||||
|
||||
Type: `'padded' | 'centered' | 'fullscreen'`
|
||||
Type: `'centered' | 'fullscreen' | 'padded'`
|
||||
|
||||
Default: `parameters.layout` or `parameters.docs.canvas.layout` or `'padded'`
|
||||
|
||||
Specifies how the canvas should layout the story.
|
||||
|
||||
- **padded**: Add padding to the story
|
||||
- **centered**: Center the story within the canvas
|
||||
- **padded**: (default) Add padding to the story
|
||||
- **fullscreen**: Show the story as-is, without padding
|
||||
|
||||
In addition to the `parameters.docs.canvas.layout` property or the `layout` prop, the `Canvas` block will respect the `parameters.layout` value that defines [how a story is laid out](../configure/story-layout.md) in the regular story view.
|
||||
|
@ -79,6 +79,12 @@ An overview of all available API references for Storybook.
|
||||
about args that are not explicitly set.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="../api/parameters">Parameters</a></td>
|
||||
<td>
|
||||
Parameters are static metadata used to configure your <a href="../get-started/whats-a-story.md">stories</a> <a href="../addons/introduction.md">addons</a> in Storybook. They are specified at the story, meta (component), project (global) levels.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -9,34 +9,13 @@ Type:
|
||||
```ts
|
||||
{
|
||||
argTypeTargetsV7?: boolean;
|
||||
buildStoriesJson?: boolean;
|
||||
legacyDecoratorFileOrder?: boolean;
|
||||
legacyMdx1?: boolean;
|
||||
storyStoreV7?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
Enables Storybook's additional features.
|
||||
|
||||
## `buildStoriesJson`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Default: `true`, when [`storyStoreV7`](#storystorev7) is `true`
|
||||
|
||||
Generates a `index.json` and `stories.json` files to help story loading with the on-demand mode.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/main-config-features-build-stories-json.js.mdx',
|
||||
'common/main-config-features-build-stories-json.ts.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## `legacyDecoratorFileOrder`
|
||||
|
||||
Type: `boolean`
|
||||
@ -54,25 +33,6 @@ Apply decorators from preview.js before decorators from addons or frameworks. [M
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## `storyStoreV7`
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Default: `true`
|
||||
|
||||
Opts out of [on-demand story loading](#on-demand-story-loading); loads all stories at build time.
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/main-config-features-story-store-v7.js.mdx',
|
||||
'common/main-config-features-story-store-v7.ts.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## `argTypeTargetsV7`
|
||||
|
||||
(⚠️ **Experimental**)
|
||||
@ -91,25 +51,3 @@ Filter args with a "target" on the type from the render function.
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
## On-demand story loading
|
||||
|
||||
As your Storybook grows, it gets challenging to load all of your stories performantly, slowing down the loading times and yielding a large bundle. Out of the box, Storybook loads your stories on demand rather than during boot-up to improve the performance of your Storybook. If you need to load all of your stories during boot-up, you can disable this feature by setting the `storyStoreV7` feature flag to `false` in your configuration as follows:
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
|
||||
<CodeSnippets
|
||||
paths={[
|
||||
'common/main-config-features-story-store-v7.js.mdx',
|
||||
'common/main-config-features-story-store-v7.ts.mdx',
|
||||
]}
|
||||
/>
|
||||
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
### Known limitations
|
||||
|
||||
Because of the way stories are currently indexed in Storybook, loading stories on demand with `storyStoreV7` has a couple of minor limitations at the moment:
|
||||
|
||||
- [CSF formats](../api/csf.md) from version 1 to version 3 are supported. The `storiesOf` construct is not.
|
||||
- Custom [`storySort` functions](../writing-stories/naming-components-and-hierarchy.md#sorting-stories) receive more limited arguments.
|
||||
|
@ -117,7 +117,7 @@ When [auto-titling](../configure/sidebar-and-urls.md#csf-30-auto-titles), prefix
|
||||
|
||||
<Callout variant="info" icon="💡">
|
||||
|
||||
With [`storyStoreV7`](./main-config-features.md#storystorev7) (the default in Storybook 7), Storybook now statically analyzes the configuration file to improve performance. Loading stories with a custom implementation may de-optimize or break this ability.
|
||||
💡 Storybook now statically analyzes the configuration file to improve performance. Loading stories with a custom implementation may de-optimize or break this ability.
|
||||
|
||||
</Callout>
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user