mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
feat(component): add storybook (#5079)
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
|
||||
import { MenuTrigger, type MenuTriggerProps } from '.';
|
||||
|
||||
export default {
|
||||
title: 'UI/MenuTrigger',
|
||||
component: MenuTrigger,
|
||||
} satisfies Meta<typeof MenuTrigger>;
|
||||
|
||||
const Template: StoryFn<MenuTriggerProps> = args => (
|
||||
<div style={{ width: '50%' }}>
|
||||
<MenuTrigger {...args}>This is a menu trigger</MenuTrigger>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Default: StoryFn<MenuTriggerProps> = Template.bind(undefined);
|
||||
Default.args = {};
|
||||
203
packages/frontend/component/src/ui/menu/menu.stories.tsx
Normal file
203
packages/frontend/component/src/ui/menu/menu.stories.tsx
Normal file
@@ -0,0 +1,203 @@
|
||||
import { InformationIcon } from '@blocksuite/icons';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import { type ReactNode, useCallback, useState } from 'react';
|
||||
|
||||
import { Button } from '../button';
|
||||
import { Tooltip } from '../tooltip';
|
||||
import {
|
||||
Menu,
|
||||
MenuIcon,
|
||||
MenuItem,
|
||||
type MenuItemProps,
|
||||
type MenuProps,
|
||||
MenuSeparator,
|
||||
MenuSub,
|
||||
MenuTrigger,
|
||||
} from '.';
|
||||
|
||||
export default {
|
||||
title: 'UI/Menu',
|
||||
component: Menu,
|
||||
} satisfies Meta<typeof Menu>;
|
||||
|
||||
const Template: StoryFn<MenuProps> = args => (
|
||||
<Menu
|
||||
{...args}
|
||||
contentOptions={{
|
||||
style: {
|
||||
width: '500px',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MenuTrigger>menu trigger</MenuTrigger>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
interface Items {
|
||||
label: ReactNode;
|
||||
type?: MenuItemProps['type'];
|
||||
preFix?: MenuItemProps['preFix'];
|
||||
disabled?: boolean;
|
||||
divider?: boolean;
|
||||
subItems?: Items[];
|
||||
block?: boolean;
|
||||
}
|
||||
|
||||
const items: Items[] = [
|
||||
{
|
||||
label: 'default menu item 1',
|
||||
},
|
||||
{
|
||||
label: 'menu item with icon',
|
||||
preFix: (
|
||||
<Tooltip content="Use `MenuIcon` to wrap your icon and choose `preFix` or `endFix`">
|
||||
<MenuIcon>
|
||||
<InformationIcon />
|
||||
</MenuIcon>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<Tooltip
|
||||
align="start"
|
||||
content="Write, Draw, and Plan All at Once Notion Open Source Alternative One
|
||||
hyper-fused platform for wildly creative minds"
|
||||
>
|
||||
<span>
|
||||
Write, Draw, and Plan All at Once Notion Open Source Alternative One
|
||||
hyper-fused platform for wildly creative minds
|
||||
</span>
|
||||
</Tooltip>
|
||||
),
|
||||
block: true,
|
||||
},
|
||||
{
|
||||
label: 'default disabled menu item',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
label: 'danger menu item',
|
||||
type: 'danger',
|
||||
block: true,
|
||||
preFix: (
|
||||
<Tooltip content="Use `MenuIcon` to wrap your icon and choose `preFix` or `endFix`">
|
||||
<MenuIcon>
|
||||
<InformationIcon />
|
||||
</MenuIcon>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: 'warning menu item',
|
||||
type: 'warning',
|
||||
divider: true,
|
||||
},
|
||||
|
||||
{
|
||||
label: 'menu item with sub menu',
|
||||
subItems: [
|
||||
{
|
||||
label: 'sub menu item 1',
|
||||
},
|
||||
{
|
||||
label: 'sub menu item 1',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
label: 'menu item with deep sub menu',
|
||||
subItems: [
|
||||
{
|
||||
label: 'sub menu item 1',
|
||||
},
|
||||
{
|
||||
label: 'sub menu with sub',
|
||||
subItems: [
|
||||
{
|
||||
label: 'sub menu item 2-1',
|
||||
},
|
||||
{
|
||||
label: 'sub menu item 2-2',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const Default: StoryFn<MenuProps> = Template.bind(undefined);
|
||||
|
||||
const ItemRender = ({ label, divider, subItems, ...otherProps }: Items) => {
|
||||
const onSelect = useCallback(() => {
|
||||
console.log('value', label);
|
||||
}, [label]);
|
||||
|
||||
if (subItems) {
|
||||
return (
|
||||
<>
|
||||
<MenuSub
|
||||
items={subItems.map((props, i) => (
|
||||
<ItemRender key={i} {...props} />
|
||||
))}
|
||||
triggerOptions={otherProps}
|
||||
>
|
||||
{label}
|
||||
</MenuSub>
|
||||
{divider ? <MenuSeparator /> : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<MenuItem onSelect={onSelect} {...otherProps}>
|
||||
{label}
|
||||
</MenuItem>
|
||||
{divider ? <MenuSeparator /> : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
items: items.map((props, i) => {
|
||||
return <ItemRender key={i} {...props} />;
|
||||
}),
|
||||
};
|
||||
|
||||
const selectList = [
|
||||
{ name: 'AFFiNE', value: '1' },
|
||||
{ name: 'blocksuite', value: '2' },
|
||||
{ name: 'octobase', value: '3' },
|
||||
{ name: 'virgo', value: '4' },
|
||||
];
|
||||
const SelectItems = ({
|
||||
selectedValue,
|
||||
onSelect,
|
||||
}: {
|
||||
selectedValue: string;
|
||||
onSelect: (value: string) => void;
|
||||
}) => {
|
||||
return selectList.map(({ name, value }) => (
|
||||
<MenuItem
|
||||
key={value}
|
||||
selected={selectedValue === value}
|
||||
onSelect={() => onSelect(value)}
|
||||
>
|
||||
{name}
|
||||
</MenuItem>
|
||||
));
|
||||
};
|
||||
|
||||
const AsSelectTemplate: StoryFn<MenuProps> = () => {
|
||||
const [value, setValue] = useState('1');
|
||||
const name = selectList.find(item => item.value === value)?.name;
|
||||
return (
|
||||
<Menu items={<SelectItems selectedValue={value} onSelect={setValue} />}>
|
||||
<Button>selected: {name}</Button>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
export const AsSelect: StoryFn<MenuProps> = AsSelectTemplate.bind({});
|
||||
Reference in New Issue
Block a user