11// NOTE This is adapted from react-native-modal-selector https://github.com/peacechen/react-native-modal-selector/blob/master/index.js
22
3+ import { useTheme } from '@storybook/react-native-theming' ;
34import { ComponentType , ReactNode , useCallback , useMemo , useState } from 'react' ;
45
56import {
@@ -21,7 +22,7 @@ import { ModalPortal } from './ModalPortal';
2122const PADDING = 8 ;
2223const BORDER_RADIUS = 5 ;
2324const FONT_SIZE = 16 ;
24- const HIGHLIGHT_COLOR = 'rgba(0,118,255,0.9)' ;
25+ const MODAL_HORIZONTAL_MARGIN = 24 ;
2526
2627type SupportedOrientation =
2728 | 'portrait'
@@ -178,7 +179,7 @@ const styles = StyleSheet.create({
178179
179180 checkmark : {
180181 fontSize : FONT_SIZE ,
181- color : HIGHLIGHT_COLOR ,
182+ color : '#333' ,
182183 } ,
183184
184185 optionRow : {
@@ -201,7 +202,7 @@ const styles = StyleSheet.create({
201202 doneButtonText : {
202203 textAlign : 'center' ,
203204 fontSize : FONT_SIZE ,
204- color : HIGHLIGHT_COLOR ,
205+ color : '#333' ,
205206 } ,
206207} ) ;
207208
@@ -260,10 +261,11 @@ export const SelectModal = ({
260261 selectedSeparator = ', ' ,
261262 maxSelectedItems,
262263 selectedItemIndicatorStyle,
263- selectedItemIndicatorColor = HIGHLIGHT_COLOR ,
264+ selectedItemIndicatorColor,
264265 doneText = 'Done' ,
265266 onDone,
266267} : SelectModalProps ) => {
268+ const theme = useTheme ( ) ;
267269 const { height : windowHeight } = useWindowDimensions ( ) ;
268270 const [ modalVisible , setModalVisible ] = useState ( false ) ;
269271 const [ selected , setSelected ] = useState < string | string [ ] > (
@@ -294,6 +296,98 @@ export const SelectModal = ({
294296 }
295297 } , [ selectedItems , keyExtractor , multiselect , selected , data , labelExtractor ] ) ;
296298
299+ const themedStyles = useMemo (
300+ ( ) => ( {
301+ modalContent : {
302+ maxHeight : windowHeight * 0.75 ,
303+ marginHorizontal : MODAL_HORIZONTAL_MARGIN ,
304+ backgroundColor : theme . background . content ,
305+ borderColor : theme . appBorderColor ,
306+ borderWidth : 1 ,
307+ borderRadius : 8 ,
308+ overflow : 'hidden' as const ,
309+ boxShadow : `0px 8px 24px 0px ${ theme . color . border } ` ,
310+ elevation : 10 ,
311+ } satisfies ViewStyle ,
312+ optionContainer : {
313+ backgroundColor : theme . background . content ,
314+ borderRadius : 0 ,
315+ borderBottomColor : theme . appBorderColor ,
316+ borderBottomWidth : 1 ,
317+ marginBottom : 0 ,
318+ } satisfies ViewStyle ,
319+ optionStyle : {
320+ minHeight : 34 ,
321+ borderBottomColor : theme . appBorderColor ,
322+ } satisfies ViewStyle ,
323+ selectedOptionStyle : {
324+ backgroundColor : theme . color . secondary ,
325+ } satisfies ViewStyle ,
326+ optionTextStyle : {
327+ color : theme . color . defaultText ,
328+ fontSize : theme . typography . size . s2 ,
329+ } satisfies TextStyle ,
330+ selectedOptionTextStyle : {
331+ color : theme . color . lightest ,
332+ fontWeight : theme . typography . weight . bold ,
333+ } satisfies TextStyle ,
334+ cancelContainer : {
335+ marginTop : 0 ,
336+ padding : 8 ,
337+ backgroundColor : theme . barBg ,
338+ } satisfies ViewStyle ,
339+ doneContainer : {
340+ paddingBottom : 4 ,
341+ } satisfies ViewStyle ,
342+ cancelAfterDoneContainer : {
343+ paddingTop : 4 ,
344+ } satisfies ViewStyle ,
345+ actionButton : {
346+ minHeight : 32 ,
347+ borderRadius : theme . input . borderRadius ,
348+ backgroundColor : theme . button . background ,
349+ borderColor : theme . button . border ,
350+ borderWidth : 1 ,
351+ alignItems : 'center' as const ,
352+ justifyContent : 'center' as const ,
353+ paddingHorizontal : 12 ,
354+ paddingVertical : 0 ,
355+ } satisfies ViewStyle ,
356+ primaryActionButton : {
357+ backgroundColor : theme . color . secondary ,
358+ borderColor : theme . color . secondary ,
359+ } satisfies ViewStyle ,
360+ actionText : {
361+ color : theme . input . color ,
362+ fontSize : theme . typography . size . s1 ,
363+ fontWeight : theme . typography . weight . bold ,
364+ } satisfies TextStyle ,
365+ primaryActionText : {
366+ color : theme . color . lightest ,
367+ } satisfies TextStyle ,
368+ checkmark : {
369+ color : theme . color . lightest ,
370+ } satisfies TextStyle ,
371+ } ) ,
372+ [
373+ theme . appBorderColor ,
374+ theme . background . content ,
375+ theme . barBg ,
376+ theme . button . background ,
377+ theme . button . border ,
378+ theme . color . border ,
379+ theme . color . defaultText ,
380+ theme . color . lightest ,
381+ theme . color . secondary ,
382+ theme . input . borderRadius ,
383+ theme . input . color ,
384+ theme . typography . size . s1 ,
385+ theme . typography . size . s2 ,
386+ theme . typography . weight . bold ,
387+ windowHeight ,
388+ ]
389+ ) ;
390+
297391 const open = useCallback ( ( ) => {
298392 if ( ! disabled ) {
299393 setModalVisible ( true ) ;
@@ -368,34 +462,52 @@ export const SelectModal = ({
368462 const optionKey = keyExtractor ( option ) ;
369463 const isSelected = selectedItemsMap [ optionKey ] ;
370464
371- const content = (
372- < >
373- < Text style = { [ styles . optionTextStyle , optionTextStyleProp ] } { ...optionTextPassThruProps } >
374- { optionLabel }
375- </ Text >
376- < View style = { [ styles . selectedItemIndicator , selectedItemIndicatorStyle ] } >
377- { isSelected && (
378- < Text style = { [ styles . checkmark , { color : selectedItemIndicatorColor } ] } > ✓</ Text >
379- ) }
380- </ View >
381- </ >
382- ) ;
383-
384465 return (
385466 < TouchableOpacity
386467 key = { optionKey }
387468 testID = { `${ optionsTestIDPrefix } -${ optionLabel } ` }
388469 onPress = { ( ) => handleChange ( option ) }
389- activeOpacity = { touchableActiveOpacity }
470+ activeOpacity = { multiselect ? 1 : touchableActiveOpacity }
390471 accessible = { listItemAccessible }
391472 accessibilityLabel = { option . accessibilityLabel }
392473 importantForAccessibility = { isFirstItem ? 'yes' : 'no' }
393474 { ...passThruProps }
394475 >
395476 < View
396- style = { [ styles . optionStyle , optionStyleProp , isLastItem && { borderBottomWidth : 0 } ] }
477+ style = { [
478+ styles . optionStyle ,
479+ themedStyles . optionStyle ,
480+ optionStyleProp ,
481+ isSelected && themedStyles . selectedOptionStyle ,
482+ isLastItem && { borderBottomWidth : 0 } ,
483+ ] }
397484 >
398- < View style = { styles . optionRow } > { content } </ View >
485+ < View style = { styles . optionRow } >
486+ < Text
487+ style = { [
488+ styles . optionTextStyle ,
489+ themedStyles . optionTextStyle ,
490+ optionTextStyleProp ,
491+ isSelected && themedStyles . selectedOptionTextStyle ,
492+ ] }
493+ { ...optionTextPassThruProps }
494+ >
495+ { optionLabel }
496+ </ Text >
497+ < View style = { [ styles . selectedItemIndicator , selectedItemIndicatorStyle ] } >
498+ { isSelected && (
499+ < Text
500+ style = { [
501+ styles . checkmark ,
502+ themedStyles . checkmark ,
503+ selectedItemIndicatorColor && { color : selectedItemIndicatorColor } ,
504+ ] }
505+ >
506+ ✓
507+ </ Text >
508+ ) }
509+ </ View >
510+ </ View >
399511 </ View >
400512 </ TouchableOpacity >
401513 ) ;
@@ -405,6 +517,7 @@ export const SelectModal = ({
405517 labelExtractor ,
406518 handleChange ,
407519 touchableActiveOpacity ,
520+ multiselect ,
408521 listItemAccessible ,
409522 passThruProps ,
410523 optionStyleProp ,
@@ -414,6 +527,7 @@ export const SelectModal = ({
414527 selectedItemsMap ,
415528 selectedItemIndicatorStyle ,
416529 selectedItemIndicatorColor ,
530+ themedStyles ,
417531 ]
418532 ) ;
419533
@@ -461,15 +575,13 @@ export const SelectModal = ({
461575 ...( scrollViewPassThruProps ?. horizontal && { flexDirection : 'row' as const } ) ,
462576 } ;
463577
464- const modalContentStyle = {
465- maxHeight : windowHeight * 0.75 ,
466- } satisfies ViewStyle ;
467-
468578 return (
469579 < OverlayComponent key = { key } { ...overlayProps } >
470580 < View style = { [ styles . overlayStyle , overlayStyleProp ] } >
471- < View style = { modalContentStyle } >
472- < View style = { [ styles . optionContainer , optionContainerStyle ] } >
581+ < View style = { themedStyles . modalContent } >
582+ < View
583+ style = { [ styles . optionContainer , themedStyles . optionContainer , optionContainerStyle ] }
584+ >
473585 { header }
474586 { listType === 'FLATLIST' ? (
475587 < FlatList
@@ -500,27 +612,52 @@ export const SelectModal = ({
500612 </ View >
501613
502614 { multiselect && (
503- < View style = { [ styles . doneContainer ] } >
615+ < View
616+ style = { [
617+ styles . doneContainer ,
618+ themedStyles . cancelContainer ,
619+ themedStyles . doneContainer ,
620+ ] }
621+ >
504622 < TouchableOpacity
505- style = { styles . doneButton }
623+ style = { [
624+ styles . doneButton ,
625+ themedStyles . actionButton ,
626+ themedStyles . primaryActionButton ,
627+ ] }
506628 onPress = { handleDone }
507629 activeOpacity = { touchableActiveOpacity }
508630 >
509- < Text style = { styles . doneButtonText } > { doneText } </ Text >
631+ < Text
632+ style = { [
633+ styles . doneButtonText ,
634+ themedStyles . actionText ,
635+ themedStyles . primaryActionText ,
636+ ] }
637+ >
638+ { doneText }
639+ </ Text >
510640 </ TouchableOpacity >
511641 </ View >
512642 ) }
513643
514- < View style = { [ styles . cancelContainer , cancelContainerStyle ] } >
644+ < View
645+ style = { [
646+ styles . cancelContainer ,
647+ themedStyles . cancelContainer ,
648+ multiselect && themedStyles . cancelAfterDoneContainer ,
649+ cancelContainerStyle ,
650+ ] }
651+ >
515652 < TouchableOpacity
516653 onPress = { close }
517654 activeOpacity = { touchableActiveOpacity }
518655 accessible = { cancelButtonAccessible }
519656 accessibilityLabel = { cancelButtonAccessibilityLabel }
520657 >
521- < View style = { [ styles . cancelStyle , cancelStyleProp ] } >
658+ < View style = { [ styles . cancelStyle , themedStyles . actionButton , cancelStyleProp ] } >
522659 < Text
523- style = { [ styles . cancelTextStyle , cancelTextStyleProp ] }
660+ style = { [ styles . cancelTextStyle , themedStyles . actionText , cancelTextStyleProp ] }
524661 { ...cancelTextPassThruProps }
525662 >
526663 { cancelText }
@@ -560,7 +697,7 @@ export const SelectModal = ({
560697 multiselect ,
561698 handleDone ,
562699 doneText ,
563- windowHeight ,
700+ themedStyles ,
564701 ] ) ;
565702
566703 const renderChildren = useCallback ( ( ) => {
0 commit comments