@retray-dev/ui-kit 1.0.0 → 1.6.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 +171 -66
- package/README.md +19 -20
- package/dist/index.d.mts +59 -5
- package/dist/index.d.ts +59 -5
- package/dist/index.js +475 -265
- package/dist/index.mjs +474 -266
- package/package.json +25 -8
- 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/CurrencyInput/CurrencyInput.tsx +65 -0
- package/src/components/CurrencyInput/index.ts +2 -0
- 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/index.ts +1 -0
- package/src/theme/colors.ts +4 -0
- package/src/theme/types.ts +2 -0
package/COMPONENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @retray-dev/ui-kit — Component Reference
|
|
1
|
+
# @retray-dev/ui-kit — Component Reference (v1.6.0)
|
|
2
2
|
|
|
3
3
|
This file is the AI reference for this package. It is shipped inside the npm package so consuming projects can import it into their `CLAUDE.md` with:
|
|
4
4
|
|
|
@@ -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 |
|
|
@@ -59,7 +74,7 @@ function MyComponent() {
|
|
|
59
74
|
|
|
60
75
|
## Theme Tokens
|
|
61
76
|
|
|
62
|
-
All
|
|
77
|
+
All 20 tokens are available via `useTheme().colors`.
|
|
63
78
|
|
|
64
79
|
| Token | Light | Dark | Semantic Role |
|
|
65
80
|
|-------|-------|------|---------------|
|
|
@@ -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 |
|
|
@@ -80,6 +95,8 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
80
95
|
| `border` | `#e5e5e5` | `#2a2a2a` | Borders and dividers |
|
|
81
96
|
| `input` | `#e5e5e5` | `#2a2a2a` | Input field border color |
|
|
82
97
|
| `ring` | `#a3a3a3` | `#d4d4d4` | Focus ring color |
|
|
98
|
+
| `success` | `#16a34a` | `#22c55e` | Success state (Toast success variant) |
|
|
99
|
+
| `successForeground` | `#ffffff` | `#ffffff` | Text on success background |
|
|
83
100
|
|
|
84
101
|
---
|
|
85
102
|
|
|
@@ -91,12 +108,12 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
91
108
|
|
|
92
109
|
**Import:** `import { Text } from '@retray-dev/ui-kit'`
|
|
93
110
|
**When to use:** All text in the app. Replaces React Native's `Text` with semantic variants.
|
|
94
|
-
**Extends:** `TextProps` from React Native.
|
|
111
|
+
**Extends:** `TextProps` from React Native — all native props pass through.
|
|
95
112
|
|
|
96
113
|
| Prop | Type | Default | Notes |
|
|
97
114
|
|------|------|---------|-------|
|
|
98
115
|
| 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
|
|
116
|
+
| color | `string` | — | Override the color. Defaults to `foreground`, except `caption` which uses `mutedForeground` |
|
|
100
117
|
|
|
101
118
|
**Sizes:**
|
|
102
119
|
- `h1`: 32px / 700 weight
|
|
@@ -127,22 +144,27 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
127
144
|
| label | `string` | required | Button text |
|
|
128
145
|
| variant | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Visual style |
|
|
129
146
|
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | — |
|
|
130
|
-
| loading | `boolean` | `false` | Replaces label with spinner and forces disabled |
|
|
131
|
-
| fullWidth | `boolean` | `false` | Stretches to container width |
|
|
147
|
+
| loading | `boolean` | `false` | Replaces label with a spinner and forces disabled state |
|
|
148
|
+
| fullWidth | `boolean` | `false` | Stretches to container width (`alignSelf: 'stretch'`) |
|
|
132
149
|
| disabled | `boolean` | — | Reduces opacity to 0.45 |
|
|
150
|
+
| icon | `React.ReactNode` | — | Icon rendered alongside the label |
|
|
151
|
+
| iconPosition | `'left' \| 'right'` | `'left'` | Side the icon appears on |
|
|
133
152
|
|
|
134
153
|
**Variants:**
|
|
135
154
|
- `primary`: filled with `primary` token — main actions
|
|
136
155
|
- `secondary`: filled with `secondary` token — less prominent actions
|
|
137
|
-
- `outline`: transparent with `border` — alternative
|
|
156
|
+
- `outline`: transparent with `border` — alternative without fill
|
|
138
157
|
- `ghost`: fully transparent — in-context or low-emphasis actions
|
|
139
158
|
|
|
159
|
+
**Animations:** Scale springs to 0.97 on `onPressIn`, back to 1.0 on `onPressOut`.
|
|
160
|
+
|
|
140
161
|
**Example:**
|
|
141
162
|
```tsx
|
|
142
163
|
<Button label="Save changes" onPress={handleSave} />
|
|
143
164
|
<Button label="Cancel" variant="ghost" onPress={onCancel} />
|
|
144
165
|
<Button label="Delete" variant="outline" size="sm" />
|
|
145
166
|
<Button label="Submitting..." loading fullWidth />
|
|
167
|
+
<Button label="Share" icon={<ShareIcon size={16} />} iconPosition="right" />
|
|
146
168
|
```
|
|
147
169
|
|
|
148
170
|
---
|
|
@@ -151,13 +173,15 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
151
173
|
|
|
152
174
|
**Import:** `import { Input } from '@retray-dev/ui-kit'`
|
|
153
175
|
**When to use:** Single-line text entry. Includes built-in label, error, and hint support.
|
|
154
|
-
**Extends:** `TextInputProps` from React Native.
|
|
176
|
+
**Extends:** `TextInputProps` from React Native — all native props pass through.
|
|
155
177
|
|
|
156
178
|
| Prop | Type | Default | Notes |
|
|
157
179
|
|------|------|---------|-------|
|
|
158
180
|
| 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) |
|
|
181
|
+
| error | `string` | — | Shows error text below; turns border red (`destructive` token) |
|
|
182
|
+
| hint | `string` | — | Helper text below (hidden when `error` is set) |
|
|
183
|
+
|
|
184
|
+
**Border colors:** `destructive` when `error` is set, `ring` when focused, `border` otherwise.
|
|
161
185
|
|
|
162
186
|
**Example:**
|
|
163
187
|
```tsx
|
|
@@ -168,18 +192,62 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
168
192
|
|
|
169
193
|
---
|
|
170
194
|
|
|
195
|
+
### CurrencyInput
|
|
196
|
+
|
|
197
|
+
**Import:** `import { CurrencyInput } from '@retray-dev/ui-kit'`
|
|
198
|
+
**When to use:** Monetary or numeric inputs that need thousands formatting while typing. Wraps `Input` — shares the same visual design, label, error, and hint behavior.
|
|
199
|
+
|
|
200
|
+
| Prop | Type | Default | Notes |
|
|
201
|
+
|------|------|---------|-------|
|
|
202
|
+
| value | `string` | — | Controlled display value (includes prefix, e.g. `'$1,234'`) |
|
|
203
|
+
| onChangeText | `(formatted: string) => void` | — | Called with the formatted display string |
|
|
204
|
+
| onChangeValue | `(raw: number) => void` | — | Called with the parsed number (no separators, no prefix) |
|
|
205
|
+
| prefix | `string` | `'$'` | Symbol prepended to the formatted value |
|
|
206
|
+
| thousandsSeparator | `'.' \| ','` | `'.'` | Character used to separate groups of three digits |
|
|
207
|
+
| label | `string` | — | Label above the input |
|
|
208
|
+
| error | `string` | — | Error text below; turns border red |
|
|
209
|
+
| hint | `string` | — | Helper text below (hidden when `error` is set) |
|
|
210
|
+
| placeholder | `string` | `'$0'` | Defaults to `prefix + '0'` |
|
|
211
|
+
| editable | `boolean` | — | Pass `false` to disable editing |
|
|
212
|
+
| containerStyle | `ViewStyle` | — | Style for the outer container |
|
|
213
|
+
|
|
214
|
+
**Example:**
|
|
215
|
+
```tsx
|
|
216
|
+
const [display, setDisplay] = useState('')
|
|
217
|
+
const [amount, setAmount] = useState(0)
|
|
218
|
+
|
|
219
|
+
<CurrencyInput
|
|
220
|
+
label="Amount"
|
|
221
|
+
value={display}
|
|
222
|
+
onChangeText={setDisplay}
|
|
223
|
+
onChangeValue={setAmount}
|
|
224
|
+
hint={`Parsed: ${amount}`}
|
|
225
|
+
/>
|
|
226
|
+
|
|
227
|
+
// European format (dot as thousands separator)
|
|
228
|
+
<CurrencyInput
|
|
229
|
+
prefix="€"
|
|
230
|
+
thousandsSeparator="."
|
|
231
|
+
value={display}
|
|
232
|
+
onChangeText={setDisplay}
|
|
233
|
+
onChangeValue={setAmount}
|
|
234
|
+
/>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
171
239
|
### Textarea
|
|
172
240
|
|
|
173
241
|
**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.
|
|
242
|
+
**When to use:** Multi-line text entry. Same API as `Input` plus `rows`.
|
|
243
|
+
**Extends:** `TextInputProps` from React Native — all native props pass through.
|
|
176
244
|
|
|
177
245
|
| Prop | Type | Default | Notes |
|
|
178
246
|
|------|------|---------|-------|
|
|
179
247
|
| label | `string` | — | Label above |
|
|
180
248
|
| error | `string` | — | Error text below; red border |
|
|
181
249
|
| hint | `string` | — | Helper text below |
|
|
182
|
-
| rows | `number` | `4` | Sets
|
|
250
|
+
| rows | `number` | `4` | Sets `minHeight` (each row ≈ 28px) |
|
|
183
251
|
|
|
184
252
|
**Example:**
|
|
185
253
|
```tsx
|
|
@@ -197,6 +265,7 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
197
265
|
|------|------|---------|-------|
|
|
198
266
|
| label | `string` | required | — |
|
|
199
267
|
| variant | `'default' \| 'secondary' \| 'destructive' \| 'outline'` | `'default'` | — |
|
|
268
|
+
| style | `ViewStyle` | — | — |
|
|
200
269
|
|
|
201
270
|
**Example:**
|
|
202
271
|
```tsx
|
|
@@ -216,8 +285,9 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
216
285
|
| Prop | Type | Default | Notes |
|
|
217
286
|
|------|------|---------|-------|
|
|
218
287
|
| src | `string` | — | Image URI |
|
|
219
|
-
| fallback | `string` | — | Text
|
|
220
|
-
| size | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | sm=24, md=32, lg=48, xl=64 |
|
|
288
|
+
| fallback | `string` | — | Text shown when image fails or `src` is absent — first 2 chars, uppercased |
|
|
289
|
+
| size | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | sm=24, md=32, lg=48, xl=64 (diameter in pt) |
|
|
290
|
+
| style | `ViewStyle` | — | — |
|
|
221
291
|
|
|
222
292
|
**Example:**
|
|
223
293
|
```tsx
|
|
@@ -234,7 +304,8 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
234
304
|
|
|
235
305
|
| Prop | Type | Default | Notes |
|
|
236
306
|
|------|------|---------|-------|
|
|
237
|
-
| orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | Vertical requires a parent with defined height |
|
|
307
|
+
| orientation | `'horizontal' \| 'vertical'` | `'horizontal'` | Vertical requires a parent with a defined height |
|
|
308
|
+
| style | `ViewStyle` | — | — |
|
|
238
309
|
|
|
239
310
|
**Example:**
|
|
240
311
|
```tsx
|
|
@@ -251,11 +322,12 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
251
322
|
### Spinner
|
|
252
323
|
|
|
253
324
|
**Import:** `import { Spinner } from '@retray-dev/ui-kit'`
|
|
254
|
-
**When to use:** Loading state indicator.
|
|
325
|
+
**When to use:** Loading state indicator. Wraps React Native's `ActivityIndicator`.
|
|
326
|
+
**Extends:** `ActivityIndicatorProps` (except `size`).
|
|
255
327
|
|
|
256
328
|
| Prop | Type | Default | Notes |
|
|
257
329
|
|------|------|---------|-------|
|
|
258
|
-
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | sm
|
|
330
|
+
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | `sm`/`md` map to RN `'small'`, `lg` maps to `'large'` |
|
|
259
331
|
| color | `string` | `primary` token | Override spinner color |
|
|
260
332
|
|
|
261
333
|
**Example:**
|
|
@@ -269,13 +341,14 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
269
341
|
### Skeleton
|
|
270
342
|
|
|
271
343
|
**Import:** `import { Skeleton } from '@retray-dev/ui-kit'`
|
|
272
|
-
**When to use:** Placeholder while content is loading. Pulses with animation.
|
|
344
|
+
**When to use:** Placeholder while content is loading. Pulses with a looping opacity animation.
|
|
273
345
|
|
|
274
346
|
| Prop | Type | Default | Notes |
|
|
275
347
|
|------|------|---------|-------|
|
|
276
348
|
| width | `number \| string` | `'100%'` | — |
|
|
277
349
|
| height | `number` | `16` | — |
|
|
278
350
|
| borderRadius | `number` | `6` | — |
|
|
351
|
+
| style | `ViewStyle` | — | — |
|
|
279
352
|
|
|
280
353
|
**Example:**
|
|
281
354
|
```tsx
|
|
@@ -294,6 +367,9 @@ All 18 tokens are available via `useTheme().colors`.
|
|
|
294
367
|
|------|------|---------|-------|
|
|
295
368
|
| value | `number` | `0` | Current value |
|
|
296
369
|
| max | `number` | `100` | Maximum value |
|
|
370
|
+
| style | `ViewStyle` | — | — |
|
|
371
|
+
|
|
372
|
+
**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
373
|
|
|
298
374
|
**Example:**
|
|
299
375
|
```tsx
|
|
@@ -326,21 +402,26 @@ All sub-components accept a `style` prop for overrides.
|
|
|
326
402
|
</Card>
|
|
327
403
|
```
|
|
328
404
|
|
|
329
|
-
**Notes:**
|
|
405
|
+
**Notes:**
|
|
406
|
+
- `CardHeader` and `CardContent` have `padding: 24`
|
|
407
|
+
- `CardFooter` has `paddingTop: 0` so it connects naturally to `CardContent`
|
|
408
|
+
- `CardTitle`: 18px / 600 weight, `cardForeground` color
|
|
409
|
+
- `CardDescription`: 14px, `mutedForeground` color
|
|
330
410
|
|
|
331
411
|
---
|
|
332
412
|
|
|
333
413
|
### Alert
|
|
334
414
|
|
|
335
415
|
**Import:** `import { Alert } from '@retray-dev/ui-kit'`
|
|
336
|
-
**When to use:** Inline feedback messages (info, success, warning, error). Not for toasts.
|
|
416
|
+
**When to use:** Inline feedback messages (info, success, warning, error). Not for transient toasts.
|
|
337
417
|
|
|
338
418
|
| Prop | Type | Default | Notes |
|
|
339
419
|
|------|------|---------|-------|
|
|
340
420
|
| title | `string` | — | Bold heading |
|
|
341
421
|
| description | `string` | — | Detail text |
|
|
342
|
-
| variant | `'default' \| 'destructive'` | `'default'` | `destructive` turns border and text
|
|
343
|
-
| icon | `ReactNode` | — | Icon placed to the left |
|
|
422
|
+
| variant | `'default' \| 'destructive'` | `'default'` | `destructive` turns border and text to `destructive` token |
|
|
423
|
+
| icon | `ReactNode` | — | Icon placed to the left of the text content |
|
|
424
|
+
| style | `ViewStyle` | — | — |
|
|
344
425
|
|
|
345
426
|
**Example:**
|
|
346
427
|
```tsx
|
|
@@ -359,8 +440,9 @@ All sub-components accept a `style` prop for overrides.
|
|
|
359
440
|
|------|------|---------|-------|
|
|
360
441
|
| title | `string` | required | — |
|
|
361
442
|
| description | `string` | — | — |
|
|
362
|
-
| icon | `ReactNode` | — | Shown in a muted square above the text |
|
|
443
|
+
| icon | `ReactNode` | — | Shown in a 48×48 muted square above the text |
|
|
363
444
|
| action | `ReactNode` | — | Usually a `Button`, placed below the text |
|
|
445
|
+
| style | `ViewStyle` | — | — |
|
|
364
446
|
|
|
365
447
|
**Example:**
|
|
366
448
|
```tsx
|
|
@@ -383,6 +465,7 @@ All sub-components accept a `style` prop for overrides.
|
|
|
383
465
|
| onCheckedChange | `(checked: boolean) => void` | — | — |
|
|
384
466
|
| label | `string` | — | Text to the right of the box |
|
|
385
467
|
| disabled | `boolean` | — | — |
|
|
468
|
+
| style | `ViewStyle` | — | — |
|
|
386
469
|
|
|
387
470
|
**Example:**
|
|
388
471
|
```tsx
|
|
@@ -395,13 +478,18 @@ const [accepted, setAccepted] = useState(false)
|
|
|
395
478
|
### Switch
|
|
396
479
|
|
|
397
480
|
**Import:** `import { Switch } from '@retray-dev/ui-kit'`
|
|
398
|
-
**When to use:** Binary on/off settings.
|
|
481
|
+
**When to use:** Binary on/off settings.
|
|
399
482
|
|
|
400
483
|
| Prop | Type | Default | Notes |
|
|
401
484
|
|------|------|---------|-------|
|
|
402
485
|
| checked | `boolean` | `false` | — |
|
|
403
486
|
| onCheckedChange | `(checked: boolean) => void` | — | — |
|
|
404
|
-
| disabled | `boolean` | — |
|
|
487
|
+
| disabled | `boolean` | — | Reduces opacity to 0.45 |
|
|
488
|
+
| style | `ViewStyle` | — | — |
|
|
489
|
+
|
|
490
|
+
**Dimensions:** Track 56×32pt, Thumb 24×24pt with 4pt offset from edges.
|
|
491
|
+
|
|
492
|
+
**Animation:** Thumb translates via spring (bounciness: 4); track color transitions via opacity timing (150ms).
|
|
405
493
|
|
|
406
494
|
**Example:**
|
|
407
495
|
```tsx
|
|
@@ -413,16 +501,16 @@ const [accepted, setAccepted] = useState(false)
|
|
|
413
501
|
### Toggle
|
|
414
502
|
|
|
415
503
|
**Import:** `import { Toggle } from '@retray-dev/ui-kit'`
|
|
416
|
-
**When to use:** Toggleable button (e.g., bold/italic in a toolbar).
|
|
504
|
+
**When to use:** Toggleable button (e.g., bold/italic in a toolbar). Looks like a button, unlike `Switch`.
|
|
417
505
|
|
|
418
506
|
| Prop | Type | Default | Notes |
|
|
419
507
|
|------|------|---------|-------|
|
|
420
508
|
| pressed | `boolean` | `false` | — |
|
|
421
509
|
| onPressedChange | `(pressed: boolean) => void` | — | — |
|
|
422
510
|
| variant | `'default' \| 'outline'` | `'default'` | `outline` adds a border when unpressed |
|
|
423
|
-
| size | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
|
511
|
+
| size | `'sm' \| 'md' \| 'lg'` | `'md'` | sm=minH 40pt, md=minH 44pt, lg=minH 48pt |
|
|
424
512
|
| label | `string` | — | Text label |
|
|
425
|
-
| icon | `ReactNode` | — | Icon
|
|
513
|
+
| icon | `ReactNode` | — | Icon — can be combined with `label` |
|
|
426
514
|
|
|
427
515
|
**Example:**
|
|
428
516
|
```tsx
|
|
@@ -437,10 +525,11 @@ const [accepted, setAccepted] = useState(false)
|
|
|
437
525
|
|
|
438
526
|
| Prop | Type | Default | Notes |
|
|
439
527
|
|------|------|---------|-------|
|
|
440
|
-
| options | `RadioOption[]` | required | Each option: `{ label, value, disabled
|
|
441
|
-
| value | `string` | — |
|
|
528
|
+
| options | `RadioOption[]` | required | Each option: `{ label: string, value: string, disabled?: boolean }` |
|
|
529
|
+
| value | `string` | — | Currently selected value |
|
|
442
530
|
| onValueChange | `(value: string) => void` | — | — |
|
|
443
531
|
| orientation | `'vertical' \| 'horizontal'` | `'vertical'` | — |
|
|
532
|
+
| style | `ViewStyle` | — | — |
|
|
444
533
|
|
|
445
534
|
**Example:**
|
|
446
535
|
```tsx
|
|
@@ -464,13 +553,14 @@ const [accepted, setAccepted] = useState(false)
|
|
|
464
553
|
|
|
465
554
|
| Prop | Type | Default | Notes |
|
|
466
555
|
|------|------|---------|-------|
|
|
467
|
-
| options | `SelectOption[]` | required | Each option: `{ label, value, disabled
|
|
556
|
+
| options | `SelectOption[]` | required | Each option: `{ label: string, value: string, disabled?: boolean }` |
|
|
468
557
|
| value | `string` | — | Selected value |
|
|
469
558
|
| onValueChange | `(value: string) => void` | — | — |
|
|
470
|
-
| placeholder | `string` | `'Select an option'` |
|
|
559
|
+
| placeholder | `string` | `'Select an option'` | Shown when no value is selected |
|
|
471
560
|
| label | `string` | — | Label above the trigger |
|
|
472
|
-
| error | `string` | — | Error text below |
|
|
561
|
+
| error | `string` | — | Error text below the trigger |
|
|
473
562
|
| disabled | `boolean` | — | — |
|
|
563
|
+
| style | `ViewStyle` | — | — |
|
|
474
564
|
|
|
475
565
|
**Example:**
|
|
476
566
|
```tsx
|
|
@@ -495,10 +585,13 @@ const [accepted, setAccepted] = useState(false)
|
|
|
495
585
|
| value | `number` | `0` | — |
|
|
496
586
|
| minimumValue | `number` | `0` | — |
|
|
497
587
|
| maximumValue | `number` | `1` | — |
|
|
498
|
-
| step | `number` | `0` | `0` means continuous |
|
|
588
|
+
| step | `number` | `0` | `0` means continuous (no snapping) |
|
|
499
589
|
| onValueChange | `(value: number) => void` | — | Fires while dragging |
|
|
500
|
-
| onSlidingComplete | `(value: number) => void` | — | Fires on release |
|
|
590
|
+
| onSlidingComplete | `(value: number) => void` | — | Fires on finger release |
|
|
501
591
|
| disabled | `boolean` | — | — |
|
|
592
|
+
| style | `ViewStyle` | — | — |
|
|
593
|
+
|
|
594
|
+
**Dimensions:** Container height=32pt, track height=6pt, thumb 28×28pt. Uses `PanResponder` internally.
|
|
502
595
|
|
|
503
596
|
**Example:**
|
|
504
597
|
```tsx
|
|
@@ -507,8 +600,6 @@ const [accepted, setAccepted] = useState(false)
|
|
|
507
600
|
|
|
508
601
|
---
|
|
509
602
|
|
|
510
|
-
|
|
511
|
-
|
|
512
603
|
### Tabs
|
|
513
604
|
|
|
514
605
|
**Import:** `import { Tabs, TabsContent } from '@retray-dev/ui-kit'`
|
|
@@ -516,18 +607,22 @@ const [accepted, setAccepted] = useState(false)
|
|
|
516
607
|
|
|
517
608
|
| Prop | Type | Default | Notes |
|
|
518
609
|
|------|------|---------|-------|
|
|
519
|
-
| tabs | `TabItem[]` | required | Each item: `{ label, value }` |
|
|
610
|
+
| tabs | `TabItem[]` | required | Each item: `{ label: string, value: string }` |
|
|
520
611
|
| value | `string` | — | Controlled active tab |
|
|
521
612
|
| onValueChange | `(value: string) => void` | — | — |
|
|
522
613
|
| children | `ReactNode` | — | `TabsContent` components |
|
|
614
|
+
| style | `ViewStyle` | — | — |
|
|
523
615
|
|
|
524
616
|
**`TabsContent` Props:**
|
|
525
617
|
|
|
526
618
|
| Prop | Type | Notes |
|
|
527
619
|
|------|------|-------|
|
|
528
|
-
| value | `string` | Must match a tab value |
|
|
529
|
-
| activeValue | `string` | Pass the current active tab
|
|
620
|
+
| value | `string` | Must match a tab value in `tabs` |
|
|
621
|
+
| activeValue | `string` | Pass the current active tab — content is hidden when not active |
|
|
530
622
|
| children | `ReactNode` | — |
|
|
623
|
+
| style | `ViewStyle` | — |
|
|
624
|
+
|
|
625
|
+
**Animation:** An absolutely-positioned pill slides and resizes via spring (speed: 20, bounciness: 0) to track the active tab.
|
|
531
626
|
|
|
532
627
|
**Example:**
|
|
533
628
|
```tsx
|
|
@@ -556,9 +651,12 @@ const [tab, setTab] = useState('profile')
|
|
|
556
651
|
|
|
557
652
|
| Prop | Type | Default | Notes |
|
|
558
653
|
|------|------|---------|-------|
|
|
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) |
|
|
654
|
+
| items | `AccordionItem[]` | required | Each: `{ value: string, trigger: string, content: ReactNode }` |
|
|
655
|
+
| type | `'single' \| 'multiple'` | `'single'` | `single`: only one open at a time. `multiple`: any number can be open |
|
|
656
|
+
| defaultValue | `string \| string[]` | — | Initially open item(s). Use `string[]` with `type='multiple'` |
|
|
657
|
+
| style | `ViewStyle` | — | — |
|
|
658
|
+
|
|
659
|
+
**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
660
|
|
|
563
661
|
**Example:**
|
|
564
662
|
```tsx
|
|
@@ -573,38 +671,38 @@ const [tab, setTab] = useState('profile')
|
|
|
573
671
|
|
|
574
672
|
---
|
|
575
673
|
|
|
576
|
-
|
|
577
|
-
|
|
578
674
|
### Sheet
|
|
579
675
|
|
|
580
676
|
**Import:** `import { Sheet, BottomSheetModalProvider } from '@retray-dev/ui-kit'`
|
|
581
677
|
**When to use:** Bottom sheet with physics-based gestures, rubber-band overscroll, and snap points. Powered by `@gorhom/bottom-sheet`.
|
|
582
678
|
|
|
583
|
-
**
|
|
679
|
+
**Required setup** — add to your app root (see Setup section above):
|
|
584
680
|
```tsx
|
|
585
|
-
import {
|
|
681
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
682
|
+
import { BottomSheetModalProvider } from '@retray-dev/ui-kit'
|
|
586
683
|
|
|
587
|
-
<
|
|
684
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
588
685
|
<BottomSheetModalProvider>
|
|
589
686
|
{/* rest of app */}
|
|
590
687
|
</BottomSheetModalProvider>
|
|
591
|
-
</
|
|
688
|
+
</GestureHandlerRootView>
|
|
592
689
|
```
|
|
593
690
|
|
|
594
691
|
**Peer dependencies** (install in your app):
|
|
595
692
|
```bash
|
|
596
|
-
pnpm add @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler
|
|
693
|
+
pnpm add @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-worklets
|
|
597
694
|
```
|
|
598
|
-
Add `react-native-reanimated/plugin` to your `babel.config.js` plugins.
|
|
695
|
+
Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to your `babel.config.js` plugins.
|
|
599
696
|
|
|
600
697
|
| Prop | Type | Default | Notes |
|
|
601
698
|
|------|------|---------|-------|
|
|
602
|
-
| open | `boolean` | required |
|
|
699
|
+
| open | `boolean` | required | `true` presents the sheet, `false` dismisses it |
|
|
603
700
|
| onClose | `() => void` | required | Called on swipe-dismiss or backdrop press |
|
|
604
701
|
| snapPoints | `(string \| number)[]` | `['50%']` | Snap positions, e.g. `['40%', '80%']` |
|
|
605
702
|
| title | `string` | — | — |
|
|
606
703
|
| description | `string` | — | — |
|
|
607
704
|
| children | `ReactNode` | — | — |
|
|
705
|
+
| style | `ViewStyle` | — | Applied to the inner content container |
|
|
608
706
|
|
|
609
707
|
**Example:**
|
|
610
708
|
```tsx
|
|
@@ -615,14 +713,14 @@ Add `react-native-reanimated/plugin` to your `babel.config.js` plugins.
|
|
|
615
713
|
|
|
616
714
|
---
|
|
617
715
|
|
|
618
|
-
|
|
619
|
-
|
|
620
716
|
### Toast / useToast
|
|
621
717
|
|
|
622
718
|
**Import:** `import { ToastProvider, useToast } from '@retray-dev/ui-kit'`
|
|
623
719
|
**When to use:** Ephemeral feedback messages (save success, network error, copy confirmation).
|
|
624
720
|
|
|
625
|
-
**
|
|
721
|
+
**Required setup** — `ToastProvider` must wrap your app inside `SafeAreaProvider` (see Setup section above).
|
|
722
|
+
|
|
723
|
+
**Peer dependency:** `react-native-safe-area-context` — required for `useSafeAreaInsets` inside `ToastProvider`.
|
|
626
724
|
|
|
627
725
|
```tsx
|
|
628
726
|
import { useToast } from '@retray-dev/ui-kit'
|
|
@@ -651,4 +749,11 @@ function MyComponent() {
|
|
|
651
749
|
| variant | `'default' \| 'destructive' \| 'success'` | `'default'` | `default`: dark background. `destructive`: red. `success`: green |
|
|
652
750
|
| duration | `number` (ms) | `3000` | Auto-dismiss after this delay |
|
|
653
751
|
|
|
654
|
-
|
|
752
|
+
**`dismiss(id)`:** Dismiss a toast programmatically. The `id` is returned by the `toast()` call — store it if you need programmatic dismissal.
|
|
753
|
+
|
|
754
|
+
**Notes:**
|
|
755
|
+
- Max 3 toasts shown simultaneously (oldest is removed when a 4th arrives)
|
|
756
|
+
- Toasts appear at the top of the screen, below the status bar (dynamic safe area inset)
|
|
757
|
+
- Entrance: `withTiming(120ms, Easing.out(Easing.exp))` slide-down + opacity fade — fast, sharp feel
|
|
758
|
+
- Exit: `withTiming(200ms)` slide-up + opacity fade
|
|
759
|
+
- Swipe left or right to dismiss early (threshold: 80px or 800 pt/s velocity)
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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
|
|
|
5
|
-
-
|
|
5
|
+
- 24 components across 5 categories
|
|
6
6
|
- Light/dark theme with 18 color tokens and full customization
|
|
7
7
|
- Apple HIG–compliant touch targets and haptic feedback
|
|
8
8
|
- Animated interactions: spring press, sliding tabs, accordion easing, animated progress
|
|
@@ -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`, `CurrencyInput`, `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
|
|