@multiplatform.one/components 7.6.3 → 7.7.1

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 (413) hide show
  1. package/dist/cjs/Accordion/index.native.js +1 -1
  2. package/dist/cjs/Accordion/index.native.js.map +1 -1
  3. package/dist/cjs/Alert/index.cjs +13 -29
  4. package/dist/cjs/Alert/index.native.js +17 -37
  5. package/dist/cjs/Alert/index.native.js.map +1 -1
  6. package/dist/cjs/AnimateHeight/index.native.js.map +1 -1
  7. package/dist/cjs/Avatar/getInitials.native.js.map +1 -1
  8. package/dist/cjs/Avatar/index.native.js.map +1 -1
  9. package/dist/cjs/Badge/index.cjs +4 -3
  10. package/dist/cjs/Badge/index.native.js +7 -6
  11. package/dist/cjs/Badge/index.native.js.map +1 -1
  12. package/dist/cjs/Button.native.js.map +1 -1
  13. package/dist/cjs/Card.cjs +1 -9
  14. package/dist/cjs/Card.native.js +2 -7
  15. package/dist/cjs/Card.native.js.map +1 -1
  16. package/dist/cjs/CardFooter.cjs +1 -9
  17. package/dist/cjs/CardFooter.native.js +2 -7
  18. package/dist/cjs/CardFooter.native.js.map +1 -1
  19. package/dist/cjs/CardHeader.cjs +1 -9
  20. package/dist/cjs/CardHeader.native.js +2 -7
  21. package/dist/cjs/CardHeader.native.js.map +1 -1
  22. package/dist/cjs/Carousel/index.native.js +1 -1
  23. package/dist/cjs/Carousel/index.native.js.map +1 -1
  24. package/dist/cjs/Chip/index.native.js.map +1 -1
  25. package/dist/cjs/ContextMenu/index.native.js.map +1 -1
  26. package/dist/cjs/CopyField/index.native.js.map +1 -1
  27. package/dist/cjs/DotIndicator/index.native.js.map +1 -1
  28. package/dist/cjs/DropdownMenu/index.native.js.map +1 -1
  29. package/dist/cjs/ErrorBoundary/index.native.js.map +1 -1
  30. package/dist/cjs/Heading.native.js.map +1 -1
  31. package/dist/cjs/Meter/index.native.js +1 -1
  32. package/dist/cjs/Meter/index.native.js.map +1 -1
  33. package/dist/cjs/Meter/meter.native.js.map +1 -1
  34. package/dist/cjs/Pagination.native.js +1 -1
  35. package/dist/cjs/Pagination.native.js.map +1 -1
  36. package/dist/cjs/ProgressSteps/index.cjs +13 -6
  37. package/dist/cjs/ProgressSteps/index.native.js +14 -6
  38. package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
  39. package/dist/cjs/Quote/index.native.js.map +1 -1
  40. package/dist/cjs/Separator/index.native.js.map +1 -1
  41. package/dist/cjs/SheetModal/detents.cjs +46 -0
  42. package/dist/cjs/SheetModal/detents.native.js +54 -0
  43. package/dist/cjs/SheetModal/detents.native.js.map +1 -0
  44. package/dist/cjs/SheetModal/index.native.js +8 -11
  45. package/dist/cjs/SheetModal/index.native.js.map +1 -1
  46. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  47. package/dist/cjs/SkipLink/index.native.js.map +1 -1
  48. package/dist/cjs/SortableList/SortableHandle.native.js.map +1 -1
  49. package/dist/cjs/SortableList/index.cjs +1 -1
  50. package/dist/cjs/SortableList/index.native.js +1 -1
  51. package/dist/cjs/SortableList/index.native.js.map +1 -1
  52. package/dist/cjs/SortableList/useSortableRows.native.js.map +1 -1
  53. package/dist/cjs/Tabs/index.native.js.map +1 -1
  54. package/dist/cjs/Text.native.js.map +1 -1
  55. package/dist/cjs/Toast/index.native.js.map +1 -1
  56. package/dist/cjs/Toast/store.native.js.map +1 -1
  57. package/dist/cjs/Tooltip/nativePress.native.js.map +1 -1
  58. package/dist/cjs/Tooltip/tooltipShared.native.js.map +1 -1
  59. package/dist/cjs/TreeSelect/index.native.js +1 -1
  60. package/dist/cjs/TreeSelect/index.native.js.map +1 -1
  61. package/dist/cjs/TreeSelect/treeSelectModel.native.js.map +1 -1
  62. package/dist/cjs/Video/PlayerChrome.native.js.map +1 -1
  63. package/dist/cjs/Video/VideoFrame.native.js.map +1 -1
  64. package/dist/cjs/Video/types.native.js.map +1 -1
  65. package/dist/cjs/Wheel/index.native.js.map +1 -1
  66. package/dist/cjs/Wizard/index.native.js +2 -2
  67. package/dist/cjs/Wizard/index.native.js.map +1 -1
  68. package/dist/cjs/actions/ActionBar.cjs +3 -1
  69. package/dist/cjs/actions/ActionBar.native.js +11 -2
  70. package/dist/cjs/actions/ActionBar.native.js.map +1 -1
  71. package/dist/cjs/actions/DestructiveAction.native.js.map +1 -1
  72. package/dist/cjs/actions/devWarn.native.js.map +1 -1
  73. package/dist/cjs/actions/index.native.js.map +1 -1
  74. package/dist/cjs/actions/severity.native.js.map +1 -1
  75. package/dist/cjs/charts/Axis.native.js.map +1 -1
  76. package/dist/cjs/charts/BarChart.native.js.map +1 -1
  77. package/dist/cjs/charts/ChartSurface.native.js.map +1 -1
  78. package/dist/cjs/charts/LineChart.native.js.map +1 -1
  79. package/dist/cjs/charts/PieChart.native.js.map +1 -1
  80. package/dist/cjs/charts/Sparkline.native.js.map +1 -1
  81. package/dist/cjs/charts/accessibility.native.js.map +1 -1
  82. package/dist/cjs/charts/composeChart.native.js.map +1 -1
  83. package/dist/cjs/charts/index.native.js.map +1 -1
  84. package/dist/cjs/charts/math.native.js.map +1 -1
  85. package/dist/cjs/charts/series.native.js.map +1 -1
  86. package/dist/cjs/charts/svg.native.js.map +1 -1
  87. package/dist/cjs/charts/types.native.js.map +1 -1
  88. package/dist/cjs/charts/useChartTheme.native.js.map +1 -1
  89. package/dist/cjs/code/Code/index.cjs +2 -15
  90. package/dist/cjs/code/Code/index.native.js +3 -13
  91. package/dist/cjs/code/Code/index.native.js.map +1 -1
  92. package/dist/cjs/code/CodeBlock/index.native.js +6 -6
  93. package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
  94. package/dist/cjs/code/HighlightedCode/index.cjs +0 -5
  95. package/dist/cjs/code/HighlightedCode/index.native.js +0 -5
  96. package/dist/cjs/code/HighlightedCode/index.native.js.map +1 -1
  97. package/dist/cjs/code/Highlighter/index.native.js.map +1 -1
  98. package/dist/cjs/code/Pre/index.native.js.map +1 -1
  99. package/dist/cjs/code/index.native.js +5 -5
  100. package/dist/cjs/code/index.native.js.map +1 -1
  101. package/dist/cjs/componentColors.native.js.map +1 -1
  102. package/dist/cjs/feedback/ConfirmDialog.native.js.map +1 -1
  103. package/dist/cjs/feedback/NotifyHost.native.js +2 -2
  104. package/dist/cjs/feedback/NotifyHost.native.js.map +1 -1
  105. package/dist/cjs/feedback/copy.native.js.map +1 -1
  106. package/dist/cjs/feedback/index.native.js.map +1 -1
  107. package/dist/cjs/feedback/notify.native.js.map +1 -1
  108. package/dist/cjs/feedback/route.native.js.map +1 -1
  109. package/dist/cjs/feedback/store.native.js.map +1 -1
  110. package/dist/cjs/hooks/index.native.js +1 -1
  111. package/dist/cjs/hooks/index.native.js.map +1 -1
  112. package/dist/cjs/hooks/useClipboard.native.js.map +1 -1
  113. package/dist/cjs/hooks/useDocumentTitle.native.js.map +1 -1
  114. package/dist/cjs/icons/CheckRegular.native.js.map +1 -1
  115. package/dist/cjs/icons/MinusRegular.native.js.map +1 -1
  116. package/dist/cjs/icons/index.native.js.map +1 -1
  117. package/dist/cjs/icons/lucide.native.js.map +1 -1
  118. package/dist/cjs/icons/themed.native.js.map +1 -1
  119. package/dist/cjs/images/Image/ImageFrame.native.js +1 -1
  120. package/dist/cjs/images/Image/ImageFrame.native.js.map +1 -1
  121. package/dist/cjs/images/Image/index.native.js +1 -1
  122. package/dist/cjs/images/Image/shared.native.js +1 -1
  123. package/dist/cjs/images/Image/shared.native.js.map +1 -1
  124. package/dist/cjs/images/Image/types.native.js.map +1 -1
  125. package/dist/cjs/images/index.native.js.map +1 -1
  126. package/dist/cjs/index.native.js +29 -29
  127. package/dist/cjs/index.native.js.map +1 -1
  128. package/dist/cjs/knobImmuneExports.cjs +8 -0
  129. package/dist/cjs/knobImmuneExports.native.js +8 -0
  130. package/dist/cjs/knobImmuneExports.native.js.map +1 -1
  131. package/dist/cjs/layouts/AsyncBoundary.native.js +2 -2
  132. package/dist/cjs/layouts/AsyncBoundary.native.js.map +1 -1
  133. package/dist/cjs/layouts/Debug/index.native.js.map +1 -1
  134. package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
  135. package/dist/cjs/layouts/KeyboardAvoidingWrapper/behavior.native.js.map +1 -1
  136. package/dist/cjs/layouts/PageTemplates.native.js.map +1 -1
  137. package/dist/cjs/layouts/PaneScaffold.native.js.map +1 -1
  138. package/dist/cjs/layouts/SafeAreaWrapper/insets.native.js.map +1 -1
  139. package/dist/cjs/layouts/ViewSwitcher.native.js.map +1 -1
  140. package/dist/cjs/layouts/attachments.native.js +1 -1
  141. package/dist/cjs/layouts/attachments.native.js.map +1 -1
  142. package/dist/cjs/layouts/breadcrumbs.cjs +3 -1
  143. package/dist/cjs/layouts/breadcrumbs.native.js +3 -1
  144. package/dist/cjs/layouts/breadcrumbs.native.js.map +1 -1
  145. package/dist/cjs/layouts/index.native.js +3 -3
  146. package/dist/cjs/layouts/index.native.js.map +1 -1
  147. package/dist/cjs/layouts/page.native.js.map +1 -1
  148. package/dist/cjs/layouts/pageHeadingScope.native.js.map +1 -1
  149. package/dist/cjs/layouts/sidebar.native.js.map +1 -1
  150. package/dist/cjs/layouts/tags.native.js +1 -1
  151. package/dist/cjs/layouts/tags.native.js.map +1 -1
  152. package/dist/cjs/layouts/timeline.native.js +2 -2
  153. package/dist/cjs/layouts/timeline.native.js.map +1 -1
  154. package/dist/cjs/layouts/toolbar.native.js.map +1 -1
  155. package/dist/cjs/shared/actionScan.native.js.map +1 -1
  156. package/dist/cjs/shared/i18n.native.js.map +1 -1
  157. package/dist/cjs/shared/t.native.js.map +1 -1
  158. package/dist/cjs/shared/textRidesText.native.js.map +1 -1
  159. package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
  160. package/dist/cjs/shared/useReturnFocusOnClose.native.js.map +1 -1
  161. package/dist/cjs/surfaces.native.js +1 -1
  162. package/dist/cjs/surfaces.native.js.map +1 -1
  163. package/dist/cjs/tamagui.cjs +5 -0
  164. package/dist/cjs/tamagui.native.js +5 -0
  165. package/dist/cjs/tamagui.native.js.map +1 -1
  166. package/dist/cjs/testSetup.native.js.map +1 -1
  167. package/dist/cjs/utils/setTinted.native.js.map +1 -1
  168. package/dist/cjs/utils/unwrapText.native.js.map +1 -1
  169. package/dist/cjs/views/Calendar.native.js.map +1 -1
  170. package/dist/cjs/views/Dashboard.cjs +3 -3
  171. package/dist/cjs/views/Dashboard.native.js +4 -4
  172. package/dist/cjs/views/Dashboard.native.js.map +1 -1
  173. package/dist/cjs/views/Gantt.native.js +1 -1
  174. package/dist/cjs/views/Gantt.native.js.map +1 -1
  175. package/dist/cjs/views/ImageGrid.native.js +1 -1
  176. package/dist/cjs/views/ImageGrid.native.js.map +1 -1
  177. package/dist/cjs/views/List.cjs +4 -5
  178. package/dist/cjs/views/List.native.js +4 -5
  179. package/dist/cjs/views/List.native.js.map +1 -1
  180. package/dist/cjs/views/ReportBuilder.native.js +1 -1
  181. package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
  182. package/dist/cjs/views/TreeView.cjs +4 -1
  183. package/dist/cjs/views/TreeView.native.js +3 -0
  184. package/dist/cjs/views/TreeView.native.js.map +1 -1
  185. package/dist/cjs/views/calendarMath.native.js.map +1 -1
  186. package/dist/cjs/views/ganttMath.native.js.map +1 -1
  187. package/dist/cjs/views/index.native.js +1 -1
  188. package/dist/cjs/views/index.native.js.map +1 -1
  189. package/dist/cjs/views/kanbanDnd.native.js.map +1 -1
  190. package/dist/cjs/views/treeViewDnd.native.js.map +1 -1
  191. package/dist/cjs/views/treeViewLayout.native.js.map +1 -1
  192. package/dist/cjs/views/treeViewMotion.native.js.map +1 -1
  193. package/dist/esm/Alert/index.mjs +14 -31
  194. package/dist/esm/Alert/index.mjs.map +1 -1
  195. package/dist/esm/Alert/index.native.js +36 -57
  196. package/dist/esm/Alert/index.native.js.map +1 -1
  197. package/dist/esm/Badge/index.mjs +4 -3
  198. package/dist/esm/Badge/index.mjs.map +1 -1
  199. package/dist/esm/Badge/index.native.js +7 -6
  200. package/dist/esm/Badge/index.native.js.map +1 -1
  201. package/dist/esm/Card.mjs +3 -11
  202. package/dist/esm/Card.mjs.map +1 -1
  203. package/dist/esm/Card.native.js +7 -12
  204. package/dist/esm/Card.native.js.map +1 -1
  205. package/dist/esm/CardFooter.mjs +3 -11
  206. package/dist/esm/CardFooter.mjs.map +1 -1
  207. package/dist/esm/CardFooter.native.js +6 -11
  208. package/dist/esm/CardFooter.native.js.map +1 -1
  209. package/dist/esm/CardHeader.mjs +3 -11
  210. package/dist/esm/CardHeader.mjs.map +1 -1
  211. package/dist/esm/CardHeader.native.js +6 -11
  212. package/dist/esm/CardHeader.native.js.map +1 -1
  213. package/dist/esm/ProgressSteps/index.mjs +14 -7
  214. package/dist/esm/ProgressSteps/index.mjs.map +1 -1
  215. package/dist/esm/ProgressSteps/index.native.js +15 -7
  216. package/dist/esm/ProgressSteps/index.native.js.map +1 -1
  217. package/dist/esm/SheetModal/detents.mjs +19 -0
  218. package/dist/esm/SheetModal/detents.mjs.map +1 -0
  219. package/dist/esm/SheetModal/detents.native.js +24 -0
  220. package/dist/esm/SheetModal/detents.native.js.map +1 -0
  221. package/dist/esm/SheetModal/index.mjs.map +1 -1
  222. package/dist/esm/SheetModal/index.native.js +7 -10
  223. package/dist/esm/SheetModal/index.native.js.map +1 -1
  224. package/dist/esm/SortableList/index.mjs +1 -1
  225. package/dist/esm/SortableList/index.mjs.map +1 -1
  226. package/dist/esm/SortableList/index.native.js +1 -1
  227. package/dist/esm/SortableList/index.native.js.map +1 -1
  228. package/dist/esm/actions/ActionBar.mjs +6 -4
  229. package/dist/esm/actions/ActionBar.mjs.map +1 -1
  230. package/dist/esm/actions/ActionBar.native.js +13 -4
  231. package/dist/esm/actions/ActionBar.native.js.map +1 -1
  232. package/dist/esm/code/Code/index.mjs +2 -15
  233. package/dist/esm/code/Code/index.mjs.map +1 -1
  234. package/dist/esm/code/Code/index.native.js +6 -16
  235. package/dist/esm/code/Code/index.native.js.map +1 -1
  236. package/dist/esm/code/HighlightedCode/index.mjs +0 -5
  237. package/dist/esm/code/HighlightedCode/index.mjs.map +1 -1
  238. package/dist/esm/code/HighlightedCode/index.native.js +0 -5
  239. package/dist/esm/code/HighlightedCode/index.native.js.map +1 -1
  240. package/dist/esm/knobImmuneExports.mjs +8 -0
  241. package/dist/esm/knobImmuneExports.mjs.map +1 -1
  242. package/dist/esm/knobImmuneExports.native.js +8 -0
  243. package/dist/esm/knobImmuneExports.native.js.map +1 -1
  244. package/dist/esm/layouts/breadcrumbs.mjs +3 -1
  245. package/dist/esm/layouts/breadcrumbs.mjs.map +1 -1
  246. package/dist/esm/layouts/breadcrumbs.native.js +3 -1
  247. package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
  248. package/dist/esm/tamagui.mjs +3 -2
  249. package/dist/esm/tamagui.mjs.map +1 -1
  250. package/dist/esm/tamagui.native.js +3 -2
  251. package/dist/esm/tamagui.native.js.map +1 -1
  252. package/dist/esm/views/Dashboard.mjs +3 -3
  253. package/dist/esm/views/Dashboard.mjs.map +1 -1
  254. package/dist/esm/views/Dashboard.native.js +3 -3
  255. package/dist/esm/views/Dashboard.native.js.map +1 -1
  256. package/dist/esm/views/List.mjs +4 -5
  257. package/dist/esm/views/List.mjs.map +1 -1
  258. package/dist/esm/views/List.native.js +4 -5
  259. package/dist/esm/views/List.native.js.map +1 -1
  260. package/dist/esm/views/TreeView.mjs +4 -1
  261. package/dist/esm/views/TreeView.mjs.map +1 -1
  262. package/dist/esm/views/TreeView.native.js +3 -0
  263. package/dist/esm/views/TreeView.native.js.map +1 -1
  264. package/dist/jsx/Alert/index.mjs +14 -31
  265. package/dist/jsx/Alert/index.mjs.map +1 -1
  266. package/dist/jsx/Alert/index.native.js +17 -37
  267. package/dist/jsx/Alert/index.native.js.map +1 -1
  268. package/dist/jsx/Badge/index.mjs +4 -3
  269. package/dist/jsx/Badge/index.mjs.map +1 -1
  270. package/dist/jsx/Badge/index.native.js +7 -6
  271. package/dist/jsx/Badge/index.native.js.map +1 -1
  272. package/dist/jsx/Card.mjs +3 -11
  273. package/dist/jsx/Card.mjs.map +1 -1
  274. package/dist/jsx/Card.native.js +2 -7
  275. package/dist/jsx/Card.native.js.map +1 -1
  276. package/dist/jsx/CardFooter.mjs +3 -11
  277. package/dist/jsx/CardFooter.mjs.map +1 -1
  278. package/dist/jsx/CardFooter.native.js +2 -7
  279. package/dist/jsx/CardFooter.native.js.map +1 -1
  280. package/dist/jsx/CardHeader.mjs +3 -11
  281. package/dist/jsx/CardHeader.mjs.map +1 -1
  282. package/dist/jsx/CardHeader.native.js +2 -7
  283. package/dist/jsx/CardHeader.native.js.map +1 -1
  284. package/dist/jsx/ProgressSteps/index.mjs +14 -7
  285. package/dist/jsx/ProgressSteps/index.mjs.map +1 -1
  286. package/dist/jsx/ProgressSteps/index.native.js +14 -6
  287. package/dist/jsx/ProgressSteps/index.native.js.map +1 -1
  288. package/dist/jsx/SheetModal/detents.mjs +19 -0
  289. package/dist/jsx/SheetModal/detents.mjs.map +1 -0
  290. package/dist/jsx/SheetModal/detents.native.js +54 -0
  291. package/dist/jsx/SheetModal/detents.native.js.map +1 -0
  292. package/dist/jsx/SheetModal/index.mjs.map +1 -1
  293. package/dist/jsx/SheetModal/index.native.js +8 -11
  294. package/dist/jsx/SheetModal/index.native.js.map +1 -1
  295. package/dist/jsx/SortableList/index.mjs +1 -1
  296. package/dist/jsx/SortableList/index.mjs.map +1 -1
  297. package/dist/jsx/SortableList/index.native.js +1 -1
  298. package/dist/jsx/SortableList/index.native.js.map +1 -1
  299. package/dist/jsx/actions/ActionBar.mjs +6 -4
  300. package/dist/jsx/actions/ActionBar.mjs.map +1 -1
  301. package/dist/jsx/actions/ActionBar.native.js +11 -2
  302. package/dist/jsx/actions/ActionBar.native.js.map +1 -1
  303. package/dist/jsx/code/Code/index.mjs +2 -15
  304. package/dist/jsx/code/Code/index.mjs.map +1 -1
  305. package/dist/jsx/code/Code/index.native.js +3 -13
  306. package/dist/jsx/code/Code/index.native.js.map +1 -1
  307. package/dist/jsx/code/CodeBlock/index.native.js +1 -1
  308. package/dist/jsx/code/HighlightedCode/index.mjs +0 -5
  309. package/dist/jsx/code/HighlightedCode/index.mjs.map +1 -1
  310. package/dist/jsx/code/HighlightedCode/index.native.js +0 -5
  311. package/dist/jsx/code/HighlightedCode/index.native.js.map +1 -1
  312. package/dist/jsx/code/index.native.js +1 -1
  313. package/dist/jsx/feedback/NotifyHost.native.js +1 -1
  314. package/dist/jsx/index.native.js +1 -1
  315. package/dist/jsx/knobImmuneExports.mjs +8 -0
  316. package/dist/jsx/knobImmuneExports.mjs.map +1 -1
  317. package/dist/jsx/knobImmuneExports.native.js +8 -0
  318. package/dist/jsx/knobImmuneExports.native.js.map +1 -1
  319. package/dist/jsx/layouts/AsyncBoundary.native.js +1 -1
  320. package/dist/jsx/layouts/AsyncBoundary.native.js.map +1 -1
  321. package/dist/jsx/layouts/breadcrumbs.mjs +3 -1
  322. package/dist/jsx/layouts/breadcrumbs.mjs.map +1 -1
  323. package/dist/jsx/layouts/breadcrumbs.native.js +3 -1
  324. package/dist/jsx/layouts/breadcrumbs.native.js.map +1 -1
  325. package/dist/jsx/tamagui.mjs +3 -2
  326. package/dist/jsx/tamagui.mjs.map +1 -1
  327. package/dist/jsx/tamagui.native.js +5 -0
  328. package/dist/jsx/tamagui.native.js.map +1 -1
  329. package/dist/jsx/views/Dashboard.mjs +3 -3
  330. package/dist/jsx/views/Dashboard.mjs.map +1 -1
  331. package/dist/jsx/views/Dashboard.native.js +3 -3
  332. package/dist/jsx/views/Dashboard.native.js.map +1 -1
  333. package/dist/jsx/views/List.mjs +4 -5
  334. package/dist/jsx/views/List.mjs.map +1 -1
  335. package/dist/jsx/views/List.native.js +4 -5
  336. package/dist/jsx/views/List.native.js.map +1 -1
  337. package/dist/jsx/views/TreeView.mjs +4 -1
  338. package/dist/jsx/views/TreeView.mjs.map +1 -1
  339. package/dist/jsx/views/TreeView.native.js +3 -0
  340. package/dist/jsx/views/TreeView.native.js.map +1 -1
  341. package/package.json +9 -9
  342. package/src/Alert/index.tsx +9 -4
  343. package/src/AnimateHeight/AnimateHeight.stories.spec.tsx +37 -0
  344. package/src/AnimateHeight/AnimateHeight.stories.tsx +95 -0
  345. package/src/Avatar/Avatar.spec.tsx +4 -1
  346. package/src/Badge/Badge.spec.tsx +10 -11
  347. package/src/Badge/index.tsx +7 -6
  348. package/src/Button.spec.tsx +26 -15
  349. package/src/Card.tsx +8 -3
  350. package/src/CardFooter.spec.tsx +1 -1
  351. package/src/CardFooter.tsx +6 -3
  352. package/src/CardHeader.spec.tsx +1 -1
  353. package/src/CardHeader.tsx +6 -3
  354. package/src/Chip/Chip.spec.tsx +1 -1
  355. package/src/Pagination.spec.tsx +1 -1
  356. package/src/ProgressSteps/ProgressSteps.spec.tsx +29 -2
  357. package/src/ProgressSteps/index.tsx +21 -7
  358. package/src/SheetModal/SheetModal.spec.tsx +88 -0
  359. package/src/SheetModal/SheetModal.stories.spec.tsx +54 -0
  360. package/src/SheetModal/SheetModal.stories.tsx +109 -0
  361. package/src/SheetModal/detents.ts +55 -0
  362. package/src/SheetModal/index.native.tsx +13 -12
  363. package/src/SheetModal/index.tsx +5 -2
  364. package/src/Skeleton/Skeleton.spec.tsx +1 -1
  365. package/src/SortableList/SortableList.spec.tsx +41 -0
  366. package/src/SortableList/SortableList.stories.tsx +35 -2
  367. package/src/SortableList/index.tsx +1 -1
  368. package/src/TreeSelect/TreeSelect.stories.tsx +76 -1
  369. package/src/Wheel/Wheel.spec.tsx +1 -1
  370. package/src/actions/ActionBar.stories.spec.tsx +45 -0
  371. package/src/actions/ActionBar.stories.tsx +161 -0
  372. package/src/actions/ActionBar.tsx +8 -1
  373. package/src/charts/Axis.stories.spec.tsx +86 -0
  374. package/src/charts/Axis.stories.tsx +186 -0
  375. package/src/charts/ChartSurface.stories.spec.tsx +43 -0
  376. package/src/charts/ChartSurface.stories.tsx +148 -0
  377. package/src/code/Code/code.spec.tsx +27 -1
  378. package/src/code/Code/index.tsx +9 -2
  379. package/src/code/HighlightedCode/index.tsx +0 -1
  380. package/src/code/highlightedCode.spec.tsx +10 -1
  381. package/src/knobImmuneExports.ts +11 -0
  382. package/src/layouts/AsyncBoundary.spec.tsx +1 -1
  383. package/src/layouts/breadcrumbs.spec.tsx +17 -0
  384. package/src/layouts/breadcrumbs.tsx +19 -2
  385. package/src/layouts/tags.r7.spec.tsx +3 -1
  386. package/src/tamagui.ts +8 -0
  387. package/src/views/Dashboard.tsx +3 -3
  388. package/src/views/List.spec.tsx +42 -1
  389. package/src/views/List.tsx +6 -5
  390. package/src/views/TreeView.spec.tsx +26 -0
  391. package/src/views/TreeView.tsx +3 -0
  392. package/types/Alert/index.d.ts.map +1 -1
  393. package/types/Badge/index.d.ts.map +1 -1
  394. package/types/Card.d.ts.map +1 -1
  395. package/types/CardFooter.d.ts.map +1 -1
  396. package/types/CardHeader.d.ts.map +1 -1
  397. package/types/ProgressSteps/index.d.ts.map +1 -1
  398. package/types/SheetModal/detents.d.ts +38 -0
  399. package/types/SheetModal/detents.d.ts.map +1 -0
  400. package/types/SheetModal/index.d.ts +1 -1
  401. package/types/SheetModal/index.d.ts.map +1 -1
  402. package/types/SheetModal/index.native.d.ts +1 -1
  403. package/types/SheetModal/index.native.d.ts.map +1 -1
  404. package/types/actions/ActionBar.d.ts.map +1 -1
  405. package/types/code/Code/index.d.ts.map +1 -1
  406. package/types/code/HighlightedCode/index.d.ts.map +1 -1
  407. package/types/knobImmuneExports.d.ts.map +1 -1
  408. package/types/layouts/breadcrumbs.d.ts +7 -1
  409. package/types/layouts/breadcrumbs.d.ts.map +1 -1
  410. package/types/tamagui.d.ts +3 -1
  411. package/types/tamagui.d.ts.map +1 -1
  412. package/types/views/List.d.ts.map +1 -1
  413. package/types/views/TreeView.d.ts.map +1 -1
@@ -14,16 +14,19 @@ import { wrapBareTextChildren } from "./shared/textRidesText";
14
14
  export type CardFooterProps = ViewProps & { children?: ReactNode };
15
15
 
16
16
  /**
17
- * Tamagui styled hosts drop JSX `data-*` (Toast gallery hole). RN-web reads
18
- * `dataSet`; jsdom still accepts the kebab attributes. Write both.
17
+ * Tamagui styled hosts drop JSX `data-*` on native (Toast gallery hole), so
18
+ * native needs the RN `dataSet` map. On web, spreading `dataSet` onto a DOM
19
+ * host is a React invalid-prop warning (`dataSet` → `dataset`). jsdom and
20
+ * Storybook keep kebab `data-*`, so web writes those only.
19
21
  */
20
22
  function hostData(attrs: Record<string, string>): Record<string, unknown> {
23
+ if (process.env.TAMAGUI_TARGET !== "native") return attrs;
21
24
  const dataSet: Record<string, string> = {};
22
25
  for (const [key, value] of Object.entries(attrs)) {
23
26
  const camel = key.replace(/^data-/, "").replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
24
27
  dataSet[camel] = value;
25
28
  }
26
- return { ...attrs, dataSet };
29
+ return { dataSet };
27
30
  }
28
31
 
29
32
  export function CardFooter({ children, ...props }: CardFooterProps) {
@@ -28,7 +28,7 @@ describe("CardHeader named exports", () => {
28
28
  expect(Card.Header).toBe(CardHeader);
29
29
  const mod = await import("./CardHeader");
30
30
  expect(mod.CardHeader).toBe(CardHeader);
31
- expect(mod.default).toBeUndefined();
31
+ expect("default" in mod).toBe(false);
32
32
  });
33
33
  });
34
34
 
@@ -14,16 +14,19 @@ import { wrapBareTextChildren } from "./shared/textRidesText";
14
14
  export type CardHeaderProps = ViewProps & { children?: ReactNode };
15
15
 
16
16
  /**
17
- * Tamagui styled hosts drop JSX `data-*` (Toast gallery hole). RN-web reads
18
- * `dataSet`; jsdom still accepts the kebab attributes. Write both.
17
+ * Tamagui styled hosts drop JSX `data-*` on native (Toast gallery hole), so
18
+ * native needs the RN `dataSet` map. On web, spreading `dataSet` onto a DOM
19
+ * host is a React invalid-prop warning (`dataSet` → `dataset`). jsdom and
20
+ * Storybook keep kebab `data-*`, so web writes those only.
19
21
  */
20
22
  function hostData(attrs: Record<string, string>): Record<string, unknown> {
23
+ if (process.env.TAMAGUI_TARGET !== "native") return attrs;
21
24
  const dataSet: Record<string, string> = {};
22
25
  for (const [key, value] of Object.entries(attrs)) {
23
26
  const camel = key.replace(/^data-/, "").replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
24
27
  dataSet[camel] = value;
25
28
  }
26
- return { ...attrs, dataSet };
29
+ return { dataSet };
27
30
  }
28
31
 
29
32
  export function CardHeader({ children, ...props }: CardHeaderProps) {
@@ -150,7 +150,7 @@ describe("Chip", () => {
150
150
  expect(mod.chipTone).toBe(chipTone);
151
151
  expect(typeof mod.chipIconSize).toBe("function");
152
152
  expect(chipIconSize("$3")).toBeGreaterThan(0);
153
- expect(mod.default).toBeUndefined();
153
+ expect("default" in mod).toBe(false);
154
154
  });
155
155
 
156
156
  it("label TEXT NODE weight is 400, never 500/600", () => {
@@ -163,7 +163,7 @@ describe("Pagination design-law (MPO-60)", () => {
163
163
  const mod = await import("./Pagination");
164
164
  expect(mod.Pagination).toBe(Pagination);
165
165
  expect(mod.getPaginationItems).toBeTypeOf("function");
166
- expect(mod.default).toBeUndefined();
166
+ expect("default" in mod).toBe(false);
167
167
  });
168
168
 
169
169
  it("LC-68: animation none publishes data-animation=none (no quick fallback)", () => {
@@ -52,6 +52,18 @@ describe("ProgressSteps", () => {
52
52
  expect(current.className).toContain("_bg-accentBackg");
53
53
  });
54
54
 
55
+ it("walks the current fill off the dark mid-solid so the numeral can clear 4.5", () => {
56
+ const { container } = render(
57
+ <TamaguiProvider config={houseConfig} defaultTheme="dark" disableInjectCSS>
58
+ <ProgressSteps steps={steps} current={1} />
59
+ </TamaguiProvider>,
60
+ );
61
+ const current = container.querySelector('[aria-current="step"]') as HTMLElement;
62
+ expect(current).toBeTruthy();
63
+ expect(current.className).toMatch(/_bg-accent/);
64
+ expect(current.className).not.toContain("_bg-accentBackg");
65
+ });
66
+
55
67
  it("calls onStepChange when jumping back to a completed step", () => {
56
68
  const onStepChange = vi.fn();
57
69
  const { container } = renderWithProviders(
@@ -110,10 +122,25 @@ describe("ProgressSteps", () => {
110
122
  expect(target.getAttribute("data-press-min")).toBe("44");
111
123
  });
112
124
 
113
- it("steps nested marker size down under compact density", () => {
125
+ it("declares the marker R-PILL and tracks the borderWidth knob for the ring", () => {
126
+ const { container } = renderWithProviders(<ProgressSteps steps={steps} current={1} />);
127
+ const marker = container.querySelector("[data-nested-px]") as HTMLElement;
128
+ expect(marker.getAttribute("data-radius-class")).toBe("R-PILL");
129
+ expect(marker.getAttribute("data-radius-part")).toBe("ProgressSteps marker");
130
+ // Default knobs: borderWidth medium = 1. The previous 2px pin is gone.
131
+ const upcoming = container.querySelector('[data-step-state="upcoming"]') as HTMLElement;
132
+ expect(upcoming.getAttribute("data-marker-ring")).toBe("1");
133
+ const current = container.querySelector('[data-step-state="current"]') as HTMLElement;
134
+ expect(current.getAttribute("data-marker-ring")).toBe("1");
135
+ });
136
+
137
+ it("keeps nested marker size on the size channel under compact (LC-76)", () => {
114
138
  const { container } = renderWithProviders(<ProgressSteps steps={steps} current={0} compact />);
139
+ const root = container.querySelector('[role="list"]') as HTMLElement;
140
+ expect(root.getAttribute("data-density")).toBe("compact");
115
141
  const marker = container.querySelector("[data-nested-px]") as HTMLElement;
116
- expect(marker.getAttribute("data-nested-px")).toBe("28");
142
+ // Compact steps space only — nestedControl follows size (medium = 32).
143
+ expect(marker.getAttribute("data-nested-px")).toBe("32");
117
144
  });
118
145
 
119
146
  it("hides visible step labels when labels is hidden", () => {
@@ -3,6 +3,8 @@ import {
3
3
  MIN_PRESS_TARGET,
4
4
  ensureKeyboardModalityTracking,
5
5
  pressTargetHitSlop,
6
+ radiusClassProps,
7
+ useAaSolidFill,
6
8
  useReadableTextOn,
7
9
  useResolvedKnobs,
8
10
  wasKeyboardFocus,
@@ -76,8 +78,11 @@ const Marker = styled(View, {
76
78
  name: "ProgressStepMarker",
77
79
  alignItems: "center",
78
80
  justifyContent: "center",
79
- borderWidth: 2,
80
81
  flexShrink: 0,
82
+ // R-PILL (D-09 / LC-60): the numbered disc is a circle at every radius
83
+ // stop — the knob moves size, never shape. Not K1 (Progress/Meter rails).
84
+ ...radiusClassProps("R-PILL", "ProgressSteps marker"),
85
+ borderRadius: 1000,
81
86
  });
82
87
 
83
88
  const StepButton = styled(View, {
@@ -148,14 +153,18 @@ export function ProgressSteps({
148
153
  );
149
154
  if (isWeb) ensureKeyboardModalityTracking();
150
155
  const [kbFocusIndex, setKbFocusIndex] = useState<number | null>(null);
151
- // LC-05: current marker rides the accent fill; completed/error fills pick
152
- // paper/ink from luminance rather than an assumed white glyph.
153
- const onSelected = useReadableTextOn(componentColors.indicator.selected);
156
+ // LC-05: current marker rides an accent solid; completed/error fills pick
157
+ // paper/ink from luminance rather than an assumed white glyph. The stock
158
+ // dark `$accentBackground` tops out at 4.02:1 against either scheme
159
+ // anchor, under the in-repo 4.5 text floor, so the current fill walks to
160
+ // the nearest accent solid that can carry the numeral.
161
+ const currentFill = useAaSolidFill(componentColors.indicator.selected);
162
+ const onSelected = useReadableTextOn(currentFill);
154
163
  const onCompleted = useReadableTextOn(componentColors.indicator.completed);
155
164
  const onError = useReadableTextOn("$red9");
156
165
  const { px: markerPx, hitSlop, box: nestedBox } = splitNestedControl(knobProps.nestedControl);
157
166
  const markerIconSize = Math.max(12, Math.round(markerPx * 0.45));
158
- const markerRadius = knobProps.pointy ? 0 : 1000;
167
+ const ringWidth = knobProps.borderRadius.borderWidth ?? 0;
159
168
  const connectorThickness = 2;
160
169
  const pressOutset = Math.max(0, Math.ceil((MIN_PRESS_TARGET - markerPx) / 2));
161
170
  const interactive = !!onStepChange && allowJump;
@@ -192,7 +201,7 @@ export function ProgressSteps({
192
201
  : kind === "completed"
193
202
  ? componentColors.indicator.completed
194
203
  : kind === "current"
195
- ? componentColors.indicator.selected
204
+ ? currentFill
196
205
  : "transparent";
197
206
  const markerBorder = kind === "upcoming" ? componentColors.indicator.track : markerBg;
198
207
  const markerFg =
@@ -207,15 +216,20 @@ export function ProgressSteps({
207
216
  step.description ?? (step.optional && kind !== "error" ? t("Optional") : null);
208
217
  const connectorFill =
209
218
  index < current ? componentColors.indicator.completed : componentColors.indicator.track;
219
+ // Upcoming is outlined-by-state: chromeless `borderWidth:none` would
220
+ // erase the empty disc, so it keeps the OUTLINED-HAIRLINE floor.
221
+ const markerRing = kind === "upcoming" ? Math.max(ringWidth, 0.5) : ringWidth;
210
222
 
211
223
  const marker = (
212
224
  <Marker
213
225
  {...nestedBox}
214
- borderRadius={markerRadius}
226
+ borderRadius={1000}
227
+ borderWidth={markerRing}
215
228
  backgroundColor={markerBg}
216
229
  borderColor={markerBorder}
217
230
  data-nested-px={markerPx}
218
231
  data-step-state={kind}
232
+ data-marker-ring={markerRing}
219
233
  transition={knobProps.transition}
220
234
  {...(state === "current"
221
235
  ? ({ "aria-current": "step" } as Record<string, unknown>)
@@ -0,0 +1,88 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { mediumDetent, minSheetHeight, resolveSheetDetents } from "./detents";
3
+
4
+ /*
5
+ * MPO-68 AC-4 — "SheetModal's snapPoint prop either drives a detent or is
6
+ * removed". It drives one. These lock that in, because it has already been
7
+ * lost once: 184746910 (MPO-71) rewrote the detents block from a pre-MPO-68
8
+ * copy and dropped the snapPoint push, leaving the prop declared, documented
9
+ * and passed by four callers while doing nothing on device.
10
+ *
11
+ * Geometry under test is a pure height list, largest first. The component's
12
+ * PanResponder turns each height h into a resting translate of `travel - h`.
13
+ */
14
+
15
+ const travel = 600;
16
+
17
+ describe("resolveSheetDetents", () => {
18
+ it("a plain sheet has exactly one rest: fully expanded", () => {
19
+ expect(resolveSheetDetents({ travel })).toEqual([600]);
20
+ });
21
+
22
+ it("REGRESSION: snapPoint creates a detent instead of being ignored", () => {
23
+ // The bug this spec exists for: main returned [600] here.
24
+ expect(resolveSheetDetents({ travel, snapPoint: 85 })).toEqual([600, 510]);
25
+ });
26
+
27
+ it("reads snapPoint as a percent of the full height, matching the web Sheet", () => {
28
+ expect(resolveSheetDetents({ travel, snapPoint: 50 })).toEqual([600, 300]);
29
+ expect(resolveSheetDetents({ travel, snapPoint: 60 })).toEqual([600, 360]);
30
+ expect(resolveSheetDetents({ travel, snapPoint: 92 })).toEqual([600, 552]);
31
+ });
32
+
33
+ it("honours the four heights real callers pass", () => {
34
+ // CommandPalette 92, list-tools-sheet 85, ListThemePlayground 85,
35
+ // Toast.stories 70 — every one of these was a no-op on device.
36
+ for (const snapPoint of [92, 85, 70]) {
37
+ const detents = resolveSheetDetents({ travel, snapPoint });
38
+ expect(detents).toContain(Math.round(travel * (snapPoint / 100)));
39
+ expect(detents.length).toBeGreaterThan(1);
40
+ }
41
+ });
42
+
43
+ it("a scrollable sheet keeps its half-open detent", () => {
44
+ expect(resolveSheetDetents({ travel, scrollable: true })).toEqual([
45
+ 600,
46
+ Math.round(travel * mediumDetent),
47
+ ]);
48
+ });
49
+
50
+ it("scrollable and snapPoint stack, largest first, no duplicates", () => {
51
+ // 600 expanded, 330 medium, 510 from snapPoint.
52
+ expect(resolveSheetDetents({ travel, scrollable: true, snapPoint: 85 })).toEqual([
53
+ 600, 510, 330,
54
+ ]);
55
+ });
56
+
57
+ it("dedupes a snapPoint that lands on a detent already present", () => {
58
+ expect(resolveSheetDetents({ travel, snapPoint: 100 })).toEqual([600]);
59
+ expect(resolveSheetDetents({ travel, scrollable: true, snapPoint: 55 })).toEqual([600, 330]);
60
+ });
61
+
62
+ it("clamps a snapPoint above 100 to fully expanded", () => {
63
+ expect(resolveSheetDetents({ travel, snapPoint: 140 })).toEqual([600]);
64
+ });
65
+
66
+ it("drops a detent shorter than the floor rather than resting near-dismissed", () => {
67
+ // 600 * 0.10 = 60, well under minSheetHeight.
68
+ expect(resolveSheetDetents({ travel, snapPoint: 10 })).toEqual([600]);
69
+ expect(minSheetHeight).toBe(180);
70
+ });
71
+
72
+ it("a sheet shorter than the floor still keeps its own full height", () => {
73
+ expect(resolveSheetDetents({ travel: 120, scrollable: true, snapPoint: 85 })).toEqual([120]);
74
+ });
75
+
76
+ it("ignores a snapPoint that is not a usable number", () => {
77
+ for (const snapPoint of [0, -20, Number.NaN, Number.POSITIVE_INFINITY]) {
78
+ expect(resolveSheetDetents({ travel, snapPoint })).toEqual([600]);
79
+ }
80
+ expect(resolveSheetDetents({ travel, snapPoint: undefined })).toEqual([600]);
81
+ });
82
+
83
+ it("always returns descending heights, so the pan release can scan in order", () => {
84
+ const detents = resolveSheetDetents({ travel, scrollable: true, snapPoint: 40 });
85
+ expect(detents).toEqual([...detents].sort((a, b) => b - a));
86
+ expect(new Set(detents).size).toBe(detents.length);
87
+ });
88
+ });
@@ -0,0 +1,54 @@
1
+ /**
2
+ * SheetModal was the harness inside SheetFrame.stories and had no title of its
3
+ * own, so the gallery listed the frame and not the sheet (MPO-193). These
4
+ * mount every exported story so an unrenderable one fails here, not in the
5
+ * Kitchen Sink.
6
+ *
7
+ * Presence is asserted by accessible NAME, not by counting dialogs: tamagui's
8
+ * Sheet keeps its portal in the tree either side of `open`, and happy-dom runs
9
+ * no animation, so `role="dialog"` matches more than one node whatever the
10
+ * open state is.
11
+ */
12
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
13
+ import { cleanup, screen } from "@testing-library/react";
14
+ import { afterEach, describe, expect, it } from "vitest";
15
+ import meta, { Default, OpenOnMount, Scrollable, TallDetent } from "./SheetModal.stories";
16
+
17
+ afterEach(cleanup);
18
+
19
+ describe("SheetModal stories", () => {
20
+ it("declares the Components/SheetModal title against the component", () => {
21
+ expect(meta.title).toBe("Components/SheetModal");
22
+ expect(meta.component).toBeDefined();
23
+ });
24
+
25
+ it("every exported story mounts its trigger", () => {
26
+ for (const story of [Default, Scrollable, TallDetent, OpenOnMount]) {
27
+ renderWithProviders(<>{story.render?.({} as never, {} as never)}</>);
28
+ expect(screen.getAllByText("Open sheet").length).toBeGreaterThan(0);
29
+ cleanup();
30
+ }
31
+ });
32
+
33
+ it("the sheet frame is a labelled modal dialog", () => {
34
+ renderWithProviders(<>{OpenOnMount.render?.({} as never, {} as never)}</>);
35
+ // tamagui renders the sheet through a portal AND inline, so the frame
36
+ // appears more than once with the same accessible name; every copy has to
37
+ // carry the modal semantics.
38
+ const frames = screen.getAllByRole("dialog", { name: "Move to project" });
39
+ expect(frames.length).toBeGreaterThan(0);
40
+ for (const frame of frames) expect(frame.getAttribute("aria-modal")).toBe("true");
41
+ });
42
+
43
+ it("the action row inside the sheet carries cancel and primary", () => {
44
+ renderWithProviders(<>{OpenOnMount.render?.({} as never, {} as never)}</>);
45
+ expect(screen.getAllByText("Cancel").length).toBeGreaterThan(0);
46
+ expect(screen.getAllByText("Move").length).toBeGreaterThan(0);
47
+ });
48
+
49
+ it("the scrollable story fills the body with rows", () => {
50
+ renderWithProviders(<>{Scrollable.render?.({} as never, {} as never)}</>);
51
+ expect(screen.getAllByText("Project 1").length).toBeGreaterThan(0);
52
+ expect(screen.getAllByText("Project 30").length).toBeGreaterThan(0);
53
+ });
54
+ });
@@ -0,0 +1,109 @@
1
+ import { Button } from "@multiplatform.one/forms";
2
+ import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
3
+ import { useState } from "react";
4
+ import { Paragraph, SizableText, YStack } from "tamagui";
5
+ import { ActionBar } from "../actions/ActionBar";
6
+ import { SheetModal } from "./index";
7
+
8
+ function Harness({
9
+ scrollable = false,
10
+ snapPoint,
11
+ startOpen = false,
12
+ }: {
13
+ scrollable?: boolean;
14
+ snapPoint?: number;
15
+ startOpen?: boolean;
16
+ }) {
17
+ const [open, setOpen] = useState(startOpen);
18
+ return (
19
+ <YStack minHeight={480} gap="$3">
20
+ <Button onPress={() => setOpen(true)}>Open sheet</Button>
21
+ <Paragraph size="$2">
22
+ Dismiss by tapping the scrim, dragging to the bottom, or pressing Escape.
23
+ </Paragraph>
24
+ <SheetModal
25
+ open={open}
26
+ onOpenChange={setOpen}
27
+ scrollable={scrollable}
28
+ {...(snapPoint === undefined ? {} : { snapPoint })}
29
+ header={<SizableText fontWeight="600">Move to project</SizableText>}
30
+ >
31
+ {scrollable ? (
32
+ <YStack gap="$2">
33
+ {Array.from({ length: 30 }).map((_, index) => (
34
+ <Paragraph key={index}>Project {index + 1}</Paragraph>
35
+ ))}
36
+ </YStack>
37
+ ) : (
38
+ <YStack gap="$3">
39
+ <Paragraph>
40
+ The sheet is a dialog region, so the action row inside it caps at two actions.
41
+ </Paragraph>
42
+ <ActionBar
43
+ cancel={
44
+ <Button chromeless onPress={() => setOpen(false)}>
45
+ Cancel
46
+ </Button>
47
+ }
48
+ primary={
49
+ <Button accent onPress={() => setOpen(false)}>
50
+ Move
51
+ </Button>
52
+ }
53
+ />
54
+ </YStack>
55
+ )}
56
+ </SheetModal>
57
+ </YStack>
58
+ );
59
+ }
60
+
61
+ const meta: Meta<typeof SheetModal> = {
62
+ title: "Components/SheetModal",
63
+ component: SheetModal,
64
+ parameters: {
65
+ status: { type: "beta" },
66
+ layout: "fullscreen",
67
+ docs: {
68
+ description: {
69
+ component:
70
+ "Modal bottom sheet. Anatomy follows the Apple HIG sheet (grabber, percent detent, swipe to dismiss) with Radix Dialog semantics: `role=dialog`, `aria-modal`, focus moved in, trapped, and returned on close, and Escape dismissal wired here because tamagui's Sheet has no key handling of its own. The frame opens a dialog region, so an ActionBar inside it inherits the two-action cap. Web renders tamagui's Sheet; the native twin is an RN Modal, because a raw Sheet cannot re-present from a trigger tap on device.",
71
+ },
72
+ },
73
+ },
74
+ argTypes: {
75
+ snapPoint: { control: { type: "range", min: 30, max: 95, step: 5 } },
76
+ scrollable: { control: "boolean" },
77
+ },
78
+ };
79
+ export default meta;
80
+
81
+ type Story = StoryObj<typeof SheetModal>;
82
+
83
+ export const Default: Story = {
84
+ name: "Main",
85
+ render: () => <Harness />,
86
+ };
87
+
88
+ export const Scrollable: Story = {
89
+ name: "Scrollable body",
90
+ render: () => <Harness scrollable />,
91
+ };
92
+
93
+ export const TallDetent: Story = {
94
+ name: "Tall detent",
95
+ parameters: {
96
+ docs: {
97
+ description: {
98
+ story:
99
+ "`snapPoint` is a percent of travel. 92 is the tallest height real callers pass (the command palette); every one of those was a no-op on device until the detent resolver landed.",
100
+ },
101
+ },
102
+ },
103
+ render: () => <Harness snapPoint={92} />,
104
+ };
105
+
106
+ export const OpenOnMount: Story = {
107
+ name: "Open",
108
+ render: () => <Harness startOpen />,
109
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * SheetModal detent geometry — the pure half, split out so it can be specced
3
+ * without standing up a React Native renderer.
4
+ *
5
+ * A detent is a VISIBLE HEIGHT in points. The native sheet's `translateY`
6
+ * measures DOWN from fully-expanded, so a detent of `h` rests at `travel - h`,
7
+ * and `travel` itself is the fully-expanded sheet.
8
+ */
9
+
10
+ /** Smallest height a native sheet is ever laid out at. */
11
+ export const minSheetHeight = 180;
12
+
13
+ /**
14
+ * Half-open detent for a sheet that owns a scrollport, as a fraction of its
15
+ * full height. Mirrors FloatingPanel so both native sheets drag alike.
16
+ */
17
+ export const mediumDetent = 0.55;
18
+
19
+ export interface ResolveSheetDetentsOptions {
20
+ /** Full (expanded) height of the sheet, in points. */
21
+ travel: number;
22
+ /** The sheet owns a scrollport, so a half-open rest is meaningful. */
23
+ scrollable?: boolean;
24
+ /** Percent detent from the caller — the same prop the web Sheet takes. */
25
+ snapPoint?: number;
26
+ }
27
+
28
+ /**
29
+ * The heights the sheet is allowed to rest at, largest first.
30
+ *
31
+ * MPO-68: `snapPoint` is a percent on the web Sheet (`snapPoints={[snapPoint]}`).
32
+ * Native honours the same prop by turning that percent into a detent, so a
33
+ * caller that writes `snapPoint={85}` gets an 85%-height rest on both twins
34
+ * rather than the prop being silently dropped on device.
35
+ *
36
+ * Anything shorter than `minSheetHeight` is discarded, because a sheet that
37
+ * rests below that is indistinguishable from a dismissed one. A sheet whose
38
+ * full height is already under the floor keeps its own height, otherwise it
39
+ * would have no detents at all.
40
+ */
41
+ export function resolveSheetDetents({
42
+ travel,
43
+ scrollable,
44
+ snapPoint,
45
+ }: ResolveSheetDetentsOptions): number[] {
46
+ const points = [travel];
47
+ if (scrollable) {
48
+ points.push(Math.round(travel * mediumDetent));
49
+ }
50
+ if (typeof snapPoint === "number" && Number.isFinite(snapPoint) && snapPoint > 0) {
51
+ points.push(Math.round(travel * (Math.min(snapPoint, 100) / 100)));
52
+ }
53
+ const floor = Math.min(minSheetHeight, travel);
54
+ return Array.from(new Set(points.filter((h) => h >= floor))).sort((a, b) => b - a);
55
+ }
@@ -24,6 +24,7 @@ import {
24
24
  useWindowDimensions,
25
25
  } from "react-native";
26
26
  import { useResolvedKnobs } from "@multiplatform.one/theme";
27
+ import { minSheetHeight, resolveSheetDetents } from "./detents";
27
28
  import { useTranslation } from "../shared/i18n";
28
29
  import { useKeyboardInset } from "../shared/useKeyboardInset";
29
30
  import { View, YStack } from "tamagui";
@@ -36,10 +37,6 @@ const sheetMaxHeightRatio = 0.85;
36
37
  const bottomInset = Platform.OS === "ios" ? 24 : 16;
37
38
  // Backdrop left visible above the sheet, so the scrim stays tappable.
38
39
  const backdropStrip = 48;
39
- const minSheetHeight = 180;
40
- // Half-open detent for a sheet that owns a scrollport, as a fraction of its
41
- // full height. Mirrors FloatingPanel so both native sheets drag alike.
42
- const mediumDetent = 0.55;
43
40
  // Released more than this far below the smallest detent, the sheet dismisses.
44
41
  const dismissThreshold = 56;
45
42
  const IN_DIALOG_REGION = { inDialogRegion: true } as const;
@@ -49,7 +46,7 @@ export function SheetModal({
49
46
  onOpenChange,
50
47
  children,
51
48
  header,
52
- snapPoint: _snapPoint,
49
+ snapPoint,
53
50
  scrollable,
54
51
  }: SheetModalProps) {
55
52
  const { t } = useTranslation();
@@ -95,16 +92,20 @@ export function SheetModal({
95
92
  *
96
93
  * translateY measures DOWN from fully-expanded: 0 is the sheet at full
97
94
  * height, `travel` is fully off-screen.
95
+ *
96
+ * The detent heights themselves live in ./detents.ts, pure, so the geometry
97
+ * is specced without a native renderer. 184746910 (MPO-71) rewrote this
98
+ * block from a pre-MPO-68 copy and silently dropped the `snapPoint` push,
99
+ * leaving the prop declared, documented and passed by four callers while
100
+ * doing nothing on device. Keep the math in one place so a rewrite of the
101
+ * animation cannot take the geometry with it again.
98
102
  */
99
103
  const [measuredHeight, setMeasuredHeight] = useState(0);
100
104
  const travel = measuredHeight || maxHeight;
101
- const detents = useMemo(() => {
102
- if (!scrollable) return [travel];
103
- const points = [travel, Math.round(travel * mediumDetent)].filter(
104
- (h) => h >= Math.min(minSheetHeight, travel),
105
- );
106
- return Array.from(new Set(points)).sort((a, b) => b - a);
107
- }, [scrollable, travel]);
105
+ const detents = useMemo(
106
+ () => resolveSheetDetents({ travel, scrollable, snapPoint }),
107
+ [travel, scrollable, snapPoint],
108
+ );
108
109
 
109
110
  /*
110
111
  * MPO-71 — park the sheet OFF-SCREEN before the modal ever presents.
@@ -21,7 +21,7 @@ export interface SheetModalProps {
21
21
  children?: ReactNode;
22
22
  /** Fixed content above the (scrollable) body, e.g. the sheet title. */
23
23
  header?: ReactNode;
24
- /** Percent snap point for the web Sheet (native sizes to content). */
24
+ /** Percent snap point. Web: the Sheet's snap point. Native: a drag detent. */
25
25
  snapPoint?: number;
26
26
  /** Wrap children in the sheet's scroll container. */
27
27
  scrollable?: boolean;
@@ -59,7 +59,10 @@ function useSheetFrameFocus(open: boolean, frameRef: RefObject<HTMLElement | nul
59
59
  if (!target || !target.isConnected) return;
60
60
  const ae = document.activeElement;
61
61
  const dropped =
62
- !ae || ae === document.body || ae === document.documentElement || !!frameRef.current?.contains(ae);
62
+ !ae ||
63
+ ae === document.body ||
64
+ ae === document.documentElement ||
65
+ !!frameRef.current?.contains(ae);
63
66
  if (dropped) {
64
67
  target.focus({
65
68
  preventScroll: true,
@@ -22,7 +22,7 @@ function radiusClasses(el: Element): string[] {
22
22
 
23
23
  describe("Skeleton named exports", () => {
24
24
  it("serves named exports only (no default) and keeps the namespace statics", () => {
25
- expect(SkeletonExports.default).toBeUndefined();
25
+ expect("default" in SkeletonExports).toBe(false);
26
26
  expect(SkeletonExports.Skeleton).toBe(Skeleton);
27
27
  expect(SkeletonExports.SkeletonText).toBe(SkeletonText);
28
28
  expect(SkeletonExports.SkeletonCircle).toBe(SkeletonCircle);