mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +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 BreakpointMap = Partial<Record<Breakpoint, string>>;
|
||||
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
|
||||
export type ScreenSizeMap = Partial<Record<Breakpoint, number>>;
|
||||
|
||||
export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
||||
|
||||
|
@ -1,13 +1,19 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from 'enzyme';
|
||||
import Avatar from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import useBreakpoint from '../../grid/hooks/useBreakpoint';
|
||||
|
||||
jest.mock('../../grid/hooks/useBreakpoint');
|
||||
|
||||
describe('Avatar Render', () => {
|
||||
mountTest(Avatar);
|
||||
rtlTest(Avatar);
|
||||
|
||||
const sizes = { xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 };
|
||||
let originOffsetWidth;
|
||||
beforeAll(() => {
|
||||
// Mock offsetHeight
|
||||
@ -152,6 +158,19 @@ describe('Avatar Render', () => {
|
||||
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', () => {
|
||||
const onMouseEnter = jest.fn();
|
||||
const wrapper = mount(<Avatar onMouseEnter={onMouseEnter}>TestString</Avatar>);
|
||||
|
@ -1,5 +1,89 @@
|
||||
// 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`] = `
|
||||
<span
|
||||
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`] = `
|
||||
Array [
|
||||
<div
|
||||
@ -583,23 +602,31 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
|
||||
Array [
|
||||
exports[`renders ./components/avatar/demo/responsive.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-icon"
|
||||
>
|
||||
<span
|
||||
class="ant-avatar ant-avatar-circle ant-avatar-image"
|
||||
aria-label="ant-design"
|
||||
class="anticon anticon-ant-design"
|
||||
role="img"
|
||||
>
|
||||
<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>,
|
||||
]
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class=""
|
||||
data-icon="ant-design"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<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`] = `
|
||||
|
@ -4,6 +4,8 @@ import classNames from 'classnames';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import { composeRef } from '../_util/ref';
|
||||
import { Breakpoint, responsiveArray, ScreenSizeMap } from '../_util/responsiveObserve';
|
||||
import useBreakpoint from '../grid/hooks/useBreakpoint';
|
||||
|
||||
export interface AvatarProps {
|
||||
/** Shape of avatar, options:`circle`, `square` */
|
||||
@ -12,7 +14,7 @@ export interface AvatarProps {
|
||||
* Size of avatar, options: `large`, `small`, `default`
|
||||
* or a custom number size
|
||||
* */
|
||||
size?: 'large' | 'small' | 'default' | number;
|
||||
size?: 'large' | 'small' | 'default' | number | ScreenSizeMap;
|
||||
gap?: number;
|
||||
/** Src of image avatar */
|
||||
src?: string;
|
||||
@ -109,6 +111,25 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
...others
|
||||
} = 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(
|
||||
!(typeof icon === 'string' && icon.length > 2),
|
||||
'Avatar',
|
||||
@ -193,7 +214,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (pr
|
||||
return (
|
||||
<span
|
||||
{...others}
|
||||
style={{ ...sizeStyle, ...others.style }}
|
||||
style={{ ...sizeStyle, ...responsiveSizeStyle, ...others.style }}
|
||||
className={classString}
|
||||
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 | - | |
|
||||
| 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 | - | |
|
||||
| srcSet | A list of sources to use for different screen resolutions | 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 | - | |
|
||||
| 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 | - | |
|
||||
| srcSet | 设置图片类头像响应式资源地址 | string | - | |
|
||||
| alt | 图像无法显示时的替代文本 | string | - | |
|
||||
|
@ -2,4 +2,5 @@ import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// style dependencies
|
||||
// deps-lint-skip: grid
|
||||
import '../../popover/style';
|
||||
|
Loading…
Reference in New Issue
Block a user