@rc-component/cascader 1.0.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/LICENSE.md +9 -0
- package/README.md +300 -0
- package/assets/index.less +3 -0
- package/assets/list.less +106 -0
- package/assets/panel.less +7 -0
- package/assets/select.less +3 -0
- package/es/Cascader.d.ts +88 -0
- package/es/Cascader.js +230 -0
- package/es/OptionList/CacheContent.d.ts +7 -0
- package/es/OptionList/CacheContent.js +8 -0
- package/es/OptionList/Checkbox.d.ts +10 -0
- package/es/OptionList/Checkbox.js +24 -0
- package/es/OptionList/Column.d.ts +21 -0
- package/es/OptionList/Column.js +175 -0
- package/es/OptionList/List.d.ts +6 -0
- package/es/OptionList/List.js +216 -0
- package/es/OptionList/index.d.ts +4 -0
- package/es/OptionList/index.js +13 -0
- package/es/OptionList/useActive.d.ts +6 -0
- package/es/OptionList/useActive.js +26 -0
- package/es/OptionList/useKeyboard.d.ts +10 -0
- package/es/OptionList/useKeyboard.js +165 -0
- package/es/Panel.d.ts +5 -0
- package/es/Panel.js +116 -0
- package/es/context.d.ts +21 -0
- package/es/context.js +3 -0
- package/es/hooks/useDisplayValues.d.ts +10 -0
- package/es/hooks/useDisplayValues.js +44 -0
- package/es/hooks/useEntities.d.ts +10 -0
- package/es/hooks/useEntities.js +35 -0
- package/es/hooks/useMissingValues.d.ts +3 -0
- package/es/hooks/useMissingValues.js +17 -0
- package/es/hooks/useOptions.d.ts +9 -0
- package/es/hooks/useOptions.js +20 -0
- package/es/hooks/useSearchConfig.d.ts +2 -0
- package/es/hooks/useSearchConfig.js +27 -0
- package/es/hooks/useSearchOptions.d.ts +4 -0
- package/es/hooks/useSearchOptions.js +63 -0
- package/es/hooks/useSelect.d.ts +4 -0
- package/es/hooks/useSelect.js +49 -0
- package/es/hooks/useValues.d.ts +9 -0
- package/es/hooks/useValues.js +21 -0
- package/es/index.d.ts +5 -0
- package/es/index.js +4 -0
- package/es/utils/commonUtil.d.ts +18 -0
- package/es/utils/commonUtil.js +69 -0
- package/es/utils/treeUtil.d.ts +9 -0
- package/es/utils/treeUtil.js +35 -0
- package/es/utils/warningPropsUtil.d.ts +4 -0
- package/es/utils/warningPropsUtil.js +29 -0
- package/lib/Cascader.d.ts +88 -0
- package/lib/Cascader.js +239 -0
- package/lib/OptionList/CacheContent.d.ts +7 -0
- package/lib/OptionList/CacheContent.js +16 -0
- package/lib/OptionList/Checkbox.d.ts +10 -0
- package/lib/OptionList/Checkbox.js +33 -0
- package/lib/OptionList/Column.d.ts +21 -0
- package/lib/OptionList/Column.js +185 -0
- package/lib/OptionList/List.d.ts +6 -0
- package/lib/OptionList/List.js +224 -0
- package/lib/OptionList/index.d.ts +4 -0
- package/lib/OptionList/index.js +22 -0
- package/lib/OptionList/useActive.d.ts +6 -0
- package/lib/OptionList/useActive.js +34 -0
- package/lib/OptionList/useKeyboard.d.ts +10 -0
- package/lib/OptionList/useKeyboard.js +175 -0
- package/lib/Panel.d.ts +5 -0
- package/lib/Panel.js +125 -0
- package/lib/context.d.ts +21 -0
- package/lib/context.js +11 -0
- package/lib/hooks/useDisplayValues.d.ts +10 -0
- package/lib/hooks/useDisplayValues.js +53 -0
- package/lib/hooks/useEntities.d.ts +10 -0
- package/lib/hooks/useEntities.js +44 -0
- package/lib/hooks/useMissingValues.d.ts +3 -0
- package/lib/hooks/useMissingValues.js +25 -0
- package/lib/hooks/useOptions.d.ts +9 -0
- package/lib/hooks/useOptions.js +29 -0
- package/lib/hooks/useSearchConfig.d.ts +2 -0
- package/lib/hooks/useSearchConfig.js +36 -0
- package/lib/hooks/useSearchOptions.d.ts +4 -0
- package/lib/hooks/useSearchOptions.js +71 -0
- package/lib/hooks/useSelect.d.ts +4 -0
- package/lib/hooks/useSelect.js +55 -0
- package/lib/hooks/useValues.d.ts +9 -0
- package/lib/hooks/useValues.js +29 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +16 -0
- package/lib/utils/commonUtil.d.ts +18 -0
- package/lib/utils/commonUtil.js +83 -0
- package/lib/utils/treeUtil.d.ts +9 -0
- package/lib/utils/treeUtil.js +42 -0
- package/lib/utils/warningPropsUtil.d.ts +4 -0
- package/lib/utils/warningPropsUtil.js +37 -0
- package/package.json +88 -0
package/es/Cascader.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
+
import { BaseSelect } from '@rc-component/select';
|
|
3
|
+
import useId from "@rc-component/select/es/hooks/useId";
|
|
4
|
+
import useEvent from "@rc-component/util/es/hooks/useEvent";
|
|
5
|
+
import useMergedState from "@rc-component/util/es/hooks/useMergedState";
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import CascaderContext from "./context";
|
|
8
|
+
import useDisplayValues from "./hooks/useDisplayValues";
|
|
9
|
+
import useMissingValues from "./hooks/useMissingValues";
|
|
10
|
+
import useOptions from "./hooks/useOptions";
|
|
11
|
+
import useSearchConfig from "./hooks/useSearchConfig";
|
|
12
|
+
import useSearchOptions from "./hooks/useSearchOptions";
|
|
13
|
+
import useSelect from "./hooks/useSelect";
|
|
14
|
+
import useValues from "./hooks/useValues";
|
|
15
|
+
import OptionList from "./OptionList";
|
|
16
|
+
import Panel from "./Panel";
|
|
17
|
+
import { fillFieldNames, SHOW_CHILD, SHOW_PARENT, toPathKeys, toRawValues } from "./utils/commonUtil";
|
|
18
|
+
import { formatStrategyValues, toPathOptions } from "./utils/treeUtil";
|
|
19
|
+
import warningProps, { warningNullOptions } from "./utils/warningPropsUtil";
|
|
20
|
+
const Cascader = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
21
|
+
const {
|
|
22
|
+
// MISC
|
|
23
|
+
id,
|
|
24
|
+
prefixCls = 'rc-cascader',
|
|
25
|
+
fieldNames,
|
|
26
|
+
// Value
|
|
27
|
+
defaultValue,
|
|
28
|
+
value,
|
|
29
|
+
changeOnSelect,
|
|
30
|
+
onChange,
|
|
31
|
+
displayRender,
|
|
32
|
+
checkable,
|
|
33
|
+
// Search
|
|
34
|
+
autoClearSearchValue = true,
|
|
35
|
+
searchValue,
|
|
36
|
+
onSearch,
|
|
37
|
+
showSearch,
|
|
38
|
+
// Trigger
|
|
39
|
+
expandTrigger,
|
|
40
|
+
// Options
|
|
41
|
+
options,
|
|
42
|
+
dropdownPrefixCls,
|
|
43
|
+
loadData,
|
|
44
|
+
// Open
|
|
45
|
+
popupVisible,
|
|
46
|
+
open,
|
|
47
|
+
popupClassName,
|
|
48
|
+
dropdownMenuColumnStyle,
|
|
49
|
+
popupStyle: customPopupStyle,
|
|
50
|
+
popupPlacement,
|
|
51
|
+
placement,
|
|
52
|
+
onPopupVisibleChange,
|
|
53
|
+
// Icon
|
|
54
|
+
expandIcon = '>',
|
|
55
|
+
loadingIcon,
|
|
56
|
+
// Children
|
|
57
|
+
children,
|
|
58
|
+
popupMatchSelectWidth = false,
|
|
59
|
+
showCheckedStrategy = SHOW_PARENT,
|
|
60
|
+
optionRender,
|
|
61
|
+
...restProps
|
|
62
|
+
} = props;
|
|
63
|
+
const mergedId = useId(id);
|
|
64
|
+
const multiple = !!checkable;
|
|
65
|
+
|
|
66
|
+
// =========================== Values ===========================
|
|
67
|
+
const [rawValues, setRawValues] = useMergedState(defaultValue, {
|
|
68
|
+
value,
|
|
69
|
+
postState: toRawValues
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// ========================= FieldNames =========================
|
|
73
|
+
const mergedFieldNames = React.useMemo(() => fillFieldNames(fieldNames), /* eslint-disable react-hooks/exhaustive-deps */
|
|
74
|
+
[JSON.stringify(fieldNames)]
|
|
75
|
+
/* eslint-enable react-hooks/exhaustive-deps */);
|
|
76
|
+
|
|
77
|
+
// =========================== Option ===========================
|
|
78
|
+
const [mergedOptions, getPathKeyEntities, getValueByKeyPath] = useOptions(mergedFieldNames, options);
|
|
79
|
+
|
|
80
|
+
// =========================== Search ===========================
|
|
81
|
+
const [mergedSearchValue, setSearchValue] = useMergedState('', {
|
|
82
|
+
value: searchValue,
|
|
83
|
+
postState: search => search || ''
|
|
84
|
+
});
|
|
85
|
+
const onInternalSearch = (searchText, info) => {
|
|
86
|
+
setSearchValue(searchText);
|
|
87
|
+
if (info.source !== 'blur' && onSearch) {
|
|
88
|
+
onSearch(searchText);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const [mergedShowSearch, searchConfig] = useSearchConfig(showSearch);
|
|
92
|
+
const searchOptions = useSearchOptions(mergedSearchValue, mergedOptions, mergedFieldNames, dropdownPrefixCls || prefixCls, searchConfig, changeOnSelect || multiple);
|
|
93
|
+
|
|
94
|
+
// =========================== Values ===========================
|
|
95
|
+
const getMissingValues = useMissingValues(mergedOptions, mergedFieldNames);
|
|
96
|
+
|
|
97
|
+
// Fill `rawValues` with checked conduction values
|
|
98
|
+
const [checkedValues, halfCheckedValues, missingCheckedValues] = useValues(multiple, rawValues, getPathKeyEntities, getValueByKeyPath, getMissingValues);
|
|
99
|
+
const deDuplicatedValues = React.useMemo(() => {
|
|
100
|
+
const checkedKeys = toPathKeys(checkedValues);
|
|
101
|
+
const deduplicateKeys = formatStrategyValues(checkedKeys, getPathKeyEntities, showCheckedStrategy);
|
|
102
|
+
return [...missingCheckedValues, ...getValueByKeyPath(deduplicateKeys)];
|
|
103
|
+
}, [checkedValues, getPathKeyEntities, getValueByKeyPath, missingCheckedValues, showCheckedStrategy]);
|
|
104
|
+
const displayValues = useDisplayValues(deDuplicatedValues, mergedOptions, mergedFieldNames, multiple, displayRender);
|
|
105
|
+
|
|
106
|
+
// =========================== Change ===========================
|
|
107
|
+
const triggerChange = useEvent(nextValues => {
|
|
108
|
+
setRawValues(nextValues);
|
|
109
|
+
|
|
110
|
+
// Save perf if no need trigger event
|
|
111
|
+
if (onChange) {
|
|
112
|
+
const nextRawValues = toRawValues(nextValues);
|
|
113
|
+
const valueOptions = nextRawValues.map(valueCells => toPathOptions(valueCells, mergedOptions, mergedFieldNames).map(valueOpt => valueOpt.option));
|
|
114
|
+
const triggerValues = multiple ? nextRawValues : nextRawValues[0];
|
|
115
|
+
const triggerOptions = multiple ? valueOptions : valueOptions[0];
|
|
116
|
+
onChange(triggerValues, triggerOptions);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// =========================== Select ===========================
|
|
121
|
+
const handleSelection = useSelect(multiple, triggerChange, checkedValues, halfCheckedValues, missingCheckedValues, getPathKeyEntities, getValueByKeyPath, showCheckedStrategy);
|
|
122
|
+
const onInternalSelect = useEvent(valuePath => {
|
|
123
|
+
if (!multiple || autoClearSearchValue) {
|
|
124
|
+
setSearchValue('');
|
|
125
|
+
}
|
|
126
|
+
handleSelection(valuePath);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Display Value change logic
|
|
130
|
+
const onDisplayValuesChange = (_, info) => {
|
|
131
|
+
if (info.type === 'clear') {
|
|
132
|
+
triggerChange([]);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Cascader do not support `add` type. Only support `remove`
|
|
137
|
+
const {
|
|
138
|
+
valueCells
|
|
139
|
+
} = info.values[0];
|
|
140
|
+
onInternalSelect(valueCells);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// ============================ Open ============================
|
|
144
|
+
const mergedOpen = open !== undefined ? open : popupVisible;
|
|
145
|
+
const mergedPlacement = placement || popupPlacement;
|
|
146
|
+
const onInternalPopupVisibleChange = nextVisible => {
|
|
147
|
+
onPopupVisibleChange?.(nextVisible);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// ========================== Warning ===========================
|
|
151
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
152
|
+
warningProps(props);
|
|
153
|
+
warningNullOptions(mergedOptions, mergedFieldNames);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ========================== Context ===========================
|
|
157
|
+
const cascaderContext = React.useMemo(() => ({
|
|
158
|
+
options: mergedOptions,
|
|
159
|
+
fieldNames: mergedFieldNames,
|
|
160
|
+
values: checkedValues,
|
|
161
|
+
halfValues: halfCheckedValues,
|
|
162
|
+
changeOnSelect,
|
|
163
|
+
onSelect: onInternalSelect,
|
|
164
|
+
checkable,
|
|
165
|
+
searchOptions,
|
|
166
|
+
dropdownPrefixCls,
|
|
167
|
+
loadData,
|
|
168
|
+
expandTrigger,
|
|
169
|
+
expandIcon,
|
|
170
|
+
loadingIcon,
|
|
171
|
+
dropdownMenuColumnStyle,
|
|
172
|
+
optionRender
|
|
173
|
+
}), [mergedOptions, mergedFieldNames, checkedValues, halfCheckedValues, changeOnSelect, onInternalSelect, checkable, searchOptions, dropdownPrefixCls, loadData, expandTrigger, expandIcon, loadingIcon, dropdownMenuColumnStyle, optionRender]);
|
|
174
|
+
|
|
175
|
+
// ==============================================================
|
|
176
|
+
// == Render ==
|
|
177
|
+
// ==============================================================
|
|
178
|
+
const emptyOptions = !(mergedSearchValue ? searchOptions : mergedOptions).length;
|
|
179
|
+
const popupStyle =
|
|
180
|
+
// Search to match width
|
|
181
|
+
mergedSearchValue && searchConfig.matchInputWidth ||
|
|
182
|
+
// Empty keep the width
|
|
183
|
+
emptyOptions ? {} : {
|
|
184
|
+
minWidth: 'auto'
|
|
185
|
+
};
|
|
186
|
+
return /*#__PURE__*/React.createElement(CascaderContext.Provider, {
|
|
187
|
+
value: cascaderContext
|
|
188
|
+
}, /*#__PURE__*/React.createElement(BaseSelect, _extends({}, restProps, {
|
|
189
|
+
// MISC
|
|
190
|
+
ref: ref,
|
|
191
|
+
id: mergedId,
|
|
192
|
+
prefixCls: prefixCls,
|
|
193
|
+
autoClearSearchValue: autoClearSearchValue,
|
|
194
|
+
popupMatchSelectWidth: popupMatchSelectWidth,
|
|
195
|
+
popupStyle: {
|
|
196
|
+
...popupStyle,
|
|
197
|
+
...customPopupStyle
|
|
198
|
+
}
|
|
199
|
+
// Value
|
|
200
|
+
,
|
|
201
|
+
displayValues: displayValues,
|
|
202
|
+
onDisplayValuesChange: onDisplayValuesChange,
|
|
203
|
+
mode: multiple ? 'multiple' : undefined
|
|
204
|
+
// Search
|
|
205
|
+
,
|
|
206
|
+
searchValue: mergedSearchValue,
|
|
207
|
+
onSearch: onInternalSearch,
|
|
208
|
+
showSearch: mergedShowSearch
|
|
209
|
+
// Options
|
|
210
|
+
,
|
|
211
|
+
OptionList: OptionList,
|
|
212
|
+
emptyOptions: emptyOptions
|
|
213
|
+
// Open
|
|
214
|
+
,
|
|
215
|
+
open: mergedOpen,
|
|
216
|
+
popupClassName: popupClassName,
|
|
217
|
+
placement: mergedPlacement,
|
|
218
|
+
onPopupVisibleChange: onInternalPopupVisibleChange
|
|
219
|
+
// Children
|
|
220
|
+
,
|
|
221
|
+
getRawInputElement: () => children
|
|
222
|
+
})));
|
|
223
|
+
});
|
|
224
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
225
|
+
Cascader.displayName = 'Cascader';
|
|
226
|
+
}
|
|
227
|
+
Cascader.SHOW_PARENT = SHOW_PARENT;
|
|
228
|
+
Cascader.SHOW_CHILD = SHOW_CHILD;
|
|
229
|
+
Cascader.Panel = Panel;
|
|
230
|
+
export default Cascader;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface CacheContentProps {
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
open?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const CacheContent: React.MemoExoticComponent<({ children }: CacheContentProps) => React.ReactElement<any, string | React.JSXElementConstructor<any>>>;
|
|
7
|
+
export default CacheContent;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface CheckboxProps {
|
|
3
|
+
prefixCls: string;
|
|
4
|
+
checked?: boolean;
|
|
5
|
+
halfChecked?: boolean;
|
|
6
|
+
disabled?: boolean;
|
|
7
|
+
onClick?: React.MouseEventHandler;
|
|
8
|
+
disableCheckbox?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export default function Checkbox({ prefixCls, checked, halfChecked, disabled, onClick, disableCheckbox, }: CheckboxProps): React.JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import CascaderContext from "../context";
|
|
4
|
+
export default function Checkbox({
|
|
5
|
+
prefixCls,
|
|
6
|
+
checked,
|
|
7
|
+
halfChecked,
|
|
8
|
+
disabled,
|
|
9
|
+
onClick,
|
|
10
|
+
disableCheckbox
|
|
11
|
+
}) {
|
|
12
|
+
const {
|
|
13
|
+
checkable
|
|
14
|
+
} = React.useContext(CascaderContext);
|
|
15
|
+
const customCheckbox = typeof checkable !== 'boolean' ? checkable : null;
|
|
16
|
+
return /*#__PURE__*/React.createElement("span", {
|
|
17
|
+
className: classNames(`${prefixCls}`, {
|
|
18
|
+
[`${prefixCls}-checked`]: checked,
|
|
19
|
+
[`${prefixCls}-indeterminate`]: !checked && halfChecked,
|
|
20
|
+
[`${prefixCls}-disabled`]: disabled || disableCheckbox
|
|
21
|
+
}),
|
|
22
|
+
onClick: onClick
|
|
23
|
+
}, customCheckbox);
|
|
24
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { DefaultOptionType, SingleValueType } from '../Cascader';
|
|
3
|
+
export declare const FIX_LABEL = "__cascader_fix_label__";
|
|
4
|
+
export interface ColumnProps<OptionType extends DefaultOptionType = DefaultOptionType> {
|
|
5
|
+
prefixCls: string;
|
|
6
|
+
multiple?: boolean;
|
|
7
|
+
options: OptionType[];
|
|
8
|
+
/** Current Column opened item key */
|
|
9
|
+
activeValue?: React.Key;
|
|
10
|
+
/** The value path before current column */
|
|
11
|
+
prevValuePath: React.Key[];
|
|
12
|
+
onToggleOpen: (open: boolean) => void;
|
|
13
|
+
onSelect: (valuePath: SingleValueType, leaf: boolean) => void;
|
|
14
|
+
onActive: (valuePath: SingleValueType) => void;
|
|
15
|
+
checkedSet: Set<React.Key>;
|
|
16
|
+
halfCheckedSet: Set<React.Key>;
|
|
17
|
+
loadingKeys: React.Key[];
|
|
18
|
+
isSelectable: (option: DefaultOptionType) => boolean;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export default function Column<OptionType extends DefaultOptionType = DefaultOptionType>({ prefixCls, multiple, options, activeValue, prevValuePath, onToggleOpen, onSelect, onActive, checkedSet, halfCheckedSet, loadingKeys, isSelectable, disabled: propsDisabled, }: ColumnProps<OptionType>): React.JSX.Element;
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import CascaderContext from "../context";
|
|
4
|
+
import { SEARCH_MARK } from "../hooks/useSearchOptions";
|
|
5
|
+
import { isLeaf, toPathKey } from "../utils/commonUtil";
|
|
6
|
+
import Checkbox from "./Checkbox";
|
|
7
|
+
export const FIX_LABEL = '__cascader_fix_label__';
|
|
8
|
+
export default function Column({
|
|
9
|
+
prefixCls,
|
|
10
|
+
multiple,
|
|
11
|
+
options,
|
|
12
|
+
activeValue,
|
|
13
|
+
prevValuePath,
|
|
14
|
+
onToggleOpen,
|
|
15
|
+
onSelect,
|
|
16
|
+
onActive,
|
|
17
|
+
checkedSet,
|
|
18
|
+
halfCheckedSet,
|
|
19
|
+
loadingKeys,
|
|
20
|
+
isSelectable,
|
|
21
|
+
disabled: propsDisabled
|
|
22
|
+
}) {
|
|
23
|
+
const menuPrefixCls = `${prefixCls}-menu`;
|
|
24
|
+
const menuItemPrefixCls = `${prefixCls}-menu-item`;
|
|
25
|
+
const {
|
|
26
|
+
fieldNames,
|
|
27
|
+
changeOnSelect,
|
|
28
|
+
expandTrigger,
|
|
29
|
+
expandIcon,
|
|
30
|
+
loadingIcon,
|
|
31
|
+
dropdownMenuColumnStyle,
|
|
32
|
+
optionRender
|
|
33
|
+
} = React.useContext(CascaderContext);
|
|
34
|
+
const hoverOpen = expandTrigger === 'hover';
|
|
35
|
+
const isOptionDisabled = disabled => propsDisabled || disabled;
|
|
36
|
+
|
|
37
|
+
// ============================ Option ============================
|
|
38
|
+
const optionInfoList = React.useMemo(() => options.map(option => {
|
|
39
|
+
const {
|
|
40
|
+
disabled,
|
|
41
|
+
disableCheckbox
|
|
42
|
+
} = option;
|
|
43
|
+
const searchOptions = option[SEARCH_MARK];
|
|
44
|
+
const label = option[FIX_LABEL] ?? option[fieldNames.label];
|
|
45
|
+
const value = option[fieldNames.value];
|
|
46
|
+
const isMergedLeaf = isLeaf(option, fieldNames);
|
|
47
|
+
|
|
48
|
+
// Get real value of option. Search option is different way.
|
|
49
|
+
const fullPath = searchOptions ? searchOptions.map(opt => opt[fieldNames.value]) : [...prevValuePath, value];
|
|
50
|
+
const fullPathKey = toPathKey(fullPath);
|
|
51
|
+
const isLoading = loadingKeys.includes(fullPathKey);
|
|
52
|
+
|
|
53
|
+
// >>>>> checked
|
|
54
|
+
const checked = checkedSet.has(fullPathKey);
|
|
55
|
+
|
|
56
|
+
// >>>>> halfChecked
|
|
57
|
+
const halfChecked = halfCheckedSet.has(fullPathKey);
|
|
58
|
+
return {
|
|
59
|
+
disabled,
|
|
60
|
+
label,
|
|
61
|
+
value,
|
|
62
|
+
isLeaf: isMergedLeaf,
|
|
63
|
+
isLoading,
|
|
64
|
+
checked,
|
|
65
|
+
halfChecked,
|
|
66
|
+
option,
|
|
67
|
+
disableCheckbox,
|
|
68
|
+
fullPath,
|
|
69
|
+
fullPathKey
|
|
70
|
+
};
|
|
71
|
+
}), [options, checkedSet, fieldNames, halfCheckedSet, loadingKeys, prevValuePath]);
|
|
72
|
+
|
|
73
|
+
// ============================ Render ============================
|
|
74
|
+
return /*#__PURE__*/React.createElement("ul", {
|
|
75
|
+
className: menuPrefixCls,
|
|
76
|
+
role: "menu"
|
|
77
|
+
}, optionInfoList.map(({
|
|
78
|
+
disabled,
|
|
79
|
+
label,
|
|
80
|
+
value,
|
|
81
|
+
isLeaf: isMergedLeaf,
|
|
82
|
+
isLoading,
|
|
83
|
+
checked,
|
|
84
|
+
halfChecked,
|
|
85
|
+
option,
|
|
86
|
+
fullPath,
|
|
87
|
+
fullPathKey,
|
|
88
|
+
disableCheckbox
|
|
89
|
+
}) => {
|
|
90
|
+
// >>>>> Open
|
|
91
|
+
const triggerOpenPath = () => {
|
|
92
|
+
if (isOptionDisabled(disabled)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const nextValueCells = [...fullPath];
|
|
96
|
+
if (hoverOpen && isMergedLeaf) {
|
|
97
|
+
nextValueCells.pop();
|
|
98
|
+
}
|
|
99
|
+
onActive(nextValueCells);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// >>>>> Selection
|
|
103
|
+
const triggerSelect = () => {
|
|
104
|
+
if (isSelectable(option) && !isOptionDisabled(disabled)) {
|
|
105
|
+
onSelect(fullPath, isMergedLeaf);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// >>>>> Title
|
|
110
|
+
let title;
|
|
111
|
+
if (typeof option.title === 'string') {
|
|
112
|
+
title = option.title;
|
|
113
|
+
} else if (typeof label === 'string') {
|
|
114
|
+
title = label;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// >>>>> Render
|
|
118
|
+
return /*#__PURE__*/React.createElement("li", {
|
|
119
|
+
key: fullPathKey,
|
|
120
|
+
className: classNames(menuItemPrefixCls, {
|
|
121
|
+
[`${menuItemPrefixCls}-expand`]: !isMergedLeaf,
|
|
122
|
+
[`${menuItemPrefixCls}-active`]: activeValue === value || activeValue === fullPathKey,
|
|
123
|
+
[`${menuItemPrefixCls}-disabled`]: isOptionDisabled(disabled),
|
|
124
|
+
[`${menuItemPrefixCls}-loading`]: isLoading
|
|
125
|
+
}),
|
|
126
|
+
style: dropdownMenuColumnStyle,
|
|
127
|
+
role: "menuitemcheckbox",
|
|
128
|
+
title: title,
|
|
129
|
+
"aria-checked": checked,
|
|
130
|
+
"data-path-key": fullPathKey,
|
|
131
|
+
onClick: () => {
|
|
132
|
+
triggerOpenPath();
|
|
133
|
+
if (disableCheckbox) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (!multiple || isMergedLeaf) {
|
|
137
|
+
triggerSelect();
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
onDoubleClick: () => {
|
|
141
|
+
if (changeOnSelect) {
|
|
142
|
+
onToggleOpen(false);
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
onMouseEnter: () => {
|
|
146
|
+
if (hoverOpen) {
|
|
147
|
+
triggerOpenPath();
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
onMouseDown: e => {
|
|
151
|
+
// Prevent selector from blurring
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
}
|
|
154
|
+
}, multiple && /*#__PURE__*/React.createElement(Checkbox, {
|
|
155
|
+
prefixCls: `${prefixCls}-checkbox`,
|
|
156
|
+
checked: checked,
|
|
157
|
+
halfChecked: halfChecked,
|
|
158
|
+
disabled: isOptionDisabled(disabled) || disableCheckbox,
|
|
159
|
+
disableCheckbox: disableCheckbox,
|
|
160
|
+
onClick: e => {
|
|
161
|
+
if (disableCheckbox) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
e.stopPropagation();
|
|
165
|
+
triggerSelect();
|
|
166
|
+
}
|
|
167
|
+
}), /*#__PURE__*/React.createElement("div", {
|
|
168
|
+
className: `${menuItemPrefixCls}-content`
|
|
169
|
+
}, optionRender ? optionRender(option) : label), !isLoading && expandIcon && !isMergedLeaf && /*#__PURE__*/React.createElement("div", {
|
|
170
|
+
className: `${menuItemPrefixCls}-expand-icon`
|
|
171
|
+
}, expandIcon), isLoading && loadingIcon && /*#__PURE__*/React.createElement("div", {
|
|
172
|
+
className: `${menuItemPrefixCls}-loading-icon`
|
|
173
|
+
}, loadingIcon));
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { useBaseProps } from '@rc-component/select';
|
|
2
|
+
import type { RefOptionListProps } from '@rc-component/select/lib/OptionList';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
export type RawOptionListProps = Pick<ReturnType<typeof useBaseProps>, 'prefixCls' | 'multiple' | 'searchValue' | 'toggleOpen' | 'notFoundContent' | 'direction' | 'open' | 'disabled'>;
|
|
5
|
+
declare const RawOptionList: React.ForwardRefExoticComponent<RawOptionListProps & React.RefAttributes<RefOptionListProps>>;
|
|
6
|
+
export default RawOptionList;
|