@retray-dev/ui-kit 5.4.0 → 6.0.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 +261 -126
- package/dist/index.d.mts +147 -44
- package/dist/index.d.ts +147 -44
- package/dist/index.js +429 -305
- package/dist/index.mjs +419 -303
- package/package.json +7 -2
- package/src/components/Accordion/Accordion.tsx +6 -2
- package/src/components/AlertBanner/AlertBanner.tsx +16 -33
- package/src/components/Button/Button.tsx +18 -6
- package/src/components/Card/Card.tsx +12 -9
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +4 -4
- package/src/components/CurrencyDisplay/CurrencyDisplay.tsx +14 -3
- package/src/components/EmptyState/EmptyState.tsx +21 -6
- package/src/components/Input/Input.tsx +21 -10
- package/src/components/ListItem/ListItem.tsx +14 -8
- package/src/components/MediaCard/MediaCard.tsx +1 -0
- package/src/components/MenuItem/MenuItem.tsx +206 -0
- package/src/components/MenuItem/index.ts +2 -0
- package/src/components/Select/Select.tsx +1 -1
- package/src/components/Separator/Separator.tsx +2 -0
- package/src/components/Sheet/Sheet.tsx +164 -51
- package/src/components/Sheet/index.ts +1 -1
- package/src/components/Tabs/Tabs.tsx +4 -4
- package/src/components/Toast/Toast.tsx +41 -267
- package/src/components/Toast/index.ts +1 -2
- package/src/components/Toggle/Toggle.tsx +2 -2
- package/src/index.ts +1 -0
- package/src/theme/colors.ts +3 -0
- package/src/theme/types.ts +11 -0
- package/src/tokens.ts +3 -3
package/COMPONENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @retray-dev/ui-kit — Component Reference (
|
|
1
|
+
# @retray-dev/ui-kit — Component Reference (v6.0.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
|
|
|
@@ -36,11 +36,11 @@ export default function App() {
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
**Provider order is mandatory:**
|
|
39
|
-
- `SafeAreaProvider` must be outermost — required by `
|
|
39
|
+
- `SafeAreaProvider` must be outermost — required by `@gorhom/bottom-sheet`
|
|
40
40
|
- `initialMetrics={initialWindowMetrics}` is required on Android to avoid a "No safe area value available" crash on first render
|
|
41
41
|
- `GestureHandlerRootView` must wrap everything — required by `@gorhom/bottom-sheet`
|
|
42
42
|
- `BottomSheetModalProvider` must be inside `GestureHandlerRootView`
|
|
43
|
-
- `ToastProvider`
|
|
43
|
+
- `ToastProvider` wraps children and renders `Toaster` (from `sonner-native`) internally
|
|
44
44
|
|
|
45
45
|
## Typography — Poppins (Required)
|
|
46
46
|
|
|
@@ -136,6 +136,9 @@ These are the only values you need to supply when customizing the theme. The lib
|
|
|
136
136
|
| `successForeground` | `#ffffff` | `#ffffff` | Text/icon on success backgrounds |
|
|
137
137
|
| `warning` | `#e67e00` | `#f57c00` | Warning / caution states |
|
|
138
138
|
| `warningForeground` | `#ffffff` | `#ffffff` | Text/icon on warning backgrounds |
|
|
139
|
+
| `overlay` *(optional)* | `rgba(0,0,0,0.45)` | `rgba(0,0,0,0.45)` | Backdrop/overlay color behind sheets and dialogs |
|
|
140
|
+
| `accent` *(optional)* | same as `primary` | same as `primary` | Secondary brand accent (e.g. Airbnb coral). Falls back to `primary` |
|
|
141
|
+
| `accentForeground` *(optional)* | same as `primaryForeground` | same as `primaryForeground` | Text/icon on accent backgrounds. Falls back to `primaryForeground` |
|
|
139
142
|
|
|
140
143
|
### Derived Tokens (ResolvedColors) — read-only via useTheme().colors
|
|
141
144
|
|
|
@@ -155,6 +158,9 @@ The full palette components consume. Never supply these directly — they are co
|
|
|
155
158
|
| `warningBorder` | `warning` @ 30% | Warning banner border |
|
|
156
159
|
| `ring` | `= primary` | Focus ring color (always matches primary) |
|
|
157
160
|
| `input` | `= border` | Input field border (always matches border) |
|
|
161
|
+
| `overlay` | `overlay` token or `rgba(0,0,0,0.45)` | Backdrop behind sheets and dialogs |
|
|
162
|
+
| `accentResolved` | `accent` token or `= primary` | Resolved accent color — always present |
|
|
163
|
+
| `accentForegroundResolved` | `accentForeground` token or `= primaryForeground` | Resolved text on accent — always present |
|
|
158
164
|
|
|
159
165
|
**Usage example — building a custom component using derived tokens:**
|
|
160
166
|
```tsx
|
|
@@ -231,10 +237,10 @@ import { SPACING, ICON_SIZES, RADIUS, SHADOWS, BREAKPOINTS, TYPOGRAPHY } from '@
|
|
|
231
237
|
| `none` | 0 | No rounding |
|
|
232
238
|
| `xs` | 4 | Micro chips, tags |
|
|
233
239
|
| `sm` | 8 | Inputs, Textarea, Select, Checkbox |
|
|
234
|
-
| `md` | 14 | Cards, MediaCard, AlertBanner, Toast, EmptyState |
|
|
240
|
+
| `md` | 14 | Cards, Buttons (all variants), MediaCard, AlertBanner, Toast, EmptyState |
|
|
235
241
|
| `lg` | 20 | Sheet top corners |
|
|
236
|
-
| `xl` | 32 |
|
|
237
|
-
| `full` | 9999 |
|
|
242
|
+
| `xl` | 32 | Large decorative elements |
|
|
243
|
+
| `full` | 9999 | IconButton (circle), CategoryStrip chips |
|
|
238
244
|
|
|
239
245
|
**Types:** `Radius`, `RadiusKey`
|
|
240
246
|
|
|
@@ -286,7 +292,7 @@ All components use these tokens for text styling. Import and use in custom compo
|
|
|
286
292
|
| `caption-sm` | 13 | 400 | 16 | 0 | Timestamps, metadata |
|
|
287
293
|
| `badge-text` | 11 | 600 | 13 | 0 | Badge labels, small tags |
|
|
288
294
|
| `micro-label` | 12 | 700 | 16 | 0 | Micro labels, overlines |
|
|
289
|
-
| `uppercase-tag` |
|
|
295
|
+
| `uppercase-tag` | 10 | 700 | 13 | 0.8 | Uppercase decorative tags (auto-uppercase) |
|
|
290
296
|
| `button-lg` | 16 | 500 | 20 | 0 | Button labels (md/lg size) |
|
|
291
297
|
| `button-sm` | 14 | 500 | 18 | 0 | Button labels (sm size) |
|
|
292
298
|
|
|
@@ -344,6 +350,59 @@ const styles = StyleSheet.create({
|
|
|
344
350
|
|
|
345
351
|
---
|
|
346
352
|
|
|
353
|
+
## Migration Guide: v5 → v6
|
|
354
|
+
|
|
355
|
+
### New Components
|
|
356
|
+
|
|
357
|
+
**`MenuItem`** — Navigation row with icon, label, and optional right slot (`rightRender`). Replaces ad-hoc `ListItem` usage for settings/nav menus. Zero horizontal padding by design — consumer controls spacing.
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
import { MenuItem } from '@retray-dev/ui-kit'
|
|
361
|
+
// variants: 'plain' (default) | 'card'
|
|
362
|
+
<MenuItem label="Profile" iconName="user" onPress={() => {}} />
|
|
363
|
+
<MenuItem label="Notifications" iconName="bell" rightRender={<Switch value={on} onValueChange={setOn} />} showChevron={false} onPress={() => {}} />
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Breaking Changes
|
|
367
|
+
|
|
368
|
+
**Sheet keyboard defaults changed:**
|
|
369
|
+
| Prop | v5 default | v6 default |
|
|
370
|
+
|------|-----------|-----------|
|
|
371
|
+
| `keyboardBehavior` | `'fillParent'` (Android) / `'interactive'` (iOS) | `'interactive'` (both) |
|
|
372
|
+
| `android_keyboardInputMode` | `'adjustResize'` | `'adjustPan'` |
|
|
373
|
+
|
|
374
|
+
If you relied on `adjustResize`, set it explicitly: `android_keyboardInputMode="adjustResize"`.
|
|
375
|
+
|
|
376
|
+
**Toast API simplified:**
|
|
377
|
+
|
|
378
|
+
```tsx
|
|
379
|
+
// v5 — hook-only API
|
|
380
|
+
const { toast } = useToast()
|
|
381
|
+
toast.success('Done')
|
|
382
|
+
|
|
383
|
+
// v6 — direct import preferred (hook still works for compat)
|
|
384
|
+
import { toast } from '@retray-dev/ui-kit'
|
|
385
|
+
toast.success('Done')
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### New Theme Tokens
|
|
389
|
+
|
|
390
|
+
Three optional `ThemeColors` tokens — fall back gracefully if omitted:
|
|
391
|
+
|
|
392
|
+
| Token | Default | Purpose |
|
|
393
|
+
|-------|---------|---------|
|
|
394
|
+
| `overlay` | `rgba(0,0,0,0.45)` | Backdrop color behind sheets and dialogs |
|
|
395
|
+
| `accent` | `= primary` | Secondary brand accent color |
|
|
396
|
+
| `accentForeground` | `= primaryForeground` | Text on accent backgrounds |
|
|
397
|
+
|
|
398
|
+
Access resolved values via `useTheme().colors.overlay`, `.accentResolved`, `.accentForegroundResolved`.
|
|
399
|
+
|
|
400
|
+
### Token Corrections
|
|
401
|
+
|
|
402
|
+
- `TYPOGRAPHY['uppercase-tag']` — size corrected to `10` (was documented as `8`, actual value was always `10`)
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
347
406
|
## Components
|
|
348
407
|
|
|
349
408
|
---
|
|
@@ -381,7 +440,7 @@ const styles = StyleSheet.create({
|
|
|
381
440
|
| `caption-sm` | 13 | 400 | `foregroundMuted` | Timestamps, metadata, helper text |
|
|
382
441
|
| `badge-text` | 11 | 600 | `foreground` | Badge labels, small status tags |
|
|
383
442
|
| `micro-label` | 12 | 700 | `foreground` | Micro labels, overlines |
|
|
384
|
-
| `uppercase-tag` |
|
|
443
|
+
| `uppercase-tag` | 10 | 700 | `foreground` | Decorative uppercase category labels (auto-transforms text) |
|
|
385
444
|
| `button-lg` | 16 | 500 | `foreground` | Internal use in Button component (md/lg) |
|
|
386
445
|
| `button-sm` | 14 | 500 | `foreground` | Internal use in Button component (sm) |
|
|
387
446
|
|
|
@@ -456,7 +515,7 @@ const styles = StyleSheet.create({
|
|
|
456
515
|
| `md` | 48px | 24px | 18px | `button-lg` (16pt/500) |
|
|
457
516
|
| `lg` | 56px | 28px | 20px | `button-lg` (16pt/500) |
|
|
458
517
|
|
|
459
|
-
**Shape:** `borderRadius: RADIUS.
|
|
518
|
+
**Shape:** `borderRadius: RADIUS.md = 14px` — Airbnb-aligned rounded rect on all variants. Exception: `IconButton` uses `RADIUS.full` (perfect circle).
|
|
460
519
|
|
|
461
520
|
**Animations:** Scale springs to 0.95 on `onPressIn`, back to 1.0 on `onPressOut`.
|
|
462
521
|
|
|
@@ -1887,7 +1946,7 @@ const [tab, setTab] = useState('profile')
|
|
|
1887
1946
|
|
|
1888
1947
|
### Sheet
|
|
1889
1948
|
|
|
1890
|
-
**Import:** `import { Sheet, BottomSheetModalProvider } from '@retray-dev/ui-kit'`
|
|
1949
|
+
**Import:** `import { Sheet, SheetTextInput, BottomSheetModalProvider } from '@retray-dev/ui-kit'`
|
|
1891
1950
|
|
|
1892
1951
|
**When to use:** Bottom sheet for contextual actions, filters, pickers, or detail views that don't need a full screen. Auto-sizes to content — no snap points needed.
|
|
1893
1952
|
|
|
@@ -1904,160 +1963,156 @@ Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to `ba
|
|
|
1904
1963
|
| open | `boolean` | required | `true` presents the sheet, `false` dismisses it |
|
|
1905
1964
|
| onClose | `() => void` | required | Called on swipe-dismiss or backdrop press |
|
|
1906
1965
|
| title | `string` | — | Sheet heading |
|
|
1907
|
-
|
|
|
1966
|
+
| subtitle | `string` | — | Supporting text below title (replaces deprecated `description`) |
|
|
1967
|
+
| showCloseButton | `boolean` | `false` | Show X close button in the header |
|
|
1908
1968
|
| children | `ReactNode` | — | Sheet content |
|
|
1909
|
-
| style | `ViewStyle` | — | Inner content container style |
|
|
1910
|
-
|
|
|
1911
|
-
|
|
|
1912
|
-
|
|
|
1913
|
-
|
|
|
1969
|
+
| style | `ViewStyle` | — | Inner scroll/content container style |
|
|
1970
|
+
| contentStyle | `ViewStyle` | — | Outer content wrapper style |
|
|
1971
|
+
| scrollable | `boolean` | `false` | Wraps children in `BottomSheetScrollView` |
|
|
1972
|
+
| maxHeight | `number` | `~85% screen` | Caps sheet height (dp). Defaults to 85% of screen height. Enables scrolling when content overflows |
|
|
1973
|
+
| keyboardBehavior | `'extend' \| 'fillParent' \| 'interactive'` | `'interactive'` | How sheet responds to keyboard. `'interactive'` (default) offsets sheet by keyboard size — works on both platforms. `'fillParent'` extends to fill parent view. `'extend'` extends to max snap point |
|
|
1974
|
+
| keyboardBlurBehavior | `'none' \| 'restore'` | `'restore'` | What happens when keyboard dismisses: `'restore'` → return to pre-keyboard position (recommended), `'none'` → stay at keyboard-adjusted position |
|
|
1975
|
+
| enableBlurKeyboardOnGesture | `boolean` | `true` | Dismiss keyboard when user starts dragging sheet down (recommended for better UX) |
|
|
1976
|
+
| android_keyboardInputMode | `'adjustPan' \| 'adjustResize'` | `'adjustPan'` | Android-only: `'adjustPan'` moves the window (default — fixes restore issues with dynamic sizing). `'adjustResize'` resizes the container (can cause transparent gap when keyboard dismisses) |
|
|
1977
|
+
| footer | `ReactNode` | — | Sticky footer below scroll area (sticky above keyboard) |
|
|
1978
|
+
| snapPoints | `(string \| number)[]` | — | Optional snap points (e.g., `['50%', '85%']`). When omitted, uses dynamic sizing (auto-fits content) |
|
|
1914
1979
|
|
|
1915
1980
|
**Features:**
|
|
1916
|
-
- `enableDynamicSizing` — height auto-fits content, no `snapPoints` needed
|
|
1981
|
+
- `enableDynamicSizing` — height auto-fits content, no `snapPoints` needed (default behavior when `snapPoints` is omitted)
|
|
1982
|
+
- `snapPoints` — optionally provide custom snap points (e.g., `['50%', '85%']`). Disables dynamic sizing when provided
|
|
1917
1983
|
- `enablePanDownToClose` — swipe down to dismiss
|
|
1918
1984
|
- Backdrop press dismisses
|
|
1919
|
-
- **Scrollable content:** use `scrollable` prop
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1985
|
+
- **Scrollable content:** use `scrollable` prop or `maxHeight`. Both use `BottomSheetScrollView` — do NOT use plain `ScrollView` inside Sheet
|
|
1986
|
+
- **Keyboard handling:** Full keyboard awareness via `@gorhom/bottom-sheet` v5. Professional defaults:
|
|
1987
|
+
- `keyboardBehavior="interactive"` — sheet offsets by keyboard size on both platforms
|
|
1988
|
+
- `android_keyboardInputMode="adjustPan"` — moves window instead of resizing (fixes restore issues on Android)
|
|
1989
|
+
- `keyboardBlurBehavior="restore"` — returns to pre-keyboard position when keyboard dismisses
|
|
1990
|
+
- `enableBlurKeyboardOnGesture={true}` — dismisses keyboard when dragging sheet down
|
|
1991
|
+
- `topInset` — automatically applied from safe area context to prevent going above notch
|
|
1992
|
+
- **Text inputs inside sheet:** **MUST use `SheetTextInput`** (re-exported `BottomSheetTextInput`) — handles focus/blur internally, communicates with sheet's keyboard system. **Never use regular `TextInput`** inside sheets — keyboard handling will break
|
|
1993
|
+
- **Custom TextInput:** If using custom input components, you must copy `handleOnFocus`/`handleOnBlur` from [BottomSheetTextInput source](https://github.com/gorhom/react-native-bottom-sheet/blob/master/src/components/bottomSheetTextInput/BottomSheetTextInput.tsx)
|
|
1994
|
+
|
|
1995
|
+
**Haptics:** `impactMedium` on open.
|
|
1924
1996
|
|
|
1925
1997
|
**Examples:**
|
|
1926
1998
|
```tsx
|
|
1927
1999
|
const [open, setOpen] = useState(false)
|
|
1928
2000
|
|
|
2001
|
+
// Basic
|
|
1929
2002
|
<Sheet open={open} onClose={() => setOpen(false)} title="Sort by">
|
|
1930
|
-
<RadioGroup
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2003
|
+
<RadioGroup options={sortOptions} value={sort} onValueChange={setSort} />
|
|
2004
|
+
</Sheet>
|
|
2005
|
+
|
|
2006
|
+
// Scrollable list
|
|
2007
|
+
<Sheet open={open} onClose={() => setOpen(false)} title="Results" scrollable maxHeight={500}>
|
|
2008
|
+
{items.map((r) => <ListItem key={r.id} title={r.name} showSeparator />)}
|
|
2009
|
+
</Sheet>
|
|
2010
|
+
|
|
2011
|
+
// With text input — keyboard handling works automatically (platform-optimized defaults)
|
|
2012
|
+
<Sheet
|
|
2013
|
+
open={open}
|
|
2014
|
+
onClose={() => setOpen(false)}
|
|
2015
|
+
title="Add note"
|
|
2016
|
+
subtitle="Keyboard handling is automatic with platform-optimized defaults"
|
|
2017
|
+
>
|
|
2018
|
+
<SheetTextInput
|
|
2019
|
+
placeholder="Write your note..."
|
|
2020
|
+
multiline
|
|
2021
|
+
style={{
|
|
2022
|
+
borderWidth: 1,
|
|
2023
|
+
borderColor: '#ddd',
|
|
2024
|
+
borderRadius: 8,
|
|
2025
|
+
padding: 12,
|
|
2026
|
+
minHeight: 80,
|
|
2027
|
+
}}
|
|
1939
2028
|
/>
|
|
2029
|
+
<Button label="Save" fullWidth style={{ marginTop: 12 }} onPress={() => setOpen(false)} />
|
|
1940
2030
|
</Sheet>
|
|
1941
2031
|
|
|
1942
|
-
//
|
|
1943
|
-
<Sheet
|
|
1944
|
-
{
|
|
1945
|
-
|
|
1946
|
-
|
|
2032
|
+
// With custom snap points (manual sizing)
|
|
2033
|
+
<Sheet
|
|
2034
|
+
open={open}
|
|
2035
|
+
onClose={() => setOpen(false)}
|
|
2036
|
+
title="Filters"
|
|
2037
|
+
snapPoints={['50%', '90%']}
|
|
2038
|
+
>
|
|
2039
|
+
<RadioGroup options={filterOptions} value={filter} onValueChange={setFilter} />
|
|
1947
2040
|
</Sheet>
|
|
1948
2041
|
|
|
1949
|
-
//
|
|
1950
|
-
<Sheet open={open} onClose={() => setOpen(false)} title="
|
|
1951
|
-
{
|
|
2042
|
+
// With sticky footer
|
|
2043
|
+
<Sheet open={open} onClose={() => setOpen(false)} title="Filters" scrollable
|
|
2044
|
+
footer={<View style={{ padding: 16 }}><Button label="Apply" fullWidth onPress={() => setOpen(false)} /></View>}>
|
|
2045
|
+
{/* long filter content */}
|
|
1952
2046
|
</Sheet>
|
|
1953
2047
|
|
|
1954
|
-
//
|
|
1955
|
-
<Sheet open={
|
|
1956
|
-
<
|
|
1957
|
-
<View>
|
|
1958
|
-
<Text variant="title-sm">Price range</Text>
|
|
1959
|
-
<Slider value={maxPrice} minimumValue={0} maximumValue={1000} step={50} onValueChange={setMaxPrice} showValue formatValue={(v) => `$${v}`} />
|
|
1960
|
-
</View>
|
|
1961
|
-
<Separator />
|
|
1962
|
-
<View>
|
|
1963
|
-
<Text variant="title-sm">Category</Text>
|
|
1964
|
-
<ChipGroup options={categoryOptions} value={selectedCategory} onValueChange={setSelectedCategory} />
|
|
1965
|
-
</View>
|
|
1966
|
-
<Button label="Apply filters" fullWidth onPress={() => { applyFilters(); setFilterOpen(false) }} />
|
|
1967
|
-
</View>
|
|
2048
|
+
// With close button
|
|
2049
|
+
<Sheet open={open} onClose={() => setOpen(false)} title="Details" subtitle="Product info" showCloseButton>
|
|
2050
|
+
<Text>Content here...</Text>
|
|
1968
2051
|
</Sheet>
|
|
1969
2052
|
```
|
|
1970
2053
|
|
|
2054
|
+
**Keyboard handling notes:**
|
|
2055
|
+
- No `KeyboardAvoidingView` needed — `@gorhom/bottom-sheet` handles everything
|
|
2056
|
+
- Always use `SheetTextInput` (not plain `TextInput`) for auto-focus/blur handling
|
|
2057
|
+
- Default `keyboardBehavior="interactive"` works on both platforms
|
|
2058
|
+
- Default `android_keyboardInputMode="adjustPan"` fixes the transparent gap that occurs with `adjustResize` when keyboard dismisses
|
|
2059
|
+
- `enableBlurKeyboardOnGesture={true}` (default) dismisses keyboard when dragging sheet
|
|
2060
|
+
|
|
1971
2061
|
---
|
|
1972
2062
|
|
|
1973
2063
|
### Toast / useToast
|
|
1974
2064
|
|
|
1975
|
-
**Import:** `import { ToastProvider, useToast } from '@retray-dev/ui-kit'`
|
|
2065
|
+
**Import:** `import { toast, ToastProvider, useToast } from '@retray-dev/ui-kit'`
|
|
1976
2066
|
|
|
1977
2067
|
**When to use:** Ephemeral feedback messages — save confirmations, errors, copy notifications, background process updates. Auto-dismiss after duration.
|
|
1978
2068
|
|
|
1979
|
-
**
|
|
2069
|
+
**Powered by:** `sonner-native` — white/black background, colored icon marks the variant (not the background), swipe-to-dismiss, promise support, stacking.
|
|
2070
|
+
|
|
2071
|
+
**Required setup:** `ToastProvider` must wrap the app. See Setup section above. Also requires `react-native-svg` and `react-native-screens` as peer deps.
|
|
1980
2072
|
|
|
1981
|
-
**
|
|
2073
|
+
**API — direct function (preferred):**
|
|
1982
2074
|
```tsx
|
|
1983
|
-
|
|
1984
|
-
|
|
2075
|
+
import { toast } from '@retray-dev/ui-kit'
|
|
2076
|
+
|
|
2077
|
+
// Variants:
|
|
2078
|
+
toast.success('Saved successfully')
|
|
2079
|
+
toast.error('Connection error', { description: 'Check your network' })
|
|
2080
|
+
toast.warning('Slow connection detected')
|
|
2081
|
+
toast('Neutral message')
|
|
2082
|
+
toast.loading('Processing...')
|
|
2083
|
+
|
|
2084
|
+
// Promise — auto-resolves:
|
|
2085
|
+
toast.promise(saveData(), {
|
|
2086
|
+
loading: 'Saving...',
|
|
2087
|
+
success: 'Saved',
|
|
2088
|
+
error: 'Failed to save',
|
|
2089
|
+
})
|
|
1985
2090
|
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
toast({ title: 'Saved', variant: 'success' })
|
|
1992
|
-
}}
|
|
1993
|
-
/>
|
|
1994
|
-
)
|
|
1995
|
-
}
|
|
2091
|
+
// Programmatic dismiss:
|
|
2092
|
+
const id = toast.loading('Uploading...')
|
|
2093
|
+
await upload()
|
|
2094
|
+
toast.dismiss(id)
|
|
2095
|
+
toast.success('Upload complete')
|
|
1996
2096
|
```
|
|
1997
2097
|
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
| Field | Type | Default | Notes |
|
|
2001
|
-
|-------|------|---------|-------|
|
|
2002
|
-
| title | `string` | — | Bold heading |
|
|
2003
|
-
| description | `string` | — | Detail text below title |
|
|
2004
|
-
| variant | `'default' \| 'destructive' \| 'success' \| 'warning'` | `'default'` | Background and icon color |
|
|
2005
|
-
| duration | `number` (ms) | `3000` | Auto-dismiss delay. Pass `Infinity` to prevent auto-dismiss |
|
|
2006
|
-
| icon | `ReactNode` | — | Custom icon. Defaults to variant symbol |
|
|
2007
|
-
| iconName | `string` | — | Icon name from `@expo/vector-icons`. Takes precedence over `icon` |
|
|
2008
|
-
| iconColor | `string` | — | Override icon color |
|
|
2009
|
-
| action | `{ label: string, onPress: () => void }` | — | Optional action button beside dismiss |
|
|
2010
|
-
|
|
2011
|
-
**`dismiss(id)`:** Dismiss a specific toast programmatically. `id` is returned by the `toast()` call.
|
|
2012
|
-
|
|
2013
|
-
**Variant details:**
|
|
2014
|
-
- `default` — dark/primary background, `impactLight` haptic
|
|
2015
|
-
- `success` — `success` token background, `notificationSuccess` haptic
|
|
2016
|
-
- `destructive` — `destructive` token background, `notificationError` haptic
|
|
2017
|
-
- `warning` — `warning` token background, `notificationError` haptic
|
|
2018
|
-
|
|
2019
|
-
**Behavior:**
|
|
2020
|
-
- Max 3 toasts shown simultaneously — oldest removed when 4th arrives
|
|
2021
|
-
- Appear at top of screen below status bar (dynamic safe area inset)
|
|
2022
|
-
- Swipe left or right to dismiss early (threshold: 80px or 800pt/s velocity)
|
|
2023
|
-
- **Web:** 400px max width, centered
|
|
2024
|
-
|
|
2025
|
-
**Animation:** Entrance: `withTiming(120ms, Easing.out(Easing.exp))` slide-down + opacity. Exit: `withTiming(200ms)` slide-up + opacity fade.
|
|
2026
|
-
|
|
2027
|
-
**Examples:**
|
|
2098
|
+
**API — hook (backward compat):**
|
|
2028
2099
|
```tsx
|
|
2029
2100
|
const { toast, dismiss } = useToast()
|
|
2030
|
-
|
|
2031
|
-
// Basic variants
|
|
2032
|
-
toast({ title: 'Saved', variant: 'success' })
|
|
2033
|
-
toast({ title: 'Connection error', variant: 'destructive' })
|
|
2034
|
-
toast({ title: 'Check your email', variant: 'warning' })
|
|
2035
|
-
toast({ title: 'Link copied' })
|
|
2036
|
-
|
|
2037
|
-
// With description
|
|
2038
|
-
toast({
|
|
2039
|
-
title: 'Payment sent',
|
|
2040
|
-
description: '$250 sent to John Doe',
|
|
2041
|
-
variant: 'success',
|
|
2042
|
-
iconName: 'check-circle',
|
|
2043
|
-
})
|
|
2044
|
-
|
|
2045
|
-
// With action button
|
|
2046
|
-
toast({
|
|
2047
|
-
title: 'Message deleted',
|
|
2048
|
-
action: { label: 'Undo', onPress: () => restoreMessage() },
|
|
2049
|
-
})
|
|
2050
|
-
|
|
2051
|
-
// Custom duration (longer)
|
|
2052
|
-
toast({ title: 'Processing your request...', duration: 8000 })
|
|
2053
|
-
|
|
2054
|
-
// Programmatic dismiss
|
|
2055
|
-
const id = toast({ title: 'Uploading...', duration: Infinity })
|
|
2056
|
-
await upload()
|
|
2101
|
+
toast.success('Saved')
|
|
2057
2102
|
dismiss(id)
|
|
2058
|
-
toast({ title: 'Upload complete', variant: 'success' })
|
|
2059
2103
|
```
|
|
2060
2104
|
|
|
2105
|
+
**Behavior:**
|
|
2106
|
+
- Max 3 toasts shown simultaneously
|
|
2107
|
+
- Appear top-center with safe area insets (respects notch/status bar)
|
|
2108
|
+
- Swipe up to dismiss early
|
|
2109
|
+
- Auto-dismiss after 4000ms
|
|
2110
|
+
- Follows `colorScheme` from `ThemeProvider` (light/dark background)
|
|
2111
|
+
|
|
2112
|
+
**Notes:**
|
|
2113
|
+
- `richColors: false` — background stays white (light) / black (dark). Variant shown via icon color only.
|
|
2114
|
+
- `closeButton: false` — swipe-to-dismiss is the gesture.
|
|
2115
|
+
|
|
2061
2116
|
---
|
|
2062
2117
|
|
|
2063
2118
|
### ConfirmDialog
|
|
@@ -2130,6 +2185,8 @@ toast({ title: 'Upload complete', variant: 'success' })
|
|
|
2130
2185
|
|
|
2131
2186
|
**When to use:** Rows in lists, feeds, menus, settings screens. The most compositional component — composes left slot, text block, and right slot in a standard horizontal layout. Supports plain (list items) and card (standalone cards) variants.
|
|
2132
2187
|
|
|
2188
|
+
**Important:** ListItem has **zero horizontal padding** by design — the consumer controls spacing. Wrap in a container with padding for standalone use, or use `variant="card"` for auto-styled surfaces.
|
|
2189
|
+
|
|
2133
2190
|
| Prop | Type | Default | Notes |
|
|
2134
2191
|
|------|------|---------|-------|
|
|
2135
2192
|
| title | `string` | required | Primary text |
|
|
@@ -2240,6 +2297,84 @@ toast({ title: 'Upload complete', variant: 'success' })
|
|
|
2240
2297
|
|
|
2241
2298
|
---
|
|
2242
2299
|
|
|
2300
|
+
### MenuItem
|
|
2301
|
+
|
|
2302
|
+
**Import:** `import { MenuItem } from '@retray-dev/ui-kit'`
|
|
2303
|
+
|
|
2304
|
+
**When to use:** Settings screens, navigation lists, menu entries — icon + label + optional right content. Purpose-built for Airbnb-style settings rows. Use `ListItem` when you need subtitle, caption, or more complex layouts.
|
|
2305
|
+
|
|
2306
|
+
**Important:** MenuItem has **zero horizontal padding** by design — the consumer controls spacing. Wrap in a container with padding for standalone use, or use `variant="card"` for auto-styled surfaces.
|
|
2307
|
+
|
|
2308
|
+
| Prop | Type | Default | Notes |
|
|
2309
|
+
|------|------|---------|-------|
|
|
2310
|
+
| label | `string` | required | Row label |
|
|
2311
|
+
| iconName | `string` | — | Icon from `@expo/vector-icons`. Auto-resolved across all 6 families |
|
|
2312
|
+
| icon | `ReactNode` | — | Custom icon (used if `iconName` not set) |
|
|
2313
|
+
| iconColor | `string` | — | Override icon color. Defaults to `foreground` |
|
|
2314
|
+
| rightRender | `ReactNode` | — | Custom content on the right. Replaces default chevron. Use for Switch, Checkbox, Badge, etc. |
|
|
2315
|
+
| showChevron | `boolean` | `true` | Show chevron on the right. Ignored when `rightRender` is set |
|
|
2316
|
+
| onPress | `() => void` | required | Press handler |
|
|
2317
|
+
| variant | `'plain' \| 'card'` | `'plain'` | `plain` sits inside parent surface. `card` has own background + border |
|
|
2318
|
+
| disabled | `boolean` | `false` | Dims and disables press |
|
|
2319
|
+
| showSeparator | `boolean` | `false` | Hairline separator at bottom |
|
|
2320
|
+
| style | `ViewStyle` | — | Container style override |
|
|
2321
|
+
| labelStyle | `TextStyle` | — | Label text style override |
|
|
2322
|
+
|
|
2323
|
+
**Features:**
|
|
2324
|
+
- Height: 54dp — consistent settings row
|
|
2325
|
+
- Chevron: shown by default (`showChevron={true}`). Can be replaced via `rightRender` prop
|
|
2326
|
+
- `rightRender` — arbitrary right slot content (Switch, Checkbox, Badge, etc). When set, chevron is hidden
|
|
2327
|
+
- Press scale: 0.97 spring (`stiffness: 350, damping: 28, mass: 0.9`)
|
|
2328
|
+
- Haptics: `selectionAsync` on press
|
|
2329
|
+
|
|
2330
|
+
**Example:**
|
|
2331
|
+
```tsx
|
|
2332
|
+
// Settings screen (wrap in container with padding)
|
|
2333
|
+
<View style={{ padding: 16, backgroundColor: colors.card, borderRadius: 12 }}>
|
|
2334
|
+
<MenuItem label="Personal info" iconName="user" onPress={() => navigate('profile')} showSeparator />
|
|
2335
|
+
<MenuItem label="Security" iconName="shield" onPress={() => navigate('security')} showSeparator />
|
|
2336
|
+
<MenuItem label="Privacy" iconName="lock" onPress={() => navigate('privacy')} showSeparator />
|
|
2337
|
+
<MenuItem
|
|
2338
|
+
label="Notifications"
|
|
2339
|
+
iconName="bell"
|
|
2340
|
+
onPress={() => setNotifs(!notifs)}
|
|
2341
|
+
rightRender={<Switch value={notifs} onValueChange={setNotifs} />}
|
|
2342
|
+
showSeparator
|
|
2343
|
+
/>
|
|
2344
|
+
<MenuItem
|
|
2345
|
+
label="Dark Mode"
|
|
2346
|
+
iconName="moon"
|
|
2347
|
+
onPress={() => setDark(!dark)}
|
|
2348
|
+
rightRender={<Checkbox checked={dark} onPress={() => setDark(!dark)} />}
|
|
2349
|
+
showSeparator
|
|
2350
|
+
/>
|
|
2351
|
+
<MenuItem
|
|
2352
|
+
label="Payments"
|
|
2353
|
+
iconName="credit-card"
|
|
2354
|
+
onPress={() => navigate('payments')}
|
|
2355
|
+
rightRender={<Badge label="New" variant="warning" size="sm" />}
|
|
2356
|
+
/>
|
|
2357
|
+
</View>
|
|
2358
|
+
|
|
2359
|
+
// Card variant (standalone)
|
|
2360
|
+
<MenuItem
|
|
2361
|
+
variant="card"
|
|
2362
|
+
label="Refer a friend"
|
|
2363
|
+
iconName="gift"
|
|
2364
|
+
onPress={() => navigate('referral')}
|
|
2365
|
+
/>
|
|
2366
|
+
|
|
2367
|
+
// No chevron (custom right content)
|
|
2368
|
+
<MenuItem
|
|
2369
|
+
label="Language"
|
|
2370
|
+
iconName="globe"
|
|
2371
|
+
rightRender={<Text>English</Text>}
|
|
2372
|
+
onPress={() => navigate('language')}
|
|
2373
|
+
/>
|
|
2374
|
+
```
|
|
2375
|
+
|
|
2376
|
+
---
|
|
2377
|
+
|
|
2243
2378
|
### Chip / ChipGroup
|
|
2244
2379
|
|
|
2245
2380
|
**Import:** `import { Chip, ChipGroup } from '@retray-dev/ui-kit'`
|