@retray-dev/ui-kit 7.0.1 → 9.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 (234) hide show
  1. package/COMPONENTS.md +567 -14
  2. package/EXAMPLES.md +21 -14
  3. package/README.md +14 -8
  4. package/dist/Accordion.js +57 -5
  5. package/dist/Accordion.mjs +4 -3
  6. package/dist/AlertBanner.js +4 -1
  7. package/dist/AlertBanner.mjs +3 -2
  8. package/dist/AppHeader.d.mts +40 -0
  9. package/dist/AppHeader.d.ts +40 -0
  10. package/dist/AppHeader.js +515 -0
  11. package/dist/AppHeader.mjs +10 -0
  12. package/dist/Avatar.js +39 -29
  13. package/dist/Avatar.mjs +2 -1
  14. package/dist/Badge.js +11 -1
  15. package/dist/Badge.mjs +2 -1
  16. package/dist/Button.d.mts +8 -3
  17. package/dist/Button.d.ts +8 -3
  18. package/dist/Button.js +126 -108
  19. package/dist/Button.mjs +6 -5
  20. package/dist/ButtonGroup.mjs +1 -0
  21. package/dist/Card.js +90 -70
  22. package/dist/Card.mjs +5 -4
  23. package/dist/CategoryStrip.js +79 -22
  24. package/dist/CategoryStrip.mjs +6 -6
  25. package/dist/Checkbox.js +118 -86
  26. package/dist/Checkbox.mjs +5 -5
  27. package/dist/Chip.js +113 -80
  28. package/dist/Chip.mjs +5 -5
  29. package/dist/ConfirmDialog.js +140 -110
  30. package/dist/ConfirmDialog.mjs +7 -6
  31. package/dist/CurrencyDisplay.mjs +1 -0
  32. package/dist/CurrencyInput.d.mts +1 -1
  33. package/dist/CurrencyInput.d.ts +1 -1
  34. package/dist/CurrencyInput.js +9 -5
  35. package/dist/CurrencyInput.mjs +5 -4
  36. package/dist/DetailRow.mjs +1 -0
  37. package/dist/EmptyState.js +131 -111
  38. package/dist/EmptyState.mjs +7 -6
  39. package/dist/ErrorBoundary.d.mts +42 -0
  40. package/dist/ErrorBoundary.d.ts +42 -0
  41. package/dist/ErrorBoundary.js +351 -0
  42. package/dist/ErrorBoundary.mjs +7 -0
  43. package/dist/Form.mjs +1 -0
  44. package/dist/HolographicCard.d.mts +55 -0
  45. package/dist/HolographicCard.d.ts +55 -0
  46. package/dist/HolographicCard.js +316 -0
  47. package/dist/HolographicCard.mjs +191 -0
  48. package/dist/IconButton.d.mts +8 -3
  49. package/dist/IconButton.d.ts +8 -3
  50. package/dist/IconButton.js +115 -98
  51. package/dist/IconButton.mjs +5 -4
  52. package/dist/ImageViewer.d.mts +23 -0
  53. package/dist/ImageViewer.d.ts +23 -0
  54. package/dist/ImageViewer.js +582 -0
  55. package/dist/ImageViewer.mjs +8 -0
  56. package/dist/Input.mjs +4 -3
  57. package/dist/LabelValue.mjs +1 -0
  58. package/dist/ListGroup.mjs +1 -0
  59. package/dist/ListItem.js +131 -117
  60. package/dist/ListItem.mjs +6 -5
  61. package/dist/MediaCard.js +54 -6
  62. package/dist/MediaCard.mjs +6 -5
  63. package/dist/MenuGroup.mjs +1 -0
  64. package/dist/MenuItem.js +91 -79
  65. package/dist/MenuItem.mjs +6 -5
  66. package/dist/MonthPicker.d.mts +10 -2
  67. package/dist/MonthPicker.d.ts +10 -2
  68. package/dist/MonthPicker.js +80 -17
  69. package/dist/MonthPicker.mjs +3 -2
  70. package/dist/PagerDots.d.mts +35 -0
  71. package/dist/PagerDots.d.ts +35 -0
  72. package/dist/PagerDots.js +392 -0
  73. package/dist/PagerDots.mjs +7 -0
  74. package/dist/Pressable.d.mts +5 -5
  75. package/dist/Pressable.d.ts +5 -5
  76. package/dist/Pressable.js +97 -86
  77. package/dist/Pressable.mjs +5 -4
  78. package/dist/PricingCard.d.mts +50 -0
  79. package/dist/PricingCard.d.ts +50 -0
  80. package/dist/PricingCard.js +636 -0
  81. package/dist/PricingCard.mjs +11 -0
  82. package/dist/Progress.mjs +3 -2
  83. package/dist/RadioGroup.js +81 -30
  84. package/dist/RadioGroup.mjs +5 -5
  85. package/dist/RetrayProvider.d.mts +2 -0
  86. package/dist/RetrayProvider.d.ts +2 -0
  87. package/dist/RetrayProvider.js +214 -0
  88. package/dist/RetrayProvider.mjs +5 -0
  89. package/dist/Select.js +51 -4
  90. package/dist/Select.mjs +5 -4
  91. package/dist/SelectableGrid.d.mts +44 -0
  92. package/dist/SelectableGrid.d.ts +44 -0
  93. package/dist/SelectableGrid.js +448 -0
  94. package/dist/SelectableGrid.mjs +9 -0
  95. package/dist/Separator.mjs +1 -0
  96. package/dist/Sheet.d.mts +13 -1
  97. package/dist/Sheet.d.ts +13 -1
  98. package/dist/Sheet.js +115 -5
  99. package/dist/Sheet.mjs +4 -2
  100. package/dist/Skeleton.d.mts +50 -0
  101. package/dist/Skeleton.d.ts +50 -0
  102. package/dist/Skeleton.js +61 -0
  103. package/dist/Skeleton.mjs +4 -2
  104. package/dist/Slider.js +51 -4
  105. package/dist/Slider.mjs +3 -2
  106. package/dist/Spinner.js +28 -7
  107. package/dist/Spinner.mjs +2 -1
  108. package/dist/Switch.js +98 -48
  109. package/dist/Switch.mjs +4 -3
  110. package/dist/TabBar.d.mts +42 -0
  111. package/dist/TabBar.d.ts +42 -0
  112. package/dist/TabBar.js +361 -0
  113. package/dist/TabBar.mjs +6 -0
  114. package/dist/Tabs.js +92 -62
  115. package/dist/Tabs.mjs +5 -4
  116. package/dist/Text.js +16 -0
  117. package/dist/Text.mjs +2 -1
  118. package/dist/Textarea.mjs +4 -3
  119. package/dist/Toast.d.mts +7 -7
  120. package/dist/Toast.d.ts +7 -7
  121. package/dist/Toast.mjs +1 -0
  122. package/dist/Toggle.d.mts +6 -3
  123. package/dist/Toggle.d.ts +6 -3
  124. package/dist/Toggle.js +135 -120
  125. package/dist/Toggle.mjs +5 -5
  126. package/dist/VirtualList.mjs +1 -0
  127. package/dist/{chunk-7H2OR44A.mjs → chunk-26BCI223.mjs} +1 -1
  128. package/dist/{chunk-CRYBX2CM.mjs → chunk-2TFTAWVJ.mjs} +44 -59
  129. package/dist/chunk-3DKJ2GIC.mjs +30 -0
  130. package/dist/{chunk-KWCPOM6W.mjs → chunk-3U4SSNWP.mjs} +32 -48
  131. package/dist/chunk-4I7D47FH.mjs +139 -0
  132. package/dist/chunk-4K625MVM.mjs +142 -0
  133. package/dist/{chunk-MN7OG7IY.mjs → chunk-6OAZJ577.mjs} +6 -4
  134. package/dist/{chunk-L7E7TVEZ.mjs → chunk-756RAKE4.mjs} +2 -2
  135. package/dist/{chunk-HSPSMN6U.mjs → chunk-7QHVVCB3.mjs} +2 -2
  136. package/dist/{chunk-URLL5JBR.mjs → chunk-A3A6KNQN.mjs} +3 -3
  137. package/dist/chunk-AJ7ZDNBT.mjs +120 -0
  138. package/dist/{chunk-FTLJOUOQ.mjs → chunk-AV4EMIRH.mjs} +25 -28
  139. package/dist/chunk-AZJF2BLK.mjs +115 -0
  140. package/dist/chunk-BNP626TY.mjs +159 -0
  141. package/dist/{chunk-5IKW3VNC.mjs → chunk-DVK4G2GT.mjs} +17 -1
  142. package/dist/{chunk-6LQYY7HC.mjs → chunk-EH745HE5.mjs} +2 -2
  143. package/dist/chunk-EJ7ZPXOH.mjs +163 -0
  144. package/dist/{chunk-RKLHUDZS.mjs → chunk-GD6KXMG5.mjs} +29 -15
  145. package/dist/{chunk-RR2VQLKE.mjs → chunk-GQYFLP3D.mjs} +14 -17
  146. package/dist/{chunk-Y6MXOREN.mjs → chunk-ID72TK46.mjs} +8 -17
  147. package/dist/{chunk-NQGVLMWG.mjs → chunk-JMOZEC77.mjs} +1 -1
  148. package/dist/{chunk-GCWOGZYL.mjs → chunk-JT7HKXRB.mjs} +39 -29
  149. package/dist/{chunk-LWG526VX.mjs → chunk-KIHCWCWL.mjs} +47 -62
  150. package/dist/chunk-LXJIIOYQ.mjs +104 -0
  151. package/dist/{chunk-SBZYEV4S.mjs → chunk-M6ZXVBTK.mjs} +5 -2
  152. package/dist/{chunk-XDMN67KV.mjs → chunk-MAC465BB.mjs} +10 -8
  153. package/dist/chunk-MBMXYJJV.mjs +36 -0
  154. package/dist/chunk-MLF3EZFW.mjs +119 -0
  155. package/dist/chunk-NA7PARID.mjs +147 -0
  156. package/dist/{chunk-QXGYKWI7.mjs → chunk-O3HA6TYM.mjs} +9 -4
  157. package/dist/{chunk-63357L2X.mjs → chunk-OB4JUQ3O.mjs} +1 -1
  158. package/dist/{chunk-AU2VDY4P.mjs → chunk-PFZTM6D5.mjs} +52 -4
  159. package/dist/chunk-QKH5ZOD5.mjs +97 -0
  160. package/dist/{chunk-KZJRQOIU.mjs → chunk-TERDKCLE.mjs} +11 -1
  161. package/dist/{chunk-U4N7WF4Z.mjs → chunk-UREA2GYY.mjs} +28 -23
  162. package/dist/{chunk-TAJ2PQ2O.mjs → chunk-VGTDN7SW.mjs} +7 -6
  163. package/dist/{chunk-URDE3EUU.mjs → chunk-VQ57HWPL.mjs} +27 -15
  164. package/dist/chunk-WBOOUHSS.mjs +62 -0
  165. package/dist/{chunk-GNGLDL6Z.mjs → chunk-WJLKJMKR.mjs} +18 -0
  166. package/dist/{chunk-YZJAFS4P.mjs → chunk-X4G6APW6.mjs} +22 -19
  167. package/dist/chunk-Y6FXYEAI.mjs +8 -0
  168. package/dist/chunk-YFZ3ELX5.mjs +16 -0
  169. package/dist/{chunk-QCNARS3X.mjs → chunk-YNROWHQJ.mjs} +1 -1
  170. package/dist/chunk-Z4BVUWW6.mjs +196 -0
  171. package/dist/{chunk-GPOUINK5.mjs → chunk-ZJKGQMYH.mjs} +10 -27
  172. package/dist/index-wt-orHUi.d.mts +85 -0
  173. package/dist/index-wt-orHUi.d.ts +85 -0
  174. package/dist/index.d.mts +59 -51
  175. package/dist/index.d.ts +59 -51
  176. package/dist/index.js +1940 -744
  177. package/dist/index.mjs +49 -39
  178. package/package.json +35 -5
  179. package/src/components/Accordion/Accordion.tsx +12 -1
  180. package/src/components/AlertBanner/AlertBanner.tsx +5 -0
  181. package/src/components/AppHeader/AppHeader.tsx +172 -0
  182. package/src/components/AppHeader/index.ts +1 -0
  183. package/src/components/Avatar/Avatar.tsx +10 -2
  184. package/src/components/Badge/Badge.tsx +8 -1
  185. package/src/components/Button/Button.tsx +20 -27
  186. package/src/components/Card/Card.tsx +12 -23
  187. package/src/components/CategoryStrip/CategoryStrip.tsx +17 -21
  188. package/src/components/Checkbox/Checkbox.tsx +26 -40
  189. package/src/components/Chip/Chip.tsx +24 -33
  190. package/src/components/CurrencyInput/CurrencyInput.tsx +10 -8
  191. package/src/components/EmptyState/EmptyState.tsx +2 -1
  192. package/src/components/ErrorBoundary/ErrorBoundary.tsx +153 -0
  193. package/src/components/ErrorBoundary/index.ts +1 -0
  194. package/src/components/HolographicCard/HolographicCard.tsx +315 -0
  195. package/src/components/HolographicCard/index.ts +1 -0
  196. package/src/components/IconButton/IconButton.tsx +19 -27
  197. package/src/components/ImageViewer/ImageViewer.tsx +290 -0
  198. package/src/components/ImageViewer/index.ts +1 -0
  199. package/src/components/ListItem/ListItem.tsx +70 -67
  200. package/src/components/MediaCard/MediaCard.tsx +8 -2
  201. package/src/components/MenuItem/MenuItem.tsx +10 -25
  202. package/src/components/MonthPicker/MonthPicker.tsx +39 -13
  203. package/src/components/MonthPicker/index.ts +1 -1
  204. package/src/components/PagerDots/PagerDots.tsx +200 -0
  205. package/src/components/PagerDots/index.ts +1 -0
  206. package/src/components/Pressable/Pressable.tsx +19 -35
  207. package/src/components/PricingCard/PricingCard.tsx +220 -0
  208. package/src/components/PricingCard/index.ts +1 -0
  209. package/src/components/RadioGroup/RadioGroup.tsx +14 -27
  210. package/src/components/RetrayProvider/RetrayProvider.tsx +59 -0
  211. package/src/components/RetrayProvider/index.ts +1 -0
  212. package/src/components/SelectableGrid/SelectableGrid.tsx +205 -0
  213. package/src/components/SelectableGrid/index.ts +1 -0
  214. package/src/components/Sheet/Sheet.tsx +65 -1
  215. package/src/components/Skeleton/Skeleton.tsx +142 -1
  216. package/src/components/Spinner/Spinner.tsx +17 -2
  217. package/src/components/Switch/Switch.tsx +30 -58
  218. package/src/components/TabBar/TabBar.tsx +169 -0
  219. package/src/components/TabBar/index.ts +1 -0
  220. package/src/components/Tabs/Tabs.tsx +23 -26
  221. package/src/components/Text/Text.tsx +2 -0
  222. package/src/components/Toggle/Toggle.tsx +35 -51
  223. package/src/fonts.ts +4 -1
  224. package/src/index.ts +23 -2
  225. package/src/utils/animations.ts +29 -1
  226. package/src/utils/fontGuard.ts +34 -0
  227. package/src/utils/haptics.ts +211 -9
  228. package/src/utils/pressable.ts +66 -0
  229. package/dist/chunk-76PFOSM2.mjs +0 -41
  230. package/dist/chunk-DITNP6PL.mjs +0 -106
  231. package/dist/chunk-JBLL7U3U.mjs +0 -64
  232. package/dist/chunk-LG4DO3DK.mjs +0 -174
  233. package/dist/chunk-RMMK64W5.mjs +0 -54
  234. package/dist/chunk-RTC3CFXF.mjs +0 -29
@@ -13,5 +13,55 @@ interface SkeletonProps {
13
13
  style?: ViewStyle;
14
14
  }
15
15
  declare function Skeleton({ width, height, borderRadius, preset, diameter, style, }: SkeletonProps): React.JSX.Element;
16
+ declare namespace Skeleton {
17
+ var MediaCard: typeof MediaCardSkeleton;
18
+ var ListItem: typeof ListItemSkeleton;
19
+ var List: typeof ListSkeleton;
20
+ }
21
+ declare const aspectRatioMap: {
22
+ readonly '1:1': 1;
23
+ readonly '4:3': number;
24
+ readonly '16:9': number;
25
+ readonly '4:5': number;
26
+ readonly '3:2': number;
27
+ };
28
+ type MediaCardSkeletonAspectRatio = keyof typeof aspectRatioMap;
29
+ interface MediaCardSkeletonProps {
30
+ /** Image aspect ratio — match your `MediaCard`. Defaults to `'4:3'`. */
31
+ aspectRatio?: MediaCardSkeletonAspectRatio;
32
+ /** Show the subtitle/caption line below the title. Defaults to true. */
33
+ showSubtitle?: boolean;
34
+ style?: ViewStyle;
35
+ }
36
+ /** Loading placeholder matching `<MediaCard>` — image block + title/subtitle lines. */
37
+ declare function MediaCardSkeleton({ aspectRatio, showSubtitle, style }: MediaCardSkeletonProps): React.JSX.Element;
38
+ interface ListItemSkeletonProps {
39
+ /** Render a circular leading avatar placeholder. Defaults to true. */
40
+ showAvatar?: boolean;
41
+ /** Render a secondary subtitle line. Defaults to true. */
42
+ showSubtitle?: boolean;
43
+ style?: ViewStyle;
44
+ }
45
+ /** Loading placeholder matching `<ListItem>` — leading circle + title/subtitle lines. */
46
+ declare function ListItemSkeleton({ showAvatar, showSubtitle, style }: ListItemSkeletonProps): React.JSX.Element;
47
+ interface ListSkeletonProps {
48
+ /** Number of placeholder rows/cells. Defaults to 6. */
49
+ count?: number;
50
+ /** 1 = stacked list of `ListItemSkeleton`; >1 = grid of `MediaCardSkeleton`. Defaults to 1. */
51
+ columns?: number;
52
+ /** Gap between items (dp). Defaults to 12. */
53
+ gap?: number;
54
+ /** Grid only — aspect ratio of each `MediaCardSkeleton`. Defaults to `'4:3'`. */
55
+ aspectRatio?: MediaCardSkeletonAspectRatio;
56
+ /** List only — show the leading avatar circle. Defaults to true. */
57
+ showAvatar?: boolean;
58
+ style?: ViewStyle;
59
+ }
60
+ /**
61
+ * Repeated loading placeholder for a `VirtualList` / list / grid. `columns={1}`
62
+ * renders stacked `ListItemSkeleton`s; `columns>1` renders a wrapping grid of
63
+ * `MediaCardSkeleton`s. Render this as the list's content while `data` is empty.
64
+ */
65
+ declare function ListSkeleton({ count, columns, gap, aspectRatio, showAvatar, style, }: ListSkeletonProps): React.JSX.Element;
16
66
 
17
67
  export { Skeleton, type SkeletonProps };
@@ -13,5 +13,55 @@ interface SkeletonProps {
13
13
  style?: ViewStyle;
14
14
  }
15
15
  declare function Skeleton({ width, height, borderRadius, preset, diameter, style, }: SkeletonProps): React.JSX.Element;
16
+ declare namespace Skeleton {
17
+ var MediaCard: typeof MediaCardSkeleton;
18
+ var ListItem: typeof ListItemSkeleton;
19
+ var List: typeof ListSkeleton;
20
+ }
21
+ declare const aspectRatioMap: {
22
+ readonly '1:1': 1;
23
+ readonly '4:3': number;
24
+ readonly '16:9': number;
25
+ readonly '4:5': number;
26
+ readonly '3:2': number;
27
+ };
28
+ type MediaCardSkeletonAspectRatio = keyof typeof aspectRatioMap;
29
+ interface MediaCardSkeletonProps {
30
+ /** Image aspect ratio — match your `MediaCard`. Defaults to `'4:3'`. */
31
+ aspectRatio?: MediaCardSkeletonAspectRatio;
32
+ /** Show the subtitle/caption line below the title. Defaults to true. */
33
+ showSubtitle?: boolean;
34
+ style?: ViewStyle;
35
+ }
36
+ /** Loading placeholder matching `<MediaCard>` — image block + title/subtitle lines. */
37
+ declare function MediaCardSkeleton({ aspectRatio, showSubtitle, style }: MediaCardSkeletonProps): React.JSX.Element;
38
+ interface ListItemSkeletonProps {
39
+ /** Render a circular leading avatar placeholder. Defaults to true. */
40
+ showAvatar?: boolean;
41
+ /** Render a secondary subtitle line. Defaults to true. */
42
+ showSubtitle?: boolean;
43
+ style?: ViewStyle;
44
+ }
45
+ /** Loading placeholder matching `<ListItem>` — leading circle + title/subtitle lines. */
46
+ declare function ListItemSkeleton({ showAvatar, showSubtitle, style }: ListItemSkeletonProps): React.JSX.Element;
47
+ interface ListSkeletonProps {
48
+ /** Number of placeholder rows/cells. Defaults to 6. */
49
+ count?: number;
50
+ /** 1 = stacked list of `ListItemSkeleton`; >1 = grid of `MediaCardSkeleton`. Defaults to 1. */
51
+ columns?: number;
52
+ /** Gap between items (dp). Defaults to 12. */
53
+ gap?: number;
54
+ /** Grid only — aspect ratio of each `MediaCardSkeleton`. Defaults to `'4:3'`. */
55
+ aspectRatio?: MediaCardSkeletonAspectRatio;
56
+ /** List only — show the leading avatar circle. Defaults to true. */
57
+ showAvatar?: boolean;
58
+ style?: ViewStyle;
59
+ }
60
+ /**
61
+ * Repeated loading placeholder for a `VirtualList` / list / grid. `columns={1}`
62
+ * renders stacked `ListItemSkeleton`s; `columns>1` renders a wrapping grid of
63
+ * `MediaCardSkeleton`s. Render this as the list's content while `data` is empty.
64
+ */
65
+ declare function ListSkeleton({ count, columns, gap, aspectRatio, showAvatar, style, }: ListSkeletonProps): React.JSX.Element;
16
66
 
17
67
  export { Skeleton, type SkeletonProps };
package/dist/Skeleton.js CHANGED
@@ -133,6 +133,7 @@ function useTheme() {
133
133
  }
134
134
  var isWeb = reactNative.Platform.OS === "web";
135
135
  var s = isWeb ? (n) => n : reactNativeSizeMatters.scale;
136
+ var vs = isWeb ? (n) => n : reactNativeSizeMatters.verticalScale;
136
137
  var TIMINGS = {
137
138
  /** Skeleton shimmer cycle (full pass). */
138
139
  shimmer: { duration: 1400 }
@@ -146,6 +147,11 @@ var TIMINGS = {
146
147
  collapse: Animated.Easing.in(Animated.Easing.ease)
147
148
  });
148
149
 
150
+ // src/tokens.ts
151
+ var RADIUS = {
152
+ xs: 4,
153
+ md: 14};
154
+
149
155
  // src/components/Skeleton/Skeleton.tsx
150
156
  function Skeleton({
151
157
  width = "100%",
@@ -196,10 +202,65 @@ function Skeleton({
196
202
  ))
197
203
  );
198
204
  }
205
+ var aspectRatioMap = {
206
+ "1:1": 1,
207
+ "4:3": 3 / 4,
208
+ "16:9": 9 / 16,
209
+ "4:5": 5 / 4,
210
+ "3:2": 2 / 3
211
+ };
212
+ function MediaCardSkeleton({ aspectRatio = "4:3", showSubtitle = true, style }) {
213
+ const ratio = aspectRatioMap[aspectRatio];
214
+ return /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style }, /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: { paddingTop: `${ratio * 100}%` } }, /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: reactNative.StyleSheet.absoluteFill }, /* @__PURE__ */ React2__default.default.createElement(Skeleton, { width: "100%", height: void 0, style: skeletonStyles.fill, borderRadius: RADIUS.md }))), /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: skeletonStyles.meta }, /* @__PURE__ */ React2__default.default.createElement(Skeleton, { width: "70%", height: vs(14), borderRadius: RADIUS.xs }), showSubtitle ? /* @__PURE__ */ React2__default.default.createElement(Skeleton, { width: "45%", height: vs(12), borderRadius: RADIUS.xs }) : null));
215
+ }
216
+ function ListItemSkeleton({ showAvatar = true, showSubtitle = true, style }) {
217
+ return /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: [skeletonStyles.row, style] }, showAvatar ? /* @__PURE__ */ React2__default.default.createElement(Skeleton, { preset: "circle", diameter: 40 }) : null, /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: skeletonStyles.rowText }, /* @__PURE__ */ React2__default.default.createElement(Skeleton, { width: "60%", height: vs(14), borderRadius: RADIUS.xs }), showSubtitle ? /* @__PURE__ */ React2__default.default.createElement(Skeleton, { width: "40%", height: vs(12), borderRadius: RADIUS.xs }) : null));
218
+ }
219
+ function ListSkeleton({
220
+ count = 6,
221
+ columns = 1,
222
+ gap = 12,
223
+ aspectRatio = "4:3",
224
+ showAvatar = true,
225
+ style
226
+ }) {
227
+ if (columns <= 1) {
228
+ return /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: [{ gap: vs(gap) }, style] }, Array.from({ length: count }).map((_, i) => /* @__PURE__ */ React2__default.default.createElement(ListItemSkeleton, { key: i, showAvatar })));
229
+ }
230
+ const widthPct = `${100 / columns}%`;
231
+ return /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: [skeletonStyles.grid, { marginHorizontal: -s(gap) / 2 }, style] }, Array.from({ length: count }).map((_, i) => /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { key: i, style: { width: widthPct, paddingHorizontal: s(gap) / 2, marginBottom: vs(gap) } }, /* @__PURE__ */ React2__default.default.createElement(MediaCardSkeleton, { aspectRatio }))));
232
+ }
233
+ Skeleton.MediaCard = MediaCardSkeleton;
234
+ Skeleton.ListItem = ListItemSkeleton;
235
+ Skeleton.List = ListSkeleton;
199
236
  var styles = reactNative.StyleSheet.create({
200
237
  base: {
201
238
  overflow: "hidden"
202
239
  }
203
240
  });
241
+ var skeletonStyles = reactNative.StyleSheet.create({
242
+ grid: {
243
+ flexDirection: "row",
244
+ flexWrap: "wrap"
245
+ },
246
+ fill: {
247
+ width: "100%",
248
+ height: "100%"
249
+ },
250
+ meta: {
251
+ paddingTop: vs(8),
252
+ gap: vs(6)
253
+ },
254
+ row: {
255
+ flexDirection: "row",
256
+ alignItems: "center",
257
+ gap: s(12),
258
+ paddingVertical: vs(8)
259
+ },
260
+ rowText: {
261
+ flex: 1,
262
+ gap: vs(6)
263
+ }
264
+ });
204
265
 
205
266
  exports.Skeleton = Skeleton;
package/dist/Skeleton.mjs CHANGED
@@ -1,4 +1,6 @@
1
- export { Skeleton } from './chunk-JBLL7U3U.mjs';
2
- import './chunk-5IKW3VNC.mjs';
1
+ export { Skeleton } from './chunk-AJ7ZDNBT.mjs';
2
+ import './chunk-DVK4G2GT.mjs';
3
+ import './chunk-QY3X2UYR.mjs';
3
4
  import './chunk-SOYNZDVY.mjs';
4
5
  import './chunk-2CE3TQVY.mjs';
6
+ import './chunk-Y6FXYEAI.mjs';
package/dist/Slider.js CHANGED
@@ -10,18 +10,65 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
10
  var React2__default = /*#__PURE__*/_interopDefault(React2);
11
11
  var RNSlider__default = /*#__PURE__*/_interopDefault(RNSlider);
12
12
 
13
- // src/components/Slider/Slider.tsx
13
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
14
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
15
+ }) : x)(function(x) {
16
+ if (typeof require !== "undefined") return require.apply(this, arguments);
17
+ throw Error('Dynamic require of "' + x + '" is not supported');
18
+ });
14
19
  var _haptics = null;
20
+ var _hapticsLoaded = false;
15
21
  async function getHaptics() {
16
22
  if (reactNative.Platform.OS === "web") return null;
17
- if (!_haptics) {
18
- _haptics = await import('expo-haptics');
23
+ if (!_hapticsLoaded) {
24
+ _hapticsLoaded = true;
25
+ try {
26
+ _haptics = await import('expo-haptics');
27
+ } catch {
28
+ _haptics = null;
29
+ }
19
30
  }
20
31
  return _haptics;
21
32
  }
33
+ var _pulsar = null;
34
+ var _pulsarChecked = false;
35
+ var _pulsarAvailable = false;
36
+ function isPulsarNativeRegistered() {
37
+ try {
38
+ const g = globalThis;
39
+ if (typeof g.__turboModuleProxy === "function") {
40
+ return g.__turboModuleProxy("RNPulsar") != null;
41
+ }
42
+ return reactNative.NativeModules?.RNPulsar != null;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+ function getPulsar() {
48
+ if (reactNative.Platform.OS === "web") return null;
49
+ if (!_pulsarChecked) {
50
+ _pulsarChecked = true;
51
+ try {
52
+ if (isPulsarNativeRegistered()) {
53
+ _pulsar = __require("react-native-pulsar");
54
+ _pulsarAvailable = true;
55
+ }
56
+ } catch {
57
+ _pulsar = null;
58
+ _pulsarAvailable = false;
59
+ }
60
+ }
61
+ return _pulsarAvailable ? _pulsar : null;
62
+ }
22
63
  function selectionAsync() {
23
64
  if (reactNative.Platform.OS === "web") return;
24
- getHaptics().then((h) => h?.selectionAsync());
65
+ getHaptics().then((h) => {
66
+ if (h) {
67
+ h.selectionAsync();
68
+ } else {
69
+ getPulsar()?.Presets.System.selection();
70
+ }
71
+ });
25
72
  }
26
73
 
27
74
  // src/theme/colorUtils.ts
package/dist/Slider.mjs CHANGED
@@ -1,4 +1,5 @@
1
- export { Slider } from './chunk-NQGVLMWG.mjs';
2
- import './chunk-RTC3CFXF.mjs';
1
+ export { Slider } from './chunk-JMOZEC77.mjs';
2
+ import './chunk-EJ7ZPXOH.mjs';
3
3
  import './chunk-SOYNZDVY.mjs';
4
4
  import './chunk-2CE3TQVY.mjs';
5
+ import './chunk-Y6FXYEAI.mjs';
package/dist/Spinner.js CHANGED
@@ -146,17 +146,38 @@ var labelFontSize = {
146
146
  };
147
147
  function Spinner({ size = "md", color, label, ...props }) {
148
148
  const { colors } = useTheme();
149
+ const a11yLabel = label || "Loading";
149
150
  if (label) {
150
- return /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: styles.wrapper }, /* @__PURE__ */ React2__default.default.createElement(reactNative.ActivityIndicator, { size: sizeMap[size], color: color ?? colors.primary, ...props }), /* @__PURE__ */ React2__default.default.createElement(
151
- reactNative.Text,
151
+ return /* @__PURE__ */ React2__default.default.createElement(
152
+ reactNative.View,
152
153
  {
153
- style: [styles.label, { color: colors.foregroundMuted, fontSize: labelFontSize[size] }],
154
- allowFontScaling: true
154
+ style: styles.wrapper,
155
+ accessibilityRole: "progressbar",
156
+ accessibilityLabel: a11yLabel,
157
+ accessibilityState: { busy: true }
155
158
  },
156
- label
157
- ));
159
+ /* @__PURE__ */ React2__default.default.createElement(reactNative.ActivityIndicator, { size: sizeMap[size], color: color ?? colors.primary, ...props }),
160
+ /* @__PURE__ */ React2__default.default.createElement(
161
+ reactNative.Text,
162
+ {
163
+ style: [styles.label, { color: colors.foregroundMuted, fontSize: labelFontSize[size] }],
164
+ allowFontScaling: true
165
+ },
166
+ label
167
+ )
168
+ );
158
169
  }
159
- return /* @__PURE__ */ React2__default.default.createElement(reactNative.ActivityIndicator, { size: sizeMap[size], color: color ?? colors.primary, ...props });
170
+ return /* @__PURE__ */ React2__default.default.createElement(
171
+ reactNative.ActivityIndicator,
172
+ {
173
+ size: sizeMap[size],
174
+ color: color ?? colors.primary,
175
+ accessibilityRole: "progressbar",
176
+ accessibilityLabel: a11yLabel,
177
+ accessibilityState: { busy: true },
178
+ ...props
179
+ }
180
+ );
160
181
  }
161
182
  var styles = reactNative.StyleSheet.create({
162
183
  wrapper: {
package/dist/Spinner.mjs CHANGED
@@ -1,3 +1,4 @@
1
- export { Spinner } from './chunk-76PFOSM2.mjs';
1
+ export { Spinner } from './chunk-WBOOUHSS.mjs';
2
2
  import './chunk-SOYNZDVY.mjs';
3
3
  import './chunk-2CE3TQVY.mjs';
4
+ import './chunk-Y6FXYEAI.mjs';
package/dist/Switch.js CHANGED
@@ -2,27 +2,74 @@
2
2
 
3
3
  var React2 = require('react');
4
4
  var reactNative = require('react-native');
5
- var Animated = require('react-native-reanimated');
5
+ var reactNativeEase = require('react-native-ease');
6
6
  var vectorIcons = require('@expo/vector-icons');
7
7
  var reactNativeSizeMatters = require('react-native-size-matters');
8
+ var reactNativeReanimated = require('react-native-reanimated');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
11
 
11
12
  var React2__default = /*#__PURE__*/_interopDefault(React2);
12
- var Animated__default = /*#__PURE__*/_interopDefault(Animated);
13
13
 
14
- // src/components/Switch/Switch.tsx
14
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
15
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
16
+ }) : x)(function(x) {
17
+ if (typeof require !== "undefined") return require.apply(this, arguments);
18
+ throw Error('Dynamic require of "' + x + '" is not supported');
19
+ });
15
20
  var _haptics = null;
21
+ var _hapticsLoaded = false;
16
22
  async function getHaptics() {
17
23
  if (reactNative.Platform.OS === "web") return null;
18
- if (!_haptics) {
19
- _haptics = await import('expo-haptics');
24
+ if (!_hapticsLoaded) {
25
+ _hapticsLoaded = true;
26
+ try {
27
+ _haptics = await import('expo-haptics');
28
+ } catch {
29
+ _haptics = null;
30
+ }
20
31
  }
21
32
  return _haptics;
22
33
  }
34
+ var _pulsar = null;
35
+ var _pulsarChecked = false;
36
+ var _pulsarAvailable = false;
37
+ function isPulsarNativeRegistered() {
38
+ try {
39
+ const g = globalThis;
40
+ if (typeof g.__turboModuleProxy === "function") {
41
+ return g.__turboModuleProxy("RNPulsar") != null;
42
+ }
43
+ return reactNative.NativeModules?.RNPulsar != null;
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ function getPulsar() {
49
+ if (reactNative.Platform.OS === "web") return null;
50
+ if (!_pulsarChecked) {
51
+ _pulsarChecked = true;
52
+ try {
53
+ if (isPulsarNativeRegistered()) {
54
+ _pulsar = __require("react-native-pulsar");
55
+ _pulsarAvailable = true;
56
+ }
57
+ } catch {
58
+ _pulsar = null;
59
+ _pulsarAvailable = false;
60
+ }
61
+ }
62
+ return _pulsarAvailable ? _pulsar : null;
63
+ }
23
64
  function selectionAsync() {
24
65
  if (reactNative.Platform.OS === "web") return;
25
- getHaptics().then((h) => h?.selectionAsync());
66
+ getHaptics().then((h) => {
67
+ if (h) {
68
+ h.selectionAsync();
69
+ } else {
70
+ getPulsar()?.Presets.System.selection();
71
+ }
72
+ });
26
73
  }
27
74
 
28
75
  // src/theme/colorUtils.ts
@@ -145,20 +192,32 @@ function useTheme() {
145
192
  }
146
193
  var isWeb = reactNative.Platform.OS === "web";
147
194
  var s = isWeb ? (n) => n : reactNativeSizeMatters.scale;
148
- var SPRINGS = {
149
- /** Elastic indicator — Switch thumb, RadioGroup dot. */
150
- elastic: { stiffness: 320, damping: 22, mass: 0.7 }
151
- };
152
195
  var TIMINGS = {
153
196
  /** Color/opacity transitions on toggles, checkboxes, switches. */
154
197
  state: { duration: 160 }};
155
- var EASINGS = {
198
+ ({
156
199
  /** Material-style ease-out — natural deceleration for state changes. */
157
- standard: Animated.Easing.bezier(0.2, 0, 0, 1),
200
+ standard: reactNativeReanimated.Easing.bezier(0.2, 0, 0, 1),
158
201
  /** Strong ease-out for expanding surfaces (Accordion open). */
159
- expand: Animated.Easing.bezier(0.23, 1, 0.32, 1),
202
+ expand: reactNativeReanimated.Easing.bezier(0.23, 1, 0.32, 1),
160
203
  /** Quick ease-in for collapsing. */
161
- collapse: Animated.Easing.in(Animated.Easing.ease)
204
+ collapse: reactNativeReanimated.Easing.in(reactNativeReanimated.Easing.ease)
205
+ });
206
+ var COLOR_TRANSITION = {
207
+ type: "timing",
208
+ duration: TIMINGS.state.duration,
209
+ easing: [0.2, 0, 0, 1]
210
+ };
211
+ var OPACITY_TRANSITION = {
212
+ type: "timing",
213
+ duration: TIMINGS.state.duration,
214
+ easing: [0.2, 0, 0, 1]
215
+ };
216
+ var SPRING_ELASTIC = {
217
+ type: "spring",
218
+ stiffness: 320,
219
+ damping: 22,
220
+ mass: 0.7
162
221
  };
163
222
 
164
223
  // src/components/Switch/Switch.tsx
@@ -170,34 +229,6 @@ var THUMB_TRAVEL = TRACK_WIDTH - THUMB_SIZE - THUMB_OFFSET * 2;
170
229
  var ICON_SIZE = s(13);
171
230
  function Switch({ checked = false, onCheckedChange, disabled, style, accessibilityLabel }) {
172
231
  const { colors } = useTheme();
173
- const progress = Animated.useSharedValue(checked ? 1 : 0);
174
- React2.useEffect(() => {
175
- progress.value = Animated.withSpring(checked ? 1 : 0, SPRINGS.elastic);
176
- }, [checked, progress]);
177
- const thumbStyle = Animated.useAnimatedStyle(() => ({
178
- transform: [{ translateX: progress.value * THUMB_TRAVEL }]
179
- }));
180
- const trackStyle = Animated.useAnimatedStyle(() => ({
181
- backgroundColor: Animated.interpolateColor(
182
- progress.value,
183
- [0, 1],
184
- [colors.surfaceStrong, colors.primary]
185
- )
186
- }));
187
- const trackBorderStyle = Animated.useAnimatedStyle(() => ({
188
- borderWidth: 1.5,
189
- borderColor: Animated.interpolateColor(
190
- progress.value,
191
- [0, 1],
192
- [colors.border, "transparent"]
193
- )
194
- }));
195
- const checkIconStyle = Animated.useAnimatedStyle(() => ({
196
- opacity: Animated.withTiming(checked ? 1 : 0, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
197
- }));
198
- const crossIconStyle = Animated.useAnimatedStyle(() => ({
199
- opacity: Animated.withTiming(checked ? 0 : 1, { duration: TIMINGS.state.duration, easing: EASINGS.standard })
200
- }));
201
232
  return /* @__PURE__ */ React2__default.default.createElement(reactNative.View, { style: [{ opacity: disabled ? 0.45 : 1, alignSelf: "flex-start" }, style] }, /* @__PURE__ */ React2__default.default.createElement(
202
233
  reactNative.TouchableOpacity,
203
234
  {
@@ -213,14 +244,33 @@ function Switch({ checked = false, onCheckedChange, disabled, style, accessibili
213
244
  accessibilityState: { checked, disabled: !!disabled },
214
245
  style: styles.touchable
215
246
  },
216
- /* @__PURE__ */ React2__default.default.createElement(Animated__default.default.View, { style: [styles.track, trackStyle] }, /* @__PURE__ */ React2__default.default.createElement(Animated__default.default.View, { style: [styles.trackBorder, trackBorderStyle], pointerEvents: "none" }), /* @__PURE__ */ React2__default.default.createElement(
217
- Animated__default.default.View,
247
+ /* @__PURE__ */ React2__default.default.createElement(
248
+ reactNativeEase.EaseView,
218
249
  {
219
- style: [styles.thumb, { backgroundColor: colors.primaryForeground }, thumbStyle]
250
+ style: styles.track,
251
+ animate: { backgroundColor: checked ? colors.primary : colors.surfaceStrong },
252
+ transition: COLOR_TRANSITION
220
253
  },
221
- /* @__PURE__ */ React2__default.default.createElement(Animated__default.default.View, { style: [styles.iconWrapper, checkIconStyle] }, /* @__PURE__ */ React2__default.default.createElement(vectorIcons.Feather, { name: "check", size: ICON_SIZE, color: colors.primary })),
222
- /* @__PURE__ */ React2__default.default.createElement(Animated__default.default.View, { style: [styles.iconWrapper, crossIconStyle] }, /* @__PURE__ */ React2__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
223
- ))
254
+ /* @__PURE__ */ React2__default.default.createElement(
255
+ reactNativeEase.EaseView,
256
+ {
257
+ style: [styles.trackBorder, { borderWidth: 1.5 }],
258
+ pointerEvents: "none",
259
+ animate: { borderColor: checked ? "transparent" : colors.border },
260
+ transition: COLOR_TRANSITION
261
+ }
262
+ ),
263
+ /* @__PURE__ */ React2__default.default.createElement(
264
+ reactNativeEase.EaseView,
265
+ {
266
+ style: [styles.thumb, { backgroundColor: colors.primaryForeground }],
267
+ animate: { translateX: checked ? THUMB_TRAVEL : 0 },
268
+ transition: SPRING_ELASTIC
269
+ },
270
+ /* @__PURE__ */ React2__default.default.createElement(reactNativeEase.EaseView, { style: styles.iconWrapper, animate: { opacity: checked ? 1 : 0 }, transition: OPACITY_TRANSITION }, /* @__PURE__ */ React2__default.default.createElement(vectorIcons.Feather, { name: "check", size: ICON_SIZE, color: colors.primary })),
271
+ /* @__PURE__ */ React2__default.default.createElement(reactNativeEase.EaseView, { style: styles.iconWrapper, animate: { opacity: checked ? 0 : 1 }, transition: OPACITY_TRANSITION }, /* @__PURE__ */ React2__default.default.createElement(vectorIcons.Feather, { name: "x", size: ICON_SIZE, color: colors.foregroundMuted }))
272
+ )
273
+ )
224
274
  ));
225
275
  }
226
276
  var styles = reactNative.StyleSheet.create({
package/dist/Switch.mjs CHANGED
@@ -1,5 +1,6 @@
1
- export { Switch } from './chunk-DITNP6PL.mjs';
2
- import './chunk-RTC3CFXF.mjs';
3
- import './chunk-5IKW3VNC.mjs';
1
+ export { Switch } from './chunk-QKH5ZOD5.mjs';
2
+ import './chunk-EJ7ZPXOH.mjs';
3
+ import './chunk-DVK4G2GT.mjs';
4
4
  import './chunk-SOYNZDVY.mjs';
5
5
  import './chunk-2CE3TQVY.mjs';
6
+ import './chunk-Y6FXYEAI.mjs';
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+
4
+ interface TabBarItem {
5
+ /** Unique key for the tab. */
6
+ key: string;
7
+ /** Label under the icon. Omit for an icon-only tab. */
8
+ label?: string;
9
+ /** Icon name (active + inactive share the name; color signals state). */
10
+ iconName?: string;
11
+ /** Custom icon node — receives no state, overrides `iconName`. */
12
+ icon?: React.ReactNode;
13
+ /** Badge overlay — `true` shows a dot, a number shows a count (capped at 99). */
14
+ badge?: boolean | number;
15
+ }
16
+ interface TabBarProps {
17
+ items: TabBarItem[];
18
+ /** Key of the active tab. */
19
+ activeKey: string;
20
+ onTabPress: (key: string) => void;
21
+ /** Active tint. Defaults to theme `primary`. */
22
+ activeColor?: string;
23
+ /** Inactive tint. Defaults to theme `foregroundMuted`. */
24
+ inactiveColor?: string;
25
+ /** Apply the bottom safe-area inset as padding. Defaults to true. */
26
+ withSafeArea?: boolean;
27
+ style?: ViewStyle;
28
+ }
29
+ /**
30
+ * Bottom tab bar — icon + label tabs with active tint and badge support. Pair
31
+ * with your navigator, or drive it with local state for a single-screen app.
32
+ *
33
+ * @example
34
+ * <TabBar
35
+ * items={[{ key: 'home', label: 'Home', iconName: 'home' }, { key: 'profile', label: 'Profile', iconName: 'user', badge: 3 }]}
36
+ * activeKey={tab}
37
+ * onTabPress={setTab}
38
+ * />
39
+ */
40
+ declare function TabBar({ items, activeKey, onTabPress, activeColor, inactiveColor, withSafeArea, style, }: TabBarProps): React.JSX.Element;
41
+
42
+ export { TabBar, type TabBarItem, type TabBarProps };
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+
4
+ interface TabBarItem {
5
+ /** Unique key for the tab. */
6
+ key: string;
7
+ /** Label under the icon. Omit for an icon-only tab. */
8
+ label?: string;
9
+ /** Icon name (active + inactive share the name; color signals state). */
10
+ iconName?: string;
11
+ /** Custom icon node — receives no state, overrides `iconName`. */
12
+ icon?: React.ReactNode;
13
+ /** Badge overlay — `true` shows a dot, a number shows a count (capped at 99). */
14
+ badge?: boolean | number;
15
+ }
16
+ interface TabBarProps {
17
+ items: TabBarItem[];
18
+ /** Key of the active tab. */
19
+ activeKey: string;
20
+ onTabPress: (key: string) => void;
21
+ /** Active tint. Defaults to theme `primary`. */
22
+ activeColor?: string;
23
+ /** Inactive tint. Defaults to theme `foregroundMuted`. */
24
+ inactiveColor?: string;
25
+ /** Apply the bottom safe-area inset as padding. Defaults to true. */
26
+ withSafeArea?: boolean;
27
+ style?: ViewStyle;
28
+ }
29
+ /**
30
+ * Bottom tab bar — icon + label tabs with active tint and badge support. Pair
31
+ * with your navigator, or drive it with local state for a single-screen app.
32
+ *
33
+ * @example
34
+ * <TabBar
35
+ * items={[{ key: 'home', label: 'Home', iconName: 'home' }, { key: 'profile', label: 'Profile', iconName: 'user', badge: 3 }]}
36
+ * activeKey={tab}
37
+ * onTabPress={setTab}
38
+ * />
39
+ */
40
+ declare function TabBar({ items, activeKey, onTabPress, activeColor, inactiveColor, withSafeArea, style, }: TabBarProps): React.JSX.Element;
41
+
42
+ export { TabBar, type TabBarItem, type TabBarProps };