Skip to content

Commit 8a6bb8e

Browse files
feat(select): 🎨 add select and select option theme (#84)
feat(select): 🎨 add select and select option theme
2 parents 299f3ae + e31d1d0 commit 8a6bb8e

File tree

8 files changed

+684
-37
lines changed

8 files changed

+684
-37
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"icons",
2222
"kodiak",
2323
"utils",
24-
"divider"
24+
"divider",
25+
"select"
2526
],
2627
"git.branchProtection": ["main"]
2728
}

example/src/AppRoot.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
MeterComponentScreen,
1515
ProgressScreen,
1616
RadioScreen,
17+
SelectScreen,
1718
SliderComponentScreen,
1819
SpinnerScreen,
1920
SwitchComponentScreen,
@@ -25,7 +26,12 @@ const Drawer = createDrawerNavigator();
2526

2627
const AppRoot = () => {
2728
return (
28-
<Drawer.Navigator initialRouteName="ButtonScreen">
29+
<Drawer.Navigator initialRouteName="SelectScreen">
30+
<Drawer.Screen
31+
options={{ title: "Select" }}
32+
name="SelectScreen"
33+
component={SelectScreen}
34+
/>
2935
<Drawer.Screen
3036
options={{ title: "Avatar" }}
3137
name="AvatarScreen"
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React from "react";
2+
import {
3+
Box,
4+
ItemData,
5+
Select,
6+
useTheme,
7+
} from "@adaptui/react-native-tailwind";
8+
import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
9+
10+
const options: ItemData[] = [
11+
{
12+
value: "apple",
13+
label: "Apple",
14+
},
15+
{
16+
value: "orange",
17+
label: "Orange",
18+
},
19+
{
20+
value: "watermelon",
21+
label: "Watermelon",
22+
},
23+
{
24+
value: "grapes",
25+
label: "Grapes",
26+
},
27+
{
28+
value: "banana",
29+
label: "Banana",
30+
},
31+
{
32+
value: "blueberry",
33+
label: "Blueberry",
34+
},
35+
{
36+
value: "sapota",
37+
label: "Sapota",
38+
},
39+
{
40+
value: "papaya",
41+
label: "Papaya",
42+
},
43+
{
44+
value: "avocado",
45+
label: "Avocado",
46+
},
47+
{
48+
value: "strawberry",
49+
label: "Strawberry",
50+
},
51+
{
52+
value: "cherry",
53+
label: "Cherry",
54+
},
55+
{
56+
value: "fig",
57+
label: "Fig",
58+
},
59+
{
60+
value: "guava",
61+
label: "Guava",
62+
},
63+
{
64+
value: "mango",
65+
label: "Mango",
66+
},
67+
];
68+
69+
export const SelectScreen = () => {
70+
const tailwind = useTheme();
71+
72+
return (
73+
<Box style={tailwind.style("flex-1 px-2 justify-center bg-white-900")}>
74+
<BottomSheetModalProvider>
75+
<Select
76+
style={tailwind.style("my-1")}
77+
size="sm"
78+
options={options}
79+
placeholder="Select fruit"
80+
/>
81+
<Select
82+
style={tailwind.style("my-1")}
83+
size="md"
84+
options={options}
85+
placeholder="Select fruit"
86+
/>
87+
<Select
88+
style={tailwind.style("my-1")}
89+
size="lg"
90+
options={options}
91+
placeholder="Select fruit"
92+
/>
93+
<Select
94+
style={tailwind.style("my-1")}
95+
size="xl"
96+
options={options}
97+
placeholder="Select fruit"
98+
/>
99+
</BottomSheetModalProvider>
100+
</Box>
101+
);
102+
};

example/src/modules/forms/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from "./CheckboxGroupScreen";
22
export * from "./InputScreen";
33
export * from "./RadioScreen";
4+
export * from "./SelectScreen";
45
export * from "./SliderComponentScreen";
56
export * from "./SwitchComponentScreen";

src/components/select/Select.tsx

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
11
import React, { forwardRef, useCallback, useMemo, useRef } from "react";
2+
import { ListRenderItemInfo, PressableProps } from "react-native";
23
import { 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";
55
import { isUndefined } from "lodash";
66

7-
import { Box, Text, Touchable } from "../../primitives";
7+
import { Text, Touchable } from "../../primitives";
88
import { 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";
1118
import { SelectPrefix } from "./SelectPrefix";
1219
import { SelectSuffix } from "./SelectSuffix";
1320

1421
export type SelectSizes = "sm" | "md" | "lg" | "xl";
1522
export 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

6681
const [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

Comments
 (0)