@@ -17,69 +17,8 @@ import * as Popover from '@radix-ui/react-popover';
17
17
import '../components/css/dropdown.css' ;
18
18
19
19
import isEqual from 'react-fast-compare' ;
20
- import { DetailedDropdownOption , DropdownProps , DropdownValue } from '../types' ;
21
- import { OptionsList } from '../utils/optionRendering' ;
22
-
23
- interface DropdownOptionProps {
24
- index : number ;
25
- option : DetailedDropdownOption ;
26
- isSelected : boolean ;
27
- onClick : ( option : DetailedDropdownOption ) => void ;
28
- style ?: React . CSSProperties ;
29
- }
30
-
31
- function DropdownLabel (
32
- props : DetailedDropdownOption & { index : string | number }
33
- ) : JSX . Element {
34
- const ctx = window . dash_component_api . useDashContext ( ) ;
35
- const ExternalWrapper = window . dash_component_api . ExternalWrapper ;
36
-
37
- if ( typeof props . label === 'object' ) {
38
- return (
39
- < ExternalWrapper
40
- component = { props . label }
41
- componentPath = { [ ...ctx . componentPath , props . index ] }
42
- />
43
- ) ;
44
- }
45
- const displayLabel = `${ props . label ?? props . value } ` ;
46
- return < span title = { props . title } > { displayLabel } </ span > ;
47
- }
48
-
49
- const DropdownOption : React . FC < DropdownOptionProps > = ( {
50
- option,
51
- isSelected,
52
- onClick,
53
- style,
54
- index,
55
- } ) => {
56
- return (
57
- < label
58
- className = { `dash-dropdown-option ${ isSelected ? 'selected' : '' } ` }
59
- role = "option"
60
- aria-selected = { isSelected }
61
- style = { style }
62
- title = { option . title }
63
- >
64
- < input
65
- type = "checkbox"
66
- checked = { isSelected }
67
- value = {
68
- typeof option . value === 'boolean'
69
- ? `${ option . value } `
70
- : option . value
71
- }
72
- disabled = { ! ! option . disabled }
73
- onChange = { ( ) => onClick ( option ) }
74
- readOnly
75
- className = "dash-dropdown-option-checkbox"
76
- />
77
- < span className = "dash-dropdown-option-text" >
78
- < DropdownLabel { ...option } index = { index } />
79
- </ span >
80
- </ label >
81
- ) ;
82
- } ;
20
+ import { DetailedOption , DropdownProps , OptionValue } from '../types' ;
21
+ import { OptionsList , OptionLabel } from '../utils/optionRendering' ;
83
22
84
23
const Dropdown = ( props : DropdownProps ) => {
85
24
const {
@@ -98,12 +37,9 @@ const Dropdown = (props: DropdownProps) => {
98
37
style,
99
38
value,
100
39
} = props ;
101
- const [ optionsCheck , setOptionsCheck ] =
102
- useState < DetailedDropdownOption [ ] > ( ) ;
40
+ const [ optionsCheck , setOptionsCheck ] = useState < DetailedOption [ ] > ( ) ;
103
41
const [ isOpen , setIsOpen ] = useState ( false ) ;
104
- const [ displayOptions , setDisplayOptions ] = useState <
105
- DetailedDropdownOption [ ]
106
- > ( [ ] ) ;
42
+ const [ displayOptions , setDisplayOptions ] = useState < DetailedOption [ ] > ( [ ] ) ;
107
43
const persistentOptions = useRef < DropdownProps [ 'options' ] > ( [ ] ) ;
108
44
const dropdownContainerRef = useRef < HTMLDivElement > ( null ) ;
109
45
@@ -124,7 +60,7 @@ const Dropdown = (props: DropdownProps) => {
124
60
[ persistentOptions . current , searchable , search_value ]
125
61
) ;
126
62
127
- const sanitizedValues : DropdownValue [ ] = useMemo ( ( ) => {
63
+ const sanitizedValues : OptionValue [ ] = useMemo ( ( ) => {
128
64
if ( value instanceof Array ) {
129
65
return value ;
130
66
}
@@ -134,58 +70,8 @@ const Dropdown = (props: DropdownProps) => {
134
70
return [ value ] ;
135
71
} , [ value ] ) ;
136
72
137
- const toggleOption = useCallback (
138
- ( option : DetailedDropdownOption ) => {
139
- const isCurrentlySelected = sanitizedValues . includes ( option . value ) ;
140
-
141
- // Close dropdown if closeOnSelect is true (default behavior)
142
- if ( closeOnSelect !== false ) {
143
- setIsOpen ( false ) ;
144
- }
145
-
146
- if ( multi ) {
147
- let newValues : DropdownValue [ ] ;
148
-
149
- if ( isCurrentlySelected ) {
150
- // Deselecting: only allow if clearable is true or more than one option selected
151
- if ( clearable || sanitizedValues . length > 1 ) {
152
- newValues = sanitizedValues . filter (
153
- v => v !== option . value
154
- ) ;
155
- } else {
156
- // Cannot deselect the last option when clearable is false
157
- return ;
158
- }
159
- } else {
160
- // Selecting: add to current selection
161
- newValues = [ ...sanitizedValues , option . value ] ;
162
- }
163
-
164
- setProps ( { value : newValues } ) ;
165
- } else {
166
- let newValue : DropdownValue | null ;
167
-
168
- if ( isCurrentlySelected ) {
169
- // Deselecting: only allow if clearable is true
170
- if ( clearable ) {
171
- newValue = null ;
172
- } else {
173
- // Cannot deselect when clearable is false
174
- return ;
175
- }
176
- } else {
177
- // Selecting: set as the single value
178
- newValue = option . value ;
179
- }
180
-
181
- setProps ( { value : newValue } ) ;
182
- }
183
- } ,
184
- [ multi , clearable , closeOnSelect , sanitizedValues ]
185
- ) ;
186
-
187
73
const updateSelection = useCallback (
188
- ( selection : DropdownValue [ ] ) => {
74
+ ( selection : OptionValue [ ] ) => {
189
75
if ( closeOnSelect !== false ) {
190
76
setIsOpen ( false ) ;
191
77
}
@@ -266,7 +152,7 @@ const Dropdown = (props: DropdownProps) => {
266
152
) ;
267
153
return (
268
154
< React . Fragment key = { `${ option ?. value } -${ i } ` } >
269
- { option && < DropdownLabel { ...option } index = { i } /> }
155
+ { option && < OptionLabel { ...option } index = { i } /> }
270
156
{ i === sanitizedValues . length - 1 ? '' : ', ' }
271
157
</ React . Fragment >
272
158
) ;
@@ -283,13 +169,6 @@ const Dropdown = (props: DropdownProps) => {
283
169
) ;
284
170
} , [ clearable , sanitizedValues , displayOptions , search_value ] ) ;
285
171
286
- const handleOptionClick = useCallback (
287
- ( option : DetailedDropdownOption ) => {
288
- toggleOption ( option ) ;
289
- } ,
290
- [ toggleOption ]
291
- ) ;
292
-
293
172
const handleClear = useCallback ( ( ) => {
294
173
const finalValue : DropdownProps [ 'value' ] = multi ? [ ] : null ;
295
174
setProps ( { value : finalValue } ) ;
@@ -433,8 +312,8 @@ const Dropdown = (props: DropdownProps) => {
433
312
434
313
if ( open ) {
435
314
// Sort options: selected first, then unselected
436
- const selectedOptions : DetailedDropdownOption [ ] = [ ] ;
437
- const unselectedOptions : DetailedDropdownOption [ ] = [ ] ;
315
+ const selectedOptions : DetailedOption [ ] = [ ] ;
316
+ const unselectedOptions : DetailedOption [ ] = [ ] ;
438
317
439
318
// First, collect selected options in the order they appear in the `value` array
440
319
sanitizedValues . forEach ( value => {
@@ -583,6 +462,11 @@ const Dropdown = (props: DropdownProps) => {
583
462
onSelectionChange = { updateSelection }
584
463
className = "dash-dropdown-options"
585
464
optionClassName = "dash-dropdown-option"
465
+ optionStyle = { {
466
+ height : optionHeight
467
+ ? `${ optionHeight } px`
468
+ : undefined ,
469
+ } }
586
470
/>
587
471
</ >
588
472
) }
0 commit comments