mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
feat: add support to responsive sizes in Avatar component (#26244)
fix lint and test failures update avatar demo card title update ts type check for undefined
This commit is contained in:
parent
a8b4e3c2e5
commit
9101f3666a
@ -1,6 +1,7 @@
|
|||||||
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
|
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
|
||||||
export type BreakpointMap = Partial<Record<Breakpoint, string>>;
|
export type BreakpointMap = Partial<Record<Breakpoint, string>>;
|
||||||
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
|
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
|
||||||
|
export type ScreenSizeMap = Partial<Record<Breakpoint, number>>;
|
||||||
|
|
||||||
export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
||||||
|
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { act } from 'react-dom/test-utils';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
import Avatar from '..';
|
import Avatar from '..';
|
||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
|
import useBreakpoint from '../../grid/hooks/useBreakpoint';
|
||||||
|
|
||||||
|
jest.mock('../../grid/hooks/useBreakpoint');
|
||||||
|
|
||||||
describe('Avatar Render', () => {
|
describe('Avatar Render', () => {
|
||||||
mountTest(Avatar);
|
mountTest(Avatar);
|
||||||
rtlTest(Avatar);
|
rtlTest(Avatar);
|
||||||
|
|
||||||
|
const sizes = { xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 };
|
||||||
let originOffsetWidth;
|
let originOffsetWidth;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
// Mock offsetHeight
|
// Mock offsetHeight
|
||||||
@ -152,6 +158,19 @@ describe('Avatar Render', () => {
|
|||||||
expect(wrapper).toMatchRenderedSnapshot();
|
expect(wrapper).toMatchRenderedSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.entries(sizes).forEach(([key, value]) => {
|
||||||
|
it(`adjusts component size to ${value} when window size is ${key}`, () => {
|
||||||
|
const wrapper = global.document.createElement('div');
|
||||||
|
|
||||||
|
useBreakpoint.mockReturnValue({ [key]: true });
|
||||||
|
act(() => {
|
||||||
|
ReactDOM.render(<Avatar size={sizes} />, wrapper);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('support onMouseEnter', () => {
|
it('support onMouseEnter', () => {
|
||||||
const onMouseEnter = jest.fn();
|
const onMouseEnter = jest.fn();
|
||||||
const wrapper = mount(<Avatar onMouseEnter={onMouseEnter}>TestString</Avatar>);
|
const wrapper = mount(<Avatar onMouseEnter={onMouseEnter}>TestString</Avatar>);
|
||||||
|
@ -1,5 +1,89 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Avatar Render adjusts component size to 24 when window size is xs 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle"
|
||||||
|
style="width: 24px; height: 24px; line-height: 24px; font-size: 18px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-avatar-string"
|
||||||
|
style="transform: scale(0.32) translateX(-50%);"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Avatar Render adjusts component size to 32 when window size is sm 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle"
|
||||||
|
style="width: 32px; height: 32px; line-height: 32px; font-size: 18px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-avatar-string"
|
||||||
|
style="transform: scale(0.32) translateX(-50%);"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Avatar Render adjusts component size to 40 when window size is md 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle"
|
||||||
|
style="width: 40px; height: 40px; line-height: 40px; font-size: 18px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-avatar-string"
|
||||||
|
style="transform: scale(0.32) translateX(-50%);"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Avatar Render adjusts component size to 64 when window size is lg 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle"
|
||||||
|
style="width: 64px; height: 64px; line-height: 64px; font-size: 18px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-avatar-string"
|
||||||
|
style="transform: scale(0.32) translateX(-50%);"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Avatar Render adjusts component size to 80 when window size is xl 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle"
|
||||||
|
style="width: 80px; height: 80px; line-height: 80px; font-size: 18px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-avatar-string"
|
||||||
|
style="transform: scale(0.32) translateX(-50%);"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Avatar Render adjusts component size to 100 when window size is xxl 1`] = `
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle"
|
||||||
|
style="width: 100px; height: 100px; line-height: 100px; font-size: 18px;"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-avatar-string"
|
||||||
|
style="transform: scale(0.32) translateX(-50%);"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`Avatar Render fallback 1`] = `
|
exports[`Avatar Render fallback 1`] = `
|
||||||
<span
|
<span
|
||||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||||
|
@ -469,6 +469,25 @@ Array [
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
|
||||||
|
Array [
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="http://abc.com/not-exist.jpg"
|
||||||
|
/>
|
||||||
|
</span>,
|
||||||
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="http://abc.com/not-exist.jpg"
|
||||||
|
/>
|
||||||
|
</span>,
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/avatar/demo/group.md correctly 1`] = `
|
exports[`renders ./components/avatar/demo/group.md correctly 1`] = `
|
||||||
Array [
|
Array [
|
||||||
<div
|
<div
|
||||||
@ -583,23 +602,31 @@ Array [
|
|||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
|
exports[`renders ./components/avatar/demo/responsive.md correctly 1`] = `
|
||||||
Array [
|
<span
|
||||||
|
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
aria-label="ant-design"
|
||||||
|
class="anticon anticon-ant-design"
|
||||||
|
role="img"
|
||||||
>
|
>
|
||||||
<img
|
<svg
|
||||||
src="http://abc.com/not-exist.jpg"
|
aria-hidden="true"
|
||||||
/>
|
class=""
|
||||||
</span>,
|
data-icon="ant-design"
|
||||||
<span
|
fill="currentColor"
|
||||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
focusable="false"
|
||||||
>
|
height="1em"
|
||||||
<img
|
viewBox="64 64 896 896"
|
||||||
src="http://abc.com/not-exist.jpg"
|
width="1em"
|
||||||
/>
|
>
|
||||||
</span>,
|
<path
|
||||||
]
|
d="M716.3 313.8c19-18.9 19-49.7 0-68.6l-69.9-69.9.1.1c-18.5-18.5-50.3-50.3-95.3-95.2-21.2-20.7-55.5-20.5-76.5.5L80.9 474.2a53.84 53.84 0 000 76.4L474.6 944a54.14 54.14 0 0076.5 0l165.1-165c19-18.9 19-49.7 0-68.6a48.7 48.7 0 00-68.7 0l-125 125.2c-5.2 5.2-13.3 5.2-18.5 0L189.5 521.4c-5.2-5.2-5.2-13.3 0-18.5l314.4-314.2c.4-.4.9-.7 1.3-1.1 5.2-4.1 12.4-3.7 17.2 1.1l125.2 125.1c19 19 49.8 19 68.7 0zM408.6 514.4a106.3 106.2 0 10212.6 0 106.3 106.2 0 10-212.6 0zm536.2-38.6L821.9 353.5c-19-18.9-49.8-18.9-68.7.1a48.4 48.4 0 000 68.6l83 82.9c5.2 5.2 5.2 13.3 0 18.5l-81.8 81.7a48.4 48.4 0 000 68.6 48.7 48.7 0 0068.7 0l121.8-121.7a53.93 53.93 0 00-.1-76.4z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = `
|
||||||
|
@ -4,6 +4,8 @@ import classNames from 'classnames';
|
|||||||
import { ConfigContext } from '../config-provider';
|
import { ConfigContext } from '../config-provider';
|
||||||
import devWarning from '../_util/devWarning';
|
import devWarning from '../_util/devWarning';
|
||||||
import { composeRef } from '../_util/ref';
|
import { composeRef } from '../_util/ref';
|
||||||
|
import { Breakpoint, responsiveArray, ScreenSizeMap } from '../_util/responsiveObserve';
|
||||||
|
import useBreakpoint from '../grid/hooks/useBreakpoint';
|
||||||
|
|
||||||
export interface AvatarProps {
|
export interface AvatarProps {
|
||||||
/** Shape of avatar, options:`circle`, `square` */
|
/** Shape of avatar, options:`circle`, `square` */
|
||||||
@ -12,7 +14,7 @@ export interface AvatarProps {
|
|||||||
* Size of avatar, options: `large`, `small`, `default`
|
* Size of avatar, options: `large`, `small`, `default`
|
||||||
* or a custom number size
|
* or a custom number size
|
||||||
* */
|
* */
|
||||||
size?: 'large' | 'small' | 'default' | number;
|
size?: 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||||
gap?: number;
|
gap?: number;
|
||||||
/** Src of image avatar */
|
/** Src of image avatar */
|
||||||
src?: string;
|
src?: string;
|
||||||
@ -109,6 +111,25 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
|||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const screens = useBreakpoint();
|
||||||
|
const responsiveSizeStyle: React.CSSProperties = React.useMemo(() => {
|
||||||
|
if (typeof size !== 'object') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentBreakpoint: Breakpoint = responsiveArray.find(screen => screens[screen])!;
|
||||||
|
const currentSize = size[currentBreakpoint];
|
||||||
|
|
||||||
|
return currentSize
|
||||||
|
? {
|
||||||
|
width: currentSize,
|
||||||
|
height: currentSize,
|
||||||
|
lineHeight: `${currentSize}px`,
|
||||||
|
fontSize: icon ? currentSize / 2 : 18,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
}, [screens, size]);
|
||||||
|
|
||||||
devWarning(
|
devWarning(
|
||||||
!(typeof icon === 'string' && icon.length > 2),
|
!(typeof icon === 'string' && icon.length > 2),
|
||||||
'Avatar',
|
'Avatar',
|
||||||
@ -193,7 +214,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
|||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
{...others}
|
{...others}
|
||||||
style={{ ...sizeStyle, ...others.style }}
|
style={{ ...sizeStyle, ...responsiveSizeStyle, ...others.style }}
|
||||||
className={classString}
|
className={classString}
|
||||||
ref={avatarNodeMergeRef as any}
|
ref={avatarNodeMergeRef as any}
|
||||||
>
|
>
|
||||||
|
27
components/avatar/demo/responsive.md
Normal file
27
components/avatar/demo/responsive.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
order: 5
|
||||||
|
title:
|
||||||
|
zh-CN: 响应式尺寸
|
||||||
|
en-US: Responsive Size
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
头像大小可以根据屏幕大小自动调整。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
Avatar size can be automatically adjusted based on the screen size.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { Avatar } from 'antd';
|
||||||
|
import { AntDesignOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<Avatar
|
||||||
|
size={{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }}
|
||||||
|
icon={<AntDesignOutlined />}
|
||||||
|
/>,
|
||||||
|
mountNode,
|
||||||
|
);
|
||||||
|
```
|
@ -15,7 +15,7 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| icon | Custom icon type for an icon avatar | ReactNode | - | |
|
| icon | Custom icon type for an icon avatar | ReactNode | - | |
|
||||||
| shape | The shape of avatar | `circle` \| `square` | `circle` | |
|
| shape | The shape of avatar | `circle` \| `square` | `circle` | |
|
||||||
| size | The size of the avatar | number \| `large` \| `small` \| `default` | `default` | |
|
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| `{ xs: number, sm: number, ...}` | `default` | 4.7.0 |
|
||||||
| src | The address of the image for an image avatar | string | - | |
|
| src | The address of the image for an image avatar | string | - | |
|
||||||
| srcSet | A list of sources to use for different screen resolutions | string | - | |
|
| srcSet | A list of sources to use for different screen resolutions | string | - | |
|
||||||
| alt | This attribute defines the alternative text describing the image | string | - | |
|
| alt | This attribute defines the alternative text describing the image | string | - | |
|
||||||
|
@ -20,7 +20,7 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/aBcnbw68hP/Avatar.svg
|
|||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| icon | 设置头像的自定义图标 | ReactNode | - | |
|
| icon | 设置头像的自定义图标 | ReactNode | - | |
|
||||||
| shape | 指定头像的形状 | `circle` \| `square` | `circle` | |
|
| shape | 指定头像的形状 | `circle` \| `square` | `circle` | |
|
||||||
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` | `default` | |
|
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| `{ xs: number, sm: number, ...}` | `default` | 4.7.0 |
|
||||||
| src | 图片类头像的资源地址 | string | - | |
|
| src | 图片类头像的资源地址 | string | - | |
|
||||||
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
|
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
|
||||||
| alt | 图像无法显示时的替代文本 | string | - | |
|
| alt | 图像无法显示时的替代文本 | string | - | |
|
||||||
|
@ -2,4 +2,5 @@ import '../../style/index.less';
|
|||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
// style dependencies
|
// style dependencies
|
||||||
|
// deps-lint-skip: grid
|
||||||
import '../../popover/style';
|
import '../../popover/style';
|
||||||
|
Loading…
Reference in New Issue
Block a user