Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Add renderLabel to customize sidebar tree labels #13121

Merged
merged 5 commits into from
Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion examples/official-storybook/manager.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import React from 'react';
import { addons } from '@storybook/addons';
import { themes } from '@storybook/theming';
import { themes, styled } from '@storybook/theming';
import { Icons } from '@storybook/components';

import addHeadWarning from './head-warning';

addHeadWarning('manager-head-not-loaded', 'Manager head not loaded');

const PrefixIcon = styled(Icons)(({ theme }) => ({
marginRight: 8,
fontSize: 'inherit',
height: '1em',
width: '1em',
display: 'inline',
alignSelf: 'center',
}));

addons.setConfig({
theme: themes.light, // { base: 'dark', brandTitle: 'Storybook!' },
previewTabs: {
Expand All @@ -15,4 +26,35 @@ addons.setConfig({
hidden: true,
},
},
sidebar: {
storyLabel: ({ id, name }) => {
const map = {
addons: (
<>
<PrefixIcon icon="power" />
{name}
</>
),
'addons-a11y': (
<>
<PrefixIcon icon="certificate" />
{name}
</>
),
'addons-a11y-basebutton': (
<>
<PrefixIcon icon="calendar" />
{name}
</>
),
'addons-a11y-basebutton--default': (
<>
<PrefixIcon icon="star" />
{name}
</>
),
};
return map[id];
},
},
});
28 changes: 23 additions & 5 deletions lib/api/src/lib/stories.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import deprecate from 'util-deprecate';
import dedent from 'ts-dedent';
import { sanitize } from '@storybook/csf';
Expand All @@ -19,6 +20,7 @@ export interface Root {
isComponent: false;
isRoot: true;
isLeaf: false;
storyLabel?: React.ReactNode;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't these be functions?

}

export interface Group {
Expand All @@ -31,6 +33,7 @@ export interface Group {
isComponent: boolean;
isRoot: false;
isLeaf: false;
storyLabel?: React.ReactNode;
// MDX docs-only stories are "Group" type
parameters?: {
docsOnly?: boolean;
Expand All @@ -49,6 +52,7 @@ export interface Story {
isComponent: boolean;
isRoot: false;
isLeaf: true;
storyLabel?: React.ReactNode;
parameters?: {
fileName: string;
options: {
Expand Down Expand Up @@ -132,6 +136,15 @@ 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 }
Expand All @@ -141,7 +154,7 @@ export const transformStoriesRawToStoriesHash = (

const storiesHashOutOfOrder = values.reduce((acc, item) => {
const { kind, parameters } = item;
const { showRoots } = provider.getConfig();
const { showRoots, sidebar = {} } = provider.getConfig();

const setShowRoots = typeof showRoots !== 'undefined';
if (usesOldHierarchySeparator && !setShowRoots) {
Expand All @@ -166,17 +179,18 @@ export const transformStoriesRawToStoriesHash = (
}

if (root.length && index === 0) {
list.push({
const rootElement: Root = {
id,
name,
depth: index,
children: [],
isComponent: false,
isLeaf: false,
isRoot: true,
});
};
list.push({ ...rootElement, storyLabel: sidebar.storyLabel?.(rootElement) });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL you can do optional chaining before a function invocation.

} else {
list.push({
const groupElement: Group = {
id,
name,
parent,
Expand All @@ -189,6 +203,10 @@ export const transformStoriesRawToStoriesHash = (
docsOnly: parameters?.docsOnly,
viewMode: parameters?.viewMode,
},
};
list.push({
...groupElement,
storyLabel: sidebar.storyLabel?.(groupElement),
});
}

Expand All @@ -215,7 +233,7 @@ export const transformStoriesRawToStoriesHash = (
isComponent: false,
isRoot: false,
};
acc[item.id] = story;
acc[item.id] = { ...story, storyLabel: sidebar.storyLabel?.(story) };

return acc;
}, {} as StoriesHash);
Expand Down
6 changes: 5 additions & 1 deletion lib/api/src/modules/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import deepEqual from 'fast-deep-equal';
import { themes, ThemeVars } from '@storybook/theming';

import merge from '../lib/merge';
import { State, ModuleFn } from '../index';
import { State, ModuleFn, Root, Group, Story } from '../index';

export type PanelPositions = 'bottom' | 'right';
export type ActiveTabsType = 'sidebar' | 'canvas' | 'addons';
Expand Down Expand Up @@ -58,6 +58,10 @@ 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 = {
Expand Down
2 changes: 2 additions & 0 deletions lib/ui/src/components/sidebar/Tree.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const singleStoryComponent = {
isComponent: true,
isLeaf: false,
isRoot: false,
storyLabel: <span>🔥 Single</span>,
},
'single--single': {
id: 'single--single',
Expand All @@ -58,6 +59,7 @@ const singleStoryComponent = {
isLeaf: true,
isComponent: false,
isRoot: false,
storyLabel: <span>🔥 Single</span>,
ghengeveld marked this conversation as resolved.
Show resolved Hide resolved
},
};

Expand Down
7 changes: 4 additions & 3 deletions lib/ui/src/components/sidebar/Tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const Action = styled.button(({ theme }) => ({
width: 20,
height: 20,
margin: 0,
marginLeft: 'auto',
padding: 0,
outline: 0,
lineHeight: 'normal',
Expand Down Expand Up @@ -91,7 +92,7 @@ const Node = React.memo<NodeProps>(
onSelectStoryId(item.id);
}}
>
{item.name}
{item.storyLabel || item.name}
ghengeveld marked this conversation as resolved.
Show resolved Hide resolved
</LeafNode>
);
}
Expand All @@ -106,7 +107,7 @@ const Node = React.memo<NodeProps>(
data-item-id={item.id}
data-nodetype="root"
>
{item.name}
<span>{item.storyLabel || item.name}</span>
<Action
type="button"
className="sidebar-subheading-action"
Expand Down Expand Up @@ -146,7 +147,7 @@ const Node = React.memo<NodeProps>(
if (item.isComponent && !isExpanded) onSelectStoryId(item.id);
}}
>
{item.name}
{item.storyLabel || item.name}
</BranchNode>
);
}
Expand Down
1 change: 0 additions & 1 deletion lib/ui/src/components/sidebar/TreeNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ export const Path = styled.span(({ theme }) => ({
export const RootNode = styled.span(({ theme }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
margin: '16px 20px 4px 20px',
fontSize: `${theme.typography.size.s1 - 1}px`,
fontWeight: theme.typography.weight.black,
Expand Down