@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,106 @@
1
+ import { type ReactElement, type ReactNode, useMemo } from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+ import Animated, { ZoomIn } from "react-native-reanimated";
4
+ import { IconCheckmark1Small, IconCrossSmall } from "../../icons/central";
5
+ import { Icon, IconDefaultsProvider } from "../icon";
6
+ import { Spinner } from "../spinner";
7
+ import { Text } from "../text";
8
+ import { type StepsItemContextValue, useStepsItemPart } from "./steps.context";
9
+ import { resolveIndicatorForeground, resolveIndicatorGlyph, stepsVariants } from "./steps.variants";
10
+
11
+ export type StepsIndicatorChildrenProps = Pick<
12
+ StepsItemContextValue,
13
+ "step" | "status" | "isCurrent" | "isInvalid" | "isLoading" | "size" | "variant"
14
+ >;
15
+
16
+ export type StepsIndicatorProps = Omit<ViewProps, "children"> & {
17
+ className?: string;
18
+ /**
19
+ * Replaces what the circle draws. The circle, its size and its colours are
20
+ * still the step's, and an `Icon` inside inherits the glyph size and colour.
21
+ */
22
+ children?: ReactNode | ((props: StepsIndicatorChildrenProps) => ReactNode);
23
+ };
24
+
25
+ /**
26
+ * The glyph's entrance. Short and un-sprung: a check lands, it does not bounce.
27
+ * Reduce motion is Reanimated's default `System`, which snaps it in — the state
28
+ * is carried by the glyph's presence, not by its motion.
29
+ */
30
+ const GLYPH_ENTERING = ZoomIn.duration(180);
31
+
32
+ /**
33
+ * The circle: a spinner while loading, a cross while invalid, a check once
34
+ * completed, and otherwise the step's one-based number.
35
+ *
36
+ * Composed in automatically, so write it out only to restyle it or to draw
37
+ * something of your own inside the circle — an icon per step, say. Wherever it
38
+ * is written among a step's children, the step lifts it into the track between
39
+ * the connector halves; it never lands in the text column.
40
+ *
41
+ * **The circle is hidden from assistive technology.** The trigger merges its
42
+ * children into one element, and the numeral would otherwise lead the name —
43
+ * "2, Shipping" — restating the position the accessibility value already reads.
44
+ *
45
+ * **The number does not scale with the OS text size.** The circle is a fixed
46
+ * edge, so a scaled numeral would spill out of it, and the position it shows is
47
+ * already announced in the step's accessibility value — scaling would buy the
48
+ * reader nothing the screen reader has not said.
49
+ *
50
+ * The check and cross are Central Icons and the spinner is `Spinner`; all three
51
+ * take their size and colour from one `IconDefaultsProvider`, whose token
52
+ * {@link resolveIndicatorForeground} keeps equal to the number's class.
53
+ */
54
+ export function StepsIndicator({ className, children, ...props }: StepsIndicatorProps): ReactElement {
55
+ const item = useStepsItemPart("Steps.Indicator");
56
+ const { step, status, isCurrent, isInvalid, isLoading, isDisabled, size, variant } = item;
57
+
58
+ const slots = stepsVariants({ isDisabled, isInvalid, size, status, variant });
59
+ const glyphClass = slots.glyph();
60
+ const labelClass = slots.indicatorLabel();
61
+ const color = resolveIndicatorForeground({ isInvalid, status, variant });
62
+ const iconDefaults = useMemo(() => ({ className: glyphClass ?? "", color }), [glyphClass, color]);
63
+
64
+ const renderGlyph = (): ReactNode => {
65
+ if (typeof children === "function") {
66
+ return children({ isCurrent, isInvalid, isLoading, size, status, step, variant });
67
+ }
68
+ if (children) return children;
69
+
70
+ const glyph = resolveIndicatorGlyph({ isInvalid, isLoading, status, step });
71
+ switch (glyph.kind) {
72
+ case "spinner":
73
+ return <Spinner />;
74
+ case "alert":
75
+ return (
76
+ <Animated.View entering={GLYPH_ENTERING} key="alert">
77
+ <Icon icon={IconCrossSmall} />
78
+ </Animated.View>
79
+ );
80
+ case "check":
81
+ return (
82
+ <Animated.View entering={GLYPH_ENTERING} key="check">
83
+ <Icon icon={IconCheckmark1Small} />
84
+ </Animated.View>
85
+ );
86
+ case "number":
87
+ return (
88
+ <Text allowFontScaling={false} className={labelClass}>
89
+ {glyph.label}
90
+ </Text>
91
+ );
92
+ }
93
+ };
94
+
95
+ return (
96
+ <View
97
+ accessibilityElementsHidden
98
+ className={slots.indicator({ className })}
99
+ importantForAccessibility="no-hide-descendants"
100
+ {...props}
101
+ >
102
+ <IconDefaultsProvider value={iconDefaults}>{renderGlyph()}</IconDefaultsProvider>
103
+ </View>
104
+ );
105
+ }
106
+ StepsIndicator.displayName = "DelacourUI.Steps.Indicator";
@@ -0,0 +1,225 @@
1
+ import { Children, isValidElement, type ReactElement, type ReactNode, useCallback, useMemo } from "react";
2
+ import { View } from "react-native";
3
+ import { Pressable, type PressableProps } from "../pressable";
4
+ import { type StepsItemContextValue, StepsItemProvider, useStepsPart } from "./steps.context";
5
+ import {
6
+ resolveStepAccessibilityValue,
7
+ resolveStepInteraction,
8
+ resolveStepStatus,
9
+ stepsVariants,
10
+ } from "./steps.variants";
11
+ import { StepsIndicator } from "./steps-indicator";
12
+ import { StepsPanel } from "./steps-panel";
13
+ import { StepsTitle } from "./steps-title";
14
+ import { StepsRail, StepsTrack } from "./steps-track";
15
+
16
+ export type StepsItemProps = Omit<PressableProps, "asChild" | "busy" | "children" | "disabled" | "ref"> & {
17
+ /** This step's index, zero-based. The indicator draws it one-based. */
18
+ step: number;
19
+ /**
20
+ * Overrides whether the step reads as done. `true` completes it wherever it
21
+ * sits — a finished flow's last step. `false` leaves a passed step looking
22
+ * unfinished — a skipped optional one. Never demotes the current step.
23
+ */
24
+ completed?: boolean;
25
+ /** The step cannot be pressed, and fades. A stepper that names `isDisabled` wins over this. */
26
+ isDisabled?: boolean;
27
+ /** The step has an error: a cross in the indicator and a destructive title. */
28
+ isInvalid?: boolean;
29
+ /** A spinner in the indicator. The step is announced busy and cannot be pressed. */
30
+ isLoading?: boolean;
31
+ children?: ReactNode;
32
+ };
33
+
34
+ /**
35
+ * One step: its indicator, the connector halves either side of it, its title and
36
+ * description, and any `Steps.Panel`.
37
+ *
38
+ * The trigger is the control — the circle, the title and the space between them
39
+ * are one tap target and one accessibility element, whose name is the title and
40
+ * whose value is "Step 2 of 3, completed". It renders a `Pressable` when the
41
+ * stepper takes presses and a plain `View` when it is read-only, so a progress
42
+ * display is never announced as a row of buttons. A panel renders after the
43
+ * trigger, outside both.
44
+ *
45
+ * `className` styles the step's outer box; every other prop — `testID`,
46
+ * `onPress`, `haptic`, the accessibility props — reaches the trigger.
47
+ *
48
+ * Bare text is wrapped in a `Steps.Title`, and a `Steps.Indicator` is composed
49
+ * in when the children hold none — the shortest step that works is
50
+ * `<Steps.Item step={0}>Account</Steps.Item>`.
51
+ */
52
+ export function StepsItem({
53
+ step,
54
+ completed,
55
+ isDisabled,
56
+ isInvalid = false,
57
+ isLoading = false,
58
+ feedback = "fade",
59
+ haptic,
60
+ onLongPress,
61
+ pressedOpacity,
62
+ pressedScale,
63
+ accessibilityState,
64
+ className,
65
+ children,
66
+ onPress,
67
+ ...props
68
+ }: StepsItemProps): ReactElement {
69
+ const root = useStepsPart("Steps.Item");
70
+ const { value, count, orientation, size, variant, select } = root;
71
+
72
+ const status = resolveStepStatus({ completed, step, value });
73
+ const isCurrent = step === value;
74
+ const resolvedIsDisabled = root.isDisabled ?? isDisabled ?? false;
75
+ const isLast = step >= count - 1;
76
+
77
+ if (process.env.NODE_ENV !== "production" && count > 0 && (step < 0 || step >= count)) {
78
+ console.warn(`Steps.Item: step ${step} is outside the ${count} steps the root counted. Steps are zero-based.`);
79
+ }
80
+
81
+ const interaction = resolveStepInteraction({
82
+ isDisabled: resolvedIsDisabled,
83
+ isLinear: root.isLinear,
84
+ isLoading,
85
+ isReadOnly: root.isReadOnly,
86
+ step,
87
+ value,
88
+ });
89
+
90
+ const context = useMemo<StepsItemContextValue>(
91
+ () => ({
92
+ isCurrent,
93
+ isDisabled: resolvedIsDisabled,
94
+ isInvalid,
95
+ isLast,
96
+ isLoading,
97
+ orientation,
98
+ size,
99
+ status,
100
+ step,
101
+ variant,
102
+ }),
103
+ [isCurrent, resolvedIsDisabled, isInvalid, isLast, isLoading, orientation, size, status, step, variant]
104
+ );
105
+
106
+ const handlePress = useCallback(() => {
107
+ select(step);
108
+ onPress?.();
109
+ }, [onPress, select, step]);
110
+
111
+ const { indicator, content, panels } = useMemo(() => splitChildren(children), [children]);
112
+ const hasPanel = panels.length > 0;
113
+ const slots = stepsVariants({ hasPanel, isDisabled: resolvedIsDisabled, isLast, orientation, size });
114
+
115
+ const trigger = (
116
+ <>
117
+ <StepsTrack indicator={indicator} />
118
+ {content.length > 0 ? <View className={slots.content()}>{content}</View> : null}
119
+ </>
120
+ );
121
+
122
+ // A vertical panel sits beside a rail that carries the line on past it; a
123
+ // horizontal one simply follows the trigger.
124
+ const panelRow =
125
+ hasPanel && orientation === "vertical" ? (
126
+ <View className={slots.panelRow()}>
127
+ <StepsRail />
128
+ {panels}
129
+ </View>
130
+ ) : (
131
+ panels
132
+ );
133
+
134
+ const accessibilityValue = {
135
+ text: resolveStepAccessibilityValue({ count, isInvalid, isLoading, status, step }),
136
+ };
137
+ const state = { ...accessibilityState, selected: isCurrent };
138
+
139
+ return (
140
+ <StepsItemProvider value={context}>
141
+ <View className={slots.item({ className })}>
142
+ {interaction === "static" ? (
143
+ <View
144
+ accessibilityState={state}
145
+ accessibilityValue={accessibilityValue}
146
+ accessible
147
+ className={slots.trigger()}
148
+ {...props}
149
+ >
150
+ {trigger}
151
+ </View>
152
+ ) : (
153
+ <Pressable
154
+ accessibilityState={state}
155
+ accessibilityValue={accessibilityValue}
156
+ busy={isLoading}
157
+ className={slots.trigger()}
158
+ disabled={interaction === "blocked" && !isLoading}
159
+ feedback={feedback}
160
+ haptic={haptic}
161
+ onLongPress={onLongPress}
162
+ onPress={handlePress}
163
+ pressedOpacity={pressedOpacity}
164
+ pressedScale={pressedScale}
165
+ {...props}
166
+ >
167
+ {trigger}
168
+ </Pressable>
169
+ )}
170
+ {panelRow}
171
+ </View>
172
+ </StepsItemProvider>
173
+ );
174
+ }
175
+ StepsItem.displayName = "DelacourUI.Steps.Item";
176
+
177
+ /**
178
+ * Lifts a `Steps.Indicator` and any `Steps.Panel` out of a step's children, and
179
+ * wraps bare text in a `Steps.Title`.
180
+ *
181
+ * Both places are structural — the indicator between the connector halves, a
182
+ * panel after the trigger — so each is pulled out wherever it was written rather
183
+ * than rendered in the text column.
184
+ * Consecutive strings and numbers collapse into one title, as `Radio` does, so
185
+ * `Step {n}` is one piece of text rather than two spaced apart.
186
+ *
187
+ * Lives here rather than in the root: it is the item that wraps its own
188
+ * children, and a helper in the root file would close a cycle. See AGENTS.md.
189
+ */
190
+ function splitChildren(children: ReactNode): {
191
+ indicator: ReactNode | null;
192
+ content: ReactNode[];
193
+ panels: ReactNode[];
194
+ } {
195
+ let indicator: ReactNode | null = null;
196
+ const content: ReactNode[] = [];
197
+ const panels: ReactNode[] = [];
198
+ let run: (string | number)[] = [];
199
+
200
+ const flushRun = () => {
201
+ if (run.length === 0) return;
202
+ content.push(<StepsTitle key={`title-${content.length}`}>{run.join("")}</StepsTitle>);
203
+ run = [];
204
+ };
205
+
206
+ for (const child of Children.toArray(children)) {
207
+ if (typeof child === "string" || typeof child === "number") {
208
+ run.push(child);
209
+ continue;
210
+ }
211
+ flushRun();
212
+ if (indicator === null && isValidElement(child) && child.type === StepsIndicator) {
213
+ indicator = child;
214
+ continue;
215
+ }
216
+ if (isValidElement(child) && child.type === StepsPanel) {
217
+ panels.push(child);
218
+ continue;
219
+ }
220
+ content.push(child);
221
+ }
222
+ flushRun();
223
+
224
+ return { content, indicator, panels };
225
+ }
@@ -0,0 +1,41 @@
1
+ import type { ReactElement } from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+ import { useStepsItemPart } from "./steps.context";
4
+ import { stepsVariants } from "./steps.variants";
5
+
6
+ export type StepsPanelProps = ViewProps & { className?: string };
7
+
8
+ /**
9
+ * Content for a step that sits below its title but outside its tap target — a
10
+ * form for the current step, a summary of a finished one.
11
+ *
12
+ * **It exists because the trigger is one accessibility element.** The trigger
13
+ * merges its indicator, title and description into a single stop, so a text
14
+ * field or a button inside it would be unreachable by VoiceOver, and its own
15
+ * tap gesture would sit inside the step's. The panel renders beside the
16
+ * trigger instead: every control in it is its own element, and a press on it
17
+ * never moves the stepper.
18
+ *
19
+ * Wherever it is written among a step's children, the step lifts it out and
20
+ * renders it after the trigger. In a vertical stepper the line carries on down
21
+ * a rail beside it, so the panel reads as part of its step. Show it
22
+ * conditionally — `{value === 1 ? <Steps.Panel>…</Steps.Panel> : null}` — there
23
+ * is no built-in "only while current", because a finished step's summary is as
24
+ * common a panel as the current step's form.
25
+ */
26
+ export function StepsPanel({ className, ...props }: StepsPanelProps): ReactElement {
27
+ const item = useStepsItemPart("Steps.Panel");
28
+
29
+ return (
30
+ <View
31
+ className={stepsVariants({
32
+ hasPanel: true,
33
+ isLast: item.isLast,
34
+ orientation: item.orientation,
35
+ size: item.size,
36
+ }).panel({ className })}
37
+ {...props}
38
+ />
39
+ );
40
+ }
41
+ StepsPanel.displayName = "DelacourUI.Steps.Panel";
@@ -0,0 +1,32 @@
1
+ import type { ReactElement } from "react";
2
+ import { Text, type TextPresetProps } from "../text";
3
+ import { useStepsItemPart } from "./steps.context";
4
+ import { STEPS_TITLE_TEXT_SIZE, stepsVariants } from "./steps.variants";
5
+
6
+ export type StepsTitleProps = TextPresetProps;
7
+
8
+ /**
9
+ * The step's name — and, because the step is one accessibility element, its
10
+ * accessible name too.
11
+ *
12
+ * Renders `Text.Label` at the step's own size step rather than a scale of its
13
+ * own, the rule `Radio.Label` follows. Its colour follows the step: muted ahead
14
+ * of the value, destructive while invalid. Bare text inside a `Steps.Item` is
15
+ * wrapped in one automatically.
16
+ */
17
+ export function StepsTitle({ className, size, ...props }: StepsTitleProps): ReactElement {
18
+ const item = useStepsItemPart("Steps.Title");
19
+
20
+ return (
21
+ <Text.Label
22
+ className={stepsVariants({
23
+ isInvalid: item.isInvalid,
24
+ orientation: item.orientation,
25
+ status: item.status,
26
+ }).title({ className })}
27
+ size={size ?? STEPS_TITLE_TEXT_SIZE[item.size]}
28
+ {...props}
29
+ />
30
+ );
31
+ }
32
+ StepsTitle.displayName = "DelacourUI.Steps.Title";
@@ -0,0 +1,59 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import { View } from "react-native";
3
+ import { useStepsItemPart, useStepsPart } from "./steps.context";
4
+ import { isConnectorComplete, resolveStepConnectors, stepsVariants } from "./steps.variants";
5
+ import { StepsConnector } from "./steps-connector";
6
+ import { StepsIndicator } from "./steps-indicator";
7
+
8
+ /**
9
+ * A step's track: `[leading] [indicator] [trailing]`. Internal.
10
+ *
11
+ * The leading half joins the previous step, so it fills off that step's index
12
+ * rather than this one's — the two halves of one line must agree, and the value
13
+ * is the only thing both can see. See `isConnectorComplete`.
14
+ */
15
+ export function StepsTrack({ indicator }: { indicator: ReactNode | null }): ReactElement {
16
+ const { value, count } = useStepsPart("Steps.Item");
17
+ const { step, orientation, size, isLast } = useStepsItemPart("Steps.Item");
18
+ const connectors = resolveStepConnectors({ count, orientation, step });
19
+
20
+ return (
21
+ <View className={stepsVariants({ isLast, orientation, size }).track()}>
22
+ {connectors.leading === "none" ? null : (
23
+ <StepsConnector
24
+ isComplete={isConnectorComplete(step - 1, value)}
25
+ orientation={orientation}
26
+ slot={connectors.leading}
27
+ />
28
+ )}
29
+ {indicator ?? <StepsIndicator />}
30
+ {connectors.trailing === "none" ? null : (
31
+ <StepsConnector
32
+ isComplete={isConnectorComplete(step, value)}
33
+ orientation={orientation}
34
+ slot={connectors.trailing}
35
+ />
36
+ )}
37
+ </View>
38
+ );
39
+ }
40
+ StepsTrack.displayName = "DelacourUI.Steps.Item.Track";
41
+
42
+ /**
43
+ * The column beside a vertical `Steps.Panel`, as wide as the indicator, that
44
+ * carries the trailing line on past the panel. Internal.
45
+ */
46
+ export function StepsRail(): ReactElement {
47
+ const { value, count } = useStepsPart("Steps.Item");
48
+ const { step, orientation, size, isLast } = useStepsItemPart("Steps.Item");
49
+ const { trailing } = resolveStepConnectors({ count, orientation, step });
50
+
51
+ return (
52
+ <View className={stepsVariants({ hasPanel: true, isLast, orientation, size }).rail()}>
53
+ {trailing === "line" ? (
54
+ <StepsConnector isComplete={isConnectorComplete(step, value)} orientation={orientation} slot="line" />
55
+ ) : null}
56
+ </View>
57
+ );
58
+ }
59
+ StepsRail.displayName = "DelacourUI.Steps.Item.Rail";
@@ -0,0 +1,123 @@
1
+ import { createContext, type ReactElement, type ReactNode, use } from "react";
2
+ import type { StepStatus, StepsOrientation, StepsSize, StepsVariant } from "./steps.variants";
3
+
4
+ export type StepsContextValue = {
5
+ /** The current step, zero-based. */
6
+ value: number;
7
+ /** How many `Steps.Item`s the root found among its direct children. `0` when it could not count them. */
8
+ count: number;
9
+ /** What a step calls on press. Stays quiet when the step is already current. */
10
+ select: (step: number) => void;
11
+ orientation: StepsOrientation;
12
+ size: StepsSize;
13
+ variant: StepsVariant;
14
+ /** Steps render as plain views and take no presses. */
15
+ isReadOnly: boolean;
16
+ /** Steps ahead of the value cannot be pressed. */
17
+ isLinear: boolean;
18
+ /** Raw rather than resolved, so one step can still disable itself — see `RadioGroupContextValue`. */
19
+ isDisabled?: boolean;
20
+ };
21
+
22
+ export type StepsItemContextValue = {
23
+ /** This step's index, zero-based. */
24
+ step: number;
25
+ status: StepStatus;
26
+ /** Whether this step is the value — true even when `completed` paints it done. */
27
+ isCurrent: boolean;
28
+ isInvalid: boolean;
29
+ isLoading: boolean;
30
+ isDisabled: boolean;
31
+ isLast: boolean;
32
+ orientation: StepsOrientation;
33
+ size: StepsSize;
34
+ variant: StepsVariant;
35
+ };
36
+
37
+ const StepsContext = createContext<StepsContextValue | null>(null);
38
+ const StepsItemContext = createContext<StepsItemContextValue | null>(null);
39
+
40
+ /**
41
+ * Supplies the stepper's value and axes to its steps.
42
+ *
43
+ * Lives in its own module, importing nothing but React and types, so a part can
44
+ * read it without importing `./steps` — which would close a cycle and leave the
45
+ * context `undefined` on a cold start. See AGENTS.md rule 3.
46
+ */
47
+ export function StepsProvider({ value, children }: { value: StepsContextValue; children: ReactNode }): ReactElement {
48
+ return <StepsContext value={value}>{children}</StepsContext>;
49
+ }
50
+ StepsProvider.displayName = "DelacourUI.Steps.Provider";
51
+
52
+ /** Supplies one step's settled state to its indicator, title and description. */
53
+ export function StepsItemProvider({
54
+ value,
55
+ children,
56
+ }: {
57
+ value: StepsItemContextValue;
58
+ children: ReactNode;
59
+ }): ReactElement {
60
+ return <StepsItemContext value={value}>{children}</StepsItemContext>;
61
+ }
62
+ StepsItemProvider.displayName = "DelacourUI.Steps.Item.Provider";
63
+
64
+ /** The enclosing stepper's context, or null outside a `<Steps>`. */
65
+ export function useStepsContext(): StepsContextValue | null {
66
+ return use(StepsContext);
67
+ }
68
+
69
+ /**
70
+ * Reads the enclosing stepper's value and axes.
71
+ *
72
+ * For a custom control — a Continue button, a progress caption — that has to
73
+ * follow the stepper it sits beside. Throws outside one.
74
+ */
75
+ export function useSteps(): StepsContextValue {
76
+ const context = useStepsContext();
77
+ if (!context) {
78
+ throw new Error("useSteps must be called inside a <Steps>.");
79
+ }
80
+ return context;
81
+ }
82
+
83
+ /** The enclosing step's settled state, or null outside a `<Steps.Item>`. */
84
+ export function useStepsItemContext(): StepsItemContextValue | null {
85
+ return use(StepsItemContext);
86
+ }
87
+
88
+ /**
89
+ * Reads the enclosing step's settled state.
90
+ *
91
+ * Lets a custom child — an indicator of your own, a status badge — style itself
92
+ * to match. Throws outside a `<Steps.Item>`.
93
+ */
94
+ export function useStepsItem(): StepsItemContextValue {
95
+ const context = useStepsItemContext();
96
+ if (!context) {
97
+ throw new Error("useStepsItem must be called inside a <Steps.Item>.");
98
+ }
99
+ return context;
100
+ }
101
+
102
+ /**
103
+ * The enclosing stepper, for a part that cannot work without one.
104
+ *
105
+ * Internal: not re-exported from `index.ts`. A caller wants {@link useSteps},
106
+ * whose error names the hook rather than a part.
107
+ */
108
+ export function useStepsPart(component: string): StepsContextValue {
109
+ const context = useStepsContext();
110
+ if (!context) {
111
+ throw new Error(`${component} must be rendered inside a <Steps>.`);
112
+ }
113
+ return context;
114
+ }
115
+
116
+ /** The enclosing step, for a part that cannot work without one. Internal. */
117
+ export function useStepsItemPart(component: string): StepsItemContextValue {
118
+ const context = useStepsItemContext();
119
+ if (!context) {
120
+ throw new Error(`${component} must be rendered inside a <Steps.Item>.`);
121
+ }
122
+ return context;
123
+ }