@titan-design/react-ui 0.0.2 → 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 (206) hide show
  1. package/dist/{chunk-NA3EES23.mjs → chunk-MGW37MPO.mjs} +26 -4
  2. package/dist/chunk-MGW37MPO.mjs.map +1 -0
  3. package/dist/index.d.mts +115 -2
  4. package/dist/index.d.ts +115 -2
  5. package/dist/index.js +262 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +225 -3
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/theme/index.d.mts +124 -109
  10. package/dist/theme/index.d.ts +124 -109
  11. package/dist/theme/index.js +24 -1
  12. package/dist/theme/index.js.map +1 -1
  13. package/dist/theme/index.mjs +1 -1
  14. package/package.json +12 -5
  15. package/src/components/custom/DateTime/DateTime.stories.tsx +180 -0
  16. package/src/components/custom/DateTime/DateTime.test.tsx +152 -0
  17. package/src/components/custom/DateTime/DateTime.tsx +235 -0
  18. package/src/components/custom/DateTime/index.ts +2 -0
  19. package/src/components/custom/EmptyState/EmptyState.stories.tsx +99 -0
  20. package/src/components/custom/EmptyState/EmptyState.test.tsx +106 -0
  21. package/src/components/custom/EmptyState/EmptyState.tsx +68 -0
  22. package/src/components/custom/EmptyState/index.ts +2 -0
  23. package/src/components/custom/Metric/Metric.stories.tsx +133 -0
  24. package/src/components/custom/Metric/Metric.test.tsx +120 -0
  25. package/src/components/custom/Metric/Metric.tsx +92 -0
  26. package/src/components/custom/Metric/index.ts +2 -0
  27. package/src/components/custom/Sidebar/Sidebar.stories.tsx +227 -0
  28. package/src/components/custom/Sidebar/Sidebar.test.tsx +185 -0
  29. package/src/components/custom/Sidebar/Sidebar.tsx +257 -0
  30. package/src/components/custom/Sidebar/index.ts +18 -0
  31. package/src/components/custom/Table/Table.stories.tsx +481 -0
  32. package/src/components/custom/Table/Table.test.tsx +531 -0
  33. package/src/components/custom/Table/Table.tsx +696 -0
  34. package/src/components/custom/Table/index.ts +22 -0
  35. package/src/components/custom/Typography/Typography.stories.tsx +153 -0
  36. package/src/components/custom/Typography/Typography.test.tsx +107 -0
  37. package/src/components/custom/Typography/Typography.tsx +218 -0
  38. package/src/components/custom/Typography/index.ts +19 -0
  39. package/src/components/custom/index.ts +8 -0
  40. package/src/components/custom/stepper/Stepper.stories.tsx +245 -0
  41. package/src/components/custom/stepper/Stepper.test.tsx +230 -0
  42. package/src/components/custom/stepper/Stepper.tsx +250 -0
  43. package/src/components/custom/stepper/index.ts +10 -0
  44. package/src/components/index.ts +5 -0
  45. package/src/components/ui/alert/Alert.stories.tsx +154 -0
  46. package/src/components/ui/alert/Alert.test.tsx +202 -0
  47. package/src/components/ui/alert/Alert.tsx +170 -0
  48. package/src/components/ui/alert/index.ts +8 -0
  49. package/src/components/ui/autocomplete/Autocomplete.stories.tsx +299 -0
  50. package/src/components/ui/autocomplete/Autocomplete.test.tsx +247 -0
  51. package/src/components/ui/autocomplete/Autocomplete.tsx +332 -0
  52. package/src/components/ui/autocomplete/index.ts +2 -0
  53. package/src/components/ui/avatar/Avatar.stories.tsx +105 -0
  54. package/src/components/ui/avatar/Avatar.test.tsx +135 -0
  55. package/src/components/ui/avatar/Avatar.tsx +168 -0
  56. package/src/components/ui/avatar/index.ts +2 -0
  57. package/src/components/ui/badge/Badge.stories.tsx +100 -0
  58. package/src/components/ui/badge/Badge.test.tsx +86 -0
  59. package/src/components/ui/badge/Badge.tsx +105 -0
  60. package/src/components/ui/badge/index.ts +2 -0
  61. package/src/components/ui/breadcrumbs/Breadcrumbs.stories.tsx +70 -0
  62. package/src/components/ui/breadcrumbs/Breadcrumbs.test.tsx +156 -0
  63. package/src/components/ui/breadcrumbs/Breadcrumbs.tsx +127 -0
  64. package/src/components/ui/breadcrumbs/index.ts +2 -0
  65. package/src/components/ui/button/Button.stories.tsx +216 -0
  66. package/src/components/ui/button/Button.test.tsx +132 -0
  67. package/src/components/ui/button/Button.tsx +242 -0
  68. package/src/components/ui/button/index.ts +10 -0
  69. package/src/components/ui/card/Card.stories.tsx +443 -0
  70. package/src/components/ui/card/Card.test.tsx +265 -0
  71. package/src/components/ui/card/Card.tsx +380 -0
  72. package/src/components/ui/card/index.ts +20 -0
  73. package/src/components/ui/checkbox/Checkbox.stories.tsx +126 -0
  74. package/src/components/ui/checkbox/Checkbox.test.tsx +152 -0
  75. package/src/components/ui/checkbox/Checkbox.tsx +163 -0
  76. package/src/components/ui/checkbox/index.ts +2 -0
  77. package/src/components/ui/chip/Chip.stories.tsx +112 -0
  78. package/src/components/ui/chip/Chip.test.tsx +119 -0
  79. package/src/components/ui/chip/Chip.tsx +151 -0
  80. package/src/components/ui/chip/index.ts +2 -0
  81. package/src/components/ui/collapse/Collapse.stories.tsx +313 -0
  82. package/src/components/ui/collapse/Collapse.test.tsx +298 -0
  83. package/src/components/ui/collapse/Collapse.tsx +275 -0
  84. package/src/components/ui/collapse/index.ts +18 -0
  85. package/src/components/ui/data-row/DataRow.stories.tsx +78 -0
  86. package/src/components/ui/data-row/DataRow.test.tsx +78 -0
  87. package/src/components/ui/data-row/DataRow.tsx +29 -0
  88. package/src/components/ui/data-row/index.ts +2 -0
  89. package/src/components/ui/divider/Divider.stories.tsx +71 -0
  90. package/src/components/ui/divider/Divider.test.tsx +55 -0
  91. package/src/components/ui/divider/Divider.tsx +37 -0
  92. package/src/components/ui/divider/index.ts +2 -0
  93. package/src/components/ui/drawer/Drawer.stories.tsx +228 -0
  94. package/src/components/ui/drawer/Drawer.test.tsx +142 -0
  95. package/src/components/ui/drawer/Drawer.tsx +228 -0
  96. package/src/components/ui/drawer/index.ts +9 -0
  97. package/src/components/ui/form-field/FormField.stories.tsx +260 -0
  98. package/src/components/ui/form-field/FormField.test.tsx +280 -0
  99. package/src/components/ui/form-field/FormField.tsx +308 -0
  100. package/src/components/ui/form-field/index.ts +2 -0
  101. package/src/components/ui/help-tip/HelpTip.stories.tsx +250 -0
  102. package/src/components/ui/help-tip/HelpTip.test.tsx +198 -0
  103. package/src/components/ui/help-tip/HelpTip.tsx +229 -0
  104. package/src/components/ui/help-tip/index.ts +2 -0
  105. package/src/components/ui/icon-box/IconBox.stories.tsx +139 -0
  106. package/src/components/ui/icon-box/IconBox.test.tsx +120 -0
  107. package/src/components/ui/icon-box/IconBox.tsx +57 -0
  108. package/src/components/ui/icon-box/index.ts +1 -0
  109. package/src/components/ui/index.ts +36 -0
  110. package/src/components/ui/input/Input.stories.tsx +192 -0
  111. package/src/components/ui/input/Input.test.tsx +86 -0
  112. package/src/components/ui/input/Input.tsx +273 -0
  113. package/src/components/ui/input/index.ts +2 -0
  114. package/src/components/ui/link/Link.stories.tsx +78 -0
  115. package/src/components/ui/link/Link.test.tsx +94 -0
  116. package/src/components/ui/link/Link.tsx +86 -0
  117. package/src/components/ui/link/index.ts +2 -0
  118. package/src/components/ui/list-item/ListItem.stories.tsx +146 -0
  119. package/src/components/ui/list-item/ListItem.test.tsx +128 -0
  120. package/src/components/ui/list-item/ListItem.tsx +89 -0
  121. package/src/components/ui/list-item/index.ts +14 -0
  122. package/src/components/ui/menu/Menu.stories.tsx +180 -0
  123. package/src/components/ui/menu/Menu.test.tsx +353 -0
  124. package/src/components/ui/menu/Menu.tsx +222 -0
  125. package/src/components/ui/menu/index.ts +2 -0
  126. package/src/components/ui/modal/Modal.stories.tsx +350 -0
  127. package/src/components/ui/modal/Modal.test.tsx +159 -0
  128. package/src/components/ui/modal/Modal.tsx +254 -0
  129. package/src/components/ui/modal/index.ts +19 -0
  130. package/src/components/ui/popover/Popover.stories.tsx +190 -0
  131. package/src/components/ui/popover/Popover.test.tsx +277 -0
  132. package/src/components/ui/popover/Popover.tsx +162 -0
  133. package/src/components/ui/popover/index.ts +2 -0
  134. package/src/components/ui/progress/Progress.stories.tsx +190 -0
  135. package/src/components/ui/progress/Progress.test.tsx +181 -0
  136. package/src/components/ui/progress/Progress.tsx +320 -0
  137. package/src/components/ui/progress/index.ts +9 -0
  138. package/src/components/ui/radio/Radio.stories.tsx +199 -0
  139. package/src/components/ui/radio/Radio.test.tsx +166 -0
  140. package/src/components/ui/radio/Radio.tsx +200 -0
  141. package/src/components/ui/radio/index.ts +2 -0
  142. package/src/components/ui/section/Section.stories.tsx +111 -0
  143. package/src/components/ui/section/Section.test.tsx +121 -0
  144. package/src/components/ui/section/Section.tsx +52 -0
  145. package/src/components/ui/section/index.ts +6 -0
  146. package/src/components/ui/select/Select.stories.tsx +286 -0
  147. package/src/components/ui/select/Select.test.tsx +180 -0
  148. package/src/components/ui/select/Select.tsx +236 -0
  149. package/src/components/ui/select/index.ts +2 -0
  150. package/src/components/ui/skeleton/Skeleton.stories.tsx +153 -0
  151. package/src/components/ui/skeleton/Skeleton.test.tsx +162 -0
  152. package/src/components/ui/skeleton/Skeleton.tsx +229 -0
  153. package/src/components/ui/skeleton/index.ts +16 -0
  154. package/src/components/ui/spinner/Spinner.stories.tsx +67 -0
  155. package/src/components/ui/spinner/Spinner.test.tsx +67 -0
  156. package/src/components/ui/spinner/Spinner.tsx +72 -0
  157. package/src/components/ui/spinner/index.ts +2 -0
  158. package/src/components/ui/stack/Stack.stories.tsx +127 -0
  159. package/src/components/ui/stack/Stack.test.tsx +184 -0
  160. package/src/components/ui/stack/Stack.tsx +76 -0
  161. package/src/components/ui/stack/index.ts +2 -0
  162. package/src/components/ui/surface/Surface.stories.tsx +91 -0
  163. package/src/components/ui/surface/Surface.test.tsx +63 -0
  164. package/src/components/ui/surface/Surface.tsx +51 -0
  165. package/src/components/ui/surface/index.ts +1 -0
  166. package/src/components/ui/switch/Switch.stories.tsx +111 -0
  167. package/src/components/ui/switch/Switch.test.tsx +112 -0
  168. package/src/components/ui/switch/Switch.tsx +103 -0
  169. package/src/components/ui/switch/index.ts +2 -0
  170. package/src/components/ui/tabs/Tabs.stories.tsx +213 -0
  171. package/src/components/ui/tabs/Tabs.test.tsx +192 -0
  172. package/src/components/ui/tabs/Tabs.tsx +253 -0
  173. package/src/components/ui/tabs/index.ts +16 -0
  174. package/src/components/ui/toast/Toast.stories.tsx +255 -0
  175. package/src/components/ui/toast/Toast.test.tsx +207 -0
  176. package/src/components/ui/toast/Toast.tsx +327 -0
  177. package/src/components/ui/toast/index.ts +8 -0
  178. package/src/components/ui/toolbar-button/ToolbarButton.stories.tsx +415 -0
  179. package/src/components/ui/toolbar-button/ToolbarButton.test.tsx +224 -0
  180. package/src/components/ui/toolbar-button/ToolbarButton.tsx +307 -0
  181. package/src/components/ui/toolbar-button/index.ts +7 -0
  182. package/src/components/ui/tooltip/Tooltip.stories.tsx +126 -0
  183. package/src/components/ui/tooltip/Tooltip.test.tsx +179 -0
  184. package/src/components/ui/tooltip/Tooltip.tsx +143 -0
  185. package/src/components/ui/tooltip/index.ts +2 -0
  186. package/src/index.ts +10 -0
  187. package/src/test/setup.ts +19 -0
  188. package/src/theme/Colors.stories.tsx +258 -0
  189. package/src/theme/config.ts +193 -0
  190. package/src/theme/elevation.stories.tsx +346 -0
  191. package/src/theme/elevation.test.ts +27 -0
  192. package/src/theme/elevation.ts +567 -0
  193. package/src/theme/index.ts +39 -0
  194. package/src/theme/shadows.stories.tsx +523 -0
  195. package/src/theme/shadows.ts +439 -0
  196. package/src/theme/tokens/index.ts +2 -0
  197. package/src/theme/tokens/primitives.ts +354 -0
  198. package/src/theme/tokens/semantic.ts +381 -0
  199. package/src/types/jest-axe.d.ts +16 -0
  200. package/src/types/nativewind.d.ts +54 -0
  201. package/src/utils/cn.ts +14 -0
  202. package/src/utils/colors.ts +140 -0
  203. package/src/utils/form.ts +188 -0
  204. package/src/utils/index.ts +29 -0
  205. package/src/utils/useTheme.ts +72 -0
  206. package/dist/chunk-NA3EES23.mjs.map +0 -1
@@ -0,0 +1,228 @@
1
+ import React from 'react'
2
+ import { View, Text, Pressable, Modal, ScrollView, type ViewProps } from 'react-native'
3
+ import { cn } from '../../../utils/cn'
4
+
5
+ export type DrawerPlacement = 'left' | 'right' | 'top' | 'bottom'
6
+ export type DrawerSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'
7
+
8
+ export interface DrawerProps extends ViewProps {
9
+ /** Whether the drawer is open */
10
+ isOpen: boolean
11
+ /** Callback when drawer should close */
12
+ onClose: () => void
13
+ /** Placement of the drawer */
14
+ placement?: DrawerPlacement
15
+ /** Size of the drawer */
16
+ size?: DrawerSize
17
+ /** Whether clicking the backdrop closes the drawer */
18
+ closeOnOverlayClick?: boolean
19
+ /** Whether to show the close button */
20
+ showCloseButton?: boolean
21
+ /** Title for the drawer header */
22
+ title?: string
23
+ /** Additional className for the drawer content */
24
+ className?: string
25
+ children?: React.ReactNode
26
+ }
27
+
28
+ const sizeStyles: Record<DrawerPlacement, Record<DrawerSize, string>> = {
29
+ left: {
30
+ sm: 'w-64',
31
+ md: 'w-80',
32
+ lg: 'w-96',
33
+ xl: 'w-[480px]',
34
+ full: 'w-full',
35
+ },
36
+ right: {
37
+ sm: 'w-64',
38
+ md: 'w-80',
39
+ lg: 'w-96',
40
+ xl: 'w-[480px]',
41
+ full: 'w-full',
42
+ },
43
+ top: {
44
+ sm: 'h-32',
45
+ md: 'h-48',
46
+ lg: 'h-64',
47
+ xl: 'h-96',
48
+ full: 'h-full',
49
+ },
50
+ bottom: {
51
+ sm: 'h-32',
52
+ md: 'h-48',
53
+ lg: 'h-64',
54
+ xl: 'h-96',
55
+ full: 'h-full',
56
+ },
57
+ }
58
+
59
+ const placementStyles: Record<DrawerPlacement, string> = {
60
+ left: 'left-0 top-0 bottom-0 h-full',
61
+ right: 'right-0 top-0 bottom-0 h-full',
62
+ top: 'top-0 left-0 right-0 w-full',
63
+ bottom: 'bottom-0 left-0 right-0 w-full',
64
+ }
65
+
66
+ /**
67
+ * Drawer component for side panel overlays.
68
+ *
69
+ * @example
70
+ * <Drawer
71
+ * isOpen={isOpen}
72
+ * onClose={() => setIsOpen(false)}
73
+ * title="Settings"
74
+ * placement="right"
75
+ * >
76
+ * <DrawerBody>
77
+ * <Text>Drawer content</Text>
78
+ * </DrawerBody>
79
+ * </Drawer>
80
+ */
81
+ export function Drawer({
82
+ isOpen,
83
+ onClose,
84
+ placement = 'right',
85
+ size = 'md',
86
+ closeOnOverlayClick = true,
87
+ showCloseButton = true,
88
+ title,
89
+ className,
90
+ children,
91
+ ...props
92
+ }: DrawerProps) {
93
+ if (!isOpen) return null
94
+
95
+ const handleOverlayPress = () => {
96
+ if (closeOnOverlayClick) {
97
+ onClose()
98
+ }
99
+ }
100
+
101
+ return (
102
+ <Modal
103
+ visible={isOpen}
104
+ transparent
105
+ animationType="fade"
106
+ onRequestClose={onClose}
107
+ >
108
+ <View className="flex-1">
109
+ {/* Backdrop */}
110
+ <Pressable
111
+ onPress={handleOverlayPress}
112
+ className="absolute inset-0 bg-black/50"
113
+ />
114
+
115
+ {/* Drawer Panel */}
116
+ <View
117
+ className={cn(
118
+ 'absolute bg-surface-elevated shadow-2xl',
119
+ placementStyles[placement],
120
+ sizeStyles[placement][size],
121
+ className
122
+ )}
123
+ accessibilityRole={'dialog' as any}
124
+ {...props}
125
+ >
126
+ {/* Header */}
127
+ {(title || showCloseButton) && (
128
+ <View className="flex-row items-center justify-between px-4 py-3 border-b border-border-default">
129
+ {title && (
130
+ <Text className="text-lg font-semibold text-text-primary">
131
+ {title}
132
+ </Text>
133
+ )}
134
+ {showCloseButton && (
135
+ <Pressable
136
+ onPress={onClose}
137
+ className="p-2 -m-2 rounded-full web:hover:bg-interactive-hover"
138
+ accessibilityLabel="Close drawer"
139
+ >
140
+ <Text className="text-text-secondary text-xl">×</Text>
141
+ </Pressable>
142
+ )}
143
+ </View>
144
+ )}
145
+
146
+ {/* Content */}
147
+ <View className="flex-1">
148
+ {children}
149
+ </View>
150
+ </View>
151
+ </View>
152
+ </Modal>
153
+ )
154
+ }
155
+
156
+ export interface DrawerHeaderProps extends ViewProps {
157
+ /** Additional className */
158
+ className?: string
159
+ children?: React.ReactNode
160
+ }
161
+
162
+ /**
163
+ * Header section for the drawer.
164
+ */
165
+ export function DrawerHeader({ className, children, ...props }: DrawerHeaderProps) {
166
+ return (
167
+ <View
168
+ className={cn('px-4 py-3 border-b border-border-default', className)}
169
+ {...props}
170
+ >
171
+ {children}
172
+ </View>
173
+ )
174
+ }
175
+
176
+ export interface DrawerBodyProps extends ViewProps {
177
+ /** Whether the body should scroll */
178
+ scrollable?: boolean
179
+ /** Additional className */
180
+ className?: string
181
+ children?: React.ReactNode
182
+ }
183
+
184
+ /**
185
+ * Body/content section for the drawer.
186
+ */
187
+ export function DrawerBody({ scrollable = true, className, children, ...props }: DrawerBodyProps) {
188
+ if (scrollable) {
189
+ return (
190
+ <ScrollView
191
+ className={cn('flex-1 p-4', className)}
192
+ {...props}
193
+ >
194
+ {children}
195
+ </ScrollView>
196
+ )
197
+ }
198
+
199
+ return (
200
+ <View className={cn('flex-1 p-4', className)} {...props}>
201
+ {children}
202
+ </View>
203
+ )
204
+ }
205
+
206
+ export interface DrawerFooterProps extends ViewProps {
207
+ /** Additional className */
208
+ className?: string
209
+ children?: React.ReactNode
210
+ }
211
+
212
+ /**
213
+ * Footer section for the drawer, typically for action buttons.
214
+ */
215
+ export function DrawerFooter({ className, children, ...props }: DrawerFooterProps) {
216
+ return (
217
+ <View
218
+ className={cn(
219
+ 'flex-row items-center justify-end gap-3',
220
+ 'px-4 py-3 border-t border-border-default',
221
+ className
222
+ )}
223
+ {...props}
224
+ >
225
+ {children}
226
+ </View>
227
+ )
228
+ }
@@ -0,0 +1,9 @@
1
+ export { Drawer, DrawerHeader, DrawerBody, DrawerFooter } from './Drawer'
2
+ export type {
3
+ DrawerProps,
4
+ DrawerHeaderProps,
5
+ DrawerBodyProps,
6
+ DrawerFooterProps,
7
+ DrawerPlacement,
8
+ DrawerSize,
9
+ } from './Drawer'
@@ -0,0 +1,260 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite'
2
+ import { View, Text, TextInput } from 'react-native'
3
+ import { FormField, FormSection, FormActions, FormRow } from './FormField'
4
+ import { Button, ButtonText } from '../button'
5
+ import { Input } from '../input'
6
+
7
+ const meta: Meta<typeof FormField> = {
8
+ title: 'Components/FormField',
9
+ component: FormField,
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ labelSize: {
13
+ control: 'select',
14
+ options: ['sm', 'md', 'lg'],
15
+ },
16
+ orientation: {
17
+ control: 'select',
18
+ options: ['vertical', 'horizontal'],
19
+ },
20
+ isRequired: {
21
+ control: 'boolean',
22
+ },
23
+ isDisabled: {
24
+ control: 'boolean',
25
+ },
26
+ },
27
+ }
28
+
29
+ export default meta
30
+ type Story = StoryObj<typeof FormField>
31
+
32
+ // Simple input for stories
33
+ function SimpleInput({ isInvalid, isDisabled, ...props }: any) {
34
+ return (
35
+ <View
36
+ className={`border rounded-md px-3 py-2 bg-surface-input ${
37
+ isInvalid ? 'border-status-error' : 'border-border-input'
38
+ } ${isDisabled ? 'opacity-50' : ''}`}
39
+ >
40
+ <TextInput
41
+ className="text-text-primary"
42
+ placeholderTextColor="var(--color-text-tertiary)"
43
+ editable={!isDisabled}
44
+ {...props}
45
+ />
46
+ </View>
47
+ )
48
+ }
49
+
50
+ export const Default: Story = {
51
+ render: () => (
52
+ <View className="w-80">
53
+ <FormField label="Email Address">
54
+ <SimpleInput placeholder="Enter your email" />
55
+ </FormField>
56
+ </View>
57
+ ),
58
+ }
59
+
60
+ export const Required: Story = {
61
+ render: () => (
62
+ <View className="w-80">
63
+ <FormField label="Email Address" isRequired>
64
+ <SimpleInput placeholder="Enter your email" />
65
+ </FormField>
66
+ </View>
67
+ ),
68
+ }
69
+
70
+ export const WithHelperText: Story = {
71
+ render: () => (
72
+ <View className="w-80">
73
+ <FormField
74
+ label="Username"
75
+ helperText="Choose a unique username between 3-20 characters"
76
+ >
77
+ <SimpleInput placeholder="Enter username" />
78
+ </FormField>
79
+ </View>
80
+ ),
81
+ }
82
+
83
+ export const WithError: Story = {
84
+ render: () => (
85
+ <View className="w-80">
86
+ <FormField
87
+ label="Password"
88
+ isRequired
89
+ errorMessage="Password must be at least 8 characters"
90
+ >
91
+ <SimpleInput placeholder="Enter password" isInvalid />
92
+ </FormField>
93
+ </View>
94
+ ),
95
+ }
96
+
97
+ export const Disabled: Story = {
98
+ render: () => (
99
+ <View className="w-80">
100
+ <FormField label="Email Address" isDisabled>
101
+ <SimpleInput placeholder="Enter your email" isDisabled />
102
+ </FormField>
103
+ </View>
104
+ ),
105
+ }
106
+
107
+ export const LabelSizes: Story = {
108
+ render: () => (
109
+ <View className="gap-6 w-80">
110
+ <FormField label="Small Label" labelSize="sm">
111
+ <SimpleInput placeholder="Small" />
112
+ </FormField>
113
+ <FormField label="Medium Label" labelSize="md">
114
+ <SimpleInput placeholder="Medium" />
115
+ </FormField>
116
+ <FormField label="Large Label" labelSize="lg">
117
+ <SimpleInput placeholder="Large" />
118
+ </FormField>
119
+ </View>
120
+ ),
121
+ }
122
+
123
+ export const HorizontalLayout: Story = {
124
+ render: () => (
125
+ <View className="gap-4 w-96">
126
+ <FormField label="Name" orientation="horizontal" labelWidth={100}>
127
+ <SimpleInput placeholder="Enter name" />
128
+ </FormField>
129
+ <FormField label="Email" orientation="horizontal" labelWidth={100} isRequired>
130
+ <SimpleInput placeholder="Enter email" />
131
+ </FormField>
132
+ <FormField
133
+ label="Bio"
134
+ orientation="horizontal"
135
+ labelWidth={100}
136
+ helperText="Brief description about yourself"
137
+ >
138
+ <SimpleInput placeholder="Enter bio" />
139
+ </FormField>
140
+ </View>
141
+ ),
142
+ }
143
+
144
+ export const FormRowExample: Story = {
145
+ render: () => (
146
+ <View className="w-full max-w-lg">
147
+ <FormRow>
148
+ <FormField label="First Name" isRequired className="flex-1">
149
+ <SimpleInput placeholder="John" />
150
+ </FormField>
151
+ <FormField label="Last Name" isRequired className="flex-1">
152
+ <SimpleInput placeholder="Doe" />
153
+ </FormField>
154
+ </FormRow>
155
+ </View>
156
+ ),
157
+ }
158
+
159
+ export const FormSectionExample: Story = {
160
+ render: () => (
161
+ <View className="w-full max-w-lg">
162
+ <FormSection
163
+ title="Personal Information"
164
+ description="Please provide your personal details"
165
+ >
166
+ <FormRow>
167
+ <FormField label="First Name" isRequired className="flex-1">
168
+ <SimpleInput placeholder="John" />
169
+ </FormField>
170
+ <FormField label="Last Name" isRequired className="flex-1">
171
+ <SimpleInput placeholder="Doe" />
172
+ </FormField>
173
+ </FormRow>
174
+ <FormField label="Email" isRequired helperText="We'll use this for notifications">
175
+ <SimpleInput placeholder="john@example.com" />
176
+ </FormField>
177
+ </FormSection>
178
+ </View>
179
+ ),
180
+ }
181
+
182
+ export const CompleteFormExample: Story = {
183
+ render: () => (
184
+ <View className="w-full max-w-lg p-6 bg-surface-base rounded-lg">
185
+ <FormSection title="Create Account" description="Fill in the details to create your account">
186
+ <FormRow>
187
+ <FormField label="First Name" isRequired className="flex-1">
188
+ <SimpleInput placeholder="John" />
189
+ </FormField>
190
+ <FormField label="Last Name" isRequired className="flex-1">
191
+ <SimpleInput placeholder="Doe" />
192
+ </FormField>
193
+ </FormRow>
194
+
195
+ <FormField label="Email" isRequired>
196
+ <SimpleInput placeholder="john@example.com" />
197
+ </FormField>
198
+
199
+ <FormField
200
+ label="Password"
201
+ isRequired
202
+ helperText="At least 8 characters with one uppercase and number"
203
+ >
204
+ <SimpleInput placeholder="••••••••" secureTextEntry />
205
+ </FormField>
206
+
207
+ <FormField label="Confirm Password" isRequired>
208
+ <SimpleInput placeholder="••••••••" secureTextEntry />
209
+ </FormField>
210
+ </FormSection>
211
+
212
+ <FormSection title="Preferences" description="Customize your experience">
213
+ <FormField label="Company (optional)">
214
+ <SimpleInput placeholder="Acme Inc." />
215
+ </FormField>
216
+
217
+ <FormField label="Timezone" helperText="Select your local timezone">
218
+ <SimpleInput placeholder="America/New_York" />
219
+ </FormField>
220
+ </FormSection>
221
+
222
+ <FormActions align="right">
223
+ <Button variant="ghost">
224
+ <ButtonText>Cancel</ButtonText>
225
+ </Button>
226
+ <Button>
227
+ <ButtonText>Create Account</ButtonText>
228
+ </Button>
229
+ </FormActions>
230
+ </View>
231
+ ),
232
+ }
233
+
234
+ export const ValidationStates: Story = {
235
+ render: () => (
236
+ <View className="gap-6 w-80">
237
+ <FormField label="Valid Input" helperText="This field is valid">
238
+ <View className="border border-status-success rounded-md px-3 py-2 bg-surface-input">
239
+ <Text className="text-text-primary">valid@email.com</Text>
240
+ </View>
241
+ </FormField>
242
+
243
+ <FormField
244
+ label="Invalid Input"
245
+ isRequired
246
+ errorMessage="Please enter a valid email address"
247
+ >
248
+ <View className="border border-status-error rounded-md px-3 py-2 bg-surface-input">
249
+ <Text className="text-text-primary">not-an-email</Text>
250
+ </View>
251
+ </FormField>
252
+
253
+ <FormField label="Disabled Input" isDisabled>
254
+ <View className="border border-border-input rounded-md px-3 py-2 bg-surface-input opacity-50">
255
+ <Text className="text-text-tertiary">Disabled value</Text>
256
+ </View>
257
+ </FormField>
258
+ </View>
259
+ ),
260
+ }