Skip to content

Commit

Permalink
Merge pull request #23811 from storybookjs/norbert/add-sidebar-top-slot
Browse files Browse the repository at this point in the history
UI: Add an experimental API for adding sidebar top toolbar
  • Loading branch information
ndelangen authored Aug 24, 2023
2 parents 1f18e29 + d3c4b6e commit c1044d6
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 18 deletions.
3 changes: 3 additions & 0 deletions code/lib/manager-api/src/lib/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
Addon_TypesMapping,
Addon_WrapperType,
Addon_SidebarBottomType,
Addon_SidebarTopType,
} from '@storybook/types';
import { Addon_TypesEnum } from '@storybook/types';
import { logger } from '@storybook/client-logger';
Expand Down Expand Up @@ -103,6 +104,7 @@ export class AddonStore {
| Addon_Types
| Addon_TypesEnum.experimental_PAGE
| Addon_TypesEnum.experimental_SIDEBAR_BOTTOM
| Addon_TypesEnum.experimental_SIDEBAR_TOP
>(type: T): Addon_Collection<Addon_TypesMapping[T]> {
if (!this.elements[type]) {
this.elements[type] = {};
Expand Down Expand Up @@ -145,6 +147,7 @@ export class AddonStore {
id: string,
addon:
| Addon_BaseType
| (Omit<Addon_SidebarTopType, 'id'> & DeprecatedAddonWithId)
| (Omit<Addon_SidebarBottomType, 'id'> & DeprecatedAddonWithId)
| (Omit<Addon_PageType, 'id'> & DeprecatedAddonWithId)
| (Omit<Addon_WrapperType, 'id'> & DeprecatedAddonWithId)
Expand Down
3 changes: 2 additions & 1 deletion code/lib/manager-api/src/modules/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export interface SubAPI {
T extends
| Addon_Types
| Addon_TypesEnum.experimental_PAGE
| Addon_TypesEnum.experimental_SIDEBAR_BOTTOM = Addon_Types
| Addon_TypesEnum.experimental_SIDEBAR_BOTTOM
| Addon_TypesEnum.experimental_SIDEBAR_TOP = Addon_Types
>(
type: T
) => Addon_Collection<Addon_TypesMapping[T]>;
Expand Down
28 changes: 26 additions & 2 deletions code/lib/types/src/modules/addons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ import type { IndexEntry } from './indexer';

export type Addon_Types = Exclude<
Addon_TypesEnum,
Addon_TypesEnum.experimental_PAGE | Addon_TypesEnum.experimental_SIDEBAR_BOTTOM
| Addon_TypesEnum.experimental_PAGE
| Addon_TypesEnum.experimental_SIDEBAR_BOTTOM
| Addon_TypesEnum.experimental_SIDEBAR_TOP
>;

export interface Addon_ArgType<TArg = unknown> extends InputType {
defaultValue?: TArg;
}
Expand Down Expand Up @@ -330,7 +333,8 @@ export type Addon_Type =
| Addon_BaseType
| Addon_PageType
| Addon_WrapperType
| Addon_SidebarBottomType;
| Addon_SidebarBottomType
| Addon_SidebarTopType;
export interface Addon_BaseType {
/**
* The title of the addon.
Expand All @@ -346,6 +350,7 @@ export interface Addon_BaseType {
| Addon_TypesEnum.PREVIEW
| Addon_TypesEnum.experimental_PAGE
| Addon_TypesEnum.experimental_SIDEBAR_BOTTOM
| Addon_TypesEnum.experimental_SIDEBAR_TOP
>;
/**
* The unique id of the addon.
Expand Down Expand Up @@ -471,17 +476,31 @@ export interface Addon_SidebarBottomType {
render: FCWithoutChildren;
}

export interface Addon_SidebarTopType {
type: Addon_TypesEnum.experimental_SIDEBAR_TOP;
/**
* The unique id of the tool.
*/
id: string;
/**
* A React.FunctionComponent.
*/
render: FCWithoutChildren;
}

type Addon_TypeBaseNames = Exclude<
Addon_TypesEnum,
| Addon_TypesEnum.PREVIEW
| Addon_TypesEnum.experimental_PAGE
| Addon_TypesEnum.experimental_SIDEBAR_BOTTOM
| Addon_TypesEnum.experimental_SIDEBAR_TOP
>;

export interface Addon_TypesMapping extends Record<Addon_TypeBaseNames, Addon_BaseType> {
[Addon_TypesEnum.PREVIEW]: Addon_WrapperType;
[Addon_TypesEnum.experimental_PAGE]: Addon_PageType;
[Addon_TypesEnum.experimental_SIDEBAR_BOTTOM]: Addon_SidebarBottomType;
[Addon_TypesEnum.experimental_SIDEBAR_TOP]: Addon_SidebarTopType;
}

export type Addon_Loader<API> = (api: API) => void;
Expand Down Expand Up @@ -540,6 +559,11 @@ export enum Addon_TypesEnum {
* @unstable
*/
experimental_SIDEBAR_BOTTOM = 'sidebar-bottom',
/**
* This adds items in the top of the sidebar.
* @unstable This will get replaced with a new API in 8.0, use at your own risk.
*/
experimental_SIDEBAR_TOP = 'sidebar-top',

/**
* @deprecated This property does nothing, and will be removed in Storybook 8.0.
Expand Down
1 change: 1 addition & 0 deletions code/ui/manager/src/components/layout/app.mockdata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const realSidebarProps: SidebarProps = {
refs: {},
status: {},
previewInitialized: true,
extra: [],
};

const PlaceholderBlock = styled.div(({ color }) => ({
Expand Down
31 changes: 19 additions & 12 deletions code/ui/manager/src/components/sidebar/Heading.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ const menuItems = [
{ title: 'Menu Item 3', onClick: action('onActivateMenuItem'), id: '3' },
];

export const MenuHighlighted: Story = () => <Heading menuHighlighted menu={menuItems} />;
export const MenuHighlighted: Story = () => (
<Heading menuHighlighted menu={menuItems} isLoading={false} extra={[]} />
);

export const standardData = { menu: menuItems };

Expand All @@ -45,7 +47,7 @@ export const Standard: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -64,7 +66,7 @@ export const StandardNoLink: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -83,7 +85,7 @@ export const LinkAndText: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -102,7 +104,7 @@ export const OnlyText: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -121,7 +123,7 @@ export const LongText: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -140,7 +142,7 @@ export const CustomTitle: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -159,7 +161,7 @@ export const CustomBrandImage: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -178,7 +180,7 @@ export const CustomBrandImageTall: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -197,7 +199,7 @@ export const CustomBrandImageUnsizedSVG: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};
Expand All @@ -216,13 +218,18 @@ export const NoBrand: Story = () => {
},
}}
>
<Heading menu={menuItems} />
<Heading menu={menuItems} isLoading={false} extra={[]} />
</ThemeProvider>
);
};

export const SkipToCanvasLinkFocused: ComponentStoryObj<typeof Heading> = {
args: { menu: menuItems, skipLinkHref: '#storybook-preview-wrapper' },
args: {
menu: menuItems,
skipLinkHref: '#storybook-preview-wrapper',
extra: [],
isLoading: false,
},
parameters: { layout: 'padded', chromatic: { delay: 300 } },
play: () => {
// focus each instance for chromatic/storybook's stacked theme
Expand Down
9 changes: 9 additions & 0 deletions code/ui/manager/src/components/sidebar/Heading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import React from 'react';
import { styled } from '@storybook/theming';
import { Button } from '@storybook/components';

import type { Addon_SidebarTopType } from '@storybook/types';
import { Brand } from './Brand';
import type { MenuList } from './Menu';
import { SidebarMenu } from './Menu';

export interface HeadingProps {
menuHighlighted?: boolean;
menu: MenuList;
extra: Addon_SidebarTopType[];
skipLinkHref?: string;
isLoading: boolean;
}

const BrandArea = styled.div(({ theme }) => ({
Expand All @@ -23,6 +26,9 @@ const BrandArea = styled.div(({ theme }) => ({
alignItems: 'center',
minHeight: 22,

'& > * > *': {
maxWidth: '100%',
},
'& > *': {
maxWidth: '100%',
height: 'auto',
Expand Down Expand Up @@ -73,6 +79,8 @@ export const Heading: FC<HeadingProps & ComponentProps<typeof HeadingWrapper>> =
menuHighlighted = false,
menu,
skipLinkHref,
extra,
isLoading,
...props
}) => {
return (
Expand All @@ -87,6 +95,7 @@ export const Heading: FC<HeadingProps & ComponentProps<typeof HeadingWrapper>> =
<Brand />
</BrandArea>

{isLoading ? null : extra.map(({ id, render: Render }) => <Render key={id} />)}
<SidebarMenu menu={menu} isHighlighted={menuHighlighted} />
</HeadingWrapper>
);
Expand Down
18 changes: 17 additions & 1 deletion code/ui/manager/src/components/sidebar/Sidebar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const Simple: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
index={index as any}
storyId={storyId}
refId={DEFAULT_REF_ID}
Expand All @@ -74,7 +75,15 @@ export const Simple: Story = {
export const Loading: Story = {
args: { previewInitialized: false },
render: (args) => (
<Sidebar {...args} menu={menu} storyId={storyId} refId={DEFAULT_REF_ID} refs={{}} status={{}} />
<Sidebar
{...args}
menu={menu}
extra={[]}
storyId={storyId}
refId={DEFAULT_REF_ID}
refs={{}}
status={{}}
/>
),
};

Expand All @@ -86,6 +95,7 @@ export const Empty: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
index={{}}
storyId={storyId}
refId={DEFAULT_REF_ID}
Expand All @@ -103,6 +113,7 @@ export const IndexError: Story = {
<Sidebar
{...args}
indexError={indexError}
extra={[]}
menu={menu}
storyId={storyId}
refId={DEFAULT_REF_ID}
Expand All @@ -120,6 +131,7 @@ export const WithRefs: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
index={index as any}
storyId={storyId}
refId={DEFAULT_REF_ID}
Expand All @@ -137,6 +149,7 @@ export const LoadingWithRefs: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
storyId={storyId}
refId={DEFAULT_REF_ID}
refs={refs}
Expand All @@ -153,6 +166,7 @@ export const LoadingWithRefError: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
storyId={storyId}
refId={DEFAULT_REF_ID}
refs={refsError}
Expand Down Expand Up @@ -185,6 +199,7 @@ export const StatusesCollapsed: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
index={index as any}
storyId={storyId}
refId={DEFAULT_REF_ID}
Expand Down Expand Up @@ -234,6 +249,7 @@ export const Bottom: Story = {
<Sidebar
{...args}
menu={menu}
extra={[]}
index={index as any}
storyId={storyId}
refId={DEFAULT_REF_ID}
Expand Down
10 changes: 9 additions & 1 deletion code/ui/manager/src/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { styled } from '@storybook/theming';
import { ScrollArea, Spaced } from '@storybook/components';
import type { State } from '@storybook/manager-api';

import type { Addon_SidebarBottomType, API_LoadedRefData } from '@storybook/types';
import type {
Addon_SidebarBottomType,
Addon_SidebarTopType,
API_LoadedRefData,
} from '@storybook/types';
import { Heading } from './Heading';

// eslint-disable-next-line import/no-cycle
Expand Down Expand Up @@ -97,6 +101,7 @@ export interface SidebarProps extends API_LoadedRefData {
refs: State['refs'];
status: State['status'];
menu: any[];
extra: Addon_SidebarTopType[];
bottom?: Addon_SidebarBottomType[];
storyId?: string;
refId?: string;
Expand All @@ -112,6 +117,7 @@ export const Sidebar = React.memo(function Sidebar({
status,
previewInitialized,
menu,
extra,
bottom = [],
menuHighlighted = false,
enableShortcuts = true,
Expand All @@ -130,7 +136,9 @@ export const Sidebar = React.memo(function Sidebar({
className="sidebar-header"
menuHighlighted={menuHighlighted}
menu={menu}
extra={extra}
skipLinkHref="#storybook-preview-wrapper"
isLoading={isLoading}
/>

<Search
Expand Down
Loading

0 comments on commit c1044d6

Please sign in to comment.