mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-01 14:19:40 +08:00
refactor(component): refactor the implementation of Button and IconButton (#7716)
## Button
- Remove props withoutHoverStyle
refactor hover impl with independent layer, so that hover-color won't affect the background even if is overridden outside
- Update `type` (renamed to `variant`):
- remove `processing` and `warning`
- rename `default` with `secondary`
- Remove `shape` props
- Remove `icon` and `iconPosition`, replaced with `prefix: ReactNode` and `suffix: ReactNode`
- Integrate tooltip for more convenient usage
- New Storybook document
- Focus style
## IconButton
- A Wrapper base on `<Button />`
- Override Button size and variant
- size: `'12' | '14' | '16' | '20' | '24' | number`
These presets size are referenced from the design system.
- variant: `'plain' | 'solid' | 'danger' | 'custom'`
- Inset icon via Button 's prefix
## Fix
- fix some button related issues
- close AF-1159, AF-1160, AF-1161, AF-1162, AF-1163, AF-1158, AF-1157
## Storybook

This commit is contained in:
@@ -1,47 +1,183 @@
|
||||
import { InformationIcon } from '@blocksuite/icons/rc';
|
||||
import type { Meta, StoryFn } from '@storybook/react';
|
||||
import {
|
||||
AfFiNeIcon,
|
||||
ArrowRightBigIcon,
|
||||
FolderIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import clsx from 'clsx';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Switch } from '../switch';
|
||||
import type { ButtonProps } from './button';
|
||||
import { Button } from './button';
|
||||
import * as styles from './button.stories.css';
|
||||
export default {
|
||||
title: 'UI/Button',
|
||||
component: Button,
|
||||
argTypes: {
|
||||
onClick: () => console.log('Click button'),
|
||||
},
|
||||
} satisfies Meta<ButtonProps>;
|
||||
|
||||
const Template: StoryFn<ButtonProps> = args => <Button {...args} />;
|
||||
// const Template: StoryFn<ButtonProps> = args => <Button {...args} />;
|
||||
|
||||
export const Default: StoryFn<ButtonProps> = Template.bind(undefined);
|
||||
Default.args = {
|
||||
type: 'default',
|
||||
children: 'This is a default button',
|
||||
icon: <InformationIcon />,
|
||||
const types: ButtonProps['variant'][] = [
|
||||
'primary',
|
||||
'secondary',
|
||||
'plain',
|
||||
'error',
|
||||
'success',
|
||||
];
|
||||
const sizes: ButtonProps['size'][] = ['default', 'large', 'extraLarge'];
|
||||
|
||||
const Groups = ({
|
||||
children,
|
||||
...props
|
||||
}: Omit<ButtonProps, 'variant' | 'size'>) => {
|
||||
return (
|
||||
<table className={styles.table}>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Type/Size</td>
|
||||
{sizes.map(size => (
|
||||
<td key={size}>{size}</td>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{types.map(type => (
|
||||
<tr key={type}>
|
||||
<td>{type}</td>
|
||||
{sizes.map(size => (
|
||||
<td key={size}>
|
||||
<Button variant={type} size={size} {...props}>
|
||||
{children ?? `${size} - ${type}`}
|
||||
</Button>
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export const Primary: StoryFn<ButtonProps> = Template.bind(undefined);
|
||||
Primary.args = {
|
||||
type: 'primary',
|
||||
children: 'Content',
|
||||
icon: <InformationIcon />,
|
||||
export const Default = () => <Groups />;
|
||||
|
||||
export const WithIcon = () => {
|
||||
return <Groups prefix={<FolderIcon />} suffix={<span>🚀</span>} />;
|
||||
};
|
||||
|
||||
export const Disabled: StoryFn<ButtonProps> = Template.bind(undefined);
|
||||
Disabled.args = {
|
||||
disabled: true,
|
||||
children: 'This is a disabled button',
|
||||
export const Loading = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const toggleLoading = useCallback(() => setLoading(v => !v), []);
|
||||
|
||||
useEffect(() => {
|
||||
setInterval(toggleLoading, 1000);
|
||||
}, [toggleLoading]);
|
||||
|
||||
return <Groups loading={loading} prefix={<FolderIcon />} />;
|
||||
};
|
||||
|
||||
export const LargeSizeButton: StoryFn<ButtonProps> = Template.bind(undefined);
|
||||
LargeSizeButton.args = {
|
||||
size: 'large',
|
||||
children: 'This is a large button',
|
||||
export const OverrideViaClassName = () => {
|
||||
const [overrideBg, setOverrideBg] = useState(false);
|
||||
const [overrideTextColor, setOverrideTextColor] = useState(false);
|
||||
const [overrideBorder, setOverrideBorder] = useState(false);
|
||||
const [overrideFontSize, setOverrideFontSize] = useState(false);
|
||||
const [overridePrefixSize, setOverridePrefixSize] = useState(false);
|
||||
const [overrideSuffixSize, setOverrideSuffixSize] = useState(false);
|
||||
const [overridePrefixColor, setOverridePrefixColor] = useState(false);
|
||||
const [overrideSuffixColor, setOverrideSuffixColor] = useState(false);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={styles.settings}>
|
||||
<section>
|
||||
<span>Override background color</span>
|
||||
<Switch checked={overrideBg} onChange={setOverrideBg} />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override text color</span>
|
||||
<Switch checked={overrideTextColor} onChange={setOverrideTextColor} />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override border color</span>
|
||||
<Switch checked={overrideBorder} onChange={setOverrideBorder} />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override font size</span>
|
||||
<Switch checked={overrideFontSize} onChange={setOverrideFontSize} />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override prefix size</span>
|
||||
<Switch
|
||||
checked={overridePrefixSize}
|
||||
onChange={setOverridePrefixSize}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override suffix size</span>
|
||||
<Switch
|
||||
checked={overrideSuffixSize}
|
||||
onChange={setOverrideSuffixSize}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override prefix color</span>
|
||||
<Switch
|
||||
checked={overridePrefixColor}
|
||||
onChange={setOverridePrefixColor}
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<span>Override suffix color</span>
|
||||
<Switch
|
||||
checked={overrideSuffixColor}
|
||||
onChange={setOverrideSuffixColor}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<Groups
|
||||
prefix={<FolderIcon />}
|
||||
suffix={<ArrowRightBigIcon />}
|
||||
className={clsx({
|
||||
[styles.overrideBackground]: overrideBg,
|
||||
[styles.overrideTextColor]: overrideTextColor,
|
||||
[styles.overrideBorder]: overrideBorder,
|
||||
[styles.overrideFontSize]: overrideFontSize,
|
||||
})}
|
||||
prefixClassName={clsx({
|
||||
[styles.overrideIconSize]: overridePrefixSize,
|
||||
[styles.overrideIconColor]: overridePrefixColor,
|
||||
})}
|
||||
suffixClassName={clsx({
|
||||
[styles.overrideIconSize]: overrideSuffixSize,
|
||||
[styles.overrideIconColor]: overrideSuffixColor,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ExtraLargeSizeButton: StoryFn<ButtonProps> =
|
||||
Template.bind(undefined);
|
||||
ExtraLargeSizeButton.args = {
|
||||
size: 'extraLarge',
|
||||
children: 'This is a extra large button',
|
||||
export const FixedWidth = () => {
|
||||
const widths = [60, 100, 120, 160, 180];
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
|
||||
{widths.map(width => (
|
||||
<Button prefix={<AfFiNeIcon />} key={width} style={{ width }}>
|
||||
This is a width fixed button
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Disabled = () => {
|
||||
return <Groups disabled />;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user