@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.
Files changed (268) hide show
  1. package/COMPONENTS.md +85 -143
  2. package/CONSUMER.md +2 -2
  3. package/DESIGN.md +2 -2
  4. package/README.md +11 -6
  5. package/dist/Accordion.js +48 -210
  6. package/dist/Accordion.mjs +6 -5
  7. package/dist/AlertBanner.js +29 -153
  8. package/dist/AlertBanner.mjs +3 -3
  9. package/dist/AppHeader.js +37 -235
  10. package/dist/AppHeader.mjs +6 -7
  11. package/dist/Avatar.d.mts +17 -1
  12. package/dist/Avatar.d.ts +17 -1
  13. package/dist/Avatar.js +80 -115
  14. package/dist/Avatar.mjs +2 -2
  15. package/dist/Badge.js +24 -149
  16. package/dist/Badge.mjs +3 -3
  17. package/dist/Button.js +79 -267
  18. package/dist/Button.mjs +6 -6
  19. package/dist/Card.js +15 -200
  20. package/dist/Card.mjs +4 -5
  21. package/dist/CategoryStrip.d.mts +0 -5
  22. package/dist/CategoryStrip.d.ts +0 -5
  23. package/dist/CategoryStrip.js +47 -265
  24. package/dist/CategoryStrip.mjs +6 -6
  25. package/dist/Checkbox.js +15 -200
  26. package/dist/Checkbox.mjs +5 -5
  27. package/dist/Chip.js +44 -236
  28. package/dist/Chip.mjs +7 -6
  29. package/dist/ConfirmDialog.js +84 -286
  30. package/dist/ConfirmDialog.mjs +7 -7
  31. package/dist/CurrencyDisplay.js +1 -114
  32. package/dist/CurrencyDisplay.mjs +2 -2
  33. package/dist/CurrencyInput.js +35 -162
  34. package/dist/CurrencyInput.mjs +5 -5
  35. package/dist/DetailRow.js +25 -150
  36. package/dist/DetailRow.mjs +3 -3
  37. package/dist/EmptyState.js +80 -268
  38. package/dist/EmptyState.mjs +7 -7
  39. package/dist/ErrorBoundary.js +32 -199
  40. package/dist/ErrorBoundary.mjs +4 -4
  41. package/dist/Form.js +1 -114
  42. package/dist/Form.mjs +2 -2
  43. package/dist/HolographicCard.d.mts +0 -28
  44. package/dist/HolographicCard.d.ts +0 -28
  45. package/dist/HolographicCard.js +20 -130
  46. package/dist/HolographicCard.mjs +9 -32
  47. package/dist/IconButton.js +36 -234
  48. package/dist/IconButton.mjs +5 -6
  49. package/dist/IconPicker.js +222 -929
  50. package/dist/IconPicker.mjs +5 -5
  51. package/dist/ImageUpload.d.mts +3 -1
  52. package/dist/ImageUpload.d.ts +3 -1
  53. package/dist/ImageUpload.js +25 -215
  54. package/dist/ImageUpload.mjs +5 -6
  55. package/dist/ImageViewer.js +75 -266
  56. package/dist/ImageViewer.mjs +8 -8
  57. package/dist/Input.d.mts +1 -1
  58. package/dist/Input.d.ts +1 -1
  59. package/dist/Input.js +35 -162
  60. package/dist/Input.mjs +4 -4
  61. package/dist/LabelValue.js +24 -149
  62. package/dist/LabelValue.mjs +3 -3
  63. package/dist/ListGroup.js +1 -114
  64. package/dist/ListGroup.mjs +2 -2
  65. package/dist/ListItem.js +38 -235
  66. package/dist/ListItem.mjs +5 -6
  67. package/dist/MediaCard.d.mts +0 -14
  68. package/dist/MediaCard.d.ts +0 -14
  69. package/dist/MediaCard.js +69 -315
  70. package/dist/MediaCard.mjs +5 -6
  71. package/dist/MenuGroup.js +1 -114
  72. package/dist/MenuGroup.mjs +2 -2
  73. package/dist/MenuItem.js +36 -234
  74. package/dist/MenuItem.mjs +5 -6
  75. package/dist/MonthPicker.js +8 -163
  76. package/dist/MonthPicker.mjs +3 -3
  77. package/dist/NumberStepper.js +40 -238
  78. package/dist/NumberStepper.mjs +5 -6
  79. package/dist/PagerDots.d.mts +1 -1
  80. package/dist/PagerDots.d.ts +1 -1
  81. package/dist/PagerDots.js +69 -224
  82. package/dist/PagerDots.mjs +6 -5
  83. package/dist/Pressable.js +14 -85
  84. package/dist/Pressable.mjs +4 -4
  85. package/dist/PricingCard.js +87 -272
  86. package/dist/PricingCard.mjs +8 -8
  87. package/dist/Progress.js +3 -123
  88. package/dist/Progress.mjs +3 -3
  89. package/dist/RadioGroup.js +52 -265
  90. package/dist/RadioGroup.mjs +5 -5
  91. package/dist/RetrayProvider.js +3 -6
  92. package/dist/RetrayProvider.mjs +3 -3
  93. package/dist/Select.d.mts +2 -1
  94. package/dist/Select.d.ts +2 -1
  95. package/dist/Select.js +24 -232
  96. package/dist/Select.mjs +4 -5
  97. package/dist/SelectableCard.js +33 -209
  98. package/dist/SelectableCard.mjs +5 -5
  99. package/dist/SelectableGrid.d.mts +0 -21
  100. package/dist/SelectableGrid.d.ts +0 -21
  101. package/dist/SelectableGrid.js +49 -271
  102. package/dist/SelectableGrid.mjs +5 -6
  103. package/dist/Separator.js +1 -114
  104. package/dist/Separator.mjs +2 -2
  105. package/dist/Sheet.js +7 -162
  106. package/dist/Sheet.mjs +3 -3
  107. package/dist/SheetSelect.js +39 -236
  108. package/dist/SheetSelect.mjs +6 -6
  109. package/dist/Skeleton.js +4 -124
  110. package/dist/Skeleton.mjs +3 -3
  111. package/dist/Slider.js +6 -161
  112. package/dist/Slider.mjs +3 -3
  113. package/dist/Spinner.js +3 -116
  114. package/dist/Spinner.mjs +2 -2
  115. package/dist/Stats.js +36 -234
  116. package/dist/Stats.mjs +5 -6
  117. package/dist/Switch.js +24 -175
  118. package/dist/Switch.mjs +5 -4
  119. package/dist/TabBar.js +43 -200
  120. package/dist/TabBar.mjs +5 -4
  121. package/dist/Tabs.js +15 -199
  122. package/dist/Tabs.mjs +5 -5
  123. package/dist/Text.js +9 -130
  124. package/dist/Text.mjs +2 -2
  125. package/dist/Textarea.d.mts +2 -1
  126. package/dist/Textarea.d.ts +2 -1
  127. package/dist/Textarea.js +71 -219
  128. package/dist/Textarea.mjs +4 -4
  129. package/dist/Toast.js +1 -114
  130. package/dist/Toast.mjs +2 -2
  131. package/dist/Toggle.js +39 -236
  132. package/dist/Toggle.mjs +6 -6
  133. package/dist/{chunk-M3C7XM2M.mjs → chunk-2QOHHBJC.mjs} +3 -3
  134. package/dist/{chunk-LIS6I5UP.mjs → chunk-2VIDP72N.mjs} +3 -3
  135. package/dist/{chunk-DF7JA72E.mjs → chunk-4NQFTHN3.mjs} +13 -7
  136. package/dist/{chunk-UBUXUMER.mjs → chunk-4ZO5PTKF.mjs} +4 -4
  137. package/dist/{chunk-3XCFYSX4.mjs → chunk-5MYNAAFE.mjs} +13 -17
  138. package/dist/{chunk-E7NEHHXV.mjs → chunk-62BBSSUF.mjs} +3 -3
  139. package/dist/{chunk-MVMGPZN6.mjs → chunk-6CR4S6W2.mjs} +3 -3
  140. package/dist/{chunk-EDLCGYIO.mjs → chunk-6QLBHUEG.mjs} +8 -7
  141. package/dist/chunk-ARONDO7M.mjs +40 -0
  142. package/dist/{chunk-GH67YXG6.mjs → chunk-AZV7KNJI.mjs} +3 -3
  143. package/dist/{chunk-RMRS44MQ.mjs → chunk-BTUW5LSG.mjs} +11 -8
  144. package/dist/{chunk-2P2CB235.mjs → chunk-BULKGOIZ.mjs} +7 -8
  145. package/dist/{chunk-NHDI3VQB.mjs → chunk-CBIZLRYH.mjs} +15 -12
  146. package/dist/chunk-CM2DG4MR.mjs +142 -0
  147. package/dist/{chunk-TS7DGUIR.mjs → chunk-DBHSUUKU.mjs} +2 -2
  148. package/dist/{chunk-57V2LXCK.mjs → chunk-DE25XTVQ.mjs} +3 -3
  149. package/dist/{chunk-UQ4742ET.mjs → chunk-E4EQSCKR.mjs} +5 -5
  150. package/dist/{chunk-GUTDFUNF.mjs → chunk-EHGBHFMH.mjs} +9 -17
  151. package/dist/{chunk-CF27NBXO.mjs → chunk-EROPDCB5.mjs} +16 -24
  152. package/dist/{chunk-ZIMY2QUM.mjs → chunk-ERWJPVX7.mjs} +2 -2
  153. package/dist/{chunk-NLZY4TXU.mjs → chunk-ESQDPO5E.mjs} +7 -7
  154. package/dist/{chunk-VJBUCITV.mjs → chunk-EW2FIDSM.mjs} +1 -1
  155. package/dist/{chunk-HC4VVCWY.mjs → chunk-FTTI6T5Q.mjs} +4 -4
  156. package/dist/{chunk-2HFD4IHU.mjs → chunk-HUSSF6TF.mjs} +1 -1
  157. package/dist/chunk-IFYMBOEN.mjs +14 -0
  158. package/dist/{chunk-QOLWA2PW.mjs → chunk-IGU223UM.mjs} +80 -4
  159. package/dist/chunk-IJCMPVW5.mjs +121 -0
  160. package/dist/{chunk-AENAVIKT.mjs → chunk-ITG4JQM3.mjs} +4 -4
  161. package/dist/{chunk-E5UKLSJZ.mjs → chunk-K3QX2M26.mjs} +11 -8
  162. package/dist/{chunk-4OORJ2DY.mjs → chunk-K7TKID3V.mjs} +8 -7
  163. package/dist/{chunk-2LG326TT.mjs → chunk-KAGADD2O.mjs} +4 -4
  164. package/dist/{chunk-IVSRW4HS.mjs → chunk-KC5QDYGZ.mjs} +4 -4
  165. package/dist/{chunk-7AFZWSCI.mjs → chunk-KPTY7UYQ.mjs} +1 -1
  166. package/dist/{chunk-YTXRIXNZ.mjs → chunk-KSSVIFYR.mjs} +9 -12
  167. package/dist/chunk-L3YKPTJQ.mjs +119 -0
  168. package/dist/chunk-M53LC4Q7.mjs +35 -0
  169. package/dist/{chunk-ZR6HSEAB.mjs → chunk-MP7GLMIR.mjs} +17 -25
  170. package/dist/chunk-MZ6WRTD2.mjs +40 -0
  171. package/dist/chunk-NGEN2EES.mjs +581 -0
  172. package/dist/{chunk-C43HRKXH.mjs → chunk-OBV72JD4.mjs} +1 -1
  173. package/dist/{chunk-LPV4NJJK.mjs → chunk-PGQ6FMXS.mjs} +6 -5
  174. package/dist/{chunk-MEPSKGBO.mjs → chunk-PI6RULJX.mjs} +1 -1
  175. package/dist/{chunk-F3YTWO3T.mjs → chunk-RA6SAAFE.mjs} +9 -8
  176. package/dist/{chunk-UNNRUJTM.mjs → chunk-RRKM4MKB.mjs} +7 -7
  177. package/dist/{chunk-ULGNQPNE.mjs → chunk-S2VGME7X.mjs} +1 -1
  178. package/dist/{chunk-OLVJFKXS.mjs → chunk-S44XWTTC.mjs} +35 -25
  179. package/dist/{chunk-YMYIEVZP.mjs → chunk-SZEKQAOY.mjs} +1 -1
  180. package/dist/{chunk-ELGEOM7I.mjs → chunk-TETMEKZE.mjs} +9 -9
  181. package/dist/{chunk-BXF4AMHY.mjs → chunk-TMH263OK.mjs} +5 -4
  182. package/dist/{chunk-NJG7DHVF.mjs → chunk-U6DEBYU5.mjs} +10 -9
  183. package/dist/{chunk-RJNLAH76.mjs → chunk-UOKFSFNJ.mjs} +2 -2
  184. package/dist/{chunk-HEDQPK4I.mjs → chunk-URIH43IJ.mjs} +13 -21
  185. package/dist/{chunk-QXDGGOLC.mjs → chunk-V2ZB2XNS.mjs} +6 -6
  186. package/dist/{chunk-KSUWPU2F.mjs → chunk-WIPEDNSD.mjs} +7 -7
  187. package/dist/{chunk-QDAZGZUF.mjs → chunk-XCIG6HT2.mjs} +3 -3
  188. package/dist/{chunk-4J2PXL36.mjs → chunk-Y6YS33GM.mjs} +40 -38
  189. package/dist/{chunk-4XOB5TTD.mjs → chunk-ZKDKKQCE.mjs} +5 -5
  190. package/dist/{chunk-LOBLCFMN.mjs → chunk-ZTPYUU5C.mjs} +5 -5
  191. package/dist/index.d.mts +12 -72
  192. package/dist/index.d.ts +12 -72
  193. package/dist/index.js +1051 -1838
  194. package/dist/index.mjs +81 -85
  195. package/package.json +8 -10
  196. package/src/components/Accordion/Accordion.tsx +12 -9
  197. package/src/components/AlertBanner/AlertBanner.tsx +7 -6
  198. package/src/components/AppHeader/AppHeader.tsx +1 -1
  199. package/src/components/Avatar/Avatar.tsx +92 -1
  200. package/src/components/Avatar/index.ts +2 -2
  201. package/src/components/Badge/Badge.tsx +2 -2
  202. package/src/components/Button/Button.tsx +50 -46
  203. package/src/components/Card/Card.tsx +1 -0
  204. package/src/components/CategoryStrip/CategoryStrip.tsx +36 -49
  205. package/src/components/Chip/Chip.tsx +5 -4
  206. package/src/components/ConfirmDialog/ConfirmDialog.tsx +3 -3
  207. package/src/components/DetailRow/DetailRow.tsx +3 -3
  208. package/src/components/EmptyState/EmptyState.tsx +2 -2
  209. package/src/components/ErrorBoundary/ErrorBoundary.tsx +6 -6
  210. package/src/components/HolographicCard/HolographicCard.tsx +14 -95
  211. package/src/components/IconButton/IconButton.tsx +2 -2
  212. package/src/components/IconPicker/IconPicker.tsx +13 -12
  213. package/src/components/ImageUpload/ImageUpload.tsx +14 -25
  214. package/src/components/ImageViewer/ImageViewer.tsx +3 -3
  215. package/src/components/Input/Input.tsx +11 -5
  216. package/src/components/LabelValue/LabelValue.tsx +2 -2
  217. package/src/components/ListItem/ListItem.tsx +4 -4
  218. package/src/components/MediaCard/MediaCard.tsx +21 -59
  219. package/src/components/MenuItem/MenuItem.tsx +2 -2
  220. package/src/components/MonthPicker/MonthPicker.tsx +2 -2
  221. package/src/components/NumberStepper/NumberStepper.tsx +6 -6
  222. package/src/components/PagerDots/PagerDots.tsx +38 -28
  223. package/src/components/PricingCard/PricingCard.tsx +6 -6
  224. package/src/components/RadioGroup/RadioGroup.tsx +18 -31
  225. package/src/components/Select/Select.tsx +32 -39
  226. package/src/components/SelectableCard/SelectableCard.tsx +4 -6
  227. package/src/components/SelectableGrid/SelectableGrid.tsx +38 -72
  228. package/src/components/Sheet/Sheet.tsx +1 -1
  229. package/src/components/SheetSelect/SheetSelect.tsx +3 -3
  230. package/src/components/Skeleton/Skeleton.tsx +1 -1
  231. package/src/components/Spinner/Spinner.tsx +2 -2
  232. package/src/components/Stats/Stats.tsx +2 -2
  233. package/src/components/Switch/Switch.tsx +9 -6
  234. package/src/components/TabBar/TabBar.tsx +9 -8
  235. package/src/components/Text/Text.tsx +12 -1
  236. package/src/components/Textarea/Textarea.tsx +18 -32
  237. package/src/components/Toggle/Toggle.tsx +3 -3
  238. package/src/hooks/useConfirmDialog.ts +31 -42
  239. package/src/index.ts +3 -4
  240. package/src/theme/ThemeProvider.tsx +1 -4
  241. package/src/theme/colorUtils.ts +1 -72
  242. package/src/theme/colors.ts +40 -1
  243. package/src/theme/types.ts +2 -2
  244. package/src/utils/animations.ts +0 -47
  245. package/src/utils/curatedIcons.ts +93 -801
  246. package/src/utils/haptics.ts +13 -208
  247. package/src/utils/icons.ts +27 -91
  248. package/src/utils/pressable.ts +10 -61
  249. package/dist/VirtualList.d.mts +0 -19
  250. package/dist/VirtualList.d.ts +0 -19
  251. package/dist/VirtualList.js +0 -38
  252. package/dist/VirtualList.mjs +0 -2
  253. package/dist/chunk-2BA3JMKK.mjs +0 -136
  254. package/dist/chunk-3DKJ2GIC.mjs +0 -30
  255. package/dist/chunk-7ELGZ66G.mjs +0 -164
  256. package/dist/chunk-DVK4G2GT.mjs +0 -59
  257. package/dist/chunk-EJ7ZPXOH.mjs +0 -163
  258. package/dist/chunk-KA7LTET3.mjs +0 -71
  259. package/dist/chunk-LNPKGWBG.mjs +0 -134
  260. package/dist/chunk-NC5ZTR2Y.mjs +0 -32
  261. package/dist/chunk-SAWUXP3A.mjs +0 -1114
  262. package/dist/chunk-YNROWHQJ.mjs +0 -46
  263. package/src/components/VirtualList/VirtualList.tsx +0 -60
  264. package/src/components/VirtualList/index.ts +0 -1
  265. package/src/utils/fontGuard.ts +0 -35
  266. package/src/utils/hover.ts +0 -25
  267. package/src/utils/useColorTransition.ts +0 -40
  268. package/src/utils/usePressScale.ts +0 -75
@@ -1,22 +1,12 @@
1
- /**
2
- * Haptic feedback utilities using expo-haptics.
3
- *
4
- * Uses expo-haptics which works with both Expo Go and development builds.
5
- * react-native-pulsar support is optional for dev builds with native modules.
6
- *
7
- * All functions are web-safe (no-op on web platform).
8
- */
9
- import { Platform, NativeModules } from 'react-native'
1
+ import { Platform } from 'react-native'
10
2
 
11
- // ─── expo-haptics (primary) ───────────────────────────────────────────────────
12
- type HapticsModule = typeof import('expo-haptics')
13
- let _haptics: HapticsModule | null = null
14
- let _hapticsLoaded = false
3
+ let _haptics: typeof import('expo-haptics') | null = null
4
+ let _loaded = false
15
5
 
16
- async function getHaptics(): Promise<HapticsModule | null> {
6
+ async function getHaptics(): Promise<typeof import('expo-haptics') | null> {
17
7
  if (Platform.OS === 'web') return null
18
- if (!_hapticsLoaded) {
19
- _hapticsLoaded = true
8
+ if (!_loaded) {
9
+ _loaded = true
20
10
  try {
21
11
  _haptics = await import('expo-haptics')
22
12
  } catch {
@@ -26,215 +16,30 @@ async function getHaptics(): Promise<HapticsModule | null> {
26
16
  return _haptics
27
17
  }
28
18
 
29
- // ─── Pulsar (optional for dev builds) ─────────────────────────────────────────
30
- // Only available in development builds with native modules installed.
31
- // Gracefully falls back to expo-haptics if not available.
32
- type PulsarModule = typeof import('react-native-pulsar')
33
- let _pulsar: PulsarModule | null = null
34
- let _pulsarChecked = false
35
- let _pulsarAvailable = false
36
-
37
- function isPulsarNativeRegistered(): boolean {
38
- // react-native-pulsar's NativeRNPulsar.ts calls
39
- // TurboModuleRegistry.getEnforcing('RNPulsar') at module-eval time. When the
40
- // native binary is absent (e.g. Expo Go), requiring the package throws during
41
- // Metro module eval — and that throw is surfaced by RN's global error handler
42
- // (red screen) even when wrapped in try/catch, because guardedLoadModule
43
- // reports it before rethrowing. So we must confirm the native module is
44
- // actually registered BEFORE requiring the JS wrapper.
45
- //
46
- // TurboModuleRegistry.get() returns a truthy proxy even for unregistered
47
- // modules (false positive), so it can't be trusted. Instead we probe the low
48
- // level: the new-arch turbo proxy returns null for unregistered names, and
49
- // the old-arch NativeModules map omits them. A direct lookup throws nothing —
50
- // unlike a top-level import — so any failure is caught safely here.
51
- try {
52
- const g = globalThis as {
53
- __turboModuleProxy?: (name: string) => unknown
54
- }
55
- if (typeof g.__turboModuleProxy === 'function') {
56
- return g.__turboModuleProxy('RNPulsar') != null
57
- }
58
- return NativeModules?.RNPulsar != null
59
- } catch {
60
- return false
61
- }
62
- }
63
-
64
- function getPulsar(): PulsarModule | null {
65
- if (Platform.OS === 'web') return null
66
- if (!_pulsarChecked) {
67
- _pulsarChecked = true
68
- try {
69
- // Only require the package when its native module is registered —
70
- // otherwise the require would red-screen the app (see above).
71
- if (isPulsarNativeRegistered()) {
72
- // eslint-disable-next-line @typescript-eslint/no-require-imports
73
- _pulsar = require('react-native-pulsar') as PulsarModule
74
- _pulsarAvailable = true
75
- }
76
- } catch {
77
- _pulsar = null
78
- _pulsarAvailable = false
79
- }
80
- }
81
- return _pulsarAvailable ? _pulsar : null
82
- }
83
-
84
- // ─── Public API ───────────────────────────────────────────────────────────────
85
-
86
- /**
87
- * Light selection feedback — checkboxes, switches, toggles, pickers.
88
- */
89
19
  export function selectionAsync(): void {
90
- if (Platform.OS === 'web') return
91
- // Try expo-haptics first (always available in Expo Go)
92
- getHaptics().then((h) => {
93
- if (h) {
94
- h.selectionAsync()
95
- } else {
96
- // Fallback to Pulsar if available
97
- getPulsar()?.Presets.System.selection()
98
- }
99
- })
20
+ getHaptics().then((h) => h?.selectionAsync())
100
21
  }
101
22
 
102
- /**
103
- * Light impact — cards, surfaces, light interactions.
104
- */
105
23
  export function impactLight(): void {
106
- if (Platform.OS === 'web') return
107
- getHaptics().then((h) => {
108
- if (h) {
109
- h.impactAsync(h.ImpactFeedbackStyle.Light)
110
- } else {
111
- getPulsar()?.Presets.System.impactLight()
112
- }
113
- })
24
+ getHaptics().then((h) => h?.impactAsync(h.ImpactFeedbackStyle.Light))
114
25
  }
115
26
 
116
- /**
117
- * Medium impact — buttons, primary actions.
118
- */
119
27
  export function impactMedium(): void {
120
- if (Platform.OS === 'web') return
121
- getHaptics().then((h) => {
122
- if (h) {
123
- h.impactAsync(h.ImpactFeedbackStyle.Medium)
124
- } else {
125
- getPulsar()?.Presets.System.impactMedium()
126
- }
127
- })
28
+ getHaptics().then((h) => h?.impactAsync(h.ImpactFeedbackStyle.Medium))
128
29
  }
129
30
 
130
- /**
131
- * Heavy impact — confirmations, important actions.
132
- */
133
31
  export function impactHeavy(): void {
134
- if (Platform.OS === 'web') return
135
- getHaptics().then((h) => {
136
- if (h) {
137
- h.impactAsync(h.ImpactFeedbackStyle.Heavy)
138
- } else {
139
- getPulsar()?.Presets.System.impactHeavy()
140
- }
141
- })
32
+ getHaptics().then((h) => h?.impactAsync(h.ImpactFeedbackStyle.Heavy))
142
33
  }
143
34
 
144
- /**
145
- * Success notification — confirmations, completed actions.
146
- */
147
35
  export function notificationSuccess(): void {
148
- if (Platform.OS === 'web') return
149
- getHaptics().then((h) => {
150
- if (h) {
151
- h.notificationAsync(h.NotificationFeedbackType.Success)
152
- } else {
153
- getPulsar()?.Presets.System.notificationSuccess()
154
- }
155
- })
36
+ getHaptics().then((h) => h?.notificationAsync(h.NotificationFeedbackType.Success))
156
37
  }
157
38
 
158
- /**
159
- * Error notification — failed actions, errors.
160
- */
161
39
  export function notificationError(): void {
162
- if (Platform.OS === 'web') return
163
- getHaptics().then((h) => {
164
- if (h) {
165
- h.notificationAsync(h.NotificationFeedbackType.Error)
166
- } else {
167
- getPulsar()?.Presets.System.notificationError()
168
- }
169
- })
40
+ getHaptics().then((h) => h?.notificationAsync(h.NotificationFeedbackType.Error))
170
41
  }
171
42
 
172
- /**
173
- * Warning notification — caution states.
174
- */
175
43
  export function notificationWarning(): void {
176
- if (Platform.OS === 'web') return
177
- getHaptics().then((h) => {
178
- if (h) {
179
- h.notificationAsync(h.NotificationFeedbackType.Warning)
180
- } else {
181
- getPulsar()?.Presets.System.notificationWarning()
182
- }
183
- })
184
- }
185
-
186
- // ─── Rich Pulsar Presets (enhanced feedback) ──────────────────────────────────
187
-
188
- /**
189
- * Rich haptic presets from Pulsar — enhanced feedback for special interactions.
190
- * Falls back to basic expo-haptics on Expo Go or unsupported devices.
191
- */
192
- export const richHaptics = {
193
- /** Hammer strike — strong confirmation feedback. */
194
- hammer: (): void => {
195
- if (Platform.OS === 'web') return
196
- const p = getPulsar()
197
- if (p) p.Presets.hammer()
198
- else impactHeavy()
199
- },
200
-
201
- /** Pulse — rhythmic feedback for toggles or state changes. */
202
- pulse: (): void => {
203
- if (Platform.OS === 'web') return
204
- const p = getPulsar()
205
- if (p) p.Presets.pulse()
206
- else selectionAsync()
207
- },
208
-
209
- /** Buzz — continuous vibration for attention. */
210
- buzz: (): void => {
211
- if (Platform.OS === 'web') return
212
- const p = getPulsar()
213
- if (p) p.Presets.buzz()
214
- else impactMedium()
215
- },
216
-
217
- /** Flick — crisp click feedback. */
218
- flick: (): void => {
219
- if (Platform.OS === 'web') return
220
- const p = getPulsar()
221
- if (p) p.Presets.flick()
222
- else selectionAsync()
223
- },
224
-
225
- /** Soft — gentle, subtle feedback. */
226
- soft: (): void => {
227
- if (Platform.OS === 'web') return
228
- const p = getPulsar()
229
- if (p) p.Presets.System.impactSoft()
230
- else impactLight()
231
- },
232
-
233
- /** Rigid — firm, solid feedback. */
234
- rigid: (): void => {
235
- if (Platform.OS === 'web') return
236
- const p = getPulsar()
237
- if (p) p.Presets.System.impactRigid()
238
- else impactMedium()
239
- },
44
+ getHaptics().then((h) => h?.notificationAsync(h.NotificationFeedbackType.Warning))
240
45
  }
@@ -9,110 +9,46 @@ import Ionicons from '@expo/vector-icons/Ionicons'
9
9
  export type IconFamily = 'Feather' | 'AntDesign' | 'Entypo' | 'FontAwesome5' | 'MaterialIcons' | 'Ionicons'
10
10
 
11
11
  export interface IconProps {
12
- /** Icon name from any supported @expo/vector-icons family. See https://icons.expo.fyi */
13
12
  name: string
14
13
  size: number
15
14
  color: string
16
- /** Override the resolved family when the same name exists in multiple families. */
17
15
  family?: IconFamily
18
16
  }
19
17
 
20
18
  type IconComponentType = React.ComponentType<{ name: string; size: number; color: string }>
21
- type IconFamilyEntry = {
22
- name: IconFamily
23
- component: IconComponentType
24
- /** Deferred — glyphMap is only read when the resolution cache is first built. */
25
- getGlyphMap: () => Record<string, number>
26
- }
27
-
28
- type WithGlyphMap = { glyphMap?: Record<string, number> }
29
-
30
- const glyphMapOf = (mod: unknown): Record<string, number> =>
31
- (mod as WithGlyphMap).glyphMap ?? {}
32
19
 
33
- // Priority order: highest-priority family LAST so it overwrites lower-priority entries in the cache.
34
- const ALL_FAMILIES: IconFamilyEntry[] = [
35
- { name: 'Ionicons', component: Ionicons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Ionicons) },
36
- { name: 'MaterialIcons', component: MaterialIcons as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(MaterialIcons) },
37
- { name: 'FontAwesome5', component: FontAwesome5 as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(FontAwesome5) },
38
- { name: 'Entypo', component: Entypo as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Entypo) },
39
- { name: 'AntDesign', component: AntDesign as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(AntDesign) },
40
- { name: 'Feather', component: Feather as unknown as IconComponentType, getGlyphMap: () => glyphMapOf(Feather) },
20
+ const ALL_FAMILIES: { name: IconFamily; component: IconComponentType; glyphMap?: Record<string, number> }[] = [
21
+ { name: 'Feather', component: Feather as unknown as IconComponentType },
22
+ { name: 'AntDesign', component: AntDesign as unknown as IconComponentType },
23
+ { name: 'Entypo', component: Entypo as unknown as IconComponentType },
24
+ { name: 'FontAwesome5', component: FontAwesome5 as unknown as IconComponentType },
25
+ { name: 'MaterialIcons', component: MaterialIcons as unknown as IconComponentType },
26
+ { name: 'Ionicons', component: Ionicons as unknown as IconComponentType },
41
27
  ]
42
28
 
43
- // Active families participating in name resolution. Defaults to all six.
44
- let activeFamilies: IconFamilyEntry[] = ALL_FAMILIES
45
- let resolvedCache: Map<string, IconFamilyEntry> | null = null
46
-
47
- /**
48
- * Restrict which icon families participate in automatic name resolution.
49
- * Narrowing to the families you actually use shrinks the resolution cache and
50
- * speeds up the first `renderIcon` call (no scanning thousands of unused glyphs).
51
- *
52
- * Note: all six families are still statically imported by this module — Metro
53
- * bundles them regardless. This controls *resolution scope*, not bundle size.
54
- *
55
- * @example configureIconFamilies(['Feather', 'MaterialIcons'])
56
- */
57
- export function configureIconFamilies(families: IconFamily[]): void {
58
- const order = families
59
- .map((n) => ALL_FAMILIES.find((f) => f.name === n))
60
- .filter((f): f is IconFamilyEntry => f !== undefined)
61
- activeFamilies = order.length > 0 ? order : ALL_FAMILIES
62
- resolvedCache = null // invalidate — rebuilt lazily on next resolve
63
- }
64
-
65
- function buildCache(families?: IconFamilyEntry[]): Map<string, IconFamilyEntry> {
66
- const cache = new Map<string, IconFamilyEntry>()
67
- for (const family of (families ?? activeFamilies)) {
68
- const glyphMap = family.getGlyphMap()
69
- for (const iconName of Object.keys(glyphMap)) {
70
- cache.set(iconName, family)
29
+ // Lazy singleton cache populates on first Icon render, persists for session.
30
+ let glyphCacheInitialized = false
31
+ function ensureGlyphCache() {
32
+ if (glyphCacheInitialized) return
33
+ glyphCacheInitialized = true
34
+ for (const entry of ALL_FAMILIES) {
35
+ try {
36
+ entry.glyphMap = (entry.component as unknown as { glyphMap?: Record<string, number> }).glyphMap
37
+ } catch {
38
+ entry.glyphMap = {}
71
39
  }
72
40
  }
73
- return cache
74
- }
75
-
76
- function resolveFamily(name: string): IconFamilyEntry | null {
77
- if (!resolvedCache) {
78
- resolvedCache = buildCache()
79
- }
80
- return resolvedCache.get(name) ?? null
81
- }
82
-
83
- let cachedIconNames: string[] | null = null
84
-
85
- export function getValidIconNames(families?: IconFamily[]): string[] {
86
- if (families && families.length > 0) {
87
- const tempFamilies = families
88
- .map((n) => ALL_FAMILIES.find((f) => f.name === n))
89
- .filter((f): f is IconFamilyEntry => f !== undefined)
90
- if (tempFamilies.length === 0) return []
91
- const cache = buildCache(tempFamilies)
92
- return Array.from(cache.keys())
93
- }
94
- if (!cachedIconNames) {
95
- const cache = buildCache()
96
- cachedIconNames = Array.from(cache.keys())
97
- }
98
- return cachedIconNames
99
41
  }
100
42
 
101
43
  export function Icon({ name, size, color, family }: IconProps): React.ReactElement | null {
102
- let resolved: IconFamilyEntry | null = null
103
-
104
- if (family) {
105
- resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null
106
- } else {
107
- resolved = resolveFamily(name)
108
- }
109
-
110
- if (!resolved) return null
111
-
112
- const Component = resolved.component
113
- return React.createElement(Component, { name, size, color })
114
- }
115
-
116
- export function renderIcon(name: string, size: number, color: string): React.ReactElement | null {
117
- return React.createElement(Icon, { name, size, color })
44
+ ensureGlyphCache()
45
+ const entry = family
46
+ ? ALL_FAMILIES.find((f) => f.name === family)
47
+ : ALL_FAMILIES.find((f) => {
48
+ const glyphMap = f.glyphMap
49
+ return glyphMap ? name in glyphMap : false
50
+ })
51
+
52
+ if (!entry) return null
53
+ return React.createElement(entry.component, { name, size, color })
118
54
  }
@@ -1,66 +1,15 @@
1
- /**
2
- * Pressto-based pressable primitives for the UI Kit.
3
- *
4
- * Pressto provides main-thread pressable animations built on react-native-gesture-handler
5
- * and react-native-reanimated. Animations run at 60fps with zero JS overhead.
6
- *
7
- * These custom pressables match the UI Kit's design language:
8
- * - Button: 0.95 scale (tight, premium press)
9
- * - Card: 0.98 scale (subtle surface response)
10
- * - Row: 0.97 scale (list items, menu items)
11
- * - Chip: 0.94 scale (compact, snappy)
12
- */
13
1
  import { createAnimatedPressable } from 'pressto'
14
- import { PRESS_SCALE } from './animations'
15
2
 
16
- /**
17
- * Button pressable — tight 0.95 scale for primary actions.
18
- * Use for: Button, IconButton, Toggle, Checkbox triggers.
19
- */
20
- export const PressableButton = createAnimatedPressable((progress) => {
21
- 'worklet'
22
- const scale = 1 - (1 - PRESS_SCALE.button) * progress
23
- return { transform: [{ scale }] }
24
- })
3
+ const makePressable = (scale: number) =>
4
+ createAnimatedPressable((progress) => {
5
+ 'worklet'
6
+ return { transform: [{ scale: 1 - (1 - scale) * progress }] }
7
+ })
25
8
 
26
- /**
27
- * Card pressable — subtle 0.98 scale for surfaces.
28
- * Use for: Card (interactive), MediaCard, Pressable component.
29
- */
30
- export const PressableCard = createAnimatedPressable((progress) => {
31
- 'worklet'
32
- const scale = 1 - (1 - PRESS_SCALE.card) * progress
33
- return { transform: [{ scale }] }
34
- })
9
+ export const PressableButton = makePressable(0.95)
10
+ export const PressableCard = makePressable(0.98)
11
+ export const PressableRow = makePressable(0.97)
12
+ export const PressableChip = makePressable(0.94)
13
+ export const PressableTab = makePressable(0.95)
35
14
 
36
- /**
37
- * Row pressable — balanced 0.97 scale for list interactions.
38
- * Use for: ListItem, MenuItem, Accordion triggers.
39
- */
40
- export const PressableRow = createAnimatedPressable((progress) => {
41
- 'worklet'
42
- const scale = 1 - (1 - PRESS_SCALE.row) * progress
43
- return { transform: [{ scale }] }
44
- })
45
-
46
- /**
47
- * Chip pressable — snappy 0.94 scale for compact elements.
48
- * Use for: Chip, small toggleable items.
49
- */
50
- export const PressableChip = createAnimatedPressable((progress) => {
51
- 'worklet'
52
- const scale = 1 - (1 - PRESS_SCALE.chip) * progress
53
- return { transform: [{ scale }] }
54
- })
55
-
56
- /**
57
- * Tab pressable — same as button for tab triggers.
58
- */
59
- export const PressableTab = createAnimatedPressable((progress) => {
60
- 'worklet'
61
- const scale = 1 - (1 - PRESS_SCALE.button) * progress
62
- return { transform: [{ scale }] }
63
- })
64
-
65
- // Re-export pressto components for direct use
66
15
  export { PressableScale, PressableOpacity, PressablesConfig } from 'pressto'
@@ -1,19 +0,0 @@
1
- import React from 'react';
2
- import { FlatListProps, FlatList } from 'react-native';
3
-
4
- interface VirtualListItem {
5
- id?: string | number;
6
- }
7
- interface VirtualListProps<T> extends Omit<FlatListProps<T>, 'getItemLayout'> {
8
- /**
9
- * Fixed row height in px. When provided, enables `getItemLayout` so the list
10
- * skips async measurement — large datasets scroll and `scrollToIndex` jump
11
- * without layout passes. Omit only for variable-height rows.
12
- */
13
- itemHeight?: number;
14
- }
15
- declare const VirtualList: <T>(props: VirtualListProps<T> & {
16
- ref?: React.Ref<FlatList<T>>;
17
- }) => React.ReactElement;
18
-
19
- export { VirtualList, type VirtualListItem, type VirtualListProps };
@@ -1,19 +0,0 @@
1
- import React from 'react';
2
- import { FlatListProps, FlatList } from 'react-native';
3
-
4
- interface VirtualListItem {
5
- id?: string | number;
6
- }
7
- interface VirtualListProps<T> extends Omit<FlatListProps<T>, 'getItemLayout'> {
8
- /**
9
- * Fixed row height in px. When provided, enables `getItemLayout` so the list
10
- * skips async measurement — large datasets scroll and `scrollToIndex` jump
11
- * without layout passes. Omit only for variable-height rows.
12
- */
13
- itemHeight?: number;
14
- }
15
- declare const VirtualList: <T>(props: VirtualListProps<T> & {
16
- ref?: React.Ref<FlatList<T>>;
17
- }) => React.ReactElement;
18
-
19
- export { VirtualList, type VirtualListItem, type VirtualListProps };
@@ -1,38 +0,0 @@
1
- 'use strict';
2
-
3
- var React = require('react');
4
- var reactNative = require('react-native');
5
-
6
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
-
8
- var React__default = /*#__PURE__*/_interopDefault(React);
9
-
10
- // src/components/VirtualList/VirtualList.tsx
11
- var defaultKeyExtractor = (item, index) => {
12
- const id = item?.id;
13
- return id !== void 0 ? String(id) : String(index);
14
- };
15
- function VirtualListInner({ itemHeight, keyExtractor, renderItem, ...props }, ref) {
16
- const getItemLayout = React.useCallback(
17
- (_data, index) => ({
18
- length: itemHeight ?? 0,
19
- offset: (itemHeight ?? 0) * index,
20
- index
21
- }),
22
- [itemHeight]
23
- );
24
- return /* @__PURE__ */ React__default.default.createElement(
25
- reactNative.FlatList,
26
- {
27
- ref,
28
- keyExtractor: keyExtractor ?? defaultKeyExtractor,
29
- renderItem,
30
- getItemLayout: itemHeight !== void 0 ? getItemLayout : void 0,
31
- removeClippedSubviews: true,
32
- ...props
33
- }
34
- );
35
- }
36
- var VirtualList = React__default.default.forwardRef(VirtualListInner);
37
-
38
- exports.VirtualList = VirtualList;
@@ -1,2 +0,0 @@
1
- export { VirtualList } from './chunk-NC5ZTR2Y.mjs';
2
- import './chunk-Y6FXYEAI.mjs';