;
// ======================== Multiple ========================
@@ -200,6 +204,8 @@ export default function Panel<
toggleOpen={noop}
open
direction={direction}
+ defaultActiveKey={defaultActiveKey}
+ disabled={disabled}
/>
)}
diff --git a/src/hooks/useSearchConfig.ts b/src/hooks/useSearchConfig.ts
index e9889ad6..b7b6da80 100644
--- a/src/hooks/useSearchConfig.ts
+++ b/src/hooks/useSearchConfig.ts
@@ -22,7 +22,7 @@ export default function useSearchConfig(showSearch?: CascaderProps['showSearch']
}
if ((searchConfig.limit as number) <= 0) {
- delete searchConfig.limit;
+ searchConfig.limit = false;
if (process.env.NODE_ENV !== 'production') {
warning(false, "'limit' of showSearch should be positive number or false.");
diff --git a/src/hooks/useSearchOptions.ts b/src/hooks/useSearchOptions.ts
index 624af9d3..3d99f603 100644
--- a/src/hooks/useSearchOptions.ts
+++ b/src/hooks/useSearchOptions.ts
@@ -9,13 +9,13 @@ const defaultFilter: ShowSearchType['filter'] = (search, options, { label = '' }
const defaultRender: ShowSearchType['render'] = (inputValue, path, prefixCls, fieldNames) =>
path.map(opt => opt[fieldNames.label as string]).join(' / ');
-export default (
+const useSearchOptions = (
search: string,
options: DefaultOptionType[],
fieldNames: InternalFieldNames,
prefixCls: string,
config: ShowSearchType,
- changeOnSelect?: boolean,
+ enableHalfPath?: boolean,
) => {
const { filter = defaultFilter, render = defaultRender, limit = 50, sort } = config;
@@ -46,8 +46,8 @@ export default (
// If is leaf option
!children ||
children.length === 0 ||
- // If is changeOnSelect
- changeOnSelect
+ // If is changeOnSelect or multiple
+ enableHalfPath
) {
if (filter(search, connectedPathOptions, { label: fieldNames.label })) {
filteredOptions.push({
@@ -87,5 +87,7 @@ export default (
return limit !== false && limit > 0
? filteredOptions.slice(0, limit as number)
: filteredOptions;
- }, [search, options, fieldNames, prefixCls, render, changeOnSelect, filter, sort, limit]);
+ }, [search, options, fieldNames, prefixCls, render, enableHalfPath, filter, sort, limit]);
};
+
+export default useSearchOptions;
diff --git a/tests/Panel.spec.tsx b/tests/Panel.spec.tsx
index 452f1be4..ad917dc0 100644
--- a/tests/Panel.spec.tsx
+++ b/tests/Panel.spec.tsx
@@ -79,6 +79,19 @@ describe('Cascader.Panel', () => {
expect(onChange).toHaveBeenCalledWith([['bamboo', 'little']], expect.anything());
});
+ it('multiple with defaultActiveKey', () => {
+ const onChange = jest.fn();
+ const { container } = render(
+ ,
+ );
+ expect(container.querySelectorAll('.rc-cascader-menu')).toHaveLength(2);
+ });
+
it('rtl', () => {
const { container } = render();
@@ -97,4 +110,17 @@ describe('Cascader.Panel', () => {
const checkedLi = container.querySelector('[aria-checked="true"]');
expect(checkedLi?.textContent).toEqual('Little');
});
+
+ it('disabled', () => {
+ const onChange = jest.fn();
+ const { container } = render(
+ ,
+ );
+
+ expect(container.querySelector('.rc-cascader-menu-item-disabled')).toBeTruthy();
+
+ const selectOption = container.querySelector('.rc-cascader-menu-item')!;
+ fireEvent.click(selectOption);
+ expect(onChange).not.toHaveBeenCalled();
+ });
});
diff --git a/tests/__snapshots__/search.spec.tsx.snap b/tests/__snapshots__/search.spec.tsx.snap
index 8fa4d0e4..a08aaac7 100644
--- a/tests/__snapshots__/search.spec.tsx.snap
+++ b/tests/__snapshots__/search.spec.tsx.snap
@@ -8,26 +8,30 @@ exports[`Cascader.Search should correct render Cascader with same field name of
class="rc-cascader-selector"
>
-
+
+
+
-
{
let selectedValue: any;
@@ -1022,6 +1022,85 @@ describe('Cascader.Basic', () => {
wrapper.find(`li[data-path-key]`).at(0).simulate('click');
wrapper.find(`li[data-path-key]`).at(1).simulate('click');
});
+ it('hover + search', () => {
+ let getOffesetTopTimes = 0;
+ const spyElement = spyElementPrototypes(HTMLElement, {
+ offsetTop: {
+ get: () => (getOffesetTopTimes++ % 2 === 0 ? 100 : 0),
+ },
+ scrollTop: {
+ get: () => 0,
+ },
+ offsetHeight: {
+ get: () => 10,
+ },
+ });
+
+ const wrapper = render(
+ ,
+ );
+ fireEvent.change(wrapper.container.querySelector('input') as HTMLElement, {
+ target: { value: 'w' },
+ });
+ const items = wrapper.container.querySelectorAll('.rc-cascader-menu-item');
+ fireEvent.mouseEnter(items[9]);
+ expect(mockScrollTo).toHaveBeenCalledTimes(0);
+
+ spyElement.mockRestore();
+ });
});
it('not crash when value type is not array', () => {
diff --git a/tests/search.limit.spec.tsx b/tests/search.limit.spec.tsx
new file mode 100644
index 00000000..2ebfd097
--- /dev/null
+++ b/tests/search.limit.spec.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import Cascader from '../src';
+import type { ReactWrapper } from './enzyme';
+import { mount } from './enzyme';
+
+describe('Cascader.Search', () => {
+ function doSearch(wrapper: ReactWrapper, search: string) {
+ wrapper.find('input').simulate('change', {
+ target: {
+ value: search,
+ },
+ });
+ }
+ const options = [
+ {
+ children: [] as any[],
+ isParent: true,
+ label: 'Asia',
+ value: 'Asia',
+ },
+ ];
+ for (let i = 0; i < 100; i++) {
+ options[0].children.push({
+ label: 'label' + i,
+ value: 'value' + i,
+ });
+ }
+
+ it('limit', () => {
+ const wrapper = mount(
+ ,
+ );
+
+ doSearch(wrapper, 'as');
+ const itemList = wrapper.find('div.rc-cascader-menu-item-content');
+ expect(itemList).toHaveLength(100);
+ });
+
+ it('limit', () => {
+ const wrapper = mount(
+ ,
+ );
+
+ doSearch(wrapper, 'as');
+ const itemList = wrapper.find('div.rc-cascader-menu-item-content');
+ expect(itemList).toHaveLength(100);
+ });
+
+ it('limit', () => {
+ const wrapper = mount(
+ ,
+ );
+
+ doSearch(wrapper, 'as');
+ const itemList = wrapper.find('div.rc-cascader-menu-item-content');
+ expect(itemList).toHaveLength(20);
+ });
+});
diff --git a/tests/search.spec.tsx b/tests/search.spec.tsx
index 2083f4cd..12c7b394 100644
--- a/tests/search.spec.tsx
+++ b/tests/search.spec.tsx
@@ -193,7 +193,7 @@ describe('Cascader.Search', () => {
errorSpy.mockRestore();
});
- it('onChange should be triggered when click option with multiple', () => {
+ it('onChange should be triggered when click option with changeOnSelect + multiple', () => {
const onChange = jest.fn();
const wrapper = mount(
,
@@ -202,6 +202,31 @@ describe('Cascader.Search', () => {
wrapper.find('.rc-cascader-menu-item').first().simulate('click');
wrapper.find('.rc-cascader-menu-item').first().simulate('mousedown');
expect(onChange).toHaveBeenCalledWith([['bamboo', 'little', 'fish']], expect.anything());
+
+ doSearch(wrapper, 'light');
+ wrapper.find('.rc-cascader-menu-item').first().simulate('click');
+ wrapper.find('.rc-cascader-menu-item').first().simulate('mousedown');
+ expect(onChange).toHaveBeenCalledWith(
+ [['bamboo', 'little', 'fish'], ['light']],
+ expect.anything(),
+ );
+ });
+
+ it('onChange should be triggered when click option with multiple', () => {
+ const onChange = jest.fn();
+ const wrapper = mount();
+ doSearch(wrapper, 'toy');
+ wrapper.find('.rc-cascader-menu-item').first().simulate('click');
+ wrapper.find('.rc-cascader-menu-item').first().simulate('mousedown');
+ expect(onChange).toHaveBeenCalledWith([['bamboo', 'little', 'fish']], expect.anything());
+
+ doSearch(wrapper, 'light');
+ wrapper.find('.rc-cascader-menu-item').first().simulate('click');
+ wrapper.find('.rc-cascader-menu-item').first().simulate('mousedown');
+ expect(onChange).toHaveBeenCalledWith(
+ [['bamboo', 'little', 'fish'], ['light']],
+ expect.anything(),
+ );
});
it('should not crash when exist options with same value on different levels', () => {
diff --git a/tests/selector.spec.tsx b/tests/selector.spec.tsx
index e7387714..dbd92540 100644
--- a/tests/selector.spec.tsx
+++ b/tests/selector.spec.tsx
@@ -5,10 +5,10 @@ import Cascader from '../src';
import { addressOptions } from './demoOptions';
// Mock `useActive` hook
-jest.mock('../src/OptionList/useActive', () => (multiple: boolean, open: boolean) => {
+jest.mock('../src/OptionList/useActive', () => (multiple: boolean, open: boolean, defaultActiveKey: React.Key[]) => {
// Pass to origin hooks
const originHook = jest.requireActual('../src/OptionList/useActive').default;
- const [activeValueCells, setActiveValueCells] = originHook(multiple, open);
+ const [activeValueCells, setActiveValueCells] = originHook(multiple, open, defaultActiveKey);
(global as any).activeValueCells = activeValueCells;