@titan-design/react-ui 0.1.0 → 0.1.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.
Files changed (192) hide show
  1. package/package.json +10 -5
  2. package/src/components/custom/DateTime/DateTime.stories.tsx +180 -0
  3. package/src/components/custom/DateTime/DateTime.test.tsx +152 -0
  4. package/src/components/custom/DateTime/DateTime.tsx +235 -0
  5. package/src/components/custom/DateTime/index.ts +2 -0
  6. package/src/components/custom/EmptyState/EmptyState.stories.tsx +99 -0
  7. package/src/components/custom/EmptyState/EmptyState.test.tsx +106 -0
  8. package/src/components/custom/EmptyState/EmptyState.tsx +68 -0
  9. package/src/components/custom/EmptyState/index.ts +2 -0
  10. package/src/components/custom/Metric/Metric.stories.tsx +133 -0
  11. package/src/components/custom/Metric/Metric.test.tsx +120 -0
  12. package/src/components/custom/Metric/Metric.tsx +92 -0
  13. package/src/components/custom/Metric/index.ts +2 -0
  14. package/src/components/custom/Sidebar/Sidebar.stories.tsx +227 -0
  15. package/src/components/custom/Sidebar/Sidebar.test.tsx +185 -0
  16. package/src/components/custom/Sidebar/Sidebar.tsx +257 -0
  17. package/src/components/custom/Sidebar/index.ts +18 -0
  18. package/src/components/custom/Table/Table.stories.tsx +481 -0
  19. package/src/components/custom/Table/Table.test.tsx +531 -0
  20. package/src/components/custom/Table/Table.tsx +696 -0
  21. package/src/components/custom/Table/index.ts +22 -0
  22. package/src/components/custom/Typography/Typography.stories.tsx +153 -0
  23. package/src/components/custom/Typography/Typography.test.tsx +107 -0
  24. package/src/components/custom/Typography/Typography.tsx +218 -0
  25. package/src/components/custom/Typography/index.ts +19 -0
  26. package/src/components/custom/index.ts +8 -0
  27. package/src/components/custom/stepper/Stepper.stories.tsx +245 -0
  28. package/src/components/custom/stepper/Stepper.test.tsx +230 -0
  29. package/src/components/custom/stepper/Stepper.tsx +250 -0
  30. package/src/components/custom/stepper/index.ts +10 -0
  31. package/src/components/index.ts +5 -0
  32. package/src/components/ui/alert/Alert.stories.tsx +154 -0
  33. package/src/components/ui/alert/Alert.test.tsx +202 -0
  34. package/src/components/ui/alert/Alert.tsx +170 -0
  35. package/src/components/ui/alert/index.ts +8 -0
  36. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +299 -0
  37. package/src/components/ui/autocomplete/Autocomplete.test.tsx +247 -0
  38. package/src/components/ui/autocomplete/Autocomplete.tsx +332 -0
  39. package/src/components/ui/autocomplete/index.ts +2 -0
  40. package/src/components/ui/avatar/Avatar.stories.tsx +105 -0
  41. package/src/components/ui/avatar/Avatar.test.tsx +135 -0
  42. package/src/components/ui/avatar/Avatar.tsx +168 -0
  43. package/src/components/ui/avatar/index.ts +2 -0
  44. package/src/components/ui/badge/Badge.stories.tsx +100 -0
  45. package/src/components/ui/badge/Badge.test.tsx +86 -0
  46. package/src/components/ui/badge/Badge.tsx +105 -0
  47. package/src/components/ui/badge/index.ts +2 -0
  48. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +70 -0
  49. package/src/components/ui/breadcrumbs/Breadcrumbs.test.tsx +156 -0
  50. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +127 -0
  51. package/src/components/ui/breadcrumbs/index.ts +2 -0
  52. package/src/components/ui/button/Button.stories.tsx +216 -0
  53. package/src/components/ui/button/Button.test.tsx +132 -0
  54. package/src/components/ui/button/Button.tsx +242 -0
  55. package/src/components/ui/button/index.ts +10 -0
  56. package/src/components/ui/card/Card.stories.tsx +443 -0
  57. package/src/components/ui/card/Card.test.tsx +265 -0
  58. package/src/components/ui/card/Card.tsx +380 -0
  59. package/src/components/ui/card/index.ts +20 -0
  60. package/src/components/ui/checkbox/Checkbox.stories.tsx +126 -0
  61. package/src/components/ui/checkbox/Checkbox.test.tsx +152 -0
  62. package/src/components/ui/checkbox/Checkbox.tsx +163 -0
  63. package/src/components/ui/checkbox/index.ts +2 -0
  64. package/src/components/ui/chip/Chip.stories.tsx +112 -0
  65. package/src/components/ui/chip/Chip.test.tsx +119 -0
  66. package/src/components/ui/chip/Chip.tsx +151 -0
  67. package/src/components/ui/chip/index.ts +2 -0
  68. package/src/components/ui/collapse/Collapse.stories.tsx +313 -0
  69. package/src/components/ui/collapse/Collapse.test.tsx +298 -0
  70. package/src/components/ui/collapse/Collapse.tsx +275 -0
  71. package/src/components/ui/collapse/index.ts +18 -0
  72. package/src/components/ui/data-row/DataRow.stories.tsx +78 -0
  73. package/src/components/ui/data-row/DataRow.test.tsx +78 -0
  74. package/src/components/ui/data-row/DataRow.tsx +29 -0
  75. package/src/components/ui/data-row/index.ts +2 -0
  76. package/src/components/ui/divider/Divider.stories.tsx +71 -0
  77. package/src/components/ui/divider/Divider.test.tsx +55 -0
  78. package/src/components/ui/divider/Divider.tsx +37 -0
  79. package/src/components/ui/divider/index.ts +2 -0
  80. package/src/components/ui/drawer/Drawer.stories.tsx +228 -0
  81. package/src/components/ui/drawer/Drawer.test.tsx +142 -0
  82. package/src/components/ui/drawer/Drawer.tsx +228 -0
  83. package/src/components/ui/drawer/index.ts +9 -0
  84. package/src/components/ui/form-field/FormField.stories.tsx +260 -0
  85. package/src/components/ui/form-field/FormField.test.tsx +280 -0
  86. package/src/components/ui/form-field/FormField.tsx +308 -0
  87. package/src/components/ui/form-field/index.ts +2 -0
  88. package/src/components/ui/help-tip/HelpTip.stories.tsx +250 -0
  89. package/src/components/ui/help-tip/HelpTip.test.tsx +198 -0
  90. package/src/components/ui/help-tip/HelpTip.tsx +229 -0
  91. package/src/components/ui/help-tip/index.ts +2 -0
  92. package/src/components/ui/icon-box/IconBox.stories.tsx +139 -0
  93. package/src/components/ui/icon-box/IconBox.test.tsx +120 -0
  94. package/src/components/ui/icon-box/IconBox.tsx +57 -0
  95. package/src/components/ui/icon-box/index.ts +1 -0
  96. package/src/components/ui/index.ts +36 -0
  97. package/src/components/ui/input/Input.stories.tsx +192 -0
  98. package/src/components/ui/input/Input.test.tsx +86 -0
  99. package/src/components/ui/input/Input.tsx +273 -0
  100. package/src/components/ui/input/index.ts +2 -0
  101. package/src/components/ui/link/Link.stories.tsx +78 -0
  102. package/src/components/ui/link/Link.test.tsx +94 -0
  103. package/src/components/ui/link/Link.tsx +86 -0
  104. package/src/components/ui/link/index.ts +2 -0
  105. package/src/components/ui/list-item/ListItem.stories.tsx +146 -0
  106. package/src/components/ui/list-item/ListItem.test.tsx +128 -0
  107. package/src/components/ui/list-item/ListItem.tsx +89 -0
  108. package/src/components/ui/list-item/index.ts +14 -0
  109. package/src/components/ui/menu/Menu.stories.tsx +180 -0
  110. package/src/components/ui/menu/Menu.test.tsx +353 -0
  111. package/src/components/ui/menu/Menu.tsx +222 -0
  112. package/src/components/ui/menu/index.ts +2 -0
  113. package/src/components/ui/modal/Modal.stories.tsx +350 -0
  114. package/src/components/ui/modal/Modal.test.tsx +159 -0
  115. package/src/components/ui/modal/Modal.tsx +254 -0
  116. package/src/components/ui/modal/index.ts +19 -0
  117. package/src/components/ui/popover/Popover.stories.tsx +190 -0
  118. package/src/components/ui/popover/Popover.test.tsx +277 -0
  119. package/src/components/ui/popover/Popover.tsx +162 -0
  120. package/src/components/ui/popover/index.ts +2 -0
  121. package/src/components/ui/progress/Progress.stories.tsx +190 -0
  122. package/src/components/ui/progress/Progress.test.tsx +181 -0
  123. package/src/components/ui/progress/Progress.tsx +320 -0
  124. package/src/components/ui/progress/index.ts +9 -0
  125. package/src/components/ui/radio/Radio.stories.tsx +199 -0
  126. package/src/components/ui/radio/Radio.test.tsx +166 -0
  127. package/src/components/ui/radio/Radio.tsx +200 -0
  128. package/src/components/ui/radio/index.ts +2 -0
  129. package/src/components/ui/section/Section.stories.tsx +111 -0
  130. package/src/components/ui/section/Section.test.tsx +121 -0
  131. package/src/components/ui/section/Section.tsx +52 -0
  132. package/src/components/ui/section/index.ts +6 -0
  133. package/src/components/ui/select/Select.stories.tsx +286 -0
  134. package/src/components/ui/select/Select.test.tsx +180 -0
  135. package/src/components/ui/select/Select.tsx +236 -0
  136. package/src/components/ui/select/index.ts +2 -0
  137. package/src/components/ui/skeleton/Skeleton.stories.tsx +153 -0
  138. package/src/components/ui/skeleton/Skeleton.test.tsx +162 -0
  139. package/src/components/ui/skeleton/Skeleton.tsx +229 -0
  140. package/src/components/ui/skeleton/index.ts +16 -0
  141. package/src/components/ui/spinner/Spinner.stories.tsx +67 -0
  142. package/src/components/ui/spinner/Spinner.test.tsx +67 -0
  143. package/src/components/ui/spinner/Spinner.tsx +72 -0
  144. package/src/components/ui/spinner/index.ts +2 -0
  145. package/src/components/ui/stack/Stack.stories.tsx +127 -0
  146. package/src/components/ui/stack/Stack.test.tsx +184 -0
  147. package/src/components/ui/stack/Stack.tsx +76 -0
  148. package/src/components/ui/stack/index.ts +2 -0
  149. package/src/components/ui/surface/Surface.stories.tsx +91 -0
  150. package/src/components/ui/surface/Surface.test.tsx +63 -0
  151. package/src/components/ui/surface/Surface.tsx +51 -0
  152. package/src/components/ui/surface/index.ts +1 -0
  153. package/src/components/ui/switch/Switch.stories.tsx +111 -0
  154. package/src/components/ui/switch/Switch.test.tsx +112 -0
  155. package/src/components/ui/switch/Switch.tsx +103 -0
  156. package/src/components/ui/switch/index.ts +2 -0
  157. package/src/components/ui/tabs/Tabs.stories.tsx +213 -0
  158. package/src/components/ui/tabs/Tabs.test.tsx +192 -0
  159. package/src/components/ui/tabs/Tabs.tsx +253 -0
  160. package/src/components/ui/tabs/index.ts +16 -0
  161. package/src/components/ui/toast/Toast.stories.tsx +255 -0
  162. package/src/components/ui/toast/Toast.test.tsx +207 -0
  163. package/src/components/ui/toast/Toast.tsx +327 -0
  164. package/src/components/ui/toast/index.ts +8 -0
  165. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +415 -0
  166. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +224 -0
  167. package/src/components/ui/toolbar-button/ToolbarButton.tsx +307 -0
  168. package/src/components/ui/toolbar-button/index.ts +7 -0
  169. package/src/components/ui/tooltip/Tooltip.stories.tsx +126 -0
  170. package/src/components/ui/tooltip/Tooltip.test.tsx +179 -0
  171. package/src/components/ui/tooltip/Tooltip.tsx +143 -0
  172. package/src/components/ui/tooltip/index.ts +2 -0
  173. package/src/index.ts +10 -0
  174. package/src/test/setup.ts +19 -0
  175. package/src/theme/Colors.stories.tsx +258 -0
  176. package/src/theme/config.ts +193 -0
  177. package/src/theme/elevation.stories.tsx +346 -0
  178. package/src/theme/elevation.test.ts +27 -0
  179. package/src/theme/elevation.ts +567 -0
  180. package/src/theme/index.ts +39 -0
  181. package/src/theme/shadows.stories.tsx +523 -0
  182. package/src/theme/shadows.ts +439 -0
  183. package/src/theme/tokens/index.ts +2 -0
  184. package/src/theme/tokens/primitives.ts +354 -0
  185. package/src/theme/tokens/semantic.ts +381 -0
  186. package/src/types/jest-axe.d.ts +16 -0
  187. package/src/types/nativewind.d.ts +54 -0
  188. package/src/utils/cn.ts +14 -0
  189. package/src/utils/colors.ts +140 -0
  190. package/src/utils/form.ts +188 -0
  191. package/src/utils/index.ts +29 -0
  192. package/src/utils/useTheme.ts +72 -0
@@ -0,0 +1,170 @@
1
+ import React from 'react'
2
+ import { View, Text, Pressable, type ViewProps } from 'react-native'
3
+ import { cn } from '../../../utils/cn'
4
+
5
+ export type AlertStatus = 'success' | 'info' | 'warning' | 'error'
6
+ export type AlertVariant = 'subtle' | 'outline' | 'solid'
7
+
8
+ export interface AlertProps extends ViewProps {
9
+ /** Alert status type */
10
+ status?: AlertStatus
11
+ /** Visual variant */
12
+ variant?: AlertVariant
13
+ /** Custom icon element */
14
+ icon?: React.ReactNode
15
+ /** Whether to show the default icon */
16
+ showIcon?: boolean
17
+ /** Callback when close button is pressed */
18
+ onClose?: () => void
19
+ /** Additional className */
20
+ className?: string
21
+ children?: React.ReactNode
22
+ }
23
+
24
+ const statusColors: Record<AlertStatus, {
25
+ subtle: string
26
+ outline: string
27
+ solid: string
28
+ icon: string
29
+ text: string
30
+ }> = {
31
+ success: {
32
+ subtle: 'bg-status-success-subtle',
33
+ outline: 'border-2 border-status-success bg-transparent',
34
+ solid: 'bg-status-success',
35
+ icon: 'text-status-success',
36
+ text: 'text-status-success',
37
+ },
38
+ info: {
39
+ subtle: 'bg-status-info-subtle',
40
+ outline: 'border-2 border-status-info bg-transparent',
41
+ solid: 'bg-status-info',
42
+ icon: 'text-status-info',
43
+ text: 'text-status-info',
44
+ },
45
+ warning: {
46
+ subtle: 'bg-status-warning-subtle',
47
+ outline: 'border-2 border-status-warning bg-transparent',
48
+ solid: 'bg-status-warning',
49
+ icon: 'text-status-warning',
50
+ text: 'text-status-warning',
51
+ },
52
+ error: {
53
+ subtle: 'bg-status-error-subtle',
54
+ outline: 'border-2 border-status-error bg-transparent',
55
+ solid: 'bg-status-error',
56
+ icon: 'text-status-error',
57
+ text: 'text-status-error',
58
+ },
59
+ }
60
+
61
+ // Default icons for each status
62
+ const defaultIcons: Record<AlertStatus, string> = {
63
+ success: '✓',
64
+ info: 'ℹ',
65
+ warning: '⚠',
66
+ error: '✕',
67
+ }
68
+
69
+ /**
70
+ * Alert component for displaying status messages.
71
+ *
72
+ * @example
73
+ * <Alert status="success">
74
+ * <AlertTitle>Success!</AlertTitle>
75
+ * <AlertDescription>Your changes have been saved.</AlertDescription>
76
+ * </Alert>
77
+ *
78
+ * <Alert status="error" variant="solid" onClose={() => {}}>
79
+ * <AlertDescription>Something went wrong.</AlertDescription>
80
+ * </Alert>
81
+ */
82
+ export function Alert({
83
+ status = 'info',
84
+ variant = 'subtle',
85
+ icon,
86
+ showIcon = true,
87
+ onClose,
88
+ className,
89
+ children,
90
+ ...props
91
+ }: AlertProps) {
92
+ const colors = statusColors[status]
93
+ const isSolid = variant === 'solid'
94
+
95
+ return (
96
+ <View
97
+ accessibilityRole="alert"
98
+ className={cn(
99
+ 'flex-row items-start p-4 rounded-lg',
100
+ colors[variant],
101
+ className
102
+ )}
103
+ {...props}
104
+ >
105
+ {showIcon && (
106
+ <View className="mr-3 mt-0.5">
107
+ {icon || (
108
+ <Text
109
+ className={cn(
110
+ 'text-lg font-bold',
111
+ isSolid ? 'text-white' : colors.icon
112
+ )}
113
+ >
114
+ {defaultIcons[status]}
115
+ </Text>
116
+ )}
117
+ </View>
118
+ )}
119
+
120
+ <View className="flex-1">
121
+ {children}
122
+ </View>
123
+
124
+ {onClose && (
125
+ <Pressable
126
+ onPress={onClose}
127
+ accessibilityRole="button"
128
+ accessibilityLabel="Close alert"
129
+ className="ml-2 p-1 rounded web:hover:bg-black/10 active:bg-black/20"
130
+ >
131
+ <Text className={cn('text-lg', isSolid ? 'text-white/70' : 'text-text-secondary')}>
132
+ ×
133
+ </Text>
134
+ </Pressable>
135
+ )}
136
+ </View>
137
+ )
138
+ }
139
+
140
+ export interface AlertTitleProps {
141
+ children?: React.ReactNode
142
+ className?: string
143
+ }
144
+
145
+ /**
146
+ * Title for Alert component.
147
+ */
148
+ export function AlertTitle({ children, className }: AlertTitleProps) {
149
+ return (
150
+ <Text className={cn('font-semibold text-text-primary mb-1', className)}>
151
+ {children}
152
+ </Text>
153
+ )
154
+ }
155
+
156
+ export interface AlertDescriptionProps {
157
+ children?: React.ReactNode
158
+ className?: string
159
+ }
160
+
161
+ /**
162
+ * Description for Alert component.
163
+ */
164
+ export function AlertDescription({ children, className }: AlertDescriptionProps) {
165
+ return (
166
+ <Text className={cn('text-sm text-text-secondary', className)}>
167
+ {children}
168
+ </Text>
169
+ )
170
+ }
@@ -0,0 +1,8 @@
1
+ export { Alert, AlertTitle, AlertDescription } from './Alert'
2
+ export type {
3
+ AlertProps,
4
+ AlertTitleProps,
5
+ AlertDescriptionProps,
6
+ AlertStatus,
7
+ AlertVariant,
8
+ } from './Alert'
@@ -0,0 +1,299 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { useState } from 'react'
3
+ import { View, Text } from 'react-native'
4
+ import { Autocomplete, AutocompleteOption } from './Autocomplete'
5
+
6
+ const meta: Meta<typeof Autocomplete> = {
7
+ title: 'Components/Autocomplete',
8
+ component: Autocomplete,
9
+ tags: ['autodocs'],
10
+ argTypes: {
11
+ isDisabled: {
12
+ control: 'boolean',
13
+ },
14
+ isLoading: {
15
+ control: 'boolean',
16
+ },
17
+ isClearable: {
18
+ control: 'boolean',
19
+ },
20
+ minChars: {
21
+ control: { type: 'number', min: 0, max: 5 },
22
+ },
23
+ },
24
+ }
25
+
26
+ export default meta
27
+ type Story = StoryObj<typeof Autocomplete>
28
+
29
+ const fruitOptions: AutocompleteOption[] = [
30
+ { value: 'apple', label: 'Apple' },
31
+ { value: 'banana', label: 'Banana' },
32
+ { value: 'cherry', label: 'Cherry' },
33
+ { value: 'date', label: 'Date' },
34
+ { value: 'elderberry', label: 'Elderberry' },
35
+ { value: 'fig', label: 'Fig' },
36
+ { value: 'grape', label: 'Grape' },
37
+ { value: 'honeydew', label: 'Honeydew' },
38
+ ]
39
+
40
+ export const Default: Story = {
41
+ render: function Render() {
42
+ const [value, setValue] = useState<string | null>(null)
43
+ return (
44
+ <View className="w-64">
45
+ <Autocomplete
46
+ options={fruitOptions}
47
+ value={value}
48
+ onChange={setValue}
49
+ placeholder="Search fruits..."
50
+ />
51
+ <Text className="text-sm text-text-secondary mt-2">
52
+ Selected: {value || 'None'}
53
+ </Text>
54
+ </View>
55
+ )
56
+ },
57
+ }
58
+
59
+ export const WithLabel: Story = {
60
+ render: function Render() {
61
+ const [value, setValue] = useState<string | null>(null)
62
+ return (
63
+ <View className="w-64">
64
+ <Autocomplete
65
+ options={fruitOptions}
66
+ value={value}
67
+ onChange={setValue}
68
+ label="Select a fruit"
69
+ placeholder="Type to search..."
70
+ helperText="Choose your favorite fruit"
71
+ />
72
+ </View>
73
+ )
74
+ },
75
+ }
76
+
77
+ const userOptions: AutocompleteOption[] = [
78
+ { value: 'user1', label: 'John Doe', description: 'john@example.com' },
79
+ { value: 'user2', label: 'Jane Smith', description: 'jane@example.com' },
80
+ { value: 'user3', label: 'Bob Johnson', description: 'bob@example.com' },
81
+ { value: 'user4', label: 'Alice Williams', description: 'alice@example.com' },
82
+ { value: 'user5', label: 'Charlie Brown', description: 'charlie@example.com' },
83
+ ]
84
+
85
+ export const WithDescriptions: Story = {
86
+ render: function Render() {
87
+ const [value, setValue] = useState<string | null>(null)
88
+ return (
89
+ <View className="w-80">
90
+ <Autocomplete
91
+ options={userOptions}
92
+ value={value}
93
+ onChange={setValue}
94
+ label="Assign to"
95
+ placeholder="Search users..."
96
+ />
97
+ </View>
98
+ )
99
+ },
100
+ }
101
+
102
+ export const MinimumCharacters: Story = {
103
+ render: function Render() {
104
+ const [value, setValue] = useState<string | null>(null)
105
+ return (
106
+ <View className="w-64">
107
+ <Autocomplete
108
+ options={fruitOptions}
109
+ value={value}
110
+ onChange={setValue}
111
+ label="Search (min 2 chars)"
112
+ placeholder="Type at least 2 characters..."
113
+ minChars={2}
114
+ />
115
+ </View>
116
+ )
117
+ },
118
+ }
119
+
120
+ export const WithError: Story = {
121
+ render: function Render() {
122
+ const [value, setValue] = useState<string | null>(null)
123
+ return (
124
+ <View className="w-64">
125
+ <Autocomplete
126
+ options={fruitOptions}
127
+ value={value}
128
+ onChange={setValue}
129
+ label="Select fruit"
130
+ placeholder="Search..."
131
+ isRequired
132
+ errorMessage="Please select a fruit"
133
+ />
134
+ </View>
135
+ )
136
+ },
137
+ }
138
+
139
+ export const Disabled: Story = {
140
+ render: function Render() {
141
+ return (
142
+ <View className="w-64">
143
+ <Autocomplete
144
+ options={fruitOptions}
145
+ value="apple"
146
+ label="Disabled field"
147
+ isDisabled
148
+ />
149
+ </View>
150
+ )
151
+ },
152
+ }
153
+
154
+ export const Loading: Story = {
155
+ render: function Render() {
156
+ const [value, setValue] = useState<string | null>(null)
157
+ return (
158
+ <View className="w-64">
159
+ <Autocomplete
160
+ options={[]}
161
+ value={value}
162
+ onChange={setValue}
163
+ label="Loading state"
164
+ placeholder="Search..."
165
+ isLoading
166
+ />
167
+ </View>
168
+ )
169
+ },
170
+ }
171
+
172
+ export const DisabledOptions: Story = {
173
+ render: function Render() {
174
+ const [value, setValue] = useState<string | null>(null)
175
+ const optionsWithDisabled: AutocompleteOption[] = [
176
+ { value: 'free', label: 'Free Plan' },
177
+ { value: 'pro', label: 'Pro Plan' },
178
+ { value: 'enterprise', label: 'Enterprise Plan', isDisabled: true, description: 'Contact sales' },
179
+ ]
180
+ return (
181
+ <View className="w-64">
182
+ <Autocomplete
183
+ options={optionsWithDisabled}
184
+ value={value}
185
+ onChange={setValue}
186
+ label="Select plan"
187
+ placeholder="Choose a plan..."
188
+ />
189
+ </View>
190
+ )
191
+ },
192
+ }
193
+
194
+ export const CustomNoResultsText: Story = {
195
+ render: function Render() {
196
+ const [value, setValue] = useState<string | null>(null)
197
+ return (
198
+ <View className="w-64">
199
+ <Autocomplete
200
+ options={fruitOptions}
201
+ value={value}
202
+ onChange={setValue}
203
+ placeholder="Search..."
204
+ noOptionsText="🔍 No fruits match your search"
205
+ minCharsText="🍎 Type to find fruits"
206
+ />
207
+ </View>
208
+ )
209
+ },
210
+ }
211
+
212
+ export const NonClearable: Story = {
213
+ render: function Render() {
214
+ const [value, setValue] = useState<string | null>('apple')
215
+ return (
216
+ <View className="w-64">
217
+ <Autocomplete
218
+ options={fruitOptions}
219
+ value={value}
220
+ onChange={setValue}
221
+ label="Cannot clear selection"
222
+ isClearable={false}
223
+ />
224
+ </View>
225
+ )
226
+ },
227
+ }
228
+
229
+ export const FormExample: Story = {
230
+ render: function Render() {
231
+ const [country, setCountry] = useState<string | null>(null)
232
+ const [city, setCity] = useState<string | null>(null)
233
+
234
+ const countryOptions: AutocompleteOption[] = [
235
+ { value: 'us', label: 'United States' },
236
+ { value: 'uk', label: 'United Kingdom' },
237
+ { value: 'ca', label: 'Canada' },
238
+ { value: 'au', label: 'Australia' },
239
+ ]
240
+
241
+ const cityOptions: Record<string, AutocompleteOption[]> = {
242
+ us: [
243
+ { value: 'nyc', label: 'New York' },
244
+ { value: 'la', label: 'Los Angeles' },
245
+ { value: 'chi', label: 'Chicago' },
246
+ ],
247
+ uk: [
248
+ { value: 'lon', label: 'London' },
249
+ { value: 'man', label: 'Manchester' },
250
+ { value: 'bir', label: 'Birmingham' },
251
+ ],
252
+ ca: [
253
+ { value: 'tor', label: 'Toronto' },
254
+ { value: 'van', label: 'Vancouver' },
255
+ { value: 'mon', label: 'Montreal' },
256
+ ],
257
+ au: [
258
+ { value: 'syd', label: 'Sydney' },
259
+ { value: 'mel', label: 'Melbourne' },
260
+ { value: 'bri', label: 'Brisbane' },
261
+ ],
262
+ }
263
+
264
+ return (
265
+ <View className="gap-4 w-80 p-4 bg-surface-base rounded-lg">
266
+ <Text className="text-lg font-semibold text-text-primary">Location</Text>
267
+
268
+ <Autocomplete
269
+ options={countryOptions}
270
+ value={country}
271
+ onChange={(val) => {
272
+ setCountry(val)
273
+ setCity(null) // Reset city when country changes
274
+ }}
275
+ label="Country"
276
+ placeholder="Select country..."
277
+ isRequired
278
+ />
279
+
280
+ <Autocomplete
281
+ options={country ? cityOptions[country] || [] : []}
282
+ value={city}
283
+ onChange={setCity}
284
+ label="City"
285
+ placeholder={country ? 'Select city...' : 'Select country first'}
286
+ isDisabled={!country}
287
+ isRequired
288
+ />
289
+
290
+ <View className="pt-2 border-t border-border-default">
291
+ <Text className="text-sm text-text-secondary">
292
+ Selected: {country ? `${countryOptions.find(c => c.value === country)?.label}` : '-'}
293
+ {city ? `, ${cityOptions[country!]?.find(c => c.value === city)?.label}` : ''}
294
+ </Text>
295
+ </View>
296
+ </View>
297
+ )
298
+ },
299
+ }