panelui-native 0.22.6 → 0.28.1

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 (258) hide show
  1. package/README.md +1 -0
  2. package/lib/module/components/accordion/index.js +8 -8
  3. package/lib/module/components/accordion/index.js.map +1 -1
  4. package/lib/module/components/alert/index.js +2 -2
  5. package/lib/module/components/alert/index.js.map +1 -1
  6. package/lib/module/components/area-chart/index.js +958 -0
  7. package/lib/module/components/area-chart/index.js.map +1 -0
  8. package/lib/module/components/attachment/index.js +2 -1
  9. package/lib/module/components/attachment/index.js.map +1 -1
  10. package/lib/module/components/avatar/index.js +4 -4
  11. package/lib/module/components/avatar/index.js.map +1 -1
  12. package/lib/module/components/badge/index.js +4 -4
  13. package/lib/module/components/badge/index.js.map +1 -1
  14. package/lib/module/components/bar-chart/index.js +994 -0
  15. package/lib/module/components/bar-chart/index.js.map +1 -0
  16. package/lib/module/components/bottom-sheet/index.js +213 -24
  17. package/lib/module/components/bottom-sheet/index.js.map +1 -1
  18. package/lib/module/components/breadcrumb/index.js +275 -0
  19. package/lib/module/components/breadcrumb/index.js.map +1 -0
  20. package/lib/module/components/button/index.js +11 -6
  21. package/lib/module/components/button/index.js.map +1 -1
  22. package/lib/module/components/calendar/index.js +557 -0
  23. package/lib/module/components/calendar/index.js.map +1 -0
  24. package/lib/module/components/carousel/index.js +680 -0
  25. package/lib/module/components/carousel/index.js.map +1 -0
  26. package/lib/module/components/chip/index.js +6 -6
  27. package/lib/module/components/chip/index.js.map +1 -1
  28. package/lib/module/components/date-picker/index.js +158 -0
  29. package/lib/module/components/date-picker/index.js.map +1 -0
  30. package/lib/module/components/dialog/index.js +7 -2
  31. package/lib/module/components/dialog/index.js.map +1 -1
  32. package/lib/module/components/direction/index.js +15 -20
  33. package/lib/module/components/direction/index.js.map +1 -1
  34. package/lib/module/components/empty-state/index.js +2 -2
  35. package/lib/module/components/empty-state/index.js.map +1 -1
  36. package/lib/module/components/field/index.js +5 -5
  37. package/lib/module/components/field/index.js.map +1 -1
  38. package/lib/module/components/flow/index.js +3 -3
  39. package/lib/module/components/flow/index.js.map +1 -1
  40. package/lib/module/components/frame/index.js +22 -5
  41. package/lib/module/components/frame/index.js.map +1 -1
  42. package/lib/module/components/heatmap-chart/index.js +28 -8
  43. package/lib/module/components/heatmap-chart/index.js.map +1 -1
  44. package/lib/module/components/input-group/index.js +5 -4
  45. package/lib/module/components/input-group/index.js.map +1 -1
  46. package/lib/module/components/item/index.js +9 -9
  47. package/lib/module/components/item/index.js.map +1 -1
  48. package/lib/module/components/label/index.js +4 -4
  49. package/lib/module/components/label/index.js.map +1 -1
  50. package/lib/module/components/line-chart/index.js +165 -184
  51. package/lib/module/components/line-chart/index.js.map +1 -1
  52. package/lib/module/components/loader/index.js +758 -0
  53. package/lib/module/components/loader/index.js.map +1 -0
  54. package/lib/module/components/map/basemap.js +265 -0
  55. package/lib/module/components/map/basemap.js.map +1 -0
  56. package/lib/module/components/map/index.js +850 -0
  57. package/lib/module/components/map/index.js.map +1 -0
  58. package/lib/module/components/map/maplibre.js +87 -0
  59. package/lib/module/components/map/maplibre.js.map +1 -0
  60. package/lib/module/components/marker/index.js +3 -3
  61. package/lib/module/components/marker/index.js.map +1 -1
  62. package/lib/module/components/message/index.js +15 -14
  63. package/lib/module/components/message/index.js.map +1 -1
  64. package/lib/module/components/message-scroller/index.js +5 -4
  65. package/lib/module/components/message-scroller/index.js.map +1 -1
  66. package/lib/module/components/otp-input/index.js +2 -2
  67. package/lib/module/components/popover/index.js +39 -7
  68. package/lib/module/components/popover/index.js.map +1 -1
  69. package/lib/module/components/progress/index.js +8 -2
  70. package/lib/module/components/progress/index.js.map +1 -1
  71. package/lib/module/components/radio-group/index.js +2 -2
  72. package/lib/module/components/radio-group/index.js.map +1 -1
  73. package/lib/module/components/ring-chart/index.js +423 -0
  74. package/lib/module/components/ring-chart/index.js.map +1 -0
  75. package/lib/module/components/section-rail/index.js +6 -6
  76. package/lib/module/components/section-rail/index.js.map +1 -1
  77. package/lib/module/components/select/index.js +10 -4
  78. package/lib/module/components/select/index.js.map +1 -1
  79. package/lib/module/components/separator/index.js +76 -22
  80. package/lib/module/components/separator/index.js.map +1 -1
  81. package/lib/module/components/shimmer/index.js +10 -1
  82. package/lib/module/components/shimmer/index.js.map +1 -1
  83. package/lib/module/components/slider/index.js +19 -5
  84. package/lib/module/components/slider/index.js.map +1 -1
  85. package/lib/module/components/steps/index.js +5 -5
  86. package/lib/module/components/steps/index.js.map +1 -1
  87. package/lib/module/components/switch/index.js +6 -1
  88. package/lib/module/components/switch/index.js.map +1 -1
  89. package/lib/module/components/tabs/index.js +7 -7
  90. package/lib/module/components/tabs/index.js.map +1 -1
  91. package/lib/module/components/timeline/index.js +4 -4
  92. package/lib/module/components/timeline/index.js.map +1 -1
  93. package/lib/module/components/toast/index.js +2 -2
  94. package/lib/module/components/toast/index.js.map +1 -1
  95. package/lib/module/components/toggle-button/index.js +5 -5
  96. package/lib/module/components/toggle-button/index.js.map +1 -1
  97. package/lib/module/components/tooltip/index.js +492 -0
  98. package/lib/module/components/tooltip/index.js.map +1 -0
  99. package/lib/module/components/typography/index.js +7 -2
  100. package/lib/module/components/typography/index.js.map +1 -1
  101. package/lib/module/hooks/index.js +1 -0
  102. package/lib/module/hooks/index.js.map +1 -1
  103. package/lib/module/hooks/use-back-handler.js +37 -0
  104. package/lib/module/hooks/use-back-handler.js.map +1 -0
  105. package/lib/module/hooks/use-direction.js +43 -0
  106. package/lib/module/hooks/use-direction.js.map +1 -0
  107. package/lib/module/icons/index.js +180 -2
  108. package/lib/module/icons/index.js.map +1 -1
  109. package/lib/module/index.js +12 -2
  110. package/lib/module/index.js.map +1 -1
  111. package/lib/module/primitives/keyboard-avoider.js +2 -1
  112. package/lib/module/primitives/keyboard-avoider.js.map +1 -1
  113. package/lib/module/primitives/text.js +55 -11
  114. package/lib/module/primitives/text.js.map +1 -1
  115. package/lib/module/utils/chart.js +279 -0
  116. package/lib/module/utils/chart.js.map +1 -0
  117. package/lib/module/utils/date.js +386 -0
  118. package/lib/module/utils/date.js.map +1 -0
  119. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  120. package/lib/typescript/src/components/alert/index.d.ts.map +1 -1
  121. package/lib/typescript/src/components/area-chart/index.d.ts +237 -0
  122. package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -0
  123. package/lib/typescript/src/components/attachment/index.d.ts.map +1 -1
  124. package/lib/typescript/src/components/bar-chart/index.d.ts +270 -0
  125. package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -0
  126. package/lib/typescript/src/components/bottom-sheet/index.d.ts +75 -4
  127. package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
  128. package/lib/typescript/src/components/breadcrumb/index.d.ts +100 -0
  129. package/lib/typescript/src/components/breadcrumb/index.d.ts.map +1 -0
  130. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  131. package/lib/typescript/src/components/calendar/index.d.ts +108 -0
  132. package/lib/typescript/src/components/calendar/index.d.ts.map +1 -0
  133. package/lib/typescript/src/components/carousel/index.d.ts +179 -0
  134. package/lib/typescript/src/components/carousel/index.d.ts.map +1 -0
  135. package/lib/typescript/src/components/chip/index.d.ts.map +1 -1
  136. package/lib/typescript/src/components/date-picker/index.d.ts +91 -0
  137. package/lib/typescript/src/components/date-picker/index.d.ts.map +1 -0
  138. package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
  139. package/lib/typescript/src/components/direction/index.d.ts +11 -10
  140. package/lib/typescript/src/components/direction/index.d.ts.map +1 -1
  141. package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
  142. package/lib/typescript/src/components/field/index.d.ts.map +1 -1
  143. package/lib/typescript/src/components/frame/index.d.ts +17 -0
  144. package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
  145. package/lib/typescript/src/components/heatmap-chart/index.d.ts +22 -3
  146. package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
  147. package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
  148. package/lib/typescript/src/components/item/index.d.ts.map +1 -1
  149. package/lib/typescript/src/components/label/index.d.ts.map +1 -1
  150. package/lib/typescript/src/components/line-chart/index.d.ts +42 -2
  151. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
  152. package/lib/typescript/src/components/loader/index.d.ts +38 -0
  153. package/lib/typescript/src/components/loader/index.d.ts.map +1 -0
  154. package/lib/typescript/src/components/map/basemap.d.ts +76 -0
  155. package/lib/typescript/src/components/map/basemap.d.ts.map +1 -0
  156. package/lib/typescript/src/components/map/index.d.ts +367 -0
  157. package/lib/typescript/src/components/map/index.d.ts.map +1 -0
  158. package/lib/typescript/src/components/map/maplibre.d.ts +193 -0
  159. package/lib/typescript/src/components/map/maplibre.d.ts.map +1 -0
  160. package/lib/typescript/src/components/marker/index.d.ts.map +1 -1
  161. package/lib/typescript/src/components/message/index.d.ts.map +1 -1
  162. package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -1
  163. package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
  164. package/lib/typescript/src/components/progress/index.d.ts.map +1 -1
  165. package/lib/typescript/src/components/ring-chart/index.d.ts +156 -0
  166. package/lib/typescript/src/components/ring-chart/index.d.ts.map +1 -0
  167. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  168. package/lib/typescript/src/components/separator/index.d.ts +36 -1
  169. package/lib/typescript/src/components/separator/index.d.ts.map +1 -1
  170. package/lib/typescript/src/components/shimmer/index.d.ts.map +1 -1
  171. package/lib/typescript/src/components/slider/index.d.ts.map +1 -1
  172. package/lib/typescript/src/components/steps/index.d.ts.map +1 -1
  173. package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
  174. package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
  175. package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
  176. package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
  177. package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -1
  178. package/lib/typescript/src/components/tooltip/index.d.ts +125 -0
  179. package/lib/typescript/src/components/tooltip/index.d.ts.map +1 -0
  180. package/lib/typescript/src/components/typography/index.d.ts +6 -0
  181. package/lib/typescript/src/components/typography/index.d.ts.map +1 -1
  182. package/lib/typescript/src/hooks/index.d.ts +1 -0
  183. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  184. package/lib/typescript/src/hooks/use-back-handler.d.ts +19 -0
  185. package/lib/typescript/src/hooks/use-back-handler.d.ts.map +1 -0
  186. package/lib/typescript/src/hooks/use-direction.d.ts +20 -0
  187. package/lib/typescript/src/hooks/use-direction.d.ts.map +1 -0
  188. package/lib/typescript/src/icons/index.d.ts +8 -0
  189. package/lib/typescript/src/icons/index.d.ts.map +1 -1
  190. package/lib/typescript/src/index.d.ts +14 -4
  191. package/lib/typescript/src/index.d.ts.map +1 -1
  192. package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
  193. package/lib/typescript/src/primitives/text.d.ts +20 -0
  194. package/lib/typescript/src/primitives/text.d.ts.map +1 -1
  195. package/lib/typescript/src/utils/chart.d.ts +96 -0
  196. package/lib/typescript/src/utils/chart.d.ts.map +1 -0
  197. package/lib/typescript/src/utils/date.d.ts +116 -0
  198. package/lib/typescript/src/utils/date.d.ts.map +1 -0
  199. package/package.json +9 -1
  200. package/src/components/accordion/index.tsx +8 -12
  201. package/src/components/alert/index.tsx +2 -2
  202. package/src/components/area-chart/index.tsx +1147 -0
  203. package/src/components/attachment/index.tsx +2 -2
  204. package/src/components/avatar/index.tsx +4 -4
  205. package/src/components/badge/index.tsx +6 -6
  206. package/src/components/bar-chart/index.tsx +1208 -0
  207. package/src/components/bottom-sheet/index.tsx +282 -21
  208. package/src/components/breadcrumb/index.tsx +363 -0
  209. package/src/components/button/index.tsx +12 -8
  210. package/src/components/calendar/index.tsx +703 -0
  211. package/src/components/carousel/index.tsx +788 -0
  212. package/src/components/chip/index.tsx +6 -8
  213. package/src/components/date-picker/index.tsx +237 -0
  214. package/src/components/dialog/index.tsx +7 -2
  215. package/src/components/direction/index.tsx +22 -22
  216. package/src/components/empty-state/index.tsx +2 -2
  217. package/src/components/field/index.tsx +3 -5
  218. package/src/components/flow/index.tsx +3 -3
  219. package/src/components/frame/index.tsx +22 -7
  220. package/src/components/heatmap-chart/index.tsx +58 -11
  221. package/src/components/input-group/index.tsx +5 -4
  222. package/src/components/item/index.tsx +9 -9
  223. package/src/components/label/index.tsx +2 -2
  224. package/src/components/line-chart/index.tsx +194 -223
  225. package/src/components/loader/index.tsx +812 -0
  226. package/src/components/map/basemap.ts +304 -0
  227. package/src/components/map/index.tsx +1116 -0
  228. package/src/components/map/maplibre.ts +201 -0
  229. package/src/components/marker/index.tsx +3 -3
  230. package/src/components/message/index.tsx +15 -14
  231. package/src/components/message-scroller/index.tsx +5 -4
  232. package/src/components/otp-input/index.tsx +2 -2
  233. package/src/components/popover/index.tsx +43 -7
  234. package/src/components/progress/index.tsx +10 -2
  235. package/src/components/radio-group/index.tsx +2 -2
  236. package/src/components/ring-chart/index.tsx +543 -0
  237. package/src/components/section-rail/index.tsx +6 -6
  238. package/src/components/select/index.tsx +10 -4
  239. package/src/components/separator/index.tsx +77 -19
  240. package/src/components/shimmer/index.tsx +10 -1
  241. package/src/components/slider/index.tsx +20 -5
  242. package/src/components/steps/index.tsx +5 -5
  243. package/src/components/switch/index.tsx +6 -1
  244. package/src/components/tabs/index.tsx +7 -9
  245. package/src/components/timeline/index.tsx +4 -4
  246. package/src/components/toast/index.tsx +2 -2
  247. package/src/components/toggle-button/index.tsx +5 -7
  248. package/src/components/tooltip/index.tsx +610 -0
  249. package/src/components/typography/index.tsx +7 -2
  250. package/src/hooks/index.ts +1 -0
  251. package/src/hooks/use-back-handler.ts +37 -0
  252. package/src/hooks/use-direction.ts +45 -0
  253. package/src/icons/index.tsx +111 -0
  254. package/src/index.ts +129 -0
  255. package/src/primitives/keyboard-avoider.tsx +2 -1
  256. package/src/primitives/text.tsx +53 -8
  257. package/src/utils/chart.ts +355 -0
  258. package/src/utils/date.ts +446 -0
@@ -0,0 +1,680 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Carousel — a run of slides, one at a time, dragged with a finger.
5
+ *
6
+ * ```tsx
7
+ * <Carousel loop>
8
+ * <Carousel.Content className="h-56">
9
+ * {photos.map((photo) => (
10
+ * <Carousel.Item key={photo.id}>
11
+ * <Image source={{ uri: photo.uri }} className="h-full w-full" />
12
+ * </Carousel.Item>
13
+ * ))}
14
+ * </Carousel.Content>
15
+ * <Carousel.Controls />
16
+ * </Carousel>
17
+ * ```
18
+ *
19
+ * ## One shared value, four layouts
20
+ *
21
+ * Everything is driven from a single `progress` — the position in the run, as a
22
+ * fractional index. `2.4` is two-fifths of the way from the third slide to the
23
+ * fourth, and every slide styles itself from its own distance to that number.
24
+ * A pan writes to it, a spring settles it onto a whole number, and the dots
25
+ * read it.
26
+ *
27
+ * That is why the track is a pan gesture rather than a paging `ScrollView`. A
28
+ * scroll view carries its offset natively and would serve `default` well
29
+ * enough, but `coverflow` and `stack` do not lay their slides along a track at
30
+ * all — they hold them in one place and pull them apart with transforms — so
31
+ * there would be nothing for it to scroll. One mechanism all four read beats a
32
+ * native scroller for one of them and something else for the rest.
33
+ *
34
+ * ## What each layout is for
35
+ *
36
+ * - **`default`** — a track. The honest choice for content that is read rather
37
+ * than admired: a row of cards, a gallery, an onboarding run.
38
+ * - **`interactive`** — the run fans out around the middle slide and tilts away
39
+ * on both sides, opening wider while a finger is down. For a small set worth
40
+ * showing off.
41
+ * - **`coverflow`** — the neighbours turn away from you in perspective. Best
42
+ * with art: covers, posters, photographs.
43
+ * - **`stack`** — a deck. The active card is on top with the next two peeking
44
+ * out behind it, and dragging takes the top one away. For cards dealt with
45
+ * one at a time, where the pile is the point.
46
+ *
47
+ * Depth is carried by scale, opacity and z-order rather than by moving slides
48
+ * along z: React Native's transform has `perspective` and `rotateY` but no
49
+ * `translateZ`, so a slide is made to *look* further away rather than put there.
50
+ */
51
+ import { Children, createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useState } from 'react';
52
+ import { Pressable, View } from 'react-native';
53
+ import { Gesture, GestureDetector } from 'react-native-gesture-handler';
54
+ import Animated, { Extrapolation, interpolate, runOnJS, useAnimatedStyle, useReducedMotion, useSharedValue, withSpring, withTiming } from 'react-native-reanimated';
55
+ import { ChevronLeftIcon, ChevronRightIcon } from "../../icons/index.js";
56
+ import { Text, textChildren } from "../../primitives/text.js";
57
+ import { cn } from "../../utils/cn.js";
58
+
59
+ /** Settles the run onto a whole index. Tuned to stop rather than to bounce. */
60
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
61
+ const SPRING = {
62
+ damping: 22,
63
+ stiffness: 190,
64
+ mass: 0.55
65
+ };
66
+
67
+ /**
68
+ * Fraction of a slide that has to be dragged past for the move to count, and
69
+ * the velocity that carries it there regardless. Together they are what lets a
70
+ * short fast flick and a long slow drag both advance exactly one slide.
71
+ */
72
+ const SNAP_FRACTION = 0.28;
73
+ const SNAP_VELOCITY = 500;
74
+
75
+ /** How far past the ends the run may be pulled when it does not loop. */
76
+ const OVERSCROLL = 0.4;
77
+ /** Fraction of the finger's travel that lands past an end. */
78
+ const RUBBER = 0.35;
79
+
80
+ /** Slides either side of the active one that `coverflow` still draws. */
81
+ const COVERFLOW_DEPTH = 2;
82
+
83
+ /**
84
+ * Gap between coverflow's slides, as a fraction of one slide's length.
85
+ *
86
+ * Proportional rather than a fixed number of points: the neighbours have to
87
+ * clear the middle slide by enough to be read as separate cards, and how much
88
+ * that is depends entirely on how wide the cards are.
89
+ */
90
+ const COVERFLOW_SPREAD = 0.55;
91
+
92
+ /** Cards behind the top one in `stack`. Two is a pile; five is a mess. */
93
+ const STACK_DEPTH = 2;
94
+ const CarouselContext = /*#__PURE__*/createContext(null);
95
+ function useCarousel(component) {
96
+ const context = useContext(CarouselContext);
97
+ if (!context) {
98
+ throw new Error(`${component} must be used within a <Carousel>`);
99
+ }
100
+ return context;
101
+ }
102
+
103
+ /**
104
+ * A slide's own position in the run, handed down by `Content` rather than
105
+ * counted up by each slide.
106
+ *
107
+ * The alternative is for a slide to register itself and be told its number
108
+ * back, which works right up until one is inserted in the middle and every
109
+ * slide after it is wrong until the next render settles.
110
+ */
111
+ const ItemIndexContext = /*#__PURE__*/createContext(0);
112
+
113
+ /** Position and controls, for a control of your own outside the built-in ones. */
114
+ export function useCarouselState() {
115
+ const {
116
+ index,
117
+ count,
118
+ scrollTo,
119
+ next,
120
+ previous
121
+ } = useCarousel('useCarouselState');
122
+ return {
123
+ index,
124
+ count,
125
+ scrollTo,
126
+ next,
127
+ previous
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Wraps a fractional index into the run. A worklet because the pan needs it
133
+ * per frame on the UI thread, and the imperative handle needs it in JS.
134
+ */
135
+ function wrap(value, count) {
136
+ 'worklet';
137
+
138
+ if (count <= 0) return 0;
139
+ return (value % count + count) % count;
140
+ }
141
+
142
+ /**
143
+ * Signed distance from a slide to the current position, taking the short way
144
+ * round when the run loops.
145
+ *
146
+ * Without the wrap the last slide sits `count - 1` away from the first, and
147
+ * every layout throws it off screen at the exact moment it should be sliding
148
+ * in from the other side.
149
+ */
150
+ function distance(index, progress, count, loop) {
151
+ 'worklet';
152
+
153
+ const raw = index - progress;
154
+ if (!loop || count <= 1) return raw;
155
+ const half = count / 2;
156
+ if (raw > half) return raw - count;
157
+ if (raw < -half) return raw + count;
158
+ return raw;
159
+ }
160
+
161
+ /** Imperative handle, for driving the run from outside its own controls. */
162
+
163
+ const CarouselRoot = /*#__PURE__*/forwardRef(function CarouselRoot({
164
+ className,
165
+ variant = 'default',
166
+ orientation = 'horizontal',
167
+ loop = false,
168
+ align = 'center',
169
+ itemSize: itemSizeProp,
170
+ autoplay = false,
171
+ autoplayInterval = 4000,
172
+ index: indexProp,
173
+ defaultIndex = 0,
174
+ onIndexChange,
175
+ scrollEnabled = true,
176
+ children,
177
+ ...props
178
+ }, ref) {
179
+ const [size, setSize] = useState({
180
+ width: 0,
181
+ height: 0
182
+ });
183
+ const [internalIndex, setInternalIndex] = useState(defaultIndex);
184
+ const [count, setCount] = useState(0);
185
+ const [touched, setTouched] = useState(false);
186
+ const reducedMotion = useReducedMotion();
187
+ const isControlled = indexProp !== undefined;
188
+ const index = isControlled ? indexProp : internalIndex;
189
+ const progress = useSharedValue(defaultIndex);
190
+ const engaged = useSharedValue(0);
191
+
192
+ // A deck is dealt from the top of a pile, so it is dragged sideways whatever
193
+ // the run's own direction is — there is no track for it to travel along.
194
+ const axis = variant === 'stack' ? 'horizontal' : orientation;
195
+ const along = axis === 'horizontal' ? size.width : size.height;
196
+ const itemSize = itemSizeProp ?? along ?? 0;
197
+ const setIndex = useCallback(next => {
198
+ if (!isControlled) setInternalIndex(next);
199
+ onIndexChange?.(next);
200
+ }, [isControlled, onIndexChange]);
201
+ const scrollTo = useCallback(target => {
202
+ if (count <= 0) return;
203
+ const settled = loop ? wrap(target, count) : Math.max(0, Math.min(target, count - 1));
204
+ if (reducedMotion) {
205
+ progress.value = settled;
206
+ } else if (loop) {
207
+ // Spring to the nearest representation of the target rather than to the
208
+ // target itself, so a wrap from the last slide to the first travels one
209
+ // step forward instead of winding all the way back through the run.
210
+ const shortest = progress.value + distance(settled, progress.value, count, true);
211
+ progress.value = withSpring(shortest, SPRING, finished => {
212
+ if (finished) progress.value = wrap(progress.value, count);
213
+ });
214
+ } else {
215
+ progress.value = withSpring(settled, SPRING);
216
+ }
217
+ setIndex(settled);
218
+ }, [count, loop, progress, reducedMotion, setIndex]);
219
+ const next = useCallback(() => scrollTo(index + 1), [index, scrollTo]);
220
+ const previous = useCallback(() => scrollTo(index - 1), [index, scrollTo]);
221
+ useImperativeHandle(ref, () => ({
222
+ next,
223
+ previous,
224
+ scrollTo
225
+ }), [next, previous, scrollTo]);
226
+
227
+ // A controlled index moving underneath us animates rather than jumps.
228
+ useEffect(() => {
229
+ if (!isControlled || indexProp === undefined || count <= 0) return;
230
+ if (Math.abs(progress.value - indexProp) < 0.001) return;
231
+ progress.value = reducedMotion ? indexProp : withSpring(indexProp, SPRING);
232
+ }, [isControlled, indexProp, count, progress, reducedMotion]);
233
+
234
+ /*
235
+ * Autoplay stops for good the first time a finger lands, rather than pausing.
236
+ * Someone who has taken hold of the run is reading it, and having it start
237
+ * moving again a few seconds later is the behaviour everybody hates.
238
+ */
239
+ useEffect(() => {
240
+ if (!autoplay || touched || count <= 1) return;
241
+ const timer = setInterval(() => scrollTo(index + 1), autoplayInterval);
242
+ return () => clearInterval(timer);
243
+ }, [autoplay, touched, count, index, autoplayInterval, scrollTo]);
244
+ const settle = useCallback(target => {
245
+ setTouched(true);
246
+ scrollTo(target);
247
+ }, [scrollTo]);
248
+ const pan = useMemo(() => Gesture.Pan().enabled(scrollEnabled && count > 1 && itemSize > 0)
249
+ // A carousel inside a scroll view has to let the cross-axis drags
250
+ // through, or the two fight over every diagonal.
251
+ .activeOffsetX(axis === 'horizontal' ? [-10, 10] : [-10000, 10000]).activeOffsetY(axis === 'horizontal' ? [-10000, 10000] : [-10, 10]).onBegin(() => {
252
+ engaged.value = withTiming(1, {
253
+ duration: 160
254
+ });
255
+ }).onUpdate(event => {
256
+ const moved = axis === 'horizontal' ? event.translationX : event.translationY;
257
+ const raw = progress.value - moved / itemSize;
258
+ if (loop) {
259
+ progress.value = raw;
260
+ return;
261
+ }
262
+ // Off the ends the run follows the finger at a fraction of the
263
+ // distance, so the edge is felt rather than hit.
264
+ const last = count - 1;
265
+ progress.value = raw < 0 ? Math.max(-OVERSCROLL, raw * RUBBER) : raw > last ? Math.min(last + OVERSCROLL, last + (raw - last) * RUBBER) : raw;
266
+ }).onEnd(event => {
267
+ const velocity = axis === 'horizontal' ? event.velocityX : event.velocityY;
268
+ const moved = axis === 'horizontal' ? event.translationX : event.translationY;
269
+
270
+ // The slide it started on, not the one it is nearest now: rounding
271
+ // the current position would let a slow drag that never reached the
272
+ // threshold still count as a move.
273
+ const from = Math.round(progress.value + moved / itemSize);
274
+ const past = Math.abs(moved) / itemSize > SNAP_FRACTION;
275
+ const flicked = Math.abs(velocity) > SNAP_VELOCITY;
276
+ const step = past || flicked ? moved < 0 ? 1 : -1 : 0;
277
+ runOnJS(settle)(from + step);
278
+ }).onFinalize(() => {
279
+ engaged.value = withTiming(0, {
280
+ duration: 220
281
+ });
282
+ }), [scrollEnabled, count, itemSize, axis, engaged, progress, loop, settle]);
283
+ const onLayout = event => {
284
+ const {
285
+ width,
286
+ height
287
+ } = event.nativeEvent.layout;
288
+ setSize(current => Math.abs(current.width - width) < 1 && Math.abs(current.height - height) < 1 ? current : {
289
+ width,
290
+ height
291
+ });
292
+ props.onLayout?.(event);
293
+ };
294
+ const context = useMemo(() => ({
295
+ progress,
296
+ engaged,
297
+ count,
298
+ setCount,
299
+ index,
300
+ scrollTo: settle,
301
+ next,
302
+ previous,
303
+ variant,
304
+ orientation: axis,
305
+ align,
306
+ loop,
307
+ itemSize
308
+ }), [progress, engaged, count, index, settle, next, previous, variant, axis, align, loop, itemSize]);
309
+ return /*#__PURE__*/_jsx(CarouselContext.Provider, {
310
+ value: context,
311
+ children: /*#__PURE__*/_jsx(GestureDetector, {
312
+ gesture: pan,
313
+ children: /*#__PURE__*/_jsx(View, {
314
+ accessibilityRole: "list",
315
+ ...props,
316
+ onLayout: onLayout,
317
+ className: cn('w-full', className),
318
+ children: textChildren(children)
319
+ })
320
+ })
321
+ });
322
+ });
323
+ CarouselRoot.displayName = 'Carousel';
324
+
325
+ /* -------------------------------------------------------------------------- */
326
+ /* Track */
327
+ /* -------------------------------------------------------------------------- */
328
+
329
+ /**
330
+ * The box the slides live in. Give it a height — nothing inside it is in the
331
+ * layout flow, so it has no height of its own to take.
332
+ *
333
+ * It does not move. Every slide places itself from `progress`, which is what
334
+ * lets `default` and `coverflow` be one component with different arithmetic
335
+ * rather than two different trees. The alignment here is the *resting* place
336
+ * every slide is offset from.
337
+ */
338
+ function CarouselContent({
339
+ className,
340
+ children,
341
+ ...props
342
+ }) {
343
+ const {
344
+ setCount,
345
+ variant,
346
+ orientation,
347
+ align
348
+ } = useCarousel('Carousel.Content');
349
+ const slides = Children.count(children);
350
+ const horizontal = orientation === 'horizontal';
351
+ const centred = align === 'center' || variant === 'coverflow' || variant === 'stack';
352
+ useEffect(() => {
353
+ setCount(slides);
354
+ }, [setCount, slides]);
355
+ return /*#__PURE__*/_jsx(View, {
356
+ ...props,
357
+ className: cn('w-full overflow-hidden',
358
+ // Absolutely positioned children with no insets still take the
359
+ // parent's alignment in Yoga, which is what puts a slide at rest.
360
+ horizontal ? cn('justify-center', centred ? 'items-center' : 'items-start') : cn('items-center', centred ? 'justify-center' : 'justify-start'), className),
361
+ style: [
362
+ // `perspective` on the container is what makes coverflow's rotation
363
+ // read as depth rather than as a squash.
364
+ variant === 'coverflow' ? {
365
+ transform: [{
366
+ perspective: 1000
367
+ }]
368
+ } : null, props.style],
369
+ children: Children.map(children, (child, index) => /*#__PURE__*/_jsx(ItemIndexContext.Provider, {
370
+ value: index,
371
+ children: child
372
+ }))
373
+ });
374
+ }
375
+ /** One slide. Its transform is whatever the root's `variant` asks for. */
376
+ function CarouselItem({
377
+ className,
378
+ children,
379
+ style,
380
+ ...props
381
+ }) {
382
+ const {
383
+ progress,
384
+ engaged,
385
+ count,
386
+ index: active,
387
+ variant,
388
+ orientation,
389
+ loop,
390
+ itemSize
391
+ } = useCarousel('Carousel.Item');
392
+ const index = useContext(ItemIndexContext);
393
+ const horizontal = orientation === 'horizontal';
394
+
395
+ /*
396
+ * In the layouts that pile slides on top of each other, only the one on top
397
+ * takes touches.
398
+ *
399
+ * `zIndex` reorders what is *drawn* but, on iOS, not what is *hit*: hit
400
+ * testing walks the subviews in the order they were added, so the last slide
401
+ * rendered sits in front of every gesture regardless of its z-order — and in
402
+ * a deck that slide is the one at the bottom of the pile, drawn at zero
403
+ * opacity. An invisible card was swallowing every drag.
404
+ */
405
+ const stacked = variant === 'coverflow' || variant === 'stack';
406
+ const inert = stacked && index !== active;
407
+ const animated = useAnimatedStyle(() => {
408
+ const d = distance(index, progress.value, count, loop);
409
+ const a = Math.abs(d);
410
+ if (variant === 'coverflow') {
411
+ return {
412
+ opacity: a > COVERFLOW_DEPTH ? 0 : Math.max(0, 1 - a * 0.25),
413
+ zIndex: Math.round(100 - a * 10),
414
+ transform: [{
415
+ perspective: 1000
416
+ }, {
417
+ translateX: d * itemSize * COVERFLOW_SPREAD
418
+ },
419
+ // Turned away from the middle and back towards it as it arrives.
420
+ // Interpolated rather than switched, or a slide would snap flat.
421
+ {
422
+ rotateY: `${interpolate(d, [-1, 0, 1], [38, 0, -38], Extrapolation.CLAMP)}deg`
423
+ }, {
424
+ scale: interpolate(a, [0, 1], [1.1, 0.92], Extrapolation.CLAMP)
425
+ }]
426
+ };
427
+ }
428
+ if (variant === 'stack') {
429
+ // The pile behind the top card is stepped, not spread: each card back is
430
+ // a little smaller and a little lower. Only the top one is dragged, and
431
+ // it leaves sideways with a tilt.
432
+ const behind = Math.min(Math.max(0, d), STACK_DEPTH);
433
+ const leaving = Math.min(0, d);
434
+ return {
435
+ opacity: d < -1 || d > STACK_DEPTH ? 0 : 1,
436
+ zIndex: Math.round(100 - Math.max(0, d) * 10),
437
+ transform: [{
438
+ translateX: leaving * itemSize * 1.15
439
+ }, {
440
+ translateY: behind * 14
441
+ }, {
442
+ rotate: `${leaving * 12}deg`
443
+ }, {
444
+ scale: 1 - behind * 0.06
445
+ }]
446
+ };
447
+ }
448
+ if (variant === 'interactive') {
449
+ /*
450
+ * Two states blended by `engaged`, rather than switched between: at rest
451
+ * the run is a tidy fan, and it opens wider under a finger. Blended, so
452
+ * taking hold of it opens it; switched, it would jump open.
453
+ */
454
+ const open = engaged.value;
455
+ const spread = d * itemSize;
456
+ const lift = d * 24 * open;
457
+ const inactive = 0.78 - open * 0.15;
458
+ return {
459
+ opacity: a > 3 ? 0 : 1,
460
+ zIndex: Math.round(100 - a * 10),
461
+ transform: [{
462
+ translateX: horizontal ? spread : lift
463
+ }, {
464
+ translateY: horizontal ? lift : spread
465
+ }, {
466
+ rotate: `${d * (5 + open * 15)}deg`
467
+ },
468
+ /*
469
+ * The slide in the middle rests at exactly 1, and the fan's depth
470
+ * comes from the others shrinking rather than from it growing.
471
+ *
472
+ * Scaling it up instead is what made its caption soft. Text is
473
+ * rasterised at its layout size and then scaled by the compositor,
474
+ * so a label on a slide held at 1.05 is drawn at the wrong raster
475
+ * size for as long as it is the active one — which is the whole time
476
+ * it is readable, since every other caption has faded out.
477
+ */
478
+ {
479
+ scale: interpolate(a, [0, 1], [1, inactive], Extrapolation.CLAMP)
480
+ }]
481
+ };
482
+ }
483
+
484
+ // `default` — a plain track, each slide one length from the last.
485
+ return {
486
+ transform: [{
487
+ translateX: horizontal ? d * itemSize : 0
488
+ }, {
489
+ translateY: horizontal ? 0 : d * itemSize
490
+ }]
491
+ };
492
+ });
493
+
494
+ // `coverflow` and `stack` are sized by whatever is put in them: they are
495
+ // built around a card, and a card that had to be the width of the screen
496
+ // would have nothing to stack behind.
497
+ const sized = variant === 'default' || variant === 'interactive';
498
+ return /*#__PURE__*/_jsx(Animated.View, {
499
+ ...props,
500
+ style: [{
501
+ position: 'absolute',
502
+ pointerEvents: inert ? 'none' : 'auto'
503
+ }, sized ? horizontal ? {
504
+ width: itemSize
505
+ } : {
506
+ height: itemSize
507
+ } : null, sized && variant === 'default' ? horizontal ? {
508
+ height: '100%'
509
+ } : {
510
+ width: '100%'
511
+ } : null, animated, style],
512
+ className: cn(className),
513
+ children: textChildren(children)
514
+ });
515
+ }
516
+
517
+ /* -------------------------------------------------------------------------- */
518
+ /* Controls */
519
+ /* -------------------------------------------------------------------------- */
520
+
521
+ /**
522
+ * A slide's label, shown only while that slide is the active one.
523
+ *
524
+ * It lives inside the slide rather than beside the run, so it travels with what
525
+ * it names — a caption that stays put while the picture moves belongs to the
526
+ * carousel rather than to the picture.
527
+ */
528
+ function CarouselCaption({
529
+ className,
530
+ children,
531
+ ...props
532
+ }) {
533
+ const {
534
+ progress,
535
+ count,
536
+ loop
537
+ } = useCarousel('Carousel.Caption');
538
+ const index = useContext(ItemIndexContext);
539
+
540
+ /*
541
+ * Gone well before the next slide arrives, rather than fading across the
542
+ * whole step. The layouts that use a caption overlap their slides, so a
543
+ * caption still at a third of its opacity halfway through a drag is a line
544
+ * of grey text sitting on top of the neighbouring picture — which reads as a
545
+ * rendering fault rather than as a transition.
546
+ */
547
+ /*
548
+ * Opacity only. A scale here would compound with the slide's own — the
549
+ * caption is inside it — and the text would be resampled twice, once for
550
+ * each. The slide already carries all the movement this needs to read as
551
+ * belonging to the picture.
552
+ */
553
+ const animated = useAnimatedStyle(() => {
554
+ const a = Math.abs(distance(index, progress.value, count, loop));
555
+ return {
556
+ opacity: interpolate(a, [0, 0.3], [1, 0], Extrapolation.CLAMP)
557
+ };
558
+ });
559
+ return /*#__PURE__*/_jsx(Animated.View, {
560
+ ...props,
561
+ style: [animated, props.style],
562
+ className: cn(className),
563
+ children: textChildren(children, text => /*#__PURE__*/_jsx(Text, {
564
+ size: "xs",
565
+ weight: "semibold",
566
+ className: "text-center",
567
+ children: text
568
+ }))
569
+ });
570
+ }
571
+ /**
572
+ * One dot per slide, the active one drawn as a bar.
573
+ *
574
+ * Length rather than colour alone carries the position: a row that differs only
575
+ * in opacity is unreadable at a glance, and invisible to anyone who cannot
576
+ * separate the two greys.
577
+ */
578
+ function CarouselDots({
579
+ className,
580
+ orientation = 'horizontal',
581
+ interactive = true,
582
+ ...props
583
+ }) {
584
+ const {
585
+ count,
586
+ index,
587
+ scrollTo
588
+ } = useCarousel('Carousel.Dots');
589
+ const horizontal = orientation === 'horizontal';
590
+ if (count <= 1) return null;
591
+ return /*#__PURE__*/_jsx(View, {
592
+ accessibilityRole: "tablist",
593
+ ...props,
594
+ className: cn('items-center gap-1', horizontal ? 'flex-row' : 'flex-col', className),
595
+ children: Array.from({
596
+ length: count
597
+ }, (_unused, dot) => {
598
+ const active = dot === index;
599
+ return /*#__PURE__*/_jsx(Pressable, {
600
+ disabled: !interactive,
601
+ onPress: () => scrollTo(dot),
602
+ hitSlop: 6,
603
+ accessibilityRole: "tab",
604
+ accessibilityLabel: `Slide ${dot + 1} of ${count}`,
605
+ accessibilityState: {
606
+ selected: active
607
+ },
608
+ className: cn('rounded-full', horizontal ? active ? 'h-1 w-4' : 'h-1 w-1' : active ? 'h-4 w-1' : 'h-1 w-1', active ? 'bg-foreground' : 'bg-foreground/30')
609
+ }, dot);
610
+ })
611
+ });
612
+ }
613
+ /** Body of the two arrows — they differ only in icon, label and direction. */
614
+ function makeArrow(direction) {
615
+ const name = direction === 'next' ? 'Next' : 'Previous';
616
+ function Arrow({
617
+ className,
618
+ children,
619
+ ...props
620
+ }) {
621
+ const {
622
+ count,
623
+ index,
624
+ loop,
625
+ next,
626
+ previous
627
+ } = useCarousel(`Carousel.${name}`);
628
+ // Without a loop the ends are dead. An arrow that stays live and does
629
+ // nothing is worse than one that says it cannot.
630
+ const disabled = !loop && (direction === 'next' ? index >= count - 1 : index <= 0);
631
+ return /*#__PURE__*/_jsx(Pressable, {
632
+ disabled: disabled,
633
+ onPress: direction === 'next' ? next : previous,
634
+ hitSlop: 8,
635
+ accessibilityRole: "button",
636
+ accessibilityLabel: direction === 'next' ? 'Next slide' : 'Previous slide',
637
+ accessibilityState: {
638
+ disabled
639
+ },
640
+ className: cn('items-center justify-center rounded-full p-1', disabled ? 'opacity-30' : 'active:bg-foreground/10', className),
641
+ ...props,
642
+ children: children ?? (direction === 'next' ? /*#__PURE__*/_jsx(ChevronRightIcon, {
643
+ size: 14
644
+ }) : /*#__PURE__*/_jsx(ChevronLeftIcon, {
645
+ size: 14
646
+ }))
647
+ });
648
+ }
649
+ Arrow.displayName = `Carousel.${name}`;
650
+ return Arrow;
651
+ }
652
+ const CarouselPrevious = makeArrow('previous');
653
+ const CarouselNext = makeArrow('next');
654
+ /**
655
+ * The arrows and the dots in one pill.
656
+ *
657
+ * Together rather than scattered, because they answer the same question — where
658
+ * am I in this, and how do I move — and a bar that reads as one object can sit
659
+ * over the content instead of taking a strip of the layout for itself.
660
+ */
661
+ function CarouselControls({
662
+ className,
663
+ ...props
664
+ }) {
665
+ return /*#__PURE__*/_jsxs(View, {
666
+ ...props,
667
+ className: cn('flex-row items-center justify-center gap-2 self-center rounded-full border border-border bg-background/80 px-1.5 py-0.5', className),
668
+ children: [/*#__PURE__*/_jsx(CarouselPrevious, {}), /*#__PURE__*/_jsx(CarouselDots, {}), /*#__PURE__*/_jsx(CarouselNext, {})]
669
+ });
670
+ }
671
+ export const Carousel = Object.assign(CarouselRoot, {
672
+ Content: CarouselContent,
673
+ Item: CarouselItem,
674
+ Caption: CarouselCaption,
675
+ Dots: CarouselDots,
676
+ Previous: CarouselPrevious,
677
+ Next: CarouselNext,
678
+ Controls: CarouselControls
679
+ });
680
+ //# sourceMappingURL=index.js.map