mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 16:16:46 +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,6 +1,7 @@
|
||||
import { Button, IconButton } from '@affine/component/ui/button';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { CloseIcon } from '@blocksuite/icons/rc';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import * as styles from './index.css';
|
||||
@@ -37,11 +38,12 @@ export const LocalDemoTips = ({
|
||||
</div>
|
||||
|
||||
<div className={styles.tipsRightItem}>
|
||||
<div>
|
||||
<Button onClick={handleClick}>{buttonLabel}</Button>
|
||||
</div>
|
||||
<Button style={{ background: cssVar('white') }} onClick={handleClick}>
|
||||
{buttonLabel}
|
||||
</Button>
|
||||
<IconButton
|
||||
onClick={onClose}
|
||||
size="20"
|
||||
data-testid="local-demo-tips-close-button"
|
||||
>
|
||||
<CloseIcon />
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ export const MobileNavbar = () => {
|
||||
onOpenChange: setOpenMenu,
|
||||
}}
|
||||
>
|
||||
<IconButton type="plain" className={styles.iconButton}>
|
||||
<IconButton variant="plain" size="24" className={styles.iconButton}>
|
||||
{openMenu ? <CloseIcon /> : <PropertyIcon />}
|
||||
</IconButton>
|
||||
</Menu>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc';
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import type { ButtonProps } from '../../ui/button';
|
||||
@@ -9,15 +10,15 @@ export const BackButton: FC<ButtonProps> = props => {
|
||||
const t = useI18n();
|
||||
return (
|
||||
<Button
|
||||
type="plain"
|
||||
variant="plain"
|
||||
style={{
|
||||
marginTop: 12,
|
||||
marginLeft: -5,
|
||||
paddingLeft: 0,
|
||||
paddingRight: 5,
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
color: cssVar('textSecondaryColor'),
|
||||
}}
|
||||
icon={<ArrowLeftSmallIcon />}
|
||||
prefix={<ArrowLeftSmallIcon />}
|
||||
{...props}
|
||||
>
|
||||
{t['com.affine.backButton']()}
|
||||
|
||||
@@ -58,7 +58,7 @@ export const ChangeEmailPage = ({
|
||||
disabled={hasSetUp}
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
variant="primary"
|
||||
size="large"
|
||||
onClick={onContinue}
|
||||
loading={loading}
|
||||
|
||||
@@ -59,7 +59,7 @@ export const ChangePasswordPage: FC<{
|
||||
}
|
||||
>
|
||||
{hasSetUp ? (
|
||||
<Button type="primary" size="large" onClick={onOpenAffine}>
|
||||
<Button variant="primary" size="large" onClick={onOpenAffine}>
|
||||
{t['com.affine.auth.open.affine']()}
|
||||
</Button>
|
||||
) : (
|
||||
|
||||
@@ -14,7 +14,7 @@ export const ConfirmChangeEmail: FC<{
|
||||
title={t['com.affine.auth.change.email.page.success.title']()}
|
||||
subtitle={t['com.affine.auth.change.email.page.success.subtitle']()}
|
||||
>
|
||||
<Button type="primary" size="large" onClick={onOpenAffine}>
|
||||
<Button variant="primary" size="large" onClick={onOpenAffine}>
|
||||
{t['com.affine.auth.open.affine']()}
|
||||
</Button>
|
||||
</AuthPageContainer>
|
||||
|
||||
@@ -14,7 +14,7 @@ export const ConfirmChangeEmail: FC<{
|
||||
title={t['com.affine.auth.change.email.page.success.title']()}
|
||||
subtitle={t['com.affine.auth.change.email.page.success.subtitle']()}
|
||||
>
|
||||
<Button type="primary" size="large" onClick={onOpenAffine}>
|
||||
<Button variant="primary" size="large" onClick={onOpenAffine}>
|
||||
{t['com.affine.auth.open.affine']()}
|
||||
</Button>
|
||||
</AuthPageContainer>
|
||||
|
||||
@@ -219,7 +219,7 @@ export const OnboardingPage = ({
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.button}
|
||||
type="primary"
|
||||
variant="primary"
|
||||
size="extraLarge"
|
||||
itemType="submit"
|
||||
onClick={() => {
|
||||
@@ -248,8 +248,7 @@ export const OnboardingPage = ({
|
||||
setQuestionIdx(questionIdx + 1);
|
||||
}
|
||||
}}
|
||||
iconPosition="end"
|
||||
icon={<ArrowRightSmallIcon />}
|
||||
suffix={<ArrowRightSmallIcon />}
|
||||
>
|
||||
{questionIdx === 0 ? 'start' : 'Next'}
|
||||
</Button>
|
||||
@@ -271,7 +270,7 @@ export const OnboardingPage = ({
|
||||
</p>
|
||||
<Button
|
||||
className={clsx(styles.button, styles.openAFFiNEButton)}
|
||||
type="primary"
|
||||
variant="primary"
|
||||
size="extraLarge"
|
||||
onClick={() => {
|
||||
if (callbackUrl) {
|
||||
@@ -280,8 +279,7 @@ export const OnboardingPage = ({
|
||||
onOpenAffine();
|
||||
}
|
||||
}}
|
||||
iconPosition="end"
|
||||
icon={<ArrowRightSmallIcon />}
|
||||
suffix={<ArrowRightSmallIcon />}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
|
||||
@@ -59,7 +59,7 @@ export const SetPasswordPage: FC<{
|
||||
}
|
||||
>
|
||||
{hasSetUp ? (
|
||||
<Button type="primary" size="large" onClick={onOpenAffine}>
|
||||
<Button variant="primary" size="large" onClick={onOpenAffine}>
|
||||
{t['com.affine.auth.open.affine']()}
|
||||
</Button>
|
||||
) : (
|
||||
|
||||
@@ -33,7 +33,7 @@ export const SetPassword: FC<{
|
||||
/>
|
||||
</Wrapper>
|
||||
<Button
|
||||
type="primary"
|
||||
variant="primary"
|
||||
size="large"
|
||||
disabled={!passwordPass}
|
||||
style={{ marginRight: 20 }}
|
||||
@@ -44,7 +44,7 @@ export const SetPassword: FC<{
|
||||
{t['com.affine.auth.set.password.save']()}
|
||||
</Button>
|
||||
{showLater ? (
|
||||
<Button type="plain" size="large" onClick={onLater}>
|
||||
<Button variant="plain" size="large" onClick={onLater}>
|
||||
{t['com.affine.auth.later']()}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
@@ -13,7 +13,7 @@ export const SignInSuccessPage: FC<{
|
||||
title={t['com.affine.auth.signed.success.title']()}
|
||||
subtitle={t['com.affine.auth.signed.success.subtitle']()}
|
||||
>
|
||||
<Button type="primary" size="large" onClick={onOpenAffine}>
|
||||
<Button variant="primary" size="large" onClick={onOpenAffine}>
|
||||
{t['com.affine.auth.open.affine']()}
|
||||
</Button>
|
||||
</AuthPageContainer>
|
||||
|
||||
@@ -63,7 +63,7 @@ export const SignUpPage: FC<{
|
||||
}
|
||||
>
|
||||
{hasSetUp ? (
|
||||
<Button type="primary" size="large" onClick={onOpenAffine}>
|
||||
<Button variant="primary" size="large" onClick={onOpenAffine}>
|
||||
{openButtonText ?? t['com.affine.auth.open.affine']()}
|
||||
</Button>
|
||||
) : (
|
||||
|
||||
@@ -3,7 +3,6 @@ import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { CollaborationIcon, SettingsIcon } from '@blocksuite/icons/rc';
|
||||
import type { WorkspaceMetadata } from '@toeverything/infra';
|
||||
import clsx from 'clsx';
|
||||
import { type MouseEvent, useCallback } from 'react';
|
||||
|
||||
import { Button } from '../../../ui/button';
|
||||
@@ -89,8 +88,7 @@ export const WorkspaceCard = ({
|
||||
<Button
|
||||
loading={!!openingId && openingId === meta.id}
|
||||
disabled={!!openingId}
|
||||
type="default"
|
||||
className={clsx(styles.enableCloudButton, styles.showOnCardHover)}
|
||||
className={styles.showOnCardHover}
|
||||
onClick={onEnableCloud}
|
||||
>
|
||||
{enableCloudText}
|
||||
|
||||
@@ -79,21 +79,16 @@ export const settingButton = style({
|
||||
boxShadow: cssVar('shadow1'),
|
||||
background: cssVar('white80'),
|
||||
},
|
||||
// [`.${card}:hover &:hover`]: {
|
||||
// background: cssVar('hoverColor'),
|
||||
// },
|
||||
},
|
||||
});
|
||||
|
||||
export const enableCloudButton = style({
|
||||
background: 'transparent',
|
||||
});
|
||||
|
||||
export const showOnCardHover = style({
|
||||
display: 'none',
|
||||
visibility: 'hidden',
|
||||
opacity: 0,
|
||||
selectors: {
|
||||
[`.${card}:hover &`]: {
|
||||
display: 'block',
|
||||
visibility: 'visible',
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ export const PublicLinkDisableModal = (props: ConfirmModalProps) => {
|
||||
cancelText={t['com.affine.publicLinkDisableModal.button.cancel']()}
|
||||
confirmText={t['com.affine.publicLinkDisableModal.button.disable']()}
|
||||
confirmButtonOptions={{
|
||||
type: 'error',
|
||||
variant: 'error',
|
||||
['data-testid' as string]: 'confirm-enable-affine-cloud-button',
|
||||
}}
|
||||
{...props}
|
||||
|
||||
@@ -16,6 +16,9 @@ import {
|
||||
importPageContainerStyle,
|
||||
} from './index.css';
|
||||
|
||||
/**
|
||||
* @deprecated Not used
|
||||
*/
|
||||
export const ImportPage = ({
|
||||
importMarkdown,
|
||||
importHtml,
|
||||
@@ -37,8 +40,9 @@ export const ImportPage = ({
|
||||
onClick={() => {
|
||||
onClose();
|
||||
}}
|
||||
icon={<CloseIcon />}
|
||||
/>
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
<div className={importPageBodyStyle}>
|
||||
<div className="title">Import</div>
|
||||
<span>
|
||||
|
||||
@@ -37,7 +37,7 @@ export const AcceptInvitePage = ({
|
||||
</FlexWrapper>
|
||||
}
|
||||
>
|
||||
<Button type="primary" size="large" onClick={onOpenWorkspace}>
|
||||
<Button variant="primary" size="large" onClick={onOpenWorkspace}>
|
||||
{t['Visit Workspace']()}
|
||||
</Button>
|
||||
</AuthPageContainer>
|
||||
|
||||
@@ -60,7 +60,7 @@ export const InviteModal = ({
|
||||
confirmText={t['Invite']()}
|
||||
confirmButtonOptions={{
|
||||
loading: isMutating,
|
||||
type: 'primary',
|
||||
variant: 'primary',
|
||||
['data-testid' as string]: 'confirm-enable-affine-cloud-button',
|
||||
}}
|
||||
onConfirm={handleConfirm}
|
||||
|
||||
@@ -44,7 +44,7 @@ export const MemberLimitModal = ({
|
||||
: 'com.affine.payment.member-limit.pro.confirm'
|
||||
]()}
|
||||
confirmButtonOptions={{
|
||||
type: 'primary',
|
||||
variant: 'primary',
|
||||
}}
|
||||
onConfirm={handleConfirm}
|
||||
></ConfirmModal>
|
||||
|
||||
@@ -3,7 +3,6 @@ import { SignOutIcon } from '@blocksuite/icons/rc';
|
||||
|
||||
import { Avatar } from '../../ui/avatar';
|
||||
import { Button, IconButton } from '../../ui/button';
|
||||
import { Tooltip } from '../../ui/tooltip';
|
||||
import { AffineOtherPageLayout } from '../affine-other-page-layout';
|
||||
import type { User } from '../auth-components';
|
||||
import { NotFoundPattern } from './not-found-pattern';
|
||||
@@ -38,7 +37,7 @@ export const NoPermissionOrNotFound = ({
|
||||
<p className={wrapper}>{t['404.hint']()}</p>
|
||||
<div className={wrapper}>
|
||||
<Button
|
||||
type="primary"
|
||||
variant="primary"
|
||||
size="extraLarge"
|
||||
onClick={onBack}
|
||||
className={largeButtonEffect}
|
||||
@@ -49,11 +48,13 @@ export const NoPermissionOrNotFound = ({
|
||||
<div className={wrapper}>
|
||||
<Avatar url={user.avatar ?? user.image} name={user.label} />
|
||||
<span style={{ margin: '0 12px' }}>{user.email}</span>
|
||||
<Tooltip content={t['404.signOut']()}>
|
||||
<IconButton onClick={onSignOut}>
|
||||
<SignOutIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
onClick={onSignOut}
|
||||
size="20"
|
||||
tooltip={t['404.signOut']()}
|
||||
>
|
||||
<SignOutIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
@@ -80,7 +81,7 @@ export const NotFoundPage = ({
|
||||
<p className={wrapper}>{t['404.hint']()}</p>
|
||||
<div className={wrapper}>
|
||||
<Button
|
||||
type="primary"
|
||||
variant="primary"
|
||||
size="extraLarge"
|
||||
onClick={onBack}
|
||||
className={largeButtonEffect}
|
||||
@@ -93,11 +94,13 @@ export const NotFoundPage = ({
|
||||
<div className={wrapper}>
|
||||
<Avatar url={user.avatar ?? user.image} name={user.label} />
|
||||
<span style={{ margin: '0 12px' }}>{user.email}</span>
|
||||
<Tooltip content={t['404.signOut']()}>
|
||||
<IconButton onClick={onSignOut}>
|
||||
<SignOutIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
onClick={onSignOut}
|
||||
size="20"
|
||||
tooltip={t['404.signOut']()}
|
||||
>
|
||||
<SignOutIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user