Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ React.render(
<td>></td>
<td>specific the default loading icon</td>
</tr>
<tr>
<td>hidePopupOnSelect</td>
<td>Boolean</td>
<td>>true</td>
<td>hide popup on select</td>
</tr>
</tbody>
</table>

Expand Down
8 changes: 5 additions & 3 deletions src/Cascader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export interface CascaderProps extends Pick<TriggerProps, 'getPopupContainer'> {
filedNames?: CascaderFieldNames; // typo but for compatibility
expandIcon?: React.ReactNode;
loadingIcon?: React.ReactNode;
hidePopupOnSelect?: boolean;
}

interface CascaderState {
Expand Down Expand Up @@ -103,6 +104,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
expandTrigger: 'click',
fieldNames: { label: 'label', value: 'value', children: 'children' },
expandIcon: '>',
hidePopupOnSelect: true,
};

static getDerivedStateFromProps(nextProps: CascaderProps, prevState: CascaderState) {
Expand Down Expand Up @@ -208,7 +210,7 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
if (triggerNode && triggerNode.focus) {
triggerNode.focus();
}
const { changeOnSelect, loadData, expandTrigger } = this.props;
const { changeOnSelect, loadData, expandTrigger, hidePopupOnSelect } = this.props;
if (!targetOption || targetOption.disabled) {
return;
}
Expand All @@ -229,13 +231,13 @@ class Cascader extends React.Component<CascaderProps, CascaderState> {
!targetOption[this.getFieldName('children')] ||
!targetOption[this.getFieldName('children')].length
) {
this.handleChange(activeOptions, { visible: false }, e);
this.handleChange(activeOptions, { visible: !hidePopupOnSelect }, e);
// set value to activeValue when select leaf option
newState.value = activeValue;
// add e.type judgement to prevent `onChange` being triggered by mouseEnter
} else if (changeOnSelect && (e.type === 'click' || e.type === 'keydown')) {
if (expandTrigger === 'hover') {
this.handleChange(activeOptions, { visible: false }, e);
this.handleChange(activeOptions, { visible: !hidePopupOnSelect }, e);
} else {
this.handleChange(activeOptions, { visible: true }, e);
}
Expand Down
1 change: 1 addition & 0 deletions tests/__snapshots__/index.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ exports[`Cascader should render custom dropdown correctly 1`] = `
"value": "value",
}
}
hidePopupOnSelect={true}
onChange={[Function]}
onItemDoubleClick={[Function]}
onPopupVisibleChange={[Function]}
Expand Down
66 changes: 66 additions & 0 deletions tests/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ import {
addressOptionsForFieldNames,
} from './demoOptions';

export const createDocumentListenersMock = () => {
const listeners = {};
const handler = (domEl, event) => listeners?.[event]?.({ target: domEl });
document.addEventListener = jest.fn((event, cb) => {
listeners[event] = cb;
});
document.removeEventListener = jest.fn((event) => {
delete listeners[event];
});
return {
mouseDown: (domEl) => handler(domEl, 'mousedown'),
click: (domEl) => handler(domEl, 'click'),
};
};

describe('Cascader', () => {
let selectedValue;
const onChange = function onChange(value) {
Expand All @@ -24,6 +39,8 @@ describe('Cascader', () => {
jest.useRealTimers();
});

const fireEvent = createDocumentListenersMock();

it('should toggle select panel when click it', () => {
const wrapper = mount(
<Cascader options={addressOptions} onChange={onChange}>
Expand Down Expand Up @@ -630,4 +647,53 @@ describe('Cascader', () => {
const menus = wrapper.find('.rc-cascader-menus');
expect(menus).toMatchSnapshot();
});

it('should display after select, when hidePopupOnSelect is false', () => {
const wrapper = mount(
<Cascader options={addressOptions} hidePopupOnSelect={false}>
<input readOnly />
</Cascader>,
);
wrapper.find('input').simulate('click');
let menus = wrapper.find('.rc-cascader-menu');
expect(menus.length).toBe(1);
const menu1Items = menus.at(0).find('.rc-cascader-menu-item');
expect(menu1Items.length).toBe(3);
menu1Items.at(2).simulate('click');
expect(
wrapper.find('.rc-cascader-menu-item').at(2).hasClass('rc-cascader-menu-item-active'),
).toBe(true);

menus = wrapper.find('.rc-cascader-menu');
expect(menus.length).toBe(2);
const menu2Items = menus.at(1).find('.rc-cascader-menu-item');
expect(menu2Items.length).toBe(2);

menu2Items.at(0).simulate('click');
expect(
wrapper
.find('.rc-cascader-menu')
.at(1)
.find('.rc-cascader-menu-item')
.first()
.hasClass('rc-cascader-menu-item-active'),
).toBe(true);

expect(wrapper.state().popupVisible).toBeTruthy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

开启 hidePopupOnSelect 后,还是可以 blur 隐藏的吧?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以的

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

补充一个用例?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好,稍等

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

加了

fireEvent.mouseDown(document.body);
expect(wrapper.state().popupVisible).toBeFalsy();
});

it('should toggle select panel when click it, even if hidePopupOnSelect is false', () => {
const wrapper = mount(
<Cascader options={addressOptions} onChange={onChange} hidePopupOnSelect={false}>
<input readOnly />
</Cascader>,
);
expect(wrapper.state().popupVisible).toBeFalsy();
wrapper.find('input').simulate('click');
expect(wrapper.state().popupVisible).toBeTruthy();
wrapper.find('input').simulate('click');
expect(wrapper.state().popupVisible).toBeFalsy();
});
});