@multiplatform.one/components 7.11.0 → 7.15.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 (413) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/Accordion/index.cjs +2 -6
  3. package/dist/cjs/Accordion/index.native.js +2 -6
  4. package/dist/cjs/Accordion/index.native.js.map +1 -1
  5. package/dist/cjs/AnimateHeight/index.cjs +1 -3
  6. package/dist/cjs/AnimateHeight/index.native.js +1 -3
  7. package/dist/cjs/AnimateHeight/index.native.js.map +1 -1
  8. package/dist/cjs/Chip/index.cjs +8 -1
  9. package/dist/cjs/Chip/index.native.js +8 -1
  10. package/dist/cjs/Chip/index.native.js.map +1 -1
  11. package/dist/cjs/SheetModal/index.native.js +70 -22
  12. package/dist/cjs/SheetModal/index.native.js.map +1 -1
  13. package/dist/cjs/Tabs/index.cjs +2 -6
  14. package/dist/cjs/Tabs/index.native.js +2 -6
  15. package/dist/cjs/Tabs/index.native.js.map +1 -1
  16. package/dist/cjs/Text.cjs +2 -0
  17. package/dist/cjs/Text.native.js +2 -0
  18. package/dist/cjs/Text.native.js.map +1 -1
  19. package/dist/cjs/TreeSelect/index.cjs +55 -52
  20. package/dist/cjs/TreeSelect/index.native.js +55 -52
  21. package/dist/cjs/TreeSelect/index.native.js.map +1 -1
  22. package/dist/cjs/Video/PlayerChrome.cjs +3 -9
  23. package/dist/cjs/Video/PlayerChrome.native.js +3 -9
  24. package/dist/cjs/Video/PlayerChrome.native.js.map +1 -1
  25. package/dist/cjs/code/Code/index.cjs +6 -0
  26. package/dist/cjs/code/Code/index.native.js +7 -4
  27. package/dist/cjs/code/Code/index.native.js.map +1 -1
  28. package/dist/cjs/code/CodeBlock/index.cjs +4 -5
  29. package/dist/cjs/code/CodeBlock/index.native.js +4 -5
  30. package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
  31. package/dist/cjs/icons/themed.cjs +2 -1
  32. package/dist/cjs/icons/themed.native.js +2 -1
  33. package/dist/cjs/icons/themed.native.js.map +1 -1
  34. package/dist/cjs/knobImmuneExports.cjs +3 -3
  35. package/dist/cjs/knobImmuneExports.native.js +3 -3
  36. package/dist/cjs/layouts/PaneScaffold.cjs +70 -42
  37. package/dist/cjs/layouts/PaneScaffold.native.js +75 -48
  38. package/dist/cjs/layouts/PaneScaffold.native.js.map +1 -1
  39. package/dist/cjs/layouts/page.cjs +2 -1
  40. package/dist/cjs/layouts/page.native.js +2 -1
  41. package/dist/cjs/layouts/page.native.js.map +1 -1
  42. package/dist/cjs/layouts/sidebar.cjs +1 -3
  43. package/dist/cjs/layouts/sidebar.native.js +1 -3
  44. package/dist/cjs/layouts/sidebar.native.js.map +1 -1
  45. package/dist/cjs/surfaces.cjs +0 -32
  46. package/dist/cjs/surfaces.native.js +0 -32
  47. package/dist/cjs/surfaces.native.js.map +1 -1
  48. package/dist/cjs/views/List.cjs +1 -3
  49. package/dist/cjs/views/List.native.js +1 -3
  50. package/dist/cjs/views/List.native.js.map +1 -1
  51. package/dist/cjs/views/Matrix.cjs +568 -0
  52. package/dist/cjs/views/Matrix.native.js +612 -0
  53. package/dist/cjs/views/Matrix.native.js.map +1 -0
  54. package/dist/cjs/views/ganttMath.cjs +2 -0
  55. package/dist/cjs/views/ganttMath.native.js +2 -0
  56. package/dist/cjs/views/ganttMath.native.js.map +1 -1
  57. package/dist/cjs/views/index.cjs +16 -0
  58. package/dist/cjs/views/index.native.js +16 -0
  59. package/dist/cjs/views/index.native.js.map +1 -1
  60. package/dist/cjs/views/matrixMath.cjs +157 -0
  61. package/dist/cjs/views/matrixMath.native.js +229 -0
  62. package/dist/cjs/views/matrixMath.native.js.map +1 -0
  63. package/dist/esm/Accordion/index.mjs +3 -7
  64. package/dist/esm/Accordion/index.mjs.map +1 -1
  65. package/dist/esm/Accordion/index.native.js +3 -7
  66. package/dist/esm/Accordion/index.native.js.map +1 -1
  67. package/dist/esm/AnimateHeight/index.mjs +2 -4
  68. package/dist/esm/AnimateHeight/index.mjs.map +1 -1
  69. package/dist/esm/AnimateHeight/index.native.js +2 -4
  70. package/dist/esm/AnimateHeight/index.native.js.map +1 -1
  71. package/dist/esm/Avatar/getInitials.native.js.map +1 -1
  72. package/dist/esm/Avatar/index.native.js.map +1 -1
  73. package/dist/esm/Badge/index.native.js.map +1 -1
  74. package/dist/esm/Button.native.js.map +1 -1
  75. package/dist/esm/Carousel/index.native.js.map +1 -1
  76. package/dist/esm/Chip/index.mjs +9 -2
  77. package/dist/esm/Chip/index.mjs.map +1 -1
  78. package/dist/esm/Chip/index.native.js +9 -2
  79. package/dist/esm/Chip/index.native.js.map +1 -1
  80. package/dist/esm/Collapsible.native.js.map +1 -1
  81. package/dist/esm/ContextMenu/index.native.js.map +1 -1
  82. package/dist/esm/CopyField/index.native.js.map +1 -1
  83. package/dist/esm/DotIndicator/index.native.js.map +1 -1
  84. package/dist/esm/DropdownMenu/index.native.js.map +1 -1
  85. package/dist/esm/ErrorBoundary/index.native.js.map +1 -1
  86. package/dist/esm/Heading.native.js.map +1 -1
  87. package/dist/esm/Meter/index.native.js.map +1 -1
  88. package/dist/esm/Meter/meter.native.js.map +1 -1
  89. package/dist/esm/Pagination.native.js.map +1 -1
  90. package/dist/esm/ProgressSteps/index.native.js.map +1 -1
  91. package/dist/esm/Quote/index.native.js.map +1 -1
  92. package/dist/esm/Separator/index.native.js.map +1 -1
  93. package/dist/esm/SheetModal/detents.native.js.map +1 -1
  94. package/dist/esm/SheetModal/index.native.js +71 -23
  95. package/dist/esm/SheetModal/index.native.js.map +1 -1
  96. package/dist/esm/Skeleton/index.native.js.map +1 -1
  97. package/dist/esm/SkipLink/index.native.js.map +1 -1
  98. package/dist/esm/SortableList/SortableHandle.native.js.map +1 -1
  99. package/dist/esm/SortableList/index.native.js.map +1 -1
  100. package/dist/esm/SortableList/useSortableRows.native.js.map +1 -1
  101. package/dist/esm/Tabs/index.mjs +3 -7
  102. package/dist/esm/Tabs/index.mjs.map +1 -1
  103. package/dist/esm/Tabs/index.native.js +3 -7
  104. package/dist/esm/Tabs/index.native.js.map +1 -1
  105. package/dist/esm/Text.mjs +3 -1
  106. package/dist/esm/Text.mjs.map +1 -1
  107. package/dist/esm/Text.native.js +3 -1
  108. package/dist/esm/Text.native.js.map +1 -1
  109. package/dist/esm/Toast/index.native.js.map +1 -1
  110. package/dist/esm/Toast/store.native.js.map +1 -1
  111. package/dist/esm/Tooltip/nativePress.native.js.map +1 -1
  112. package/dist/esm/Tooltip/tooltipShared.native.js.map +1 -1
  113. package/dist/esm/TreeSelect/index.mjs +56 -53
  114. package/dist/esm/TreeSelect/index.mjs.map +1 -1
  115. package/dist/esm/TreeSelect/index.native.js +56 -53
  116. package/dist/esm/TreeSelect/index.native.js.map +1 -1
  117. package/dist/esm/TreeSelect/treeSelectModel.native.js.map +1 -1
  118. package/dist/esm/Video/PlayerChrome.mjs +4 -10
  119. package/dist/esm/Video/PlayerChrome.mjs.map +1 -1
  120. package/dist/esm/Video/PlayerChrome.native.js +4 -10
  121. package/dist/esm/Video/PlayerChrome.native.js.map +1 -1
  122. package/dist/esm/Video/VideoFrame.native.js.map +1 -1
  123. package/dist/esm/Video/types.native.js.map +1 -1
  124. package/dist/esm/Wheel/index.native.js.map +1 -1
  125. package/dist/esm/Wizard/index.native.js.map +1 -1
  126. package/dist/esm/actions/ActionBar.native.js.map +1 -1
  127. package/dist/esm/actions/DestructiveAction.native.js.map +1 -1
  128. package/dist/esm/actions/devWarn.native.js.map +1 -1
  129. package/dist/esm/actions/index.native.js.map +1 -1
  130. package/dist/esm/actions/severity.native.js.map +1 -1
  131. package/dist/esm/charts/Axis.native.js.map +1 -1
  132. package/dist/esm/charts/BarChart.native.js.map +1 -1
  133. package/dist/esm/charts/ChartDataView.native.js.map +1 -1
  134. package/dist/esm/charts/ChartSurface.native.js.map +1 -1
  135. package/dist/esm/charts/LineChart.native.js.map +1 -1
  136. package/dist/esm/charts/PieChart.native.js.map +1 -1
  137. package/dist/esm/charts/Sparkline.native.js.map +1 -1
  138. package/dist/esm/charts/accessibility.native.js.map +1 -1
  139. package/dist/esm/charts/composeChart.native.js.map +1 -1
  140. package/dist/esm/charts/index.native.js.map +1 -1
  141. package/dist/esm/charts/math.native.js.map +1 -1
  142. package/dist/esm/charts/series.native.js.map +1 -1
  143. package/dist/esm/charts/svg.native.js.map +1 -1
  144. package/dist/esm/charts/types.native.js.map +1 -1
  145. package/dist/esm/charts/useChartTheme.native.js.map +1 -1
  146. package/dist/esm/code/Code/index.mjs +6 -0
  147. package/dist/esm/code/Code/index.mjs.map +1 -1
  148. package/dist/esm/code/Code/index.native.js +10 -7
  149. package/dist/esm/code/Code/index.native.js.map +1 -1
  150. package/dist/esm/code/CodeBlock/index.mjs +5 -6
  151. package/dist/esm/code/CodeBlock/index.mjs.map +1 -1
  152. package/dist/esm/code/CodeBlock/index.native.js +5 -6
  153. package/dist/esm/code/CodeBlock/index.native.js.map +1 -1
  154. package/dist/esm/code/HighlightedCode/index.native.js.map +1 -1
  155. package/dist/esm/code/Highlighter/index.native.js.map +1 -1
  156. package/dist/esm/code/Pre/index.native.js.map +1 -1
  157. package/dist/esm/code/index.native.js.map +1 -1
  158. package/dist/esm/componentColors.native.js.map +1 -1
  159. package/dist/esm/feedback/ConfirmDialog.native.js.map +1 -1
  160. package/dist/esm/feedback/NotifyHost.native.js.map +1 -1
  161. package/dist/esm/feedback/copy.native.js.map +1 -1
  162. package/dist/esm/feedback/index.native.js.map +1 -1
  163. package/dist/esm/feedback/notify.native.js.map +1 -1
  164. package/dist/esm/feedback/route.native.js.map +1 -1
  165. package/dist/esm/feedback/store.native.js.map +1 -1
  166. package/dist/esm/hooks/index.native.js.map +1 -1
  167. package/dist/esm/hooks/useClipboard.native.js.map +1 -1
  168. package/dist/esm/hooks/useDocumentTitle.native.js.map +1 -1
  169. package/dist/esm/icons/CheckRegular.native.js.map +1 -1
  170. package/dist/esm/icons/MinusRegular.native.js.map +1 -1
  171. package/dist/esm/icons/index.native.js.map +1 -1
  172. package/dist/esm/icons/lucide.native.js.map +1 -1
  173. package/dist/esm/icons/themed.mjs +3 -2
  174. package/dist/esm/icons/themed.mjs.map +1 -1
  175. package/dist/esm/icons/themed.native.js +3 -2
  176. package/dist/esm/icons/themed.native.js.map +1 -1
  177. package/dist/esm/images/Image/ImageFrame.native.js.map +1 -1
  178. package/dist/esm/images/Image/shared.native.js.map +1 -1
  179. package/dist/esm/images/Image/types.native.js.map +1 -1
  180. package/dist/esm/images/index.native.js.map +1 -1
  181. package/dist/esm/index.native.js.map +1 -1
  182. package/dist/esm/knobImmuneExports.mjs +3 -3
  183. package/dist/esm/knobImmuneExports.native.js +3 -3
  184. package/dist/esm/knobImmuneExports.native.js.map +1 -1
  185. package/dist/esm/layouts/AsyncBoundary.native.js.map +1 -1
  186. package/dist/esm/layouts/Debug/index.native.js.map +1 -1
  187. package/dist/esm/layouts/EmptyState.native.js.map +1 -1
  188. package/dist/esm/layouts/KeyboardAvoidingWrapper/behavior.native.js.map +1 -1
  189. package/dist/esm/layouts/PageTemplates.native.js.map +1 -1
  190. package/dist/esm/layouts/PaneScaffold.mjs +70 -42
  191. package/dist/esm/layouts/PaneScaffold.mjs.map +1 -1
  192. package/dist/esm/layouts/PaneScaffold.native.js +75 -48
  193. package/dist/esm/layouts/PaneScaffold.native.js.map +1 -1
  194. package/dist/esm/layouts/SafeAreaWrapper/insets.native.js.map +1 -1
  195. package/dist/esm/layouts/ViewSwitcher.native.js.map +1 -1
  196. package/dist/esm/layouts/attachments.native.js.map +1 -1
  197. package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
  198. package/dist/esm/layouts/index.native.js.map +1 -1
  199. package/dist/esm/layouts/page.mjs +3 -2
  200. package/dist/esm/layouts/page.mjs.map +1 -1
  201. package/dist/esm/layouts/page.native.js +3 -2
  202. package/dist/esm/layouts/page.native.js.map +1 -1
  203. package/dist/esm/layouts/pageHeadingScope.native.js.map +1 -1
  204. package/dist/esm/layouts/sidebar.mjs +2 -4
  205. package/dist/esm/layouts/sidebar.mjs.map +1 -1
  206. package/dist/esm/layouts/sidebar.native.js +2 -4
  207. package/dist/esm/layouts/sidebar.native.js.map +1 -1
  208. package/dist/esm/layouts/tags.native.js.map +1 -1
  209. package/dist/esm/layouts/timeline.native.js.map +1 -1
  210. package/dist/esm/layouts/toolbar.native.js.map +1 -1
  211. package/dist/esm/shared/actionScan.native.js.map +1 -1
  212. package/dist/esm/shared/i18n.native.js.map +1 -1
  213. package/dist/esm/shared/t.native.js.map +1 -1
  214. package/dist/esm/shared/textRidesText.native.js.map +1 -1
  215. package/dist/esm/shared/useReturnFocusOnClose.native.js.map +1 -1
  216. package/dist/esm/surfaces.mjs +1 -33
  217. package/dist/esm/surfaces.mjs.map +1 -1
  218. package/dist/esm/surfaces.native.js +1 -33
  219. package/dist/esm/surfaces.native.js.map +1 -1
  220. package/dist/esm/tamagui.native.js.map +1 -1
  221. package/dist/esm/testSetup.native.js.map +1 -1
  222. package/dist/esm/utils/setTinted.native.js.map +1 -1
  223. package/dist/esm/utils/unwrapText.native.js.map +1 -1
  224. package/dist/esm/views/Calendar.native.js.map +1 -1
  225. package/dist/esm/views/Dashboard.native.js.map +1 -1
  226. package/dist/esm/views/Gantt.native.js.map +1 -1
  227. package/dist/esm/views/ImageGrid.native.js.map +1 -1
  228. package/dist/esm/views/List.mjs +2 -4
  229. package/dist/esm/views/List.mjs.map +1 -1
  230. package/dist/esm/views/List.native.js +2 -4
  231. package/dist/esm/views/List.native.js.map +1 -1
  232. package/dist/esm/views/Matrix.mjs +543 -0
  233. package/dist/esm/views/Matrix.mjs.map +1 -0
  234. package/dist/esm/views/Matrix.native.js +573 -0
  235. package/dist/esm/views/Matrix.native.js.map +1 -0
  236. package/dist/esm/views/ReportBuilder.native.js.map +1 -1
  237. package/dist/esm/views/TreeView.native.js.map +1 -1
  238. package/dist/esm/views/calendarMath.native.js.map +1 -1
  239. package/dist/esm/views/ganttMath.mjs +1 -1
  240. package/dist/esm/views/ganttMath.mjs.map +1 -1
  241. package/dist/esm/views/ganttMath.native.js +1 -1
  242. package/dist/esm/views/ganttMath.native.js.map +1 -1
  243. package/dist/esm/views/index.mjs +4 -2
  244. package/dist/esm/views/index.mjs.map +1 -1
  245. package/dist/esm/views/index.native.js +4 -2
  246. package/dist/esm/views/index.native.js.map +1 -1
  247. package/dist/esm/views/kanbanDnd.native.js.map +1 -1
  248. package/dist/esm/views/matrixMath.mjs +122 -0
  249. package/dist/esm/views/matrixMath.mjs.map +1 -0
  250. package/dist/esm/views/matrixMath.native.js +191 -0
  251. package/dist/esm/views/matrixMath.native.js.map +1 -0
  252. package/dist/esm/views/treeViewDnd.native.js.map +1 -1
  253. package/dist/esm/views/treeViewLayout.native.js.map +1 -1
  254. package/dist/esm/views/treeViewMotion.native.js.map +1 -1
  255. package/dist/esm/views/treeViewReveal.native.js.map +1 -1
  256. package/dist/jsx/Accordion/index.mjs +3 -7
  257. package/dist/jsx/Accordion/index.mjs.map +1 -1
  258. package/dist/jsx/Accordion/index.native.js +2 -6
  259. package/dist/jsx/Accordion/index.native.js.map +1 -1
  260. package/dist/jsx/AnimateHeight/index.mjs +2 -4
  261. package/dist/jsx/AnimateHeight/index.mjs.map +1 -1
  262. package/dist/jsx/AnimateHeight/index.native.js +1 -3
  263. package/dist/jsx/AnimateHeight/index.native.js.map +1 -1
  264. package/dist/jsx/Chip/index.mjs +9 -2
  265. package/dist/jsx/Chip/index.mjs.map +1 -1
  266. package/dist/jsx/Chip/index.native.js +8 -1
  267. package/dist/jsx/Chip/index.native.js.map +1 -1
  268. package/dist/jsx/SheetModal/index.native.js +70 -22
  269. package/dist/jsx/SheetModal/index.native.js.map +1 -1
  270. package/dist/jsx/Tabs/index.mjs +3 -7
  271. package/dist/jsx/Tabs/index.mjs.map +1 -1
  272. package/dist/jsx/Tabs/index.native.js +2 -6
  273. package/dist/jsx/Tabs/index.native.js.map +1 -1
  274. package/dist/jsx/Text.mjs +3 -1
  275. package/dist/jsx/Text.mjs.map +1 -1
  276. package/dist/jsx/Text.native.js +2 -0
  277. package/dist/jsx/Text.native.js.map +1 -1
  278. package/dist/jsx/TreeSelect/index.mjs +56 -53
  279. package/dist/jsx/TreeSelect/index.mjs.map +1 -1
  280. package/dist/jsx/TreeSelect/index.native.js +55 -52
  281. package/dist/jsx/TreeSelect/index.native.js.map +1 -1
  282. package/dist/jsx/Video/PlayerChrome.mjs +4 -10
  283. package/dist/jsx/Video/PlayerChrome.mjs.map +1 -1
  284. package/dist/jsx/Video/PlayerChrome.native.js +3 -9
  285. package/dist/jsx/Video/PlayerChrome.native.js.map +1 -1
  286. package/dist/jsx/code/Code/index.mjs +6 -0
  287. package/dist/jsx/code/Code/index.mjs.map +1 -1
  288. package/dist/jsx/code/Code/index.native.js +7 -4
  289. package/dist/jsx/code/Code/index.native.js.map +1 -1
  290. package/dist/jsx/code/CodeBlock/index.mjs +5 -6
  291. package/dist/jsx/code/CodeBlock/index.mjs.map +1 -1
  292. package/dist/jsx/code/CodeBlock/index.native.js +4 -5
  293. package/dist/jsx/code/CodeBlock/index.native.js.map +1 -1
  294. package/dist/jsx/icons/themed.mjs +3 -2
  295. package/dist/jsx/icons/themed.mjs.map +1 -1
  296. package/dist/jsx/icons/themed.native.js +2 -1
  297. package/dist/jsx/icons/themed.native.js.map +1 -1
  298. package/dist/jsx/knobImmuneExports.mjs +3 -3
  299. package/dist/jsx/knobImmuneExports.native.js +3 -3
  300. package/dist/jsx/layouts/PaneScaffold.mjs +70 -42
  301. package/dist/jsx/layouts/PaneScaffold.mjs.map +1 -1
  302. package/dist/jsx/layouts/PaneScaffold.native.js +75 -48
  303. package/dist/jsx/layouts/PaneScaffold.native.js.map +1 -1
  304. package/dist/jsx/layouts/page.mjs +3 -2
  305. package/dist/jsx/layouts/page.mjs.map +1 -1
  306. package/dist/jsx/layouts/page.native.js +2 -1
  307. package/dist/jsx/layouts/page.native.js.map +1 -1
  308. package/dist/jsx/layouts/sidebar.mjs +2 -4
  309. package/dist/jsx/layouts/sidebar.mjs.map +1 -1
  310. package/dist/jsx/layouts/sidebar.native.js +1 -3
  311. package/dist/jsx/layouts/sidebar.native.js.map +1 -1
  312. package/dist/jsx/surfaces.mjs +1 -33
  313. package/dist/jsx/surfaces.mjs.map +1 -1
  314. package/dist/jsx/surfaces.native.js +0 -32
  315. package/dist/jsx/surfaces.native.js.map +1 -1
  316. package/dist/jsx/views/List.mjs +2 -4
  317. package/dist/jsx/views/List.mjs.map +1 -1
  318. package/dist/jsx/views/List.native.js +1 -3
  319. package/dist/jsx/views/List.native.js.map +1 -1
  320. package/dist/jsx/views/Matrix.mjs +543 -0
  321. package/dist/jsx/views/Matrix.mjs.map +1 -0
  322. package/dist/jsx/views/Matrix.native.js +612 -0
  323. package/dist/jsx/views/Matrix.native.js.map +1 -0
  324. package/dist/jsx/views/ganttMath.mjs +1 -1
  325. package/dist/jsx/views/ganttMath.mjs.map +1 -1
  326. package/dist/jsx/views/ganttMath.native.js +2 -0
  327. package/dist/jsx/views/ganttMath.native.js.map +1 -1
  328. package/dist/jsx/views/index.mjs +4 -2
  329. package/dist/jsx/views/index.mjs.map +1 -1
  330. package/dist/jsx/views/index.native.js +16 -0
  331. package/dist/jsx/views/index.native.js.map +1 -1
  332. package/dist/jsx/views/matrixMath.mjs +122 -0
  333. package/dist/jsx/views/matrixMath.mjs.map +1 -0
  334. package/dist/jsx/views/matrixMath.native.js +229 -0
  335. package/dist/jsx/views/matrixMath.native.js.map +1 -0
  336. package/package.json +10 -10
  337. package/src/Accordion/Accordion.spec.tsx +20 -0
  338. package/src/Accordion/index.tsx +7 -3
  339. package/src/AnimateHeight/index.tsx +143 -142
  340. package/src/Chip/Chip.borderLadder.spec.tsx +54 -0
  341. package/src/Chip/Chip.pressSlop.spec.tsx +57 -0
  342. package/src/Chip/index.tsx +15 -1
  343. package/src/Heading.native.spec.tsx +1 -1
  344. package/src/Separator/index.tsx +3 -3
  345. package/src/SheetModal/SheetModal.detentLayout.spec.tsx +173 -0
  346. package/src/SheetModal/SheetModal.touch.spec.tsx +63 -0
  347. package/src/SheetModal/index.native.tsx +95 -17
  348. package/src/Tabs/Tabs.hydration.spec.tsx +123 -0
  349. package/src/Tabs/index.tsx +3 -2
  350. package/src/Text.spec.tsx +32 -2
  351. package/src/Text.tsx +7 -6
  352. package/src/Toast/Toast.spec.tsx +50 -0
  353. package/src/Tooltip/Tooltip.spec.tsx +55 -2
  354. package/src/TreeSelect/TreeSelect.spec.tsx +15 -15
  355. package/src/TreeSelect/index.tsx +53 -50
  356. package/src/Video/PlayerChrome.tsx +4 -3
  357. package/src/Wheel/Wheel.spec.tsx +4 -4
  358. package/src/adjacency.l1.spec.tsx +175 -0
  359. package/src/code/Code/code.spec.tsx +2 -19
  360. package/src/code/Code/index.tsx +0 -6
  361. package/src/code/CodeBlock/index.tsx +5 -3
  362. package/src/code/highlightedCode.spec.tsx +2 -2
  363. package/src/code/hostProps.spec.tsx +55 -0
  364. package/src/icons/themed.hydration.spec.tsx +60 -0
  365. package/src/icons/themed.tsx +3 -6
  366. package/src/knobImmuneExports.ts +3 -3
  367. package/src/layouts/PaneScaffold.spec.tsx +148 -2
  368. package/src/layouts/PaneScaffold.stories.tsx +33 -1
  369. package/src/layouts/PaneScaffold.tsx +101 -48
  370. package/src/layouts/page.designLaw.spec.tsx +20 -0
  371. package/src/layouts/page.tsx +2 -0
  372. package/src/layouts/sidebar.tsx +2 -3
  373. package/src/overlayElevation.spec.tsx +39 -51
  374. package/src/surfaces.spec.tsx +13 -10
  375. package/src/surfaces.tsx +4 -33
  376. package/src/tamagui.spec.ts +4 -3
  377. package/src/textAccentSecondary.spec.tsx +100 -2
  378. package/src/views/List.tsx +2 -1
  379. package/src/views/Matrix.spec.tsx +339 -0
  380. package/src/views/Matrix.stories.spec.tsx +68 -0
  381. package/src/views/Matrix.stories.tsx +153 -0
  382. package/src/views/Matrix.tsx +738 -0
  383. package/src/views/ganttMath.ts +4 -2
  384. package/src/views/index.ts +30 -0
  385. package/src/views/matrixMath.spec.ts +237 -0
  386. package/src/views/matrixMath.ts +251 -0
  387. package/src/views/views.spec.tsx +3 -1
  388. package/types/Accordion/index.d.ts.map +1 -1
  389. package/types/AnimateHeight/index.d.ts.map +1 -1
  390. package/types/Chip/index.d.ts.map +1 -1
  391. package/types/Separator/index.d.ts +3 -3
  392. package/types/SheetModal/index.native.d.ts.map +1 -1
  393. package/types/Tabs/index.d.ts.map +1 -1
  394. package/types/Text.d.ts.map +1 -1
  395. package/types/TreeSelect/index.d.ts.map +1 -1
  396. package/types/Video/PlayerChrome.d.ts.map +1 -1
  397. package/types/code/Code/index.d.ts.map +1 -1
  398. package/types/code/CodeBlock/index.d.ts.map +1 -1
  399. package/types/icons/themed.d.ts.map +1 -1
  400. package/types/layouts/PaneScaffold.d.ts +14 -1
  401. package/types/layouts/PaneScaffold.d.ts.map +1 -1
  402. package/types/layouts/page.d.ts.map +1 -1
  403. package/types/layouts/sidebar.d.ts.map +1 -1
  404. package/types/surfaces.d.ts.map +1 -1
  405. package/types/views/List.d.ts.map +1 -1
  406. package/types/views/Matrix.d.ts +102 -0
  407. package/types/views/Matrix.d.ts.map +1 -0
  408. package/types/views/ganttMath.d.ts +4 -0
  409. package/types/views/ganttMath.d.ts.map +1 -1
  410. package/types/views/index.d.ts +3 -1
  411. package/types/views/index.d.ts.map +1 -1
  412. package/types/views/matrixMath.d.ts +114 -0
  413. package/types/views/matrixMath.d.ts.map +1 -0
@@ -6,6 +6,12 @@
6
6
  * resolved size class rides a context down, so an inner scaffold reflows with
7
7
  * the outer one instead of splitting inside a stacked column.
8
8
  *
9
+ * The seam runs on one axis. `orientation="horizontal"` (the default) puts the
10
+ * panes side by side; `orientation="vertical"` puts `secondary` under
11
+ * `primary` (a console under a source pane, an editor under a page). The sash,
12
+ * its clamps, keyboard handling and the controlled-fraction contract are the
13
+ * same code with the axis swapped; only the dimension it reads changes.
14
+ *
9
15
  * Devs declare pane roles; the scaffold picks 1 vs 2 columns from the
10
16
  * canonical layout size class (`expanded` @ 860 = two-pane budget).
11
17
  *
@@ -64,10 +70,17 @@ const DEFAULT_MAX_FRACTION = 0.8;
64
70
  // ── PaneScaffold ──────────────────────────────────────────────────────────
65
71
 
66
72
  export type PaneRole = "primary" | "secondary";
73
+ export type PaneOrientation = "horizontal" | "vertical";
67
74
 
68
75
  export interface PaneScaffoldProps extends Omit<XStackProps, "children"> {
69
76
  primary: ReactNode;
70
77
  secondary?: ReactNode;
78
+ /**
79
+ * Axis of the seam. `horizontal` (default) sets the panes side by side;
80
+ * `vertical` docks `secondary` under `primary`. A vertical scaffold splits
81
+ * the height its parent gives it, so the parent must be bounded.
82
+ */
83
+ orientation?: PaneOrientation;
71
84
  /**
72
85
  * Which pane to show when `narrowLayout` is `swap`. Default: `primary`.
73
86
  * List-detail on compact typically flips to `secondary` once an item is
@@ -122,6 +135,7 @@ const PaneSizeClassContext = createContext<LayoutSizeClass | null>(null);
122
135
  export function PaneScaffold({
123
136
  primary,
124
137
  secondary,
138
+ orientation = "horizontal",
125
139
  activePane: activePaneProp,
126
140
  narrowLayout: narrowLayoutProp,
127
141
  maxPanes: maxPanesProp,
@@ -150,6 +164,7 @@ export function PaneScaffold({
150
164
  // secondary by default leaves that content unreachable on a phone.
151
165
  const narrowLayout = narrowLayoutProp ?? (activePaneProp === undefined ? "stack" : "swap");
152
166
  const stacked = !split && hasSecondary && narrowLayout === "stack";
167
+ const vertical = orientation === "vertical";
153
168
  const [primaryFlex, secondaryFlex] = paneFlex;
154
169
 
155
170
  // flexBasis auto, not the flex:1 shorthand's 0%: react-native-web resets
@@ -170,6 +185,7 @@ export function PaneScaffold({
170
185
  data-testid="pane-scaffold"
171
186
  data-panes="2"
172
187
  data-pane-layout="stack"
188
+ data-orientation={orientation}
173
189
  data-size-class={sizeClass}
174
190
  data-sash="false"
175
191
  {...rest}
@@ -212,6 +228,7 @@ export function PaneScaffold({
212
228
  data-testid="pane-scaffold"
213
229
  data-panes="1"
214
230
  data-pane-layout="single"
231
+ data-orientation={orientation}
215
232
  data-size-class={sizeClass}
216
233
  {...rest}
217
234
  >
@@ -221,6 +238,7 @@ export function PaneScaffold({
221
238
  } else {
222
239
  content = (
223
240
  <XStack
241
+ flexDirection={vertical ? "column" : "row"}
224
242
  flexGrow={1}
225
243
  flexShrink={1}
226
244
  flexBasis="auto"
@@ -233,12 +251,14 @@ export function PaneScaffold({
233
251
  data-testid="pane-scaffold"
234
252
  data-panes="2"
235
253
  data-pane-layout="split"
254
+ data-orientation={orientation}
236
255
  data-size-class={sizeClass}
237
256
  data-sash={resizable ? "true" : "false"}
238
257
  {...rest}
239
258
  >
240
259
  {resizable ? (
241
260
  <ResizablePanes
261
+ vertical={vertical}
242
262
  primary={primary}
243
263
  secondary={secondary}
244
264
  primaryFlex={primaryFlex}
@@ -254,7 +274,7 @@ export function PaneScaffold({
254
274
  flex={primaryFlex}
255
275
  minWidth={0}
256
276
  minHeight={0}
257
- {...(gapped ? undefined : paneHairlineEnd)}
277
+ {...(gapped ? undefined : vertical ? paneHairlineBottom : paneHairlineEnd)}
258
278
  data-testid="pane-primary"
259
279
  >
260
280
  {primary}
@@ -287,7 +307,21 @@ function clampFraction(value: number, min: number, max: number): number {
287
307
  return Math.min(max, Math.max(min, value));
288
308
  }
289
309
 
310
+ function axisSize(
311
+ vertical: boolean,
312
+ rect: { width?: number; height?: number } | null | undefined,
313
+ ): number {
314
+ return (vertical ? rect?.height : rect?.width) ?? 0;
315
+ }
316
+
317
+ function pointerPos(vertical: boolean, e: any): number {
318
+ return vertical
319
+ ? (e.clientY ?? e.nativeEvent?.pageY ?? 0)
320
+ : (e.clientX ?? e.nativeEvent?.pageX ?? 0);
321
+ }
322
+
290
323
  function ResizablePanes({
324
+ vertical,
291
325
  primary,
292
326
  secondary,
293
327
  primaryFlex,
@@ -297,6 +331,7 @@ function ResizablePanes({
297
331
  fraction: fractionProp,
298
332
  onFractionChange,
299
333
  }: {
334
+ vertical: boolean;
300
335
  primary: ReactNode;
301
336
  secondary: ReactNode;
302
337
  primaryFlex: number;
@@ -308,23 +343,24 @@ function ResizablePanes({
308
343
  }) {
309
344
  const sashId = useId();
310
345
  const rtl = useDirection() === "rtl";
311
- const dirSign = rtl ? -1 : 1;
346
+ // RTL mirrors the inline axis only; a vertical seam has no mirror.
347
+ const dirSign = !vertical && rtl ? -1 : 1;
312
348
  const defaultFraction = primaryFlex / Math.max(primaryFlex + secondaryFlex, 1);
313
349
  const [uncontrolled, setUncontrolled] = useState(defaultFraction);
314
350
  const fraction = clampFraction(fractionProp ?? uncontrolled, minFraction, maxFraction);
315
351
  const [hot, setHot] = useState(false);
316
352
  const [kbFocus, setKbFocus] = useState(false);
317
353
  const [dragging, setDragging] = useState(false);
318
- const widthRef = useRef(0);
354
+ const sizeRef = useRef(0);
319
355
  const rowRef = useRef<any>(null);
320
- const dragRef = useRef<{ startX: number; startFraction: number; moved: boolean } | null>(null);
356
+ const dragRef = useRef<{ start: number; startFraction: number; moved: boolean } | null>(null);
321
357
  const lastTapRef = useRef(0);
358
+ const resizeCursor = vertical ? "row-resize" : "col-resize";
322
359
 
323
- const measureWidth = () => {
324
- const node = rowRef.current;
325
- const rect = node?.getBoundingClientRect?.();
326
- if (rect?.width) widthRef.current = rect.width;
327
- };
360
+ const measureSize = useCallback(() => {
361
+ const size = axisSize(vertical, rowRef.current?.getBoundingClientRect?.());
362
+ if (size) sizeRef.current = size;
363
+ }, [vertical]);
328
364
 
329
365
  ensureKeyboardModalityTracking();
330
366
 
@@ -356,22 +392,16 @@ function ResizablePanes({
356
392
  const prevUserSelect = document.body.style.userSelect;
357
393
  const prevCursor = document.documentElement.style.cursor;
358
394
  document.body.style.userSelect = "none";
359
- document.documentElement.style.cursor = "col-resize";
395
+ document.documentElement.style.cursor = resizeCursor;
360
396
 
361
397
  const onMove = (e: PointerEvent) => {
362
398
  const session = dragRef.current;
363
- let width = widthRef.current;
364
- if (width <= 0) {
365
- const rect = rowRef.current?.getBoundingClientRect?.();
366
- if (rect?.width) {
367
- width = rect.width;
368
- widthRef.current = width;
369
- }
370
- }
371
- if (!session || width <= 0) return;
372
- const dx = (e.clientX - session.startX) * dirSign;
373
- if (Math.abs(dx) > 2) session.moved = true;
374
- commit(session.startFraction + dx / width);
399
+ if (sizeRef.current <= 0) measureSize();
400
+ const size = sizeRef.current;
401
+ if (!session || size <= 0) return;
402
+ const delta = (pointerPos(vertical, e) - session.start) * dirSign;
403
+ if (Math.abs(delta) > 2) session.moved = true;
404
+ commit(session.startFraction + delta / size);
375
405
  };
376
406
  window.addEventListener("pointermove", onMove);
377
407
  window.addEventListener("pointerup", finishDrag);
@@ -383,7 +413,7 @@ function ResizablePanes({
383
413
  window.removeEventListener("pointerup", finishDrag);
384
414
  window.removeEventListener("pointercancel", finishDrag);
385
415
  };
386
- }, [commit, dirSign, dragging, finishDrag]);
416
+ }, [commit, dirSign, dragging, finishDrag, measureSize, resizeCursor, vertical]);
387
417
 
388
418
  const onSashPointerDown = (e: any) => {
389
419
  if (e.button != null && e.button !== 0) return;
@@ -394,9 +424,9 @@ function ResizablePanes({
394
424
  } catch {
395
425
  /* native / no capture */
396
426
  }
397
- measureWidth();
427
+ measureSize();
398
428
  dragRef.current = {
399
- startX: e.clientX ?? e.nativeEvent?.pageX ?? 0,
429
+ start: pointerPos(vertical, e),
400
430
  startFraction: fraction,
401
431
  moved: false,
402
432
  };
@@ -406,21 +436,23 @@ function ResizablePanes({
406
436
 
407
437
  const onSashPointerMove = (e: any) => {
408
438
  if (!dragRef.current || isWeb) return;
409
- const width = widthRef.current;
410
- if (width <= 0) return;
411
- const x = e.clientX ?? e.nativeEvent?.pageX ?? 0;
412
- const dx = (x - dragRef.current.startX) * dirSign;
413
- if (Math.abs(dx) > 2) dragRef.current.moved = true;
414
- commit(dragRef.current.startFraction + dx / width);
439
+ const size = sizeRef.current;
440
+ if (size <= 0) return;
441
+ const delta = (pointerPos(vertical, e) - dragRef.current.start) * dirSign;
442
+ if (Math.abs(delta) > 2) dragRef.current.moved = true;
443
+ commit(dragRef.current.startFraction + delta / size);
415
444
  };
416
445
 
446
+ const keyBack = vertical ? "ArrowUp" : "ArrowLeft";
447
+ const keyForward = vertical ? "ArrowDown" : "ArrowRight";
448
+
417
449
  const onSashKeyDown = (e: any) => {
418
450
  const key = e.key as string;
419
451
  const step = e.shiftKey ? FRACTION_STEP_LARGE : FRACTION_STEP;
420
- if (key === "ArrowLeft") {
452
+ if (key === keyBack) {
421
453
  e.preventDefault?.();
422
454
  commit(fraction - step * dirSign);
423
- } else if (key === "ArrowRight") {
455
+ } else if (key === keyForward) {
424
456
  e.preventDefault?.();
425
457
  commit(fraction + step * dirSign);
426
458
  } else if (key === "Home") {
@@ -437,10 +469,12 @@ function ResizablePanes({
437
469
 
438
470
  const percent = Math.round(fraction * 100);
439
471
  const lineHot = hot || dragging || kbFocus;
472
+ const sashOverhang = -(SASH_VISUAL - hairlineWidth) / 2;
440
473
 
441
474
  return (
442
475
  <XStack
443
476
  ref={rowRef}
477
+ flexDirection={vertical ? "column" : "row"}
444
478
  flexGrow={1}
445
479
  flexShrink={1}
446
480
  flexBasis="auto"
@@ -449,7 +483,7 @@ function ResizablePanes({
449
483
  width="100%"
450
484
  alignItems="stretch"
451
485
  onLayout={(e) => {
452
- widthRef.current = e.nativeEvent.layout.width;
486
+ sizeRef.current = axisSize(vertical, e.nativeEvent.layout);
453
487
  }}
454
488
  >
455
489
  <YStack
@@ -463,7 +497,7 @@ function ResizablePanes({
463
497
  {primary}
464
498
  </YStack>
465
499
  <YStack
466
- width={hairlineWidth}
500
+ {...(vertical ? { height: hairlineWidth } : { width: hairlineWidth })}
467
501
  flexGrow={0}
468
502
  flexShrink={0}
469
503
  alignSelf="stretch"
@@ -472,16 +506,26 @@ function ResizablePanes({
472
506
  >
473
507
  <YStack
474
508
  position="absolute"
475
- top={0}
476
- bottom={0}
477
- width={SASH_VISUAL}
478
- left={-(SASH_VISUAL - hairlineWidth) / 2}
479
- alignItems="center"
480
- cursor="col-resize"
509
+ {...(vertical
510
+ ? {
511
+ left: 0,
512
+ right: 0,
513
+ height: SASH_VISUAL,
514
+ top: sashOverhang,
515
+ justifyContent: "center" as const,
516
+ }
517
+ : {
518
+ top: 0,
519
+ bottom: 0,
520
+ width: SASH_VISUAL,
521
+ left: sashOverhang,
522
+ alignItems: "center" as const,
523
+ })}
524
+ cursor={resizeCursor}
481
525
  userSelect="none"
482
526
  tabIndex={0}
483
527
  role="separator"
484
- aria-orientation="vertical"
528
+ aria-orientation={vertical ? "horizontal" : "vertical"}
485
529
  aria-controls={sashId}
486
530
  aria-valuemin={Math.round(minFraction * 100)}
487
531
  aria-valuemax={Math.round(maxFraction * 100)}
@@ -508,12 +552,21 @@ function ResizablePanes({
508
552
  onBlur={() => setKbFocus(false)}
509
553
  onKeyDown={onSashKeyDown}
510
554
  >
511
- <YStack
512
- flex={1}
513
- width={lineHot ? 2 : hairlineWidth}
514
- backgroundColor={lineHot ? "$accentBackground" : "$borderColor"}
515
- {...(lineHot ? undefined : hairline.vline)}
516
- />
555
+ {vertical ? (
556
+ <YStack
557
+ alignSelf="stretch"
558
+ height={lineHot ? 2 : hairlineWidth}
559
+ backgroundColor={lineHot ? "$accentBackground" : "$borderColor"}
560
+ {...(lineHot ? undefined : hairline.line)}
561
+ />
562
+ ) : (
563
+ <YStack
564
+ flex={1}
565
+ width={lineHot ? 2 : hairlineWidth}
566
+ backgroundColor={lineHot ? "$accentBackground" : "$borderColor"}
567
+ {...(lineHot ? undefined : hairline.vline)}
568
+ />
569
+ )}
517
570
  </YStack>
518
571
  </YStack>
519
572
  <YStack
@@ -161,3 +161,23 @@ describe("density unpinned (LC-76)", () => {
161
161
  expect(screen.getByTestId("inner-section").getAttribute("data-density")).toBe("compact");
162
162
  });
163
163
  });
164
+
165
+ describe("PageSection surface declares its container cap (DG-RAD-04)", () => {
166
+ it("the painted surface carries the knob stops its radius resolved from", () => {
167
+ renderWithProviders(
168
+ <Preset overrides={{ borderRadius: "full", space: "small" }}>
169
+ <PageSection surface title="Details" data-testid="details">
170
+ <></>
171
+ </PageSection>
172
+ </Preset>,
173
+ );
174
+ const surface = document.querySelector('[data-constraint-container="PageSection"]');
175
+ expect(surface?.getAttribute("data-radius-knob")).toBe("full");
176
+ expect(surface?.getAttribute("data-space-knob")).toBe("small");
177
+ });
178
+
179
+ it("a section without a surface makes no claim", () => {
180
+ renderWithProviders(<PageSection title="Plain" />);
181
+ expect(document.querySelector("[data-constraint-container]")).toBeNull();
182
+ });
183
+ });
@@ -19,6 +19,7 @@ import {
19
19
  MIN_PRESS_TARGET,
20
20
  Preset,
21
21
  Surface,
22
+ containerCapProps,
22
23
  hairline,
23
24
  layoutBreakpoints,
24
25
  resolvePageTitleScale,
@@ -396,6 +397,7 @@ export function PageSection({
396
397
  ...knobProps.surface,
397
398
  ...knobProps.containerRadius,
398
399
  ...knobProps.panelPadding,
400
+ ...containerCapProps("PageSection", knobProps.borderRadius.borderRadius, knobProps.space),
399
401
  } as Partial<YStackProps>)
400
402
  : {};
401
403
 
@@ -8,6 +8,7 @@ import {
8
8
  useReadableTextOn,
9
9
  useResolvedKnobs,
10
10
  wasKeyboardFocus,
11
+ transitionProps,
11
12
  } from "@multiplatform.one/theme";
12
13
  import type React from "react";
13
14
  import { Fragment, useId, useState } from "react";
@@ -168,9 +169,7 @@ export function Sidebar({
168
169
  cursor={pressable ? "pointer" : "default"}
169
170
  userSelect="none"
170
171
  onPress={item.onPress}
171
- {...(knobProps.transition
172
- ? { transition: knobProps.transition }
173
- : undefined)}
172
+ {...transitionProps(knobProps.transition)}
174
173
  {...(pressable
175
174
  ? {
176
175
  role: "button" as const,
@@ -28,14 +28,16 @@ afterEach(cleanup);
28
28
  // same hole MPO-40 / MPO-44 / MPO-48 all fell through, one layer further in:
29
29
  // the fragment reaches the frame and still never reaches the pixel.
30
30
 
31
- /** Reference §8, tamagui-rendered-reference.md — the one dialog shadow. */
32
- const referenceOverlayShadow = "0px 12px 24px rgba(0,0,0,0.12)";
31
+ /** Reference §8 dialog shadow: the overlay ladder's `$5` stop (MPO-99). */
32
+ const dialogStopPaint = "0 12px 24px rgba(0,0,0,0.12)";
33
33
  /** Same §8 geometry and alpha, hue inverted — LC-85 forbids a dark umbra. */
34
- const referenceOverlayShadowDark = "0px 12px 24px rgba(255,255,255,0.12)";
35
- /** `webShadowLight.$1` — the in-page control stop every Button carries. */
36
- const controlStopPaint = "0 1px 2px rgba(0,0,0,0.12), 0 0 1px rgba(0,0,0,0.08)";
37
- /** `webShadowLight.$2` — `elevatedSurface`'s own overlay paint. */
38
- const elevatedSurfacePaint = "0 3px 6px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.10)";
34
+ const dialogStopPaintDark = "0 12px 24px rgba(255,255,255,0.12)";
35
+ /** Reference §8 popper shadow: the overlay ladder's `$3` stop (MPO-99). */
36
+ const popperStopPaint = "0 4px 8px rgba(0,0,0,0.10), 0 12px 32px rgba(0,0,0,0.08)";
37
+ /** `webShadowLight.$2` — the overlay ladder's default `small` stop. */
38
+ const overlaySmallPaint = "0 3px 6px rgba(0,0,0,0.15), 0 2px 4px rgba(0,0,0,0.10)";
39
+ /** `webShadowLight.$4` — the control stop at elevation large. */
40
+ const controlLargePaint = "0 10px 20px rgba(0,0,0,0.15), 0 3px 6px rgba(0,0,0,0.10)";
39
41
 
40
42
  function frame(id: string): HTMLElement {
41
43
  const el = document.querySelector(`[data-testid="${id}"]`);
@@ -61,9 +63,9 @@ function bgAtoms(id: string): string[] {
61
63
  .filter((c) => c.startsWith("_bg-"));
62
64
  }
63
65
 
64
- function renderDialogsBesideAButton() {
66
+ function renderDialogsBesideAButton(elevation?: "small" | "medium" | "large") {
65
67
  renderWithProviders(
66
- <Preset>
68
+ <Preset overrides={elevation ? { elevation } : undefined}>
67
69
  <Button testID="control">Save</Button>
68
70
  <Dialog modal open>
69
71
  <Dialog.Portal>
@@ -79,61 +81,49 @@ function renderDialogsBesideAButton() {
79
81
  );
80
82
  }
81
83
 
82
- describe("overlay elevation is a different distance off the surface (MPO-49)", () => {
83
- it("DialogContent PAINTS the reference §8 shadow, not the $2 fragment underneath it", () => {
84
- renderDialogsBesideAButton();
85
- expect(paintedShadow("dialog")).toBe(referenceOverlayShadow);
86
- expect(paintedShadow("dialog")).not.toBe(elevatedSurfacePaint);
87
- expect(paintedShadow("dialog")).not.toBe(controlStopPaint);
84
+ describe("overlay elevation is a different distance off the surface (MPO-49, MPO-96, MPO-99)", () => {
85
+ it("DialogContent paints the overlay ladder, reaching the reference §8 dialog shadow at large", () => {
86
+ renderDialogsBesideAButton("large");
87
+ expect(paintedShadow("dialog")).toBe(dialogStopPaint);
88
+ expect(paintedShadow("dialog")).not.toBe(paintedShadow("control"));
89
+ expect(paintedShadow("control")).toBe(controlLargePaint);
90
+ });
91
+
92
+ it("at medium the overlay paints the §8 popper stop, not the control's $2", () => {
93
+ renderDialogsBesideAButton("medium");
94
+ expect(paintedShadow("dialog")).toBe(popperStopPaint);
95
+ expect(paintedShadow("dialog")).not.toBe(paintedShadow("control"));
88
96
  });
89
97
 
90
- it("the atom and the inline style agree — no dead §8 class over a live $2 paint", () => {
98
+ it("at the default stop the control is flat and the overlay still lifts", () => {
91
99
  renderDialogsBesideAButton();
92
- // The atom half alone does NOT discriminate: it reads `_bxsh-0px12px24px…`
93
- // with the defect present too, which is why a class-only probe passes
94
- // against a frame painting `$2`. Pair it with the painted value.
100
+ expect(paintedShadow("control")).toBe("");
101
+ expect(paintedShadow("dialog")).toBe(overlaySmallPaint);
102
+ });
103
+
104
+ it("the atom and the inline style agree — no dead class under a different live paint", () => {
105
+ renderDialogsBesideAButton("large");
106
+ // The atom half alone does not discriminate (a class can name one shadow
107
+ // while the inline style paints another), so pair it with the painted value.
95
108
  expect(shadowAtoms("dialog")).toHaveLength(1);
96
109
  expect(shadowAtoms("dialog")[0]).toMatch(/^_bxsh-0px12px24px/);
97
110
  expect(paintedShadow("dialog")).toContain("12px 24px");
98
- });
99
-
100
- it("the dialog shadow differs from the Button shadow, and the Button keeps the $1 stop", () => {
101
- renderDialogsBesideAButton();
102
- // "differs" alone does not discriminate: with the defect present the
103
- // dialog paints `$2` and the Button `$1`, which also differ. The §8 value
104
- // itself is pinned by the first case in this file; here the control side
105
- // is pinned to `$1` so a Button regression cannot fake this one either.
106
- expect(paintedShadow("control")).toBe(controlStopPaint);
107
- expect(paintedShadow("dialog")).not.toBe(paintedShadow("control"));
108
111
  expect(shadowAtoms("dialog")).not.toEqual(shadowAtoms("control"));
109
112
  });
110
113
 
111
- it("AlertDialogContent wears the same §8 shadow — one dialog row, one distance", () => {
114
+ it("AlertDialogContent wears the same ladder stop as DialogContent — one dialog row, one distance", () => {
112
115
  // Tamagui's AlertDialog.Content IS Dialog.Content, and reference §8
113
116
  // carries a single dialog row. confirm-dialog-{destructive,gated,warning}
114
117
  // render through this frame.
115
- renderDialogsBesideAButton();
116
- expect(paintedShadow("alertdialog")).toBe(referenceOverlayShadow);
118
+ renderDialogsBesideAButton("large");
119
+ expect(paintedShadow("alertdialog")).toBe(dialogStopPaint);
117
120
  expect(paintedShadow("alertdialog")).toBe(paintedShadow("dialog"));
118
121
  });
119
122
 
120
123
  it("dark inverts the hue and keeps the §8 geometry; the ground steps up the ramp (LC-85)", () => {
121
- renderWithProviders(
122
- <Preset>
123
- <Dialog modal open>
124
- <Dialog.Portal>
125
- <DialogContent testID="dialog">dialog</DialogContent>
126
- </Dialog.Portal>
127
- </Dialog>
128
- </Preset>,
129
- );
130
- expect(paintedShadow("dialog")).toBe(referenceOverlayShadow);
131
- expect(bgAtoms("dialog")).toEqual(["_bg-background"]);
132
- cleanup();
133
-
134
124
  renderWithProviders(
135
125
  <Theme name="dark">
136
- <Preset>
126
+ <Preset overrides={{ elevation: "large" }}>
137
127
  <Dialog modal open>
138
128
  <Dialog.Portal>
139
129
  <DialogContent testID="dialog">dialog</DialogContent>
@@ -143,12 +133,10 @@ describe("overlay elevation is a different distance off the surface (MPO-49)", (
143
133
  </Theme>,
144
134
  );
145
135
  // LC-85 DARK-ELEVATION-TINT: light-coloured shadow, never a black umbra.
146
- expect(paintedShadow("dialog")).toBe(referenceOverlayShadowDark);
147
- expect(paintedShadow("dialog")).not.toBe(referenceOverlayShadow);
136
+ expect(paintedShadow("dialog")).toBe(dialogStopPaintDark);
148
137
  expect(paintedShadow("dialog")).not.toMatch(/rgba\(0,\s*0,\s*0/);
149
138
  // resolveKnobs owns the dark ground: `overlayFill` steps the filled rest
150
- // fill up the ramp under dark + elevation (LC-85). Asserted so a later
151
- // change to that rule shows up here rather than silently on a board.
152
- expect(bgAtoms("dialog")).toEqual(["_bg-color2"]);
139
+ // fill up the ramp under dark + elevation (LC-85).
140
+ expect(bgAtoms("dialog")).toEqual(["_bg-color4"]);
153
141
  });
154
142
  });
@@ -88,14 +88,14 @@ describe("SheetFrame overlay chrome", () => {
88
88
  });
89
89
 
90
90
  describe("DialogContent overlay elevation (MPO-49)", () => {
91
- it("binds overlayElevation, elevate=false, and the §8 overlay shadow — not Tamagui $1 elevate", () => {
91
+ it("binds the overlay ladder through elevatedSurface with elevate=false, and hardcodes no shadow (MPO-99)", () => {
92
92
  const src = readFileSync(join(dirname(fileURLToPath(import.meta.url)), "surfaces.tsx"), "utf8");
93
93
  const start = src.indexOf("// ── DialogContent");
94
94
  const end = src.indexOf("// ── DialogOverlay");
95
95
  const dialog = src.slice(start, end);
96
96
  expect(dialog).toContain("elevate={false}");
97
- expect(dialog).toContain("overlayElevationShadow");
98
- expect(dialog).toContain("rgba(0,0,0,0.12)");
97
+ expect(dialog).not.toContain("overlayElevationShadow");
98
+ expect(dialog).not.toContain("rgba(0,0,0,0.12)");
99
99
  expect(dialog).toContain("elevatedSurface");
100
100
  expect(dialog).toContain("containerRadius");
101
101
  expect(dialog).toContain("panelPadding");
@@ -122,9 +122,12 @@ describe("DialogContent overlay elevation (MPO-49)", () => {
122
122
  // dialog elevation defect Button/control `$1` -> `_bxsh-0px1px2px…`
123
123
  // fixed reference §8 -> `_bxsh-0px12px24px…`
124
124
  //
125
+ // Since MPO-99 the §8 value is the overlay ladder's `$5` stop, which the
126
+ // dialog reaches at elevation large; the control paints `$4` there.
127
+ //
125
128
  // A "differs from the Button" assertion does NOT discriminate: the Button
126
129
  // paints `0 6px 12px` from its own source in both states, so that comparison
127
- // passes with the defect present. Assert against the $1 CONTROL stop.
130
+ // passes with the defect present. Assert against the CONTROL stop.
128
131
 
129
132
  function atomsWithPrefix(el: Element | null, prefix: string): string[] {
130
133
  if (!el) return [];
@@ -134,9 +137,9 @@ function atomsWithPrefix(el: Element | null, prefix: string): string[] {
134
137
  .sort();
135
138
  }
136
139
 
137
- /** The `$1` control paint — `webShadowLight.$1`, "0 1px 2px …" (resolveKnobs.ts). */
138
- const controlStopShadowAtom = /^_bxsh-0px1px2px/;
139
- /** Rendered reference §8 DialogContent — `rgba(0,0,0,0.12) 0 12px 24px`. */
140
+ /** The `$4` control paint at elevation large — `webShadowLight.$4`, "0 10px 20px …". */
141
+ const controlStopShadowAtom = /^_bxsh-0px10px20px/;
142
+ /** The `$5` overlay stop at elevation large — reference §8 dialog shadow, "0 12px 24px …". */
140
143
  const overlayStopShadowAtom = /^_bxsh-0px12px24px/;
141
144
 
142
145
  describe("surfaces address $background at the FRAME (MPO-19 X5/X6)", () => {
@@ -164,9 +167,9 @@ describe("surfaces address $background at the FRAME (MPO-19 X5/X6)", () => {
164
167
  });
165
168
 
166
169
  describe("DialogContent paints the OVERLAY elevation stop, not the control one (MPO-49)", () => {
167
- it("renders the reference §8 shadow and not the Button $1 stop", () => {
170
+ it("renders the reference §8 shadow at elevation large and not the Button $4 stop (MPO-99)", () => {
168
171
  renderWithProviders(
169
- <Preset>
172
+ <Preset overrides={{ elevation: "large" }}>
170
173
  <Button testID="mpo-button-control">Save</Button>
171
174
  <Dialog modal open>
172
175
  <Dialog.Portal>
@@ -184,7 +187,7 @@ describe("DialogContent paints the OVERLAY elevation stop, not the control one (
184
187
  const dialogShadow = atomsWithPrefix(dialog, "_bxsh-");
185
188
  expect(dialogShadow, "DialogContent paints exactly one shadow atom").toHaveLength(1);
186
189
  expect(dialogShadow[0], "dialog wears the §8 overlay shadow").toMatch(overlayStopShadowAtom);
187
- expect(dialogShadow[0], "dialog must not wear the $1 control stop").not.toMatch(
190
+ expect(dialogShadow[0], "dialog must not wear the $4 control stop").not.toMatch(
188
191
  controlStopShadowAtom,
189
192
  );
190
193
  expect(dialogShadow, "dialog and control are different distances off the surface").not.toEqual(
package/src/surfaces.tsx CHANGED
@@ -7,7 +7,6 @@ import {
7
7
  Popover,
8
8
  Sheet,
9
9
  View,
10
- isWeb,
11
10
  type DialogContentProps as TamaguiDialogContentProps,
12
11
  type DialogOverlayProps as TamaguiDialogOverlayProps,
13
12
  type TamaguiElement,
@@ -103,42 +102,16 @@ export const DialogContent = forwardRef<
103
102
  );
104
103
  });
105
104
 
106
- /**
107
- * Reference §8 overlay shadow — rgba(0,0,0,0.12) 0 12px 24px. Not Button $1,
108
- * and not the `$2` fragment `elevatedSurface` carries either: that fragment's
109
- * web paint arrives as an INLINE style (`elevationPaint` emits
110
- * `style.boxShadow`, and Tamagui stamps `!important` only on pseudo atoms),
111
- * so a shadow expressed only as `shadow*` props is a dead class atom under a
112
- * live `$2` paint. The §8 value must land on the `style` prop too, replacing
113
- * the fragment's. Dark inverts the hue and keeps the geometry — LC-85
114
- * DARK-ELEVATION-TINT forbids a black umbra on a dark ground.
115
- */
116
- const overlayElevationShadow = {
117
- light: {
118
- shadowColor: "rgba(0,0,0,0.12)",
119
- shadowOffset: { width: 0, height: 12 },
120
- shadowOpacity: 1,
121
- shadowRadius: 24,
122
- ...(isWeb ? { style: { boxShadow: "0px 12px 24px rgba(0,0,0,0.12)" } } : null),
123
- },
124
- dark: {
125
- shadowColor: "rgba(255,255,255,0.12)",
126
- shadowOffset: { width: 0, height: 12 },
127
- shadowOpacity: 1,
128
- shadowRadius: 24,
129
- ...(isWeb ? { style: { boxShadow: "0px 12px 24px rgba(255,255,255,0.12)" } } : null),
130
- },
131
- } as const;
132
-
133
105
  const DialogContentInner = forwardRef<
134
106
  TamaguiElement,
135
107
  TamaguiDialogContentProps & { children?: ReactNode }
136
108
  >(function DialogContentInner({ children, ...props }, ref) {
137
109
  const { knobProps } = useResolvedKnobs({ component: "DialogContent" });
138
110
  // ThemeableStack unstyled:false defaults `elevate: true`, which paints
139
- // getElevation(size) — `$true` is the same $1 stop every Button carries.
140
- // Bind the §8 overlay shadow instead. Geometry (panelPadding 18,
141
- // containerRadius 9, border 1px) stays on the recipe fragments below.
111
+ // getElevation(size) — `$true` is a control stop. `elevate={false}` leaves
112
+ // the overlay ladder in `elevatedSurface` as the only shadow (MPO-99).
113
+ // Geometry (panelPadding 18, containerRadius 9, border 1px) stays on the
114
+ // recipe fragments below.
142
115
  return (
143
116
  <Dialog.Content
144
117
  ref={ref}
@@ -147,7 +120,6 @@ const DialogContentInner = forwardRef<
147
120
  {...knobProps.panelPadding}
148
121
  {...knobProps.gap}
149
122
  elevate={false}
150
- {...overlayElevationShadow[knobProps.scheme]}
151
123
  transition={knobProps.transition}
152
124
  enterStyle={overlayEnterExit}
153
125
  exitStyle={overlayEnterExit}
@@ -227,7 +199,6 @@ const AlertDialogContentInner = forwardRef<
227
199
  {...knobProps.panelPadding}
228
200
  {...knobProps.gap}
229
201
  elevate={false}
230
- {...overlayElevationShadow[knobProps.scheme]}
231
202
  transition={knobProps.transition}
232
203
  enterStyle={overlayEnterExit}
233
204
  exitStyle={overlayEnterExit}