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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (481) hide show
  1. package/README.md +10 -6
  2. package/package.json +48 -4
  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 +5 -0
  34. package/src/components/badge/badge.tsx +6 -1
  35. package/src/components/bottom-sheet/AGENTS.md +186 -231
  36. package/src/components/bottom-sheet/bottom-sheet-background.tsx +31 -22
  37. package/src/components/bottom-sheet/bottom-sheet-close.tsx +23 -30
  38. package/src/components/bottom-sheet/bottom-sheet-container.tsx +54 -208
  39. package/src/components/bottom-sheet/bottom-sheet-content.tsx +25 -48
  40. package/src/components/bottom-sheet/bottom-sheet-description.tsx +8 -2
  41. package/src/components/bottom-sheet/bottom-sheet-flat-list.tsx +65 -0
  42. package/src/components/bottom-sheet/bottom-sheet-footer.tsx +53 -122
  43. package/src/components/bottom-sheet/bottom-sheet-handle.tsx +31 -26
  44. package/src/components/bottom-sheet/bottom-sheet-legend-list.tsx +69 -0
  45. package/src/components/bottom-sheet/bottom-sheet-overlay.tsx +25 -147
  46. package/src/components/bottom-sheet/bottom-sheet-provider.tsx +42 -0
  47. package/src/components/bottom-sheet/bottom-sheet-scroll-view.tsx +38 -62
  48. package/src/components/bottom-sheet/bottom-sheet-section-list.tsx +58 -0
  49. package/src/components/bottom-sheet/bottom-sheet-steps.tsx +88 -0
  50. package/src/components/bottom-sheet/bottom-sheet-text-input.tsx +44 -0
  51. package/src/components/bottom-sheet/bottom-sheet-title.tsx +12 -8
  52. package/src/components/bottom-sheet/bottom-sheet-trigger.tsx +19 -37
  53. package/src/components/bottom-sheet/bottom-sheet.tsx +113 -60
  54. package/src/components/bottom-sheet/bottom-sheet.variants.test.ts +47 -87
  55. package/src/components/bottom-sheet/bottom-sheet.variants.ts +50 -126
  56. package/src/components/bottom-sheet/index.ts +39 -17
  57. package/src/components/bottom-sheet/use-bottom-sheet-input.ts +16 -115
  58. package/src/components/button/AGENTS.md +45 -11
  59. package/src/components/button/button-group.tsx +44 -8
  60. package/src/components/button/button.context.tsx +10 -0
  61. package/src/components/button/button.tsx +2 -1
  62. package/src/components/button/button.variants.test.ts +154 -0
  63. package/src/components/button/button.variants.ts +71 -6
  64. package/src/components/button/index.ts +2 -0
  65. package/src/components/calendar/AGENTS.md +142 -0
  66. package/src/components/calendar/calendar-caption.tsx +116 -0
  67. package/src/components/calendar/calendar-day.tsx +103 -0
  68. package/src/components/calendar/calendar-grid.tsx +183 -0
  69. package/src/components/calendar/calendar-header.tsx +34 -0
  70. package/src/components/calendar/calendar-nav.tsx +51 -0
  71. package/src/components/calendar/calendar-picker.tsx +128 -0
  72. package/src/components/calendar/calendar-weekdays.tsx +48 -0
  73. package/src/components/calendar/calendar.context.tsx +108 -0
  74. package/src/components/calendar/calendar.date.test.ts +456 -0
  75. package/src/components/calendar/calendar.date.ts +584 -0
  76. package/src/components/calendar/calendar.tsx +389 -0
  77. package/src/components/calendar/calendar.types.ts +87 -0
  78. package/src/components/calendar/calendar.variants.test.ts +363 -0
  79. package/src/components/calendar/calendar.variants.ts +426 -0
  80. package/src/components/calendar/index.ts +96 -0
  81. package/src/components/card/AGENTS.md +88 -0
  82. package/src/components/card/card-action.tsx +16 -0
  83. package/src/components/card/card-content.tsx +12 -0
  84. package/src/components/card/card-description.tsx +12 -0
  85. package/src/components/card/card-footer.tsx +30 -0
  86. package/src/components/card/card-header.tsx +45 -0
  87. package/src/components/card/card-title.tsx +25 -0
  88. package/src/components/card/card.context.tsx +64 -0
  89. package/src/components/card/card.tsx +94 -0
  90. package/src/components/card/card.types.ts +13 -0
  91. package/src/components/card/card.variants.test.ts +240 -0
  92. package/src/components/card/card.variants.ts +177 -0
  93. package/src/components/card/index.ts +15 -0
  94. package/src/components/chart/AGENTS.md +8 -0
  95. package/src/components/chart/chart.tsx +8 -1
  96. package/src/components/chip/AGENTS.md +113 -0
  97. package/src/components/chip/chip-close-button.tsx +48 -0
  98. package/src/components/chip/chip-end-content.tsx +15 -0
  99. package/src/components/chip/chip-label.tsx +21 -0
  100. package/src/components/chip/chip-start-content.tsx +16 -0
  101. package/src/components/chip/chip.context.tsx +66 -0
  102. package/src/components/chip/chip.tsx +268 -0
  103. package/src/components/chip/chip.types.ts +10 -0
  104. package/src/components/chip/chip.variants.test.ts +335 -0
  105. package/src/components/chip/chip.variants.ts +321 -0
  106. package/src/components/chip/index.ts +24 -0
  107. package/src/components/collapsible/AGENTS.md +97 -0
  108. package/src/components/collapsible/collapsible-content.tsx +97 -0
  109. package/src/components/collapsible/collapsible-description.tsx +17 -0
  110. package/src/components/collapsible/collapsible-indicator.tsx +92 -0
  111. package/src/components/collapsible/collapsible-title.tsx +17 -0
  112. package/src/components/collapsible/collapsible-trigger.tsx +133 -0
  113. package/src/components/collapsible/collapsible.context.tsx +91 -0
  114. package/src/components/collapsible/collapsible.tsx +167 -0
  115. package/src/components/collapsible/collapsible.types.ts +9 -0
  116. package/src/components/collapsible/collapsible.variants.test.ts +338 -0
  117. package/src/components/collapsible/collapsible.variants.ts +228 -0
  118. package/src/components/collapsible/index.ts +32 -0
  119. package/src/components/context-menu/AGENTS.md +103 -0
  120. package/src/components/context-menu/context-menu-content.tsx +64 -0
  121. package/src/components/context-menu/context-menu-item.tsx +22 -0
  122. package/src/components/context-menu/context-menu-preview.tsx +60 -0
  123. package/src/components/context-menu/context-menu-trigger.tsx +160 -0
  124. package/src/components/context-menu/context-menu.context.tsx +91 -0
  125. package/src/components/context-menu/context-menu.tsx +90 -0
  126. package/src/components/context-menu/context-menu.variants.test.ts +266 -0
  127. package/src/components/context-menu/context-menu.variants.ts +147 -0
  128. package/src/components/context-menu/index.ts +18 -0
  129. package/src/components/dialog/AGENTS.md +97 -0
  130. package/src/components/dialog/dialog-body.tsx +21 -0
  131. package/src/components/dialog/dialog-close.tsx +82 -0
  132. package/src/components/dialog/dialog-content.tsx +153 -0
  133. package/src/components/dialog/dialog-description.tsx +23 -0
  134. package/src/components/dialog/dialog-footer.tsx +32 -0
  135. package/src/components/dialog/dialog-header.tsx +20 -0
  136. package/src/components/dialog/dialog-title.tsx +42 -0
  137. package/src/components/dialog/dialog-trigger.tsx +54 -0
  138. package/src/components/dialog/dialog.context.tsx +90 -0
  139. package/src/components/dialog/dialog.tsx +119 -0
  140. package/src/components/dialog/dialog.variants.test.ts +224 -0
  141. package/src/components/dialog/dialog.variants.ts +173 -0
  142. package/src/components/dialog/index.ts +30 -0
  143. package/src/components/drawer/AGENTS.md +123 -0
  144. package/src/components/drawer/drawer-body.tsx +46 -0
  145. package/src/components/drawer/drawer-close.tsx +76 -0
  146. package/src/components/drawer/drawer-content.tsx +186 -0
  147. package/src/components/drawer/drawer-description.tsx +23 -0
  148. package/src/components/drawer/drawer-footer.tsx +21 -0
  149. package/src/components/drawer/drawer-header.tsx +42 -0
  150. package/src/components/drawer/drawer-title.tsx +35 -0
  151. package/src/components/drawer/drawer-trigger.tsx +54 -0
  152. package/src/components/drawer/drawer.context.tsx +114 -0
  153. package/src/components/drawer/drawer.tsx +119 -0
  154. package/src/components/drawer/drawer.variants.test.ts +392 -0
  155. package/src/components/drawer/drawer.variants.ts +244 -0
  156. package/src/components/drawer/index.ts +41 -0
  157. package/src/components/drawer/use-drawer-pan.ts +108 -0
  158. package/src/components/empty-state/AGENTS.md +90 -0
  159. package/src/components/empty-state/empty-state-content.tsx +17 -0
  160. package/src/components/empty-state/empty-state-description.tsx +12 -0
  161. package/src/components/empty-state/empty-state-header.tsx +17 -0
  162. package/src/components/empty-state/empty-state-media.tsx +56 -0
  163. package/src/components/empty-state/empty-state-title.tsx +18 -0
  164. package/src/components/empty-state/empty-state.context.tsx +65 -0
  165. package/src/components/empty-state/empty-state.tsx +84 -0
  166. package/src/components/empty-state/empty-state.types.ts +14 -0
  167. package/src/components/empty-state/empty-state.variants.test.ts +245 -0
  168. package/src/components/empty-state/empty-state.variants.ts +132 -0
  169. package/src/components/empty-state/index.ts +20 -0
  170. package/src/components/fab/AGENTS.md +119 -0
  171. package/src/components/fab/fab-action.tsx +118 -0
  172. package/src/components/fab/fab-group.tsx +214 -0
  173. package/src/components/fab/fab-label.tsx +18 -0
  174. package/src/components/fab/fab.context.tsx +125 -0
  175. package/src/components/fab/fab.tsx +156 -0
  176. package/src/components/fab/fab.types.ts +17 -0
  177. package/src/components/fab/fab.variants.test.ts +274 -0
  178. package/src/components/fab/fab.variants.ts +234 -0
  179. package/src/components/fab/index.ts +37 -0
  180. package/src/components/feedback/AGENTS.md +95 -0
  181. package/src/components/feedback/feedback-action.tsx +16 -0
  182. package/src/components/feedback/feedback-cancel.tsx +34 -0
  183. package/src/components/feedback/feedback-close.tsx +21 -0
  184. package/src/components/feedback/feedback-content.tsx +24 -0
  185. package/src/components/feedback/feedback-field.tsx +70 -0
  186. package/src/components/feedback/feedback-footer.tsx +21 -0
  187. package/src/components/feedback/feedback-panel.tsx +54 -0
  188. package/src/components/feedback/feedback-submit.tsx +74 -0
  189. package/src/components/feedback/feedback-title.tsx +34 -0
  190. package/src/components/feedback/feedback-trigger.tsx +20 -0
  191. package/src/components/feedback/feedback.context.tsx +73 -0
  192. package/src/components/feedback/feedback.tsx +135 -0
  193. package/src/components/feedback/feedback.variants.test.ts +185 -0
  194. package/src/components/feedback/feedback.variants.ts +128 -0
  195. package/src/components/feedback/index.ts +24 -0
  196. package/src/components/field/AGENTS.md +19 -0
  197. package/src/components/field/field-label.tsx +19 -5
  198. package/src/components/field/field.context.tsx +17 -0
  199. package/src/components/field/field.tsx +15 -2
  200. package/src/components/field/field.variants.test.ts +24 -0
  201. package/src/components/field/field.variants.ts +20 -0
  202. package/src/components/field/index.ts +1 -0
  203. package/src/components/item/AGENTS.md +92 -0
  204. package/src/components/item/index.ts +25 -0
  205. package/src/components/item/item-actions.tsx +28 -0
  206. package/src/components/item/item-content.tsx +15 -0
  207. package/src/components/item/item-description.tsx +12 -0
  208. package/src/components/item/item-footer.tsx +13 -0
  209. package/src/components/item/item-group.tsx +32 -0
  210. package/src/components/item/item-header.tsx +13 -0
  211. package/src/components/item/item-media.tsx +37 -0
  212. package/src/components/item/item-separator.tsx +13 -0
  213. package/src/components/item/item-title.tsx +17 -0
  214. package/src/components/item/item.context.tsx +66 -0
  215. package/src/components/item/item.tsx +218 -0
  216. package/src/components/item/item.types.ts +12 -0
  217. package/src/components/item/item.variants.test.ts +263 -0
  218. package/src/components/item/item.variants.ts +200 -0
  219. package/src/components/kpi/AGENTS.md +125 -0
  220. package/src/components/kpi/index.ts +45 -0
  221. package/src/components/kpi/kpi-action.tsx +12 -0
  222. package/src/components/kpi/kpi-content.tsx +35 -0
  223. package/src/components/kpi/kpi-footer.tsx +52 -0
  224. package/src/components/kpi/kpi-group.tsx +70 -0
  225. package/src/components/kpi/kpi-header.tsx +25 -0
  226. package/src/components/kpi/kpi-icon.tsx +28 -0
  227. package/src/components/kpi/kpi-sparkline.tsx +145 -0
  228. package/src/components/kpi/kpi-stat.tsx +20 -0
  229. package/src/components/kpi/kpi-title.tsx +19 -0
  230. package/src/components/kpi/kpi-trend.tsx +105 -0
  231. package/src/components/kpi/kpi-value.tsx +32 -0
  232. package/src/components/kpi/kpi.context.tsx +111 -0
  233. package/src/components/kpi/kpi.tsx +154 -0
  234. package/src/components/kpi/kpi.types.ts +9 -0
  235. package/src/components/kpi/kpi.variants.test.ts +428 -0
  236. package/src/components/kpi/kpi.variants.ts +347 -0
  237. package/src/components/label/AGENTS.md +89 -0
  238. package/src/components/label/index.ts +10 -0
  239. package/src/components/label/label.tsx +97 -0
  240. package/src/components/label/label.variants.test.ts +176 -0
  241. package/src/components/label/label.variants.ts +123 -0
  242. package/src/components/menu/AGENTS.md +176 -0
  243. package/src/components/menu/index.ts +44 -0
  244. package/src/components/menu/menu-background.tsx +17 -0
  245. package/src/components/menu/menu-checkbox-item.tsx +57 -0
  246. package/src/components/menu/menu-content.tsx +303 -0
  247. package/src/components/menu/menu-item.tsx +162 -0
  248. package/src/components/menu/menu-label.tsx +14 -0
  249. package/src/components/menu/menu-radio-group.tsx +50 -0
  250. package/src/components/menu/menu-radio-item.tsx +57 -0
  251. package/src/components/menu/menu-separator.tsx +11 -0
  252. package/src/components/menu/menu-sub-content.tsx +72 -0
  253. package/src/components/menu/menu-sub-trigger.tsx +50 -0
  254. package/src/components/menu/menu-sub.tsx +75 -0
  255. package/src/components/menu/menu-trigger.tsx +57 -0
  256. package/src/components/menu/menu.context.tsx +214 -0
  257. package/src/components/menu/menu.tsx +88 -0
  258. package/src/components/menu/menu.types.ts +33 -0
  259. package/src/components/menu/menu.variants.test.ts +400 -0
  260. package/src/components/menu/menu.variants.ts +353 -0
  261. package/src/components/meter/AGENTS.md +135 -0
  262. package/src/components/meter/index.ts +43 -0
  263. package/src/components/meter/meter-fill.tsx +19 -0
  264. package/src/components/meter/meter-header.tsx +17 -0
  265. package/src/components/meter/meter-label.tsx +18 -0
  266. package/src/components/meter/meter-output.tsx +42 -0
  267. package/src/components/meter/meter-segments.tsx +83 -0
  268. package/src/components/meter/meter-track.tsx +16 -0
  269. package/src/components/meter/meter.context.tsx +62 -0
  270. package/src/components/meter/meter.tsx +286 -0
  271. package/src/components/meter/meter.types.ts +30 -0
  272. package/src/components/meter/meter.variants.test.ts +430 -0
  273. package/src/components/meter/meter.variants.ts +347 -0
  274. package/src/components/overlay/AGENTS.md +89 -0
  275. package/src/components/overlay/index.ts +27 -0
  276. package/src/components/overlay/overlay-portal.tsx +84 -0
  277. package/src/components/overlay/overlay-presence.test.ts +46 -0
  278. package/src/components/overlay/overlay-presence.ts +49 -0
  279. package/src/components/overlay/overlay-registry.test.ts +96 -0
  280. package/src/components/overlay/overlay-registry.ts +99 -0
  281. package/src/components/overlay/overlay-scrim.tsx +49 -0
  282. package/src/components/overlay/overlay.context.tsx +48 -0
  283. package/src/components/overlay/overlay.tsx +118 -0
  284. package/src/components/overlay/overlay.variants.test.ts +37 -0
  285. package/src/components/overlay/overlay.variants.ts +33 -0
  286. package/src/components/overlay/use-overlay-back-handler.ts +34 -0
  287. package/src/components/overlay/use-overlay-presence.ts +87 -0
  288. package/src/components/popover/AGENTS.md +138 -0
  289. package/src/components/popover/index.ts +48 -0
  290. package/src/components/popover/popover-anchor.tsx +49 -0
  291. package/src/components/popover/popover-arrow.tsx +89 -0
  292. package/src/components/popover/popover-close.tsx +73 -0
  293. package/src/components/popover/popover-content.tsx +235 -0
  294. package/src/components/popover/popover-description.tsx +18 -0
  295. package/src/components/popover/popover-title.tsx +33 -0
  296. package/src/components/popover/popover-trigger.tsx +56 -0
  297. package/src/components/popover/popover.context.tsx +71 -0
  298. package/src/components/popover/popover.position.test.ts +354 -0
  299. package/src/components/popover/popover.position.ts +286 -0
  300. package/src/components/popover/popover.tsx +123 -0
  301. package/src/components/popover/popover.variants.test.ts +135 -0
  302. package/src/components/popover/popover.variants.ts +85 -0
  303. package/src/components/popover/use-anchor-measure.ts +76 -0
  304. package/src/components/popover/use-anchored-content.ts +219 -0
  305. package/src/components/pressable/AGENTS.md +11 -1
  306. package/src/components/pressable/pressable.tsx +7 -2
  307. package/src/components/pressable/pressable.variants.test.ts +29 -0
  308. package/src/components/pressable/pressable.variants.ts +17 -0
  309. package/src/components/progress/AGENTS.md +120 -0
  310. package/src/components/progress/index.ts +40 -0
  311. package/src/components/progress/progress-fill.tsx +152 -0
  312. package/src/components/progress/progress-header.tsx +19 -0
  313. package/src/components/progress/progress-label.tsx +27 -0
  314. package/src/components/progress/progress-output.tsx +47 -0
  315. package/src/components/progress/progress-track.tsx +38 -0
  316. package/src/components/progress/progress.context.tsx +79 -0
  317. package/src/components/progress/progress.tsx +171 -0
  318. package/src/components/progress/progress.types.ts +23 -0
  319. package/src/components/progress/progress.variants.test.ts +335 -0
  320. package/src/components/progress/progress.variants.ts +284 -0
  321. package/src/components/progress-button/AGENTS.md +116 -0
  322. package/src/components/progress-button/index.ts +36 -0
  323. package/src/components/progress-button/progress-button-done.tsx +33 -0
  324. package/src/components/progress-button/progress-button-label.tsx +27 -0
  325. package/src/components/progress-button/progress-button.context.tsx +93 -0
  326. package/src/components/progress-button/progress-button.tsx +414 -0
  327. package/src/components/progress-button/progress-button.variants.test.ts +314 -0
  328. package/src/components/progress-button/progress-button.variants.ts +236 -0
  329. package/src/components/provider/AGENTS.md +38 -25
  330. package/src/components/provider/provider.tsx +38 -11
  331. package/src/components/radio/AGENTS.md +8 -10
  332. package/src/components/radio/radio.variants.test.ts +5 -6
  333. package/src/components/radio/radio.variants.ts +6 -7
  334. package/src/components/rating/AGENTS.md +143 -0
  335. package/src/components/rating/index.ts +43 -0
  336. package/src/components/rating/rating-output.tsx +39 -0
  337. package/src/components/rating/rating-star.tsx +70 -0
  338. package/src/components/rating/rating-stars.tsx +219 -0
  339. package/src/components/rating/rating.context.tsx +79 -0
  340. package/src/components/rating/rating.tsx +163 -0
  341. package/src/components/rating/rating.variants.test.ts +347 -0
  342. package/src/components/rating/rating.variants.ts +354 -0
  343. package/src/components/selection-mode/AGENTS.md +155 -0
  344. package/src/components/selection-mode/index.ts +43 -0
  345. package/src/components/selection-mode/selection-mode-action.tsx +65 -0
  346. package/src/components/selection-mode/selection-mode-bar.tsx +79 -0
  347. package/src/components/selection-mode/selection-mode-group.tsx +123 -0
  348. package/src/components/selection-mode/selection-mode-header.tsx +85 -0
  349. package/src/components/selection-mode/selection-mode-indicator.tsx +118 -0
  350. package/src/components/selection-mode/selection-mode-item.tsx +182 -0
  351. package/src/components/selection-mode/selection-mode.context.tsx +89 -0
  352. package/src/components/selection-mode/selection-mode.tsx +207 -0
  353. package/src/components/selection-mode/selection-mode.types.ts +36 -0
  354. package/src/components/selection-mode/selection-mode.variants.test.ts +292 -0
  355. package/src/components/selection-mode/selection-mode.variants.ts +329 -0
  356. package/src/components/skeleton/AGENTS.md +120 -0
  357. package/src/components/skeleton/index.ts +15 -0
  358. package/src/components/skeleton/skeleton-clock.ts +48 -0
  359. package/src/components/skeleton/skeleton-group.tsx +64 -0
  360. package/src/components/skeleton/skeleton-shimmer.tsx +80 -0
  361. package/src/components/skeleton/skeleton.context.tsx +45 -0
  362. package/src/components/skeleton/skeleton.tsx +227 -0
  363. package/src/components/skeleton/skeleton.variants.test.ts +245 -0
  364. package/src/components/skeleton/skeleton.variants.ts +222 -0
  365. package/src/components/slide-button/AGENTS.md +122 -0
  366. package/src/components/slide-button/index.ts +43 -0
  367. package/src/components/slide-button/slide-button-label.tsx +70 -0
  368. package/src/components/slide-button/slide-button-thumb.tsx +93 -0
  369. package/src/components/slide-button/slide-button.context.tsx +76 -0
  370. package/src/components/slide-button/slide-button.tsx +457 -0
  371. package/src/components/slide-button/slide-button.variants.test.ts +288 -0
  372. package/src/components/slide-button/slide-button.variants.ts +324 -0
  373. package/src/components/slider/index.ts +2 -0
  374. package/src/components/slider/slider-thumb.tsx +33 -1
  375. package/src/components/slider/slider.variants.test.ts +52 -0
  376. package/src/components/slider/slider.variants.ts +56 -2
  377. package/src/components/stack-card/AGENTS.md +169 -0
  378. package/src/components/stack-card/index.ts +37 -0
  379. package/src/components/stack-card/stack-card-action.tsx +66 -0
  380. package/src/components/stack-card/stack-card-actions.tsx +18 -0
  381. package/src/components/stack-card/stack-card-card.tsx +71 -0
  382. package/src/components/stack-card/stack-card-empty.tsx +30 -0
  383. package/src/components/stack-card/stack-card-slot.tsx +90 -0
  384. package/src/components/stack-card/stack-card-stamp.tsx +76 -0
  385. package/src/components/stack-card/stack-card.context.tsx +117 -0
  386. package/src/components/stack-card/stack-card.tsx +557 -0
  387. package/src/components/stack-card/stack-card.types.ts +26 -0
  388. package/src/components/stack-card/stack-card.variants.test.ts +355 -0
  389. package/src/components/stack-card/stack-card.variants.ts +360 -0
  390. package/src/components/steps/AGENTS.md +153 -0
  391. package/src/components/steps/index.ts +45 -0
  392. package/src/components/steps/steps-connector.tsx +31 -0
  393. package/src/components/steps/steps-description.tsx +26 -0
  394. package/src/components/steps/steps-indicator.tsx +106 -0
  395. package/src/components/steps/steps-item.tsx +225 -0
  396. package/src/components/steps/steps-panel.tsx +41 -0
  397. package/src/components/steps/steps-title.tsx +32 -0
  398. package/src/components/steps/steps-track.tsx +59 -0
  399. package/src/components/steps/steps.context.tsx +123 -0
  400. package/src/components/steps/steps.tsx +166 -0
  401. package/src/components/steps/steps.variants.test.ts +388 -0
  402. package/src/components/steps/steps.variants.ts +468 -0
  403. package/src/components/surface/AGENTS.md +72 -0
  404. package/src/components/surface/index.ts +15 -0
  405. package/src/components/surface/surface.context.tsx +54 -0
  406. package/src/components/surface/surface.tsx +70 -0
  407. package/src/components/surface/surface.variants.test.ts +180 -0
  408. package/src/components/surface/surface.variants.ts +133 -0
  409. package/src/components/swipe/AGENTS.md +140 -0
  410. package/src/components/swipe/index.ts +31 -0
  411. package/src/components/swipe/swipe-action.tsx +99 -0
  412. package/src/components/swipe/swipe-end.tsx +14 -0
  413. package/src/components/swipe/swipe-group.tsx +55 -0
  414. package/src/components/swipe/swipe-panel.tsx +55 -0
  415. package/src/components/swipe/swipe-start.tsx +15 -0
  416. package/src/components/swipe/swipe.context.tsx +135 -0
  417. package/src/components/swipe/swipe.tsx +393 -0
  418. package/src/components/swipe/swipe.types.ts +7 -0
  419. package/src/components/swipe/swipe.variants.test.ts +337 -0
  420. package/src/components/swipe/swipe.variants.ts +290 -0
  421. package/src/components/switch/switch.variants.ts +2 -2
  422. package/src/components/tabs/AGENTS.md +4 -3
  423. package/src/components/tabs/tabs.variants.test.ts +1 -1
  424. package/src/components/tabs/tabs.variants.ts +4 -6
  425. package/src/components/textarea/AGENTS.md +86 -0
  426. package/src/components/textarea/index.ts +16 -0
  427. package/src/components/textarea/textarea.tsx +157 -0
  428. package/src/components/textarea/textarea.variants.test.ts +219 -0
  429. package/src/components/textarea/textarea.variants.ts +171 -0
  430. package/src/components/toast/AGENTS.md +140 -0
  431. package/src/components/toast/index.ts +74 -0
  432. package/src/components/toast/toast-action.tsx +59 -0
  433. package/src/components/toast/toast-api.ts +32 -0
  434. package/src/components/toast/toast-close.tsx +44 -0
  435. package/src/components/toast/toast-content.tsx +11 -0
  436. package/src/components/toast/toast-description.tsx +11 -0
  437. package/src/components/toast/toast-indicator.tsx +34 -0
  438. package/src/components/toast/toast-item.tsx +308 -0
  439. package/src/components/toast/toast-title.tsx +13 -0
  440. package/src/components/toast/toast-viewport.tsx +135 -0
  441. package/src/components/toast/toast.context.tsx +69 -0
  442. package/src/components/toast/toast.store.test.ts +259 -0
  443. package/src/components/toast/toast.store.ts +338 -0
  444. package/src/components/toast/toast.timer.test.ts +64 -0
  445. package/src/components/toast/toast.timer.ts +51 -0
  446. package/src/components/toast/toast.tsx +132 -0
  447. package/src/components/toast/toast.variants.test.ts +393 -0
  448. package/src/components/toast/toast.variants.ts +304 -0
  449. package/src/components/toggle-button/AGENTS.md +106 -0
  450. package/src/components/toggle-button/index.ts +30 -0
  451. package/src/components/toggle-button/toggle-button-group.tsx +156 -0
  452. package/src/components/toggle-button/toggle-button-label.tsx +19 -0
  453. package/src/components/toggle-button/toggle-button.context.tsx +130 -0
  454. package/src/components/toggle-button/toggle-button.tsx +172 -0
  455. package/src/components/toggle-button/toggle-button.variants.test.ts +189 -0
  456. package/src/components/toggle-button/toggle-button.variants.ts +160 -0
  457. package/src/components/tooltip/AGENTS.md +133 -0
  458. package/src/components/tooltip/index.ts +28 -0
  459. package/src/components/tooltip/tooltip-arrow.tsx +40 -0
  460. package/src/components/tooltip/tooltip-content.tsx +179 -0
  461. package/src/components/tooltip/tooltip-description.tsx +19 -0
  462. package/src/components/tooltip/tooltip-text.tsx +21 -0
  463. package/src/components/tooltip/tooltip-title.tsx +20 -0
  464. package/src/components/tooltip/tooltip-trigger.tsx +103 -0
  465. package/src/components/tooltip/tooltip.context.tsx +68 -0
  466. package/src/components/tooltip/tooltip.tsx +213 -0
  467. package/src/components/tooltip/tooltip.variants.test.ts +231 -0
  468. package/src/components/tooltip/tooltip.variants.ts +177 -0
  469. package/src/hooks/use-calm-motion.tsx +31 -0
  470. package/src/lib/calm-motion.test.ts +17 -0
  471. package/src/lib/calm-motion.ts +23 -0
  472. package/src/lib/cn.test.ts +14 -0
  473. package/src/lib/cn.ts +2 -2
  474. package/src/no-gorhom.test.ts +54 -0
  475. package/src/styles/geometry.test.ts +1 -0
  476. package/src/styles/theme.css +4 -0
  477. package/src/styles/tokens.css +11 -0
  478. package/src/styles/tokens.test.ts +22 -0
  479. package/src/styles/tokens.ts +20 -0
  480. package/src/components/bottom-sheet/bottom-sheet-portal.tsx +0 -72
  481. package/src/components/bottom-sheet/bottom-sheet.context.tsx +0 -135
@@ -1,73 +1,106 @@
1
- import { type ReactElement, type ReactNode, useCallback, useMemo, useRef } from "react";
2
- import { useControllableState } from "../../hooks/use-controllable-state";
3
- import { type BottomSheetContextValue, type BottomSheetHandle, BottomSheetProvider } from "./bottom-sheet.context";
1
+ import {
2
+ BottomSheetHost,
3
+ BottomSheet as Headless,
4
+ type BottomSheetProps as HeadlessBottomSheetProps,
5
+ } from "@delacour/react-native-bottom-sheet";
6
+ import type { ReactElement } from "react";
7
+ import { Presets } from "react-native-pulsar";
8
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
9
+ import { useKeyboardAnimationGuard } from "../../hooks/use-keyboard-state-sync";
10
+ import { BottomSheetBackground } from "./bottom-sheet-background";
4
11
  import { BottomSheetClose } from "./bottom-sheet-close";
5
12
  import { BottomSheetContainer } from "./bottom-sheet-container";
6
13
  import { BottomSheetContent } from "./bottom-sheet-content";
7
14
  import { BottomSheetDescription } from "./bottom-sheet-description";
15
+ import { BottomSheetFlatList } from "./bottom-sheet-flat-list";
8
16
  import { BottomSheetFooter } from "./bottom-sheet-footer";
17
+ import { BottomSheetHandle } from "./bottom-sheet-handle";
18
+ import { BottomSheetLegendList } from "./bottom-sheet-legend-list";
9
19
  import { BottomSheetOverlay } from "./bottom-sheet-overlay";
10
- import { BottomSheetPortal } from "./bottom-sheet-portal";
20
+ import { BottomSheetProvider } from "./bottom-sheet-provider";
11
21
  import { BottomSheetScrollView } from "./bottom-sheet-scroll-view";
22
+ import { BottomSheetSectionList } from "./bottom-sheet-section-list";
23
+ import { BottomSheetStep, BottomSheetSteps } from "./bottom-sheet-steps";
24
+ import { BottomSheetTextInput } from "./bottom-sheet-text-input";
12
25
  import { BottomSheetTitle } from "./bottom-sheet-title";
13
26
  import { BottomSheetTrigger } from "./bottom-sheet-trigger";
14
27
 
15
- export type BottomSheetProps = {
16
- children?: ReactNode;
17
- /** Controlled open state. Leave it off and the sheet holds its own. */
18
- isOpen?: boolean;
19
- /** Initial open state while uncontrolled. */
20
- defaultOpen?: boolean;
21
- /**
22
- * Called whenever the sheet opens or closes — by a trigger, a swipe down, a
23
- * press on the backdrop, `BottomSheet.Close`, or a controlled `isOpen`.
24
- *
25
- * One callback for every path, deliberately. gorhom's own `onClose` fires for
26
- * the gesture alone, which is the shape that makes a caller wire three
27
- * handlers and still miss one.
28
- */
29
- onOpenChange?: (isOpen: boolean) => void;
30
- };
28
+ /**
29
+ * Every prop the engine's root takes, with two defaults this skin fills in:
30
+ * `bottomInset` is the device's safe-area bottom unless a caller says
31
+ * otherwise, and the two haptics are the library's own.
32
+ */
33
+ export type BottomSheetProps = HeadlessBottomSheetProps;
31
34
 
32
- function BottomSheetRoot({ children, defaultOpen = false, isOpen, onOpenChange }: BottomSheetProps): ReactElement {
33
- const sheetRef = useRef<BottomSheetHandle | null>(null);
34
- const [isSheetOpen, setOpen] = useControllableState<boolean>({
35
- defaultValue: defaultOpen,
36
- onChange: onOpenChange,
37
- value: isOpen,
38
- });
35
+ /**
36
+ * The haptics the sheet plays, as module-scope worklets.
37
+ *
38
+ * Both run on the UI thread from inside the engine's pan, so they are
39
+ * `Presets.System.*` — themselves worklets — and nothing else: a JS function
40
+ * here would be `undefined is not a function` at the moment a finger crosses a
41
+ * snap point. `selection` on a snap point because that is what a picker's tick feels
42
+ * like, and `impactLight` on a close because letting go of a sheet is a
43
+ * heavier event than passing a stop, but not by much.
44
+ */
45
+ const snapPointHaptic = Presets.System.selection;
46
+ const closeHaptic = Presets.System.impactLight;
39
47
 
40
- const open = useCallback(() => setOpen(true), [setOpen]);
41
- const close = useCallback(() => setOpen(false), [setOpen]);
48
+ /**
49
+ * The engine's root with this library's defaults on it. It renders no view of
50
+ * its own.
51
+ *
52
+ * Three things happen here and nowhere else in the skin:
53
+ *
54
+ * - **`bottomInset` defaults to the safe-area bottom**, read from
55
+ * `useSafeAreaInsets()`. The engine reserves that band under the body or the
56
+ * sticky footer and gives it back to the keyboard as it arrives; a caller
57
+ * never pads for the home indicator by hand.
58
+ * - **The haptics are on by default.** Pass `onSnapPointHaptic={undefined}` to
59
+ * turn one off, or a worklet of your own to change it.
60
+ * - **The stale-keyboard guard runs on mount.** A sheet mounted while
61
+ * `KeyboardProvider`'s shared values are pinned open by a keyboard that
62
+ * vanished without a `will` event would lift for a keyboard that is not
63
+ * there; `Screen.Footer` runs the same repair for the same reason.
64
+ *
65
+ * `topInset` is left at the engine's zero, so a `%` snap point is a fraction of the
66
+ * whole window — the same fraction it was before this rewrite.
67
+ */
68
+ function BottomSheetRoot({
69
+ bottomInset,
70
+ onSnapPointHaptic = snapPointHaptic,
71
+ onCloseHaptic = closeHaptic,
72
+ ...props
73
+ }: BottomSheetProps): ReactElement {
74
+ const insets = useSafeAreaInsets();
75
+ useKeyboardAnimationGuard();
42
76
 
43
- const context = useMemo<BottomSheetContextValue>(
44
- () => ({ close, isOpen: isSheetOpen, open, setOpen, sheetRef }),
45
- [close, isSheetOpen, open, setOpen]
77
+ return (
78
+ <Headless
79
+ bottomInset={bottomInset ?? insets.bottom}
80
+ onCloseHaptic={onCloseHaptic}
81
+ onSnapPointHaptic={onSnapPointHaptic}
82
+ {...props}
83
+ />
46
84
  );
47
-
48
- return <BottomSheetProvider value={context}>{children}</BottomSheetProvider>;
49
85
  }
50
86
 
51
87
  /**
52
88
  * A panel that slides up from the bottom of the screen, over everything.
53
89
  *
54
- * The library's first overlay, built on `@gorhom/bottom-sheet`'s modal. It
55
- * renders no view of its own — it owns the open state and hands it to the parts
56
- * through context, so a trigger anywhere inside can open a sheet declared
57
- * anywhere else in the same tree.
90
+ * A thin Uniwind skin over `@delacour/react-native-bottom-sheet`: every part
91
+ * here is the engine's part with this library's classes, `Text` presets and
92
+ * `Pressable` on it. The engine owns the state, the geometry, the gestures,
93
+ * the keyboard, the portal and the accessibility; this file owns what it looks
94
+ * like.
58
95
  *
59
- * **The app must mount `DelacourProvider` at its root.** The sheet hosts itself in
60
- * the `BottomSheetModalProvider` that provider's innermost layer supplies, and it
61
- * needs the gesture root above it for the pan.
62
- *
63
- * **Two parts are not drawn where they are written.** `BottomSheet.Overlay` and a
64
- * `BottomSheet.Footer sticky` are lifted out of the tree and handed to gorhom as
65
- * render props — see `BottomSheet.Portal` and `BottomSheet.Container` for why the
66
- * anatomy is worth that. Everything else renders in place.
96
+ * **The app mounts `BottomSheetProvider` once**, inside `DelacourProvider` and
97
+ * around its navigator. `DelacourProvider` cannot do it — the engine is an
98
+ * optional peer of this library — so the provider is exported from this
99
+ * subpath for the app to place. Without it a `Portal` renders where it is
100
+ * written, which is the inline sheet.
67
101
  *
68
102
  * Controlled or not, from one hook: pass `isOpen` and `onOpenChange` to own the
69
- * state, or nothing at all and let the sheet hold it. Which mode is in play is
70
- * locked in on first render.
103
+ * state, or nothing at all and let the sheet hold it.
71
104
  *
72
105
  * @example
73
106
  * <BottomSheet>
@@ -90,12 +123,12 @@ function BottomSheetRoot({ children, defaultOpen = false, isOpen, onOpenChange }
90
123
  * </BottomSheet>
91
124
  *
92
125
  * @example
93
- * // Controlled, and opened from somewhere other than a trigger.
94
- * <BottomSheet isOpen={isOpen} onOpenChange={setOpen}>
126
+ * // Controlled, snapped, and scrolling.
127
+ * <BottomSheet dynamicSizing={false} isOpen={isOpen} onOpenChange={setOpen} snapPoints={["50%", "90%"]}>
95
128
  * <BottomSheet.Portal>
96
129
  * <BottomSheet.Overlay />
97
130
  * <BottomSheet.Container>
98
- * <BottomSheet.Content>{…}</BottomSheet.Content>
131
+ * <BottomSheet.ScrollView>{rows}</BottomSheet.ScrollView>
99
132
  * </BottomSheet.Container>
100
133
  * </BottomSheet.Portal>
101
134
  * </BottomSheet>
@@ -103,23 +136,43 @@ function BottomSheetRoot({ children, defaultOpen = false, isOpen, onOpenChange }
103
136
  export const BottomSheet = Object.assign(BottomSheetRoot, {
104
137
  /** The control that opens the sheet. `asChild` to make a `Button` the trigger. */
105
138
  Trigger: BottomSheetTrigger,
106
- /** Everything drawn above the app. Lifts the overlay out to the container. */
107
- Portal: BottomSheetPortal,
108
- /** The scrim. Written beside the container, drawn as its backdrop. */
139
+ /** Everything drawn above the app, teleported to the nearest host. `inline` to render in place. */
140
+ Portal: Headless.Portal,
141
+ /** The scrim. Omit it and the sheet has none. */
109
142
  Overlay: BottomSheetOverlay,
110
- /** The sheet itself. Every gorhom prop passes through it. */
143
+ /** The panel that moves. Brings its own `Background` and `Handle` unless you write them. */
111
144
  Container: BottomSheetContainer,
112
- /** The sheet's body, sized to itself under `enableDynamicSizing`. */
145
+ /** The panel's surface — `bg-popover`, top corners rounded, every corner when `detached`. */
146
+ Background: BottomSheetBackground,
147
+ /** The grabber's row, and the sheet's one adjustable accessibility element. */
148
+ Handle: BottomSheetHandle,
149
+ /** The static body. A sheet sized to its content is sized to this. */
113
150
  Content: BottomSheetContent,
114
- /** A scrolling body. Needs `enableDynamicSizing={false}` and snap points. */
151
+ /** A scrolling body. Sizes to its rows, capped by `maxDynamicContentSize`, or fills explicit `snapPoints`. */
115
152
  ScrollView: BottomSheetScrollView,
153
+ /** A virtualised body. */
154
+ FlatList: BottomSheetFlatList,
155
+ /** A virtualised body with sticky section headers. */
156
+ SectionList: BottomSheetSectionList,
157
+ /** A `LegendList` body. Needs the optional `@legendapp/list` peer. */
158
+ LegendList: BottomSheetLegendList,
159
+ /** Controls at the bottom. `sticky` pins them over the body and rides the keyboard. */
160
+ Footer: BottomSheetFooter,
116
161
  /** The dismiss control, positioned out of the content's flow. */
117
162
  Close: BottomSheetClose,
118
- /** The sheet's heading — a `Text.Header` with the close control's clearance. */
163
+ /** The sheet's heading — a `Text.Header` that labels the panel for a screen reader. */
119
164
  Title: BottomSheetTitle,
120
165
  /** Supporting copy under the title — a muted `Text.Paragraph`. */
121
166
  Description: BottomSheetDescription,
122
- /** Controls at the bottom. `sticky` pins them above the keyboard. */
123
- Footer: BottomSheetFooter,
167
+ /** An `Input` registered with the sheet, so the keyboard it raises is the sheet's. */
168
+ TextInput: BottomSheetTextInput,
169
+ /** A body whose contents follow a step machine and whose height glides between them. */
170
+ Steps: BottomSheetSteps,
171
+ /** One step of a `Steps` body. */
172
+ Step: BottomSheetStep,
173
+ /** A place for sheets to teleport to other than the root — the recipe for a native modal. */
174
+ Host: BottomSheetHost,
175
+ /** The engine's provider, sharing `OverlayProvider`'s teleport host. Mount it once, inside `DelacourProvider`. */
176
+ Provider: BottomSheetProvider,
124
177
  displayName: "DelacourUI.BottomSheet",
125
178
  });
@@ -1,17 +1,14 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { resolveSheetBottomInset, resolveSheetScrollEndPadding } from "@delacour/react-native-bottom-sheet/core";
2
3
  import { declaredTokens, tokenValue } from "../../styles/theme-tokens.test";
3
4
  import {
4
5
  BOTTOM_SHEET_BACKDROP_INDICES,
5
6
  BOTTOM_SHEET_CLOSE_HIT_SLOP,
6
7
  BOTTOM_SHEET_FOOTER_GAP,
7
8
  BOTTOM_SHEET_FOOTER_PADDING,
8
- BOTTOM_SHEET_KEYBOARD_DEFAULTS,
9
9
  BOTTOM_SHEET_OVERLAY_OPACITY,
10
10
  BOTTOM_SHEET_OVERLAY_TOKEN,
11
11
  bottomSheetVariants,
12
- resolveFooterPlacement,
13
- resolveSheetBottomInset,
14
- resolveSheetScrollEndPadding,
15
12
  } from "./bottom-sheet.variants";
16
13
 
17
14
  const LIGHT = declaredTokens("light");
@@ -33,6 +30,7 @@ function colorTokens(cls: string): string[] {
33
30
  }
34
31
 
35
32
  const SLOTS = bottomSheetVariants();
33
+ const DETACHED = bottomSheetVariants({ detached: true });
36
34
 
37
35
  /**
38
36
  * The slots this component declares, pinned rather than derived.
@@ -48,6 +46,8 @@ const SLOT_NAMES = [
48
46
  "handleIndicator",
49
47
  "content",
50
48
  "scrollContent",
49
+ "steps",
50
+ "step",
51
51
  "footer",
52
52
  "stickyFooter",
53
53
  "close",
@@ -82,8 +82,8 @@ describe("the overlay token", () => {
82
82
  expect(alpha).toBeLessThan(1);
83
83
  }
84
84
 
85
- // Leaving gorhom's 0.5 in place would multiply against that alpha and land
86
- // the scrim at roughly a fifth of what the theme asked for.
85
+ // Any other opacity would multiply against that alpha and land the scrim
86
+ // somewhere the theme did not ask for.
87
87
  expect(BOTTOM_SHEET_OVERLAY_OPACITY).toBe(1);
88
88
  });
89
89
 
@@ -113,90 +113,28 @@ describe("every token the slots name", () => {
113
113
 
114
114
  describe("the backdrop indices", () => {
115
115
  test("show the scrim from the first snap point and hide it only when closed", () => {
116
- // gorhom's own defaults (1 / 0) suit a persistent sheet resting collapsed
117
- // on screen. A modal sheet has no resting state.
116
+ // A modal sheet has no resting state: presented or gone.
118
117
  expect(BOTTOM_SHEET_BACKDROP_INDICES.appearsOnIndex).toBe(0);
119
118
  expect(BOTTOM_SHEET_BACKDROP_INDICES.disappearsOnIndex).toBe(-1);
120
119
  expect(BOTTOM_SHEET_BACKDROP_INDICES.disappearsOnIndex).toBeLessThan(BOTTOM_SHEET_BACKDROP_INDICES.appearsOnIndex);
121
120
  });
122
121
  });
123
122
 
124
- describe("the keyboard defaults", () => {
125
- test("follow the keyboard, restore on blur, and resize the Android window", () => {
126
- expect(BOTTOM_SHEET_KEYBOARD_DEFAULTS).toEqual({
127
- keyboardBehavior: "interactive",
128
- keyboardBlurBehavior: "restore",
129
- android_keyboardInputMode: "adjustResize",
130
- });
131
- });
132
-
133
- test("does not leave Android on gorhom's adjustPan", () => {
134
- // `adjustPan` slides the whole window up instead of resizing it, which puts
135
- // a sheet's footer off-screen. `resize` is what Expo configures and what
136
- // `KeyboardProvider` requires, so this is the value that matches reality.
137
- expect(BOTTOM_SHEET_KEYBOARD_DEFAULTS.android_keyboardInputMode).not.toBe("adjustPan");
138
- });
139
- });
140
-
141
- describe("resolveFooterPlacement", () => {
142
- const footer = (isSticky: boolean) => ({ isFooter: true, isSticky });
143
- const other = { isFooter: false, isSticky: false };
144
-
145
- test("reports none for children holding no footer", () => {
146
- expect(resolveFooterPlacement([])).toBe("none");
147
- expect(resolveFooterPlacement([other, other])).toBe("none");
148
- });
149
-
150
- test("reports inline for a footer that did not ask to be pinned", () => {
151
- expect(resolveFooterPlacement([other, footer(false)])).toBe("inline");
152
- });
153
-
154
- test("reports sticky for one that did, wherever it sits", () => {
155
- expect(resolveFooterPlacement([footer(true), other])).toBe("sticky");
156
- expect(resolveFooterPlacement([other, footer(true)])).toBe("sticky");
157
- });
158
-
159
- test("lets a single sticky footer win over an inline one", () => {
160
- // Two footers is not a state worth expressing, and the pinned one is the
161
- // one a caller meant.
162
- expect(resolveFooterPlacement([footer(false), footer(true)])).toBe("sticky");
163
- expect(resolveFooterPlacement([footer(true), footer(false)])).toBe("sticky");
164
- });
165
-
166
- test("never reads a sticky flag off a child that is not a footer", () => {
167
- expect(resolveFooterPlacement([{ isFooter: false, isSticky: true }])).toBe("none");
168
- });
169
- });
170
-
171
- describe("resolveSheetBottomInset", () => {
172
- test("gives the safe-area band to the content when nothing is pinned below it", () => {
123
+ describe("the inset helpers the engine's core exports", () => {
124
+ // They used to live here. They moved to the engine so the engine's own footer
125
+ // and body could share them; the skin re-exports them for the callers that
126
+ // imported them from `@delacour/react-native-ui/bottom-sheet`.
127
+ test("give the safe-area band to static content when nothing is pinned below it", () => {
173
128
  expect(resolveSheetBottomInset({ bottom: 34, hasStickyFooter: false })).toBe(34);
174
129
  });
175
130
 
176
- test("withholds it once a pinned footer's own box is carrying it", () => {
177
- // gorhom adds the footer's whole measured height — band included — to the
178
- // content's reserve, so asking for it here too counts it twice.
131
+ test("hold content off a pinned footer by the gap alone, never the band", () => {
132
+ // The footer's own box carries the band; the content asking for it too
133
+ // would count it twice.
179
134
  expect(resolveSheetBottomInset({ bottom: 34, hasStickyFooter: true })).toBe(0);
180
- });
181
-
182
- test("is a no-op on a device with no bottom inset", () => {
183
- expect(resolveSheetBottomInset({ bottom: 0, hasStickyFooter: false })).toBe(0);
184
- });
185
- });
186
-
187
- describe("resolveSheetScrollEndPadding", () => {
188
- test("gives the safe-area band to the content when nothing is pinned below it", () => {
189
- expect(resolveSheetScrollEndPadding({ bottom: 34, hasStickyFooter: false })).toBe(34);
190
- });
191
-
192
- test("holds the content off a pinned footer by the gap alone", () => {
193
- // The scroll view's frame already stops at the footer's top edge, so the
194
- // footer's height — band included — is not the content's to reserve.
195
- expect(resolveSheetScrollEndPadding({ bottom: 34, hasStickyFooter: true })).toBe(BOTTOM_SHEET_FOOTER_GAP);
196
- });
197
-
198
- test("keeps the gap on a device with no bottom inset", () => {
199
- expect(resolveSheetScrollEndPadding({ bottom: 0, hasStickyFooter: true })).toBe(BOTTOM_SHEET_FOOTER_GAP);
135
+ expect(
136
+ resolveSheetScrollEndPadding({ bottom: 34, footerGap: BOTTOM_SHEET_FOOTER_GAP, hasStickyFooter: true })
137
+ ).toBe(BOTTOM_SHEET_FOOTER_GAP);
200
138
  });
201
139
  });
202
140
 
@@ -228,7 +166,7 @@ describe("bottomSheetVariants slots", () => {
228
166
  expect(declared.sort()).toEqual([...SLOT_NAMES].sort());
229
167
  });
230
168
 
231
- test("the sheet's surface rounds its top corners only", () => {
169
+ test("an attached sheet's surface rounds its top corners only", () => {
232
170
  const background = SLOTS.background();
233
171
  expect(background).toMatch(/\brounded-t-/);
234
172
  expect(background).not.toMatch(/\brounded-b-/);
@@ -237,6 +175,17 @@ describe("bottomSheetVariants slots", () => {
237
175
  expect(background).not.toMatch(/\brounded-(?:none|xs|sm|md|lg|xl|2xl|3xl|full)\b/);
238
176
  });
239
177
 
178
+ test("a detached card's surface rounds every corner, and only once", () => {
179
+ const background = DETACHED.background();
180
+ // The card floats, so its bottom edge is on screen and needs the radius.
181
+ expect(background).toMatch(/\brounded-2xl\b/);
182
+ // tailwind-merge has to have replaced the top-only radius, not stacked
183
+ // beside it — two radius utilities on one view is order-dependent.
184
+ expect(background).not.toMatch(/\brounded-t-/);
185
+ // The surface itself is unchanged.
186
+ expect(colorTokens(background)).toEqual(colorTokens(SLOTS.background()));
187
+ });
188
+
240
189
  test("a pinned footer brings a surface and a line where an inline one does not", () => {
241
190
  // It draws OVER the content, so without them the content scrolls straight
242
191
  // through it. An inline footer is in the flow and needs neither.
@@ -246,10 +195,10 @@ describe("bottomSheetVariants slots", () => {
246
195
  expect(SLOTS.footer()).not.toMatch(/\bborder-t\b/);
247
196
  });
248
197
 
249
- test("a pinned footer writes its vertical padding as a style, never a class", () => {
250
- // The bottom padding is animated — the safe-area band collapses into it as
251
- // the keyboard arrives — and a class cannot carry an animated value. The
252
- // top is written the same way so the two cannot drift.
198
+ test("a pinned footer writes its vertical padding as the engine's prop, never a class", () => {
199
+ // The engine measures the footer's inner box into the sheet's height, and
200
+ // padding handed to its `padding` prop lands on that box. A class on the
201
+ // outer view would be height the snap point never counts.
253
202
  expect(SLOTS.stickyFooter()).not.toMatch(/\bp[tby]?-[\d.]+\b/);
254
203
  expect(BOTTOM_SHEET_FOOTER_PADDING).toBeGreaterThan(0);
255
204
  });
@@ -273,9 +222,20 @@ describe("bottomSheetVariants slots", () => {
273
222
  expect(SLOTS.scrollContent()).toMatch(/\bpx-screen-gutter\b/);
274
223
  });
275
224
 
225
+ test("a multi-step body keeps the gutter on the stack and the vertical padding on each step", () => {
226
+ // The engine measures each `Step`, not the box around the stack, so
227
+ // vertical padding on `steps` would be height the sheet never counts.
228
+ expect(SLOTS.steps()).toMatch(/\bpx-screen-gutter\b/);
229
+ expect(SLOTS.steps()).not.toMatch(/\bp[tby]-[\d.]+\b/);
230
+ expect(SLOTS.step()).not.toMatch(/\bpx-/);
231
+ // A step reads like static content: same gap, same top padding.
232
+ expect(SLOTS.step().match(/\bgap-[\d.]+\b/)?.[0]).toBe(SLOTS.content().match(/\bgap-[\d.]+\b/)?.[0]);
233
+ expect(SLOTS.step().match(/\bpt-[\d.]+\b/)?.[0]).toBe(SLOTS.content().match(/\bpt-[\d.]+\b/)?.[0]);
234
+ });
235
+
276
236
  test("the overlay sets no opacity of its own", () => {
277
- // gorhom animates the scrim's opacity off the sheet's position; a class here
278
- // would be a second writer of the same style property.
237
+ // The engine animates the scrim's opacity off the sheet's index; a class
238
+ // here would be a second writer of the same style property.
279
239
  expect(SLOTS.overlay()).not.toMatch(/\bopacity-\d/);
280
240
  });
281
241