@retray-dev/ui-kit 9.3.1 → 10.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.
Files changed (39) hide show
  1. package/COMPONENTS.md +136 -22
  2. package/CONSUMER.md +48 -8
  3. package/FONTS.md +54 -13
  4. package/README.md +40 -3
  5. package/dist/Accordion.d.mts +1 -1
  6. package/dist/Accordion.d.ts +1 -1
  7. package/dist/Accordion.js +2 -2
  8. package/dist/Accordion.mjs +1 -1
  9. package/dist/ConfirmDialog.d.mts +6 -1
  10. package/dist/ConfirmDialog.d.ts +6 -1
  11. package/dist/ConfirmDialog.js +44 -14
  12. package/dist/ConfirmDialog.mjs +1 -1
  13. package/dist/ImageViewer.js +282 -141
  14. package/dist/ImageViewer.mjs +3 -1
  15. package/dist/Sheet.js +16 -13
  16. package/dist/Sheet.mjs +1 -1
  17. package/dist/Switch.js +40 -17
  18. package/dist/Switch.mjs +1 -1
  19. package/dist/{chunk-O3HA6TYM.mjs → chunk-DJ7RN37L.mjs} +2 -2
  20. package/dist/{chunk-FZZLPJ6B.mjs → chunk-KZL5VTYK.mjs} +43 -14
  21. package/dist/{chunk-QKH5ZOD5.mjs → chunk-WF2XDFRK.mjs} +40 -17
  22. package/dist/{chunk-Z4BVUWW6.mjs → chunk-WOEYDUJZ.mjs} +19 -31
  23. package/dist/{chunk-PFZTM6D5.mjs → chunk-Y2NS74WS.mjs} +9 -7
  24. package/dist/fonts.d.mts +39 -31
  25. package/dist/fonts.d.ts +39 -31
  26. package/dist/fonts.js +34 -39
  27. package/dist/fonts.mjs +35 -34
  28. package/dist/index.js +119 -76
  29. package/dist/index.mjs +5 -5
  30. package/package.json +3 -1
  31. package/scripts/build-apk.sh +84 -0
  32. package/scripts/copy-fonts.js +90 -0
  33. package/scripts/test-consumer-fonts.sh +82 -0
  34. package/src/components/Accordion/Accordion.tsx +7 -3
  35. package/src/components/ConfirmDialog/ConfirmDialog.tsx +61 -23
  36. package/src/components/ImageViewer/ImageViewer.tsx +25 -30
  37. package/src/components/Sheet/Sheet.tsx +10 -9
  38. package/src/components/Switch/Switch.tsx +30 -17
  39. package/src/fonts.ts +59 -40
package/COMPONENTS.md CHANGED
@@ -1,4 +1,4 @@
1
- # @retray-dev/ui-kit — Component Reference (v9.3.0)
1
+ # @retray-dev/ui-kit — Component Reference (v10.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
 
@@ -129,9 +129,49 @@ module.exports = config
129
129
 
130
130
  All components use **Sohne** as the font family. You **must** load it before rendering any UI kit component.
131
131
 
132
+ ### How it works
133
+
134
+ 1. When you install `@retray-dev/ui-kit`, the **postinstall script** automatically copies 28 `.otf` font files to `assets/fonts/sohne/` in your project root
135
+ 2. You must define `SohneFonts` with static `require()` calls in your `App.tsx` (see boilerplate below)
136
+ 3. Pass it to `expo-font`'s `useFonts()` hook at your app root
137
+ 4. All library components reference fonts by family name (e.g., `fontFamily: 'Sohne-SemiBold'`)
138
+
139
+ ### SohneFonts boilerplate — copy this into your App.tsx
140
+
132
141
  ```tsx
133
142
  import { useFonts } from 'expo-font'
134
- import { SohneFonts } from '@retray-dev/ui-kit/fonts'
143
+
144
+ // Fonts copied to assets/fonts/sohne/ by @retray-dev/ui-kit postinstall
145
+ const SohneFonts = {
146
+ 'Sohne-ExtraLight': require('./assets/fonts/sohne/Sohne-ExtraLight.otf'),
147
+ 'Sohne-ExtraLightItalic': require('./assets/fonts/sohne/Sohne-ExtraLightItalic.otf'),
148
+ 'Sohne-Light': require('./assets/fonts/sohne/Sohne-Light.otf'),
149
+ 'Sohne-LightItalic': require('./assets/fonts/sohne/Sohne-LightItalic.otf'),
150
+ 'Sohne-Regular': require('./assets/fonts/sohne/Sohne-Regular.otf'),
151
+ 'Sohne-Italic': require('./assets/fonts/sohne/Sohne-Italic.otf'),
152
+ 'Sohne-Medium': require('./assets/fonts/sohne/Sohne-Medium.otf'),
153
+ 'Sohne-MediumItalic': require('./assets/fonts/sohne/Sohne-MediumItalic.otf'),
154
+ 'Sohne-SemiBold': require('./assets/fonts/sohne/Sohne-SemiBold.otf'),
155
+ 'Sohne-SemiBoldItalic': require('./assets/fonts/sohne/Sohne-SemiBoldItalic.otf'),
156
+ 'Sohne-Bold': require('./assets/fonts/sohne/Sohne-Bold.otf'),
157
+ 'Sohne-BoldItalic': require('./assets/fonts/sohne/Sohne-BoldItalic.otf'),
158
+ 'Sohne-ExtraBold': require('./assets/fonts/sohne/Sohne-ExtraBold.otf'),
159
+ 'Sohne-ExtraBoldItalic': require('./assets/fonts/sohne/Sohne-ExtraBoldItalic.otf'),
160
+ 'SohneMono-ExtraLight': require('./assets/fonts/sohne/SohneMono-ExtraLight.otf'),
161
+ 'SohneMono-ExtraLightItalic': require('./assets/fonts/sohne/SohneMono-ExtraLightItalic.otf'),
162
+ 'SohneMono-Light': require('./assets/fonts/sohne/SohneMono-Light.otf'),
163
+ 'SohneMono-LightItalic': require('./assets/fonts/sohne/SohneMono-LightItalic.otf'),
164
+ 'SohneMono-Regular': require('./assets/fonts/sohne/SohneMono-Regular.otf'),
165
+ 'SohneMono-Italic': require('./assets/fonts/sohne/SohneMono-Italic.otf'),
166
+ 'SohneMono-Medium': require('./assets/fonts/sohne/SohneMono-Medium.otf'),
167
+ 'SohneMono-MediumItalic': require('./assets/fonts/sohne/SohneMono-MediumItalic.otf'),
168
+ 'SohneMono-SemiBold': require('./assets/fonts/sohne/SohneMono-SemiBold.otf'),
169
+ 'SohneMono-SemiBoldItalic': require('./assets/fonts/sohne/SohneMono-SemiBoldItalic.otf'),
170
+ 'SohneMono-Bold': require('./assets/fonts/sohne/SohneMono-Bold.otf'),
171
+ 'SohneMono-BoldItalic': require('./assets/fonts/sohne/SohneMono-BoldItalic.otf'),
172
+ 'SohneMono-ExtraBold': require('./assets/fonts/sohne/SohneMono-ExtraBold.otf'),
173
+ 'SohneMono-ExtraBoldItalic': require('./assets/fonts/sohne/SohneMono-ExtraBoldItalic.otf'),
174
+ }
135
175
 
136
176
  export default function App() {
137
177
  const [fontsLoaded] = useFonts(SohneFonts)
@@ -142,18 +182,22 @@ export default function App() {
142
182
  }
143
183
  ```
144
184
 
145
- **How it works:**
146
- 1. Import `SohneFonts` from `@retray-dev/ui-kit/fonts` (separate export path)
147
- 2. Pass it to `expo-font`'s `useFonts()` hook at your app root
148
- 3. Metro resolves font files from `node_modules/@retray-dev/ui-kit/src/assets/fonts/` at bundle time
149
- 4. All library components reference fonts by family name (e.g., `fontFamily: 'Sohne-SemiBold'`)
185
+ ### .gitignore recommendation
150
186
 
151
- **Included weights:**
187
+ Fonts are copied to `assets/fonts/sohne/` on install. You can either:
188
+ - **Commit them** (no network needed during CI builds)
189
+ - **Ignore them** (re-copied on every `pnpm install`)
190
+
191
+ ```gitignore
192
+ # Sohne fonts — copied by @retray-dev/ui-kit postinstall
193
+ # Either commit these or ignore them (re-copied on install)
194
+ assets/fonts/sohne/
195
+ ```
196
+
197
+ **Included weights (28 files):**
152
198
  - Sohne: `Sohne-ExtraLight`, `Sohne-Light`, `Sohne-Regular`, `Sohne-Medium`, `Sohne-SemiBold`, `Sohne-Bold`, `Sohne-ExtraBold` + italic variants
153
199
  - SohneMono: `SohneMono-ExtraLight`, `SohneMono-Light`, `SohneMono-Regular`, `SohneMono-Medium`, `SohneMono-SemiBold`, `SohneMono-Bold`, `SohneMono-ExtraBold` + italic variants
154
200
 
155
- **Total: 28 font files** exported from the package. Font `.otf` files ship as raw assets in `src/assets/fonts/` — NOT bundled into `dist/`. Metro resolves `require()` calls at build time.
156
-
157
201
  Pair with `expo-splash-screen` in production:
158
202
  ```tsx
159
203
  import * as SplashScreen from 'expo-splash-screen'
@@ -208,19 +252,19 @@ These are the only values you need to supply when customizing the theme. The lib
208
252
  | Token | Light Default | Dark Default | Semantic Role |
209
253
  |-------|--------------|--------------|---------------|
210
254
  | `background` | `#ffffff` | `#0f0f0f` | Screen / page background |
211
- | `foreground` | `#222222` | `#fafafa` | Primary text — deep near-black, not pure black |
255
+ | `foreground` | `#1a1a1a` | `#fafafa` | Primary text — deep near-black, not pure black |
212
256
  | `card` | `#ffffff` | `#1c1c1c` | Card / elevated surface background |
213
257
  | `primary` | `#1a1a1a` | `#fafafa` | Primary action (buttons, selected states, active indicators) |
214
258
  | `primaryForeground` | `#ffffff` | `#0f0f0f` | Text/icon placed on primary-colored backgrounds |
215
259
  | `border` | `#dddddd` | `#303030` | Borders, dividers, input outlines |
216
- | `destructive` | `#e53935` | `#ef5350` | Error / danger / delete actions |
260
+ | `destructive` | `#c72828` | `#ef5350` | Error / danger / delete actions |
217
261
  | `destructiveForeground` | `#ffffff` | `#ffffff` | Text/icon on destructive backgrounds |
218
262
  | `success` | `#1a7a45` | `#2e7d52` | Success / confirmation states |
219
263
  | `successForeground` | `#ffffff` | `#ffffff` | Text/icon on success backgrounds |
220
- | `warning` | `#e67e00` | `#f57c00` | Warning / caution states |
221
- | `warningForeground` | `#ffffff` | `#ffffff` | Text/icon on warning backgrounds |
264
+ | `warning` | `#9a5200` | `#f5a623` | Warning / caution states |
265
+ | `warningForeground` | `#ffffff` | `#0f0f0f` | Text/icon on warning backgrounds |
222
266
  | `overlay` *(optional)* | `rgba(0,0,0,0.45)` | `rgba(0,0,0,0.45)` | Backdrop/overlay color behind sheets and dialogs |
223
- | `accent` *(optional)* | same as `primary` | same as `primary` | Secondary brand accent (e.g. Airbnb coral). Falls back to `primary` |
267
+ | `accent` *(optional)* | `#d4561d` | `#e87645` | Secondary brand accent (e.g. Airbnb coral). Falls back to `primary` |
224
268
  | `accentForeground` *(optional)* | same as `primaryForeground` | same as `primaryForeground` | Text/icon on accent backgrounds. Falls back to `primaryForeground` |
225
269
 
226
270
  ### Derived Tokens (ResolvedColors) — read-only via useTheme().colors
@@ -229,8 +273,8 @@ The full palette components consume. Never supply these directly — they are co
229
273
 
230
274
  | Token | Derived From | Purpose |
231
275
  |-------|-------------|---------|
232
- | `foregroundSubtle` | `foreground` @ ~55% | Body text, subtitles, secondary content |
233
- | `foregroundMuted` | `foreground` @ ~38% | Captions, timestamps, placeholders |
276
+ | `foregroundSubtle` | `foreground` @ ~70% | Body text, subtitles, secondary content |
277
+ | `foregroundMuted` | `foreground` @ ~62% | Captions, timestamps, placeholders |
234
278
  | `surface` | `background` slightly off-canvas | Chip backgrounds, input fills, tag backgrounds, skeleton |
235
279
  | `surfaceStrong` | `background` stronger offset | Pressed/hover fill states |
236
280
  | `destructiveTint` | `destructive` blended to bg | Alert banner background, toast background |
@@ -572,6 +616,74 @@ import { SohneFonts } from '@retray-dev/ui-kit/fonts'
572
616
 
573
617
  ---
574
618
 
619
+ ## Migration Guide: v9 → v10
620
+
621
+ ### Breaking Changes
622
+
623
+ **1. `SohneFonts` export removed from `@retray-dev/ui-kit/fonts`**
624
+
625
+ The `SohneFonts` object with `require()` calls is no longer exported. Metro cannot reliably resolve `require()` from inside `node_modules`, especially in monorepos. The export now returns `undefined` and logs a deprecation warning.
626
+
627
+ **New approach — postinstall script:**
628
+ 1. When you install `@retray-dev/ui-kit`, a **postinstall script** automatically copies 28 `.otf` font files to `assets/fonts/sohne/` in your project root
629
+ 2. Define `SohneFonts` locally in your `App.tsx` with static `require()` calls (see below)
630
+ 3. Pass it to `expo-font`'s `useFonts()` hook
631
+
632
+ **Migration:**
633
+
634
+ ```diff
635
+ // App.tsx
636
+ import { useFonts } from 'expo-font'
637
+ -import { SohneFonts } from '@retray-dev/ui-kit/fonts'
638
+
639
+ +// Fonts copied to assets/fonts/sohne/ by @retray-dev/ui-kit postinstall
640
+ +const SohneFonts = {
641
+ + 'Sohne-ExtraLight': require('./assets/fonts/sohne/Sohne-ExtraLight.otf'),
642
+ + 'Sohne-ExtraLightItalic': require('./assets/fonts/sohne/Sohne-ExtraLightItalic.otf'),
643
+ + 'Sohne-Light': require('./assets/fonts/sohne/Sohne-Light.otf'),
644
+ + 'Sohne-LightItalic': require('./assets/fonts/sohne/Sohne-LightItalic.otf'),
645
+ + 'Sohne-Regular': require('./assets/fonts/sohne/Sohne-Regular.otf'),
646
+ + 'Sohne-Italic': require('./assets/fonts/sohne/Sohne-Italic.otf'),
647
+ + 'Sohne-Medium': require('./assets/fonts/sohne/Sohne-Medium.otf'),
648
+ + 'Sohne-MediumItalic': require('./assets/fonts/sohne/Sohne-MediumItalic.otf'),
649
+ + 'Sohne-SemiBold': require('./assets/fonts/sohne/Sohne-SemiBold.otf'),
650
+ + 'Sohne-SemiBoldItalic': require('./assets/fonts/sohne/Sohne-SemiBoldItalic.otf'),
651
+ + 'Sohne-Bold': require('./assets/fonts/sohne/Sohne-Bold.otf'),
652
+ + 'Sohne-BoldItalic': require('./assets/fonts/sohne/Sohne-BoldItalic.otf'),
653
+ + 'Sohne-ExtraBold': require('./assets/fonts/sohne/Sohne-ExtraBold.otf'),
654
+ + 'Sohne-ExtraBoldItalic': require('./assets/fonts/sohne/Sohne-ExtraBoldItalic.otf'),
655
+ + 'SohneMono-ExtraLight': require('./assets/fonts/sohne/SohneMono-ExtraLight.otf'),
656
+ + 'SohneMono-ExtraLightItalic': require('./assets/fonts/sohne/SohneMono-ExtraLightItalic.otf'),
657
+ + 'SohneMono-Light': require('./assets/fonts/sohne/SohneMono-Light.otf'),
658
+ + 'SohneMono-LightItalic': require('./assets/fonts/sohne/SohneMono-LightItalic.otf'),
659
+ + 'SohneMono-Regular': require('./assets/fonts/sohne/SohneMono-Regular.otf'),
660
+ + 'SohneMono-Italic': require('./assets/fonts/sohne/SohneMono-Italic.otf'),
661
+ + 'SohneMono-Medium': require('./assets/fonts/sohne/SohneMono-Medium.otf'),
662
+ + 'SohneMono-MediumItalic': require('./assets/fonts/sohne/SohneMono-MediumItalic.otf'),
663
+ + 'SohneMono-SemiBold': require('./assets/fonts/sohne/SohneMono-SemiBold.otf'),
664
+ + 'SohneMono-SemiBoldItalic': require('./assets/fonts/sohne/SohneMono-SemiBoldItalic.otf'),
665
+ + 'SohneMono-Bold': require('./assets/fonts/sohne/SohneMono-Bold.otf'),
666
+ + 'SohneMono-BoldItalic': require('./assets/fonts/sohne/SohneMono-BoldItalic.otf'),
667
+ + 'SohneMono-ExtraBold': require('./assets/fonts/sohne/SohneMono-ExtraBold.otf'),
668
+ + 'SohneMono-ExtraBoldItalic': require('./assets/fonts/sohne/SohneMono-ExtraBoldItalic.otf'),
669
+ +}
670
+
671
+ export default function App() {
672
+ const [fontsLoaded] = useFonts(SohneFonts)
673
+ // ...
674
+ }
675
+ ```
676
+
677
+ **.gitignore recommendation:**
678
+ ```gitignore
679
+ # Sohne fonts — copied by @retray-dev/ui-kit postinstall
680
+ assets/fonts/sohne/
681
+ ```
682
+
683
+ **Why this change:** Metro bundler requires `require()` calls to originate from the consumer's source tree, not from `node_modules`. The previous approach worked in simple setups but failed in monorepos and symlinked workspaces.
684
+
685
+ ---
686
+
575
687
  ## Components
576
688
 
577
689
  ---
@@ -1814,7 +1926,7 @@ const [accepted, setAccepted] = useState(false)
1814
1926
 
1815
1927
  **Dimensions:** Track 52×30px (pill), Thumb 24×24px with 3px offset.
1816
1928
 
1817
- **Animation:** Thumb translates via spring; track color transitions via opacity (150ms).
1929
+ **Animation:** Thumb translates via spring (`SPRINGS.elastic`); track color and border animate via `EaseView` `COLOR_TRANSITION`; icons crossfade via `OPACITY_TRANSITION`. All declarative — UI thread.
1818
1930
 
1819
1931
  **Haptics:** `selectionAsync` on toggle.
1820
1932
 
@@ -2165,7 +2277,7 @@ const [tab, setTab] = useState('profile')
2165
2277
  ```ts
2166
2278
  {
2167
2279
  value: string
2168
- trigger: string
2280
+ trigger: string | ReactNode
2169
2281
  content: ReactNode
2170
2282
  iconName?: string // Icon name from @expo/vector-icons
2171
2283
  icon?: ReactNode // Custom icon node
@@ -2173,7 +2285,7 @@ const [tab, setTab] = useState('profile')
2173
2285
  }
2174
2286
  ```
2175
2287
 
2176
- **Animation:** `react-native-reanimated` `withTiming` (220ms) for height and chevron rotation (180°). Press scale uses `withSpring`. Runs on UI thread at 60fps.
2288
+ **Animation:** `react-native-reanimated` `withTiming` (240ms expand / 200ms collapse) for height and chevron rotation (180°). Runs on UI thread at 60fps.
2177
2289
 
2178
2290
  **Haptics:** `selectionAsync` on toggle.
2179
2291
 
@@ -2581,11 +2693,13 @@ dismiss(id)
2581
2693
  |------|------|---------|-------|
2582
2694
  | visible | `boolean` | required | Controls dialog visibility |
2583
2695
  | title | `string` | required | Dialog heading |
2584
- | description | `string` | — | Supporting text describe what exactly will happen |
2696
+ | subtitle | `string` | — | Secondary text below title |
2697
+ | description | `string` | — | **Deprecated** — use `subtitle` instead |
2585
2698
  | confirmLabel | `string` | `'Confirm'` | Confirm button text |
2586
2699
  | cancelLabel | `string` | `'Cancel'` | Cancel button text |
2587
2700
  | confirmVariant | `'primary' \| 'destructive'` | `'primary'` | Use `'destructive'` for delete/remove actions |
2588
2701
  | loading | `boolean` | `false` | Show spinner in confirm button and disable it (for async `onConfirm`) |
2702
+ | showCloseButton | `boolean` | `false` | Show an X close button in the top-right corner |
2589
2703
  | onConfirm | `() => void` | required | Called when confirm is tapped |
2590
2704
  | onCancel | `() => void` | required | Called when cancel is tapped or backdrop pressed |
2591
2705
 
@@ -3654,7 +3768,7 @@ export default function TabLayout() {
3654
3768
  | onClose | `() => void` | required | — |
3655
3769
  | initialIndex | `number` | `0` | Page to open on |
3656
3770
 
3657
- **Behavior:** pinch to zoom (max 3×), double-tap to toggle 2.5× zoom, pan while zoomed. Paging locks automatically while a page is zoomed in. `PagerDots` shown when there is more than one image.
3771
+ **Behavior:** pinch to zoom (max 3×), double-tap to toggle 2.5× zoom, pan while zoomed. Paging locks automatically while a page is zoomed in. Swipe down to dismiss (drag down or fling; backdrop fades proportionally). `PagerDots` shown when there is more than one image.
3658
3772
 
3659
3773
  **Example:**
3660
3774
  ```tsx
package/CONSUMER.md CHANGED
@@ -1,4 +1,4 @@
1
- # @retray-dev/ui-kit — Consumer Setup Guide (v9.2.0)
1
+ # @retray-dev/ui-kit — Consumer Setup Guide (v10.1.0)
2
2
 
3
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
4
  > ```markdown
@@ -119,9 +119,40 @@ module.exports = config
119
119
 
120
120
  ```tsx
121
121
  import { useFonts } from 'expo-font'
122
- import { SohneFonts } from '@retray-dev/ui-kit/fonts'
123
122
  import { RetrayProvider } from '@retray-dev/ui-kit'
124
123
 
124
+ // Fonts copied to assets/fonts/sohne/ by @retray-dev/ui-kit postinstall
125
+ const SohneFonts = {
126
+ 'Sohne-ExtraLight': require('./assets/fonts/sohne/Sohne-ExtraLight.otf'),
127
+ 'Sohne-ExtraLightItalic': require('./assets/fonts/sohne/Sohne-ExtraLightItalic.otf'),
128
+ 'Sohne-Light': require('./assets/fonts/sohne/Sohne-Light.otf'),
129
+ 'Sohne-LightItalic': require('./assets/fonts/sohne/Sohne-LightItalic.otf'),
130
+ 'Sohne-Regular': require('./assets/fonts/sohne/Sohne-Regular.otf'),
131
+ 'Sohne-Italic': require('./assets/fonts/sohne/Sohne-Italic.otf'),
132
+ 'Sohne-Medium': require('./assets/fonts/sohne/Sohne-Medium.otf'),
133
+ 'Sohne-MediumItalic': require('./assets/fonts/sohne/Sohne-MediumItalic.otf'),
134
+ 'Sohne-SemiBold': require('./assets/fonts/sohne/Sohne-SemiBold.otf'),
135
+ 'Sohne-SemiBoldItalic': require('./assets/fonts/sohne/Sohne-SemiBoldItalic.otf'),
136
+ 'Sohne-Bold': require('./assets/fonts/sohne/Sohne-Bold.otf'),
137
+ 'Sohne-BoldItalic': require('./assets/fonts/sohne/Sohne-BoldItalic.otf'),
138
+ 'Sohne-ExtraBold': require('./assets/fonts/sohne/Sohne-ExtraBold.otf'),
139
+ 'Sohne-ExtraBoldItalic': require('./assets/fonts/sohne/Sohne-ExtraBoldItalic.otf'),
140
+ 'SohneMono-ExtraLight': require('./assets/fonts/sohne/SohneMono-ExtraLight.otf'),
141
+ 'SohneMono-ExtraLightItalic': require('./assets/fonts/sohne/SohneMono-ExtraLightItalic.otf'),
142
+ 'SohneMono-Light': require('./assets/fonts/sohne/SohneMono-Light.otf'),
143
+ 'SohneMono-LightItalic': require('./assets/fonts/sohne/SohneMono-LightItalic.otf'),
144
+ 'SohneMono-Regular': require('./assets/fonts/sohne/SohneMono-Regular.otf'),
145
+ 'SohneMono-Italic': require('./assets/fonts/sohne/SohneMono-Italic.otf'),
146
+ 'SohneMono-Medium': require('./assets/fonts/sohne/SohneMono-Medium.otf'),
147
+ 'SohneMono-MediumItalic': require('./assets/fonts/sohne/SohneMono-MediumItalic.otf'),
148
+ 'SohneMono-SemiBold': require('./assets/fonts/sohne/SohneMono-SemiBold.otf'),
149
+ 'SohneMono-SemiBoldItalic': require('./assets/fonts/sohne/SohneMono-SemiBoldItalic.otf'),
150
+ 'SohneMono-Bold': require('./assets/fonts/sohne/SohneMono-Bold.otf'),
151
+ 'SohneMono-BoldItalic': require('./assets/fonts/sohne/SohneMono-BoldItalic.otf'),
152
+ 'SohneMono-ExtraBold': require('./assets/fonts/sohne/SohneMono-ExtraBold.otf'),
153
+ 'SohneMono-ExtraBoldItalic': require('./assets/fonts/sohne/SohneMono-ExtraBoldItalic.otf'),
154
+ }
155
+
125
156
  export default function App() {
126
157
  const [fontsLoaded] = useFonts(SohneFonts)
127
158
  if (!fontsLoaded) return null
@@ -234,14 +265,23 @@ npx expo install @shopify/react-native-skia expo-sensors
234
265
 
235
266
  ## Fonts
236
267
 
237
- All components use the **Sohne** font family. Load fonts before rendering any component:
268
+ All components use the **Sohne** font family.
238
269
 
239
- ```tsx
240
- import { useFonts } from 'expo-font'
241
- import { SohneFonts } from '@retray-dev/ui-kit/fonts'
270
+ ### How it works
271
+
272
+ 1. When you install `@retray-dev/ui-kit`, the **postinstall script** copies 28 `.otf` font files to `assets/fonts/sohne/` in your project
273
+ 2. You define `SohneFonts` with static `require()` calls in your `App.tsx` (see Provider Setup above for the full boilerplate)
274
+ 3. Metro resolves fonts from your project's `assets/` folder at bundle time
275
+
276
+ ### .gitignore recommendation
277
+
278
+ Fonts are copied to `assets/fonts/sohne/` on install. You can either:
279
+ - **Commit them** — no network needed during CI builds
280
+ - **Ignore them** — re-copied on every `pnpm install`
242
281
 
243
- const [fontsLoaded] = useFonts(SohneFonts)
244
- if (!fontsLoaded) return null
282
+ ```gitignore
283
+ # Sohne fonts — copied by @retray-dev/ui-kit postinstall
284
+ assets/fonts/sohne/
245
285
  ```
246
286
 
247
287
  See `FONTS.md` for the full font inventory and weight reference.
package/FONTS.md CHANGED
@@ -4,13 +4,51 @@
4
4
 
5
5
  All components in `@retray-dev/ui-kit` use the **Sohne** font family. Consumer apps must load these fonts at the app root using `expo-font`.
6
6
 
7
- ### Installation
7
+ ### How It Works
8
+
9
+ 1. When you install `@retray-dev/ui-kit`, the **postinstall script** automatically copies 28 `.otf` font files to `assets/fonts/sohne/` in your project root
10
+ 2. You must define `SohneFonts` with static `require()` calls in your `App.tsx` (see boilerplate below)
11
+ 3. Pass it to `expo-font`'s `useFonts()` hook at your app root
12
+ 4. All library components reference fonts by family name (e.g., `fontFamily: 'Sohne-SemiBold'`)
8
13
 
9
- The library includes Sohne font files as raw `.otf` assets. Import and load them:
14
+ ### SohneFonts Boilerplate
15
+
16
+ Copy this into your `App.tsx`:
10
17
 
11
18
  ```tsx
12
19
  import { useFonts } from 'expo-font'
13
- import { SohneFonts } from '@retray-dev/ui-kit/fonts'
20
+
21
+ // Fonts copied to assets/fonts/sohne/ by @retray-dev/ui-kit postinstall
22
+ const SohneFonts = {
23
+ 'Sohne-ExtraLight': require('./assets/fonts/sohne/Sohne-ExtraLight.otf'),
24
+ 'Sohne-ExtraLightItalic': require('./assets/fonts/sohne/Sohne-ExtraLightItalic.otf'),
25
+ 'Sohne-Light': require('./assets/fonts/sohne/Sohne-Light.otf'),
26
+ 'Sohne-LightItalic': require('./assets/fonts/sohne/Sohne-LightItalic.otf'),
27
+ 'Sohne-Regular': require('./assets/fonts/sohne/Sohne-Regular.otf'),
28
+ 'Sohne-Italic': require('./assets/fonts/sohne/Sohne-Italic.otf'),
29
+ 'Sohne-Medium': require('./assets/fonts/sohne/Sohne-Medium.otf'),
30
+ 'Sohne-MediumItalic': require('./assets/fonts/sohne/Sohne-MediumItalic.otf'),
31
+ 'Sohne-SemiBold': require('./assets/fonts/sohne/Sohne-SemiBold.otf'),
32
+ 'Sohne-SemiBoldItalic': require('./assets/fonts/sohne/Sohne-SemiBoldItalic.otf'),
33
+ 'Sohne-Bold': require('./assets/fonts/sohne/Sohne-Bold.otf'),
34
+ 'Sohne-BoldItalic': require('./assets/fonts/sohne/Sohne-BoldItalic.otf'),
35
+ 'Sohne-ExtraBold': require('./assets/fonts/sohne/Sohne-ExtraBold.otf'),
36
+ 'Sohne-ExtraBoldItalic': require('./assets/fonts/sohne/Sohne-ExtraBoldItalic.otf'),
37
+ 'SohneMono-ExtraLight': require('./assets/fonts/sohne/SohneMono-ExtraLight.otf'),
38
+ 'SohneMono-ExtraLightItalic': require('./assets/fonts/sohne/SohneMono-ExtraLightItalic.otf'),
39
+ 'SohneMono-Light': require('./assets/fonts/sohne/SohneMono-Light.otf'),
40
+ 'SohneMono-LightItalic': require('./assets/fonts/sohne/SohneMono-LightItalic.otf'),
41
+ 'SohneMono-Regular': require('./assets/fonts/sohne/SohneMono-Regular.otf'),
42
+ 'SohneMono-Italic': require('./assets/fonts/sohne/SohneMono-Italic.otf'),
43
+ 'SohneMono-Medium': require('./assets/fonts/sohne/SohneMono-Medium.otf'),
44
+ 'SohneMono-MediumItalic': require('./assets/fonts/sohne/SohneMono-MediumItalic.otf'),
45
+ 'SohneMono-SemiBold': require('./assets/fonts/sohne/SohneMono-SemiBold.otf'),
46
+ 'SohneMono-SemiBoldItalic': require('./assets/fonts/sohne/SohneMono-SemiBoldItalic.otf'),
47
+ 'SohneMono-Bold': require('./assets/fonts/sohne/SohneMono-Bold.otf'),
48
+ 'SohneMono-BoldItalic': require('./assets/fonts/sohne/SohneMono-BoldItalic.otf'),
49
+ 'SohneMono-ExtraBold': require('./assets/fonts/sohne/SohneMono-ExtraBold.otf'),
50
+ 'SohneMono-ExtraBoldItalic': require('./assets/fonts/sohne/SohneMono-ExtraBoldItalic.otf'),
51
+ }
14
52
 
15
53
  export default function App() {
16
54
  const [fontsLoaded] = useFonts(SohneFonts)
@@ -32,12 +70,11 @@ export default function App() {
32
70
  ```tsx
33
71
  import * as SplashScreen from 'expo-splash-screen'
34
72
  import { useFonts } from 'expo-font'
35
- import { SohneFonts } from '@retray-dev/ui-kit/fonts'
36
73
 
37
74
  SplashScreen.preventAutoHideAsync()
38
75
 
39
76
  export default function App() {
40
- const [fontsLoaded] = useFonts(SohneFonts)
77
+ const [fontsLoaded] = useFonts(SohneFonts) // Use the SohneFonts object above
41
78
 
42
79
  useEffect(() => {
43
80
  if (fontsLoaded) {
@@ -57,9 +94,20 @@ export default function App() {
57
94
  }
58
95
  ```
59
96
 
97
+ ### .gitignore Recommendation
98
+
99
+ Fonts are copied to `assets/fonts/sohne/` on install. You can either:
100
+ - **Commit them** — no network needed during CI builds
101
+ - **Ignore them** — re-copied on every `pnpm install`
102
+
103
+ ```gitignore
104
+ # Sohne fonts — copied by @retray-dev/ui-kit postinstall
105
+ assets/fonts/sohne/
106
+ ```
107
+
60
108
  ### Font Weights Included
61
109
 
62
- `SohneFonts` exports 28 `.otf` files total.
110
+ `SohneFonts` includes 28 `.otf` files total.
63
111
 
64
112
  **Sohne (14 files):**
65
113
  - `Sohne-ExtraLight`
@@ -93,13 +141,6 @@ export default function App() {
93
141
  - `SohneMono-ExtraBold`
94
142
  - `SohneMono-ExtraBoldItalic`
95
143
 
96
- ### How It Works
97
-
98
- 1. **Library components** reference fonts by family name (e.g., `fontFamily: 'Sohne-SemiBold'`)
99
- 2. **Consumer app** loads font files at startup via `useFonts(SohneFonts)`
100
- 3. **Metro bundler** resolves `require()` calls to `.otf` files in `node_modules/@retray-dev/ui-kit/src/assets/fonts/`
101
- 4. **React Native** maps family names to loaded font files
102
-
103
144
  Font files ship as raw assets — **not bundled into `dist/`**. Metro handles asset resolution natively.
104
145
 
105
146
  ### Peer Dependency
package/README.md CHANGED
@@ -46,11 +46,44 @@ module.exports = function (api) {
46
46
 
47
47
  ## Typography
48
48
 
49
- All components use **Sohne** font family. You must load the fonts at app root before rendering any component:
49
+ All components use **Sohne** font family. You must load the fonts at app root before rendering any component.
50
+
51
+ When you install `@retray-dev/ui-kit`, a **postinstall script** automatically copies 28 `.otf` font files to `assets/fonts/sohne/` in your project. Then define `SohneFonts` locally in your `App.tsx`:
50
52
 
51
53
  ```tsx
52
54
  import { useFonts } from 'expo-font'
53
- import { SohneFonts } from '@retray-dev/ui-kit/fonts'
55
+
56
+ // Fonts copied to assets/fonts/sohne/ by @retray-dev/ui-kit postinstall
57
+ const SohneFonts = {
58
+ 'Sohne-ExtraLight': require('./assets/fonts/sohne/Sohne-ExtraLight.otf'),
59
+ 'Sohne-ExtraLightItalic': require('./assets/fonts/sohne/Sohne-ExtraLightItalic.otf'),
60
+ 'Sohne-Light': require('./assets/fonts/sohne/Sohne-Light.otf'),
61
+ 'Sohne-LightItalic': require('./assets/fonts/sohne/Sohne-LightItalic.otf'),
62
+ 'Sohne-Regular': require('./assets/fonts/sohne/Sohne-Regular.otf'),
63
+ 'Sohne-Italic': require('./assets/fonts/sohne/Sohne-Italic.otf'),
64
+ 'Sohne-Medium': require('./assets/fonts/sohne/Sohne-Medium.otf'),
65
+ 'Sohne-MediumItalic': require('./assets/fonts/sohne/Sohne-MediumItalic.otf'),
66
+ 'Sohne-SemiBold': require('./assets/fonts/sohne/Sohne-SemiBold.otf'),
67
+ 'Sohne-SemiBoldItalic': require('./assets/fonts/sohne/Sohne-SemiBoldItalic.otf'),
68
+ 'Sohne-Bold': require('./assets/fonts/sohne/Sohne-Bold.otf'),
69
+ 'Sohne-BoldItalic': require('./assets/fonts/sohne/Sohne-BoldItalic.otf'),
70
+ 'Sohne-ExtraBold': require('./assets/fonts/sohne/Sohne-ExtraBold.otf'),
71
+ 'Sohne-ExtraBoldItalic': require('./assets/fonts/sohne/Sohne-ExtraBoldItalic.otf'),
72
+ 'SohneMono-ExtraLight': require('./assets/fonts/sohne/SohneMono-ExtraLight.otf'),
73
+ 'SohneMono-ExtraLightItalic': require('./assets/fonts/sohne/SohneMono-ExtraLightItalic.otf'),
74
+ 'SohneMono-Light': require('./assets/fonts/sohne/SohneMono-Light.otf'),
75
+ 'SohneMono-LightItalic': require('./assets/fonts/sohne/SohneMono-LightItalic.otf'),
76
+ 'SohneMono-Regular': require('./assets/fonts/sohne/SohneMono-Regular.otf'),
77
+ 'SohneMono-Italic': require('./assets/fonts/sohne/SohneMono-Italic.otf'),
78
+ 'SohneMono-Medium': require('./assets/fonts/sohne/SohneMono-Medium.otf'),
79
+ 'SohneMono-MediumItalic': require('./assets/fonts/sohne/SohneMono-MediumItalic.otf'),
80
+ 'SohneMono-SemiBold': require('./assets/fonts/sohne/SohneMono-SemiBold.otf'),
81
+ 'SohneMono-SemiBoldItalic': require('./assets/fonts/sohne/SohneMono-SemiBoldItalic.otf'),
82
+ 'SohneMono-Bold': require('./assets/fonts/sohne/SohneMono-Bold.otf'),
83
+ 'SohneMono-BoldItalic': require('./assets/fonts/sohne/SohneMono-BoldItalic.otf'),
84
+ 'SohneMono-ExtraBold': require('./assets/fonts/sohne/SohneMono-ExtraBold.otf'),
85
+ 'SohneMono-ExtraBoldItalic': require('./assets/fonts/sohne/SohneMono-ExtraBoldItalic.otf'),
86
+ }
54
87
 
55
88
  export default function App() {
56
89
  const [fontsLoaded] = useFonts(SohneFonts)
@@ -62,7 +95,11 @@ export default function App() {
62
95
  }
63
96
  ```
64
97
 
65
- The library ships 28 font files (14 Sohne base + 14 SohneMono, each with 7 weights + italic variants) as raw `.otf` files. Metro resolves them at bundle time.
98
+ **.gitignore recommendation:**
99
+ ```gitignore
100
+ # Sohne fonts — copied by @retray-dev/ui-kit postinstall
101
+ assets/fonts/sohne/
102
+ ```
66
103
 
67
104
  ## Setup
68
105
 
@@ -3,7 +3,7 @@ import { ViewStyle } from 'react-native';
3
3
 
4
4
  interface AccordionItem {
5
5
  value: string;
6
- trigger: string;
6
+ trigger: string | React.ReactNode;
7
7
  content: React.ReactNode;
8
8
  /** Icon name from @expo/vector-icons rendered left of trigger. */
9
9
  iconName?: string;
@@ -3,7 +3,7 @@ import { ViewStyle } from 'react-native';
3
3
 
4
4
  interface AccordionItem {
5
5
  value: string;
6
- trigger: string;
6
+ trigger: string | React.ReactNode;
7
7
  content: React.ReactNode;
8
8
  /** Icon name from @expo/vector-icons rendered left of trigger. */
9
9
  iconName?: string;
package/dist/Accordion.js CHANGED
@@ -302,9 +302,9 @@ function AccordionItemComponent({
302
302
  },
303
303
  accessibilityRole: "button",
304
304
  accessibilityState: { expanded: isOpen },
305
- accessibilityLabel: item.trigger
305
+ accessibilityLabel: typeof item.trigger === "string" ? item.trigger : void 0
306
306
  },
307
- /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.triggerContent }, resolvedIcon ? /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.icon }, resolvedIcon) : null, /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger)),
307
+ /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.triggerContent }, resolvedIcon ? /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.icon }, resolvedIcon) : null, typeof item.trigger === "string" ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.triggerText, { color: colors.foreground }], allowFontScaling: true }, item.trigger) : item.trigger),
308
308
  /* @__PURE__ */ React3__default.default.createElement(Animated__default.default.View, { style: [styles.chevron, rotationStyle] }, /* @__PURE__ */ React3__default.default.createElement(vectorIcons.Entypo, { name: "chevron-down", size: 18, color: colors.foregroundMuted }))
309
309
  ), /* @__PURE__ */ React3__default.default.createElement(Animated__default.default.View, { style: bodyStyle }, /* @__PURE__ */ React3__default.default.createElement(
310
310
  reactNative.View,
@@ -1,4 +1,4 @@
1
- export { Accordion } from './chunk-O3HA6TYM.mjs';
1
+ export { Accordion } from './chunk-DJ7RN37L.mjs';
2
2
  import './chunk-EJ7ZPXOH.mjs';
3
3
  import './chunk-DVK4G2GT.mjs';
4
4
  import './chunk-T7XZ7H7Y.mjs';
@@ -3,15 +3,20 @@ import React from 'react';
3
3
  interface ConfirmDialogProps {
4
4
  visible: boolean;
5
5
  title: string;
6
+ /** Secondary text below title. */
7
+ subtitle?: string;
8
+ /** @deprecated Use `subtitle` instead. */
6
9
  description?: string;
7
10
  confirmLabel?: string;
8
11
  cancelLabel?: string;
9
12
  confirmVariant?: 'primary' | 'destructive';
10
13
  /** Show a loading spinner in the confirm button (e.g. while async action completes). */
11
14
  loading?: boolean;
15
+ /** Show an X close button in the top-right corner. */
16
+ showCloseButton?: boolean;
12
17
  onConfirm: () => void;
13
18
  onCancel: () => void;
14
19
  }
15
- declare function ConfirmDialog({ visible, title, description, confirmLabel, cancelLabel, confirmVariant, loading, onConfirm, onCancel, }: ConfirmDialogProps): React.JSX.Element;
20
+ declare function ConfirmDialog({ visible, title, subtitle, description, confirmLabel, cancelLabel, confirmVariant, loading, showCloseButton, onConfirm, onCancel, }: ConfirmDialogProps): React.JSX.Element;
16
21
 
17
22
  export { ConfirmDialog, type ConfirmDialogProps };
@@ -3,15 +3,20 @@ import React from 'react';
3
3
  interface ConfirmDialogProps {
4
4
  visible: boolean;
5
5
  title: string;
6
+ /** Secondary text below title. */
7
+ subtitle?: string;
8
+ /** @deprecated Use `subtitle` instead. */
6
9
  description?: string;
7
10
  confirmLabel?: string;
8
11
  cancelLabel?: string;
9
12
  confirmVariant?: 'primary' | 'destructive';
10
13
  /** Show a loading spinner in the confirm button (e.g. while async action completes). */
11
14
  loading?: boolean;
15
+ /** Show an X close button in the top-right corner. */
16
+ showCloseButton?: boolean;
12
17
  onConfirm: () => void;
13
18
  onCancel: () => void;
14
19
  }
15
- declare function ConfirmDialog({ visible, title, description, confirmLabel, cancelLabel, confirmVariant, loading, onConfirm, onCancel, }: ConfirmDialogProps): React.JSX.Element;
20
+ declare function ConfirmDialog({ visible, title, subtitle, description, confirmLabel, cancelLabel, confirmVariant, loading, showCloseButton, onConfirm, onCancel, }: ConfirmDialogProps): React.JSX.Element;
16
21
 
17
22
  export { ConfirmDialog, type ConfirmDialogProps };