chore: auto merge branches (#37130)

chore: Feature merge master
This commit is contained in:
github-actions[bot] 2022-08-18 09:03:06 +00:00 committed by GitHub
commit 845e58ca07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 1887 additions and 639 deletions

View File

@ -15,6 +15,25 @@ timeline: true
---
## 4.22.6
`2022-08-17`
- 🐞 Revert [#36710](https://github.com/ant-design/ant-design/pull/36710) to fix Table `onChange` argument `sorter` error in multiple columns sort.
- 🐞 Fix Drawer can not close when config `opacity` on the `maskStyle`. [#37100](https://github.com/ant-design/ant-design/pull/37100)
## 4.22.5
`2022-08-15`
- 🇭🇺 Form add defaultValidateMessages.i18n az_AZ language #23369. [#36967](https://github.com/ant-design/ant-design/pull/36967) [@YMiemie-cy](https://github.com/YMiemie-cy)
- 💄 Popover remove Popover incorrect box-shadow. [#37030](https://github.com/ant-design/ant-design/pull/37030) [@jerrykingxyz](https://github.com/jerrykingxyz)
- 🐞 Fix Steps tail position bug when `labelPlacement="vertical"`. [#36996](https://github.com/ant-design/ant-design/pull/36996)
- 💄 Removed exception error border for `Pagination`. [#36972](https://github.com/ant-design/ant-design/pull/36972) [@hydraZty](https://github.com/hydraZty)
- 🐞 Fix Upload trigger mistake files status when upload multiple files at same time in React 18. [#36968](https://github.com/ant-design/ant-design/pull/36968)
- TypeScript
- 🤖 Fix type error of useWatch. [#37013](https://github.com/ant-design/ant-design/pull/37013) [@LiZhiHao97](https://github.com/LiZhiHao97)
## 4.22.4
`2022-08-08`

View File

@ -15,6 +15,25 @@ timeline: true
---
## 4.22.6
`2022-08-17`
- 🐞 回滚 [#36710](https://github.com/ant-design/ant-design/pull/36710) 以修复 Table 多列排序时 `onChange``sorter` 参数错误的问题。
- 🐞 修复 Drawer 的 `maskStyle` 配置 `opacity` 样式时无法关闭的问题。[#37100](https://github.com/ant-design/ant-design/pull/37100)
## 4.22.5
`2022-08-15`
- 🇭🇺 Form `defaultValidateMessages.i18n` 增加匈牙利语。[#36967](https://github.com/ant-design/ant-design/pull/36967) [@YMiemie-cy](https://github.com/YMiemie-cy)
- 💄 移除 Popover 中无效的 `box-shadow` 样式。[#37030](https://github.com/ant-design/ant-design/pull/37030) [@jerrykingxyz](https://github.com/jerrykingxyz)
- 🐞 修复 Steps `labelPlacement="vertical"` 时连接线位置偏上的问题。[#36996](https://github.com/ant-design/ant-design/pull/36996)
- 💄 去掉 Pagination 的异常错误边框。[#36972](https://github.com/ant-design/ant-design/pull/36972) [@hydraZty](https://github.com/hydraZty)
- 🐞 修复 Upload 在 React 18 下同时上传多份文件会出现上传状态不正确的问题。[#36968](https://github.com/ant-design/ant-design/pull/36968)
- TypeScript
- 🤖 修复 useWatch 的类型错误。[#37013](https://github.com/ant-design/ant-design/pull/37013) [@LiZhiHao97](https://github.com/LiZhiHao97)
## 4.22.4
`2022-08-08`

View File

@ -15,7 +15,7 @@ exports[`Drawer className is test_drawer 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -91,7 +91,7 @@ exports[`Drawer closable is false 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -139,7 +139,7 @@ exports[`Drawer getContainer return undefined 2`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 400px;"
>
<div
@ -216,7 +216,7 @@ exports[`Drawer have a footer 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -297,7 +297,7 @@ exports[`Drawer have a title 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -378,7 +378,7 @@ exports[`Drawer render correctly 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 400px;"
>
<div
@ -454,7 +454,7 @@ exports[`Drawer render top drawer 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-top-appear ant-drawer-panel-motion-top-appear-active ant-drawer-panel-motion-top"
class="ant-drawer-content-wrapper"
style="height: 400px;"
>
<div
@ -533,7 +533,7 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -612,7 +612,7 @@ exports[`Drawer support closeIcon 1`] = `
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 400px;"
>
<div

View File

@ -15,7 +15,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -24,7 +24,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -117,7 +117,7 @@ exports[`renders ./components/drawer/demo/config-provider.md extend context corr
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -126,7 +126,7 @@ exports[`renders ./components/drawer/demo/config-provider.md extend context corr
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -310,7 +310,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -319,7 +319,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 500px;"
>
<div
@ -467,7 +467,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -476,7 +476,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 720px;"
>
<div
@ -2512,7 +2512,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -2521,7 +2521,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 520px; transform: translateX(-180px);"
>
<div
@ -2561,7 +2561,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -2570,7 +2570,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 320px;"
>
<div
@ -2644,7 +2644,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 333px; background: red; border-radius: 20px; box-shadow: -5px 0 5px green; overflow: hidden;"
>
<div
@ -2828,7 +2828,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -2837,7 +2837,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-left-appear ant-drawer-panel-motion-left-appear-active ant-drawer-panel-motion-left"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -2910,7 +2910,7 @@ exports[`renders ./components/drawer/demo/render-in-current.md extend context co
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -2919,7 +2919,7 @@ exports[`renders ./components/drawer/demo/render-in-current.md extend context co
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -2999,7 +2999,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -3008,7 +3008,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 378px;"
>
<div
@ -3231,7 +3231,7 @@ HTMLCollection [
tabindex="-1"
>
<div
class="ant-drawer-mask ant-drawer-mask-motion-appear ant-drawer-mask-motion-appear-active ant-drawer-mask-motion"
class="ant-drawer-mask"
/>
<div
aria-hidden="true"
@ -3240,7 +3240,7 @@ HTMLCollection [
tabindex="0"
/>
<div
class="ant-drawer-content-wrapper ant-drawer-panel-motion-right-appear ant-drawer-panel-motion-right-appear-active ant-drawer-panel-motion-right"
class="ant-drawer-content-wrapper"
style="width: 640px;"
>
<div

View File

@ -9,6 +9,8 @@ jest.mock('rc-drawer', () => {
...props,
open: true,
getContainer: false,
maskMotion: null,
motion: null,
};
return <MockDrawer {...newProps} />;
};

View File

@ -134,6 +134,7 @@ function Drawer({
motionAppear: true,
motionEnter: true,
motionLeave: true,
motionDeadline: 500,
};
const panelMotion: RcDrawerProps['motion'] = motionPlacement => ({
@ -141,6 +142,7 @@ function Drawer({
motionAppear: true,
motionEnter: true,
motionLeave: true,
motionDeadline: 500,
});
// =========================== Render ===========================

View File

@ -1,106 +0,0 @@
import { mount } from 'enzyme';
import React from 'react';
import Dropdown from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import Menu from '../../menu';
describe('DropdownButton', () => {
mountTest(Dropdown.Button);
rtlTest(Dropdown.Button);
it('pass appropriate props to Dropdown', () => {
const props = {
align: {
offset: [10, 20],
},
overlay: (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
),
disabled: false,
trigger: ['hover'],
visible: true,
onVisibleChange: () => {},
};
const wrapper = mount(<Dropdown.Button {...props} />);
const dropdownProps = wrapper.find(Dropdown).props();
Object.keys(props).forEach(key => {
expect(dropdownProps[key]).toBe(props[key]);
});
});
it("don't pass visible to Dropdown if it's not exits", () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const wrapper = mount(<Dropdown.Button overlay={menu} />);
const dropdownProps = wrapper.find(Dropdown).props();
expect('visible' in dropdownProps).toBe(false);
});
it('should support href like Button', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const wrapper = mount(<Dropdown.Button overlay={menu} href="https://ant.design" />);
expect(wrapper.render()).toMatchSnapshot();
});
it('have static property for type detecting', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const wrapper = mount(<Dropdown.Button overlay={menu} />);
expect(wrapper.find(Dropdown.Button).type().__ANT_BUTTON).toBe(true);
});
it('should pass mouseEnterDelay and mouseLeaveDelay to Dropdown', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const wrapper = mount(
<Dropdown.Button mouseEnterDelay={1} mouseLeaveDelay={2} overlay={menu} />,
);
expect(wrapper.find('Dropdown').props().mouseEnterDelay).toBe(1);
expect(wrapper.find('Dropdown').props().mouseLeaveDelay).toBe(2);
});
it('should support overlayClassName and overlayStyle', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const wrapper = mount(
<Dropdown.Button
overlayClassName="className"
overlayStyle={{ color: 'red' }}
overlay={menu}
visible
/>,
);
expect(wrapper.find('.ant-dropdown').getDOMNode().className).toContain('className');
expect(wrapper.find('.ant-dropdown').getDOMNode().style.color).toContain('red');
});
it('should support loading', () => {
const wrapper = mount(<Dropdown.Button loading />);
expect(wrapper.find('.ant-dropdown-button .ant-btn-loading').getDOMNode().className).toContain(
'ant-btn',
);
});
});

View File

@ -0,0 +1,117 @@
import React from 'react';
import DropdownButton from '../dropdown-button';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import Menu from '../../menu';
import type { DropdownProps } from '../dropdown';
import { render } from '../../../tests/utils';
let dropdownProps: DropdownProps;
jest.mock('../dropdown', () => {
const ActualDropdown = jest.requireActual('../dropdown');
const ActualDropdownComponent = ActualDropdown.default;
const h: typeof React = jest.requireActual('react');
const mockedDropdown = (props: DropdownProps) => {
dropdownProps = props;
const { children, ...restProps } = props;
return h.createElement(ActualDropdownComponent, { ...restProps }, children);
};
mockedDropdown.defaultProps = ActualDropdownComponent.defaultProps;
mockedDropdown.Button = ActualDropdownComponent.Button;
return {
...ActualDropdown,
__esModule: true,
default: mockedDropdown,
};
});
describe('DropdownButton', () => {
mountTest(DropdownButton);
rtlTest(DropdownButton);
it('pass appropriate props to Dropdown', () => {
const props: DropdownProps = {
align: {
offset: [10, 20],
},
overlay: (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
),
disabled: false,
trigger: ['hover'],
visible: true,
onVisibleChange: () => {},
};
render(<DropdownButton {...props} />);
Object.keys(props).forEach((key: keyof DropdownProps) => {
expect(dropdownProps[key]).toBe(props[key]);
});
});
it("don't pass visible to Dropdown if it's not exits", () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
render(<DropdownButton overlay={menu} />);
expect('visible' in dropdownProps).toBe(false);
});
it('should support href like Button', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const { asFragment } = render(<DropdownButton overlay={menu} href="https://ant.design" />);
expect(asFragment().firstChild).toMatchSnapshot();
});
it('have static property for type detecting', () => {
expect(DropdownButton.__ANT_BUTTON).toBe(true);
});
it('should pass mouseEnterDelay and mouseLeaveDelay to Dropdown', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
render(<DropdownButton mouseEnterDelay={1} mouseLeaveDelay={2} overlay={menu} />);
expect(dropdownProps.mouseEnterDelay).toBe(1);
expect(dropdownProps.mouseLeaveDelay).toBe(2);
});
it('should support overlayClassName and overlayStyle', () => {
const menu = (
<Menu>
<Menu.Item key="1">foo</Menu.Item>
</Menu>
);
const { container } = render(
<DropdownButton
overlayClassName="className"
overlayStyle={{ color: 'red' }}
overlay={menu}
visible
/>,
);
expect(container.querySelector('.ant-dropdown')?.classList).toContain('className');
expect((container.querySelector('.ant-dropdown') as HTMLElement).style.color).toContain('red');
});
it('should support loading', () => {
const { container } = render(<DropdownButton overlay={<div />} loading />);
expect(container.querySelector('.ant-dropdown-button .ant-btn-loading')?.classList).toContain(
'ant-btn',
);
});
});

View File

@ -1,44 +1,61 @@
import { mount } from 'enzyme';
import React from 'react';
import type { TriggerProps } from 'rc-trigger';
import Dropdown from '..';
import type { DropDownProps } from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { act, fireEvent, render, sleep } from '../../../tests/utils';
import Menu from '../../menu';
let triggerProps: TriggerProps;
jest.mock('rc-trigger', () => {
let Trigger = jest.requireActual('rc-trigger/lib/mock');
Trigger = Trigger.default || Trigger;
const h: typeof React = jest.requireActual('react');
return {
default: h.forwardRef<unknown, TriggerProps>((props, ref) => {
triggerProps = props;
return h.createElement(Trigger, { ref, ...props });
}),
__esModule: true,
};
});
describe('Dropdown', () => {
mountTest(() => (
<Dropdown menu={<Menu />}>
<Dropdown overlay={<Menu />}>
<span />
</Dropdown>
));
rtlTest(() => (
<Dropdown menu={<Menu />}>
<Dropdown overlay={<Menu />}>
<span />
</Dropdown>
));
it('overlay is function and has custom transitionName', () => {
const wrapper = mount(
const { asFragment } = render(
<Dropdown overlay={() => <div>menu</div>} transitionName="move-up" visible>
<button type="button">button</button>
</Dropdown>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(Array.from(asFragment().childNodes)).toMatchSnapshot();
});
it('overlay is string', () => {
const wrapper = mount(
<Dropdown overlay="string" visible>
const { asFragment } = render(
<Dropdown overlay={'string' as any} visible>
<button type="button">button</button>
</Dropdown>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(Array.from(asFragment().childNodes)).toMatchSnapshot();
});
it('support Menu expandIcon', async () => {
const props = {
const props: DropDownProps = {
overlay: (
<Menu expandIcon={<span id="customExpandIcon" />}>
<Menu.Item key="1">foo</Menu.Item>
@ -51,23 +68,23 @@ describe('Dropdown', () => {
getPopupContainer: node => node,
};
const wrapper = mount(
const { container } = render(
<Dropdown {...props}>
<button type="button">button</button>
</Dropdown>,
);
await sleep(500);
expect(wrapper.find(Dropdown).find('#customExpandIcon').length).toBe(1);
expect(container.querySelectorAll('#customExpandIcon').length).toBe(1);
});
it('should warn if use topCenter or bottomCenter', () => {
const error = jest.spyOn(console, 'error');
mount(
render(
<div>
<Dropdown overlay="123" placement="bottomCenter">
<Dropdown overlay={'123' as any} placement="bottomCenter">
<button type="button">bottomCenter</button>
</Dropdown>
<Dropdown overlay="123" placement="topCenter">
<Dropdown overlay={'123' as any} placement="topCenter">
<button type="button">topCenter</button>
</Dropdown>
</div>,
@ -82,13 +99,13 @@ describe('Dropdown', () => {
// zombieJ: when replaced with react test lib, it may be mock fully content
it('dropdown should support auto adjust placement', () => {
const wrapper = mount(
render(
<Dropdown overlay={<div>menu</div>} visible>
<button type="button">button</button>
</Dropdown>,
);
expect(wrapper.find('Trigger').prop('builtinPlacements')).toEqual(
expect(triggerProps.builtinPlacements).toEqual(
expect.objectContaining({
bottomLeft: expect.objectContaining({
overflow: {
@ -104,7 +121,7 @@ describe('Dropdown', () => {
jest.useFakeTimers();
const { container } = render(
<Dropdown
trigger="click"
trigger={['click']}
overlay={
<Menu
items={[
@ -127,13 +144,13 @@ describe('Dropdown', () => {
);
// Open
fireEvent.click(container.querySelector('a'));
fireEvent.click(container.querySelector('a')!);
act(() => {
jest.runAllTimers();
});
// Close
fireEvent.click(container.querySelector('.ant-dropdown-menu-item'));
fireEvent.click(container.querySelector('.ant-dropdown-menu-item')!);
// Force Motion move on
for (let i = 0; i < 10; i += 1) {
@ -143,7 +160,7 @@ describe('Dropdown', () => {
}
// Motion End
fireEvent.animationEnd(container.querySelector('.ant-slide-up-leave-active'));
fireEvent.animationEnd(container.querySelector('.ant-slide-up-leave-active')!);
expect(container.querySelector('.ant-dropdown-hidden')).toBeTruthy();

View File

@ -315,7 +315,7 @@ export default () => {
### Form.useWatch
`type Form.useWatch = (namePath: NamePath, formInstance: FormInstance): Value`
`type Form.useWatch = (namePath: NamePath, formInstance?: FormInstance): Value`
Added in `4.20.0`. Watch the value of a field. You can use this to interactive with other hooks like `useSWR` to reduce develop cost:

View File

@ -314,7 +314,7 @@ export default () => {
### Form.useWatch
`type Form.useWatch = (namePath: NamePath, formInstance: FormInstance): Value`
`type Form.useWatch = (namePath: NamePath, formInstance?: FormInstance): Value`
`4.20.0` 新增,用于直接获取 form 中字段对应的值。通过该 Hooks 可以与诸如 `useSWR` 进行联动从而降低维护成本:

View File

@ -3,17 +3,17 @@
exports[`Grid renders wrapped Col correctly 1`] = `
<div
class="ant-row"
style="margin-left:-10px;margin-right:-10px"
style="margin-left: -10px; margin-right: -10px;"
>
<div>
<div
class="ant-col ant-col-12"
style="padding-left:10px;padding-right:10px"
style="padding-left: 10px; padding-right: 10px;"
/>
</div>
<div
class="ant-col ant-col-12"
style="padding-left:10px;padding-right:10px"
style="padding-left: 10px; padding-right: 10px;"
/>
</div>
`;
@ -45,6 +45,6 @@ exports[`Grid should render Row 1`] = `
exports[`Grid when typeof gutter is object array in large screen 1`] = `
<div
class="ant-row"
style="margin-left:-20px;margin-right:-20px;margin-top:-200px;margin-bottom:-200px"
style="margin: -200px -20px -200px -20px;"
/>
`;

View File

@ -1,7 +1,7 @@
import { mount } from 'enzyme';
import React, { memo, useContext, useRef, useState } from 'react';
import Row from '../row';
import RowContext from '../RowContext';
import { render, fireEvent } from '../../../tests/utils';
const CacheInner = memo(() => {
const countRef = useRef(0);
@ -33,16 +33,16 @@ const CacheOuter = () => {
};
it('Cached RowContext is working', () => {
const wrapper = mount(<CacheOuter />);
const childCount = wrapper.find('#child_count').text();
const { container } = render(<CacheOuter />);
const childCount = container.querySelector('#child_count')?.textContent;
wrapper.find('#parent_btn').at(0).simulate('click');
expect(wrapper.find('#parent_count').text()).toBe('2');
fireEvent.click(container.querySelector('#parent_btn')!);
expect(container.querySelector('#parent_count')?.textContent).toBe('2');
// child component won't rerender
expect(wrapper.find('#child_count').text()).toBe(childCount);
expect(container.querySelector('#child_count')?.textContent).toBe(childCount);
wrapper.find('#parent_btn').at(0).simulate('click');
expect(wrapper.find('#parent_count').text()).toBe('3');
fireEvent.click(container.querySelector('#parent_btn')!);
expect(container.querySelector('#parent_count')?.textContent).toBe('3');
// child component won't rerender
expect(wrapper.find('#child_count').text()).toBe(childCount);
expect(container.querySelector('#child_count')?.textContent).toBe(childCount);
});

View File

@ -1,4 +1,3 @@
import { mount } from 'enzyme';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { Col, Row } from '..';
@ -22,19 +21,15 @@ describe('Grid.Gap', () => {
});
it('should use gap', () => {
const wrapper = mount(
const { container } = render(
<Row gutter={[16, 8]}>
<Col />
</Row>,
);
expect(wrapper.find('.ant-row').props().style).toEqual(
expect.objectContaining({
marginLeft: -8,
rowGap: 8,
marginRight: -8,
}),
);
expect((container.querySelector('.ant-row') as HTMLElement)!.style.marginLeft).toEqual('-8px');
expect((container.querySelector('.ant-row') as HTMLElement)!.style.marginRight).toEqual('-8px');
expect((container.querySelector('.ant-row') as HTMLElement)!.style.rowGap).toEqual('8px');
});
it('not break ssr', () => {

View File

@ -1,127 +0,0 @@
import { mount, render } from 'enzyme';
import React from 'react';
import { act } from 'react-dom/test-utils';
import { Col, Row } from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import ResponsiveObserve from '../../_util/responsiveObserve';
import useBreakpoint from '../hooks/useBreakpoint';
describe('Grid', () => {
mountTest(Row);
mountTest(Col);
rtlTest(Row);
rtlTest(Col);
it('should render Col', () => {
const wrapper = render(<Col span={2} />);
expect(wrapper).toMatchSnapshot();
});
it('should render Row', () => {
const wrapper = render(<Row />);
expect(wrapper).toMatchSnapshot();
});
it('when typeof gutter is object', () => {
const wrapper = mount(<Row gutter={{ xs: 8, sm: 16, md: 24 }} />);
expect(wrapper.find('div').first().props().style).toEqual(
expect.objectContaining({
marginLeft: -4,
marginRight: -4,
}),
);
});
it('when typeof gutter is object array', () => {
const wrapper = mount(
<Row
gutter={[
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
]}
/>,
);
expect(wrapper.find('div').first().props().style).toEqual(
expect.objectContaining({
marginLeft: -4,
marginRight: -4,
}),
);
});
it('when typeof gutter is object array in large screen', () => {
const wrapper = render(
<Row
gutter={[
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
{ xs: 8, sm: 16, md: 24, lg: 100, xl: 400 },
]}
/>,
);
expect(wrapper).toMatchSnapshot();
});
it('renders wrapped Col correctly', () => {
const MyCol = () => <Col span={12} />;
const wrapper = render(
<Row gutter={20}>
<div>
<Col span={12} />
</div>
<MyCol />
</Row>,
);
expect(wrapper).toMatchSnapshot();
});
it('ResponsiveObserve.unsubscribe should be called when unmounted', () => {
const Unmount = jest.spyOn(ResponsiveObserve, 'unsubscribe');
const wrapper = mount(<Row gutter={{ xs: 20 }} />);
act(() => {
wrapper.unmount();
});
expect(Unmount).toHaveBeenCalled();
});
it('should work correct when gutter is object', () => {
const wrapper = mount(<Row gutter={{ xs: 20 }} />);
expect(wrapper.find('div').prop('style')).toEqual({
marginLeft: -10,
marginRight: -10,
});
});
it('should work current when gutter is array', () => {
const wrapper = mount(<Row gutter={[16, 20]} />);
expect(wrapper.find('div').prop('style')).toEqual({
marginLeft: -8,
marginRight: -8,
marginTop: -10,
marginBottom: -10,
});
});
// By jsdom mock, actual jsdom not implemented matchMedia
// https://jestjs.io/docs/en/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
it('should work with useBreakpoint', () => {
function Demo() {
const screens = useBreakpoint();
return JSON.stringify(screens);
}
const wrapper = mount(<Demo />);
expect(wrapper.text()).toEqual(
JSON.stringify({
xs: true,
sm: false,
md: false,
lg: false,
xl: false,
xxl: false,
}),
);
});
});

View File

@ -0,0 +1,146 @@
import React from 'react';
import { Col, Row } from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import ResponsiveObserve from '../../_util/responsiveObserve';
import useBreakpoint from '../hooks/useBreakpoint';
import { render, act } from '../../../tests/utils';
describe('Grid', () => {
mountTest(Row);
mountTest(Col);
rtlTest(Row);
rtlTest(Col);
afterEach(() => {
ResponsiveObserve.unregister();
});
it('should render Col', () => {
const { asFragment } = render(<Col span={2} />);
expect(asFragment().firstChild).toMatchSnapshot();
});
it('should render Row', () => {
const { asFragment } = render(<Row />);
expect(asFragment().firstChild).toMatchSnapshot();
});
it('when typeof gutter is object', () => {
const { container } = render(<Row gutter={{ xs: 8, sm: 16, md: 24 }} />);
expect(container.querySelector('div')!.style.marginLeft).toEqual('-4px');
expect(container.querySelector('div')!.style.marginRight).toEqual('-4px');
});
it('when typeof gutter is object array', () => {
const { container } = render(
<Row
gutter={[
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
]}
/>,
);
expect(container.querySelector('div')!.style.marginLeft).toEqual('-4px');
expect(container.querySelector('div')!.style.marginRight).toEqual('-4px');
});
it('when typeof gutter is object array in large screen', () => {
jest.spyOn(window, 'matchMedia').mockImplementation(
query =>
({
addListener: (cb: (e: { matches: boolean }) => void) => {
cb({ matches: query === '(min-width: 1200px)' });
},
removeListener: jest.fn(),
matches: query === '(min-width: 1200px)',
} as any),
);
const { container, asFragment } = render(
<Row
gutter={[
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
{ xs: 8, sm: 16, md: 24, lg: 100, xl: 400 },
]}
/>,
);
expect(asFragment().firstChild).toMatchSnapshot();
expect(container.querySelector('div')!.style.marginLeft).toEqual('-20px');
expect(container.querySelector('div')!.style.marginRight).toEqual('-20px');
expect(container.querySelector('div')!.style.marginTop).toEqual('-200px');
expect(container.querySelector('div')!.style.marginBottom).toEqual('-200px');
});
it('renders wrapped Col correctly', () => {
const MyCol = () => <Col span={12} />;
const { asFragment } = render(
<Row gutter={20}>
<div>
<Col span={12} />
</div>
<MyCol />
</Row>,
);
expect(asFragment().firstChild).toMatchSnapshot();
});
it('ResponsiveObserve.unsubscribe should be called when unmounted', () => {
const Unmount = jest.spyOn(ResponsiveObserve, 'unsubscribe');
const { unmount } = render(<Row gutter={{ xs: 20 }} />);
act(() => {
unmount();
});
expect(Unmount).toHaveBeenCalled();
});
it('should work correct when gutter is object', () => {
const { container } = render(<Row gutter={{ xs: 20 }} />);
expect(container.querySelector('div')!.style.marginLeft).toEqual('-10px');
expect(container.querySelector('div')!.style.marginRight).toEqual('-10px');
});
it('should work current when gutter is array', () => {
const { container } = render(<Row gutter={[16, 20]} />);
expect(container.querySelector('div')!.style.marginLeft).toEqual('-8px');
expect(container.querySelector('div')!.style.marginRight).toEqual('-8px');
expect(container.querySelector('div')!.style.marginTop).toEqual('-10px');
expect(container.querySelector('div')!.style.marginBottom).toEqual('-10px');
});
// By jsdom mock, actual jsdom not implemented matchMedia
// https://jestjs.io/docs/en/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
it('should work with useBreakpoint', () => {
const matchMediaSpy = jest.spyOn(window, 'matchMedia');
matchMediaSpy.mockImplementation(
query =>
({
addListener: (cb: (e: { matches: boolean }) => void) => {
cb({ matches: query === '(max-width: 575px)' });
},
removeListener: jest.fn(),
matches: query === '(max-width: 575px)',
} as any),
);
let screensVar;
function Demo() {
const screens = useBreakpoint();
screensVar = screens;
return <div />;
}
render(<Demo />);
expect(screensVar).toEqual({
xs: true,
sm: false,
md: false,
lg: false,
xl: false,
xxl: false,
});
});
});

View File

@ -1,34 +0,0 @@
import { mount } from 'enzyme';
import React from 'react';
// eslint-disable-next-line no-unused-vars
import { Col, Row } from '..';
jest.mock('rc-util/lib/Dom/canUseDom', () => () => false);
describe('Grid.Server', () => {
it('use compatible gap logic', () => {
const wrapper = mount(
<Row gutter={[8, 16]}>
<Col />
</Row>,
);
expect(wrapper.find('.ant-row').props().style).toEqual(
expect.objectContaining({
marginLeft: -4,
marginRight: -4,
marginTop: -8,
marginBottom: -8,
}),
);
expect(wrapper.find('.ant-col').props().style).toEqual(
expect.objectContaining({
paddingLeft: 4,
paddingRight: 4,
paddingTop: 8,
paddingBottom: 8,
}),
);
});
});

View File

@ -0,0 +1,30 @@
import React from 'react';
// eslint-disable-next-line no-unused-vars
import { Col, Row } from '..';
import { render } from '../../../tests/utils';
jest.mock('rc-util/lib/Dom/canUseDom', () => () => false);
describe('Grid.Server', () => {
it('use compatible gap logic', () => {
const { container } = render(
<Row gutter={[8, 16]}>
<Col />
</Row>,
);
expect((container.querySelector('.ant-row') as HTMLElement)!.style.marginLeft).toEqual('-4px');
expect((container.querySelector('.ant-row') as HTMLElement)!.style.marginRight).toEqual('-4px');
expect((container.querySelector('.ant-row') as HTMLElement)!.style.marginTop).toEqual('-8px');
expect((container.querySelector('.ant-row') as HTMLElement)!.style.marginBottom).toEqual(
'-8px',
);
expect((container.querySelector('.ant-col') as HTMLElement)!.style.paddingLeft).toEqual('4px');
expect((container.querySelector('.ant-col') as HTMLElement)!.style.paddingRight).toEqual('4px');
expect((container.querySelector('.ant-col') as HTMLElement)!.style.paddingTop).toEqual('8px');
expect((container.querySelector('.ant-col') as HTMLElement)!.style.paddingBottom).toEqual(
'8px',
);
});
});

View File

@ -27,8 +27,8 @@
width: 90px;
margin: 0;
padding: 0;
border: @border-width-base @border-style-base @border-color-base;
border-radius: @border-radius-base;
border: @border-width-base @border-style-base @input-border-color;
border-radius: @control-border-radius;
&-handler {
position: relative;
@ -102,7 +102,7 @@
text-align: left;
background-color: transparent;
border: 0;
border-radius: @border-radius-base;
border-radius: @control-border-radius;
outline: 0;
transition: all 0.3s linear;
appearance: textfield !important;
@ -142,7 +142,7 @@
width: 22px;
height: 100%;
background: @input-number-handler-bg;
border-radius: 0 @border-radius-base @border-radius-base 0;
border-radius: 0 @control-border-radius @control-border-radius 0;
opacity: 0;
transition: opacity 0.24s linear 0.1s;
@ -176,7 +176,7 @@
}
&-handler-up {
border-top-right-radius: @border-radius-base;
border-top-right-radius: @control-border-radius;
cursor: pointer;
&-inner {
@ -192,8 +192,8 @@
&-handler-down {
top: 0;
border-top: @border-width-base @border-style-base @border-color-base;
border-bottom-right-radius: @border-radius-base;
border-top: @border-width-base @border-style-base @input-number-handler-border-color;
border-bottom-right-radius: @control-border-radius;
cursor: pointer;
&-inner {
@ -210,6 +210,11 @@
}
}
&:hover:not(.@{input-number-prefix-cls}-borderless) &-handler-down,
&-focused:not(.@{input-number-prefix-cls}-borderless) &-handler-down {
border-top: @border-width-base @border-style-base @input-number-handler-border-color;
}
&-handler-up-disabled,
&-handler-down-disabled {
cursor: not-allowed;

View File

@ -1,97 +0,0 @@
import { mount } from 'enzyme';
import React from 'react';
import Mentions from '..';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { act } from '../../../tests/utils';
const { getMentions } = Mentions;
function simulateInput(wrapper, text, keyEvent) {
const lastChar = text[text.length - 1];
const myKeyEvent = keyEvent || {
which: lastChar.charCodeAt(0),
key: lastChar,
target: {
value: text,
selectionStart: text.length,
},
};
wrapper.find('textarea').simulate('keyDown', myKeyEvent);
const textareaInstance = wrapper.find('textarea').instance();
textareaInstance.value = text;
textareaInstance.selectionStart = text.length;
textareaInstance.selectionStart = text.length;
if (!keyEvent) {
wrapper.find('textarea').simulate('change', {
target: { value: text },
});
}
wrapper.find('textarea').simulate('keyUp', myKeyEvent);
wrapper.update();
}
describe('Mentions', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('getMentions', () => {
const mentions = getMentions('@light #bamboo cat', { prefix: ['@', '#'] });
expect(mentions).toEqual([
{
prefix: '@',
value: 'light',
},
{
prefix: '#',
value: 'bamboo',
},
]);
});
it('focus', () => {
const onFocus = jest.fn();
const onBlur = jest.fn();
const wrapper = mount(<Mentions onFocus={onFocus} onBlur={onBlur} />);
wrapper.find('textarea').simulate('focus');
expect(wrapper.find('.ant-mentions').hasClass('ant-mentions-focused')).toBeTruthy();
expect(onFocus).toHaveBeenCalled();
wrapper.find('textarea').simulate('blur');
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find('.ant-mentions').hasClass('ant-mentions-focused')).toBeFalsy();
expect(onBlur).toHaveBeenCalled();
});
focusTest(Mentions, { refFocus: true });
mountTest(Mentions);
rtlTest(Mentions);
it('loading', () => {
const wrapper = mount(<Mentions loading />);
simulateInput(wrapper, '@');
expect(wrapper.find('li.ant-mentions-dropdown-menu-item').length).toBe(1);
expect(wrapper.find('.ant-spin').length).toBeTruthy();
});
it('notFoundContent', () => {
const wrapper = mount(<Mentions notFoundContent={<span className="bamboo-light" />} />);
simulateInput(wrapper, '@');
expect(wrapper.find('li.ant-mentions-dropdown-menu-item').length).toBe(1);
expect(wrapper.find('.bamboo-light').length).toBeTruthy();
});
});

View File

@ -0,0 +1,87 @@
import React from 'react';
import Mentions from '..';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { act, render, fireEvent } from '../../../tests/utils';
const { getMentions } = Mentions;
function simulateInput(wrapper: ReturnType<typeof render>, text: string, keyEvent?: Event): void {
const lastChar = text[text.length - 1];
const myKeyEvent = keyEvent || {
which: lastChar.charCodeAt(0),
key: lastChar,
target: {
value: text,
selectionStart: text.length,
},
};
fireEvent.keyDown(wrapper.container.querySelector('textarea')!, myKeyEvent);
const textareaInstance = wrapper.container.querySelector('textarea');
if (textareaInstance) {
textareaInstance.value = text;
textareaInstance.selectionStart = text.length;
textareaInstance.selectionStart = text.length;
}
if (!keyEvent) {
fireEvent.change(wrapper.container.querySelector('textarea')!, { target: { value: text } });
}
fireEvent.keyUp(wrapper.container.querySelector('textarea')!, myKeyEvent);
}
describe('Mentions', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('getMentions', () => {
const mentions = getMentions('@light #bamboo cat', { prefix: ['@', '#'] });
expect(mentions).toEqual([
{ prefix: '@', value: 'light' },
{ prefix: '#', value: 'bamboo' },
]);
});
it('focus', () => {
const onFocus = jest.fn();
const onBlur = jest.fn();
const { container } = render(<Mentions onFocus={onFocus} onBlur={onBlur} />);
fireEvent.focus(container.querySelector('textarea')!);
expect(container.querySelector('.ant-mentions')).toHaveClass('ant-mentions-focused');
expect(onFocus).toHaveBeenCalled();
fireEvent.blur(container.querySelector('textarea')!);
act(() => {
jest.runAllTimers();
});
expect(container.querySelector('.ant-mentions')).not.toHaveClass('ant-mentions-focused');
expect(onBlur).toHaveBeenCalled();
});
focusTest(Mentions, { refFocus: true });
mountTest(Mentions);
rtlTest(Mentions);
it('loading', () => {
const wrapper = render(<Mentions loading />);
simulateInput(wrapper, '@');
expect(wrapper.container.querySelectorAll('li.ant-mentions-dropdown-menu-item').length).toBe(1);
expect(wrapper.container.querySelectorAll('.ant-spin').length).toBeTruthy();
});
it('notFoundContent', () => {
const wrapper = render(<Mentions notFoundContent={<span className="bamboo-light" />} />);
simulateInput(wrapper, '@');
expect(wrapper.container.querySelectorAll('li.ant-mentions-dropdown-menu-item').length).toBe(1);
expect(wrapper.container.querySelectorAll('.bamboo-light').length).toBeTruthy();
});
});

View File

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Menu Menu.Item with icon children auto wrap span 1`] = `
Array [
<DocumentFragment>
<ul
class="ant-menu ant-menu-root ant-menu-vertical ant-menu-light"
data-menu-list="true"
@ -154,16 +154,16 @@ Array [
/>
</div>
</li>
</ul>,
</ul>
<div
aria-hidden="true"
style="display: none;"
/>,
]
/>
</DocumentFragment>
`;
exports[`Menu all types must be available in the "items" syntax 1`] = `
Array [
<DocumentFragment>
<ul
class="ant-menu ant-menu-root ant-menu-inline ant-menu-light"
data-menu-list="true"
@ -315,12 +315,12 @@ Array [
</li>
</ul>
</li>
</ul>,
</ul>
<div
aria-hidden="true"
style="display: none;"
/>,
]
/>
</DocumentFragment>
`;
exports[`Menu rtl render component should be rendered correctly in RTL direction 1`] = `
@ -382,7 +382,7 @@ Array [
`;
exports[`Menu should controlled collapse work 1`] = `
Array [
<DocumentFragment>
<ul
class="ant-menu ant-menu-root ant-menu-inline ant-menu-light"
data-menu-list="true"
@ -421,16 +421,16 @@ Array [
Option 1
</span>
</li>
</ul>,
</ul>
<div
aria-hidden="true"
style="display: none;"
/>,
]
/>
</DocumentFragment>
`;
exports[`Menu should controlled collapse work 2`] = `
Array [
<DocumentFragment>
<ul
class="ant-menu ant-menu-root ant-menu-vertical ant-menu-light ant-menu-inline-collapsed"
data-menu-list="true"
@ -469,10 +469,10 @@ Array [
Option 1
</span>
</li>
</ul>,
</ul>
<div
aria-hidden="true"
style="display: none;"
/>,
]
/>
</DocumentFragment>
`;

View File

@ -5,14 +5,13 @@ import {
PieChartOutlined,
UserOutlined,
} from '@ant-design/icons';
import { mount } from 'enzyme';
// import { mount } from 'enzyme';
import React, { useState } from 'react';
import Menu from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render, act } from '../../../tests/utils';
import Layout from '../../layout';
import Tooltip from '../../tooltip';
import collapseMotion from '../../_util/motion';
import { noop } from '../../_util/warning';
@ -137,7 +136,7 @@ describe('Menu', () => {
});
it('If has select nested submenu item ,the menu items on the grandfather level should be highlight', () => {
const wrapper = mount(
const { container } = render(
<Menu defaultSelectedKeys={['1-3-2']} mode="vertical">
<SubMenu key="1" title="submenu1">
<Menu.Item key="1-1">Option 1</Menu.Item>
@ -150,11 +149,11 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.find('li.ant-menu-submenu-selected').length).toBe(1);
expect(container.querySelectorAll('li.ant-menu-submenu-selected').length).toBe(1);
});
it('forceSubMenuRender', () => {
const wrapper = mount(
const { container, rerender } = render(
<Menu mode="horizontal">
<SubMenu key="1" title="submenu1">
<Menu.Item key="1-1">
@ -164,14 +163,22 @@ describe('Menu', () => {
</Menu>,
);
expect(wrapper.find('.bamboo').hostNodes()).toHaveLength(0);
expect(container.querySelector('.bamboo')).toBeFalsy();
wrapper.setProps({ forceSubMenuRender: true });
expect(wrapper.find('.bamboo').hostNodes()).toHaveLength(1);
rerender(
<Menu mode="horizontal" forceSubMenuRender>
<SubMenu key="1" title="submenu1">
<Menu.Item key="1-1">
<span className="bamboo" />
</Menu.Item>
</SubMenu>
</Menu>,
);
expect(container.querySelector('.bamboo')).toBeTruthy();
});
it('should accept defaultOpenKeys in mode horizontal', () => {
const wrapper = mount(
const { container } = render(
<Menu defaultOpenKeys={['1']} mode="horizontal">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -180,11 +187,15 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.exists('.ant-menu-sub')).toBeFalsy();
expect(
container.querySelector('.ant-menu-submenu-open').querySelector('.ant-menu-submenu-title')
.textContent,
).toEqual('submenu1');
});
it('should accept defaultOpenKeys in mode inline', () => {
const wrapper = mount(
const { container } = render(
<Menu defaultOpenKeys={['1']} mode="inline">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -193,11 +204,15 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.find('.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).not.toBe(true);
expect(
container.querySelector('.ant-menu-submenu-open').querySelector('.ant-menu-submenu-title')
.textContent,
).toEqual('submenu1');
});
it('should accept defaultOpenKeys in mode vertical', () => {
const wrapper = mount(
const { container } = render(
<Menu defaultOpenKeys={['1']} mode="vertical">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -206,11 +221,11 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.find('PopupTrigger').first().prop('visible')).toBeTruthy();
expect(container.querySelector('.ant-menu-sub')).toBeFalsy();
});
it('should accept openKeys in mode horizontal', () => {
const wrapper = mount(
const { container } = render(
<Menu openKeys={['1']} mode="horizontal">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -219,11 +234,14 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.find('PopupTrigger').first().prop('visible')).toBeTruthy();
triggerAllTimer();
expect(container.querySelector('div.ant-menu-submenu-popup')).not.toHaveClass(
'ant-menu-submenu-hidden',
);
});
it('should accept openKeys in mode inline', () => {
const wrapper = mount(
const { container } = render(
<Menu openKeys={['1']} mode="inline">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -232,11 +250,11 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.find('InlineSubMenuList').first().prop('open')).toBeTruthy();
expect(container.querySelector('ul.ant-menu-sub')).not.toHaveClass('ant-menu-hidden');
});
it('should accept openKeys in mode vertical', () => {
const wrapper = mount(
const { container } = render(
<Menu openKeys={['1']} mode="vertical">
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -245,7 +263,10 @@ describe('Menu', () => {
<Menu.Item key="2">menu2</Menu.Item>
</Menu>,
);
expect(wrapper.find('PopupTrigger').first().prop('visible')).toBeTruthy();
triggerAllTimer();
expect(container.querySelector('div.ant-menu-submenu-popup')).not.toHaveClass(
'ant-menu-submenu-hidden',
);
});
it('test submenu in mode horizontal', async () => {
@ -384,8 +405,8 @@ describe('Menu', () => {
});
it('should always follow openKeys when inlineCollapsed is switched', () => {
const wrapper = mount(
<Menu defaultOpenKeys={['1']} mode="inline">
const Demo = props => (
<Menu defaultOpenKeys={['1']} mode="inline" {...props}>
<Menu.Item key="menu1" icon={<InboxOutlined />}>
Option
</Menu.Item>
@ -393,30 +414,34 @@ describe('Menu', () => {
<Menu.Item key="submenu1">Option</Menu.Item>
<Menu.Item key="submenu2">Option</Menu.Item>
</SubMenu>
</Menu>,
</Menu>
);
const { container, rerender } = render(<Demo />);
expect(wrapper.find('InlineSubMenuList').prop('open')).toBeTruthy();
expect(container.querySelector('li.ant-menu-submenu-inline')).toHaveClass(
'ant-menu-submenu-open',
);
// inlineCollapsed
wrapper.setProps({ inlineCollapsed: true });
rerender(<Demo inlineCollapsed />);
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find('ul.ant-menu-root').hasClass('ant-menu-vertical')).toBeTruthy();
expect(wrapper.find('PopupTrigger').prop('visible')).toBeFalsy();
expect(container.querySelector('ul.ant-menu-root')).toHaveClass('ant-menu-vertical');
expect(container.querySelector('.ant-menu-submenu-popup')).toBeFalsy();
// !inlineCollapsed
wrapper.setProps({ inlineCollapsed: false });
rerender(<Demo inlineCollapsed={false} />);
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find('ul.ant-menu-sub').last().hasClass('ant-menu-inline')).toBeTruthy();
expect(wrapper.find('InlineSubMenuList').prop('open')).toBeTruthy();
expect(container.querySelector('ul.ant-menu-sub')).toHaveClass('ant-menu-inline');
expect(container.querySelector('li.ant-menu-submenu-inline')).toHaveClass(
'ant-menu-submenu-open',
);
});
it('inlineCollapsed should works well when specify a not existed default openKeys', () => {
@ -456,7 +481,7 @@ describe('Menu', () => {
});
it('inlineCollapsed Menu.Item Tooltip can be removed', () => {
const wrapper = mount(
const { container } = render(
<Menu
defaultOpenKeys={['not-existed']}
mode="inline"
@ -481,12 +506,19 @@ describe('Menu', () => {
</Menu.Item>
</Menu>,
);
expect(wrapper.find(Menu.Item).at(0).find(Tooltip).props().title).toBe('item');
expect(wrapper.find(Menu.Item).at(1).find(Tooltip).props().title).toBe('title');
expect(wrapper.find(Menu.Item).at(2).find(Tooltip).props().title).toBe('item');
expect(wrapper.find(Menu.Item).at(3).find(Tooltip).props().title).toBe(null);
expect(wrapper.find(Menu.Item).at(4).find(Tooltip).props().title).toBe('');
expect(wrapper.find(Menu.Item).at(4).find(Tooltip).props().title).toBe('');
fireEvent.mouseEnter(container.querySelectorAll('li.ant-menu-item')[0]);
fireEvent.mouseEnter(container.querySelectorAll('li.ant-menu-item')[1]);
fireEvent.mouseEnter(container.querySelectorAll('li.ant-menu-item')[2]);
fireEvent.mouseEnter(container.querySelectorAll('li.ant-menu-item')[3]);
fireEvent.mouseEnter(container.querySelectorAll('li.ant-menu-item')[4]);
fireEvent.mouseEnter(container.querySelectorAll('li.ant-menu-item')[5]);
triggerAllTimer();
// when title is null or '' and false, tooltip will not render.
expect(container.querySelectorAll('.ant-tooltip-inner').length).toBe(3);
expect(container.querySelectorAll('.ant-tooltip-inner')[0].textContent).toBe('item');
expect(container.querySelectorAll('.ant-tooltip-inner')[1].textContent).toBe('title');
expect(container.querySelectorAll('.ant-tooltip-inner')[2].textContent).toBe('item');
});
describe('open submenu when click submenu title', () => {
@ -637,7 +669,7 @@ describe('Menu', () => {
});
it('inline title', () => {
const wrapper = mount(
const { container } = render(
<Menu mode="inline" inlineCollapsed>
<Menu.Item key="1" title="bamboo lucky" icon={<PieChartOutlined />}>
Option 1
@ -649,13 +681,10 @@ describe('Menu', () => {
</Menu.Item>
</Menu>,
);
wrapper.find('.ant-menu-item').hostNodes().simulate('mouseenter');
fireEvent.mouseEnter(container.querySelector('.ant-menu-item'));
triggerAllTimer();
wrapper.update();
const text = wrapper.find('.ant-tooltip-inner').text();
expect(text).toBe('bamboo lucky');
expect(container.querySelector('.ant-tooltip-inner').textContent).toBe('bamboo lucky');
});
it('render correctly when using with Layout.Sider', () => {
@ -684,34 +713,34 @@ describe('Menu', () => {
);
}
}
const wrapper = mount(<Demo />);
expect(wrapper.find(Menu).at(0).getDOMNode().classList.contains('ant-menu-inline')).toBe(true);
wrapper.find('.ant-menu-submenu-title').simulate('click');
wrapper.find('.ant-layout-sider-trigger').simulate('click');
const { container } = render(<Demo />);
expect(container.querySelector('ul.ant-menu-root')).toHaveClass('ant-menu-inline');
fireEvent.click(container.querySelector('.ant-menu-submenu-title'));
fireEvent.click(container.querySelector('.ant-layout-sider-trigger'));
triggerAllTimer();
wrapper.update();
expect(wrapper.find(Menu).getDOMNode().classList.contains('ant-menu-inline-collapsed')).toBe(
true,
);
wrapper.find(Menu).simulate('mouseenter');
expect(wrapper.find(Menu).getDOMNode().classList.contains('ant-menu-inline')).toBe(false);
expect(wrapper.find(Menu).getDOMNode().classList.contains('ant-menu-vertical')).toBe(true);
expect(container.querySelector('ul.ant-menu-root')).toHaveClass('ant-menu-inline-collapsed');
fireEvent.mouseEnter(container.querySelector('ul.ant-menu-root'));
expect(container.querySelector('ul.ant-menu-root')).not.toHaveClass('ant-menu-inline');
expect(container.querySelector('ul.ant-menu-root')).toHaveClass('ant-menu-vertical');
});
it('onMouseEnter should work', () => {
const onMouseEnter = jest.fn();
const wrapper = mount(
const { container } = render(
<Menu onMouseEnter={onMouseEnter} defaultSelectedKeys={['test1']}>
<Menu.Item key="test1">Navigation One</Menu.Item>
<Menu.Item key="test2">Navigation Two</Menu.Item>
</Menu>,
);
wrapper.find('ul.ant-menu-root').simulate('mouseenter');
fireEvent.mouseEnter(container.querySelector('ul.ant-menu-root'));
expect(onMouseEnter).toHaveBeenCalled();
});
it('MenuItem should not render Tooltip when inlineCollapsed is false', () => {
const wrapper = mount(
const { container } = render(
<Menu defaultSelectedKeys={['mail']} defaultOpenKeys={['mail']} mode="horizontal">
<Menu.Item key="mail" icon={<MailOutlined />}>
Navigation One
@ -728,29 +757,27 @@ describe('Menu', () => {
{ attachTo: div },
);
wrapper.find('li.ant-menu-item').first().simulate('mouseenter');
fireEvent.mouseEnter(container.querySelector('li.ant-menu-item'));
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find('.ant-tooltip-inner').length).toBe(0);
expect(container.querySelectorAll('.ant-tooltip-inner').length).toBe(0);
});
it('MenuItem should render icon and icon should be the first child when icon exists', () => {
const wrapper = mount(
const { container } = render(
<Menu>
<Menu.Item key="mail" icon={<MailOutlined />}>
Navigation One
</Menu.Item>
</Menu>,
);
expect(wrapper.find('.ant-menu-item .anticon').hasClass('anticon-mail')).toBe(true);
expect(container.querySelector('.ant-menu-item .anticon')).toHaveClass('anticon-mail');
});
it('should controlled collapse work', () => {
const wrapper = mount(
const { asFragment, rerender } = render(
<Menu mode="inline" inlineCollapsed={false}>
<Menu.Item key="1" icon={<PieChartOutlined />}>
Option 1
@ -758,30 +785,34 @@ describe('Menu', () => {
</Menu>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(asFragment()).toMatchSnapshot();
wrapper.setProps({ inlineCollapsed: true });
rerender(
<Menu mode="inline" inlineCollapsed>
<Menu.Item key="1" icon={<PieChartOutlined />}>
Option 1
</Menu.Item>
</Menu>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(asFragment()).toMatchSnapshot();
});
it('not title if not collapsed', () => {
jest.useFakeTimers();
const wrapper = mount(
const { container } = render(
<Menu mode="inline" inlineCollapsed={false}>
<Menu.Item key="1" icon={<PieChartOutlined />}>
Option 1
</Menu.Item>
</Menu>,
);
wrapper.find('.ant-menu-item').hostNodes().simulate('mouseenter');
fireEvent.mouseEnter(container.querySelector('.ant-menu-item'));
act(() => {
jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find('.ant-tooltip-inner').length).toBeFalsy();
expect(container.querySelectorAll('.ant-tooltip-inner').length).toBeFalsy();
jest.useRealTimers();
});
@ -824,45 +855,42 @@ describe('Menu', () => {
// https://github.com/ant-design/ant-design/issues/8587
it('should keep selectedKeys in state when collapsed to 0px', () => {
jest.useFakeTimers();
const wrapper = mount(
const Demo = props => (
<Menu
mode="inline"
inlineCollapsed={false}
defaultSelectedKeys={['1']}
collapsedWidth={0}
openKeys={['3']}
{...props}
>
<Menu.Item key="1">Option 1</Menu.Item>
<Menu.Item key="2">Option 2</Menu.Item>
<Menu.SubMenu key="3" title="Option 3">
<Menu.Item key="4">Option 4</Menu.Item>
</Menu.SubMenu>
</Menu>,
</Menu>
);
expect(wrapper.find('li.ant-menu-item-selected').getDOMNode().textContent).toBe('Option 1');
wrapper.find('li.ant-menu-item').at(1).simulate('click');
expect(wrapper.find('li.ant-menu-item-selected').getDOMNode().textContent).toBe('Option 2');
wrapper.setProps({ inlineCollapsed: true });
const { container, rerender } = render(<Demo />);
expect(container.querySelector('li.ant-menu-item-selected').textContent).toBe('Option 1');
fireEvent.click(container.querySelectorAll('li.ant-menu-item')[1]);
expect(container.querySelector('li.ant-menu-item-selected').textContent).toBe('Option 2');
rerender(<Demo inlineCollapsed />);
act(() => {
jest.runAllTimers();
wrapper.update();
});
expect(container.querySelector('li.ant-menu-item-selected').textContent).toBe('O');
expect(
wrapper
.find('PopupTrigger')
.map(node => node.prop('popupVisible'))
.findIndex(node => !!node),
).toBe(-1);
rerender(<Demo inlineCollapsed={false} />);
wrapper.setProps({ inlineCollapsed: false });
expect(wrapper.find('li.ant-menu-item-selected').getDOMNode().textContent).toBe('Option 2');
expect(container.querySelector('li.ant-menu-item-selected').textContent).toBe('Option 2');
jest.useRealTimers();
});
it('Menu.Item with icon children auto wrap span', () => {
const wrapper = mount(
const { asFragment } = render(
<Menu>
<Menu.Item key="1" icon={<MailOutlined />}>
Navigation One
@ -874,7 +902,7 @@ describe('Menu', () => {
<Menu.SubMenu key="4" icon={<MailOutlined />} title={<span>Navigation One</span>} />
</Menu>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(asFragment()).toMatchSnapshot();
});
// https://github.com/ant-design/ant-design/issues/23755
@ -901,25 +929,29 @@ describe('Menu', () => {
</>
);
}
const wrapper = mount(<App />);
wrapper.find('button').simulate('click');
const { container } = render(<App />);
fireEvent.click(container.querySelector('button'));
expect(onOpenChange).toHaveBeenCalledWith([]);
});
it('Use first char as Icon when collapsed', () => {
const wrapper = mount(
const { container } = render(
<Menu mode="inline" inlineCollapsed>
<Menu.SubMenu title="Light" />
<Menu.Item>Bamboo</Menu.Item>
</Menu>,
);
expect(wrapper.find('.ant-menu-inline-collapsed-noicon').first().text()).toEqual('L');
expect(wrapper.find('.ant-menu-inline-collapsed-noicon').last().text()).toEqual('B');
expect(container.querySelectorAll('.ant-menu-inline-collapsed-noicon')[0].textContent).toEqual(
'L',
);
expect(container.querySelectorAll('.ant-menu-inline-collapsed-noicon')[1].textContent).toEqual(
'B',
);
});
it('divider should show', () => {
const wrapper = mount(
const { container } = render(
<Menu mode="vertical">
<SubMenu key="sub1" title="Navigation One">
<Menu.Item key="1">Option 1</Menu.Item>
@ -935,8 +967,8 @@ describe('Menu', () => {
</Menu>,
);
expect(wrapper.find('li.ant-menu-item-divider').length).toBe(2);
expect(wrapper.find('li.ant-menu-item-divider-dashed').length).toBe(1);
expect(container.querySelectorAll('li.ant-menu-item-divider').length).toBe(2);
expect(container.querySelectorAll('li.ant-menu-item-divider-dashed').length).toBe(1);
});
it('should support ref', async () => {
@ -952,7 +984,7 @@ describe('Menu', () => {
});
it('expandIcon', () => {
const wrapper = mount(
const { container } = render(
<Menu defaultOpenKeys={['1']} mode="inline" expandIcon={() => <span className="bamboo" />}>
<SubMenu key="1" title="submenu1">
<Menu.Item key="submenu1">Option 1</Menu.Item>
@ -960,11 +992,11 @@ describe('Menu', () => {
</Menu>,
);
expect(wrapper.exists('.bamboo')).toBeTruthy();
expect(container.querySelector('.bamboo')).toBeTruthy();
});
it('all types must be available in the "items" syntax', () => {
const wrapper = mount(
const { asFragment } = render(
<Menu
mode="inline"
defaultOpenKeys={['submenu', 'group-submenu']}
@ -1002,12 +1034,12 @@ describe('Menu', () => {
/>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(asFragment()).toMatchSnapshot();
});
it('should not warning deprecated message when items={undefined}', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
mount(<Menu items={undefined} />);
render(<Menu items={undefined} />);
expect(errorSpy).not.toHaveBeenCalledWith(
expect.stringContaining('`children` will be removed in next major version'),
);

View File

@ -1,40 +1,39 @@
import { mount } from 'enzyme';
import React from 'react';
import Popover from '..';
import mountTest from '../../../tests/shared/mountTest';
import { render } from '../../../tests/utils';
import { render, fireEvent } from '../../../tests/utils';
import ConfigProvider from '../../config-provider';
describe('Popover', () => {
mountTest(Popover);
it('should show overlay when trigger is clicked', () => {
const ref = React.createRef();
const ref = React.createRef<any>();
const popover = mount(
const popover = render(
<Popover ref={ref} content="console.log('hello world')" title="code" trigger="click">
<span>show me your code</span>
</Popover>,
);
expect(ref.current.getPopupDomNode()).toBe(null);
popover.find('span').simulate('click');
expect(popover.find('Trigger PopupInner').props().visible).toBeTruthy();
expect(popover.container.querySelector('.ant-popover-inner-content')).toBeFalsy();
fireEvent.click(popover.container.querySelector('span')!);
expect(popover.container.querySelector('.ant-popover-inner-content')).toBeTruthy();
});
it('shows content for render functions', () => {
const renderTitle = () => 'some-title';
const renderContent = () => 'some-content';
const ref = React.createRef();
const ref = React.createRef<any>();
const popover = mount(
const popover = render(
<Popover ref={ref} content={renderContent} title={renderTitle} trigger="click">
<span>show me your code</span>
<span>show me your code </span>
</Popover>,
);
popover.find('span').simulate('click');
fireEvent.click(popover.container.querySelector('span')!);
const popup = ref.current.getPopupDomNode();
expect(popup).not.toBe(null);
@ -44,30 +43,31 @@ describe('Popover', () => {
});
it('handles empty title/content props safely', () => {
const ref = React.createRef();
const ref = React.createRef<any>();
const popover = mount(
const popover = render(
<Popover trigger="click" ref={ref}>
<span>show me your code</span>
</Popover>,
);
popover.find('span').simulate('click');
fireEvent.click(popover.container.querySelector('span')!);
const popup = ref.current.getPopupDomNode();
expect(popup).toBe(null);
});
it('should not render popover when the title & content props is empty', () => {
const ref = React.createRef();
const ref = React.createRef<any>();
const popover = mount(
const popover = render(
<Popover trigger="click" ref={ref} content="">
<span>show me your code</span>
</Popover>,
);
popover.find('span').simulate('click');
fireEvent.click(popover.container.querySelector('span')!);
const popup = ref.current.getPopupDomNode();
expect(popup).toBe(null);
@ -88,13 +88,13 @@ describe('Popover', () => {
});
it(`should be rendered correctly in RTL direction`, () => {
const wrapper = mount(
const wrapper = render(
<ConfigProvider direction="rtl">
<Popover title="RTL" visible>
<span>show me your Rtl demo</span>
</Popover>
</ConfigProvider>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(Array.from(wrapper.container.children)).toMatchSnapshot();
});
});

View File

@ -65,7 +65,6 @@
background-clip: padding-box;
border-radius: @border-radius-base;
box-shadow: @box-shadow-base;
box-shadow: ~'0 0 8px @{shadow-color} \9';
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {

View File

@ -844,6 +844,435 @@ exports[`renders ./components/steps/demo/icon.md extend context correctly 1`] =
</div>
`;
exports[`renders ./components/steps/demo/label-placement.md extend context correctly 1`] = `
Array [
<div
class="ant-steps ant-steps-horizontal ant-steps-label-vertical"
>
<div
class="ant-steps-item ant-steps-item-finish"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
<span
aria-label="check"
class="anticon anticon-check ant-steps-finish-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Finished
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-process ant-steps-item-active"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
2
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
In Progress
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-wait"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
3
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Waiting
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
</div>,
<br />,
<div
class="ant-steps ant-steps-horizontal ant-steps-with-progress ant-steps-label-vertical"
>
<div
class="ant-steps-item ant-steps-item-finish"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
<span
aria-label="check"
class="anticon anticon-check ant-steps-finish-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Finished
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-process ant-steps-item-active"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<div
class="ant-steps-progress-icon"
>
<div
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
>
<div
class="ant-progress-inner"
style="width:40px;height:40px;font-size:12px"
>
<svg
class="ant-progress-circle"
viewBox="0 0 100 100"
>
<circle
class="ant-progress-circle-trail"
cx="50"
cy="50"
r="48"
stroke-linecap="round"
stroke-width="4"
style="stroke-dasharray:301.59289474462014px 301.59289474462014;stroke-dashoffset:0;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;fill-opacity:0"
/>
<circle
class="ant-progress-circle-path"
cx="50"
cy="50"
opacity="1"
r="48"
stroke-linecap="round"
stroke-width="4"
style="stroke-dasharray:301.59289474462014px 301.59289474462014;stroke-dashoffset:122.63715789784806;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;fill-opacity:0"
/>
<circle
class="ant-progress-circle-path"
cx="50"
cy="50"
opacity="0"
r="48"
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:301.59289474462014px 301.59289474462014;stroke-dashoffset:301.58289474462015;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;fill-opacity:0"
/>
</svg>
<span
class="ant-progress-text"
/>
</div>
</div>
<span
class="ant-steps-icon"
>
2
</span>
</div>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
In Progress
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-wait"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
3
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Waiting
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
</div>,
<br />,
<div
class="ant-steps ant-steps-horizontal ant-steps-small ant-steps-label-vertical"
>
<div
class="ant-steps-item ant-steps-item-finish"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
<span
aria-label="check"
class="anticon anticon-check ant-steps-finish-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Finished
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-process ant-steps-item-active"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
2
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
In Progress
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-wait"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
3
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Waiting
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/steps/demo/nav.md extend context correctly 1`] = `
Array [
<div

View File

@ -724,6 +724,435 @@ exports[`renders ./components/steps/demo/icon.md correctly 1`] = `
</div>
`;
exports[`renders ./components/steps/demo/label-placement.md correctly 1`] = `
Array [
<div
class="ant-steps ant-steps-horizontal ant-steps-label-vertical"
>
<div
class="ant-steps-item ant-steps-item-finish"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
<span
aria-label="check"
class="anticon anticon-check ant-steps-finish-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Finished
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-process ant-steps-item-active"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
2
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
In Progress
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-wait"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
3
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Waiting
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
</div>,
<br />,
<div
class="ant-steps ant-steps-horizontal ant-steps-with-progress ant-steps-label-vertical"
>
<div
class="ant-steps-item ant-steps-item-finish"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
<span
aria-label="check"
class="anticon anticon-check ant-steps-finish-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Finished
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-process ant-steps-item-active"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<div
class="ant-steps-progress-icon"
>
<div
class="ant-progress ant-progress-circle ant-progress-status-normal ant-progress-show-info ant-progress-default"
>
<div
class="ant-progress-inner"
style="width:40px;height:40px;font-size:12px"
>
<svg
class="ant-progress-circle"
viewBox="0 0 100 100"
>
<circle
class="ant-progress-circle-trail"
cx="50"
cy="50"
r="48"
stroke-linecap="round"
stroke-width="4"
style="stroke-dasharray:301.59289474462014px 301.59289474462014;stroke-dashoffset:0;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;fill-opacity:0"
/>
<circle
class="ant-progress-circle-path"
cx="50"
cy="50"
opacity="1"
r="48"
stroke-linecap="round"
stroke-width="4"
style="stroke-dasharray:301.59289474462014px 301.59289474462014;stroke-dashoffset:122.63715789784806;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;fill-opacity:0"
/>
<circle
class="ant-progress-circle-path"
cx="50"
cy="50"
opacity="0"
r="48"
stroke-linecap="round"
stroke-width="4"
style="stroke:#52C41A;stroke-dasharray:301.59289474462014px 301.59289474462014;stroke-dashoffset:301.58289474462015;transform:rotate(-90deg);transform-origin:50% 50%;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s;fill-opacity:0"
/>
</svg>
<span
class="ant-progress-text"
/>
</div>
</div>
<span
class="ant-steps-icon"
>
2
</span>
</div>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
In Progress
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-wait"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
3
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Waiting
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
</div>,
<br />,
<div
class="ant-steps ant-steps-horizontal ant-steps-small ant-steps-label-vertical"
>
<div
class="ant-steps-item ant-steps-item-finish"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
<span
aria-label="check"
class="anticon anticon-check ant-steps-finish-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="check"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"
/>
</svg>
</span>
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Finished
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-process ant-steps-item-active"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
2
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
In Progress
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
<div
class="ant-steps-item ant-steps-item-wait"
>
<div
class="ant-steps-item-container"
>
<div
class="ant-steps-item-tail"
/>
<div
class="ant-steps-item-icon"
>
<span
class="ant-steps-icon"
>
3
</span>
</div>
<div
class="ant-steps-item-content"
>
<div
class="ant-steps-item-title"
>
Waiting
</div>
<div
class="ant-steps-item-description"
>
This is a description.
</div>
</div>
</div>
</div>
</div>,
]
`;
exports[`renders ./components/steps/demo/nav.md correctly 1`] = `
Array [
<div

View File

@ -0,0 +1,45 @@
---
order: 14
title:
zh-CN: 标签放置位置
en-US: Label Placement
---
## zh-CN
修改标签放置位置为 `vertical`
## en-US
Set labelPlacement to `vertical`.
```tsx
import { Steps } from 'antd';
import React from 'react';
const { Step } = Steps;
const App: React.FC = () => (
<>
<Steps current={1} labelPlacement="vertical">
<Step title="Finished" description="This is a description." />
<Step title="In Progress" description="This is a description." />
<Step title="Waiting" description="This is a description." />
</Steps>
<br />
<Steps current={1} percent={60} labelPlacement="vertical">
<Step title="Finished" description="This is a description." />
<Step title="In Progress" description="This is a description." />
<Step title="Waiting" description="This is a description." />
</Steps>
<br />
<Steps current={1} size="small" labelPlacement="vertical">
<Step title="Finished" description="This is a description." />
<Step title="In Progress" description="This is a description." />
<Step title="Waiting" description="This is a description." />
</Steps>
</>
);
export default App;
```

View File

@ -9,9 +9,17 @@
}
}
&.@{steps-prefix-cls}-horizontal .@{steps-prefix-cls}-item:first-child {
padding-bottom: 4px;
padding-left: 4px;
&.@{steps-prefix-cls}-horizontal {
.@{steps-prefix-cls}-item:first-child {
padding-bottom: 4px;
padding-left: 4px;
}
}
&.@{steps-prefix-cls}-label-vertical {
.@{steps-prefix-cls}-item .@{steps-prefix-cls}-item-tail {
top: 14px !important;
}
}
.@{steps-prefix-cls}-item-icon {

View File

@ -33,6 +33,7 @@ function renderExpandIcon(locale: TableLocale) {
[`${iconPrefix}-collapsed`]: expandable && !expanded,
})}
aria-label={expanded ? locale.collapse : locale.expand}
aria-expanded={expanded}
/>
);
};

View File

@ -61,7 +61,7 @@ interface ChangeEventInfo<RecordType> {
total?: number;
};
filters: Record<string, FilterValue | null>;
sorter: SorterResult<RecordType> | SorterResult<RecordType[]>;
sorter: SorterResult<RecordType> | SorterResult<RecordType>[];
filterStates: FilterState<RecordType>[];
sorterStates: SortState<RecordType>[];
@ -92,7 +92,7 @@ export interface TableProps<RecordType>
onChange?: (
pagination: TablePaginationConfig,
filters: Record<string, FilterValue | null>,
sorter: SorterResult<RecordType> | SorterResult<RecordType[]>,
sorter: SorterResult<RecordType> | SorterResult<RecordType>[],
extra: TableCurrentDataSource<RecordType>,
) => void;
rowSelection?: TableRowSelection<RecordType>;
@ -263,7 +263,7 @@ function InternalTable<RecordType extends object = any>(
// ============================ Sorter =============================
const onSorterChange = (
sorter: SorterResult<RecordType> | SorterResult<RecordType[]>,
sorter: SorterResult<RecordType> | SorterResult<RecordType>[],
sorterStates: SortState<RecordType>[],
) => {
triggerOnChange(

View File

@ -81,6 +81,13 @@ describe('Table.expand', () => {
fireEvent.click(container.querySelector('.ant-table-row-expand-icon'));
expect(container.querySelector('.indent-level-1').style.paddingLeft).toEqual('0px');
});
it('has right aria-expanded state', () => {
const { container } = render(<Table columns={columns} dataSource={data} />);
expect(container.querySelector('[aria-expanded=false]')).toBeTruthy();
fireEvent.click(container.querySelector('.ant-table-row-expand-icon'));
expect(container.querySelector('[aria-expanded=true]')).toBeTruthy();
});
describe('expandIconColumnIndex', () => {
it('basic', () => {

View File

@ -992,4 +992,104 @@ describe('Table.sorter', () => {
clickToMatchExpect(1, { field: 'english', order: 'descend' });
clickToMatchExpect(1, { field: 'english', order: undefined });
});
// https://github.com/ant-design/ant-design/issues/37024
it('multiple sort should pass array sorter as onChange param', () => {
const columns = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Chinese Score',
dataIndex: 'chinese',
sorter: {
compare: (a, b) => a.chinese - b.chinese,
multiple: 3,
},
},
{
title: 'Math Score',
dataIndex: 'math',
sorter: {
compare: (a, b) => a.math - b.math,
multiple: 2,
},
},
{
title: 'English Score',
dataIndex: 'english',
sorter: {
compare: (a, b) => a.english - b.english,
multiple: 1,
},
},
];
const tableData = [
{
key: '1',
name: 'John Brown',
chinese: 98,
math: 60,
english: 70,
},
{
key: '2',
name: 'Jim Green',
chinese: 98,
math: 66,
english: 89,
},
{
key: '3',
name: 'Joe Black',
chinese: 98,
math: 90,
english: 70,
},
{
key: '4',
name: 'Jim Red',
chinese: 88,
math: 99,
english: 89,
},
];
const onChange = jest.fn();
const { container } = render(
<Table columns={columns} dataSource={tableData} onChange={onChange} />,
);
const sorterColumns = Array.from(container.querySelectorAll('.ant-table-column-has-sorters'));
expect(sorterColumns.length).toBe(3);
fireEvent.click(sorterColumns[0]);
expect(onChange).toHaveBeenLastCalledWith(
expect.anything(),
expect.anything(),
expect.objectContaining({ field: 'chinese' }),
expect.anything(),
);
fireEvent.click(sorterColumns[1]);
expect(onChange).toHaveBeenLastCalledWith(
expect.anything(),
expect.anything(),
expect.arrayContaining([
expect.objectContaining({ field: 'chinese' }),
expect.objectContaining({ field: 'math' }),
]),
expect.anything(),
);
fireEvent.click(sorterColumns[2]);
expect(onChange).toHaveBeenLastCalledWith(
expect.anything(),
expect.anything(),
expect.arrayContaining([
expect.objectContaining({ field: 'chinese' }),
expect.objectContaining({ field: 'math' }),
expect.objectContaining({ field: 'english' }),
]),
expect.anything(),
);
});
});

View File

@ -49,6 +49,7 @@ exports[`Table.expand click to expand 1`] = `
style="padding-left: 0px;"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -67,6 +68,7 @@ exports[`Table.expand click to expand 1`] = `
style="padding-left: 15px;"
/>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"

View File

@ -116,6 +116,7 @@ exports[`Table.rowSelection fix expand on th left when selection column fixed on
style="position: sticky; left: 0px;"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -157,6 +158,7 @@ exports[`Table.rowSelection fix expand on th left when selection column fixed on
style="position: sticky; left: 0px;"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -198,6 +200,7 @@ exports[`Table.rowSelection fix expand on th left when selection column fixed on
style="position: sticky; left: 0px;"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -239,6 +242,7 @@ exports[`Table.rowSelection fix expand on th left when selection column fixed on
style="position: sticky; left: 0px;"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"

View File

@ -3672,6 +3672,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3775,6 +3776,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3878,6 +3880,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3981,6 +3984,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -4084,6 +4088,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -4187,6 +4192,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -4290,6 +4296,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -4393,6 +4400,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -4496,6 +4504,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -4599,6 +4608,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -6817,6 +6827,7 @@ exports[`renders ./components/table/demo/expand.md extend context correctly 1`]
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -6853,6 +6864,7 @@ exports[`renders ./components/table/demo/expand.md extend context correctly 1`]
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -6889,6 +6901,7 @@ exports[`renders ./components/table/demo/expand.md extend context correctly 1`]
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -6925,6 +6938,7 @@ exports[`renders ./components/table/demo/expand.md extend context correctly 1`]
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -15952,6 +15966,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -16003,6 +16018,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -16054,6 +16070,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -16276,6 +16293,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -17054,6 +17072,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -17105,6 +17124,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -17317,6 +17337,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -18095,6 +18116,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -18146,6 +18168,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -18358,6 +18381,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -19136,6 +19160,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -19187,6 +19212,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -19416,6 +19442,7 @@ exports[`renders ./components/table/demo/order-column.md extend context correctl
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -19464,6 +19491,7 @@ exports[`renders ./components/table/demo/order-column.md extend context correctl
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -19512,6 +19540,7 @@ exports[`renders ./components/table/demo/order-column.md extend context correctl
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -19560,6 +19589,7 @@ exports[`renders ./components/table/demo/order-column.md extend context correctl
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -26481,6 +26511,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -26529,6 +26560,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -26788,6 +26820,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -26843,6 +26876,7 @@ Array [
style="padding-left:15px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -26898,6 +26932,7 @@ Array [
style="padding-left:15px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -26953,6 +26988,7 @@ Array [
style="padding-left:30px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -27008,6 +27044,7 @@ Array [
style="padding-left:15px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -27063,6 +27100,7 @@ Array [
style="padding-left:30px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -27118,6 +27156,7 @@ Array [
style="padding-left:45px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -27173,6 +27212,7 @@ Array [
style="padding-left:45px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -27228,6 +27268,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"

View File

@ -2945,6 +2945,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3048,6 +3049,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3151,6 +3153,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3254,6 +3257,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3357,6 +3361,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3460,6 +3465,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3563,6 +3569,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3666,6 +3673,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3769,6 +3777,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -3872,6 +3881,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -5536,6 +5546,7 @@ exports[`renders ./components/table/demo/expand.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -5572,6 +5583,7 @@ exports[`renders ./components/table/demo/expand.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -5608,6 +5620,7 @@ exports[`renders ./components/table/demo/expand.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -5644,6 +5657,7 @@ exports[`renders ./components/table/demo/expand.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -12174,6 +12188,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -12225,6 +12240,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -12276,6 +12292,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -12498,6 +12515,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -12889,6 +12907,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -12940,6 +12959,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -13152,6 +13172,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -13543,6 +13564,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -13594,6 +13616,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -13806,6 +13829,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -14197,6 +14221,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -14248,6 +14273,7 @@ Array [
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -14477,6 +14503,7 @@ exports[`renders ./components/table/demo/order-column.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -14525,6 +14552,7 @@ exports[`renders ./components/table/demo/order-column.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -14573,6 +14601,7 @@ exports[`renders ./components/table/demo/order-column.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -14621,6 +14650,7 @@ exports[`renders ./components/table/demo/order-column.md correctly 1`] = `
class="ant-table-cell ant-table-row-expand-icon-cell"
>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -20660,6 +20690,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
type="button"
@ -20708,6 +20739,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="false"
aria-label="Expand row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -20967,6 +20999,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -21022,6 +21055,7 @@ Array [
style="padding-left:15px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -21077,6 +21111,7 @@ Array [
style="padding-left:15px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -21132,6 +21167,7 @@ Array [
style="padding-left:30px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -21187,6 +21223,7 @@ Array [
style="padding-left:15px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -21242,6 +21279,7 @@ Array [
style="padding-left:30px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-expanded"
type="button"
@ -21297,6 +21335,7 @@ Array [
style="padding-left:45px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -21352,6 +21391,7 @@ Array [
style="padding-left:45px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"
@ -21407,6 +21447,7 @@ Array [
style="padding-left:0px"
/>
<button
aria-expanded="true"
aria-label="Collapse row"
class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
type="button"

View File

@ -36,12 +36,6 @@ describe('Table.typescript', () => {
const table = <Table<RecordType> dataSource={[{ key: 'Bamboo' }]} />;
expect(table).toBeTruthy();
});
it('Sorter types', () => {
const table = <Table onChange={(_pagination, _filters, sorter) => sorter.field} />;
expect(table).toBeTruthy();
});
});
describe('Table.typescript types', () => {

View File

@ -247,7 +247,7 @@ function stateToInfo<RecordType>(sorterStates: SortState<RecordType>) {
function generateSorterInfo<RecordType>(
sorterStates: SortState<RecordType>[],
): SorterResult<RecordType> | SorterResult<RecordType[]> {
): SorterResult<RecordType> | SorterResult<RecordType>[] {
const list = sorterStates.filter(({ sortOrder }) => sortOrder).map(stateToInfo);
// =========== Legacy compatible support ===========
@ -259,7 +259,11 @@ function generateSorterInfo<RecordType>(
};
}
return list[0] || {};
if (list.length <= 1) {
return list[0] || {};
}
return list;
}
export function getSortData<RecordType>(
@ -320,7 +324,7 @@ interface SorterConfig<RecordType> {
prefixCls: string;
mergedColumns: ColumnsType<RecordType>;
onSorterChange: (
sorterResult: SorterResult<RecordType> | SorterResult<RecordType[]>,
sorterResult: SorterResult<RecordType> | SorterResult<RecordType>[],
sortStates: SortState<RecordType>[],
) => void;
sortDirections: SortOrder[];
@ -339,7 +343,7 @@ export default function useFilterSorter<RecordType>({
TransformColumns<RecordType>,
SortState<RecordType>[],
ColumnTitleProps<RecordType>,
() => SorterResult<RecordType> | SorterResult<RecordType[]>,
() => SorterResult<RecordType> | SorterResult<RecordType>[],
] {
const [sortStates, setSortStates] = React.useState<SortState<RecordType>[]>(
collectSortStates(mergedColumns, true),

View File

@ -1,11 +1,12 @@
import { mount } from 'enzyme';
import moment from 'moment';
import React from 'react';
import type { PickerLocale } from 'antd/es/date-picker/generatePicker';
import TimePicker from '..';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import { resetWarned } from '../../_util/warning';
import { render } from '../../../tests/utils';
describe('TimePicker', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
@ -29,83 +30,86 @@ describe('TimePicker', () => {
OK
</button>
);
const wrapper = mount(<TimePicker addon={addon} open />);
expect(wrapper.find('.my-btn').length).toBeTruthy();
const { container } = render(<TimePicker addon={addon} open />);
expect(container.querySelectorAll('.my-btn').length).toBeTruthy();
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: TimePicker] `addon` is deprecated. Please use `renderExtraFooter` instead.',
);
});
it('not render clean icon when allowClear is false', () => {
const wrapper = mount(
const { container } = render(
<TimePicker defaultValue={moment('2000-01-01 00:00:00')} allowClear={false} />,
);
expect(wrapper.render()).toMatchSnapshot();
expect(container.firstChild).toMatchSnapshot();
});
it('clearIcon should render correctly', () => {
const clearIcon = <div className="test-clear-icon">test</div>;
const wrapper = mount(<TimePicker clearIcon={clearIcon} />);
expect(wrapper.find('Picker').last().prop('clearIcon')).toEqual(
<div className="test-clear-icon">test</div>,
const { container } = render(
<TimePicker clearIcon={clearIcon} value={moment('00:00:00', 'HH:mm:ss')} />,
);
expect(container.querySelector('.test-clear-icon')).toBeTruthy();
});
it('prop locale should works', () => {
const locale = {
placeholder: 'Избери дата',
};
const wrapper = mount(
<TimePicker defaultValue={moment('2000-01-01 00:00:00')} open locale={locale} />,
const locale = { placeholder: 'Избери дата' };
const { container } = render(
<TimePicker
open
defaultValue={moment('2000-01-01 00:00:00')}
locale={locale as unknown as PickerLocale}
/>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(Array.from(container.children)).toMatchSnapshot();
});
it('should pass popupClassName prop to Picker as dropdownClassName prop', () => {
const popupClassName = 'myCustomClassName';
const wrapper = mount(
const { container } = render(
<TimePicker
open
defaultOpenValue={moment('00:00:00', 'HH:mm:ss')}
popupClassName={popupClassName}
/>,
);
expect(wrapper.find('Picker').last().prop('dropdownClassName')).toEqual(popupClassName);
expect(container.querySelector(`.${popupClassName}`)).toBeTruthy();
});
it('should pass popupClassName prop to RangePicker as dropdownClassName prop', () => {
const popupClassName = 'myCustomClassName';
const wrapper = mount(
const { container } = render(
<TimePicker.RangePicker
open
defaultOpenValue={moment('00:00:00', 'HH:mm:ss')}
popupClassName={popupClassName}
/>,
);
expect(wrapper.find('RangePicker').last().prop('dropdownClassName')).toEqual(popupClassName);
expect(container.querySelector(`.${popupClassName}`)).toBeTruthy();
});
it('RangePicker should show warning when use dropdownClassName', () => {
mount(<TimePicker.RangePicker dropdownClassName="myCustomClassName" />);
render(<TimePicker.RangePicker dropdownClassName="myCustomClassName" />);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: RangePicker] `dropdownClassName` is deprecated which will be removed in next major version. Please use `popupClassName` instead.',
);
});
it('TimePicker should show warning when use dropdownClassName', () => {
mount(<TimePicker dropdownClassName="myCustomClassName" />);
render(<TimePicker dropdownClassName="myCustomClassName" />);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: TimePicker] `dropdownClassName` is deprecated which will be removed in next major version. Please use `popupClassName` instead.',
);
});
it('should support bordered', () => {
const wrapper = mount(
const { container } = render(
<TimePicker
className="custom-class"
defaultValue={moment('2000-01-01 00:00:00')}
bordered={false}
/>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(container.firstChild).toMatchSnapshot();
});
});

View File

@ -17,7 +17,11 @@ Please find below some of the design resources and tools about Ant Design that w
- Sketch Symbols
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
- Sketch Symbols for Desktop
- https://github.com/ant-design/ant-design/files/2051729/Ant.Design.Template.sketch.zip
- https://gw.alipayobjects.com/os/bmw-prod/a5ff1d86-44cd-4b86-92f8-daab59cba5b7.sketch
- Sketch Symbols (Dark)
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
- Sketch Symbols for Desktop with dark theme
- https://gw.alipayobjects.com/os/bmw-prod/6b670a1c-26e3-4379-9c86-7a2b95e170e5.sketch
- Mobile Components
- https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg
- Sketch Symbols File for Mobile

View File

@ -17,7 +17,11 @@ toc: false
- Sketch 组件包
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
- 桌面组件 Sketch 模板包
- https://gw.alipayobjects.com/os/antfincdn/EfSt1N5LCk/Ant.Design.Components.4.0.zip
- https://gw.alipayobjects.com/os/bmw-prod/82c08c51-9993-4568-90c1-249c8301c0af.sketch
- Sketch 组件包 (暗色)
- https://gw.alipayobjects.com/zos/basement_prod/048ee28f-2c80-4d15-9aa3-4f5ddac50465.svg
- 桌面组件 Sketch 模板包,内含暗色版本的 antd 组件
- https://gw.alipayobjects.com/os/bmw-prod/f002145c-33d9-408e-ba75-a1a68896dfa3.sketch
- Mobile Components
- https://gw.alipayobjects.com/zos/basement_prod/c0c3852c-d245-4330-886b-cb02ef49eb6d.svg
- 移动组件 Sketch 模板

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "4.22.4",
"version": "4.22.6",
"description": "An enterprise-class UI design language and React components implementation",
"title": "Ant Design",
"keywords": [
@ -119,7 +119,6 @@
"@ant-design/react-slick": "~0.29.1",
"@babel/runtime": "^7.18.3",
"@ctrl/tinycolor": "^3.4.0",
"@testing-library/user-event": "^14.4.2",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.2.0",
"lodash": "^4.17.21",
@ -136,7 +135,7 @@
"rc-input": "~0.1.2",
"rc-input-number": "~7.3.5",
"rc-mentions": "~1.9.1",
"rc-menu": "~9.6.0",
"rc-menu": "~9.6.3",
"rc-motion": "^2.6.1",
"rc-notification": "~4.6.0",
"rc-pagination": "~3.1.17",
@ -170,6 +169,7 @@
"@stackblitz/sdk": "^1.3.0",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^12.0.0",
"@testing-library/user-event": "^14.4.2",
"@types/enzyme": "^3.10.5",
"@types/gtag.js": "^0.0.10",
"@types/jest": "^28.0.0",
@ -289,7 +289,7 @@
"stylelint": "^14.9.0",
"stylelint-config-prettier": "^9.0.2",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-config-standard": "^26.0.0",
"stylelint-config-standard": "^27.0.0",
"stylelint-declaration-block-no-ignored-properties": "^2.1.0",
"stylelint-order": "^5.0.0",
"theme-switcher": "^1.0.2",

View File

@ -8,6 +8,11 @@ const { spawnSync } = require('child_process');
const DEPRECIATED_VERSION = {
'>= 4.21.6 < 4.22.0': ['https://github.com/ant-design/ant-design/pull/36682'],
'>=4.22.2 <=4.22.5': [
'https://github.com/ant-design/ant-design/issues/36932',
'https://github.com/ant-design/ant-design/pull/36800',
'https://github.com/ant-design/ant-design/issues/37024',
],
};
function matchDeprecated(version) {
@ -82,7 +87,12 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
// Not find to use the latest version instead
defaultVersionObj = defaultVersionObj || defaultVersionList[defaultVersionList.length - 1];
const defaultVersion = defaultVersionObj ? defaultVersionObj.value : null;
let defaultVersion = defaultVersionObj ? defaultVersionObj.value : null;
// If default version is less than current, use current
if (semver.compare(defaultVersion, distTags.conch) < 0) {
defaultVersion = distTags.conch;
}
// Selection
let { conchVersion } = await inquirer.prompt([
@ -95,11 +105,24 @@ const SAFE_DAYS_DIFF = 1000 * 60 * 60 * 24 * 3; // 3 days not update seems to be
const { value, publishTime, depreciated } = info;
const desc = moment(publishTime).fromNow();
//
return {
...info,
name: `${depreciated ? '🚨' : '✅'} ${value} (${desc}) ${
value === defaultVersion ? '(default)' : ''
}`,
name: [
// Warning
depreciated ? '🚨' : '✅',
// Version
value,
// Date Diff
`(${desc})`,
// Default Mark
value === defaultVersion ? '(default)' : '',
// Current Mark
value === distTags.conch ? chalk.gray('- current') : '',
]
.filter(str => String(str).trim())
.join(' '),
};
}),
},

View File

@ -17,6 +17,8 @@
}
html {
direction: initial;
&.rtl {
direction: rtl;
}

View File

@ -13,7 +13,6 @@ import './Navigation.less';
export interface NavigationProps extends SharedProps {
isMobile: boolean;
isRTL: boolean;
pathname: string;
responsive: null | 'narrow' | 'crowded';
location: { pathname: string; query: any };

View File

@ -186,7 +186,7 @@ const Header: React.FC<HeaderProps & WrappedComponentProps<'intl'>> = props => {
);
}, [location]);
const getNextDirectionText = useMemo<string>(
const nextDirectionText = useMemo<string>(
() => (direction !== 'rtl' ? 'RTL' : 'LTR'),
[direction],
);
@ -242,7 +242,7 @@ const Header: React.FC<HeaderProps & WrappedComponentProps<'intl'>> = props => {
isMobile={isMobile}
showTechUIButton={showTechUIButton}
pathname={pathname}
directionText={getNextDirectionText}
directionText={nextDirectionText}
onLangChange={onLangChange}
onDirectionChange={onDirectionChange}
/>
@ -275,7 +275,7 @@ const Header: React.FC<HeaderProps & WrappedComponentProps<'intl'>> = props => {
className="header-button header-direction-button"
key="direction-button"
>
{getNextDirectionText}
{nextDirectionText}
</Button>,
<More key="more" {...sharedProps} />,
<Github key="github" responsive={responsive} />,

View File

@ -226,6 +226,7 @@ export default class Layout extends React.Component<LayoutPropsType, LayoutState
appLocale.locale === 'zh-CN'
? '基于 Ant Design 设计体系的 React UI 组件库,用于研发企业级中后台产品。'
: 'An enterprise-class UI design language and React UI library with a set of high-quality React components, one of best React UI library for enterprises';
return (
// eslint-disable-next-line react/jsx-no-constructed-context-values
<SiteContext.Provider value={{ isMobile, direction, theme, setTheme, setIframeTheme }}>