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

UI: Add an experimental API for adding sidebar top toolbar #23811

Merged
merged 11 commits into from
Aug 24, 2023
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