diff --git a/MIGRATION.md b/MIGRATION.md
index a16d22e00d34..22bd0a923f32 100644
--- a/MIGRATION.md
+++ b/MIGRATION.md
@@ -1,10 +1,12 @@
Migration
- [From version 8.0.x to 8.1.x](#from-version-80x-to-81x)
- - [Subtitle block and `parameters.componentSubtitle`](#subtitle-block-and-parameterscomponentsubtitle)
- - [Title block](#title-block)
- [Portable stories](#portable-stories)
- [@storybook/nextjs requires specific path aliases to be setup](#storybooknextjs-requires-specific-path-aliases-to-be-setup)
+ - [main.js `docs.autodocs` is deprecated](#mainjs-docsautodocs-is-deprecated)
+ - [`docs` and `story` system tags removed](#docs-and-story-system-tags-removed)
+ - [Subtitle block and `parameters.componentSubtitle`](#subtitle-block-and-parameterscomponentsubtitle)
+ - [Title block `of` prop](#title-block-of-prop)
- [From version 7.x to 8.0.0](#from-version-7x-to-800)
- [Portable stories](#portable-stories-1)
- [Project annotations are now merged instead of overwritten in composeStory](#project-annotations-are-now-merged-instead-of-overwritten-in-composestory)
@@ -430,13 +432,51 @@ module.exports = createJestConfig(customJestConfig);
This will make sure you end using the correct implementation of the packages and avoid having issues in your tests.
+### main.js `docs.autodocs` is deprecated
+
+The `docs.autodocs` setting in `main.js` is deprecated in 8.1 and will be removed in 9.0.
+
+It has been replaced with a tags-based system which is more flexible than before.
+
+`docs.autodocs` takes three values:
+- `true`: generate autodocs for every component
+- `false`: don't generate autodocs at all
+- `tag`: generate autodocs for components that have been tagged `'autodocs'`.
+
+Starting in 8.1, to generate autodocs for every component (`docs.autodocs = true`), add the following code to `.storybook/preview.js`:
+
+```js
+// .storybook/preview.js
+export default {
+ tags: ['autodocs'],
+}
+```
+
+Tags cascade, so setting `'autodocs'` at the project level automatically propagates to every component and story. If you set autodocs globally and want to opt-out for a particular component, you can remove the `'autodocs'` tag for a component like this:
+
+```js
+// Button.stories.ts
+export default {
+ component: Button,
+ tags: ['!autodocs'],
+}
+```
+
+If you had set `docs.autodocs = 'tag'`, the default setting, you can remove the setting from `.storybook/main.js`. That is now the default behavior.
+
+If you had set `docs.autodocs = false`, this still works in 8.x, but will go away in 9.0 as a breaking change. If you don't want autodocs at all, simply remove the `'autodocs'` tag throughout your Storybook and autodocs will not be created.
+
+### `docs` and `story` system tags removed
+
+Storybook automatically added the tag `'docs'` to any docs entry in the index and `'story'` to any story entry in the index. This behavior was undocumented, and in an effort to reduce the number of tags we've removed them in 8.1. If you depended on these tags, please file an issue on the [Storybook monorepo](https://github.com/storybookjs/storybook) and let us know!
+
### Subtitle block and `parameters.componentSubtitle`
The `Subtitle` block now accepts an `of` prop, which can be a reference to a CSF file or a default export (meta).
`parameters.componentSubtitle` has been deprecated to be consistent with other parameters related to autodocs, instead use `parameters.docs.subtitle`.
-##### Title block
+### Title block `of` prop
The `Title` block now accepts an `of` prop, which can be a reference to a CSF file or a default export (meta).
diff --git a/code/addons/docs/src/preview.ts b/code/addons/docs/src/preview.ts
index 991a7811b472..7a352b15b0a6 100644
--- a/code/addons/docs/src/preview.ts
+++ b/code/addons/docs/src/preview.ts
@@ -22,7 +22,9 @@ export const parameters: any = {
filter: (story: PreparedStory) => {
const tags = story.tags || [];
return (
- tags.filter((tag) => excludeTags[tag]).length === 0 && !story.parameters.docs?.disable
+ tags.includes('autodocs') &&
+ tags.filter((tag) => excludeTags[tag]).length === 0 &&
+ !story.parameters.docs?.disable
);
},
},
diff --git a/code/addons/links/package.json b/code/addons/links/package.json
index 785c56ba7b87..0155bf1635de 100644
--- a/code/addons/links/package.json
+++ b/code/addons/links/package.json
@@ -67,7 +67,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/addon-bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/global": "^5.0.0",
"ts-dedent": "^2.0.0"
},
diff --git a/code/e2e-tests/tags.spec.ts b/code/e2e-tests/tags.spec.ts
index 8302a9a6a338..da3637deb7e9 100644
--- a/code/e2e-tests/tags.spec.ts
+++ b/code/e2e-tests/tags.spec.ts
@@ -9,56 +9,96 @@ test.describe('tags', () => {
await new SbPage(page).waitUntilLoaded();
});
- test('@flaky: should correctly filter dev-only, docs-only, test-only stories', async ({
- page,
- }) => {
+ test('should correctly filter dev-only, docs-only, test-only stories', async ({ page }) => {
const sbPage = new SbPage(page);
- await sbPage.navigateToStory('lib/preview-api/tags', 'docs');
+ await sbPage.navigateToStory('lib/preview-api/tags-config', 'docs');
// Sidebar should include dev-only and exclude docs-only and test-only
- const devOnlyEntry = await page.locator('#lib-preview-api-tags--dev-only').all();
+ const devOnlyEntry = await page.locator('#lib-preview-api-tags-config--dev-only').all();
expect(devOnlyEntry.length).toBe(1);
- const docsOnlyEntry = await page.locator('#lib-preview-api-tags--docs-only').all();
+ const docsOnlyEntry = await page.locator('#lib-preview-api-tags-config--docs-only').all();
expect(docsOnlyEntry.length).toBe(0);
- const testOnlyEntry = await page.locator('#lib-preview-api-tags--test-only').all();
+ const testOnlyEntry = await page.locator('#lib-preview-api-tags-config--test-only').all();
expect(testOnlyEntry.length).toBe(0);
// Autodocs should include docs-only and exclude dev-only and test-only
const root = sbPage.previewRoot();
- const devOnlyAnchor = await root.locator('#anchor--lib-preview-api-tags--dev-only').all();
+ const devOnlyAnchor = await root
+ .locator('#anchor--lib-preview-api-tags-config--dev-only')
+ .all();
expect(devOnlyAnchor.length).toBe(0);
- const docsOnlyAnchor = await root.locator('#anchor--lib-preview-api-tags--docs-only').all();
+ const docsOnlyAnchor = await root
+ .locator('#anchor--lib-preview-api-tags-config--docs-only')
+ .all();
expect(docsOnlyAnchor.length).toBe(1);
- const testOnlyAnchor = await root.locator('#anchor--lib-preview-api-tags--test-only').all();
+ const testOnlyAnchor = await root
+ .locator('#anchor--lib-preview-api-tags-config--test-only')
+ .all();
expect(testOnlyAnchor.length).toBe(0);
});
- test('should correctly filter out test-only autodocs pages', async ({ page }) => {
+ test('should correctly add dev, autodocs, test stories', async ({ page }) => {
const sbPage = new SbPage(page);
- await sbPage.selectToolbar('#lib-preview-api');
+ await sbPage.navigateToStory('lib/preview-api/tags-add', 'docs');
- // Sidebar should exclude test-only stories and their docs
- const componentEntry = await page.locator('#lib-preview-api-test-only-tag').all();
- expect(componentEntry.length).toBe(0);
+ // Sidebar should include dev and exclude inheritance, autodocs, test
+ const devEntry = await page.locator('#lib-preview-api-tags-add--dev').all();
+ expect(devEntry.length).toBe(1);
- // Even though test-only autodocs not sidebar, it is still in the preview
- // Even though the test-only story is filtered out of the stories, it is still the primary story (should it be?)
- await sbPage.deepLinkToStory(storybookUrl, 'lib/preview-api/test-only-tag', 'docs');
- await sbPage.waitUntilLoaded();
- const docsButton = await sbPage.previewRoot().locator('button', { hasText: 'Button' });
- await expect(docsButton).toBeVisible();
+ const autodocsEntry = await page.locator('#lib-preview-api-tags-add--autodocs').all();
+ expect(autodocsEntry.length).toBe(0);
- // Even though test-only story not sidebar, it is still in the preview
- await sbPage.deepLinkToStory(storybookUrl, 'lib/preview-api/test-only-tag', 'default');
- await sbPage.waitUntilLoaded();
- const storyButton = await sbPage.previewRoot().locator('button', { hasText: 'Button' });
- await expect(storyButton).toBeVisible();
+ const testOnlyEntry = await page.locator('#lib-preview-api-tags-add--test').all();
+ expect(testOnlyEntry.length).toBe(0);
+
+ // Autodocs should include autodocs and exclude dev, test
+ const root = sbPage.previewRoot();
+
+ const devAnchor = await root.locator('#anchor--lib-preview-api-tags-add--dev').all();
+ expect(devAnchor.length).toBe(0);
+
+ // FIXME: shows as primary story and also in stories, inconsistent btw dev/CI?
+ const autodocsAnchor = await root.locator('#anchor--lib-preview-api-tags-add--autodocs').all();
+ expect(autodocsAnchor.length).not.toBe(0);
+
+ const testAnchor = await root.locator('#anchor--lib-preview-api-tags-add--test').all();
+ expect(testAnchor.length).toBe(0);
+ });
+
+ test('should correctly remove dev, autodocs, test stories', async ({ page }) => {
+ const sbPage = new SbPage(page);
+
+ await sbPage.navigateToStory('lib/preview-api/tags-remove', 'docs');
+
+ // Sidebar should include inheritance, no-autodocs, no-test. and exclude no-dev
+ const noDevEntry = await page.locator('#lib-preview-api-tags-remove--no-dev').all();
+ expect(noDevEntry.length).toBe(0);
+
+ const noAutodocsEntry = await page.locator('#lib-preview-api-tags-remove--no-autodocs').all();
+ expect(noAutodocsEntry.length).toBe(1);
+
+ const noTestEntry = await page.locator('#lib-preview-api-tags-remove--no-test').all();
+ expect(noTestEntry.length).toBe(1);
+
+ // Autodocs should include inheritance, no-dev, no-test. and exclude no-autodocs
+ const root = sbPage.previewRoot();
+
+ const noDevAnchor = await root.locator('#anchor--lib-preview-api-tags-remove--no-dev').all();
+ expect(noDevAnchor.length).toBe(1);
+
+ const noAutodocsAnchor = await root
+ .locator('#anchor--lib-preview-api-tags-remove--no-autodocs')
+ .all();
+ expect(noAutodocsAnchor.length).toBe(0);
+
+ const noTestAnchor = await root.locator('#anchor--lib-preview-api-tags-remove--no-test').all();
+ expect(noTestAnchor.length).toBe(1);
});
});
diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts
index 2f85d0af4549..44f1214c0aa6 100644
--- a/code/lib/cli/src/generators/baseGenerator.ts
+++ b/code/lib/cli/src/generators/baseGenerator.ts
@@ -354,7 +354,6 @@ export async function baseGenerator(
},
prefixes,
storybookConfigFolder,
- docs: { autodocs: 'tag' },
addons: shouldApplyRequireWrapperOnPackageNames
? addons.map((addon) => applyRequireWrapper(addon))
: addons,
diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json
index 372a02e07daf..651182b854fc 100644
--- a/code/lib/codemod/package.json
+++ b/code/lib/codemod/package.json
@@ -57,7 +57,7 @@
"@babel/core": "^7.24.4",
"@babel/preset-env": "^7.24.4",
"@babel/types": "^7.24.0",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/csf-tools": "workspace:*",
"@storybook/node-logger": "workspace:*",
"@storybook/types": "workspace:*",
diff --git a/code/lib/core-events/package.json b/code/lib/core-events/package.json
index 9ea0fb4dddb0..7079b244b78e 100644
--- a/code/lib/core-events/package.json
+++ b/code/lib/core-events/package.json
@@ -78,7 +78,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.5",
+ "@storybook/csf": "^0.1.7",
"ts-dedent": "^2.0.0"
},
"devDependencies": {
diff --git a/code/lib/core-server/package.json b/code/lib/core-server/package.json
index 9d4850f18142..67f33e9fa492 100644
--- a/code/lib/core-server/package.json
+++ b/code/lib/core-server/package.json
@@ -63,9 +63,9 @@
"@storybook/channels": "workspace:*",
"@storybook/core-common": "workspace:*",
"@storybook/core-events": "workspace:*",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/csf-tools": "workspace:*",
- "@storybook/docs-mdx": "3.0.0",
+ "@storybook/docs-mdx": "3.1.0-next.0",
"@storybook/global": "^5.0.0",
"@storybook/manager": "workspace:*",
"@storybook/manager-api": "workspace:*",
diff --git a/code/lib/core-server/src/presets/common-manager.ts b/code/lib/core-server/src/presets/common-manager.ts
index 0564f8e00b92..bbc5432eeb31 100644
--- a/code/lib/core-server/src/presets/common-manager.ts
+++ b/code/lib/core-server/src/presets/common-manager.ts
@@ -18,7 +18,11 @@ addons.register(STATIC_FILTER, (api) => {
);
api.experimental_setFilter(STATIC_FILTER, (item) => {
- const tags = item.tags || [];
- return tags.filter((tag) => excludeTags[tag]).length === 0;
+ const tags = item.tags ?? [];
+ return (
+ // we can filter out the primary story, but we still want to show autodocs
+ (tags.includes('dev') || item.type === 'docs') &&
+ tags.filter((tag) => excludeTags[tag]).length === 0
+ );
});
});
diff --git a/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts b/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
index ad4aafd4a26e..0e51a725470a 100644
--- a/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
+++ b/code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
@@ -79,9 +79,10 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -110,8 +111,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/F.story.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "F",
"type": "story",
@@ -140,8 +142,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "stories",
"type": "story",
@@ -170,8 +173,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/nested/Button.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
- "story",
],
"title": "nested/Button",
"type": "story",
@@ -181,7 +185,8 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/second-nested/G.stories.ts",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "second-nested/G",
"type": "story",
@@ -210,9 +215,10 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -222,8 +228,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/B.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "B",
"type": "story",
@@ -233,8 +240,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/D.stories.jsx",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "D",
"type": "story",
@@ -244,7 +252,8 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/first-nested/deeply/F.stories.js",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "first-nested/deeply/F",
"type": "story",
@@ -254,8 +263,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/H.stories.mjs",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "H",
"type": "story",
@@ -265,8 +275,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/nested/Button.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
- "story",
],
"title": "nested/Button",
"type": "story",
@@ -276,7 +287,8 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/second-nested/G.stories.ts",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "second-nested/G",
"type": "story",
@@ -310,9 +322,10 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -323,8 +336,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "B",
"type": "docs",
@@ -334,8 +348,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/B.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "B",
"type": "story",
@@ -346,8 +361,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "D",
"type": "docs",
@@ -357,8 +373,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/D.stories.jsx",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "D",
"type": "story",
@@ -368,7 +385,8 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/first-nested/deeply/F.stories.js",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "first-nested/deeply/F",
"type": "story",
@@ -379,8 +397,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "H",
"type": "docs",
@@ -390,8 +409,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/H.stories.mjs",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "H",
"type": "story",
@@ -401,8 +421,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/nested/Button.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
- "story",
],
"title": "nested/Button",
"type": "story",
@@ -412,7 +433,8 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/second-nested/G.stories.ts",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "second-nested/G",
"type": "story",
@@ -535,8 +557,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "B",
"type": "docs",
@@ -549,8 +572,10 @@ describe('StoryIndexGenerator', () => {
"./src/B.stories.ts",
],
"tags": [
+ "dev",
+ "test",
+ "autodocs",
"attached-mdx",
- "docs",
],
"title": "B",
"type": "docs",
@@ -560,8 +585,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/B.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "B",
"type": "story",
@@ -594,8 +620,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "B",
"type": "docs",
@@ -608,8 +635,10 @@ describe('StoryIndexGenerator', () => {
"./src/B.stories.ts",
],
"tags": [
+ "dev",
+ "test",
+ "autodocs",
"attached-mdx",
- "docs",
],
"title": "B",
"type": "docs",
@@ -619,8 +648,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/B.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "B",
"type": "story",
@@ -659,8 +689,12 @@ describe('StoryIndexGenerator', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "autodocs",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -670,9 +704,11 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
+ "autodocs",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -703,8 +739,9 @@ describe('StoryIndexGenerator', () => {
"./duplicate/SecondA.stories.js",
],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "duplicate/A",
"type": "docs",
@@ -714,8 +751,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./duplicate/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "duplicate/A",
"type": "story",
@@ -725,8 +763,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./duplicate/SecondA.stories.js",
"name": "Story Two",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "duplicate/A",
"type": "story",
@@ -773,8 +812,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"autodocs",
- "docs",
],
"title": "A",
"type": "docs",
@@ -784,8 +824,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./docs-id-generation/A.stories.jsx",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "A",
"type": "story",
@@ -813,8 +854,11 @@ describe('StoryIndexGenerator', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -827,8 +871,11 @@ describe('StoryIndexGenerator', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -838,9 +885,10 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -851,8 +899,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "ComponentReference",
"type": "docs",
@@ -863,8 +912,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "docs2/Yabbadabbadooo",
"type": "docs",
@@ -875,8 +925,9 @@ describe('StoryIndexGenerator', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "NoTitle",
"type": "docs",
@@ -936,8 +987,11 @@ describe('StoryIndexGenerator', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -950,8 +1004,11 @@ describe('StoryIndexGenerator', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -961,9 +1018,10 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -974,8 +1032,9 @@ describe('StoryIndexGenerator', () => {
"name": "Info",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "ComponentReference",
"type": "docs",
@@ -986,8 +1045,9 @@ describe('StoryIndexGenerator', () => {
"name": "Info",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "docs2/Yabbadabbadooo",
"type": "docs",
@@ -998,8 +1058,9 @@ describe('StoryIndexGenerator', () => {
"name": "Info",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "NoTitle",
"type": "docs",
@@ -1028,9 +1089,10 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -1040,8 +1102,9 @@ describe('StoryIndexGenerator', () => {
"importPath": "./src/B.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "B",
"type": "story",
@@ -1055,8 +1118,10 @@ describe('StoryIndexGenerator', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "autodocs",
"attached-mdx",
- "docs",
],
"title": "B",
"type": "docs",
@@ -1092,8 +1157,9 @@ describe('StoryIndexGenerator', () => {
"./docs-id-generation/B.stories.jsx",
],
"tags": [
+ "dev",
+ "test",
"attached-mdx",
- "docs",
],
"title": "B",
"type": "docs",
@@ -1103,7 +1169,8 @@ describe('StoryIndexGenerator', () => {
"importPath": "./docs-id-generation/B.stories.jsx",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "B",
"type": "story",
diff --git a/code/lib/core-server/src/utils/StoryIndexGenerator.ts b/code/lib/core-server/src/utils/StoryIndexGenerator.ts
index 9f2c147c9a1f..7e65fc75dfca 100644
--- a/code/lib/core-server/src/utils/StoryIndexGenerator.ts
+++ b/code/lib/core-server/src/utils/StoryIndexGenerator.ts
@@ -8,21 +8,19 @@ import type {
IndexEntry,
StoryIndexEntry,
DocsIndexEntry,
- ComponentTitle,
NormalizedStoriesSpecifier,
DocsOptions,
Path,
Tag,
StoryIndex,
- StoryName,
Indexer,
StorybookConfigRaw,
} from '@storybook/types';
import { userOrAutoTitleFromSpecifier, sortStoriesV7 } from '@storybook/preview-api';
import { commonGlobOptions, normalizeStoryPath } from '@storybook/core-common';
import { logger, once } from '@storybook/node-logger';
-import { getStorySortParameter } from '@storybook/csf-tools';
-import { storyNameFromExport, toId } from '@storybook/csf';
+import { getStorySortParameter, loadConfig } from '@storybook/csf-tools';
+import { storyNameFromExport, toId, combineTags } from '@storybook/csf';
import { analyze } from '@storybook/docs-mdx';
import dedent from 'ts-dedent';
import { autoName } from './autoName';
@@ -55,11 +53,13 @@ export type StoryIndexGeneratorOptions = {
export const AUTODOCS_TAG = 'autodocs';
export const STORIES_MDX_TAG = 'stories-mdx';
+export const UNATTACHED_MDX_TAG = 'unattached-mdx';
+export const ATTACHED_MDX_TAG = 'attached-mdx';
export const PLAY_FN_TAG = 'play-fn';
/** Was this docs entry generated by a .mdx file? (see discussion below) */
export function isMdxEntry({ tags }: DocsIndexEntry) {
- return !tags?.includes(AUTODOCS_TAG) && !tags?.includes(STORIES_MDX_TAG);
+ return tags?.includes(UNATTACHED_MDX_TAG) || tags?.includes(ATTACHED_MDX_TAG);
}
const makeAbsolute = (otherImport: Path, normalizedPath: Path, workingDir: Path) =>
@@ -158,8 +158,11 @@ export class StoryIndexGenerator {
this.specifierToCache.set(specifier, cache)
);
+ const previewCode = await this.getPreviewCode();
+ const projectTags = previewCode ? this.getProjectTags(previewCode) : [];
+
// Extract stories for each file
- await this.ensureExtracted();
+ await this.ensureExtracted({ projectTags });
}
/**
@@ -213,17 +216,23 @@ export class StoryIndexGenerator {
return /(? {
+ async ensureExtracted({
+ projectTags,
+ }: {
+ projectTags?: Tag[];
+ }): Promise<(IndexEntry | ErrorEntry)[]> {
// First process all the story files. Then, in a second pass,
// process the docs files. The reason for this is that the docs
// files may use the `` syntax, which requires
// that the story file that contains the meta be processed first.
await this.updateExtracted(async (specifier, absolutePath) =>
- this.isDocsMdx(absolutePath) ? false : this.extractStories(specifier, absolutePath)
+ this.isDocsMdx(absolutePath)
+ ? false
+ : this.extractStories(specifier, absolutePath, projectTags)
);
await this.updateExtracted(async (specifier, absolutePath) =>
- this.extractDocs(specifier, absolutePath)
+ this.extractDocs(specifier, absolutePath, projectTags)
);
return this.specifiers.flatMap((specifier) => {
@@ -269,7 +278,8 @@ export class StoryIndexGenerator {
async extractStories(
specifier: NormalizedStoriesSpecifier,
- absolutePath: Path
+ absolutePath: Path,
+ projectTags: Tag[] = []
): Promise {
const relativePath = path.relative(this.options.workingDir, absolutePath);
const importPath = slash(normalizeStoryPath(relativePath));
@@ -294,7 +304,7 @@ export class StoryIndexGenerator {
const title = input.title ?? defaultMakeTitle();
// eslint-disable-next-line no-underscore-dangle
const id = input.__id ?? toId(input.metaId ?? title, storyNameFromExport(input.exportName));
- const tags = (input.tags || []).concat('story');
+ const tags = combineTags(...projectTags, ...(input.tags ?? []));
return {
type: 'story',
@@ -307,29 +317,27 @@ export class StoryIndexGenerator {
};
});
- const { autodocs } = this.options.docs;
// We need a docs entry attached to the CSF file if either:
- // a) autodocs is globally enabled
- // b) we have autodocs enabled for this file
- // c) it is a stories.mdx transpiled to CSF
+ // a) we have autodocs enabled for this file
+ // b) it is a stories.mdx transpiled to CSF
const hasAutodocsTag = entries.some((entry) => entry.tags.includes(AUTODOCS_TAG));
const isStoriesMdx = entries.some((entry) => entry.tags.includes(STORIES_MDX_TAG));
- const createDocEntry =
- autodocs === true || (autodocs === 'tag' && hasAutodocsTag) || isStoriesMdx;
+ const createDocEntry = (hasAutodocsTag && this.options.docs.autodocs !== false) || isStoriesMdx;
if (createDocEntry && this.options.build?.test?.disableAutoDocs !== true) {
const name = this.options.docs.defaultName ?? 'Docs';
const { metaId } = indexInputs[0];
const { title } = entries[0];
- const metaTags = indexInputs[0].metaTags || [];
const id = toId(metaId ?? title, name);
+ const tags = combineTags(...projectTags, ...(indexInputs[0].tags ?? []));
+
entries.unshift({
id,
title,
name,
importPath,
type: 'docs',
- tags: [...metaTags, 'docs', ...(!hasAutodocsTag && !isStoriesMdx ? [AUTODOCS_TAG] : [])],
+ tags,
storiesImports: [],
});
}
@@ -345,7 +353,11 @@ export class StoryIndexGenerator {
};
}
- async extractDocs(specifier: NormalizedStoriesSpecifier, absolutePath: Path) {
+ async extractDocs(
+ specifier: NormalizedStoriesSpecifier,
+ absolutePath: Path,
+ projectTags: Tag[] = []
+ ) {
const relativePath = path.relative(this.options.workingDir, absolutePath);
try {
const normalizedPath = normalizeStoryPath(relativePath);
@@ -353,14 +365,7 @@ export class StoryIndexGenerator {
const content = await fs.readFile(absolutePath, 'utf8');
- const result: {
- title?: ComponentTitle;
- of?: Path;
- name?: StoryName;
- isTemplate?: boolean;
- imports?: Path[];
- tags?: Tag[];
- } = analyze(content);
+ const result = analyze(content);
// Templates are not indexed
if (result.isTemplate) return false;
@@ -426,8 +431,16 @@ export class StoryIndexGenerator {
const name =
result.name ||
(csfEntry ? autoName(importPath, csfEntry.importPath, defaultName) : defaultName);
+
const id = toId(csfEntry?.metaId || title, name);
+ const tags = combineTags(
+ ...projectTags,
+ ...(csfEntry?.tags ?? []),
+ ...(result.metaTags ?? []),
+ csfEntry ? 'attached-mdx' : 'unattached-mdx'
+ );
+
const docsEntry: DocsCacheEntry = {
id,
title,
@@ -435,8 +448,7 @@ export class StoryIndexGenerator {
importPath,
storiesImports: sortedDependencies.map((dep) => dep.entries[0].importPath),
type: 'docs',
- // FIXME: update this to use the index entry's metaTags once we update this to run on `IndexInputs`
- tags: [...(result.tags || []), csfEntry ? 'attached-mdx' : 'unattached-mdx', 'docs'],
+ tags,
};
return docsEntry;
} catch (err) {
@@ -525,10 +537,8 @@ export class StoryIndexGenerator {
return betterEntry;
}
- async sortStories(entries: StoryIndex['entries']) {
+ async sortStories(entries: StoryIndex['entries'], storySortParameter: any) {
const sortableStories = Object.values(entries);
-
- const storySortParameter = await this.getStorySortParameter();
const fileNameOrder = this.storyFileNames();
sortStoriesV7(sortableStories, storySortParameter, fileNameOrder);
@@ -545,9 +555,12 @@ export class StoryIndexGenerator {
if (this.lastIndex) return this.lastIndex;
if (this.lastError) throw this.lastError;
+ const previewCode = await this.getPreviewCode();
+ const projectTags = previewCode ? this.getProjectTags(previewCode) : [];
+
// Extract any entries that are currently missing
// Pull out each file's stories into a list of stories, to be composed and sorted
- const storiesList = await this.ensureExtracted();
+ const storiesList = await this.ensureExtracted({ projectTags });
try {
const errorEntries = storiesList.filter((entry) => entry.type === 'error');
@@ -571,7 +584,10 @@ export class StoryIndexGenerator {
});
if (duplicateErrors.length) throw new MultipleIndexingError(duplicateErrors);
- const sorted = await this.sortStories(indexEntries);
+ const sorted = await this.sortStories(
+ indexEntries,
+ previewCode && getStorySortParameter(previewCode)
+ );
this.lastIndex = {
v: 4,
@@ -587,6 +603,16 @@ export class StoryIndexGenerator {
}
}
+ invalidateAll() {
+ this.specifierToCache.forEach((cache) => {
+ Object.keys(cache).forEach((key) => {
+ cache[key] = false;
+ });
+ });
+ this.lastIndex = null;
+ this.lastError = null;
+ }
+
invalidate(specifier: NormalizedStoriesSpecifier, importPath: Path, removed: boolean) {
const absolutePath = slash(path.resolve(this.options.workingDir, importPath));
const cache = this.specifierToCache.get(specifier);
@@ -631,17 +657,20 @@ export class StoryIndexGenerator {
this.lastError = null;
}
- async getStorySortParameter() {
- const previewFile = ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs']
+ async getPreviewCode() {
+ const previewFile = ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'mts']
.map((ext) => path.join(this.options.configDir, `preview.${ext}`))
.find((fname) => fs.existsSync(fname));
- let storySortParameter;
- if (previewFile) {
- const previewCode = (await fs.readFile(previewFile, 'utf-8')).toString();
- storySortParameter = await getStorySortParameter(previewCode);
- }
- return storySortParameter;
+ return previewFile && (await fs.readFile(previewFile, 'utf-8')).toString();
+ }
+
+ getProjectTags(previewCode: string) {
+ const projectAnnotations = loadConfig(previewCode).parse();
+ const defaultTags = ['dev', 'test'];
+ const extraTags = this.options.docs.autodocs === true ? [AUTODOCS_TAG] : [];
+ const projectTags = projectAnnotations.getFieldValue(['tags']) ?? [];
+ return [...defaultTags, ...projectTags, ...extraTags];
}
// Get the story file names in "imported order"
diff --git a/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts b/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts
index a1936c6719dd..a7bc19ae8ab9 100644
--- a/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts
+++ b/code/lib/core-server/src/utils/__tests__/index-extraction.test.ts
@@ -70,7 +70,6 @@ describe('story extraction', () => {
"name": "Story One",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -82,7 +81,6 @@ describe('story extraction', () => {
"name": "Another Story Name",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "Custom Title",
"type": "story",
@@ -124,9 +122,7 @@ describe('story extraction', () => {
"importPath": "./src/first-nested/deeply/F.stories.js",
"metaId": undefined,
"name": "Story One",
- "tags": [
- "story",
- ],
+ "tags": [],
"title": "F",
"type": "story",
},
@@ -173,7 +169,6 @@ describe('story extraction', () => {
"name": "Story One",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "F",
"type": "story",
@@ -221,7 +216,6 @@ describe('story extraction', () => {
"name": "Story One",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -287,7 +281,6 @@ describe('story extraction', () => {
"name": "Story One",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -299,7 +292,6 @@ describe('story extraction', () => {
"name": "Custom Name For Second Story",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "Custom Title",
"type": "story",
@@ -311,7 +303,6 @@ describe('story extraction', () => {
"name": "Story Three",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "Custom Title",
"type": "story",
@@ -356,7 +347,6 @@ describe('story extraction', () => {
"name": "Story One",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -399,18 +389,6 @@ describe('docs entries from story extraction', () => {
{
"dependents": [],
"entries": [
- {
- "id": "a--docs",
- "importPath": "./src/A.stories.js",
- "name": "docs",
- "storiesImports": [],
- "tags": [
- "docs",
- "autodocs",
- ],
- "title": "A",
- "type": "docs",
- },
{
"id": "a--story-one",
"importPath": "./src/A.stories.js",
@@ -418,7 +396,6 @@ describe('docs entries from story extraction', () => {
"name": "Story One",
"tags": [
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -465,7 +442,8 @@ describe('docs entries from story extraction', () => {
"name": "docs",
"storiesImports": [],
"tags": [
- "docs",
+ "autodocs",
+ "story-tag-from-indexer",
],
"title": "A",
"type": "docs",
@@ -478,7 +456,6 @@ describe('docs entries from story extraction', () => {
"tags": [
"autodocs",
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -527,7 +504,6 @@ describe('docs entries from story extraction', () => {
"tags": [
"autodocs",
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
@@ -574,7 +550,8 @@ describe('docs entries from story extraction', () => {
"name": "docs",
"storiesImports": [],
"tags": [
- "docs",
+ "stories-mdx",
+ "story-tag-from-indexer",
],
"title": "A",
"type": "docs",
@@ -587,7 +564,6 @@ describe('docs entries from story extraction', () => {
"tags": [
"stories-mdx",
"story-tag-from-indexer",
- "story",
],
"title": "A",
"type": "story",
diff --git a/code/lib/core-server/src/utils/getStoryIndexGenerator.ts b/code/lib/core-server/src/utils/getStoryIndexGenerator.ts
index f8c1bc97f615..9c2a32385db9 100644
--- a/code/lib/core-server/src/utils/getStoryIndexGenerator.ts
+++ b/code/lib/core-server/src/utils/getStoryIndexGenerator.ts
@@ -13,8 +13,9 @@ export async function getStoryIndexGenerator(
serverChannel: ServerChannel
): Promise {
const workingDir = process.cwd();
+ const configDir = options.configDir;
const directories = {
- configDir: options.configDir,
+ configDir,
workingDir,
};
const stories = options.presets.apply('stories');
@@ -37,6 +38,7 @@ export async function getStoryIndexGenerator(
normalizedStories,
serverChannel,
workingDir,
+ configDir,
});
return initializedStoryIndexGenerator;
diff --git a/code/lib/core-server/src/utils/stories-json.test.ts b/code/lib/core-server/src/utils/stories-json.test.ts
index a621f5443ce3..21a901ada040 100644
--- a/code/lib/core-server/src/utils/stories-json.test.ts
+++ b/code/lib/core-server/src/utils/stories-json.test.ts
@@ -75,6 +75,7 @@ describe('useStoriesJson', () => {
send.mockClear();
write.mockClear();
vi.mocked(debounce).mockImplementation((cb) => cb as any);
+ Watchpack.mockClear();
});
const request: Request = {
@@ -113,8 +114,11 @@ describe('useStoriesJson', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -127,8 +131,11 @@ describe('useStoriesJson', () => {
"./src/A.stories.js",
],
"tags": [
+ "dev",
+ "test",
+ "component-tag",
+ "story-tag",
"attached-mdx",
- "docs",
],
"title": "A",
"type": "docs",
@@ -138,9 +145,10 @@ describe('useStoriesJson', () => {
"importPath": "./src/A.stories.js",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
"story-tag",
- "story",
],
"title": "A",
"type": "story",
@@ -150,8 +158,9 @@ describe('useStoriesJson', () => {
"importPath": "./src/B.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "B",
"type": "story",
@@ -161,8 +170,9 @@ describe('useStoriesJson', () => {
"importPath": "./src/D.stories.jsx",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "D",
"type": "story",
@@ -173,8 +183,9 @@ describe('useStoriesJson', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "docs2/ComponentReference",
"type": "docs",
@@ -185,8 +196,9 @@ describe('useStoriesJson', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "docs2/NoTitle",
"type": "docs",
@@ -197,8 +209,9 @@ describe('useStoriesJson', () => {
"name": "docs",
"storiesImports": [],
"tags": [
+ "dev",
+ "test",
"unattached-mdx",
- "docs",
],
"title": "docs2/Yabbadabbadooo",
"type": "docs",
@@ -208,7 +221,8 @@ describe('useStoriesJson', () => {
"importPath": "./src/first-nested/deeply/F.stories.js",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "first-nested/deeply/F",
"type": "story",
@@ -218,8 +232,9 @@ describe('useStoriesJson', () => {
"importPath": "./src/H.stories.mjs",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"autodocs",
- "story",
],
"title": "H",
"type": "story",
@@ -229,8 +244,9 @@ describe('useStoriesJson', () => {
"importPath": "./src/nested/Button.stories.ts",
"name": "Story One",
"tags": [
+ "dev",
+ "test",
"component-tag",
- "story",
],
"title": "nested/Button",
"type": "story",
@@ -240,7 +256,8 @@ describe('useStoriesJson', () => {
"importPath": "./src/second-nested/G.stories.ts",
"name": "Story One",
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "second-nested/G",
"type": "story",
diff --git a/code/lib/core-server/src/utils/stories-json.ts b/code/lib/core-server/src/utils/stories-json.ts
index 074c0248cb0c..71b29a54a30b 100644
--- a/code/lib/core-server/src/utils/stories-json.ts
+++ b/code/lib/core-server/src/utils/stories-json.ts
@@ -1,3 +1,4 @@
+import { basename } from 'path';
import type { Router, Request, Response } from 'express';
import { writeJSON } from 'fs-extra';
@@ -7,6 +8,7 @@ import debounce from 'lodash/debounce.js';
import { STORY_INDEX_INVALIDATED } from '@storybook/core-events';
import type { StoryIndexGenerator } from './StoryIndexGenerator';
import { watchStorySpecifiers } from './watch-story-specifiers';
+import { watchConfig } from './watchConfig';
import type { ServerChannel } from './get-server-channel';
export const DEBOUNCE = 100;
@@ -25,6 +27,7 @@ export function useStoriesJson({
router,
initializedStoryIndexGenerator,
workingDir = process.cwd(),
+ configDir,
serverChannel,
normalizedStories,
}: {
@@ -32,6 +35,7 @@ export function useStoriesJson({
initializedStoryIndexGenerator: Promise;
serverChannel: ServerChannel;
workingDir?: string;
+ configDir?: string;
normalizedStories: NormalizedStoriesSpecifier[];
}) {
const maybeInvalidate = debounce(() => serverChannel.emit(STORY_INDEX_INVALIDATED), DEBOUNCE, {
@@ -42,6 +46,15 @@ export function useStoriesJson({
generator.invalidate(specifier, path, removed);
maybeInvalidate();
});
+ if (configDir) {
+ watchConfig(configDir, async (filePath) => {
+ if (basename(filePath).startsWith('preview')) {
+ const generator = await initializedStoryIndexGenerator;
+ generator.invalidateAll();
+ maybeInvalidate();
+ }
+ });
+ }
router.use('/index.json', async (req: Request, res: Response) => {
try {
diff --git a/code/lib/core-server/src/utils/summarizeIndex.test.ts b/code/lib/core-server/src/utils/summarizeIndex.test.ts
index 8647c007463b..a2702a38a704 100644
--- a/code/lib/core-server/src/utils/summarizeIndex.test.ts
+++ b/code/lib/core-server/src/utils/summarizeIndex.test.ts
@@ -457,7 +457,7 @@ describe('summarizeIndex', () => {
importPath: './template-stories/addons/docs/docs2/NoTitle.mdx',
storiesImports: [],
type: 'docs',
- tags: ['docs'],
+ tags: ['docs', 'attached-mdx'],
},
'addons-docs-yabbadabbadooo--docs': {
id: 'addons-docs-yabbadabbadooo--docs',
@@ -466,7 +466,7 @@ describe('summarizeIndex', () => {
importPath: './template-stories/addons/docs/docs2/Title.mdx',
storiesImports: [],
type: 'docs',
- tags: ['docs'],
+ tags: ['docs', 'attached-mdx'],
},
},
})
diff --git a/code/lib/core-server/src/utils/watchConfig.ts b/code/lib/core-server/src/utils/watchConfig.ts
new file mode 100644
index 000000000000..99b85fe62e2a
--- /dev/null
+++ b/code/lib/core-server/src/utils/watchConfig.ts
@@ -0,0 +1,27 @@
+import Watchpack from 'watchpack';
+import type { Path } from '@storybook/types';
+
+// copied from './watch-story-specifiers.ts'
+/** Watch the .storybook dir for changes */
+export function watchConfig(
+ configDir: Path,
+ onInvalidate: (path: Path, removed: boolean) => Promise
+) {
+ const wp = new Watchpack({
+ followSymlinks: false,
+ ignored: ['**/.git', '**/node_modules'],
+ });
+
+ wp.watch({
+ directories: [configDir],
+ });
+ wp.on('change', async (filePath: Path, mtime: Date, explanation: string) => {
+ const removed = !mtime;
+ await onInvalidate(filePath, removed);
+ });
+ wp.on('remove', async (filePath: Path, explanation: string) => {
+ await onInvalidate(filePath, true);
+ });
+
+ return () => wp.close();
+}
diff --git a/code/lib/csf-tools/package.json b/code/lib/csf-tools/package.json
index 4bbd8043c549..0526a70658c3 100644
--- a/code/lib/csf-tools/package.json
+++ b/code/lib/csf-tools/package.json
@@ -46,7 +46,7 @@
"@babel/parser": "^7.24.4",
"@babel/traverse": "^7.24.1",
"@babel/types": "^7.24.0",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/types": "workspace:*",
"fs-extra": "^11.1.0",
"recast": "^0.23.5",
diff --git a/code/lib/csf-tools/src/CsfFile.test.ts b/code/lib/csf-tools/src/CsfFile.test.ts
index 21e902cce52f..669109d268ac 100644
--- a/code/lib/csf-tools/src/CsfFile.test.ts
+++ b/code/lib/csf-tools/src/CsfFile.test.ts
@@ -1104,8 +1104,6 @@ describe('CsfFile', () => {
- component-tag
- story-tag
- play-fn
- metaTags: &ref_0
- - component-tag
__id: component-id--a
- type: story
importPath: foo/bar.stories.js
@@ -1117,7 +1115,6 @@ describe('CsfFile', () => {
- component-tag
- story-tag
- play-fn
- metaTags: *ref_0
__id: component-id--b
`);
});
@@ -1147,8 +1144,6 @@ describe('CsfFile', () => {
metaId: component-id
tags:
- component-tag
- metaTags:
- - component-tag
__id: custom-story-id
`);
});
@@ -1177,13 +1172,11 @@ describe('CsfFile', () => {
tags:
- component-tag
- component-tag-dup
+ - component-tag-dup
- inherit-tag-dup
- story-tag
- story-tag-dup
- metaTags:
- - component-tag
- - component-tag-dup
- - component-tag-dup
+ - story-tag-dup
- inherit-tag-dup
__id: custom-foo-title--a
`);
diff --git a/code/lib/csf-tools/src/CsfFile.ts b/code/lib/csf-tools/src/CsfFile.ts
index 4516a293b1cc..cac931501eec 100644
--- a/code/lib/csf-tools/src/CsfFile.ts
+++ b/code/lib/csf-tools/src/CsfFile.ts
@@ -557,9 +557,10 @@ export class CsfFile {
Either add the fileName option when creating the CsfFile instance, or create the index inputs manually.`
);
}
+
return Object.entries(this._stories).map(([exportName, story]) => {
- // combine meta and story tags, removing any duplicates
- const tags = Array.from(new Set([...(this._meta?.tags ?? []), ...(story.tags ?? [])]));
+ // don't remove any duplicates or negations -- tags will be combined in the index
+ const tags = [...(this._meta?.tags ?? []), ...(story.tags ?? [])];
return {
type: 'story',
importPath: this._fileName,
@@ -568,7 +569,6 @@ export class CsfFile {
title: this.meta?.title,
metaId: this.meta?.id,
tags,
- metaTags: this.meta?.tags,
__id: story.id,
};
});
diff --git a/code/lib/manager-api/package.json b/code/lib/manager-api/package.json
index 53a8b18ea03d..582007302b26 100644
--- a/code/lib/manager-api/package.json
+++ b/code/lib/manager-api/package.json
@@ -47,7 +47,7 @@
"@storybook/channels": "workspace:*",
"@storybook/client-logger": "workspace:*",
"@storybook/core-events": "workspace:*",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.5",
"@storybook/router": "workspace:*",
diff --git a/code/lib/preview-api/package.json b/code/lib/preview-api/package.json
index 6f1ed6c24999..1ca60c2d5adb 100644
--- a/code/lib/preview-api/package.json
+++ b/code/lib/preview-api/package.json
@@ -47,7 +47,7 @@
"@storybook/channels": "workspace:*",
"@storybook/client-logger": "workspace:*",
"@storybook/core-events": "workspace:*",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/global": "^5.0.0",
"@storybook/types": "workspace:*",
"@types/qs": "^6.9.5",
diff --git a/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts b/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts
index f71c3ab31eaf..0ba45568789d 100644
--- a/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts
+++ b/code/lib/preview-api/src/modules/preview-web/PreviewWeb.test.ts
@@ -3625,7 +3625,8 @@ describe('PreviewWeb', () => {
"story": "A",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -3672,7 +3673,8 @@ describe('PreviewWeb', () => {
"story": "B",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -3697,7 +3699,8 @@ describe('PreviewWeb', () => {
"story": "E",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -3732,7 +3735,8 @@ describe('PreviewWeb', () => {
"story": "C",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component Two",
},
diff --git a/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx b/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx
index f4c15e000d14..193a5f52358a 100644
--- a/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx
+++ b/code/lib/preview-api/src/modules/preview-web/PreviewWithSelection.tsx
@@ -55,10 +55,11 @@ function focusInInput(event: Event) {
export const AUTODOCS_TAG = 'autodocs';
export const STORIES_MDX_TAG = 'stories-mdx';
export const ATTACHED_MDX_TAG = 'attached-mdx';
+export const UNATTACHED_MDX_TAG = 'unattached-mdx';
/** Was this docs entry generated by a .mdx file? (see discussion below) */
export function isMdxEntry({ tags }: DocsIndexEntry) {
- return !tags?.includes(AUTODOCS_TAG) && !tags?.includes(STORIES_MDX_TAG);
+ return tags?.includes(UNATTACHED_MDX_TAG) || tags?.includes(ATTACHED_MDX_TAG);
}
type PossibleRender =
diff --git a/code/lib/preview-api/src/modules/store/StoryStore.test.ts b/code/lib/preview-api/src/modules/store/StoryStore.test.ts
index 6117e5592f4e..5df413e09ceb 100644
--- a/code/lib/preview-api/src/modules/store/StoryStore.test.ts
+++ b/code/lib/preview-api/src/modules/store/StoryStore.test.ts
@@ -311,7 +311,8 @@ describe('StoryStore', () => {
"story": "A",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -476,7 +477,8 @@ describe('StoryStore', () => {
"story": "A",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -514,7 +516,8 @@ describe('StoryStore', () => {
"story": "B",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -552,7 +555,8 @@ describe('StoryStore', () => {
"story": "C",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component Two",
},
@@ -660,7 +664,8 @@ describe('StoryStore', () => {
"storyFn": [Function],
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
"unboundStoryFn": [Function],
@@ -706,7 +711,8 @@ describe('StoryStore', () => {
"storyFn": [Function],
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
"unboundStoryFn": [Function],
@@ -752,7 +758,8 @@ describe('StoryStore', () => {
"storyFn": [Function],
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component Two",
"unboundStoryFn": [Function],
@@ -813,7 +820,8 @@ describe('StoryStore', () => {
"story": "A",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -851,7 +859,8 @@ describe('StoryStore', () => {
"story": "B",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component One",
},
@@ -889,7 +898,8 @@ describe('StoryStore', () => {
"story": "C",
"subcomponents": undefined,
"tags": [
- "story",
+ "dev",
+ "test",
],
"title": "Component Two",
},
diff --git a/code/lib/preview-api/src/modules/store/csf/composeConfigs.test.ts b/code/lib/preview-api/src/modules/store/csf/composeConfigs.test.ts
index bfad2ebe5f21..ba9ead34d119 100644
--- a/code/lib/preview-api/src/modules/store/csf/composeConfigs.test.ts
+++ b/code/lib/preview-api/src/modules/store/csf/composeConfigs.test.ts
@@ -23,6 +23,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -48,6 +49,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -77,6 +79,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -112,6 +115,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -150,6 +154,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -179,6 +184,7 @@ describe('composeConfigs', () => {
loaders: ['1', '2', '3', '4'],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -208,6 +214,7 @@ describe('composeConfigs', () => {
loaders: ['1', '2', '3'],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -233,6 +240,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -259,6 +267,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeEach: [],
runStep: expect.any(Function),
+ tags: [],
});
});
@@ -291,6 +300,7 @@ describe('composeConfigs', () => {
renderToCanvas: 'renderToCanvas-2',
applyDecorators: 'applyDecorators-2',
runStep: expect.any(Function),
+ tags: [],
});
});
diff --git a/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts b/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts
index 12bf9fc9e050..9c943e14f1c1 100644
--- a/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts
+++ b/code/lib/preview-api/src/modules/store/csf/composeConfigs.ts
@@ -64,5 +64,6 @@ export function composeConfigs(
renderToDOM: getSingletonField(moduleExportList, 'renderToDOM'), // deprecated
applyDecorators: getSingletonField(moduleExportList, 'applyDecorators'),
runStep: composeStepRunners(stepRunners),
+ tags: getArrayField(moduleExportList, 'tags'),
};
}
diff --git a/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts b/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts
index 5d5389beeb36..a574080558c5 100644
--- a/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts
+++ b/code/lib/preview-api/src/modules/store/csf/prepareStory.test.ts
@@ -44,7 +44,7 @@ describe('prepareStory', () => {
{ render }
);
- expect(tags).toEqual(['story-1', 'story-2', 'story']);
+ expect(tags).toEqual(['dev', 'test', 'component-1', 'component-2', 'story-1', 'story-2']);
});
it('component tags work if story are unset', () => {
@@ -58,13 +58,13 @@ describe('prepareStory', () => {
{ render }
);
- expect(tags).toEqual(['component-1', 'component-2', 'story']);
+ expect(tags).toEqual(['dev', 'test', 'component-1', 'component-2']);
});
it('sets a value even if annotations do not have tags', () => {
const { tags } = prepareStory({ id, name, moduleExport }, { id, title }, { render });
- expect(tags).toEqual(['story']);
+ expect(tags).toEqual(['dev', 'test']);
});
});
diff --git a/code/lib/preview-api/src/modules/store/csf/prepareStory.ts b/code/lib/preview-api/src/modules/store/csf/prepareStory.ts
index 84439187c4de..6183274669fe 100644
--- a/code/lib/preview-api/src/modules/store/csf/prepareStory.ts
+++ b/code/lib/preview-api/src/modules/store/csf/prepareStory.ts
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-loop-func,no-underscore-dangle */
-import { global } from '@storybook/global';
+import { dedent } from 'ts-dedent';
+import { global } from '@storybook/global';
import type {
Args,
ArgsStoryFn,
@@ -20,7 +21,9 @@ import type {
StoryContextForLoaders,
StrictArgTypes,
} from '@storybook/types';
-import { type CleanupCallback, includeConditionalArg } from '@storybook/csf';
+import { type CleanupCallback, includeConditionalArg, combineTags } from '@storybook/csf';
+import { global as globalThis } from '@storybook/global';
+import { once } from '@storybook/client-logger';
import { applyHooks } from '../../addons';
import { combineParameters } from '../parameters';
@@ -155,7 +158,23 @@ function preparePartialAnnotations(
// anything at render time. The assumption is that as we don't load all the stories at once, this
// will have a limited cost. If this proves misguided, we can refactor it.
- const tags = [...(storyAnnotations?.tags || componentAnnotations.tags || []), 'story'];
+ const defaultTags = ['dev', 'test'];
+ if (typeof globalThis.DOCS_OPTIONS?.autodocs !== 'undefined') {
+ once.warn(dedent`
+ The \`docs.autodocs\` setting in '.storybook/main.js' is deprecated. Use \`tags: ['autodocs']\` in \`.storybook/preview.js\` instead.
+
+ For more info see: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-docsautodocs-is-deprecated
+ `);
+ }
+ const extraTags = globalThis.DOCS_OPTIONS?.autodocs === true ? ['autodocs'] : [];
+
+ const tags = combineTags(
+ ...defaultTags,
+ ...extraTags,
+ ...(projectAnnotations.tags ?? []),
+ ...(componentAnnotations.tags ?? []),
+ ...(storyAnnotations?.tags ?? [])
+ );
const parameters: Parameters = combineParameters(
projectAnnotations.parameters,
diff --git a/code/lib/preview-api/template/stories/tags-add.stories.ts b/code/lib/preview-api/template/stories/tags-add.stories.ts
new file mode 100644
index 000000000000..6302085e5c19
--- /dev/null
+++ b/code/lib/preview-api/template/stories/tags-add.stories.ts
@@ -0,0 +1,39 @@
+import { global as globalThis } from '@storybook/global';
+import type { PartialStoryFn, PlayFunctionContext, StoryContext } from '@storybook/types';
+import { within, expect } from '@storybook/test';
+
+export default {
+ component: globalThis.Components.Pre,
+ tags: ['!dev', '!autodocs', '!test'],
+ decorators: [
+ (storyFn: PartialStoryFn, context: StoryContext) => {
+ return storyFn({
+ args: { object: { tags: context.tags } },
+ });
+ },
+ ],
+ parameters: { chromatic: { disable: true } },
+};
+
+export const Inheritance = {
+ tags: ['story-one'],
+ play: async ({ canvasElement }: PlayFunctionContext) => {
+ const canvas = within(canvasElement);
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['story-one'],
+ });
+ },
+ parameters: { chromatic: { disable: false } },
+};
+
+export const Dev = {
+ tags: ['dev'],
+};
+
+export const Autodocs = {
+ tags: ['autodocs'],
+};
+
+export const Test = {
+ tags: ['test'],
+};
diff --git a/code/lib/preview-api/template/stories/tags.stories.ts b/code/lib/preview-api/template/stories/tags-config.stories.ts
similarity index 84%
rename from code/lib/preview-api/template/stories/tags.stories.ts
rename to code/lib/preview-api/template/stories/tags-config.stories.ts
index 61ffe8811429..e36784304d39 100644
--- a/code/lib/preview-api/template/stories/tags.stories.ts
+++ b/code/lib/preview-api/template/stories/tags-config.stories.ts
@@ -16,11 +16,11 @@ export default {
};
export const Inheritance = {
- tags: ['story-one', 'story-two'],
+ tags: ['story-one'],
play: async ({ canvasElement }: PlayFunctionContext) => {
const canvas = within(canvasElement);
await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
- tags: ['story-one', 'story-two', 'story'],
+ tags: ['dev', 'test', 'component-one', 'component-two', 'autodocs', 'story-one'],
});
},
parameters: { chromatic: { disable: false } },
@@ -37,3 +37,7 @@ export const TestOnly = {
export const DevOnly = {
tags: ['dev-only'],
};
+
+export const TagRemoval = {
+ tags: ['!component-two'],
+};
diff --git a/code/lib/preview-api/template/stories/tags-remove.stories.ts b/code/lib/preview-api/template/stories/tags-remove.stories.ts
new file mode 100644
index 000000000000..852d4f63585d
--- /dev/null
+++ b/code/lib/preview-api/template/stories/tags-remove.stories.ts
@@ -0,0 +1,39 @@
+import { global as globalThis } from '@storybook/global';
+import type { PartialStoryFn, PlayFunctionContext, StoryContext } from '@storybook/types';
+import { within, expect } from '@storybook/test';
+
+export default {
+ component: globalThis.Components.Pre,
+ tags: ['component-one', 'autodocs'],
+ decorators: [
+ (storyFn: PartialStoryFn, context: StoryContext) => {
+ return storyFn({
+ args: { object: { tags: context.tags } },
+ });
+ },
+ ],
+ parameters: { chromatic: { disable: true } },
+};
+
+export const Inheritance = {
+ tags: ['story-one'],
+ play: async ({ canvasElement }: PlayFunctionContext) => {
+ const canvas = within(canvasElement);
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['dev', 'test', 'component-one', 'autodocs', 'story-one'],
+ });
+ },
+ parameters: { chromatic: { disable: false } },
+};
+
+export const NoDev = {
+ tags: ['!dev'],
+};
+
+export const NoAutodocs = {
+ tags: ['!autodocs'],
+};
+
+export const NoTest = {
+ tags: ['!test'],
+};
diff --git a/code/lib/preview-api/template/stories/test-only-tag.stories.ts b/code/lib/preview-api/template/stories/test-only-tag.stories.ts
deleted file mode 100644
index 138f221d3ff7..000000000000
--- a/code/lib/preview-api/template/stories/test-only-tag.stories.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { global as globalThis } from '@storybook/global';
-
-export default {
- component: globalThis.Components.Button,
- tags: ['autodocs', 'test-only'],
- parameters: { chromatic: { disable: true } },
-};
-
-export const Default = {
- args: { label: 'Button' },
-};
diff --git a/code/lib/source-loader/package.json b/code/lib/source-loader/package.json
index 2d661fd16c36..bc1b9457df79 100644
--- a/code/lib/source-loader/package.json
+++ b/code/lib/source-loader/package.json
@@ -45,7 +45,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/types": "workspace:*",
"estraverse": "^5.2.0",
"lodash": "^4.17.21",
diff --git a/code/lib/types/package.json b/code/lib/types/package.json
index 58824511b291..d7b66b977f9a 100644
--- a/code/lib/types/package.json
+++ b/code/lib/types/package.json
@@ -49,7 +49,7 @@
"file-system-cache": "2.3.0"
},
"devDependencies": {
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@types/fs-extra": "^11.0.1",
"@types/node": "^18.0.0",
"typescript": "^5.3.2"
diff --git a/code/lib/types/src/modules/core-common.ts b/code/lib/types/src/modules/core-common.ts
index c4aeeacbcf1f..9a3106931053 100644
--- a/code/lib/types/src/modules/core-common.ts
+++ b/code/lib/types/src/modules/core-common.ts
@@ -280,6 +280,8 @@ export type DocsOptions = {
* Should we generate a docs entry per CSF file?
* Set to 'tag' (the default) to generate an entry for every CSF file with the
* 'autodocs' tag.
+ *
+ * @deprecated Use `tags: ['autodocs']` in `.storybook/preview.js` instead
*/
autodocs?: boolean | 'tag';
/**
diff --git a/code/lib/types/src/modules/indexer.ts b/code/lib/types/src/modules/indexer.ts
index 1064354eefe0..56d435cdb533 100644
--- a/code/lib/types/src/modules/indexer.ts
+++ b/code/lib/types/src/modules/indexer.ts
@@ -107,8 +107,6 @@ export type BaseIndexInput = {
metaId?: MetaId;
/** Tags for filtering entries in Storybook and its tools. */
tags?: Tag[];
- /** Tags from the meta for filtering entries in Storybook and its tools. */
- metaTags?: Tag[];
/**
* The id of the entry, auto-generated from {@link title}/{@link metaId} and {@link exportName} if unspecified.
* If specified, the story in the CSF file _must_ have a matching id set at `parameters.__id`, to be correctly matched.
diff --git a/code/package.json b/code/package.json
index 6550aff79cb0..0444fc8fd4df 100644
--- a/code/package.json
+++ b/code/package.json
@@ -127,7 +127,7 @@
"@storybook/core-events": "workspace:*",
"@storybook/core-server": "workspace:*",
"@storybook/core-webpack": "workspace:*",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/csf-plugin": "workspace:*",
"@storybook/csf-tools": "workspace:*",
"@storybook/docs-tools": "workspace:*",
diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json
index 39151f1ab7af..489123a4e44a 100644
--- a/code/renderers/server/package.json
+++ b/code/renderers/server/package.json
@@ -46,7 +46,7 @@
"prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/csf-tools": "workspace:*",
"@storybook/global": "^5.0.0",
"@storybook/preview-api": "workspace:*",
diff --git a/code/ui/blocks/package.json b/code/ui/blocks/package.json
index 78c2af269e11..a54a3726f998 100644
--- a/code/ui/blocks/package.json
+++ b/code/ui/blocks/package.json
@@ -48,7 +48,7 @@
"@storybook/client-logger": "workspace:*",
"@storybook/components": "workspace:*",
"@storybook/core-events": "workspace:*",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/docs-tools": "workspace:*",
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.5",
diff --git a/code/ui/components/package.json b/code/ui/components/package.json
index 0b257d116983..b1ea9cf01935 100644
--- a/code/ui/components/package.json
+++ b/code/ui/components/package.json
@@ -62,7 +62,7 @@
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-slot": "^1.0.2",
"@storybook/client-logger": "workspace:*",
- "@storybook/csf": "^0.1.6",
+ "@storybook/csf": "^0.1.7",
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.5",
"@storybook/theming": "workspace:*",
diff --git a/code/yarn.lock b/code/yarn.lock
index ff0198d37e40..1bc536bb9e1e 100644
--- a/code/yarn.lock
+++ b/code/yarn.lock
@@ -5323,7 +5323,7 @@ __metadata:
dependencies:
"@storybook/client-logger": "workspace:*"
"@storybook/core-events": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/global": "npm:^5.0.0"
"@storybook/manager-api": "workspace:*"
"@storybook/preview-api": "workspace:*"
@@ -5591,7 +5591,7 @@ __metadata:
"@storybook/client-logger": "workspace:*"
"@storybook/components": "workspace:*"
"@storybook/core-events": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/docs-tools": "workspace:*"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.5"
@@ -5822,7 +5822,7 @@ __metadata:
"@babel/core": "npm:^7.24.4"
"@babel/preset-env": "npm:^7.24.4"
"@babel/types": "npm:^7.24.0"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/csf-tools": "workspace:*"
"@storybook/node-logger": "workspace:*"
"@storybook/types": "workspace:*"
@@ -5859,7 +5859,7 @@ __metadata:
"@radix-ui/react-scroll-area": "npm:^1.0.5"
"@radix-ui/react-slot": "npm:^1.0.2"
"@storybook/client-logger": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.5"
"@storybook/test": "workspace:*"
@@ -5943,7 +5943,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/core-events@workspace:lib/core-events"
dependencies:
- "@storybook/csf": "npm:^0.1.5"
+ "@storybook/csf": "npm:^0.1.7"
chalk: "npm:^4.1.0"
ts-dedent: "npm:^2.0.0"
typescript: "npm:^5.3.2"
@@ -5963,9 +5963,9 @@ __metadata:
"@storybook/channels": "workspace:*"
"@storybook/core-common": "workspace:*"
"@storybook/core-events": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/csf-tools": "workspace:*"
- "@storybook/docs-mdx": "npm:3.0.0"
+ "@storybook/docs-mdx": "npm:3.1.0-next.0"
"@storybook/global": "npm:^5.0.0"
"@storybook/manager": "workspace:*"
"@storybook/manager-api": "workspace:*"
@@ -6046,7 +6046,7 @@ __metadata:
"@babel/parser": "npm:^7.24.4"
"@babel/traverse": "npm:^7.24.1"
"@babel/types": "npm:^7.24.0"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/types": "workspace:*"
"@types/fs-extra": "npm:^11.0.1"
"@types/js-yaml": "npm:^4.0.5"
@@ -6067,19 +6067,19 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/csf@npm:^0.1.5, @storybook/csf@npm:^0.1.6":
- version: 0.1.6
- resolution: "@storybook/csf@npm:0.1.6"
+"@storybook/csf@npm:^0.1.7":
+ version: 0.1.7
+ resolution: "@storybook/csf@npm:0.1.7"
dependencies:
type-fest: "npm:^2.19.0"
- checksum: 10c0/81d1ee28a258381ed1cd5e0f9177f2ee06a3b7488ac2cfc9182ba4276662eee8b93f3941f4a141f8f11479991efee55696bf9f442137188255934bbd1de98226
+ checksum: 10c0/aaebc9fa5f850cebef1fd9d786d7b5844e2d88e5c8078904ea4571c053f858fab064392960274b854037b9f8693d12c7c45c3c4c9142ec88a08fb498f3f056a5
languageName: node
linkType: hard
-"@storybook/docs-mdx@npm:3.0.0":
- version: 3.0.0
- resolution: "@storybook/docs-mdx@npm:3.0.0"
- checksum: 10c0/4f4242fc05b57e8dc239204c71fd0d1481c9abbf20d12dd0f3dace74f77a7ff7cbe0bd07d7d785873b45747be64cad273423d3dc0cf89b52e9f117592a4b054f
+"@storybook/docs-mdx@npm:3.1.0-next.0":
+ version: 3.1.0-next.0
+ resolution: "@storybook/docs-mdx@npm:3.1.0-next.0"
+ checksum: 10c0/7622d7c6318e842c90a71c1836d68531236c31fff7081c885803eddfafb7e3f8998689f612eaa0292209ada8352a36657dcacb5d3ef4632b8e8b8a283c39602e
languageName: node
linkType: hard
@@ -6244,7 +6244,7 @@ __metadata:
"@storybook/channels": "workspace:*"
"@storybook/client-logger": "workspace:*"
"@storybook/core-events": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.5"
"@storybook/router": "workspace:*"
@@ -6582,7 +6582,7 @@ __metadata:
"@storybook/client-logger": "workspace:*"
"@storybook/core-common": "workspace:*"
"@storybook/core-events": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/global": "npm:^5.0.0"
"@storybook/types": "workspace:*"
"@types/qs": "npm:^6.9.5"
@@ -6767,7 +6767,7 @@ __metadata:
"@storybook/core-events": "workspace:*"
"@storybook/core-server": "workspace:*"
"@storybook/core-webpack": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/csf-plugin": "workspace:*"
"@storybook/csf-tools": "workspace:*"
"@storybook/docs-tools": "workspace:*"
@@ -6922,7 +6922,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/server@workspace:renderers/server"
dependencies:
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/csf-tools": "workspace:*"
"@storybook/global": "npm:^5.0.0"
"@storybook/preview-api": "workspace:*"
@@ -6939,7 +6939,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/source-loader@workspace:lib/source-loader"
dependencies:
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@storybook/types": "workspace:*"
estraverse: "npm:^5.2.0"
lodash: "npm:^4.17.21"
@@ -7118,7 +7118,7 @@ __metadata:
resolution: "@storybook/types@workspace:lib/types"
dependencies:
"@storybook/channels": "workspace:*"
- "@storybook/csf": "npm:^0.1.6"
+ "@storybook/csf": "npm:^0.1.7"
"@types/express": "npm:^4.7.0"
"@types/fs-extra": "npm:^11.0.1"
"@types/node": "npm:^18.0.0"