diff --git a/MIGRATION.md b/MIGRATION.md
index 7de591ad2951..4175b5833d42 100644
--- a/MIGRATION.md
+++ b/MIGRATION.md
@@ -9,6 +9,7 @@
- [6.2 Deprecations](#62-deprecations)
- [Deprecated implicit PostCSS loader](#deprecated-implicit-postcss-loader)
- [Deprecated default PostCSS plugins](#deprecated-default-postcss-plugins)
+ - [Deprecated showRoots config option](#deprecated-showroots-config-option)
- [From version 6.0.x to 6.1.0](#from-version-60x-to-610)
- [Addon-backgrounds preset](#addon-backgrounds-preset)
- [Single story hoisting](#single-story-hoisting)
@@ -230,6 +231,21 @@ module.exports = {
};
```
+#### Deprecated showRoots config option
+
+Config options for the sidebar are now under the `sidebar` namespace. The `showRoots` option should be set as follows:
+
+```js
+addons.setConfig({
+ sidebar: {
+ showRoots: false,
+ },
+ // showRoots: false <- this is deprecated
+});
+```
+
+The top-level `showRoots` option will be removed in Storybook 7.0.
+
## From version 6.0.x to 6.1.0
### Addon-backgrounds preset
diff --git a/docs/configure/features-and-behavior.md b/docs/configure/features-and-behavior.md
index 2dc5b27049f7..b6b0596f7c5a 100644
--- a/docs/configure/features-and-behavior.md
+++ b/docs/configure/features-and-behavior.md
@@ -22,11 +22,17 @@ The following table details how to use the API values:
| **showNav** | Boolean |Display panel that shows a list of stories |`true` |
| **showPanel** | Boolean |Display panel that shows addon configurations |`true` |
| **panelPosition** | String/Object |Where to show the addon panel |`bottom` or `right` |
-| **sidebarAnimations** | Boolean |Sidebar tree animations |`true` |
| **enableShortcuts** | Boolean |Enable/disable shortcuts |`true` |
| **isToolshown** | String |Show/hide tool bar |`true` |
| **theme** | Object |Storybook Theme, see next section |`undefined` |
| **selectedPanel** | String |Id to select an addon panel |`my-panel` |
-| **initialActive** | String |Select the default active tab on Mobile. |`sidebar` or `canvas` or `addons` |
-| **showRoots** | Boolean |Display the top-level grouping as a "root" in the sidebar |`false` |
+| **initialActive** | String |Select the default active tab on Mobile |`sidebar` or `canvas` or `addons` |
+| **sidebar** | Object |Sidebar options, see below |`{ showRoots: false }` |
+The following options are configurable under the `sidebar` namespace:
+
+| Name | Type | Description | Example Value |
+| ----------------------|:-------------:|:-------------------------------------------------------------:|:----------------------------------------------:|
+| **showRoots** | Boolean |Display the top-level nodes as a "root" in the sidebar |`false` |
+| **collapsedRoots** | Array |Set of root node IDs to visually collapse by default |`['misc', 'other']` |
+| **renderLabel** | Function |Create a custom label for tree nodes; must return a ReactNode |`(item) => {item.name}`|
diff --git a/docs/configure/sidebar-and-urls.md b/docs/configure/sidebar-and-urls.md
index 161ad961aa0b..bcf9cb2d3161 100644
--- a/docs/configure/sidebar-and-urls.md
+++ b/docs/configure/sidebar-and-urls.md
@@ -10,11 +10,11 @@ We recommend using a nesting scheme that mirrors the filesystem path of the comp
## Roots
-By default, Storybook will treat your highest level of groups as “roots”--which are displayed in the UI as “sections” of the hierarchy. Lower level groups are displayed as expandable items in the hierarchy:
+By default, Storybook will treat your top-level nodes as “roots”. Roots are displayed in the UI as “sections” of the hierarchy. Lower level groups are displayed as folders:
![Storybook sidebar story roots](./sidebar-roots.jpg)
-If you’d prefer all groups to be expandable, you can set the `showRoots` option to `false` in [`./storybook/manager.js`](./overview.md#configure-story-rendering):
+If you’d prefer to show top-level nodes as folders rather than roots, you can set the `sidebar.showRoots` option to `false` in [`./storybook/manager.js`](./overview.md#configure-story-rendering):
@@ -30,7 +30,6 @@ If you’d prefer all groups to be expandable, you can set the `showRoots` optio
As a CSF file is a JavaScript file, the exports (including the default export) can be generated dynamically. In particular you can use the `__dirname` variable to generate the title based on the path name (this example uses the paths.macro):
-
-
## Permalinking to stories
By default, Storybook generates an `id` for each story based on the component title and the story name. This `id` in particular is used in the URL for each story and that URL can serve as a permalink (especially when you [publish](../workflows/publish-storybook.md) your Storybook).
diff --git a/docs/snippets/common/storybook-config-layout.js.mdx b/docs/snippets/common/storybook-config-layout.js.mdx
index 6f06abb551c7..a73cbd0ef46c 100644
--- a/docs/snippets/common/storybook-config-layout.js.mdx
+++ b/docs/snippets/common/storybook-config-layout.js.mdx
@@ -8,12 +8,14 @@ addons.setConfig({
showNav: true,
showPanel: true,
panelPosition: 'bottom',
- sidebarAnimations: true,
enableShortcuts: true,
isToolshown: true,
theme: undefined,
selectedPanel: undefined,
initialActive: 'sidebar',
- showRoots: false,
+ sidebar: {
+ showRoots: false,
+ collapsedRoots: ['other'],
+ },
});
-```
\ No newline at end of file
+```
diff --git a/docs/snippets/common/storybook-manager-disable-roots.js.mdx b/docs/snippets/common/storybook-manager-disable-roots.js.mdx
index 5776c86769c8..3cf13c00b4a6 100644
--- a/docs/snippets/common/storybook-manager-disable-roots.js.mdx
+++ b/docs/snippets/common/storybook-manager-disable-roots.js.mdx
@@ -2,5 +2,9 @@
// ./storybook/manager.js
import { addons } from '@storybook/addons';
-addons.setConfig({ showRoots: false });
+addons.setConfig({
+ sidebar: {
+ showRoots: false,
+ },
+});
```
diff --git a/examples/official-storybook/manager.js b/examples/official-storybook/manager.js
index 2b983096e02b..b46efbc338c5 100644
--- a/examples/official-storybook/manager.js
+++ b/examples/official-storybook/manager.js
@@ -26,9 +26,9 @@ addons.setConfig({
hidden: true,
},
},
- collapsedRoots: ['other'],
sidebar: {
- storyLabel: ({ id, name }) => {
+ collapsedRoots: ['other'],
+ renderLabel: ({ id, name }) => {
const map = {
addons: (
<>
diff --git a/lib/api/src/lib/stories.ts b/lib/api/src/lib/stories.ts
index d44212f60325..3983d06525f8 100644
--- a/lib/api/src/lib/stories.ts
+++ b/lib/api/src/lib/stories.ts
@@ -20,8 +20,8 @@ export interface Root {
isComponent: false;
isRoot: true;
isLeaf: false;
+ label?: React.ReactNode;
startCollapsed?: boolean;
- storyLabel?: React.ReactNode;
}
export interface Group {
@@ -34,7 +34,7 @@ export interface Group {
isComponent: boolean;
isRoot: false;
isLeaf: false;
- storyLabel?: React.ReactNode;
+ label?: React.ReactNode;
// MDX docs-only stories are "Group" type
parameters?: {
docsOnly?: boolean;
@@ -53,7 +53,7 @@ export interface Story {
isComponent: boolean;
isRoot: false;
isLeaf: true;
- storyLabel?: React.ReactNode;
+ label?: React.ReactNode;
parameters?: {
fileName: string;
options: {
@@ -115,6 +115,14 @@ export type SetStoriesPayload =
stories: StoriesRaw;
} & Record);
+const warnLegacyShowRoots = deprecate(
+ () => {},
+ dedent`
+ The 'showRoots' config option is deprecated and will be removed in Storybook 7.0. Use 'sidebar.showRoots' instead.
+ Read more about it in the migration guide: https://github.com/storybookjs/storybook/blob/master/MIGRATION.md
+ `
+);
+
const warnChangedDefaultHierarchySeparators = deprecate(
() => {},
dedent`
@@ -139,15 +147,6 @@ export const denormalizeStoryParameters = ({
}));
};
-// The client call can return undefined, let's return something by default
-const storyLabelSafe = (
- item: Root | Group | Story,
- fn?: (item: Root | Group | Story) => React.ReactNode
-) => {
- const fnResult = fn(item);
- return fnResult || item.name;
-};
-
export const transformStoriesRawToStoriesHash = (
input: StoriesRaw,
{ provider }: { provider: Provider }
@@ -157,7 +156,12 @@ export const transformStoriesRawToStoriesHash = (
const storiesHashOutOfOrder = values.reduce((acc, item) => {
const { kind, parameters } = item;
- const { showRoots, collapsedRoots = [], sidebar = {} } = provider.getConfig();
+ const { sidebar = {}, showRoots: deprecatedShowRoots } = provider.getConfig();
+ const { showRoots = deprecatedShowRoots, collapsedRoots = [], renderLabel } = sidebar;
+
+ if (typeof deprecatedShowRoots !== 'undefined') {
+ warnLegacyShowRoots();
+ }
const setShowRoots = typeof showRoots !== 'undefined';
if (usesOldHierarchySeparator && !setShowRoots) {
@@ -192,7 +196,7 @@ export const transformStoriesRawToStoriesHash = (
isRoot: true,
startCollapsed: collapsedRoots.includes(id),
};
- list.push({ ...rootElement, storyLabel: sidebar.storyLabel?.(rootElement) });
+ list.push({ ...rootElement, label: renderLabel?.(rootElement) });
} else {
const groupElement: Group = {
id,
@@ -210,7 +214,7 @@ export const transformStoriesRawToStoriesHash = (
};
list.push({
...groupElement,
- storyLabel: sidebar.storyLabel?.(groupElement),
+ label: renderLabel?.(groupElement),
});
}
@@ -237,7 +241,7 @@ export const transformStoriesRawToStoriesHash = (
isComponent: false,
isRoot: false,
};
- acc[item.id] = { ...story, storyLabel: sidebar.storyLabel?.(story) };
+ acc[item.id] = { ...story, label: renderLabel?.(story) };
return acc;
}, {} as StoriesHash);
diff --git a/lib/api/src/modules/layout.ts b/lib/api/src/modules/layout.ts
index c8c2183cdbbb..41c4a16bdae0 100644
--- a/lib/api/src/modules/layout.ts
+++ b/lib/api/src/modules/layout.ts
@@ -4,7 +4,7 @@ import deepEqual from 'fast-deep-equal';
import { themes, ThemeVars } from '@storybook/theming';
import merge from '../lib/merge';
-import { State, ModuleFn, Root, Group, Story } from '../index';
+import { State, ModuleFn } from '../index';
export type PanelPositions = 'bottom' | 'right';
export type ActiveTabsType = 'sidebar' | 'canvas' | 'addons';
@@ -27,7 +27,6 @@ export interface UI {
name?: string;
url?: string;
enableShortcuts: boolean;
- sidebarAnimations: boolean;
docsMode: boolean;
}
@@ -58,16 +57,11 @@ export interface UIOptions {
addonPanelInRight: boolean;
theme?: ThemeVars;
selectedPanel?: string;
- sidebar?: {
- /** Used to render a custom label based on the current item */
- storyLabel?: (item: Root | Group | Story) => React.ReactNode | undefined;
- };
}
const defaultState: SubState = {
ui: {
enableShortcuts: true,
- sidebarAnimations: true,
docsMode: false,
},
layout: {
diff --git a/lib/api/src/modules/provider.ts b/lib/api/src/modules/provider.ts
index d79822034188..298546b1dcdd 100644
--- a/lib/api/src/modules/provider.ts
+++ b/lib/api/src/modules/provider.ts
@@ -2,10 +2,16 @@ import { ReactNode } from 'react';
import { Channel } from '@storybook/channels';
import { ThemeVars } from '@storybook/theming';
-import { API, State, ModuleFn } from '../index';
+import { API, State, ModuleFn, Root, Group, Story } from '../index';
import { StoryMapper, Refs } from './refs';
import { UIOptions } from './layout';
+interface SidebarOptions {
+ showRoots?: boolean;
+ collapsedRoots?: string[];
+ renderLabel?: (item: Root | Group | Story) => ReactNode;
+}
+
type IframeRenderer = (
storyId: string,
viewMode: State['viewMode'],
@@ -20,6 +26,7 @@ export interface Provider {
renderPreview?: IframeRenderer;
handleAPI(api: API): void;
getConfig(): {
+ sidebar?: SidebarOptions;
theme?: ThemeVars;
refs?: Refs;
StoryMapper?: StoryMapper;
diff --git a/lib/api/src/modules/stories.ts b/lib/api/src/modules/stories.ts
index 775b3254e829..aa9407152eba 100644
--- a/lib/api/src/modules/stories.ts
+++ b/lib/api/src/modules/stories.ts
@@ -77,7 +77,6 @@ interface Meta {
}
const deprecatedOptionsParameterWarnings: Record void> = [
- 'sidebarAnimations',
'enableShortcuts',
'theme',
'showRoots',
diff --git a/lib/api/src/tests/layout.test.js b/lib/api/src/tests/layout.test.js
index ed729cc06f42..30acdf9abcd6 100644
--- a/lib/api/src/tests/layout.test.js
+++ b/lib/api/src/tests/layout.test.js
@@ -16,7 +16,6 @@ describe('layout API', () => {
currentState = {
ui: {
enableShortcuts: true,
- sidebarAnimations: true,
docsMode: false,
},
layout: {
diff --git a/lib/api/src/tests/stories.test.js b/lib/api/src/tests/stories.test.js
index b700c9be51d6..d76257575a9c 100644
--- a/lib/api/src/tests/stories.test.js
+++ b/lib/api/src/tests/stories.test.js
@@ -93,7 +93,7 @@ describe('stories API', () => {
api: { setStories },
} = initStories({ store, navigate, provider });
- provider.getConfig.mockReturnValue({ showRoots: false });
+ provider.getConfig.mockReturnValue({ sidebar: { showRoots: false } });
setStories(storiesHash);
const { storiesHash: storedStoriesHash } = store.getState();
@@ -255,7 +255,7 @@ describe('stories API', () => {
api: { setStories },
} = initStories({ store, navigate, provider });
- provider.getConfig.mockReturnValue({ showRoots: true });
+ provider.getConfig.mockReturnValue({ sidebar: { showRoots: true } });
setStories({
'a-b--1': {
kind: 'a/b',
@@ -302,7 +302,7 @@ describe('stories API', () => {
api: { setStories },
} = initStories({ store, navigate, provider });
- provider.getConfig.mockReturnValue({ showRoots: true });
+ provider.getConfig.mockReturnValue({ sidebar: { showRoots: true } });
setStories({
'a--1': {
kind: 'a',
diff --git a/lib/ui/src/components/sidebar/Tree.stories.tsx b/lib/ui/src/components/sidebar/Tree.stories.tsx
index 326eb3197276..98a38247522e 100644
--- a/lib/ui/src/components/sidebar/Tree.stories.tsx
+++ b/lib/ui/src/components/sidebar/Tree.stories.tsx
@@ -44,7 +44,7 @@ const singleStoryComponent = {
isComponent: true,
isLeaf: false,
isRoot: false,
- storyLabel: 🔥 Single,
+ label: 🔥 Single,
},
'single--single': {
id: 'single--single',
@@ -59,7 +59,7 @@ const singleStoryComponent = {
isLeaf: true,
isComponent: false,
isRoot: false,
- storyLabel: 🔥 Single,
+ label: 🔥 Single,
},
};
diff --git a/lib/ui/src/components/sidebar/Tree.tsx b/lib/ui/src/components/sidebar/Tree.tsx
index 401c59b55fc5..616724ccbec4 100644
--- a/lib/ui/src/components/sidebar/Tree.tsx
+++ b/lib/ui/src/components/sidebar/Tree.tsx
@@ -137,7 +137,7 @@ const Node = React.memo(
onSelectStoryId(item.id);
}}
>
- {item.storyLabel || item.name}
+ {item.label || item.name}
);
}
@@ -162,7 +162,7 @@ const Node = React.memo(
}}
>
- {item.storyLabel || item.name}
+ {item.label || item.name}
{isExpanded && (
(
if (item.isComponent && !isExpanded) onSelectStoryId(item.id);
}}
>
- {item.storyLabel || item.name}
+ {item.label || item.name}
);
}