From 439ef1ba90a06d69723c162f005bf41ea5ec0887 Mon Sep 17 00:00:00 2001 From: Qi <474021214@qq.com> Date: Fri, 21 Jul 2023 19:07:28 +0800 Subject: [PATCH] feat: refactor button with new design (#3343) --- .../affine/create-workspace-modal/index.tsx | 4 +- .../components/affine/language-menu/index.tsx | 2 +- .../delete-leave-workspace/delete/index.tsx | 2 +- .../delete-leave-workspace/leave/index.tsx | 2 +- .../new-workspace-setting-detail/export.tsx | 1 - .../new-workspace-setting-detail/profile.tsx | 3 +- .../new-workspace-setting-detail/publish.tsx | 4 +- .../new-workspace-setting-detail/storage.tsx | 4 +- .../general-setting/appearance/index.tsx | 8 +- .../header-right-items/editor-option-menu.tsx | 4 +- .../header-right-items/language-menu.tsx | 2 +- .../header-right-items/trash-button-group.tsx | 6 +- .../core/src/components/pure/footer/index.tsx | 3 +- .../components/pure/shortcuts-modal/index.tsx | 2 - apps/storybook/src/stories/button.stories.tsx | 9 +- .../src/stories/icon-button.stories.tsx | 25 ++ .../app-sidebar/sidebar-header/index.tsx | 2 - .../components/image-preview-modal/index.tsx | 29 +- .../page-list/components/favorite-tag.tsx | 7 +- .../components/page-list/operation-cell.tsx | 4 +- .../operation-menu-items/move-to-trash.tsx | 2 +- .../page-list/view/collection-list.tsx | 4 - .../page-list/view/create-collection.tsx | 9 +- .../share-menu/disable-public-link/index.tsx | 10 +- .../share-menu/disable-public-link/style.ts | 23 +- .../src/components/share-menu/share-menu.tsx | 9 +- .../src/components/share-menu/share-page.tsx | 22 +- .../components/share-menu/share-workspace.tsx | 10 +- .../src/components/share-menu/styles.ts | 42 +-- packages/component/src/ui/button/button.tsx | 166 ++++++--- .../component/src/ui/button/icon-button.tsx | 119 +++--- packages/component/src/ui/button/index.ts | 1 - packages/component/src/ui/button/style.css.ts | 349 ++++++++++++++++++ packages/component/src/ui/button/styles.ts | 116 ------ .../component/src/ui/button/text-button.tsx | 53 --- packages/component/src/ui/confirm/confirm.tsx | 6 +- packages/component/src/ui/loading/index.ts | 1 + packages/component/src/ui/loading/loading.tsx | 31 ++ .../component/src/ui/loading/styles.css.ts | 17 + .../component/src/ui/menu/menu-trigger.tsx | 9 +- plugins/copilot/src/UI/debug-content.tsx | 2 +- .../core/components/conversation/index.tsx | 14 +- 42 files changed, 665 insertions(+), 473 deletions(-) create mode 100644 apps/storybook/src/stories/icon-button.stories.tsx create mode 100644 packages/component/src/ui/button/style.css.ts delete mode 100644 packages/component/src/ui/button/text-button.tsx create mode 100644 packages/component/src/ui/loading/index.ts create mode 100644 packages/component/src/ui/loading/loading.tsx create mode 100644 packages/component/src/ui/loading/styles.css.ts diff --git a/apps/core/src/components/affine/create-workspace-modal/index.tsx b/apps/core/src/components/affine/create-workspace-modal/index.tsx index b4a6974e73..34712ec244 100644 --- a/apps/core/src/components/affine/create-workspace-modal/index.tsx +++ b/apps/core/src/components/affine/create-workspace-modal/index.tsx @@ -79,7 +79,7 @@ const NameWorkspaceContent = ({
- diff --git a/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx b/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx index ff2e278018..0a819e71cc 100644 --- a/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx +++ b/apps/core/src/components/affine/new-workspace-setting-detail/storage.tsx @@ -79,14 +79,13 @@ export const StoragePanel: FC<{
diff --git a/packages/component/src/components/page-list/components/favorite-tag.tsx b/packages/component/src/components/page-list/components/favorite-tag.tsx index b9beabb716..25c76098ef 100644 --- a/packages/component/src/components/page-list/components/favorite-tag.tsx +++ b/packages/component/src/components/page-list/components/favorite-tag.tsx @@ -19,12 +19,7 @@ export const FavoriteTag = forwardRef< > { e.stopPropagation(); onClick?.(e); diff --git a/packages/component/src/components/page-list/operation-cell.tsx b/packages/component/src/components/page-list/operation-cell.tsx index 3b9dd9d1f9..1066439795 100644 --- a/packages/component/src/components/page-list/operation-cell.tsx +++ b/packages/component/src/components/page-list/operation-cell.tsx @@ -147,8 +147,6 @@ export const TrashOperationCell: React.FC = ({ onClick={() => { setOpen(true); }} - hoverBackground="var(--affine-background-error-color)" - hoverColor="var(--affine-error-color)" > @@ -157,7 +155,7 @@ export const TrashOperationCell: React.FC = ({ title={t['Delete permanently?']()} content={t['TrashButtonGroupDescription']()} confirmText={t['Delete']()} - confirmType="danger" + confirmType="error" open={open} onConfirm={() => { onPermanentlyDeletePage(); diff --git a/packages/component/src/components/page-list/operation-menu-items/move-to-trash.tsx b/packages/component/src/components/page-list/operation-menu-items/move-to-trash.tsx index 57f18f120b..8900bba831 100644 --- a/packages/component/src/components/page-list/operation-menu-items/move-to-trash.tsx +++ b/packages/component/src/components/page-list/operation-menu-items/move-to-trash.tsx @@ -44,7 +44,7 @@ const ConfirmModal = ({ title: title || 'Untitled', })} confirmText={t.Delete()} - confirmType="danger" + confirmType="error" {...confirmModalProps} /> ); diff --git a/packages/component/src/components/page-list/view/collection-list.tsx b/packages/component/src/components/page-list/view/collection-list.tsx index 2802d1b321..8b465dd00e 100644 --- a/packages/component/src/components/page-list/view/collection-list.tsx +++ b/packages/component/src/components/page-list/view/collection-list.tsx @@ -207,9 +207,7 @@ export const CollectionList = ({ } > + diff --git a/packages/component/src/components/share-menu/disable-public-link/style.ts b/packages/component/src/components/share-menu/disable-public-link/style.ts index 56ff275fa4..c34fccd34c 100644 --- a/packages/component/src/components/share-menu/disable-public-link/style.ts +++ b/packages/component/src/components/share-menu/disable-public-link/style.ts @@ -1,4 +1,4 @@ -import { styled, TextButton } from '../../..'; +import { styled } from '../../..'; export const StyledModalWrapper = styled('div')(() => { return { @@ -40,24 +40,3 @@ export const StyledButtonContent = styled('div')(() => { justifyContent: 'center', }; }); -export const StyledButton = styled(TextButton)(() => { - return { - color: 'var(--affine-primary-color)', - height: '32px', - background: '#F3F0FF', - border: 'none', - borderRadius: '8px', - padding: '4px 20px', - }; -}); -export const StyledDangerButton = styled(TextButton)(() => { - return { - color: '#FF631F', - height: '32px', - background: - 'linear-gradient(0deg, rgba(255, 99, 31, 0.1), rgba(255, 99, 31, 0.1)), #FFFFFF;', - border: 'none', - borderRadius: '8px', - padding: '4px 20px', - }; -}); diff --git a/packages/component/src/components/share-menu/share-menu.tsx b/packages/component/src/components/share-menu/share-menu.tsx index 09ae9f2260..fd9b281321 100644 --- a/packages/component/src/components/share-menu/share-menu.tsx +++ b/packages/component/src/components/share-menu/share-menu.tsx @@ -9,12 +9,13 @@ import type { FC } from 'react'; import { useRef } from 'react'; import { useCallback, useState } from 'react'; +import { Button } from '../../ui/button'; import { Menu } from '../../ui/menu/menu'; import { Export } from './export'; import { containerStyle, indicatorContainerStyle, tabStyle } from './index.css'; import { SharePage } from './share-page'; import { ShareWorkspace } from './share-workspace'; -import { StyledIndicator, StyledShareButton, TabItem } from './styles'; +import { StyledIndicator, TabItem } from './styles'; type SharePanel = 'SharePage' | 'Export' | 'ShareWorkspace'; const MenuItems: Record> = { SharePage: SharePage, @@ -134,15 +135,15 @@ export const ShareMenu: FC = props => { setOpen(false); }} > - { setOpen(!open); }} - isShared={isPublic} + type={isPublic ? 'primary' : undefined} >
{isPublic ? 'Shared' : 'Share'}
-
+ ); }; diff --git a/packages/component/src/components/share-menu/share-page.tsx b/packages/component/src/components/share-menu/share-page.tsx index 419fd23b00..b182b2b72f 100644 --- a/packages/component/src/components/share-menu/share-page.tsx +++ b/packages/component/src/components/share-menu/share-page.tsx @@ -7,7 +7,7 @@ import type { FC } from 'react'; import { useState } from 'react'; import { useCallback, useMemo } from 'react'; -import { toast } from '../..'; +import { Button, toast } from '../..'; import { PublicLinkDisableModal } from './disable-public-link'; import { descriptionStyle, @@ -15,26 +15,22 @@ import { menuItemStyle, } from './index.css'; import type { ShareMenuProps } from './share-menu'; -import { - StyledButton, - StyledDisableButton, - StyledInput, - StyledLinkSpan, -} from './styles'; +import { StyledDisableButton, StyledInput, StyledLinkSpan } from './styles'; export const LocalSharePage: FC = props => { const t = useAFFiNEI18N(); return (
{t['Shared Pages Description']()}
- { props.onEnableAffineCloud(props.workspace as LocalWorkspace); }} > {t['Enable AFFiNE Cloud']()} - +
); }; @@ -74,20 +70,20 @@ export const AffineSharePage: FC = props => { value={isPublic ? sharingUrl : 'https://app.affine.pro/xxxx'} /> {!isPublic && ( - {t['Create']()} - + )} {isPublic && ( - {t['Copy Link']()} - + )}
diff --git a/packages/component/src/components/share-menu/share-workspace.tsx b/packages/component/src/components/share-menu/share-workspace.tsx index ebd76615ca..6a01f85632 100644 --- a/packages/component/src/components/share-menu/share-workspace.tsx +++ b/packages/component/src/components/share-menu/share-workspace.tsx @@ -6,9 +6,9 @@ import { WorkspaceFlavour } from '@affine/env/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import type { FC } from 'react'; +import { Button } from '../../ui/button'; import { descriptionStyle, menuItemStyle } from './index.css'; import type { ShareMenuProps } from './share-menu'; -import { StyledButton } from './styles'; const ShareLocalWorkspace: FC> = props => { const t = useAFFiNEI18N(); @@ -17,14 +17,14 @@ const ShareLocalWorkspace: FC> = props => {
{t['Share Menu Public Workspace Description1']()}
- { props.onOpenWorkspaceSettings(props.workspace); }} > {t['Open Workspace Settings']()} - +
); }; @@ -42,14 +42,14 @@ const ShareAffineWorkspace: FC< ? t['Share Menu Public Workspace Description2']() : t['Share Menu Public Workspace Description1']()} - { props.onOpenWorkspaceSettings(props.workspace); }} > {t['Open Workspace Settings']()} - + ); }; diff --git a/packages/component/src/components/share-menu/styles.ts b/packages/component/src/components/share-menu/styles.ts index 6856c21f43..b8ca29b47d 100644 --- a/packages/component/src/components/share-menu/styles.ts +++ b/packages/component/src/components/share-menu/styles.ts @@ -1,34 +1,4 @@ -import { Button, displayFlex, styled, TextButton } from '../..'; - -export const StyledShareButton = styled(TextButton, { - shouldForwardProp: (prop: string) => prop !== 'isShared', -})<{ isShared?: boolean }>(({ isShared }) => { - return { - padding: '4px 8px', - marginLeft: '4px', - marginRight: '16px', - border: `1px solid ${ - isShared ? 'var(--affine-primary-color)' : 'var(--affine-icon-color)' - }`, - color: isShared - ? 'var(--affine-primary-color)' - : 'var(--affine-icon-color)', - borderRadius: '8px', - ':hover': { - border: `1px solid ${'var(--affine-primary-color)'}`, - }, - span: { - ...displayFlex('center', 'center'), - }, - }; -}); - -export const StyledTabsWrapper = styled('div')(() => { - return { - ...displayFlex('space-around', 'center'), - position: 'relative', - }; -}); +import { Button, displayFlex, styled } from '../..'; export const TabItem = styled('li')<{ isActive?: boolean }>(({ isActive }) => { { @@ -99,16 +69,6 @@ export const StyledInput = styled('input')(() => { marginRight: '10px', }; }); -export const StyledButton = styled(TextButton)(() => { - return { - color: 'var(--affine-primary-color)', - height: '32px', - background: '#F3F0FF', - border: 'none', - borderRadius: '8px', - padding: '4px 20px', - }; -}); export const StyledDisableButton = styled(Button)(() => { return { color: '#FF631F', diff --git a/packages/component/src/ui/button/button.tsx b/packages/component/src/ui/button/button.tsx index 51ccfdf264..00a92be97b 100644 --- a/packages/component/src/ui/button/button.tsx +++ b/packages/component/src/ui/button/button.tsx @@ -1,71 +1,125 @@ -import { Children, cloneElement, forwardRef } from 'react'; +import clsx from 'clsx'; +import { + type FC, + forwardRef, + type HTMLAttributes, + type PropsWithChildren, + type ReactElement, + useMemo, +} from 'react'; -import type { ButtonProps } from './interface'; -import { Loading } from './loading'; -import { StyledButton } from './styles'; -import { getSize } from './utils'; - -export type { ButtonProps }; +import { Loading } from '../loading'; +import { button, buttonIcon } from './style.css'; +export type ButtonType = + | 'default' + | 'primary' + | 'plain' + | 'error' + | 'warning' + | 'success' + | 'processing'; +export type ButtonSize = 'default' | 'large' | 'extraLarge'; +export type ButtonProps = PropsWithChildren & + Omit, 'type'> & { + type?: ButtonType; + disabled?: boolean; + icon?: ReactElement; + iconPosition?: 'start' | 'end'; + shape?: 'default' | 'round' | 'circle'; + block?: boolean; + size?: ButtonSize; + loading?: boolean; + }; +const defaultProps = { + type: 'default', + disabled: false, + shape: 'default', + size: 'default', + iconPosition: 'start', + loading: false, +}; +const ButtonIcon: FC = props => { + const { + size, + icon, + iconPosition = 'start', + children, + type, + } = { + ...defaultProps, + ...props, + }; + const onlyIcon = icon && !children; + return ( +
+ {icon} +
+ ); +}; export const Button = forwardRef( - ( - { - size = 'default', - disabled = false, - hoverBackground, - hoverColor, - hoverStyle, - shape = 'default', - icon, - iconPosition = 'start', - type = 'default', + (props, ref) => { + const { children, - bold = false, - loading = false, - noBorder = false, - ...props - }, - ref - ) => { - const { iconSize } = getSize(size); + type, + disabled, + shape, + size, + icon: propsIcon, + iconPosition, + block, + loading, + ...otherProps + } = { + ...defaultProps, + ...props, + }; - const iconElement = - icon && - cloneElement(Children.only(icon), { - width: iconSize, - height: iconSize, - className: `affine-button-icon ${icon.props.className ?? ''}`, - }); + const icon = useMemo(() => { + if (loading) { + return ; + } + return propsIcon; + }, [propsIcon, loading]); return ( - - {loading ? ( - - ) : ( - <> - {iconPosition === 'start' && iconElement} - {children && {children}} - {iconPosition === 'end' && iconElement} - - )} - + {icon && iconPosition === 'start' ? ( + + ) : null} + {children} + {icon && iconPosition === 'end' ? : null} + ); } ); Button.displayName = 'Button'; - export default Button; diff --git a/packages/component/src/ui/button/icon-button.tsx b/packages/component/src/ui/button/icon-button.tsx index d2b84f3902..55e019cd99 100644 --- a/packages/component/src/ui/button/icon-button.tsx +++ b/packages/component/src/ui/button/icon-button.tsx @@ -1,73 +1,76 @@ -import type { CSSProperties, HTMLAttributes, ReactElement } from 'react'; +import clsx from 'clsx'; +import type { HTMLAttributes, PropsWithChildren } from 'react'; import { forwardRef } from 'react'; -import { StyledIconButton } from './styles'; -const SIZE_SMALL = 'small' as const; -const SIZE_MIDDLE = 'middle' as const; -const SIZE_NORMAL = 'normal' as const; -// TODO: IconButton should merge into Button, but it has not been designed yet -const SIZE_CONFIG = { - [SIZE_SMALL]: { - iconSize: 16, - areaSize: 20, - }, - [SIZE_MIDDLE]: { - iconSize: 20, - areaSize: 24, - }, - [SIZE_NORMAL]: { - iconSize: 24, - areaSize: 32, - }, -} as const; +import { Loading } from '../loading'; +import type { ButtonType } from './button'; +import { iconButton } from './style.css'; -export type IconButtonProps = { - size?: - | typeof SIZE_SMALL - | typeof SIZE_MIDDLE - | typeof SIZE_NORMAL - | [number, number]; - iconSize?: - | typeof SIZE_SMALL - | typeof SIZE_MIDDLE - | typeof SIZE_NORMAL - | [number, number]; - disabled?: boolean; - hoverBackground?: CSSProperties['background']; - hoverColor?: string; - hoverStyle?: CSSProperties; - children: ReactElement, 'svg'>; - darker?: boolean; -} & HTMLAttributes; +export type IconButtonSize = 'default' | 'large' | 'small' | 'extraSmall'; +export type IconButtonProps = PropsWithChildren & + Omit, 'type'> & { + type?: ButtonType; + disabled?: boolean; + size?: IconButtonSize; + loading?: boolean; + withoutPadding?: boolean; + active?: boolean; + }; +const defaultProps = { + type: 'plain', + disabled: false, + size: 'default', + loading: false, + withoutPadding: false, + active: false, +}; export const IconButton = forwardRef( - ( - { size = 'normal', iconSize, disabled = false, children, ...props }, - ref - ) => { - iconSize = size; - const [width, height] = Array.isArray(size) - ? size - : [SIZE_CONFIG[size]['areaSize'], SIZE_CONFIG[size]['areaSize']]; - const [iconWidth] = Array.isArray(iconSize) - ? iconSize - : [SIZE_CONFIG[iconSize]['iconSize'], SIZE_CONFIG[iconSize]['iconSize']]; + (props, ref) => { + const { + type, + size, + withoutPadding, + children, + disabled, + loading, + active, + ...otherProps + } = { + ...defaultProps, + ...props, + }; return ( - - {children} - + {loading ? : children} + ); } ); -IconButton.displayName = 'IconButton'; +IconButton.displayName = 'IconButton'; export default IconButton; diff --git a/packages/component/src/ui/button/index.ts b/packages/component/src/ui/button/index.ts index 1086dcb470..21499a0da9 100644 --- a/packages/component/src/ui/button/index.ts +++ b/packages/component/src/ui/button/index.ts @@ -2,4 +2,3 @@ export * from './button'; export * from './dropdown'; export * from './icon-button'; export * from './radio'; -export * from './text-button'; diff --git a/packages/component/src/ui/button/style.css.ts b/packages/component/src/ui/button/style.css.ts new file mode 100644 index 0000000000..e2f405e510 --- /dev/null +++ b/packages/component/src/ui/button/style.css.ts @@ -0,0 +1,349 @@ +import { globalStyle, style } from '@vanilla-extract/css'; + +export const button = style({ + display: 'inline-flex', + justifyContent: 'center', + alignItems: 'center', + userSelect: 'none', + touchAction: 'manipulation', + outline: '0', + border: '1px solid', + padding: '0 18px', + borderRadius: '8px', + fontSize: 'var(--affine-font-base)', + transition: 'all .3s', + ['WebkitAppRegion' as string]: 'no-drag', + fontWeight: 600, + + // changeable + height: '28px', + background: 'var(--affine-white)', + borderColor: 'var(--affine-border-color)', + color: 'var(--affine-text-primary-color)', + + selectors: { + '&.text-bold': { + fontWeight: 600, + }, + '&:hover': { + background: 'var(--affine-hover-color)', + }, + '&.disabled, &.loading': { + opacity: '.4', + cursor: 'default', + color: 'var(--affine-disable-color)', + pointerEvents: 'none', + }, + '&.disabled:hover, &.loading:hover': { + background: 'inherit', + }, + + '&.block': { display: 'flex', width: '100%' }, + + '&.circle': { + borderRadius: '50%', + }, + '&.round': { + borderRadius: '14px', + }, + // size + '&.large': { + height: '32px', + }, + '&.round.large': { + borderRadius: '16px', + }, + '&.extraLarge': { + height: '40px', + }, + '&.round.extraLarge': { + borderRadius: '20px', + }, + + // type + '&.plain': { + color: 'var(--affine-text-primary-color)', + borderColor: 'transparent', + }, + + '&.primary': { + color: 'var(--affine-white)', + background: 'var(--affine-primary-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.primary:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-primary-color)', + }, + '&.primary.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.primary.disabled:hover': { + background: 'var(--affine-primary-color)', + }, + + '&.error': { + color: 'var(--affine-white)', + background: 'var(--affine-error-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.error:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-error-color)', + }, + '&.error.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.error.disabled:hover': { + background: 'var(--affine-error-color)', + }, + + '&.warning': { + color: 'var(--affine-white)', + background: 'var(--affine-warning-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.warning:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-warning-color)', + }, + '&.warning.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.warning.disabled:hover': { + background: 'var(--affine-warning-color)', + }, + + '&.success': { + color: 'var(--affine-white)', + background: 'var(--affine-success-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.success:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-success-color)', + }, + '&.success.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.success.disabled:hover': { + background: 'var(--affine-success-color)', + }, + + '&.processing': { + color: 'var(--affine-white)', + background: 'var(--affine-processing-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.processing:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-processing-color)', + }, + '&.processing.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.processing.disabled:hover': { + background: 'var(--affine-processing-color)', + }, + }, +}); + +globalStyle(`${button} > span`, { + // flex: 1, + lineHeight: 1, + padding: '0 4px', +}); + +export const buttonIcon = style({ + flexShrink: 0, + display: 'inline-flex', + justifyContent: 'center', + alignItems: 'center', + color: 'var(--affine-icon-color)', + fontSize: '16px', + width: '16px', + height: '16px', + selectors: { + '&.start': { + marginRight: '4px', + }, + '&.end': { + marginLeft: '4px', + }, + '&.large': { + fontSize: '20px', + width: '20px', + height: '20px', + }, + '&.extraLarge': { + fontSize: '20px', + width: '20px', + height: '20px', + }, + '&.color-white': { + color: 'var(--affine-white)', + }, + }, +}); + +export const iconButton = style({ + display: 'inline-flex', + justifyContent: 'center', + alignItems: 'center', + userSelect: 'none', + touchAction: 'manipulation', + outline: '0', + border: '1px solid', + borderRadius: '4px', + transition: 'all .3s', + ['WebkitAppRegion' as string]: 'no-drag', + + // changeable + width: '24px', + height: '24px', + fontSize: '20px', + color: 'var(--affine-text-primary-color)', + borderColor: 'var(--affine-border-color)', + selectors: { + '&.without-padding': { + margin: '-2px', + }, + '&.active': { + color: 'var(--affine-primary-color)', + }, + + '&:hover': { + background: 'var(--affine-hover-color)', + }, + '&.disabled, &.loading': { + opacity: '.4', + cursor: 'default', + color: 'var(--affine-disable-color)', + pointerEvents: 'none', + }, + '&.disabled:hover, &.loading:hover': { + background: 'inherit', + }, + + // size + '&.large': { + width: '32px', + height: '32px', + fontSize: '24px', + }, + '&.large.without-padding': { + margin: '-4px', + }, + '&.small': { width: '20px', height: '20px', fontSize: '16px' }, + '&.extra-small': { width: '16px', height: '16px', fontSize: '12px' }, + + // type + '&.plain': { + color: 'var(--affine-icon-color)', + borderColor: 'transparent', + }, + '&.plain.active': { + color: 'var(--affine-primary-color)', + }, + + '&.primary': { + color: 'var(--affine-white)', + background: 'var(--affine-primary-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.primary:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-primary-color)', + }, + '&.primary.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.primary.disabled:hover': { + background: 'var(--affine-primary-color)', + }, + + '&.error': { + color: 'var(--affine-white)', + background: 'var(--affine-error-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.error:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-error-color)', + }, + '&.error.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.error.disabled:hover': { + background: 'var(--affine-error-color)', + }, + + '&.warning': { + color: 'var(--affine-white)', + background: 'var(--affine-warning-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.warning:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-warning-color)', + }, + '&.warning.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.warning.disabled:hover': { + background: 'var(--affine-warning-color)', + }, + + '&.success': { + color: 'var(--affine-white)', + background: 'var(--affine-success-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.success:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-success-color)', + }, + '&.success.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.success.disabled:hover': { + background: 'var(--affine-success-color)', + }, + + '&.processing': { + color: 'var(--affine-white)', + background: 'var(--affine-processing-color)', + borderColor: 'var(--affine-black-10)', + boxShadow: '0px 1px 2px 0px rgba(255, 255, 255, 0.25) inset', + }, + '&.processing:hover': { + background: + 'linear-gradient(0deg, rgba(0, 0, 0, 0.04) 0%, rgba(0, 0, 0, 0.04) 100%), var(--affine-processing-color)', + }, + '&.processing.disabled': { + opacity: '.4', + cursor: 'default', + }, + '&.processing.disabled:hover': { + background: 'var(--affine-processing-color)', + }, + }, +}); diff --git a/packages/component/src/ui/button/styles.ts b/packages/component/src/ui/button/styles.ts index 0472f8fdb1..5f4e305958 100644 --- a/packages/component/src/ui/button/styles.ts +++ b/packages/component/src/ui/button/styles.ts @@ -1,123 +1,7 @@ -import type { CSSProperties } from 'react'; - import { displayInlineFlex, styled } from '../../styles'; import type { ButtonProps } from './interface'; import { getButtonColors, getSize } from './utils'; -export const StyledIconButton = styled('button', { - shouldForwardProp: prop => { - return ![ - 'borderRadius', - 'top', - 'right', - 'width', - 'height', - 'hoverBackground', - 'hoverColor', - 'hoverStyle', - 'fontSize', - ].includes(prop as string); - }, -})<{ - width: number; - height: number; - borderRadius: number; - disabled?: boolean; - hoverBackground?: CSSProperties['background']; - hoverColor?: string; - hoverStyle?: CSSProperties; - // In some cases, button is in a normal hover status, it should be darkened - fontSize?: CSSProperties['fontSize']; -}>(({ - width, - height, - borderRadius, - disabled, - hoverBackground, - hoverColor, - hoverStyle, - fontSize, -}) => { - return { - width, - height, - fontSize, - WebkitAppRegion: 'no-drag', - color: 'var(--affine-icon-color)', - ...displayInlineFlex('center', 'center'), - ...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}), - transition: 'background .15s', - borderRadius, - - ':hover': { - color: hoverColor ?? 'var(--affine-icon-color)', - background: hoverBackground || 'var(--affine-hover-color)', - ...(hoverStyle ?? {}), - }, - }; -}); - -export const StyledTextButton = styled('button', { - shouldForwardProp: prop => { - return ![ - 'borderRadius', - 'top', - 'right', - 'width', - 'height', - 'hoverBackground', - 'hoverColor', - 'hoverStyle', - 'bold', - ].includes(prop as string); - }, -})< - Pick< - ButtonProps, - | 'size' - | 'disabled' - | 'hoverBackground' - | 'hoverColor' - | 'hoverStyle' - | 'shape' - | 'type' - | 'bold' - > ->(({ - size = 'default', - disabled, - hoverBackground, - hoverColor, - hoverStyle, - bold = false, - shape = 'default', - // TODO: Implement type - // eslint-disable-next-line @typescript-eslint/no-unused-vars - // type = 'default', -}) => { - const { fontSize, borderRadius, padding, height } = getSize(size); - - return { - height, - paddingLeft: padding, - paddingRight: padding, - ...displayInlineFlex('flex-start', 'center'), - position: 'relative', - ...(disabled ? { cursor: 'not-allowed', pointerEvents: 'none' } : {}), - transition: 'background .15s', - // TODO: Implement circle shape - borderRadius: shape === 'default' ? borderRadius : height / 2, - fontSize, - fontWeight: bold ? '500' : '400', - - ':hover': { - color: hoverColor ?? 'var(--affine-primary-color)', - background: hoverBackground ?? 'var(--affine-hover-color)', - ...(hoverStyle ?? {}), - }, - }; -}); - export const StyledButton = styled('button', { shouldForwardProp: prop => { return ![ diff --git a/packages/component/src/ui/button/text-button.tsx b/packages/component/src/ui/button/text-button.tsx deleted file mode 100644 index 87817150b2..0000000000 --- a/packages/component/src/ui/button/text-button.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Children, cloneElement, forwardRef } from 'react'; - -import type { ButtonProps } from './interface'; -import { StyledTextButton } from './styles'; -import { getSize } from './utils'; -export const TextButton = forwardRef( - ( - { - size = 'default', - disabled = false, - hoverBackground, - hoverColor, - hoverStyle, - shape = 'default', - icon, - type = 'default', - children, - bold = false, - ...props - }, - ref - ) => { - const { iconSize } = getSize(size); - - return ( - - {icon && - cloneElement(Children.only(icon), { - width: iconSize, - height: iconSize, - className: `affine-button-icon ${icon.props.className ?? ''}`, - })} - {children && {children}} - - ); - } -); -TextButton.displayName = 'TextButton'; - -export default TextButton; diff --git a/packages/component/src/ui/confirm/confirm.tsx b/packages/component/src/ui/confirm/confirm.tsx index cf97b08e55..b9189f1760 100644 --- a/packages/component/src/ui/confirm/confirm.tsx +++ b/packages/component/src/ui/confirm/confirm.tsx @@ -17,7 +17,7 @@ export type ConfirmProps = { confirmText?: string; cancelText?: string; // TODO: Confirm button's color should depend on confirm type - confirmType?: 'primary' | 'warning' | 'danger'; + confirmType?: 'primary' | 'warning' | 'error'; buttonDirection?: 'row' | 'column'; onConfirm?: () => void; onCancel?: () => void; @@ -53,7 +53,6 @@ export const Confirm = ({ ); } ); diff --git a/plugins/copilot/src/UI/debug-content.tsx b/plugins/copilot/src/UI/debug-content.tsx index da50803323..8bedb984de 100644 --- a/plugins/copilot/src/UI/debug-content.tsx +++ b/plugins/copilot/src/UI/debug-content.tsx @@ -37,7 +37,7 @@ export const DebugContent: PluginUIAdapter['debugContent'] = () => { )} /> -