@retray-dev/ui-kit 1.0.0 → 1.5.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.
- package/COMPONENTS.md +120 -64
- package/README.md +18 -19
- package/dist/index.d.mts +39 -4
- package/dist/index.d.ts +39 -4
- package/dist/index.js +431 -265
- package/dist/index.mjs +430 -265
- package/package.json +20 -3
- package/src/components/Accordion/Accordion.tsx +50 -38
- package/src/components/Alert/Alert.tsx +3 -1
- package/src/components/Avatar/Avatar.tsx +5 -1
- package/src/components/Badge/Badge.tsx +1 -1
- package/src/components/Button/Button.tsx +24 -8
- package/src/components/Card/Card.tsx +2 -8
- package/src/components/Checkbox/Checkbox.tsx +35 -7
- package/src/components/EmptyState/EmptyState.tsx +1 -3
- package/src/components/Input/Input.tsx +18 -10
- package/src/components/Progress/Progress.tsx +3 -4
- package/src/components/RadioGroup/RadioGroup.tsx +72 -45
- package/src/components/Select/Select.tsx +117 -70
- package/src/components/Sheet/Sheet.tsx +9 -2
- package/src/components/Skeleton/Skeleton.tsx +36 -13
- package/src/components/Slider/Slider.tsx +5 -4
- package/src/components/Spinner/Spinner.tsx +1 -7
- package/src/components/Switch/Switch.tsx +5 -1
- package/src/components/Tabs/Tabs.tsx +82 -31
- package/src/components/Textarea/Textarea.tsx +29 -10
- package/src/components/Toast/Toast.tsx +69 -33
- package/src/components/Toggle/Toggle.tsx +32 -20
- package/src/theme/colors.ts +4 -0
- package/src/theme/types.ts +2 -0
package/COMPONENTS.md
CHANGED
|
@@ -11,22 +11,37 @@ This file is the AI reference for this package. It is shipped inside the npm pac
|
|
|
11
11
|
|
|
12
12
|
## Setup (Required)
|
|
13
13
|
|
|
14
|
-
Wrap your app root with
|
|
14
|
+
Wrap your app root with all required providers in this exact order:
|
|
15
15
|
|
|
16
16
|
```tsx
|
|
17
|
-
import {
|
|
17
|
+
import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context'
|
|
18
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
19
|
+
import { ThemeProvider, BottomSheetModalProvider, ToastProvider } from '@retray-dev/ui-kit'
|
|
18
20
|
|
|
19
|
-
export default function
|
|
21
|
+
export default function App() {
|
|
20
22
|
return (
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
|
|
24
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
25
|
+
<ThemeProvider colorScheme="system">
|
|
26
|
+
<BottomSheetModalProvider>
|
|
27
|
+
<ToastProvider>
|
|
28
|
+
{/* your app */}
|
|
29
|
+
</ToastProvider>
|
|
30
|
+
</BottomSheetModalProvider>
|
|
31
|
+
</ThemeProvider>
|
|
32
|
+
</GestureHandlerRootView>
|
|
33
|
+
</SafeAreaProvider>
|
|
26
34
|
)
|
|
27
35
|
}
|
|
28
36
|
```
|
|
29
37
|
|
|
38
|
+
**Provider order is mandatory:**
|
|
39
|
+
- `SafeAreaProvider` must be outermost — required by `useSafeAreaInsets` in `ToastProvider`
|
|
40
|
+
- `initialMetrics={initialWindowMetrics}` is required on Android to avoid a "No safe area value available" crash on first render
|
|
41
|
+
- `GestureHandlerRootView` must wrap everything — required by `@gorhom/bottom-sheet`
|
|
42
|
+
- `BottomSheetModalProvider` must be inside `GestureHandlerRootView`
|
|
43
|
+
- `ToastProvider` must be inside `SafeAreaProvider`
|
|
44
|
+
|
|
30
45
|
### ThemeProvider Props
|
|
31
46
|
|
|
32
47
|
| Prop | Type | Default | Notes |
|
|
@@ -72,7 +87,7 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
72
87
|
| `secondary` | `#f5f5f5` | `#2a2a2a` | Secondary surfaces |
|
|
73
88
|
| `secondaryForeground` | `#1a1a1a` | `#fafafa` | Text on secondary |
|
|
74
89
|
| `muted` | `#f5f5f5` | `#2a2a2a` | Muted backgrounds, skeleton fills, track fills |
|
|
75
|
-
| `mutedForeground` | `#
|
|
90
|
+
| `mutedForeground` | `#646464` | `#a3a3a3` | Placeholder text, helper text, captions (WCAG AA ≥4.5:1) |
|
|
76
91
|
| `accent` | `#f5f5f5` | `#2a2a2a` | Hover / pressed state fills |
|
|
77
92
|
| `accentForeground` | `#1a1a1a` | `#fafafa` | Text on accent |
|
|
78
93
|
| `destructive` | `#ef4444` | `#dc2626` | Error / danger / delete actions |
|
|
@@ -91,12 +106,12 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
91
106
|
|
|
92
107
|
**Import:** `import { Text } from '@retray-dev/ui-kit'`
|
|
93
108
|
**When to use:** All text in the app. Replaces React Native's `Text` with semantic variants.
|
|
94
|
-
**Extends:** `TextProps` from React Native.
|
|
109
|
+
**Extends:** `TextProps` from React Native — all native props pass through.
|
|
95
110
|
|
|
96
111
|
| Prop | Type | Default | Notes |
|
|
97
112
|
|------|------|---------|-------|
|
|
98
113
|
| variant | `'h1' \| 'h2' \| 'h3' \| 'body' \| 'caption' \| 'label'` | `'body'` | Sets font size, weight, and line height |
|
|
99
|
-
| color | `string` | — | Override the color. Defaults to `foreground`, except `caption` which
|
|
114
|
+
| color | `string` | — | Override the color. Defaults to `foreground`, except `caption` which uses `mutedForeground` |
|
|
100
115
|
|
|
101
116
|
**Sizes:**
|
|
102
117
|
- `h1`: 32px / 700 weight
|
|
@@ -127,16 +142,18 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
127
142
|
| label | `string` | required | Button text |
|
|
128
143
|
| variant | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Visual style |
|
|
129
144
|
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | — |
|
|
130
|
-
| loading | `boolean` | `false` | Replaces label with spinner and forces disabled |
|
|
131
|
-
| fullWidth | `boolean` | `false` | Stretches to container width |
|
|
145
|
+
| loading | `boolean` | `false` | Replaces label with a spinner and forces disabled state |
|
|
146
|
+
| fullWidth | `boolean` | `false` | Stretches to container width (`alignSelf: 'stretch'`) |
|
|
132
147
|
| disabled | `boolean` | — | Reduces opacity to 0.45 |
|
|
133
148
|
|
|
134
149
|
**Variants:**
|
|
135
150
|
- `primary`: filled with `primary` token — main actions
|
|
136
151
|
- `secondary`: filled with `secondary` token — less prominent actions
|
|
137
|
-
- `outline`: transparent with `border` — alternative
|
|
152
|
+
- `outline`: transparent with `border` — alternative without fill
|
|
138
153
|
- `ghost`: fully transparent — in-context or low-emphasis actions
|
|
139
154
|
|
|
155
|
+
**Animations:** Scale springs to 0.97 on `onPressIn`, back to 1.0 on `onPressOut`.
|
|
156
|
+
|
|
140
157
|
**Example:**
|
|
141
158
|
```tsx
|
|
142
159
|
<Button label="Save changes" onPress={handleSave} />
|
|
@@ -151,13 +168,15 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
151
168
|
|
|
152
169
|
**Import:** `import { Input } from '@retray-dev/ui-kit'`
|
|
153
170
|
**When to use:** Single-line text entry. Includes built-in label, error, and hint support.
|
|
154
|
-
**Extends:** `TextInputProps` from React Native.
|
|
171
|
+
**Extends:** `TextInputProps` from React Native — all native props pass through.
|
|
155
172
|
|
|
156
173
|
| Prop | Type | Default | Notes |
|
|
157
174
|
|------|------|---------|-------|
|
|
158
175
|
| label | `string` | — | Label above the input |
|
|
159
|
-
| error | `string` | — | Shows error text below; turns border red |
|
|
160
|
-
| hint | `string` | — | Helper text below (hidden when error is set) |
|
|
176
|
+
| error | `string` | — | Shows error text below; turns border red (`destructive` token) |
|
|
177
|
+
| hint | `string` | — | Helper text below (hidden when `error` is set) |
|
|
178
|
+
|
|
179
|
+
**Border colors:** `destructive` when `error` is set, `ring` when focused, `border` otherwise.
|
|
161
180
|
|
|
162
181
|
**Example:**
|
|
163
182
|
```tsx
|
|
@@ -171,15 +190,15 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
171
190
|
### Textarea
|
|
172
191
|
|
|
173
192
|
**Import:** `import { Textarea } from '@retray-dev/ui-kit'`
|
|
174
|
-
**When to use:** Multi-line text entry. Same API as Input plus `rows`.
|
|
175
|
-
**Extends:** `TextInputProps` from React Native.
|
|
193
|
+
**When to use:** Multi-line text entry. Same API as `Input` plus `rows`.
|
|
194
|
+
**Extends:** `TextInputProps` from React Native — all native props pass through.
|
|
176
195
|
|
|
177
196
|
| Prop | Type | Default | Notes |
|
|
178
197
|
|------|------|---------|-------|
|
|
179
198
|
| label | `string` | — | Label above |
|
|
180
199
|
| error | `string` | — | Error text below; red border |
|
|
181
200
|
| hint | `string` | — | Helper text below |
|
|
182
|
-
| rows | `number` | `4` | Sets
|
|
201
|
+
| rows | `number` | `4` | Sets `minHeight` (each row ≈ 28px) |
|
|
183
202
|
|
|
184
203
|
**Example:**
|
|
185
204
|
```tsx
|
|
@@ -197,6 +216,7 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
197
216
|
|------|------|---------|-------|
|
|
198
217
|
| label | `string` | required | — |
|
|
199
218
|
| variant | `'default' \| 'secondary' \| 'destructive' \| 'outline'` | `'default'` | — |
|
|
219
|
+
| style | `ViewStyle` | — | — |
|
|
200
220
|
|
|
201
221
|
**Example:**
|
|
202
222
|
```tsx
|
|
@@ -216,8 +236,9 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
216
236
|
| Prop | Type | Default | Notes |
|
|
217
237
|
|------|------|---------|-------|
|
|
218
238
|
| src | `string` | — | Image URI |
|
|
219
|
-
| fallback | `string` | — | Text
|
|
220
|
-
| size | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | sm=24, md=32, lg=48, xl=64 |
|
|
239
|
+
| fallback | `string` | — | Text shown when image fails or `src` is absent — first 2 chars, uppercased |
|
|
240
|
+
| size | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | sm=24, md=32, lg=48, xl=64 (diameter in pt) |
|
|
241
|
+
| style | `ViewStyle` | — | — |
|
|
221
242
|
|
|
222
243
|
**Example:**
|
|
223
244
|
```tsx
|
|
@@ -234,7 +255,8 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
234
255
|
|
|
235
256
|
| Prop | Type | Default | Notes |
|
|
236
257
|
|------|------|---------|-------|
|
|
237
|
-
| orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | Vertical requires a parent with defined height |
|
|
258
|
+
| orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | Vertical requires a parent with a defined height |
|
|
259
|
+
| style | `ViewStyle` | — | — |
|
|
238
260
|
|
|
239
261
|
**Example:**
|
|
240
262
|
```tsx
|
|
@@ -251,11 +273,12 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
251
273
|
### Spinner
|
|
252
274
|
|
|
253
275
|
**Import:** `import { Spinner } from '@retray-dev/ui-kit'`
|
|
254
|
-
**When to use:** Loading state indicator.
|
|
276
|
+
**When to use:** Loading state indicator. Wraps React Native's `ActivityIndicator`.
|
|
277
|
+
**Extends:** `ActivityIndicatorProps` (except `size`).
|
|
255
278
|
|
|
256
279
|
| Prop | Type | Default | Notes |
|
|
257
280
|
|------|------|---------|-------|
|
|
258
|
-
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | sm
|
|
281
|
+
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | `sm`/`md` map to RN `'small'`, `lg` maps to `'large'` |
|
|
259
282
|
| color | `string` | `primary` token | Override spinner color |
|
|
260
283
|
|
|
261
284
|
**Example:**
|
|
@@ -269,13 +292,14 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
269
292
|
### Skeleton
|
|
270
293
|
|
|
271
294
|
**Import:** `import { Skeleton } from '@retray-dev/ui-kit'`
|
|
272
|
-
**When to use:** Placeholder while content is loading. Pulses with animation.
|
|
295
|
+
**When to use:** Placeholder while content is loading. Pulses with a looping opacity animation.
|
|
273
296
|
|
|
274
297
|
| Prop | Type | Default | Notes |
|
|
275
298
|
|------|------|---------|-------|
|
|
276
299
|
| width | `number \| string` | `'100%'` | — |
|
|
277
300
|
| height | `number` | `16` | — |
|
|
278
301
|
| borderRadius | `number` | `6` | — |
|
|
302
|
+
| style | `ViewStyle` | — | — |
|
|
279
303
|
|
|
280
304
|
**Example:**
|
|
281
305
|
```tsx
|
|
@@ -294,6 +318,9 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
294
318
|
|------|------|---------|-------|
|
|
295
319
|
| value | `number` | `0` | Current value |
|
|
296
320
|
| max | `number` | `100` | Maximum value |
|
|
321
|
+
| style | `ViewStyle` | — | — |
|
|
322
|
+
|
|
323
|
+
**Animation:** Spring-animates the fill width on `value` changes (JS thread — `useNativeDriver: false`). Uses `onLayout` to capture track pixel width and interpolates to pixels (cannot animate `width: '%'`).
|
|
297
324
|
|
|
298
325
|
**Example:**
|
|
299
326
|
```tsx
|
|
@@ -326,21 +353,26 @@ All sub-components accept a `style` prop for overrides.
|
|
|
326
353
|
</Card>
|
|
327
354
|
```
|
|
328
355
|
|
|
329
|
-
**Notes:**
|
|
356
|
+
**Notes:**
|
|
357
|
+
- `CardHeader` and `CardContent` have `padding: 24`
|
|
358
|
+
- `CardFooter` has `paddingTop: 0` so it connects naturally to `CardContent`
|
|
359
|
+
- `CardTitle`: 18px / 600 weight, `cardForeground` color
|
|
360
|
+
- `CardDescription`: 14px, `mutedForeground` color
|
|
330
361
|
|
|
331
362
|
---
|
|
332
363
|
|
|
333
364
|
### Alert
|
|
334
365
|
|
|
335
366
|
**Import:** `import { Alert } from '@retray-dev/ui-kit'`
|
|
336
|
-
**When to use:** Inline feedback messages (info, success, warning, error). Not for toasts.
|
|
367
|
+
**When to use:** Inline feedback messages (info, success, warning, error). Not for transient toasts.
|
|
337
368
|
|
|
338
369
|
| Prop | Type | Default | Notes |
|
|
339
370
|
|------|------|---------|-------|
|
|
340
371
|
| title | `string` | — | Bold heading |
|
|
341
372
|
| description | `string` | — | Detail text |
|
|
342
|
-
| variant | `'default' \| 'destructive'` | `'default'` | `destructive` turns border and text
|
|
343
|
-
| icon | `ReactNode` | — | Icon placed to the left |
|
|
373
|
+
| variant | `'default' \| 'destructive'` | `'default'` | `destructive` turns border and text to `destructive` token |
|
|
374
|
+
| icon | `ReactNode` | — | Icon placed to the left of the text content |
|
|
375
|
+
| style | `ViewStyle` | — | — |
|
|
344
376
|
|
|
345
377
|
**Example:**
|
|
346
378
|
```tsx
|
|
@@ -359,8 +391,9 @@ All sub-components accept a `style` prop for overrides.
|
|
|
359
391
|
|------|------|---------|-------|
|
|
360
392
|
| title | `string` | required | — |
|
|
361
393
|
| description | `string` | — | — |
|
|
362
|
-
| icon | `ReactNode` | — | Shown in a muted square above the text |
|
|
394
|
+
| icon | `ReactNode` | — | Shown in a 48×48 muted square above the text |
|
|
363
395
|
| action | `ReactNode` | — | Usually a `Button`, placed below the text |
|
|
396
|
+
| style | `ViewStyle` | — | — |
|
|
364
397
|
|
|
365
398
|
**Example:**
|
|
366
399
|
```tsx
|
|
@@ -383,6 +416,7 @@ All sub-components accept a `style` prop for overrides.
|
|
|
383
416
|
| onCheckedChange | `(checked: boolean) => void` | — | — |
|
|
384
417
|
| label | `string` | — | Text to the right of the box |
|
|
385
418
|
| disabled | `boolean` | — | — |
|
|
419
|
+
| style | `ViewStyle` | — | — |
|
|
386
420
|
|
|
387
421
|
**Example:**
|
|
388
422
|
```tsx
|
|
@@ -395,13 +429,18 @@ const [accepted, setAccepted] = useState(false)
|
|
|
395
429
|
### Switch
|
|
396
430
|
|
|
397
431
|
**Import:** `import { Switch } from '@retray-dev/ui-kit'`
|
|
398
|
-
**When to use:** Binary on/off settings.
|
|
432
|
+
**When to use:** Binary on/off settings.
|
|
399
433
|
|
|
400
434
|
| Prop | Type | Default | Notes |
|
|
401
435
|
|------|------|---------|-------|
|
|
402
436
|
| checked | `boolean` | `false` | — |
|
|
403
437
|
| onCheckedChange | `(checked: boolean) => void` | — | — |
|
|
404
|
-
| disabled | `boolean` | — |
|
|
438
|
+
| disabled | `boolean` | — | Reduces opacity to 0.45 |
|
|
439
|
+
| style | `ViewStyle` | — | — |
|
|
440
|
+
|
|
441
|
+
**Dimensions:** Track 56×32pt, Thumb 24×24pt with 4pt offset from edges.
|
|
442
|
+
|
|
443
|
+
**Animation:** Thumb translates via spring (bounciness: 4); track color transitions via opacity timing (150ms).
|
|
405
444
|
|
|
406
445
|
**Example:**
|
|
407
446
|
```tsx
|
|
@@ -413,16 +452,16 @@ const [accepted, setAccepted] = useState(false)
|
|
|
413
452
|
### Toggle
|
|
414
453
|
|
|
415
454
|
**Import:** `import { Toggle } from '@retray-dev/ui-kit'`
|
|
416
|
-
**When to use:** Toggleable button (e.g., bold/italic in a toolbar).
|
|
455
|
+
**When to use:** Toggleable button (e.g., bold/italic in a toolbar). Looks like a button, unlike `Switch`.
|
|
417
456
|
|
|
418
457
|
| Prop | Type | Default | Notes |
|
|
419
458
|
|------|------|---------|-------|
|
|
420
459
|
| pressed | `boolean` | `false` | — |
|
|
421
460
|
| onPressedChange | `(pressed: boolean) => void` | — | — |
|
|
422
461
|
| variant | `'default' \| 'outline'` | `'default'` | `outline` adds a border when unpressed |
|
|
423
|
-
| size | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
462
|
+
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | sm=minH 40pt, md=minH 44pt, lg=minH 48pt |
|
|
424
463
|
| label | `string` | — | Text label |
|
|
425
|
-
| icon | `ReactNode` | — | Icon
|
|
464
|
+
| icon | `ReactNode` | — | Icon — can be combined with `label` |
|
|
426
465
|
|
|
427
466
|
**Example:**
|
|
428
467
|
```tsx
|
|
@@ -437,10 +476,11 @@ const [accepted, setAccepted] = useState(false)
|
|
|
437
476
|
|
|
438
477
|
| Prop | Type | Default | Notes |
|
|
439
478
|
|------|------|---------|-------|
|
|
440
|
-
| options | `RadioOption[]` | required | Each option: `{ label, value, disabled
|
|
441
|
-
| value | `string` | — |
|
|
479
|
+
| options | `RadioOption[]` | required | Each option: `{ label: string, value: string, disabled?: boolean }` |
|
|
480
|
+
| value | `string` | — | Currently selected value |
|
|
442
481
|
| onValueChange | `(value: string) => void` | — | — |
|
|
443
482
|
| orientation | `'vertical' \| 'horizontal'` | `'vertical'` | — |
|
|
483
|
+
| style | `ViewStyle` | — | — |
|
|
444
484
|
|
|
445
485
|
**Example:**
|
|
446
486
|
```tsx
|
|
@@ -464,13 +504,14 @@ const [accepted, setAccepted] = useState(false)
|
|
|
464
504
|
|
|
465
505
|
| Prop | Type | Default | Notes |
|
|
466
506
|
|------|------|---------|-------|
|
|
467
|
-
| options | `SelectOption[]` | required | Each option: `{ label, value, disabled
|
|
507
|
+
| options | `SelectOption[]` | required | Each option: `{ label: string, value: string, disabled?: boolean }` |
|
|
468
508
|
| value | `string` | — | Selected value |
|
|
469
509
|
| onValueChange | `(value: string) => void` | — | — |
|
|
470
|
-
| placeholder | `string` | `'Select an option'` |
|
|
510
|
+
| placeholder | `string` | `'Select an option'` | Shown when no value is selected |
|
|
471
511
|
| label | `string` | — | Label above the trigger |
|
|
472
|
-
| error | `string` | — | Error text below |
|
|
512
|
+
| error | `string` | — | Error text below the trigger |
|
|
473
513
|
| disabled | `boolean` | — | — |
|
|
514
|
+
| style | `ViewStyle` | — | — |
|
|
474
515
|
|
|
475
516
|
**Example:**
|
|
476
517
|
```tsx
|
|
@@ -495,10 +536,13 @@ const [accepted, setAccepted] = useState(false)
|
|
|
495
536
|
| value | `number` | `0` | — |
|
|
496
537
|
| minimumValue | `number` | `0` | — |
|
|
497
538
|
| maximumValue | `number` | `1` | — |
|
|
498
|
-
| step | `number` | `0` | `0` means continuous |
|
|
539
|
+
| step | `number` | `0` | `0` means continuous (no snapping) |
|
|
499
540
|
| onValueChange | `(value: number) => void` | — | Fires while dragging |
|
|
500
|
-
| onSlidingComplete | `(value: number) => void` | — | Fires on release |
|
|
541
|
+
| onSlidingComplete | `(value: number) => void` | — | Fires on finger release |
|
|
501
542
|
| disabled | `boolean` | — | — |
|
|
543
|
+
| style | `ViewStyle` | — | — |
|
|
544
|
+
|
|
545
|
+
**Dimensions:** Container height=32pt, track height=6pt, thumb 28×28pt. Uses `PanResponder` internally.
|
|
502
546
|
|
|
503
547
|
**Example:**
|
|
504
548
|
```tsx
|
|
@@ -507,8 +551,6 @@ const [accepted, setAccepted] = useState(false)
|
|
|
507
551
|
|
|
508
552
|
---
|
|
509
553
|
|
|
510
|
-
|
|
511
|
-
|
|
512
554
|
### Tabs
|
|
513
555
|
|
|
514
556
|
**Import:** `import { Tabs, TabsContent } from '@retray-dev/ui-kit'`
|
|
@@ -516,18 +558,22 @@ const [accepted, setAccepted] = useState(false)
|
|
|
516
558
|
|
|
517
559
|
| Prop | Type | Default | Notes |
|
|
518
560
|
|------|------|---------|-------|
|
|
519
|
-
| tabs | `TabItem[]` | required | Each item: `{ label, value }` |
|
|
561
|
+
| tabs | `TabItem[]` | required | Each item: `{ label: string, value: string }` |
|
|
520
562
|
| value | `string` | — | Controlled active tab |
|
|
521
563
|
| onValueChange | `(value: string) => void` | — | — |
|
|
522
564
|
| children | `ReactNode` | — | `TabsContent` components |
|
|
565
|
+
| style | `ViewStyle` | — | — |
|
|
523
566
|
|
|
524
567
|
**`TabsContent` Props:**
|
|
525
568
|
|
|
526
569
|
| Prop | Type | Notes |
|
|
527
570
|
|------|------|-------|
|
|
528
|
-
| value | `string` | Must match a tab value |
|
|
529
|
-
| activeValue | `string` | Pass the current active tab
|
|
571
|
+
| value | `string` | Must match a tab value in `tabs` |
|
|
572
|
+
| activeValue | `string` | Pass the current active tab — content is hidden when not active |
|
|
530
573
|
| children | `ReactNode` | — |
|
|
574
|
+
| style | `ViewStyle` | — |
|
|
575
|
+
|
|
576
|
+
**Animation:** An absolutely-positioned pill slides and resizes via spring (speed: 20, bounciness: 0) to track the active tab.
|
|
531
577
|
|
|
532
578
|
**Example:**
|
|
533
579
|
```tsx
|
|
@@ -556,9 +602,12 @@ const [tab, setTab] = useState('profile')
|
|
|
556
602
|
|
|
557
603
|
| Prop | Type | Default | Notes |
|
|
558
604
|
|------|------|---------|-------|
|
|
559
|
-
| items | `AccordionItem[]` | required | Each: `{ value, trigger: string, content: ReactNode }` |
|
|
560
|
-
| type | `'single' \| 'multiple'` | `'single'` | `single`: only one open at a time. `multiple`:
|
|
561
|
-
| defaultValue | `string \| string[]` | — | Initially open item(s) |
|
|
605
|
+
| items | `AccordionItem[]` | required | Each: `{ value: string, trigger: string, content: ReactNode }` |
|
|
606
|
+
| type | `'single' \| 'multiple'` | `'single'` | `single`: only one open at a time. `multiple`: any number can be open |
|
|
607
|
+
| defaultValue | `string \| string[]` | — | Initially open item(s). Use `string[]` with `type='multiple'` |
|
|
608
|
+
| style | `ViewStyle` | — | — |
|
|
609
|
+
|
|
610
|
+
**Animation:** Height and chevron rotation are animated on the UI thread via `react-native-reanimated` (`withTiming`, `useSharedValue`). `Easing.out(Easing.ease)` for expand, `Easing.in(Easing.ease)` for collapse (220ms, 60 fps).
|
|
562
611
|
|
|
563
612
|
**Example:**
|
|
564
613
|
```tsx
|
|
@@ -573,38 +622,38 @@ const [tab, setTab] = useState('profile')
|
|
|
573
622
|
|
|
574
623
|
---
|
|
575
624
|
|
|
576
|
-
|
|
577
|
-
|
|
578
625
|
### Sheet
|
|
579
626
|
|
|
580
627
|
**Import:** `import { Sheet, BottomSheetModalProvider } from '@retray-dev/ui-kit'`
|
|
581
628
|
**When to use:** Bottom sheet with physics-based gestures, rubber-band overscroll, and snap points. Powered by `@gorhom/bottom-sheet`.
|
|
582
629
|
|
|
583
|
-
**
|
|
630
|
+
**Required setup** — add to your app root (see Setup section above):
|
|
584
631
|
```tsx
|
|
585
|
-
import {
|
|
632
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
633
|
+
import { BottomSheetModalProvider } from '@retray-dev/ui-kit'
|
|
586
634
|
|
|
587
|
-
<
|
|
635
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
588
636
|
<BottomSheetModalProvider>
|
|
589
637
|
{/* rest of app */}
|
|
590
638
|
</BottomSheetModalProvider>
|
|
591
|
-
</
|
|
639
|
+
</GestureHandlerRootView>
|
|
592
640
|
```
|
|
593
641
|
|
|
594
642
|
**Peer dependencies** (install in your app):
|
|
595
643
|
```bash
|
|
596
|
-
pnpm add @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler
|
|
644
|
+
pnpm add @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-worklets
|
|
597
645
|
```
|
|
598
|
-
Add `react-native-reanimated/plugin` to your `babel.config.js` plugins.
|
|
646
|
+
Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to your `babel.config.js` plugins.
|
|
599
647
|
|
|
600
648
|
| Prop | Type | Default | Notes |
|
|
601
649
|
|------|------|---------|-------|
|
|
602
|
-
| open | `boolean` | required |
|
|
650
|
+
| open | `boolean` | required | `true` presents the sheet, `false` dismisses it |
|
|
603
651
|
| onClose | `() => void` | required | Called on swipe-dismiss or backdrop press |
|
|
604
652
|
| snapPoints | `(string \| number)[]` | `['50%']` | Snap positions, e.g. `['40%', '80%']` |
|
|
605
653
|
| title | `string` | — | — |
|
|
606
654
|
| description | `string` | — | — |
|
|
607
655
|
| children | `ReactNode` | — | — |
|
|
656
|
+
| style | `ViewStyle` | — | Applied to the inner content container |
|
|
608
657
|
|
|
609
658
|
**Example:**
|
|
610
659
|
```tsx
|
|
@@ -615,14 +664,14 @@ Add `react-native-reanimated/plugin` to your `babel.config.js` plugins.
|
|
|
615
664
|
|
|
616
665
|
---
|
|
617
666
|
|
|
618
|
-
|
|
619
|
-
|
|
620
667
|
### Toast / useToast
|
|
621
668
|
|
|
622
669
|
**Import:** `import { ToastProvider, useToast } from '@retray-dev/ui-kit'`
|
|
623
670
|
**When to use:** Ephemeral feedback messages (save success, network error, copy confirmation).
|
|
624
671
|
|
|
625
|
-
**
|
|
672
|
+
**Required setup** — `ToastProvider` must wrap your app inside `SafeAreaProvider` (see Setup section above).
|
|
673
|
+
|
|
674
|
+
**Peer dependency:** `react-native-safe-area-context` — required for `useSafeAreaInsets` inside `ToastProvider`.
|
|
626
675
|
|
|
627
676
|
```tsx
|
|
628
677
|
import { useToast } from '@retray-dev/ui-kit'
|
|
@@ -651,4 +700,11 @@ function MyComponent() {
|
|
|
651
700
|
| variant | `'default' \| 'destructive' \| 'success'` | `'default'` | `default`: dark background. `destructive`: red. `success`: green |
|
|
652
701
|
| duration | `number` (ms) | `3000` | Auto-dismiss after this delay |
|
|
653
702
|
|
|
654
|
-
|
|
703
|
+
**`dismiss(id)`:** Dismiss a toast programmatically. The `id` is returned by the `toast()` call — store it if you need programmatic dismissal.
|
|
704
|
+
|
|
705
|
+
**Notes:**
|
|
706
|
+
- Max 3 toasts shown simultaneously (oldest is removed when a 4th arrives)
|
|
707
|
+
- Toasts appear at the top of the screen, below the status bar (dynamic safe area inset)
|
|
708
|
+
- Entrance: `withTiming(120ms, Easing.out(Easing.exp))` slide-down + opacity fade — fast, sharp feel
|
|
709
|
+
- Exit: `withTiming(200ms)` slide-up + opacity fade
|
|
710
|
+
- Swipe left or right to dismiss early (threshold: 80px or 800 pt/s velocity)
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @retray-dev/ui-kit
|
|
1
|
+
# 📦 @retray-dev/ui-kit
|
|
2
2
|
|
|
3
3
|
A personal React Native / Expo UI component library with a built-in design system, dark mode support, haptic feedback, and smooth animations.
|
|
4
4
|
|
|
@@ -55,9 +55,7 @@ export default function App() {
|
|
|
55
55
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
56
56
|
<ThemeProvider colorScheme="system">
|
|
57
57
|
<BottomSheetModalProvider>
|
|
58
|
-
<ToastProvider>
|
|
59
|
-
{/* your app */}
|
|
60
|
-
</ToastProvider>
|
|
58
|
+
<ToastProvider>{/* your app */}</ToastProvider>
|
|
61
59
|
</BottomSheetModalProvider>
|
|
62
60
|
</ThemeProvider>
|
|
63
61
|
</GestureHandlerRootView>
|
|
@@ -66,13 +64,13 @@ export default function App() {
|
|
|
66
64
|
}
|
|
67
65
|
```
|
|
68
66
|
|
|
69
|
-
| Provider
|
|
70
|
-
|
|
71
|
-
| `SafeAreaProvider`
|
|
72
|
-
| `GestureHandlerRootView`
|
|
73
|
-
| `ThemeProvider`
|
|
74
|
-
| `BottomSheetModalProvider` | `Sheet`
|
|
75
|
-
| `ToastProvider`
|
|
67
|
+
| Provider | Required by |
|
|
68
|
+
| -------------------------- | ------------------------------------------ |
|
|
69
|
+
| `SafeAreaProvider` | `ToastProvider` (uses `useSafeAreaInsets`) |
|
|
70
|
+
| `GestureHandlerRootView` | `Sheet` (uses `@gorhom/bottom-sheet`) |
|
|
71
|
+
| `ThemeProvider` | All components |
|
|
72
|
+
| `BottomSheetModalProvider` | `Sheet` |
|
|
73
|
+
| `ToastProvider` | `useToast` hook |
|
|
76
74
|
|
|
77
75
|
## Theme
|
|
78
76
|
|
|
@@ -99,14 +97,14 @@ const { colors, colorScheme } = useTheme()
|
|
|
99
97
|
|
|
100
98
|
## Components
|
|
101
99
|
|
|
102
|
-
| Category
|
|
103
|
-
|
|
104
|
-
| Display
|
|
105
|
-
| Surfaces
|
|
106
|
-
| Form
|
|
107
|
-
| Composition | `Tabs`, `Accordion`
|
|
108
|
-
| Overlays
|
|
109
|
-
| Feedback
|
|
100
|
+
| Category | Components |
|
|
101
|
+
| ----------- | ----------------------------------------------------------------------------------------------- |
|
|
102
|
+
| Display | `Text`, `Badge`, `Avatar`, `Separator`, `Spinner`, `Skeleton`, `Progress` |
|
|
103
|
+
| Surfaces | `Card`, `Alert`, `EmptyState` |
|
|
104
|
+
| Form | `Button`, `Input`, `Textarea`, `Checkbox`, `Switch`, `Toggle`, `RadioGroup`, `Select`, `Slider` |
|
|
105
|
+
| Composition | `Tabs`, `Accordion` |
|
|
106
|
+
| Overlays | `Sheet` |
|
|
107
|
+
| Feedback | `Toast` / `ToastProvider` / `useToast` |
|
|
110
108
|
|
|
111
109
|
### Quick examples
|
|
112
110
|
|
|
@@ -143,6 +141,7 @@ Full props reference and more examples are available in [COMPONENTS.md](./COMPON
|
|
|
143
141
|
|
|
144
142
|
```markdown
|
|
145
143
|
## UI Components
|
|
144
|
+
|
|
146
145
|
@./node_modules/@retray-dev/ui-kit/COMPONENTS.md
|
|
147
146
|
```
|
|
148
147
|
|
package/dist/index.d.mts
CHANGED
|
@@ -20,6 +20,8 @@ type ThemeColors = {
|
|
|
20
20
|
border: string;
|
|
21
21
|
input: string;
|
|
22
22
|
ring: string;
|
|
23
|
+
success: string;
|
|
24
|
+
successForeground: string;
|
|
23
25
|
};
|
|
24
26
|
type Theme = {
|
|
25
27
|
light?: Partial<ThemeColors>;
|
|
@@ -68,8 +70,12 @@ interface ButtonProps extends TouchableOpacityProps {
|
|
|
68
70
|
/** Replaces the label with a spinner and forces `disabled`. */
|
|
69
71
|
loading?: boolean;
|
|
70
72
|
fullWidth?: boolean;
|
|
73
|
+
/** Icon rendered alongside the label. */
|
|
74
|
+
icon?: React.ReactNode;
|
|
75
|
+
/** Side the icon appears on. Defaults to `'left'`. */
|
|
76
|
+
iconPosition?: 'left' | 'right';
|
|
71
77
|
}
|
|
72
|
-
declare function Button({ label, variant, size, loading, fullWidth, disabled, style, onPress, ...props }: ButtonProps): React.JSX.Element;
|
|
78
|
+
declare function Button({ label, variant, size, loading, fullWidth, icon, iconPosition, disabled, style, onPress, ...props }: ButtonProps): React.JSX.Element;
|
|
73
79
|
|
|
74
80
|
type TextVariant = 'h1' | 'h2' | 'h3' | 'body' | 'caption' | 'label';
|
|
75
81
|
interface TextProps extends TextProps$1 {
|
|
@@ -80,10 +86,14 @@ declare function Text({ variant, color, style, children, ...props }: TextProps):
|
|
|
80
86
|
|
|
81
87
|
interface InputProps extends TextInputProps {
|
|
82
88
|
label?: string;
|
|
89
|
+
/** Red helper text below the input; also changes border to `destructive` color. Takes priority over `hint`. */
|
|
83
90
|
error?: string;
|
|
91
|
+
/** Helper text shown below the input when there is no error. */
|
|
84
92
|
hint?: string;
|
|
93
|
+
/** Style for the outer container `View`. Use `style` (from `TextInputProps`) to style the `TextInput` itself. */
|
|
94
|
+
containerStyle?: ViewStyle;
|
|
85
95
|
}
|
|
86
|
-
declare function Input({ label, error, hint, style, onFocus, onBlur, ...props }: InputProps): React.JSX.Element;
|
|
96
|
+
declare function Input({ label, error, hint, containerStyle, style, onFocus, onBlur, ...props }: InputProps): React.JSX.Element;
|
|
87
97
|
|
|
88
98
|
type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline';
|
|
89
99
|
interface BadgeProps {
|
|
@@ -147,7 +157,9 @@ declare function Skeleton({ width, height, borderRadius, style }: SkeletonProps)
|
|
|
147
157
|
|
|
148
158
|
type AvatarSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
149
159
|
interface AvatarProps {
|
|
160
|
+
/** Remote image URI. Falls back to `fallback` initials on error or when omitted. */
|
|
150
161
|
src?: string;
|
|
162
|
+
/** Up to 2 characters shown when the image is unavailable. Auto-uppercased. Defaults to `'?'`. */
|
|
151
163
|
fallback?: string;
|
|
152
164
|
size?: AvatarSize;
|
|
153
165
|
style?: ViewStyle;
|
|
@@ -165,7 +177,9 @@ interface AlertProps {
|
|
|
165
177
|
declare function Alert({ title, description, variant, icon, style }: AlertProps): React.JSX.Element;
|
|
166
178
|
|
|
167
179
|
interface ProgressProps {
|
|
180
|
+
/** Current progress value. Clamped to `[0, max]`. Defaults to `0`. */
|
|
168
181
|
value?: number;
|
|
182
|
+
/** Maximum value. Defaults to `100`. */
|
|
169
183
|
max?: number;
|
|
170
184
|
style?: ViewStyle;
|
|
171
185
|
}
|
|
@@ -182,11 +196,16 @@ declare function EmptyState({ icon, title, description, action, style }: EmptySt
|
|
|
182
196
|
|
|
183
197
|
interface TextareaProps extends TextInputProps {
|
|
184
198
|
label?: string;
|
|
199
|
+
/** Red helper text below the textarea; also changes border to `destructive` color. Takes priority over `hint`. */
|
|
185
200
|
error?: string;
|
|
201
|
+
/** Helper text shown below the textarea when there is no error. */
|
|
186
202
|
hint?: string;
|
|
203
|
+
/** Number of visible text rows. Defaults to `4`. Controls `numberOfLines` and `minHeight`. */
|
|
187
204
|
rows?: number;
|
|
205
|
+
/** Style for the outer container `View`. Use `style` (from `TextInputProps`) to style the `TextInput` itself. */
|
|
206
|
+
containerStyle?: ViewStyle;
|
|
188
207
|
}
|
|
189
|
-
declare function Textarea({ label, error, hint, rows, style, onFocus, onBlur, ...props }: TextareaProps): React.JSX.Element;
|
|
208
|
+
declare function Textarea({ label, error, hint, rows, containerStyle, style, onFocus, onBlur, ...props }: TextareaProps): React.JSX.Element;
|
|
190
209
|
|
|
191
210
|
interface CheckboxProps {
|
|
192
211
|
checked?: boolean;
|
|
@@ -195,7 +214,7 @@ interface CheckboxProps {
|
|
|
195
214
|
disabled?: boolean;
|
|
196
215
|
style?: ViewStyle;
|
|
197
216
|
}
|
|
198
|
-
declare function Checkbox({ checked, onCheckedChange, label, disabled, style }: CheckboxProps): React.JSX.Element;
|
|
217
|
+
declare function Checkbox({ checked, onCheckedChange, label, disabled, style, }: CheckboxProps): React.JSX.Element;
|
|
199
218
|
|
|
200
219
|
interface SwitchProps {
|
|
201
220
|
checked?: boolean;
|
|
@@ -237,6 +256,10 @@ interface TabItem {
|
|
|
237
256
|
}
|
|
238
257
|
interface TabsProps {
|
|
239
258
|
tabs: TabItem[];
|
|
259
|
+
/**
|
|
260
|
+
* Controlled active tab value. When omitted the component manages state internally
|
|
261
|
+
* (uncontrolled), defaulting to the first tab.
|
|
262
|
+
*/
|
|
240
263
|
value?: string;
|
|
241
264
|
onValueChange?: (value: string) => void;
|
|
242
265
|
children?: React.ReactNode;
|
|
@@ -270,11 +293,15 @@ interface AccordionProps {
|
|
|
270
293
|
declare function Accordion({ items, type, defaultValue, style }: AccordionProps): React.JSX.Element;
|
|
271
294
|
|
|
272
295
|
interface SliderProps {
|
|
296
|
+
/** Current value. Controlled when provided; falls back to internal state otherwise. */
|
|
273
297
|
value?: number;
|
|
274
298
|
minimumValue?: number;
|
|
275
299
|
maximumValue?: number;
|
|
300
|
+
/** Snap interval. `0` (default) means continuous (no snapping). */
|
|
276
301
|
step?: number;
|
|
302
|
+
/** Called on every move while dragging. */
|
|
277
303
|
onValueChange?: (value: number) => void;
|
|
304
|
+
/** Called once when the user releases the thumb. */
|
|
278
305
|
onSlidingComplete?: (value: number) => void;
|
|
279
306
|
disabled?: boolean;
|
|
280
307
|
style?: ViewStyle;
|
|
@@ -287,7 +314,12 @@ interface SheetProps {
|
|
|
287
314
|
title?: string;
|
|
288
315
|
description?: string;
|
|
289
316
|
children?: React.ReactNode;
|
|
317
|
+
/**
|
|
318
|
+
* Heights the sheet can snap to. Accepts percentage strings (`'50%'`) or
|
|
319
|
+
* absolute point values (`300`). Defaults to `['50%']`.
|
|
320
|
+
*/
|
|
290
321
|
snapPoints?: (string | number)[];
|
|
322
|
+
/** Style for the inner `BottomSheetView` content container. */
|
|
291
323
|
style?: ViewStyle;
|
|
292
324
|
}
|
|
293
325
|
declare function Sheet({ open, onClose, title, description, children, snapPoints, style, }: SheetProps): React.JSX.Element;
|
|
@@ -301,8 +333,10 @@ interface SelectProps {
|
|
|
301
333
|
options: SelectOption[];
|
|
302
334
|
value?: string;
|
|
303
335
|
onValueChange?: (value: string) => void;
|
|
336
|
+
/** Text shown when no option is selected. Defaults to `'Select an option'`. */
|
|
304
337
|
placeholder?: string;
|
|
305
338
|
label?: string;
|
|
339
|
+
/** Red helper text; also changes trigger border to `destructive` color. */
|
|
306
340
|
error?: string;
|
|
307
341
|
disabled?: boolean;
|
|
308
342
|
style?: ViewStyle;
|
|
@@ -315,6 +349,7 @@ interface ToastItem {
|
|
|
315
349
|
title?: string;
|
|
316
350
|
description?: string;
|
|
317
351
|
variant?: ToastVariant;
|
|
352
|
+
/** Auto-dismiss delay in milliseconds. Defaults to `3000`. */
|
|
318
353
|
duration?: number;
|
|
319
354
|
}
|
|
320
355
|
interface ToastContextValue {
|