@@ -17,69 +17,8 @@ import * as Popover from '@radix-ui/react-popover';
1717import '../components/css/dropdown.css' ;
1818
1919import 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' ;
8322
8423const Dropdown = ( props : DropdownProps ) => {
8524 const {
@@ -98,12 +37,9 @@ const Dropdown = (props: DropdownProps) => {
9837 style,
9938 value,
10039 } = props ;
101- const [ optionsCheck , setOptionsCheck ] =
102- useState < DetailedDropdownOption [ ] > ( ) ;
40+ const [ optionsCheck , setOptionsCheck ] = useState < DetailedOption [ ] > ( ) ;
10341 const [ isOpen , setIsOpen ] = useState ( false ) ;
104- const [ displayOptions , setDisplayOptions ] = useState <
105- DetailedDropdownOption [ ]
106- > ( [ ] ) ;
42+ const [ displayOptions , setDisplayOptions ] = useState < DetailedOption [ ] > ( [ ] ) ;
10743 const persistentOptions = useRef < DropdownProps [ 'options' ] > ( [ ] ) ;
10844 const dropdownContainerRef = useRef < HTMLDivElement > ( null ) ;
10945
@@ -124,7 +60,7 @@ const Dropdown = (props: DropdownProps) => {
12460 [ persistentOptions . current , searchable , search_value ]
12561 ) ;
12662
127- const sanitizedValues : DropdownValue [ ] = useMemo ( ( ) => {
63+ const sanitizedValues : OptionValue [ ] = useMemo ( ( ) => {
12864 if ( value instanceof Array ) {
12965 return value ;
13066 }
@@ -134,58 +70,8 @@ const Dropdown = (props: DropdownProps) => {
13470 return [ value ] ;
13571 } , [ value ] ) ;
13672
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-
18773 const updateSelection = useCallback (
188- ( selection : DropdownValue [ ] ) => {
74+ ( selection : OptionValue [ ] ) => {
18975 if ( closeOnSelect !== false ) {
19076 setIsOpen ( false ) ;
19177 }
@@ -266,7 +152,7 @@ const Dropdown = (props: DropdownProps) => {
266152 ) ;
267153 return (
268154 < React . Fragment key = { `${ option ?. value } -${ i } ` } >
269- { option && < DropdownLabel { ...option } index = { i } /> }
155+ { option && < OptionLabel { ...option } index = { i } /> }
270156 { i === sanitizedValues . length - 1 ? '' : ', ' }
271157 </ React . Fragment >
272158 ) ;
@@ -283,13 +169,6 @@ const Dropdown = (props: DropdownProps) => {
283169 ) ;
284170 } , [ clearable , sanitizedValues , displayOptions , search_value ] ) ;
285171
286- const handleOptionClick = useCallback (
287- ( option : DetailedDropdownOption ) => {
288- toggleOption ( option ) ;
289- } ,
290- [ toggleOption ]
291- ) ;
292-
293172 const handleClear = useCallback ( ( ) => {
294173 const finalValue : DropdownProps [ 'value' ] = multi ? [ ] : null ;
295174 setProps ( { value : finalValue } ) ;
@@ -433,8 +312,8 @@ const Dropdown = (props: DropdownProps) => {
433312
434313 if ( open ) {
435314 // Sort options: selected first, then unselected
436- const selectedOptions : DetailedDropdownOption [ ] = [ ] ;
437- const unselectedOptions : DetailedDropdownOption [ ] = [ ] ;
315+ const selectedOptions : DetailedOption [ ] = [ ] ;
316+ const unselectedOptions : DetailedOption [ ] = [ ] ;
438317
439318 // First, collect selected options in the order they appear in the `value` array
440319 sanitizedValues . forEach ( value => {
@@ -583,6 +462,11 @@ const Dropdown = (props: DropdownProps) => {
583462 onSelectionChange = { updateSelection }
584463 className = "dash-dropdown-options"
585464 optionClassName = "dash-dropdown-option"
465+ optionStyle = { {
466+ height : optionHeight
467+ ? `${ optionHeight } px`
468+ : undefined ,
469+ } }
586470 />
587471 </ >
588472 ) }
0 commit comments