mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 05:05:48 +08:00
fix: Table customize filterDropdown with Menu should not block default selectable (#36098)
* fix: Table customize Menu should be selectable * test: Add test case * test: Update snapshow
This commit is contained in:
parent
f19cf66c88
commit
63fc5055f9
@ -8194,6 +8194,232 @@ exports[`renders ./components/dropdown/demo/placement.md extend context correctl
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/dropdown/demo/selectable.md extend context correctly 1`] = `
|
||||
Array [
|
||||
<a
|
||||
class="ant-typography ant-dropdown-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
Selectable
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>,
|
||||
<div>
|
||||
<div
|
||||
class="ant-dropdown"
|
||||
style="opacity:0"
|
||||
>
|
||||
<ul
|
||||
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
|
||||
data-menu-list="true"
|
||||
role="menu"
|
||||
tabindex="0"
|
||||
>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
Item 1
|
||||
</span>
|
||||
</li>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-dropdown-menu-inline-collapsed-tooltip"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-tooltip-arrow-content"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-only-child"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
Item 2
|
||||
</span>
|
||||
</li>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-dropdown-menu-inline-collapsed-tooltip"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-tooltip-arrow-content"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<li
|
||||
class="ant-dropdown-menu-item ant-dropdown-menu-item-selected ant-dropdown-menu-item-only-child"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="ant-dropdown-menu-title-content"
|
||||
>
|
||||
Item 3
|
||||
</span>
|
||||
</li>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-dropdown-menu-inline-collapsed-tooltip"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-tooltip-arrow-content"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style="display:none"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-dropdown-menu-inline-collapsed-tooltip"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-tooltip-arrow-content"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-dropdown-menu-inline-collapsed-tooltip"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-tooltip-arrow-content"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="ant-tooltip ant-dropdown-menu-inline-collapsed-tooltip"
|
||||
style="opacity:0"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-tooltip-arrow-content"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
role="tooltip"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/dropdown/demo/sub-menu.md extend context correctly 1`] = `
|
||||
Array [
|
||||
<a
|
||||
|
@ -858,6 +858,46 @@ exports[`renders ./components/dropdown/demo/placement.md correctly 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/dropdown/demo/selectable.md correctly 1`] = `
|
||||
<a
|
||||
class="ant-typography ant-dropdown-trigger"
|
||||
>
|
||||
<div
|
||||
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-right:8px"
|
||||
>
|
||||
Selectable
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/dropdown/demo/sub-menu.md correctly 1`] = `
|
||||
<a
|
||||
class="ant-dropdown-trigger"
|
||||
|
54
components/dropdown/demo/selectable.md
Normal file
54
components/dropdown/demo/selectable.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
order: 10
|
||||
title:
|
||||
zh-CN: 菜单可选选择
|
||||
en-US: Selectable Menu
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
为 Menu 添加 `selectable` 属性可以开启选择能力。
|
||||
|
||||
## en-US
|
||||
|
||||
Config Menu `selectable` prop to enable selectable ability.
|
||||
|
||||
```tsx
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import { Dropdown, Menu, Space, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
|
||||
const menu = (
|
||||
<Menu
|
||||
selectable
|
||||
defaultSelectedKeys={['3']}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: 'Item 1',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'Item 2',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: 'Item 3',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Dropdown overlay={menu}>
|
||||
<Typography.Link>
|
||||
<Space>
|
||||
Selectable
|
||||
<DownOutlined />
|
||||
</Space>
|
||||
</Typography.Link>
|
||||
</Dropdown>
|
||||
);
|
||||
|
||||
export default App;
|
||||
```
|
@ -3,8 +3,7 @@ import classNames from 'classnames';
|
||||
import RcDropdown from 'rc-dropdown';
|
||||
import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import type { OverrideContextProps } from '../menu/OverrideContext';
|
||||
import OverrideContext from '../menu/OverrideContext';
|
||||
import { OverrideProvider } from '../menu/OverrideContext';
|
||||
import getPlacements from '../_util/placements';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import { tuple } from '../_util/type';
|
||||
@ -148,28 +147,6 @@ const Dropdown: DropdownInterface = props => {
|
||||
autoAdjustOverflow: true,
|
||||
});
|
||||
|
||||
const overlayContext = React.useMemo<OverrideContextProps>(
|
||||
() => ({
|
||||
prefixCls: `${prefixCls}-menu`,
|
||||
expandIcon: (
|
||||
<span className={`${prefixCls}-menu-submenu-arrow`}>
|
||||
<RightOutlined className={`${prefixCls}-menu-submenu-arrow-icon`} />
|
||||
</span>
|
||||
),
|
||||
mode: 'vertical',
|
||||
selectable: false,
|
||||
validator: ({ mode }) => {
|
||||
// Warning if use other mode
|
||||
warning(
|
||||
!mode || mode === 'vertical',
|
||||
'Dropdown',
|
||||
`mode="${mode}" is not supported for Dropdown's Menu.`,
|
||||
);
|
||||
},
|
||||
}),
|
||||
[prefixCls],
|
||||
);
|
||||
|
||||
const renderOverlay = () => {
|
||||
// rc-dropdown already can process the function of overlay, but we have check logic here.
|
||||
// So we need render the element to check and pass back to rc-dropdown.
|
||||
@ -186,7 +163,26 @@ const Dropdown: DropdownInterface = props => {
|
||||
);
|
||||
|
||||
return (
|
||||
<OverrideContext.Provider value={overlayContext}>{overlayNode}</OverrideContext.Provider>
|
||||
<OverrideProvider
|
||||
prefixCls={`${prefixCls}-menu`}
|
||||
expandIcon={
|
||||
<span className={`${prefixCls}-menu-submenu-arrow`}>
|
||||
<RightOutlined className={`${prefixCls}-menu-submenu-arrow-icon`} />
|
||||
</span>
|
||||
}
|
||||
mode="vertical"
|
||||
selectable={false}
|
||||
validator={({ mode }) => {
|
||||
// Warning if use other mode
|
||||
warning(
|
||||
!mode || mode === 'vertical',
|
||||
'Dropdown',
|
||||
`mode="${mode}" is not supported for Dropdown's Menu.`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
{overlayNode}
|
||||
</OverrideProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import type { MenuProps } from '.';
|
||||
|
||||
// Used for Dropdown only
|
||||
export interface OverrideContextProps {
|
||||
prefixCls?: string;
|
||||
expandIcon?: React.ReactNode;
|
||||
mode?: MenuProps['mode'];
|
||||
selectable?: boolean;
|
||||
validator?: (menuProps: Pick<MenuProps, 'mode'>) => void;
|
||||
}
|
||||
|
||||
/** @private Internal Usage. Only used for Dropdown component. Do not use this in your production. */
|
||||
const OverrideContext = React.createContext<OverrideContextProps | null>(null);
|
||||
|
||||
export default OverrideContext;
|
41
components/menu/OverrideContext.tsx
Normal file
41
components/menu/OverrideContext.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import * as React from 'react';
|
||||
import type { MenuProps } from '.';
|
||||
|
||||
// Used for Dropdown only
|
||||
export interface OverrideContextProps {
|
||||
prefixCls?: string;
|
||||
expandIcon?: React.ReactNode;
|
||||
mode?: MenuProps['mode'];
|
||||
selectable?: boolean;
|
||||
validator?: (menuProps: Pick<MenuProps, 'mode'>) => void;
|
||||
}
|
||||
|
||||
/** @private Internal Usage. Only used for Dropdown component. Do not use this in your production. */
|
||||
const OverrideContext = React.createContext<OverrideContextProps | null>(null);
|
||||
|
||||
/** @private Internal Usage. Only used for Dropdown component. Do not use this in your production. */
|
||||
export const OverrideProvider = ({
|
||||
children,
|
||||
...restProps
|
||||
}: OverrideContextProps & { children: React.ReactNode }) => {
|
||||
const override = React.useContext(OverrideContext);
|
||||
|
||||
const context = React.useMemo(
|
||||
() => ({
|
||||
...override,
|
||||
...restProps,
|
||||
}),
|
||||
[
|
||||
override,
|
||||
restProps.prefixCls,
|
||||
// restProps.expandIcon, Not mark as deps since this is a ReactNode
|
||||
restProps.mode,
|
||||
restProps.selectable,
|
||||
// restProps.validator, Not mark as deps since this is a function
|
||||
],
|
||||
);
|
||||
|
||||
return <OverrideContext.Provider value={context}>{children}</OverrideContext.Provider>;
|
||||
};
|
||||
|
||||
export default OverrideContext;
|
@ -1,13 +1,14 @@
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { render, fireEvent, waitFor } from '../../../tests/utils';
|
||||
import Table from '..';
|
||||
import Input from '../../input';
|
||||
import Tooltip from '../../tooltip';
|
||||
import { fireEvent, render, waitFor } from '../../../tests/utils';
|
||||
import Button from '../../button';
|
||||
import Select from '../../select';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import Input from '../../input';
|
||||
import Menu from '../../menu';
|
||||
import Select from '../../select';
|
||||
import Tooltip from '../../tooltip';
|
||||
|
||||
// https://github.com/Semantic-Org/Semantic-UI-React/blob/72c45080e4f20b531fda2e3e430e384083d6766b/test/specs/modules/Dropdown/Dropdown-test.js#L73
|
||||
const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => {} } };
|
||||
@ -65,6 +66,14 @@ describe('Table.filter', () => {
|
||||
return namesList;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('not show filter icon when undefined', () => {
|
||||
const noFilterColumn = { ...column, filters: undefined };
|
||||
delete noFilterColumn.onFilter;
|
||||
@ -106,8 +115,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('renders empty menu correctly', () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -129,8 +136,6 @@ describe('Table.filter', () => {
|
||||
expect(container.querySelector('.ant-empty')).toBeTruthy();
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
errorSpy.mockRestore();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('renders radio filter correctly', async () => {
|
||||
@ -613,7 +618,6 @@ describe('Table.filter', () => {
|
||||
onChange,
|
||||
}),
|
||||
);
|
||||
jest.useFakeTimers();
|
||||
|
||||
expect(renderedNames(container)).toEqual(['Jack', 'Lucy', 'Tom', 'Jerry']);
|
||||
|
||||
@ -665,8 +669,6 @@ describe('Table.filter', () => {
|
||||
// What's this? Is that a coverage case? Or check a crash?
|
||||
const latestItems = getFilterMenu().querySelectorAll('li.ant-dropdown-menu-item');
|
||||
fireEvent.click(latestItems[latestItems.length - 1]);
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
describe('should support value types', () => {
|
||||
@ -676,7 +678,6 @@ describe('Table.filter', () => {
|
||||
['Bamboo', false],
|
||||
].forEach(([text, value]) => {
|
||||
it(`${typeof value} type`, async () => {
|
||||
jest.useFakeTimers();
|
||||
const onChange = jest.fn();
|
||||
const filters = [{ text, value }];
|
||||
const { container } = render(
|
||||
@ -698,8 +699,6 @@ describe('Table.filter', () => {
|
||||
|
||||
fireEvent.click(container.querySelector('.ant-dropdown-trigger'));
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
fireEvent.click(container.querySelectorAll('.ant-dropdown-menu-item')[0]);
|
||||
|
||||
// This test can be remove if refactor
|
||||
@ -733,7 +732,6 @@ describe('Table.filter', () => {
|
||||
.querySelector('.ant-table-filter-dropdown')
|
||||
.querySelectorAll('.ant-checkbox-input')[0].checked,
|
||||
).toEqual(false);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1831,7 +1829,6 @@ describe('Table.filter', () => {
|
||||
|
||||
describe('filter tree mode', () => {
|
||||
it('supports filter tree', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -1852,7 +1849,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('supports search input in filter tree', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -1875,7 +1871,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('supports search input in filter menu', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -1897,7 +1892,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('should skip search when filters[0].text is ReactNode', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -1936,7 +1930,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('should supports filterSearch has type of function', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -1974,7 +1967,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('supports check all items', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -2007,7 +1999,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('supports check item by selecting it', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -2043,7 +2034,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('select-all checkbox should change when all items are selected', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -2075,7 +2065,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('filterMultiple is false - check item', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -2123,7 +2112,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('filterMultiple is false - select item', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -2170,7 +2158,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('should select children when select parent', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
@ -2299,7 +2286,6 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('filterDropdown should support filterResetToDefaultFilteredValue', () => {
|
||||
jest.useFakeTimers();
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
|
||||
const columnFilter = {
|
||||
@ -2347,6 +2333,44 @@ describe('Table.filter', () => {
|
||||
expect(container.querySelector('.ant-tree-checkbox-checked+span').textContent).toBe('Girl');
|
||||
});
|
||||
|
||||
it('filterDropdown should not override customize Menu selectable', () => {
|
||||
const onSelect = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
createTable({
|
||||
columns: [
|
||||
{
|
||||
...column,
|
||||
filterDropdown: (
|
||||
<div className="custom-filter-dropdown">
|
||||
<Menu
|
||||
onSelect={onSelect}
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: 'Item 1',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
// Open Filter
|
||||
fireEvent.click(container.querySelector('span.ant-dropdown-trigger'));
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Click Item
|
||||
fireEvent.click(container.querySelector('.ant-table-filter-dropdown .ant-dropdown-menu-item'));
|
||||
|
||||
expect(onSelect).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('filteredKeys should all be controlled or not controlled', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
errorSpy.mockReset();
|
||||
|
@ -1,32 +1,33 @@
|
||||
import * as React from 'react';
|
||||
import FilterFilled from '@ant-design/icons/FilterFilled';
|
||||
import classNames from 'classnames';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import type { FieldDataNode } from 'rc-tree';
|
||||
import FilterFilled from '@ant-design/icons/FilterFilled';
|
||||
import Button from '../../../button';
|
||||
import Menu from '../../../menu';
|
||||
import type { MenuProps } from '../../../menu';
|
||||
import Tree from '../../../tree';
|
||||
import type { EventDataNode } from '../../../tree';
|
||||
import Checkbox from '../../../checkbox';
|
||||
import type { CheckboxChangeEvent } from '../../../checkbox';
|
||||
import Radio from '../../../radio';
|
||||
import Dropdown from '../../../dropdown';
|
||||
import Empty from '../../../empty';
|
||||
import type {
|
||||
ColumnType,
|
||||
ColumnFilterItem,
|
||||
Key,
|
||||
TableLocale,
|
||||
GetPopupContainer,
|
||||
FilterSearchType,
|
||||
} from '../../interface';
|
||||
import FilterDropdownMenuWrapper from './FilterWrapper';
|
||||
import FilterSearch from './FilterSearch';
|
||||
import * as React from 'react';
|
||||
import type { FilterState } from '.';
|
||||
import { flattenKeys } from '.';
|
||||
import useSyncState from '../../../_util/hooks/useSyncState';
|
||||
import Button from '../../../button';
|
||||
import type { CheckboxChangeEvent } from '../../../checkbox';
|
||||
import Checkbox from '../../../checkbox';
|
||||
import { ConfigContext } from '../../../config-provider/context';
|
||||
import Dropdown from '../../../dropdown';
|
||||
import Empty from '../../../empty';
|
||||
import type { MenuProps } from '../../../menu';
|
||||
import Menu from '../../../menu';
|
||||
import { OverrideProvider } from '../../../menu/OverrideContext';
|
||||
import Radio from '../../../radio';
|
||||
import type { EventDataNode } from '../../../tree';
|
||||
import Tree from '../../../tree';
|
||||
import useSyncState from '../../../_util/hooks/useSyncState';
|
||||
import type {
|
||||
ColumnFilterItem,
|
||||
ColumnType,
|
||||
FilterSearchType,
|
||||
GetPopupContainer,
|
||||
Key,
|
||||
TableLocale,
|
||||
} from '../../interface';
|
||||
import FilterSearch from './FilterSearch';
|
||||
import FilterDropdownMenuWrapper from './FilterWrapper';
|
||||
|
||||
type FilterTreeDataNode = FieldDataNode<{ title: React.ReactNode; key: React.Key }>;
|
||||
|
||||
@ -303,6 +304,7 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
|
||||
});
|
||||
|
||||
let dropdownContent: React.ReactNode;
|
||||
|
||||
if (typeof column.filterDropdown === 'function') {
|
||||
dropdownContent = column.filterDropdown({
|
||||
prefixCls: `${dropdownPrefixCls}-custom`,
|
||||
@ -441,6 +443,11 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
|
||||
);
|
||||
}
|
||||
|
||||
// We should not block customize Menu with additional props
|
||||
if (column.filterDropdown) {
|
||||
dropdownContent = <OverrideProvider selectable={undefined}>{dropdownContent}</OverrideProvider>;
|
||||
}
|
||||
|
||||
const menu = (
|
||||
<FilterDropdownMenuWrapper className={`${prefixCls}-dropdown`}>
|
||||
{dropdownContent}
|
||||
|
Loading…
Reference in New Issue
Block a user