1- import React , { ReactNode , useState } from 'react' ;
1+ import React , { ReactNode , useEffect , useMemo , useState } from 'react' ;
22import { Button , Checkbox , Col , Dropdown , type DropDownProps , Row , Space } from 'antd' ;
33import type { CheckboxChangeEvent } from 'antd/lib/checkbox' ;
4- import type { CheckboxGroupProps , CheckboxValueType } from 'antd/lib/checkbox/Group' ;
4+ import type {
5+ CheckboxGroupProps ,
6+ CheckboxOptionType ,
7+ CheckboxValueType ,
8+ } from 'antd/lib/checkbox/Group' ;
59import classNames from 'classnames' ;
610import { isEqual } from 'lodash' ;
711import List from 'rc-virtual-list' ;
@@ -10,10 +14,9 @@ import './style.scss';
1014
1115interface IDropdownSelectProps
1216 extends Pick < DropDownProps , 'getPopupContainer' > ,
13- Required < Pick < CheckboxGroupProps , 'value' | 'options' | 'onChange' > > {
17+ Pick < CheckboxGroupProps , 'value' | 'defaultValue' | ' options' | 'onChange' > {
1418 children : ReactNode ;
1519 className ?: string ;
16- onSubmit ?: ( value : CheckboxValueType [ ] ) => void ;
1720}
1821
1922const prefix = 'dtc-dropdown-select' ;
@@ -23,37 +26,37 @@ const MAX_HEIGHT = 264;
2326export default function Select ( {
2427 className,
2528 value,
29+ defaultValue,
2630 options : rawOptions ,
2731 children,
2832 getPopupContainer,
2933 onChange,
30- onSubmit,
3134} : IDropdownSelectProps ) {
3235 const [ visible , setVisible ] = useState ( false ) ;
36+ const [ selected , setSelected ] = useState < CheckboxValueType [ ] > ( value || defaultValue || [ ] ) ;
3337
3438 const handleCheckedAll = ( e : CheckboxChangeEvent ) => {
3539 if ( e . target . checked ) {
36- onChange ?. ( options ?. map ( ( i ) => i . value ) || [ ] ) ;
40+ setSelected ( options ?. map ( ( i ) => i . value ) || [ ] ) ;
3741 } else {
3842 handleReset ( ) ;
3943 }
4044 } ;
4145
4246 const handleSubmit = ( ) => {
43- onSubmit ?.( value ) ;
47+ onChange ?.( selected ) ;
4448 setVisible ( false ) ;
4549 } ;
4650
4751 const handleReset = ( ) => {
4852 // Clear checked but disabled item
49- onChange ?. ( options ?. filter ( ( i ) => i . disabled ) . map ( ( i ) => i . value ) || [ ] ) ;
53+ setSelected ( disabledValue ) ;
5054 } ;
5155
5256 const handleChange = ( e : CheckboxChangeEvent ) => {
53- const next = e . target . checked
54- ? [ ...( value || [ ] ) , e . target . value ]
55- : value ?. filter ( ( i ) => i !== e . target . value ) ;
56- onChange ?.( next ) ;
57+ const { checked, value } = e . target ;
58+ const next = checked ? [ ...selected , value ] : selected ?. filter ( ( i ) => i !== value ) ;
59+ setSelected ( next ) ;
5760 } ;
5861
5962 const handleShadow = ( target : HTMLDivElement ) => {
@@ -64,51 +67,59 @@ export default function Select({
6467 target . insertBefore ( shadow , target . firstChild ) ;
6568 }
6669
67- if (
68- Number (
69- target
70- . querySelector < HTMLDivElement > ( '.rc-virtual-list-scrollbar-thumb' )
71- ?. style . top . replace ( 'px' , '' )
72- ) > 0
73- ) {
74- target . querySelector < HTMLDivElement > ( `.${ prefix } __shadow` ) ?. classList . add ( 'active' ) ;
70+ const scrollbar_thumb = target . querySelector < HTMLDivElement > (
71+ '.rc-virtual-list-scrollbar-thumb'
72+ ) ;
73+ const shadow = target . querySelector < HTMLDivElement > ( `.${ prefix } __shadow` ) ;
74+
75+ if ( parseFloat ( scrollbar_thumb ?. style . top as string ) > 0 ) {
76+ shadow ?. classList . add ( 'active' ) ;
7577 } else {
76- target
77- . querySelector < HTMLDivElement > ( `.${ prefix } __shadow` )
78- ?. classList . remove ( 'active' ) ;
78+ shadow ?. classList . remove ( 'active' ) ;
7979 }
8080 }
8181 } ;
8282
83- // Always turn string and number options into complex options
84- const options = rawOptions . map ( ( i ) => {
85- if ( typeof i === 'string' || typeof i === 'number' ) {
86- return {
87- label : i ,
88- value : i ,
89- } ;
83+ useEffect ( ( ) => {
84+ if ( value !== undefined && value !== selected ) {
85+ setSelected ( value || [ ] ) ;
9086 }
87+ } , [ value ] ) ;
88+
89+ // Always turn string and number options into complex options
90+ const options = useMemo < CheckboxOptionType [ ] > ( ( ) => {
91+ return (
92+ rawOptions ?. map ( ( i ) => {
93+ if ( typeof i === 'string' || typeof i === 'number' ) {
94+ return {
95+ label : i ,
96+ value : i ,
97+ } ;
98+ }
9199
92- return i ;
93- } ) ;
100+ return i ;
101+ } ) || [ ]
102+ ) ;
103+ } , [ rawOptions ] ) ;
94104
95- const resetDisabled = value . every ( ( i ) =>
96- options
97- ?. filter ( ( i ) => i . disabled )
98- . map ( ( i ) => i . value )
99- ?. includes ( i )
100- ) ;
105+ const disabledValue = useMemo < CheckboxValueType [ ] > ( ( ) => {
106+ return options ?. filter ( ( i ) => i . disabled ) . map ( ( i ) => i . value ) || [ ] ;
107+ } , [ options ] ) ;
108+
109+ const resetDisabled = selected . every ( ( i ) => disabledValue ?. includes ( i ) ) ;
101110
102111 // If options' number is larger then the maxHeight, then enable virtual list
103112 const virtual = options . length > Math . floor ( MAX_HEIGHT / ITEM_HEIGHT ) ;
104113
105114 // ONLY the options are all be pushed into value array means select all
106- const checkAll = ! ! value ?. length && isEqual ( options . map ( ( i ) => i . value ) . sort ( ) , value . sort ( ) ) ;
115+ const checkAll =
116+ ! ! selected ?. length && isEqual ( options . map ( ( i ) => i . value ) . sort ( ) , [ ...selected ] . sort ( ) ) ;
117+
107118 // At least one option's value is included in value array but not all options means indeterminate select
108119 const indeterminate =
109- ! ! value ?. length &&
110- ! isEqual ( options . map ( ( i ) => i . value ) . sort ( ) , value . sort ( ) ) &&
111- options . some ( ( o ) => value . includes ( o . value ) ) ;
120+ ! ! selected ?. length &&
121+ ! isEqual ( options . map ( ( i ) => i . value ) . sort ( ) , [ ... selected ] . sort ( ) ) &&
122+ options . some ( ( o ) => selected . includes ( o . value ) ) ;
112123
113124 const overlay = (
114125 < >
@@ -123,7 +134,7 @@ export default function Select({
123134 </ Checkbox >
124135 </ Col >
125136 < Col span = { 24 } className = { `${ prefix } __menu` } >
126- < Checkbox . Group value = { value } >
137+ < Checkbox . Group value = { selected } >
127138 < List
128139 data = { options }
129140 itemKey = "value"
0 commit comments