@@ -72,7 +72,11 @@ function SelectOption<T>({
7272 elementRef,
7373} : SelectOptionProps < T > ) {
7474 const checkboxRef = useRef < HTMLElement | null > ( null ) ;
75+ const checkboxContainerRef = useRef < HTMLLabelElement | null > ( null ) ;
7576 const optionRef = useSyncedRef ( elementRef ) ;
77+ const eventTriggeredInCheckbox = ( e : Event ) =>
78+ e . target === checkboxRef . current ||
79+ e . target === checkboxContainerRef . current ;
7680
7781 const selectContext = useContext ( SelectContext ) ;
7882 if ( ! selectContext ) {
@@ -150,9 +154,12 @@ function SelectOption<T>({
150154 classes ,
151155 ) }
152156 onClick = { e => {
153- // Do not invoke callback if clicked element is the checkbox, as it has
154- // its own event handler.
155- if ( ! disabled && e . target !== checkboxRef . current ) {
157+ if (
158+ ! disabled &&
159+ // Do not invoke callback if clicked element is the checkbox or its
160+ // container, as it has its own event handler.
161+ ! eventTriggeredInCheckbox ( e )
162+ ) {
156163 selectOneValue ( ) ;
157164 }
158165 } }
@@ -163,9 +170,9 @@ function SelectOption<T>({
163170
164171 if (
165172 [ 'Enter' , ' ' ] . includes ( e . key ) &&
166- // Do not invoke callback if event triggers in checkbox, as it has its
167- // own event handler.
168- e . target !== checkboxRef . current
173+ // Do not invoke callback if event triggered in the checkbox or its
174+ // container, as it has its own event handler.
175+ ! eventTriggeredInCheckbox ( e )
169176 ) {
170177 e . preventDefault ( ) ;
171178 selectOneValue ( ) ;
@@ -183,46 +190,57 @@ function SelectOption<T>({
183190 >
184191 < div
185192 className = { classnames (
186- 'w-full flex justify-between items-center gap-3' ,
187- 'rounded py-2 px-3' ,
193+ // Make items stretch so that all have the same height. This is
194+ // important for multi-selects, where the checkbox actionable surface
195+ // should span to the very edges of the option containing it.
196+ 'flex justify-between items-stretch' ,
197+ 'w-full rounded' ,
188198 {
189199 'hover:bg-grey-1 group-focus-visible:ring' : ! disabled ,
190200 'bg-grey-1 hover:bg-grey-2' : selected ,
191201 } ,
192202 ) }
193203 >
194- { optionChildren ( children , { selected, disabled } ) }
204+ < div className = "flex items-center py-2 pl-3" >
205+ { optionChildren ( children , { selected, disabled } ) }
206+ </ div >
195207 { ! multiple && (
196- < CheckIcon
197- className = { classnames ( 'text-grey-6 scale-125' , {
198- // Make the icon visible/invisible, instead of conditionally
199- // rendering it, to ensure consistent spacing among selected and
200- // non-selected options
201- 'opacity-0' : ! selected ,
202- } ) }
203- />
204- ) }
205- { multiple && (
206- < div
207- className = { classnames ( 'scale-125' , {
208- 'text-grey-6' : selected ,
209- 'text-grey-3 hover:text-grey-6' : ! selected ,
210- } ) }
211- >
212- < Checkbox
213- checked = { selected }
214- checkedIcon = { CheckboxCheckedFilledIcon }
215- elementRef = { checkboxRef }
216- onChange = { toggleValue }
217- onKeyDown = { e => {
218- if ( e . key === 'ArrowLeft' ) {
219- e . preventDefault ( ) ;
220- optionRef . current ?. focus ( ) ;
221- }
222- } }
208+ < div className = "flex items-center py-2 px-3" >
209+ < CheckIcon
210+ className = { classnames ( 'text-grey-6 scale-125' , {
211+ // Make the icon visible/invisible, instead of conditionally
212+ // rendering it, to ensure consistent spacing among selected and
213+ // non-selected options
214+ 'opacity-0' : ! selected ,
215+ } ) }
223216 />
224217 </ div >
225218 ) }
219+ { multiple && (
220+ < Checkbox
221+ containerClasses = { classnames (
222+ 'flex items-center py-2 px-3' ,
223+ // The checkbox is sized based on the container's font size. Make
224+ // it a bit larger.
225+ 'text-lg' ,
226+ {
227+ 'text-grey-6' : selected ,
228+ 'text-grey-3 hover:text-grey-6' : ! selected ,
229+ } ,
230+ ) }
231+ checked = { selected }
232+ checkedIcon = { CheckboxCheckedFilledIcon }
233+ elementRef = { checkboxRef }
234+ containerRef = { checkboxContainerRef }
235+ onChange = { toggleValue }
236+ onKeyDown = { e => {
237+ if ( e . key === 'ArrowLeft' ) {
238+ e . preventDefault ( ) ;
239+ optionRef . current ?. focus ( ) ;
240+ }
241+ } }
242+ />
243+ ) }
226244 </ div >
227245 </ li >
228246 ) ;
0 commit comments