@@ -3,18 +3,26 @@ import type { BaseSelectProps, BaseSelectPropsWithoutPrivate, BaseSelectRef } fr
33import { BaseSelect } from 'rc-select' ;
44import type { DisplayValueType , Placement } from 'rc-select/lib/BaseSelect' ;
55import useId from 'rc-select/lib/hooks/useId' ;
6- import { conductCheck } from 'rc-tree/lib/utils/conductUtil' ;
76import useEvent from 'rc-util/lib/hooks/useEvent' ;
87import useMergedState from 'rc-util/lib/hooks/useMergedState' ;
98import * as React from 'react' ;
109import CascaderContext from './context' ;
1110import useDisplayValues from './hooks/useDisplayValues' ;
12- import useEntities from './hooks/useEntities' ;
1311import useMissingValues from './hooks/useMissingValues' ;
12+ import useOptions from './hooks/useOptions' ;
1413import useSearchConfig from './hooks/useSearchConfig' ;
1514import useSearchOptions from './hooks/useSearchOptions' ;
15+ import useSelect from './hooks/useSelect' ;
16+ import useValues from './hooks/useValues' ;
1617import OptionList from './OptionList' ;
17- import { fillFieldNames , SHOW_CHILD , SHOW_PARENT , toPathKey , toPathKeys } from './utils/commonUtil' ;
18+ import Panel from './Panel' ;
19+ import {
20+ fillFieldNames ,
21+ SHOW_CHILD ,
22+ SHOW_PARENT ,
23+ toPathKeys ,
24+ toRawValues ,
25+ } from './utils/commonUtil' ;
1826import { formatStrategyValues , toPathOptions } from './utils/treeUtil' ;
1927import warningProps , { warningNullOptions } from './utils/warningPropsUtil' ;
2028
@@ -150,22 +158,6 @@ export type InternalCascaderProps<OptionType extends BaseOptionType = DefaultOpt
150158
151159export type CascaderRef = Omit < BaseSelectRef , 'scrollTo' > ;
152160
153- function isMultipleValue ( value : ValueType ) : value is SingleValueType [ ] {
154- return Array . isArray ( value ) && Array . isArray ( value [ 0 ] ) ;
155- }
156-
157- function toRawValues ( value : ValueType ) : SingleValueType [ ] {
158- if ( ! value ) {
159- return [ ] ;
160- }
161-
162- if ( isMultipleValue ( value ) ) {
163- return value ;
164- }
165-
166- return ( value . length === 0 ? [ ] : [ value ] ) . map ( val => ( Array . isArray ( val ) ? val : [ val ] ) ) ;
167- }
168-
169161const Cascader = React . forwardRef < CascaderRef , InternalCascaderProps > ( ( props , ref ) => {
170162 const {
171163 // MISC
@@ -238,23 +230,9 @@ const Cascader = React.forwardRef<CascaderRef, InternalCascaderProps>((props, re
238230 ) ;
239231
240232 // =========================== Option ===========================
241- const mergedOptions = React . useMemo ( ( ) => options || [ ] , [ options ] ) ;
242-
243- // Only used in multiple mode, this fn will not call in single mode
244- const getPathKeyEntities = useEntities ( mergedOptions , mergedFieldNames ) ;
245-
246- /** Convert path key back to value format */
247- const getValueByKeyPath = React . useCallback (
248- ( pathKeys : React . Key [ ] ) : SingleValueType [ ] => {
249- const keyPathEntities = getPathKeyEntities ( ) ;
250-
251- return pathKeys . map ( pathKey => {
252- const { nodes } = keyPathEntities [ pathKey ] ;
253-
254- return nodes . map ( node => node [ mergedFieldNames . value ] ) ;
255- } ) ;
256- } ,
257- [ getPathKeyEntities , mergedFieldNames ] ,
233+ const [ mergedOptions , getPathKeyEntities , getValueByKeyPath ] = useOptions (
234+ mergedFieldNames ,
235+ options ,
258236 ) ;
259237
260238 // =========================== Search ===========================
@@ -286,21 +264,13 @@ const Cascader = React.forwardRef<CascaderRef, InternalCascaderProps>((props, re
286264 const getMissingValues = useMissingValues ( mergedOptions , mergedFieldNames ) ;
287265
288266 // Fill `rawValues` with checked conduction values
289- const [ checkedValues , halfCheckedValues , missingCheckedValues ] = React . useMemo ( ( ) => {
290- const [ existValues , missingValues ] = getMissingValues ( rawValues ) ;
291-
292- if ( ! multiple || ! rawValues . length ) {
293- return [ existValues , [ ] , missingValues ] ;
294- }
295-
296- const keyPathValues = toPathKeys ( existValues ) ;
297- const keyPathEntities = getPathKeyEntities ( ) ;
298-
299- const { checkedKeys, halfCheckedKeys } = conductCheck ( keyPathValues , true , keyPathEntities ) ;
300-
301- // Convert key back to value cells
302- return [ getValueByKeyPath ( checkedKeys ) , getValueByKeyPath ( halfCheckedKeys ) , missingValues ] ;
303- } , [ multiple , rawValues , getPathKeyEntities , getValueByKeyPath , getMissingValues ] ) ;
267+ const [ checkedValues , halfCheckedValues , missingCheckedValues ] = useValues (
268+ multiple ,
269+ rawValues ,
270+ getPathKeyEntities ,
271+ getValueByKeyPath ,
272+ getMissingValues ,
273+ ) ;
304274
305275 const deDuplicatedValues = React . useMemo ( ( ) => {
306276 const checkedKeys = toPathKeys ( checkedValues ) ;
@@ -347,63 +317,23 @@ const Cascader = React.forwardRef<CascaderRef, InternalCascaderProps>((props, re
347317 } ) ;
348318
349319 // =========================== Select ===========================
320+ const handleSelection = useSelect (
321+ multiple ,
322+ triggerChange ,
323+ checkedValues ,
324+ halfCheckedValues ,
325+ missingCheckedValues ,
326+ getPathKeyEntities ,
327+ getValueByKeyPath ,
328+ showCheckedStrategy ,
329+ ) ;
330+
350331 const onInternalSelect = useEvent ( ( valuePath : SingleValueType ) => {
351332 if ( ! multiple || autoClearSearchValue ) {
352333 setSearchValue ( '' ) ;
353334 }
354- if ( ! multiple ) {
355- triggerChange ( valuePath ) ;
356- } else {
357- // Prepare conduct required info
358- const pathKey = toPathKey ( valuePath ) ;
359- const checkedPathKeys = toPathKeys ( checkedValues ) ;
360- const halfCheckedPathKeys = toPathKeys ( halfCheckedValues ) ;
361-
362- const existInChecked = checkedPathKeys . includes ( pathKey ) ;
363- const existInMissing = missingCheckedValues . some (
364- valueCells => toPathKey ( valueCells ) === pathKey ,
365- ) ;
366335
367- // Do update
368- let nextCheckedValues = checkedValues ;
369- let nextMissingValues = missingCheckedValues ;
370-
371- if ( existInMissing && ! existInChecked ) {
372- // Missing value only do filter
373- nextMissingValues = missingCheckedValues . filter (
374- valueCells => toPathKey ( valueCells ) !== pathKey ,
375- ) ;
376- } else {
377- // Update checked key first
378- const nextRawCheckedKeys = existInChecked
379- ? checkedPathKeys . filter ( key => key !== pathKey )
380- : [ ...checkedPathKeys , pathKey ] ;
381-
382- const pathKeyEntities = getPathKeyEntities ( ) ;
383-
384- // Conduction by selected or not
385- let checkedKeys : React . Key [ ] ;
386- if ( existInChecked ) {
387- ( { checkedKeys } = conductCheck (
388- nextRawCheckedKeys ,
389- { checked : false , halfCheckedKeys : halfCheckedPathKeys } ,
390- pathKeyEntities ,
391- ) ) ;
392- } else {
393- ( { checkedKeys } = conductCheck ( nextRawCheckedKeys , true , pathKeyEntities ) ) ;
394- }
395-
396- // Roll up to parent level keys
397- const deDuplicatedKeys = formatStrategyValues (
398- checkedKeys ,
399- getPathKeyEntities ,
400- showCheckedStrategy ,
401- ) ;
402- nextCheckedValues = getValueByKeyPath ( deDuplicatedKeys ) ;
403- }
404-
405- triggerChange ( [ ...nextMissingValues , ...nextCheckedValues ] ) ;
406- }
336+ handleSelection ( valuePath ) ;
407337 } ) ;
408338
409339 // Display Value change logic
@@ -527,6 +457,7 @@ const Cascader = React.forwardRef<CascaderRef, InternalCascaderProps>((props, re
527457 displayName ?: string ;
528458 SHOW_PARENT : typeof SHOW_PARENT ;
529459 SHOW_CHILD : typeof SHOW_CHILD ;
460+ Panel : typeof Panel ;
530461} ;
531462
532463if ( process . env . NODE_ENV !== 'production' ) {
@@ -535,4 +466,6 @@ if (process.env.NODE_ENV !== 'production') {
535466
536467Cascader . SHOW_PARENT = SHOW_PARENT ;
537468Cascader . SHOW_CHILD = SHOW_CHILD ;
469+ Cascader . Panel = Panel ;
470+
538471export default Cascader ;
0 commit comments