@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,219 @@
1
+ import { type ReactElement, useCallback, useEffect, useMemo, useState } from "react";
2
+ import { type AccessibilityActionEvent, type LayoutChangeEvent, View, type ViewProps } from "react-native";
3
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
4
+ import { useSharedValue } from "react-native-reanimated";
5
+ import { scheduleOnRN } from "react-native-worklets";
6
+ import { useThemeColor } from "../../hooks/use-theme-color";
7
+ import { playHaptic } from "../pressable";
8
+ import { useRatingPart } from "./rating.context";
9
+ import {
10
+ describeRating,
11
+ ratingFromOffset,
12
+ ratingVariants,
13
+ resolveRatingPaint,
14
+ shouldClearRating,
15
+ starFillOf,
16
+ stepRating,
17
+ } from "./rating.variants";
18
+ import { RatingStar } from "./rating-star";
19
+
20
+ export type RatingStarsProps = Omit<ViewProps, "children" | "style"> & {
21
+ className?: string;
22
+ };
23
+
24
+ /**
25
+ * The row of stars, the surface the gesture is claimed on, and the whole
26
+ * accessibility surface.
27
+ *
28
+ * **It is not a `Pressable`, and neither is a star.** The reasons are
29
+ * `Slider.Track`'s: `Pressable`'s tap fires `onPress` on every touch-to-set, and a
30
+ * `Pressable` per star would nest five taps inside the row's pan and leave them
31
+ * to negotiate for one drag. One `Gesture.Pan()` on the row reads the star under
32
+ * the finger, on touch-down and throughout the drag. What is inherited is the
33
+ * vocabulary — `playHaptic` from `pressable.tsx`, the one haptic switch.
34
+ *
35
+ * **The value is written in `onBegin`**, because a pan activates on the first
36
+ * movement and a stationary tap would otherwise never set anything.
37
+ * `minDistance(0)` wins the touch from an enclosing scroll view, and
38
+ * `shouldCancelWhenOutside(false)` keeps a drag past the last star tracking it.
39
+ * `onFinalize` is where a clear is decided and the gesture reported finished,
40
+ * because it is the one callback that fires on every path.
41
+ *
42
+ * **The stars render from React state; the gesture reads a shared value.** A
43
+ * rating crosses at most a handful of stops in a drag, so a commit per crossing
44
+ * is a handful of commits and no mirror on the UI thread is worth its code. The
45
+ * shared value exists so the worklet can tell a crossing from a repeat without
46
+ * waiting on a render, and it is re-synced from React whenever the gesture ends —
47
+ * which is what snaps a controlled rating back when its parent rejects a value.
48
+ *
49
+ * **To assistive technology the row is one `adjustable` control.** Its value is
50
+ * spoken as "3.5 out of 5" and a swipe up or down steps it. A read-only rating
51
+ * is an `image` with the same value: something to read, not something to set.
52
+ */
53
+ export function RatingStars({ className, onLayout, ...props }: RatingStarsProps): ReactElement {
54
+ const {
55
+ value,
56
+ count,
57
+ step,
58
+ color,
59
+ size,
60
+ isDisabled,
61
+ isInvalid,
62
+ isReadOnly,
63
+ allowClear,
64
+ haptic,
65
+ setValue,
66
+ commitEnd,
67
+ } = useRatingPart("Rating.Stars");
68
+ const slots = ratingVariants({ isDisabled, size });
69
+ const paint = resolveRatingPaint({ color, isInvalid });
70
+ const fillColor = useThemeColor(paint.fill);
71
+ const emptyColor = useThemeColor(paint.empty);
72
+ const isInteractive = !isDisabled && !isReadOnly;
73
+
74
+ const width = useSharedValue(0);
75
+ const current = useSharedValue(value);
76
+ const startValue = useSharedValue(value);
77
+ const startX = useSharedValue(0);
78
+ const travel = useSharedValue(0);
79
+
80
+ // Bumped when a gesture ends, purely to re-run the sync below. A controlled
81
+ // parent that rejects a value leaves `value` unchanged, so without the token
82
+ // the shared value would keep the rejected one and the next tap would compare
83
+ // against a number nobody holds.
84
+ const [settledGestures, setSettledGestures] = useState(0);
85
+ const settle = useCallback(() => setSettledGestures((settledCount) => settledCount + 1), []);
86
+
87
+ // biome-ignore lint/correctness/useExhaustiveDependencies: the token is the re-run trigger, see above
88
+ useEffect(() => {
89
+ current.value = value;
90
+ }, [current, value, settledGestures]);
91
+
92
+ const handleLayout = useCallback(
93
+ (event: LayoutChangeEvent) => {
94
+ width.value = event.nativeEvent.layout.width;
95
+ onLayout?.(event);
96
+ },
97
+ [onLayout, width]
98
+ );
99
+
100
+ const gesture = useMemo(() => {
101
+ // Beside its callers rather than at module scope, so it is captured by
102
+ // ordinary closure — see Slider's AGENTS.md on module-scope worklets.
103
+ const applyTouch = (x: number, isGrab: boolean) => {
104
+ "worklet";
105
+ const next = ratingFromOffset({ count, position: x, step, width: width.value });
106
+ if (next <= 0) return;
107
+
108
+ const changed = next !== current.value;
109
+ if (changed) {
110
+ current.value = next;
111
+ scheduleOnRN(setValue, next);
112
+ }
113
+ if (haptic !== false && (isGrab || changed)) playHaptic(haptic);
114
+ };
115
+
116
+ return Gesture.Pan()
117
+ .enabled(isInteractive)
118
+ .minDistance(0)
119
+ .shouldCancelWhenOutside(false)
120
+ .onBegin((event) => {
121
+ "worklet";
122
+ startValue.value = current.value;
123
+ startX.value = event.x;
124
+ travel.value = 0;
125
+ applyTouch(event.x, true);
126
+ })
127
+ .onUpdate((event) => {
128
+ "worklet";
129
+ const moved = Math.abs(event.x - startX.value);
130
+ if (moved > travel.value) travel.value = moved;
131
+ applyTouch(event.x, false);
132
+ })
133
+ .onFinalize(() => {
134
+ "worklet";
135
+ if (
136
+ shouldClearRating({
137
+ allowClear,
138
+ startValue: startValue.value,
139
+ touchedValue: current.value,
140
+ travel: travel.value,
141
+ })
142
+ ) {
143
+ current.value = 0;
144
+ scheduleOnRN(setValue, 0);
145
+ if (haptic !== false) playHaptic(haptic);
146
+ }
147
+ scheduleOnRN(commitEnd, current.value);
148
+ scheduleOnRN(settle);
149
+ });
150
+ }, [
151
+ allowClear,
152
+ commitEnd,
153
+ count,
154
+ current,
155
+ haptic,
156
+ isInteractive,
157
+ setValue,
158
+ settle,
159
+ startValue,
160
+ startX,
161
+ step,
162
+ travel,
163
+ width,
164
+ ]);
165
+
166
+ const handleAccessibilityAction = useCallback(
167
+ (event: AccessibilityActionEvent) => {
168
+ if (!isInteractive) return;
169
+ const direction = event.nativeEvent.actionName === "increment" ? 1 : -1;
170
+ const next = stepRating(value, direction, step, count);
171
+ if (next === value) return;
172
+ setValue(next);
173
+ commitEnd(next);
174
+ },
175
+ [commitEnd, count, isInteractive, setValue, step, value]
176
+ );
177
+
178
+ const glyphClassName = slots.glyph();
179
+ const clipClassName = slots.clip();
180
+ const cellClassName = slots.cell();
181
+ const stars = Array.from({ length: count }, (_, index) => index);
182
+
183
+ return (
184
+ <GestureDetector gesture={gesture}>
185
+ <View
186
+ accessibilityActions={isReadOnly ? undefined : ACCESSIBILITY_ACTIONS}
187
+ accessibilityLabel="Rating"
188
+ accessibilityRole={isReadOnly ? "image" : "adjustable"}
189
+ accessibilityState={{ disabled: isDisabled }}
190
+ accessibilityValue={{ max: count, min: 0, now: value, text: describeRating(value, count) }}
191
+ accessible
192
+ className={slots.stars({ className })}
193
+ onAccessibilityAction={handleAccessibilityAction}
194
+ onLayout={handleLayout}
195
+ {...props}
196
+ >
197
+ {stars.map((index) => (
198
+ <View className={cellClassName} key={index}>
199
+ <RatingStar
200
+ clipClassName={clipClassName}
201
+ emptyColor={emptyColor}
202
+ fill={starFillOf(index, value)}
203
+ fillColor={fillColor}
204
+ glyphClassName={glyphClassName}
205
+ />
206
+ </View>
207
+ ))}
208
+ </View>
209
+ </GestureDetector>
210
+ );
211
+ }
212
+ RatingStars.displayName = "DelacourUI.Rating.Stars";
213
+
214
+ /**
215
+ * The two actions an assistive swipe on an `adjustable` maps to.
216
+ *
217
+ * Module scope on purpose: a fresh array each render is a new prop every commit.
218
+ */
219
+ const ACCESSIBILITY_ACTIONS = [{ name: "increment" }, { name: "decrement" }] as const;
@@ -0,0 +1,79 @@
1
+ import { createContext, type ReactElement, type ReactNode, use } from "react";
2
+ import type { HapticFeedback } from "../pressable";
3
+ import type { RatingColor, RatingSize } from "./rating.variants";
4
+
5
+ /** What a render function inside a rating is handed. */
6
+ export type RatingRenderProps = {
7
+ /** The value, clamped to the count but not snapped — a read-only 3.7 stays 3.7. */
8
+ value: number;
9
+ /** How many stars the row draws. */
10
+ count: number;
11
+ /** The increment a touch snaps to. */
12
+ step: number;
13
+ isDisabled: boolean;
14
+ isInvalid: boolean;
15
+ isReadOnly: boolean;
16
+ };
17
+
18
+ export type RatingContextValue = RatingRenderProps & {
19
+ color: RatingColor;
20
+ size: RatingSize;
21
+ /** A tap on the value already held clears it back to zero. */
22
+ allowClear: boolean;
23
+ /** Played on grab, on every star crossed and on a clear. `false` silences it. */
24
+ haptic: false | HapticFeedback;
25
+ /**
26
+ * Writes a new value from the **JS thread**. Called from the gesture's mirror,
27
+ * from an assistive action and from a clear — never in render.
28
+ */
29
+ setValue: (next: number) => void;
30
+ /** Reports the value a gesture or an assistive action settled on, once. */
31
+ commitEnd: (next: number) => void;
32
+ /** The settled state a render function is handed. */
33
+ renderProps: RatingRenderProps;
34
+ };
35
+
36
+ const RatingContext = createContext<RatingContextValue | null>(null);
37
+
38
+ /**
39
+ * Supplies one rating's settled state to its own parts.
40
+ *
41
+ * Lives in its own module, importing nothing but React and types, so a part can
42
+ * read it without importing `./rating` and closing a cycle (AGENTS.md rule 3).
43
+ */
44
+ export function RatingProvider({ value, children }: { value: RatingContextValue; children: ReactNode }): ReactElement {
45
+ return <RatingContext value={value}>{children}</RatingContext>;
46
+ }
47
+ RatingProvider.displayName = "DelacourUI.Rating.Provider";
48
+
49
+ /** The enclosing rating's state, or null outside a `<Rating>`. */
50
+ export function useRatingContext(): RatingContextValue | null {
51
+ return use(RatingContext);
52
+ }
53
+
54
+ /**
55
+ * Reads the enclosing rating's settled state.
56
+ *
57
+ * For a custom readout that has to match the rating it sits beside. Throws
58
+ * outside one — use {@link useRatingContext} where the rating is optional.
59
+ */
60
+ export function useRating(): RatingContextValue {
61
+ const context = useRatingContext();
62
+ if (!context) {
63
+ throw new Error("useRating must be called inside a <Rating>.");
64
+ }
65
+ return context;
66
+ }
67
+
68
+ /**
69
+ * The enclosing rating's state, for a compound part that cannot work without one.
70
+ *
71
+ * Internal: deliberately not re-exported from `index.ts`.
72
+ */
73
+ export function useRatingPart(component: string): RatingContextValue {
74
+ const context = useRatingContext();
75
+ if (!context) {
76
+ throw new Error(`${component} must be rendered inside a <Rating>.`);
77
+ }
78
+ return context;
79
+ }
@@ -0,0 +1,163 @@
1
+ import { type ReactElement, type ReactNode, useCallback, useMemo } from "react";
2
+ import { View, type ViewProps } from "react-native";
3
+ import { useControllableState } from "../../hooks/use-controllable-state";
4
+ import { useFieldContext } from "../field/field.context";
5
+ import type { HapticFeedback } from "../pressable";
6
+ import { type RatingContextValue, RatingProvider, type RatingRenderProps } from "./rating.context";
7
+ import {
8
+ clampRating,
9
+ normalizeRatingCount,
10
+ normalizeRatingStep,
11
+ type RatingColor,
12
+ type RatingSize,
13
+ ratingVariants,
14
+ resolveRatingAxes,
15
+ } from "./rating.variants";
16
+ import { RatingOutput } from "./rating-output";
17
+ import { RatingStars } from "./rating-stars";
18
+
19
+ export type RatingProps = Omit<ViewProps, "children"> & {
20
+ /** Controlled value. Any number is drawn; only `step` limits what a touch can set. */
21
+ value?: number;
22
+ /** Starting value while uncontrolled. */
23
+ defaultValue?: number;
24
+ /** How many stars. A fraction rounds down; anything that is not a count falls back to 5. */
25
+ maxValue?: number;
26
+ /** The increment a touch snaps to — `1` for whole stars, `0.5` for halves. Must divide one star. */
27
+ step?: number;
28
+ /** What a filled star means. */
29
+ color?: RatingColor;
30
+ size?: RatingSize;
31
+ /** Blocks the gesture and fades the control. Inherited from an enclosing `Field`. */
32
+ isDisabled?: boolean;
33
+ /** Paints the stars destructive. Inherited from an enclosing `Field`. */
34
+ isInvalid?: boolean;
35
+ /** Shows the score without taking a touch, and without fading. */
36
+ isReadOnly?: boolean;
37
+ /** A tap on the value already held clears it back to zero. */
38
+ allowClear?: boolean;
39
+ /** Played on grab, on every star crossed and on a clear. `false` silences it. */
40
+ haptic?: false | HapticFeedback;
41
+ /** Fires on every change during a drag. */
42
+ onChange?: (value: number) => void;
43
+ /** Fires once, when the gesture ends. Where a network write belongs. */
44
+ onChangeEnd?: (value: number) => void;
45
+ children?: ReactNode;
46
+ };
47
+
48
+ function RatingRoot({
49
+ value,
50
+ defaultValue = 0,
51
+ maxValue,
52
+ step,
53
+ color,
54
+ size,
55
+ isDisabled,
56
+ isInvalid,
57
+ isReadOnly,
58
+ allowClear = false,
59
+ haptic = "selection",
60
+ onChange,
61
+ onChangeEnd,
62
+ className,
63
+ children,
64
+ ...props
65
+ }: RatingProps): ReactElement {
66
+ const field = useFieldContext();
67
+ const axes = resolveRatingAxes({ field, own: { color, isDisabled, isInvalid, isReadOnly, size } });
68
+ const count = normalizeRatingCount(maxValue);
69
+ const settledStep = normalizeRatingStep(step);
70
+
71
+ const [current, setCurrent] = useControllableState<number>({ defaultValue, onChange, value });
72
+ const settled = clampRating(current, count);
73
+
74
+ const commitEnd = useCallback((next: number) => onChangeEnd?.(next), [onChangeEnd]);
75
+
76
+ const renderProps = useMemo<RatingRenderProps>(
77
+ () => ({
78
+ count,
79
+ isDisabled: axes.isDisabled,
80
+ isInvalid: axes.isInvalid,
81
+ isReadOnly: axes.isReadOnly,
82
+ step: settledStep,
83
+ value: settled,
84
+ }),
85
+ [axes.isDisabled, axes.isInvalid, axes.isReadOnly, count, settled, settledStep]
86
+ );
87
+
88
+ const context = useMemo<RatingContextValue>(
89
+ () => ({
90
+ ...renderProps,
91
+ allowClear,
92
+ color: axes.color,
93
+ commitEnd,
94
+ haptic,
95
+ renderProps,
96
+ setValue: setCurrent,
97
+ size: axes.size,
98
+ }),
99
+ [allowClear, axes.color, axes.size, commitEnd, haptic, renderProps, setCurrent]
100
+ );
101
+
102
+ return (
103
+ <RatingProvider value={context}>
104
+ <View className={ratingVariants({ isDisabled: axes.isDisabled, size: axes.size }).root({ className })} {...props}>
105
+ {children}
106
+ </View>
107
+ </RatingProvider>
108
+ );
109
+ }
110
+
111
+ /**
112
+ * A row of stars that reads or sets a score.
113
+ *
114
+ * The anatomy is written out: a `Rating.Stars` row, with an optional
115
+ * `Rating.Output` beside or below it. The root is a plain column, so a readout
116
+ * on the same line is a `className="flex-row items-center"` away.
117
+ *
118
+ * **The whole row is the target.** Touching down takes the star under the
119
+ * finger, and dragging along the row follows it — one rule, not a tap mode and a
120
+ * drag mode. `step={0.5}` splits every star at its centre. `allowClear` lets a
121
+ * tap on the value already held withdraw the rating.
122
+ *
123
+ * **Any value is drawn; only a touch is snapped.** A read-only average of 3.7
124
+ * fills three stars and seven tenths of the fourth, while a finger on the same
125
+ * control can land only on the stops `step` allows. A non-finite value draws as
126
+ * zero rather than breaking the row.
127
+ *
128
+ * **State works either way from one hook**: pass `value` to control it, or
129
+ * `defaultValue` and let it hold its own. `onChange` fires as a drag crosses
130
+ * each star; `onChangeEnd` fires once when the gesture ends.
131
+ *
132
+ * `isInvalid` and `isDisabled` cascade in from an enclosing `Field`, and an
133
+ * explicit prop still wins. `isReadOnly` is the rating's own: it takes no touch
134
+ * and does not fade, because a score on a review card is content, not a control
135
+ * that happens to be off.
136
+ *
137
+ * To assistive technology the row is one `adjustable` control whose swipe up and
138
+ * down step the value — see `Rating.Stars`.
139
+ *
140
+ * @example
141
+ * <Rating defaultValue={3}>
142
+ * <Rating.Stars accessibilityLabel="Your rating" />
143
+ * </Rating>
144
+ *
145
+ * @example
146
+ * <Rating allowClear onChange={setScore} step={0.5} value={score}>
147
+ * <Rating.Stars accessibilityLabel="Rate this recipe" />
148
+ * <Rating.Output />
149
+ * </Rating>
150
+ *
151
+ * @example
152
+ * <Rating className="flex-row items-center gap-2" isReadOnly size="sm" value={4.3}>
153
+ * <Rating.Stars accessibilityLabel="Average rating" />
154
+ * <Rating.Output>{({ value }) => `${value.toFixed(1)} · 128 reviews`}</Rating.Output>
155
+ * </Rating>
156
+ */
157
+ export const Rating = Object.assign(RatingRoot, {
158
+ /** The row of stars — the drag surface, and the whole accessibility surface. */
159
+ Stars: RatingStars,
160
+ /** The value, formatted. Give it a function to label it yourself. */
161
+ Output: RatingOutput,
162
+ displayName: "DelacourUI.Rating",
163
+ });