11import React , { forwardRef , useCallback , useMemo , useRef } from "react" ;
2+ import { ListRenderItemInfo , PressableProps } from "react-native" ;
23import { useControllableState } from "@chakra-ui/hooks" ;
3- import { BottomSheetModal } from "@gorhom/bottom-sheet" ;
4- import { useHover } from "@react-native-aria/interactions" ;
4+ import { BottomSheetFlatList , BottomSheetModal } from "@gorhom/bottom-sheet" ;
55import { isUndefined } from "lodash" ;
66
7- import { Box , Text , Touchable } from "../../primitives" ;
7+ import { Text , Touchable } from "../../primitives" ;
88import { useTheme } from "../../theme" ;
9- import { createComponent , createContext , RenderPropType } from "../../utils" ;
10-
9+ import {
10+ createComponent ,
11+ createContext ,
12+ RenderPropType ,
13+ styleAdapter ,
14+ useOnHover ,
15+ } from "../../utils" ;
16+
17+ import { SelectOption } from "./SelectOption" ;
1118import { SelectPrefix } from "./SelectPrefix" ;
1219import { SelectSuffix } from "./SelectSuffix" ;
1320
1421export type SelectSizes = "sm" | "md" | "lg" | "xl" ;
1522export type SelectVariants = "outline" | "subtle" | "underline" | "ghost" ;
1623
17- type ItemData = { value : string ; disabled : boolean ; label : string } ;
24+ export type ItemData = { value : string ; disabled ?: boolean ; label : string } ;
25+
26+ function keyExtractor ( item : ItemData ) {
27+ return `select-item-${ item . value } ` ;
28+ }
1829
19- export interface SelectProps {
30+ export interface SelectProps extends PressableProps {
2031 /**
2132 * The Select Options
2233 */
@@ -61,6 +72,10 @@ export interface SelectProps {
6172 * True, if the select is disabled.
6273 */
6374 disabled : boolean ;
75+ /**
76+ * Bottomsheet Snap points
77+ */
78+ snapPoints : string [ ] ;
6479}
6580
6681const [ SelectGroupProvider , useSelectGroupContext ] = createContext ( {
@@ -87,6 +102,10 @@ const RNSelect: React.FC<Partial<SelectProps>> = forwardRef<
87102 state,
88103 onStateChange,
89104 placeholder = "Select option" ,
105+ options,
106+ snapPoints : _snapPoints ,
107+ style,
108+ ...otherProps
90109 } = props ;
91110
92111 const [ prefixWidth , setPrefixWidth ] = React . useState ( 0 ) ;
@@ -100,43 +119,68 @@ const RNSelect: React.FC<Partial<SelectProps>> = forwardRef<
100119
101120 const selectRef = useRef ( ) ;
102121
103- const { isHovered, hoverProps } = useHover ( { } , selectRef ) ;
104-
122+ const { onHoverIn, onHoverOut, hovered } = useOnHover ( ) ;
123+ const isHovered = useMemo (
124+ ( ) => ( hovered . value ? true : false ) ,
125+ [ hovered . value ] ,
126+ ) ;
105127 // ref
106128 const bottomSheetModalRef = useRef < BottomSheetModal > ( null ) ;
107129
108130 // variables
109- const snapPoints = useMemo ( ( ) => [ "25%" , "50%" ] , [ ] ) ;
110-
111- const handleSheetChanges = useCallback ( ( index : number ) => {
112- console . log ( "handleSheetChanges" , index ) ;
113- } , [ ] ) ;
131+ const snapPoints = useMemo (
132+ ( ) => ( _snapPoints ? _snapPoints : [ "50%" ] ) ,
133+ [ _snapPoints ] ,
134+ ) ;
114135
115136 // callbacks
116137 const handlePresentModalPress = useCallback ( ( ) => {
117138 bottomSheetModalRef . current ?. present ( ) ;
118139 } , [ ] ) ;
119140
141+ const renderSelectItem = ( { item } : ListRenderItemInfo < ItemData > ) => {
142+ const handleSelectItemPress = ( ) => {
143+ setSelectState ( item . value ) ;
144+ bottomSheetModalRef . current ?. dismiss ( ) ;
145+ } ;
146+ const isSelected = selectState === item . value ;
147+ return (
148+ < SelectOption
149+ key = { `select-item-${ item . value } ` }
150+ value = { item . value }
151+ label = { item . label }
152+ size = { size }
153+ handlePress = { handleSelectItemPress }
154+ isSelected = { isSelected }
155+ />
156+ ) ;
157+ } ;
158+
120159 return (
121160 < SelectGroupProvider value = { { selectState, setSelectState } } >
122161 < Touchable
162+ // Web Callbacks
163+ onHoverIn = { onHoverIn }
164+ onHoverOut = { onHoverOut }
165+ // Web Callbacks
123166 onPress = { handlePresentModalPress }
124- style = { ( { pressed } ) => [
167+ style = { touchState => [
125168 tailwind . style ( [
126169 selectStyle . base . common ,
127170 selectStyle . base . size [ size ] . common ,
128171 ! prefix ? selectStyle . base . size [ size ] . withoutAddon : "" ,
129172 selectStyle . base . variant [ variant ] . common ,
130173 invalid ? selectStyle . base . variant [ variant ] . invalid : "" ,
131174 disabled ? selectStyle . base . variant [ variant ] . disabled : "" ,
132- pressed || isHovered
175+ touchState . pressed || hovered . value
133176 ? selectStyle . base . variant [ variant ] . pressedOrHovered
134177 : "" ,
135178 ] ) ,
179+ styleAdapter ( style , touchState ) ,
136180 ] }
181+ { ...otherProps }
137182 disabled = { disabled }
138183 ref = { selectRef }
139- { ...hoverProps }
140184 >
141185 { ( { pressed } ) => {
142186 return (
@@ -155,7 +199,7 @@ const RNSelect: React.FC<Partial<SelectProps>> = forwardRef<
155199 < Text
156200 style = { tailwind . style ( [
157201 selectStyle . base . text . size [ size ] ,
158- pressed || isHovered
202+ pressed || hovered . value
159203 ? selectStyle . base . text . variant [ variant ] . common
160204 : disabled
161205 ? selectStyle . base . text . variant [ variant ] . disabled
@@ -166,7 +210,10 @@ const RNSelect: React.FC<Partial<SelectProps>> = forwardRef<
166210 `pr-[${ suffixWidth } px]` ,
167211 ] ) }
168212 >
169- { isUndefined ( selectState ) ? placeholder : selectState }
213+ { isUndefined ( selectState )
214+ ? placeholder
215+ : options ?. filter ( item => item . value === selectState ) [ 0 ]
216+ ?. label }
170217 </ Text >
171218 < SelectSuffix
172219 onLayout = { event =>
@@ -186,10 +233,15 @@ const RNSelect: React.FC<Partial<SelectProps>> = forwardRef<
186233 ref = { bottomSheetModalRef }
187234 index = { 0 }
188235 snapPoints = { snapPoints }
189- onChange = { handleSheetChanges }
190236 style = { tailwind . style ( "rounded-t-lg shadow-lg" ) }
191237 >
192- < Box style = { tailwind . style ( "flex-1" ) } > { props . children } </ Box >
238+ < BottomSheetFlatList
239+ data = { options }
240+ keyExtractor = { keyExtractor }
241+ renderItem = { renderSelectItem }
242+ contentContainerStyle = { tailwind . style ( "px-4" ) }
243+ extraData = { selectState }
244+ />
193245 </ BottomSheetModal >
194246 </ SelectGroupProvider >
195247 ) ;
0 commit comments