@butternutbox/pawprint-native 0.0.1 → 0.1.0

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 (182) hide show
  1. package/.turbo/turbo-build.log +15 -15
  2. package/CHANGELOG.md +16 -0
  3. package/COMPONENT_GUIDELINES.md +111 -4
  4. package/dist/index.cjs +12370 -1455
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +1110 -11
  7. package/dist/index.d.ts +1110 -11
  8. package/dist/index.js +12324 -1455
  9. package/dist/index.js.map +1 -1
  10. package/package.json +28 -9
  11. package/src/__mocks__/asset-stub.ts +1 -0
  12. package/src/__mocks__/emotion-native.tsx +18 -0
  13. package/src/__mocks__/react-native-gesture-handler.tsx +41 -0
  14. package/src/__mocks__/react-native-reanimated.tsx +79 -0
  15. package/src/__mocks__/react-native-safe-area-context.tsx +6 -0
  16. package/src/__mocks__/react-native-svg.tsx +27 -0
  17. package/src/__mocks__/react-native-worklets.tsx +11 -0
  18. package/src/__mocks__/react-native.tsx +338 -0
  19. package/src/__mocks__/rn-primitives/avatar.tsx +24 -0
  20. package/src/__mocks__/rn-primitives/checkbox.tsx +19 -0
  21. package/src/__mocks__/rn-primitives/select.tsx +116 -0
  22. package/src/__mocks__/rn-primitives/slider.tsx +40 -0
  23. package/src/__mocks__/rn-primitives/slot.tsx +30 -0
  24. package/src/__mocks__/rn-primitives/switch.tsx +24 -0
  25. package/src/__mocks__/rn-primitives/toggle.tsx +16 -0
  26. package/src/components/atoms/Avatar/Avatar.stories.tsx +57 -49
  27. package/src/components/atoms/Avatar/Avatar.test.tsx +269 -0
  28. package/src/components/atoms/Avatar/Avatar.tsx +68 -22
  29. package/src/components/atoms/Avatar/index.ts +1 -6
  30. package/src/components/atoms/Badge/Badge.stories.tsx +5 -29
  31. package/src/components/atoms/Badge/Badge.test.tsx +90 -0
  32. package/src/components/atoms/Button/Button.test.tsx +123 -0
  33. package/src/components/atoms/Button/Button.tsx +1 -1
  34. package/src/components/atoms/CarouselControls/CarouselControls.stories.tsx +217 -0
  35. package/src/components/atoms/CarouselControls/CarouselControls.tsx +127 -0
  36. package/src/components/atoms/CarouselControls/index.ts +2 -0
  37. package/src/components/atoms/Hint/Hint.test.tsx +36 -0
  38. package/src/components/atoms/Icon/Icon.test.tsx +98 -0
  39. package/src/components/atoms/Icon/Icon.tsx +5 -1
  40. package/src/components/atoms/IconButton/IconButton.test.tsx +101 -0
  41. package/src/components/atoms/Illustration/Illustration.test.tsx +55 -0
  42. package/src/components/atoms/Input/Input.stories.tsx +129 -86
  43. package/src/components/atoms/Input/Input.test.tsx +306 -0
  44. package/src/components/atoms/Input/Input.tsx +9 -1
  45. package/src/components/atoms/Input/InputField.tsx +226 -74
  46. package/src/components/atoms/Link/Link.test.tsx +89 -0
  47. package/src/components/atoms/Logo/Logo.registry.ts +30 -5
  48. package/src/components/atoms/Logo/Logo.stories.tsx +108 -0
  49. package/src/components/atoms/Logo/Logo.test.tsx +56 -0
  50. package/src/components/atoms/Logo/assets/BCorp.tsx +113 -0
  51. package/src/components/atoms/Logo/assets/ButternutFavicon.tsx +33 -0
  52. package/src/components/atoms/Logo/assets/ButternutPrimary.tsx +294 -0
  53. package/src/components/atoms/Logo/assets/ButternutTabbedBottom.tsx +294 -0
  54. package/src/components/atoms/Logo/assets/ButternutTabbedTop.tsx +294 -0
  55. package/src/components/atoms/Logo/assets/ButternutWordmark.tsx +274 -0
  56. package/src/components/atoms/Logo/assets/PsiBufetFavicon.tsx +45 -0
  57. package/src/components/atoms/Logo/assets/PsiBufetPrimary.tsx +218 -0
  58. package/src/components/atoms/Logo/assets/PsiBufetTabbedBottom.tsx +218 -0
  59. package/src/components/atoms/Logo/assets/PsiBufetTabbedTop.tsx +218 -0
  60. package/src/components/atoms/Logo/assets/PsiBufetWordmark.tsx +195 -0
  61. package/src/components/atoms/Logo/assets/index.ts +11 -0
  62. package/src/components/atoms/NumberInput/NumberInput.stories.tsx +183 -0
  63. package/src/components/atoms/NumberInput/NumberInput.test.tsx +261 -0
  64. package/src/components/atoms/NumberInput/NumberInput.tsx +129 -0
  65. package/src/components/atoms/NumberInput/NumberInputField.tsx +77 -0
  66. package/src/components/atoms/NumberInput/index.ts +4 -0
  67. package/src/components/atoms/Spinner/Spinner.test.tsx +46 -0
  68. package/src/components/atoms/Spinner/Spinner.tsx +14 -5
  69. package/src/components/atoms/Switch/Switch.test.tsx +92 -0
  70. package/src/components/atoms/Switch/Switch.tsx +16 -13
  71. package/src/components/atoms/Tag/Tag.test.tsx +70 -0
  72. package/src/components/atoms/TextArea/TextArea.stories.tsx +303 -0
  73. package/src/components/atoms/TextArea/TextArea.test.tsx +416 -0
  74. package/src/components/atoms/TextArea/TextArea.tsx +171 -0
  75. package/src/components/atoms/TextArea/TextAreaField.tsx +304 -0
  76. package/src/components/atoms/TextArea/TextAreaLabel.tsx +103 -0
  77. package/src/components/atoms/TextArea/index.ts +6 -0
  78. package/src/components/atoms/Typography/Typography.test.tsx +94 -0
  79. package/src/components/atoms/index.ts +3 -0
  80. package/src/components/molecules/Accordion/Accordion.stories.tsx +177 -0
  81. package/src/components/molecules/Accordion/Accordion.test.tsx +185 -0
  82. package/src/components/molecules/Accordion/Accordion.tsx +284 -0
  83. package/src/components/molecules/Accordion/index.ts +6 -0
  84. package/src/components/molecules/Animated/Animated.stories.tsx +254 -0
  85. package/src/components/molecules/Animated/Animated.tsx +283 -0
  86. package/src/components/molecules/Animated/index.ts +10 -0
  87. package/src/components/molecules/ButtonDock/ButtonDock.test.tsx +83 -0
  88. package/src/components/molecules/ButtonGroup/ButtonGroup.stories.tsx +8 -14
  89. package/src/components/molecules/ButtonGroup/ButtonGroup.test.tsx +73 -0
  90. package/src/components/molecules/ButtonGroup/ButtonGroup.tsx +25 -3
  91. package/src/components/molecules/Checkbox/Checkbox.stories.tsx +72 -0
  92. package/src/components/molecules/Checkbox/Checkbox.test.tsx +117 -0
  93. package/src/components/molecules/Checkbox/Checkbox.tsx +101 -95
  94. package/src/components/molecules/CopyField/CopyField.stories.tsx +313 -0
  95. package/src/components/molecules/CopyField/CopyField.test.tsx +431 -0
  96. package/src/components/molecules/CopyField/CopyField.tsx +156 -0
  97. package/src/components/molecules/CopyField/CopyFieldInput.tsx +127 -0
  98. package/src/components/molecules/CopyField/hooks/index.ts +1 -0
  99. package/src/components/molecules/CopyField/hooks/useCopyField.ts +25 -0
  100. package/src/components/molecules/CopyField/index.ts +4 -0
  101. package/src/components/molecules/DatePicker/DatePicker.stories.tsx +298 -0
  102. package/src/components/molecules/DatePicker/DatePicker.test.tsx +201 -0
  103. package/src/components/molecules/DatePicker/DatePicker.tsx +590 -0
  104. package/src/components/molecules/DatePicker/index.ts +2 -0
  105. package/src/components/molecules/Drawer/Drawer.stories.tsx +285 -0
  106. package/src/components/molecules/Drawer/Drawer.test.tsx +180 -0
  107. package/src/components/molecules/Drawer/Drawer.tsx +187 -0
  108. package/src/components/molecules/Drawer/DrawerBody.tsx +80 -0
  109. package/src/components/molecules/Drawer/DrawerClose.tsx +76 -0
  110. package/src/components/molecules/Drawer/DrawerContent.tsx +339 -0
  111. package/src/components/molecules/Drawer/DrawerContext.ts +19 -0
  112. package/src/components/molecules/Drawer/DrawerDescription.tsx +31 -0
  113. package/src/components/molecules/Drawer/DrawerDragContext.ts +11 -0
  114. package/src/components/molecules/Drawer/DrawerFooter.tsx +49 -0
  115. package/src/components/molecules/Drawer/DrawerFooterContext.ts +6 -0
  116. package/src/components/molecules/Drawer/DrawerGrabber.tsx +62 -0
  117. package/src/components/molecules/Drawer/DrawerHeader.tsx +244 -0
  118. package/src/components/molecules/Drawer/DrawerHeaderContext.ts +13 -0
  119. package/src/components/molecules/Drawer/DrawerOverlay.tsx +53 -0
  120. package/src/components/molecules/Drawer/DrawerTitle.tsx +32 -0
  121. package/src/components/molecules/Drawer/index.ts +12 -0
  122. package/src/components/molecules/FilterTab/FilterTab.stories.tsx +210 -0
  123. package/src/components/molecules/FilterTab/FilterTab.tsx +310 -0
  124. package/src/components/molecules/FilterTab/index.ts +2 -0
  125. package/src/components/molecules/MessageCard/MessageCard.stories.tsx +169 -0
  126. package/src/components/molecules/MessageCard/MessageCard.tsx +362 -0
  127. package/src/components/molecules/MessageCard/index.ts +10 -0
  128. package/src/components/molecules/Notification/Notification.stories.tsx +219 -0
  129. package/src/components/molecules/Notification/Notification.tsx +426 -0
  130. package/src/components/molecules/Notification/index.ts +2 -0
  131. package/src/components/molecules/NumberField/NumberField.stories.tsx +231 -0
  132. package/src/components/molecules/NumberField/NumberField.tsx +186 -0
  133. package/src/components/molecules/NumberField/NumberFieldInput.tsx +287 -0
  134. package/src/components/molecules/NumberField/index.ts +2 -0
  135. package/src/components/molecules/PasswordField/PasswordField.stories.tsx +362 -0
  136. package/src/components/molecules/PasswordField/PasswordField.test.tsx +369 -0
  137. package/src/components/molecules/PasswordField/PasswordField.tsx +194 -0
  138. package/src/components/molecules/PasswordField/PasswordFieldError.tsx +52 -0
  139. package/src/components/molecules/PasswordField/PasswordFieldInput.tsx +73 -0
  140. package/src/components/molecules/PasswordField/PasswordFieldRequirements.tsx +92 -0
  141. package/src/components/molecules/PasswordField/hooks/index.ts +2 -0
  142. package/src/components/molecules/PasswordField/hooks/usePasswordField.ts +113 -0
  143. package/src/components/molecules/PasswordField/index.ts +10 -0
  144. package/src/components/molecules/PictureSelector/PictureSelector.stories.tsx +243 -0
  145. package/src/components/molecules/PictureSelector/PictureSelector.tsx +313 -0
  146. package/src/components/molecules/PictureSelector/index.ts +5 -0
  147. package/src/components/molecules/Progress/Progress.stories.tsx +145 -0
  148. package/src/components/molecules/Progress/Progress.tsx +184 -0
  149. package/src/components/molecules/Progress/index.ts +2 -0
  150. package/src/components/molecules/Radio/Radio.test.tsx +104 -0
  151. package/src/components/molecules/Radio/Radio.tsx +1 -2
  152. package/src/components/molecules/SearchField/SearchField.stories.tsx +242 -0
  153. package/src/components/molecules/SearchField/SearchField.test.tsx +318 -0
  154. package/src/components/molecules/SearchField/SearchField.tsx +143 -0
  155. package/src/components/molecules/SearchField/SearchFieldInput.tsx +63 -0
  156. package/src/components/molecules/SearchField/hooks/index.ts +1 -0
  157. package/src/components/molecules/SearchField/hooks/useSearchField.ts +56 -0
  158. package/src/components/molecules/SearchField/index.ts +4 -0
  159. package/src/components/molecules/SegmentedControl/SegmentedControl.stories.tsx +31 -8
  160. package/src/components/molecules/SegmentedControl/SegmentedControl.test.tsx +141 -0
  161. package/src/components/molecules/SegmentedControl/SegmentedControl.tsx +237 -23
  162. package/src/components/molecules/SelectField/SelectField.stories.tsx +320 -0
  163. package/src/components/molecules/SelectField/SelectField.test.tsx +254 -0
  164. package/src/components/molecules/SelectField/SelectField.tsx +236 -0
  165. package/src/components/molecules/SelectField/SelectFieldContent.tsx +85 -0
  166. package/src/components/molecules/SelectField/SelectFieldItem.tsx +133 -0
  167. package/src/components/molecules/SelectField/SelectFieldTrigger.tsx +170 -0
  168. package/src/components/molecules/SelectField/SelectFieldValue.tsx +31 -0
  169. package/src/components/molecules/SelectField/hooks/index.ts +2 -0
  170. package/src/components/molecules/SelectField/hooks/useSelectField.ts +84 -0
  171. package/src/components/molecules/SelectField/index.ts +10 -0
  172. package/src/components/molecules/Slider/Slider.test.tsx +102 -0
  173. package/src/components/molecules/Slider/Slider.tsx +293 -180
  174. package/src/components/molecules/Tooltip/Tooltip.stories.tsx +168 -0
  175. package/src/components/molecules/Tooltip/Tooltip.tsx +326 -0
  176. package/src/components/molecules/Tooltip/index.ts +2 -0
  177. package/src/components/molecules/index.ts +15 -0
  178. package/src/test-utils.tsx +20 -0
  179. package/tsconfig.json +1 -1
  180. package/tsup.config.ts +16 -2
  181. package/vitest.config.ts +114 -0
  182. package/vitest.setup.ts +16 -0
@@ -0,0 +1,313 @@
1
+ import React, { useState } from "react"
2
+ import { View, StyleSheet } from "react-native"
3
+ import { CopyField } from "./CopyField"
4
+ import { Typography } from "../../atoms/Typography"
5
+ import { useCopyField } from "./hooks/useCopyField"
6
+ import type { InputState } from "../../atoms/Input/InputField"
7
+ import { Icon } from "../../atoms/Icon"
8
+ import { Lock } from "@butternutbox/pawprint-icons/core"
9
+
10
+ export default {
11
+ title: "Molecules/CopyField",
12
+ component: CopyField,
13
+ parameters: {
14
+ docs: {
15
+ description: {
16
+ component:
17
+ "Copy field component with a copy button that copies the input value to clipboard. Supports both simple props API and compound component API."
18
+ }
19
+ }
20
+ },
21
+ argTypes: {
22
+ label: {
23
+ control: { type: "text" },
24
+ description: "Label text"
25
+ },
26
+ placeholder: {
27
+ control: { type: "text" },
28
+ description: "Placeholder text"
29
+ },
30
+ description: {
31
+ control: { type: "text" },
32
+ description: "Help text below input"
33
+ },
34
+ error: {
35
+ control: { type: "text" },
36
+ description: "Error message"
37
+ },
38
+ state: {
39
+ control: { type: "select" },
40
+ options: ["default", "error", "success"],
41
+ description: "Visual state of the input"
42
+ },
43
+ optionalText: {
44
+ control: { type: "text" },
45
+ description: "Optional text to display next to label"
46
+ },
47
+ copyButtonLabel: {
48
+ control: { type: "text" },
49
+ description: "Label for the copy button"
50
+ },
51
+ editable: {
52
+ control: { type: "boolean" },
53
+ description: "Controls whether the input is editable"
54
+ }
55
+ }
56
+ }
57
+
58
+ export const Default = () => {
59
+ const copyProps = useCopyField({
60
+ onCopy: (value) => console.log("Copied:", value) // eslint-disable-line no-console
61
+ })
62
+
63
+ return (
64
+ <View style={styles.column}>
65
+ <View style={styles.section}>
66
+ <Typography size="sm" weight="semiBold" color="tertiary">
67
+ Using useCopyField Hook
68
+ </Typography>
69
+ <CopyField
70
+ {...copyProps}
71
+ label="API Key"
72
+ placeholder="Enter your API key..."
73
+ description="Your unique API key for authentication"
74
+ leadingIcon={<Icon icon={Lock} size="md" />}
75
+ />
76
+ </View>
77
+ </View>
78
+ )
79
+ }
80
+
81
+ export const States = () => {
82
+ const defaultProps = useCopyField()
83
+ const filledProps = useCopyField({ initialValue: "sk-1234567890abcdef" })
84
+ const errorProps = useCopyField({ initialValue: "invalid-key" })
85
+ const successProps = useCopyField({ initialValue: "sk-1234567890abcdef" })
86
+
87
+ return (
88
+ <View style={styles.column}>
89
+ <View style={styles.section}>
90
+ <Typography size="sm" weight="semiBold" color="tertiary">
91
+ Default State
92
+ </Typography>
93
+ <CopyField
94
+ {...defaultProps}
95
+ label="Default"
96
+ placeholder="Enter API key..."
97
+ description="Help text"
98
+ />
99
+ </View>
100
+ <View style={styles.section}>
101
+ <Typography size="sm" weight="semiBold" color="tertiary">
102
+ Disabled
103
+ </Typography>
104
+ <CopyField
105
+ label="Disabled"
106
+ placeholder="Enter API key..."
107
+ description="Help text"
108
+ editable={false}
109
+ />
110
+ </View>
111
+ <View style={styles.section}>
112
+ <Typography size="sm" weight="semiBold" color="tertiary">
113
+ With Value
114
+ </Typography>
115
+ <CopyField
116
+ {...filledProps}
117
+ label="With Value"
118
+ placeholder="Enter API key..."
119
+ description="Copy button enabled when field has text"
120
+ />
121
+ </View>
122
+ <View style={styles.section}>
123
+ <Typography size="sm" weight="semiBold" color="tertiary">
124
+ Success State
125
+ </Typography>
126
+ <CopyField
127
+ {...successProps}
128
+ label="Success State"
129
+ placeholder="Enter API key..."
130
+ state="success"
131
+ description="API key verified"
132
+ />
133
+ </View>
134
+ <View style={styles.section}>
135
+ <Typography size="sm" weight="semiBold" color="tertiary">
136
+ Error State
137
+ </Typography>
138
+ <CopyField
139
+ {...errorProps}
140
+ label="Error State"
141
+ placeholder="Enter API key..."
142
+ state="error"
143
+ error="Invalid API key format"
144
+ description="Help text"
145
+ />
146
+ </View>
147
+ </View>
148
+ )
149
+ }
150
+
151
+ export const ManualValidation = () => {
152
+ const [apiKey, setApiKey] = useState("")
153
+ const [apiKeyState, setApiKeyState] = useState<InputState>("default")
154
+
155
+ const handleChange = (newValue: string) => {
156
+ setApiKey(newValue)
157
+
158
+ if (!newValue) {
159
+ setApiKeyState("default")
160
+ return
161
+ }
162
+
163
+ const hasMinLength = newValue.length >= 10
164
+ const hasPrefix = newValue.startsWith("sk-")
165
+ const hasValidChars = /^sk-[a-z0-9]+$/.test(newValue)
166
+
167
+ const allRequirementsMet = hasMinLength && hasPrefix && hasValidChars
168
+
169
+ setApiKeyState(allRequirementsMet ? "success" : "error")
170
+ }
171
+
172
+ return (
173
+ <View style={styles.column}>
174
+ <View style={styles.section}>
175
+ <Typography size="sm" weight="semiBold" color="tertiary">
176
+ Manual Validation with Success State
177
+ </Typography>
178
+ <CopyField
179
+ label="API Key"
180
+ placeholder="sk-xxxxxxxxxxxxxxxx"
181
+ value={apiKey}
182
+ onValueChange={handleChange}
183
+ onCopy={(value) => console.log("Copied:", value)} // eslint-disable-line no-console
184
+ state={apiKeyState}
185
+ description="Must start with 'sk-', at least 10 chars, lowercase letters and numbers only"
186
+ error="Invalid API key format"
187
+ />
188
+ </View>
189
+ </View>
190
+ )
191
+ }
192
+
193
+ export const CompoundComponentAPI = () => {
194
+ const [apiKey, setApiKey] = useState("")
195
+ const [apiKeyState, setApiKeyState] = useState<InputState>("default")
196
+
197
+ const handleChange = (newValue: string) => {
198
+ setApiKey(newValue)
199
+
200
+ if (!newValue) {
201
+ setApiKeyState("default")
202
+ return
203
+ }
204
+
205
+ const hasMinLength = newValue.length >= 10
206
+ const hasPrefix = newValue.startsWith("sk-")
207
+ const hasValidChars = /^sk-[a-z0-9]+$/.test(newValue)
208
+
209
+ const allRequirementsMet = hasMinLength && hasPrefix && hasValidChars
210
+
211
+ setApiKeyState(allRequirementsMet ? "success" : "error")
212
+ }
213
+
214
+ return (
215
+ <View style={styles.column}>
216
+ <View style={styles.section}>
217
+ <Typography size="sm" weight="semiBold" color="tertiary">
218
+ Compound Component API
219
+ </Typography>
220
+ <CopyField.Root>
221
+ <CopyField.Label state={apiKeyState}>API Key</CopyField.Label>
222
+ <CopyField.Field
223
+ placeholder="sk-xxxxxxxxxxxxxxxx"
224
+ value={apiKey}
225
+ onValueChange={handleChange}
226
+ onCopy={(value) => console.log("Copied:", value)} // eslint-disable-line no-console
227
+ state={apiKeyState}
228
+ />
229
+ <CopyField.Description state={apiKeyState}>
230
+ Must start with 'sk-' and be at least 10 characters
231
+ </CopyField.Description>
232
+ {apiKeyState === "error" && apiKey.length > 0 && (
233
+ <CopyField.Error>Invalid API key format</CopyField.Error>
234
+ )}
235
+ </CopyField.Root>
236
+ </View>
237
+ </View>
238
+ )
239
+ }
240
+
241
+ export const WithOptionalText = () => (
242
+ <View style={styles.column}>
243
+ <View style={styles.section}>
244
+ <Typography size="sm" weight="semiBold" color="tertiary">
245
+ With Optional Text
246
+ </Typography>
247
+ <CopyField
248
+ label="API Key"
249
+ optionalText="(optional)"
250
+ placeholder="Enter API key..."
251
+ description="Optional API key field"
252
+ />
253
+ </View>
254
+ </View>
255
+ )
256
+
257
+ export const Controlled = () => {
258
+ const copyProps = useCopyField({
259
+ onCopy: (value) => console.log("Copied to clipboard:", value) // eslint-disable-line no-console
260
+ })
261
+
262
+ return (
263
+ <View style={styles.column}>
264
+ <View style={styles.section}>
265
+ <Typography size="sm" weight="semiBold" color="tertiary">
266
+ Controlled: {copyProps.value || "(empty)"}
267
+ </Typography>
268
+ <CopyField
269
+ {...copyProps}
270
+ label="API Key"
271
+ placeholder="Enter API key..."
272
+ description={`Current value: "${copyProps.value || "empty"}"`}
273
+ />
274
+ </View>
275
+ </View>
276
+ )
277
+ }
278
+
279
+ export const CustomButtonLabel = () => {
280
+ const copyProps = useCopyField({ initialValue: "sk-1234567890abcdef" })
281
+
282
+ return (
283
+ <View style={styles.column}>
284
+ <View style={styles.section}>
285
+ <Typography size="sm" weight="semiBold" color="tertiary">
286
+ Custom Copy Button Label
287
+ </Typography>
288
+ <CopyField
289
+ {...copyProps}
290
+ label="API Key"
291
+ placeholder="Enter API key..."
292
+ copyButtonLabel="Copy Key"
293
+ description="Custom button label example"
294
+ />
295
+ </View>
296
+ </View>
297
+ )
298
+ }
299
+
300
+ const styles = StyleSheet.create({
301
+ container: {
302
+ width: 320
303
+ },
304
+ column: {
305
+ flexDirection: "column",
306
+ gap: 24,
307
+ width: 320
308
+ },
309
+ section: {
310
+ flexDirection: "column",
311
+ gap: 8
312
+ }
313
+ })