From 0444dd9264fb26a96f39ae58dba2c385088829fc Mon Sep 17 00:00:00 2001 From: Whitewater Date: Wed, 17 May 2023 01:32:37 -0700 Subject: [PATCH] feat: add dropdown button (#2407) --- .../component/src/stories/button.stories.tsx | 47 ++++++++++++++++++- packages/component/src/ui/button/dropdown.tsx | 35 ++++++++++++++ .../component/src/ui/button/styles.css.ts | 40 ++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 packages/component/src/ui/button/dropdown.tsx create mode 100644 packages/component/src/ui/button/styles.css.ts diff --git a/packages/component/src/stories/button.stories.tsx b/packages/component/src/stories/button.stories.tsx index 47fd0c205a..ed4b0ebe25 100644 --- a/packages/component/src/stories/button.stories.tsx +++ b/packages/component/src/stories/button.stories.tsx @@ -2,8 +2,11 @@ import type { Meta, StoryFn } from '@storybook/react'; import { useState } from 'react'; -import { Button } from '..'; +import { Button } from '../ui/button/button'; +import { DropdownButton } from '../ui/button/dropdown'; import type { ButtonProps } from '../ui/button/interface'; +import { Menu } from '../ui/menu/menu'; +import { toast } from '../ui/toast/toast'; export default { title: 'AFFiNE/Button', @@ -20,30 +23,72 @@ export const Primary = Template.bind(undefined); Primary.args = { type: 'primary', children: 'This is a primary button', + onClick: () => toast('Click button'), }; export const Default = Template.bind(undefined); Default.args = { type: 'default', children: 'This is a default button', + onClick: () => toast('Click button'), }; export const Light = Template.bind(undefined); Light.args = { type: 'light', children: 'This is a light button', + onClick: () => toast('Click button'), }; export const Warning = Template.bind(undefined); Warning.args = { type: 'warning', children: 'This is a warning button', + onClick: () => toast('Click button'), }; export const Danger = Template.bind(undefined); Danger.args = { type: 'danger', children: 'This is a danger button', + onClick: () => toast('Click button'), +}; + +export const Dropdown: StoryFn = ({ onClickDropDown, ...props }) => { + const [open, setOpen] = useState(false); + return ( + <> + + Dropdown Button + + + { + setOpen(false); + }} + content={<>Dropdown Menu} + > + { + toast('Click button'); + setOpen(false); + }} + onClickDropDown={() => setOpen(!open)} + > + Dropdown with Menu + + + + ); +}; +Dropdown.args = { + onClick: () => toast('Click button'), + onClickDropDown: () => toast('Click dropdown'), }; export const Test: StoryFn = () => { diff --git a/packages/component/src/ui/button/dropdown.tsx b/packages/component/src/ui/button/dropdown.tsx new file mode 100644 index 0000000000..005b7194bf --- /dev/null +++ b/packages/component/src/ui/button/dropdown.tsx @@ -0,0 +1,35 @@ +import { ArrowDownSmallIcon } from '@blocksuite/icons'; +import { + type ButtonHTMLAttributes, + forwardRef, + type MouseEventHandler, +} from 'react'; + +import * as styles from './styles.css'; + +type DropdownButtonProps = { + onClickDropDown?: MouseEventHandler; +} & ButtonHTMLAttributes; + +export const DropdownButton = forwardRef< + HTMLButtonElement, + DropdownButtonProps +>(({ onClickDropDown, children, ...props }, ref) => { + const handleClickDropDown: MouseEventHandler = e => { + e.stopPropagation(); + onClickDropDown?.(e); + }; + return ( + + ); +}); +DropdownButton.displayName = 'SimpleDropdownButton'; diff --git a/packages/component/src/ui/button/styles.css.ts b/packages/component/src/ui/button/styles.css.ts new file mode 100644 index 0000000000..d4da59a1ab --- /dev/null +++ b/packages/component/src/ui/button/styles.css.ts @@ -0,0 +1,40 @@ +import { style } from '@vanilla-extract/css'; + +export const dropdownBtn = style({ + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + padding: '0 10px', + gap: '4px', + color: 'var(--affine-text-primary-color)', + fontWeight: 600, + background: 'var(--affine-button-gray-color)', + boxShadow: 'var(--affine-float-button-shadow)', + borderRadius: '8px', + fontSize: 'var(--affine-font-sm)', + // width: '100%', + height: '32px', + userSelect: 'none', + whiteSpace: 'nowrap', + cursor: 'pointer', + selectors: { + '&:hover': { + background: 'var(--affine-hover-color)', + }, + }, +}); + +export const divider = style({ + width: '0.5px', + height: '16px', + background: 'var(--affine-border-color)', +}); + +export const icon = style({ + borderRadius: '4px', + selectors: { + '&:hover': { + background: 'var(--affine-hover-color)', + }, + }, +});