panelui-native 0.71.0 → 0.75.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 (306) hide show
  1. package/README.md +5 -2
  2. package/lib/module/components/accordion/index.js +10 -4
  3. package/lib/module/components/accordion/index.js.map +1 -1
  4. package/lib/module/components/area-chart/index.js +1 -0
  5. package/lib/module/components/area-chart/index.js.map +1 -1
  6. package/lib/module/components/avatar/avatar-group.js +64 -0
  7. package/lib/module/components/avatar/avatar-group.js.map +1 -0
  8. package/lib/module/components/avatar/index.js +84 -2
  9. package/lib/module/components/avatar/index.js.map +1 -1
  10. package/lib/module/components/breadcrumb/index.js +2 -1
  11. package/lib/module/components/breadcrumb/index.js.map +1 -1
  12. package/lib/module/components/button/index.js +7 -5
  13. package/lib/module/components/button/index.js.map +1 -1
  14. package/lib/module/components/carousel/index.js +1 -1
  15. package/lib/module/components/carousel/index.js.map +1 -1
  16. package/lib/module/components/chip/index.js +2 -2
  17. package/lib/module/components/chip/index.js.map +1 -1
  18. package/lib/module/components/code-block/index.js.map +1 -1
  19. package/lib/module/components/collapsible/index.js +5 -1
  20. package/lib/module/components/collapsible/index.js.map +1 -1
  21. package/lib/module/components/color-picker/color-picker-accessibility.js +12 -0
  22. package/lib/module/components/color-picker/color-picker-accessibility.js.map +1 -0
  23. package/lib/module/components/color-picker/index.js +9 -5
  24. package/lib/module/components/color-picker/index.js.map +1 -1
  25. package/lib/module/components/date-time-picker/index.js +11 -3
  26. package/lib/module/components/date-time-picker/index.js.map +1 -1
  27. package/lib/module/components/drawer/index.js +58 -13
  28. package/lib/module/components/drawer/index.js.map +1 -1
  29. package/lib/module/components/fab/index.js +7 -6
  30. package/lib/module/components/fab/index.js.map +1 -1
  31. package/lib/module/components/flow/index.js +1 -1
  32. package/lib/module/components/flow/index.js.map +1 -1
  33. package/lib/module/components/frame/index.js +2 -2
  34. package/lib/module/components/frame/index.js.map +1 -1
  35. package/lib/module/components/grid-item/index.js +2 -2
  36. package/lib/module/components/grid-item/index.js.map +1 -1
  37. package/lib/module/components/heatmap-chart/index.js +1 -0
  38. package/lib/module/components/heatmap-chart/index.js.map +1 -1
  39. package/lib/module/components/hex-chart/index.js +1 -0
  40. package/lib/module/components/hex-chart/index.js.map +1 -1
  41. package/lib/module/components/input/index.js +7 -4
  42. package/lib/module/components/input/index.js.map +1 -1
  43. package/lib/module/components/input/input-content-padding.js +6 -0
  44. package/lib/module/components/input/input-content-padding.js.map +1 -0
  45. package/lib/module/components/input-group/index.js +21 -11
  46. package/lib/module/components/input-group/index.js.map +1 -1
  47. package/lib/module/components/input-group/input-group-measurements.js +60 -0
  48. package/lib/module/components/input-group/input-group-measurements.js.map +1 -0
  49. package/lib/module/components/item/index.js +2 -2
  50. package/lib/module/components/item/index.js.map +1 -1
  51. package/lib/module/components/line-chart/index.js +1 -0
  52. package/lib/module/components/line-chart/index.js.map +1 -1
  53. package/lib/module/components/marker/index.js +2 -2
  54. package/lib/module/components/marker/index.js.map +1 -1
  55. package/lib/module/components/marquee/index.js +9 -12
  56. package/lib/module/components/marquee/index.js.map +1 -1
  57. package/lib/module/components/marquee/marquee-math.js +39 -0
  58. package/lib/module/components/marquee/marquee-math.js.map +1 -0
  59. package/lib/module/components/menu/index.js +11 -3
  60. package/lib/module/components/menu/index.js.map +1 -1
  61. package/lib/module/components/otp-input/index.js +3 -1
  62. package/lib/module/components/otp-input/index.js.map +1 -1
  63. package/lib/module/components/otp-input/otp-input-state.js +7 -0
  64. package/lib/module/components/otp-input/otp-input-state.js.map +1 -0
  65. package/lib/module/components/pagination/index.js +27 -11
  66. package/lib/module/components/pagination/index.js.map +1 -1
  67. package/lib/module/components/panelside/index.js +7 -2
  68. package/lib/module/components/panelside/index.js.map +1 -1
  69. package/lib/module/components/planner/index.js +46 -11
  70. package/lib/module/components/planner/index.js.map +1 -1
  71. package/lib/module/components/planner/planner-today.js +8 -0
  72. package/lib/module/components/planner/planner-today.js.map +1 -0
  73. package/lib/module/components/plot/index.js +113 -53
  74. package/lib/module/components/plot/index.js.map +1 -1
  75. package/lib/module/components/plot/plot-series-registry.js +32 -0
  76. package/lib/module/components/plot/plot-series-registry.js.map +1 -0
  77. package/lib/module/components/post/index.js +4 -4
  78. package/lib/module/components/post/index.js.map +1 -1
  79. package/lib/module/components/radio-group/index.js +2 -1
  80. package/lib/module/components/radio-group/index.js.map +1 -1
  81. package/lib/module/components/radio-group/radio-group-value.js +8 -0
  82. package/lib/module/components/radio-group/radio-group-value.js.map +1 -0
  83. package/lib/module/components/rating/index.js +7 -4
  84. package/lib/module/components/rating/index.js.map +1 -1
  85. package/lib/module/components/rating/rating-inputs.js +15 -0
  86. package/lib/module/components/rating/rating-inputs.js.map +1 -0
  87. package/lib/module/components/search-bar/index.js +331 -0
  88. package/lib/module/components/search-bar/index.js.map +1 -0
  89. package/lib/module/components/search-bar/search-bar-debounce.js +23 -0
  90. package/lib/module/components/search-bar/search-bar-debounce.js.map +1 -0
  91. package/lib/module/components/select/index.js +9 -1
  92. package/lib/module/components/select/index.js.map +1 -1
  93. package/lib/module/components/select/native-select-contract.js +11 -0
  94. package/lib/module/components/select/native-select-contract.js.map +1 -0
  95. package/lib/module/components/split-view/index.js +439 -0
  96. package/lib/module/components/split-view/index.js.map +1 -0
  97. package/lib/module/components/split-view/split-view-math.js +132 -0
  98. package/lib/module/components/split-view/split-view-math.js.map +1 -0
  99. package/lib/module/components/splitter/index.js +433 -0
  100. package/lib/module/components/splitter/index.js.map +1 -0
  101. package/lib/module/components/splitter/splitter-math.js +206 -0
  102. package/lib/module/components/splitter/splitter-math.js.map +1 -0
  103. package/lib/module/components/steps/index.js +16 -5
  104. package/lib/module/components/steps/index.js.map +1 -1
  105. package/lib/module/components/steps/steps-trigger.js +6 -0
  106. package/lib/module/components/steps/steps-trigger.js.map +1 -0
  107. package/lib/module/components/table/index.js +3 -4
  108. package/lib/module/components/table/index.js.map +1 -1
  109. package/lib/module/components/tag-input/index.js +15 -10
  110. package/lib/module/components/tag-input/index.js.map +1 -1
  111. package/lib/module/components/tag-input/tag-input-state.js +14 -0
  112. package/lib/module/components/tag-input/tag-input-state.js.map +1 -0
  113. package/lib/module/components/textarea/index.js +9 -4
  114. package/lib/module/components/textarea/index.js.map +1 -1
  115. package/lib/module/components/textarea/textarea-disabled.js +6 -0
  116. package/lib/module/components/textarea/textarea-disabled.js.map +1 -0
  117. package/lib/module/components/timeline/index.js +352 -47
  118. package/lib/module/components/timeline/index.js.map +1 -1
  119. package/lib/module/components/timeline/timeline-geometry.js +11 -0
  120. package/lib/module/components/timeline/timeline-geometry.js.map +1 -0
  121. package/lib/module/components/toast/index.js +18 -1
  122. package/lib/module/components/toast/index.js.map +1 -1
  123. package/lib/module/components/toast/toast-store.js +36 -4
  124. package/lib/module/components/toast/toast-store.js.map +1 -1
  125. package/lib/module/components/toggle-button/index.js +1 -1
  126. package/lib/module/components/toggle-button/index.js.map +1 -1
  127. package/lib/module/components/tour/index.js +4 -2
  128. package/lib/module/components/tour/index.js.map +1 -1
  129. package/lib/module/components/tour/tour-card-measurement.js +24 -0
  130. package/lib/module/components/tour/tour-card-measurement.js.map +1 -0
  131. package/lib/module/components/tree/index.js +13 -8
  132. package/lib/module/components/tree/index.js.map +1 -1
  133. package/lib/module/hooks/use-keyboard-avoidance.js.map +1 -1
  134. package/lib/module/index.js +3 -0
  135. package/lib/module/index.js.map +1 -1
  136. package/lib/module/utils/chart.js +50 -7
  137. package/lib/module/utils/chart.js.map +1 -1
  138. package/lib/typescript/src/components/accordion/index.d.ts +2 -2
  139. package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
  140. package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
  141. package/lib/typescript/src/components/avatar/avatar-group.d.ts +46 -0
  142. package/lib/typescript/src/components/avatar/avatar-group.d.ts.map +1 -0
  143. package/lib/typescript/src/components/avatar/index.d.ts +23 -1
  144. package/lib/typescript/src/components/avatar/index.d.ts.map +1 -1
  145. package/lib/typescript/src/components/breadcrumb/index.d.ts.map +1 -1
  146. package/lib/typescript/src/components/button/index.d.ts.map +1 -1
  147. package/lib/typescript/src/components/code-block/index.d.ts +3 -3
  148. package/lib/typescript/src/components/code-block/index.d.ts.map +1 -1
  149. package/lib/typescript/src/components/collapsible/index.d.ts +2 -2
  150. package/lib/typescript/src/components/collapsible/index.d.ts.map +1 -1
  151. package/lib/typescript/src/components/color-picker/color-picker-accessibility.d.ts +8 -0
  152. package/lib/typescript/src/components/color-picker/color-picker-accessibility.d.ts.map +1 -0
  153. package/lib/typescript/src/components/color-picker/index.d.ts.map +1 -1
  154. package/lib/typescript/src/components/date-time-picker/index.d.ts.map +1 -1
  155. package/lib/typescript/src/components/drawer/index.d.ts.map +1 -1
  156. package/lib/typescript/src/components/fab/index.d.ts +4 -2
  157. package/lib/typescript/src/components/fab/index.d.ts.map +1 -1
  158. package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
  159. package/lib/typescript/src/components/hex-chart/index.d.ts.map +1 -1
  160. package/lib/typescript/src/components/input/index.d.ts.map +1 -1
  161. package/lib/typescript/src/components/input/input-content-padding.d.ts +2 -0
  162. package/lib/typescript/src/components/input/input-content-padding.d.ts.map +1 -0
  163. package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
  164. package/lib/typescript/src/components/input-group/input-group-measurements.d.ts +16 -0
  165. package/lib/typescript/src/components/input-group/input-group-measurements.d.ts.map +1 -0
  166. package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
  167. package/lib/typescript/src/components/marquee/index.d.ts +1 -1
  168. package/lib/typescript/src/components/marquee/index.d.ts.map +1 -1
  169. package/lib/typescript/src/components/marquee/marquee-math.d.ts +21 -0
  170. package/lib/typescript/src/components/marquee/marquee-math.d.ts.map +1 -0
  171. package/lib/typescript/src/components/menu/index.d.ts +1 -1
  172. package/lib/typescript/src/components/menu/index.d.ts.map +1 -1
  173. package/lib/typescript/src/components/otp-input/index.d.ts.map +1 -1
  174. package/lib/typescript/src/components/otp-input/otp-input-state.d.ts +3 -0
  175. package/lib/typescript/src/components/otp-input/otp-input-state.d.ts.map +1 -0
  176. package/lib/typescript/src/components/pagination/index.d.ts.map +1 -1
  177. package/lib/typescript/src/components/panelside/index.d.ts +1 -1
  178. package/lib/typescript/src/components/panelside/index.d.ts.map +1 -1
  179. package/lib/typescript/src/components/plan/index.d.ts +2 -2
  180. package/lib/typescript/src/components/planner/index.d.ts.map +1 -1
  181. package/lib/typescript/src/components/planner/planner-today.d.ts +2 -0
  182. package/lib/typescript/src/components/planner/planner-today.d.ts.map +1 -0
  183. package/lib/typescript/src/components/plot/index.d.ts +60 -6
  184. package/lib/typescript/src/components/plot/index.d.ts.map +1 -1
  185. package/lib/typescript/src/components/plot/plot-series-registry.d.ts +8 -0
  186. package/lib/typescript/src/components/plot/plot-series-registry.d.ts.map +1 -0
  187. package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
  188. package/lib/typescript/src/components/radio-group/radio-group-value.d.ts +2 -0
  189. package/lib/typescript/src/components/radio-group/radio-group-value.d.ts.map +1 -0
  190. package/lib/typescript/src/components/rating/index.d.ts.map +1 -1
  191. package/lib/typescript/src/components/rating/rating-inputs.d.ts +4 -0
  192. package/lib/typescript/src/components/rating/rating-inputs.d.ts.map +1 -0
  193. package/lib/typescript/src/components/search-bar/index.d.ts +216 -0
  194. package/lib/typescript/src/components/search-bar/index.d.ts.map +1 -0
  195. package/lib/typescript/src/components/search-bar/search-bar-debounce.d.ts +7 -0
  196. package/lib/typescript/src/components/search-bar/search-bar-debounce.d.ts.map +1 -0
  197. package/lib/typescript/src/components/select/index.d.ts.map +1 -1
  198. package/lib/typescript/src/components/select/native-select-contract.d.ts +11 -0
  199. package/lib/typescript/src/components/select/native-select-contract.d.ts.map +1 -0
  200. package/lib/typescript/src/components/split-view/index.d.ts +159 -0
  201. package/lib/typescript/src/components/split-view/index.d.ts.map +1 -0
  202. package/lib/typescript/src/components/split-view/split-view-math.d.ts +54 -0
  203. package/lib/typescript/src/components/split-view/split-view-math.d.ts.map +1 -0
  204. package/lib/typescript/src/components/splitter/index.d.ts +78 -0
  205. package/lib/typescript/src/components/splitter/index.d.ts.map +1 -0
  206. package/lib/typescript/src/components/splitter/splitter-math.d.ts +67 -0
  207. package/lib/typescript/src/components/splitter/splitter-math.d.ts.map +1 -0
  208. package/lib/typescript/src/components/steps/index.d.ts +2 -2
  209. package/lib/typescript/src/components/steps/index.d.ts.map +1 -1
  210. package/lib/typescript/src/components/steps/steps-trigger.d.ts +2 -0
  211. package/lib/typescript/src/components/steps/steps-trigger.d.ts.map +1 -0
  212. package/lib/typescript/src/components/tag-input/index.d.ts.map +1 -1
  213. package/lib/typescript/src/components/tag-input/tag-input-state.d.ts +12 -0
  214. package/lib/typescript/src/components/tag-input/tag-input-state.d.ts.map +1 -0
  215. package/lib/typescript/src/components/textarea/index.d.ts.map +1 -1
  216. package/lib/typescript/src/components/textarea/textarea-disabled.d.ts +2 -0
  217. package/lib/typescript/src/components/textarea/textarea-disabled.d.ts.map +1 -0
  218. package/lib/typescript/src/components/timeline/index.d.ts +36 -2
  219. package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
  220. package/lib/typescript/src/components/timeline/timeline-geometry.d.ts +4 -0
  221. package/lib/typescript/src/components/timeline/timeline-geometry.d.ts.map +1 -0
  222. package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
  223. package/lib/typescript/src/components/toast/toast-store.d.ts +7 -2
  224. package/lib/typescript/src/components/toast/toast-store.d.ts.map +1 -1
  225. package/lib/typescript/src/components/tour/index.d.ts.map +1 -1
  226. package/lib/typescript/src/components/tour/tour-card-measurement.d.ts +14 -0
  227. package/lib/typescript/src/components/tour/tour-card-measurement.d.ts.map +1 -0
  228. package/lib/typescript/src/components/tree/index.d.ts +3 -4
  229. package/lib/typescript/src/components/tree/index.d.ts.map +1 -1
  230. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts +2 -2
  231. package/lib/typescript/src/hooks/use-keyboard-avoidance.d.ts.map +1 -1
  232. package/lib/typescript/src/index.d.ts +5 -2
  233. package/lib/typescript/src/index.d.ts.map +1 -1
  234. package/lib/typescript/src/utils/chart.d.ts +28 -3
  235. package/lib/typescript/src/utils/chart.d.ts.map +1 -1
  236. package/package.json +1 -1
  237. package/src/components/accordion/index.tsx +17 -7
  238. package/src/components/area-chart/index.tsx +8 -0
  239. package/src/components/avatar/avatar-group.ts +78 -0
  240. package/src/components/avatar/index.tsx +121 -1
  241. package/src/components/breadcrumb/index.tsx +2 -1
  242. package/src/components/button/index.tsx +3 -2
  243. package/src/components/carousel/index.tsx +1 -1
  244. package/src/components/chip/index.tsx +2 -2
  245. package/src/components/code-block/index.tsx +3 -3
  246. package/src/components/collapsible/index.tsx +13 -4
  247. package/src/components/color-picker/color-picker-accessibility.ts +12 -0
  248. package/src/components/color-picker/index.tsx +30 -10
  249. package/src/components/date-time-picker/index.tsx +11 -3
  250. package/src/components/drawer/index.tsx +42 -14
  251. package/src/components/fab/index.tsx +21 -11
  252. package/src/components/flow/index.tsx +1 -1
  253. package/src/components/frame/index.tsx +2 -2
  254. package/src/components/grid-item/index.tsx +2 -2
  255. package/src/components/heatmap-chart/index.tsx +7 -1
  256. package/src/components/hex-chart/index.tsx +7 -1
  257. package/src/components/input/index.tsx +6 -2
  258. package/src/components/input/input-content-padding.ts +3 -0
  259. package/src/components/input-group/index.tsx +45 -12
  260. package/src/components/input-group/input-group-measurements.ts +98 -0
  261. package/src/components/item/index.tsx +2 -2
  262. package/src/components/line-chart/index.tsx +9 -0
  263. package/src/components/marker/index.tsx +2 -2
  264. package/src/components/marquee/index.tsx +14 -12
  265. package/src/components/marquee/marquee-math.ts +37 -0
  266. package/src/components/menu/index.tsx +11 -3
  267. package/src/components/otp-input/index.tsx +3 -1
  268. package/src/components/otp-input/otp-input-state.ts +7 -0
  269. package/src/components/pagination/index.tsx +26 -13
  270. package/src/components/panelside/index.tsx +7 -2
  271. package/src/components/plan/index.tsx +2 -2
  272. package/src/components/planner/index.tsx +44 -11
  273. package/src/components/planner/planner-today.ts +5 -0
  274. package/src/components/plot/index.tsx +199 -51
  275. package/src/components/plot/plot-series-registry.ts +41 -0
  276. package/src/components/post/index.tsx +4 -4
  277. package/src/components/radio-group/index.tsx +4 -1
  278. package/src/components/radio-group/radio-group-value.ts +9 -0
  279. package/src/components/rating/index.tsx +11 -4
  280. package/src/components/rating/rating-inputs.ts +19 -0
  281. package/src/components/search-bar/index.tsx +441 -0
  282. package/src/components/search-bar/search-bar-debounce.ts +35 -0
  283. package/src/components/select/index.tsx +10 -1
  284. package/src/components/select/native-select-contract.ts +12 -0
  285. package/src/components/split-view/index.tsx +565 -0
  286. package/src/components/split-view/split-view-math.ts +146 -0
  287. package/src/components/splitter/index.tsx +589 -0
  288. package/src/components/splitter/splitter-math.ts +244 -0
  289. package/src/components/steps/index.tsx +35 -9
  290. package/src/components/steps/steps-trigger.ts +6 -0
  291. package/src/components/table/index.tsx +2 -2
  292. package/src/components/tag-input/index.tsx +13 -11
  293. package/src/components/tag-input/tag-input-state.ts +18 -0
  294. package/src/components/textarea/index.tsx +8 -4
  295. package/src/components/textarea/textarea-disabled.ts +6 -0
  296. package/src/components/timeline/index.tsx +405 -46
  297. package/src/components/timeline/timeline-geometry.ts +9 -0
  298. package/src/components/toast/index.tsx +26 -1
  299. package/src/components/toast/toast-store.ts +43 -8
  300. package/src/components/toggle-button/index.tsx +1 -1
  301. package/src/components/tour/index.tsx +11 -3
  302. package/src/components/tour/tour-card-measurement.ts +29 -0
  303. package/src/components/tree/index.tsx +17 -12
  304. package/src/hooks/use-keyboard-avoidance.ts +7 -2
  305. package/src/index.ts +19 -0
  306. package/src/utils/chart.ts +66 -7
@@ -477,11 +477,20 @@ const LineChartRoot = forwardRef<LineChartHandle, LineChartProps>(function LineC
477
477
  * One clip for everything in the plot. Sharing it is what
478
478
  * makes the reveal read as the chart arriving, rather than as
479
479
  * three separate things animating in at once.
480
+ *
481
+ * `width` is set statically as well as animated, and it has
482
+ * to be. Animated props on an element inside `Defs` do not
483
+ * reach the native clip on every platform, and with the width
484
+ * coming only from the animation there is no width at all
485
+ * when they do not — an empty clip, and a chart whose marks
486
+ * are all invisible while its axes draw normally. Declared,
487
+ * the worst case is the reveal not playing.
480
488
  */}
481
489
  <ClipPath id={clipId}>
482
490
  <AnimatedRect
483
491
  x={plot.left}
484
492
  y={0}
493
+ width={plot.width}
485
494
  height={size.height}
486
495
  animatedProps={clipProps}
487
496
  />
@@ -100,21 +100,21 @@ const MarkerRoot = forwardRef<View, MarkerProps>(
100
100
  const body = !onPress ? (
101
101
  <View
102
102
  ref={ref}
103
+ {...(props as ViewProps)}
103
104
  accessibilityState={{ disabled: !!disabled }}
104
105
  className={root({ className })}
105
- {...(props as ViewProps)}
106
106
  >
107
107
  {inner}
108
108
  </View>
109
109
  ) : (
110
110
  <AnimatedPressable
111
111
  ref={ref}
112
+ {...props}
112
113
  accessibilityRole="button"
113
114
  accessibilityState={{ disabled: !!disabled }}
114
115
  disabled={disabled}
115
116
  onPress={onPress}
116
117
  className={root({ className })}
117
- {...props}
118
118
  >
119
119
  {inner}
120
120
  </AnimatedPressable>
@@ -62,12 +62,11 @@ import Animated, {
62
62
  } from 'react-native-reanimated';
63
63
  import { useDirectionSign } from '../../hooks/use-direction';
64
64
  import { cn } from '../../utils/cn';
65
-
66
- /**
67
- * Points per second. Slow enough that a word stays readable as it crosses,
68
- * which is the speed a ticker is actually for.
69
- */
70
- const DEFAULT_SPEED = 40;
65
+ import {
66
+ DEFAULT_MARQUEE_SPEED,
67
+ marqueeCopyCount,
68
+ normalizeMarqueeSpeed,
69
+ } from './marquee-math';
71
70
 
72
71
  export type MarqueeDirection = 'horizontal' | 'vertical';
73
72
 
@@ -98,7 +97,7 @@ export interface MarqueeProps extends Omit<ViewProps, 'children'> {
98
97
  export function Marquee({
99
98
  className,
100
99
  children,
101
- speed = DEFAULT_SPEED,
100
+ speed: speedProp = DEFAULT_MARQUEE_SPEED,
102
101
  spacing = 0,
103
102
  direction = 'horizontal',
104
103
  reverse = false,
@@ -115,19 +114,22 @@ export function Marquee({
115
114
 
116
115
  const [viewport, setViewport] = useState(0);
117
116
  const [content, setContent] = useState(0);
117
+ const speed = normalizeMarqueeSpeed(speedProp);
118
118
 
119
119
  // The distance from one copy to the same point on the next, and therefore
120
120
  // both the layout step and the exact loop length. They are the same number
121
121
  // on purpose: taking the gap from anywhere else is how a seam appears.
122
- const period = content > 0 ? content + spacing : 0;
122
+ const layout = useMemo(
123
+ () => marqueeCopyCount(viewport, content, spacing),
124
+ [viewport, content, spacing]
125
+ );
126
+ const { period } = layout;
123
127
 
124
128
  const copies = useMemo(() => {
125
- if (period <= 0 || viewport <= 0) return [];
126
129
  // Enough to span the container, plus one trailing into view and one
127
130
  // already past it — the two the travel consumes before the loop restarts.
128
- const count = Math.ceil(viewport / period) + 2;
129
- return Array.from({ length: count }, (_, index) => index);
130
- }, [period, viewport]);
131
+ return Array.from({ length: layout.count }, (_, index) => index);
132
+ }, [layout.count]);
131
133
 
132
134
  const offset = useSharedValue(0);
133
135
 
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The arithmetic behind the loop, kept out of the component so it can be tested
3
+ * without rendering one.
4
+ *
5
+ * Every value here reaches a Reanimated timing or a layout offset, and both
6
+ * treat `NaN` and `Infinity` as a frame that never resolves rather than as an
7
+ * error. A marquee handed a bad number should hold still, not wedge — so the
8
+ * guards live at the boundary, once, instead of at each use.
9
+ */
10
+
11
+ /**
12
+ * Points per second. Slow enough that a word stays readable as it crosses,
13
+ * which is the speed a ticker is actually for.
14
+ */
15
+ export const DEFAULT_MARQUEE_SPEED = 40;
16
+
17
+ export function normalizeMarqueeSpeed(value: number): number {
18
+ if (!Number.isFinite(value)) return DEFAULT_MARQUEE_SPEED;
19
+ return Math.max(value, 0);
20
+ }
21
+
22
+ export function normalizeMarqueeSpacing(value: number): number {
23
+ if (!Number.isFinite(value)) return 0;
24
+ return Math.max(value, 0);
25
+ }
26
+
27
+ export function marqueeCopyCount(
28
+ viewport: number,
29
+ content: number,
30
+ spacing: number
31
+ ): { period: number; count: number } {
32
+ const safeViewport = Number.isFinite(viewport) ? Math.max(viewport, 0) : 0;
33
+ const safeContent = Number.isFinite(content) ? Math.max(content, 0) : 0;
34
+ const period = safeContent > 0 ? safeContent + normalizeMarqueeSpacing(spacing) : 0;
35
+ if (period <= 0 || safeViewport <= 0) return { period, count: 0 };
36
+ return { period, count: Math.ceil(safeViewport / period) + 2 };
37
+ }
@@ -451,6 +451,8 @@ export function MenuItem({
451
451
  closeOnSelect = true,
452
452
  onSelect,
453
453
  onPress,
454
+ onPressIn,
455
+ onPressOut,
454
456
  ...props
455
457
  }: MenuItemProps) {
456
458
  const { close, haptics } = useMenu('Menu.Item');
@@ -467,15 +469,21 @@ export function MenuItem({
467
469
 
468
470
  return (
469
471
  <AnimatedPressable
472
+ {...props}
470
473
  accessibilityRole="menuitem"
471
474
  accessibilityState={{ disabled }}
472
475
  disabled={disabled}
473
476
  onPress={handlePress}
474
- onPressIn={press.onPressIn}
475
- onPressOut={press.onPressOut}
477
+ onPressIn={(event) => {
478
+ onPressIn?.(event);
479
+ press.onPressIn();
480
+ }}
481
+ onPressOut={(event) => {
482
+ onPressOut?.(event);
483
+ press.onPressOut();
484
+ }}
476
485
  style={press.rowStyle}
477
486
  className={cn(slots.item(), 'overflow-hidden', className)}
478
- {...props}
479
487
  >
480
488
  <Animated.View
481
489
  pointerEvents="none"
@@ -38,6 +38,7 @@ import Animated, {
38
38
  import { tv, type VariantProps } from 'tailwind-variants';
39
39
  import { useCSSVariable } from 'uniwind';
40
40
  import { Text } from '../../primitives/text';
41
+ import { resolveOtpEditable } from './otp-input-state';
41
42
 
42
43
  /** Long enough to read as a transition, short enough not to lag a fast type. */
43
44
  const FOCUS_DURATION = 150;
@@ -245,6 +246,7 @@ export const OtpInput = forwardRef<TextInput, OtpInputProps>(
245
246
  groupEvery = 0,
246
247
  size,
247
248
  disabled,
249
+ editable,
248
250
  isInvalid,
249
251
  errorMessage,
250
252
  accessibilityLabel,
@@ -351,7 +353,7 @@ export const OtpInput = forwardRef<TextInput, OtpInputProps>(
351
353
  ref={setRef}
352
354
  value={value}
353
355
  onChangeText={handleChange}
354
- editable={!disabled}
356
+ editable={resolveOtpEditable(editable, disabled)}
355
357
  keyboardType={type === 'numeric' ? 'number-pad' : 'default'}
356
358
  // The OS one-time-code affordances: iOS surfaces the SMS code above
357
359
  // the keyboard, Android offers to autofill it.
@@ -0,0 +1,7 @@
1
+ /** Resolve the native editing state without allowing `disabled` to be bypassed. */
2
+ export function resolveOtpEditable(
3
+ editable: boolean | undefined,
4
+ disabled: boolean | undefined
5
+ ): boolean {
6
+ return editable !== false && !disabled;
7
+ }
@@ -367,7 +367,7 @@ export interface PaginationItemProps
367
367
  * are on, so the current page is spoken as state rather than only painted.
368
368
  */
369
369
  const PaginationItem = forwardRef<View, PaginationItemProps>(
370
- ({ className, labelClassName, page, children, ...props }, ref) => {
370
+ ({ className, labelClassName, page, children, onPress, ...props }, ref) => {
371
371
  const { page: current, size, disabled, goTo } = usePagination('Pagination.Item');
372
372
  const isCurrent = page === current;
373
373
  const { item, itemLabel } = paginationVariants({ size, current: isCurrent, disabled });
@@ -375,14 +375,17 @@ const PaginationItem = forwardRef<View, PaginationItemProps>(
375
375
  return (
376
376
  <AnimatedPressable
377
377
  ref={ref}
378
+ {...props}
378
379
  accessibilityRole="button"
379
380
  accessibilityLabel={`Page ${page}`}
380
381
  accessibilityState={{ selected: isCurrent, disabled }}
381
382
  disabled={disabled}
382
383
  hitSlop={size === 'sm' ? SMALL_HIT_SLOP : undefined}
383
- onPress={() => goTo(page)}
384
+ onPress={(event) => {
385
+ onPress?.(event);
386
+ goTo(page);
387
+ }}
384
388
  className={item({ className })}
385
- {...props}
386
389
  >
387
390
  {textChildren(children ?? String(page), (text) => (
388
391
  <Text className={itemLabel({ className: labelClassName })}>{text}</Text>
@@ -437,23 +440,29 @@ function PaginationArrow({
437
440
  word,
438
441
  className,
439
442
  label,
443
+ disabled,
444
+ onPress,
440
445
  ...props
441
446
  }: PaginationArrowProps & { step: -1 | 1; part: string; word: string }) {
442
447
  const { Glyph, size, spent, color, press } = useArrow(step, part);
443
- const { item, itemLabel } = paginationVariants({ size, disabled: spent });
448
+ const isDisabled = Boolean(spent || disabled);
449
+ const { item, itemLabel } = paginationVariants({ size, disabled: isDisabled });
444
450
 
445
451
  return (
446
452
  <AnimatedPressable
453
+ {...props}
447
454
  accessibilityRole="button"
448
455
  accessibilityLabel={word}
449
- accessibilityState={{ disabled: spent }}
450
- disabled={spent}
456
+ accessibilityState={{ disabled: isDisabled }}
457
+ disabled={isDisabled}
451
458
  hitSlop={size === 'sm' ? SMALL_HIT_SLOP : undefined}
452
- onPress={press}
459
+ onPress={(event) => {
460
+ onPress?.(event);
461
+ press();
462
+ }}
453
463
  className={item({
454
464
  className: cn('flex-row gap-1', label && (size === 'sm' ? 'px-2' : 'px-3'), className),
455
465
  })}
456
- {...props}
457
466
  >
458
467
  {step === -1 ? <Glyph size={iconSize[size]} color={color} /> : null}
459
468
  {label ? <Text className={itemLabel()}>{word}</Text> : null}
@@ -489,24 +498,28 @@ export interface PaginationEllipsisProps
489
498
  * that always went forwards would strand anyone reading the row right to left.
490
499
  */
491
500
  const PaginationEllipsis = forwardRef<View, PaginationEllipsisProps>(
492
- ({ className, direction = 1, jump = 5, ...props }, ref) => {
501
+ ({ className, direction = 1, jump = 5, disabled: disabledProp, onPress, ...props }, ref) => {
493
502
  const { page, size, disabled, goTo } = usePagination('Pagination.Ellipsis');
494
503
  const color = useCSSVariable('--color-muted-foreground');
495
504
  const { ellipsis } = paginationVariants({ size });
505
+ const isDisabled = Boolean(disabled || disabledProp);
496
506
 
497
507
  return (
498
508
  <AnimatedPressable
499
509
  ref={ref}
510
+ {...props}
500
511
  accessibilityRole="button"
501
512
  accessibilityLabel={
502
513
  direction === -1 ? `Back ${jump} pages` : `Forward ${jump} pages`
503
514
  }
504
- accessibilityState={{ disabled }}
505
- disabled={disabled}
515
+ accessibilityState={{ disabled: isDisabled }}
516
+ disabled={isDisabled}
506
517
  hitSlop={size === 'sm' ? SMALL_HIT_SLOP : undefined}
507
- onPress={() => goTo(page + direction * jump)}
518
+ onPress={(event) => {
519
+ onPress?.(event);
520
+ goTo(page + direction * jump);
521
+ }}
508
522
  className={ellipsis({ className })}
509
- {...props}
510
523
  >
511
524
  <EllipsisIcon
512
525
  size={iconSize[size]}
@@ -1412,6 +1412,7 @@ function PanelsideTrigger({
1412
1412
  className,
1413
1413
  label = 'Open navigation panel',
1414
1414
  children,
1415
+ onPress,
1415
1416
  ...props
1416
1417
  }: PanelsideTriggerProps) {
1417
1418
  const { toggle, docked } = usePanelsideContext('Panelside.Trigger');
@@ -1426,6 +1427,7 @@ function PanelsideTrigger({
1426
1427
  return cloneElement(children, {
1427
1428
  onPress: (...args: unknown[]) => {
1428
1429
  children.props.onPress?.(...args);
1430
+ onPress?.(...(args as Parameters<NonNullable<PressableProps['onPress']>>));
1429
1431
  toggle();
1430
1432
  },
1431
1433
  });
@@ -1433,11 +1435,14 @@ function PanelsideTrigger({
1433
1435
 
1434
1436
  return (
1435
1437
  <AnimatedPressable
1436
- onPress={toggle}
1438
+ {...props}
1439
+ onPress={(event) => {
1440
+ onPress?.(event);
1441
+ toggle();
1442
+ }}
1437
1443
  className={cn('h-10 w-10 items-center justify-center rounded-full', className)}
1438
1444
  accessibilityRole="button"
1439
1445
  accessibilityLabel={label}
1440
- {...props}
1441
1446
  >
1442
1447
  <MenuIcon size={20} color={color} />
1443
1448
  </AnimatedPressable>
@@ -285,7 +285,7 @@ function PlanIcon({ className, children, ...props }: PlanIconProps) {
285
285
  );
286
286
  }
287
287
 
288
- export interface PlanTitleProps extends ViewProps {
288
+ export interface PlanTitleProps extends TextProps {
289
289
  className?: string;
290
290
  children?: ReactNode;
291
291
  }
@@ -306,7 +306,7 @@ function PlanTitle({ className, children, ...props }: PlanTitleProps) {
306
306
  );
307
307
  }
308
308
 
309
- export interface PlanDescriptionProps extends ViewProps {
309
+ export interface PlanDescriptionProps extends TextProps {
310
310
  className?: string;
311
311
  children?: ReactNode;
312
312
  }
@@ -115,6 +115,7 @@ import {
115
115
  usePlannerMonthLifecycle,
116
116
  usePlannerSelectionLifecycle,
117
117
  } from './planner-lifecycle';
118
+ import { millisecondsUntilNextLocalDay } from './planner-today';
118
119
 
119
120
  /** How many of a day's entries a cell draws before it stops and counts. */
120
121
  const DEFAULT_ENTRY_LIMIT = 2;
@@ -149,7 +150,13 @@ const dayVariants = tv({
149
150
  * Square-ish because a day here holds a number, a marker and sometimes an
150
151
  * icon, and a circle wastes the corners it needs for them.
151
152
  */
152
- cell: 'mx-0.5 h-14 flex-1 rounded-xl px-1.5 pt-1.5',
153
+ /*
154
+ * The transparent border is load-bearing: today and the open day both draw
155
+ * one, and a cell that only grows a border when it is picked shifts its
156
+ * contents by a point at the moment you look at it. Every cell reserves the
157
+ * point; the variants below only colour it.
158
+ */
159
+ cell: 'mx-0.5 h-14 flex-1 rounded-xl border border-transparent px-1.5 pt-1.5',
153
160
  number: 'text-xs leading-none',
154
161
  marker: 'absolute right-1.5 top-1.5 h-1.5 w-1.5 rounded-full',
155
162
  body: 'flex-1 flex-row items-center justify-center gap-0.5 pb-1',
@@ -161,13 +168,22 @@ const dayVariants = tv({
161
168
  false: { cell: 'bg-muted/15', number: 'text-muted-foreground/40' },
162
169
  },
163
170
  /*
164
- * Today is the number, not the tile. A ring on today and a ring on the
165
- * open day are two rings that mean different things and look the same.
171
+ * Today rings the tile; the open day fills it. Two rings would be the
172
+ * problem — two channels are not, and the ring is the one that has to
173
+ * survive being read at a glance across forty-two tiles.
166
174
  */
167
- today: { true: { number: 'text-primary font-semibold' } },
168
- selected: { true: { cell: 'border border-primary/60 bg-primary/10' } },
175
+ today: { true: { cell: 'border-foreground', number: 'font-semibold' } },
176
+ selected: { true: { cell: 'border-primary/60 bg-primary/10' } },
169
177
  disabled: { true: { cell: 'opacity-40' } },
170
178
  },
179
+ compoundVariants: [
180
+ /*
181
+ * Today, and open. Declaration order would otherwise hand the border to
182
+ * `selected` and lose the one mark that says which day it actually is —
183
+ * so the ring is restated over the fill.
184
+ */
185
+ { today: true, selected: true, class: { cell: 'border-foreground bg-primary/10' } },
186
+ ],
171
187
  defaultVariants: { inMonth: true },
172
188
  });
173
189
 
@@ -234,21 +250,38 @@ function usePlanner(component: string): PlannerContextValue {
234
250
  return context;
235
251
  }
236
252
 
237
- /** Today, recomputed when the app comes back rather than only at mount. */
253
+ /** Today, recomputed at local midnight and whenever the app comes back. */
238
254
  function useToday(): Date {
239
255
  const [today, setToday] = useState(() => startOfDay(new Date()));
240
256
 
241
257
  useEffect(() => {
242
- const refresh = () => {
243
- const now = startOfDay(new Date());
258
+ let timer: ReturnType<typeof setTimeout> | null = null;
259
+
260
+ const clearTimer = () => {
261
+ if (timer === null) return;
262
+ clearTimeout(timer);
263
+ timer = null;
264
+ };
265
+
266
+ const refreshAndSchedule = () => {
267
+ const current = new Date();
268
+ const now = startOfDay(current);
244
269
  // A new object every resume would invalidate every memo below it for a
245
270
  // date that has not changed.
246
- setToday((current) => (current.getTime() === now.getTime() ? current : now));
271
+ setToday((previous) => (previous.getTime() === now.getTime() ? previous : now));
272
+ clearTimer();
273
+ timer = setTimeout(refreshAndSchedule, millisecondsUntilNextLocalDay(current));
247
274
  };
275
+
276
+ refreshAndSchedule();
248
277
  const subscription = AppState.addEventListener('change', (state) => {
249
- if (state === 'active') refresh();
278
+ if (state === 'active') refreshAndSchedule();
279
+ else clearTimer();
250
280
  });
251
- return () => subscription.remove();
281
+ return () => {
282
+ clearTimer();
283
+ subscription.remove();
284
+ };
252
285
  }, []);
253
286
 
254
287
  return today;
@@ -0,0 +1,5 @@
1
+ export function millisecondsUntilNextLocalDay(now: Date): number {
2
+ const next = new Date(now);
3
+ next.setHours(24, 0, 0, 0);
4
+ return Math.max(next.getTime() - now.getTime(), 1);
5
+ }