@urbint/cl 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules +313 -0
- package/.rnstorybook/index.ts +11 -0
- package/.rnstorybook/main.ts +8 -0
- package/.rnstorybook/preview.tsx +14 -0
- package/.rnstorybook/storybook.requires.ts +49 -0
- package/.storybook/main.ts +16 -0
- package/.storybook/preview.ts +32 -0
- package/.storybook/vitest.setup.ts +7 -0
- package/App.tsx +422 -0
- package/README.md +229 -0
- package/app.json +33 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/splash-icon.png +0 -0
- package/babel.config.js +16 -0
- package/docs/components/CodeBlock.tsx +80 -0
- package/docs/components/PropTable.tsx +93 -0
- package/docs/components/Sidebar.tsx +199 -0
- package/docs/components/index.ts +8 -0
- package/docs/data/colorTokens.ts +70 -0
- package/docs/data/componentData.tsx +1685 -0
- package/docs/data/index.ts +7 -0
- package/docs/index.ts +19 -0
- package/docs/navigation.ts +94 -0
- package/docs/pages/ColorsPage.tsx +226 -0
- package/docs/pages/ComponentPage.tsx +235 -0
- package/docs/pages/InstallationPage.tsx +232 -0
- package/docs/pages/IntroductionPage.tsx +163 -0
- package/docs/pages/ThemingPage.tsx +251 -0
- package/docs/pages/index.ts +10 -0
- package/docs/theme.ts +64 -0
- package/docs/types.ts +54 -0
- package/index.ts +8 -0
- package/llms.txt +1893 -0
- package/mcp-config.example.json +10 -0
- package/mcp-server/README.md +192 -0
- package/mcp-server/package-lock.json +1707 -0
- package/mcp-server/package.json +38 -0
- package/mcp-server/src/index.ts +1136 -0
- package/mcp-server/src/registry/components.ts +1446 -0
- package/mcp-server/src/registry/index.ts +3 -0
- package/mcp-server/src/registry/tokens.ts +256 -0
- package/mcp-server/tsconfig.json +19 -0
- package/package.json +92 -0
- package/src/components/Accordion/Accordion.stories.tsx +226 -0
- package/src/components/Accordion/Accordion.tsx +255 -0
- package/src/components/Accordion/index.ts +12 -0
- package/src/components/ActionSheet/ActionSheet.stories.tsx +393 -0
- package/src/components/ActionSheet/ActionSheet.tsx +258 -0
- package/src/components/ActionSheet/index.ts +2 -0
- package/src/components/Alert/Alert.stories.tsx +165 -0
- package/src/components/Alert/Alert.tsx +164 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/AlertDialog/AlertDialog.stories.tsx +330 -0
- package/src/components/AlertDialog/AlertDialog.tsx +234 -0
- package/src/components/AlertDialog/index.ts +2 -0
- package/src/components/Avatar/Avatar.stories.tsx +154 -0
- package/src/components/Avatar/Avatar.tsx +219 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Badge/Badge.stories.tsx +146 -0
- package/src/components/Badge/Badge.tsx +125 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Box/Box.stories.tsx +192 -0
- package/src/components/Box/Box.tsx +184 -0
- package/src/components/Box/index.ts +2 -0
- package/src/components/Button/Button.stories.tsx +157 -0
- package/src/components/Button/Button.tsx +180 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Card/Card.stories.tsx +145 -0
- package/src/components/Card/Card.tsx +169 -0
- package/src/components/Card/index.ts +11 -0
- package/src/components/Center/Center.stories.tsx +215 -0
- package/src/components/Center/Center.tsx +29 -0
- package/src/components/Center/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +94 -0
- package/src/components/Checkbox/Checkbox.tsx +242 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +623 -0
- package/src/components/DatePicker/DatePicker.tsx +1228 -0
- package/src/components/DatePicker/index.ts +8 -0
- package/src/components/Divider/Divider.stories.tsx +224 -0
- package/src/components/Divider/Divider.tsx +73 -0
- package/src/components/Divider/index.ts +2 -0
- package/src/components/Drawer/Drawer.stories.tsx +414 -0
- package/src/components/Drawer/Drawer.tsx +342 -0
- package/src/components/Drawer/index.ts +11 -0
- package/src/components/Fab/Fab.stories.tsx +360 -0
- package/src/components/Fab/Fab.tsx +185 -0
- package/src/components/Fab/index.ts +2 -0
- package/src/components/FormControl/FormControl.stories.tsx +276 -0
- package/src/components/FormControl/FormControl.tsx +185 -0
- package/src/components/FormControl/index.ts +12 -0
- package/src/components/Grid/Grid.stories.tsx +244 -0
- package/src/components/Grid/Grid.tsx +93 -0
- package/src/components/Grid/index.ts +2 -0
- package/src/components/HStack/HStack.stories.tsx +230 -0
- package/src/components/HStack/HStack.tsx +80 -0
- package/src/components/HStack/index.ts +2 -0
- package/src/components/Heading/Heading.stories.tsx +111 -0
- package/src/components/Heading/Heading.tsx +85 -0
- package/src/components/Heading/index.ts +2 -0
- package/src/components/Icon/Icon.stories.tsx +320 -0
- package/src/components/Icon/Icon.tsx +117 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Image/Image.stories.tsx +357 -0
- package/src/components/Image/Image.tsx +168 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/Input/Input.stories.tsx +164 -0
- package/src/components/Input/Input.tsx +274 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Link/Link.stories.tsx +187 -0
- package/src/components/Link/Link.tsx +104 -0
- package/src/components/Link/index.ts +2 -0
- package/src/components/Menu/Menu.stories.tsx +363 -0
- package/src/components/Menu/Menu.tsx +238 -0
- package/src/components/Menu/index.ts +2 -0
- package/src/components/Modal/Modal.stories.tsx +156 -0
- package/src/components/Modal/Modal.tsx +280 -0
- package/src/components/Modal/index.ts +11 -0
- package/src/components/Popover/Popover.stories.tsx +330 -0
- package/src/components/Popover/Popover.tsx +315 -0
- package/src/components/Popover/index.ts +11 -0
- package/src/components/Portal/Portal.stories.tsx +376 -0
- package/src/components/Portal/Portal.tsx +100 -0
- package/src/components/Portal/index.ts +2 -0
- package/src/components/Pressable/Pressable.stories.tsx +338 -0
- package/src/components/Pressable/Pressable.tsx +71 -0
- package/src/components/Pressable/index.ts +2 -0
- package/src/components/Progress/Progress.stories.tsx +131 -0
- package/src/components/Progress/Progress.tsx +219 -0
- package/src/components/Progress/index.ts +2 -0
- package/src/components/Radio/Radio.stories.tsx +101 -0
- package/src/components/Radio/Radio.tsx +234 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/Select/Select.stories.tsx +908 -0
- package/src/components/Select/Select.tsx +659 -0
- package/src/components/Select/index.ts +8 -0
- package/src/components/Skeleton/Skeleton.stories.tsx +154 -0
- package/src/components/Skeleton/Skeleton.tsx +192 -0
- package/src/components/Skeleton/index.ts +8 -0
- package/src/components/Slider/Slider.stories.tsx +363 -0
- package/src/components/Slider/Slider.tsx +209 -0
- package/src/components/Slider/index.ts +2 -0
- package/src/components/Spinner/Spinner.stories.tsx +108 -0
- package/src/components/Spinner/Spinner.tsx +121 -0
- package/src/components/Spinner/index.ts +2 -0
- package/src/components/Switch/Switch.stories.tsx +116 -0
- package/src/components/Switch/Switch.tsx +172 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Table/Table.stories.tsx +417 -0
- package/src/components/Table/Table.tsx +233 -0
- package/src/components/Table/index.ts +2 -0
- package/src/components/Text/Text.stories.tsx +93 -0
- package/src/components/Text/Text.tsx +119 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Textarea/Textarea.stories.tsx +280 -0
- package/src/components/Textarea/Textarea.tsx +212 -0
- package/src/components/Textarea/index.ts +2 -0
- package/src/components/Toast/Toast.stories.tsx +446 -0
- package/src/components/Toast/Toast.tsx +221 -0
- package/src/components/Toast/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +354 -0
- package/src/components/Tooltip/Tooltip.tsx +261 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/VStack/VStack.stories.tsx +183 -0
- package/src/components/VStack/VStack.tsx +76 -0
- package/src/components/VStack/index.ts +2 -0
- package/src/components/index.ts +62 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useControllableState.ts +41 -0
- package/src/hooks/useDisclosure.ts +51 -0
- package/src/index.ts +22 -0
- package/src/stories/Button.stories.tsx +53 -0
- package/src/stories/Button.tsx +101 -0
- package/src/stories/Configure.mdx +364 -0
- package/src/stories/Header.stories.tsx +33 -0
- package/src/stories/Header.tsx +75 -0
- package/src/stories/Page.stories.tsx +25 -0
- package/src/stories/Page.tsx +154 -0
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +1 -0
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +1 -0
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +1 -0
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +1 -0
- package/src/stories/assets/youtube.svg +1 -0
- package/src/styles/index.ts +7 -0
- package/src/styles/tokens.ts +318 -0
- package/src/styles/unistyles.ts +254 -0
- package/src/utils/createContext.tsx +25 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/mergeRefs.ts +21 -0
- package/tsconfig.json +26 -0
- package/urbint-cl-1.0.0.tgz +0 -0
- package/vitest.config.ts +37 -0
- package/vitest.shims.d.ts +1 -0
|
@@ -0,0 +1,908 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { Select, SelectOption } from './Select';
|
|
4
|
+
import { VStack } from '../VStack';
|
|
5
|
+
import { HStack } from '../HStack';
|
|
6
|
+
import { Text } from '../Text';
|
|
7
|
+
import { View, StyleSheet } from 'react-native';
|
|
8
|
+
import { colors, spacing, borderRadius } from '../../styles/tokens';
|
|
9
|
+
|
|
10
|
+
const meta: Meta<typeof Select> = {
|
|
11
|
+
title: 'Forms/Select',
|
|
12
|
+
component: Select,
|
|
13
|
+
argTypes: {
|
|
14
|
+
variant: {
|
|
15
|
+
control: 'select',
|
|
16
|
+
options: ['outline', 'filled'],
|
|
17
|
+
},
|
|
18
|
+
size: {
|
|
19
|
+
control: 'select',
|
|
20
|
+
options: ['sm', 'md', 'lg'],
|
|
21
|
+
},
|
|
22
|
+
isInvalid: { control: 'boolean' },
|
|
23
|
+
isDisabled: { control: 'boolean' },
|
|
24
|
+
isRequired: { control: 'boolean' },
|
|
25
|
+
isMultiple: { control: 'boolean' },
|
|
26
|
+
isSearchable: { control: 'boolean' },
|
|
27
|
+
},
|
|
28
|
+
args: {
|
|
29
|
+
placeholder: 'Select an option',
|
|
30
|
+
variant: 'outline',
|
|
31
|
+
size: 'md',
|
|
32
|
+
options: [
|
|
33
|
+
{ label: 'Option 1', value: '1' },
|
|
34
|
+
{ label: 'Option 2', value: '2' },
|
|
35
|
+
{ label: 'Option 3', value: '3' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export default meta;
|
|
41
|
+
|
|
42
|
+
type Story = StoryObj<typeof Select>;
|
|
43
|
+
|
|
44
|
+
export const Default: Story = {
|
|
45
|
+
render: (args) => (
|
|
46
|
+
<View style={{ width: 300 }}>
|
|
47
|
+
<Select {...args} />
|
|
48
|
+
</View>
|
|
49
|
+
),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const WithLabel: Story = {
|
|
53
|
+
render: () => (
|
|
54
|
+
<VStack space={16}>
|
|
55
|
+
<Select
|
|
56
|
+
label="Country"
|
|
57
|
+
placeholder="Select a country"
|
|
58
|
+
options={[
|
|
59
|
+
{ label: 'United States', value: 'us' },
|
|
60
|
+
{ label: 'Canada', value: 'ca' },
|
|
61
|
+
{ label: 'United Kingdom', value: 'uk' },
|
|
62
|
+
{ label: 'Australia', value: 'au' },
|
|
63
|
+
]}
|
|
64
|
+
/>
|
|
65
|
+
<Select
|
|
66
|
+
label="Language"
|
|
67
|
+
placeholder="Select a language"
|
|
68
|
+
helperText="Choose your preferred language"
|
|
69
|
+
options={[
|
|
70
|
+
{ label: 'English', value: 'en' },
|
|
71
|
+
{ label: 'Spanish', value: 'es' },
|
|
72
|
+
{ label: 'French', value: 'fr' },
|
|
73
|
+
{ label: 'German', value: 'de' },
|
|
74
|
+
]}
|
|
75
|
+
/>
|
|
76
|
+
</VStack>
|
|
77
|
+
),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const Variants: Story = {
|
|
81
|
+
render: () => (
|
|
82
|
+
<VStack space={16}>
|
|
83
|
+
<Text weight="semiBold">Select Variants</Text>
|
|
84
|
+
<Select
|
|
85
|
+
label="Outline"
|
|
86
|
+
variant="outline"
|
|
87
|
+
placeholder="Select..."
|
|
88
|
+
options={[
|
|
89
|
+
{ label: 'Option A', value: 'a' },
|
|
90
|
+
{ label: 'Option B', value: 'b' },
|
|
91
|
+
]}
|
|
92
|
+
/>
|
|
93
|
+
<Select
|
|
94
|
+
label="Filled"
|
|
95
|
+
variant="filled"
|
|
96
|
+
placeholder="Select..."
|
|
97
|
+
options={[
|
|
98
|
+
{ label: 'Option A', value: 'a' },
|
|
99
|
+
{ label: 'Option B', value: 'b' },
|
|
100
|
+
]}
|
|
101
|
+
/>
|
|
102
|
+
</VStack>
|
|
103
|
+
),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const Sizes: Story = {
|
|
107
|
+
render: () => (
|
|
108
|
+
<VStack space={16}>
|
|
109
|
+
<Text weight="semiBold">Select Sizes</Text>
|
|
110
|
+
<Select
|
|
111
|
+
label="Small"
|
|
112
|
+
size="sm"
|
|
113
|
+
placeholder="Small select..."
|
|
114
|
+
options={[
|
|
115
|
+
{ label: 'Small Option', value: 'sm' },
|
|
116
|
+
]}
|
|
117
|
+
/>
|
|
118
|
+
<Select
|
|
119
|
+
label="Medium"
|
|
120
|
+
size="md"
|
|
121
|
+
placeholder="Medium select..."
|
|
122
|
+
options={[
|
|
123
|
+
{ label: 'Medium Option', value: 'md' },
|
|
124
|
+
]}
|
|
125
|
+
/>
|
|
126
|
+
<Select
|
|
127
|
+
label="Large"
|
|
128
|
+
size="lg"
|
|
129
|
+
placeholder="Large select..."
|
|
130
|
+
options={[
|
|
131
|
+
{ label: 'Large Option', value: 'lg' },
|
|
132
|
+
]}
|
|
133
|
+
/>
|
|
134
|
+
</VStack>
|
|
135
|
+
),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const States: Story = {
|
|
139
|
+
render: () => (
|
|
140
|
+
<VStack space={16}>
|
|
141
|
+
<Text weight="semiBold">Select States</Text>
|
|
142
|
+
<Select
|
|
143
|
+
label="Normal"
|
|
144
|
+
placeholder="Select..."
|
|
145
|
+
options={[
|
|
146
|
+
{ label: 'Option 1', value: '1' },
|
|
147
|
+
{ label: 'Option 2', value: '2' },
|
|
148
|
+
]}
|
|
149
|
+
/>
|
|
150
|
+
<Select
|
|
151
|
+
label="With Default Value"
|
|
152
|
+
defaultValue="2"
|
|
153
|
+
options={[
|
|
154
|
+
{ label: 'Option 1', value: '1' },
|
|
155
|
+
{ label: 'Option 2', value: '2' },
|
|
156
|
+
]}
|
|
157
|
+
/>
|
|
158
|
+
<Select
|
|
159
|
+
label="Disabled"
|
|
160
|
+
placeholder="Select..."
|
|
161
|
+
isDisabled
|
|
162
|
+
options={[
|
|
163
|
+
{ label: 'Option 1', value: '1' },
|
|
164
|
+
{ label: 'Option 2', value: '2' },
|
|
165
|
+
]}
|
|
166
|
+
/>
|
|
167
|
+
<Select
|
|
168
|
+
label="Required"
|
|
169
|
+
placeholder="Select..."
|
|
170
|
+
isRequired
|
|
171
|
+
options={[
|
|
172
|
+
{ label: 'Option 1', value: '1' },
|
|
173
|
+
{ label: 'Option 2', value: '2' },
|
|
174
|
+
]}
|
|
175
|
+
/>
|
|
176
|
+
</VStack>
|
|
177
|
+
),
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
export const Validation: Story = {
|
|
181
|
+
render: () => (
|
|
182
|
+
<VStack space={16}>
|
|
183
|
+
<Text weight="semiBold">Validation States</Text>
|
|
184
|
+
<Select
|
|
185
|
+
label="Valid Selection"
|
|
186
|
+
defaultValue="approved"
|
|
187
|
+
helperText="Your selection has been saved"
|
|
188
|
+
options={[
|
|
189
|
+
{ label: 'Approved', value: 'approved' },
|
|
190
|
+
{ label: 'Pending', value: 'pending' },
|
|
191
|
+
]}
|
|
192
|
+
/>
|
|
193
|
+
<Select
|
|
194
|
+
label="Invalid Selection"
|
|
195
|
+
placeholder="Select..."
|
|
196
|
+
isInvalid
|
|
197
|
+
errorMessage="Please select an option"
|
|
198
|
+
options={[
|
|
199
|
+
{ label: 'Option 1', value: '1' },
|
|
200
|
+
{ label: 'Option 2', value: '2' },
|
|
201
|
+
]}
|
|
202
|
+
/>
|
|
203
|
+
</VStack>
|
|
204
|
+
),
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const WithDisabledOptions: Story = {
|
|
208
|
+
render: () => (
|
|
209
|
+
<VStack space={16}>
|
|
210
|
+
<Text weight="semiBold">Disabled Options</Text>
|
|
211
|
+
<Select
|
|
212
|
+
label="Plan"
|
|
213
|
+
placeholder="Select a plan"
|
|
214
|
+
options={[
|
|
215
|
+
{ label: 'Free', value: 'free' },
|
|
216
|
+
{ label: 'Pro', value: 'pro' },
|
|
217
|
+
{ label: 'Enterprise', value: 'enterprise', disabled: true },
|
|
218
|
+
]}
|
|
219
|
+
helperText="Enterprise plan is currently unavailable"
|
|
220
|
+
/>
|
|
221
|
+
</VStack>
|
|
222
|
+
),
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export const ManyOptions: Story = {
|
|
226
|
+
render: () => (
|
|
227
|
+
<VStack space={16}>
|
|
228
|
+
<Text weight="semiBold">Many Options</Text>
|
|
229
|
+
<Select
|
|
230
|
+
label="State/Province"
|
|
231
|
+
placeholder="Select a state"
|
|
232
|
+
options={[
|
|
233
|
+
{ label: 'Alabama', value: 'AL' },
|
|
234
|
+
{ label: 'Alaska', value: 'AK' },
|
|
235
|
+
{ label: 'Arizona', value: 'AZ' },
|
|
236
|
+
{ label: 'Arkansas', value: 'AR' },
|
|
237
|
+
{ label: 'California', value: 'CA' },
|
|
238
|
+
{ label: 'Colorado', value: 'CO' },
|
|
239
|
+
{ label: 'Connecticut', value: 'CT' },
|
|
240
|
+
{ label: 'Delaware', value: 'DE' },
|
|
241
|
+
{ label: 'Florida', value: 'FL' },
|
|
242
|
+
{ label: 'Georgia', value: 'GA' },
|
|
243
|
+
{ label: 'Hawaii', value: 'HI' },
|
|
244
|
+
{ label: 'Idaho', value: 'ID' },
|
|
245
|
+
{ label: 'Illinois', value: 'IL' },
|
|
246
|
+
{ label: 'Indiana', value: 'IN' },
|
|
247
|
+
{ label: 'Iowa', value: 'IA' },
|
|
248
|
+
]}
|
|
249
|
+
/>
|
|
250
|
+
</VStack>
|
|
251
|
+
),
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// ============================================================================
|
|
255
|
+
// SEARCHABLE SELECT STORIES
|
|
256
|
+
// ============================================================================
|
|
257
|
+
|
|
258
|
+
const countryOptions = [
|
|
259
|
+
{ label: 'United States', value: 'us' },
|
|
260
|
+
{ label: 'United Kingdom', value: 'uk' },
|
|
261
|
+
{ label: 'Canada', value: 'ca' },
|
|
262
|
+
{ label: 'Australia', value: 'au' },
|
|
263
|
+
{ label: 'Germany', value: 'de' },
|
|
264
|
+
{ label: 'France', value: 'fr' },
|
|
265
|
+
{ label: 'Spain', value: 'es' },
|
|
266
|
+
{ label: 'Italy', value: 'it' },
|
|
267
|
+
{ label: 'Japan', value: 'jp' },
|
|
268
|
+
{ label: 'China', value: 'cn' },
|
|
269
|
+
{ label: 'India', value: 'in' },
|
|
270
|
+
{ label: 'Brazil', value: 'br' },
|
|
271
|
+
{ label: 'Mexico', value: 'mx' },
|
|
272
|
+
{ label: 'Argentina', value: 'ar' },
|
|
273
|
+
{ label: 'South Korea', value: 'kr' },
|
|
274
|
+
{ label: 'Netherlands', value: 'nl' },
|
|
275
|
+
{ label: 'Sweden', value: 'se' },
|
|
276
|
+
{ label: 'Norway', value: 'no' },
|
|
277
|
+
{ label: 'Denmark', value: 'dk' },
|
|
278
|
+
{ label: 'Finland', value: 'fi' },
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
export const Searchable: Story = {
|
|
282
|
+
render: () => (
|
|
283
|
+
<VStack space={16}>
|
|
284
|
+
<Text weight="semiBold">Searchable Select</Text>
|
|
285
|
+
<Text size="caption" color="secondary">
|
|
286
|
+
Type to filter options. Search is case-insensitive.
|
|
287
|
+
</Text>
|
|
288
|
+
<Select
|
|
289
|
+
label="Country"
|
|
290
|
+
placeholder="Select a country..."
|
|
291
|
+
isSearchable
|
|
292
|
+
searchPlaceholder="Search countries..."
|
|
293
|
+
options={countryOptions}
|
|
294
|
+
helperText="Start typing to filter the list"
|
|
295
|
+
/>
|
|
296
|
+
</VStack>
|
|
297
|
+
),
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
export const SearchableWithDefaultValue: Story = {
|
|
301
|
+
render: () => (
|
|
302
|
+
<VStack space={16}>
|
|
303
|
+
<Text weight="semiBold">Searchable with Default Value</Text>
|
|
304
|
+
<Select
|
|
305
|
+
label="Country"
|
|
306
|
+
placeholder="Select a country..."
|
|
307
|
+
isSearchable
|
|
308
|
+
defaultValue="us"
|
|
309
|
+
options={countryOptions}
|
|
310
|
+
/>
|
|
311
|
+
</VStack>
|
|
312
|
+
),
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
export const SearchableMultiSelect: Story = {
|
|
316
|
+
render: () => (
|
|
317
|
+
<VStack space={16}>
|
|
318
|
+
<Text weight="semiBold">Searchable Multi-Select</Text>
|
|
319
|
+
<Text size="caption" color="secondary">
|
|
320
|
+
Combine search with multi-select for powerful filtering.
|
|
321
|
+
</Text>
|
|
322
|
+
<Select
|
|
323
|
+
label="Countries"
|
|
324
|
+
placeholder="Select countries..."
|
|
325
|
+
isSearchable
|
|
326
|
+
isMultiple
|
|
327
|
+
searchPlaceholder="Search countries..."
|
|
328
|
+
options={countryOptions}
|
|
329
|
+
helperText="Select multiple countries"
|
|
330
|
+
/>
|
|
331
|
+
</VStack>
|
|
332
|
+
),
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
export const SearchableMultiSelectWithDefaults: Story = {
|
|
336
|
+
render: () => (
|
|
337
|
+
<VStack space={16}>
|
|
338
|
+
<Text weight="semiBold">Searchable Multi-Select with Defaults</Text>
|
|
339
|
+
<Select
|
|
340
|
+
label="Countries"
|
|
341
|
+
placeholder="Select countries..."
|
|
342
|
+
isSearchable
|
|
343
|
+
isMultiple
|
|
344
|
+
defaultValue={['us', 'uk', 'ca']}
|
|
345
|
+
options={countryOptions}
|
|
346
|
+
helperText="Pre-selected: United States, United Kingdom, Canada"
|
|
347
|
+
/>
|
|
348
|
+
</VStack>
|
|
349
|
+
),
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const technologyOptions = [
|
|
353
|
+
{ label: 'React', value: 'react', category: 'frontend' },
|
|
354
|
+
{ label: 'Vue.js', value: 'vue', category: 'frontend' },
|
|
355
|
+
{ label: 'Angular', value: 'angular', category: 'frontend' },
|
|
356
|
+
{ label: 'Svelte', value: 'svelte', category: 'frontend' },
|
|
357
|
+
{ label: 'Node.js', value: 'nodejs', category: 'backend' },
|
|
358
|
+
{ label: 'Python', value: 'python', category: 'backend' },
|
|
359
|
+
{ label: 'Go', value: 'go', category: 'backend' },
|
|
360
|
+
{ label: 'Rust', value: 'rust', category: 'backend' },
|
|
361
|
+
{ label: 'PostgreSQL', value: 'postgres', category: 'database' },
|
|
362
|
+
{ label: 'MongoDB', value: 'mongodb', category: 'database' },
|
|
363
|
+
{ label: 'Redis', value: 'redis', category: 'database' },
|
|
364
|
+
{ label: 'MySQL', value: 'mysql', category: 'database' },
|
|
365
|
+
{ label: 'Docker', value: 'docker', category: 'devops' },
|
|
366
|
+
{ label: 'Kubernetes', value: 'kubernetes', category: 'devops' },
|
|
367
|
+
{ label: 'AWS', value: 'aws', category: 'cloud' },
|
|
368
|
+
{ label: 'Google Cloud', value: 'gcp', category: 'cloud' },
|
|
369
|
+
{ label: 'Azure', value: 'azure', category: 'cloud' },
|
|
370
|
+
];
|
|
371
|
+
|
|
372
|
+
export const SearchableWithCustomFilter: Story = {
|
|
373
|
+
render: () => (
|
|
374
|
+
<VStack space={16}>
|
|
375
|
+
<Text weight="semiBold">Custom Filter Function</Text>
|
|
376
|
+
<Text size="caption" color="secondary">
|
|
377
|
+
Search by label or category (e.g., try "frontend", "backend", "database")
|
|
378
|
+
</Text>
|
|
379
|
+
<Select
|
|
380
|
+
label="Technologies"
|
|
381
|
+
placeholder="Search technologies..."
|
|
382
|
+
isSearchable
|
|
383
|
+
isMultiple
|
|
384
|
+
searchPlaceholder="Search by name or category..."
|
|
385
|
+
options={technologyOptions}
|
|
386
|
+
filterOption={(option, query) => {
|
|
387
|
+
const searchLower = query.toLowerCase();
|
|
388
|
+
return (
|
|
389
|
+
option.label.toLowerCase().includes(searchLower) ||
|
|
390
|
+
option.category?.toLowerCase().includes(searchLower)
|
|
391
|
+
);
|
|
392
|
+
}}
|
|
393
|
+
helperText="Try searching 'frontend' or 'database'"
|
|
394
|
+
/>
|
|
395
|
+
</VStack>
|
|
396
|
+
),
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
export const SearchableNoResults: Story = {
|
|
400
|
+
render: () => (
|
|
401
|
+
<VStack space={16}>
|
|
402
|
+
<Text weight="semiBold">Custom No Results Text</Text>
|
|
403
|
+
<Text size="caption" color="secondary">
|
|
404
|
+
Customize the message shown when no options match the search.
|
|
405
|
+
</Text>
|
|
406
|
+
<Select
|
|
407
|
+
label="Country"
|
|
408
|
+
placeholder="Select a country..."
|
|
409
|
+
isSearchable
|
|
410
|
+
noResultsText="No countries match your search"
|
|
411
|
+
options={[
|
|
412
|
+
{ label: 'United States', value: 'us' },
|
|
413
|
+
{ label: 'Canada', value: 'ca' },
|
|
414
|
+
{ label: 'Mexico', value: 'mx' },
|
|
415
|
+
]}
|
|
416
|
+
helperText='Try typing "xyz" to see the no results message'
|
|
417
|
+
/>
|
|
418
|
+
</VStack>
|
|
419
|
+
),
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
export const SearchableControlled: Story = {
|
|
423
|
+
render: () => {
|
|
424
|
+
const [selected, setSelected] = useState<string>('');
|
|
425
|
+
|
|
426
|
+
return (
|
|
427
|
+
<VStack space={16}>
|
|
428
|
+
<Text weight="semiBold">Controlled Searchable Select</Text>
|
|
429
|
+
<Select
|
|
430
|
+
label="Country"
|
|
431
|
+
placeholder="Select a country..."
|
|
432
|
+
isSearchable
|
|
433
|
+
value={selected}
|
|
434
|
+
onChange={(value) => setSelected(value as string)}
|
|
435
|
+
options={countryOptions}
|
|
436
|
+
/>
|
|
437
|
+
<Text size="caption" color="secondary">
|
|
438
|
+
Selected: {selected || 'None'}
|
|
439
|
+
</Text>
|
|
440
|
+
</VStack>
|
|
441
|
+
);
|
|
442
|
+
},
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
export const SearchableSizes: Story = {
|
|
446
|
+
render: () => (
|
|
447
|
+
<VStack space={16}>
|
|
448
|
+
<Text weight="semiBold">Searchable Select Sizes</Text>
|
|
449
|
+
<Select
|
|
450
|
+
label="Small"
|
|
451
|
+
size="sm"
|
|
452
|
+
isSearchable
|
|
453
|
+
placeholder="Search..."
|
|
454
|
+
options={countryOptions.slice(0, 8)}
|
|
455
|
+
/>
|
|
456
|
+
<Select
|
|
457
|
+
label="Medium"
|
|
458
|
+
size="md"
|
|
459
|
+
isSearchable
|
|
460
|
+
placeholder="Search..."
|
|
461
|
+
options={countryOptions.slice(0, 8)}
|
|
462
|
+
/>
|
|
463
|
+
<Select
|
|
464
|
+
label="Large"
|
|
465
|
+
size="lg"
|
|
466
|
+
isSearchable
|
|
467
|
+
placeholder="Search..."
|
|
468
|
+
options={countryOptions.slice(0, 8)}
|
|
469
|
+
/>
|
|
470
|
+
</VStack>
|
|
471
|
+
),
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// ============================================================================
|
|
475
|
+
// MULTISELECT STORIES
|
|
476
|
+
// ============================================================================
|
|
477
|
+
|
|
478
|
+
export const MultiSelect: Story = {
|
|
479
|
+
render: () => (
|
|
480
|
+
<VStack space={16}>
|
|
481
|
+
<Text weight="semiBold">Multi-Select</Text>
|
|
482
|
+
<Select
|
|
483
|
+
label="Dropdown Test"
|
|
484
|
+
placeholder="Select options..."
|
|
485
|
+
isMultiple
|
|
486
|
+
options={[
|
|
487
|
+
{ label: 'Option 1', value: '1' },
|
|
488
|
+
{ label: 'Option 2', value: '2' },
|
|
489
|
+
{ label: 'Option 3', value: '3' },
|
|
490
|
+
{ label: 'Option 4', value: '4' },
|
|
491
|
+
{ label: 'Option 5', value: '5' },
|
|
492
|
+
{ label: 'Other', value: 'other' },
|
|
493
|
+
]}
|
|
494
|
+
helperText="You can select multiple options"
|
|
495
|
+
/>
|
|
496
|
+
</VStack>
|
|
497
|
+
),
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
export const MultiSelectWithDefaultValues: Story = {
|
|
501
|
+
render: () => (
|
|
502
|
+
<VStack space={16}>
|
|
503
|
+
<Text weight="semiBold">Multi-Select with Default Values</Text>
|
|
504
|
+
<Select
|
|
505
|
+
label="Select Skills"
|
|
506
|
+
placeholder="Choose your skills..."
|
|
507
|
+
isMultiple
|
|
508
|
+
defaultValue={['react', 'typescript', 'nodejs']}
|
|
509
|
+
options={[
|
|
510
|
+
{ label: 'React', value: 'react' },
|
|
511
|
+
{ label: 'TypeScript', value: 'typescript' },
|
|
512
|
+
{ label: 'Node.js', value: 'nodejs' },
|
|
513
|
+
{ label: 'Python', value: 'python' },
|
|
514
|
+
{ label: 'Go', value: 'go' },
|
|
515
|
+
{ label: 'Rust', value: 'rust' },
|
|
516
|
+
]}
|
|
517
|
+
helperText="Pre-selected skills: React, TypeScript, Node.js"
|
|
518
|
+
/>
|
|
519
|
+
</VStack>
|
|
520
|
+
),
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
export const MultiSelectControlled: Story = {
|
|
524
|
+
render: () => {
|
|
525
|
+
const [selectedValues, setSelectedValues] = useState<string[]>(['frontend', 'backend']);
|
|
526
|
+
|
|
527
|
+
return (
|
|
528
|
+
<VStack space={16}>
|
|
529
|
+
<Text weight="semiBold">Controlled Multi-Select</Text>
|
|
530
|
+
<Select
|
|
531
|
+
label="Team Roles"
|
|
532
|
+
placeholder="Assign roles..."
|
|
533
|
+
isMultiple
|
|
534
|
+
value={selectedValues}
|
|
535
|
+
onChange={(value) => setSelectedValues(value as string[])}
|
|
536
|
+
options={[
|
|
537
|
+
{ label: 'Frontend', value: 'frontend' },
|
|
538
|
+
{ label: 'Backend', value: 'backend' },
|
|
539
|
+
{ label: 'DevOps', value: 'devops' },
|
|
540
|
+
{ label: 'Design', value: 'design' },
|
|
541
|
+
{ label: 'QA', value: 'qa' },
|
|
542
|
+
{ label: 'Product', value: 'product' },
|
|
543
|
+
]}
|
|
544
|
+
/>
|
|
545
|
+
<Text size="caption" color="secondary">
|
|
546
|
+
Selected: {selectedValues.join(', ') || 'None'}
|
|
547
|
+
</Text>
|
|
548
|
+
</VStack>
|
|
549
|
+
);
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
export const MultiSelectWithDisabledOptions: Story = {
|
|
554
|
+
render: () => (
|
|
555
|
+
<VStack space={16}>
|
|
556
|
+
<Text weight="semiBold">Multi-Select with Disabled Options</Text>
|
|
557
|
+
<Select
|
|
558
|
+
label="Subscription Features"
|
|
559
|
+
placeholder="Choose features..."
|
|
560
|
+
isMultiple
|
|
561
|
+
defaultValue={['basic']}
|
|
562
|
+
options={[
|
|
563
|
+
{ label: 'Basic Analytics', value: 'basic' },
|
|
564
|
+
{ label: 'Advanced Analytics', value: 'advanced' },
|
|
565
|
+
{ label: 'Custom Reports', value: 'reports', disabled: true },
|
|
566
|
+
{ label: 'API Access', value: 'api' },
|
|
567
|
+
{ label: 'Priority Support', value: 'support', disabled: true },
|
|
568
|
+
{ label: 'Team Collaboration', value: 'team' },
|
|
569
|
+
]}
|
|
570
|
+
helperText="Some features require a higher subscription tier"
|
|
571
|
+
/>
|
|
572
|
+
</VStack>
|
|
573
|
+
),
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
export const MultiSelectSizes: Story = {
|
|
577
|
+
render: () => (
|
|
578
|
+
<VStack space={16}>
|
|
579
|
+
<Text weight="semiBold">Multi-Select Sizes</Text>
|
|
580
|
+
<Select
|
|
581
|
+
label="Small"
|
|
582
|
+
size="sm"
|
|
583
|
+
isMultiple
|
|
584
|
+
placeholder="Select categories..."
|
|
585
|
+
defaultValue={['tech']}
|
|
586
|
+
options={[
|
|
587
|
+
{ label: 'Technology', value: 'tech' },
|
|
588
|
+
{ label: 'Business', value: 'business' },
|
|
589
|
+
{ label: 'Design', value: 'design' },
|
|
590
|
+
]}
|
|
591
|
+
/>
|
|
592
|
+
<Select
|
|
593
|
+
label="Medium"
|
|
594
|
+
size="md"
|
|
595
|
+
isMultiple
|
|
596
|
+
placeholder="Select categories..."
|
|
597
|
+
defaultValue={['tech', 'design']}
|
|
598
|
+
options={[
|
|
599
|
+
{ label: 'Technology', value: 'tech' },
|
|
600
|
+
{ label: 'Business', value: 'business' },
|
|
601
|
+
{ label: 'Design', value: 'design' },
|
|
602
|
+
]}
|
|
603
|
+
/>
|
|
604
|
+
<Select
|
|
605
|
+
label="Large"
|
|
606
|
+
size="lg"
|
|
607
|
+
isMultiple
|
|
608
|
+
placeholder="Select categories..."
|
|
609
|
+
defaultValue={['tech', 'business', 'design']}
|
|
610
|
+
options={[
|
|
611
|
+
{ label: 'Technology', value: 'tech' },
|
|
612
|
+
{ label: 'Business', value: 'business' },
|
|
613
|
+
{ label: 'Design', value: 'design' },
|
|
614
|
+
]}
|
|
615
|
+
/>
|
|
616
|
+
</VStack>
|
|
617
|
+
),
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
export const MultiSelectValidation: Story = {
|
|
621
|
+
render: () => (
|
|
622
|
+
<VStack space={16}>
|
|
623
|
+
<Text weight="semiBold">Multi-Select Validation</Text>
|
|
624
|
+
<Select
|
|
625
|
+
label="Required Tags"
|
|
626
|
+
placeholder="Select at least one tag..."
|
|
627
|
+
isMultiple
|
|
628
|
+
isRequired
|
|
629
|
+
isInvalid
|
|
630
|
+
errorMessage="Please select at least one tag"
|
|
631
|
+
options={[
|
|
632
|
+
{ label: 'Important', value: 'important' },
|
|
633
|
+
{ label: 'Urgent', value: 'urgent' },
|
|
634
|
+
{ label: 'Review', value: 'review' },
|
|
635
|
+
{ label: 'Follow-up', value: 'followup' },
|
|
636
|
+
]}
|
|
637
|
+
/>
|
|
638
|
+
<Select
|
|
639
|
+
label="Selected Tags"
|
|
640
|
+
placeholder="Select tags..."
|
|
641
|
+
isMultiple
|
|
642
|
+
defaultValue={['important', 'urgent']}
|
|
643
|
+
helperText="Tags applied successfully"
|
|
644
|
+
options={[
|
|
645
|
+
{ label: 'Important', value: 'important' },
|
|
646
|
+
{ label: 'Urgent', value: 'urgent' },
|
|
647
|
+
{ label: 'Review', value: 'review' },
|
|
648
|
+
{ label: 'Follow-up', value: 'followup' },
|
|
649
|
+
]}
|
|
650
|
+
/>
|
|
651
|
+
</VStack>
|
|
652
|
+
),
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// ============================================================================
|
|
656
|
+
// FORM EXAMPLES
|
|
657
|
+
// ============================================================================
|
|
658
|
+
|
|
659
|
+
export const FormExample: Story = {
|
|
660
|
+
render: () => (
|
|
661
|
+
<VStack space={16}>
|
|
662
|
+
<Text weight="semiBold">Shipping Information</Text>
|
|
663
|
+
<VStack space={12}>
|
|
664
|
+
<Select
|
|
665
|
+
label="Country"
|
|
666
|
+
placeholder="Select country"
|
|
667
|
+
isRequired
|
|
668
|
+
isSearchable
|
|
669
|
+
options={countryOptions}
|
|
670
|
+
/>
|
|
671
|
+
<Select
|
|
672
|
+
label="Shipping Method"
|
|
673
|
+
placeholder="Select method"
|
|
674
|
+
isRequired
|
|
675
|
+
options={[
|
|
676
|
+
{ label: 'Standard (5-7 days)', value: 'standard' },
|
|
677
|
+
{ label: 'Express (2-3 days)', value: 'express' },
|
|
678
|
+
{ label: 'Next Day', value: 'next_day' },
|
|
679
|
+
]}
|
|
680
|
+
helperText="Delivery times are estimates"
|
|
681
|
+
/>
|
|
682
|
+
<Select
|
|
683
|
+
label="Package Size"
|
|
684
|
+
placeholder="Select size"
|
|
685
|
+
options={[
|
|
686
|
+
{ label: 'Small (up to 1 lb)', value: 'small' },
|
|
687
|
+
{ label: 'Medium (1-5 lbs)', value: 'medium' },
|
|
688
|
+
{ label: 'Large (5-20 lbs)', value: 'large' },
|
|
689
|
+
{ label: 'Extra Large (20+ lbs)', value: 'xl' },
|
|
690
|
+
]}
|
|
691
|
+
/>
|
|
692
|
+
</VStack>
|
|
693
|
+
</VStack>
|
|
694
|
+
),
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
export const MultiSelectFormExample: Story = {
|
|
698
|
+
render: () => (
|
|
699
|
+
<VStack space={16}>
|
|
700
|
+
<Text weight="semiBold">Project Settings</Text>
|
|
701
|
+
<VStack space={12}>
|
|
702
|
+
<Select
|
|
703
|
+
label="Project Type"
|
|
704
|
+
placeholder="Select type"
|
|
705
|
+
isRequired
|
|
706
|
+
options={[
|
|
707
|
+
{ label: 'Web Application', value: 'web' },
|
|
708
|
+
{ label: 'Mobile App', value: 'mobile' },
|
|
709
|
+
{ label: 'API Service', value: 'api' },
|
|
710
|
+
{ label: 'Desktop App', value: 'desktop' },
|
|
711
|
+
]}
|
|
712
|
+
/>
|
|
713
|
+
<Select
|
|
714
|
+
label="Technologies"
|
|
715
|
+
placeholder="Select technologies..."
|
|
716
|
+
isMultiple
|
|
717
|
+
isSearchable
|
|
718
|
+
isRequired
|
|
719
|
+
options={technologyOptions}
|
|
720
|
+
helperText="Select all technologies used in this project"
|
|
721
|
+
/>
|
|
722
|
+
<Select
|
|
723
|
+
label="Team Members"
|
|
724
|
+
placeholder="Assign team members..."
|
|
725
|
+
isMultiple
|
|
726
|
+
isSearchable
|
|
727
|
+
options={[
|
|
728
|
+
{ label: 'John Doe', value: 'john' },
|
|
729
|
+
{ label: 'Jane Smith', value: 'jane' },
|
|
730
|
+
{ label: 'Bob Johnson', value: 'bob' },
|
|
731
|
+
{ label: 'Alice Williams', value: 'alice' },
|
|
732
|
+
{ label: 'Charlie Brown', value: 'charlie' },
|
|
733
|
+
]}
|
|
734
|
+
helperText="Optional: Assign team members to this project"
|
|
735
|
+
/>
|
|
736
|
+
<Select
|
|
737
|
+
label="Priority"
|
|
738
|
+
placeholder="Select priority"
|
|
739
|
+
defaultValue="medium"
|
|
740
|
+
options={[
|
|
741
|
+
{ label: 'Low', value: 'low' },
|
|
742
|
+
{ label: 'Medium', value: 'medium' },
|
|
743
|
+
{ label: 'High', value: 'high' },
|
|
744
|
+
{ label: 'Critical', value: 'critical' },
|
|
745
|
+
]}
|
|
746
|
+
/>
|
|
747
|
+
</VStack>
|
|
748
|
+
</VStack>
|
|
749
|
+
),
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
// ============================================================================
|
|
753
|
+
// CUSTOM RENDERING
|
|
754
|
+
// ============================================================================
|
|
755
|
+
|
|
756
|
+
const colorOptions = [
|
|
757
|
+
{ label: 'Red', value: 'red', color: '#EF4444' },
|
|
758
|
+
{ label: 'Green', value: 'green', color: '#22C55E' },
|
|
759
|
+
{ label: 'Blue', value: 'blue', color: '#3B82F6' },
|
|
760
|
+
{ label: 'Yellow', value: 'yellow', color: '#EAB308' },
|
|
761
|
+
{ label: 'Purple', value: 'purple', color: '#A855F7' },
|
|
762
|
+
{ label: 'Pink', value: 'pink', color: '#EC4899' },
|
|
763
|
+
];
|
|
764
|
+
|
|
765
|
+
const customStyles = StyleSheet.create({
|
|
766
|
+
colorSwatch: {
|
|
767
|
+
width: 16,
|
|
768
|
+
height: 16,
|
|
769
|
+
borderRadius: 4,
|
|
770
|
+
marginRight: 8,
|
|
771
|
+
},
|
|
772
|
+
optionRow: {
|
|
773
|
+
flexDirection: 'row',
|
|
774
|
+
alignItems: 'center',
|
|
775
|
+
flex: 1,
|
|
776
|
+
},
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
export const CustomRendering: Story = {
|
|
780
|
+
render: () => (
|
|
781
|
+
<VStack space={16}>
|
|
782
|
+
<Text weight="semiBold">Custom Option Rendering</Text>
|
|
783
|
+
<Select
|
|
784
|
+
label="Select Color"
|
|
785
|
+
placeholder="Choose a color..."
|
|
786
|
+
options={colorOptions}
|
|
787
|
+
renderOption={({ option, isSelected }) => (
|
|
788
|
+
<View style={customStyles.optionRow}>
|
|
789
|
+
<View style={[customStyles.colorSwatch, { backgroundColor: option.color }]} />
|
|
790
|
+
<Text style={{ color: isSelected ? colors.brand.blue : colors.text.default }}>
|
|
791
|
+
{option.label}
|
|
792
|
+
</Text>
|
|
793
|
+
</View>
|
|
794
|
+
)}
|
|
795
|
+
renderSelectedValue={({ option, placeholder }) => (
|
|
796
|
+
<View style={customStyles.optionRow}>
|
|
797
|
+
{option ? (
|
|
798
|
+
<>
|
|
799
|
+
<View style={[customStyles.colorSwatch, { backgroundColor: option.color }]} />
|
|
800
|
+
<Text>{option.label}</Text>
|
|
801
|
+
</>
|
|
802
|
+
) : (
|
|
803
|
+
<Text style={{ color: colors.text.disabled }}>{placeholder}</Text>
|
|
804
|
+
)}
|
|
805
|
+
</View>
|
|
806
|
+
)}
|
|
807
|
+
/>
|
|
808
|
+
<Select
|
|
809
|
+
label="Select Colors (Multi)"
|
|
810
|
+
placeholder="Choose colors..."
|
|
811
|
+
isMultiple
|
|
812
|
+
options={colorOptions}
|
|
813
|
+
renderOption={({ option, isSelected, isHovered }) => (
|
|
814
|
+
<View style={customStyles.optionRow}>
|
|
815
|
+
<View style={[customStyles.colorSwatch, { backgroundColor: option.color }]} />
|
|
816
|
+
<Text style={{ color: isSelected ? colors.brand.blue : colors.text.default }}>
|
|
817
|
+
{option.label}
|
|
818
|
+
</Text>
|
|
819
|
+
</View>
|
|
820
|
+
)}
|
|
821
|
+
renderSelectedValue={({ selectedOptions, placeholder, isMultiple }) => (
|
|
822
|
+
<View style={[customStyles.optionRow, { gap: 4 }]}>
|
|
823
|
+
{selectedOptions.length > 0 ? (
|
|
824
|
+
selectedOptions.map((opt) => (
|
|
825
|
+
<View
|
|
826
|
+
key={opt.value}
|
|
827
|
+
style={[
|
|
828
|
+
customStyles.colorSwatch,
|
|
829
|
+
{ backgroundColor: opt.color, marginRight: 0 }
|
|
830
|
+
]}
|
|
831
|
+
/>
|
|
832
|
+
))
|
|
833
|
+
) : (
|
|
834
|
+
<Text style={{ color: colors.text.disabled }}>{placeholder}</Text>
|
|
835
|
+
)}
|
|
836
|
+
</View>
|
|
837
|
+
)}
|
|
838
|
+
/>
|
|
839
|
+
</VStack>
|
|
840
|
+
),
|
|
841
|
+
};
|
|
842
|
+
|
|
843
|
+
export const CustomRenderingWithSearch: Story = {
|
|
844
|
+
render: () => (
|
|
845
|
+
<VStack space={16}>
|
|
846
|
+
<Text weight="semiBold">Searchable with Custom Rendering</Text>
|
|
847
|
+
<Select
|
|
848
|
+
label="Select Colors"
|
|
849
|
+
placeholder="Search colors..."
|
|
850
|
+
isSearchable
|
|
851
|
+
isMultiple
|
|
852
|
+
options={colorOptions}
|
|
853
|
+
renderOption={({ option, isSelected, searchQuery }) => (
|
|
854
|
+
<View style={customStyles.optionRow}>
|
|
855
|
+
<View style={[customStyles.colorSwatch, { backgroundColor: option.color }]} />
|
|
856
|
+
<Text style={{ color: isSelected ? colors.brand.blue : colors.text.default }}>
|
|
857
|
+
{option.label}
|
|
858
|
+
</Text>
|
|
859
|
+
</View>
|
|
860
|
+
)}
|
|
861
|
+
renderSelectedValue={({ selectedOptions, placeholder }) => (
|
|
862
|
+
<View style={[customStyles.optionRow, { gap: 4 }]}>
|
|
863
|
+
{selectedOptions.length > 0 ? (
|
|
864
|
+
selectedOptions.map((opt) => (
|
|
865
|
+
<View
|
|
866
|
+
key={opt.value}
|
|
867
|
+
style={[
|
|
868
|
+
customStyles.colorSwatch,
|
|
869
|
+
{ backgroundColor: opt.color, marginRight: 0 }
|
|
870
|
+
]}
|
|
871
|
+
/>
|
|
872
|
+
))
|
|
873
|
+
) : (
|
|
874
|
+
<Text style={{ color: colors.text.disabled }}>{placeholder}</Text>
|
|
875
|
+
)}
|
|
876
|
+
</View>
|
|
877
|
+
)}
|
|
878
|
+
/>
|
|
879
|
+
</VStack>
|
|
880
|
+
),
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
// ============================================================================
|
|
884
|
+
// HOVER STATE DEMO
|
|
885
|
+
// ============================================================================
|
|
886
|
+
|
|
887
|
+
export const HoverStateDemo: Story = {
|
|
888
|
+
render: () => (
|
|
889
|
+
<VStack space={16}>
|
|
890
|
+
<Text weight="semiBold">Hover State Demo</Text>
|
|
891
|
+
<Text size="caption" color="secondary">
|
|
892
|
+
On web, hover over the select trigger and dropdown options to see hover states.
|
|
893
|
+
</Text>
|
|
894
|
+
<Select
|
|
895
|
+
label="Hover over me"
|
|
896
|
+
placeholder="Hover to see border change..."
|
|
897
|
+
options={[
|
|
898
|
+
{ label: 'Option 1 - Hover to highlight', value: '1' },
|
|
899
|
+
{ label: 'Option 2 - Hover to highlight', value: '2' },
|
|
900
|
+
{ label: 'Option 3 - Hover to highlight', value: '3' },
|
|
901
|
+
{ label: 'Option 4 - Hover to highlight', value: '4' },
|
|
902
|
+
{ label: 'Option 5 - Hover to highlight', value: '5' },
|
|
903
|
+
]}
|
|
904
|
+
helperText="Hover states provide visual feedback on web"
|
|
905
|
+
/>
|
|
906
|
+
</VStack>
|
|
907
|
+
),
|
|
908
|
+
};
|