@multiplatform.one/components 7.78.0 → 7.79.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 (466) 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.native.js.map +1 -1
  4. package/dist/cjs/AnimateHeight/index.native.js.map +1 -1
  5. package/dist/cjs/Avatar/getInitials.native.js.map +1 -1
  6. package/dist/cjs/Avatar/index.native.js.map +1 -1
  7. package/dist/cjs/Badge/index.native.js.map +1 -1
  8. package/dist/cjs/Button.native.js.map +1 -1
  9. package/dist/cjs/Card.native.js.map +1 -1
  10. package/dist/cjs/CardFooter.native.js.map +1 -1
  11. package/dist/cjs/CardHeader.native.js.map +1 -1
  12. package/dist/cjs/Carousel/index.native.js +3 -3
  13. package/dist/cjs/Carousel/index.native.js.map +1 -1
  14. package/dist/cjs/Chip/index.native.js.map +1 -1
  15. package/dist/cjs/Collapsible.native.js.map +1 -1
  16. package/dist/cjs/ContextMenu/index.native.js.map +1 -1
  17. package/dist/cjs/CopyField/CopyMenuButton.native.js +1 -1
  18. package/dist/cjs/CopyField/CopyMenuButton.native.js.map +1 -1
  19. package/dist/cjs/CopyField/index.native.js.map +1 -1
  20. package/dist/cjs/Dialog.native.js.map +1 -1
  21. package/dist/cjs/Diff/diff.cjs +84 -0
  22. package/dist/cjs/Diff/diff.native.js +108 -0
  23. package/dist/cjs/Diff/diff.native.js.map +1 -0
  24. package/dist/cjs/Diff/index.cjs +174 -0
  25. package/dist/cjs/Diff/index.native.js +181 -0
  26. package/dist/cjs/Diff/index.native.js.map +1 -0
  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/DropdownMenu/menuSettle.native.js.map +1 -1
  30. package/dist/cjs/ElapsedProgress/index.cjs +102 -0
  31. package/dist/cjs/ElapsedProgress/index.native.js +112 -0
  32. package/dist/cjs/ElapsedProgress/index.native.js.map +1 -0
  33. package/dist/cjs/ErrorBoundary/index.native.js.map +1 -1
  34. package/dist/cjs/Heading.native.js.map +1 -1
  35. package/dist/cjs/Kbd/index.native.js.map +1 -1
  36. package/dist/cjs/Kbd/keys.native.js.map +1 -1
  37. package/dist/cjs/Lightbox/MediaControl.native.js.map +1 -1
  38. package/dist/cjs/Lightbox/index.gnome.native.js.map +1 -1
  39. package/dist/cjs/Lightbox/index.native.js +1 -1
  40. package/dist/cjs/Lightbox/shared.native.js.map +1 -1
  41. package/dist/cjs/Lightbox/useLightbox.native.js.map +1 -1
  42. package/dist/cjs/MachineLiteral/index.cjs +98 -0
  43. package/dist/cjs/MachineLiteral/index.native.js +102 -0
  44. package/dist/cjs/MachineLiteral/index.native.js.map +1 -0
  45. package/dist/cjs/Material/blur.cjs +34 -0
  46. package/dist/cjs/Material/blur.native.js +100 -0
  47. package/dist/cjs/Material/blur.native.js.map +1 -0
  48. package/dist/cjs/Material/index.cjs +9 -3
  49. package/dist/cjs/Material/index.native.js +9 -3
  50. package/dist/cjs/Material/index.native.js.map +1 -1
  51. package/dist/cjs/Meter/index.cjs +3 -1
  52. package/dist/cjs/Meter/index.native.js +4 -2
  53. package/dist/cjs/Meter/index.native.js.map +1 -1
  54. package/dist/cjs/Meter/meter.native.js.map +1 -1
  55. package/dist/cjs/OverflowRow/index.native.js +1 -1
  56. package/dist/cjs/OverflowRow/index.native.js.map +1 -1
  57. package/dist/cjs/Pagination.native.js +1 -1
  58. package/dist/cjs/Pagination.native.js.map +1 -1
  59. package/dist/cjs/Popover.native.js +1 -1
  60. package/dist/cjs/Popover.native.js.map +1 -1
  61. package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
  62. package/dist/cjs/Quote/index.native.js.map +1 -1
  63. package/dist/cjs/SchemeToggle/index.native.js +1 -1
  64. package/dist/cjs/SchemeToggle/index.native.js.map +1 -1
  65. package/dist/cjs/ScrollView/revealFocusedField.native.js.map +1 -1
  66. package/dist/cjs/Separator/index.native.js.map +1 -1
  67. package/dist/cjs/Sheet.native.js.map +1 -1
  68. package/dist/cjs/SheetModal/SheetHeader.native.js.map +1 -1
  69. package/dist/cjs/SheetModal/SheetNavigation.native.js.map +1 -1
  70. package/dist/cjs/SheetModal/detents.native.js.map +1 -1
  71. package/dist/cjs/SheetModal/useSheetFrameFocus.native.js.map +1 -1
  72. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  73. package/dist/cjs/SkipLink/index.native.js.map +1 -1
  74. package/dist/cjs/SortableList/SortableHandle.native.js.map +1 -1
  75. package/dist/cjs/SortableList/index.cjs +4 -1
  76. package/dist/cjs/SortableList/index.native.js +4 -1
  77. package/dist/cjs/SortableList/index.native.js.map +1 -1
  78. package/dist/cjs/SortableList/useSortableRows.native.js.map +1 -1
  79. package/dist/cjs/SortableList/useUserOrder.cjs +84 -0
  80. package/dist/cjs/SortableList/useUserOrder.native.js +107 -0
  81. package/dist/cjs/SortableList/useUserOrder.native.js.map +1 -0
  82. package/dist/cjs/Tabs/index.native.js +1 -1
  83. package/dist/cjs/Tabs/index.native.js.map +1 -1
  84. package/dist/cjs/Text.native.js.map +1 -1
  85. package/dist/cjs/ThemePresetPicker/index.native.js +2 -2
  86. package/dist/cjs/ThemePresetPicker/index.native.js.map +1 -1
  87. package/dist/cjs/Toast/index.native.js.map +1 -1
  88. package/dist/cjs/Toast/store.native.js.map +1 -1
  89. package/dist/cjs/Tooltip/nativePress.native.js.map +1 -1
  90. package/dist/cjs/Tooltip/tooltipShared.native.js.map +1 -1
  91. package/dist/cjs/TreeSelect/index.cjs +7 -1
  92. package/dist/cjs/TreeSelect/index.native.js +8 -2
  93. package/dist/cjs/TreeSelect/index.native.js.map +1 -1
  94. package/dist/cjs/TreeSelect/treeSelectModel.native.js.map +1 -1
  95. package/dist/cjs/Video/PlayerChrome.native.js.map +1 -1
  96. package/dist/cjs/Video/VideoFrame.native.js.map +1 -1
  97. package/dist/cjs/Video/types.native.js.map +1 -1
  98. package/dist/cjs/Wheel/index.native.js.map +1 -1
  99. package/dist/cjs/Wizard/index.native.js +2 -2
  100. package/dist/cjs/Wizard/index.native.js.map +1 -1
  101. package/dist/cjs/actions/ActionBar.native.js.map +1 -1
  102. package/dist/cjs/actions/DangerSection.native.js.map +1 -1
  103. package/dist/cjs/actions/DestructiveAction.native.js.map +1 -1
  104. package/dist/cjs/actions/HeaderActions.native.js +2 -2
  105. package/dist/cjs/actions/HeaderActions.native.js.map +1 -1
  106. package/dist/cjs/actions/StandardAction.native.js +1 -1
  107. package/dist/cjs/actions/StandardAction.native.js.map +1 -1
  108. package/dist/cjs/actions/devWarn.native.js.map +1 -1
  109. package/dist/cjs/actions/index.native.js.map +1 -1
  110. package/dist/cjs/actions/severity.native.js.map +1 -1
  111. package/dist/cjs/appShell/Dock.native.js.map +1 -1
  112. package/dist/cjs/appShell/MpoTabHost.native.js.map +1 -1
  113. package/dist/cjs/appShell/ScopeMenu.native.js.map +1 -1
  114. package/dist/cjs/appShell/SettingsSplit.native.js +1 -1
  115. package/dist/cjs/appShell/SettingsSplit.native.js.map +1 -1
  116. package/dist/cjs/appShell/Springboard.native.js +1 -1
  117. package/dist/cjs/appShell/Springboard.native.js.map +1 -1
  118. package/dist/cjs/appShell/SystemBar.native.js.map +1 -1
  119. package/dist/cjs/appShell/TabBar.cjs +10 -5
  120. package/dist/cjs/appShell/TabBar.native.js +11 -6
  121. package/dist/cjs/appShell/TabBar.native.js.map +1 -1
  122. package/dist/cjs/appShell/appTile.native.js +1 -1
  123. package/dist/cjs/appShell/appTile.native.js.map +1 -1
  124. package/dist/cjs/appShell/bottomChrome.native.js.map +1 -1
  125. package/dist/cjs/appShell/index.native.js.map +1 -1
  126. package/dist/cjs/charts/Axis.native.js.map +1 -1
  127. package/dist/cjs/charts/BarChart.native.js.map +1 -1
  128. package/dist/cjs/charts/ChartDataView.native.js +1 -1
  129. package/dist/cjs/charts/ChartDataView.native.js.map +1 -1
  130. package/dist/cjs/charts/ChartSurface.native.js.map +1 -1
  131. package/dist/cjs/charts/LineChart.native.js.map +1 -1
  132. package/dist/cjs/charts/PieChart.native.js.map +1 -1
  133. package/dist/cjs/charts/Sparkline.cjs +1 -1
  134. package/dist/cjs/charts/Sparkline.native.js +1 -1
  135. package/dist/cjs/charts/Sparkline.native.js.map +1 -1
  136. package/dist/cjs/charts/accessibility.native.js.map +1 -1
  137. package/dist/cjs/charts/chartHeight.native.js.map +1 -1
  138. package/dist/cjs/charts/composeChart.native.js.map +1 -1
  139. package/dist/cjs/charts/index.native.js.map +1 -1
  140. package/dist/cjs/charts/math.native.js.map +1 -1
  141. package/dist/cjs/charts/series.native.js.map +1 -1
  142. package/dist/cjs/charts/svg.native.js.map +1 -1
  143. package/dist/cjs/charts/types.native.js.map +1 -1
  144. package/dist/cjs/charts/useChartTheme.native.js.map +1 -1
  145. package/dist/cjs/code/Code/index.native.js.map +1 -1
  146. package/dist/cjs/code/CodeBlock/index.native.js +7 -7
  147. package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
  148. package/dist/cjs/code/HighlightedCode/index.native.js.map +1 -1
  149. package/dist/cjs/code/Highlighter/houseSyntaxTheme.native.js.map +1 -1
  150. package/dist/cjs/code/Highlighter/index.native.js.map +1 -1
  151. package/dist/cjs/code/Highlighter/namedGroupMatchAll.native.js.map +1 -1
  152. package/dist/cjs/code/Pre/index.native.js.map +1 -1
  153. package/dist/cjs/code/index.native.js +5 -5
  154. package/dist/cjs/code/index.native.js.map +1 -1
  155. package/dist/cjs/componentColors.native.js.map +1 -1
  156. package/dist/cjs/feedback/ConfirmDialog.native.js.map +1 -1
  157. package/dist/cjs/feedback/NotifyHost.native.js +2 -2
  158. package/dist/cjs/feedback/NotifyHost.native.js.map +1 -1
  159. package/dist/cjs/feedback/copy.native.js.map +1 -1
  160. package/dist/cjs/feedback/index.native.js.map +1 -1
  161. package/dist/cjs/feedback/notify.native.js.map +1 -1
  162. package/dist/cjs/feedback/route.native.js.map +1 -1
  163. package/dist/cjs/feedback/store.native.js.map +1 -1
  164. package/dist/cjs/formLayouts/FormLayouts.native.js +1 -1
  165. package/dist/cjs/formLayouts/FormLayouts.native.js.map +1 -1
  166. package/dist/cjs/formLayouts/PreferencePanel.native.js +2 -2
  167. package/dist/cjs/formLayouts/PreferencePanel.native.js.map +1 -1
  168. package/dist/cjs/formLayouts/index.native.js.map +1 -1
  169. package/dist/cjs/hooks/index.native.js +1 -1
  170. package/dist/cjs/hooks/index.native.js.map +1 -1
  171. package/dist/cjs/hooks/useClipboard.native.js.map +1 -1
  172. package/dist/cjs/hooks/useDocumentTitle.native.js.map +1 -1
  173. package/dist/cjs/hooks/useHoldCue.native.js.map +1 -1
  174. package/dist/cjs/icons/CheckRegular.native.js.map +1 -1
  175. package/dist/cjs/icons/MinusRegular.native.js.map +1 -1
  176. package/dist/cjs/icons/index.native.js.map +1 -1
  177. package/dist/cjs/icons/lucide.native.js.map +1 -1
  178. package/dist/cjs/icons/themed.native.js.map +1 -1
  179. package/dist/cjs/images/Image/ImageFrame.native.js +1 -1
  180. package/dist/cjs/images/Image/ImageFrame.native.js.map +1 -1
  181. package/dist/cjs/images/Image/framing.native.js.map +1 -1
  182. package/dist/cjs/images/Image/index.native.js +1 -1
  183. package/dist/cjs/images/Image/mediaRadius.native.js.map +1 -1
  184. package/dist/cjs/images/Image/shared.native.js +1 -1
  185. package/dist/cjs/images/Image/shared.native.js.map +1 -1
  186. package/dist/cjs/images/Image/types.native.js.map +1 -1
  187. package/dist/cjs/images/index.native.js.map +1 -1
  188. package/dist/cjs/index.cjs +6 -1
  189. package/dist/cjs/index.native.js +42 -37
  190. package/dist/cjs/index.native.js.map +1 -1
  191. package/dist/cjs/knobImmuneExports.native.js.map +1 -1
  192. package/dist/cjs/layouts/AsyncBoundary.native.js +2 -2
  193. package/dist/cjs/layouts/AsyncBoundary.native.js.map +1 -1
  194. package/dist/cjs/layouts/Debug/index.native.js.map +1 -1
  195. package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
  196. package/dist/cjs/layouts/IdentityPlate.native.js.map +1 -1
  197. package/dist/cjs/layouts/KeyboardAvoidingWrapper/behavior.native.js.map +1 -1
  198. package/dist/cjs/layouts/PageTemplates.native.js.map +1 -1
  199. package/dist/cjs/layouts/PaneScaffold.native.js.map +1 -1
  200. package/dist/cjs/layouts/SafeAreaWrapper/insets.native.js.map +1 -1
  201. package/dist/cjs/layouts/StatusDot.native.js.map +1 -1
  202. package/dist/cjs/layouts/StatusGlyphStrip.native.js +1 -1
  203. package/dist/cjs/layouts/StatusGlyphStrip.native.js.map +1 -1
  204. package/dist/cjs/layouts/ViewSwitcher.native.js.map +1 -1
  205. package/dist/cjs/layouts/attachments.native.js +1 -1
  206. package/dist/cjs/layouts/attachments.native.js.map +1 -1
  207. package/dist/cjs/layouts/bottomAccessory.native.js.map +1 -1
  208. package/dist/cjs/layouts/breadcrumbs.native.js.map +1 -1
  209. package/dist/cjs/layouts/index.native.js +3 -3
  210. package/dist/cjs/layouts/index.native.js.map +1 -1
  211. package/dist/cjs/layouts/page.native.js +2 -2
  212. package/dist/cjs/layouts/page.native.js.map +1 -1
  213. package/dist/cjs/layouts/pageHeadingScope.native.js.map +1 -1
  214. package/dist/cjs/layouts/screenScroll.native.js.map +1 -1
  215. package/dist/cjs/layouts/shellSidebarSlot.native.js.map +1 -1
  216. package/dist/cjs/layouts/sidebar.native.js +1 -1
  217. package/dist/cjs/layouts/sidebar.native.js.map +1 -1
  218. package/dist/cjs/layouts/tags.native.js +2 -2
  219. package/dist/cjs/layouts/tags.native.js.map +1 -1
  220. package/dist/cjs/layouts/timeline.native.js +2 -2
  221. package/dist/cjs/layouts/timeline.native.js.map +1 -1
  222. package/dist/cjs/layouts/toolbar.native.js +1 -1
  223. package/dist/cjs/layouts/toolbar.native.js.map +1 -1
  224. package/dist/cjs/shared/actionScan.native.js.map +1 -1
  225. package/dist/cjs/shared/i18n.native.js.map +1 -1
  226. package/dist/cjs/shared/restoreRetries.native.js.map +1 -1
  227. package/dist/cjs/shared/t.native.js.map +1 -1
  228. package/dist/cjs/shared/textRidesText.native.js.map +1 -1
  229. package/dist/cjs/shared/useReturnFocusOnClose.native.js.map +1 -1
  230. package/dist/cjs/surfaces.native.js +1 -1
  231. package/dist/cjs/surfaces.native.js.map +1 -1
  232. package/dist/cjs/tamagui.native.js +1 -1
  233. package/dist/cjs/tamagui.native.js.map +1 -1
  234. package/dist/cjs/testSetup.native.js.map +1 -1
  235. package/dist/cjs/utils/setTinted.native.js.map +1 -1
  236. package/dist/cjs/utils/unwrapText.native.js.map +1 -1
  237. package/dist/cjs/views/Calendar.native.js +1 -1
  238. package/dist/cjs/views/Calendar.native.js.map +1 -1
  239. package/dist/cjs/views/Dashboard.native.js +2 -2
  240. package/dist/cjs/views/Dashboard.native.js.map +1 -1
  241. package/dist/cjs/views/Gantt.native.js +2 -2
  242. package/dist/cjs/views/Gantt.native.js.map +1 -1
  243. package/dist/cjs/views/GanttDateGrip.native.js.map +1 -1
  244. package/dist/cjs/views/ImageGrid.native.js +2 -2
  245. package/dist/cjs/views/ImageGrid.native.js.map +1 -1
  246. package/dist/cjs/views/Kanban.native.js +1 -1
  247. package/dist/cjs/views/List.native.js.map +1 -1
  248. package/dist/cjs/views/ListGroup.native.js.map +1 -1
  249. package/dist/cjs/views/ListRow.native.js.map +1 -1
  250. package/dist/cjs/views/Matrix.native.js +2 -2
  251. package/dist/cjs/views/Matrix.native.js.map +1 -1
  252. package/dist/cjs/views/ReportBuilder.cjs +3 -3
  253. package/dist/cjs/views/ReportBuilder.native.js +5 -5
  254. package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
  255. package/dist/cjs/views/ShortcutCard.native.js.map +1 -1
  256. package/dist/cjs/views/TreeView.native.js.map +1 -1
  257. package/dist/cjs/views/calendarMath.native.js.map +1 -1
  258. package/dist/cjs/views/ganttIntervals.native.js.map +1 -1
  259. package/dist/cjs/views/ganttMath.native.js.map +1 -1
  260. package/dist/cjs/views/index.cjs +3 -1
  261. package/dist/cjs/views/index.native.js +3 -1
  262. package/dist/cjs/views/index.native.js.map +1 -1
  263. package/dist/cjs/views/kanbanDnd.native.js.map +1 -1
  264. package/dist/cjs/views/matrixMath.native.js.map +1 -1
  265. package/dist/cjs/views/sameNameScope.cjs +39 -0
  266. package/dist/cjs/views/sameNameScope.native.js +63 -0
  267. package/dist/cjs/views/sameNameScope.native.js.map +1 -0
  268. package/dist/cjs/views/treeViewDnd.native.js.map +1 -1
  269. package/dist/cjs/views/treeViewLayout.native.js.map +1 -1
  270. package/dist/cjs/views/treeViewMotion.native.js.map +1 -1
  271. package/dist/cjs/views/treeViewReveal.native.js.map +1 -1
  272. package/dist/cjs/views/usePageFlowLoadMore.native.js.map +1 -1
  273. package/dist/cjs/views/widgetChrome.native.js.map +1 -1
  274. package/dist/esm/Diff/diff.mjs +58 -0
  275. package/dist/esm/Diff/diff.mjs.map +1 -0
  276. package/dist/esm/Diff/diff.native.js +79 -0
  277. package/dist/esm/Diff/diff.native.js.map +1 -0
  278. package/dist/esm/Diff/index.mjs +147 -0
  279. package/dist/esm/Diff/index.mjs.map +1 -0
  280. package/dist/esm/Diff/index.native.js +151 -0
  281. package/dist/esm/Diff/index.native.js.map +1 -0
  282. package/dist/esm/ElapsedProgress/index.mjs +76 -0
  283. package/dist/esm/ElapsedProgress/index.mjs.map +1 -0
  284. package/dist/esm/ElapsedProgress/index.native.js +83 -0
  285. package/dist/esm/ElapsedProgress/index.native.js.map +1 -0
  286. package/dist/esm/MachineLiteral/index.mjs +73 -0
  287. package/dist/esm/MachineLiteral/index.mjs.map +1 -0
  288. package/dist/esm/MachineLiteral/index.native.js +74 -0
  289. package/dist/esm/MachineLiteral/index.native.js.map +1 -0
  290. package/dist/esm/Material/blur.mjs +8 -0
  291. package/dist/esm/Material/blur.mjs.map +1 -0
  292. package/dist/esm/Material/blur.native.js +67 -0
  293. package/dist/esm/Material/blur.native.js.map +1 -0
  294. package/dist/esm/Material/index.mjs +10 -4
  295. package/dist/esm/Material/index.mjs.map +1 -1
  296. package/dist/esm/Material/index.native.js +10 -4
  297. package/dist/esm/Material/index.native.js.map +1 -1
  298. package/dist/esm/Meter/index.mjs +4 -3
  299. package/dist/esm/Meter/index.mjs.map +1 -1
  300. package/dist/esm/Meter/index.native.js +4 -3
  301. package/dist/esm/Meter/index.native.js.map +1 -1
  302. package/dist/esm/SortableList/index.mjs +2 -1
  303. package/dist/esm/SortableList/index.mjs.map +1 -1
  304. package/dist/esm/SortableList/index.native.js +2 -1
  305. package/dist/esm/SortableList/index.native.js.map +1 -1
  306. package/dist/esm/SortableList/useUserOrder.mjs +58 -0
  307. package/dist/esm/SortableList/useUserOrder.mjs.map +1 -0
  308. package/dist/esm/SortableList/useUserOrder.native.js +78 -0
  309. package/dist/esm/SortableList/useUserOrder.native.js.map +1 -0
  310. package/dist/esm/TreeSelect/index.mjs +8 -2
  311. package/dist/esm/TreeSelect/index.mjs.map +1 -1
  312. package/dist/esm/TreeSelect/index.native.js +8 -2
  313. package/dist/esm/TreeSelect/index.native.js.map +1 -1
  314. package/dist/esm/appShell/TabBar.mjs +10 -5
  315. package/dist/esm/appShell/TabBar.mjs.map +1 -1
  316. package/dist/esm/appShell/TabBar.native.js +10 -5
  317. package/dist/esm/appShell/TabBar.native.js.map +1 -1
  318. package/dist/esm/charts/Sparkline.mjs +1 -1
  319. package/dist/esm/charts/Sparkline.mjs.map +1 -1
  320. package/dist/esm/charts/Sparkline.native.js +1 -1
  321. package/dist/esm/charts/Sparkline.native.js.map +1 -1
  322. package/dist/esm/index.mjs +5 -2
  323. package/dist/esm/index.mjs.map +1 -1
  324. package/dist/esm/index.native.js +5 -2
  325. package/dist/esm/index.native.js.map +1 -1
  326. package/dist/esm/views/ReportBuilder.mjs +4 -4
  327. package/dist/esm/views/ReportBuilder.mjs.map +1 -1
  328. package/dist/esm/views/ReportBuilder.native.js +4 -4
  329. package/dist/esm/views/ReportBuilder.native.js.map +1 -1
  330. package/dist/esm/views/index.mjs +2 -1
  331. package/dist/esm/views/index.mjs.map +1 -1
  332. package/dist/esm/views/index.native.js +2 -1
  333. package/dist/esm/views/index.native.js.map +1 -1
  334. package/dist/esm/views/sameNameScope.mjs +14 -0
  335. package/dist/esm/views/sameNameScope.mjs.map +1 -0
  336. package/dist/esm/views/sameNameScope.native.js +35 -0
  337. package/dist/esm/views/sameNameScope.native.js.map +1 -0
  338. package/dist/jsx/Diff/diff.mjs +58 -0
  339. package/dist/jsx/Diff/diff.mjs.map +1 -0
  340. package/dist/jsx/Diff/diff.native.js +108 -0
  341. package/dist/jsx/Diff/diff.native.js.map +1 -0
  342. package/dist/jsx/Diff/index.mjs +147 -0
  343. package/dist/jsx/Diff/index.mjs.map +1 -0
  344. package/dist/jsx/Diff/index.native.js +181 -0
  345. package/dist/jsx/Diff/index.native.js.map +1 -0
  346. package/dist/jsx/ElapsedProgress/index.mjs +76 -0
  347. package/dist/jsx/ElapsedProgress/index.mjs.map +1 -0
  348. package/dist/jsx/ElapsedProgress/index.native.js +112 -0
  349. package/dist/jsx/ElapsedProgress/index.native.js.map +1 -0
  350. package/dist/jsx/MachineLiteral/index.mjs +73 -0
  351. package/dist/jsx/MachineLiteral/index.mjs.map +1 -0
  352. package/dist/jsx/MachineLiteral/index.native.js +102 -0
  353. package/dist/jsx/MachineLiteral/index.native.js.map +1 -0
  354. package/dist/jsx/Material/blur.mjs +8 -0
  355. package/dist/jsx/Material/blur.mjs.map +1 -0
  356. package/dist/jsx/Material/blur.native.js +100 -0
  357. package/dist/jsx/Material/blur.native.js.map +1 -0
  358. package/dist/jsx/Material/index.mjs +10 -4
  359. package/dist/jsx/Material/index.mjs.map +1 -1
  360. package/dist/jsx/Material/index.native.js +9 -3
  361. package/dist/jsx/Material/index.native.js.map +1 -1
  362. package/dist/jsx/Meter/index.mjs +4 -3
  363. package/dist/jsx/Meter/index.mjs.map +1 -1
  364. package/dist/jsx/Meter/index.native.js +3 -1
  365. package/dist/jsx/Meter/index.native.js.map +1 -1
  366. package/dist/jsx/SortableList/index.mjs +2 -1
  367. package/dist/jsx/SortableList/index.mjs.map +1 -1
  368. package/dist/jsx/SortableList/index.native.js +4 -1
  369. package/dist/jsx/SortableList/index.native.js.map +1 -1
  370. package/dist/jsx/SortableList/useUserOrder.mjs +58 -0
  371. package/dist/jsx/SortableList/useUserOrder.mjs.map +1 -0
  372. package/dist/jsx/SortableList/useUserOrder.native.js +107 -0
  373. package/dist/jsx/SortableList/useUserOrder.native.js.map +1 -0
  374. package/dist/jsx/TreeSelect/index.mjs +8 -2
  375. package/dist/jsx/TreeSelect/index.mjs.map +1 -1
  376. package/dist/jsx/TreeSelect/index.native.js +7 -1
  377. package/dist/jsx/TreeSelect/index.native.js.map +1 -1
  378. package/dist/jsx/appShell/TabBar.mjs +10 -5
  379. package/dist/jsx/appShell/TabBar.mjs.map +1 -1
  380. package/dist/jsx/appShell/TabBar.native.js +10 -5
  381. package/dist/jsx/appShell/TabBar.native.js.map +1 -1
  382. package/dist/jsx/charts/Sparkline.mjs +1 -1
  383. package/dist/jsx/charts/Sparkline.mjs.map +1 -1
  384. package/dist/jsx/charts/Sparkline.native.js +1 -1
  385. package/dist/jsx/charts/Sparkline.native.js.map +1 -1
  386. package/dist/jsx/feedback/NotifyHost.native.js +1 -1
  387. package/dist/jsx/formLayouts/PreferencePanel.native.js +1 -1
  388. package/dist/jsx/index.js +5 -2
  389. package/dist/jsx/index.js.map +1 -1
  390. package/dist/jsx/index.mjs +5 -2
  391. package/dist/jsx/index.mjs.map +1 -1
  392. package/dist/jsx/index.native.js +7 -2
  393. package/dist/jsx/index.native.js.map +1 -1
  394. package/dist/jsx/layouts/AsyncBoundary.native.js +1 -1
  395. package/dist/jsx/layouts/AsyncBoundary.native.js.map +1 -1
  396. package/dist/jsx/views/ReportBuilder.mjs +4 -4
  397. package/dist/jsx/views/ReportBuilder.mjs.map +1 -1
  398. package/dist/jsx/views/ReportBuilder.native.js +3 -3
  399. package/dist/jsx/views/ReportBuilder.native.js.map +1 -1
  400. package/dist/jsx/views/index.mjs +2 -1
  401. package/dist/jsx/views/index.mjs.map +1 -1
  402. package/dist/jsx/views/index.native.js +2 -0
  403. package/dist/jsx/views/index.native.js.map +1 -1
  404. package/dist/jsx/views/sameNameScope.mjs +14 -0
  405. package/dist/jsx/views/sameNameScope.mjs.map +1 -0
  406. package/dist/jsx/views/sameNameScope.native.js +63 -0
  407. package/dist/jsx/views/sameNameScope.native.js.map +1 -0
  408. package/package.json +18 -9
  409. package/src/Diff/Diff.spec.tsx +105 -0
  410. package/src/Diff/Diff.stories.tsx +44 -0
  411. package/src/Diff/diff.ts +61 -0
  412. package/src/Diff/index.tsx +145 -0
  413. package/src/ElapsedProgress/ElapsedProgress.spec.tsx +66 -0
  414. package/src/ElapsedProgress/ElapsedProgress.stories.tsx +43 -0
  415. package/src/ElapsedProgress/index.tsx +89 -0
  416. package/src/MachineLiteral/MachineLiteral.spec.tsx +86 -0
  417. package/src/MachineLiteral/MachineLiteral.stories.tsx +44 -0
  418. package/src/MachineLiteral/index.tsx +75 -0
  419. package/src/Material/blur.native.spec.tsx +135 -0
  420. package/src/Material/blur.native.tsx +93 -0
  421. package/src/Material/blur.ts +11 -0
  422. package/src/Material/index.tsx +18 -6
  423. package/src/Meter/index.tsx +4 -2
  424. package/src/SortableList/index.tsx +2 -0
  425. package/src/SortableList/useUserOrder.spec.tsx +110 -0
  426. package/src/SortableList/useUserOrder.ts +96 -0
  427. package/src/TreeSelect/TreeSelect.rows.spec.tsx +44 -0
  428. package/src/TreeSelect/index.tsx +12 -1
  429. package/src/appShell/TabBar.tsx +3 -0
  430. package/src/charts/Sparkline.tsx +3 -3
  431. package/src/index.ts +7 -0
  432. package/src/presentationEmpty.spec.tsx +71 -0
  433. package/src/views/ReportBuilder.tsx +4 -3
  434. package/src/views/index.ts +1 -0
  435. package/src/views/sameNameScope.spec.tsx +55 -0
  436. package/src/views/sameNameScope.ts +22 -0
  437. package/types/Diff/diff.d.ts +17 -0
  438. package/types/Diff/diff.d.ts.map +1 -0
  439. package/types/Diff/index.d.ts +15 -0
  440. package/types/Diff/index.d.ts.map +1 -0
  441. package/types/ElapsedProgress/index.d.ts +15 -0
  442. package/types/ElapsedProgress/index.d.ts.map +1 -0
  443. package/types/MachineLiteral/index.d.ts +13 -0
  444. package/types/MachineLiteral/index.d.ts.map +1 -0
  445. package/types/Material/blur.d.ts +9 -0
  446. package/types/Material/blur.d.ts.map +1 -0
  447. package/types/Material/blur.native.d.ts +38 -0
  448. package/types/Material/blur.native.d.ts.map +1 -0
  449. package/types/Material/index.d.ts.map +1 -1
  450. package/types/Meter/index.d.ts +2 -0
  451. package/types/Meter/index.d.ts.map +1 -1
  452. package/types/SortableList/index.d.ts +2 -0
  453. package/types/SortableList/index.d.ts.map +1 -1
  454. package/types/SortableList/useUserOrder.d.ts +28 -0
  455. package/types/SortableList/useUserOrder.d.ts.map +1 -0
  456. package/types/TreeSelect/index.d.ts.map +1 -1
  457. package/types/appShell/TabBar.d.ts.map +1 -1
  458. package/types/charts/Sparkline.d.ts +2 -2
  459. package/types/charts/Sparkline.d.ts.map +1 -1
  460. package/types/index.d.ts +5 -2
  461. package/types/index.d.ts.map +1 -1
  462. package/types/views/ReportBuilder.d.ts.map +1 -1
  463. package/types/views/index.d.ts +1 -0
  464. package/types/views/index.d.ts.map +1 -1
  465. package/types/views/sameNameScope.d.ts +8 -0
  466. package/types/views/sameNameScope.d.ts.map +1 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ElapsedProgress — long work shows how long (LC-185). Determinate progress
3
+ * draws the bar; otherwise the indeterminate spinner gets the elapsed time
4
+ * beside it once the wait outlasts `threshold`. Reduced motion stops the
5
+ * spinner (the Spinner's own CSS), never the count.
6
+ */
7
+ import { Progress, Spinner } from "@multiplatform.one/forms";
8
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
9
+ import { useEffect, useState } from "react";
10
+ import { Text, XStack, YStack, type XStackProps } from "tamagui";
11
+ import { useTranslation } from "../shared/i18n";
12
+ import { withInterp } from "../shared/t";
13
+
14
+ export interface ElapsedProgressProps extends Omit<XStackProps, "children"> {
15
+ /** When the work started (epoch ms or a Date). */
16
+ startedAt: number | Date;
17
+ /** Determinate share done, 0 to 1; omit when the work can't say. */
18
+ progress?: number | null;
19
+ /** How long the spinner stays bare before the elapsed time joins it (ms, default 3000). */
20
+ threshold?: number;
21
+ /** What is running, for the accessible name ("Build"). */
22
+ label?: string;
23
+ }
24
+
25
+ /** m:ss under an hour, h:mm:ss past it. */
26
+ export function formatElapsed(ms: number): string {
27
+ const total = Math.max(0, Math.floor(ms / 1000));
28
+ const hours = Math.floor(total / 3600);
29
+ const minutes = Math.floor((total % 3600) / 60);
30
+ const seconds = String(total % 60).padStart(2, "0");
31
+ return hours > 0
32
+ ? `${hours}:${String(minutes).padStart(2, "0")}:${seconds}`
33
+ : `${minutes}:${seconds}`;
34
+ }
35
+
36
+ export function ElapsedProgress({
37
+ startedAt,
38
+ progress,
39
+ threshold = 3000,
40
+ label,
41
+ ...rowProps
42
+ }: ElapsedProgressProps) {
43
+ const { t } = useTranslation();
44
+ const { knobProps } = useResolvedKnobs({ component: "ElapsedProgress" });
45
+ const start = typeof startedAt === "number" ? startedAt : startedAt.getTime();
46
+ const [now, setNow] = useState(() => Date.now());
47
+ useEffect(() => {
48
+ const id = setInterval(() => setNow(Date.now()), 1000);
49
+ return () => clearInterval(id);
50
+ }, []);
51
+ const elapsed = Math.max(0, now - start);
52
+ const determinate = progress != null && Number.isFinite(progress);
53
+ const showElapsed = determinate || elapsed >= threshold;
54
+ const time = formatElapsed(elapsed);
55
+ const name = label
56
+ ? withInterp(t("{{label}}, running for {{time}}", { label, time }), { label, time })
57
+ : withInterp(t("Running for {{time}}", { time }), { time });
58
+ return (
59
+ <XStack
60
+ alignItems="center"
61
+ {...knobProps.gapSm}
62
+ aria-label={name}
63
+ accessibilityLabel={name}
64
+ data-elapsed-state={determinate ? "determinate" : showElapsed ? "elapsed" : "short"}
65
+ {...rowProps}
66
+ >
67
+ {determinate ? (
68
+ <YStack flex={1}>
69
+ <Progress
70
+ value={Math.round(Math.min(1, Math.max(0, progress as number)) * 100)}
71
+ max={100}
72
+ />
73
+ </YStack>
74
+ ) : (
75
+ <Spinner size="small" />
76
+ )}
77
+ {showElapsed ? (
78
+ <Text
79
+ {...knobProps.body}
80
+ {...knobProps.textRole.meta}
81
+ {...knobProps.typography.tabular}
82
+ data-elapsed=""
83
+ >
84
+ {time}
85
+ </Text>
86
+ ) : null}
87
+ </XStack>
88
+ );
89
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * LC-221 MACHINE-LITERAL: the literal renders byte for byte in $mono, never
3
+ * re-cased or cut; the reading shows when a formatter derives one; the copy
4
+ * glyph writes the literal itself.
5
+ */
6
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
7
+ import { cleanup, fireEvent, waitFor } from "@testing-library/react";
8
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
9
+ import { resetFeedback } from "../feedback/store";
10
+ import { resetToasts } from "../Toast/store";
11
+ import { MachineLiteral, type MachineLiteralProps } from "./index";
12
+ import meta, { Default, Literals } from "./MachineLiteral.stories";
13
+
14
+ const writeText = vi.fn();
15
+
16
+ beforeEach(() => {
17
+ writeText.mockReset();
18
+ writeText.mockResolvedValue(undefined);
19
+ vi.stubGlobal("navigator", {
20
+ ...(typeof navigator !== "undefined" ? navigator : {}),
21
+ clipboard: { writeText },
22
+ });
23
+ resetToasts();
24
+ resetFeedback();
25
+ });
26
+
27
+ afterEach(() => {
28
+ cleanup();
29
+ vi.unstubAllGlobals();
30
+ resetToasts();
31
+ resetFeedback();
32
+ });
33
+
34
+ const digest = "sha256:9F86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08";
35
+
36
+ function literalOf(container: HTMLElement) {
37
+ return container.querySelector("[data-machine-literal]") as HTMLElement;
38
+ }
39
+
40
+ describe("MachineLiteral (LC-221)", () => {
41
+ it("renders the literal byte for byte in the mono voice, uncut", () => {
42
+ const { container } = renderWithProviders(<MachineLiteral value={digest} label="digest" />);
43
+ const literal = literalOf(container);
44
+ expect(literal.textContent).toBe(digest);
45
+ expect(literal.className + (literal.getAttribute("style") ?? "")).toMatch(/mono/i);
46
+ expect(literal.textContent).not.toContain("…");
47
+ });
48
+
49
+ it("the copy glyph writes the literal and is named for it", async () => {
50
+ const { container } = renderWithProviders(<MachineLiteral value={digest} label="digest" />);
51
+ const copy = container.querySelector("[aria-label='Copy digest']") as HTMLElement;
52
+ expect(copy).toBeTruthy();
53
+ expect(copy.textContent?.trim()).toBe("");
54
+ fireEvent.click(copy);
55
+ await waitFor(() => expect(writeText).toHaveBeenCalledWith(digest));
56
+ });
57
+
58
+ it("shows the reading beside the literal only when the formatter derives one", () => {
59
+ const reading = (cron: string) => (cron === "0 2 * * *" ? "daily at 02:00" : undefined);
60
+ const daily = renderWithProviders(<MachineLiteral value="0 2 * * *" reading={reading} />);
61
+ expect(daily.container.querySelector("[data-machine-reading]")?.textContent).toBe(
62
+ "daily at 02:00",
63
+ );
64
+ expect(literalOf(daily.container).textContent).toBe("0 2 * * *");
65
+ daily.unmount();
66
+
67
+ const odd = renderWithProviders(<MachineLiteral value="*/7 3 * * 1" reading={reading} />);
68
+ expect(odd.container.querySelector("[data-machine-reading]")).toBeNull();
69
+ expect(literalOf(odd.container).textContent).toBe("*/7 3 * * 1");
70
+ });
71
+
72
+ it("the stories mount: Main reads the cron, Literals keep each literal verbatim", () => {
73
+ expect(meta.title).toBe("Components/MachineLiteral");
74
+ const main = renderWithProviders(<MachineLiteral {...(Default.args as MachineLiteralProps)} />);
75
+ expect(main.container.querySelector("[data-machine-reading]")?.textContent).toBe(
76
+ "daily at 02:00",
77
+ );
78
+ main.unmount();
79
+ const all = renderWithProviders(<>{Literals.render?.({} as never, {} as never)}</>);
80
+ const values = [...all.container.querySelectorAll("[data-machine-literal]")].map(
81
+ (node) => node.textContent,
82
+ );
83
+ expect(values).toContain("ERR_TLS_CERT_ALTNAME_INVALID");
84
+ expect(values).toContain("SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8");
85
+ });
86
+ });
@@ -0,0 +1,44 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
2
+ import { YStack } from "tamagui";
3
+ import { MachineLiteral } from "./index";
4
+
5
+ const meta: Meta<typeof MachineLiteral> = {
6
+ title: "Components/MachineLiteral",
7
+ component: MachineLiteral,
8
+ parameters: {
9
+ status: { type: "beta" },
10
+ docs: {
11
+ description: {
12
+ component:
13
+ "A machine literal in display (LC-221): verbatim in $mono, its human reading beside it, and a bare copy glyph that writes the literal byte for byte. In a field, use CopyField.",
14
+ },
15
+ },
16
+ },
17
+ };
18
+ export default meta;
19
+
20
+ type Story = StoryObj<typeof MachineLiteral>;
21
+
22
+ const cronReading = (cron: string) => (cron === "0 2 * * *" ? "daily at 02:00" : undefined);
23
+
24
+ export const Default: Story = {
25
+ name: "Main",
26
+ args: { value: "0 2 * * *", reading: cronReading, label: "cron expression" },
27
+ };
28
+
29
+ export const Literals: Story = {
30
+ render: () => (
31
+ <YStack gap="$3">
32
+ <MachineLiteral value="0 2 * * *" reading={cronReading} label="cron expression" />
33
+ <MachineLiteral
34
+ value="sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
35
+ label="digest"
36
+ />
37
+ <MachineLiteral
38
+ value="SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8"
39
+ label="fingerprint"
40
+ />
41
+ <MachineLiteral value="ERR_TLS_CERT_ALTNAME_INVALID" label="error code" />
42
+ </YStack>
43
+ ),
44
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * MachineLiteral — a cron expression, digest, fingerprint, error code or key
3
+ * id in display (LC-221). The literal renders verbatim in `$mono`, never
4
+ * re-cased or cut; its human reading sits beside it when one is given or
5
+ * derived; a bare copy glyph (LC-176) writes the literal byte for byte. In a
6
+ * field, the same literal is a CopyField.
7
+ */
8
+ import { CopyIcon } from "@phosphor-icons/react";
9
+ import { Button } from "@multiplatform.one/forms";
10
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
11
+ import { Text, XStack, YStack, type XStackProps } from "tamagui";
12
+ import { NotifyRegion } from "../feedback/NotifyHost";
13
+ import { useCopyFeedback } from "../feedback/copy";
14
+ import { useTranslation } from "../shared/i18n";
15
+ import { withInterp } from "../shared/t";
16
+
17
+ export interface MachineLiteralProps extends Omit<XStackProps, "children"> {
18
+ /** The literal, shown and copied exactly as given. */
19
+ value: string;
20
+ /** Its human reading, or a formatter that derives one ("daily at 02:00"). */
21
+ reading?: string | ((value: string) => string | null | undefined);
22
+ /** What the literal is, for the copy action's name ("cron expression"). */
23
+ label?: string;
24
+ /** False drops the copy action (default true). */
25
+ copyable?: boolean;
26
+ }
27
+
28
+ export function MachineLiteral({
29
+ value,
30
+ reading,
31
+ label,
32
+ copyable = true,
33
+ ...rowProps
34
+ }: MachineLiteralProps) {
35
+ const { t } = useTranslation();
36
+ const { knobProps } = useResolvedKnobs({ component: "MachineLiteral" });
37
+ const { region, copy } = useCopyFeedback();
38
+ const readingText = typeof reading === "function" ? reading(value) : reading;
39
+ const copyLabel = label ? withInterp(t("Copy {{label}}", { label }), { label }) : t("Copy");
40
+ return (
41
+ <YStack>
42
+ <XStack alignItems="center" {...knobProps.gapSm} flexWrap="wrap" {...rowProps}>
43
+ <Text
44
+ {...knobProps.body}
45
+ fontFamily="$mono"
46
+ letterSpacing={0}
47
+ color="$color12"
48
+ selectable
49
+ userSelect="text"
50
+ data-machine-literal=""
51
+ >
52
+ {value}
53
+ </Text>
54
+ {readingText ? (
55
+ <Text {...knobProps.body} {...knobProps.textRole.meta} data-machine-reading="">
56
+ {readingText}
57
+ </Text>
58
+ ) : null}
59
+ {copyable ? (
60
+ <Button
61
+ chromeless
62
+ size={knobProps.sizeToken}
63
+ icon={CopyIcon}
64
+ aria-label={copyLabel}
65
+ onPress={() => {
66
+ void copy(value);
67
+ }}
68
+ data-machine-copy=""
69
+ />
70
+ ) : null}
71
+ </XStack>
72
+ {copyable ? <NotifyRegion scope="field" region={region} size="$3" /> : null}
73
+ </YStack>
74
+ );
75
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The material's native blur (FZ-8099): expo-blur when the binary carries it,
3
+ * the theme fill when it does not, so an OTA never crashes an older build.
4
+ */
5
+ import { TestProviders, renderWithProviders } from "@multiplatform.one/test-utils";
6
+ import { cleanup, renderHook, screen } from "@testing-library/react";
7
+ import { readFileSync, readdirSync } from "node:fs";
8
+ import { createRequire } from "node:module";
9
+ import { dirname, join } from "node:path";
10
+ import { afterEach, describe, expect, it, vi } from "vitest";
11
+ import {
12
+ type BlurSources,
13
+ type MaterialBlurView,
14
+ blurNativeModule,
15
+ blurTintFor,
16
+ materialBlurTint,
17
+ resolveBlurView,
18
+ } from "./blur.native";
19
+ import { Material, useMaterial } from "./index";
20
+
21
+ const blurState = vi.hoisted(() => ({ present: false }));
22
+
23
+ vi.mock("@multiplatform.one/platform", async (importOriginal) => ({
24
+ ...(await importOriginal<typeof import("@multiplatform.one/platform")>()),
25
+ isWeb: false,
26
+ isNative: true,
27
+ }));
28
+
29
+ vi.mock("./blur", () => ({
30
+ useMaterialBlur: () =>
31
+ blurState.present ? { BlurView: () => null, tint: "systemChromeMaterialLight" } : null,
32
+ MaterialBlurFill: ({ radius }: { radius?: number }) =>
33
+ blurState.present ? <span data-testid="material-blur" data-radius={radius} /> : null,
34
+ }));
35
+
36
+ afterEach(() => {
37
+ cleanup();
38
+ blurState.present = false;
39
+ });
40
+
41
+ const FakeBlurView: MaterialBlurView = () => null;
42
+
43
+ function sources(nativeModule: unknown, blur: () => { BlurView?: MaterialBlurView }): BlurSources {
44
+ return { core: () => ({ requireOptionalNativeModule: () => nativeModule }), blur };
45
+ }
46
+
47
+ describe("native blur detection", () => {
48
+ it("draws expo-blur's view on iOS when the binary registers ExpoBlur", () => {
49
+ const probe = vi.fn((name: string) => (name === blurNativeModule ? {} : null));
50
+ const view = resolveBlurView(
51
+ {
52
+ core: () => ({ requireOptionalNativeModule: probe }),
53
+ blur: () => ({ BlurView: FakeBlurView }),
54
+ },
55
+ "ios",
56
+ );
57
+ expect(view).toBe(FakeBlurView);
58
+ expect(probe).toHaveBeenCalledWith("ExpoBlur");
59
+ });
60
+
61
+ it("never requires expo-blur on a binary without its native module", () => {
62
+ const blur = vi.fn(() => ({ BlurView: FakeBlurView }));
63
+ expect(resolveBlurView(sources(null, blur), "ios")).toBeNull();
64
+ expect(blur).not.toHaveBeenCalled();
65
+ });
66
+
67
+ it("falls back when expo-modules-core or expo-blur cannot load", () => {
68
+ const throws = () => {
69
+ throw new Error("Cannot find module");
70
+ };
71
+ expect(
72
+ resolveBlurView({ core: throws, blur: () => ({ BlurView: FakeBlurView }) }, "ios"),
73
+ ).toBeNull();
74
+ expect(resolveBlurView(sources({}, throws), "ios")).toBeNull();
75
+ });
76
+
77
+ it("keeps the fill on Android, where expo-blur needs a BlurTargetView to blur", () => {
78
+ const blur = vi.fn(() => ({ BlurView: FakeBlurView }));
79
+ expect(resolveBlurView(sources({}, blur), "android")).toBeNull();
80
+ expect(blur).not.toHaveBeenCalled();
81
+ });
82
+
83
+ it("picks the HIG chrome material per colour scheme", () => {
84
+ expect(blurTintFor("light")).toBe(materialBlurTint.light);
85
+ expect(blurTintFor("light_accent")).toBe("systemChromeMaterialLight");
86
+ expect(blurTintFor("dark")).toBe(materialBlurTint.dark);
87
+ expect(blurTintFor("dark_accent")).toBe("systemChromeMaterialDark");
88
+ });
89
+
90
+ it("probes the name expo-blur registers its view under", () => {
91
+ const require = createRequire(import.meta.url);
92
+ const build = join(dirname(require.resolve("expo-blur/package.json")), "build");
93
+ const names = new Set<string>();
94
+ for (const file of readdirSync(build).filter((name) => name.endsWith(".js"))) {
95
+ const source = readFileSync(join(build, file), "utf8");
96
+ for (const match of source.matchAll(/requireNativeViewManager\(\s*['"]([^'"]+)['"]/g)) {
97
+ names.add(match[1]!);
98
+ }
99
+ }
100
+ expect([...names]).toEqual([blurNativeModule]);
101
+ });
102
+ });
103
+
104
+ describe("Material on native", () => {
105
+ it("lets the system material paint when the binary has expo-blur", () => {
106
+ blurState.present = true;
107
+ const { result } = renderHook(() => useMaterial(), { wrapper: TestProviders });
108
+ expect(result.current.backgroundColor).toBe("transparent");
109
+ expect(result.current).toMatchObject({ borderColor: "$borderColor", shadowColor: "$shadow3" });
110
+ expect(result.current).not.toHaveProperty("backdropFilter");
111
+ });
112
+
113
+ it("keeps the 94% chrome fill when the binary has no expo-blur", () => {
114
+ const { result } = renderHook(() => useMaterial(), { wrapper: TestProviders });
115
+ expect(result.current.backgroundColor).toMatch(/^rgba\(\d+, \d+, \d+, 0\.94\)$/);
116
+ });
117
+
118
+ it("puts the blur behind its content, clipped to its radius", () => {
119
+ blurState.present = true;
120
+ renderWithProviders(
121
+ <Material testID="material" borderRadius={20}>
122
+ <span>inside</span>
123
+ </Material>,
124
+ );
125
+ const material = screen.getByTestId("material");
126
+ expect(material.firstElementChild?.getAttribute("data-testid")).toBe("material-blur");
127
+ expect(screen.getByTestId("material-blur").getAttribute("data-radius")).toBe("20");
128
+ expect(material.textContent).toBe("inside");
129
+ });
130
+
131
+ it("draws no blur view without expo-blur", () => {
132
+ renderWithProviders(<Material testID="material">inside</Material>);
133
+ expect(screen.queryByTestId("material-blur")).toBeNull();
134
+ });
135
+ });
@@ -0,0 +1,93 @@
1
+ /**
2
+ * The material's native blur (FZ-8099): expo-blur's BlurView drawing the iOS
3
+ * system chrome material, when the app binary carries it.
4
+ *
5
+ * expo-blur is native code, so it reaches a phone only through a new binary.
6
+ * An OTA carries this JS to every binary at the same runtimeVersion, including
7
+ * the ones built before expo-blur was added, so the view is feature-detected
8
+ * at runtime: `requireOptionalNativeModule("ExpoBlur")` answers null on those
9
+ * binaries and the material keeps its theme fill. The probe runs before the
10
+ * `require`, the same order as the picker and maps loaders, because a module
11
+ * factory that throws is a fatal LogBox in dev even when the caller catches.
12
+ *
13
+ * iOS only. On Android expo-blur blurs only content wrapped in a
14
+ * BlurTargetView it is given a ref to; without one it draws a flat
15
+ * translucent view, which is what the theme fill already is.
16
+ */
17
+ import { isDarkThemeName } from "@multiplatform.one/theme";
18
+ import type { ComponentType } from "react";
19
+ import { Platform, StyleSheet, type ViewStyle } from "react-native";
20
+ import { useThemeName } from "tamagui";
21
+
22
+ /** The name expo-blur registers its native module and view under. */
23
+ export const blurNativeModule = "ExpoBlur";
24
+
25
+ /** The HIG material a tab bar or toolbar uses, per colour scheme. */
26
+ export const materialBlurTint = {
27
+ light: "systemChromeMaterialLight",
28
+ dark: "systemChromeMaterialDark",
29
+ } as const;
30
+
31
+ export function blurTintFor(themeName: string | undefined): string {
32
+ return isDarkThemeName(themeName) ? materialBlurTint.dark : materialBlurTint.light;
33
+ }
34
+
35
+ export type MaterialBlurView = ComponentType<{
36
+ tint?: string;
37
+ intensity?: number;
38
+ pointerEvents?: "none";
39
+ style?: ViewStyle | ViewStyle[];
40
+ }>;
41
+
42
+ export interface BlurSources {
43
+ core: () => { requireOptionalNativeModule?: (name: string) => unknown };
44
+ blur: () => { BlurView?: MaterialBlurView };
45
+ }
46
+
47
+ const appSources: BlurSources = {
48
+ core: () => require("expo-modules-core"),
49
+ blur: () => require("expo-blur"),
50
+ };
51
+
52
+ /** The BlurView, or null when this platform or binary cannot draw it. */
53
+ export function resolveBlurView(sources: BlurSources, os: string): MaterialBlurView | null {
54
+ if (os !== "ios") return null;
55
+ try {
56
+ if (sources.core().requireOptionalNativeModule?.(blurNativeModule) == null) return null;
57
+ return sources.blur().BlurView ?? null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ let cached: MaterialBlurView | null | undefined;
64
+
65
+ function loadBlurView(): MaterialBlurView | null {
66
+ if (cached === undefined) cached = resolveBlurView(appSources, Platform.OS);
67
+ return cached;
68
+ }
69
+
70
+ export function useMaterialBlur(): { BlurView: MaterialBlurView; tint: string } | null {
71
+ const themeName = useThemeName() as string | undefined;
72
+ const BlurView = loadBlurView();
73
+ if (!BlurView) return null;
74
+ return { BlurView, tint: blurTintFor(themeName) };
75
+ }
76
+
77
+ /**
78
+ * The blur behind a material's content: fills its parent inside the hairline
79
+ * and clips to the parent's corner radius, so the parent keeps its shadow.
80
+ */
81
+ export function MaterialBlurFill({ radius = 0 }: { radius?: number }) {
82
+ const blur = useMaterialBlur();
83
+ if (!blur) return null;
84
+ const { BlurView, tint } = blur;
85
+ return (
86
+ <BlurView
87
+ tint={tint}
88
+ intensity={100}
89
+ pointerEvents="none"
90
+ style={[StyleSheet.absoluteFill, { borderRadius: radius, overflow: "hidden" }]}
91
+ />
92
+ );
93
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The material's native blur, web arm: the browser blurs through
3
+ * `backdropFilter`, so there is no blur view to draw.
4
+ */
5
+ export function useMaterialBlur(): null {
6
+ return null;
7
+ }
8
+
9
+ export function MaterialBlurFill(_props: { radius?: number }): null {
10
+ return null;
11
+ }
@@ -8,13 +8,15 @@
8
8
  * The material is one theme token on every platform: the chrome surface
9
9
  * step one off the page (`$color2`, as the SystemBar paints it), shown
10
10
  * through at the material's opacity, with the hairline and the floating
11
- * shadow. Web blurs and saturates what is behind it. Native draws the same
12
- * token at a higher opacity, because React Native has no backdrop blur
13
- * without a native view in the app binary.
11
+ * shadow. Web blurs and saturates what is behind it. On iOS, a binary that
12
+ * carries expo-blur draws the system chrome material instead (FZ-8099,
13
+ * `blur.native.tsx`); any other native binary draws the token at a higher
14
+ * opacity, because React Native has no backdrop blur without that view.
14
15
  */
15
16
  import { hairlineWidth, normalizeToHex } from "@multiplatform.one/theme";
16
17
  import { isWeb } from "@multiplatform.one/platform";
17
18
  import { forwardRef } from "react";
19
+ import { MaterialBlurFill, useMaterialBlur } from "./blur";
18
20
  import { type TamaguiElement, YStack, type YStackProps, useTheme } from "tamagui";
19
21
 
20
22
  export type MaterialThickness = "chrome";
@@ -45,10 +47,13 @@ export function translucent(color: string | undefined, opacity: number): string
45
47
  export function useMaterial(thickness: MaterialThickness = "chrome") {
46
48
  const theme = useTheme() as unknown as Record<string, { val?: unknown } | undefined>;
47
49
  const { base, blur } = materials[thickness];
50
+ const nativeBlur = useMaterialBlur();
48
51
  const resolved = theme[base.slice(1)]?.val;
49
52
  const color = typeof resolved === "string" ? resolved : undefined;
50
53
  return {
51
- backgroundColor: translucent(color, materialOpacity(thickness)) ?? base,
54
+ backgroundColor: nativeBlur
55
+ ? "transparent"
56
+ : (translucent(color, materialOpacity(thickness)) ?? base),
52
57
  borderWidth: hairlineWidth,
53
58
  borderColor: "$borderColor",
54
59
  shadowColor: "$shadow3",
@@ -64,9 +69,16 @@ export interface MaterialProps extends YStackProps {
64
69
  }
65
70
 
66
71
  export const Material = forwardRef<TamaguiElement, MaterialProps>(function Material(
67
- { thickness = "chrome", ...props },
72
+ { thickness = "chrome", children, ...props },
68
73
  ref,
69
74
  ) {
70
75
  const material = useMaterial(thickness);
71
- return <YStack ref={ref} {...material} {...props} />;
76
+ return (
77
+ <YStack ref={ref} {...material} {...props}>
78
+ <MaterialBlurFill
79
+ radius={typeof props.borderRadius === "number" ? props.borderRadius : undefined}
80
+ />
81
+ {children}
82
+ </YStack>
83
+ );
72
84
  });
@@ -23,7 +23,6 @@ import {
23
23
  METER_TICK,
24
24
  METER_TRACK,
25
25
  METER_ZONE_PAINT,
26
- UNKNOWN_VALUE,
27
26
  formatMeterValue,
28
27
  meterFillRatio,
29
28
  meterTrackHeightPx,
@@ -114,13 +113,16 @@ function tickLeftPercent(cut: number, min: number, max: number): number | null {
114
113
  return ((cut - min) / (max - min)) * 100;
115
114
  }
116
115
 
116
+ /** LC-220: an unknown level is spoken as no reading, never as a zero or a bare dash. */
117
+ export const NO_READING = "No reading";
118
+
117
119
  function defaultValueText(opts: {
118
120
  value?: number | null;
119
121
  visible: string;
120
122
  unit?: string;
121
123
  format?: MeterFormat;
122
124
  }): string {
123
- if (opts.value == null || !Number.isFinite(opts.value)) return UNKNOWN_VALUE;
125
+ if (opts.value == null || !Number.isFinite(opts.value)) return NO_READING;
124
126
  if (opts.format === "percent") return opts.visible;
125
127
  if (opts.unit) return `${opts.visible} used`;
126
128
  return opts.visible;
@@ -23,6 +23,8 @@ import { Text } from "../Text";
23
23
  export { SortableHandle, SortableHandleWell } from "./SortableHandle";
24
24
  export { SortableSessionProvider, useSortableRows } from "./useSortableRows";
25
25
  export type { SortableSession, UseSortableRowsOptions } from "./useSortableRows";
26
+ export { applyUserOrder, useUserOrder } from "./useUserOrder";
27
+ export type { UseUserOrderOptions, UserOrderStorage } from "./useUserOrder";
26
28
 
27
29
  export type SortableDisabledStyle = "keepLabel" | "dimWhole";
28
30