chore: merge master

This commit is contained in:
二货机器人 2022-09-07 10:35:16 +08:00
commit 1cad665d15
20 changed files with 263 additions and 197 deletions

View File

@ -30,7 +30,7 @@ timeline: true
- 🛠 Table changes `filterDropdownVisible` to `filterDropdownOpen`. [#37026](https://github.com/ant-design/ant-design/pull/37026) [@yykoypj](https://github.com/yykoypj)
- 🛠 Slider add `tooltip` prop for all props related with Tooltip. [#37000](https://github.com/ant-design/ant-design/pull/37000) [@yykoypj](https://github.com/yykoypj)
- 🛠 Tooltip Popover and Popconfirm change `visible` to `open`. [#37241](https://github.com/ant-design/ant-design/pull/37241) [@yykoypj](https://github.com/yykoypj)
- 🛠 Remove `visible` prop of Tag. [#36934](https://github.com/ant-design/ant-design/pull/36934) [@yykoypj](https://github.com/yykoypj)
- 🛠 Deprecate `visible` prop of Tag. [#36934](https://github.com/ant-design/ant-design/pull/36934) [@yykoypj](https://github.com/yykoypj)
- 🛠 Deprecate `dropdownClassName` prop of all components and change to `popupClassName`. [#36880](https://github.com/ant-design/ant-design/pull/36880) [@heiyu4585](https://github.com/heiyu4585)
- 🛠 Tabs support `items` props and origin jsx usage will be depreacted. [#36889](https://github.com/ant-design/ant-design/pull/36889)
- 🐞 Fix that some css variables are not consistent with less variables.

View File

@ -30,7 +30,7 @@ timeline: true
- 🛠 Table 组件 `columns` 中的 `filterDropdownVisible` 改为 `filterDropdownOpen`。[#37026](https://github.com/ant-design/ant-design/pull/37026) [@yykoypj](https://github.com/yykoypj)
- 🛠 Tooltip, Popover 和 Popconfirm 中的 `visible` 改为 `open`。[#37241](https://github.com/ant-design/ant-design/pull/37241) [@yykoypj](https://github.com/yykoypj)
- 🛠 Slider 的 `tooltip` 相关属性合并到 `tooltip` 属性中。[#37000](https://github.com/ant-design/ant-design/pull/37000) [@yykoypj](https://github.com/yykoypj)
- 🛠 移除 Tag 组件的 `visible` 属性。[#36934](https://github.com/ant-design/ant-design/pull/36934) [@yykoypj](https://github.com/yykoypj)
- 🛠 废弃 Tag 组件的 `visible` 属性。[#36934](https://github.com/ant-design/ant-design/pull/36934) [@yykoypj](https://github.com/yykoypj)
- 🛠 废弃所有组件的 `dropdownClassName`,统一为 `popupClassName`。[#36880](https://github.com/ant-design/ant-design/pull/36880) [@heiyu4585](https://github.com/heiyu4585)
- 🛠 Tabs 支持 `items` 属性,并且废弃原 jsx 语法糖用法。[#36889](https://github.com/ant-design/ant-design/pull/36889)
- 🐞 修复 css 变量与 less 变量不一致的问题。

View File

@ -141,7 +141,7 @@ describe('Affix Render', () => {
describe('updatePosition when target changed', () => {
it('function change', async () => {
document.body.innerHTML = '<div id="mounter" />';
const container = document.querySelector('#id') as HTMLDivElement;
const container = document.getElementById('mounter');
const getTarget = () => container;
let affixInstance: InternalAffixClass;
const { rerender } = render(

View File

@ -25,6 +25,33 @@ export interface BackTopProps {
visible?: boolean; // Only for test. Don't use it.
}
interface ChildrenProps {
prefixCls: string;
rootPrefixCls: string;
children?: React.ReactNode;
visible?: boolean; // Only for test. Don't use it.
}
const BackTopContent: React.FC<ChildrenProps> = props => {
const { prefixCls, rootPrefixCls, children, visible } = props;
const defaultElement = (
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-icon`}>
<VerticalAlignTopOutlined />
</div>
</div>
);
return (
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
{({ className: motionClassName }) =>
cloneElement(children || defaultElement, ({ className }) => ({
className: classNames(motionClassName, className),
}))
}
</CSSMotion>
);
};
const BackTop: React.FC<BackTopProps> = props => {
const [visible, setVisible] = useMergedState(false, {
value: props.visible,
@ -51,9 +78,7 @@ const BackTop: React.FC<BackTopProps> = props => {
scrollEvent.current = addEventListener(container, 'scroll', (e: React.UIEvent<HTMLElement>) => {
handleScroll(e);
});
handleScroll({
target: container,
});
handleScroll({ target: container });
};
React.useEffect(() => {
@ -62,7 +87,7 @@ const BackTop: React.FC<BackTopProps> = props => {
if (scrollEvent.current) {
scrollEvent.current.remove();
}
(handleScroll as any).cancel();
handleScroll.cancel();
};
}, [props.target]);
@ -77,32 +102,6 @@ const BackTop: React.FC<BackTopProps> = props => {
}
};
const renderChildren = ({
prefixCls,
rootPrefixCls,
}: {
prefixCls: string;
rootPrefixCls: string;
}) => {
const { children } = props;
const defaultElement = (
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-icon`}>
<VerticalAlignTopOutlined />
</div>
</div>
);
return (
<CSSMotion visible={visible} motionName={`${rootPrefixCls}-fade`}>
{({ className: motionClassName }) =>
cloneElement(children || defaultElement, ({ className }) => ({
className: classNames(motionClassName, className),
}))
}
</CSSMotion>
);
};
const { getPrefixCls, direction } = React.useContext(ConfigContext);
const { prefixCls: customizePrefixCls, className = '' } = props;
const prefixCls = getPrefixCls('back-top', customizePrefixCls);
@ -130,7 +129,9 @@ const BackTop: React.FC<BackTopProps> = props => {
return wrapSSR(
<div {...divProps} className={classString} onClick={scrollToTop} ref={ref}>
{renderChildren({ prefixCls, rootPrefixCls })}
<BackTopContent prefixCls={prefixCls} rootPrefixCls={rootPrefixCls} visible={visible}>
{props.children}
</BackTopContent>
</div>,
);
};

View File

@ -48,7 +48,7 @@ A Drawer is a panel that is typically overlaid on top of a page and slides in fr
| style | Style of Drawer panel. Use `bodyStyle` if want to config body only | CSSProperties | - | |
| size | presetted size of drawer, default `378px` and large `736px` | 'default' \| 'large' | 'default' | 4.17.0 |
| title | The title for Drawer | ReactNode | - | |
<<<<<<< HEAD | open | Whether the Drawer dialog is visible or not | boolean | false | | ======= | open | Whether the Drawer dialog is visible or not | boolean | false | 4.23.0 |
> > > > > > > feature | width | Width of the Drawer dialog | string \| number | 378 | | | zIndex | The `z-index` of the Drawer | number | 1000 | | | onClose | Specify a callback that will be called when a user clicks mask, close button or Cancel button | function(e) | - | |
| open | Whether the Drawer dialog is visible or not | boolean | false | |
| width | Width of the Drawer dialog | string \| number | 378 | |
| zIndex | The `z-index` of the Drawer | number | 1000 | |
| onClose | Specify a callback that will be called when a user clicks mask, close button or Cancel button | function(e) | - | |

View File

@ -47,7 +47,7 @@ cover: https://img.alicdn.com/imgextra/i4/O1CN019djdZP1OHwXSRGCOW_!!600000000168
| size | 预设抽屉宽度或高度default `378px` 和 large `736px` | 'default' \| 'large' | 'default' | 4.17.0 |
| style | 设计 Drawer 容器样式,如果你只需要设置内容部分请使用 `bodyStyle` | CSSProperties | - | |
| title | 标题 | ReactNode | - | |
<<<<<<< HEAD | open | Drawer 是否可见 | boolean | - | | ======= | open | Drawer 是否可见 | boolean | - | 4.23.0 |
> > > > > > > feature | width | 宽度 | string \| number | 378 | | | zIndex | 设置 Drawer 的 `z-index` | number | 1000 | | | onClose | 点击遮罩层或左上角叉或取消按钮的回调 | function(e) | - | |
| open | Drawer 是否可见 | boolean | - |
| width | 宽度 | string \| number | 378 | |
| zIndex | 设置 Drawer 的 `z-index` | number | 1000 | |
| onClose | 点击遮罩层或左上角叉或取消按钮的回调 | function(e) | - | |

View File

@ -27,8 +27,8 @@ When there are more than a few options to choose from, you can wrap them in a `D
| overlayStyle | The style of the dropdown root element | CSSProperties | - | |
| placement | Placement of popup menu: `bottom` `bottomLeft` `bottomRight` `top` `topLeft` `topRight` | string | `bottomLeft` | |
| trigger | The trigger mode which executes the dropdown action. Note that hover can't be used on touchscreens | Array&lt;`click`\|`hover`\|`contextMenu`> | \[`hover`] | |
| open | Whether the dropdown menu is currently open | boolean | - | 4.23.0 |
| onOpenChange | Called when the open state is changed. Not trigger when hidden by click item | (open: boolean) => void | - | 4.23.0 |
| open | Whether the dropdown menu is currently open. Use `visible` under 4.23.0 ([why?](/docs/react/faq#why-open)) | boolean | - | 4.23.0 |
| onOpenChange | Called when the open state is changed. Not trigger when hidden by click item. Use `onVisibleChange` under 4.23.0 ([why?](/docs/react/faq#why-open)) | (open: boolean) => void | - | 4.23.0 |
You should use [Menu](/components/menu/) as `overlay`. The menu items and dividers are also available by using `Menu.Item` and `Menu.Divider`.

View File

@ -31,8 +31,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
| overlayStyle | 下拉根元素的样式 | CSSProperties | - | |
| placement | 菜单弹出位置:`bottom` `bottomLeft` `bottomRight` `top` `topLeft` `topRight` | string | `bottomLeft` | |
| trigger | 触发下拉的行为, 移动端不支持 hover | Array&lt;`click`\|`hover`\|`contextMenu`> | \[`hover`] | |
| open | 菜单是否显示 | boolean | - | 4.23.0 |
| onOpenChange | 菜单显示状态改变时调用,参数为 `visible`点击菜单按钮导致的消失不会触发 | (open: boolean) => void | - | 4.23.0 |
| open | 菜单是否显示,小于 4.23.0 使用 `visible`[为什么?](/docs/react/faq#why-open) | boolean | - | 4.23.0 |
| onOpenChange | 菜单显示状态改变时调用,点击菜单按钮导致的消失不会触发。小于 4.23.0 使用 `onVisibleChange`[为什么?](/docs/react/faq#why-open) | (open: boolean) => void | - | 4.23.0 |
`overlay` 菜单使用 [Menu](/components/menu/),还包括菜单项 `Menu.Item`,分割线 `Menu.Divider`
@ -56,4 +56,4 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
| type | 按钮类型,和 [Button](/components/button/#API) 一致 | string | `default` | |
| open | 菜单是否显示 | boolean | - | 4.23.0 |
| onClick | 点击左侧按钮的回调,和 [Button](/components/button/#API) 一致 | (event) => void | - | |
| onOpenChange | 菜单显示状态改变时调用,参数为 `visible` | (open: boolean) => void | - | 4.23.0 |
| onOpenChange | 菜单显示状态改变时调用 | (open: boolean) => void | - | 4.23.0 |

View File

@ -18,7 +18,7 @@ import { Button, InputNumber, Space } from 'antd';
import React, { useState } from 'react';
const App: React.FC = () => {
const [value, setValue] = useState<string | number>('99');
const [value, setValue] = useState<string | number | null>('99');
return (
<Space>

View File

@ -3,6 +3,7 @@ import UpOutlined from '@ant-design/icons/UpOutlined';
import classNames from 'classnames';
import type { InputNumberProps as RcInputNumberProps } from 'rc-input-number';
import RcInputNumber from 'rc-input-number';
import type { ValueType } from 'rc-input-number/lib/utils/MiniDecimal';
import * as React from 'react';
import { useContext } from 'react';
import { ConfigContext } from '../config-provider';
@ -15,8 +16,6 @@ import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import useStyle from './style';
type ValueType = string | number;
export interface InputNumberProps<T extends ValueType = ValueType>
extends Omit<RcInputNumberProps<T>, 'prefix' | 'size' | 'controls'> {
prefixCls?: string;

View File

@ -10,7 +10,7 @@ describe('Result', () => {
rtlTest(Result);
it('🙂 successPercent should decide the progress status when it exists', () => {
const { container: wrapper } = render(
const { container } = render(
<Result
status="success"
title="Successfully Purchased Cloud Server ECS!"
@ -23,37 +23,35 @@ describe('Result', () => {
]}
/>,
);
expect(wrapper.querySelectorAll('.anticon-check-circle')).toHaveLength(1);
expect(container.querySelectorAll('.anticon-check-circle')).toHaveLength(1);
});
it('🙂 different status, different class', () => {
const { container: wrapper, rerender } = render(<Result status="warning" />);
expect(wrapper.querySelectorAll('.ant-result-warning')).toHaveLength(1);
const { container, rerender } = render(<Result status="warning" />);
expect(container.querySelectorAll('.ant-result-warning')).toHaveLength(1);
rerender(<Result status="error" />);
expect(wrapper.querySelectorAll('.ant-result-error')).toHaveLength(1);
expect(container.querySelectorAll('.ant-result-error')).toHaveLength(1);
rerender(<Result status="500" />);
expect(wrapper.querySelectorAll('.ant-result-500')).toHaveLength(1);
expect(container.querySelectorAll('.ant-result-500')).toHaveLength(1);
});
it('🙂 When status = 404, the icon is an image', () => {
const { container: wrapper } = render(<Result status="404" />);
expect(wrapper.querySelectorAll('.ant-result-404 .ant-result-image')).toHaveLength(1);
const { container } = render(<Result status="404" />);
expect(container.querySelectorAll('.ant-result-404 .ant-result-image')).toHaveLength(1);
});
it('🙂 When extra is undefined, the extra dom is undefined', () => {
const { container: wrapper } = render(<Result status="404" />);
expect(wrapper.querySelectorAll('.ant-result-extra')).toHaveLength(0);
const { container } = render(<Result status="404" />);
expect(container.querySelectorAll('.ant-result-extra')).toHaveLength(0);
});
it('🙂 result should support className', () => {
const { container: wrapper } = render(
<Result status="404" title="404" className="my-result" />,
);
expect(wrapper.querySelectorAll('.ant-result.my-result')).toHaveLength(1);
const { container } = render(<Result status="404" title="404" className="my-result" />);
expect(container.querySelectorAll('.ant-result.my-result')).toHaveLength(1);
});
it('should warning when pass a string as icon props', () => {

View File

@ -44,12 +44,11 @@ interface DataType {
};
}
interface Params {
interface TableParams {
pagination?: TablePaginationConfig;
sorter?: SorterResult<any> | SorterResult<any>[];
total?: number;
sortField?: string;
sortOrder?: string;
filters?: Record<string, FilterValue>;
}
const columns: ColumnsType<DataType> = [
@ -75,7 +74,7 @@ const columns: ColumnsType<DataType> = [
},
];
const getRandomuserParams = (params: Params) => ({
const getRandomuserParams = (params: TableParams) => ({
results: params.pagination?.pageSize,
page: params.pagination?.current,
...params,
@ -84,41 +83,45 @@ const getRandomuserParams = (params: Params) => ({
const App: React.FC = () => {
const [data, setData] = useState();
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10,
const [tableParams, setTableParams] = useState<TableParams>({
pagination: {
current: 1,
pageSize: 10,
},
});
const fetchData = (params: Params = {}) => {
const fetchData = () => {
setLoading(true);
fetch(`https://randomuser.me/api?${qs.stringify(getRandomuserParams(params))}`)
fetch(`https://randomuser.me/api?${qs.stringify(getRandomuserParams(tableParams))}`)
.then(res => res.json())
.then(({ results }) => {
setData(results);
setLoading(false);
setPagination({
...params.pagination,
total: 200,
// 200 is mock data, you should read it from server
// total: data.totalCount,
setTableParams({
...tableParams,
pagination: {
...tableParams.pagination,
total: 200,
// 200 is mock data, you should read it from server
// total: data.totalCount,
},
});
});
};
useEffect(() => {
fetchData({ pagination });
}, []);
fetchData();
}, [JSON.stringify(tableParams)]);
const handleTableChange = (
newPagination: TablePaginationConfig,
pagination: TablePaginationConfig,
filters: Record<string, FilterValue>,
sorter: SorterResult<DataType>,
) => {
fetchData({
sortField: sorter.field as string,
sortOrder: sorter.order as string,
pagination: newPagination,
...filters,
setTableParams({
pagination,
filters,
...sorter,
});
};
@ -127,7 +130,7 @@ const App: React.FC = () => {
columns={columns}
rowKey={record => record.login.uuid}
dataSource={data}
pagination={pagination}
pagination={tableParams.pagination}
loading={loading}
onChange={handleTableChange}
/>

View File

@ -1,106 +0,0 @@
import { mount } from 'enzyme';
import React from 'react';
import Tag from '..';
import mountTest from '../../../tests/shared/mountTest';
import { render, act } from '../../../tests/utils';
import rtlTest from '../../../tests/shared/rtlTest';
import { resetWarned } from '../../_util/warning';
describe('Tag', () => {
mountTest(Tag);
mountTest(Tag.CheckableTag);
rtlTest(Tag);
rtlTest(Tag.CheckableTag);
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('should be closable', () => {
const onClose = jest.fn();
const wrapper = mount(<Tag closable onClose={onClose} />);
expect(wrapper.find('.anticon-close').length).toBe(1);
expect(wrapper.find('.ant-tag:not(.ant-tag-hidden)').length).toBe(1);
wrapper.find('.anticon-close').simulate('click');
expect(onClose).toHaveBeenCalled();
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find('.ant-tag:not(.ant-tag-hidden)').length).toBe(0);
});
it('should not be closed when prevent default', () => {
const onClose = e => {
e.preventDefault();
};
const wrapper = mount(<Tag closable onClose={onClose} />);
expect(wrapper.find('.anticon-close').length).toBe(1);
expect(wrapper.find('.ant-tag:not(.ant-tag-hidden)').length).toBe(1);
wrapper.find('.anticon-close').simulate('click');
act(() => {
jest.runAllTimers();
});
expect(wrapper.find('.ant-tag:not(.ant-tag-hidden)').length).toBe(1);
});
it('should trigger onClick', () => {
const onClick = jest.fn();
const wrapper = mount(<Tag onClick={onClick} />);
wrapper.find('.ant-tag').simulate('click');
expect(onClick).toHaveBeenCalledWith(
expect.objectContaining({
type: 'click',
preventDefault: expect.any(Function),
}),
);
});
it('should trigger onClick on CheckableTag', () => {
const onClick = jest.fn();
const wrapper = mount(<Tag.CheckableTag onClick={onClick} />);
wrapper.find('.ant-tag').simulate('click');
expect(onClick).toHaveBeenCalledWith(
expect.objectContaining({
type: 'click',
preventDefault: expect.any(Function),
}),
);
});
// https://github.com/ant-design/ant-design/issues/20344
it('should not trigger onClick when click close icon', () => {
const onClose = jest.fn();
const onClick = jest.fn();
const wrapper = mount(<Tag closable onClose={onClose} onClick={onClick} />);
wrapper.find('.anticon-close').simulate('click');
expect(onClose).toHaveBeenCalled();
expect(onClick).not.toHaveBeenCalled();
});
it('deprecated warning', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const { container } = render(<Tag visible={false} />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tag] `visible` is deprecated, please use `visible && <Tag />` instead.',
);
expect(container.querySelector('.ant-tag-hidden')).toBeTruthy();
errSpy.mockRestore();
});
describe('CheckableTag', () => {
it('support onChange', () => {
const onChange = jest.fn();
const wrapper = mount(<Tag.CheckableTag onChange={onChange} />);
wrapper.find('.ant-tag').simulate('click');
expect(onChange).toHaveBeenCalledWith(true);
});
});
});

View File

@ -0,0 +1,151 @@
import React from 'react';
import { Simulate } from 'react-dom/test-utils';
import Tag from '..';
import { resetWarned } from '../../_util/warning';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { act, render, fireEvent } from '../../../tests/utils';
describe('Tag', () => {
mountTest(Tag);
mountTest(Tag.CheckableTag);
rtlTest(Tag);
rtlTest(Tag.CheckableTag);
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('should be closable', () => {
const onClose = jest.fn();
const { container } = render(<Tag closable onClose={onClose} />);
expect(container.querySelectorAll('.anticon-close').length).toBe(1);
expect(container.querySelectorAll('.ant-tag:not(.ant-tag-hidden)').length).toBe(1);
fireEvent.click(container.querySelectorAll('.anticon-close')[0]);
expect(onClose).toHaveBeenCalled();
act(() => {
jest.runAllTimers();
});
expect(container.querySelectorAll('.ant-tag:not(.ant-tag-hidden)').length).toBe(0);
});
it('should not be closed when prevent default', () => {
const onClose = (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault();
};
const { container } = render(<Tag closable onClose={onClose} />);
expect(container.querySelectorAll('.anticon-close').length).toBe(1);
expect(container.querySelectorAll('.ant-tag:not(.ant-tag-hidden)').length).toBe(1);
fireEvent.click(container.querySelectorAll('.anticon-close')[0]);
act(() => {
jest.runAllTimers();
});
expect(container.querySelectorAll('.ant-tag:not(.ant-tag-hidden)').length).toBe(1);
});
it('should trigger onClick', () => {
const onClick = jest.fn();
const { container } = render(<Tag onClick={onClick} />);
const target = container.querySelectorAll('.ant-tag')[0];
Simulate.click(target);
expect(onClick).toHaveBeenCalledWith(
expect.objectContaining({
type: 'click',
target,
preventDefault: expect.any(Function),
nativeEvent: {
type: 'click',
target,
},
}),
);
});
it('should trigger onClick on CheckableTag', () => {
const onClick = jest.fn();
const { container } = render(<Tag.CheckableTag checked={false} onClick={onClick} />);
const target = container.querySelectorAll('.ant-tag')[0];
Simulate.click(target);
expect(onClick).toHaveBeenCalledWith(
expect.objectContaining({
type: 'click',
target,
preventDefault: expect.any(Function),
nativeEvent: {
type: 'click',
target,
},
}),
);
});
// https://github.com/ant-design/ant-design/issues/20344
it('should not trigger onClick when click close icon', () => {
const onClose = jest.fn();
const onClick = jest.fn();
const { container } = render(<Tag closable onClose={onClose} onClick={onClick} />);
fireEvent.click(container.querySelectorAll('.anticon-close')[0]);
expect(onClose).toHaveBeenCalled();
expect(onClick).not.toHaveBeenCalled();
});
it('deprecated warning', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const { container } = render(<Tag visible={false} />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tag] `visible` is deprecated, please use `visible && <Tag />` instead.',
);
expect(container.querySelector('.ant-tag-hidden')).toBeTruthy();
errSpy.mockRestore();
});
describe('visibility', () => {
it('can be controlled by visible with visible as initial value', () => {
const { asFragment, rerender } = render(<Tag visible />);
expect(asFragment().firstChild).toMatchSnapshot();
rerender(<Tag visible={false} />);
act(() => {
jest.runAllTimers();
});
expect(asFragment().firstChild).toMatchSnapshot();
rerender(<Tag visible />);
act(() => {
jest.runAllTimers();
});
expect(asFragment().firstChild).toMatchSnapshot();
});
it('can be controlled by visible with hidden as initial value', () => {
const { asFragment, rerender } = render(<Tag visible={false} />);
expect(asFragment().firstChild).toMatchSnapshot();
rerender(<Tag visible />);
act(() => {
jest.runAllTimers();
});
expect(asFragment().firstChild).toMatchSnapshot();
rerender(<Tag visible={false} />);
act(() => {
jest.runAllTimers();
});
expect(asFragment().firstChild).toMatchSnapshot();
});
});
describe('CheckableTag', () => {
it('support onChange', () => {
const onChange = jest.fn();
const { container } = render(<Tag.CheckableTag checked={false} onChange={onChange} />);
fireEvent.click(container.querySelectorAll('.ant-tag')[0]);
expect(onChange).toHaveBeenCalledWith(true);
});
});
});

View File

@ -38,7 +38,7 @@ The following APIs are shared by Tooltip, Popconfirm, Popover.
| overlayInnerStyle | Style of the tooltip inner content | object | - | |
| placement | The position of the tooltip relative to the target, which can be one of `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | `top` | |
| trigger | Tooltip trigger mode. Could be multiple by passing an array | `hover` \| `focus` \| `click` \| `contextMenu` \| Array&lt;string> | `hover` | |
| open | Whether the floating tooltip card is open or not | boolean | false | 4.23.0 |
| open | Whether the floating tooltip card is open or not. Use `visible` under 4.23.0 ([why?](/docs/react/faq#why-open)) | boolean | false | 4.23.0 |
| zIndex | Config `z-index` of Tooltip | number | - | |
| onOpenChange | Callback executed when visibility of the tooltip card is changed | (open) => void | - | 4.23.0 |

View File

@ -40,7 +40,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/Vyyeu8jq2/Tooltp.svg
| overlayInnerStyle | 卡片内容区域的样式对象 | object | - | |
| placement | 气泡框位置,可选 `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | `top` | |
| trigger | 触发行为,可选 `hover` \| `focus` \| `click` \| `contextMenu`,可使用数组设置多个触发行为 | string \| string\[] | `hover` | |
| open | 用于手动控制浮层显隐 | boolean | false | 4.23.0 |
| open | 用于手动控制浮层显隐,小于 4.23.0 使用 `visible`[为什么?](/docs/react/faq#why-open) | boolean | false | 4.23.0 |
| zIndex | 设置 Tooltip 的 `z-index` | number | - | |
| onOpenChange | 显示隐藏的回调 | (open) => void | - | 4.23.0 |

View File

@ -108,7 +108,7 @@ import { Table } from 'antd';
type Props<T extends (...args: any) => any> = Parameters<T>[0];
type TableProps = Props<typeof Table<{ key: string, name: string, age: number }>>;
type TableProps = Props<typeof Table<{ key: string; name: string; age: number }>>;
type DataSource = TableProps['dataSource'];
```
@ -169,6 +169,12 @@ ConfigProvider.config({
You should only access the API by official doc with ref. Directly access internal `props` or `state` is not recommended which will make your code strong coupling with current version. Any refactor will break your code like refactor with [Hooks](https://reactjs.org/docs/hooks-intro.html) version, delete or rename internal `props` or `state`, adjust internal node constructor, etc.
<div id="why-open"></div>
## Why we need align pop component with `open` prop?
For historical reasons, the display names of the pop components are not uniform, and both `open` and `visible` are used. This makes the memory cost that non-tsx users encounter when developing. It also leads to ambiguity about what name to choose when adding a feature. So we want to unify the attribute name, you can still use the original `visible` and it will still be backward compatible, but we will remove this attribute from the documentation as of v5.
## How to spell Ant Design correctly?
- ✅ **Ant Design**: Capitalized with space, for the design language.

View File

@ -122,7 +122,7 @@ import { Table } from 'antd';
type Props<T extends (...args: any) => any> = Parameters<T>[0];
type TableProps = Props<typeof Table<{ key: string, name: string, age: number }>>;
type TableProps = Props<typeof Table<{ key: string; name: string; age: number }>>;
type DataSource = TableProps['dataSource'];
```
@ -189,6 +189,12 @@ ConfigProvider.config({
你通过 ref 获得引用时只应该使用文档提供的方法。直接读取组件内部的 `props``state` 不是一个好的设计,这会使你的代码与组件版本强耦合。任何重构都可能会使你的代码无法工作,其中重构包括且不仅限于改造成 [Hooks](https://reactjs.org/docs/hooks-intro.html) 版本、移除 / 更名内部 `props``state`、调整内部 React 节点结构等等。
<div id="why-open"></div>
## 弹层类组件为什么要统一至 `open` 属性?
因为历史原因,弹层类组件展示命名并不统一,出现了 `open``visible` 都在使用的情况。这使得非 tsx 用户在开发时遭遇的记忆成本。同样导致新增 feature 时选择何种命名的模棱两可。因而我们希望统一该属性命名,你仍然可以使用原本的 `visible` 它仍然会向下兼容,但是从 v5 起我们将从文档中移除该属性。
## 如何正确的拼写 Ant Design
- ✅ **Ant Design**:用空格分隔的首字母大写单词,指代设计语言。

View File

@ -195,6 +195,14 @@ class MainContent extends Component {
handleLoad = () => {
if (window.location.hash) {
updateActiveToc(window.location.hash.replace(/^#/, ''));
//
setTimeout(() => {
const target = document.querySelector(window.location.hash);
if (target) {
target.scrollIntoView();
}
}, 100);
}
this.bindScroller();
};