Files
AFFiNE-Mirror/packages/frontend/component/src/ui/avatar/avatar.tsx
T
Cats Juice 0abadbe7bb refactor(component): migrate design components (#5000)
```[tasklist]
### Tasks
- [x] Migrate components from [design](https://github.com/toeverything/design)
- [x] Replace all imports from `@toeverything/components`
- [x] Clean up `@toeverything/components` dependencies
- [x] Storybook
```

### Influence

Here are all the components that are influenced by `@toeverything/components`

- `@affine/component`
    - App update `Button` `Tooltip`
    - App sidebar header `IconButton`, `Tooltip`
    - Back `Button`
    - Auth
      - Change email page save `Button`
      - Change password page all `Button`s (Save, Later, Open)
      - Confirm change email `Button`
      - Set password page `Button`
      - Sign in success page `Button`
      - Sign up page `Button`
      - Auth `Modal`
    - Workspace card `Avatar`, `Divider`, `Tooltip`, `IconButton`
    - Share
      - Disable shared public link `Modal`
    - Import page `IconButton`, `Tooltip`
    - Accept invite page `Avatar`, `Button`
    - Invite member `Modal`
    - 404 Page `Avatar`, `Button`, `IconButton`, `Tooltip`
    - Notification center `IconButton`
    - Page list
      - operation cell `IconButton`, `Menu`, `ConfirmModal`, `Tooltip`
      - tags more `Menu`
      - favorite `IconButton`, `Tooltip`
      - new page dropdown `Menu`
      - filter `Menu`, `Button`, `IconButton`
    - Page operation `Menu`
      - export `MenuItem`
      - move to trash `MenuItem`, `ConfirmModal`
    - Workspace header filter `Menu`, `Button`
    - Collection bar `Button`, `Tooltip` (*⚠️ seems not used*)
    - Collection operation `Menu`, `MenuItem`
      - Create collection `Modal`, `Button`
      - Edit collection `Modal`, `Button`
      - Page mode filter `Menu`
      - Page mode `Button`, `Menu`
    - Setting modal
      - storage usage progress `Button`, `Tooltip`
    - On boarding tour `Modal`
- `@affine/core`
  - Bookmark `Menu`
  - Affine error boundary `Button`
  - After sign in send email `Button`
  - After sign up send email `Button`
  - Send email `Button`
  - Sign in `Button`
  - Subscription redirect `Loading`, `Button`
  - Setting `Modal`
    - User plan button `Tooltip`
    - Members `Avatar`, `Button`, `IconButton`, `Loading`, `Tooltip`, `Menu`
    - Profile `Button`, `Avatar`
    - Workspace
      - publish panel `Button`, `Tooltip`
      - export panel `Button`
      - storage panel `Button`, `Tooltip`
      - delete `ConfirmModal`
    - Language `Menu`
    - Account setting `Avatar`, `Button`
    - Date format setting `Menu`
    - Billing `Button`, `IconButton`, `Loading`
    - Payment plans `Button`, `ConfirmModal`, `Modal`, `Tooltip`
  - Create workspace `Modal`, `ConfirmModal`, `Button`
  - Payment disabled `ConfirmModal`
  - Share/Export `Menu`, `Button`, `Divider`
  - Sign out `ConfirmModal`
  - Temp disable affine cloud `Modal`
  - Page detail operation `Menu`
  - Blocksuite mode switch `Tooltip`
  - Login card `Avatar`
  - Help island `Tooltip`
- `plugin`
  - copilot
  - hello world
  - image preview
  - outline
2023-12-04 08:32:12 +00:00

144 lines
4.1 KiB
TypeScript

import { CloseIcon } from '@blocksuite/icons';
import {
type AvatarFallbackProps,
type AvatarImageProps,
type AvatarProps as RadixAvatarProps,
Fallback as AvatarFallback,
Image as AvatarImage,
Root as AvatarRoot,
} from '@radix-ui/react-avatar';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import type { CSSProperties, HTMLAttributes, MouseEvent } from 'react';
import { forwardRef, type ReactElement, useMemo, useState } from 'react';
import { IconButton } from '../button';
import { Tooltip, type TooltipProps } from '../tooltip';
import { ColorfulFallback } from './colorful-fallback';
import * as style from './style.css';
import { sizeVar } from './style.css';
export type AvatarProps = {
size?: number;
url?: string | null;
name?: string;
className?: string;
style?: CSSProperties;
colorfulFallback?: boolean;
hoverIcon?: ReactElement;
onRemove?: (e: MouseEvent<HTMLButtonElement>) => void;
avatarTooltipOptions?: Omit<TooltipProps, 'children'>;
removeTooltipOptions?: Omit<TooltipProps, 'children'>;
fallbackProps?: AvatarFallbackProps;
imageProps?: Omit<AvatarImageProps, 'src'>;
avatarProps?: RadixAvatarProps;
hoverWrapperProps?: HTMLAttributes<HTMLDivElement>;
removeButtonProps?: HTMLAttributes<HTMLButtonElement>;
} & HTMLAttributes<HTMLSpanElement>;
export const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(
(
{
size = 20,
style: propsStyles = {},
url,
name,
className,
colorfulFallback = false,
hoverIcon,
fallbackProps: { className: fallbackClassName, ...fallbackProps } = {},
imageProps,
avatarProps,
onRemove,
hoverWrapperProps: {
className: hoverWrapperClassName,
...hoverWrapperProps
} = {},
avatarTooltipOptions,
removeTooltipOptions,
removeButtonProps: {
className: removeButtonClassName,
...removeButtonProps
} = {},
...props
},
ref
) => {
const firstCharOfName = useMemo(() => {
return name?.slice(0, 1) || 'A';
}, [name]);
const [imageDom, setImageDom] = useState<HTMLDivElement | null>(null);
const [removeButtonDom, setRemoveButtonDom] =
useState<HTMLButtonElement | null>(null);
return (
<AvatarRoot className={style.avatarRoot} {...avatarProps} ref={ref}>
<Tooltip
portalOptions={{ container: imageDom }}
{...avatarTooltipOptions}
>
<div
ref={setImageDom}
className={clsx(style.avatarWrapper, className)}
style={{
...assignInlineVars({
[sizeVar]: size ? `${size}px` : '20px',
}),
...propsStyles,
}}
{...props}
>
<AvatarImage
className={style.avatarImage}
src={url || ''}
alt={name}
{...imageProps}
/>
<AvatarFallback
className={clsx(style.avatarFallback, fallbackClassName)}
delayMs={url ? 600 : undefined}
{...fallbackProps}
>
{colorfulFallback ? (
<ColorfulFallback char={firstCharOfName} />
) : (
firstCharOfName
)}
</AvatarFallback>
{hoverIcon ? (
<div
className={clsx(style.hoverWrapper, hoverWrapperClassName)}
{...hoverWrapperProps}
>
{hoverIcon}
</div>
) : null}
</div>
</Tooltip>
{onRemove ? (
<Tooltip
portalOptions={{ container: removeButtonDom }}
{...removeTooltipOptions}
>
<IconButton
size="extraSmall"
type="default"
className={clsx(style.removeButton, removeButtonClassName)}
onClick={onRemove}
ref={setRemoveButtonDom}
{...removeButtonProps}
>
<CloseIcon />
</IconButton>
</Tooltip>
) : null}
</AvatarRoot>
);
}
);
Avatar.displayName = 'Avatar';