diff --git a/components/_util/responsiveObserve.ts b/components/_util/responsiveObserve.ts index b4b7446648..d2da1decd0 100644 --- a/components/_util/responsiveObserve.ts +++ b/components/_util/responsiveObserve.ts @@ -1,6 +1,7 @@ export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs'; export type BreakpointMap = Partial>; export type ScreenMap = Partial>; +export type ScreenSizeMap = Partial>; export const responsiveArray: Breakpoint[] = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs']; diff --git a/components/avatar/__tests__/Avatar.test.js b/components/avatar/__tests__/Avatar.test.js index 714029b810..962232b37d 100644 --- a/components/avatar/__tests__/Avatar.test.js +++ b/components/avatar/__tests__/Avatar.test.js @@ -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(, wrapper); + }); + + expect(wrapper).toMatchSnapshot(); + }); + }); + it('support onMouseEnter', () => { const onMouseEnter = jest.fn(); const wrapper = mount(TestString); diff --git a/components/avatar/__tests__/__snapshots__/Avatar.test.js.snap b/components/avatar/__tests__/__snapshots__/Avatar.test.js.snap index 82b960d2a6..a72b772f08 100644 --- a/components/avatar/__tests__/__snapshots__/Avatar.test.js.snap +++ b/components/avatar/__tests__/__snapshots__/Avatar.test.js.snap @@ -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`] = ` +
+ + + +
+`; + +exports[`Avatar Render adjusts component size to 32 when window size is sm 1`] = ` +
+ + + +
+`; + +exports[`Avatar Render adjusts component size to 40 when window size is md 1`] = ` +
+ + + +
+`; + +exports[`Avatar Render adjusts component size to 64 when window size is lg 1`] = ` +
+ + + +
+`; + +exports[`Avatar Render adjusts component size to 80 when window size is xl 1`] = ` +
+ + + +
+`; + +exports[`Avatar Render adjusts component size to 100 when window size is xxl 1`] = ` +
+ + + +
+`; + exports[`Avatar Render fallback 1`] = ` + + , + + + , +] +`; + exports[`renders ./components/avatar/demo/group.md correctly 1`] = ` Array [
- - , - - - , -] + + + `; exports[`renders ./components/avatar/demo/toggle-debug.md correctly 1`] = ` diff --git a/components/avatar/avatar.tsx b/components/avatar/avatar.tsx index 8f6f86344b..41b6b7e0af 100644 --- a/components/avatar/avatar.tsx +++ b/components/avatar/avatar.tsx @@ -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 = (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 = (pr return ( diff --git a/components/avatar/demo/responsive.md b/components/avatar/demo/responsive.md new file mode 100644 index 0000000000..5c12da64fc --- /dev/null +++ b/components/avatar/demo/responsive.md @@ -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( + } + />, + mountNode, +); +``` diff --git a/components/avatar/index.en-US.md b/components/avatar/index.en-US.md index 89b1487ea8..31db6d84a8 100644 --- a/components/avatar/index.en-US.md +++ b/components/avatar/index.en-US.md @@ -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 | - | | diff --git a/components/avatar/index.zh-CN.md b/components/avatar/index.zh-CN.md index 13ff9ff426..5841856892 100644 --- a/components/avatar/index.zh-CN.md +++ b/components/avatar/index.zh-CN.md @@ -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 | - | | diff --git a/components/avatar/style/index.tsx b/components/avatar/style/index.tsx index aada6bd0ff..dccbd8457c 100644 --- a/components/avatar/style/index.tsx +++ b/components/avatar/style/index.tsx @@ -2,4 +2,5 @@ import '../../style/index.less'; import './index.less'; // style dependencies +// deps-lint-skip: grid import '../../popover/style';