@retray-dev/ui-kit 12.2.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/COMPONENTS.md +85 -143
- package/CONSUMER.md +2 -2
- package/DESIGN.md +2 -2
- package/README.md +11 -6
- package/dist/Accordion.js +48 -210
- package/dist/Accordion.mjs +6 -5
- package/dist/AlertBanner.js +29 -153
- package/dist/AlertBanner.mjs +3 -3
- package/dist/AppHeader.js +37 -235
- package/dist/AppHeader.mjs +6 -7
- package/dist/Avatar.d.mts +17 -1
- package/dist/Avatar.d.ts +17 -1
- package/dist/Avatar.js +80 -115
- package/dist/Avatar.mjs +2 -2
- package/dist/Badge.js +24 -149
- package/dist/Badge.mjs +3 -3
- package/dist/Button.js +79 -267
- package/dist/Button.mjs +6 -6
- package/dist/Card.js +15 -200
- package/dist/Card.mjs +4 -5
- package/dist/CategoryStrip.d.mts +0 -5
- package/dist/CategoryStrip.d.ts +0 -5
- package/dist/CategoryStrip.js +47 -265
- package/dist/CategoryStrip.mjs +6 -6
- package/dist/Checkbox.js +15 -200
- package/dist/Checkbox.mjs +5 -5
- package/dist/Chip.js +44 -236
- package/dist/Chip.mjs +7 -6
- package/dist/ConfirmDialog.js +84 -286
- package/dist/ConfirmDialog.mjs +7 -7
- package/dist/CurrencyDisplay.js +1 -114
- package/dist/CurrencyDisplay.mjs +2 -2
- package/dist/CurrencyInput.js +35 -162
- package/dist/CurrencyInput.mjs +5 -5
- package/dist/DetailRow.js +25 -150
- package/dist/DetailRow.mjs +3 -3
- package/dist/EmptyState.js +80 -268
- package/dist/EmptyState.mjs +7 -7
- package/dist/ErrorBoundary.js +32 -199
- package/dist/ErrorBoundary.mjs +4 -4
- package/dist/Form.js +1 -114
- package/dist/Form.mjs +2 -2
- package/dist/HolographicCard.d.mts +0 -28
- package/dist/HolographicCard.d.ts +0 -28
- package/dist/HolographicCard.js +20 -130
- package/dist/HolographicCard.mjs +9 -32
- package/dist/IconButton.js +36 -234
- package/dist/IconButton.mjs +5 -6
- package/dist/IconPicker.js +222 -929
- package/dist/IconPicker.mjs +5 -5
- package/dist/ImageUpload.d.mts +3 -1
- package/dist/ImageUpload.d.ts +3 -1
- package/dist/ImageUpload.js +25 -215
- package/dist/ImageUpload.mjs +5 -6
- package/dist/ImageViewer.js +75 -266
- package/dist/ImageViewer.mjs +8 -8
- package/dist/Input.d.mts +1 -1
- package/dist/Input.d.ts +1 -1
- package/dist/Input.js +35 -162
- package/dist/Input.mjs +4 -4
- package/dist/LabelValue.js +24 -149
- package/dist/LabelValue.mjs +3 -3
- package/dist/ListGroup.js +1 -114
- package/dist/ListGroup.mjs +2 -2
- package/dist/ListItem.js +38 -235
- package/dist/ListItem.mjs +5 -6
- package/dist/MediaCard.d.mts +0 -14
- package/dist/MediaCard.d.ts +0 -14
- package/dist/MediaCard.js +69 -315
- package/dist/MediaCard.mjs +5 -6
- package/dist/MenuGroup.js +1 -114
- package/dist/MenuGroup.mjs +2 -2
- package/dist/MenuItem.js +36 -234
- package/dist/MenuItem.mjs +5 -6
- package/dist/MonthPicker.js +8 -163
- package/dist/MonthPicker.mjs +3 -3
- package/dist/NumberStepper.js +40 -238
- package/dist/NumberStepper.mjs +5 -6
- package/dist/PagerDots.d.mts +1 -1
- package/dist/PagerDots.d.ts +1 -1
- package/dist/PagerDots.js +69 -224
- package/dist/PagerDots.mjs +6 -5
- package/dist/Pressable.js +14 -85
- package/dist/Pressable.mjs +4 -4
- package/dist/PricingCard.js +87 -272
- package/dist/PricingCard.mjs +8 -8
- package/dist/Progress.js +3 -123
- package/dist/Progress.mjs +3 -3
- package/dist/RadioGroup.js +52 -265
- package/dist/RadioGroup.mjs +5 -5
- package/dist/RetrayProvider.js +3 -6
- package/dist/RetrayProvider.mjs +3 -3
- package/dist/Select.d.mts +2 -1
- package/dist/Select.d.ts +2 -1
- package/dist/Select.js +24 -232
- package/dist/Select.mjs +4 -5
- package/dist/SelectableCard.js +33 -209
- package/dist/SelectableCard.mjs +5 -5
- package/dist/SelectableGrid.d.mts +0 -21
- package/dist/SelectableGrid.d.ts +0 -21
- package/dist/SelectableGrid.js +49 -271
- package/dist/SelectableGrid.mjs +5 -6
- package/dist/Separator.js +1 -114
- package/dist/Separator.mjs +2 -2
- package/dist/Sheet.js +7 -162
- package/dist/Sheet.mjs +3 -3
- package/dist/SheetSelect.js +39 -236
- package/dist/SheetSelect.mjs +6 -6
- package/dist/Skeleton.js +4 -124
- package/dist/Skeleton.mjs +3 -3
- package/dist/Slider.js +6 -161
- package/dist/Slider.mjs +3 -3
- package/dist/Spinner.js +3 -116
- package/dist/Spinner.mjs +2 -2
- package/dist/Stats.js +36 -234
- package/dist/Stats.mjs +5 -6
- package/dist/Switch.js +24 -175
- package/dist/Switch.mjs +5 -4
- package/dist/TabBar.js +43 -200
- package/dist/TabBar.mjs +5 -4
- package/dist/Tabs.js +15 -199
- package/dist/Tabs.mjs +5 -5
- package/dist/Text.js +9 -130
- package/dist/Text.mjs +2 -2
- package/dist/Textarea.d.mts +2 -1
- package/dist/Textarea.d.ts +2 -1
- package/dist/Textarea.js +71 -219
- package/dist/Textarea.mjs +4 -4
- package/dist/Toast.js +1 -114
- package/dist/Toast.mjs +2 -2
- package/dist/Toggle.js +39 -236
- package/dist/Toggle.mjs +6 -6
- package/dist/{chunk-M3C7XM2M.mjs → chunk-2QOHHBJC.mjs} +3 -3
- package/dist/{chunk-LIS6I5UP.mjs → chunk-2VIDP72N.mjs} +3 -3
- package/dist/{chunk-DF7JA72E.mjs → chunk-4NQFTHN3.mjs} +13 -7
- package/dist/{chunk-UBUXUMER.mjs → chunk-4ZO5PTKF.mjs} +4 -4
- package/dist/{chunk-3XCFYSX4.mjs → chunk-5MYNAAFE.mjs} +13 -17
- package/dist/{chunk-E7NEHHXV.mjs → chunk-62BBSSUF.mjs} +3 -3
- package/dist/{chunk-MVMGPZN6.mjs → chunk-6CR4S6W2.mjs} +3 -3
- package/dist/{chunk-EDLCGYIO.mjs → chunk-6QLBHUEG.mjs} +8 -7
- package/dist/chunk-ARONDO7M.mjs +40 -0
- package/dist/{chunk-GH67YXG6.mjs → chunk-AZV7KNJI.mjs} +3 -3
- package/dist/{chunk-RMRS44MQ.mjs → chunk-BTUW5LSG.mjs} +11 -8
- package/dist/{chunk-2P2CB235.mjs → chunk-BULKGOIZ.mjs} +7 -8
- package/dist/{chunk-NHDI3VQB.mjs → chunk-CBIZLRYH.mjs} +15 -12
- package/dist/chunk-CM2DG4MR.mjs +142 -0
- package/dist/{chunk-TS7DGUIR.mjs → chunk-DBHSUUKU.mjs} +2 -2
- package/dist/{chunk-57V2LXCK.mjs → chunk-DE25XTVQ.mjs} +3 -3
- package/dist/{chunk-UQ4742ET.mjs → chunk-E4EQSCKR.mjs} +5 -5
- package/dist/{chunk-GUTDFUNF.mjs → chunk-EHGBHFMH.mjs} +9 -17
- package/dist/{chunk-CF27NBXO.mjs → chunk-EROPDCB5.mjs} +16 -24
- package/dist/{chunk-ZIMY2QUM.mjs → chunk-ERWJPVX7.mjs} +2 -2
- package/dist/{chunk-NLZY4TXU.mjs → chunk-ESQDPO5E.mjs} +7 -7
- package/dist/{chunk-VJBUCITV.mjs → chunk-EW2FIDSM.mjs} +1 -1
- package/dist/{chunk-HC4VVCWY.mjs → chunk-FTTI6T5Q.mjs} +4 -4
- package/dist/{chunk-2HFD4IHU.mjs → chunk-HUSSF6TF.mjs} +1 -1
- package/dist/chunk-IFYMBOEN.mjs +14 -0
- package/dist/{chunk-QOLWA2PW.mjs → chunk-IGU223UM.mjs} +80 -4
- package/dist/chunk-IJCMPVW5.mjs +121 -0
- package/dist/{chunk-AENAVIKT.mjs → chunk-ITG4JQM3.mjs} +4 -4
- package/dist/{chunk-E5UKLSJZ.mjs → chunk-K3QX2M26.mjs} +11 -8
- package/dist/{chunk-4OORJ2DY.mjs → chunk-K7TKID3V.mjs} +8 -7
- package/dist/{chunk-2LG326TT.mjs → chunk-KAGADD2O.mjs} +4 -4
- package/dist/{chunk-IVSRW4HS.mjs → chunk-KC5QDYGZ.mjs} +4 -4
- package/dist/{chunk-7AFZWSCI.mjs → chunk-KPTY7UYQ.mjs} +1 -1
- package/dist/{chunk-YTXRIXNZ.mjs → chunk-KSSVIFYR.mjs} +9 -12
- package/dist/chunk-L3YKPTJQ.mjs +119 -0
- package/dist/chunk-M53LC4Q7.mjs +35 -0
- package/dist/{chunk-ZR6HSEAB.mjs → chunk-MP7GLMIR.mjs} +17 -25
- package/dist/chunk-MZ6WRTD2.mjs +40 -0
- package/dist/chunk-NGEN2EES.mjs +581 -0
- package/dist/{chunk-C43HRKXH.mjs → chunk-OBV72JD4.mjs} +1 -1
- package/dist/{chunk-LPV4NJJK.mjs → chunk-PGQ6FMXS.mjs} +6 -5
- package/dist/{chunk-MEPSKGBO.mjs → chunk-PI6RULJX.mjs} +1 -1
- package/dist/{chunk-F3YTWO3T.mjs → chunk-RA6SAAFE.mjs} +9 -8
- package/dist/{chunk-UNNRUJTM.mjs → chunk-RRKM4MKB.mjs} +7 -7
- package/dist/{chunk-ULGNQPNE.mjs → chunk-S2VGME7X.mjs} +1 -1
- package/dist/{chunk-OLVJFKXS.mjs → chunk-S44XWTTC.mjs} +35 -25
- package/dist/{chunk-YMYIEVZP.mjs → chunk-SZEKQAOY.mjs} +1 -1
- package/dist/{chunk-ELGEOM7I.mjs → chunk-TETMEKZE.mjs} +9 -9
- package/dist/{chunk-BXF4AMHY.mjs → chunk-TMH263OK.mjs} +5 -4
- package/dist/{chunk-NJG7DHVF.mjs → chunk-U6DEBYU5.mjs} +10 -9
- package/dist/{chunk-RJNLAH76.mjs → chunk-UOKFSFNJ.mjs} +2 -2
- package/dist/{chunk-HEDQPK4I.mjs → chunk-URIH43IJ.mjs} +13 -21
- package/dist/{chunk-QXDGGOLC.mjs → chunk-V2ZB2XNS.mjs} +6 -6
- package/dist/{chunk-KSUWPU2F.mjs → chunk-WIPEDNSD.mjs} +7 -7
- package/dist/{chunk-QDAZGZUF.mjs → chunk-XCIG6HT2.mjs} +3 -3
- package/dist/{chunk-4J2PXL36.mjs → chunk-Y6YS33GM.mjs} +40 -38
- package/dist/{chunk-4XOB5TTD.mjs → chunk-ZKDKKQCE.mjs} +5 -5
- package/dist/{chunk-LOBLCFMN.mjs → chunk-ZTPYUU5C.mjs} +5 -5
- package/dist/index.d.mts +12 -72
- package/dist/index.d.ts +12 -72
- package/dist/index.js +1051 -1838
- package/dist/index.mjs +81 -85
- package/package.json +8 -10
- package/src/components/Accordion/Accordion.tsx +12 -9
- package/src/components/AlertBanner/AlertBanner.tsx +7 -6
- package/src/components/AppHeader/AppHeader.tsx +1 -1
- package/src/components/Avatar/Avatar.tsx +92 -1
- package/src/components/Avatar/index.ts +2 -2
- package/src/components/Badge/Badge.tsx +2 -2
- package/src/components/Button/Button.tsx +50 -46
- package/src/components/Card/Card.tsx +1 -0
- package/src/components/CategoryStrip/CategoryStrip.tsx +36 -49
- package/src/components/Chip/Chip.tsx +5 -4
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +3 -3
- package/src/components/DetailRow/DetailRow.tsx +3 -3
- package/src/components/EmptyState/EmptyState.tsx +2 -2
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +6 -6
- package/src/components/HolographicCard/HolographicCard.tsx +14 -95
- package/src/components/IconButton/IconButton.tsx +2 -2
- package/src/components/IconPicker/IconPicker.tsx +13 -12
- package/src/components/ImageUpload/ImageUpload.tsx +14 -25
- package/src/components/ImageViewer/ImageViewer.tsx +3 -3
- package/src/components/Input/Input.tsx +11 -5
- package/src/components/LabelValue/LabelValue.tsx +2 -2
- package/src/components/ListItem/ListItem.tsx +4 -4
- package/src/components/MediaCard/MediaCard.tsx +21 -59
- package/src/components/MenuItem/MenuItem.tsx +2 -2
- package/src/components/MonthPicker/MonthPicker.tsx +2 -2
- package/src/components/NumberStepper/NumberStepper.tsx +6 -6
- package/src/components/PagerDots/PagerDots.tsx +38 -28
- package/src/components/PricingCard/PricingCard.tsx +6 -6
- package/src/components/RadioGroup/RadioGroup.tsx +18 -31
- package/src/components/Select/Select.tsx +32 -39
- package/src/components/SelectableCard/SelectableCard.tsx +4 -6
- package/src/components/SelectableGrid/SelectableGrid.tsx +38 -72
- package/src/components/Sheet/Sheet.tsx +1 -1
- package/src/components/SheetSelect/SheetSelect.tsx +3 -3
- package/src/components/Skeleton/Skeleton.tsx +1 -1
- package/src/components/Spinner/Spinner.tsx +2 -2
- package/src/components/Stats/Stats.tsx +2 -2
- package/src/components/Switch/Switch.tsx +9 -6
- package/src/components/TabBar/TabBar.tsx +9 -8
- package/src/components/Text/Text.tsx +12 -1
- package/src/components/Textarea/Textarea.tsx +18 -32
- package/src/components/Toggle/Toggle.tsx +3 -3
- package/src/hooks/useConfirmDialog.ts +31 -42
- package/src/index.ts +3 -4
- package/src/theme/ThemeProvider.tsx +1 -4
- package/src/theme/colorUtils.ts +1 -72
- package/src/theme/colors.ts +40 -1
- package/src/theme/types.ts +2 -2
- package/src/utils/animations.ts +0 -47
- package/src/utils/curatedIcons.ts +93 -801
- package/src/utils/haptics.ts +13 -208
- package/src/utils/icons.ts +27 -91
- package/src/utils/pressable.ts +10 -61
- package/dist/VirtualList.d.mts +0 -19
- package/dist/VirtualList.d.ts +0 -19
- package/dist/VirtualList.js +0 -38
- package/dist/VirtualList.mjs +0 -2
- package/dist/chunk-2BA3JMKK.mjs +0 -136
- package/dist/chunk-3DKJ2GIC.mjs +0 -30
- package/dist/chunk-7ELGZ66G.mjs +0 -164
- package/dist/chunk-DVK4G2GT.mjs +0 -59
- package/dist/chunk-EJ7ZPXOH.mjs +0 -163
- package/dist/chunk-KA7LTET3.mjs +0 -71
- package/dist/chunk-LNPKGWBG.mjs +0 -134
- package/dist/chunk-NC5ZTR2Y.mjs +0 -32
- package/dist/chunk-SAWUXP3A.mjs +0 -1114
- package/dist/chunk-YNROWHQJ.mjs +0 -46
- package/src/components/VirtualList/VirtualList.tsx +0 -60
- package/src/components/VirtualList/index.ts +0 -1
- package/src/utils/fontGuard.ts +0 -35
- package/src/utils/hover.ts +0 -25
- package/src/utils/useColorTransition.ts +0 -40
- package/src/utils/usePressScale.ts +0 -75
package/COMPONENTS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @retray-dev/ui-kit — Component Reference (
|
|
1
|
+
# @retray-dev/ui-kit — Component Reference (v13.0.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
|
|
|
@@ -99,10 +99,10 @@ module.exports = function (api) {
|
|
|
99
99
|
| `@expo/vector-icons` | **Required** | Icons everywhere | |
|
|
100
100
|
| `react-native-size-matters` | **Required** | Responsive scaling | |
|
|
101
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` |
|
|
102
|
-
|
|
102
|
+
|
|
103
103
|
| `@shopify/react-native-skia` + `expo-sensors` | **Optional** | Deep-import `HolographicCard` only | `pnpm add @shopify/react-native-skia expo-sensors` |
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
|
|
107
107
|
### Troubleshooting: `react-native-screens` codegen on RN 0.83
|
|
108
108
|
|
|
@@ -1561,6 +1561,65 @@ const [guests, setGuests] = useState(2)
|
|
|
1561
1561
|
|
|
1562
1562
|
---
|
|
1563
1563
|
|
|
1564
|
+
### AvatarGroup
|
|
1565
|
+
|
|
1566
|
+
**Import:** `import { AvatarGroup } from '@retray-dev/ui-kit'`
|
|
1567
|
+
|
|
1568
|
+
**When to use:** Stacked/overlapping avatars to show multiple users in a compact space. Common for collaborator indicators, multi-waiter tables, and team members.
|
|
1569
|
+
|
|
1570
|
+
| Prop | Type | Default | Notes |
|
|
1571
|
+
|------|------|---------|-------|
|
|
1572
|
+
| users | `{ name: string; src?: string }[]` | required | User data — name used for fallback initials |
|
|
1573
|
+
| max | `number` | `3` | Max avatars visible before `+N` overflow badge |
|
|
1574
|
+
| size | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'sm'` | Avatar size preset, passed to each `Avatar` |
|
|
1575
|
+
| overlap | `number` | `vs(8)` | Overlap in points between consecutive avatars |
|
|
1576
|
+
| onOverflowPress | `() => void` | — | Tap handler for the `+N` overflow badge |
|
|
1577
|
+
| style | `ViewStyle` | — | Outer container style |
|
|
1578
|
+
|
|
1579
|
+
**Sizes:** Same as `Avatar` — `sm` (28px), `md` (40px), `lg` (56px), `xl` (72px).
|
|
1580
|
+
|
|
1581
|
+
**Notes:**
|
|
1582
|
+
- Overflow badge uses `surfaceStrong` background with `foregroundMuted` text.
|
|
1583
|
+
- Individual avatars are not tappable — only the `+N` badge fires `onOverflowPress`.
|
|
1584
|
+
- `overlap` follows the spacing grid (defaults to `spacing.sm` = 8pt).
|
|
1585
|
+
|
|
1586
|
+
**Examples:**
|
|
1587
|
+
```tsx
|
|
1588
|
+
// Basic — 5 waiters, show max 3
|
|
1589
|
+
<AvatarGroup
|
|
1590
|
+
users={[
|
|
1591
|
+
{ name: 'Ana', src: 'https://...' },
|
|
1592
|
+
{ name: 'Bob', src: 'https://...' },
|
|
1593
|
+
{ name: 'Carlos' },
|
|
1594
|
+
{ name: 'Diana', src: 'https://...' },
|
|
1595
|
+
{ name: 'Elena' },
|
|
1596
|
+
]}
|
|
1597
|
+
max={3}
|
|
1598
|
+
/>
|
|
1599
|
+
|
|
1600
|
+
// With overflow tap
|
|
1601
|
+
<AvatarGroup
|
|
1602
|
+
users={waiters}
|
|
1603
|
+
max={3}
|
|
1604
|
+
size="sm"
|
|
1605
|
+
onOverflowPress={() => showAllWaiters()}
|
|
1606
|
+
/>
|
|
1607
|
+
|
|
1608
|
+
// In a ListItem
|
|
1609
|
+
<ListItem
|
|
1610
|
+
title="Table 4 — 5 waiters"
|
|
1611
|
+
leftRender={
|
|
1612
|
+
<AvatarGroup
|
|
1613
|
+
users={table.waiters}
|
|
1614
|
+
max={3}
|
|
1615
|
+
size="sm"
|
|
1616
|
+
/>
|
|
1617
|
+
}
|
|
1618
|
+
/>
|
|
1619
|
+
```
|
|
1620
|
+
|
|
1621
|
+
---
|
|
1622
|
+
|
|
1564
1623
|
### Card
|
|
1565
1624
|
|
|
1566
1625
|
**Import:** `import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '@retray-dev/ui-kit'`
|
|
@@ -1765,73 +1824,7 @@ const [guests, setGuests] = useState(2)
|
|
|
1765
1824
|
|
|
1766
1825
|
---
|
|
1767
1826
|
|
|
1768
|
-
### VirtualList
|
|
1769
|
-
|
|
1770
|
-
**Import:** `import { VirtualList } from '@retray-dev/ui-kit'`
|
|
1771
|
-
|
|
1772
|
-
**When to use:** Large lists (100+ items) where you need efficient rendering. Thin wrapper over `FlatList` with sane defaults for stable keys and optional fixed-height fast path.
|
|
1773
|
-
|
|
1774
|
-
| Prop | Type | Default | Notes |
|
|
1775
|
-
|------|------|---------|-------|
|
|
1776
|
-
| data | `T[]` | — | Array of items to render |
|
|
1777
|
-
| renderItem | `ListRenderItem<T>` | — | Render function for each item |
|
|
1778
|
-
| itemHeight | `number` | — | Fixed row height in px. Enables `getItemLayout` for performance with large datasets |
|
|
1779
|
-
| keyExtractor | `(item: T, index: number) => string` | Auto | Defaults to `item.id` or index. Override for custom keys |
|
|
1780
|
-
| ...FlatListProps | — | — | All standard FlatList props pass through |
|
|
1781
|
-
|
|
1782
|
-
**Performance optimization:** When `itemHeight` is provided, `VirtualList` enables `getItemLayout` so FlatList skips async measurement. For 10k+ rows, combine with `React.memo`-wrapped `renderItem` so only on-screen rows mount and re-render.
|
|
1783
|
-
|
|
1784
|
-
**Default key extraction:** Uses `item.id` (converted to string) or falls back to index. Override with `keyExtractor` for custom logic.
|
|
1785
|
-
|
|
1786
|
-
**Example — simple list:**
|
|
1787
|
-
```tsx
|
|
1788
|
-
<VirtualList
|
|
1789
|
-
data={items}
|
|
1790
|
-
renderItem={({ item }) => (
|
|
1791
|
-
<ListItem
|
|
1792
|
-
title={item.title}
|
|
1793
|
-
subtitle={item.subtitle}
|
|
1794
|
-
onPress={() => handlePress(item.id)}
|
|
1795
|
-
/>
|
|
1796
|
-
)}
|
|
1797
|
-
itemHeight={56}
|
|
1798
|
-
/>
|
|
1799
|
-
```
|
|
1800
|
-
|
|
1801
|
-
**Example — large dataset with memoized render:**
|
|
1802
|
-
```tsx
|
|
1803
|
-
const renderItem = useCallback(({ item }) => (
|
|
1804
|
-
<ListItem
|
|
1805
|
-
title={item.title}
|
|
1806
|
-
subtitle={item.subtitle}
|
|
1807
|
-
leftIcon="circle"
|
|
1808
|
-
showSeparator
|
|
1809
|
-
onPress={() => navigate('detail', { id: item.id })}
|
|
1810
|
-
/>
|
|
1811
|
-
), [])
|
|
1812
|
-
|
|
1813
|
-
<VirtualList
|
|
1814
|
-
data={thousands}
|
|
1815
|
-
renderItem={renderItem}
|
|
1816
|
-
itemHeight={64}
|
|
1817
|
-
/>
|
|
1818
|
-
```
|
|
1819
1827
|
|
|
1820
|
-
**Example — variable height rows (omit itemHeight):**
|
|
1821
|
-
```tsx
|
|
1822
|
-
<VirtualList
|
|
1823
|
-
data={posts}
|
|
1824
|
-
renderItem={({ item }) => (
|
|
1825
|
-
<Card style={{ margin: SPACING.sm }}>
|
|
1826
|
-
<CardContent>
|
|
1827
|
-
<Text>{item.content}</Text>
|
|
1828
|
-
</CardContent>
|
|
1829
|
-
</Card>
|
|
1830
|
-
)}
|
|
1831
|
-
/>
|
|
1832
|
-
```
|
|
1833
|
-
|
|
1834
|
-
---
|
|
1835
1828
|
|
|
1836
1829
|
### Separator
|
|
1837
1830
|
|
|
@@ -1946,7 +1939,7 @@ const renderItem = useCallback(({ item }) => (
|
|
|
1946
1939
|
// Matches <ListItem> — leading circle + title/subtitle lines
|
|
1947
1940
|
<Skeleton.ListItem /> // props: showAvatar, showSubtitle, style
|
|
1948
1941
|
|
|
1949
|
-
// Repeated list/grid placeholder — for
|
|
1942
|
+
// Repeated list/grid placeholder — for FlatList while loading.
|
|
1950
1943
|
// columns=1 → stacked ListItemSkeleton; columns>1 → grid of MediaCardSkeleton.
|
|
1951
1944
|
<Skeleton.List count={6} /> // stacked list
|
|
1952
1945
|
<Skeleton.List count={6} columns={2} /> // 2-col card grid
|
|
@@ -1954,8 +1947,8 @@ const renderItem = useCallback(({ item }) => (
|
|
|
1954
1947
|
|
|
1955
1948
|
// Also exported as named components: MediaCardSkeleton, ListItemSkeleton, ListSkeleton
|
|
1956
1949
|
|
|
1957
|
-
// As a
|
|
1958
|
-
<
|
|
1950
|
+
// As a FlatList loading state
|
|
1951
|
+
<FlatList
|
|
1959
1952
|
data={loading ? [] : rows}
|
|
1960
1953
|
renderItem={renderItem}
|
|
1961
1954
|
ListEmptyComponent={loading ? <Skeleton.List count={8} /> : <EmptyState .../>}
|
|
@@ -4425,10 +4418,12 @@ const [icon, setIcon] = useState<string | null>(null)
|
|
|
4425
4418
|
|
|
4426
4419
|
**Import:** `import { useConfirmDialog } from '@retray-dev/ui-kit'`
|
|
4427
4420
|
|
|
4428
|
-
**When to use:** Manage `ConfirmDialog` state without boilerplate. Replaces the `
|
|
4421
|
+
**When to use:** Manage `ConfirmDialog` state without boilerplate. Replaces the `visible` + `loading` state pattern that each screen would otherwise duplicate.
|
|
4422
|
+
|
|
4423
|
+
**Note (v13):** The generic `T`, `target`, and `dialogProps` convenience object were removed. Returns `onConfirm`/`onCancel` directly. Uses refs for callback stability and `mountedRef` for safe async cleanup.
|
|
4429
4424
|
|
|
4430
4425
|
```ts
|
|
4431
|
-
function useConfirmDialog
|
|
4426
|
+
function useConfirmDialog(options: UseConfirmDialogOptions): UseConfirmDialogResult
|
|
4432
4427
|
|
|
4433
4428
|
interface UseConfirmDialogOptions {
|
|
4434
4429
|
onConfirm: () => void | Promise<void>
|
|
@@ -4441,34 +4436,30 @@ interface UseConfirmDialogOptions {
|
|
|
4441
4436
|
| Field | Type | Notes |
|
|
4442
4437
|
|-------|------|-------|
|
|
4443
4438
|
| visible | `boolean` | Pass to `ConfirmDialog.visible` |
|
|
4444
|
-
| target | `T \| null` | The value passed to `open()` — e.g. the item being deleted |
|
|
4445
4439
|
| loading | `boolean` | Pass to `ConfirmDialog.loading` |
|
|
4446
|
-
| open | `(
|
|
4447
|
-
|
|
|
4440
|
+
| open | `() => void` | Call to show the dialog |
|
|
4441
|
+
| onConfirm | `() => void` | Pass directly to `ConfirmDialog.onConfirm` |
|
|
4442
|
+
| onCancel | `() => void` | Pass directly to `ConfirmDialog.onCancel` |
|
|
4448
4443
|
|
|
4449
4444
|
**Example:**
|
|
4450
4445
|
```tsx
|
|
4451
|
-
const { open,
|
|
4446
|
+
const { visible, loading, open, onConfirm, onCancel } = useConfirmDialog({
|
|
4452
4447
|
onConfirm: async () => {
|
|
4453
|
-
await deleteProduct(
|
|
4448
|
+
await deleteProduct(productId)
|
|
4454
4449
|
toast.success('Product deleted')
|
|
4455
4450
|
},
|
|
4456
4451
|
})
|
|
4457
4452
|
|
|
4458
|
-
// Somewhere in your
|
|
4459
|
-
<ListItem
|
|
4460
|
-
title={product.name}
|
|
4461
|
-
rightIcon="trash-2"
|
|
4462
|
-
onPress={() => open(product)}
|
|
4463
|
-
/>
|
|
4464
|
-
|
|
4465
|
-
// Once in your screen's JSX:
|
|
4453
|
+
// Somewhere in your screen:
|
|
4466
4454
|
<ConfirmDialog
|
|
4467
|
-
|
|
4468
|
-
|
|
4455
|
+
visible={visible}
|
|
4456
|
+
title="Delete product?"
|
|
4457
|
+
subtitle="This action cannot be undone."
|
|
4469
4458
|
confirmLabel="Delete"
|
|
4470
4459
|
confirmVariant="destructive"
|
|
4471
|
-
{
|
|
4460
|
+
loading={loading}
|
|
4461
|
+
onConfirm={onConfirm}
|
|
4462
|
+
onCancel={onCancel}
|
|
4472
4463
|
/>
|
|
4473
4464
|
```
|
|
4474
4465
|
|
|
@@ -4482,12 +4473,12 @@ The library ships a built-in icon resolver — pass any icon name string to comp
|
|
|
4482
4473
|
|
|
4483
4474
|
| Priority | Family | Best for |
|
|
4484
4475
|
|---|---|---|
|
|
4485
|
-
| 1
|
|
4476
|
+
| 1 | `Feather` | Clean line icons, UI essentials (first match wins) |
|
|
4486
4477
|
| 2 | `AntDesign` | Semantic UI icons |
|
|
4487
4478
|
| 3 | `Entypo` | Social, media, navigation icons |
|
|
4488
4479
|
| 4 | `FontAwesome5` | Wide coverage |
|
|
4489
4480
|
| 5 | `MaterialIcons` | Material-style icons |
|
|
4490
|
-
| 6
|
|
4481
|
+
| 6 | `Ionicons` | Fallback |
|
|
4491
4482
|
|
|
4492
4483
|
Browse all available icons: **https://icons.expo.fyi**
|
|
4493
4484
|
|
|
@@ -4514,29 +4505,7 @@ import { Icon } from '@retray-dev/ui-kit'
|
|
|
4514
4505
|
|
|
4515
4506
|
Returns `null` (no crash) if name not found in any family.
|
|
4516
4507
|
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
```tsx
|
|
4520
|
-
import { renderIcon } from '@retray-dev/ui-kit'
|
|
4521
|
-
|
|
4522
|
-
// Returns ReactNode or null
|
|
4523
|
-
const icon = renderIcon('check', 18, colors.primary)
|
|
4524
|
-
```
|
|
4525
|
-
|
|
4526
|
-
### `getValidIconNames` utility
|
|
4527
|
-
|
|
4528
|
-
```tsx
|
|
4529
|
-
import { getValidIconNames } from '@retray-dev/ui-kit'
|
|
4530
|
-
|
|
4531
|
-
// All icon names across all configured families
|
|
4532
|
-
const allIcons: string[] = getValidIconNames()
|
|
4533
|
-
// => ["home", "user", "heart", "star", ...]
|
|
4534
|
-
|
|
4535
|
-
// Scoped to specific families (does not mutate global config)
|
|
4536
|
-
const featherOnly: string[] = getValidIconNames(['Feather'])
|
|
4537
|
-
```
|
|
4538
|
-
|
|
4539
|
-
Returns `string[]` — all resolvable icon names from the configured families. Respects `configureIconFamilies()` global config. The optional `families` parameter builds a temporary cache scoped to those families without mutating global state. Use to build icon pickers, search, and galleries.
|
|
4508
|
+
> **v13:** `renderIcon`, `getValidIconNames`, and `configureIconFamilies` were removed. Use `Icon` component directly for all icon rendering.
|
|
4540
4509
|
|
|
4541
4510
|
### `iconName` props on components
|
|
4542
4511
|
|
|
@@ -4600,33 +4569,6 @@ getResponsiveFontSize(text, 48, [
|
|
|
4600
4569
|
|
|
4601
4570
|
---
|
|
4602
4571
|
|
|
4603
|
-
## Hover Support (Web)
|
|
4604
|
-
|
|
4605
|
-
```tsx
|
|
4606
|
-
import { useHover } from '@retray-dev/ui-kit'
|
|
4607
|
-
|
|
4608
|
-
function MyHoverableComponent() {
|
|
4609
|
-
const { hovered, hoverHandlers } = useHover()
|
|
4610
|
-
|
|
4611
|
-
return (
|
|
4612
|
-
<View
|
|
4613
|
-
{...hoverHandlers}
|
|
4614
|
-
style={[
|
|
4615
|
-
styles.container,
|
|
4616
|
-
hovered && { backgroundColor: colors.surfaceStrong }
|
|
4617
|
-
]}
|
|
4618
|
-
/>
|
|
4619
|
-
)
|
|
4620
|
-
}
|
|
4621
|
-
```
|
|
4622
|
-
|
|
4623
|
-
- **Web:** Returns `{ hovered: boolean, hoverHandlers: { onMouseEnter, onMouseLeave } }`
|
|
4624
|
-
- **Native:** Always returns `{ hovered: false, hoverHandlers: {} }` — no-op, no crashes
|
|
4625
|
-
|
|
4626
|
-
Built-in web hover: `MediaCard` (shadow lift), interactive components use this internally.
|
|
4627
|
-
|
|
4628
|
-
---
|
|
4629
|
-
|
|
4630
4572
|
## Design System Conventions
|
|
4631
4573
|
|
|
4632
4574
|
### Touch targets
|
|
@@ -4656,7 +4598,7 @@ All interactive elements maintain ≥44pt touch height per Apple HIG:
|
|
|
4656
4598
|
- `useNativeDriver` — `Platform.OS !== 'web'` everywhere (native driver disabled on web)
|
|
4657
4599
|
- `Select` — wheel modal on iOS, dialog on Android, `<select>` on web
|
|
4658
4600
|
- `Toast` — full width on mobile, 400px centered on web
|
|
4659
|
-
- Hover states — web only
|
|
4601
|
+
- Hover states — web only
|
|
4660
4602
|
- `Skeleton` shimmer highlight — adapts opacity for light/dark mode
|
|
4661
4603
|
|
|
4662
4604
|
### Dynamic Type
|
package/CONSUMER.md
CHANGED
|
@@ -32,6 +32,7 @@ npx expo install \
|
|
|
32
32
|
expo-haptics \
|
|
33
33
|
expo-linear-gradient \
|
|
34
34
|
expo-font \
|
|
35
|
+
expo-image \
|
|
35
36
|
react-native-reanimated \
|
|
36
37
|
react-native-gesture-handler \
|
|
37
38
|
react-native-worklets \
|
|
@@ -48,7 +49,7 @@ npx expo install \
|
|
|
48
49
|
pressto
|
|
49
50
|
```
|
|
50
51
|
|
|
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
|
+
> `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. `expo-image` is required for image-based components (Avatar, MediaCard, ListItem, ImageUpload, ImageViewer).
|
|
52
53
|
|
|
53
54
|
---
|
|
54
55
|
|
|
@@ -56,7 +57,6 @@ npx expo install \
|
|
|
56
57
|
|
|
57
58
|
```bash
|
|
58
59
|
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
60
|
|
|
61
61
|
# HolographicCard only — deep-import, NOT in main barrel:
|
|
62
62
|
npx expo install @shopify/react-native-skia expo-sensors
|
package/DESIGN.md
CHANGED
|
@@ -324,7 +324,7 @@ Shape language is **soft everywhere**. Buttons use `{rounded.md}` (14px) — a f
|
|
|
324
324
|
- Sohne type family. Display weights 600–700. Body weight 400. Modest weight is intentional.
|
|
325
325
|
- 8pt spacing grid with 4pt micro-steps. Section bands at `{spacing.section}` (64px).
|
|
326
326
|
- Maximum two elevation tiers — flat baseline (95% of surfaces) plus one card float tier.
|
|
327
|
-
- Haptics on every interaction via `
|
|
327
|
+
- Haptics on every interaction via `expo-haptics`.
|
|
328
328
|
- Press animations via `pressto` — main-thread, gesture-handler worklets. Color transitions via `react-native-reanimated` v4.
|
|
329
329
|
|
|
330
330
|
## Colors
|
|
@@ -602,7 +602,7 @@ All pressables: `enabled={!disabled}`, `rippleColor="transparent"`, `touchSoundD
|
|
|
602
602
|
|
|
603
603
|
## Haptic Feedback
|
|
604
604
|
|
|
605
|
-
All haptics via `src/utils/haptics.ts` — `
|
|
605
|
+
All haptics via `src/utils/haptics.ts` — `expo-haptics`.
|
|
606
606
|
|
|
607
607
|
| Function | Use |
|
|
608
608
|
|---|---|
|
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 (26 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
|
|
@@ -23,14 +23,16 @@ pnpm add @retray-dev/ui-kit
|
|
|
23
23
|
Install these in your app if not already present:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
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 expo-image-picker
|
|
26
|
+
pnpm add expo-font expo-haptics expo-linear-gradient expo-image 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 expo-image-picker
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
For Expo projects, run `npx expo install` instead to get SDK-compatible versions.
|
|
30
30
|
|
|
31
31
|
`pressto` is **required** — it powers the press animations on every interactive component. Omitting it crashes the import. `sonner-native` is **required** for `Toast`.
|
|
32
32
|
|
|
33
|
-
**
|
|
33
|
+
**Required:** `expo-image` is required for `Avatar`, `ImageUpload`, `ImageViewer`, `ListItem`, and `MediaCard` image rendering. It replaces React Native's built-in `Image` with caching, blurhash placeholders, and cross-fade transitions.
|
|
34
|
+
|
|
35
|
+
**Optional:** for `ImageUpload`, add `expo-image-picker`. For the deep-import `HolographicCard`, add `@shopify/react-native-skia expo-sensors`.
|
|
34
36
|
|
|
35
37
|
Add the Worklets Babel plugin to `babel.config.js` (required by `@gorhom/bottom-sheet`):
|
|
36
38
|
|
|
@@ -179,7 +181,8 @@ import { SPACING, ICON_SIZES, RADIUS, SHADOWS, BREAKPOINTS, TYPOGRAPHY } from '@
|
|
|
179
181
|
|
|
180
182
|
### Color Utilities
|
|
181
183
|
|
|
182
|
-
- **`withAlpha(
|
|
184
|
+
- **`withAlpha(hex: 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.
|
|
185
|
+
- **`hexToRgb(hex: string)`** — returns `{ r, g, b } | null`. Converts hex color to RGB components.
|
|
183
186
|
|
|
184
187
|
## Components
|
|
185
188
|
|
|
@@ -192,7 +195,7 @@ import { SPACING, ICON_SIZES, RADIUS, SHADOWS, BREAKPOINTS, TYPOGRAPHY } from '@
|
|
|
192
195
|
| Navigation | `AppHeader`, `TabBar`, `PagerDots` |
|
|
193
196
|
| Overlays | `Sheet`, `ConfirmDialog`, `ImageViewer` |
|
|
194
197
|
| Feedback | `Toast` / `ToastProvider` / `useToast` |
|
|
195
|
-
| Data | `ListItem`, `ListGroup` (+ `.Header` / `.Footer`), `MenuItem`, `MenuGroup` (+ `.Header` / `.Footer`), `
|
|
198
|
+
| Data | `ListItem`, `ListGroup` (+ `.Header` / `.Footer`), `MenuItem`, `MenuGroup` (+ `.Header` / `.Footer`), `Chip` / `ChipGroup`, `LabelValue`, `MonthPicker`, `CategoryStrip`, `DetailRow` |
|
|
196
199
|
| Utilities | `Pressable`, `Icon`, `RetrayProvider`, `ErrorBoundary` |
|
|
197
200
|
|
|
198
201
|
Deep-import only: `HolographicCard` — `import { HolographicCard } from '@retray-dev/ui-kit/HolographicCard'`.
|
|
@@ -226,9 +229,11 @@ toast({ title: 'Saved', variant: 'success' })
|
|
|
226
229
|
/>
|
|
227
230
|
|
|
228
231
|
// Color utilities
|
|
229
|
-
import { useTheme, withAlpha } from '@retray-dev/ui-kit'
|
|
232
|
+
import { useTheme, withAlpha, hexToRgb } from '@retray-dev/ui-kit'
|
|
230
233
|
const { colors } = useTheme()
|
|
231
234
|
;<View style={{ backgroundColor: withAlpha(colors.primary, 0.15) }} />
|
|
235
|
+
// hexToRgb — converts hex to RGB components
|
|
236
|
+
const rgb = hexToRgb('#6366f1') // { r: 99, g: 102, b: 241 }
|
|
232
237
|
```
|
|
233
238
|
|
|
234
239
|
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:
|