1
This commit is contained in:
Generated
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import type { DefaultOptionType, SingleValueType, CascaderProps, InternalFieldNames } from '../Cascader';
|
||||
declare const _default: (rawValues: SingleValueType[], options: DefaultOptionType[], fieldNames: InternalFieldNames, multiple: boolean, displayRender: CascaderProps['displayRender']) => {
|
||||
label: React.ReactNode;
|
||||
value: string;
|
||||
key: string;
|
||||
valueCells: SingleValueType;
|
||||
disabled: boolean | undefined;
|
||||
}[];
|
||||
export default _default;
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
import { toPathOptions } from "../utils/treeUtil";
|
||||
import * as React from 'react';
|
||||
import { toPathKey } from "../utils/commonUtil";
|
||||
export default ((rawValues, options, fieldNames, multiple, displayRender) => {
|
||||
return React.useMemo(() => {
|
||||
const mergedDisplayRender = displayRender || (
|
||||
// Default displayRender
|
||||
labels => {
|
||||
const mergedLabels = multiple ? labels.slice(-1) : labels;
|
||||
const SPLIT = ' / ';
|
||||
if (mergedLabels.every(label => ['string', 'number'].includes(typeof label))) {
|
||||
return mergedLabels.join(SPLIT);
|
||||
}
|
||||
|
||||
// If exist non-string value, use ReactNode instead
|
||||
return mergedLabels.reduce((list, label, index) => {
|
||||
const keyedLabel = /*#__PURE__*/React.isValidElement(label) ? /*#__PURE__*/React.cloneElement(label, {
|
||||
key: index
|
||||
}) : label;
|
||||
if (index === 0) {
|
||||
return [keyedLabel];
|
||||
}
|
||||
return [...list, SPLIT, keyedLabel];
|
||||
}, []);
|
||||
});
|
||||
return rawValues.map(valueCells => {
|
||||
const valueOptions = toPathOptions(valueCells, options, fieldNames);
|
||||
const label = mergedDisplayRender(valueOptions.map(({
|
||||
option,
|
||||
value
|
||||
}) => option?.[fieldNames.label] ?? value), valueOptions.map(({
|
||||
option
|
||||
}) => option));
|
||||
const value = toPathKey(valueCells);
|
||||
return {
|
||||
label,
|
||||
value,
|
||||
key: value,
|
||||
valueCells,
|
||||
disabled: valueOptions[valueOptions.length - 1]?.option?.disabled
|
||||
};
|
||||
});
|
||||
}, [rawValues, options, fieldNames, displayRender, multiple]);
|
||||
});
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import type { DefaultOptionType, InternalFieldNames } from '../Cascader';
|
||||
import type { DataEntity } from '@rc-component/tree/lib/interface';
|
||||
export interface OptionsInfo {
|
||||
keyEntities: Record<string, DataEntity>;
|
||||
pathKeyEntities: Record<string, DataEntity>;
|
||||
}
|
||||
export type GetEntities = () => OptionsInfo['pathKeyEntities'];
|
||||
/** Lazy parse options data into conduct-able info to avoid perf issue in single mode */
|
||||
declare const _default: (options: DefaultOptionType[], fieldNames: InternalFieldNames) => GetEntities;
|
||||
export default _default;
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import * as React from 'react';
|
||||
import { convertDataToEntities } from "@rc-component/tree/es/utils/treeUtil";
|
||||
import { VALUE_SPLIT } from "../utils/commonUtil";
|
||||
/** Lazy parse options data into conduct-able info to avoid perf issue in single mode */
|
||||
export default ((options, fieldNames) => {
|
||||
const cacheRef = React.useRef({
|
||||
options: [],
|
||||
info: {
|
||||
keyEntities: {},
|
||||
pathKeyEntities: {}
|
||||
}
|
||||
});
|
||||
const getEntities = React.useCallback(() => {
|
||||
if (cacheRef.current.options !== options) {
|
||||
cacheRef.current.options = options;
|
||||
cacheRef.current.info = convertDataToEntities(options, {
|
||||
fieldNames: fieldNames,
|
||||
initWrapper: wrapper => ({
|
||||
...wrapper,
|
||||
pathKeyEntities: {}
|
||||
}),
|
||||
processEntity: (entity, wrapper) => {
|
||||
const pathKey = entity.nodes.map(node => node[fieldNames.value]).join(VALUE_SPLIT);
|
||||
wrapper.pathKeyEntities[pathKey] = entity;
|
||||
|
||||
// Overwrite origin key.
|
||||
// this is very hack but we need let conduct logic work with connect path
|
||||
entity.key = pathKey;
|
||||
}
|
||||
});
|
||||
}
|
||||
return cacheRef.current.info.pathKeyEntities;
|
||||
}, [fieldNames, options]);
|
||||
return getEntities;
|
||||
});
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import type { DefaultOptionType, InternalFieldNames, SingleValueType } from '../Cascader';
|
||||
export type GetMissValues = ReturnType<typeof useMissingValues>;
|
||||
export default function useMissingValues(options: DefaultOptionType[], fieldNames: InternalFieldNames): (rawValues: SingleValueType[]) => [SingleValueType[], SingleValueType[]];
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import { toPathOptions } from "../utils/treeUtil";
|
||||
export default function useMissingValues(options, fieldNames) {
|
||||
return React.useCallback(rawValues => {
|
||||
const missingValues = [];
|
||||
const existsValues = [];
|
||||
rawValues.forEach(valueCell => {
|
||||
const pathOptions = toPathOptions(valueCell, options, fieldNames);
|
||||
if (pathOptions.every(opt => opt.option)) {
|
||||
existsValues.push(valueCell);
|
||||
} else {
|
||||
missingValues.push(valueCell);
|
||||
}
|
||||
});
|
||||
return [existsValues, missingValues];
|
||||
}, [options, fieldNames]);
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { DefaultOptionType } from '..';
|
||||
import type { InternalFieldNames, SingleValueType, LegacyKey } from '../Cascader';
|
||||
import { type GetEntities } from './useEntities';
|
||||
export default function useOptions(mergedFieldNames: InternalFieldNames, options?: DefaultOptionType[]): [
|
||||
mergedOptions: DefaultOptionType[],
|
||||
getPathKeyEntities: GetEntities,
|
||||
getValueByKeyPath: (pathKeys: LegacyKey[]) => SingleValueType[]
|
||||
];
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import * as React from 'react';
|
||||
import useEntities from "./useEntities";
|
||||
export default function useOptions(mergedFieldNames, options) {
|
||||
const mergedOptions = React.useMemo(() => options || [], [options]);
|
||||
|
||||
// Only used in multiple mode, this fn will not call in single mode
|
||||
const getPathKeyEntities = useEntities(mergedOptions, mergedFieldNames);
|
||||
|
||||
/** Convert path key back to value format */
|
||||
const getValueByKeyPath = React.useCallback(pathKeys => {
|
||||
const keyPathEntities = getPathKeyEntities();
|
||||
return pathKeys.map(pathKey => {
|
||||
const {
|
||||
nodes
|
||||
} = keyPathEntities[pathKey];
|
||||
return nodes.map(node => node[mergedFieldNames.value]);
|
||||
});
|
||||
}, [getPathKeyEntities, mergedFieldNames]);
|
||||
return [mergedOptions, getPathKeyEntities, getValueByKeyPath];
|
||||
}
|
||||
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
import type { CascaderProps, SearchConfig } from '../Cascader';
|
||||
export default function useSearchConfig(showSearch?: CascaderProps['showSearch'], props?: any): [boolean, SearchConfig<import("../Cascader").DefaultOptionType, string>];
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import warning from "@rc-component/util/es/warning";
|
||||
import * as React from 'react';
|
||||
// Convert `showSearch` to unique config
|
||||
export default function useSearchConfig(showSearch, props) {
|
||||
const {
|
||||
autoClearSearchValue,
|
||||
searchValue,
|
||||
onSearch
|
||||
} = props;
|
||||
return React.useMemo(() => {
|
||||
if (!showSearch) {
|
||||
return [false, {}];
|
||||
}
|
||||
let searchConfig = {
|
||||
matchInputWidth: true,
|
||||
limit: 50,
|
||||
autoClearSearchValue,
|
||||
searchValue,
|
||||
onSearch
|
||||
};
|
||||
if (showSearch && typeof showSearch === 'object') {
|
||||
searchConfig = {
|
||||
...searchConfig,
|
||||
...showSearch
|
||||
};
|
||||
}
|
||||
if (searchConfig.limit <= 0) {
|
||||
searchConfig.limit = false;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(false, "'limit' of showSearch should be positive number or false.");
|
||||
}
|
||||
}
|
||||
return [true, searchConfig];
|
||||
}, [showSearch, autoClearSearchValue, searchValue, onSearch]);
|
||||
}
|
||||
Generated
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
import type { DefaultOptionType, InternalFieldNames, SearchConfig } from '../Cascader';
|
||||
export declare const SEARCH_MARK = "__rc_cascader_search_mark__";
|
||||
declare const useSearchOptions: (search: string, options: DefaultOptionType[], fieldNames: InternalFieldNames, prefixCls: string, config: SearchConfig, enableHalfPath?: boolean) => DefaultOptionType[];
|
||||
export default useSearchOptions;
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
import * as React from 'react';
|
||||
export const SEARCH_MARK = '__rc_cascader_search_mark__';
|
||||
const defaultFilter = (search, options, {
|
||||
label = ''
|
||||
}) => options.some(opt => String(opt[label]).toLowerCase().includes(search.toLowerCase()));
|
||||
const defaultRender = (inputValue, path, prefixCls, fieldNames) => path.map(opt => opt[fieldNames.label]).join(' / ');
|
||||
const useSearchOptions = (search, options, fieldNames, prefixCls, config, enableHalfPath) => {
|
||||
const {
|
||||
filter = defaultFilter,
|
||||
render = defaultRender,
|
||||
limit = 50,
|
||||
sort
|
||||
} = config;
|
||||
return React.useMemo(() => {
|
||||
const filteredOptions = [];
|
||||
if (!search) {
|
||||
return [];
|
||||
}
|
||||
function dig(list, pathOptions, parentDisabled = false) {
|
||||
list.forEach(option => {
|
||||
// Perf saving when `sort` is disabled and `limit` is provided
|
||||
if (!sort && limit !== false && limit > 0 && filteredOptions.length >= limit) {
|
||||
return;
|
||||
}
|
||||
const connectedPathOptions = [...pathOptions, option];
|
||||
const children = option[fieldNames.children];
|
||||
const mergedDisabled = parentDisabled || option.disabled;
|
||||
|
||||
// If current option is filterable
|
||||
if (
|
||||
// If is leaf option
|
||||
!children || children.length === 0 ||
|
||||
// If is changeOnSelect or multiple
|
||||
enableHalfPath) {
|
||||
if (filter(search, connectedPathOptions, {
|
||||
label: fieldNames.label
|
||||
})) {
|
||||
filteredOptions.push({
|
||||
...option,
|
||||
disabled: mergedDisabled,
|
||||
[fieldNames.label]: render(search, connectedPathOptions, prefixCls, fieldNames),
|
||||
[SEARCH_MARK]: connectedPathOptions,
|
||||
[fieldNames.children]: undefined
|
||||
});
|
||||
}
|
||||
}
|
||||
if (children) {
|
||||
dig(option[fieldNames.children], connectedPathOptions, mergedDisabled);
|
||||
}
|
||||
});
|
||||
}
|
||||
dig(options, []);
|
||||
|
||||
// Do sort
|
||||
if (sort) {
|
||||
filteredOptions.sort((a, b) => {
|
||||
return sort(a[SEARCH_MARK], b[SEARCH_MARK], search, fieldNames);
|
||||
});
|
||||
}
|
||||
return limit !== false && limit > 0 ? filteredOptions.slice(0, limit) : filteredOptions;
|
||||
}, [search, options, fieldNames, prefixCls, render, enableHalfPath, filter, sort, limit]);
|
||||
};
|
||||
export default useSearchOptions;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
import type { InternalValueType, LegacyKey, ShowCheckedStrategy, SingleValueType } from '../Cascader';
|
||||
import type { GetEntities } from './useEntities';
|
||||
export default function useSelect(multiple: boolean, triggerChange: (nextValues: InternalValueType) => void, checkedValues: SingleValueType[], halfCheckedValues: SingleValueType[], missingCheckedValues: SingleValueType[], getPathKeyEntities: GetEntities, getValueByKeyPath: (pathKeys: LegacyKey[]) => SingleValueType[], showCheckedStrategy?: ShowCheckedStrategy): (valuePath: SingleValueType) => void;
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import { conductCheck } from "@rc-component/tree/es/utils/conductUtil";
|
||||
import { toPathKey, toPathKeys } from "../utils/commonUtil";
|
||||
import { formatStrategyValues } from "../utils/treeUtil";
|
||||
export default function useSelect(multiple, triggerChange, checkedValues, halfCheckedValues, missingCheckedValues, getPathKeyEntities, getValueByKeyPath, showCheckedStrategy) {
|
||||
return valuePath => {
|
||||
if (!multiple) {
|
||||
triggerChange(valuePath);
|
||||
} else {
|
||||
// Prepare conduct required info
|
||||
const pathKey = toPathKey(valuePath);
|
||||
const checkedPathKeys = toPathKeys(checkedValues);
|
||||
const halfCheckedPathKeys = toPathKeys(halfCheckedValues);
|
||||
const existInChecked = checkedPathKeys.includes(pathKey);
|
||||
const existInMissing = missingCheckedValues.some(valueCells => toPathKey(valueCells) === pathKey);
|
||||
|
||||
// Do update
|
||||
let nextCheckedValues = checkedValues;
|
||||
let nextMissingValues = missingCheckedValues;
|
||||
if (existInMissing && !existInChecked) {
|
||||
// Missing value only do filter
|
||||
nextMissingValues = missingCheckedValues.filter(valueCells => toPathKey(valueCells) !== pathKey);
|
||||
} else {
|
||||
// Update checked key first
|
||||
const nextRawCheckedKeys = existInChecked ? checkedPathKeys.filter(key => key !== pathKey) : [...checkedPathKeys, pathKey];
|
||||
const pathKeyEntities = getPathKeyEntities();
|
||||
|
||||
// Conduction by selected or not
|
||||
let checkedKeys;
|
||||
if (existInChecked) {
|
||||
({
|
||||
checkedKeys
|
||||
} = conductCheck(nextRawCheckedKeys, {
|
||||
checked: false,
|
||||
halfCheckedKeys: halfCheckedPathKeys
|
||||
}, pathKeyEntities));
|
||||
} else {
|
||||
({
|
||||
checkedKeys
|
||||
} = conductCheck(nextRawCheckedKeys, true, pathKeyEntities));
|
||||
}
|
||||
|
||||
// Roll up to parent level keys
|
||||
const deDuplicatedKeys = formatStrategyValues(checkedKeys, getPathKeyEntities, showCheckedStrategy);
|
||||
nextCheckedValues = getValueByKeyPath(deDuplicatedKeys);
|
||||
}
|
||||
triggerChange([...nextMissingValues, ...nextCheckedValues]);
|
||||
}
|
||||
};
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import type { DataEntity } from '@rc-component/tree/lib/interface';
|
||||
import type { LegacyKey, SingleValueType } from '../Cascader';
|
||||
import type { GetMissValues } from './useMissingValues';
|
||||
export default function useValues(multiple: boolean, rawValues: SingleValueType[], getPathKeyEntities: () => Record<string, DataEntity>, getValueByKeyPath: (pathKeys: LegacyKey[]) => SingleValueType[], getMissingValues: GetMissValues): [
|
||||
checkedValues: SingleValueType[],
|
||||
halfCheckedValues: SingleValueType[],
|
||||
missingCheckedValues: SingleValueType[]
|
||||
];
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { conductCheck } from "@rc-component/tree/es/utils/conductUtil";
|
||||
import * as React from 'react';
|
||||
import { toPathKeys } from "../utils/commonUtil";
|
||||
export default function useValues(multiple, rawValues, getPathKeyEntities, getValueByKeyPath, getMissingValues) {
|
||||
// Fill `rawValues` with checked conduction values
|
||||
return React.useMemo(() => {
|
||||
const [existValues, missingValues] = getMissingValues(rawValues);
|
||||
if (!multiple || !rawValues.length) {
|
||||
return [existValues, [], missingValues];
|
||||
}
|
||||
const keyPathValues = toPathKeys(existValues);
|
||||
const keyPathEntities = getPathKeyEntities();
|
||||
const {
|
||||
checkedKeys,
|
||||
halfCheckedKeys
|
||||
} = conductCheck(keyPathValues, true, keyPathEntities);
|
||||
|
||||
// Convert key back to value cells
|
||||
return [getValueByKeyPath(checkedKeys), getValueByKeyPath(halfCheckedKeys), missingValues];
|
||||
}, [multiple, rawValues, getPathKeyEntities, getValueByKeyPath, getMissingValues]);
|
||||
}
|
||||
Reference in New Issue
Block a user