@retray-dev/ui-kit 9.0.0 → 9.2.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 +178 -7
- package/CONSUMER.md +247 -0
- package/DESIGN.md +668 -0
- package/EXAMPLES.md +19 -12
- package/FONTS.md +107 -0
- package/README.md +3 -3
- package/dist/AlertBanner.d.mts +3 -1
- package/dist/AlertBanner.d.ts +3 -1
- package/dist/AlertBanner.js +18 -2
- package/dist/AlertBanner.mjs +1 -1
- package/dist/ConfirmDialog.d.mts +3 -1
- package/dist/ConfirmDialog.d.ts +3 -1
- package/dist/ConfirmDialog.js +3 -0
- package/dist/ConfirmDialog.mjs +1 -1
- package/dist/CurrencyInput.d.mts +3 -1
- package/dist/CurrencyInput.d.ts +3 -1
- package/dist/CurrencyInput.js +31 -4
- package/dist/CurrencyInput.mjs +2 -2
- package/dist/ImageUpload.d.mts +27 -0
- package/dist/ImageUpload.d.ts +27 -0
- package/dist/ImageUpload.js +399 -0
- package/dist/ImageUpload.mjs +9 -0
- package/dist/Input.d.mts +3 -1
- package/dist/Input.d.ts +3 -1
- package/dist/Input.js +27 -2
- package/dist/Input.mjs +1 -1
- package/dist/ListItem.d.mts +3 -1
- package/dist/ListItem.d.ts +3 -1
- package/dist/ListItem.js +2 -1
- package/dist/ListItem.mjs +1 -1
- package/dist/SheetSelect.d.mts +25 -0
- package/dist/SheetSelect.d.ts +25 -0
- package/dist/SheetSelect.js +440 -0
- package/dist/SheetSelect.mjs +9 -0
- package/dist/{chunk-M6ZXVBTK.mjs → chunk-6MKGPAR2.mjs} +21 -5
- package/dist/{chunk-7QHVVCB3.mjs → chunk-FZZLPJ6B.mjs} +3 -0
- package/dist/{chunk-MAC465BB.mjs → chunk-KNSENOV4.mjs} +5 -3
- package/dist/{chunk-756RAKE4.mjs → chunk-LVYEU5ZK.mjs} +27 -2
- package/dist/{chunk-BNP626TY.mjs → chunk-T4I5WVHA.mjs} +2 -1
- package/dist/chunk-URI2WBIV.mjs +147 -0
- package/dist/chunk-Y4GL2MHX.mjs +112 -0
- package/dist/index.d.mts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +327 -8
- package/dist/index.mjs +51 -12
- package/package.json +18 -5
- package/src/components/AlertBanner/AlertBanner.tsx +21 -3
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +5 -0
- package/src/components/CurrencyInput/CurrencyInput.tsx +4 -0
- package/src/components/ImageUpload/ImageUpload.tsx +158 -0
- package/src/components/ImageUpload/index.ts +1 -0
- package/src/components/Input/Input.tsx +51 -23
- package/src/components/ListItem/ListItem.tsx +4 -1
- package/src/components/SheetSelect/SheetSelect.tsx +192 -0
- package/src/components/SheetSelect/index.ts +1 -0
- package/src/hooks/useConfirmDialog.ts +67 -0
- package/src/index.ts +6 -0
package/COMPONENTS.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# @retray-dev/ui-kit — Component Reference (
|
|
1
|
+
# @retray-dev/ui-kit — Component Reference (v9.2.0)
|
|
2
2
|
|
|
3
|
-
This file is the AI reference for this package.
|
|
3
|
+
This file is the AI reference for this package. Add all three lines below to your project's `CLAUDE.md` to give Claude full context — components, setup guide, and usage examples:
|
|
4
4
|
|
|
5
5
|
```markdown
|
|
6
6
|
## UI Components
|
|
7
7
|
@./node_modules/@retray-dev/ui-kit/COMPONENTS.md
|
|
8
|
+
@./node_modules/@retray-dev/ui-kit/CONSUMER.md
|
|
9
|
+
@./node_modules/@retray-dev/ui-kit/EXAMPLES.md
|
|
8
10
|
```
|
|
9
11
|
|
|
10
12
|
---
|
|
@@ -67,7 +69,7 @@ export default function App() {
|
|
|
67
69
|
Install all required peers (Expo projects: swap `pnpm add` for `npx expo install` to get SDK-pinned versions):
|
|
68
70
|
|
|
69
71
|
```bash
|
|
70
|
-
pnpm add expo-font expo-haptics expo-linear-gradient react-native-safe-area-context @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-worklets @react-native-picker/picker @react-native-community/slider @expo/vector-icons react-native-size-matters react-native-svg react-native-screens sonner-native pressto
|
|
72
|
+
pnpm add expo-font expo-haptics expo-linear-gradient react-native-safe-area-context @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler react-native-worklets @react-native-picker/picker @react-native-community/slider @expo/vector-icons react-native-size-matters react-native-svg react-native-screens sonner-native pressto react-native-ease
|
|
71
73
|
```
|
|
72
74
|
|
|
73
75
|
Then add the Worklets Babel plugin to `babel.config.js` (required by `@gorhom/bottom-sheet` and the pressable animations):
|
|
@@ -96,6 +98,7 @@ module.exports = function (api) {
|
|
|
96
98
|
| `@react-native-community/slider` | **Required** | `Slider` | |
|
|
97
99
|
| `@expo/vector-icons` | **Required** | Icons everywhere | |
|
|
98
100
|
| `react-native-size-matters` | **Required** | Responsive scaling | |
|
|
101
|
+
| `react-native-ease` | **Required** | `Checkbox`, `Chip`, `CategoryStrip`, `Switch`, `RadioGroup`, `Toggle` | Declarative `EaseView` animation layer. Static import in source — omitting it crashes the module load. `pnpm add react-native-ease` |
|
|
99
102
|
| `react-native-pulsar` | **Optional** | Rich haptics on dev builds | Loaded via dynamic `import()` + try/catch; falls back to `expo-haptics`. Skip in Expo Go. `pnpm add react-native-pulsar` |
|
|
100
103
|
| `@shopify/react-native-skia` + `expo-sensors` | **Optional** | Deep-import `HolographicCard` only | `pnpm add @shopify/react-native-skia expo-sensors` |
|
|
101
104
|
|
|
@@ -663,6 +666,8 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
663
666
|
| iconColor | `string` | — | Override icon color. Defaults to variant label color |
|
|
664
667
|
| iconPosition | `'left' \| 'right'` | `'left'` | Side the icon appears on |
|
|
665
668
|
| style | `ViewStyle` | — | Override container style |
|
|
669
|
+
| accessibilityLabel | `string` | — | Screen reader label. Defaults to `label` |
|
|
670
|
+
| accessibilityHint | `string` | — | Screen reader hint |
|
|
666
671
|
|
|
667
672
|
**Variants:**
|
|
668
673
|
|
|
@@ -804,6 +809,8 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
804
809
|
| badge | `boolean \| number` | — | Notification badge overlay |
|
|
805
810
|
| disabled | `boolean` | — | Reduces opacity to 0.5 |
|
|
806
811
|
| style | `ViewStyle` | — | — |
|
|
812
|
+
| accessibilityLabel | `string` | — | Screen reader label |
|
|
813
|
+
| accessibilityHint | `string` | — | Screen reader hint |
|
|
807
814
|
|
|
808
815
|
**Variants:** Same token logic as Button.
|
|
809
816
|
|
|
@@ -819,7 +826,7 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
819
826
|
|
|
820
827
|
| Size | Dimensions | Icon size |
|
|
821
828
|
|------|-----------|-----------|
|
|
822
|
-
| `sm` |
|
|
829
|
+
| `sm` | 44 × 44px | 18px |
|
|
823
830
|
| `md` | 44 × 44px | 20px |
|
|
824
831
|
| `lg` | 52 × 52px | 24px |
|
|
825
832
|
|
|
@@ -880,6 +887,7 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
880
887
|
| label | `string` | — | Label above the input field |
|
|
881
888
|
| error | `string` | — | Error text below — turns border `destructive` (2px) |
|
|
882
889
|
| hint | `string` | — | Helper text below (hidden when `error` is set) |
|
|
890
|
+
| disabled | `boolean` | — | Reduces opacity to 0.5, disables interaction |
|
|
883
891
|
| prefix | `string \| ReactNode` | — | Content before the input text (e.g. `"$"`, icon node) |
|
|
884
892
|
| suffix | `string \| ReactNode` | — | Content after the input text (e.g. `"kg"`, icon node) |
|
|
885
893
|
| prefixStyle | `TextStyle` | — | Style for prefix string (no effect on ReactNode) |
|
|
@@ -891,6 +899,7 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
891
899
|
| type | `'text' \| 'password'` | `'text'` | Password shows eye/eye-off toggle button in suffix slot |
|
|
892
900
|
| containerStyle | `ViewStyle` | — | Outer container View style |
|
|
893
901
|
| inputWrapperStyle | `ViewStyle` | — | The bordered wrapper around the input row |
|
|
902
|
+
| sheetMode | `boolean` | `false` | Use inside a Sheet — swaps `TextInput` for `BottomSheetTextInput` to fix keyboard handling |
|
|
894
903
|
| style | `TextStyle` | — | TextInput element style |
|
|
895
904
|
|
|
896
905
|
**Dimensions:** 56px height (14px vertical padding), 8px border radius.
|
|
@@ -1005,6 +1014,7 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
1005
1014
|
| placeholder | `string` | `'$0'` | Defaults to `prefix + '0'` |
|
|
1006
1015
|
| editable | `boolean` | — | Pass `false` to disable |
|
|
1007
1016
|
| containerStyle | `ViewStyle` | — | Outer container style |
|
|
1017
|
+
| sheetMode | `boolean` | `false` | Use inside a Sheet — forwards `sheetMode` to underlying `Input` |
|
|
1008
1018
|
|
|
1009
1019
|
**Formatting behavior:** Strips all non-digit characters from input, then re-applies thousands separator every 3 digits from the right, then prepends `prefix`. Decimal point input is not supported — this is for whole-number monetary amounts.
|
|
1010
1020
|
|
|
@@ -1670,6 +1680,7 @@ const renderItem = useCallback(({ item }) => (
|
|
|
1670
1680
|
| icon | `ReactNode` | — | Override default icon with custom ReactNode |
|
|
1671
1681
|
| iconName | `string` | — | Icon name from `@expo/vector-icons`. Takes precedence over `icon`, but still falls back to variant default when neither is set |
|
|
1672
1682
|
| iconColor | `string` | — | Override icon color. Defaults to variant title color |
|
|
1683
|
+
| onDismiss | `() => void` | — | When provided, shows an × button on the right. Call to hide the banner from state. |
|
|
1673
1684
|
| style | `ViewStyle` | — | — |
|
|
1674
1685
|
|
|
1675
1686
|
**Variants:**
|
|
@@ -1710,6 +1721,8 @@ const renderItem = useCallback(({ item }) => (
|
|
|
1710
1721
|
| iconName | `string` | — | Icon name from `@expo/vector-icons`. Takes precedence over `icon` |
|
|
1711
1722
|
| iconColor | `string` | — | Override icon color. Defaults to `foregroundMuted` |
|
|
1712
1723
|
| action | `ReactNode` | — | CTA below text — typically a `Button`. Hidden in `compact` size |
|
|
1724
|
+
| actionLabel | `string` | — | Shorthand for a primary `Button` CTA — renders a default `Button` with this label. Requires `onAction`. Hidden in `compact` size |
|
|
1725
|
+
| onAction | `() => void` | — | Handler for the shorthand `actionLabel` button. Required when `actionLabel` is set |
|
|
1713
1726
|
| size | `'default' \| 'compact'` | `'default'` | `compact` is smaller, hides description and action |
|
|
1714
1727
|
| style | `ViewStyle` | — | — |
|
|
1715
1728
|
|
|
@@ -2211,7 +2224,8 @@ Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to `ba
|
|
|
2211
2224
|
| open | `boolean` | required | `true` presents the sheet, `false` dismisses it |
|
|
2212
2225
|
| onClose | `() => void` | required | Called on swipe-dismiss or backdrop press |
|
|
2213
2226
|
| title | `string` | — | Sheet heading |
|
|
2214
|
-
| subtitle | `string` | — | Supporting text below title
|
|
2227
|
+
| subtitle | `string` | — | Supporting text below title |
|
|
2228
|
+
| description | `string` | — | **Deprecated alias** for `subtitle` — prefer `subtitle` |
|
|
2215
2229
|
| showCloseButton | `boolean` | `false` | Show X close button in the header |
|
|
2216
2230
|
| children | `ReactNode` | — | Sheet content |
|
|
2217
2231
|
| style | `ViewStyle` | — | Inner scroll/content container style |
|
|
@@ -2571,6 +2585,7 @@ dismiss(id)
|
|
|
2571
2585
|
| confirmLabel | `string` | `'Confirm'` | Confirm button text |
|
|
2572
2586
|
| cancelLabel | `string` | `'Cancel'` | Cancel button text |
|
|
2573
2587
|
| confirmVariant | `'primary' \| 'destructive'` | `'primary'` | Use `'destructive'` for delete/remove actions |
|
|
2588
|
+
| loading | `boolean` | `false` | Show spinner in confirm button and disable it (for async `onConfirm`) |
|
|
2574
2589
|
| onConfirm | `() => void` | required | Called when confirm is tapped |
|
|
2575
2590
|
| onCancel | `() => void` | required | Called when cancel is tapped or backdrop pressed |
|
|
2576
2591
|
|
|
@@ -2646,6 +2661,7 @@ dismiss(id)
|
|
|
2646
2661
|
| style | `ViewStyle` | — | Outer container style |
|
|
2647
2662
|
| titleStyle | `TextStyle` | — | Override title text style |
|
|
2648
2663
|
| subtitleStyle | `TextStyle` | — | Override subtitle text style |
|
|
2664
|
+
| subtitleNumberOfLines | `number` | `2` | Max lines for subtitle before truncation |
|
|
2649
2665
|
| captionStyle | `TextStyle` | — | Override caption text style |
|
|
2650
2666
|
| icon | `ReactNode` | — | **Deprecated** — use `leftRender` |
|
|
2651
2667
|
| trailing | `string \| ReactNode` | — | **Deprecated** — use `rightRender` |
|
|
@@ -3028,6 +3044,7 @@ const [categories, setCategories] = useState<number[]>([1, 3])
|
|
|
3028
3044
|
| multiSelect | `boolean` | `false` | Allow multiple simultaneous selections |
|
|
3029
3045
|
| style | `ViewStyle` | — | ScrollView content container style |
|
|
3030
3046
|
| itemStyle | `ViewStyle` | — | Style applied to each chip's wrapper |
|
|
3047
|
+
| accessibilityLabel | `string` | — | Screen reader label for the scroll container |
|
|
3031
3048
|
|
|
3032
3049
|
**CategoryItem type:**
|
|
3033
3050
|
```ts
|
|
@@ -3729,6 +3746,159 @@ import { HolographicCard, FOIL_PRESETS } from '@retray-dev/ui-kit/HolographicCar
|
|
|
3729
3746
|
|
|
3730
3747
|
---
|
|
3731
3748
|
|
|
3749
|
+
### SheetSelect
|
|
3750
|
+
|
|
3751
|
+
**Import:** `import { SheetSelect } from '@retray-dev/ui-kit'`
|
|
3752
|
+
|
|
3753
|
+
**When to use:** Selecting one or multiple options from a list *inside a Sheet or BottomSheet*. Replaces `Select` (which uses `@react-native-picker/picker` — broken inside BottomSheet) with a chip-based UI that works correctly in any surface.
|
|
3754
|
+
|
|
3755
|
+
| Prop | Type | Default | Notes |
|
|
3756
|
+
|------|------|---------|-------|
|
|
3757
|
+
| options | `SheetSelectOption[]` | required | `{ label, value, iconName?, disabled? }` |
|
|
3758
|
+
| value | `string \| number \| (string \| number)[]` | — | Controlled selected value(s) |
|
|
3759
|
+
| onValueChange | `(value) => void` | — | Called with new value on selection |
|
|
3760
|
+
| multiSelect | `boolean` | `false` | Allow multiple simultaneous selections |
|
|
3761
|
+
| label | `string` | — | Label above the chips |
|
|
3762
|
+
| error | `string` | — | Error text below |
|
|
3763
|
+
| wrap | `boolean` | `false` | Wrap chips to multiple rows. Default: single horizontal scroll |
|
|
3764
|
+
| style | `ViewStyle` | — | — |
|
|
3765
|
+
| accessibilityLabel | `string` | — | — |
|
|
3766
|
+
|
|
3767
|
+
**Examples:**
|
|
3768
|
+
```tsx
|
|
3769
|
+
// Single-select category picker (inside Sheet)
|
|
3770
|
+
<SheetSelect
|
|
3771
|
+
label="Category"
|
|
3772
|
+
options={[
|
|
3773
|
+
{ label: 'Food', value: 'food', iconName: 'coffee' },
|
|
3774
|
+
{ label: 'Transport', value: 'transport', iconName: 'truck' },
|
|
3775
|
+
{ label: 'Entertainment', value: 'entertainment' },
|
|
3776
|
+
]}
|
|
3777
|
+
value={category}
|
|
3778
|
+
onValueChange={(v) => setCategory(v as string)}
|
|
3779
|
+
/>
|
|
3780
|
+
|
|
3781
|
+
// Multi-select roles (wrap layout)
|
|
3782
|
+
<SheetSelect
|
|
3783
|
+
label="Roles"
|
|
3784
|
+
options={roles.map((r) => ({ label: r.name, value: r.id }))}
|
|
3785
|
+
value={selectedRoles}
|
|
3786
|
+
onValueChange={(v) => setSelectedRoles(v as string[])}
|
|
3787
|
+
multiSelect
|
|
3788
|
+
wrap
|
|
3789
|
+
/>
|
|
3790
|
+
```
|
|
3791
|
+
|
|
3792
|
+
---
|
|
3793
|
+
|
|
3794
|
+
### ImageUpload
|
|
3795
|
+
|
|
3796
|
+
**Import:** `import { ImageUpload } from '@retray-dev/ui-kit'`
|
|
3797
|
+
|
|
3798
|
+
**When to use:** Image selection from the device library — product photos, profile avatars, tenant logos. Shows a dashed placeholder when empty, the selected image when filled, and a loading overlay while uploading.
|
|
3799
|
+
|
|
3800
|
+
**Requires:** `expo-image-picker` installed in the consuming app (`pnpm add expo-image-picker`). It is an optional peer dep — consumers who don't use `ImageUpload` never pull it.
|
|
3801
|
+
|
|
3802
|
+
| Prop | Type | Default | Notes |
|
|
3803
|
+
|------|------|---------|-------|
|
|
3804
|
+
| value | `string \| null` | — | Current image URI. `null`/`undefined` shows placeholder |
|
|
3805
|
+
| onChange | `(uri: string \| null) => void` | — | Called with selected URI after picker completes |
|
|
3806
|
+
| loading | `boolean` | `false` | Show spinner overlay (e.g. while uploading to server) |
|
|
3807
|
+
| placeholder | `string` | `'Tap to add image'` | Text shown when no image selected |
|
|
3808
|
+
| width | `number` | — | Width of the upload area. Defaults to full width |
|
|
3809
|
+
| height | `number` | `200` | Height of the upload area |
|
|
3810
|
+
| borderRadius | `number` | `RADIUS.lg` | — |
|
|
3811
|
+
| resizeMode | `'cover' \| 'contain' \| 'stretch'` | `'cover'` | Image resize mode |
|
|
3812
|
+
| disabled | `boolean` | `false` | Prevents pressing |
|
|
3813
|
+
| style | `ViewStyle` | — | — |
|
|
3814
|
+
| accessibilityLabel | `string` | — | — |
|
|
3815
|
+
|
|
3816
|
+
**Examples:**
|
|
3817
|
+
```tsx
|
|
3818
|
+
const [imageUri, setImageUri] = useState<string | null>(null)
|
|
3819
|
+
const [uploading, setUploading] = useState(false)
|
|
3820
|
+
|
|
3821
|
+
const handleChange = async (uri: string | null) => {
|
|
3822
|
+
if (!uri) return
|
|
3823
|
+
setImageUri(uri)
|
|
3824
|
+
setUploading(true)
|
|
3825
|
+
await uploadToServer(uri)
|
|
3826
|
+
setUploading(false)
|
|
3827
|
+
}
|
|
3828
|
+
|
|
3829
|
+
<ImageUpload
|
|
3830
|
+
value={imageUri}
|
|
3831
|
+
onChange={handleChange}
|
|
3832
|
+
loading={uploading}
|
|
3833
|
+
placeholder="Tap to add product image"
|
|
3834
|
+
height={200}
|
|
3835
|
+
/>
|
|
3836
|
+
|
|
3837
|
+
// Avatar upload (square)
|
|
3838
|
+
<ImageUpload
|
|
3839
|
+
value={avatarUri}
|
|
3840
|
+
onChange={setAvatarUri}
|
|
3841
|
+
width={100}
|
|
3842
|
+
height={100}
|
|
3843
|
+
borderRadius={50}
|
|
3844
|
+
/>
|
|
3845
|
+
```
|
|
3846
|
+
|
|
3847
|
+
---
|
|
3848
|
+
|
|
3849
|
+
### useConfirmDialog
|
|
3850
|
+
|
|
3851
|
+
**Import:** `import { useConfirmDialog } from '@retray-dev/ui-kit'`
|
|
3852
|
+
|
|
3853
|
+
**When to use:** Manage `ConfirmDialog` state without boilerplate. Replaces the `[target, setTarget]` + `visible` + `loading` state pattern that each screen would otherwise duplicate.
|
|
3854
|
+
|
|
3855
|
+
```ts
|
|
3856
|
+
function useConfirmDialog<T>(options: UseConfirmDialogOptions): UseConfirmDialogResult<T>
|
|
3857
|
+
|
|
3858
|
+
interface UseConfirmDialogOptions {
|
|
3859
|
+
onConfirm: () => void | Promise<void>
|
|
3860
|
+
onCancel?: () => void
|
|
3861
|
+
}
|
|
3862
|
+
```
|
|
3863
|
+
|
|
3864
|
+
**Returns:**
|
|
3865
|
+
|
|
3866
|
+
| Field | Type | Notes |
|
|
3867
|
+
|-------|------|-------|
|
|
3868
|
+
| visible | `boolean` | Pass to `ConfirmDialog.visible` |
|
|
3869
|
+
| target | `T \| null` | The value passed to `open()` — e.g. the item being deleted |
|
|
3870
|
+
| loading | `boolean` | Pass to `ConfirmDialog.loading` |
|
|
3871
|
+
| open | `(target?: T) => void` | Call to show the dialog |
|
|
3872
|
+
| dialogProps | `object` | Spread directly onto `<ConfirmDialog>` (contains `visible`, `loading`, `onConfirm`, `onCancel`) |
|
|
3873
|
+
|
|
3874
|
+
**Example:**
|
|
3875
|
+
```tsx
|
|
3876
|
+
const { open, target, dialogProps } = useConfirmDialog<Product>({
|
|
3877
|
+
onConfirm: async () => {
|
|
3878
|
+
await deleteProduct(target!.id)
|
|
3879
|
+
toast.success('Product deleted')
|
|
3880
|
+
},
|
|
3881
|
+
})
|
|
3882
|
+
|
|
3883
|
+
// Somewhere in your list:
|
|
3884
|
+
<ListItem
|
|
3885
|
+
title={product.name}
|
|
3886
|
+
rightIcon="trash-2"
|
|
3887
|
+
onPress={() => open(product)}
|
|
3888
|
+
/>
|
|
3889
|
+
|
|
3890
|
+
// Once in your screen's JSX:
|
|
3891
|
+
<ConfirmDialog
|
|
3892
|
+
title={`Delete "${target?.name}"?`}
|
|
3893
|
+
description="This action cannot be undone."
|
|
3894
|
+
confirmLabel="Delete"
|
|
3895
|
+
confirmVariant="destructive"
|
|
3896
|
+
{...dialogProps}
|
|
3897
|
+
/>
|
|
3898
|
+
```
|
|
3899
|
+
|
|
3900
|
+
---
|
|
3901
|
+
|
|
3732
3902
|
## Icon System
|
|
3733
3903
|
|
|
3734
3904
|
The library ships a built-in icon resolver — pass any icon name string to components without manual imports.
|
|
@@ -3909,11 +4079,12 @@ Used internally — not exported. `s()` horizontal scale, `vs()` vertical scale,
|
|
|
3909
4079
|
|
|
3910
4080
|
## Full Composition Examples
|
|
3911
4081
|
|
|
3912
|
-
The package includes **EXAMPLES.md** with complete, working code for
|
|
4082
|
+
The package includes **EXAMPLES.md** with complete, working code for 4 real-world app screens:
|
|
3913
4083
|
|
|
3914
4084
|
1. **Finance Dashboard** — MonthPicker, CurrencyDisplay, Progress, CategoryStrip, ListItem, DetailRow
|
|
3915
4085
|
2. **Edit Profile** — Avatar, Badge, Input, Select, Switch, Card, AlertBanner
|
|
3916
4086
|
3. **Onboarding Flow** — Badge, Progress, Input, RadioGroup, EmptyState (multi-step wizard)
|
|
4087
|
+
4. **Settings Screen** — MenuGroup, ListGroup, Form, MenuItem, ListItem, compound component patterns
|
|
3917
4088
|
|
|
3918
4089
|
**For AI agents:** Import EXAMPLES.md from the package for full source code and patterns:
|
|
3919
4090
|
|
|
@@ -3929,4 +4100,4 @@ Each example includes:
|
|
|
3929
4100
|
- Common patterns (spacing, colors, navigation, toast feedback)
|
|
3930
4101
|
- StyleSheet definitions
|
|
3931
4102
|
|
|
3932
|
-
**For human developers:** Examples are also live in the `example/` app. Clone the repo, run `pnpm install && pnpm build`, then `cd example && pnpm start` to see them in action.
|
|
4103
|
+
**For human developers:** Examples are also live in the `example/` app. Clone the repo, run `pnpm install && pnpm build`, then `cd example && pnpm start` to see them in action.
|
package/CONSUMER.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# @retray-dev/ui-kit — Consumer Setup Guide (v9.2.0)
|
|
2
|
+
|
|
3
|
+
> **For AI assistants (Claude Code):** Add all three lines below to your project's `CLAUDE.md` so Claude has full context about this UI kit:
|
|
4
|
+
> ```markdown
|
|
5
|
+
> ## UI Components
|
|
6
|
+
> @./node_modules/@retray-dev/ui-kit/COMPONENTS.md
|
|
7
|
+
> @./node_modules/@retray-dev/ui-kit/CONSUMER.md
|
|
8
|
+
> @./node_modules/@retray-dev/ui-kit/EXAMPLES.md
|
|
9
|
+
> ```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
| Requirement | Minimum | Notes |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Node | 18.18 | |
|
|
18
|
+
| Expo SDK | 54 | SDK 53 not supported |
|
|
19
|
+
| React Native | 0.79 | Tested up to 0.81.5 |
|
|
20
|
+
| React | 19 | |
|
|
21
|
+
| Expo Go | NOT supported | Missing native TurboModules for Sheet, ConfirmDialog, haptics |
|
|
22
|
+
| Dev build | Required | Use `npx expo run:ios` / `npx expo run:android` or EAS Build |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Install: Required Peer Dependencies
|
|
27
|
+
|
|
28
|
+
**All of these are required.** Missing any one will crash the app at load time.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx expo install \
|
|
32
|
+
expo-haptics \
|
|
33
|
+
expo-linear-gradient \
|
|
34
|
+
expo-font \
|
|
35
|
+
react-native-reanimated \
|
|
36
|
+
react-native-gesture-handler \
|
|
37
|
+
react-native-worklets \
|
|
38
|
+
react-native-safe-area-context \
|
|
39
|
+
react-native-screens \
|
|
40
|
+
react-native-svg \
|
|
41
|
+
@gorhom/bottom-sheet \
|
|
42
|
+
@react-native-picker/picker \
|
|
43
|
+
@react-native-community/slider \
|
|
44
|
+
@expo/vector-icons \
|
|
45
|
+
react-native-size-matters \
|
|
46
|
+
sonner-native \
|
|
47
|
+
react-native-ease \
|
|
48
|
+
pressto
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> `react-native-ease` and `pressto` are hard required. Omitting either crashes every component at module load — you will see a blank screen with no error message on screen.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Install: Optional Peer Dependencies
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx expo install expo-image-picker # Required only for ImageUpload component
|
|
59
|
+
npx expo install react-native-pulsar # Richer haptic feedback (graceful fallback to expo-haptics when absent)
|
|
60
|
+
|
|
61
|
+
# HolographicCard only — deep-import, NOT in main barrel:
|
|
62
|
+
npx expo install @shopify/react-native-skia expo-sensors
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Bundler Configuration
|
|
68
|
+
|
|
69
|
+
### `babel.config.js` — CRITICAL
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
module.exports = function (api) {
|
|
73
|
+
api.cache(true)
|
|
74
|
+
return {
|
|
75
|
+
presets: ['babel-preset-expo'],
|
|
76
|
+
plugins: ['react-native-worklets/plugin'], // ← NOT 'react-native-reanimated/plugin'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> Using `react-native-reanimated/plugin` instead of `react-native-worklets/plugin` is the **#1 cause of broken animations and missing input borders**. The worklets plugin covers both.
|
|
82
|
+
|
|
83
|
+
After changing `babel.config.js` always clear cache:
|
|
84
|
+
```bash
|
|
85
|
+
npx expo start --clear
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `metro.config.js` — Monorepo / Workspace only
|
|
89
|
+
|
|
90
|
+
If your app lives inside a monorepo (pnpm/yarn workspaces), you must prevent duplicate React/React Native instances:
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
const { getDefaultConfig } = require('expo/metro-config')
|
|
94
|
+
const path = require('path')
|
|
95
|
+
|
|
96
|
+
const projectRoot = __dirname
|
|
97
|
+
const workspaceRoot = path.resolve(projectRoot, '../..') // adjust to your repo root
|
|
98
|
+
|
|
99
|
+
const config = getDefaultConfig(projectRoot)
|
|
100
|
+
|
|
101
|
+
config.watchFolders = [workspaceRoot]
|
|
102
|
+
config.resolver.nodeModulesPaths = [
|
|
103
|
+
path.resolve(projectRoot, 'node_modules'),
|
|
104
|
+
path.resolve(workspaceRoot, 'node_modules'),
|
|
105
|
+
]
|
|
106
|
+
config.resolver.extraNodeModules = {
|
|
107
|
+
react: path.resolve(projectRoot, 'node_modules/react'),
|
|
108
|
+
'react-native': path.resolve(projectRoot, 'node_modules/react-native'),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = config
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Provider Setup
|
|
117
|
+
|
|
118
|
+
### Recommended — `RetrayProvider` (one wrapper, correct order)
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { useFonts } from 'expo-font'
|
|
122
|
+
import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
123
|
+
import { RetrayProvider } from '@retray-dev/ui-kit'
|
|
124
|
+
|
|
125
|
+
export default function App() {
|
|
126
|
+
const [fontsLoaded] = useFonts(SohneFonts)
|
|
127
|
+
if (!fontsLoaded) return null
|
|
128
|
+
return (
|
|
129
|
+
<RetrayProvider colorScheme="system">
|
|
130
|
+
{/* your app */}
|
|
131
|
+
</RetrayProvider>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Manual — only if custom provider tree required
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context'
|
|
140
|
+
import { GestureHandlerRootView } from 'react-native-gesture-handler'
|
|
141
|
+
import { ThemeProvider, BottomSheetModalProvider, ToastProvider } from '@retray-dev/ui-kit'
|
|
142
|
+
|
|
143
|
+
export default function App() {
|
|
144
|
+
return (
|
|
145
|
+
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
|
|
146
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
147
|
+
<ThemeProvider>
|
|
148
|
+
<BottomSheetModalProvider>
|
|
149
|
+
<ToastProvider>
|
|
150
|
+
{/* your app */}
|
|
151
|
+
</ToastProvider>
|
|
152
|
+
</BottomSheetModalProvider>
|
|
153
|
+
</ThemeProvider>
|
|
154
|
+
</GestureHandlerRootView>
|
|
155
|
+
</SafeAreaProvider>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Provider order is strict: `SafeAreaProvider` outermost, `GestureHandlerRootView` second.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Version Compatibility Table
|
|
165
|
+
|
|
166
|
+
| Package | Min | Max tested | Notes |
|
|
167
|
+
|---|---|---|---|
|
|
168
|
+
| Expo SDK | 54 | 54 | SDK 53 not supported |
|
|
169
|
+
| React Native | 0.79 | 0.81.5 | |
|
|
170
|
+
| react-native-reanimated | 4.0.0 | 4.1.1 | **v3 NOT supported** — animations will not work |
|
|
171
|
+
| react-native-worklets | 0.5.1 | 0.5.1 | Exact version — other 0.5.x may crash |
|
|
172
|
+
| @gorhom/bottom-sheet | 5.2.0 | 5.2.8 | <5.2.0 crashes with Reanimated v4 |
|
|
173
|
+
| sonner-native | 0.22.0 | 0.23.1 | <0.22.0 has incompatible toast API |
|
|
174
|
+
| react-native-ease | 0.7.0 | 0.7.2 | **Required** — not optional |
|
|
175
|
+
| pressto | 0.6.0 | 0.6.1 | **Required** — not optional |
|
|
176
|
+
| expo-haptics | 15.0.0 | 15.0.8 | |
|
|
177
|
+
| expo-linear-gradient | 15.0.0 | 15.0.8 | |
|
|
178
|
+
| expo-font | 14.0.0 | 14.0.11 | |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Troubleshooting
|
|
183
|
+
|
|
184
|
+
### 1. Blank screen / "Cannot find module 'react-native-ease'" or `'pressto'`
|
|
185
|
+
|
|
186
|
+
These are required peers — not optional. The barrel import crashes at module load, rendering nothing.
|
|
187
|
+
|
|
188
|
+
**Fix:**
|
|
189
|
+
```bash
|
|
190
|
+
npx expo install react-native-ease pressto
|
|
191
|
+
npx expo run:ios # or run:android — full native rebuild required
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 2. Input has no visible border / all animations are frozen
|
|
195
|
+
|
|
196
|
+
Wrong or missing Babel plugin. Reanimated worklets never initialize.
|
|
197
|
+
|
|
198
|
+
**Fix:**
|
|
199
|
+
1. Open `babel.config.js` — confirm it has `plugins: ['react-native-worklets/plugin']`
|
|
200
|
+
2. If it has `react-native-reanimated/plugin` instead, replace it with `react-native-worklets/plugin`
|
|
201
|
+
3. Clear cache and restart:
|
|
202
|
+
```bash
|
|
203
|
+
npx expo start --clear
|
|
204
|
+
```
|
|
205
|
+
4. If in monorepo: verify `metro.config.js` `extraNodeModules` points `react-native` to a single copy (duplicate instances break Reanimated context)
|
|
206
|
+
|
|
207
|
+
### 3. "useWorkletCallback is not a function" crash on Sheet or ConfirmDialog
|
|
208
|
+
|
|
209
|
+
`@gorhom/bottom-sheet` version older than 5.2.0 installed.
|
|
210
|
+
|
|
211
|
+
**Fix:**
|
|
212
|
+
```bash
|
|
213
|
+
npx expo install @gorhom/bottom-sheet@5.2.8
|
|
214
|
+
npx expo run:ios # or run:android
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## HolographicCard (Optional Deep Import)
|
|
220
|
+
|
|
221
|
+
`HolographicCard` depends on `@shopify/react-native-skia` and `expo-sensors` which are heavy optional peers. It is **not included in the main barrel** to avoid pulling Skia for consumers who don't need it.
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
// Deep import — do NOT import from '@retray-dev/ui-kit'
|
|
225
|
+
import { HolographicCard } from '@retray-dev/ui-kit/HolographicCard'
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Install before using:
|
|
229
|
+
```bash
|
|
230
|
+
npx expo install @shopify/react-native-skia expo-sensors
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Fonts
|
|
236
|
+
|
|
237
|
+
All components use the **Sohne** font family. Load fonts before rendering any component:
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import { useFonts } from 'expo-font'
|
|
241
|
+
import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
242
|
+
|
|
243
|
+
const [fontsLoaded] = useFonts(SohneFonts)
|
|
244
|
+
if (!fontsLoaded) return null
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
See `FONTS.md` for the full font inventory and weight reference.
|