@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
@@ -1,150 +1,81 @@
1
- import { BottomSheetFooter as GorhomBottomSheetFooter } from "@gorhom/bottom-sheet";
2
- import { type ComponentProps, type ReactElement, type ReactNode, useCallback, useEffect } from "react";
3
- import { type LayoutChangeEvent, View, type ViewProps } from "react-native";
4
- import { useReanimatedKeyboardAnimation } from "react-native-keyboard-controller";
5
- import Animated, { type SharedValue, useAnimatedStyle } from "react-native-reanimated";
6
- import { useSafeAreaInsets } from "react-native-safe-area-context";
1
+ import {
2
+ BottomSheet as Headless,
3
+ type BottomSheetFooterProps as HeadlessProps,
4
+ } from "@delacour/react-native-bottom-sheet";
5
+ import type { ReactElement } from "react";
6
+ import { withUniwind } from "uniwind";
7
7
  import { BOTTOM_SHEET_FOOTER_PADDING, bottomSheetVariants } from "./bottom-sheet.variants";
8
8
 
9
- type GorhomFooterProps = ComponentProps<typeof GorhomBottomSheetFooter>;
9
+ type StyledFooterComponent = (props: HeadlessProps & { className?: string }) => ReactElement | null;
10
10
 
11
- export type BottomSheetFooterProps = Omit<ViewProps, "children"> & {
12
- /**
13
- * Pin the footer to the bottom of the sheet, above the keyboard, instead of
14
- * leaving it in the content's flow.
15
- *
16
- * Off by default, matching `Screen.Footer` — a footer holding a submit button
17
- * under a short sheet wants to sit where it was written, and a sheet only
18
- * needs the pinned treatment once its body can scroll under one.
19
- *
20
- * @default false
21
- */
22
- sticky?: boolean;
11
+ // Built once at module scope; the classes land on the engine's inner, measured
12
+ // view, after its own `padding`, so the gutter here wins the horizontal axis.
13
+ const StyledFooter = withUniwind(Headless.Footer) as unknown as StyledFooterComponent;
14
+
15
+ export type BottomSheetFooterProps = HeadlessProps & {
23
16
  className?: string;
24
- children?: ReactNode;
25
- /**
26
- * The sheet's own footer position. Injected by `BottomSheet.Container` when it
27
- * hoists a sticky footer; never written at a call site.
28
- */
29
- animatedFooterPosition?: GorhomFooterProps["animatedFooterPosition"];
30
- /**
31
- * Where this footer publishes its measured height. Injected alongside the
32
- * position, and read by whatever the sheet's body is so it can reserve exactly
33
- * what the footer covers. Never written at a call site.
34
- */
35
- footerHeight?: SharedValue<number>;
36
17
  };
37
18
 
38
19
  /**
39
- * A row of controls at the bottom of the sheet — pinned, or in the flow.
40
- *
41
- * **A sticky footer is not rendered where it is written.** gorhom takes it as a
42
- * `footerComponent` render prop rather than as a child, so
43
- * `BottomSheet.Container` lifts this element out of its children and clones it
44
- * into that slot with the sheet's animated footer position attached. An inline
45
- * footer needs none of that and stays exactly where it was put.
46
- *
47
- * The two branches deliberately look different. An inline footer is in the flow
48
- * and inherits the sheet's surface; a pinned one draws OVER the content, so it
49
- * brings a background and a top hairline of its own — without them the content
50
- * scrolls straight through it and its buttons are legible only where they happen
51
- * to overlap blank space. That is `Screen.Footer`'s rule about its backing, one
52
- * component along.
53
- *
54
- * **A pinned footer is TALLER by the safe-area band; it is not moved up by it.**
55
- * gorhom's own `bottomInset` translates the whole footer up instead, which
56
- * leaves a band the height of the home indicator between the footer and the
57
- * bottom of the sheet — and the content scrolls through it in plain view. So
58
- * `bottomInset` stays 0 and the band becomes the footer's own `paddingBottom`,
59
- * which puts its surface against the bottom of the screen where it belongs.
60
- *
61
- * The keyboard then needs that band back, and **only that band**. Its own
62
- * padding stays, so the controls never end up flush against the keyboard, and
63
- * the footer genuinely gets shorter rather than sliding down — which is what
64
- * lets the body's reserve shrink with it instead of over-reserving by the height
65
- * of a home indicator that is no longer there.
20
+ * A row of controls at the bottom of the sheet — in the flow, or pinned.
66
21
  *
67
- * It publishes its measured height into the sheet. `BottomSheet.Content` reserves
68
- * exactly that plus a gap with a spacer, and `BottomSheet.ScrollView` gives it up
69
- * as its own frame so its scroll indicator stops at this footer's hairline. The
70
- * height is a shared value read by an animated style either way, never
71
- * content-container padding — `Screen` reserves its own chrome the same way and
72
- * for the same reason.
22
+ * **`sticky` is off by default, matching `Screen.Footer`**, and that is the one
23
+ * place this skin overrides the engine's default: a footer holding a submit
24
+ * button under a short sheet wants to sit where it was written, and a sheet
25
+ * only needs the pinned treatment once its body can scroll under one. Write a
26
+ * pinned footer inside `Container`, after the body; an inline one inside the
27
+ * body, where it should scroll.
73
28
  *
74
- * **Do not put a `KeyboardStickyView` in here.** gorhom's `animatedFooterPosition`
75
- * already carries the footer clear of the keyboard; this translate only gives up
76
- * the safe-area band on top of that. A third mechanism moving the same view
77
- * would fight both for prop ownership every frame.
29
+ * The two branches deliberately look different. An inline footer is in the
30
+ * flow and inherits the sheet's surface; a pinned one draws OVER the content,
31
+ * so it brings a background and a top hairline of its own — without them the
32
+ * content scrolls straight through it. That is `Screen.Footer`'s rule about its
33
+ * backing, one component along.
78
34
  *
79
- * Written with `sticky` but rendered outside a container, it falls back to the
80
- * inline branch rather than throwing: there is no footer position to ride, and a
81
- * row of buttons in the flow is the useful failure.
35
+ * Everything else is the engine's: a pinned footer is translated to the
36
+ * geometry's footer line, which the core proves holds still through a keyboard
37
+ * animation, so its buttons land on the keyboard's top edge without moving;
38
+ * the safe-area band under it is a spacer the geometry owns; and its measured
39
+ * height is what the body reserves and the dynamic snap point counts. The
40
+ * `padding` goes to the engine rather than a class for that reason — it has to
41
+ * be inside the measured box.
82
42
  *
83
43
  * @example
84
- * <BottomSheet.Footer>
85
- * <Button onPress={save}>Save</Button>
86
- * </BottomSheet.Footer>
44
+ * <BottomSheet.Container>
45
+ * <BottomSheet.Content>{fields}</BottomSheet.Content>
46
+ * <BottomSheet.Footer sticky>
47
+ * <Button onPress={save}>Save</Button>
48
+ * </BottomSheet.Footer>
49
+ * </BottomSheet.Container>
87
50
  *
88
51
  * @example
89
- * <BottomSheet.Footer sticky>
90
- * <Button onPress={submit}>Submit</Button>
91
- * </BottomSheet.Footer>
52
+ * // In the flow — inside the body, scrolling with it.
53
+ * <BottomSheet.ScrollView>
54
+ * {copy}
55
+ * <BottomSheet.Footer>
56
+ * <Button>Continue</Button>
57
+ * </BottomSheet.Footer>
58
+ * </BottomSheet.ScrollView>
92
59
  */
93
60
  export function BottomSheetFooter({
94
- animatedFooterPosition,
95
61
  className,
96
- children,
97
- footerHeight,
98
- onLayout,
99
62
  sticky = false,
100
- style,
63
+ padding,
101
64
  ...props
102
65
  }: BottomSheetFooterProps): ReactElement {
103
- const { bottom } = useSafeAreaInsets();
104
- const { progress } = useReanimatedKeyboardAnimation();
105
66
  const slots = bottomSheetVariants();
106
67
 
107
- // The footer keeps its own padding and gives up only the safe-area band, which
108
- // collapses as the keyboard arrives. `progress` runs 0 → 1 over the keyboard's
109
- // own animation, so the two travel together.
110
- const padding = useAnimatedStyle(() => ({
111
- paddingBottom: BOTTOM_SHEET_FOOTER_PADDING + bottom * (1 - progress.value),
112
- paddingTop: BOTTOM_SHEET_FOOTER_PADDING,
113
- }));
114
-
115
- const handleLayout = useCallback(
116
- (event: LayoutChangeEvent) => {
117
- if (footerHeight) footerHeight.value = event.nativeEvent.layout.height;
118
- onLayout?.(event);
119
- },
120
- [footerHeight, onLayout]
121
- );
122
-
123
- useEffect(() => {
124
- return () => {
125
- if (footerHeight) footerHeight.value = 0;
126
- };
127
- }, [footerHeight]);
128
-
129
- if (!sticky || animatedFooterPosition === undefined) {
130
- return (
131
- <View className={slots.footer({ className })} style={style} {...props}>
132
- {children}
133
- </View>
134
- );
68
+ if (!sticky) {
69
+ return <StyledFooter className={slots.footer({ className })} padding={padding} sticky={false} {...props} />;
135
70
  }
136
71
 
137
72
  return (
138
- <GorhomBottomSheetFooter animatedFooterPosition={animatedFooterPosition} bottomInset={0}>
139
- <Animated.View
140
- className={slots.stickyFooter({ className })}
141
- onLayout={handleLayout}
142
- style={[padding, style]}
143
- {...props}
144
- >
145
- {children}
146
- </Animated.View>
147
- </GorhomBottomSheetFooter>
73
+ <StyledFooter
74
+ className={slots.stickyFooter({ className })}
75
+ padding={padding ?? BOTTOM_SHEET_FOOTER_PADDING}
76
+ sticky
77
+ {...props}
78
+ />
148
79
  );
149
80
  }
150
81
  BottomSheetFooter.displayName = "DelacourUI.BottomSheet.Footer";
@@ -1,36 +1,41 @@
1
- import type { BottomSheetHandleProps as GorhomBottomSheetHandleProps } from "@gorhom/bottom-sheet";
1
+ import {
2
+ BottomSheet as Headless,
3
+ type BottomSheetHandleProps as HeadlessProps,
4
+ } from "@delacour/react-native-bottom-sheet";
2
5
  import type { ReactElement } from "react";
3
- import { View, type ViewProps } from "react-native";
6
+ import { type StyleProp, View, type ViewStyle } from "react-native";
7
+ import { withUniwind } from "uniwind";
4
8
  import { bottomSheetVariants } from "./bottom-sheet.variants";
5
9
 
6
- export type BottomSheetHandleProps = Partial<GorhomBottomSheetHandleProps> &
7
- Omit<ViewProps, "children"> & {
8
- className?: string;
9
- /** Style for the pill itself. What gorhom's `handleIndicatorStyle` becomes. */
10
- indicatorStyle?: ViewProps["style"];
11
- indicatorClassName?: string;
12
- };
10
+ type StyledHandleComponent = (props: HeadlessProps & { className?: string }) => ReactElement | null;
11
+
12
+ // Built at module scope, or every render mints a new component type and the
13
+ // engine's pan re-attaches to a fresh view.
14
+ const StyledHandle = withUniwind(Headless.Handle) as unknown as StyledHandleComponent;
15
+
16
+ export type BottomSheetHandleProps = HeadlessProps & {
17
+ className?: string;
18
+ /** Classes for the grabber itself. */
19
+ indicatorClassName?: string;
20
+ indicatorStyle?: StyleProp<ViewStyle>;
21
+ };
13
22
 
14
23
  /**
15
- * The grabber at the top of the sheet.
24
+ * The grabber's row.
16
25
  *
17
- * Supplied to gorhom as `handleComponent` for the same reason the background is:
18
- * this package paints with classNames, and gorhom's `handleStyle` /
19
- * `handleIndicatorStyle` cannot carry one. Both still arrive — gorhom passes
20
- * them down as `style` and `indicatorStyle` — so a caller who has a style object
21
- * rather than a class is not locked out.
26
+ * The engine's handle draws nothing of its own: it owns the pan, measures
27
+ * itself into the sheet's height, and is the adjustable element a screen
28
+ * reader steps through the snap points with. This puts the pill inside it, and
29
+ * classes on both.
22
30
  *
23
- * The pill is drawn but never announced: gorhom's own handle container wraps this
24
- * in the `Animated.View` that owns the pan and carries the accessibility surface,
25
- * so a second announced element here would put a nameless control in front of
26
- * every sheet.
31
+ * Pass children to replace the pill; the row, the pan and the accessibility
32
+ * stay.
27
33
  *
28
- * The two animated variables are destructured off rather than spread — see
29
- * `BottomSheetBackground`.
34
+ * @example
35
+ * <BottomSheet.Handle indicatorClassName="bg-primary" />
30
36
  */
31
37
  export function BottomSheetHandle({
32
- animatedIndex: _animatedIndex,
33
- animatedPosition: _animatedPosition,
38
+ children,
34
39
  className,
35
40
  indicatorClassName,
36
41
  indicatorStyle,
@@ -39,9 +44,9 @@ export function BottomSheetHandle({
39
44
  const slots = bottomSheetVariants();
40
45
 
41
46
  return (
42
- <View className={slots.handle({ className })} {...props}>
43
- <View className={slots.handleIndicator({ className: indicatorClassName })} style={indicatorStyle} />
44
- </View>
47
+ <StyledHandle className={slots.handle({ className })} {...props}>
48
+ {children ?? <View className={slots.handleIndicator({ className: indicatorClassName })} style={indicatorStyle} />}
49
+ </StyledHandle>
45
50
  );
46
51
  }
47
52
  BottomSheetHandle.displayName = "DelacourUI.BottomSheet.Handle";
@@ -0,0 +1,69 @@
1
+ import {
2
+ type BottomSheetScrollableProps,
3
+ createBottomSheetScrollable,
4
+ SCROLLABLE_TYPE,
5
+ useBottomSheetInternal,
6
+ } from "@delacour/react-native-bottom-sheet";
7
+ import type { LegendListRef } from "@legendapp/list/react-native";
8
+ import { AnimatedLegendList, type AnimatedLegendListProps } from "@legendapp/list/reanimated";
9
+ import type { ReactElement, Ref } from "react";
10
+ import { withUniwind } from "uniwind";
11
+ import { cn } from "../../lib/cn";
12
+ import { BOTTOM_SHEET_FOOTER_GAP, bottomSheetVariants } from "./bottom-sheet.variants";
13
+
14
+ /**
15
+ * `AnimatedLegendList` as a sheet body.
16
+ *
17
+ * Made once at module scope, as the factory requires: the wrapper drives the
18
+ * list with `animatedProps` and an animated `onScroll`, and a component made
19
+ * inside a render is a new type every frame. Registered as a flat list, which
20
+ * is what it is to the sheet — one scroll offset, one drag budget.
21
+ */
22
+ const SheetLegendList = createBottomSheetScrollable(AnimatedLegendList, SCROLLABLE_TYPE.FLAT_LIST);
23
+
24
+ /** The class props restated so `<ItemT>` survives `withUniwind` — see `bottom-sheet-flat-list.tsx`. */
25
+ type StyledLegendListComponent = <ItemT>(
26
+ props: AnimatedLegendListProps<ItemT> &
27
+ BottomSheetScrollableProps & { ref?: Ref<LegendListRef>; className?: string; contentContainerClassName?: string }
28
+ ) => ReactElement | null;
29
+
30
+ const StyledLegendList = withUniwind(SheetLegendList) as unknown as StyledLegendListComponent;
31
+
32
+ export type BottomSheetLegendListProps<ItemT> = Omit<AnimatedLegendListProps<ItemT>, "renderScrollComponent"> &
33
+ BottomSheetScrollableProps & {
34
+ ref?: Ref<LegendListRef>;
35
+ className?: string;
36
+ /** Classes for the content container. Same gutter and gap as `Content`. */
37
+ contentContainerClassName?: string;
38
+ };
39
+
40
+ /**
41
+ * A `LegendList` body, for a list long enough that `FlatList`'s virtualisation
42
+ * shows.
43
+ *
44
+ * Built here rather than in the engine because `@legendapp/list` is this
45
+ * library's optional peer, not the engine's: the engine exports the factory,
46
+ * and this is what the factory is for. The same scroll lock, drag budget and
47
+ * content-size snap point as the other three bodies.
48
+ *
49
+ * @example
50
+ * <BottomSheet.LegendList data={rows} keyExtractor={(row) => row.id} renderItem={renderRow} />
51
+ */
52
+ export function BottomSheetLegendList<ItemT>({
53
+ className,
54
+ contentContainerClassName,
55
+ contentContainerStyle,
56
+ ...props
57
+ }: BottomSheetLegendListProps<ItemT>): ReactElement {
58
+ const { hasFooter } = useBottomSheetInternal();
59
+
60
+ return (
61
+ <StyledLegendList
62
+ className={cn(className)}
63
+ contentContainerClassName={bottomSheetVariants().scrollContent({ className: contentContainerClassName })}
64
+ contentContainerStyle={[{ paddingBottom: hasFooter ? BOTTOM_SHEET_FOOTER_GAP : 0 }, contentContainerStyle]}
65
+ {...props}
66
+ />
67
+ );
68
+ }
69
+ BottomSheetLegendList.displayName = "DelacourUI.BottomSheet.LegendList";
@@ -1,180 +1,58 @@
1
1
  import {
2
- BottomSheetBackdrop,
3
- type BottomSheetBackdropProps,
4
- useBottomSheet as useGorhomBottomSheet,
5
- } from "@gorhom/bottom-sheet";
6
- import type { ReactElement, ReactNode } from "react";
7
- import { StyleSheet } from "react-native";
8
- import Animated, { useAnimatedStyle } from "react-native-reanimated";
2
+ BottomSheet as Headless,
3
+ type BottomSheetOverlayProps as HeadlessProps,
4
+ } from "@delacour/react-native-bottom-sheet";
5
+ import type { ReactElement } from "react";
9
6
  import { withUniwind } from "uniwind";
10
- import { Pressable } from "../pressable";
11
7
  import {
12
8
  BOTTOM_SHEET_BACKDROP_INDICES,
13
9
  BOTTOM_SHEET_OVERLAY_OPACITY,
14
10
  bottomSheetVariants,
15
11
  } from "./bottom-sheet.variants";
16
12
 
17
- /**
18
- * gorhom's backdrop is third-party and takes a `style`, never a `className`, and
19
- * it is a leaf — there is no inner view to hang classes on the way
20
- * `BottomSheet.Content` and `BottomSheet.Footer` do. So it is wrapped, once, at
21
- * module scope. In render `withUniwind` would mint a new component type every
22
- * frame and remount the scrim mid-fade. See AGENTS.md rule 7.
23
- */
24
- const StyledBackdrop = withUniwind(BottomSheetBackdrop);
13
+ type StyledOverlayComponent = (props: HeadlessProps & { className?: string }) => ReactElement | null;
14
+
15
+ // Third-party to Uniwind, so `className` needs the wrapper, built once at
16
+ // module scope.
17
+ const StyledOverlay = withUniwind(Headless.Overlay) as unknown as StyledOverlayComponent;
25
18
 
26
- export type BottomSheetOverlayProps = Partial<BottomSheetBackdropProps> & {
19
+ export type BottomSheetOverlayProps = HeadlessProps & {
27
20
  className?: string;
28
- /**
29
- * Opacity at full appearance.
30
- *
31
- * Defaults to 1 rather than gorhom's 0.5, because `--overlay` carries
32
- * its own alpha — the two would otherwise multiply and land the scrim at a
33
- * fifth of what the theme asked for.
34
- */
35
- opacity?: number;
36
- /** Snap index the scrim is fully in by. @default 0, the first snap point */
37
- appearsOnIndex?: number;
38
- /** Snap index the scrim is gone by. @default -1, the closed position */
39
- disappearsOnIndex?: number;
40
- /** Let touches reach the app behind the scrim. @default false */
41
- enableTouchThrough?: boolean;
42
- /** Close the sheet when the scrim is pressed. @default true */
43
- isCloseOnPress?: boolean;
44
- /** Announced on the pressable scrim. Ignored when it does not close. */
45
- accessibilityLabel?: string;
46
- onPress?: () => void;
47
- children?: ReactNode;
48
21
  };
49
22
 
50
23
  /**
51
24
  * The scrim over the app behind the sheet.
52
25
  *
53
- * **It is not rendered where it is written.** gorhom takes the backdrop as a
54
- * `backdropComponent` render prop rather than as a child, so
55
- * `BottomSheet.Portal` lifts this element out of its own children, publishes it
56
- * on context, and `BottomSheet.Container` clones it into that slot with the
57
- * sheet's animated position attached. Writing it as a sibling of the container is
58
- * what makes the anatomy read like the thing it draws.
59
- *
60
- * Omit it and the sheet has no scrim at all — gorhom's own default for
61
- * `backdropComponent` is nothing.
62
- *
63
- * **gorhom's own press handling is deliberately turned off, and the press area
64
- * is rebuilt here.** Its backdrop puts a full-screen `Gesture.Tap()` behind the
65
- * sheet, and Gesture Handler resolves a touch between competing GESTURES: a
66
- * `Button` in the sheet has one of its own and wins, but a `TextInput` has none,
67
- * so the backdrop takes the tap and the sheet closes instead of the field
68
- * focusing. That is why gorhom ships its own `BottomSheetTextInput` — and taking
69
- * that route would mean this package's `Input`, with its variants, its
70
- * `Input.Group` and its `Field` cascade, could not be used in a sheet at all.
26
+ * `bg-overlay`, a token that carries its own alpha, so the `opacity` here is 1
27
+ * and the two theme variants can differ. The engine fades it with the sheet's
28
+ * index — never with the keyboard — and makes it a plain `Pressable` written
29
+ * before the panel, which is what lets a tap on a field inside the sheet reach
30
+ * the field.
71
31
  *
72
- * So the scrim keeps `pressBehavior="none"` — no gesture anywhere — and a
73
- * `Pressable` is laid over the region ABOVE the sheet, sized from the sheet's own
74
- * `animatedPosition`. It never overlaps the sheet, so there is nothing for it to
75
- * take, and pressing the part of the scrim anyone can actually see still closes.
76
- * The colour and the fade stay gorhom's, driven off the sheet's position on the
77
- * UI thread; the slot therefore carries no `opacity-*`, or a class and an
78
- * animated style would be two writers of one property.
32
+ * Omit it and the sheet has no scrim at all. `pressBehavior="none"` keeps it
33
+ * and makes it inert, for a sheet that must be answered.
79
34
  *
80
35
  * @example
81
36
  * <BottomSheet.Overlay />
82
37
  *
83
38
  * @example
84
- * // A scrim that does not close the sheet — a decision the caller has to make.
85
- * <BottomSheet.Overlay isCloseOnPress={false} />
39
+ * <BottomSheet.Overlay pressBehavior="none" />
86
40
  */
87
41
  export function BottomSheetOverlay({
88
- accessibilityLabel = "Close",
89
- animatedIndex,
90
- animatedPosition,
91
42
  appearsOnIndex = BOTTOM_SHEET_BACKDROP_INDICES.appearsOnIndex,
92
43
  className,
93
44
  disappearsOnIndex = BOTTOM_SHEET_BACKDROP_INDICES.disappearsOnIndex,
94
- isCloseOnPress = true,
95
45
  opacity = BOTTOM_SHEET_OVERLAY_OPACITY,
96
- onPress,
97
46
  ...props
98
47
  }: BottomSheetOverlayProps): ReactElement {
99
- if (animatedIndex === undefined || animatedPosition === undefined) {
100
- throw new Error(
101
- "BottomSheet.Overlay must be written inside a <BottomSheet.Portal>, beside its <BottomSheet.Container>."
102
- );
103
- }
104
-
105
48
  return (
106
- <>
107
- <StyledBackdrop
108
- animatedIndex={animatedIndex}
109
- animatedPosition={animatedPosition}
110
- appearsOnIndex={appearsOnIndex}
111
- className={bottomSheetVariants().overlay({ className })}
112
- disappearsOnIndex={disappearsOnIndex}
113
- opacity={opacity}
114
- pressBehavior="none"
115
- {...props}
116
- />
117
- {isCloseOnPress ? (
118
- <BottomSheetOverlayPressArea
119
- accessibilityLabel={accessibilityLabel}
120
- animatedPosition={animatedPosition}
121
- onPress={onPress}
122
- />
123
- ) : null}
124
- </>
49
+ <StyledOverlay
50
+ appearsOnIndex={appearsOnIndex}
51
+ className={bottomSheetVariants().overlay({ className })}
52
+ disappearsOnIndex={disappearsOnIndex}
53
+ opacity={opacity}
54
+ {...props}
55
+ />
125
56
  );
126
57
  }
127
58
  BottomSheetOverlay.displayName = "DelacourUI.BottomSheet.Overlay";
128
-
129
- /**
130
- * The pressable band between the top of the screen and the top of the sheet.
131
- *
132
- * Its height is the sheet's own `animatedPosition`, so it grows and shrinks with
133
- * the sheet on the UI thread and stops exactly where the sheet begins — which is
134
- * the whole point. The `Pressable` is a child rather than the animated view
135
- * itself because `Pressable` takes no `style`: its own `Animated.View` already
136
- * owns one, and a second would fight it for prop ownership every frame.
137
- *
138
- * It reads gorhom's `useBottomSheet()` rather than this package's. The backdrop
139
- * is rendered by gorhom's own container, OUTSIDE the children
140
- * `BottomSheet.Container` re-publishes its context around, so the sheet's own
141
- * handle is the one thing in scope here — and closing through it lands on
142
- * `onDismiss`, which is where `onOpenChange` already is.
143
- */
144
- function BottomSheetOverlayPressArea({
145
- accessibilityLabel,
146
- animatedPosition,
147
- onPress,
148
- }: {
149
- accessibilityLabel: string;
150
- animatedPosition: NonNullable<BottomSheetBackdropProps["animatedPosition"]>;
151
- onPress?: () => void;
152
- }): ReactElement {
153
- const { close } = useGorhomBottomSheet();
154
-
155
- const style = useAnimatedStyle(() => ({ height: Math.max(0, animatedPosition.value) }));
156
-
157
- const handlePress = () => {
158
- onPress?.();
159
- close();
160
- };
161
-
162
- return (
163
- <Animated.View style={[styles.pressArea, style]}>
164
- <Pressable
165
- accessibilityLabel={accessibilityLabel}
166
- accessibilityRole="button"
167
- className="flex-1"
168
- feedback="none"
169
- onPress={handlePress}
170
- />
171
- </Animated.View>
172
- );
173
- }
174
- BottomSheetOverlayPressArea.displayName = "DelacourUI.BottomSheet.Overlay.PressArea";
175
-
176
- // A style rather than a class: the height beside it is an animated value, and the
177
- // two have to arrive on the same node.
178
- const styles = StyleSheet.create({
179
- pressArea: { left: 0, position: "absolute", right: 0, top: 0 },
180
- });
@@ -0,0 +1,42 @@
1
+ import {
2
+ BottomSheetProvider as HeadlessProvider,
3
+ type BottomSheetProviderProps as HeadlessProviderProps,
4
+ } from "@delacour/react-native-bottom-sheet";
5
+ import type { ReactElement } from "react";
6
+ import { TeleportProvidedContext, useIsTeleportProvided } from "../overlay/overlay.context";
7
+
8
+ export type BottomSheetProviderProps = Omit<HeadlessProviderProps, "hasPortalProvider">;
9
+
10
+ /**
11
+ * The engine's provider, mounted once by the app — and aware of
12
+ * `OverlayProvider`.
13
+ *
14
+ * Both providers need teleport's `PortalProvider`, and there must be exactly
15
+ * one: teleport registers hosts natively by name, so two would mean two hosts
16
+ * called `"root"`. Whichever of the two mounts outermost mounts it and says so
17
+ * through `TeleportProvidedContext`; the inner one skips its own. Sheets and
18
+ * overlays then share one `"root"` host, ordered by `zIndex` — every overlay's
19
+ * band starts above every sheet's.
20
+ *
21
+ * The overlay folder's context file is a leaf (rule 3): it imports nothing but
22
+ * React, so this cross-folder import cannot close a cycle.
23
+ *
24
+ * @example
25
+ * <DelacourProvider>
26
+ * <OverlayProvider>
27
+ * <BottomSheetProvider>
28
+ * <Stack />
29
+ * </BottomSheetProvider>
30
+ * </OverlayProvider>
31
+ * </DelacourProvider>
32
+ */
33
+ export function BottomSheetProvider({ children }: BottomSheetProviderProps): ReactElement {
34
+ const isTeleportProvided = useIsTeleportProvided();
35
+
36
+ return (
37
+ <HeadlessProvider hasPortalProvider={isTeleportProvided}>
38
+ <TeleportProvidedContext.Provider value>{children}</TeleportProvidedContext.Provider>
39
+ </HeadlessProvider>
40
+ );
41
+ }
42
+ BottomSheetProvider.displayName = "DelacourUI.BottomSheet.Provider";