@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
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { convertDataToEntities } from "rc-tree/es/utils/treeUtil";
|
|
3
|
+
import { VALUE_SPLIT } from "../utils/commonUtil";
|
|
4
|
+
/** Lazy parse options data into conduct-able info to avoid perf issue in single mode */
|
|
5
|
+
export default ((options, fieldNames) => {
|
|
6
|
+
const cacheRef = React.useRef({
|
|
7
|
+
options: [],
|
|
8
|
+
info: {
|
|
9
|
+
keyEntities: {},
|
|
10
|
+
pathKeyEntities: {}
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const getEntities = React.useCallback(() => {
|
|
14
|
+
if (cacheRef.current.options !== options) {
|
|
15
|
+
cacheRef.current.options = options;
|
|
16
|
+
cacheRef.current.info = convertDataToEntities(options, {
|
|
17
|
+
fieldNames: fieldNames,
|
|
18
|
+
initWrapper: wrapper => ({
|
|
19
|
+
...wrapper,
|
|
20
|
+
pathKeyEntities: {}
|
|
21
|
+
}),
|
|
22
|
+
processEntity: (entity, wrapper) => {
|
|
23
|
+
const pathKey = entity.nodes.map(node => node[fieldNames.value]).join(VALUE_SPLIT);
|
|
24
|
+
wrapper.pathKeyEntities[pathKey] = entity;
|
|
25
|
+
|
|
26
|
+
// Overwrite origin key.
|
|
27
|
+
// this is very hack but we need let conduct logic work with connect path
|
|
28
|
+
entity.key = pathKey;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return cacheRef.current.info.pathKeyEntities;
|
|
33
|
+
}, [fieldNames, options]);
|
|
34
|
+
return getEntities;
|
|
35
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DefaultOptionType, InternalFieldNames, SingleValueType } from '../Cascader';
|
|
2
|
+
export type GetMissValues = ReturnType<typeof useMissingValues>;
|
|
3
|
+
export default function useMissingValues(options: DefaultOptionType[], fieldNames: InternalFieldNames): (rawValues: SingleValueType[]) => [SingleValueType[], SingleValueType[]];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { toPathOptions } from "../utils/treeUtil";
|
|
3
|
+
export default function useMissingValues(options, fieldNames) {
|
|
4
|
+
return React.useCallback(rawValues => {
|
|
5
|
+
const missingValues = [];
|
|
6
|
+
const existsValues = [];
|
|
7
|
+
rawValues.forEach(valueCell => {
|
|
8
|
+
const pathOptions = toPathOptions(valueCell, options, fieldNames);
|
|
9
|
+
if (pathOptions.every(opt => opt.option)) {
|
|
10
|
+
existsValues.push(valueCell);
|
|
11
|
+
} else {
|
|
12
|
+
missingValues.push(valueCell);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return [existsValues, missingValues];
|
|
16
|
+
}, [options, fieldNames]);
|
|
17
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { DefaultOptionType } from '..';
|
|
3
|
+
import type { InternalFieldNames, SingleValueType } from '../Cascader';
|
|
4
|
+
import { type GetEntities } from './useEntities';
|
|
5
|
+
export default function useOptions(mergedFieldNames: InternalFieldNames, options?: DefaultOptionType[]): [
|
|
6
|
+
mergedOptions: DefaultOptionType[],
|
|
7
|
+
getPathKeyEntities: GetEntities,
|
|
8
|
+
getValueByKeyPath: (pathKeys: React.Key[]) => SingleValueType[]
|
|
9
|
+
];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import useEntities from "./useEntities";
|
|
3
|
+
export default function useOptions(mergedFieldNames, options) {
|
|
4
|
+
const mergedOptions = React.useMemo(() => options || [], [options]);
|
|
5
|
+
|
|
6
|
+
// Only used in multiple mode, this fn will not call in single mode
|
|
7
|
+
const getPathKeyEntities = useEntities(mergedOptions, mergedFieldNames);
|
|
8
|
+
|
|
9
|
+
/** Convert path key back to value format */
|
|
10
|
+
const getValueByKeyPath = React.useCallback(pathKeys => {
|
|
11
|
+
const keyPathEntities = getPathKeyEntities();
|
|
12
|
+
return pathKeys.map(pathKey => {
|
|
13
|
+
const {
|
|
14
|
+
nodes
|
|
15
|
+
} = keyPathEntities[pathKey];
|
|
16
|
+
return nodes.map(node => node[mergedFieldNames.value]);
|
|
17
|
+
});
|
|
18
|
+
}, [getPathKeyEntities, mergedFieldNames]);
|
|
19
|
+
return [mergedOptions, getPathKeyEntities, getValueByKeyPath];
|
|
20
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import warning from "@rc-component/util/es/warning";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
// Convert `showSearch` to unique config
|
|
4
|
+
export default function useSearchConfig(showSearch) {
|
|
5
|
+
return React.useMemo(() => {
|
|
6
|
+
if (!showSearch) {
|
|
7
|
+
return [false, {}];
|
|
8
|
+
}
|
|
9
|
+
let searchConfig = {
|
|
10
|
+
matchInputWidth: true,
|
|
11
|
+
limit: 50
|
|
12
|
+
};
|
|
13
|
+
if (showSearch && typeof showSearch === 'object') {
|
|
14
|
+
searchConfig = {
|
|
15
|
+
...searchConfig,
|
|
16
|
+
...showSearch
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (searchConfig.limit <= 0) {
|
|
20
|
+
searchConfig.limit = false;
|
|
21
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
22
|
+
warning(false, "'limit' of showSearch should be positive number or false.");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return [true, searchConfig];
|
|
26
|
+
}, [showSearch]);
|
|
27
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DefaultOptionType, InternalFieldNames, ShowSearchType } from '../Cascader';
|
|
2
|
+
export declare const SEARCH_MARK = "__rc_cascader_search_mark__";
|
|
3
|
+
declare const useSearchOptions: (search: string, options: DefaultOptionType[], fieldNames: InternalFieldNames, prefixCls: string, config: ShowSearchType, enableHalfPath?: boolean) => DefaultOptionType[];
|
|
4
|
+
export default useSearchOptions;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export const SEARCH_MARK = '__rc_cascader_search_mark__';
|
|
3
|
+
const defaultFilter = (search, options, {
|
|
4
|
+
label = ''
|
|
5
|
+
}) => options.some(opt => String(opt[label]).toLowerCase().includes(search.toLowerCase()));
|
|
6
|
+
const defaultRender = (inputValue, path, prefixCls, fieldNames) => path.map(opt => opt[fieldNames.label]).join(' / ');
|
|
7
|
+
const useSearchOptions = (search, options, fieldNames, prefixCls, config, enableHalfPath) => {
|
|
8
|
+
const {
|
|
9
|
+
filter = defaultFilter,
|
|
10
|
+
render = defaultRender,
|
|
11
|
+
limit = 50,
|
|
12
|
+
sort
|
|
13
|
+
} = config;
|
|
14
|
+
return React.useMemo(() => {
|
|
15
|
+
const filteredOptions = [];
|
|
16
|
+
if (!search) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
function dig(list, pathOptions, parentDisabled = false) {
|
|
20
|
+
list.forEach(option => {
|
|
21
|
+
// Perf saving when `sort` is disabled and `limit` is provided
|
|
22
|
+
if (!sort && limit !== false && limit > 0 && filteredOptions.length >= limit) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const connectedPathOptions = [...pathOptions, option];
|
|
26
|
+
const children = option[fieldNames.children];
|
|
27
|
+
const mergedDisabled = parentDisabled || option.disabled;
|
|
28
|
+
|
|
29
|
+
// If current option is filterable
|
|
30
|
+
if (
|
|
31
|
+
// If is leaf option
|
|
32
|
+
!children || children.length === 0 ||
|
|
33
|
+
// If is changeOnSelect or multiple
|
|
34
|
+
enableHalfPath) {
|
|
35
|
+
if (filter(search, connectedPathOptions, {
|
|
36
|
+
label: fieldNames.label
|
|
37
|
+
})) {
|
|
38
|
+
filteredOptions.push({
|
|
39
|
+
...option,
|
|
40
|
+
disabled: mergedDisabled,
|
|
41
|
+
[fieldNames.label]: render(search, connectedPathOptions, prefixCls, fieldNames),
|
|
42
|
+
[SEARCH_MARK]: connectedPathOptions,
|
|
43
|
+
[fieldNames.children]: undefined
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (children) {
|
|
48
|
+
dig(option[fieldNames.children], connectedPathOptions, mergedDisabled);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
dig(options, []);
|
|
53
|
+
|
|
54
|
+
// Do sort
|
|
55
|
+
if (sort) {
|
|
56
|
+
filteredOptions.sort((a, b) => {
|
|
57
|
+
return sort(a[SEARCH_MARK], b[SEARCH_MARK], search, fieldNames);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return limit !== false && limit > 0 ? filteredOptions.slice(0, limit) : filteredOptions;
|
|
61
|
+
}, [search, options, fieldNames, prefixCls, render, enableHalfPath, filter, sort, limit]);
|
|
62
|
+
};
|
|
63
|
+
export default useSearchOptions;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { InternalValueType, ShowCheckedStrategy, SingleValueType } from '../Cascader';
|
|
3
|
+
import type { GetEntities } from './useEntities';
|
|
4
|
+
export default function useSelect(multiple: boolean, triggerChange: (nextValues: InternalValueType) => void, checkedValues: SingleValueType[], halfCheckedValues: SingleValueType[], missingCheckedValues: SingleValueType[], getPathKeyEntities: GetEntities, getValueByKeyPath: (pathKeys: React.Key[]) => SingleValueType[], showCheckedStrategy?: ShowCheckedStrategy): (valuePath: SingleValueType) => void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { conductCheck } from "rc-tree/es/utils/conductUtil";
|
|
2
|
+
import { toPathKey, toPathKeys } from "../utils/commonUtil";
|
|
3
|
+
import { formatStrategyValues } from "../utils/treeUtil";
|
|
4
|
+
export default function useSelect(multiple, triggerChange, checkedValues, halfCheckedValues, missingCheckedValues, getPathKeyEntities, getValueByKeyPath, showCheckedStrategy) {
|
|
5
|
+
return valuePath => {
|
|
6
|
+
if (!multiple) {
|
|
7
|
+
triggerChange(valuePath);
|
|
8
|
+
} else {
|
|
9
|
+
// Prepare conduct required info
|
|
10
|
+
const pathKey = toPathKey(valuePath);
|
|
11
|
+
const checkedPathKeys = toPathKeys(checkedValues);
|
|
12
|
+
const halfCheckedPathKeys = toPathKeys(halfCheckedValues);
|
|
13
|
+
const existInChecked = checkedPathKeys.includes(pathKey);
|
|
14
|
+
const existInMissing = missingCheckedValues.some(valueCells => toPathKey(valueCells) === pathKey);
|
|
15
|
+
|
|
16
|
+
// Do update
|
|
17
|
+
let nextCheckedValues = checkedValues;
|
|
18
|
+
let nextMissingValues = missingCheckedValues;
|
|
19
|
+
if (existInMissing && !existInChecked) {
|
|
20
|
+
// Missing value only do filter
|
|
21
|
+
nextMissingValues = missingCheckedValues.filter(valueCells => toPathKey(valueCells) !== pathKey);
|
|
22
|
+
} else {
|
|
23
|
+
// Update checked key first
|
|
24
|
+
const nextRawCheckedKeys = existInChecked ? checkedPathKeys.filter(key => key !== pathKey) : [...checkedPathKeys, pathKey];
|
|
25
|
+
const pathKeyEntities = getPathKeyEntities();
|
|
26
|
+
|
|
27
|
+
// Conduction by selected or not
|
|
28
|
+
let checkedKeys;
|
|
29
|
+
if (existInChecked) {
|
|
30
|
+
({
|
|
31
|
+
checkedKeys
|
|
32
|
+
} = conductCheck(nextRawCheckedKeys, {
|
|
33
|
+
checked: false,
|
|
34
|
+
halfCheckedKeys: halfCheckedPathKeys
|
|
35
|
+
}, pathKeyEntities));
|
|
36
|
+
} else {
|
|
37
|
+
({
|
|
38
|
+
checkedKeys
|
|
39
|
+
} = conductCheck(nextRawCheckedKeys, true, pathKeyEntities));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Roll up to parent level keys
|
|
43
|
+
const deDuplicatedKeys = formatStrategyValues(checkedKeys, getPathKeyEntities, showCheckedStrategy);
|
|
44
|
+
nextCheckedValues = getValueByKeyPath(deDuplicatedKeys);
|
|
45
|
+
}
|
|
46
|
+
triggerChange([...nextMissingValues, ...nextCheckedValues]);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DataEntity } from 'rc-tree/lib/interface';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import type { SingleValueType } from '../Cascader';
|
|
4
|
+
import type { GetMissValues } from './useMissingValues';
|
|
5
|
+
export default function useValues(multiple: boolean, rawValues: SingleValueType[], getPathKeyEntities: () => Record<string, DataEntity>, getValueByKeyPath: (pathKeys: React.Key[]) => SingleValueType[], getMissingValues: GetMissValues): [
|
|
6
|
+
checkedValues: SingleValueType[],
|
|
7
|
+
halfCheckedValues: SingleValueType[],
|
|
8
|
+
missingCheckedValues: SingleValueType[]
|
|
9
|
+
];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { conductCheck } from "rc-tree/es/utils/conductUtil";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { toPathKeys } from "../utils/commonUtil";
|
|
4
|
+
export default function useValues(multiple, rawValues, getPathKeyEntities, getValueByKeyPath, getMissingValues) {
|
|
5
|
+
// Fill `rawValues` with checked conduction values
|
|
6
|
+
return React.useMemo(() => {
|
|
7
|
+
const [existValues, missingValues] = getMissingValues(rawValues);
|
|
8
|
+
if (!multiple || !rawValues.length) {
|
|
9
|
+
return [existValues, [], missingValues];
|
|
10
|
+
}
|
|
11
|
+
const keyPathValues = toPathKeys(existValues);
|
|
12
|
+
const keyPathEntities = getPathKeyEntities();
|
|
13
|
+
const {
|
|
14
|
+
checkedKeys,
|
|
15
|
+
halfCheckedKeys
|
|
16
|
+
} = conductCheck(keyPathValues, true, keyPathEntities);
|
|
17
|
+
|
|
18
|
+
// Convert key back to value cells
|
|
19
|
+
return [getValueByKeyPath(checkedKeys), getValueByKeyPath(halfCheckedKeys), missingValues];
|
|
20
|
+
}, [multiple, rawValues, getPathKeyEntities, getValueByKeyPath, getMissingValues]);
|
|
21
|
+
}
|
package/es/index.d.ts
ADDED
package/es/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DefaultOptionType, FieldNames, InternalFieldNames, InternalValueType, SingleValueType } from '../Cascader';
|
|
2
|
+
export declare const VALUE_SPLIT = "__RC_CASCADER_SPLIT__";
|
|
3
|
+
export declare const SHOW_PARENT = "SHOW_PARENT";
|
|
4
|
+
export declare const SHOW_CHILD = "SHOW_CHILD";
|
|
5
|
+
/**
|
|
6
|
+
* Will convert value to string, and join with `VALUE_SPLIT`
|
|
7
|
+
*/
|
|
8
|
+
export declare function toPathKey(value: SingleValueType): string;
|
|
9
|
+
/**
|
|
10
|
+
* Batch convert value to string, and join with `VALUE_SPLIT`
|
|
11
|
+
*/
|
|
12
|
+
export declare function toPathKeys(value: SingleValueType[]): string[];
|
|
13
|
+
export declare function toPathValueStr(pathKey: string): string[];
|
|
14
|
+
export declare function fillFieldNames(fieldNames?: FieldNames): InternalFieldNames;
|
|
15
|
+
export declare function isLeaf(option: DefaultOptionType, fieldNames: FieldNames): any;
|
|
16
|
+
export declare function scrollIntoParentView(element: HTMLElement): void;
|
|
17
|
+
export declare function getFullPathKeys(options: DefaultOptionType[], fieldNames: FieldNames): any[];
|
|
18
|
+
export declare function toRawValues(value?: InternalValueType): SingleValueType[];
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { SEARCH_MARK } from "../hooks/useSearchOptions";
|
|
2
|
+
export const VALUE_SPLIT = '__RC_CASCADER_SPLIT__';
|
|
3
|
+
export const SHOW_PARENT = 'SHOW_PARENT';
|
|
4
|
+
export const SHOW_CHILD = 'SHOW_CHILD';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Will convert value to string, and join with `VALUE_SPLIT`
|
|
8
|
+
*/
|
|
9
|
+
export function toPathKey(value) {
|
|
10
|
+
return value.join(VALUE_SPLIT);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Batch convert value to string, and join with `VALUE_SPLIT`
|
|
15
|
+
*/
|
|
16
|
+
export function toPathKeys(value) {
|
|
17
|
+
return value.map(toPathKey);
|
|
18
|
+
}
|
|
19
|
+
export function toPathValueStr(pathKey) {
|
|
20
|
+
return pathKey.split(VALUE_SPLIT);
|
|
21
|
+
}
|
|
22
|
+
export function fillFieldNames(fieldNames) {
|
|
23
|
+
const {
|
|
24
|
+
label,
|
|
25
|
+
value,
|
|
26
|
+
children
|
|
27
|
+
} = fieldNames || {};
|
|
28
|
+
const val = value || 'value';
|
|
29
|
+
return {
|
|
30
|
+
label: label || 'label',
|
|
31
|
+
value: val,
|
|
32
|
+
key: val,
|
|
33
|
+
children: children || 'children'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function isLeaf(option, fieldNames) {
|
|
37
|
+
return option.isLeaf ?? !option[fieldNames.children]?.length;
|
|
38
|
+
}
|
|
39
|
+
export function scrollIntoParentView(element) {
|
|
40
|
+
const parent = element.parentElement;
|
|
41
|
+
if (!parent) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const elementToParent = element.offsetTop - parent.offsetTop; // offsetParent may not be parent.
|
|
45
|
+
if (elementToParent - parent.scrollTop < 0) {
|
|
46
|
+
parent.scrollTo({
|
|
47
|
+
top: elementToParent
|
|
48
|
+
});
|
|
49
|
+
} else if (elementToParent + element.offsetHeight - parent.scrollTop > parent.offsetHeight) {
|
|
50
|
+
parent.scrollTo({
|
|
51
|
+
top: elementToParent + element.offsetHeight - parent.offsetHeight
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function getFullPathKeys(options, fieldNames) {
|
|
56
|
+
return options.map(item => item[SEARCH_MARK]?.map(opt => opt[fieldNames.value]));
|
|
57
|
+
}
|
|
58
|
+
function isMultipleValue(value) {
|
|
59
|
+
return Array.isArray(value) && Array.isArray(value[0]);
|
|
60
|
+
}
|
|
61
|
+
export function toRawValues(value) {
|
|
62
|
+
if (!value) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
if (isMultipleValue(value)) {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
return (value.length === 0 ? [] : [value]).map(val => Array.isArray(val) ? val : [val]);
|
|
69
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { SingleValueType, DefaultOptionType, InternalFieldNames, ShowCheckedStrategy } from '../Cascader';
|
|
3
|
+
import type { GetEntities } from '../hooks/useEntities';
|
|
4
|
+
export declare function formatStrategyValues(pathKeys: React.Key[], getKeyPathEntities: GetEntities, showCheckedStrategy?: ShowCheckedStrategy): import("react").Key[];
|
|
5
|
+
export declare function toPathOptions(valueCells: SingleValueType, options: DefaultOptionType[], fieldNames: InternalFieldNames, stringMode?: boolean): {
|
|
6
|
+
value: SingleValueType[number];
|
|
7
|
+
index: number;
|
|
8
|
+
option: DefaultOptionType;
|
|
9
|
+
}[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SHOW_CHILD } from "./commonUtil";
|
|
2
|
+
export function formatStrategyValues(pathKeys, getKeyPathEntities, showCheckedStrategy) {
|
|
3
|
+
const valueSet = new Set(pathKeys);
|
|
4
|
+
const keyPathEntities = getKeyPathEntities();
|
|
5
|
+
return pathKeys.filter(key => {
|
|
6
|
+
const entity = keyPathEntities[key];
|
|
7
|
+
const parent = entity ? entity.parent : null;
|
|
8
|
+
const children = entity ? entity.children : null;
|
|
9
|
+
if (entity && entity.node.disabled) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
return showCheckedStrategy === SHOW_CHILD ? !(children && children.some(child => child.key && valueSet.has(child.key))) : !(parent && !parent.node.disabled && valueSet.has(parent.key));
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function toPathOptions(valueCells, options, fieldNames,
|
|
16
|
+
// Used for loadingKeys which saved loaded keys as string
|
|
17
|
+
stringMode = false) {
|
|
18
|
+
let currentList = options;
|
|
19
|
+
const valueOptions = [];
|
|
20
|
+
for (let i = 0; i < valueCells.length; i += 1) {
|
|
21
|
+
const valueCell = valueCells[i];
|
|
22
|
+
const foundIndex = currentList?.findIndex(option => {
|
|
23
|
+
const val = option[fieldNames.value];
|
|
24
|
+
return stringMode ? String(val) === String(valueCell) : val === valueCell;
|
|
25
|
+
});
|
|
26
|
+
const foundOption = foundIndex !== -1 ? currentList?.[foundIndex] : null;
|
|
27
|
+
valueOptions.push({
|
|
28
|
+
value: foundOption?.[fieldNames.value] ?? valueCell,
|
|
29
|
+
index: foundIndex,
|
|
30
|
+
option: foundOption
|
|
31
|
+
});
|
|
32
|
+
currentList = foundOption?.[fieldNames.children];
|
|
33
|
+
}
|
|
34
|
+
return valueOptions;
|
|
35
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DefaultOptionType, FieldNames, InternalCascaderProps } from '../Cascader';
|
|
2
|
+
declare function warningProps(props: InternalCascaderProps): void;
|
|
3
|
+
export declare function warningNullOptions(options: DefaultOptionType[], fieldNames: FieldNames): void;
|
|
4
|
+
export default warningProps;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import warning from "@rc-component/util/es/warning";
|
|
2
|
+
function warningProps(props) {
|
|
3
|
+
const {
|
|
4
|
+
popupVisible,
|
|
5
|
+
popupPlacement
|
|
6
|
+
} = props;
|
|
7
|
+
warning(popupVisible === undefined, '`popupVisible` is deprecated. Please use `open` instead.');
|
|
8
|
+
warning(popupPlacement === undefined, '`popupPlacement` is deprecated. Please use `placement` instead.');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// value in Cascader options should not be null
|
|
12
|
+
export function warningNullOptions(options, fieldNames) {
|
|
13
|
+
if (options) {
|
|
14
|
+
const recursiveOptions = optionsList => {
|
|
15
|
+
for (let i = 0; i < optionsList.length; i++) {
|
|
16
|
+
const option = optionsList[i];
|
|
17
|
+
if (option[fieldNames?.value] === null) {
|
|
18
|
+
warning(false, '`value` in Cascader options should not be `null`.');
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(option[fieldNames?.children]) && recursiveOptions(option[fieldNames?.children])) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
recursiveOptions(options);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export default warningProps;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { BuildInPlacements } from '@rc-component/trigger/lib/interface';
|
|
2
|
+
import type { BaseSelectPropsWithoutPrivate, BaseSelectRef } from '@rc-component/select';
|
|
3
|
+
import type { Placement } from '@rc-component/select/lib/BaseSelect';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import Panel from './Panel';
|
|
6
|
+
import { SHOW_CHILD, SHOW_PARENT } from './utils/commonUtil';
|
|
7
|
+
export interface BaseOptionType {
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
disableCheckbox?: boolean;
|
|
10
|
+
label?: React.ReactNode;
|
|
11
|
+
value?: string | number | null;
|
|
12
|
+
children?: DefaultOptionType[];
|
|
13
|
+
}
|
|
14
|
+
export type DefaultOptionType = BaseOptionType & Record<string, any>;
|
|
15
|
+
export interface ShowSearchType<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType> {
|
|
16
|
+
filter?: (inputValue: string, options: OptionType[], fieldNames: FieldNames<OptionType, ValueField>) => boolean;
|
|
17
|
+
render?: (inputValue: string, path: OptionType[], prefixCls: string, fieldNames: FieldNames<OptionType, ValueField>) => React.ReactNode;
|
|
18
|
+
sort?: (a: OptionType[], b: OptionType[], inputValue: string, fieldNames: FieldNames<OptionType, ValueField>) => number;
|
|
19
|
+
matchInputWidth?: boolean;
|
|
20
|
+
limit?: number | false;
|
|
21
|
+
}
|
|
22
|
+
export type ShowCheckedStrategy = typeof SHOW_PARENT | typeof SHOW_CHILD;
|
|
23
|
+
interface BaseCascaderProps<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType> extends Omit<BaseSelectPropsWithoutPrivate, 'tokenSeparators' | 'labelInValue' | 'mode' | 'showSearch'> {
|
|
24
|
+
id?: string;
|
|
25
|
+
prefixCls?: string;
|
|
26
|
+
fieldNames?: FieldNames<OptionType, ValueField>;
|
|
27
|
+
optionRender?: (option: OptionType) => React.ReactNode;
|
|
28
|
+
children?: React.ReactElement;
|
|
29
|
+
changeOnSelect?: boolean;
|
|
30
|
+
displayRender?: (label: string[], selectedOptions?: OptionType[]) => React.ReactNode;
|
|
31
|
+
checkable?: boolean | React.ReactNode;
|
|
32
|
+
showCheckedStrategy?: ShowCheckedStrategy;
|
|
33
|
+
autoClearSearchValue?: boolean;
|
|
34
|
+
showSearch?: boolean | ShowSearchType<OptionType>;
|
|
35
|
+
searchValue?: string;
|
|
36
|
+
onSearch?: (value: string) => void;
|
|
37
|
+
expandTrigger?: 'hover' | 'click';
|
|
38
|
+
options?: OptionType[];
|
|
39
|
+
/** @private Internal usage. Do not use in your production. */
|
|
40
|
+
dropdownPrefixCls?: string;
|
|
41
|
+
loadData?: (selectOptions: OptionType[]) => void;
|
|
42
|
+
/** @deprecated Use `open` instead */
|
|
43
|
+
popupVisible?: boolean;
|
|
44
|
+
popupClassName?: string;
|
|
45
|
+
dropdownMenuColumnStyle?: React.CSSProperties;
|
|
46
|
+
/** @deprecated Use `placement` instead */
|
|
47
|
+
popupPlacement?: Placement;
|
|
48
|
+
placement?: Placement;
|
|
49
|
+
builtinPlacements?: BuildInPlacements;
|
|
50
|
+
onPopupVisibleChange?: (open: boolean) => void;
|
|
51
|
+
expandIcon?: React.ReactNode;
|
|
52
|
+
loadingIcon?: React.ReactNode;
|
|
53
|
+
}
|
|
54
|
+
export interface FieldNames<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType> {
|
|
55
|
+
label?: keyof OptionType;
|
|
56
|
+
value?: keyof OptionType | ValueField;
|
|
57
|
+
children?: keyof OptionType;
|
|
58
|
+
}
|
|
59
|
+
export type ValueType<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType> = keyof OptionType extends ValueField ? unknown extends OptionType['value'] ? OptionType[ValueField] : OptionType['value'] : OptionType[ValueField];
|
|
60
|
+
export type GetValueType<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType, Multiple extends boolean | React.ReactNode = false> = false extends Multiple ? ValueType<Required<OptionType>, ValueField>[] : ValueType<Required<OptionType>, ValueField>[][];
|
|
61
|
+
export interface CascaderProps<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType, Multiple extends boolean | React.ReactNode = false> extends BaseCascaderProps<OptionType, ValueField> {
|
|
62
|
+
checkable?: Multiple;
|
|
63
|
+
value?: GetValueType<OptionType, ValueField, Multiple>;
|
|
64
|
+
defaultValue?: GetValueType<OptionType, ValueField, Multiple>;
|
|
65
|
+
onChange?: (value: GetValueType<OptionType, ValueField, Multiple>, selectOptions: OptionType[]) => void;
|
|
66
|
+
}
|
|
67
|
+
export type SingleValueType = (string | number)[];
|
|
68
|
+
export type InternalValueType = SingleValueType | SingleValueType[];
|
|
69
|
+
export interface InternalFieldNames extends Required<FieldNames> {
|
|
70
|
+
key: string;
|
|
71
|
+
}
|
|
72
|
+
export type InternalCascaderProps = Omit<CascaderProps, 'onChange' | 'value' | 'defaultValue'> & {
|
|
73
|
+
value?: InternalValueType;
|
|
74
|
+
defaultValue?: InternalValueType;
|
|
75
|
+
onChange?: (value: InternalValueType, selectOptions: BaseOptionType[] | BaseOptionType[][]) => void;
|
|
76
|
+
};
|
|
77
|
+
export type CascaderRef = Omit<BaseSelectRef, 'scrollTo'>;
|
|
78
|
+
declare const Cascader: (<OptionType extends DefaultOptionType = DefaultOptionType, ValueField extends keyof OptionType = keyof OptionType, Multiple extends React.ReactNode = false>(props: CascaderProps<OptionType, ValueField, Multiple> & {
|
|
79
|
+
children?: React.ReactNode;
|
|
80
|
+
} & {
|
|
81
|
+
ref?: React.Ref<CascaderRef> | undefined;
|
|
82
|
+
}) => React.ReactElement) & {
|
|
83
|
+
displayName?: string | undefined;
|
|
84
|
+
SHOW_PARENT: typeof SHOW_PARENT;
|
|
85
|
+
SHOW_CHILD: typeof SHOW_CHILD;
|
|
86
|
+
Panel: typeof Panel;
|
|
87
|
+
};
|
|
88
|
+
export default Cascader;
|