@delacour/react-native-ui 0.1.0-alpha.4 → 0.2.0-alpha.20261010061731

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 (493) hide show
  1. package/README.md +10 -6
  2. package/package.json +49 -5
  3. package/src/components/accordion/AGENTS.md +21 -9
  4. package/src/components/accordion/accordion-content.tsx +7 -4
  5. package/src/components/accordion/accordion-item.tsx +15 -13
  6. package/src/components/accordion/accordion.context.tsx +11 -5
  7. package/src/components/accordion/accordion.variants.test.ts +64 -3
  8. package/src/components/accordion/accordion.variants.ts +33 -9
  9. package/src/components/alert/AGENTS.md +102 -0
  10. package/src/components/alert/alert-action.tsx +17 -0
  11. package/src/components/alert/alert-close-button.tsx +50 -0
  12. package/src/components/alert/alert-content.tsx +15 -0
  13. package/src/components/alert/alert-description.tsx +16 -0
  14. package/src/components/alert/alert-glyphs.ts +25 -0
  15. package/src/components/alert/alert-indicator.tsx +40 -0
  16. package/src/components/alert/alert-title.tsx +18 -0
  17. package/src/components/alert/alert.context.tsx +69 -0
  18. package/src/components/alert/alert.tsx +160 -0
  19. package/src/components/alert/alert.types.ts +10 -0
  20. package/src/components/alert/alert.variants.test.ts +218 -0
  21. package/src/components/alert/alert.variants.ts +180 -0
  22. package/src/components/alert/index.ts +23 -0
  23. package/src/components/avatar/AGENTS.md +106 -0
  24. package/src/components/avatar/avatar-badge.tsx +51 -0
  25. package/src/components/avatar/avatar-group.tsx +139 -0
  26. package/src/components/avatar/avatar.context.tsx +93 -0
  27. package/src/components/avatar/avatar.tsx +201 -0
  28. package/src/components/avatar/avatar.utils.test.ts +174 -0
  29. package/src/components/avatar/avatar.utils.ts +141 -0
  30. package/src/components/avatar/avatar.variants.test.ts +251 -0
  31. package/src/components/avatar/avatar.variants.ts +270 -0
  32. package/src/components/avatar/index.ts +39 -0
  33. package/src/components/badge/AGENTS.md +10 -0
  34. package/src/components/badge/badge-close-button.tsx +2 -2
  35. package/src/components/badge/badge.context.tsx +2 -1
  36. package/src/components/badge/badge.tsx +13 -4
  37. package/src/components/badge/badge.variants.test.ts +26 -0
  38. package/src/components/badge/badge.variants.ts +21 -0
  39. package/src/components/bottom-sheet/AGENTS.md +186 -231
  40. package/src/components/bottom-sheet/bottom-sheet-background.tsx +31 -22
  41. package/src/components/bottom-sheet/bottom-sheet-close.tsx +23 -30
  42. package/src/components/bottom-sheet/bottom-sheet-container.tsx +54 -208
  43. package/src/components/bottom-sheet/bottom-sheet-content.tsx +25 -48
  44. package/src/components/bottom-sheet/bottom-sheet-description.tsx +8 -2
  45. package/src/components/bottom-sheet/bottom-sheet-flat-list.tsx +65 -0
  46. package/src/components/bottom-sheet/bottom-sheet-footer.tsx +53 -122
  47. package/src/components/bottom-sheet/bottom-sheet-handle.tsx +31 -26
  48. package/src/components/bottom-sheet/bottom-sheet-legend-list.tsx +69 -0
  49. package/src/components/bottom-sheet/bottom-sheet-overlay.tsx +25 -147
  50. package/src/components/bottom-sheet/bottom-sheet-provider.tsx +42 -0
  51. package/src/components/bottom-sheet/bottom-sheet-scroll-view.tsx +38 -62
  52. package/src/components/bottom-sheet/bottom-sheet-section-list.tsx +58 -0
  53. package/src/components/bottom-sheet/bottom-sheet-steps.tsx +88 -0
  54. package/src/components/bottom-sheet/bottom-sheet-text-input.tsx +44 -0
  55. package/src/components/bottom-sheet/bottom-sheet-title.tsx +12 -8
  56. package/src/components/bottom-sheet/bottom-sheet-trigger.tsx +19 -37
  57. package/src/components/bottom-sheet/bottom-sheet.tsx +113 -60
  58. package/src/components/bottom-sheet/bottom-sheet.variants.test.ts +47 -87
  59. package/src/components/bottom-sheet/bottom-sheet.variants.ts +50 -126
  60. package/src/components/bottom-sheet/index.ts +39 -17
  61. package/src/components/bottom-sheet/use-bottom-sheet-input.ts +16 -115
  62. package/src/components/button/AGENTS.md +51 -11
  63. package/src/components/button/button-group.tsx +44 -8
  64. package/src/components/button/button.context.tsx +10 -0
  65. package/src/components/button/button.tsx +7 -1
  66. package/src/components/button/button.variants.test.ts +190 -0
  67. package/src/components/button/button.variants.ts +87 -6
  68. package/src/components/button/index.ts +2 -0
  69. package/src/components/calendar/AGENTS.md +142 -0
  70. package/src/components/calendar/calendar-caption.tsx +116 -0
  71. package/src/components/calendar/calendar-day.tsx +103 -0
  72. package/src/components/calendar/calendar-grid.tsx +183 -0
  73. package/src/components/calendar/calendar-header.tsx +34 -0
  74. package/src/components/calendar/calendar-nav.tsx +51 -0
  75. package/src/components/calendar/calendar-picker.tsx +128 -0
  76. package/src/components/calendar/calendar-weekdays.tsx +48 -0
  77. package/src/components/calendar/calendar.context.tsx +108 -0
  78. package/src/components/calendar/calendar.date.test.ts +456 -0
  79. package/src/components/calendar/calendar.date.ts +584 -0
  80. package/src/components/calendar/calendar.tsx +389 -0
  81. package/src/components/calendar/calendar.types.ts +87 -0
  82. package/src/components/calendar/calendar.variants.test.ts +363 -0
  83. package/src/components/calendar/calendar.variants.ts +426 -0
  84. package/src/components/calendar/index.ts +96 -0
  85. package/src/components/card/AGENTS.md +92 -0
  86. package/src/components/card/card-action.tsx +16 -0
  87. package/src/components/card/card-content.tsx +12 -0
  88. package/src/components/card/card-description.tsx +12 -0
  89. package/src/components/card/card-footer.tsx +30 -0
  90. package/src/components/card/card-header.tsx +45 -0
  91. package/src/components/card/card-title.tsx +25 -0
  92. package/src/components/card/card.context.tsx +64 -0
  93. package/src/components/card/card.tsx +100 -0
  94. package/src/components/card/card.types.ts +13 -0
  95. package/src/components/card/card.variants.test.ts +240 -0
  96. package/src/components/card/card.variants.ts +177 -0
  97. package/src/components/card/index.ts +15 -0
  98. package/src/components/chart/AGENTS.md +8 -0
  99. package/src/components/chart/chart.tsx +8 -1
  100. package/src/components/chip/AGENTS.md +113 -0
  101. package/src/components/chip/chip-close-button.tsx +48 -0
  102. package/src/components/chip/chip-end-content.tsx +15 -0
  103. package/src/components/chip/chip-label.tsx +21 -0
  104. package/src/components/chip/chip-start-content.tsx +16 -0
  105. package/src/components/chip/chip.context.tsx +66 -0
  106. package/src/components/chip/chip.tsx +268 -0
  107. package/src/components/chip/chip.types.ts +10 -0
  108. package/src/components/chip/chip.variants.test.ts +335 -0
  109. package/src/components/chip/chip.variants.ts +321 -0
  110. package/src/components/chip/index.ts +24 -0
  111. package/src/components/collapsible/AGENTS.md +97 -0
  112. package/src/components/collapsible/collapsible-content.tsx +97 -0
  113. package/src/components/collapsible/collapsible-description.tsx +17 -0
  114. package/src/components/collapsible/collapsible-indicator.tsx +92 -0
  115. package/src/components/collapsible/collapsible-title.tsx +17 -0
  116. package/src/components/collapsible/collapsible-trigger.tsx +133 -0
  117. package/src/components/collapsible/collapsible.context.tsx +91 -0
  118. package/src/components/collapsible/collapsible.tsx +167 -0
  119. package/src/components/collapsible/collapsible.types.ts +9 -0
  120. package/src/components/collapsible/collapsible.variants.test.ts +338 -0
  121. package/src/components/collapsible/collapsible.variants.ts +228 -0
  122. package/src/components/collapsible/index.ts +32 -0
  123. package/src/components/context-menu/AGENTS.md +103 -0
  124. package/src/components/context-menu/context-menu-content.tsx +64 -0
  125. package/src/components/context-menu/context-menu-item.tsx +22 -0
  126. package/src/components/context-menu/context-menu-preview.tsx +60 -0
  127. package/src/components/context-menu/context-menu-trigger.tsx +160 -0
  128. package/src/components/context-menu/context-menu.context.tsx +91 -0
  129. package/src/components/context-menu/context-menu.tsx +90 -0
  130. package/src/components/context-menu/context-menu.variants.test.ts +266 -0
  131. package/src/components/context-menu/context-menu.variants.ts +147 -0
  132. package/src/components/context-menu/index.ts +18 -0
  133. package/src/components/dialog/AGENTS.md +97 -0
  134. package/src/components/dialog/dialog-body.tsx +21 -0
  135. package/src/components/dialog/dialog-close.tsx +82 -0
  136. package/src/components/dialog/dialog-content.tsx +153 -0
  137. package/src/components/dialog/dialog-description.tsx +23 -0
  138. package/src/components/dialog/dialog-footer.tsx +32 -0
  139. package/src/components/dialog/dialog-header.tsx +20 -0
  140. package/src/components/dialog/dialog-title.tsx +42 -0
  141. package/src/components/dialog/dialog-trigger.tsx +54 -0
  142. package/src/components/dialog/dialog.context.tsx +90 -0
  143. package/src/components/dialog/dialog.tsx +119 -0
  144. package/src/components/dialog/dialog.variants.test.ts +224 -0
  145. package/src/components/dialog/dialog.variants.ts +173 -0
  146. package/src/components/dialog/index.ts +30 -0
  147. package/src/components/drawer/AGENTS.md +123 -0
  148. package/src/components/drawer/drawer-body.tsx +46 -0
  149. package/src/components/drawer/drawer-close.tsx +76 -0
  150. package/src/components/drawer/drawer-content.tsx +186 -0
  151. package/src/components/drawer/drawer-description.tsx +23 -0
  152. package/src/components/drawer/drawer-footer.tsx +21 -0
  153. package/src/components/drawer/drawer-header.tsx +42 -0
  154. package/src/components/drawer/drawer-title.tsx +35 -0
  155. package/src/components/drawer/drawer-trigger.tsx +54 -0
  156. package/src/components/drawer/drawer.context.tsx +114 -0
  157. package/src/components/drawer/drawer.tsx +119 -0
  158. package/src/components/drawer/drawer.variants.test.ts +392 -0
  159. package/src/components/drawer/drawer.variants.ts +244 -0
  160. package/src/components/drawer/index.ts +41 -0
  161. package/src/components/drawer/use-drawer-pan.ts +108 -0
  162. package/src/components/empty-state/AGENTS.md +90 -0
  163. package/src/components/empty-state/empty-state-content.tsx +17 -0
  164. package/src/components/empty-state/empty-state-description.tsx +12 -0
  165. package/src/components/empty-state/empty-state-header.tsx +17 -0
  166. package/src/components/empty-state/empty-state-media.tsx +56 -0
  167. package/src/components/empty-state/empty-state-title.tsx +18 -0
  168. package/src/components/empty-state/empty-state.context.tsx +65 -0
  169. package/src/components/empty-state/empty-state.tsx +84 -0
  170. package/src/components/empty-state/empty-state.types.ts +14 -0
  171. package/src/components/empty-state/empty-state.variants.test.ts +245 -0
  172. package/src/components/empty-state/empty-state.variants.ts +132 -0
  173. package/src/components/empty-state/index.ts +20 -0
  174. package/src/components/fab/AGENTS.md +119 -0
  175. package/src/components/fab/fab-action.tsx +118 -0
  176. package/src/components/fab/fab-group.tsx +214 -0
  177. package/src/components/fab/fab-label.tsx +18 -0
  178. package/src/components/fab/fab.context.tsx +125 -0
  179. package/src/components/fab/fab.tsx +156 -0
  180. package/src/components/fab/fab.types.ts +17 -0
  181. package/src/components/fab/fab.variants.test.ts +274 -0
  182. package/src/components/fab/fab.variants.ts +234 -0
  183. package/src/components/fab/index.ts +37 -0
  184. package/src/components/feedback/AGENTS.md +95 -0
  185. package/src/components/feedback/feedback-action.tsx +16 -0
  186. package/src/components/feedback/feedback-cancel.tsx +34 -0
  187. package/src/components/feedback/feedback-close.tsx +21 -0
  188. package/src/components/feedback/feedback-content.tsx +24 -0
  189. package/src/components/feedback/feedback-field.tsx +70 -0
  190. package/src/components/feedback/feedback-footer.tsx +21 -0
  191. package/src/components/feedback/feedback-panel.tsx +54 -0
  192. package/src/components/feedback/feedback-submit.tsx +74 -0
  193. package/src/components/feedback/feedback-title.tsx +34 -0
  194. package/src/components/feedback/feedback-trigger.tsx +20 -0
  195. package/src/components/feedback/feedback.context.tsx +73 -0
  196. package/src/components/feedback/feedback.tsx +135 -0
  197. package/src/components/feedback/feedback.variants.test.ts +185 -0
  198. package/src/components/feedback/feedback.variants.ts +128 -0
  199. package/src/components/feedback/index.ts +24 -0
  200. package/src/components/field/AGENTS.md +19 -0
  201. package/src/components/field/field-label.tsx +19 -5
  202. package/src/components/field/field.context.tsx +17 -0
  203. package/src/components/field/field.tsx +15 -2
  204. package/src/components/field/field.variants.test.ts +24 -0
  205. package/src/components/field/field.variants.ts +20 -0
  206. package/src/components/field/index.ts +1 -0
  207. package/src/components/input/AGENTS.md +5 -0
  208. package/src/components/input/input.variants.test.ts +32 -0
  209. package/src/components/input/input.variants.ts +13 -1
  210. package/src/components/item/AGENTS.md +92 -0
  211. package/src/components/item/index.ts +25 -0
  212. package/src/components/item/item-actions.tsx +28 -0
  213. package/src/components/item/item-content.tsx +15 -0
  214. package/src/components/item/item-description.tsx +12 -0
  215. package/src/components/item/item-footer.tsx +13 -0
  216. package/src/components/item/item-group.tsx +32 -0
  217. package/src/components/item/item-header.tsx +13 -0
  218. package/src/components/item/item-media.tsx +37 -0
  219. package/src/components/item/item-separator.tsx +13 -0
  220. package/src/components/item/item-title.tsx +17 -0
  221. package/src/components/item/item.context.tsx +66 -0
  222. package/src/components/item/item.tsx +218 -0
  223. package/src/components/item/item.types.ts +12 -0
  224. package/src/components/item/item.variants.test.ts +263 -0
  225. package/src/components/item/item.variants.ts +200 -0
  226. package/src/components/kpi/AGENTS.md +125 -0
  227. package/src/components/kpi/index.ts +45 -0
  228. package/src/components/kpi/kpi-action.tsx +12 -0
  229. package/src/components/kpi/kpi-content.tsx +35 -0
  230. package/src/components/kpi/kpi-footer.tsx +52 -0
  231. package/src/components/kpi/kpi-group.tsx +70 -0
  232. package/src/components/kpi/kpi-header.tsx +25 -0
  233. package/src/components/kpi/kpi-icon.tsx +28 -0
  234. package/src/components/kpi/kpi-sparkline.tsx +145 -0
  235. package/src/components/kpi/kpi-stat.tsx +20 -0
  236. package/src/components/kpi/kpi-title.tsx +19 -0
  237. package/src/components/kpi/kpi-trend.tsx +105 -0
  238. package/src/components/kpi/kpi-value.tsx +32 -0
  239. package/src/components/kpi/kpi.context.tsx +111 -0
  240. package/src/components/kpi/kpi.tsx +154 -0
  241. package/src/components/kpi/kpi.types.ts +9 -0
  242. package/src/components/kpi/kpi.variants.test.ts +428 -0
  243. package/src/components/kpi/kpi.variants.ts +347 -0
  244. package/src/components/label/AGENTS.md +89 -0
  245. package/src/components/label/index.ts +10 -0
  246. package/src/components/label/label.tsx +97 -0
  247. package/src/components/label/label.variants.test.ts +176 -0
  248. package/src/components/label/label.variants.ts +123 -0
  249. package/src/components/menu/AGENTS.md +176 -0
  250. package/src/components/menu/index.ts +44 -0
  251. package/src/components/menu/menu-background.tsx +17 -0
  252. package/src/components/menu/menu-checkbox-item.tsx +57 -0
  253. package/src/components/menu/menu-content.tsx +303 -0
  254. package/src/components/menu/menu-item.tsx +162 -0
  255. package/src/components/menu/menu-label.tsx +14 -0
  256. package/src/components/menu/menu-radio-group.tsx +50 -0
  257. package/src/components/menu/menu-radio-item.tsx +57 -0
  258. package/src/components/menu/menu-separator.tsx +11 -0
  259. package/src/components/menu/menu-sub-content.tsx +72 -0
  260. package/src/components/menu/menu-sub-trigger.tsx +50 -0
  261. package/src/components/menu/menu-sub.tsx +75 -0
  262. package/src/components/menu/menu-trigger.tsx +57 -0
  263. package/src/components/menu/menu.context.tsx +214 -0
  264. package/src/components/menu/menu.tsx +88 -0
  265. package/src/components/menu/menu.types.ts +33 -0
  266. package/src/components/menu/menu.variants.test.ts +400 -0
  267. package/src/components/menu/menu.variants.ts +353 -0
  268. package/src/components/meter/AGENTS.md +135 -0
  269. package/src/components/meter/index.ts +43 -0
  270. package/src/components/meter/meter-fill.tsx +19 -0
  271. package/src/components/meter/meter-header.tsx +17 -0
  272. package/src/components/meter/meter-label.tsx +18 -0
  273. package/src/components/meter/meter-output.tsx +42 -0
  274. package/src/components/meter/meter-segments.tsx +83 -0
  275. package/src/components/meter/meter-track.tsx +16 -0
  276. package/src/components/meter/meter.context.tsx +62 -0
  277. package/src/components/meter/meter.tsx +286 -0
  278. package/src/components/meter/meter.types.ts +30 -0
  279. package/src/components/meter/meter.variants.test.ts +430 -0
  280. package/src/components/meter/meter.variants.ts +347 -0
  281. package/src/components/overlay/AGENTS.md +89 -0
  282. package/src/components/overlay/index.ts +27 -0
  283. package/src/components/overlay/overlay-portal.tsx +84 -0
  284. package/src/components/overlay/overlay-presence.test.ts +46 -0
  285. package/src/components/overlay/overlay-presence.ts +49 -0
  286. package/src/components/overlay/overlay-registry.test.ts +96 -0
  287. package/src/components/overlay/overlay-registry.ts +99 -0
  288. package/src/components/overlay/overlay-scrim.tsx +49 -0
  289. package/src/components/overlay/overlay.context.tsx +48 -0
  290. package/src/components/overlay/overlay.tsx +118 -0
  291. package/src/components/overlay/overlay.variants.test.ts +37 -0
  292. package/src/components/overlay/overlay.variants.ts +33 -0
  293. package/src/components/overlay/use-overlay-back-handler.ts +34 -0
  294. package/src/components/overlay/use-overlay-presence.ts +87 -0
  295. package/src/components/popover/AGENTS.md +138 -0
  296. package/src/components/popover/index.ts +48 -0
  297. package/src/components/popover/popover-anchor.tsx +49 -0
  298. package/src/components/popover/popover-arrow.tsx +89 -0
  299. package/src/components/popover/popover-close.tsx +73 -0
  300. package/src/components/popover/popover-content.tsx +235 -0
  301. package/src/components/popover/popover-description.tsx +18 -0
  302. package/src/components/popover/popover-title.tsx +33 -0
  303. package/src/components/popover/popover-trigger.tsx +56 -0
  304. package/src/components/popover/popover.context.tsx +71 -0
  305. package/src/components/popover/popover.position.test.ts +354 -0
  306. package/src/components/popover/popover.position.ts +286 -0
  307. package/src/components/popover/popover.tsx +123 -0
  308. package/src/components/popover/popover.variants.test.ts +135 -0
  309. package/src/components/popover/popover.variants.ts +85 -0
  310. package/src/components/popover/use-anchor-measure.ts +76 -0
  311. package/src/components/popover/use-anchored-content.ts +219 -0
  312. package/src/components/pressable/AGENTS.md +11 -1
  313. package/src/components/pressable/pressable.tsx +7 -2
  314. package/src/components/pressable/pressable.variants.test.ts +29 -0
  315. package/src/components/pressable/pressable.variants.ts +17 -0
  316. package/src/components/progress/AGENTS.md +120 -0
  317. package/src/components/progress/index.ts +40 -0
  318. package/src/components/progress/progress-fill.tsx +152 -0
  319. package/src/components/progress/progress-header.tsx +19 -0
  320. package/src/components/progress/progress-label.tsx +27 -0
  321. package/src/components/progress/progress-output.tsx +47 -0
  322. package/src/components/progress/progress-track.tsx +38 -0
  323. package/src/components/progress/progress.context.tsx +79 -0
  324. package/src/components/progress/progress.tsx +171 -0
  325. package/src/components/progress/progress.types.ts +23 -0
  326. package/src/components/progress/progress.variants.test.ts +335 -0
  327. package/src/components/progress/progress.variants.ts +284 -0
  328. package/src/components/progress-button/AGENTS.md +116 -0
  329. package/src/components/progress-button/index.ts +36 -0
  330. package/src/components/progress-button/progress-button-done.tsx +33 -0
  331. package/src/components/progress-button/progress-button-label.tsx +27 -0
  332. package/src/components/progress-button/progress-button.context.tsx +93 -0
  333. package/src/components/progress-button/progress-button.tsx +414 -0
  334. package/src/components/progress-button/progress-button.variants.test.ts +314 -0
  335. package/src/components/progress-button/progress-button.variants.ts +236 -0
  336. package/src/components/provider/AGENTS.md +38 -25
  337. package/src/components/provider/provider.tsx +38 -11
  338. package/src/components/radio/AGENTS.md +8 -10
  339. package/src/components/radio/radio.variants.test.ts +5 -6
  340. package/src/components/radio/radio.variants.ts +6 -7
  341. package/src/components/rating/AGENTS.md +143 -0
  342. package/src/components/rating/index.ts +43 -0
  343. package/src/components/rating/rating-output.tsx +39 -0
  344. package/src/components/rating/rating-star.tsx +70 -0
  345. package/src/components/rating/rating-stars.tsx +219 -0
  346. package/src/components/rating/rating.context.tsx +79 -0
  347. package/src/components/rating/rating.tsx +163 -0
  348. package/src/components/rating/rating.variants.test.ts +347 -0
  349. package/src/components/rating/rating.variants.ts +354 -0
  350. package/src/components/selection-mode/AGENTS.md +155 -0
  351. package/src/components/selection-mode/index.ts +43 -0
  352. package/src/components/selection-mode/selection-mode-action.tsx +65 -0
  353. package/src/components/selection-mode/selection-mode-bar.tsx +79 -0
  354. package/src/components/selection-mode/selection-mode-group.tsx +123 -0
  355. package/src/components/selection-mode/selection-mode-header.tsx +85 -0
  356. package/src/components/selection-mode/selection-mode-indicator.tsx +118 -0
  357. package/src/components/selection-mode/selection-mode-item.tsx +182 -0
  358. package/src/components/selection-mode/selection-mode.context.tsx +89 -0
  359. package/src/components/selection-mode/selection-mode.tsx +207 -0
  360. package/src/components/selection-mode/selection-mode.types.ts +36 -0
  361. package/src/components/selection-mode/selection-mode.variants.test.ts +292 -0
  362. package/src/components/selection-mode/selection-mode.variants.ts +329 -0
  363. package/src/components/skeleton/AGENTS.md +120 -0
  364. package/src/components/skeleton/index.ts +15 -0
  365. package/src/components/skeleton/skeleton-clock.ts +48 -0
  366. package/src/components/skeleton/skeleton-group.tsx +64 -0
  367. package/src/components/skeleton/skeleton-shimmer.tsx +80 -0
  368. package/src/components/skeleton/skeleton.context.tsx +45 -0
  369. package/src/components/skeleton/skeleton.tsx +227 -0
  370. package/src/components/skeleton/skeleton.variants.test.ts +245 -0
  371. package/src/components/skeleton/skeleton.variants.ts +222 -0
  372. package/src/components/slide-button/AGENTS.md +122 -0
  373. package/src/components/slide-button/index.ts +43 -0
  374. package/src/components/slide-button/slide-button-label.tsx +70 -0
  375. package/src/components/slide-button/slide-button-thumb.tsx +93 -0
  376. package/src/components/slide-button/slide-button.context.tsx +76 -0
  377. package/src/components/slide-button/slide-button.tsx +457 -0
  378. package/src/components/slide-button/slide-button.variants.test.ts +288 -0
  379. package/src/components/slide-button/slide-button.variants.ts +324 -0
  380. package/src/components/slider/index.ts +2 -0
  381. package/src/components/slider/slider-thumb.tsx +33 -1
  382. package/src/components/slider/slider.variants.test.ts +52 -0
  383. package/src/components/slider/slider.variants.ts +56 -2
  384. package/src/components/stack-card/AGENTS.md +169 -0
  385. package/src/components/stack-card/index.ts +37 -0
  386. package/src/components/stack-card/stack-card-action.tsx +66 -0
  387. package/src/components/stack-card/stack-card-actions.tsx +18 -0
  388. package/src/components/stack-card/stack-card-card.tsx +71 -0
  389. package/src/components/stack-card/stack-card-empty.tsx +30 -0
  390. package/src/components/stack-card/stack-card-slot.tsx +90 -0
  391. package/src/components/stack-card/stack-card-stamp.tsx +76 -0
  392. package/src/components/stack-card/stack-card.context.tsx +117 -0
  393. package/src/components/stack-card/stack-card.tsx +557 -0
  394. package/src/components/stack-card/stack-card.types.ts +26 -0
  395. package/src/components/stack-card/stack-card.variants.test.ts +355 -0
  396. package/src/components/stack-card/stack-card.variants.ts +360 -0
  397. package/src/components/steps/AGENTS.md +153 -0
  398. package/src/components/steps/index.ts +45 -0
  399. package/src/components/steps/steps-connector.tsx +31 -0
  400. package/src/components/steps/steps-description.tsx +26 -0
  401. package/src/components/steps/steps-indicator.tsx +106 -0
  402. package/src/components/steps/steps-item.tsx +225 -0
  403. package/src/components/steps/steps-panel.tsx +41 -0
  404. package/src/components/steps/steps-title.tsx +32 -0
  405. package/src/components/steps/steps-track.tsx +59 -0
  406. package/src/components/steps/steps.context.tsx +123 -0
  407. package/src/components/steps/steps.tsx +166 -0
  408. package/src/components/steps/steps.variants.test.ts +388 -0
  409. package/src/components/steps/steps.variants.ts +468 -0
  410. package/src/components/surface/AGENTS.md +82 -0
  411. package/src/components/surface/index.ts +15 -0
  412. package/src/components/surface/surface.context.tsx +56 -0
  413. package/src/components/surface/surface.tsx +87 -0
  414. package/src/components/surface/surface.variants.test.ts +227 -0
  415. package/src/components/surface/surface.variants.ts +165 -0
  416. package/src/components/swipe/AGENTS.md +140 -0
  417. package/src/components/swipe/index.ts +31 -0
  418. package/src/components/swipe/swipe-action.tsx +99 -0
  419. package/src/components/swipe/swipe-end.tsx +14 -0
  420. package/src/components/swipe/swipe-group.tsx +55 -0
  421. package/src/components/swipe/swipe-panel.tsx +55 -0
  422. package/src/components/swipe/swipe-start.tsx +15 -0
  423. package/src/components/swipe/swipe.context.tsx +135 -0
  424. package/src/components/swipe/swipe.tsx +393 -0
  425. package/src/components/swipe/swipe.types.ts +7 -0
  426. package/src/components/swipe/swipe.variants.test.ts +337 -0
  427. package/src/components/swipe/swipe.variants.ts +290 -0
  428. package/src/components/switch/switch.variants.ts +2 -2
  429. package/src/components/tabs/AGENTS.md +4 -3
  430. package/src/components/tabs/tabs.variants.test.ts +1 -1
  431. package/src/components/tabs/tabs.variants.ts +4 -6
  432. package/src/components/text/AGENTS.md +8 -2
  433. package/src/components/text/text.tsx +7 -0
  434. package/src/components/text/text.variants.test.ts +24 -1
  435. package/src/components/text/text.variants.ts +5 -0
  436. package/src/components/textarea/AGENTS.md +89 -0
  437. package/src/components/textarea/index.ts +16 -0
  438. package/src/components/textarea/textarea.tsx +157 -0
  439. package/src/components/textarea/textarea.variants.test.ts +219 -0
  440. package/src/components/textarea/textarea.variants.ts +171 -0
  441. package/src/components/toast/AGENTS.md +140 -0
  442. package/src/components/toast/index.ts +74 -0
  443. package/src/components/toast/toast-action.tsx +59 -0
  444. package/src/components/toast/toast-api.ts +32 -0
  445. package/src/components/toast/toast-close.tsx +44 -0
  446. package/src/components/toast/toast-content.tsx +11 -0
  447. package/src/components/toast/toast-description.tsx +11 -0
  448. package/src/components/toast/toast-indicator.tsx +34 -0
  449. package/src/components/toast/toast-item.tsx +308 -0
  450. package/src/components/toast/toast-title.tsx +13 -0
  451. package/src/components/toast/toast-viewport.tsx +135 -0
  452. package/src/components/toast/toast.context.tsx +69 -0
  453. package/src/components/toast/toast.store.test.ts +259 -0
  454. package/src/components/toast/toast.store.ts +338 -0
  455. package/src/components/toast/toast.timer.test.ts +64 -0
  456. package/src/components/toast/toast.timer.ts +51 -0
  457. package/src/components/toast/toast.tsx +132 -0
  458. package/src/components/toast/toast.variants.test.ts +393 -0
  459. package/src/components/toast/toast.variants.ts +304 -0
  460. package/src/components/toggle-button/AGENTS.md +106 -0
  461. package/src/components/toggle-button/index.ts +30 -0
  462. package/src/components/toggle-button/toggle-button-group.tsx +156 -0
  463. package/src/components/toggle-button/toggle-button-label.tsx +19 -0
  464. package/src/components/toggle-button/toggle-button.context.tsx +130 -0
  465. package/src/components/toggle-button/toggle-button.tsx +172 -0
  466. package/src/components/toggle-button/toggle-button.variants.test.ts +189 -0
  467. package/src/components/toggle-button/toggle-button.variants.ts +160 -0
  468. package/src/components/tooltip/AGENTS.md +133 -0
  469. package/src/components/tooltip/index.ts +28 -0
  470. package/src/components/tooltip/tooltip-arrow.tsx +40 -0
  471. package/src/components/tooltip/tooltip-content.tsx +179 -0
  472. package/src/components/tooltip/tooltip-description.tsx +19 -0
  473. package/src/components/tooltip/tooltip-text.tsx +21 -0
  474. package/src/components/tooltip/tooltip-title.tsx +20 -0
  475. package/src/components/tooltip/tooltip-trigger.tsx +103 -0
  476. package/src/components/tooltip/tooltip.context.tsx +68 -0
  477. package/src/components/tooltip/tooltip.tsx +213 -0
  478. package/src/components/tooltip/tooltip.variants.test.ts +231 -0
  479. package/src/components/tooltip/tooltip.variants.ts +177 -0
  480. package/src/hooks/use-calm-motion.tsx +31 -0
  481. package/src/lib/calm-motion.test.ts +17 -0
  482. package/src/lib/calm-motion.ts +23 -0
  483. package/src/lib/cn.parity.test.ts +62 -0
  484. package/src/lib/cn.test.ts +14 -0
  485. package/src/lib/cn.ts +11 -6
  486. package/src/no-gorhom.test.ts +54 -0
  487. package/src/styles/geometry.test.ts +1 -0
  488. package/src/styles/theme.css +4 -0
  489. package/src/styles/tokens.css +44 -0
  490. package/src/styles/tokens.test.ts +56 -0
  491. package/src/styles/tokens.ts +29 -1
  492. package/src/components/bottom-sheet/bottom-sheet-portal.tsx +0 -72
  493. package/src/components/bottom-sheet/bottom-sheet.context.tsx +0 -135
@@ -0,0 +1,152 @@
1
+ import { type ReactElement, useEffect } from "react";
2
+ import type { ViewProps } from "react-native";
3
+ import Animated, {
4
+ cancelAnimation,
5
+ Easing,
6
+ ReduceMotion,
7
+ useAnimatedStyle,
8
+ useReducedMotion,
9
+ useSharedValue,
10
+ withRepeat,
11
+ withTiming,
12
+ } from "react-native-reanimated";
13
+ import { useProgressPart } from "./progress.context";
14
+ import {
15
+ fillTranslate,
16
+ indeterminateSegment,
17
+ PROGRESS_FILL_DURATION_MS,
18
+ PROGRESS_INDETERMINATE_DURATION_MS,
19
+ PROGRESS_INDETERMINATE_SEGMENT,
20
+ PROGRESS_PULSE,
21
+ progressVariants,
22
+ } from "./progress.variants";
23
+
24
+ export type ProgressFillProps = Omit<ViewProps, "children" | "style"> & {
25
+ className?: string;
26
+ };
27
+
28
+ /**
29
+ * The painted bar.
30
+ *
31
+ * **Everything it animates runs on the UI thread.** A new value is handed to
32
+ * `withTiming` once, from an effect, and the frames that follow never touch
33
+ * React — so an upload reporting ten times a second costs ten renders, not six
34
+ * hundred.
35
+ *
36
+ * **Determinate, it is a full-length bar parked left of the track** by what is
37
+ * still to go, and a `translateX` slides it in. A transform composites without a
38
+ * layout pass; an animated `width` would re-lay the bar out on every frame. The
39
+ * track clips what is parked.
40
+ *
41
+ * **Indeterminate, it is a segment sweeping across**, from wholly off the left
42
+ * edge to wholly off the right, so the loop's seam is never on screen. With the
43
+ * system's reduce-motion setting on, the sweep becomes the whole track breathing
44
+ * between two opacities instead: still visibly alive — which a status indicator
45
+ * must be, the same reasoning `Spinner` gives for opting out of the policy — but
46
+ * with nothing travelling across the screen.
47
+ *
48
+ * It is hidden until the track has been measured. A fill positioned against a
49
+ * width of 0 would flash at full length for the frame before layout lands.
50
+ */
51
+ export function ProgressFill({ className, ...props }: ProgressFillProps): ReactElement {
52
+ const { ratio, isIndeterminate, color, size, trackSize } = useProgressPart("Progress.Fill");
53
+ const isReducedMotion = useReducedMotion();
54
+
55
+ // Seeded at the current ratio, so a bar that mounts at 60% is drawn at 60%
56
+ // rather than animating up from nothing every time a list row scrolls in.
57
+ const progress = useSharedValue(ratio);
58
+ const phase = useSharedValue(0);
59
+ const pulse = useSharedValue<number>(PROGRESS_PULSE.to);
60
+
61
+ useEffect(() => {
62
+ if (isIndeterminate) return;
63
+ progress.value = withTiming(ratio, {
64
+ duration: PROGRESS_FILL_DURATION_MS,
65
+ easing: Easing.out(Easing.cubic),
66
+ });
67
+ }, [isIndeterminate, progress, ratio]);
68
+
69
+ useEffect(() => {
70
+ if (!isIndeterminate) return;
71
+
72
+ if (isReducedMotion) {
73
+ pulse.value = PROGRESS_PULSE.to;
74
+ pulse.value = withRepeat(
75
+ withTiming(PROGRESS_PULSE.from, {
76
+ duration: PROGRESS_PULSE.durationMs,
77
+ easing: Easing.inOut(Easing.ease),
78
+ // Under the default `System` policy the timing completes instantly
79
+ // while reduce motion is on, and `withRepeat(-1)` would spin a
80
+ // zero-length animation forever — a frozen bar, which reads as hung.
81
+ reduceMotion: ReduceMotion.Never,
82
+ }),
83
+ -1,
84
+ true,
85
+ undefined,
86
+ // The repeat has a reduce-motion policy of its own, separate from the
87
+ // timing's. Left at `System`, it declines to start a reversing loop at
88
+ // all and stops a forward one after a single pass.
89
+ ReduceMotion.Never
90
+ );
91
+ } else {
92
+ phase.value = 0;
93
+ phase.value = withRepeat(
94
+ withTiming(1, {
95
+ duration: PROGRESS_INDETERMINATE_DURATION_MS,
96
+ easing: Easing.inOut(Easing.ease),
97
+ reduceMotion: ReduceMotion.Never,
98
+ }),
99
+ -1,
100
+ false,
101
+ undefined,
102
+ ReduceMotion.Never
103
+ );
104
+ }
105
+
106
+ // Without this the repeat outlives the bar, or the switch back to a value.
107
+ return () => {
108
+ cancelAnimation(phase);
109
+ cancelAnimation(pulse);
110
+ pulse.value = PROGRESS_PULSE.to;
111
+ };
112
+ }, [isIndeterminate, isReducedMotion, phase, pulse]);
113
+
114
+ const fillStyle = useAnimatedStyle(() => {
115
+ const track = trackSize.value;
116
+ const isMeasured = track > 0;
117
+
118
+ // The same keys every frame, so Reanimated is never asked to swap a style's
119
+ // shape when the bar flips between modes.
120
+ if (isIndeterminate && !isReducedMotion) {
121
+ const segment = indeterminateSegment({
122
+ phase: phase.value,
123
+ segment: PROGRESS_INDETERMINATE_SEGMENT,
124
+ trackSize: track,
125
+ });
126
+ return {
127
+ opacity: isMeasured ? 1 : 0,
128
+ transform: [{ translateX: segment.translate }],
129
+ width: segment.width,
130
+ };
131
+ }
132
+
133
+ if (isIndeterminate) {
134
+ return { opacity: isMeasured ? pulse.value : 0, transform: [{ translateX: 0 }], width: track };
135
+ }
136
+
137
+ return {
138
+ opacity: isMeasured ? 1 : 0,
139
+ transform: [{ translateX: fillTranslate({ ratio: progress.value, trackSize: track }) }],
140
+ width: track,
141
+ };
142
+ });
143
+
144
+ return (
145
+ <Animated.View
146
+ className={progressVariants({ color, isIndeterminate, size }).fill({ className })}
147
+ style={fillStyle}
148
+ {...props}
149
+ />
150
+ );
151
+ }
152
+ ProgressFill.displayName = "DelacourUI.Progress.Fill";
@@ -0,0 +1,19 @@
1
+ import type { ReactElement } from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+ import { useProgressPart } from "./progress.context";
4
+ import { progressVariants } from "./progress.variants";
5
+
6
+ export type ProgressHeaderProps = ViewProps;
7
+
8
+ /**
9
+ * The row above the track: a label at the start, a readout at the end.
10
+ *
11
+ * A part rather than a `View` the caller writes because every labelled bar
12
+ * wants exactly this row, and a hand-written one drifts — a missing `gap` lets a
13
+ * long label run into the percentage.
14
+ */
15
+ export function ProgressHeader({ className, ...props }: ProgressHeaderProps): ReactElement {
16
+ const { color, size, isIndeterminate } = useProgressPart("Progress.Header");
17
+ return <View className={progressVariants({ color, isIndeterminate, size }).header({ className })} {...props} />;
18
+ }
19
+ ProgressHeader.displayName = "DelacourUI.Progress.Header";
@@ -0,0 +1,27 @@
1
+ import type { ReactElement } from "react";
2
+ import { Text, type TextPresetProps } from "../text";
3
+ import { useProgressPart } from "./progress.context";
4
+ import { PROGRESS_OUTPUT_TEXT_SIZE, progressVariants } from "./progress.variants";
5
+
6
+ export type ProgressLabelProps = TextPresetProps;
7
+
8
+ /**
9
+ * What the bar is measuring — "Uploading", "Storage".
10
+ *
11
+ * Renders `Text.Label` and names a size step, never a scale of its own, so the
12
+ * weight and colour stay in the preset. It is left visible to assistive
13
+ * technology: the root is one accessible element, and a label inside it is what
14
+ * VoiceOver and TalkBack read as that element's name.
15
+ */
16
+ export function ProgressLabel({ className, size, ...props }: ProgressLabelProps): ReactElement {
17
+ const { color, size: progressSize, isIndeterminate } = useProgressPart("Progress.Label");
18
+ return (
19
+ <Text.Label
20
+ className={progressVariants({ color, isIndeterminate, size: progressSize }).label({ className })}
21
+ numberOfLines={1}
22
+ size={size ?? PROGRESS_OUTPUT_TEXT_SIZE[progressSize]}
23
+ {...props}
24
+ />
25
+ );
26
+ }
27
+ ProgressLabel.displayName = "DelacourUI.Progress.Label";
@@ -0,0 +1,47 @@
1
+ import type { ReactElement } from "react";
2
+ import { Text, type TextPresetProps } from "../text";
3
+ import { useProgressPart } from "./progress.context";
4
+ import type { ProgressRenderChildren } from "./progress.types";
5
+ import { PROGRESS_OUTPUT_TEXT_SIZE, progressVariants } from "./progress.variants";
6
+
7
+ export type ProgressOutputProps = Omit<TextPresetProps, "children"> & {
8
+ /** Custom content, or a function called with the bar's settled state. */
9
+ children?: ProgressRenderChildren;
10
+ };
11
+
12
+ /**
13
+ * The current value, formatted — `72%` by default.
14
+ *
15
+ * A function child is handed the bar's state, which is how a count reads
16
+ * `18 of 24` rather than a percentage.
17
+ *
18
+ * **Hidden from assistive technology on purpose.** The root already publishes
19
+ * the value as `accessibilityValue`, so a readout left visible inside it would be
20
+ * read twice — once as part of the element's name, once as its value.
21
+ *
22
+ * **An indeterminate bar has no value**, so the default readout renders nothing.
23
+ * A function child still runs, which is where a "Waiting…" belongs.
24
+ */
25
+ export function ProgressOutput({ children, className, size, ...props }: ProgressOutputProps): ReactElement | null {
26
+ const { color, size: progressSize, isIndeterminate, renderProps } = useProgressPart("Progress.Output");
27
+
28
+ const content =
29
+ typeof children === "function"
30
+ ? children(renderProps)
31
+ : (children ?? (isIndeterminate ? null : renderProps.formatted));
32
+
33
+ if (content === null || content === undefined) return null;
34
+
35
+ return (
36
+ <Text.Label
37
+ accessibilityElementsHidden
38
+ className={progressVariants({ color, isIndeterminate, size: progressSize }).output({ className })}
39
+ importantForAccessibility="no-hide-descendants"
40
+ size={size ?? PROGRESS_OUTPUT_TEXT_SIZE[progressSize]}
41
+ {...props}
42
+ >
43
+ {content}
44
+ </Text.Label>
45
+ );
46
+ }
47
+ ProgressOutput.displayName = "DelacourUI.Progress.Output";
@@ -0,0 +1,38 @@
1
+ import { type ReactElement, type ReactNode, useCallback } from "react";
2
+ import { type LayoutChangeEvent, View, type ViewProps } from "react-native";
3
+ import { useProgressPart } from "./progress.context";
4
+ import { progressVariants } from "./progress.variants";
5
+
6
+ export type ProgressTrackProps = Omit<ViewProps, "children"> & {
7
+ /** The fill. */
8
+ children?: ReactNode;
9
+ };
10
+
11
+ /**
12
+ * The clipped, rounded groove the fill slides along.
13
+ *
14
+ * It measures its own width into the shared value the fill reads, because the
15
+ * fill is positioned by a transform in points and a transform cannot name a
16
+ * percentage. The clip is what turns a full-length bar parked off to the left
17
+ * into a bar that appears to grow — see `progressVariants`.
18
+ */
19
+ export function ProgressTrack({ className, onLayout, ...props }: ProgressTrackProps): ReactElement {
20
+ const { color, size, isIndeterminate, trackSize } = useProgressPart("Progress.Track");
21
+
22
+ const handleLayout = useCallback(
23
+ (event: LayoutChangeEvent) => {
24
+ trackSize.value = event.nativeEvent.layout.width;
25
+ onLayout?.(event);
26
+ },
27
+ [onLayout, trackSize]
28
+ );
29
+
30
+ return (
31
+ <View
32
+ className={progressVariants({ color, isIndeterminate, size }).track({ className })}
33
+ onLayout={handleLayout}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+ ProgressTrack.displayName = "DelacourUI.Progress.Track";
@@ -0,0 +1,79 @@
1
+ import { createContext, type ReactElement, type ReactNode, use } from "react";
2
+ import type { SharedValue } from "react-native-reanimated";
3
+ import type { ProgressRenderProps } from "./progress.types";
4
+ import type { ProgressColor, ProgressSize } from "./progress.variants";
5
+
6
+ /**
7
+ * What a progress bar's parts read.
8
+ *
9
+ * **The track and the fill read only `ratio`, `isIndeterminate`, `color`, `size`
10
+ * and `trackSize`.** That is deliberate: a meter is the same track and the same
11
+ * fill with a different root deciding the ratio and the colour, so a root that
12
+ * publishes this shape can reuse `Progress.Track` and `Progress.Fill` as they
13
+ * stand. Nothing the parts draw reaches back to how the ratio was arrived at.
14
+ */
15
+ export type ProgressContextValue = {
16
+ /** Where the value sits in the range, clamped to 0–1, on the JS thread. */
17
+ ratio: number;
18
+ /** Loops a segment along the track instead of showing a value. */
19
+ isIndeterminate: boolean;
20
+ color: ProgressColor;
21
+ size: ProgressSize;
22
+ /** The track's own width, from its `onLayout`. `0` until it has been measured. */
23
+ trackSize: SharedValue<number>;
24
+ /** The settled state `Progress.Output` formats and a render function is handed. */
25
+ renderProps: ProgressRenderProps;
26
+ };
27
+
28
+ const ProgressContext = createContext<ProgressContextValue | null>(null);
29
+
30
+ /**
31
+ * Supplies one progress bar's state to its own parts.
32
+ *
33
+ * Lives in its own module, importing nothing but React and types, so a part can
34
+ * read it without importing `./progress` — that import would close a cycle, and
35
+ * Metro serves a partially initialised module for a cycle.
36
+ */
37
+ export function ProgressProvider({
38
+ value,
39
+ children,
40
+ }: {
41
+ value: ProgressContextValue;
42
+ children: ReactNode;
43
+ }): ReactElement {
44
+ return <ProgressContext value={value}>{children}</ProgressContext>;
45
+ }
46
+ ProgressProvider.displayName = "DelacourUI.Progress.Provider";
47
+
48
+ /** The enclosing progress bar's state, or null outside a `<Progress>`. */
49
+ export function useProgressContext(): ProgressContextValue | null {
50
+ return use(ProgressContext);
51
+ }
52
+
53
+ /**
54
+ * Reads the enclosing progress bar's state.
55
+ *
56
+ * For a custom readout or a custom fill that has to match the bar it sits in.
57
+ * Throws outside one — use {@link useProgressContext} where the bar is optional.
58
+ */
59
+ export function useProgress(): ProgressContextValue {
60
+ const context = useProgressContext();
61
+ if (!context) {
62
+ throw new Error("useProgress must be called inside a <Progress>.");
63
+ }
64
+ return context;
65
+ }
66
+
67
+ /**
68
+ * The enclosing bar's state, for a compound part that cannot work without one.
69
+ *
70
+ * Internal: deliberately not re-exported from `index.ts`. A caller outside the
71
+ * library wants {@link useProgress}, whose error names the hook rather than a part.
72
+ */
73
+ export function useProgressPart(component: string): ProgressContextValue {
74
+ const context = useProgressContext();
75
+ if (!context) {
76
+ throw new Error(`${component} must be rendered inside a <Progress>.`);
77
+ }
78
+ return context;
79
+ }
@@ -0,0 +1,171 @@
1
+ import { type ReactElement, type ReactNode, useMemo } from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+ import { useSharedValue } from "react-native-reanimated";
4
+ import { type ProgressContextValue, ProgressProvider } from "./progress.context";
5
+ import type { ProgressRenderProps } from "./progress.types";
6
+ import {
7
+ formatProgressValue,
8
+ PROGRESS_MAX_VALUE,
9
+ PROGRESS_MIN_VALUE,
10
+ type ProgressColor,
11
+ type ProgressSize,
12
+ progressRatio,
13
+ progressVariants,
14
+ resolveProgressAccessibility,
15
+ resolveProgressAxes,
16
+ } from "./progress.variants";
17
+ import { ProgressFill } from "./progress-fill";
18
+ import { ProgressHeader } from "./progress-header";
19
+ import { ProgressLabel } from "./progress-label";
20
+ import { ProgressOutput } from "./progress-output";
21
+ import { ProgressTrack } from "./progress-track";
22
+
23
+ export type ProgressProps = Omit<ViewProps, "children"> & {
24
+ /** How far along, between `minValue` and `maxValue`. Ignored while indeterminate. */
25
+ value?: number;
26
+ minValue?: number;
27
+ maxValue?: number;
28
+ /** Loops a segment along the track, for work whose length is not known yet. */
29
+ isIndeterminate?: boolean;
30
+ /**
31
+ * Passed to `Intl.NumberFormat` by `Progress.Output` and the spoken value.
32
+ * With none, or a `percent` style, the readout is the share of the range.
33
+ */
34
+ formatOptions?: Intl.NumberFormatOptions;
35
+ /** Replaces the formatted readout, on screen and to assistive technology. */
36
+ valueLabel?: string;
37
+ /** What the filled part of the track means. */
38
+ color?: ProgressColor;
39
+ size?: ProgressSize;
40
+ /** The anatomy. With none, the bar draws a bare track and fill. */
41
+ children?: ReactNode;
42
+ };
43
+
44
+ function ProgressRoot({
45
+ value = PROGRESS_MIN_VALUE,
46
+ minValue = PROGRESS_MIN_VALUE,
47
+ maxValue = PROGRESS_MAX_VALUE,
48
+ isIndeterminate,
49
+ formatOptions,
50
+ valueLabel,
51
+ color,
52
+ size,
53
+ className,
54
+ children,
55
+ ...props
56
+ }: ProgressProps): ReactElement {
57
+ const axes = resolveProgressAxes({ color, isIndeterminate, size });
58
+ const trackSize = useSharedValue(0);
59
+
60
+ const ratio = progressRatio(value, minValue, maxValue);
61
+
62
+ const formatted = useMemo(
63
+ () => valueLabel ?? formatProgressValue({ formatOptions, maxValue, minValue, value }),
64
+ [formatOptions, maxValue, minValue, value, valueLabel]
65
+ );
66
+
67
+ const accessibility = useMemo(
68
+ () =>
69
+ resolveProgressAccessibility({
70
+ formatOptions,
71
+ isIndeterminate: axes.isIndeterminate,
72
+ maxValue,
73
+ minValue,
74
+ value,
75
+ valueLabel,
76
+ }),
77
+ [axes.isIndeterminate, formatOptions, maxValue, minValue, value, valueLabel]
78
+ );
79
+
80
+ const renderProps = useMemo<ProgressRenderProps>(
81
+ () => ({ formatted, isIndeterminate: axes.isIndeterminate, maxValue, minValue, ratio, value }),
82
+ [axes.isIndeterminate, formatted, maxValue, minValue, ratio, value]
83
+ );
84
+
85
+ const context = useMemo<ProgressContextValue>(
86
+ () => ({
87
+ color: axes.color,
88
+ isIndeterminate: axes.isIndeterminate,
89
+ ratio,
90
+ renderProps,
91
+ size: axes.size,
92
+ trackSize,
93
+ }),
94
+ [axes.color, axes.isIndeterminate, axes.size, ratio, renderProps, trackSize]
95
+ );
96
+
97
+ // A bare `<Progress value={40} />` draws the bar. A compound root with no
98
+ // default anatomy draws nothing at all, which is a failure with no error.
99
+ const content = children ?? (
100
+ <ProgressTrack>
101
+ <ProgressFill />
102
+ </ProgressTrack>
103
+ );
104
+
105
+ return (
106
+ <ProgressProvider value={context}>
107
+ <View
108
+ accessibilityRole="progressbar"
109
+ accessibilityState={{ busy: accessibility.busy }}
110
+ accessibilityValue={accessibility.value}
111
+ accessible
112
+ className={progressVariants(axes).root({ className })}
113
+ {...props}
114
+ >
115
+ {content}
116
+ </View>
117
+ </ProgressProvider>
118
+ );
119
+ }
120
+
121
+ /**
122
+ * How far a task has got — or, indeterminate, that it is under way.
123
+ *
124
+ * The anatomy is written out: a `Progress.Track` holding a `Progress.Fill`, with
125
+ * an optional `Progress.Header` above it carrying a `Progress.Label` and a
126
+ * `Progress.Output`. A bare `<Progress value={40} />` draws the track and fill on
127
+ * its own.
128
+ *
129
+ * **The fill animates on the UI thread.** A new value starts one timing and the
130
+ * frames never touch React. `isIndeterminate` loops a segment along the track
131
+ * instead, and with the system's reduce-motion setting on it breathes in place
132
+ * rather than travelling.
133
+ *
134
+ * **It is one accessible element with the `progressbar` role.** The range and
135
+ * the value are published as `accessibilityValue`, spoken as `72%` over 0–100
136
+ * and as `18 of 24` over any other range; a `Progress.Label` inside it is its
137
+ * name. An indeterminate bar reports `busy` and no value.
138
+ *
139
+ * It is not a control, so there is no disabled or invalid state and it takes
140
+ * nothing from an enclosing `Field`. A bar that has failed is `color="destructive"`.
141
+ *
142
+ * @example
143
+ * <Progress value={40} />
144
+ *
145
+ * @example
146
+ * <Progress color="success" value={uploaded} maxValue={total} formatOptions={{ style: "unit", unit: "megabyte" }}>
147
+ * <Progress.Header>
148
+ * <Progress.Label>Uploading</Progress.Label>
149
+ * <Progress.Output />
150
+ * </Progress.Header>
151
+ * <Progress.Track>
152
+ * <Progress.Fill />
153
+ * </Progress.Track>
154
+ * </Progress>
155
+ *
156
+ * @example
157
+ * <Progress accessibilityLabel="Syncing" isIndeterminate />
158
+ */
159
+ export const Progress = Object.assign(ProgressRoot, {
160
+ /** The row above the track: a label at the start, a readout at the end. */
161
+ Header: ProgressHeader,
162
+ /** What the bar is measuring. Read as the bar's accessible name. */
163
+ Label: ProgressLabel,
164
+ /** The value, formatted. Give it a function to word it yourself. */
165
+ Output: ProgressOutput,
166
+ /** The clipped groove the fill slides along. */
167
+ Track: ProgressTrack,
168
+ /** The painted bar — a value, or a looping segment while indeterminate. */
169
+ Fill: ProgressFill,
170
+ displayName: "DelacourUI.Progress",
171
+ });
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from "react";
2
+
3
+ /**
4
+ * What a render function inside a progress bar is handed.
5
+ *
6
+ * Shared by the root's context and `Progress.Output`, which is what puts it here
7
+ * rather than in either one's own file — two consumers is the bar a
8
+ * `{name}.types.ts` entry has to clear. See AGENTS.md.
9
+ */
10
+ export type ProgressRenderProps = {
11
+ /** The value as given, unclamped — the readout is the caller's to word. */
12
+ value: number;
13
+ minValue: number;
14
+ maxValue: number;
15
+ /** Where the value sits in the range, clamped to 0–1. */
16
+ ratio: number;
17
+ /** The readout's default text: `valueLabel`, or the formatted value. */
18
+ formatted: string;
19
+ isIndeterminate: boolean;
20
+ };
21
+
22
+ /** A part whose children may be written out or computed from the bar's state. */
23
+ export type ProgressRenderChildren = ReactNode | ((props: ProgressRenderProps) => ReactNode);