feat: Avatar.Group adding max props (#49131)

* feat: Avatar.Group adding max props

* feat: update

* feat: update

* feat: update test case

* feat: update docs

* Update components/avatar/index.en-US.md

Co-authored-by: afc163 <afc163@gmail.com>
Signed-off-by: Wanpan <wanpan96@163.com>

* feat: update docs

* feat: update

* feat: update snap

* feat: delete default value

---------

Signed-off-by: Wanpan <wanpan96@163.com>
Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
Wanpan 2024-06-01 14:44:53 +08:00 committed by GitHub
parent ab7ac623cb
commit 8875ca7043
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 150 additions and 31 deletions

View File

@ -3,7 +3,7 @@ import React, { useState } from 'react';
import Avatar from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render } from '../../../tests/utils';
import { fireEvent, render, waitFakeTimer } from '../../../tests/utils';
import ConfigProvider from '../../config-provider';
import useBreakpoint from '../../grid/hooks/useBreakpoint';
@ -222,4 +222,83 @@ describe('Avatar Render', () => {
expect(container.querySelector('.ant-avatar-sm')).toBeTruthy();
expect(container.querySelector('.ant-avatar-lg')).toBeTruthy();
});
it('Avatar.Group support max series props and prompt to deprecated', async () => {
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
jest.useFakeTimers();
const { container } = render(
<Avatar.Group maxCount={2} maxStyle={{ color: 'blue' }} maxPopoverPlacement="bottom">
<Avatar>A</Avatar>
<Avatar>B</Avatar>
<Avatar>C</Avatar>
<Avatar>D</Avatar>
</Avatar.Group>,
);
const avatars = container?.querySelectorAll<HTMLSpanElement>('.ant-avatar-group .ant-avatar');
fireEvent.mouseEnter(avatars?.[2]);
await waitFakeTimer();
/* check style */
expect(container.querySelector('.ant-popover-open')).toBeTruthy();
expect(container.querySelector('.ant-popover-open')).toHaveStyle('color: blue');
/* check count */
expect(avatars.length).toBe(3);
/* check popover */
const popover = container.querySelector('.ant-avatar-group-popover');
expect(popover).toBeTruthy();
expect(popover).toHaveClass('ant-popover-placement-bottom');
expect(errSpy).toHaveBeenNthCalledWith(
1,
'Warning: [antd: Avatar.Group] `maxCount` is deprecated. Please use `max={{ count: number }}` instead.',
);
expect(errSpy).toHaveBeenNthCalledWith(
2,
'Warning: [antd: Avatar.Group] `maxStyle` is deprecated. Please use `max={{ style: CSSProperties }}` instead.',
);
expect(errSpy).toHaveBeenNthCalledWith(
3,
'Warning: [antd: Avatar.Group] `maxPopoverPlacement` is deprecated. Please use `max={{ popover: PopoverProps }}` instead.',
);
});
it('Avatar.Group support max object props', () => {
const { container } = render(
<Avatar.Group
max={{
count: 2,
popover: {
placement: 'bottomRight',
overlayClassName: 'wanpan-111',
overlayStyle: { background: 'red' },
content: 'Avatar.Group',
open: true,
},
style: {
color: 'blue',
},
}}
>
<Avatar>A</Avatar>
<Avatar>B</Avatar>
<Avatar>C</Avatar>
<Avatar>D</Avatar>
</Avatar.Group>,
);
/* check count */
expect(container.querySelectorAll('.ant-avatar-group .ant-avatar').length).toBe(3);
/* check popover */
const popover = container.querySelector('.ant-avatar-group-popover');
expect(popover).toBeTruthy();
expect(popover).toHaveStyle('background: red');
expect(popover).toHaveClass('wanpan-111 ant-popover-placement-bottomRight');
expect(container.querySelector('.ant-popover-inner-content')).toHaveTextContent('Avatar.Group');
/* check style */
expect(container.querySelector('.ant-popover-open')).toHaveStyle('color: blue');
});
});

View File

@ -7,7 +7,7 @@ demoTest('avatar');
rootPropsTest(
'avatar',
(Avatar, props) => (
<Avatar.Group {...props} maxCount={1}>
<Avatar.Group {...props} max={{ count: 1 }}>
<Avatar>Bamboo</Avatar>
<Avatar>Light</Avatar>
</Avatar.Group>

View File

@ -28,7 +28,12 @@ const App: React.FC = () => (
</Avatar>
</Space>
<Space>
<Avatar.Group maxCount={2} maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>
<Avatar.Group
max={{
count: 2,
style: { color: '#f56a00', backgroundColor: '#fde3cf' },
}}
>
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=2" />
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
<Tooltip title="Ant User" placement="top">

View File

@ -15,7 +15,12 @@ const App: React.FC = () => (
<Avatar style={{ backgroundColor: '#1677ff' }} icon={<AntDesignOutlined />} />
</Avatar.Group>
<Divider />
<Avatar.Group maxCount={2} maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}>
<Avatar.Group
max={{
count: 2,
style: { color: '#f56a00', backgroundColor: '#fde3cf' },
}}
>
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=2" />
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
<Tooltip title="Ant User" placement="top">
@ -25,9 +30,11 @@ const App: React.FC = () => (
</Avatar.Group>
<Divider />
<Avatar.Group
maxCount={2}
size="large"
maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf' }}
max={{
count: 2,
style: { color: '#f56a00', backgroundColor: '#fde3cf' },
}}
>
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=3" />
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>
@ -38,10 +45,12 @@ const App: React.FC = () => (
</Avatar.Group>
<Divider />
<Avatar.Group
maxCount={2}
maxPopoverTrigger="click"
size="large"
maxStyle={{ color: '#f56a00', backgroundColor: '#fde3cf', cursor: 'pointer' }}
max={{
count: 2,
style: { color: '#f56a00', backgroundColor: '#fde3cf', cursor: 'pointer' },
popover: { trigger: 'click' },
}}
>
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
<Avatar style={{ backgroundColor: '#f56a00' }}>K</Avatar>

View File

@ -3,8 +3,10 @@ import classNames from 'classnames';
import toArray from 'rc-util/lib/Children/toArray';
import { cloneElement } from '../_util/reactNode';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import type { PopoverProps } from '../popover';
import Popover from '../popover';
import Avatar from './avatar';
import AvatarContext from './AvatarContext';
@ -32,10 +34,19 @@ export interface GroupProps {
children?: React.ReactNode;
style?: React.CSSProperties;
prefixCls?: string;
/** @deprecated Please use `max={{ count: number }}` */
maxCount?: number;
/** @deprecated Please use `max={{ style: CSSProperties }}` */
maxStyle?: React.CSSProperties;
/** @deprecated Please use `max={{ popover: PopoverProps }}` */
maxPopoverPlacement?: 'top' | 'bottom';
/** @deprecated Please use `max={{ popover: PopoverProps }}` */
maxPopoverTrigger?: 'hover' | 'focus' | 'click';
max?: {
count?: number;
style?: React.CSSProperties;
popover?: PopoverProps;
};
/*
* Size of avatar, options: `large`, `small`, `default`
* or a custom number size
@ -55,11 +66,24 @@ const Group: React.FC<GroupProps> = (props) => {
maxStyle,
size,
shape,
maxPopoverPlacement = 'top',
maxPopoverTrigger = 'hover',
maxPopoverPlacement,
maxPopoverTrigger,
children,
max,
} = props;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Avatar.Group');
warning.deprecated(!maxCount, 'maxCount', 'max={{ count: number }}');
warning.deprecated(!maxStyle, 'maxStyle', 'max={{ style: CSSProperties }}');
warning.deprecated(
!maxPopoverPlacement,
'maxPopoverPlacement',
'max={{ popover: PopoverProps }}',
);
warning.deprecated(!maxPopoverTrigger, 'maxPopoverTrigger', 'max={{ popover: PopoverProps }}');
}
const prefixCls = getPrefixCls('avatar', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
const rootCls = useCSSVarCls(prefixCls);
@ -81,22 +105,30 @@ const Group: React.FC<GroupProps> = (props) => {
cloneElement(child, { key: `avatar-key-${index}` }),
);
const mergeCount = max?.count || maxCount;
const numOfChildren = childrenWithProps.length;
if (maxCount && maxCount < numOfChildren) {
const childrenShow = childrenWithProps.slice(0, maxCount);
const childrenHidden = childrenWithProps.slice(maxCount, numOfChildren);
if (mergeCount && mergeCount < numOfChildren) {
const childrenShow = childrenWithProps.slice(0, mergeCount);
const childrenHidden = childrenWithProps.slice(mergeCount, numOfChildren);
const mergeStyle = max?.style || maxStyle;
const mergePopoverTrigger = max?.popover?.trigger || maxPopoverTrigger || 'hover';
const mergePopoverPlacement = max?.popover?.placement || maxPopoverPlacement || 'top';
const mergeProps = {
content: childrenHidden,
...max?.popover,
overlayClassName: classNames(`${groupPrefixCls}-popover`, max?.popover?.overlayClassName),
placement: mergePopoverPlacement,
trigger: mergePopoverTrigger,
};
childrenShow.push(
<Popover
key="avatar-popover-key"
content={childrenHidden}
trigger={maxPopoverTrigger}
placement={maxPopoverPlacement}
overlayClassName={`${groupPrefixCls}-popover`}
destroyTooltipOnHide
>
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar>
<Popover key="avatar-popover-key" destroyTooltipOnHide {...mergeProps}>
<Avatar style={mergeStyle}>{`+${numOfChildren - mergeCount}`}</Avatar>
</Popover>,
);
return wrapCSSVar(
<AvatarContextProvider shape={shape} size={size}>
<div className={cls} style={style}>

View File

@ -49,10 +49,7 @@ Common props ref[Common props](/docs/react/common-props)
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| maxCount | Max avatars to show | number | - | |
| maxPopoverPlacement | The placement of excess avatar Popover | `top` \| `bottom` | `top` | |
| maxPopoverTrigger | Set the trigger of excess avatar Popover | `hover` \| `focus` \| `click` | `hover` | 4.17.0 |
| maxStyle | The style of excess avatar style | CSSProperties | - | |
| max | Set maximum display related configurations, Before `5.18.0` you can use [parameters](https://github.com/ant-design/ant-design/blob/9d134859becbdae5b9ce276f6d9af4264691d81f/components/avatar/group.tsx#L35-L38) | `{ count?: number; style?: CSSProperties; popover?: PopoverProps }` | - | 5.18.0 |
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.8.0 |
| shape | The shape of the avatar | `circle` \| `square` | `circle` | 5.8.0 |

View File

@ -54,10 +54,7 @@ group:
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| maxCount | 显示的最大头像个数 | number | - | |
| maxPopoverPlacement | 多余头像气泡弹出位置 | `top` \| `bottom` | `top` | |
| maxPopoverTrigger | 设置多余头像 Popover 的触发方式 | `hover` \| `focus` \| `click` | `hover` | 4.17.0 |
| maxStyle | 多余头像样式 | CSSProperties | - | |
| max | 设置最多显示相关配置,`5.18.0` 前可使用 [参数](https://github.com/ant-design/ant-design/blob/9d134859becbdae5b9ce276f6d9af4264691d81f/components/avatar/group.tsx#L35-L38) | `{ count?: number; style?: CSSProperties; popover?: PopoverProps }` | - | 5.18.0 |
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | 4.8.0 |
| shape | 设置头像的形状 | `circle` \| `square` | `circle` | 5.8.0 |