mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
feat: Cascader support multiple mode (#31936)
* chore: Update cascader version * chore: replace cascader * chore: default allowClear * chore: Update docs * test: Back of part * test: More snapshot * test: more and more * test: Failed of defaultValue * test: all basic test case * test: All snapshot * chore: Update cascader * chore: disable react/jsx-no-bind * chore: fix lint * chore: fix less order * chore: fix deps * docs: Update multiple demo * docs: Add multiple example * test: Update snapshot * test: update snapshot
This commit is contained in:
parent
d86e1b5153
commit
282b7c8575
@ -94,6 +94,7 @@ module.exports = {
|
||||
'react/sort-comp': 0,
|
||||
'react/display-name': 0,
|
||||
'react/static-property-placement': 0,
|
||||
'react/jsx-no-bind': 0, // Should not check test file
|
||||
'react/no-find-dom-node': 0,
|
||||
'react/no-unused-prop-types': 0,
|
||||
'react/default-props-match-prop-types': 0,
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,31 @@
|
||||
import React from 'react';
|
||||
import { render, mount } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import Cascader from '..';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import excludeAllWarning from '../../../tests/shared/excludeWarning';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
function toggleOpen(wrapper) {
|
||||
wrapper.find('.ant-select-selector').simulate('mousedown');
|
||||
}
|
||||
|
||||
function isOpen(wrapper) {
|
||||
return !!wrapper.find('Trigger').props().popupVisible;
|
||||
}
|
||||
|
||||
function getDropdown(wrapper) {
|
||||
return wrapper.find('.ant-select-dropdown');
|
||||
}
|
||||
|
||||
function clickOption(wrapper, menuIndex, itemIndex, type = 'click') {
|
||||
const menu = wrapper.find('ul.ant-cascader-menu').at(menuIndex);
|
||||
const itemList = menu.find('li.ant-cascader-menu-item');
|
||||
|
||||
itemList.at(itemIndex).simulate(type);
|
||||
}
|
||||
|
||||
const options = [
|
||||
{
|
||||
@ -48,13 +67,15 @@ function filter(inputValue, path) {
|
||||
}
|
||||
|
||||
describe('Cascader', () => {
|
||||
focusTest(Cascader);
|
||||
excludeAllWarning();
|
||||
|
||||
focusTest(Cascader, { refFocus: true });
|
||||
mountTest(Cascader);
|
||||
rtlTest(Cascader);
|
||||
|
||||
it('popup correctly when panel is hidden', () => {
|
||||
const wrapper = mount(<Cascader options={options} />);
|
||||
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
|
||||
expect(isOpen(wrapper)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('popup correctly when panel is open', () => {
|
||||
@ -62,8 +83,8 @@ describe('Cascader', () => {
|
||||
const wrapper = mount(
|
||||
<Cascader options={options} onPopupVisibleChange={onPopupVisibleChange} />,
|
||||
);
|
||||
wrapper.find('input').simulate('click');
|
||||
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
|
||||
toggleOpen(wrapper);
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
@ -77,83 +98,71 @@ describe('Cascader', () => {
|
||||
|
||||
it('popup correctly with defaultValue', () => {
|
||||
const wrapper = mount(<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
|
||||
toggleOpen(wrapper);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support popupVisible', () => {
|
||||
const wrapper = mount(<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} />);
|
||||
expect(wrapper.find('Trigger').instance().getComponent().props.visible).toBe(false);
|
||||
expect(isOpen(wrapper)).toBeFalsy();
|
||||
wrapper.setProps({ popupVisible: true });
|
||||
expect(wrapper.find('Trigger').instance().getComponent().props.visible).toBe(true);
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('can be selected', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(<Cascader options={options} onChange={onChange} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
let popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(0)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
|
||||
popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(1)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
|
||||
popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(2)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(render(wrapper.find('Trigger').instance().getComponent())).toMatchSnapshot();
|
||||
|
||||
toggleOpen(wrapper);
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
|
||||
clickOption(wrapper, 0, 0);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
|
||||
clickOption(wrapper, 1, 0);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
|
||||
clickOption(wrapper, 2, 0);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
expect(onChange).toHaveBeenCalledWith(['zhejiang', 'hangzhou', 'xihu'], expect.anything());
|
||||
});
|
||||
|
||||
it('backspace should work with `Cascader[showSearch]`', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch />);
|
||||
wrapper.find('input').simulate('change', { target: { value: '123' } });
|
||||
expect(wrapper.state('inputValue')).toBe('123');
|
||||
wrapper.find('input').simulate('keydown', { keyCode: KeyCode.BACKSPACE });
|
||||
// Simulate onKeyDown will not trigger onChange by default, so the value is still '123'
|
||||
expect(wrapper.state('inputValue')).toBe('123');
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
|
||||
wrapper.find('input').simulate('keydown', { which: KeyCode.BACKSPACE });
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
|
||||
wrapper.find('input').simulate('change', { target: { value: '' } });
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
|
||||
wrapper.find('input').simulate('keydown', { which: KeyCode.BACKSPACE });
|
||||
expect(isOpen(wrapper)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should highlight keyword and filter when search in Cascader', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'z' } });
|
||||
expect(wrapper.state('inputValue')).toBe('z');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should highlight keyword and filter when search in Cascader with same field name of label and value', () => {
|
||||
const customOptions = [
|
||||
{
|
||||
name: 'Zhejiang',
|
||||
value: 'Zhejiang',
|
||||
children: [
|
||||
{
|
||||
name: 'Hangzhou',
|
||||
value: 'Hangzhou',
|
||||
children: [
|
||||
{
|
||||
name: 'West Lake',
|
||||
value: 'West Lake',
|
||||
},
|
||||
{
|
||||
name: 'Xia Sha',
|
||||
value: 'Xia Sha',
|
||||
disabled: true,
|
||||
},
|
||||
],
|
||||
@ -171,81 +180,35 @@ describe('Cascader', () => {
|
||||
showSearch={{ filter: customFilter }}
|
||||
/>,
|
||||
);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'z' } });
|
||||
expect(wrapper.state('inputValue')).toBe('z');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render not found content', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: '__notfoundkeyword__' } });
|
||||
expect(wrapper.state('inputValue')).toBe('__notfoundkeyword__');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support to clear selection', async () => {
|
||||
it('should support to clear selection', () => {
|
||||
const wrapper = mount(<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} />);
|
||||
const willUnmount = jest.spyOn(wrapper.instance(), 'componentWillUnmount');
|
||||
const clearTimeoutSpy = jest.spyOn(global, 'clearTimeout');
|
||||
expect(wrapper.find('.ant-cascader-picker-label').text()).toBe('Zhejiang / Hangzhou');
|
||||
wrapper.find('.ant-cascader-picker-clear').at(0).simulate('click');
|
||||
await sleep(300);
|
||||
expect(wrapper.find('.ant-cascader-picker-label').text()).toBe('');
|
||||
wrapper.unmount();
|
||||
expect(willUnmount).toHaveBeenCalled();
|
||||
expect(clearTimeoutSpy).toHaveBeenCalled();
|
||||
clearTimeoutSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should close popup when clear selection', () => {
|
||||
const onPopupVisibleChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Cascader
|
||||
options={options}
|
||||
popupVisible
|
||||
defaultValue={['zhejiang', 'hangzhou']}
|
||||
onPopupVisibleChange={onPopupVisibleChange}
|
||||
/>,
|
||||
);
|
||||
wrapper.find('.ant-cascader-picker-clear').at(0).simulate('click');
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledWith(false);
|
||||
expect(wrapper.find('.ant-select-selection-item').text()).toEqual('Zhejiang / Hangzhou');
|
||||
wrapper.find('.ant-select-clear').at(0).simulate('mouseDown');
|
||||
expect(wrapper.exists('.ant-select-selection-item')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should clear search input when clear selection', () => {
|
||||
const wrapper = mount(
|
||||
<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} showSearch />,
|
||||
);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'xxx' } });
|
||||
expect(wrapper.state('inputValue')).toBe('xxx');
|
||||
wrapper.find('.ant-cascader-picker-clear').at(0).simulate('click');
|
||||
expect(wrapper.state('inputValue')).toBe('');
|
||||
});
|
||||
|
||||
it('should not trigger visible change when click search input', () => {
|
||||
const onPopupVisibleChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
<Cascader options={options} showSearch onPopupVisibleChange={onPopupVisibleChange} />,
|
||||
);
|
||||
wrapper.find('input').simulate('focus');
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledTimes(0);
|
||||
wrapper.find('input').simulate('click');
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledTimes(1);
|
||||
wrapper.find('input').simulate('click');
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledTimes(1);
|
||||
wrapper.find('input').simulate('blur');
|
||||
wrapper.setState({ popupVisible: false });
|
||||
wrapper.find('input').simulate('click');
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledTimes(2);
|
||||
wrapper.find('.ant-select-clear').at(0).simulate('mouseDown');
|
||||
expect(wrapper.find('input').props().value).toEqual('');
|
||||
});
|
||||
|
||||
it('should change filtered item when options are changed', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'a' } });
|
||||
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
|
||||
wrapper.setProps({ options: [options[0]] });
|
||||
@ -254,12 +217,12 @@ describe('Cascader', () => {
|
||||
|
||||
it('should select item immediately when searching and pressing down arrow key', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'a' } });
|
||||
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
|
||||
expect(wrapper.find('.ant-cascader-menu-item-active').length).toBe(0);
|
||||
|
||||
wrapper.find('input').simulate('keyDown', {
|
||||
keyCode: KeyCode.DOWN,
|
||||
which: KeyCode.DOWN,
|
||||
});
|
||||
expect(wrapper.find('.ant-cascader-menu-item-active').length).toBe(1);
|
||||
});
|
||||
@ -299,31 +262,40 @@ describe('Cascader', () => {
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const onChange = jest.fn();
|
||||
|
||||
const wrapper = mount(
|
||||
<Cascader
|
||||
options={customerOptions}
|
||||
onChange={onChange}
|
||||
fieldNames={{
|
||||
children: 'items',
|
||||
label: 'name',
|
||||
value: 'code',
|
||||
}}
|
||||
open
|
||||
/>,
|
||||
);
|
||||
wrapper.instance().handleChange(['zhejiang', 'hangzhou', 'xihu'], customerOptions);
|
||||
expect(wrapper.find('.ant-cascader-picker-label').text().split('/').length).toBe(3);
|
||||
|
||||
clickOption(wrapper, 0, 0);
|
||||
clickOption(wrapper, 1, 0);
|
||||
clickOption(wrapper, 2, 0);
|
||||
expect(wrapper.find('.ant-select-selection-item').text()).toEqual(
|
||||
'Zhejiang / Hangzhou / West Lake',
|
||||
);
|
||||
expect(onChange).toHaveBeenCalledWith(['zhejiang', 'hangzhou', 'xihu'], expect.anything());
|
||||
});
|
||||
|
||||
it('should show not found content when options.length is 0', () => {
|
||||
const customerOptions = [];
|
||||
const wrapper = mount(<Cascader options={customerOptions} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
toggleOpen(wrapper);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('not found content shoule be disabled', () => {
|
||||
const wrapper = mount(<Cascader options={[]} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
it('not found content should be disabled', () => {
|
||||
const wrapper = mount(<Cascader options={[]} open />);
|
||||
expect(wrapper.find('.ant-cascader-menu-item-disabled').length).toBe(1);
|
||||
});
|
||||
|
||||
@ -336,37 +308,33 @@ describe('Cascader', () => {
|
||||
|
||||
it('limit with positive number', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter, limit: 1 }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'a' } });
|
||||
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(1);
|
||||
expect(wrapper.find('.ant-cascader-menu-item')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('not limit', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter, limit: false }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'a' } });
|
||||
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
|
||||
expect(wrapper.find('.ant-cascader-menu-item')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('negative limit', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch={{ filter, limit: -1 }} />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'a' } });
|
||||
expect(wrapper.find('.ant-cascader-menu-item').length).toBe(2);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
"Warning: [antd: Cascader] 'limit' of showSearch should be positive number or false.",
|
||||
);
|
||||
expect(wrapper.find('.ant-cascader-menu-item')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('should warning if not find `value` in `options`', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Cascader options={[{ label: 'a', value: 'a', children: [{ label: 'b' }] }]} />);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] Not found `value` in `options`.',
|
||||
);
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
// FIXME: Move to `rc-tree-select` instead
|
||||
// it('should warning if not find `value` in `options`', () => {
|
||||
// const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
// mount(<Cascader options={[{ label: 'a', value: 'a', children: [{ label: 'b' }] }]} />);
|
||||
// expect(errorSpy).toHaveBeenCalledWith(
|
||||
// 'Warning: [antd: Cascader] Not found `value` in `options`.',
|
||||
// );
|
||||
// errorSpy.mockRestore();
|
||||
// });
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/17690
|
||||
it('should not breaks when children is null', () => {
|
||||
@ -388,40 +356,24 @@ describe('Cascader', () => {
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18176
|
||||
it('have a notFoundContent that fit trigger input width', () => {
|
||||
const wrapper = mount(
|
||||
<Cascader
|
||||
popupVisible
|
||||
options={[]}
|
||||
fieldNames={{ label: 'name', value: 'code', children: 'items' }}
|
||||
/>,
|
||||
);
|
||||
const popupWrapper = mount(wrapper.find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('placeholder works correctly', () => {
|
||||
const wrapper = mount(<Cascader options={[]} />);
|
||||
expect(wrapper.find('input').prop('placeholder')).toBe('Please select');
|
||||
expect(wrapper.find('.ant-select-selection-placeholder').text()).toEqual('');
|
||||
|
||||
const customPlaceholder = 'Custom placeholder';
|
||||
wrapper.setProps({
|
||||
placeholder: customPlaceholder,
|
||||
});
|
||||
expect(wrapper.find('input').prop('placeholder')).toBe(customPlaceholder);
|
||||
expect(wrapper.find('.ant-select-selection-placeholder').text()).toEqual(customPlaceholder);
|
||||
});
|
||||
|
||||
it('popup correctly with defaultValue RTL', () => {
|
||||
const wrapper = mount(
|
||||
<ConfigProvider direction="rtl">
|
||||
<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} />
|
||||
<Cascader options={options} defaultValue={['zhejiang', 'hangzhou']} open />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
wrapper.find('Cascader').find('input').simulate('click');
|
||||
expect(
|
||||
render(wrapper.find('Cascader').find('Trigger').instance().getComponent()),
|
||||
).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('can be selected in RTL direction', () => {
|
||||
@ -471,81 +423,54 @@ describe('Cascader', () => {
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
wrapper.find('Cascader').find('input').simulate('click');
|
||||
let popupWrapper = mount(wrapper.find('Cascader').find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(0)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(
|
||||
render(wrapper.find('Cascader').find('Trigger').instance().getComponent()),
|
||||
).toMatchSnapshot();
|
||||
popupWrapper = mount(wrapper.find('Cascader').find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(1)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(
|
||||
render(wrapper.find('Cascader').find('Trigger').instance().getComponent()),
|
||||
).toMatchSnapshot();
|
||||
popupWrapper = mount(wrapper.find('Cascader').find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(2)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
toggleOpen(wrapper);
|
||||
clickOption(wrapper, 0, 0);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
|
||||
toggleOpen(wrapper);
|
||||
clickOption(wrapper, 1, 0);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
|
||||
toggleOpen(wrapper);
|
||||
clickOption(wrapper, 2, 0);
|
||||
expect(getDropdown(wrapper).render()).toMatchSnapshot();
|
||||
|
||||
expect(onChange).toHaveBeenCalledTimes(1);
|
||||
expect(onChange).toHaveBeenCalledWith(['zhejiang', 'hangzhou', 'xihu'], expect.anything());
|
||||
});
|
||||
|
||||
it('defaultValue works correctly when no match options', () => {
|
||||
const wrapper = mount(<Cascader options={options} defaultValue={['options1', 'options2']} />);
|
||||
expect(wrapper.find('.ant-cascader-picker-label').text()).toBe('options1 / options2');
|
||||
expect(wrapper.find('.ant-select-selection-item').text()).toEqual('options1 / options2');
|
||||
});
|
||||
|
||||
it('can be selected when showSearch', () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(<Cascader options={options} onChange={onChange} showSearch />);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'Zh' } });
|
||||
const popupWrapper = mount(wrapper.find('Cascader').find('Trigger').instance().getComponent());
|
||||
expect(popupWrapper.find('.ant-cascader-menu').length).toBe(1);
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(0)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
expect(wrapper.find('.ant-cascader-menu').length).toBe(1);
|
||||
clickOption(wrapper, 0, 0);
|
||||
expect(onChange).toHaveBeenCalledWith(['zhejiang', 'hangzhou', 'xihu'], expect.anything());
|
||||
});
|
||||
|
||||
it('options should open after press esc and then search', () => {
|
||||
const wrapper = mount(<Cascader options={options} showSearch />);
|
||||
wrapper.find('input').simulate('change', { target: { value: 'jin' } });
|
||||
wrapper.find('input').simulate('keydown', { keyCode: KeyCode.ESC });
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
wrapper.find('input').simulate('keydown', { which: KeyCode.ESC });
|
||||
expect(isOpen(wrapper)).toBeFalsy();
|
||||
wrapper.find('input').simulate('change', { target: { value: 'jin' } });
|
||||
expect(wrapper.state('popupVisible')).toBe(true);
|
||||
expect(isOpen(wrapper)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('onChange works correctly when the label of fieldNames is the same as value', () => {
|
||||
const onChange = jest.fn();
|
||||
const sameNames = { label: 'label', value: 'label', children: 'children' };
|
||||
const sameNames = { label: 'label', value: 'label' };
|
||||
const wrapper = mount(
|
||||
<Cascader options={options} onChange={onChange} showSearch fieldNames={sameNames} />,
|
||||
);
|
||||
wrapper.find('input').simulate('click');
|
||||
wrapper.find('input').simulate('change', { target: { value: 'est' } });
|
||||
const popupWrapper = mount(wrapper.find('Cascader').find('Trigger').instance().getComponent());
|
||||
popupWrapper
|
||||
.find('.ant-cascader-menu')
|
||||
.at(0)
|
||||
.find('.ant-cascader-menu-item')
|
||||
.at(0)
|
||||
.simulate('click');
|
||||
clickOption(wrapper, 0, 0);
|
||||
expect(onChange).toHaveBeenCalledWith(['Zhejiang', 'Hangzhou', 'West Lake'], expect.anything());
|
||||
});
|
||||
});
|
||||
|
67
components/cascader/demo/multiple.md
Normal file
67
components/cascader/demo/multiple.md
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
order: 5.1
|
||||
title:
|
||||
zh-CN: 多选
|
||||
en-US: Multiple
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
一次性选择多个选项。
|
||||
|
||||
## en-US
|
||||
|
||||
Select multiple options
|
||||
|
||||
```jsx
|
||||
import { Cascader } from 'antd';
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: 'Light',
|
||||
value: 'light',
|
||||
children: new Array(20)
|
||||
.fill(null)
|
||||
.map((_, index) => ({ label: `Number ${index}`, value: index })),
|
||||
},
|
||||
{
|
||||
label: 'Bamboo',
|
||||
value: 'bamboo',
|
||||
children: [
|
||||
{
|
||||
label: 'Little',
|
||||
value: 'little',
|
||||
children: [
|
||||
{
|
||||
label: 'Toy Fish',
|
||||
value: 'fish',
|
||||
},
|
||||
{
|
||||
label: 'Toy Cards',
|
||||
value: 'cards',
|
||||
},
|
||||
{
|
||||
label: 'Toy Bird',
|
||||
value: 'bird',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
function onChange(value) {
|
||||
console.log(value);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Cascader
|
||||
style={{ width: 233 }}
|
||||
options={options}
|
||||
onChange={onChange}
|
||||
multiple
|
||||
maxTagCount="responsive"
|
||||
/>,
|
||||
mountNode,
|
||||
);
|
||||
```
|
@ -36,18 +36,18 @@ Cascade selection box.
|
||||
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | function(triggerNode) | () => document.body | |
|
||||
| loadData | To load option lazily, and it cannot work with `showSearch` | (selectedOptions) => void | - | |
|
||||
| notFoundContent | Specify content to show when no result matches | string | `Not Found` | |
|
||||
| open | Set visible of cascader popup | boolean | - | 4.17.0 |
|
||||
| options | The data options of cascade | [Option](#Option)\[] | - | |
|
||||
| placeholder | The input placeholder | string | `Please select` | |
|
||||
| popupClassName | The additional className of popup overlay | string | - | |
|
||||
| popupPlacement | Use preset popup align config from builtinPlacements:`bottomLeft` `bottomRight` `topLeft` `topRight` | string | `bottomLeft` | |
|
||||
| popupVisible | Set visible of cascader popup | boolean | - | |
|
||||
| showSearch | Whether show search input in single mode | boolean \| [Object](#showSearch) | false | |
|
||||
| size | The input size | `large` \| `middle` \| `small` | - | |
|
||||
| style | The additional style | CSSProperties | - | |
|
||||
| suffixIcon | The custom suffix icon | ReactNode | - | |
|
||||
| value | The selected value | string\[] \| number\[] | - | |
|
||||
| onChange | Callback when finishing cascader select | (value, selectedOptions) => void | - | |
|
||||
| onPopupVisibleChange | Callback when popup shown or hidden | (value) => void | - | |
|
||||
| onDropdownVisibleChange | Callback when popup shown or hidden | (value) => void | - | 4.17.0 |
|
||||
|
||||
### showSearch
|
||||
|
||||
|
@ -1,716 +1,215 @@
|
||||
import * as React from 'react';
|
||||
import RcCascader from 'rc-cascader';
|
||||
import arrayTreeFilter from 'array-tree-filter';
|
||||
import classNames from 'classnames';
|
||||
import RcCascader from 'rc-cascader';
|
||||
import type { CascaderProps as RcCascaderProps } from 'rc-cascader';
|
||||
import type { ShowSearchType, FieldNames } from 'rc-cascader/lib/interface';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
|
||||
import DownOutlined from '@ant-design/icons/DownOutlined';
|
||||
import RightOutlined from '@ant-design/icons/RightOutlined';
|
||||
import RedoOutlined from '@ant-design/icons/RedoOutlined';
|
||||
import LeftOutlined from '@ant-design/icons/LeftOutlined';
|
||||
|
||||
import Input from '../input';
|
||||
import {
|
||||
ConfigConsumer,
|
||||
ConfigConsumerProps,
|
||||
RenderEmptyHandler,
|
||||
DirectionType,
|
||||
} from '../config-provider';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import SizeContext, { SizeType } from '../config-provider/SizeContext';
|
||||
import { replaceElement } from '../_util/reactNode';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import type { SizeType } from '../config-provider/SizeContext';
|
||||
import SizeContext from '../config-provider/SizeContext';
|
||||
import getIcons from '../select/utils/iconUtil';
|
||||
import { getTransitionName } from '../_util/motion';
|
||||
|
||||
export interface CascaderOptionType {
|
||||
value?: string | number;
|
||||
label?: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
isLeaf?: boolean;
|
||||
loading?: boolean;
|
||||
children?: Array<CascaderOptionType>;
|
||||
[key: string]: any;
|
||||
// Align the design since we use `rc-select` in root. This help:
|
||||
// - List search content will show all content
|
||||
// - Hover opacity style
|
||||
// - Search filter match case
|
||||
|
||||
export type FieldNamesType = FieldNames;
|
||||
|
||||
export type FilledFieldNamesType = Required<FieldNamesType>;
|
||||
|
||||
function highlightKeyword(str: string, lowerKeyword: string, prefixCls: string | undefined) {
|
||||
const cells = str
|
||||
.toLowerCase()
|
||||
.split(lowerKeyword)
|
||||
.reduce((list, cur, index) => (index === 0 ? [cur] : [...list, lowerKeyword, cur]), []);
|
||||
const fillCells: React.ReactNode[] = [];
|
||||
let start = 0;
|
||||
|
||||
cells.forEach((cell, index) => {
|
||||
const end = start + cell.length;
|
||||
let originWorld: React.ReactNode = str.slice(start, end);
|
||||
start = end;
|
||||
|
||||
if (index % 2 === 1) {
|
||||
originWorld = (
|
||||
<span className={`${prefixCls}-menu-item-keyword`} key="seperator">
|
||||
{originWorld}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
fillCells.push(originWorld);
|
||||
});
|
||||
|
||||
return fillCells;
|
||||
}
|
||||
|
||||
export interface FieldNamesType {
|
||||
value?: string | number;
|
||||
label?: string;
|
||||
children?: string;
|
||||
}
|
||||
const defaultSearchRender: ShowSearchType['render'] = (inputValue, path, prefixCls, fieldNames) => {
|
||||
const optionList: React.ReactNode[] = [];
|
||||
|
||||
export interface FilledFieldNamesType {
|
||||
value: string | number;
|
||||
label: string;
|
||||
children: string;
|
||||
}
|
||||
// We do lower here to save perf
|
||||
const lower = inputValue.toLowerCase();
|
||||
|
||||
export type CascaderExpandTrigger = 'click' | 'hover';
|
||||
path.forEach((node, index) => {
|
||||
if (index !== 0) {
|
||||
optionList.push(' / ');
|
||||
}
|
||||
|
||||
export type CascaderValueType = (string | number)[];
|
||||
let label = (node as any)[fieldNames.label!];
|
||||
const type = typeof label;
|
||||
if (type === 'string' || type === 'number') {
|
||||
label = highlightKeyword(String(label), lower, prefixCls);
|
||||
}
|
||||
|
||||
export interface ShowSearchType {
|
||||
filter?: (inputValue: string, path: CascaderOptionType[], names: FilledFieldNamesType) => boolean;
|
||||
render?: (
|
||||
inputValue: string,
|
||||
path: CascaderOptionType[],
|
||||
prefixCls: string | undefined,
|
||||
names: FilledFieldNamesType,
|
||||
) => React.ReactNode;
|
||||
sort?: (
|
||||
a: CascaderOptionType[],
|
||||
b: CascaderOptionType[],
|
||||
inputValue: string,
|
||||
names: FilledFieldNamesType,
|
||||
) => number;
|
||||
matchInputWidth?: boolean;
|
||||
limit?: number | false;
|
||||
}
|
||||
optionList.push(label);
|
||||
});
|
||||
return optionList;
|
||||
};
|
||||
|
||||
export interface CascaderProps {
|
||||
/** 可选项数据源 */
|
||||
options: CascaderOptionType[];
|
||||
/** 默认的选中项 */
|
||||
defaultValue?: CascaderValueType;
|
||||
/** 指定选中项 */
|
||||
value?: CascaderValueType;
|
||||
/** 选择完成后的回调 */
|
||||
onChange?: (value: CascaderValueType, selectedOptions?: CascaderOptionType[]) => void;
|
||||
/** 选择后展示的渲染函数 */
|
||||
displayRender?: (label: string[], selectedOptions?: CascaderOptionType[]) => React.ReactNode;
|
||||
/** 自定义样式 */
|
||||
style?: React.CSSProperties;
|
||||
/** 自定义类名 */
|
||||
className?: string;
|
||||
/** 自定义浮层类名 */
|
||||
popupClassName?: string;
|
||||
/** 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` */
|
||||
popupPlacement?: string;
|
||||
/** 输入框占位文本 */
|
||||
placeholder?: string;
|
||||
/** 输入框大小,可选 `large` `default` `small` */
|
||||
export interface CascaderProps extends Omit<RcCascaderProps, 'checkable'> {
|
||||
multiple?: boolean;
|
||||
size?: SizeType;
|
||||
/** 输入框 name */
|
||||
name?: string;
|
||||
/** 输入框 id */
|
||||
id?: string;
|
||||
/** Whether has border style */
|
||||
bordered?: boolean;
|
||||
/** 禁用 */
|
||||
disabled?: boolean;
|
||||
/** 是否支持清除 */
|
||||
allowClear?: boolean;
|
||||
/** 自动获取焦点 */
|
||||
autoFocus?: boolean;
|
||||
showSearch?: boolean | ShowSearchType;
|
||||
notFoundContent?: React.ReactNode;
|
||||
loadData?: (selectedOptions?: CascaderOptionType[]) => void;
|
||||
/** 次级菜单的展开方式,可选 'click' 和 'hover' */
|
||||
expandTrigger?: CascaderExpandTrigger;
|
||||
expandIcon?: React.ReactNode;
|
||||
/** 当此项为 true 时,点选每级菜单选项值都会发生变化 */
|
||||
changeOnSelect?: boolean;
|
||||
/** 浮层可见变化时回调 */
|
||||
onPopupVisibleChange?: (popupVisible: boolean) => void;
|
||||
prefixCls?: string;
|
||||
inputPrefixCls?: string;
|
||||
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
||||
popupVisible?: boolean;
|
||||
/** Use this after antd@3.7.0 */
|
||||
fieldNames?: FieldNamesType;
|
||||
suffixIcon?: React.ReactNode;
|
||||
dropdownRender?: (menus: React.ReactNode) => React.ReactNode;
|
||||
|
||||
// Miss prop defines.
|
||||
autoComplete?: string;
|
||||
transitionName?: string;
|
||||
children?: React.ReactElement;
|
||||
}
|
||||
|
||||
export interface CascaderState {
|
||||
inputFocused: boolean;
|
||||
inputValue: string;
|
||||
value: CascaderValueType;
|
||||
popupVisible: boolean | undefined;
|
||||
flattenOptions: CascaderOptionType[][] | undefined;
|
||||
prevProps: CascaderProps;
|
||||
interface CascaderRef {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
}
|
||||
|
||||
interface CascaderLocale {
|
||||
placeholder?: string;
|
||||
}
|
||||
const Cascader = React.forwardRef((props: CascaderProps, ref: React.Ref<CascaderRef>) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
size: customizeSize,
|
||||
className,
|
||||
multiple,
|
||||
bordered = true,
|
||||
transitionName,
|
||||
choiceTransitionName = '',
|
||||
dropdownClassName,
|
||||
expandIcon,
|
||||
showSearch,
|
||||
allowClear = true,
|
||||
notFoundContent,
|
||||
direction,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
// We limit the filtered item count by default
|
||||
const defaultLimit = 50;
|
||||
const restProps = omit(rest, ['suffixIcon' as any]);
|
||||
|
||||
// keep value when filtering
|
||||
const keepFilteredValueField = '__KEEP_FILTERED_OPTION_VALUE';
|
||||
const {
|
||||
// getPopupContainer: getContextPopupContainer,
|
||||
getPrefixCls,
|
||||
renderEmpty,
|
||||
direction: rootDirection,
|
||||
// virtual,
|
||||
// dropdownMatchSelectWidth,
|
||||
} = React.useContext(ConfigContext);
|
||||
|
||||
function highlightKeyword(str: string, keyword: string, prefixCls: string | undefined) {
|
||||
return str.split(keyword).map((node: string, index: number) =>
|
||||
index === 0
|
||||
? node
|
||||
: [
|
||||
<span className={`${prefixCls}-menu-item-keyword`} key="seperator">
|
||||
{keyword}
|
||||
</span>,
|
||||
node,
|
||||
],
|
||||
);
|
||||
}
|
||||
const mergedDirection = direction || rootDirection;
|
||||
const isRtl = mergedDirection === 'rtl';
|
||||
|
||||
function defaultFilterOption(
|
||||
inputValue: string,
|
||||
path: CascaderOptionType[],
|
||||
names: FilledFieldNamesType,
|
||||
) {
|
||||
return path.some(option => (option[names.label] as string).indexOf(inputValue) > -1);
|
||||
}
|
||||
// =================== No Found ====================
|
||||
const mergedNotFoundContent = notFoundContent || renderEmpty('Cascader');
|
||||
|
||||
function defaultRenderFilteredOption(
|
||||
inputValue: string,
|
||||
path: CascaderOptionType[],
|
||||
prefixCls: string | undefined,
|
||||
names: FilledFieldNamesType,
|
||||
) {
|
||||
return path.map((option, index) => {
|
||||
const label = option[names.label];
|
||||
const node =
|
||||
(label as string).indexOf(inputValue) > -1
|
||||
? highlightKeyword(label as string, inputValue, prefixCls)
|
||||
: label;
|
||||
return index === 0 ? node : [' / ', node];
|
||||
// ==================== Prefix =====================
|
||||
const rootPrefixCls = getPrefixCls();
|
||||
const prefixCls = getPrefixCls('select', customizePrefixCls);
|
||||
const cascaderPrefixCls = getPrefixCls('cascader', customizePrefixCls);
|
||||
|
||||
// =================== Dropdown ====================
|
||||
const mergedDropdownClassName = classNames(dropdownClassName, `${cascaderPrefixCls}-dropdown`, {
|
||||
[`${cascaderPrefixCls}-dropdown-rtl`]: mergedDirection === 'rtl',
|
||||
});
|
||||
}
|
||||
|
||||
function defaultSortFilteredOption(
|
||||
a: CascaderOptionType[],
|
||||
b: CascaderOptionType[],
|
||||
inputValue: string,
|
||||
names: FilledFieldNamesType,
|
||||
) {
|
||||
function callback(elem: CascaderOptionType) {
|
||||
return (elem[names.label] as string).indexOf(inputValue) > -1;
|
||||
}
|
||||
|
||||
return a.findIndex(callback) - b.findIndex(callback);
|
||||
}
|
||||
|
||||
function getFieldNames({ fieldNames }: CascaderProps) {
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
function getFilledFieldNames(props: CascaderProps) {
|
||||
const fieldNames = getFieldNames(props) || {};
|
||||
const names: FilledFieldNamesType = {
|
||||
children: fieldNames.children || 'children',
|
||||
label: fieldNames.label || 'label',
|
||||
value: fieldNames.value || 'value',
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
function flattenTree(
|
||||
options: CascaderOptionType[],
|
||||
props: CascaderProps,
|
||||
ancestor: CascaderOptionType[] = [],
|
||||
) {
|
||||
const names: FilledFieldNamesType = getFilledFieldNames(props);
|
||||
let flattenOptions: CascaderOptionType[][] = [];
|
||||
const childrenName = names.children;
|
||||
options.forEach(option => {
|
||||
const path = ancestor.concat(option);
|
||||
if (props.changeOnSelect || !option[childrenName] || !option[childrenName].length) {
|
||||
flattenOptions.push(path);
|
||||
// ==================== Search =====================
|
||||
const mergedShowSearch = React.useMemo(() => {
|
||||
if (!showSearch) {
|
||||
return showSearch;
|
||||
}
|
||||
if (option[childrenName]) {
|
||||
flattenOptions = flattenOptions.concat(flattenTree(option[childrenName], props, path));
|
||||
}
|
||||
});
|
||||
return flattenOptions;
|
||||
}
|
||||
|
||||
const defaultDisplayRender = (label: string[]) => label.join(' / ');
|
||||
|
||||
function warningValueNotExist(list: CascaderOptionType[], fieldNames: FieldNamesType = {}) {
|
||||
(list || []).forEach(item => {
|
||||
const valueFieldName = fieldNames.value || 'value';
|
||||
devWarning(valueFieldName in item, 'Cascader', 'Not found `value` in `options`.');
|
||||
warningValueNotExist(item[fieldNames.children || 'children'], fieldNames);
|
||||
});
|
||||
}
|
||||
|
||||
function getEmptyNode(
|
||||
renderEmpty: RenderEmptyHandler,
|
||||
names: FilledFieldNamesType,
|
||||
notFoundContent?: React.ReactNode,
|
||||
) {
|
||||
return {
|
||||
[names.value]: 'ANT_CASCADER_NOT_FOUND',
|
||||
[names.label]: notFoundContent || renderEmpty('Cascader'),
|
||||
disabled: true,
|
||||
isEmptyNode: true,
|
||||
};
|
||||
}
|
||||
|
||||
class Cascader extends React.Component<CascaderProps, CascaderState> {
|
||||
static defaultProps = {
|
||||
options: [],
|
||||
disabled: false,
|
||||
allowClear: true,
|
||||
bordered: true,
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(nextProps: CascaderProps, { prevProps }: CascaderState) {
|
||||
const newState: Partial<CascaderState> = {
|
||||
prevProps: nextProps,
|
||||
let searchConfig: ShowSearchType = {
|
||||
render: defaultSearchRender,
|
||||
};
|
||||
|
||||
if ('value' in nextProps) {
|
||||
newState.value = nextProps.value || [];
|
||||
}
|
||||
if ('popupVisible' in nextProps) {
|
||||
newState.popupVisible = nextProps.popupVisible;
|
||||
}
|
||||
if (nextProps.showSearch && prevProps.options !== nextProps.options) {
|
||||
newState.flattenOptions = flattenTree(nextProps.options, nextProps);
|
||||
if (typeof showSearch === 'object') {
|
||||
searchConfig = {
|
||||
...searchConfig,
|
||||
...showSearch,
|
||||
};
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && nextProps.options) {
|
||||
warningValueNotExist(nextProps.options, getFieldNames(nextProps));
|
||||
}
|
||||
return searchConfig;
|
||||
}, [showSearch]);
|
||||
|
||||
return newState;
|
||||
// ===================== Size ======================
|
||||
const size = React.useContext(SizeContext);
|
||||
const mergedSize = customizeSize || size;
|
||||
|
||||
// ===================== Icon ======================
|
||||
let mergedExpandIcon = expandIcon;
|
||||
if (!expandIcon) {
|
||||
mergedExpandIcon = isRtl ? <LeftOutlined /> : <RightOutlined />;
|
||||
}
|
||||
|
||||
cachedOptions: CascaderOptionType[] = [];
|
||||
|
||||
clearSelectionTimeout: any;
|
||||
|
||||
private input: Input;
|
||||
|
||||
constructor(props: CascaderProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
value: props.value || props.defaultValue || [],
|
||||
inputValue: '',
|
||||
inputFocused: false,
|
||||
popupVisible: props.popupVisible,
|
||||
flattenOptions: props.showSearch ? flattenTree(props.options, props) : undefined,
|
||||
prevProps: props,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.clearSelectionTimeout) {
|
||||
clearTimeout(this.clearSelectionTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
setValue = (value: CascaderValueType, selectedOptions: CascaderOptionType[] = []) => {
|
||||
if (!('value' in this.props)) {
|
||||
this.setState({ value });
|
||||
}
|
||||
const { onChange } = this.props;
|
||||
onChange?.(value, selectedOptions);
|
||||
};
|
||||
|
||||
getLabel() {
|
||||
const { options, displayRender = defaultDisplayRender } = this.props;
|
||||
const names = getFilledFieldNames(this.props);
|
||||
const { value } = this.state;
|
||||
const unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
|
||||
const selectedOptions: CascaderOptionType[] = arrayTreeFilter(
|
||||
options,
|
||||
(o: CascaderOptionType, level: number) => o[names.value] === unwrappedValue[level],
|
||||
{ childrenKeyName: names.children },
|
||||
);
|
||||
const label = selectedOptions.length ? selectedOptions.map(o => o[names.label]) : value;
|
||||
return displayRender(label, selectedOptions);
|
||||
}
|
||||
|
||||
saveInput = (node: Input) => {
|
||||
this.input = node;
|
||||
};
|
||||
|
||||
handleChange = (value: any, selectedOptions: CascaderOptionType[]) => {
|
||||
this.setState({ inputValue: '' });
|
||||
if (selectedOptions[0].__IS_FILTERED_OPTION) {
|
||||
const unwrappedValue =
|
||||
selectedOptions[0][keepFilteredValueField] === undefined
|
||||
? value[0]
|
||||
: selectedOptions[0][keepFilteredValueField];
|
||||
const unwrappedSelectedOptions = selectedOptions[0].path;
|
||||
this.setValue(unwrappedValue, unwrappedSelectedOptions);
|
||||
return;
|
||||
}
|
||||
this.setValue(value, selectedOptions);
|
||||
};
|
||||
|
||||
handlePopupVisibleChange = (popupVisible: boolean) => {
|
||||
if (!('popupVisible' in this.props)) {
|
||||
this.setState(state => ({
|
||||
popupVisible,
|
||||
inputFocused: popupVisible,
|
||||
inputValue: popupVisible ? state.inputValue : '',
|
||||
}));
|
||||
}
|
||||
|
||||
const { onPopupVisibleChange } = this.props;
|
||||
onPopupVisibleChange?.(popupVisible);
|
||||
};
|
||||
|
||||
handleInputBlur = () => {
|
||||
this.setState({
|
||||
inputFocused: false,
|
||||
});
|
||||
};
|
||||
|
||||
handleInputClick = (e: React.MouseEvent<HTMLInputElement>) => {
|
||||
const { inputFocused, popupVisible } = this.state;
|
||||
// Prevent `Trigger` behaviour.
|
||||
if (inputFocused || popupVisible) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
// SPACE => https://github.com/ant-design/ant-design/issues/16871
|
||||
if (e.keyCode === KeyCode.BACKSPACE || e.keyCode === KeyCode.SPACE) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { popupVisible } = this.state;
|
||||
const inputValue = e.target.value;
|
||||
if (!popupVisible) {
|
||||
this.handlePopupVisibleChange(true);
|
||||
}
|
||||
this.setState({ inputValue });
|
||||
};
|
||||
|
||||
clearSelection = (e: React.MouseEvent<HTMLElement>) => {
|
||||
const { inputValue } = this.state;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!inputValue) {
|
||||
this.handlePopupVisibleChange(false);
|
||||
this.clearSelectionTimeout = setTimeout(() => {
|
||||
this.setValue([]);
|
||||
}, 200);
|
||||
} else {
|
||||
this.setState({ inputValue: '' });
|
||||
}
|
||||
};
|
||||
|
||||
generateFilteredOptions(prefixCls: string | undefined, renderEmpty: RenderEmptyHandler) {
|
||||
const { showSearch, notFoundContent } = this.props;
|
||||
const names: FilledFieldNamesType = getFilledFieldNames(this.props);
|
||||
const {
|
||||
filter = defaultFilterOption,
|
||||
render = defaultRenderFilteredOption,
|
||||
sort = defaultSortFilteredOption,
|
||||
limit = defaultLimit,
|
||||
} = showSearch as ShowSearchType;
|
||||
const { flattenOptions = [], inputValue } = this.state;
|
||||
|
||||
// Limit the filter if needed
|
||||
let filtered: Array<CascaderOptionType[]>;
|
||||
if (limit > 0) {
|
||||
filtered = [];
|
||||
let matchCount = 0;
|
||||
|
||||
// Perf optimization to filter items only below the limit
|
||||
flattenOptions.some(path => {
|
||||
const match = filter(this.state.inputValue, path, names);
|
||||
if (match) {
|
||||
filtered.push(path);
|
||||
matchCount += 1;
|
||||
}
|
||||
return matchCount >= limit;
|
||||
});
|
||||
} else {
|
||||
devWarning(
|
||||
typeof limit !== 'number',
|
||||
'Cascader',
|
||||
"'limit' of showSearch should be positive number or false.",
|
||||
);
|
||||
filtered = flattenOptions.filter(path => filter(this.state.inputValue, path, names));
|
||||
}
|
||||
|
||||
filtered = filtered.sort((a, b) => sort(a, b, inputValue, names));
|
||||
|
||||
if (filtered.length > 0) {
|
||||
// Fix issue: https://github.com/ant-design/ant-design/issues/26554
|
||||
const field = names.value === names.label ? keepFilteredValueField : names.value;
|
||||
|
||||
return filtered.map(
|
||||
(path: CascaderOptionType[]) =>
|
||||
({
|
||||
__IS_FILTERED_OPTION: true,
|
||||
path,
|
||||
[field]: path.map((o: CascaderOptionType) => o[names.value]),
|
||||
[names.label]: render(inputValue, path, prefixCls, names),
|
||||
disabled: path.some((o: CascaderOptionType) => !!o.disabled),
|
||||
isEmptyNode: true,
|
||||
} as CascaderOptionType),
|
||||
);
|
||||
}
|
||||
return [getEmptyNode(renderEmpty, names, notFoundContent)];
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.input.focus();
|
||||
}
|
||||
|
||||
blur() {
|
||||
this.input.blur();
|
||||
}
|
||||
|
||||
getPopupPlacement(direction: DirectionType = 'ltr') {
|
||||
const { popupPlacement } = this.props;
|
||||
if (popupPlacement !== undefined) {
|
||||
return popupPlacement;
|
||||
}
|
||||
return direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
|
||||
}
|
||||
|
||||
renderCascader = (
|
||||
{
|
||||
getPopupContainer: getContextPopupContainer,
|
||||
getPrefixCls,
|
||||
renderEmpty,
|
||||
direction,
|
||||
}: ConfigConsumerProps,
|
||||
locale: CascaderLocale,
|
||||
) => (
|
||||
<SizeContext.Consumer>
|
||||
{size => {
|
||||
const { props, state } = this;
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
inputPrefixCls: customizeInputPrefixCls,
|
||||
children,
|
||||
placeholder = locale.placeholder || 'Please select',
|
||||
size: customizeSize,
|
||||
disabled,
|
||||
className,
|
||||
style,
|
||||
allowClear,
|
||||
showSearch = false,
|
||||
suffixIcon,
|
||||
expandIcon,
|
||||
notFoundContent,
|
||||
popupClassName,
|
||||
bordered,
|
||||
dropdownRender,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const mergedSize = customizeSize || size;
|
||||
|
||||
const { value, inputFocused } = state;
|
||||
|
||||
const isRtlLayout = direction === 'rtl';
|
||||
|
||||
const prefixCls = getPrefixCls('cascader', customizePrefixCls);
|
||||
const inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
|
||||
|
||||
const sizeCls = classNames({
|
||||
[`${inputPrefixCls}-lg`]: mergedSize === 'large',
|
||||
[`${inputPrefixCls}-sm`]: mergedSize === 'small',
|
||||
});
|
||||
const clearIcon =
|
||||
(allowClear && !disabled && value.length > 0) || state.inputValue ? (
|
||||
<CloseCircleFilled
|
||||
className={`${prefixCls}-picker-clear`}
|
||||
onClick={this.clearSelection}
|
||||
/>
|
||||
) : null;
|
||||
const arrowCls = classNames({
|
||||
[`${prefixCls}-picker-arrow`]: true,
|
||||
[`${prefixCls}-picker-arrow-expand`]: state.popupVisible,
|
||||
});
|
||||
const pickerCls = classNames(
|
||||
`${prefixCls}-picker`,
|
||||
{
|
||||
[`${prefixCls}-picker-rtl`]: isRtlLayout,
|
||||
[`${prefixCls}-picker-with-value`]: state.inputValue,
|
||||
[`${prefixCls}-picker-disabled`]: disabled,
|
||||
[`${prefixCls}-picker-${mergedSize}`]: !!mergedSize,
|
||||
[`${prefixCls}-picker-show-search`]: !!showSearch,
|
||||
[`${prefixCls}-picker-focused`]: inputFocused,
|
||||
[`${prefixCls}-picker-borderless`]: !bordered,
|
||||
},
|
||||
className,
|
||||
);
|
||||
|
||||
// Fix bug of https://github.com/facebook/react/pull/5004
|
||||
// and https://fb.me/react-unknown-prop
|
||||
const inputProps = omit(
|
||||
// Not know why these props left
|
||||
otherProps as typeof otherProps & {
|
||||
filterOption: any;
|
||||
renderFilteredOption: any;
|
||||
sortFilteredOption: any;
|
||||
defaultValue: any;
|
||||
},
|
||||
[
|
||||
'onChange',
|
||||
'options',
|
||||
'popupPlacement',
|
||||
'transitionName',
|
||||
'displayRender',
|
||||
'onPopupVisibleChange',
|
||||
'changeOnSelect',
|
||||
'expandTrigger',
|
||||
'popupVisible',
|
||||
'getPopupContainer',
|
||||
'loadData',
|
||||
'filterOption',
|
||||
'renderFilteredOption',
|
||||
'sortFilteredOption',
|
||||
'fieldNames',
|
||||
],
|
||||
);
|
||||
|
||||
let { options } = props;
|
||||
const names: FilledFieldNamesType = getFilledFieldNames(this.props);
|
||||
if (options && options.length > 0) {
|
||||
if (state.inputValue) {
|
||||
options = this.generateFilteredOptions(prefixCls, renderEmpty);
|
||||
}
|
||||
} else {
|
||||
options = [getEmptyNode(renderEmpty, names, notFoundContent)];
|
||||
}
|
||||
// Dropdown menu should keep previous status until it is fully closed.
|
||||
if (!state.popupVisible) {
|
||||
options = this.cachedOptions;
|
||||
} else {
|
||||
this.cachedOptions = options;
|
||||
}
|
||||
|
||||
const dropdownMenuColumnStyle: { width?: number; height?: string } = {};
|
||||
const isNotFound = (options || []).length === 1 && options[0].isEmptyNode;
|
||||
if (isNotFound) {
|
||||
dropdownMenuColumnStyle.height = 'auto'; // Height of one row.
|
||||
}
|
||||
// The default value of `matchInputWidth` is `true`
|
||||
const resultListMatchInputWidth = (showSearch as ShowSearchType).matchInputWidth !== false;
|
||||
if (resultListMatchInputWidth && (state.inputValue || isNotFound) && this.input) {
|
||||
dropdownMenuColumnStyle.width = this.input.input.offsetWidth;
|
||||
}
|
||||
|
||||
let inputIcon: React.ReactNode;
|
||||
if (suffixIcon) {
|
||||
inputIcon = replaceElement(
|
||||
suffixIcon,
|
||||
<span className={`${prefixCls}-picker-arrow`}>{suffixIcon}</span>,
|
||||
() => ({
|
||||
className: classNames({
|
||||
[(suffixIcon as any).props.className!]: (suffixIcon as any).props.className,
|
||||
[`${prefixCls}-picker-arrow`]: true,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
inputIcon = <DownOutlined className={arrowCls} />;
|
||||
}
|
||||
|
||||
const label = this.getLabel();
|
||||
const input: React.ReactElement = children || (
|
||||
<span style={style} className={pickerCls}>
|
||||
<span
|
||||
className={`${prefixCls}-picker-label`}
|
||||
title={typeof label === 'string' && label ? label : undefined}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
<Input
|
||||
{...inputProps}
|
||||
tabIndex={-1}
|
||||
ref={this.saveInput}
|
||||
prefixCls={inputPrefixCls}
|
||||
placeholder={value && value.length > 0 ? undefined : placeholder}
|
||||
className={`${prefixCls}-input ${sizeCls}`}
|
||||
value={state.inputValue}
|
||||
disabled={disabled}
|
||||
readOnly={!showSearch}
|
||||
autoComplete={inputProps.autoComplete || 'off'}
|
||||
onClick={showSearch ? this.handleInputClick : undefined}
|
||||
onBlur={showSearch ? this.handleInputBlur : undefined}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onChange={showSearch ? this.handleInputChange : undefined}
|
||||
/>
|
||||
{clearIcon}
|
||||
{inputIcon}
|
||||
</span>
|
||||
);
|
||||
|
||||
let expandIconNode;
|
||||
if (expandIcon) {
|
||||
expandIconNode = expandIcon;
|
||||
} else {
|
||||
expandIconNode = isRtlLayout ? <LeftOutlined /> : <RightOutlined />;
|
||||
}
|
||||
|
||||
const loadingIcon = (
|
||||
<span className={`${prefixCls}-menu-item-loading-icon`}>
|
||||
<RedoOutlined spin />
|
||||
</span>
|
||||
);
|
||||
|
||||
const getPopupContainer = props.getPopupContainer || getContextPopupContainer;
|
||||
const rest = omit(props as typeof props & { inputIcon: any; loadingIcon: any }, [
|
||||
'inputIcon',
|
||||
'expandIcon',
|
||||
'loadingIcon',
|
||||
'bordered',
|
||||
'className',
|
||||
]);
|
||||
const rcCascaderPopupClassName = classNames(popupClassName, {
|
||||
[`${prefixCls}-menu-${direction}`]: direction === 'rtl',
|
||||
[`${prefixCls}-menu-empty`]:
|
||||
options.length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND',
|
||||
});
|
||||
const rootPrefixCls = getPrefixCls();
|
||||
|
||||
return (
|
||||
<RcCascader
|
||||
{...rest}
|
||||
prefixCls={prefixCls}
|
||||
getPopupContainer={getPopupContainer}
|
||||
options={options}
|
||||
value={value}
|
||||
popupVisible={state.popupVisible}
|
||||
onPopupVisibleChange={this.handlePopupVisibleChange}
|
||||
onChange={this.handleChange}
|
||||
dropdownMenuColumnStyle={dropdownMenuColumnStyle}
|
||||
expandIcon={expandIconNode}
|
||||
loadingIcon={loadingIcon}
|
||||
popupClassName={rcCascaderPopupClassName}
|
||||
popupPlacement={this.getPopupPlacement(direction)}
|
||||
// rc-cascader should update ts define to fix this case
|
||||
dropdownRender={dropdownRender as any}
|
||||
transitionName={getTransitionName(rootPrefixCls, 'slide-up', props.transitionName)}
|
||||
>
|
||||
{input}
|
||||
</RcCascader>
|
||||
);
|
||||
}}
|
||||
</SizeContext.Consumer>
|
||||
const loadingIcon = (
|
||||
<span className={`${prefixCls}-menu-item-loading-icon`}>
|
||||
<RedoOutlined spin />
|
||||
</span>
|
||||
);
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ConfigConsumer>
|
||||
{(configArgument: ConfigConsumerProps) => (
|
||||
<LocaleReceiver>{locale => this.renderCascader(configArgument, locale)}</LocaleReceiver>
|
||||
)}
|
||||
</ConfigConsumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
// =================== Multiple ====================
|
||||
const checkable = React.useMemo(
|
||||
() => (multiple ? <span className={`${cascaderPrefixCls}-checkbox-inner`} /> : false),
|
||||
[multiple],
|
||||
);
|
||||
|
||||
// ===================== Icons =====================
|
||||
const { suffixIcon, removeIcon, clearIcon } = getIcons({
|
||||
...props,
|
||||
multiple,
|
||||
prefixCls,
|
||||
});
|
||||
|
||||
// ==================== Render =====================
|
||||
return (
|
||||
<RcCascader
|
||||
prefixCls={prefixCls}
|
||||
className={classNames(
|
||||
!customizePrefixCls && cascaderPrefixCls,
|
||||
{
|
||||
[`${prefixCls}-lg`]: mergedSize === 'large',
|
||||
[`${prefixCls}-sm`]: mergedSize === 'small',
|
||||
[`${prefixCls}-rtl`]: isRtl,
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
{...(restProps as any)}
|
||||
direction={mergedDirection}
|
||||
notFoundContent={mergedNotFoundContent}
|
||||
allowClear={allowClear}
|
||||
showSearch={mergedShowSearch}
|
||||
expandIcon={mergedExpandIcon}
|
||||
inputIcon={suffixIcon}
|
||||
removeIcon={removeIcon}
|
||||
clearIcon={clearIcon}
|
||||
loadingIcon={loadingIcon}
|
||||
checkable={checkable}
|
||||
dropdownClassName={mergedDropdownClassName}
|
||||
dropdownPrefixCls={customizePrefixCls || cascaderPrefixCls}
|
||||
choiceTransitionName={getTransitionName(rootPrefixCls, '', choiceTransitionName)}
|
||||
transitionName={getTransitionName(rootPrefixCls, 'slide-up', transitionName)}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Cascader.displayName = 'Cascader';
|
||||
|
||||
export default Cascader;
|
||||
|
@ -37,18 +37,18 @@ cover: https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | function(triggerNode) | () => document.body | |
|
||||
| loadData | 用于动态加载选项,无法与 `showSearch` 一起使用 | (selectedOptions) => void | - | |
|
||||
| notFoundContent | 当下拉列表为空时显示的内容 | string | `Not Found` | |
|
||||
| open | 控制浮层显隐 | boolean | - | 4.17.0 |
|
||||
| options | 可选项数据源 | [Option](#Option)\[] | - | |
|
||||
| placeholder | 输入框占位文本 | string | `请选择` | |
|
||||
| popupClassName | 自定义浮层类名 | string | - | |
|
||||
| popupPlacement | 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` | string | `bottomLeft` | |
|
||||
| popupVisible | 控制浮层显隐 | boolean | - | |
|
||||
| showSearch | 在选择框中显示搜索框 | boolean \| [Object](#showSearch) | false | |
|
||||
| size | 输入框大小 | `large` \| `middle` \| `small` | - | |
|
||||
| style | 自定义样式 | CSSProperties | - | |
|
||||
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
|
||||
| value | 指定选中项 | string\[] \| number\[] | - | |
|
||||
| onChange | 选择完成后的回调 | (value, selectedOptions) => void | - | |
|
||||
| onPopupVisibleChange | 显示/隐藏浮层的回调 | (value) => void | - | |
|
||||
| onDropdownVisibleChange | 显示/隐藏浮层的回调 | (value) => void | - | 4.17.0 |
|
||||
|
||||
### showSearch
|
||||
|
||||
|
@ -1,172 +1,38 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
@import '../../input/style/mixin';
|
||||
@import '../../checkbox/style/mixin';
|
||||
|
||||
@cascader-prefix-cls: ~'@{ant-prefix}-cascader';
|
||||
|
||||
.antCheckboxFn(@checkbox-prefix-cls: ~'@{cascader-prefix-cls}-checkbox');
|
||||
|
||||
.@{cascader-prefix-cls} {
|
||||
.reset-component();
|
||||
width: 184px;
|
||||
|
||||
&-input.@{ant-prefix}-input {
|
||||
// Keep it static for https://github.com/ant-design/ant-design/issues/16738
|
||||
position: static;
|
||||
width: 100%;
|
||||
// https://github.com/ant-design/ant-design/issues/17582
|
||||
padding-right: 24px;
|
||||
// Add important to fix https://github.com/ant-design/ant-design/issues/5078
|
||||
// because input.less will compile after cascader.less
|
||||
background-color: transparent !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-picker-show-search &-input.@{ant-prefix}-input {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&-picker {
|
||||
.reset-component();
|
||||
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
background-color: @cascader-bg;
|
||||
border-radius: @border-radius-base;
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
|
||||
&-with-value &-label {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
color: @disabled-color;
|
||||
background: @input-disabled-bg;
|
||||
cursor: not-allowed;
|
||||
.@{cascader-prefix-cls}-input {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus .@{cascader-prefix-cls}-input {
|
||||
.active();
|
||||
}
|
||||
|
||||
&-borderless .@{cascader-prefix-cls}-input {
|
||||
border-color: transparent !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
&-show-search&-focused {
|
||||
color: @disabled-color;
|
||||
}
|
||||
|
||||
&-label {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
margin-top: -10px;
|
||||
padding: 0 20px 0 @control-padding-horizontal;
|
||||
overflow: hidden;
|
||||
line-height: 20px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&-clear {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: @control-padding-horizontal;
|
||||
z-index: 2;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: -6px;
|
||||
color: @disabled-color;
|
||||
font-size: @font-size-sm;
|
||||
line-height: 12px;
|
||||
background: @component-background;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: color 0.3s ease, opacity 0.15s ease;
|
||||
&:hover {
|
||||
color: @text-color-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover &-clear {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
// arrow
|
||||
&-arrow {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: @control-padding-horizontal;
|
||||
z-index: 1;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-top: -6px;
|
||||
color: @disabled-color;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ant-design/ant-design/pull/12407#issuecomment-424657810
|
||||
&-picker-label:hover + &-input {
|
||||
&:not(.@{cascader-prefix-cls}-picker-disabled &) {
|
||||
.hover();
|
||||
}
|
||||
}
|
||||
|
||||
&-picker-small &-picker-clear,
|
||||
&-picker-small &-picker-arrow {
|
||||
right: @control-padding-horizontal-sm;
|
||||
&-checkbox {
|
||||
top: 0;
|
||||
margin-right: @padding-xs;
|
||||
}
|
||||
|
||||
&-menus {
|
||||
position: absolute;
|
||||
z-index: @zindex-dropdown;
|
||||
font-size: @cascader-dropdown-font-size;
|
||||
white-space: nowrap;
|
||||
background: @cascader-menu-bg;
|
||||
border-radius: @border-radius-base;
|
||||
box-shadow: @box-shadow-base;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: flex-start;
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
&-empty,
|
||||
&-hidden {
|
||||
display: none;
|
||||
}
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft {
|
||||
animation-name: antSlideUpIn;
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
|
||||
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft {
|
||||
animation-name: antSlideDownIn;
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft {
|
||||
animation-name: antSlideUpOut;
|
||||
}
|
||||
|
||||
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft {
|
||||
animation-name: antSlideDownOut;
|
||||
&.@{cascader-prefix-cls}-menu-empty {
|
||||
.@{cascader-prefix-cls}-menu {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
display: inline-block;
|
||||
min-width: 111px;
|
||||
height: 180px;
|
||||
margin: 0;
|
||||
margin: -@dropdown-edge-child-vertical-padding 0;
|
||||
padding: @cascader-dropdown-edge-child-vertical-padding 0;
|
||||
overflow: auto;
|
||||
vertical-align: top;
|
||||
@ -174,67 +40,62 @@
|
||||
border-right: @border-width-base @border-style-base @cascader-menu-border-color-split;
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar; // https://github.com/ant-design/ant-design/issues/11857
|
||||
|
||||
&:first-child {
|
||||
border-radius: @border-radius-base 0 0 @border-radius-base;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: -1px;
|
||||
border-right-color: transparent;
|
||||
border-radius: 0 @border-radius-base @border-radius-base 0;
|
||||
}
|
||||
&:only-child {
|
||||
border-radius: @border-radius-base;
|
||||
}
|
||||
}
|
||||
&-menu-item {
|
||||
padding: @cascader-dropdown-vertical-padding @control-padding-horizontal;
|
||||
overflow: hidden;
|
||||
line-height: @cascader-dropdown-line-height;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
background: @item-hover-bg;
|
||||
}
|
||||
&-disabled {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
.@{cascader-prefix-cls}-menu-empty & {
|
||||
color: @disabled-color;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
&-active:not(&-disabled) {
|
||||
&,
|
||||
&:hover {
|
||||
font-weight: @select-item-selected-font-weight;
|
||||
background-color: @cascader-item-selected-bg;
|
||||
}
|
||||
}
|
||||
&-expand {
|
||||
position: relative;
|
||||
padding-right: 24px;
|
||||
}
|
||||
&-item {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
padding: @cascader-dropdown-vertical-padding @control-padding-horizontal;
|
||||
overflow: hidden;
|
||||
line-height: @cascader-dropdown-line-height;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&-expand &-expand-icon,
|
||||
&-loading-icon {
|
||||
position: absolute;
|
||||
right: @control-padding-horizontal;
|
||||
color: @text-color-secondary;
|
||||
font-size: 10px;
|
||||
&:hover {
|
||||
background: @item-hover-bg;
|
||||
}
|
||||
|
||||
.@{cascader-prefix-cls}-menu-item-disabled& {
|
||||
&-disabled {
|
||||
color: @disabled-color;
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& &-keyword {
|
||||
color: @highlight-color;
|
||||
.@{cascader-prefix-cls}-menu-empty & {
|
||||
color: @disabled-color;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-active:not(&-disabled) {
|
||||
&,
|
||||
&:hover {
|
||||
font-weight: @select-item-selected-font-weight;
|
||||
background-color: @cascader-item-selected-bg;
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
&-expand &-expand-icon,
|
||||
&-loading-icon {
|
||||
margin-left: @padding-xss;
|
||||
color: @text-color-secondary;
|
||||
font-size: 10px;
|
||||
|
||||
.@{cascader-prefix-cls}-menu-item-disabled& {
|
||||
color: @disabled-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-keyword {
|
||||
color: @highlight-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,4 +3,4 @@ import './index.less';
|
||||
|
||||
// style dependencies
|
||||
import '../../empty/style';
|
||||
import '../../input/style';
|
||||
import '../../select/style';
|
||||
|
@ -1,95 +1,17 @@
|
||||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
@import '../../input/style/mixin';
|
||||
@import (reference) './index';
|
||||
|
||||
@cascader-prefix-cls: ~'@{ant-prefix}-cascader';
|
||||
@picker-rtl-cls: ~'@{cascader-prefix-cls}-picker-rtl';
|
||||
@menu-rtl-cls: ~'@{cascader-prefix-cls}-menu-rtl';
|
||||
|
||||
.@{cascader-prefix-cls} {
|
||||
&-input.@{ant-prefix}-input {
|
||||
.@{picker-rtl-cls} & {
|
||||
padding-right: @input-padding-horizontal-base;
|
||||
padding-left: 24px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
&-picker {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&-label {
|
||||
.@{picker-rtl-cls} & {
|
||||
padding: 0 @control-padding-horizontal 0 20px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
&-clear {
|
||||
.@{picker-rtl-cls} & {
|
||||
right: auto;
|
||||
left: @control-padding-horizontal;
|
||||
}
|
||||
}
|
||||
|
||||
&-arrow {
|
||||
.@{picker-rtl-cls} & {
|
||||
right: auto;
|
||||
left: @control-padding-horizontal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-picker-small &-picker-clear,
|
||||
&-picker-small &-picker-arrow {
|
||||
.@{picker-rtl-cls}& {
|
||||
right: auto;
|
||||
left: @control-padding-horizontal-sm;
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
&-rtl & {
|
||||
direction: rtl;
|
||||
border-right: none;
|
||||
border-left: @border-width-base @border-style-base @border-color-split;
|
||||
&:first-child {
|
||||
border-radius: 0 @border-radius-base @border-radius-base 0;
|
||||
}
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
margin-left: -1px;
|
||||
border-left-color: transparent;
|
||||
border-radius: @border-radius-base 0 0 @border-radius-base;
|
||||
}
|
||||
&:only-child {
|
||||
border-radius: @border-radius-base;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-menu-item {
|
||||
&-expand {
|
||||
.@{menu-rtl-cls} & {
|
||||
padding-right: @control-padding-horizontal;
|
||||
padding-left: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
&-expand &-expand-icon,
|
||||
.@{cascader-prefix-cls}-rtl {
|
||||
.@{cascader-prefix-cls}-menu-item {
|
||||
&-expand-icon,
|
||||
&-loading-icon {
|
||||
.@{menu-rtl-cls} & {
|
||||
right: auto;
|
||||
left: @control-padding-horizontal;
|
||||
}
|
||||
margin-right: @padding-xss;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-loading-icon {
|
||||
.@{menu-rtl-cls} & {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
}
|
||||
.@{cascader-prefix-cls}-checkbox {
|
||||
top: 0;
|
||||
margin-right: 0;
|
||||
margin-left: @padding-xs;
|
||||
}
|
||||
}
|
||||
|
@ -9985,231 +9985,339 @@ exports[`ConfigProvider components Carousel prefixCls 1`] = `
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Cascader configProvider 1`] = `
|
||||
<span
|
||||
class="config-cascader-picker config-cascader-picker-show-search"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="config-select config-cascader config-select-single config-select-allow-clear config-select-show-arrow config-select-show-search"
|
||||
>
|
||||
<span
|
||||
class="config-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="config-input config-cascader-input "
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="config-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="config-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="config-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Cascader configProvider componentSize large 1`] = `
|
||||
<span
|
||||
class="config-cascader-picker config-cascader-picker-large config-cascader-picker-show-search"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="config-select config-cascader config-select-lg config-select-single config-select-allow-clear config-select-show-arrow config-select-show-search"
|
||||
>
|
||||
<span
|
||||
class="config-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="config-input config-input-lg config-cascader-input config-input-lg"
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="config-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="config-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="config-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Cascader configProvider componentSize middle 1`] = `
|
||||
<span
|
||||
class="config-cascader-picker config-cascader-picker-middle config-cascader-picker-show-search"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="config-select config-cascader config-select-single config-select-allow-clear config-select-show-arrow config-select-show-search"
|
||||
>
|
||||
<span
|
||||
class="config-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="config-input config-cascader-input "
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="config-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="config-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="config-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="config-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="config-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down config-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Cascader configProvider virtual and dropdownMatchSelectWidth 1`] = `
|
||||
<span
|
||||
class="ant-cascader-picker ant-cascader-picker-show-search"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow ant-select-show-search"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Cascader normal 1`] = `
|
||||
<span
|
||||
class="ant-cascader-picker ant-cascader-picker-show-search"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow ant-select-show-search"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Cascader prefixCls 1`] = `
|
||||
<span
|
||||
class="prefix-Cascader-picker prefix-Cascader-picker-show-search"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="prefix-Cascader prefix-Cascader-single prefix-Cascader-allow-clear prefix-Cascader-show-arrow prefix-Cascader-show-search"
|
||||
>
|
||||
<span
|
||||
class="prefix-Cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input prefix-Cascader-input "
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down prefix-Cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="prefix-Cascader-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="prefix-Cascader-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="prefix-Cascader-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="prefix-Cascader-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="prefix-Cascader-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down prefix-Cascader-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Checkbox configProvider 1`] = `
|
||||
|
@ -222,42 +222,60 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
|
||||
<h4>
|
||||
Cascader
|
||||
</h4>
|
||||
<span
|
||||
class="ant-cascader-picker ant-cascader-picker-show-search"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow ant-select-show-search"
|
||||
style="width:200px"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="Please select"
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
role="combobox"
|
||||
type="search"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<h4>
|
||||
Transfer
|
||||
</h4>
|
||||
|
@ -3430,65 +3430,92 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
id="register_residence"
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-cascader-picker-clear"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
<input
|
||||
aria-activedescendant="register_residence_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="register_residence_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="register_residence_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
id="register_residence"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-item"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
class="ant-select-clear"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<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>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -4596,42 +4623,62 @@ exports[`renders ./components/form/demo/size.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker ant-cascader-picker-default"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="Please select"
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -7396,42 +7443,62 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="Please select"
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
|
@ -436,43 +436,65 @@ exports[`renders ./components/input-number/demo/addon.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-input-number-group-addon"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
style="width:150px"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="cascader"
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
>
|
||||
cascader
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-input-number"
|
||||
|
@ -261,43 +261,65 @@ exports[`renders ./components/input/demo/addon.md correctly 1`] = `
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
style="width:150px"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="cascader"
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
>
|
||||
cascader
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input"
|
||||
@ -690,64 +712,91 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
</div>,
|
||||
<span
|
||||
class="ant-cascader-picker"
|
||||
tabindex="0"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-cascader-picker-clear"
|
||||
role="img"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-item"
|
||||
title="Zhejiang / Hangzhou / West Lake"
|
||||
>
|
||||
Zhejiang / Hangzhou / West Lake
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
class="ant-select-clear"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<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>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
</div>,
|
||||
<div
|
||||
class="ant-picker ant-picker-range"
|
||||
>
|
||||
@ -2390,43 +2439,65 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="ant-cascader-picker"
|
||||
<div
|
||||
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
style="width:70%"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="ant-cascader-picker-label"
|
||||
/>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="ant-input ant-cascader-input "
|
||||
placeholder="Select Address"
|
||||
readonly=""
|
||||
tabindex="-1"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-cascader-picker-arrow"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<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"
|
||||
<input
|
||||
aria-activedescendant="undefined_list_0"
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
>
|
||||
Select Address
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
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>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
@ -117,7 +117,7 @@
|
||||
"copy-to-clipboard": "^3.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.25.3",
|
||||
"rc-cascader": "~1.4.0",
|
||||
"rc-cascader": "~2.0.0-alpha.17",
|
||||
"rc-checkbox": "~2.3.0",
|
||||
"rc-collapse": "~3.1.0",
|
||||
"rc-dialog": "~8.6.0",
|
||||
|
@ -2,6 +2,7 @@ import glob from 'glob';
|
||||
import { render } from 'enzyme';
|
||||
import MockDate from 'mockdate';
|
||||
import moment from 'moment';
|
||||
import { excludeWarning } from './excludeWarning';
|
||||
|
||||
type CheerIO = ReturnType<typeof render>;
|
||||
type CheerIOElement = CheerIO[0];
|
||||
@ -57,6 +58,8 @@ export default function demoTest(component: string, options: Options = {}) {
|
||||
testMethod = test.skip;
|
||||
}
|
||||
testMethod(`renders ${file} correctly`, () => {
|
||||
const errSpy = excludeWarning();
|
||||
|
||||
MockDate.set(moment('2016-11-22').valueOf());
|
||||
const demo = require(`../.${file}`).default; // eslint-disable-line global-require, import/no-dynamic-require
|
||||
const wrapper = render(demo);
|
||||
@ -66,6 +69,8 @@ export default function demoTest(component: string, options: Options = {}) {
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
MockDate.reset();
|
||||
|
||||
errSpy();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
27
tests/shared/excludeWarning.tsx
Normal file
27
tests/shared/excludeWarning.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
const originError = console.error;
|
||||
|
||||
/** This function will remove `useLayoutEffect` server side warning. Since it's useless. */
|
||||
export function excludeWarning() {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation((msg, ...rest) => {
|
||||
if (String(msg).includes('useLayoutEffect does nothing on the server')) {
|
||||
return;
|
||||
}
|
||||
originError(msg, ...rest);
|
||||
});
|
||||
|
||||
return () => {
|
||||
errorSpy.mockRestore();
|
||||
};
|
||||
}
|
||||
|
||||
export default function excludeAllWarning() {
|
||||
let cleanUp: Function;
|
||||
|
||||
beforeAll(() => {
|
||||
cleanUp = excludeWarning();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
cleanUp();
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user