From c7846367017237350575932eb3f05c0e7c80c1f3 Mon Sep 17 00:00:00 2001 From: slatejack Date: Fri, 18 Oct 2024 15:57:39 +0800 Subject: [PATCH 1/3] feat(avatar): update avatar style to v2, alignment vue mobile feat #536 --- src/avatar/Avatar.tsx | 144 ++++++++++++++---------------- src/avatar/AvatarGroup.tsx | 95 +++++++++----------- src/avatar/AvatarGroupContext.tsx | 9 +- src/avatar/avatar-group.en-US.md | 17 ++++ src/avatar/avatar-group.md | 17 ++++ src/avatar/avatar.en-US.md | 34 +++++++ src/avatar/avatar.md | 24 +++-- src/avatar/defaultProps.ts | 9 ++ src/avatar/hooks/useSizeHooks.ts | 21 ----- src/avatar/style/index.js | 2 +- src/avatar/type.ts | 37 +++++--- 11 files changed, 235 insertions(+), 174 deletions(-) create mode 100644 src/avatar/avatar-group.en-US.md create mode 100644 src/avatar/avatar-group.md create mode 100644 src/avatar/avatar.en-US.md create mode 100644 src/avatar/defaultProps.ts delete mode 100644 src/avatar/hooks/useSizeHooks.ts diff --git a/src/avatar/Avatar.tsx b/src/avatar/Avatar.tsx index 1760bde0..b7eb2831 100644 --- a/src/avatar/Avatar.tsx +++ b/src/avatar/Avatar.tsx @@ -1,89 +1,83 @@ -import React, { useContext, useMemo, Ref, useState } from 'react'; +import type { FC } from 'react'; +import React, { useContext } from 'react'; import cls from 'classnames'; -import type { TdAvatarProps } from './type'; -import Badge from '../badge/index'; -import { StyledProps } from '../common'; -import { ConfigContext } from '../config-provider'; -import useSizeHook from './hooks/useSizeHooks'; -import AvatarGroup from './AvatarGroup'; -import forwardRefWithStatics from '../_util/forwardRefWithStatics'; +import Image from 'tdesign-mobile-react/image'; +import Badge from 'tdesign-mobile-react/badge'; import { AvatarGroupContext } from './AvatarGroupContext'; +import { isValidSize } from '../_common/js/avatar/utils'; +import parseTNode from '../_util/parseTNode'; +import useDefaultProps from '../hooks/useDefaultProps'; +import { usePrefixClass } from '../hooks/useClass'; +import { avatarDefaultProps } from './defaultProps'; +import type { TdAvatarProps } from './type'; +import type { StyledProps } from '../common'; -export interface AvatarProps extends TdAvatarProps, StyledProps { - children?: React.ReactNode; -} +export interface AvatarProps extends TdAvatarProps, StyledProps {} -const Avatar = forwardRefWithStatics( - (props: AvatarProps, ref: Ref) => { - const { - size = '', - shape = 'circle', - icon, - children, - hideOnLoadFailed = false, - image = '', - badgeProps, - alt = '', - onError, - className, - ...restProps - } = props; - const { size: avatarGroupSize } = useContext(AvatarGroupContext) || {}; - const sizeCls = useSizeHook(size || avatarGroupSize); - const [sizeValue] = useState(size || avatarGroupSize); - const { classPrefix } = useContext(ConfigContext); - const baseAvatarCls = `${classPrefix}-avatar`; +const Avatar: FC = (props) => { + const { + size = '', + shape = 'circle', + icon, + children, + hideOnLoadFailed = false, + image = '', + badgeProps, + alt = '', + imageProps, + onError, + } = useDefaultProps(props, avatarDefaultProps); + const avatarGroupProps = useContext(AvatarGroupContext) || {}; + const rootClassName = usePrefixClass('avatar'); - const isIconOnly = icon && !children; + const { size: avatarGroupSize, shape: avatarGroupShape } = avatarGroupProps; + const hasAvatarGroupProps = Object.keys(avatarGroupProps).length > 0; + const shapeValue = shape || avatarGroupShape || 'circle'; + const sizeValue = size || avatarGroupSize; + const isCustomSize = !isValidSize(sizeValue); - const avatarCls = cls( - baseAvatarCls, - { - [sizeCls]: true, - [`${baseAvatarCls}--${shape}`]: shape, - }, - className, - ); + const avatarClasses = cls( + rootClassName, + `${rootClassName}-${isCustomSize ? 'medium' : sizeValue}`, + `${rootClassName}-${shapeValue}`, + { + [`${rootClassName}--border ${rootClassName}--border-${isCustomSize ? 'medium' : sizeValue}`]: hasAvatarGroupProps, + }, + ); - // size 没有命中原有 size 规则且 size 仍有值, 推断为 size 值 - const customSize = useMemo(() => { - if (sizeCls === '' && sizeValue) { - return { - width: sizeValue, - height: sizeValue, - }; + const customSize = isCustomSize + ? { + height: sizeValue, + width: sizeValue, + 'font-size': `${(Number.parseInt(sizeValue, 10) / 8) * 3 + 2}px`, } - return {}; - }, [sizeCls, sizeValue]); + : {}; - const iconCls = `${baseAvatarCls}__icon`; - const badgeCls = `${baseAvatarCls}__badge`; - const innerCls = `${baseAvatarCls}__inner`; + const handleImgLoaderError = (context: any) => { + onError?.(context); + }; - const renderIcon =
{icon}
; - const renderImage = {alt}; - const renderContent = <>{children}; - const renderBadge = ; + const renderAvatar = () => { + if (image && !hideOnLoadFailed) { + return {alt}; + } + if (icon) { + return
{icon}
; + } + return parseTNode(children); + }; - const isShowImage = image && !hideOnLoadFailed; - const isShowBadge = !!badgeProps; - - return ( -
-
- {isShowImage && renderImage} - {!isShowImage && isIconOnly && renderIcon} - {!isShowImage && !isIconOnly && renderContent} -
- {isShowBadge &&
{renderBadge}
} + return ( +
+
+ +
+ {renderAvatar()} +
+
- ); - }, - { - Group: AvatarGroup, - }, -); - -Avatar.displayName = 'Avatar'; +
+ ); +}; export default Avatar; diff --git a/src/avatar/AvatarGroup.tsx b/src/avatar/AvatarGroup.tsx index 396dda47..d934bfcd 100644 --- a/src/avatar/AvatarGroup.tsx +++ b/src/avatar/AvatarGroup.tsx @@ -1,10 +1,15 @@ -import React, { forwardRef, Ref, useContext, useEffect, useMemo, useState } from 'react'; +import type { MouseEvent } from 'react'; +import React from 'react'; import cls from 'classnames'; -import { ShapeEnum, TdAvatarGroupProps } from './type'; -import { StyledProps } from '../common'; -import { ConfigContext } from '../config-provider'; import Avatar from './Avatar'; import { AvatarGroupContextProvider } from './AvatarGroupContext'; +import parseTNode from '../_util/parseTNode'; +import { isValidSize } from '../_common/js/avatar/utils'; +import useDefaultProps from '../hooks/useDefaultProps'; +import { usePrefixClass } from '../hooks/useClass'; +import { avatarGroupDefaultProps } from './defaultProps'; +import type { TdAvatarGroupProps } from './type'; +import type { StyledProps } from '../common'; export interface AvatarGroupProps extends TdAvatarGroupProps, StyledProps { children?: React.ReactNode; @@ -14,67 +19,51 @@ function getValidChildren(children: React.ReactNode) { return React.Children.toArray(children).filter((child) => React.isValidElement(child)) as React.ReactElement[]; } -const AvatarGroup = forwardRef((props: AvatarGroupProps, ref: Ref) => { - const { cascading, children, max, collapseAvatar, size, className, ...restProps } = props; - const { classPrefix } = useContext(ConfigContext); - const [isShowEllipsisContent, setIsShowEllipsisContent] = useState(false); - const [lastOneShape, setLastOneShape] = useState('circle'); - - const baseAvatarGroupCls = `${classPrefix}-avatar-group`; - - const avatarGroupCls = cls( - baseAvatarGroupCls, - { - [`${classPrefix}-avatar--offset-right`]: cascading === 'right-up', - [`${classPrefix}-avatar--offset-left`]: cascading === 'left-up', - }, - className, +const AvatarGroup = (props: AvatarGroupProps) => { + const { cascading, children, size, shape, max, collapseAvatar, onCollapsedItemClick } = useDefaultProps( + props, + avatarGroupDefaultProps, ); + const rootClassName = usePrefixClass('avatar-group'); - const validChildren = getValidChildren(children); - const childrenCount = validChildren.length; - const childrenWithinMax = max ? validChildren.slice(0, max) : validChildren; + const direction = cascading ? cascading.split('-')[0] : 'right'; + const isCustomSize = !isValidSize(size); - const renderCollapseAvatar = useMemo(() => { - const popupNum = `+${childrenCount - max}`; - return collapseAvatar || popupNum; - }, [collapseAvatar, max, childrenCount]); - - const ellipsisSize = useMemo( - () => childrenWithinMax[childrenWithinMax.length - 1]?.props.size || props.size, - [childrenWithinMax, props.size], + const avatarGroupClasses = cls( + rootClassName, + `${rootClassName}-offset-${direction}`, + `${rootClassName}-offset-${direction}-${isCustomSize ? 'medium' : size}`, ); - useEffect(() => { - if (max && childrenCount > max) { - setIsShowEllipsisContent(true); - } else { - setIsShowEllipsisContent(false); - } - }, [max, childrenCount]); + const handleCollapsedItemClick = (e: MouseEvent) => { + onCollapsedItemClick?.({ e }); + }; - useEffect(() => { - if ( - childrenWithinMax.length > 0 && - childrenWithinMax?.[childrenWithinMax.length - 1]?.props?.shape !== lastOneShape - ) { - setLastOneShape(childrenWithinMax[childrenWithinMax.length - 1].props.shape); + const renderAvatar = () => { + const validChildren = getValidChildren(children); + if (validChildren.length <= max) { + return validChildren; } - }, [childrenWithinMax, lastOneShape]); + const showAvatarList = validChildren.slice(0, max); + const renderCollapseAvatar = () => parseTNode(collapseAvatar); + showAvatarList.push( +
+ + {renderCollapseAvatar() || `+${validChildren.length - max}`} + +
, + ); + return showAvatarList; + }; return ( -
- - {childrenWithinMax} - {isShowEllipsisContent ? ( - - {renderCollapseAvatar} - - ) : null} +
+ + {renderAvatar()}
); -}); +}; AvatarGroup.displayName = 'AvatarGroup'; diff --git a/src/avatar/AvatarGroupContext.tsx b/src/avatar/AvatarGroupContext.tsx index 076a94da..e1d00f6b 100644 --- a/src/avatar/AvatarGroupContext.tsx +++ b/src/avatar/AvatarGroupContext.tsx @@ -3,12 +3,13 @@ import type { AvatarGroupProps } from './AvatarGroup'; export const AvatarGroupContext = React.createContext(null); -export function AvatarGroupContextProvider(props: Pick) { - const memoSize = useMemo( +export function AvatarGroupContextProvider(props: Pick) { + const memoInfo = useMemo( () => ({ size: props.size, + shape: props.shape, }), - [props.size], + [props.size, props.shape], ); - return {props.children}; + return {props.children}; } diff --git a/src/avatar/avatar-group.en-US.md b/src/avatar/avatar-group.en-US.md new file mode 100644 index 00000000..9cfde397 --- /dev/null +++ b/src/avatar/avatar-group.en-US.md @@ -0,0 +1,17 @@ +:: BASE_DOC :: + +## API + + +### AvatarGroup Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +cascading | String | 'right-up' | multiple images cascading。options: left-up/right-up。Typescript:`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +collapseAvatar | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +max | Number | - | \- | N +shape | String | - | shape。options: circle/round。Typescript:`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | - | size | N +onCollapsedItemClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N diff --git a/src/avatar/avatar-group.md b/src/avatar/avatar-group.md new file mode 100644 index 00000000..2ead60d7 --- /dev/null +++ b/src/avatar/avatar-group.md @@ -0,0 +1,17 @@ +:: BASE_DOC :: + +## API + + +### AvatarGroup Props + +名称 | 类型 | 默认值 | 描述 | 必传 +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,TS 类型:`React.CSSProperties` | N +cascading | String | 'right-up' | 图片之间的层叠关系,可选值:左侧图片在上和右侧图片在上。可选项:left-up/right-up。TS 类型:`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +collapseAvatar | TNode | - | 头像数量超出时,会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例:`+5`,`...`, `更多`。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +max | Number | - | 能够同时显示的最多头像数量 | N +shape | String | - | 形状。优先级低于 Avatar.shape。可选项:circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | - | 尺寸,示例值:small/medium/large/24px/38px 等。优先级低于 Avatar.size | N +onCollapsedItemClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
点击头像折叠元素触发 | N diff --git a/src/avatar/avatar.en-US.md b/src/avatar/avatar.en-US.md new file mode 100644 index 00000000..3b388d26 --- /dev/null +++ b/src/avatar/avatar.en-US.md @@ -0,0 +1,34 @@ +:: BASE_DOC :: + +## API + +### Avatar Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +alt | String | - | show it when url is not valid | N +badgeProps | Object | - | Typescript:`BadgeProps`,[Badge API Documents](./badge?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +children | TNode | - | children, same as `content`。Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +hideOnLoadFailed | Boolean | false | hide image when loading image failed | N +icon | TElement | - | use icon to fill。Typescript:`TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +image | String | - | images url | N +imageProps | Object | - | Typescript:`ImageProps`,[Image API Documents](./image?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +shape | String | - | shape。options: circle/round。Typescript:`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | - | size | N +onError | Function | | Typescript:`(context: { e: Event }) => void`
trigger on image load failed | N + + +### AvatarGroup Props + +name | type | default | description | required +-- | -- | -- | -- | -- +className | String | - | className of component | N +style | Object | - | CSS(Cascading Style Sheets),Typescript:`React.CSSProperties` | N +cascading | String | 'right-up' | multiple images cascading。options: left-up/right-up。Typescript:`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +collapseAvatar | TNode | - | Typescript:`string \| TNode`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +max | Number | - | \- | N +shape | String | - | shape。options: circle/round。Typescript:`ShapeEnum`。[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | - | size | N +onCollapsedItemClick | Function | | Typescript:`(context: { e: MouseEvent }) => void`
| N diff --git a/src/avatar/avatar.md b/src/avatar/avatar.md index 517f7484..f9eb5a7e 100644 --- a/src/avatar/avatar.md +++ b/src/avatar/avatar.md @@ -1,28 +1,34 @@ :: BASE_DOC :: ## API + ### Avatar Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- className | String | - | 类名 | N style | Object | - | 样式,TS 类型:`React.CSSProperties` | N alt | String | - | 头像替换文本,仅当图片加载失败时有效 | N -badgeProps | Object | - | 头像右上角提示信息,继承 Badge 组件的全部特性。如:小红点,或者数字。TS 类型:`TdBadgeProps`,[Badge API Documents](./badge?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +badgeProps | Object | - | 头像右上角提示信息,继承 Badge 组件的全部特性。如:小红点,或者数字。TS 类型:`BadgeProps`,[Badge API Documents](./badge?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +children | TNode | - | 子元素内容,同 content。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N hideOnLoadFailed | Boolean | false | 加载失败时隐藏图片 | N icon | TElement | - | 图标。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N image | String | - | 图片地址 | N -shape | String | circle | 形状。可选项:circle/round。TS 类型:`ShapeEnum ` `type ShapeEnum = 'circle' | 'round'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N -size | String | - | 尺寸,示例值:small/medium/large/24px/38px 等,默认为 large | N -onError | Function | | TS 类型:`() => void`
图片加载失败时触发 | N +imageProps | Object | - | 透传至 Image 组件。TS 类型:`ImageProps`,[Image API Documents](./image?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +shape | String | - | 形状。优先级高于 AvatarGroup.shape 。Avatar 单独存在时,默认值为 circle。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.shape 决定。可选项:circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | - | 尺寸,示例值:small/medium/large/24px/38px 等。优先级高于 AvatarGroup.size 。Avatar 单独存在时,默认值为 medium。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.size 决定 | N +onError | Function | | TS 类型:`(context: { e: Event }) => void`
图片加载失败时触发 | N + ### AvatarGroup Props -名称 | 类型 | 默认值 | 说明 | 必传 +名称 | 类型 | 默认值 | 描述 | 必传 -- | -- | -- | -- | -- className | String | - | 类名 | N style | Object | - | 样式,TS 类型:`React.CSSProperties` | N -cascading | String | 'right-up' | 图片之间的层叠关系,可选值:左侧图片在上和右侧图片在上。可选项:left-up/right-up。TS 类型:`CascadingValue` `type CascadingValue = 'left-up' | 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N -collapseAvatar | TNode | - | 头像数量超出时,会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例:`+5`,`...`, `更多`。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +cascading | String | 'right-up' | 图片之间的层叠关系,可选值:左侧图片在上和右侧图片在上。可选项:left-up/right-up。TS 类型:`CascadingValue` `type CascadingValue = 'left-up' \| 'right-up'`。[详细类型定义](https://github.com/Tencent/tdesign-mobile-react/tree/develop/src/avatar/type.ts) | N +collapseAvatar | TNode | - | 头像数量超出时,会出现一个头像折叠元素。该元素内容可自定义。默认为 `+N`。示例:`+5`,`...`, `更多`。TS 类型:`string \| TNode`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N max | Number | - | 能够同时显示的最多头像数量 | N -size | String | medium | 尺寸,示例值:small/medium/large/24px/38px 等。优先级低于 Avatar.size | N +shape | String | - | 形状。优先级低于 Avatar.shape。可选项:circle/round。TS 类型:`ShapeEnum`。[通用类型定义](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N +size | String | - | 尺寸,示例值:small/medium/large/24px/38px 等。优先级低于 Avatar.size | N +onCollapsedItemClick | Function | | TS 类型:`(context: { e: MouseEvent }) => void`
点击头像折叠元素触发 | N diff --git a/src/avatar/defaultProps.ts b/src/avatar/defaultProps.ts new file mode 100644 index 00000000..895eeb21 --- /dev/null +++ b/src/avatar/defaultProps.ts @@ -0,0 +1,9 @@ +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdAvatarProps, TdAvatarGroupProps } from './type'; + +export const avatarDefaultProps: TdAvatarProps = { hideOnLoadFailed: false }; + +export const avatarGroupDefaultProps: TdAvatarGroupProps = { cascading: 'right-up' }; diff --git a/src/avatar/hooks/useSizeHooks.ts b/src/avatar/hooks/useSizeHooks.ts deleted file mode 100644 index 2b7f3e45..00000000 --- a/src/avatar/hooks/useSizeHooks.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useContext, useMemo } from 'react'; -import { ConfigContext } from '../../config-provider'; - -export const SIZE_CLASSNAMES = { - small: `-size-s`, - medium: `-size-m`, - large: `-size-l`, - default: '', - xs: `-size-xs`, - xl: `-size-xl`, - block: `-size-full-width`, -}; - -export type sizeType = 'small' | 'medium' | 'large' | 'xs' | 'xl' | 'block' | 'default'; - -function useSizeHook(size: sizeType) { - const { classPrefix } = useContext(ConfigContext); - return useMemo(() => (SIZE_CLASSNAMES[size] ? `${classPrefix}${SIZE_CLASSNAMES[size]}` : ''), [size, classPrefix]); -} - -export default useSizeHook; diff --git a/src/avatar/style/index.js b/src/avatar/style/index.js index d6491de5..fc4ae653 100644 --- a/src/avatar/style/index.js +++ b/src/avatar/style/index.js @@ -1 +1 @@ -import '../../_common/style/mobile/components/avatar/_index.less'; +import '../../_common/style/mobile/components/avatar/v2/_index.less'; diff --git a/src/avatar/type.ts b/src/avatar/type.ts index 70661f28..2dd79047 100644 --- a/src/avatar/type.ts +++ b/src/avatar/type.ts @@ -4,8 +4,10 @@ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC * */ -import { TdBadgeProps } from '../badge'; -import { TNode, TElement } from '../common'; +import { BadgeProps } from '../badge'; +import { ImageProps } from '../image'; +import { TNode, TElement, ShapeEnum } from '../common'; +import { MouseEvent } from 'react'; export interface TdAvatarProps { /** @@ -16,7 +18,11 @@ export interface TdAvatarProps { /** * 头像右上角提示信息,继承 Badge 组件的全部特性。如:小红点,或者数字 */ - badgeProps?: TdBadgeProps; + badgeProps?: BadgeProps; + /** + * 子元素内容,同 content + */ + children?: TNode; /** * 加载失败时隐藏图片 * @default false @@ -32,19 +38,22 @@ export interface TdAvatarProps { */ image?: string; /** - * 形状 - * @default circle + * 透传至 Image 组件 */ - shape?: ShapeEnum ; + imageProps?: ImageProps; /** - * 尺寸,示例值:small/medium/large/24px/38px 等,默认为 large + * 形状。优先级高于 AvatarGroup.shape 。Avatar 单独存在时,默认值为 circle。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.shape 决定 + */ + shape?: ShapeEnum; + /** + * 尺寸,示例值:small/medium/large/24px/38px 等。优先级高于 AvatarGroup.size 。Avatar 单独存在时,默认值为 medium。如果父组件 AvatarGroup 存在,默认值便由 AvatarGroup.size 决定 * @default '' */ size?: string; /** * 图片加载失败时触发 */ - onError?: () => void; + onError?: (context: { e: Event }) => void; } export interface TdAvatarGroupProps { @@ -61,13 +70,19 @@ export interface TdAvatarGroupProps { * 能够同时显示的最多头像数量 */ max?: number; + /** + * 形状。优先级低于 Avatar.shape + */ + shape?: ShapeEnum; /** * 尺寸,示例值:small/medium/large/24px/38px 等。优先级低于 Avatar.size - * @default medium + * @default '' */ size?: string; + /** + * 点击头像折叠元素触发 + */ + onCollapsedItemClick?: (context: { e: MouseEvent }) => void; } -export type ShapeEnum = 'circle' | 'round'; - export type CascadingValue = 'left-up' | 'right-up'; From 74999a9cc16ed903f9e4f5598afd87b8113124ab Mon Sep 17 00:00:00 2001 From: slatejack Date: Fri, 18 Oct 2024 17:29:11 +0800 Subject: [PATCH 2/3] fix(avatar): fix avatar container style --- src/avatar/Avatar.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/avatar/Avatar.tsx b/src/avatar/Avatar.tsx index b7eb2831..4ff967d0 100644 --- a/src/avatar/Avatar.tsx +++ b/src/avatar/Avatar.tsx @@ -16,6 +16,7 @@ export interface AvatarProps extends TdAvatarProps, StyledProps {} const Avatar: FC = (props) => { const { + className, size = '', shape = 'circle', icon, @@ -38,12 +39,13 @@ const Avatar: FC = (props) => { const avatarClasses = cls( rootClassName, - `${rootClassName}-${isCustomSize ? 'medium' : sizeValue}`, - `${rootClassName}-${shapeValue}`, + `${rootClassName}--${isCustomSize ? 'medium' : sizeValue}`, + `${rootClassName}--${shapeValue}`, { [`${rootClassName}--border ${rootClassName}--border-${isCustomSize ? 'medium' : sizeValue}`]: hasAvatarGroupProps, }, ); + const containerClassName = cls(`${rootClassName}__wrapper`, className); const customSize = isCustomSize ? { @@ -68,7 +70,7 @@ const Avatar: FC = (props) => { }; return ( -
+
From 80dfbe0c25a79796667dadf5f3d5d9288d39d0a4 Mon Sep 17 00:00:00 2001 From: slatejack Date: Fri, 18 Oct 2024 17:43:04 +0800 Subject: [PATCH 3/3] feat(avatar): update avatar demo to style v2, alignment vue mobile --- site/mobile/mobile.config.js | 2 +- src/avatar/AvatarGroup.tsx | 6 +- src/avatar/_example/action.jsx | 54 - src/avatar/_example/action.tsx | 27 + src/avatar/_example/adjust.jsx | 14 - src/avatar/_example/badgeAvatar.tsx | 22 + src/avatar/_example/characterAvatar.tsx | 15 + src/avatar/_example/exhibition.jsx | 43 - src/avatar/_example/exhibition.tsx | 26 + src/avatar/_example/iconAvatar.tsx | 12 + src/avatar/_example/imageAvatar.tsx | 11 + src/avatar/_example/index.jsx | 30 - src/avatar/_example/index.tsx | 40 + src/avatar/_example/shape.jsx | 19 - src/avatar/_example/size.jsx | 72 - src/avatar/_example/size.tsx | 49 + src/avatar/_example/style/index.less | 34 +- src/avatar/_example/type.jsx | 19 - test/snap/__snapshots__/csr.test.jsx.snap | 3206 ++++++++++++++++++++- test/snap/__snapshots__/ssr.test.jsx.snap | 24 +- 20 files changed, 3357 insertions(+), 368 deletions(-) delete mode 100644 src/avatar/_example/action.jsx create mode 100644 src/avatar/_example/action.tsx delete mode 100644 src/avatar/_example/adjust.jsx create mode 100644 src/avatar/_example/badgeAvatar.tsx create mode 100644 src/avatar/_example/characterAvatar.tsx delete mode 100644 src/avatar/_example/exhibition.jsx create mode 100644 src/avatar/_example/exhibition.tsx create mode 100644 src/avatar/_example/iconAvatar.tsx create mode 100644 src/avatar/_example/imageAvatar.tsx delete mode 100644 src/avatar/_example/index.jsx create mode 100644 src/avatar/_example/index.tsx delete mode 100644 src/avatar/_example/shape.jsx delete mode 100644 src/avatar/_example/size.jsx create mode 100644 src/avatar/_example/size.tsx delete mode 100644 src/avatar/_example/type.jsx diff --git a/site/mobile/mobile.config.js b/site/mobile/mobile.config.js index e40f14b5..a1afe2c0 100644 --- a/site/mobile/mobile.config.js +++ b/site/mobile/mobile.config.js @@ -215,7 +215,7 @@ export default { { title: 'Avatar 头像', name: 'avatar', - component: () => import('tdesign-mobile-react/avatar/_example/index.jsx'), + component: () => import('tdesign-mobile-react/avatar/_example/index.tsx'), }, { title: 'Indexes 索引', diff --git a/src/avatar/AvatarGroup.tsx b/src/avatar/AvatarGroup.tsx index d934bfcd..6cdf05d0 100644 --- a/src/avatar/AvatarGroup.tsx +++ b/src/avatar/AvatarGroup.tsx @@ -47,7 +47,11 @@ const AvatarGroup = (props: AvatarGroupProps) => { const showAvatarList = validChildren.slice(0, max); const renderCollapseAvatar = () => parseTNode(collapseAvatar); showAvatarList.push( -
+
{renderCollapseAvatar() || `+${validChildren.length - max}`} diff --git a/src/avatar/_example/action.jsx b/src/avatar/_example/action.jsx deleted file mode 100644 index 43a0bcff..00000000 --- a/src/avatar/_example/action.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import { Avatar } from 'tdesign-mobile-react'; -import { UserAddIcon } from 'tdesign-icons-react'; - -const imageList = [ - 'https://tdesign.gtimg.com/mobile/demos/avatar_1.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_2.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_3.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_4.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_5.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_1.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_2.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_3.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_4.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_5.png', -]; - -export default function AvatarTypeDemo() { - return ( - <> -
- } - > - {imageList.map((url, idx) => ( - - ))} - -
-
- } - > - {imageList.map((url, idx) => ( - - ))} - -
-
- }> - {imageList.map((url, idx) => ( - - ))} - -
- - ); -} diff --git a/src/avatar/_example/action.tsx b/src/avatar/_example/action.tsx new file mode 100644 index 00000000..bf9e3e9b --- /dev/null +++ b/src/avatar/_example/action.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Avatar, AvatarGroup } from 'tdesign-mobile-react'; +import { UserAddIcon } from 'tdesign-icons-react'; + +export default function ActionAvatar() { + const imageList = [ + 'https://tdesign.gtimg.com/mobile/demos/avatar1.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar2.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar3.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar4.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar5.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar1.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar2.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar3.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar4.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar5.png', + ]; + return ( +
+ }> + {imageList.map((url, index) => ( + + ))} + +
+ ); +} diff --git a/src/avatar/_example/adjust.jsx b/src/avatar/_example/adjust.jsx deleted file mode 100644 index 7b82feac..00000000 --- a/src/avatar/_example/adjust.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { Avatar } from 'tdesign-mobile-react'; - -export default function AvatarAdjustDemo() { - return ( -
-
- - 陈晚 - 陈晚晚 -
-
- ); -} diff --git a/src/avatar/_example/badgeAvatar.tsx b/src/avatar/_example/badgeAvatar.tsx new file mode 100644 index 00000000..e67a3cd3 --- /dev/null +++ b/src/avatar/_example/badgeAvatar.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Avatar } from 'tdesign-mobile-react'; +import { UserIcon } from 'tdesign-icons-react'; + +export default function BadgeAvatar() { + return ( +
+ + + A + + } badgeProps={{ count: 12, offset: [6, 6] }} /> +
+ ); +} diff --git a/src/avatar/_example/characterAvatar.tsx b/src/avatar/_example/characterAvatar.tsx new file mode 100644 index 00000000..92ab753a --- /dev/null +++ b/src/avatar/_example/characterAvatar.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { Avatar } from 'tdesign-mobile-react'; + +export default function CharacterAvatar() { + return ( +
+ + A + + + A + +
+ ); +} diff --git a/src/avatar/_example/exhibition.jsx b/src/avatar/_example/exhibition.jsx deleted file mode 100644 index fd748a5a..00000000 --- a/src/avatar/_example/exhibition.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import { Avatar } from 'tdesign-mobile-react'; - -const imageList = [ - 'https://tdesign.gtimg.com/mobile/demos/avatar_1.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_2.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_3.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_4.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_5.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_1.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_2.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_3.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_4.png', - 'https://tdesign.gtimg.com/mobile/demos/avatar_5.png', -]; - -export default function AvatarTypeDemo() { - return ( - <> -
- - {imageList.map((url, idx) => ( - - ))} - -
-
- - {imageList.map((url, idx) => ( - - ))} - -
-
- - {imageList.map((url, idx) => ( - - ))} - -
- - ); -} diff --git a/src/avatar/_example/exhibition.tsx b/src/avatar/_example/exhibition.tsx new file mode 100644 index 00000000..630a5c68 --- /dev/null +++ b/src/avatar/_example/exhibition.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Avatar, AvatarGroup } from 'tdesign-mobile-react'; + +export default function ExhibitionAvatar() { + const imageList = [ + 'https://tdesign.gtimg.com/mobile/demos/avatar1.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar2.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar3.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar4.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar5.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar1.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar2.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar3.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar4.png', + 'https://tdesign.gtimg.com/mobile/demos/avatar5.png', + ]; + return ( +
+ + {imageList.map((url, index) => ( + + ))} + +
+ ); +} diff --git a/src/avatar/_example/iconAvatar.tsx b/src/avatar/_example/iconAvatar.tsx new file mode 100644 index 00000000..5bdd2c79 --- /dev/null +++ b/src/avatar/_example/iconAvatar.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Avatar } from 'tdesign-mobile-react'; +import { UserIcon } from 'tdesign-icons-react'; + +export default function IconAvatar() { + return ( +
+ } /> + } /> +
+ ); +} diff --git a/src/avatar/_example/imageAvatar.tsx b/src/avatar/_example/imageAvatar.tsx new file mode 100644 index 00000000..c6fa699d --- /dev/null +++ b/src/avatar/_example/imageAvatar.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { Avatar } from 'tdesign-mobile-react'; + +export default function ImageAvatar() { + return ( +
+ + +
+ ); +} diff --git a/src/avatar/_example/index.jsx b/src/avatar/_example/index.jsx deleted file mode 100644 index e65b2cb1..00000000 --- a/src/avatar/_example/index.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import TDemoHeader from '../../../site/mobile/components/DemoHeader'; -import TDemoBlock from '../../../site/mobile/components/DemoBlock'; -import ShapeDemo from './shape'; -import ExhibitionDemo from './exhibition'; -import ActionDemo from './action'; -import SizeDemo from './size'; -import './style/index.less'; - -export default function () { - return ( -
- - -
- -
-
- - - - - - - - - -
- ); -} diff --git a/src/avatar/_example/index.tsx b/src/avatar/_example/index.tsx new file mode 100644 index 00000000..fc7525c4 --- /dev/null +++ b/src/avatar/_example/index.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import TDemoHeader from '../../../site/mobile/components/DemoHeader'; +import TDemoBlock from '../../../site/mobile/components/DemoBlock'; +import ImageAvatar from './imageAvatar'; +import CharacterAvatar from './characterAvatar'; +import IconAvatar from './iconAvatar'; +import BadgeAvatar from './badgeAvatar'; +import ExhibitionAvatar from './exhibition'; +import ActionAvatar from './action'; +import SizeAvatar from './size'; +import './style/index.less'; + +export default function () { + return ( +
+ + + + + + + + + + + + + + + + + + + + + + +
+ ); +} diff --git a/src/avatar/_example/shape.jsx b/src/avatar/_example/shape.jsx deleted file mode 100644 index 3d68cd81..00000000 --- a/src/avatar/_example/shape.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { UserIcon } from 'tdesign-icons-react'; -import { Avatar } from 'tdesign-mobile-react'; - -const demoPicture = 'https://tdesign.gtimg.com/mobile/demos/avatar_1.png'; - -export default function AvatarTypeDemo() { - return ( - <> - } /> - - - - } /> - - A - - ); -} diff --git a/src/avatar/_example/size.jsx b/src/avatar/_example/size.jsx deleted file mode 100644 index 692c58f3..00000000 --- a/src/avatar/_example/size.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import { Avatar } from 'tdesign-mobile-react'; -import { UserIcon } from 'tdesign-icons-react'; - -export default function AvatarSizeDemo() { - return ( - <> -
- }> - }> - }> -
-
- - - -
-
- - - -
-
- - A - - - A - - - A - -
- - ); -} diff --git a/src/avatar/_example/size.tsx b/src/avatar/_example/size.tsx new file mode 100644 index 00000000..e362e589 --- /dev/null +++ b/src/avatar/_example/size.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { Avatar } from 'tdesign-mobile-react'; +import { UserIcon } from 'tdesign-icons-react'; + +export default function SizeAvatar() { + return ( +
+
+ + + A + + } /> +
+
+ + + A + + } /> +
+
+ + + A + + } /> +
+
+ ); +} diff --git a/src/avatar/_example/style/index.less b/src/avatar/_example/style/index.less index 079b02e9..4bc31277 100644 --- a/src/avatar/_example/style/index.less +++ b/src/avatar/_example/style/index.less @@ -1,17 +1,45 @@ .avatar-demo { margin-left: 16px; margin-bottom: 16px; - .t-avatar { - margin-right: 20px; - } + + .custom { .t-avatar__inner { background-color: #0052d9; color: #fff; } } + + .avatar-example:not(:last-child) { + margin-right: 32px; + } + + .avatar-example--small:not(:last-child) { + margin-right: 56px; + } + + .avatar-example--medium:not(:last-child) { + margin-right: 48px; + } + + .avatar-example--large:not(:last-child) { + margin-right: 32px; + } + + .external-class-content { + .t-avatar { + color: #fff; + background-color: #0052d9; + font-weight: 400; + } + } } + .avatar-group-demo { margin-left: 16px; margin-bottom: 16px; } + +.tdesign-mobile-demo { + background-color: var(--bg-color-demo, #fff); +} diff --git a/src/avatar/_example/type.jsx b/src/avatar/_example/type.jsx deleted file mode 100644 index 3d68cd81..00000000 --- a/src/avatar/_example/type.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { UserIcon } from 'tdesign-icons-react'; -import { Avatar } from 'tdesign-mobile-react'; - -const demoPicture = 'https://tdesign.gtimg.com/mobile/demos/avatar_1.png'; - -export default function AvatarTypeDemo() { - return ( - <> - } /> - - - - } /> - - A - - ); -} diff --git a/test/snap/__snapshots__/csr.test.jsx.snap b/test/snap/__snapshots__/csr.test.jsx.snap index 625b72d4..7d0fe02d 100644 --- a/test/snap/__snapshots__/csr.test.jsx.snap +++ b/test/snap/__snapshots__/csr.test.jsx.snap @@ -1,5 +1,2893 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`csr snapshot test > csr test src/avatar/_example/action.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/badgeAvatar.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+ 8 +
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+ 12 +
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/characterAvatar.tsx 1`] = ` +
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/exhibition.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +5 +
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/iconAvatar.tsx 1`] = ` +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/imageAvatar.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/index.tsx 1`] = ` +
+
+
+

+ Avatar 头像 +

+

+ 用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。 +

+
+
+
+

+ 01 头像类型 +

+

+ 图片头像 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+

+ 字符头像 +

+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+

+ 图标头像 +

+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+

+ 徽标头像 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+ 8 +
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+ 12 +
+
+
+
+
+
+
+
+
+

+ 02 特殊类型 +

+

+ 纯展示的头像组 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +5 +
+
+
+
+
+
+
+
+
+
+
+
+

+ 带操作的头像组 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+

+ 03 组件尺寸 +

+

+ 组件尺寸 +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 实例图片 +
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 实例图片 +
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 实例图片 +
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+`; + +exports[`csr snapshot test > csr test src/avatar/_example/size.tsx 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 实例图片 +
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 实例图片 +
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 实例图片 +
+
+
+
+
+
+
+
+
+
+
+ A +
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+`; + exports[`csr snapshot test > csr test src/back-top/_example/base.tsx 1`] = `
csr test src/badge/_example/index.tsx 1`] = ` class="block" >
-
- -
- - - -
-
@@ -915,7 +3782,28 @@ exports[`csr snapshot test > csr test src/badge/_example/index.tsx 1`] = ` >
+ > +
+
+ + + +
+
+
csr test src/badge/_example/index.tsx 1`] = ` class="block" >
-
- -
- - - -
-
@@ -966,7 +3833,28 @@ exports[`csr snapshot test > csr test src/badge/_example/index.tsx 1`] = ` >
+ > +
+
+ + + +
+
+
csr test src/badge/_example/size.tsx 1`] = ` class="block" >
-
- -
- - - -
-
@@ -1025,7 +3892,28 @@ exports[`csr snapshot test > csr test src/badge/_example/size.tsx 1`] = ` >
+ > +
+
+ + + +
+
+
csr test src/badge/_example/size.tsx 1`] = ` class="block" >
-
- -
- - - -
-
@@ -1076,7 +3943,28 @@ exports[`csr snapshot test > csr test src/badge/_example/size.tsx 1`] = ` >
+ > +
+
+ + + +
+
+
csr test src/cell/_example/base.tsx 1`] = ` class="t-cell__left-icon" >
- +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
@@ -4070,15 +7001,58 @@ exports[`csr snapshot test > csr test src/cell/_example/multiple.tsx 1`] = ` class="t-cell__left-icon" >
- +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
@@ -56103,15 +59077,31 @@ exports[`csr snapshot test > csr test src/toast/_example/theme.tsx 1`] = `
`; +exports[`ssr snapshot test > ssr test src/avatar/_example/action.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/badgeAvatar.tsx 1`] = `"
A
8
12
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/characterAvatar.tsx 1`] = `"
A
A
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/exhibition.tsx 1`] = `"
+5
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/iconAvatar.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/imageAvatar.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/index.tsx 1`] = `"

Avatar 头像

用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。

01 头像类型

图片头像

字符头像

A
A

图标头像

徽标头像

A
8
12

02 特殊类型

纯展示的头像组

+5

带操作的头像组

03 组件尺寸

组件尺寸

实例图片
A
实例图片
A
实例图片
A
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/size.tsx 1`] = `"
实例图片
A
实例图片
A
实例图片
A
"`; + exports[`ssr snapshot test > ssr test src/back-top/_example/base.tsx 1`] = `"
"`; exports[`ssr snapshot test > ssr test src/back-top/_example/index.tsx 1`] = `"

BackTop 返回顶部

当页面过长往下滑动是会出现返回顶部的便捷操作,帮助用户快速回到页面顶部

形状

"`; exports[`ssr snapshot test > ssr test src/badge/_example/base.tsx 1`] = `"
红点徽标
消息
数字徽标
消息
8
2
8
自定义徽标
NEW
"`; -exports[`ssr snapshot test > ssr test src/badge/_example/index.tsx 1`] = `"

Badge 徽标

用于告知用户,该区域的状态变化或者待处理任务的数量。

01 组件类型

红点徽标
消息
数字徽标
消息
8
2
8
自定义徽标
NEW

02 组件样式

圆形徽标
2
方形徽标
2
气泡徽标
领积分
角标
单行标题
New

03 组件尺寸

Large
8
Middle
8
"`; +exports[`ssr snapshot test > ssr test src/badge/_example/index.tsx 1`] = `"

Badge 徽标

用于告知用户,该区域的状态变化或者待处理任务的数量。

01 组件类型

红点徽标
消息
数字徽标
消息
8
2
8
自定义徽标
NEW

02 组件样式

圆形徽标
2
方形徽标
2
气泡徽标
领积分
角标
单行标题
New

03 组件尺寸

Large
8
Middle
8
"`; -exports[`ssr snapshot test > ssr test src/badge/_example/size.tsx 1`] = `"
Large
8
Middle
8
"`; +exports[`ssr snapshot test > ssr test src/badge/_example/size.tsx 1`] = `"
Large
8
Middle
8
"`; exports[`ssr snapshot test > ssr test src/badge/_example/theme.tsx 1`] = `"
圆形徽标
2
方形徽标
2
气泡徽标
领积分
角标
单行标题
New
"`; @@ -56137,11 +59127,11 @@ exports[`ssr snapshot test > ssr test src/button/_example/test.tsx 1`] = `"
exports[`ssr snapshot test > ssr test src/button/_example/theme.tsx 1`] = `"
"`; -exports[`ssr snapshot test > ssr test src/cell/_example/base.tsx 1`] = `"

Cell 单元格

一行内容/功能的垂直排列方式。一行项目左侧为主要内容展示区域,右侧可增加更多操作内容

01 类型

单行单元格

单行标题
单行标题 *
单行标题
16
单行标题
单行标题
辅助信息
单行标题

02

多行单元格

单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字

03 组件样式

卡片单元格

单行标题
单行标题
单行标题
"`; +exports[`ssr snapshot test > ssr test src/cell/_example/base.tsx 1`] = `"

Cell 单元格

一行内容/功能的垂直排列方式。一行项目左侧为主要内容展示区域,右侧可增加更多操作内容

01 类型

单行单元格

单行标题
单行标题 *
单行标题
16
单行标题
单行标题
辅助信息
单行标题

02

多行单元格

单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字

03 组件样式

卡片单元格

单行标题
单行标题
单行标题
"`; exports[`ssr snapshot test > ssr test src/cell/_example/group.tsx 1`] = `"
单行标题
单行标题
单行标题
"`; -exports[`ssr snapshot test > ssr test src/cell/_example/multiple.tsx 1`] = `"
单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字
"`; +exports[`ssr snapshot test > ssr test src/cell/_example/multiple.tsx 1`] = `"
单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字
"`; exports[`ssr snapshot test > ssr test src/cell/_example/single.tsx 1`] = `"
单行标题
单行标题 *
单行标题
16
单行标题
单行标题
辅助信息
单行标题
"`; diff --git a/test/snap/__snapshots__/ssr.test.jsx.snap b/test/snap/__snapshots__/ssr.test.jsx.snap index bec660d5..d7d03875 100644 --- a/test/snap/__snapshots__/ssr.test.jsx.snap +++ b/test/snap/__snapshots__/ssr.test.jsx.snap @@ -1,14 +1,30 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`ssr snapshot test > ssr test src/avatar/_example/action.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/badgeAvatar.tsx 1`] = `"
A
8
12
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/characterAvatar.tsx 1`] = `"
A
A
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/exhibition.tsx 1`] = `"
+5
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/iconAvatar.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/imageAvatar.tsx 1`] = `"
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/index.tsx 1`] = `"

Avatar 头像

用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。

01 头像类型

图片头像

字符头像

A
A

图标头像

徽标头像

A
8
12

02 特殊类型

纯展示的头像组

+5

带操作的头像组

03 组件尺寸

组件尺寸

实例图片
A
实例图片
A
实例图片
A
"`; + +exports[`ssr snapshot test > ssr test src/avatar/_example/size.tsx 1`] = `"
实例图片
A
实例图片
A
实例图片
A
"`; + exports[`ssr snapshot test > ssr test src/back-top/_example/base.tsx 1`] = `"
"`; exports[`ssr snapshot test > ssr test src/back-top/_example/index.tsx 1`] = `"

BackTop 返回顶部

当页面过长往下滑动是会出现返回顶部的便捷操作,帮助用户快速回到页面顶部

形状

"`; exports[`ssr snapshot test > ssr test src/badge/_example/base.tsx 1`] = `"
红点徽标
消息
数字徽标
消息
8
2
8
自定义徽标
NEW
"`; -exports[`ssr snapshot test > ssr test src/badge/_example/index.tsx 1`] = `"

Badge 徽标

用于告知用户,该区域的状态变化或者待处理任务的数量。

01 组件类型

红点徽标
消息
数字徽标
消息
8
2
8
自定义徽标
NEW

02 组件样式

圆形徽标
2
方形徽标
2
气泡徽标
领积分
角标
单行标题
New

03 组件尺寸

Large
8
Middle
8
"`; +exports[`ssr snapshot test > ssr test src/badge/_example/index.tsx 1`] = `"

Badge 徽标

用于告知用户,该区域的状态变化或者待处理任务的数量。

01 组件类型

红点徽标
消息
数字徽标
消息
8
2
8
自定义徽标
NEW

02 组件样式

圆形徽标
2
方形徽标
2
气泡徽标
领积分
角标
单行标题
New

03 组件尺寸

Large
8
Middle
8
"`; -exports[`ssr snapshot test > ssr test src/badge/_example/size.tsx 1`] = `"
Large
8
Middle
8
"`; +exports[`ssr snapshot test > ssr test src/badge/_example/size.tsx 1`] = `"
Large
8
Middle
8
"`; exports[`ssr snapshot test > ssr test src/badge/_example/theme.tsx 1`] = `"
圆形徽标
2
方形徽标
2
气泡徽标
领积分
角标
单行标题
New
"`; @@ -34,11 +50,11 @@ exports[`ssr snapshot test > ssr test src/button/_example/test.tsx 1`] = `"
exports[`ssr snapshot test > ssr test src/button/_example/theme.tsx 1`] = `"
"`; -exports[`ssr snapshot test > ssr test src/cell/_example/base.tsx 1`] = `"

Cell 单元格

一行内容/功能的垂直排列方式。一行项目左侧为主要内容展示区域,右侧可增加更多操作内容

01 类型

单行单元格

单行标题
单行标题 *
单行标题
16
单行标题
单行标题
辅助信息
单行标题

02

多行单元格

单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字

03 组件样式

卡片单元格

单行标题
单行标题
单行标题
"`; +exports[`ssr snapshot test > ssr test src/cell/_example/base.tsx 1`] = `"

Cell 单元格

一行内容/功能的垂直排列方式。一行项目左侧为主要内容展示区域,右侧可增加更多操作内容

01 类型

单行单元格

单行标题
单行标题 *
单行标题
16
单行标题
单行标题
辅助信息
单行标题

02

多行单元格

单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字

03 组件样式

卡片单元格

单行标题
单行标题
单行标题
"`; exports[`ssr snapshot test > ssr test src/cell/_example/group.tsx 1`] = `"
单行标题
单行标题
单行标题
"`; -exports[`ssr snapshot test > ssr test src/cell/_example/multiple.tsx 1`] = `"
单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字
"`; +exports[`ssr snapshot test > ssr test src/cell/_example/multiple.tsx 1`] = `"
单行标题
一段很长很长的内容文字
单行标题 *
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
16
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字
辅助信息
单行标题
一段很长很长的内容文字
单行标题
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行高度不定,长文本自动换行,该选项的描述是一段很长的内容
一段很长很长的内容文字,长文本自动换行,该选项的描述是一段很长的内容
多行带头像
一段很长很长的内容文字
多行带图片
一段很长很长的内容文字
"`; exports[`ssr snapshot test > ssr test src/cell/_example/single.tsx 1`] = `"
单行标题
单行标题 *
单行标题
16
单行标题
单行标题
辅助信息
单行标题
"`;