@rc-component/select 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/BaseSelect/index.d.ts +1 -1
- package/es/OptionList.d.ts +1 -1
- package/es/OptionList.js +1 -1
- package/es/Select.d.ts +3 -3
- package/es/Select.js +14 -4
- package/es/SelectInput/index.js +5 -0
- package/es/hooks/useFilterOptions.d.ts +1 -1
- package/es/hooks/useFilterOptions.js +49 -47
- package/es/hooks/useOptions.d.ts +1 -1
- package/es/hooks/useOptions.js +3 -1
- package/es/hooks/useSelectTriggerControl.js +3 -1
- package/lib/BaseSelect/index.d.ts +1 -1
- package/lib/OptionList.d.ts +1 -1
- package/lib/OptionList.js +2 -2
- package/lib/Select.d.ts +3 -3
- package/lib/Select.js +14 -4
- package/lib/SelectInput/index.js +5 -0
- package/lib/hooks/useFilterOptions.d.ts +1 -1
- package/lib/hooks/useFilterOptions.js +49 -47
- package/lib/hooks/useOptions.d.ts +1 -1
- package/lib/hooks/useOptions.js +3 -1
- package/lib/hooks/useSelectTriggerControl.js +3 -1
- package/package.json +4 -4
package/es/BaseSelect/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AlignType, BuildInPlacements } from '@rc-component/trigger/lib/interface';
|
|
2
|
-
import type { ScrollConfig, ScrollTo } from 'rc-virtual-list/lib/List';
|
|
2
|
+
import type { ScrollConfig, ScrollTo } from '@rc-component/virtual-list/lib/List';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import type { DisplayInfoType, DisplayValueType, Mode, Placement, RawValueType, RenderDOMFunc, RenderNode } from '../interface';
|
|
5
5
|
import type { ComponentsConfig } from '../hooks/useComponents';
|
package/es/OptionList.d.ts
CHANGED
package/es/OptionList.js
CHANGED
|
@@ -4,7 +4,7 @@ import KeyCode from "@rc-component/util/es/KeyCode";
|
|
|
4
4
|
import useMemo from "@rc-component/util/es/hooks/useMemo";
|
|
5
5
|
import omit from "@rc-component/util/es/omit";
|
|
6
6
|
import pickAttrs from "@rc-component/util/es/pickAttrs";
|
|
7
|
-
import List from 'rc-virtual-list';
|
|
7
|
+
import List from '@rc-component/virtual-list';
|
|
8
8
|
import * as React from 'react';
|
|
9
9
|
import { useEffect } from 'react';
|
|
10
10
|
import SelectContext from "./SelectContext";
|
package/es/Select.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export interface SearchConfig<OptionType> {
|
|
|
75
75
|
filterSort?: (optionA: OptionType, optionB: OptionType, info: {
|
|
76
76
|
searchValue: string;
|
|
77
77
|
}) => number;
|
|
78
|
-
optionFilterProp?: string;
|
|
78
|
+
optionFilterProp?: string | string[];
|
|
79
79
|
}
|
|
80
80
|
export interface SelectProps<ValueType = any, OptionType extends BaseOptionType = DefaultOptionType> extends Omit<BaseSelectPropsWithoutPrivate, 'showSearch'> {
|
|
81
81
|
prefixCls?: string;
|
|
@@ -102,7 +102,7 @@ export interface SelectProps<ValueType = any, OptionType extends BaseOptionType
|
|
|
102
102
|
/** @deprecated please use showSearch.filterSort */
|
|
103
103
|
filterSort?: SearchConfig<OptionType>['filterSort'];
|
|
104
104
|
/** @deprecated please use showSearch.optionFilterProp */
|
|
105
|
-
optionFilterProp?: string;
|
|
105
|
+
optionFilterProp?: string | string[];
|
|
106
106
|
optionLabelProp?: string;
|
|
107
107
|
children?: React.ReactNode;
|
|
108
108
|
options?: OptionType[];
|
|
@@ -125,7 +125,7 @@ export interface SelectProps<ValueType = any, OptionType extends BaseOptionType
|
|
|
125
125
|
classNames?: Partial<Record<SemanticName, string>>;
|
|
126
126
|
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
|
|
127
127
|
}
|
|
128
|
-
declare const TypedSelect: (<ValueType = any, OptionType extends
|
|
128
|
+
declare const TypedSelect: (<ValueType = any, OptionType extends DefaultOptionType | BaseOptionType = DefaultOptionType>(props: React.PropsWithChildren<SelectProps<ValueType, OptionType>> & React.RefAttributes<BaseSelectRef>) => React.ReactElement) & {
|
|
129
129
|
Option: typeof Option;
|
|
130
130
|
OptGroup: typeof OptGroup;
|
|
131
131
|
};
|
package/es/Select.js
CHANGED
|
@@ -109,6 +109,10 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
109
109
|
onSearch,
|
|
110
110
|
autoClearSearchValue = true
|
|
111
111
|
} = searchConfig;
|
|
112
|
+
const normalizedOptionFilterProp = React.useMemo(() => {
|
|
113
|
+
if (!optionFilterProp) return [];
|
|
114
|
+
return Array.isArray(optionFilterProp) ? optionFilterProp : [optionFilterProp];
|
|
115
|
+
}, [optionFilterProp]);
|
|
112
116
|
const mergedId = useId(id);
|
|
113
117
|
const multiple = isMultiple(mode);
|
|
114
118
|
const childrenAsData = !!(!options && children);
|
|
@@ -131,7 +135,7 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
131
135
|
const mergedSearchValue = internalSearchValue || '';
|
|
132
136
|
|
|
133
137
|
// =========================== Option ===========================
|
|
134
|
-
const parsedOptions = useOptions(options, children, mergedFieldNames,
|
|
138
|
+
const parsedOptions = useOptions(options, children, mergedFieldNames, normalizedOptionFilterProp, optionLabelProp);
|
|
135
139
|
const {
|
|
136
140
|
valueOptions,
|
|
137
141
|
labelOptions,
|
|
@@ -254,11 +258,17 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
254
258
|
});
|
|
255
259
|
return cloneOptions;
|
|
256
260
|
}, [createTagOption, mergedOptions, valueOptions, mergedValues, mode]);
|
|
257
|
-
const filteredOptions = useFilterOptions(filledTagOptions, mergedFieldNames, mergedSearchValue, mergedFilterOption,
|
|
261
|
+
const filteredOptions = useFilterOptions(filledTagOptions, mergedFieldNames, mergedSearchValue, mergedFilterOption, normalizedOptionFilterProp);
|
|
258
262
|
|
|
259
263
|
// Fill options with search value if needed
|
|
260
264
|
const filledSearchOptions = React.useMemo(() => {
|
|
261
|
-
|
|
265
|
+
const hasItemMatchingSearch = item => {
|
|
266
|
+
if (normalizedOptionFilterProp.length) {
|
|
267
|
+
return normalizedOptionFilterProp.some(prop => item?.[prop] === mergedSearchValue);
|
|
268
|
+
}
|
|
269
|
+
return item?.value === mergedSearchValue;
|
|
270
|
+
};
|
|
271
|
+
if (mode !== 'tags' || !mergedSearchValue || filteredOptions.some(item => hasItemMatchingSearch(item))) {
|
|
262
272
|
return filteredOptions;
|
|
263
273
|
}
|
|
264
274
|
// ignore when search value equal select input value
|
|
@@ -267,7 +277,7 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
267
277
|
}
|
|
268
278
|
// Fill search value as option
|
|
269
279
|
return [createTagOption(mergedSearchValue), ...filteredOptions];
|
|
270
|
-
}, [createTagOption,
|
|
280
|
+
}, [createTagOption, normalizedOptionFilterProp, mode, filteredOptions, mergedSearchValue, mergedFieldNames]);
|
|
271
281
|
const sorter = inputOptions => {
|
|
272
282
|
const sortedOptions = [...inputOptions].sort((a, b) => filterSort(a, b, {
|
|
273
283
|
searchValue: mergedSearchValue
|
package/es/SelectInput/index.js
CHANGED
|
@@ -107,6 +107,11 @@ export default /*#__PURE__*/React.forwardRef(function SelectInput(props, ref) {
|
|
|
107
107
|
// ====================== Open ======================
|
|
108
108
|
const onInternalMouseDown = useEvent(event => {
|
|
109
109
|
if (!disabled) {
|
|
110
|
+
// https://github.com/ant-design/ant-design/issues/56002
|
|
111
|
+
// Tell `useSelectTriggerControl` to ignore this event
|
|
112
|
+
// When icon is dynamic render, the parentNode will miss
|
|
113
|
+
// so we need to mark the event directly
|
|
114
|
+
event.nativeEvent._ignore_global_close = true;
|
|
110
115
|
const inputDOM = getDOM(inputRef.current);
|
|
111
116
|
if (inputDOM && event.target !== inputDOM && !inputDOM.contains(event.target)) {
|
|
112
117
|
event.preventDefault();
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FieldNames, DefaultOptionType, SelectProps } from '../Select';
|
|
2
|
-
declare const _default: (options: DefaultOptionType[], fieldNames: FieldNames, searchValue?: string, filterOption?: SelectProps['filterOption'], optionFilterProp?: string) => DefaultOptionType[];
|
|
2
|
+
declare const _default: (options: DefaultOptionType[], fieldNames: FieldNames, searchValue?: string, filterOption?: SelectProps['filterOption'], optionFilterProp?: string[]) => DefaultOptionType[];
|
|
3
3
|
export default _default;
|
|
@@ -4,54 +4,56 @@ import { injectPropsWithOption } from "../utils/valueUtil";
|
|
|
4
4
|
function includes(test, search) {
|
|
5
5
|
return toArray(test).join('').toUpperCase().includes(search);
|
|
6
6
|
}
|
|
7
|
-
export default ((options, fieldNames, searchValue, filterOption, optionFilterProp) =>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
options: fieldOptions,
|
|
13
|
-
label: fieldLabel,
|
|
14
|
-
value: fieldValue
|
|
15
|
-
} = fieldNames;
|
|
16
|
-
const filteredOptions = [];
|
|
17
|
-
const customizeFilter = typeof filterOption === 'function';
|
|
18
|
-
const upperSearch = searchValue.toUpperCase();
|
|
19
|
-
const filterFunc = customizeFilter ? filterOption : (_, option) => {
|
|
20
|
-
// Use provided `optionFilterProp`
|
|
21
|
-
if (optionFilterProp) {
|
|
22
|
-
return includes(option[optionFilterProp], upperSearch);
|
|
7
|
+
export default ((options, fieldNames, searchValue, filterOption, optionFilterProp) => {
|
|
8
|
+
return React.useMemo(() => {
|
|
9
|
+
if (!searchValue || filterOption === false) {
|
|
10
|
+
return options;
|
|
23
11
|
}
|
|
12
|
+
const {
|
|
13
|
+
options: fieldOptions,
|
|
14
|
+
label: fieldLabel,
|
|
15
|
+
value: fieldValue
|
|
16
|
+
} = fieldNames;
|
|
17
|
+
const filteredOptions = [];
|
|
18
|
+
const customizeFilter = typeof filterOption === 'function';
|
|
19
|
+
const upperSearch = searchValue.toUpperCase();
|
|
20
|
+
const filterFunc = customizeFilter ? filterOption : (_, option) => {
|
|
21
|
+
// Use provided `optionFilterProp`
|
|
22
|
+
if (optionFilterProp && optionFilterProp.length) {
|
|
23
|
+
return optionFilterProp.some(prop => includes(option[prop], upperSearch));
|
|
24
|
+
}
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
26
|
+
// Auto select `label` or `value` by option type
|
|
27
|
+
if (option[fieldOptions]) {
|
|
28
|
+
// hack `fieldLabel` since `OptionGroup` children is not `label`
|
|
29
|
+
return includes(option[fieldLabel !== 'children' ? fieldLabel : 'label'], upperSearch);
|
|
30
|
+
}
|
|
31
|
+
return includes(option[fieldValue], upperSearch);
|
|
32
|
+
};
|
|
33
|
+
const wrapOption = customizeFilter ? opt => injectPropsWithOption(opt) : opt => opt;
|
|
34
|
+
options.forEach(item => {
|
|
35
|
+
// Group should check child options
|
|
36
|
+
if (item[fieldOptions]) {
|
|
37
|
+
// Check group first
|
|
38
|
+
const matchGroup = filterFunc(searchValue, wrapOption(item));
|
|
39
|
+
if (matchGroup) {
|
|
40
|
+
filteredOptions.push(item);
|
|
41
|
+
} else {
|
|
42
|
+
// Check option
|
|
43
|
+
const subOptions = item[fieldOptions].filter(subItem => filterFunc(searchValue, wrapOption(subItem)));
|
|
44
|
+
if (subOptions.length) {
|
|
45
|
+
filteredOptions.push({
|
|
46
|
+
...item,
|
|
47
|
+
[fieldOptions]: subOptions
|
|
48
|
+
});
|
|
49
|
+
}
|
|
48
50
|
}
|
|
51
|
+
return;
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
}, [options, filterOption, optionFilterProp, searchValue, fieldNames]));
|
|
53
|
+
if (filterFunc(searchValue, wrapOption(item))) {
|
|
54
|
+
filteredOptions.push(item);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return filteredOptions;
|
|
58
|
+
}, [options, filterOption, optionFilterProp, searchValue, fieldNames]);
|
|
59
|
+
});
|
package/es/hooks/useOptions.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { FieldNames, RawValueType } from '../Select';
|
|
|
4
4
|
* Parse `children` to `options` if `options` is not provided.
|
|
5
5
|
* Then flatten the `options`.
|
|
6
6
|
*/
|
|
7
|
-
declare const useOptions: <OptionType>(options: OptionType[], children: React.ReactNode, fieldNames: FieldNames, optionFilterProp: string, optionLabelProp: string) => {
|
|
7
|
+
declare const useOptions: <OptionType>(options: OptionType[], children: React.ReactNode, fieldNames: FieldNames, optionFilterProp: string[], optionLabelProp: string) => {
|
|
8
8
|
options: OptionType[];
|
|
9
9
|
valueOptions: Map<RawValueType, OptionType>;
|
|
10
10
|
labelOptions: Map<React.ReactNode, OptionType>;
|
package/es/hooks/useOptions.js
CHANGED
|
@@ -27,7 +27,9 @@ const useOptions = (options, children, fieldNames, optionFilterProp, optionLabel
|
|
|
27
27
|
valueOptions.set(option[fieldNames.value], option);
|
|
28
28
|
setLabelOptions(labelOptions, option, fieldNames.label);
|
|
29
29
|
// https://github.com/ant-design/ant-design/issues/35304
|
|
30
|
-
|
|
30
|
+
optionFilterProp.forEach(prop => {
|
|
31
|
+
setLabelOptions(labelOptions, option, prop);
|
|
32
|
+
});
|
|
31
33
|
setLabelOptions(labelOptions, option, optionLabelProp);
|
|
32
34
|
} else {
|
|
33
35
|
dig(option[fieldNames.options], true);
|
|
@@ -10,7 +10,9 @@ export default function useSelectTriggerControl(elements, open, triggerOpen, cus
|
|
|
10
10
|
if (target.shadowRoot && event.composed) {
|
|
11
11
|
target = event.composedPath()[0] || target;
|
|
12
12
|
}
|
|
13
|
-
if (open &&
|
|
13
|
+
if (open &&
|
|
14
|
+
// Marked by SelectInput mouseDown event
|
|
15
|
+
!event._ignore_global_close && elements().filter(element => element).every(element => !element.contains(target) && element !== target)) {
|
|
14
16
|
// Should trigger close
|
|
15
17
|
triggerOpen(false);
|
|
16
18
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AlignType, BuildInPlacements } from '@rc-component/trigger/lib/interface';
|
|
2
|
-
import type { ScrollConfig, ScrollTo } from 'rc-virtual-list/lib/List';
|
|
2
|
+
import type { ScrollConfig, ScrollTo } from '@rc-component/virtual-list/lib/List';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import type { DisplayInfoType, DisplayValueType, Mode, Placement, RawValueType, RenderDOMFunc, RenderNode } from '../interface';
|
|
5
5
|
import type { ComponentsConfig } from '../hooks/useComponents';
|
package/lib/OptionList.d.ts
CHANGED
package/lib/OptionList.js
CHANGED
|
@@ -9,7 +9,7 @@ var _KeyCode = _interopRequireDefault(require("@rc-component/util/lib/KeyCode"))
|
|
|
9
9
|
var _useMemo = _interopRequireDefault(require("@rc-component/util/lib/hooks/useMemo"));
|
|
10
10
|
var _omit = _interopRequireDefault(require("@rc-component/util/lib/omit"));
|
|
11
11
|
var _pickAttrs = _interopRequireDefault(require("@rc-component/util/lib/pickAttrs"));
|
|
12
|
-
var
|
|
12
|
+
var _virtualList = _interopRequireDefault(require("@rc-component/virtual-list"));
|
|
13
13
|
var _react = _interopRequireWildcard(require("react"));
|
|
14
14
|
var React = _react;
|
|
15
15
|
var _SelectContext = _interopRequireDefault(require("./SelectContext"));
|
|
@@ -293,7 +293,7 @@ const OptionList = (_, ref) => {
|
|
|
293
293
|
width: 0,
|
|
294
294
|
overflow: 'hidden'
|
|
295
295
|
}
|
|
296
|
-
}), renderItem(activeIndex - 1), renderItem(activeIndex), renderItem(activeIndex + 1)), /*#__PURE__*/React.createElement(
|
|
296
|
+
}), renderItem(activeIndex - 1), renderItem(activeIndex), renderItem(activeIndex + 1)), /*#__PURE__*/React.createElement(_virtualList.default, {
|
|
297
297
|
itemKey: "key",
|
|
298
298
|
ref: listRef,
|
|
299
299
|
data: memoFlattenOptions,
|
package/lib/Select.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export interface SearchConfig<OptionType> {
|
|
|
75
75
|
filterSort?: (optionA: OptionType, optionB: OptionType, info: {
|
|
76
76
|
searchValue: string;
|
|
77
77
|
}) => number;
|
|
78
|
-
optionFilterProp?: string;
|
|
78
|
+
optionFilterProp?: string | string[];
|
|
79
79
|
}
|
|
80
80
|
export interface SelectProps<ValueType = any, OptionType extends BaseOptionType = DefaultOptionType> extends Omit<BaseSelectPropsWithoutPrivate, 'showSearch'> {
|
|
81
81
|
prefixCls?: string;
|
|
@@ -102,7 +102,7 @@ export interface SelectProps<ValueType = any, OptionType extends BaseOptionType
|
|
|
102
102
|
/** @deprecated please use showSearch.filterSort */
|
|
103
103
|
filterSort?: SearchConfig<OptionType>['filterSort'];
|
|
104
104
|
/** @deprecated please use showSearch.optionFilterProp */
|
|
105
|
-
optionFilterProp?: string;
|
|
105
|
+
optionFilterProp?: string | string[];
|
|
106
106
|
optionLabelProp?: string;
|
|
107
107
|
children?: React.ReactNode;
|
|
108
108
|
options?: OptionType[];
|
|
@@ -125,7 +125,7 @@ export interface SelectProps<ValueType = any, OptionType extends BaseOptionType
|
|
|
125
125
|
classNames?: Partial<Record<SemanticName, string>>;
|
|
126
126
|
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
|
|
127
127
|
}
|
|
128
|
-
declare const TypedSelect: (<ValueType = any, OptionType extends
|
|
128
|
+
declare const TypedSelect: (<ValueType = any, OptionType extends DefaultOptionType | BaseOptionType = DefaultOptionType>(props: React.PropsWithChildren<SelectProps<ValueType, OptionType>> & React.RefAttributes<BaseSelectRef>) => React.ReactElement) & {
|
|
129
129
|
Option: typeof Option;
|
|
130
130
|
OptGroup: typeof OptGroup;
|
|
131
131
|
};
|
package/lib/Select.js
CHANGED
|
@@ -116,6 +116,10 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
116
116
|
onSearch,
|
|
117
117
|
autoClearSearchValue = true
|
|
118
118
|
} = searchConfig;
|
|
119
|
+
const normalizedOptionFilterProp = React.useMemo(() => {
|
|
120
|
+
if (!optionFilterProp) return [];
|
|
121
|
+
return Array.isArray(optionFilterProp) ? optionFilterProp : [optionFilterProp];
|
|
122
|
+
}, [optionFilterProp]);
|
|
119
123
|
const mergedId = (0, _useId.default)(id);
|
|
120
124
|
const multiple = (0, _BaseSelect.isMultiple)(mode);
|
|
121
125
|
const childrenAsData = !!(!options && children);
|
|
@@ -138,7 +142,7 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
138
142
|
const mergedSearchValue = internalSearchValue || '';
|
|
139
143
|
|
|
140
144
|
// =========================== Option ===========================
|
|
141
|
-
const parsedOptions = (0, _useOptions.default)(options, children, mergedFieldNames,
|
|
145
|
+
const parsedOptions = (0, _useOptions.default)(options, children, mergedFieldNames, normalizedOptionFilterProp, optionLabelProp);
|
|
142
146
|
const {
|
|
143
147
|
valueOptions,
|
|
144
148
|
labelOptions,
|
|
@@ -261,11 +265,17 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
261
265
|
});
|
|
262
266
|
return cloneOptions;
|
|
263
267
|
}, [createTagOption, mergedOptions, valueOptions, mergedValues, mode]);
|
|
264
|
-
const filteredOptions = (0, _useFilterOptions.default)(filledTagOptions, mergedFieldNames, mergedSearchValue, mergedFilterOption,
|
|
268
|
+
const filteredOptions = (0, _useFilterOptions.default)(filledTagOptions, mergedFieldNames, mergedSearchValue, mergedFilterOption, normalizedOptionFilterProp);
|
|
265
269
|
|
|
266
270
|
// Fill options with search value if needed
|
|
267
271
|
const filledSearchOptions = React.useMemo(() => {
|
|
268
|
-
|
|
272
|
+
const hasItemMatchingSearch = item => {
|
|
273
|
+
if (normalizedOptionFilterProp.length) {
|
|
274
|
+
return normalizedOptionFilterProp.some(prop => item?.[prop] === mergedSearchValue);
|
|
275
|
+
}
|
|
276
|
+
return item?.value === mergedSearchValue;
|
|
277
|
+
};
|
|
278
|
+
if (mode !== 'tags' || !mergedSearchValue || filteredOptions.some(item => hasItemMatchingSearch(item))) {
|
|
269
279
|
return filteredOptions;
|
|
270
280
|
}
|
|
271
281
|
// ignore when search value equal select input value
|
|
@@ -274,7 +284,7 @@ const Select = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
274
284
|
}
|
|
275
285
|
// Fill search value as option
|
|
276
286
|
return [createTagOption(mergedSearchValue), ...filteredOptions];
|
|
277
|
-
}, [createTagOption,
|
|
287
|
+
}, [createTagOption, normalizedOptionFilterProp, mode, filteredOptions, mergedSearchValue, mergedFieldNames]);
|
|
278
288
|
const sorter = inputOptions => {
|
|
279
289
|
const sortedOptions = [...inputOptions].sort((a, b) => filterSort(a, b, {
|
|
280
290
|
searchValue: mergedSearchValue
|
package/lib/SelectInput/index.js
CHANGED
|
@@ -116,6 +116,11 @@ var _default = exports.default = /*#__PURE__*/React.forwardRef(function SelectIn
|
|
|
116
116
|
// ====================== Open ======================
|
|
117
117
|
const onInternalMouseDown = (0, _util.useEvent)(event => {
|
|
118
118
|
if (!disabled) {
|
|
119
|
+
// https://github.com/ant-design/ant-design/issues/56002
|
|
120
|
+
// Tell `useSelectTriggerControl` to ignore this event
|
|
121
|
+
// When icon is dynamic render, the parentNode will miss
|
|
122
|
+
// so we need to mark the event directly
|
|
123
|
+
event.nativeEvent._ignore_global_close = true;
|
|
119
124
|
const inputDOM = (0, _findDOMNode.getDOM)(inputRef.current);
|
|
120
125
|
if (inputDOM && event.target !== inputDOM && !inputDOM.contains(event.target)) {
|
|
121
126
|
event.preventDefault();
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { FieldNames, DefaultOptionType, SelectProps } from '../Select';
|
|
2
|
-
declare const _default: (options: DefaultOptionType[], fieldNames: FieldNames, searchValue?: string, filterOption?: SelectProps['filterOption'], optionFilterProp?: string) => DefaultOptionType[];
|
|
2
|
+
declare const _default: (options: DefaultOptionType[], fieldNames: FieldNames, searchValue?: string, filterOption?: SelectProps['filterOption'], optionFilterProp?: string[]) => DefaultOptionType[];
|
|
3
3
|
export default _default;
|
|
@@ -12,55 +12,57 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
|
|
|
12
12
|
function includes(test, search) {
|
|
13
13
|
return (0, _commonUtil.toArray)(test).join('').toUpperCase().includes(search);
|
|
14
14
|
}
|
|
15
|
-
var _default = (options, fieldNames, searchValue, filterOption, optionFilterProp) =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const {
|
|
20
|
-
options: fieldOptions,
|
|
21
|
-
label: fieldLabel,
|
|
22
|
-
value: fieldValue
|
|
23
|
-
} = fieldNames;
|
|
24
|
-
const filteredOptions = [];
|
|
25
|
-
const customizeFilter = typeof filterOption === 'function';
|
|
26
|
-
const upperSearch = searchValue.toUpperCase();
|
|
27
|
-
const filterFunc = customizeFilter ? filterOption : (_, option) => {
|
|
28
|
-
// Use provided `optionFilterProp`
|
|
29
|
-
if (optionFilterProp) {
|
|
30
|
-
return includes(option[optionFilterProp], upperSearch);
|
|
15
|
+
var _default = (options, fieldNames, searchValue, filterOption, optionFilterProp) => {
|
|
16
|
+
return React.useMemo(() => {
|
|
17
|
+
if (!searchValue || filterOption === false) {
|
|
18
|
+
return options;
|
|
31
19
|
}
|
|
20
|
+
const {
|
|
21
|
+
options: fieldOptions,
|
|
22
|
+
label: fieldLabel,
|
|
23
|
+
value: fieldValue
|
|
24
|
+
} = fieldNames;
|
|
25
|
+
const filteredOptions = [];
|
|
26
|
+
const customizeFilter = typeof filterOption === 'function';
|
|
27
|
+
const upperSearch = searchValue.toUpperCase();
|
|
28
|
+
const filterFunc = customizeFilter ? filterOption : (_, option) => {
|
|
29
|
+
// Use provided `optionFilterProp`
|
|
30
|
+
if (optionFilterProp && optionFilterProp.length) {
|
|
31
|
+
return optionFilterProp.some(prop => includes(option[prop], upperSearch));
|
|
32
|
+
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
// Auto select `label` or `value` by option type
|
|
35
|
+
if (option[fieldOptions]) {
|
|
36
|
+
// hack `fieldLabel` since `OptionGroup` children is not `label`
|
|
37
|
+
return includes(option[fieldLabel !== 'children' ? fieldLabel : 'label'], upperSearch);
|
|
38
|
+
}
|
|
39
|
+
return includes(option[fieldValue], upperSearch);
|
|
40
|
+
};
|
|
41
|
+
const wrapOption = customizeFilter ? opt => (0, _valueUtil.injectPropsWithOption)(opt) : opt => opt;
|
|
42
|
+
options.forEach(item => {
|
|
43
|
+
// Group should check child options
|
|
44
|
+
if (item[fieldOptions]) {
|
|
45
|
+
// Check group first
|
|
46
|
+
const matchGroup = filterFunc(searchValue, wrapOption(item));
|
|
47
|
+
if (matchGroup) {
|
|
48
|
+
filteredOptions.push(item);
|
|
49
|
+
} else {
|
|
50
|
+
// Check option
|
|
51
|
+
const subOptions = item[fieldOptions].filter(subItem => filterFunc(searchValue, wrapOption(subItem)));
|
|
52
|
+
if (subOptions.length) {
|
|
53
|
+
filteredOptions.push({
|
|
54
|
+
...item,
|
|
55
|
+
[fieldOptions]: subOptions
|
|
56
|
+
});
|
|
57
|
+
}
|
|
56
58
|
}
|
|
59
|
+
return;
|
|
57
60
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
}, [options, filterOption, optionFilterProp, searchValue, fieldNames]);
|
|
61
|
+
if (filterFunc(searchValue, wrapOption(item))) {
|
|
62
|
+
filteredOptions.push(item);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return filteredOptions;
|
|
66
|
+
}, [options, filterOption, optionFilterProp, searchValue, fieldNames]);
|
|
67
|
+
};
|
|
66
68
|
exports.default = _default;
|
|
@@ -4,7 +4,7 @@ import type { FieldNames, RawValueType } from '../Select';
|
|
|
4
4
|
* Parse `children` to `options` if `options` is not provided.
|
|
5
5
|
* Then flatten the `options`.
|
|
6
6
|
*/
|
|
7
|
-
declare const useOptions: <OptionType>(options: OptionType[], children: React.ReactNode, fieldNames: FieldNames, optionFilterProp: string, optionLabelProp: string) => {
|
|
7
|
+
declare const useOptions: <OptionType>(options: OptionType[], children: React.ReactNode, fieldNames: FieldNames, optionFilterProp: string[], optionLabelProp: string) => {
|
|
8
8
|
options: OptionType[];
|
|
9
9
|
valueOptions: Map<RawValueType, OptionType>;
|
|
10
10
|
labelOptions: Map<React.ReactNode, OptionType>;
|
package/lib/hooks/useOptions.js
CHANGED
|
@@ -34,7 +34,9 @@ const useOptions = (options, children, fieldNames, optionFilterProp, optionLabel
|
|
|
34
34
|
valueOptions.set(option[fieldNames.value], option);
|
|
35
35
|
setLabelOptions(labelOptions, option, fieldNames.label);
|
|
36
36
|
// https://github.com/ant-design/ant-design/issues/35304
|
|
37
|
-
|
|
37
|
+
optionFilterProp.forEach(prop => {
|
|
38
|
+
setLabelOptions(labelOptions, option, prop);
|
|
39
|
+
});
|
|
38
40
|
setLabelOptions(labelOptions, option, optionLabelProp);
|
|
39
41
|
} else {
|
|
40
42
|
dig(option[fieldNames.options], true);
|
|
@@ -18,7 +18,9 @@ function useSelectTriggerControl(elements, open, triggerOpen, customizedTrigger)
|
|
|
18
18
|
if (target.shadowRoot && event.composed) {
|
|
19
19
|
target = event.composedPath()[0] || target;
|
|
20
20
|
}
|
|
21
|
-
if (open &&
|
|
21
|
+
if (open &&
|
|
22
|
+
// Marked by SelectInput mouseDown event
|
|
23
|
+
!event._ignore_global_close && elements().filter(element => element).every(element => !element.contains(target) && element !== target)) {
|
|
22
24
|
// Should trigger close
|
|
23
25
|
triggerOpen(false);
|
|
24
26
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rc-component/select",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "React Select",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=8.x"
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@rc-component/trigger": "^3.0.0",
|
|
53
53
|
"@rc-component/util": "^1.3.0",
|
|
54
|
+
"@rc-component/virtual-list": "^1.0.1",
|
|
54
55
|
"clsx": "^2.1.1",
|
|
55
|
-
"rc-overflow": "^1.5.0"
|
|
56
|
-
"rc-virtual-list": "^3.5.2"
|
|
56
|
+
"rc-overflow": "^1.5.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@rc-component/father-plugin": "^2.0.2",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"prettier": "^3.1.1",
|
|
77
77
|
"querystring": "^0.2.1",
|
|
78
78
|
"rc-dialog": "^9.0.0",
|
|
79
|
-
"rc-test": "^7.
|
|
79
|
+
"rc-test": "^7.1.2",
|
|
80
80
|
"react": "^18.2.0",
|
|
81
81
|
"react-dom": "^18.2.0",
|
|
82
82
|
"typescript": "^5.2.2"
|