diff --git a/README.md b/README.md
index 151b91a0..2f6e0b03 100644
--- a/README.md
+++ b/README.md
@@ -114,12 +114,6 @@ React.render(
-
- | autoClearSearchValue |
- boolean |
- true |
- Whether the current search will be cleared on selecting an item. Only applies when checkable |
-
| options |
Object |
@@ -234,9 +228,28 @@ React.render(
>true |
hide popup on select |
+
+ | showSearch |
+ boolean | object |
+ false |
+ Whether show search input in single mode |
+
+### showSearch
+
+| Property | Description | Type | Default | Version |
+| --- | --- | --- | --- | --- |
+| autoClearSearchValue | Whether the current search will be cleared on selecting an item. Only applies when checkable| boolean | true |
+| filter | The function will receive two arguments, inputValue and option, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded | function(inputValue, path): boolean | - | |
+| limit | Set the count of filtered items | number \| false | 50 | |
+| matchInputWidth | Whether the width of list matches input, ([how it looks](https://github.com/ant-design/ant-design/issues/25779)) | boolean | true | |
+| render | Used to render filtered options | function(inputValue, path): ReactNode | - | |
+| sort | Used to sort filtered options | function(a, b, inputValue) | - | |
+| searchValue | The current input "search" text | string | - | - |
+| onSearch | called when input changed | function | - | - |
+
### option
diff --git a/src/Cascader.tsx b/src/Cascader.tsx
index 268c370c..689f3e4f 100644
--- a/src/Cascader.tsx
+++ b/src/Cascader.tsx
@@ -40,7 +40,7 @@ export interface BaseOptionType {
export type DefaultOptionType = BaseOptionType & Record;
-export interface ShowSearchType<
+export interface SearchConfig<
OptionType extends DefaultOptionType = DefaultOptionType,
ValueField extends keyof OptionType = keyof OptionType,
> {
@@ -63,6 +63,9 @@ export interface ShowSearchType<
) => number;
matchInputWidth?: boolean;
limit?: number | false;
+ searchValue?: string;
+ onSearch?: (value: string) => void;
+ autoClearSearchValue?: boolean;
}
export type ShowCheckedStrategy = typeof SHOW_PARENT | typeof SHOW_CHILD;
@@ -88,9 +91,12 @@ interface BaseCascaderProps<
showCheckedStrategy?: ShowCheckedStrategy;
// Search
+ /** @deprecated please use showSearch.autoClearSearchValue */
autoClearSearchValue?: boolean;
- showSearch?: boolean | ShowSearchType;
+ showSearch?: boolean | SearchConfig;
+ /** @deprecated please use showSearch.searchValue */
searchValue?: string;
+ /** @deprecated please use showSearch.onSearch */
onSearch?: (value: string) => void;
// Trigger
@@ -205,9 +211,6 @@ const Cascader = React.forwardRef((props, re
checkable,
// Search
- autoClearSearchValue = true,
- searchValue,
- onSearch,
showSearch,
// Trigger
@@ -267,6 +270,8 @@ const Cascader = React.forwardRef((props, re
);
// =========================== Search ===========================
+ const [mergedShowSearch, searchConfig] = useSearchConfig(showSearch, props);
+ const { autoClearSearchValue = true, searchValue, onSearch } = searchConfig;
const [mergedSearchValue, setSearchValue] = useMergedState('', {
value: searchValue,
postState: search => search || '',
@@ -274,14 +279,11 @@ const Cascader = React.forwardRef((props, re
const onInternalSearch: BaseSelectProps['onSearch'] = (searchText, info) => {
setSearchValue(searchText);
-
if (info.source !== 'blur' && onSearch) {
onSearch(searchText);
}
};
- const [mergedShowSearch, searchConfig] = useSearchConfig(showSearch);
-
const searchOptions = useSearchOptions(
mergedSearchValue,
mergedOptions,
diff --git a/src/hooks/useSearchConfig.ts b/src/hooks/useSearchConfig.ts
index a8a96eb9..f6be7bab 100644
--- a/src/hooks/useSearchConfig.ts
+++ b/src/hooks/useSearchConfig.ts
@@ -1,17 +1,21 @@
import warning from '@rc-component/util/lib/warning';
import * as React from 'react';
-import type { CascaderProps, ShowSearchType } from '../Cascader';
+import type { CascaderProps, SearchConfig } from '../Cascader';
// Convert `showSearch` to unique config
-export default function useSearchConfig(showSearch?: CascaderProps['showSearch']) {
- return React.useMemo<[boolean, ShowSearchType]>(() => {
+export default function useSearchConfig(showSearch?: CascaderProps['showSearch'], props?: any) {
+ const { autoClearSearchValue, searchValue, onSearch } = props;
+ return React.useMemo<[boolean, SearchConfig]>(() => {
if (!showSearch) {
return [false, {}];
}
- let searchConfig: ShowSearchType = {
+ let searchConfig: SearchConfig = {
matchInputWidth: true,
limit: 50,
+ autoClearSearchValue,
+ searchValue,
+ onSearch,
};
if (showSearch && typeof showSearch === 'object') {
@@ -30,5 +34,5 @@ export default function useSearchConfig(showSearch?: CascaderProps['showSearch']
}
return [true, searchConfig];
- }, [showSearch]);
+ }, [showSearch, autoClearSearchValue, searchValue, onSearch]);
}
diff --git a/src/hooks/useSearchOptions.ts b/src/hooks/useSearchOptions.ts
index 3d99f603..856bd7ac 100644
--- a/src/hooks/useSearchOptions.ts
+++ b/src/hooks/useSearchOptions.ts
@@ -1,12 +1,12 @@
import * as React from 'react';
-import type { DefaultOptionType, InternalFieldNames, ShowSearchType } from '../Cascader';
+import type { DefaultOptionType, InternalFieldNames, SearchConfig } from '../Cascader';
export const SEARCH_MARK = '__rc_cascader_search_mark__';
-const defaultFilter: ShowSearchType['filter'] = (search, options, { label = '' }) =>
+const defaultFilter: SearchConfig['filter'] = (search, options, { label = '' }) =>
options.some(opt => String(opt[label]).toLowerCase().includes(search.toLowerCase()));
-const defaultRender: ShowSearchType['render'] = (inputValue, path, prefixCls, fieldNames) =>
+const defaultRender: SearchConfig['render'] = (inputValue, path, prefixCls, fieldNames) =>
path.map(opt => opt[fieldNames.label as string]).join(' / ');
const useSearchOptions = (
@@ -14,7 +14,7 @@ const useSearchOptions = (
options: DefaultOptionType[],
fieldNames: InternalFieldNames,
prefixCls: string,
- config: ShowSearchType,
+ config: SearchConfig,
enableHalfPath?: boolean,
) => {
const { filter = defaultFilter, render = defaultRender, limit = 50, sort } = config;
diff --git a/src/index.tsx b/src/index.tsx
index b73a5f68..77527ff9 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -6,7 +6,7 @@ export type {
DefaultOptionType,
CascaderProps,
FieldNames,
- ShowSearchType,
+ SearchConfig,
CascaderRef,
} from './Cascader';
export { Panel };
diff --git a/tests/search.spec.tsx b/tests/search.spec.tsx
index ba6c6713..3c9fed0e 100644
--- a/tests/search.spec.tsx
+++ b/tests/search.spec.tsx
@@ -308,6 +308,7 @@ describe('Cascader.Search', () => {
{
'{"label":"bamboo","disabled":true,"value":"bamboo"}',
);
});
+
+ it('onSearch and searchValue in showSearch', () => {
+ const onSearch = jest.fn();
+ const wrapper = mount();
+
+ // Leaf
+ doSearch(wrapper, 'toy');
+ let itemList = wrapper.find('div.rc-cascader-menu-item-content');
+ expect(itemList).toHaveLength(2);
+ expect(itemList.at(0).text()).toEqual('Label Bamboo / Label Little / Toy Fish');
+ expect(itemList.at(1).text()).toEqual('Label Bamboo / Label Little / Toy Cards');
+ expect(onSearch).toHaveBeenCalledWith('toy');
+
+ // Parent
+ doSearch(wrapper, 'Label Little');
+ itemList = wrapper.find('div.rc-cascader-menu-item-content');
+ expect(itemList).toHaveLength(2);
+ expect(itemList.at(0).text()).toEqual('Label Bamboo / Label Little / Toy Fish');
+ expect(itemList.at(1).text()).toEqual('Label Bamboo / Label Little / Toy Cards');
+ expect(onSearch).toHaveBeenCalledWith('Label Little');
+ });
+
+ it('searchValue in showSearch', () => {
+ const { container } = render(
+ ,
+ );
+ expect(container.querySelectorAll('.rc-cascader-menu-item')).toHaveLength(1);
+ expect(
+ (container.querySelector('.rc-cascader-selection-search-input') as HTMLInputElement)?.value,
+ ).toBe('little');
+ });
+ it('autoClearSearchValue in showSearch', () => {
+ const { container } = render(
+ ,
+ );
+
+ const inputNode = container.querySelector(
+ '.rc-cascader-selection-search-input',
+ );
+ fireEvent.change(inputNode as HTMLInputElement, { target: { value: 'little' } });
+ expect(inputNode).toHaveValue('little');
+ fireEvent.click(document.querySelector('.rc-cascader-checkbox') as HTMLElement);
+ expect(inputNode).toHaveValue('little');
+ });
});