@retray-dev/ui-kit 10.2.0 → 12.1.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 +287 -37
- package/README.md +11 -2
- package/dist/Accordion.mjs +2 -2
- package/dist/AlertBanner.mjs +2 -2
- package/dist/AppHeader.mjs +3 -3
- package/dist/Avatar.mjs +2 -2
- package/dist/Badge.mjs +2 -2
- package/dist/Button.mjs +2 -2
- package/dist/Card.mjs +2 -2
- package/dist/CategoryStrip.mjs +2 -2
- package/dist/Checkbox.mjs +2 -2
- package/dist/Chip.mjs +2 -2
- package/dist/ConfirmDialog.d.mts +1 -6
- package/dist/ConfirmDialog.d.ts +1 -6
- package/dist/ConfirmDialog.js +29 -23
- package/dist/ConfirmDialog.mjs +3 -3
- package/dist/CurrencyDisplay.mjs +2 -2
- package/dist/CurrencyInput.d.mts +3 -8
- package/dist/CurrencyInput.d.ts +3 -8
- package/dist/CurrencyInput.js +3 -1
- package/dist/CurrencyInput.mjs +3 -3
- package/dist/DetailRow.mjs +2 -2
- package/dist/EmptyState.mjs +3 -3
- package/dist/ErrorBoundary.mjs +2 -2
- package/dist/Form.mjs +2 -2
- package/dist/IconButton.mjs +2 -2
- package/dist/IconPicker.js +675 -248
- package/dist/IconPicker.mjs +3 -2
- package/dist/ImageUpload.mjs +3 -3
- package/dist/ImageViewer.mjs +4 -4
- package/dist/Input.mjs +2 -2
- package/dist/LabelValue.mjs +2 -2
- package/dist/ListGroup.mjs +2 -2
- package/dist/ListItem.d.mts +7 -7
- package/dist/ListItem.d.ts +7 -7
- package/dist/ListItem.js +12 -7
- package/dist/ListItem.mjs +2 -2
- package/dist/MediaCard.mjs +2 -2
- package/dist/MenuGroup.mjs +2 -2
- package/dist/MenuItem.mjs +2 -2
- package/dist/MonthPicker.mjs +2 -2
- package/dist/NumberStepper.mjs +2 -2
- package/dist/PagerDots.mjs +2 -2
- package/dist/Pressable.d.mts +15 -7
- package/dist/Pressable.d.ts +15 -7
- package/dist/Pressable.js +7 -3
- package/dist/Pressable.mjs +1 -1
- package/dist/PricingCard.mjs +4 -4
- package/dist/Progress.mjs +2 -2
- package/dist/RadioGroup.mjs +2 -2
- package/dist/RetrayProvider.mjs +3 -3
- package/dist/Select.mjs +2 -2
- package/dist/SelectableGrid.mjs +2 -2
- package/dist/Separator.mjs +2 -2
- package/dist/Sheet.d.mts +4 -46
- package/dist/Sheet.d.ts +4 -46
- package/dist/Sheet.js +46 -114
- package/dist/Sheet.mjs +2 -3
- package/dist/SheetSelect.mjs +2 -2
- package/dist/Skeleton.mjs +2 -2
- package/dist/Slider.mjs +2 -2
- package/dist/Spinner.mjs +2 -2
- package/dist/Stats.d.mts +30 -0
- package/dist/Stats.d.ts +30 -0
- package/dist/Stats.js +429 -0
- package/dist/Stats.mjs +9 -0
- package/dist/Switch.mjs +2 -2
- package/dist/TabBar.mjs +2 -2
- package/dist/Tabs.mjs +2 -2
- package/dist/Text.d.mts +3 -1
- package/dist/Text.d.ts +3 -1
- package/dist/Text.js +3 -3
- package/dist/Text.mjs +2 -2
- package/dist/Textarea.mjs +2 -2
- package/dist/Toast.mjs +2 -2
- package/dist/Toggle.mjs +2 -2
- package/dist/{chunk-YJ7I257J.mjs → chunk-265G6A46.mjs} +1 -1
- package/dist/{chunk-ELXBDILQ.mjs → chunk-2A2LEFZG.mjs} +2 -2
- package/dist/{chunk-ID72TK46.mjs → chunk-2CBQKU7H.mjs} +1 -1
- package/dist/{chunk-OB4JUQ3O.mjs → chunk-2I2AYECM.mjs} +1 -1
- package/dist/{chunk-WJLKJMKR.mjs → chunk-357YO24D.mjs} +4 -4
- package/dist/{chunk-GQYFLP3D.mjs → chunk-3GEYJ7I5.mjs} +1 -1
- package/dist/{chunk-AV4EMIRH.mjs → chunk-3N2M3WZL.mjs} +1 -1
- package/dist/{chunk-VF2ATYN3.mjs → chunk-3UYAZ7I4.mjs} +1 -1
- package/dist/{chunk-JMOZEC77.mjs → chunk-4WFMPFZB.mjs} +1 -1
- package/dist/chunk-5OLNXP3S.mjs +144 -0
- package/dist/{chunk-6SECQ2ZF.mjs → chunk-7HSILTC4.mjs} +2 -2
- package/dist/{chunk-IRRY3CRZ.mjs → chunk-AKM4EPOT.mjs} +1 -1
- package/dist/{chunk-IX3NYLYQ.mjs → chunk-AQEVCEXV.mjs} +1 -1
- package/dist/{chunk-WBOOUHSS.mjs → chunk-BCWEHE34.mjs} +1 -1
- package/dist/{chunk-AJ7ZDNBT.mjs → chunk-BOVUP27T.mjs} +1 -1
- package/dist/{chunk-BRKYVJVV.mjs → chunk-BQZE3HAW.mjs} +1 -1
- package/dist/{chunk-Z6SFHN6T.mjs → chunk-D3Y2T42P.mjs} +1 -1
- package/dist/{chunk-T2KCAHOS.mjs → chunk-DF6DU42P.mjs} +1 -1
- package/dist/{chunk-TB6SD2FT.mjs → chunk-DI7CBDL6.mjs} +1 -1
- package/dist/{chunk-HTHGSXFG.mjs → chunk-DOGIPOF5.mjs} +1 -1
- package/dist/{chunk-MBMXYJJV.mjs → chunk-E7NEHHXV.mjs} +7 -3
- package/dist/{chunk-MX6HRKMI.mjs → chunk-EFLFRAHD.mjs} +1 -1
- package/dist/{chunk-SOYNZDVY.mjs → chunk-EMUWGDWC.mjs} +6 -1
- package/dist/{chunk-AJRVDP2H.mjs → chunk-F4V6XLP4.mjs} +3 -3
- package/dist/{chunk-DYT7BG5I.mjs → chunk-FA2KMTH5.mjs} +1 -1
- package/dist/{chunk-Y2NS74WS.mjs → chunk-FFTYLPSB.mjs} +46 -98
- package/dist/{chunk-VKID2D2I.mjs → chunk-FUVYSVGR.mjs} +13 -8
- package/dist/{chunk-7LWRKMF5.mjs → chunk-FVTVCJAH.mjs} +1 -1
- package/dist/{chunk-TZDGAP5N.mjs → chunk-GK4VRMNE.mjs} +2 -2
- package/dist/{chunk-6Q64UFIA.mjs → chunk-HJ46DTJE.mjs} +1 -1
- package/dist/{chunk-WF2XDFRK.mjs → chunk-HLMPMUK2.mjs} +1 -1
- package/dist/{chunk-GD6KXMG5.mjs → chunk-I4V5XZPS.mjs} +1 -1
- package/dist/{chunk-TBNZHU6C.mjs → chunk-ISY26JQJ.mjs} +2 -2
- package/dist/{chunk-X4G6APW6.mjs → chunk-J6Q2YJEV.mjs} +1 -1
- package/dist/{chunk-WYEUNUTP.mjs → chunk-JCZQOY4O.mjs} +31 -24
- package/dist/{chunk-U2XJFYED.mjs → chunk-JNVAIDLK.mjs} +1 -1
- package/dist/{chunk-SOA2Z4RB.mjs → chunk-JULSIZDM.mjs} +1 -1
- package/dist/chunk-KHYX4IOM.mjs +1114 -0
- package/dist/{chunk-RYZC432S.mjs → chunk-LRM4AVYY.mjs} +1 -1
- package/dist/{chunk-6L4G6PBT.mjs → chunk-MYZ2EDYU.mjs} +1 -1
- package/dist/{chunk-BUMAMSTZ.mjs → chunk-N4ZPVCJH.mjs} +1 -1
- package/dist/{chunk-Z4VHZ7B5.mjs → chunk-NXI4YDZ2.mjs} +1 -1
- package/dist/{chunk-ZZ2R6KZ3.mjs → chunk-OULVKTWL.mjs} +1 -1
- package/dist/{chunk-FCSSQK3L.mjs → chunk-P64WHW4A.mjs} +1 -1
- package/dist/{chunk-KOO4WITD.mjs → chunk-P73V2EKS.mjs} +1 -1
- package/dist/{chunk-SXLKNTA4.mjs → chunk-PGERH3P7.mjs} +1 -1
- package/dist/{chunk-2UYENBLV.mjs → chunk-QSFV2P7O.mjs} +1 -1
- package/dist/{chunk-JT7HKXRB.mjs → chunk-S3KJCPEJ.mjs} +1 -1
- package/dist/{chunk-BEMIQXXU.mjs → chunk-V6NFJXKO.mjs} +1 -1
- package/dist/{chunk-A3A6KNQN.mjs → chunk-WOEWGSTU.mjs} +1 -1
- package/dist/{chunk-NMU5FMQJ.mjs → chunk-X26S5EVZ.mjs} +4 -2
- package/dist/{chunk-YFZ3ELX5.mjs → chunk-XBAGGKLW.mjs} +2 -2
- package/dist/{chunk-S2R7UVOE.mjs → chunk-ZHMSAYLT.mjs} +1 -1
- package/dist/fonts.d.mts +1 -7
- package/dist/fonts.d.ts +1 -7
- package/dist/fonts.js +0 -2
- package/dist/fonts.mjs +1 -2
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1184 -708
- package/dist/index.mjs +53 -52
- package/package.json +3 -3
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +39 -30
- package/src/components/CurrencyInput/CurrencyInput.tsx +4 -7
- package/src/components/IconPicker/IconPicker.tsx +124 -112
- package/src/components/ListItem/ListItem.tsx +43 -28
- package/src/components/Pressable/Pressable.tsx +20 -8
- package/src/components/Sheet/Sheet.tsx +64 -172
- package/src/components/Stats/Stats.tsx +226 -0
- package/src/components/Stats/index.ts +2 -0
- package/src/components/Text/Text.tsx +4 -2
- package/src/fonts.ts +0 -7
- package/src/index.ts +4 -0
- package/src/theme/colorUtils.ts +9 -0
- package/src/utils/curatedIcons.ts +698 -135
- package/src/utils/fontGuard.ts +2 -1
- package/dist/chunk-53Z3NYGE.mjs +0 -742
package/COMPONENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @retray-dev/ui-kit — Component Reference (
|
|
1
|
+
# @retray-dev/ui-kit — Component Reference (v12.1.0)
|
|
2
2
|
|
|
3
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
|
|
|
@@ -317,6 +317,24 @@ const resolved = deriveColors(myThemeColors, 'light')
|
|
|
317
317
|
|
|
318
318
|
---
|
|
319
319
|
|
|
320
|
+
### Color Utilities
|
|
321
|
+
|
|
322
|
+
**Import:** `import { withAlpha } from '@retray-dev/ui-kit'`
|
|
323
|
+
|
|
324
|
+
Convert a hex color to rgba with the given alpha. Useful for semi-transparent backgrounds, borders, and overlays derived from theme colors.
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
import { useTheme, withAlpha } from '@retray-dev/ui-kit'
|
|
328
|
+
|
|
329
|
+
const { colors } = useTheme()
|
|
330
|
+
|
|
331
|
+
<View style={{ backgroundColor: withAlpha(colors.primary, 0.15) }}>
|
|
332
|
+
<Text style={{ color: colors.primary }}>Tinted background</Text>
|
|
333
|
+
</View>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
320
338
|
## Design Tokens
|
|
321
339
|
|
|
322
340
|
Static structural constants — no context or provider needed.
|
|
@@ -684,6 +702,132 @@ assets/fonts/sohne/
|
|
|
684
702
|
|
|
685
703
|
---
|
|
686
704
|
|
|
705
|
+
## Migration Guide: v10 → v11
|
|
706
|
+
|
|
707
|
+
### New — public utility
|
|
708
|
+
|
|
709
|
+
**`withAlpha(hex, alpha)`** — hex-to-rgba color helper, now exported from the package root. Useful for semi-transparent overlays derived from theme colors without adding a new token.
|
|
710
|
+
|
|
711
|
+
```tsx
|
|
712
|
+
import { useTheme, withAlpha } from '@retray-dev/ui-kit'
|
|
713
|
+
|
|
714
|
+
const { colors } = useTheme()
|
|
715
|
+
<View style={{ backgroundColor: withAlpha(colors.primary, 0.15) }} />
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Updated
|
|
719
|
+
|
|
720
|
+
- `Stats` component promoted from internal/experimental to public (`Stats` + `Stats.Group`).
|
|
721
|
+
- Documentation refreshed for `IconPicker` and `NumberStepper`.
|
|
722
|
+
|
|
723
|
+
No breaking changes in v11. Safe minor upgrade from v10.
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## Migration Guide: v11 → v12
|
|
728
|
+
|
|
729
|
+
### Breaking Changes
|
|
730
|
+
|
|
731
|
+
`Sheet` and `ConfirmDialog` were rewritten on top of `@gorhom/bottom-sheet`'s **`BottomSheetModal`** (lazy-mounted, `present()` / `dismiss()` driven) — replacing the old `BottomSheet` + `index={-1}` + `snapToIndex(0)` pattern. This fixes timing issues with `enableDynamicSizing` and unifies the API with the rest of the gorhom ecosystem.
|
|
732
|
+
|
|
733
|
+
**1. Removed `responsive` / `dialogMaxWidth` props from `Sheet` and `ConfirmDialog`**
|
|
734
|
+
|
|
735
|
+
The previous wide-screen fallback that bypassed gorhom with a native `Modal` + `ScrollView` was a partial workaround (see REGLA 1). It has been deleted. `@gorhom/bottom-sheet` handles responsive behavior natively — the modal simply renders inside its modal layer at the device width.
|
|
736
|
+
|
|
737
|
+
```diff
|
|
738
|
+
<Sheet
|
|
739
|
+
open={open}
|
|
740
|
+
onClose={() => setOpen(false)}
|
|
741
|
+
title="Options"
|
|
742
|
+
- responsive
|
|
743
|
+
- dialogMaxWidth={600}
|
|
744
|
+
/>
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
**2. `onClose` is the only close handler**
|
|
748
|
+
|
|
749
|
+
`onClose` is called from `BottomSheetModal.onDismiss` — the native gorhom callback. The previous `onClose` prop (passed directly to `BottomSheet`) was redundant. No public-API change for consumers; this is an internal alignment.
|
|
750
|
+
|
|
751
|
+
**3. `Sheet` requires `BottomSheetModalProvider` at app root**
|
|
752
|
+
|
|
753
|
+
`RetrayProvider` already wires it. If you assemble providers manually, ensure `BottomSheetModalProvider` sits inside `GestureHandlerRootView`:
|
|
754
|
+
|
|
755
|
+
```tsx
|
|
756
|
+
<SafeAreaProvider initialMetrics={initialWindowMetrics}>
|
|
757
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
758
|
+
<ThemeProvider>
|
|
759
|
+
<BottomSheetModalProvider>
|
|
760
|
+
<ToastProvider>{/* app */}</ToastProvider>
|
|
761
|
+
</BottomSheetModalProvider>
|
|
762
|
+
</ThemeProvider>
|
|
763
|
+
</GestureHandlerRootView>
|
|
764
|
+
</SafeAreaProvider>
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**4. Keyboard prop renames (no consumer action — defaults match v11)**
|
|
768
|
+
|
|
769
|
+
| Prop | v11 | v12 default |
|
|
770
|
+
|------|-----|-------------|
|
|
771
|
+
| `keyboardBehavior` | `'interactive'` | `'interactive'` (unchanged) |
|
|
772
|
+
| `android_keyboardInputMode` | `'adjustPan'` | `'adjustPan'` (unchanged) |
|
|
773
|
+
|
|
774
|
+
**5. Removed top-level imports of `Modal`, `ScrollView`, `useWindowDimensions`, `BREAKPOINTS` from `Sheet.tsx`**
|
|
775
|
+
|
|
776
|
+
Internal only — no public API.
|
|
777
|
+
|
|
778
|
+
### Behavioral changes (no code change required)
|
|
779
|
+
|
|
780
|
+
- **Backdrop / swipe close is now driven by gorhom's modal lifecycle** — `onClose` fires once on full dismiss instead of on every interaction. State-setter closures (e.g. `setOpen(false)`) are safe to call from `onClose` without causing "dismiss on unmounted" loops.
|
|
781
|
+
- **`topInset={insets.top}`** is now applied automatically from safe-area context — sheet never crosses the notch / status bar on iOS or Android.
|
|
782
|
+
- **`snapPoints` + `enableDynamicSizing` are mutually exclusive.** If you pass `snapPoints`, dynamic sizing is disabled and the sheet snaps to those points. Omit `snapPoints` to use dynamic sizing (default).
|
|
783
|
+
|
|
784
|
+
### New — recommended pattern
|
|
785
|
+
|
|
786
|
+
**Use `Input` with `sheetMode` inside a Sheet** instead of `SheetTextInput` directly. The new `sheetMode` prop on `Input` swaps in `BottomSheetTextInput` for keyboard-aware focus/blur handling while preserving the full `Input` API (label, error, hint, prefix/suffix, icons, type="password").
|
|
787
|
+
|
|
788
|
+
```tsx
|
|
789
|
+
<Sheet open={open} onClose={() => setOpen(false)} title="Add note">
|
|
790
|
+
<Input
|
|
791
|
+
label="Note"
|
|
792
|
+
placeholder="Type your note..."
|
|
793
|
+
value={note}
|
|
794
|
+
onChangeText={setNote}
|
|
795
|
+
sheetMode
|
|
796
|
+
/>
|
|
797
|
+
<Button label="Save" fullWidth onPress={handleSave} />
|
|
798
|
+
</Sheet>
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
`SheetTextInput` is still re-exported for low-level use.
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## Migration Guide: v12.0 → v12.1
|
|
806
|
+
|
|
807
|
+
### New — IconPicker feedback pattern (REGLA 4)
|
|
808
|
+
|
|
809
|
+
`IconPicker` now follows the "no frozen screen" rule. When the user taps the trigger, the sheet presents **immediately** (no `useEffect` delay). While the inner grid measures its container, a centered `<Spinner />` is shown inside the sheet so the user sees visible feedback. The grid fades in as soon as `onLayout` fires.
|
|
810
|
+
|
|
811
|
+
This is now the canonical pattern for any sheet whose content needs to measure or load before rendering — apply it to new overlay components.
|
|
812
|
+
|
|
813
|
+
### New — race-condition fix in `Sheet` and `ConfirmDialog`
|
|
814
|
+
|
|
815
|
+
Both components now track a `wasOpened` ref so `dismiss()` is only called after the sheet has been presented at least once. This eliminates a class of crashes that occurred when the parent component unmounted (or the `open`/`visible` prop flipped) before the gorham modal had a chance to mount.
|
|
816
|
+
|
|
817
|
+
No consumer action required — the fix is internal.
|
|
818
|
+
|
|
819
|
+
### New — expanded curated icon library
|
|
820
|
+
|
|
821
|
+
`src/utils/curatedIcons.ts` has been expanded: every category now carries 42+ icons (some up to 66), totaling ~600 themed icons across the 12 categories. Selection rules are now codified in REGLA 5 — only Feather, Ionicons `-outline`, and themed FA5/Entypo/AntDesign icons are eligible (no filled variants).
|
|
822
|
+
|
|
823
|
+
### Updated
|
|
824
|
+
|
|
825
|
+
- `Sheet` and `ConfirmDialog` pass a stable `name` prop to `BottomSheetModal` (from `useId()`) for correct gorhom modal registry behavior when multiple modals are mounted.
|
|
826
|
+
- `Input` `sheetMode` prop documented in the Setup section (replaces the `SheetTextInput` boilerplate inside sheets).
|
|
827
|
+
- `CompositionScreen` example now uses `<Input sheetMode />` inside a `Sheet` to demonstrate the keyboard-friendly pattern.
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
687
831
|
## Components
|
|
688
832
|
|
|
689
833
|
---
|
|
@@ -700,6 +844,7 @@ assets/fonts/sohne/
|
|
|
700
844
|
|------|------|---------|-------|
|
|
701
845
|
| variant | `TextVariant` | `'body-md'` | Sets font, size, weight, line height, letter spacing |
|
|
702
846
|
| color | `string` | — | Override text color. Each variant has a semantic default (see table below) |
|
|
847
|
+
| uppercase | `boolean` | `false` | Force text-transform: uppercase on any variant |
|
|
703
848
|
| children | `ReactNode` | required | — |
|
|
704
849
|
| style | `TextStyle` | — | Additional styles (merged after variant styles) |
|
|
705
850
|
| (all TextProps) | — | — | `numberOfLines`, `ellipsizeMode`, `onPress`, etc. all pass through |
|
|
@@ -1073,6 +1218,23 @@ assets/fonts/sohne/
|
|
|
1073
1218
|
</View>
|
|
1074
1219
|
```
|
|
1075
1220
|
|
|
1221
|
+
**Composition — inside a Sheet (preferred pattern, v12+):**
|
|
1222
|
+
|
|
1223
|
+
Use `sheetMode` to opt the inner `TextInput` into `BottomSheetTextInput` so keyboard handling works correctly. This is the canonical replacement for raw `SheetTextInput` inside sheets.
|
|
1224
|
+
|
|
1225
|
+
```tsx
|
|
1226
|
+
<Sheet open={open} onClose={() => setOpen(false)} title="Add note">
|
|
1227
|
+
<Input
|
|
1228
|
+
label="Note"
|
|
1229
|
+
placeholder="Write your note..."
|
|
1230
|
+
value={note}
|
|
1231
|
+
onChangeText={setNote}
|
|
1232
|
+
sheetMode
|
|
1233
|
+
/>
|
|
1234
|
+
<Button label="Save" fullWidth onPress={handleSave} />
|
|
1235
|
+
</Sheet>
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1076
1238
|
---
|
|
1077
1239
|
|
|
1078
1240
|
### Textarea
|
|
@@ -1125,9 +1287,12 @@ assets/fonts/sohne/
|
|
|
1125
1287
|
| hint | `string` | — | Helper text below (hidden when `error` is set) |
|
|
1126
1288
|
| placeholder | `string` | `'$0'` | Defaults to `prefix + '0'` |
|
|
1127
1289
|
| editable | `boolean` | — | Pass `false` to disable |
|
|
1290
|
+
| autoFocus | `boolean` | — | Auto-focus on mount (inherited from TextInputProps) |
|
|
1128
1291
|
| containerStyle | `ViewStyle` | — | Outer container style |
|
|
1129
1292
|
| sheetMode | `boolean` | `false` | Use inside a Sheet — forwards `sheetMode` to underlying `Input` |
|
|
1130
1293
|
|
|
1294
|
+
**Extends `TextInputProps` from React Native** — all TextInput props (autoFocus, onFocus, onBlur, etc.) pass through to the underlying input.
|
|
1295
|
+
|
|
1131
1296
|
**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.
|
|
1132
1297
|
|
|
1133
1298
|
**Examples:**
|
|
@@ -2400,7 +2565,6 @@ Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to `ba
|
|
|
2400
2565
|
| onClose | `() => void` | required | Called on swipe-dismiss or backdrop press |
|
|
2401
2566
|
| title | `string` | — | Sheet heading |
|
|
2402
2567
|
| subtitle | `string` | — | Supporting text below title |
|
|
2403
|
-
| description | `string` | — | **Deprecated alias** for `subtitle` — prefer `subtitle` |
|
|
2404
2568
|
| showCloseButton | `boolean` | `false` | Show X close button in the header |
|
|
2405
2569
|
| children | `ReactNode` | — | Sheet content |
|
|
2406
2570
|
| style | `ViewStyle` | — | Inner scroll/content container style |
|
|
@@ -2413,14 +2577,11 @@ Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to `ba
|
|
|
2413
2577
|
| 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) |
|
|
2414
2578
|
| footer | `ReactNode` | — | Sticky footer below scroll area (sticky above keyboard) |
|
|
2415
2579
|
| snapPoints | `(string \| number)[]` | — | Optional snap points (e.g., `['50%', '85%']`). When omitted, uses dynamic sizing (auto-fits content) |
|
|
2416
|
-
| responsive | `boolean` | `false` | **(v8)** On wide screens (width ≥ `BREAKPOINTS.wide`) render a centered modal dialog instead of a bottom sheet. Stays a bottom sheet on phones |
|
|
2417
|
-
| dialogMaxWidth | `number` | `480` | Max width of the centered dialog. Only applies when `responsive` |
|
|
2418
2580
|
|
|
2419
2581
|
**Features:**
|
|
2420
2582
|
- `enableDynamicSizing` — height auto-fits content, no `snapPoints` needed (default behavior when `snapPoints` is omitted)
|
|
2421
2583
|
- `snapPoints` — optionally provide custom snap points (e.g., `['50%', '85%']`). Disables dynamic sizing when provided
|
|
2422
|
-
- `
|
|
2423
|
-
- `enablePanDownToClose` — swipe down to dismiss
|
|
2584
|
+
- `enablePanDownToClose` — swipe down to dismiss (always enabled)
|
|
2424
2585
|
- Backdrop press dismisses
|
|
2425
2586
|
- **Scrollable content:** use `scrollable` prop or `maxHeight`. Both use `BottomSheetScrollView` — do NOT use plain `ScrollView` inside Sheet
|
|
2426
2587
|
- **Keyboard handling:** Full keyboard awareness via `@gorhom/bottom-sheet` v5. Professional defaults:
|
|
@@ -2429,7 +2590,7 @@ Add `react-native-worklets/plugin` (not `react-native-reanimated/plugin`) to `ba
|
|
|
2429
2590
|
- `keyboardBlurBehavior="restore"` — returns to pre-keyboard position when keyboard dismisses
|
|
2430
2591
|
- `enableBlurKeyboardOnGesture={true}` — dismisses keyboard when dragging sheet down
|
|
2431
2592
|
- `topInset` — automatically applied from safe area context to prevent going above notch
|
|
2432
|
-
- **Text inputs inside sheet:**
|
|
2593
|
+
- **Text inputs inside sheet:** use `<Input sheetMode />` — it transparently swaps in `BottomSheetTextInput` for keyboard-aware focus/blur handling, while preserving the full `Input` API (label, error, hint, prefix/suffix, icons, type="password"). For low-level access, `SheetTextInput` (re-exported `BottomSheetTextInput`) is also available. **Never use regular `<TextInput>`** inside sheets — keyboard handling will break.
|
|
2433
2594
|
- **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)
|
|
2434
2595
|
|
|
2435
2596
|
**Haptics:** `impactMedium` on open.
|
|
@@ -2448,23 +2609,39 @@ const [open, setOpen] = useState(false)
|
|
|
2448
2609
|
{items.map((r) => <ListItem key={r.id} title={r.name} showSeparator />)}
|
|
2449
2610
|
</Sheet>
|
|
2450
2611
|
|
|
2451
|
-
// With text input —
|
|
2452
|
-
<Sheet
|
|
2453
|
-
open={open}
|
|
2454
|
-
onClose={() => setOpen(false)}
|
|
2612
|
+
// With text input — recommended pattern (v12+): Input sheetMode
|
|
2613
|
+
<Sheet
|
|
2614
|
+
open={open}
|
|
2615
|
+
onClose={() => setOpen(false)}
|
|
2616
|
+
title="Add note"
|
|
2617
|
+
subtitle="Keyboard handling is automatic with platform-optimized defaults"
|
|
2618
|
+
>
|
|
2619
|
+
<Input
|
|
2620
|
+
label="Note"
|
|
2621
|
+
placeholder="Write your note..."
|
|
2622
|
+
value={note}
|
|
2623
|
+
onChangeText={setNote}
|
|
2624
|
+
sheetMode
|
|
2625
|
+
/>
|
|
2626
|
+
<Button label="Save" fullWidth onPress={handleSave} />
|
|
2627
|
+
</Sheet>
|
|
2628
|
+
|
|
2629
|
+
// Low-level alternative: SheetTextInput
|
|
2630
|
+
<Sheet
|
|
2631
|
+
open={open}
|
|
2632
|
+
onClose={() => setOpen(false)}
|
|
2455
2633
|
title="Add note"
|
|
2456
|
-
subtitle="Keyboard handling is automatic with platform-optimized defaults"
|
|
2457
2634
|
>
|
|
2458
|
-
<SheetTextInput
|
|
2459
|
-
placeholder="Write your note..."
|
|
2635
|
+
<SheetTextInput
|
|
2636
|
+
placeholder="Write your note..."
|
|
2460
2637
|
multiline
|
|
2461
|
-
style={{
|
|
2462
|
-
borderWidth: 1,
|
|
2638
|
+
style={{
|
|
2639
|
+
borderWidth: 1,
|
|
2463
2640
|
borderColor: '#ddd',
|
|
2464
2641
|
borderRadius: 8,
|
|
2465
2642
|
padding: 12,
|
|
2466
2643
|
minHeight: 80,
|
|
2467
|
-
}}
|
|
2644
|
+
}}
|
|
2468
2645
|
/>
|
|
2469
2646
|
<Button label="Save" fullWidth style={{ marginTop: 12 }} onPress={() => setOpen(false)} />
|
|
2470
2647
|
</Sheet>
|
|
@@ -2493,7 +2670,7 @@ const [open, setOpen] = useState(false)
|
|
|
2493
2670
|
|
|
2494
2671
|
**Keyboard handling notes:**
|
|
2495
2672
|
- No `KeyboardAvoidingView` needed — `@gorhom/bottom-sheet` handles everything
|
|
2496
|
-
-
|
|
2673
|
+
- Use `<Input sheetMode />` (preferred) or `SheetTextInput` (low-level) for text inputs inside the sheet
|
|
2497
2674
|
- Default `keyboardBehavior="interactive"` works on both platforms
|
|
2498
2675
|
- Default `android_keyboardInputMode="adjustPan"` fixes the transparent gap that occurs with `adjustResize` when keyboard dismisses
|
|
2499
2676
|
- `enableBlurKeyboardOnGesture={true}` (default) dismisses keyboard when dragging sheet
|
|
@@ -2757,7 +2934,6 @@ dismiss(id)
|
|
|
2757
2934
|
| visible | `boolean` | required | Controls dialog visibility |
|
|
2758
2935
|
| title | `string` | required | Dialog heading |
|
|
2759
2936
|
| subtitle | `string` | — | Secondary text below title |
|
|
2760
|
-
| description | `string` | — | **Deprecated** — use `subtitle` instead |
|
|
2761
2937
|
| confirmLabel | `string` | `'Confirm'` | Confirm button text |
|
|
2762
2938
|
| cancelLabel | `string` | `'Cancel'` | Cancel button text |
|
|
2763
2939
|
| confirmVariant | `'primary' \| 'destructive'` | `'primary'` | Use `'destructive'` for delete/remove actions |
|
|
@@ -2767,12 +2943,15 @@ dismiss(id)
|
|
|
2767
2943
|
| onCancel | `() => void` | required | Called when cancel is tapped or backdrop pressed |
|
|
2768
2944
|
|
|
2769
2945
|
**Notes:**
|
|
2770
|
-
- Powered by `@gorhom/bottom-sheet` with `enableDynamicSizing`
|
|
2946
|
+
- Powered by `@gorhom/bottom-sheet` `BottomSheetModal` with `enableDynamicSizing` (v12 refactor — `present()` / `dismiss()` driven, lazy-mounted, no `index={-1}` + `snapToIndex(0)` timing traps)
|
|
2947
|
+
- `topInset={insets.top}` applied automatically — dialog never crosses the notch / status bar
|
|
2948
|
+
- Internal `wasOpened` ref prevents `dismiss()` being called before the sheet is mounted (race-condition fix from v12.1)
|
|
2949
|
+
- A stable `name` prop (from `useId()`) is passed to `BottomSheetModal` for correct gorhom modal registry behavior when multiple modals are open
|
|
2771
2950
|
- Buttons are full-width, stacked vertically (confirm on top)
|
|
2772
2951
|
- Cancel shows X icon, confirm shows check (primary) or trash-2 (destructive) icon
|
|
2773
2952
|
- Swipe down or backdrop press calls `onCancel`
|
|
2774
2953
|
|
|
2775
|
-
**Haptics:** `
|
|
2954
|
+
**Haptics:** `impactMedium` on open.
|
|
2776
2955
|
|
|
2777
2956
|
**Examples:**
|
|
2778
2957
|
```tsx
|
|
@@ -2780,7 +2959,7 @@ dismiss(id)
|
|
|
2780
2959
|
<ConfirmDialog
|
|
2781
2960
|
visible={showDelete}
|
|
2782
2961
|
title="Delete transaction?"
|
|
2783
|
-
|
|
2962
|
+
subtitle="$45.000 · Mercado · 12 mar · This action cannot be undone."
|
|
2784
2963
|
confirmLabel="Delete"
|
|
2785
2964
|
confirmVariant="destructive"
|
|
2786
2965
|
onConfirm={handleDelete}
|
|
@@ -2791,7 +2970,7 @@ dismiss(id)
|
|
|
2791
2970
|
<ConfirmDialog
|
|
2792
2971
|
visible={showConfirm}
|
|
2793
2972
|
title="Send payment?"
|
|
2794
|
-
|
|
2973
|
+
subtitle={`Send $${amount} to ${recipientName}`}
|
|
2795
2974
|
confirmLabel="Send"
|
|
2796
2975
|
onConfirm={handleSend}
|
|
2797
2976
|
onCancel={() => setShowConfirm(false)}
|
|
@@ -2801,7 +2980,7 @@ dismiss(id)
|
|
|
2801
2980
|
<ConfirmDialog
|
|
2802
2981
|
visible={showDiscard}
|
|
2803
2982
|
title="Discard changes?"
|
|
2804
|
-
|
|
2983
|
+
subtitle="All unsaved changes will be lost."
|
|
2805
2984
|
confirmLabel="Discard"
|
|
2806
2985
|
confirmVariant="destructive"
|
|
2807
2986
|
onConfirm={() => { setShowDiscard(false); goBack() }}
|
|
@@ -2832,7 +3011,7 @@ dismiss(id)
|
|
|
2832
3011
|
| leftIconColor | `string` | — | Override left icon color (default: `foreground`) |
|
|
2833
3012
|
| rightIconColor | `string` | — | Override right icon color (default: `foregroundMuted`) |
|
|
2834
3013
|
| variant | `'plain' \| 'card'` | `'plain'` | `plain`: no background. `card`: surface with border and shadow |
|
|
2835
|
-
| showChevron | `boolean` | `false` | Right-pointing chevron. Ignored when `rightRender` is set |
|
|
3014
|
+
| showChevron | `boolean` | `false` | Right-pointing chevron. Ignored when `rightActions`, `rightRender`, or `rightIcon` is set |
|
|
2836
3015
|
| showSeparator | `boolean` | `false` | Hairline separator at bottom. Useful for stacking plain items |
|
|
2837
3016
|
| onPress | `() => void` | — | Makes row pressable (scale animation + haptics) |
|
|
2838
3017
|
| disabled | `boolean` | — | Reduces opacity to 0.45 |
|
|
@@ -2841,13 +3020,12 @@ dismiss(id)
|
|
|
2841
3020
|
| subtitleStyle | `TextStyle` | — | Override subtitle text style |
|
|
2842
3021
|
| subtitleNumberOfLines | `number` | `2` | Max lines for subtitle before truncation |
|
|
2843
3022
|
| captionStyle | `TextStyle` | — | Override caption text style |
|
|
2844
|
-
|
|
|
2845
|
-
| trailing | `string \| ReactNode` | — | **Deprecated** — use `rightRender` |
|
|
3023
|
+
| rightActions | `ReactNode[]` | — | Multiple action buttons on the right with 8pt gap. Takes precedence over `rightRender` |
|
|
2846
3024
|
|
|
2847
3025
|
**Slots:**
|
|
2848
3026
|
- `leftRender` / `leftIcon` — 44×44pt fixed container, centered. Good for Avatar, icons, thumbnails
|
|
2849
3027
|
- `rightRender` / `rightIcon` — max 160pt wide, right-aligned. Good for Badge, price text, Switch
|
|
2850
|
-
- `showChevron` — `›` chevron, 24pt, `foregroundMuted` color. Only shows when `rightRender`
|
|
3028
|
+
- `showChevron` — `›` chevron, 24pt, `foregroundMuted` color. Only shows when `rightRender`, `rightActions`, and `rightIcon` are absent
|
|
2851
3029
|
|
|
2852
3030
|
**Separator inset:** Aligns to text block — `marginLeft` adjusts to skip over left slot when present.
|
|
2853
3031
|
|
|
@@ -3465,22 +3643,22 @@ const [period, setPeriod] = useState({
|
|
|
3465
3643
|
|
|
3466
3644
|
**When to use:** Custom interactive content that needs beautiful spring bounce effect matching MediaCard. Use when you need a pressable wrapper around custom layouts that aren't covered by existing button components.
|
|
3467
3645
|
|
|
3468
|
-
**Extends:** `TouchableOpacityProps` (all native props pass through except `activeOpacity`)
|
|
3469
|
-
|
|
3470
3646
|
| Prop | Type | Default | Notes |
|
|
3471
3647
|
|------|------|---------|-------|
|
|
3472
3648
|
| children | `ReactNode` | required | Content to render inside the pressable |
|
|
3473
3649
|
| onPress | `() => void` | — | Press handler |
|
|
3474
3650
|
| pressScale | `number` | `0.98` | Scale value on press (MediaCard-style) |
|
|
3475
|
-
| bounciness | `number` | `4` | Spring bounciness on release |
|
|
3476
3651
|
| haptics | `boolean` | `true` | Enable haptic feedback on press |
|
|
3477
3652
|
| hoverScale | `number` | `1.02` | Hover scale (web only). Set to `1` to disable |
|
|
3478
3653
|
| disabled | `boolean` | `false` | Disable interaction |
|
|
3654
|
+
| accessibilityRole | `AccessibilityRole` | `'button'` | Override the accessibility role for screen readers |
|
|
3655
|
+
| accessibilityState | `Record<string, unknown>` | `{ disabled: !!disabled }` | Accessibility state for selected/expanded/checked |
|
|
3656
|
+
| accessibilityLabel | `string` | — | Accessibility label for screen readers |
|
|
3479
3657
|
| style | `ViewStyle` | — | Animated wrapper style |
|
|
3480
3658
|
|
|
3481
3659
|
**Behavior:**
|
|
3482
3660
|
- Press: springs to `pressScale` (default 0.98) with `speed: 40, bounciness: 0`
|
|
3483
|
-
- Release: springs back to 1.0 with `speed: 40
|
|
3661
|
+
- Release: springs back to 1.0 with `speed: 40`
|
|
3484
3662
|
- Web: optional hover scale (default 1.02)
|
|
3485
3663
|
- Haptics: `impactLight` on press (unless `haptics={false}`)
|
|
3486
3664
|
|
|
@@ -3499,7 +3677,7 @@ const [period, setPeriod] = useState({
|
|
|
3499
3677
|
</Pressable>
|
|
3500
3678
|
|
|
3501
3679
|
// Wrapping complex layout
|
|
3502
|
-
<Pressable onPress={handleSelect} pressScale={0.96}
|
|
3680
|
+
<Pressable onPress={handleSelect} pressScale={0.96}>
|
|
3503
3681
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 12, padding: 16 }}>
|
|
3504
3682
|
<Avatar src={user.avatar} size="md" />
|
|
3505
3683
|
<View style={{ flex: 1 }}>
|
|
@@ -3516,7 +3694,7 @@ const [period, setPeriod] = useState({
|
|
|
3516
3694
|
</Pressable>
|
|
3517
3695
|
|
|
3518
3696
|
// Custom press scale (deeper press)
|
|
3519
|
-
<Pressable onPress={handlePress} pressScale={0.92}
|
|
3697
|
+
<Pressable onPress={handlePress} pressScale={0.92}>
|
|
3520
3698
|
{/* content */}
|
|
3521
3699
|
</Pressable>
|
|
3522
3700
|
```
|
|
@@ -3788,6 +3966,76 @@ export default function TabLayout() {
|
|
|
3788
3966
|
|
|
3789
3967
|
---
|
|
3790
3968
|
|
|
3969
|
+
### Stats
|
|
3970
|
+
|
|
3971
|
+
**Import:** `import { Stats } from '@retray-dev/ui-kit'`
|
|
3972
|
+
|
|
3973
|
+
**When to use:** Dashboards and analytics screens — single-stat card with a large value, icon, label, and optional description. Tappable cards wire haptics automatically.
|
|
3974
|
+
|
|
3975
|
+
| Prop | Type | Default | Notes |
|
|
3976
|
+
|------|------|---------|-------|
|
|
3977
|
+
| value | `string` | required | Large display value, e.g. `"$12,450"` or `"847"` |
|
|
3978
|
+
| label | `string` | required | Label below the value, e.g. `"Monthly Revenue"` |
|
|
3979
|
+
| description | `string` | — | Third line — smaller, muted text for trend/context |
|
|
3980
|
+
| icon | `React.ReactNode` | — | Custom icon node |
|
|
3981
|
+
| iconName | `string` | — | Icon from `@expo/vector-icons` (left of value, `colors.primary`) |
|
|
3982
|
+
| iconColor | `string` | `colors.primary` | Override icon color |
|
|
3983
|
+
| variant | `'elevated' \| 'outlined' \| 'filled'` | `'elevated'` | Card surface variant |
|
|
3984
|
+
| onPress | `() => void` | — | Makes the card pressable (haptic `impactLight()`) |
|
|
3985
|
+
| style | `ViewStyle` | — | — |
|
|
3986
|
+
| accessibilityLabel | `string` | — | — |
|
|
3987
|
+
|
|
3988
|
+
**Design notes:** Value uses `Sohne-Bold` at 28px. Label uses `Sohne-Regular` at 13px in `foregroundSubtle`. Description uses `Sohne-Regular` at 12px in `foregroundMuted`. Icon renders at 22px, left-aligned with the value. All content is centered vertically and horizontally. The card shrinks to fit its content by default (`alignSelf: 'flex-start'`). When placed inside `Stats.Group`, cards stretch to equal width. When the card is narrow (< 150dp) and has an icon, the layout switches to vertical stacking (icon → value → label → description) to avoid overflow.
|
|
3989
|
+
|
|
3990
|
+
**`Stats.Group`** — horizontal layout wrapper that distributes children equally:
|
|
3991
|
+
|
|
3992
|
+
| Prop | Type | Default | Notes |
|
|
3993
|
+
|------|------|---------|-------|
|
|
3994
|
+
| children | `React.ReactNode` | required | `Stats` components to arrange horizontally |
|
|
3995
|
+
| gap | `number` | `s(12)` | Spacing between cards |
|
|
3996
|
+
| style | `ViewStyle` | — | — |
|
|
3997
|
+
|
|
3998
|
+
**Layout guidance:** Prefer 2-up for values longer than ~3 digits (e.g. `"$12,450"`, `"1,234"`) or with descriptions. Use 3-up only for very compact metrics with short values (e.g. `"847"`, `"98%"`) and no description — otherwise values will wrap and look broken.
|
|
3999
|
+
|
|
4000
|
+
**Example:**
|
|
4001
|
+
```tsx
|
|
4002
|
+
// Standalone
|
|
4003
|
+
<Stats
|
|
4004
|
+
value="$12,450"
|
|
4005
|
+
label="Monthly Revenue"
|
|
4006
|
+
description="+12% from last month"
|
|
4007
|
+
iconName="trending-up"
|
|
4008
|
+
/>
|
|
4009
|
+
|
|
4010
|
+
// 3-up — short values only, no description
|
|
4011
|
+
<Stats.Group>
|
|
4012
|
+
<Stats value="847" label="Users" variant="elevated" />
|
|
4013
|
+
<Stats value="98%" label="Uptime" variant="outlined" />
|
|
4014
|
+
<Stats value="12" label="Alerts" variant="filled" />
|
|
4015
|
+
</Stats.Group>
|
|
4016
|
+
|
|
4017
|
+
// 2-up with icons, long values, and description
|
|
4018
|
+
<Stats.Group gap={s(16)}>
|
|
4019
|
+
<Stats
|
|
4020
|
+
value="$8,200"
|
|
4021
|
+
label="Spent"
|
|
4022
|
+
description="This month"
|
|
4023
|
+
iconName="credit-card"
|
|
4024
|
+
variant="elevated"
|
|
4025
|
+
onPress={() => navigateToBilling()}
|
|
4026
|
+
/>
|
|
4027
|
+
<Stats
|
|
4028
|
+
value="$2,150"
|
|
4029
|
+
label="Saved"
|
|
4030
|
+
description="12% of budget"
|
|
4031
|
+
iconName="trending-up"
|
|
4032
|
+
variant="outlined"
|
|
4033
|
+
/>
|
|
4034
|
+
</Stats.Group>
|
|
4035
|
+
```
|
|
4036
|
+
|
|
4037
|
+
---
|
|
4038
|
+
|
|
3791
4039
|
### ErrorBoundary
|
|
3792
4040
|
|
|
3793
4041
|
**Import:** `import { ErrorBoundary } from '@retray-dev/ui-kit'`
|
|
@@ -4030,7 +4278,7 @@ const handleChange = async (uri: string | null) => {
|
|
|
4030
4278
|
|
|
4031
4279
|
**Import:** `import { IconPicker } from '@retray-dev/ui-kit'`
|
|
4032
4280
|
|
|
4033
|
-
**When to use:** Selecting an icon from a curated catalog of ~
|
|
4281
|
+
**When to use:** Selecting an icon from a curated catalog of ~600 themed icons (across Feather, Ionicons `-outline`, FA5 Brands/regular, Entypo, AntDesign — only outlined variants) organized by 12 categories. The trigger is a simple tappable square showing the selected icon (or a + placeholder). Tapping opens a bottom sheet with category chips (icon + label) and a scrollable grid. No search, no text clutter — purely visual selection.
|
|
4034
4282
|
|
|
4035
4283
|
**Requires:** `@gorhom/bottom-sheet` (already a peer dependency of the UI kit).
|
|
4036
4284
|
|
|
@@ -4067,10 +4315,12 @@ const [icon, setIcon] = useState<string | null>(null)
|
|
|
4067
4315
|
```
|
|
4068
4316
|
|
|
4069
4317
|
**Notes:**
|
|
4070
|
-
- Uses a static curated list of ~
|
|
4318
|
+
- Uses a static curated list of ~600 outlined icons in 12 categories (food, sports, business, objects, status, actions, communication, navigation, media, layout, nature, brands), with at least 42 icons per category — instant load, no runtime glyphMap scanning.
|
|
4319
|
+
- Icon selection rules are strict: only Feather, Ionicons `-outline`, and themed FA5/Entypo/AntDesign icons are eligible. Filled variants and FA5-only-solid icons are excluded to keep the visual style consistent. See `src/utils/curatedIcons.ts` for the source of truth.
|
|
4320
|
+
- **Feedback pattern (v12.1):** the sheet presents **immediately** on trigger tap (no `useEffect` delay). While the grid container measures its width via `onLayout`, a centered `<Spinner />` is shown inside the sheet so the user always sees visible feedback. The grid transitions in as soon as measurement is complete. This is the canonical REGLA 4 pattern — apply it to any overlay whose content needs to measure before rendering.
|
|
4071
4321
|
- Category chips use representative icons (coffee, activity, briefcase, folder, alert-circle, edit-3, message-circle, compass, image, grid, sun, globe) with Spanish labels and a "Todos" (All) chip.
|
|
4072
4322
|
- Grid cells show only icons — clean, fast visual scanning. Cell size adapts to container width.
|
|
4073
|
-
- Sheet uses `enableDynamicSizing` with `maxDynamicContentSize` (70% screen height) — height auto-fits content up to that cap.
|
|
4323
|
+
- Sheet uses `enableDynamicSizing` with `maxDynamicContentSize` (70% screen height) — height auto-fits content up to that cap. `topInset={insets.top}` is applied automatically.
|
|
4074
4324
|
- Category strip is a horizontal `ScrollView` of pill-shaped chips. The grid is rendered in rows inside a `BottomSheetScrollView`.
|
|
4075
4325
|
- Selection closes the sheet immediately and resets category to "Todos".
|
|
4076
4326
|
- Haptics: medium impact on open, selection on icon tap.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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
|
+
- 54 components across 9 categories (plus the deep-import `HolographicCard`)
|
|
6
6
|
- Light/dark theme with 12 public tokens (25 resolved) 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
|
|
@@ -177,11 +177,15 @@ import { SPACING, ICON_SIZES, RADIUS, SHADOWS, BREAKPOINTS, TYPOGRAPHY } from '@
|
|
|
177
177
|
| `BREAKPOINTS` | `wide` (700) |
|
|
178
178
|
| `TYPOGRAPHY` | 16 variants: `display-hero`, `display-xl`, `display-lg`, `display-md`, `display-sm`, `title-md`, `title-sm`, `body-md`, `body-sm`, `caption`, `caption-sm`, `badge-text`, `micro-label`, `uppercase-tag`, `button-lg`, `button-sm` |
|
|
179
179
|
|
|
180
|
+
### Color Utilities
|
|
181
|
+
|
|
182
|
+
- **`withAlpha(color: string, alpha: number)`** — takes a hex color string (e.g., `"#6366f1"`) and an opacity value (0–1), returns an `rgba()` string. Useful for semi-transparent overlays without adding a separate token.
|
|
183
|
+
|
|
180
184
|
## Components
|
|
181
185
|
|
|
182
186
|
| Category | Components |
|
|
183
187
|
| ----------- | ----------------------------------------------------------------------------------------------- |
|
|
184
|
-
| Display | `Text`, `Badge`, `Avatar`, `Separator`, `Spinner`, `Skeleton`, `Progress`, `CurrencyDisplay`
|
|
188
|
+
| Display | `Text`, `Badge`, `Avatar`, `Separator`, `Spinner`, `Skeleton`, `Progress`, `CurrencyDisplay`, `Stats` |
|
|
185
189
|
| Surfaces | `Card`, `AlertBanner`, `EmptyState`, `MediaCard`, `PricingCard` |
|
|
186
190
|
| Form | `Form` (+ `Form.Field` / `Form.Section` / `Form.Footer`), `Button`, `ButtonGroup`, `IconButton`, `Input`, `CurrencyInput`, `Textarea`, `Checkbox`, `Switch`, `Toggle`, `RadioGroup`, `Select`, `Slider`, `SelectableGrid`, `SheetSelect`, `ImageUpload`, `IconPicker`, `NumberStepper` |
|
|
187
191
|
| Composition | `Tabs`, `Accordion` |
|
|
@@ -220,6 +224,11 @@ toast({ title: 'Saved', variant: 'success' })
|
|
|
220
224
|
options={[{ label: 'Option A', value: 'a' }, { label: 'Option B', value: 'b' }]}
|
|
221
225
|
placeholder="Pick one"
|
|
222
226
|
/>
|
|
227
|
+
|
|
228
|
+
// Color utilities
|
|
229
|
+
import { useTheme, withAlpha } from '@retray-dev/ui-kit'
|
|
230
|
+
const { colors } = useTheme()
|
|
231
|
+
;<View style={{ backgroundColor: withAlpha(colors.primary, 0.15) }} />
|
|
223
232
|
```
|
|
224
233
|
|
|
225
234
|
Full props reference and more examples are available in [COMPONENTS.md](./COMPONENTS.md), which is also shipped inside the npm package for use with AI tools:
|
package/dist/Accordion.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { Accordion } from './chunk-
|
|
1
|
+
export { Accordion } from './chunk-265G6A46.mjs';
|
|
2
2
|
import './chunk-EJ7ZPXOH.mjs';
|
|
3
3
|
import './chunk-DVK4G2GT.mjs';
|
|
4
4
|
import './chunk-KA7LTET3.mjs';
|
|
5
|
-
import './chunk-
|
|
5
|
+
import './chunk-EMUWGDWC.mjs';
|
|
6
6
|
import './chunk-2CE3TQVY.mjs';
|
|
7
7
|
import './chunk-Y6FXYEAI.mjs';
|
package/dist/AlertBanner.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { AlertBanner } from './chunk-
|
|
1
|
+
export { AlertBanner } from './chunk-V6NFJXKO.mjs';
|
|
2
2
|
import './chunk-QY3X2UYR.mjs';
|
|
3
3
|
import './chunk-KA7LTET3.mjs';
|
|
4
|
-
import './chunk-
|
|
4
|
+
import './chunk-EMUWGDWC.mjs';
|
|
5
5
|
import './chunk-2CE3TQVY.mjs';
|
|
6
6
|
import './chunk-Y6FXYEAI.mjs';
|
package/dist/AppHeader.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export { AppHeader } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { AppHeader } from './chunk-ISY26JQJ.mjs';
|
|
2
|
+
import './chunk-DF6DU42P.mjs';
|
|
3
3
|
import './chunk-3DKJ2GIC.mjs';
|
|
4
4
|
import './chunk-EJ7ZPXOH.mjs';
|
|
5
5
|
import './chunk-DVK4G2GT.mjs';
|
|
6
6
|
import './chunk-QY3X2UYR.mjs';
|
|
7
7
|
import './chunk-KA7LTET3.mjs';
|
|
8
|
-
import './chunk-
|
|
8
|
+
import './chunk-EMUWGDWC.mjs';
|
|
9
9
|
import './chunk-2CE3TQVY.mjs';
|
|
10
10
|
import './chunk-Y6FXYEAI.mjs';
|
package/dist/Avatar.mjs
CHANGED
package/dist/Badge.mjs
CHANGED
package/dist/Button.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { Button } from './chunk-
|
|
1
|
+
export { Button } from './chunk-DOGIPOF5.mjs';
|
|
2
2
|
import './chunk-3DKJ2GIC.mjs';
|
|
3
3
|
import './chunk-EJ7ZPXOH.mjs';
|
|
4
4
|
import './chunk-DVK4G2GT.mjs';
|
|
5
5
|
import './chunk-QY3X2UYR.mjs';
|
|
6
6
|
import './chunk-KA7LTET3.mjs';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-EMUWGDWC.mjs';
|
|
8
8
|
import './chunk-2CE3TQVY.mjs';
|
|
9
9
|
import './chunk-Y6FXYEAI.mjs';
|
package/dist/Card.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-
|
|
1
|
+
export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-2CBQKU7H.mjs';
|
|
2
2
|
import './chunk-3DKJ2GIC.mjs';
|
|
3
3
|
import './chunk-EJ7ZPXOH.mjs';
|
|
4
4
|
import './chunk-DVK4G2GT.mjs';
|
|
5
5
|
import './chunk-QY3X2UYR.mjs';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-EMUWGDWC.mjs';
|
|
7
7
|
import './chunk-2CE3TQVY.mjs';
|
|
8
8
|
import './chunk-Y6FXYEAI.mjs';
|
package/dist/CategoryStrip.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { CategoryStrip } from './chunk-
|
|
1
|
+
export { CategoryStrip } from './chunk-MYZ2EDYU.mjs';
|
|
2
2
|
import './chunk-YNROWHQJ.mjs';
|
|
3
3
|
import './chunk-EJ7ZPXOH.mjs';
|
|
4
4
|
import './chunk-DVK4G2GT.mjs';
|
|
5
5
|
import './chunk-QY3X2UYR.mjs';
|
|
6
6
|
import './chunk-KA7LTET3.mjs';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-EMUWGDWC.mjs';
|
|
8
8
|
import './chunk-2CE3TQVY.mjs';
|
|
9
9
|
import './chunk-Y6FXYEAI.mjs';
|