@retray-dev/ui-kit 9.1.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 +165 -4
- package/CONSUMER.md +247 -0
- package/DESIGN.md +668 -0
- 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 (v9.
|
|
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
|
|
|
@@ -896,6 +899,7 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
896
899
|
| type | `'text' \| 'password'` | `'text'` | Password shows eye/eye-off toggle button in suffix slot |
|
|
897
900
|
| containerStyle | `ViewStyle` | — | Outer container View style |
|
|
898
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 |
|
|
899
903
|
| style | `TextStyle` | — | TextInput element style |
|
|
900
904
|
|
|
901
905
|
**Dimensions:** 56px height (14px vertical padding), 8px border radius.
|
|
@@ -1010,6 +1014,7 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
|
|
|
1010
1014
|
| placeholder | `string` | `'$0'` | Defaults to `prefix + '0'` |
|
|
1011
1015
|
| editable | `boolean` | — | Pass `false` to disable |
|
|
1012
1016
|
| containerStyle | `ViewStyle` | — | Outer container style |
|
|
1017
|
+
| sheetMode | `boolean` | `false` | Use inside a Sheet — forwards `sheetMode` to underlying `Input` |
|
|
1013
1018
|
|
|
1014
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.
|
|
1015
1020
|
|
|
@@ -1675,6 +1680,7 @@ const renderItem = useCallback(({ item }) => (
|
|
|
1675
1680
|
| icon | `ReactNode` | — | Override default icon with custom ReactNode |
|
|
1676
1681
|
| iconName | `string` | — | Icon name from `@expo/vector-icons`. Takes precedence over `icon`, but still falls back to variant default when neither is set |
|
|
1677
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. |
|
|
1678
1684
|
| style | `ViewStyle` | — | — |
|
|
1679
1685
|
|
|
1680
1686
|
**Variants:**
|
|
@@ -2579,6 +2585,7 @@ dismiss(id)
|
|
|
2579
2585
|
| confirmLabel | `string` | `'Confirm'` | Confirm button text |
|
|
2580
2586
|
| cancelLabel | `string` | `'Cancel'` | Cancel button text |
|
|
2581
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`) |
|
|
2582
2589
|
| onConfirm | `() => void` | required | Called when confirm is tapped |
|
|
2583
2590
|
| onCancel | `() => void` | required | Called when cancel is tapped or backdrop pressed |
|
|
2584
2591
|
|
|
@@ -2654,6 +2661,7 @@ dismiss(id)
|
|
|
2654
2661
|
| style | `ViewStyle` | — | Outer container style |
|
|
2655
2662
|
| titleStyle | `TextStyle` | — | Override title text style |
|
|
2656
2663
|
| subtitleStyle | `TextStyle` | — | Override subtitle text style |
|
|
2664
|
+
| subtitleNumberOfLines | `number` | `2` | Max lines for subtitle before truncation |
|
|
2657
2665
|
| captionStyle | `TextStyle` | — | Override caption text style |
|
|
2658
2666
|
| icon | `ReactNode` | — | **Deprecated** — use `leftRender` |
|
|
2659
2667
|
| trailing | `string \| ReactNode` | — | **Deprecated** — use `rightRender` |
|
|
@@ -3738,6 +3746,159 @@ import { HolographicCard, FOIL_PRESETS } from '@retray-dev/ui-kit/HolographicCar
|
|
|
3738
3746
|
|
|
3739
3747
|
---
|
|
3740
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
|
+
|
|
3741
3902
|
## Icon System
|
|
3742
3903
|
|
|
3743
3904
|
The library ships a built-in icon resolver — pass any icon name string to components without manual imports.
|
|
@@ -3939,4 +4100,4 @@ Each example includes:
|
|
|
3939
4100
|
- Common patterns (spacing, colors, navigation, toast feedback)
|
|
3940
4101
|
- StyleSheet definitions
|
|
3941
4102
|
|
|
3942
|
-
**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.
|