@multiplatform.one/components 6.7.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (997) hide show
  1. package/dist/cjs/Accordion/index.cjs +213 -70
  2. package/dist/cjs/Accordion/index.native.js +254 -75
  3. package/dist/cjs/Accordion/index.native.js.map +1 -1
  4. package/dist/cjs/Alert/index.cjs +204 -56
  5. package/dist/cjs/Alert/index.native.js +211 -60
  6. package/dist/cjs/Alert/index.native.js.map +1 -1
  7. package/dist/cjs/AnimateHeight/index.cjs +166 -0
  8. package/dist/cjs/AnimateHeight/index.native.js +176 -0
  9. package/dist/cjs/AnimateHeight/index.native.js.map +1 -0
  10. package/dist/cjs/Avatar/getInitials.cjs +34 -0
  11. package/dist/cjs/Avatar/getInitials.native.js +34 -0
  12. package/dist/cjs/Avatar/getInitials.native.js.map +1 -1
  13. package/dist/cjs/Avatar/index.cjs +246 -62
  14. package/dist/cjs/Avatar/index.native.js +252 -68
  15. package/dist/cjs/Avatar/index.native.js.map +1 -1
  16. package/dist/cjs/Badge/index.cjs +109 -75
  17. package/dist/cjs/Badge/index.native.js +110 -76
  18. package/dist/cjs/Badge/index.native.js.map +1 -1
  19. package/dist/cjs/Button.cjs +41 -0
  20. package/dist/cjs/Button.native.js +45 -0
  21. package/dist/cjs/Button.native.js.map +1 -0
  22. package/dist/cjs/Carousel/index.cjs +184 -105
  23. package/dist/cjs/Carousel/index.native.js +212 -107
  24. package/dist/cjs/Carousel/index.native.js.map +1 -1
  25. package/dist/cjs/Chip/index.cjs +360 -5
  26. package/dist/cjs/Chip/index.native.js +374 -5
  27. package/dist/cjs/Chip/index.native.js.map +1 -1
  28. package/dist/cjs/DotIndicator/index.cjs +129 -13
  29. package/dist/cjs/DotIndicator/index.native.js +133 -13
  30. package/dist/cjs/DotIndicator/index.native.js.map +1 -1
  31. package/dist/cjs/DropdownMenu/index.cjs +110 -44
  32. package/dist/cjs/DropdownMenu/index.native.js +113 -46
  33. package/dist/cjs/DropdownMenu/index.native.js.map +1 -1
  34. package/dist/cjs/ErrorBoundary/index.cjs +2 -2
  35. package/dist/cjs/ErrorBoundary/index.native.js +2 -2
  36. package/dist/cjs/ErrorBoundary/index.native.js.map +1 -1
  37. package/dist/cjs/Pagination.cjs +40 -11
  38. package/dist/cjs/Pagination.native.js +44 -11
  39. package/dist/cjs/Pagination.native.js.map +1 -1
  40. package/dist/cjs/ProgressSteps/index.cjs +163 -107
  41. package/dist/cjs/ProgressSteps/index.native.js +171 -115
  42. package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
  43. package/dist/cjs/Quote/index.cjs +58 -39
  44. package/dist/cjs/Quote/index.native.js +69 -45
  45. package/dist/cjs/Quote/index.native.js.map +1 -1
  46. package/dist/cjs/SheetModal/index.cjs +141 -4
  47. package/dist/cjs/SheetModal/index.native.js +42 -29
  48. package/dist/cjs/SheetModal/index.native.js.map +1 -1
  49. package/dist/cjs/Skeleton/index.cjs +216 -4
  50. package/dist/cjs/Skeleton/index.native.js +223 -4
  51. package/dist/cjs/Skeleton/index.native.js.map +1 -1
  52. package/dist/cjs/SkipLink/index.cjs +91 -57
  53. package/dist/cjs/SkipLink/index.native.js +92 -66
  54. package/dist/cjs/SkipLink/index.native.js.map +1 -1
  55. package/dist/cjs/Tabs/index.cjs +136 -95
  56. package/dist/cjs/Tabs/index.native.js +161 -108
  57. package/dist/cjs/Tabs/index.native.js.map +1 -1
  58. package/dist/cjs/Toast/index.cjs +229 -67
  59. package/dist/cjs/Toast/index.native.js +232 -67
  60. package/dist/cjs/Toast/index.native.js.map +1 -1
  61. package/dist/cjs/Toast/store.cjs +83 -10
  62. package/dist/cjs/Toast/store.native.js +108 -10
  63. package/dist/cjs/Toast/store.native.js.map +1 -1
  64. package/dist/cjs/Tooltip/index.cjs +159 -42
  65. package/dist/cjs/Tooltip/index.native.js +195 -43
  66. package/dist/cjs/Tooltip/index.native.js.map +1 -1
  67. package/dist/cjs/Video/PlayerChrome.cjs +403 -0
  68. package/dist/cjs/Video/PlayerChrome.native.js +436 -0
  69. package/dist/cjs/Video/PlayerChrome.native.js.map +1 -0
  70. package/dist/cjs/Video/VideoFrame.cjs +14 -5
  71. package/dist/cjs/Video/VideoFrame.native.js +16 -5
  72. package/dist/cjs/Video/VideoFrame.native.js.map +1 -1
  73. package/dist/cjs/Video/index.cjs +227 -11
  74. package/dist/cjs/Video/index.native.js +28 -13
  75. package/dist/cjs/Video/index.native.js.map +1 -1
  76. package/dist/cjs/Wheel/index.cjs +144 -93
  77. package/dist/cjs/Wheel/index.native.js +149 -96
  78. package/dist/cjs/Wheel/index.native.js.map +1 -1
  79. package/dist/cjs/actions/DestructiveAction.cjs +2 -2
  80. package/dist/cjs/actions/DestructiveAction.native.js +2 -2
  81. package/dist/cjs/actions/DestructiveAction.native.js.map +1 -1
  82. package/dist/cjs/charts/BarChart.cjs +9 -5
  83. package/dist/cjs/charts/BarChart.native.js +9 -5
  84. package/dist/cjs/charts/BarChart.native.js.map +1 -1
  85. package/dist/cjs/charts/LineChart.cjs +2 -2
  86. package/dist/cjs/charts/LineChart.native.js +2 -2
  87. package/dist/cjs/charts/LineChart.native.js.map +1 -1
  88. package/dist/cjs/charts/PieChart.cjs +2 -2
  89. package/dist/cjs/charts/PieChart.native.js +2 -2
  90. package/dist/cjs/charts/PieChart.native.js.map +1 -1
  91. package/dist/cjs/charts/Sparkline.cjs +2 -2
  92. package/dist/cjs/charts/Sparkline.native.js +2 -2
  93. package/dist/cjs/charts/Sparkline.native.js.map +1 -1
  94. package/dist/cjs/charts/index.cjs +4 -0
  95. package/dist/cjs/charts/index.native.js +4 -0
  96. package/dist/cjs/charts/index.native.js.map +1 -1
  97. package/dist/cjs/code/CodeBlock/index.cjs +34 -7
  98. package/dist/cjs/code/CodeBlock/index.native.js +36 -9
  99. package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
  100. package/dist/cjs/feedback/ConfirmDialog.cjs +92 -5
  101. package/dist/cjs/feedback/ConfirmDialog.native.js +123 -5
  102. package/dist/cjs/feedback/ConfirmDialog.native.js.map +1 -1
  103. package/dist/cjs/feedback/NotifyHost.cjs +2 -2
  104. package/dist/cjs/feedback/NotifyHost.native.js +2 -2
  105. package/dist/cjs/feedback/NotifyHost.native.js.map +1 -1
  106. package/dist/cjs/icons/themed.cjs +4 -1
  107. package/dist/cjs/icons/themed.native.js +4 -1
  108. package/dist/cjs/icons/themed.native.js.map +1 -1
  109. package/dist/cjs/images/Image/ImageFrame.cjs +242 -0
  110. package/dist/cjs/images/Image/ImageFrame.native.js +248 -0
  111. package/dist/cjs/images/Image/ImageFrame.native.js.map +1 -0
  112. package/dist/cjs/images/Image/index.cjs +93 -40
  113. package/dist/cjs/images/Image/index.native.js +146 -108
  114. package/dist/cjs/images/Image/index.native.js.map +1 -1
  115. package/dist/cjs/images/Image/shared.cjs +106 -0
  116. package/dist/cjs/images/Image/shared.native.js +109 -0
  117. package/dist/cjs/images/Image/shared.native.js.map +1 -0
  118. package/dist/cjs/index.cjs +7 -0
  119. package/dist/cjs/index.native.js +7 -0
  120. package/dist/cjs/index.native.js.map +1 -1
  121. package/dist/cjs/knobImmuneExports.cjs +95 -0
  122. package/dist/cjs/knobImmuneExports.native.js +98 -0
  123. package/dist/cjs/knobImmuneExports.native.js.map +1 -0
  124. package/dist/cjs/layouts/AsyncBoundary.cjs +163 -36
  125. package/dist/cjs/layouts/AsyncBoundary.native.js +166 -37
  126. package/dist/cjs/layouts/AsyncBoundary.native.js.map +1 -1
  127. package/dist/cjs/layouts/EmptyState.cjs +157 -0
  128. package/dist/cjs/layouts/EmptyState.native.js +165 -0
  129. package/dist/cjs/layouts/EmptyState.native.js.map +1 -0
  130. package/dist/cjs/layouts/PageTemplates.cjs +13 -5
  131. package/dist/cjs/layouts/PageTemplates.native.js +13 -5
  132. package/dist/cjs/layouts/PageTemplates.native.js.map +1 -1
  133. package/dist/cjs/layouts/PaneScaffold.cjs +273 -13
  134. package/dist/cjs/layouts/PaneScaffold.native.js +294 -13
  135. package/dist/cjs/layouts/PaneScaffold.native.js.map +1 -1
  136. package/dist/cjs/layouts/ViewSwitcher.cjs +65 -23
  137. package/dist/cjs/layouts/ViewSwitcher.native.js +78 -30
  138. package/dist/cjs/layouts/ViewSwitcher.native.js.map +1 -1
  139. package/dist/cjs/layouts/attachments.cjs +350 -185
  140. package/dist/cjs/layouts/attachments.native.js +370 -186
  141. package/dist/cjs/layouts/attachments.native.js.map +1 -1
  142. package/dist/cjs/layouts/breadcrumbs.cjs +161 -62
  143. package/dist/cjs/layouts/breadcrumbs.native.js +184 -65
  144. package/dist/cjs/layouts/breadcrumbs.native.js.map +1 -1
  145. package/dist/cjs/layouts/page.cjs +71 -111
  146. package/dist/cjs/layouts/page.native.js +82 -130
  147. package/dist/cjs/layouts/page.native.js.map +1 -1
  148. package/dist/cjs/layouts/pageHeadingScope.cjs +8 -2
  149. package/dist/cjs/layouts/pageHeadingScope.native.js +10 -2
  150. package/dist/cjs/layouts/pageHeadingScope.native.js.map +1 -1
  151. package/dist/cjs/layouts/sidebar.cjs +150 -66
  152. package/dist/cjs/layouts/sidebar.native.js +118 -47
  153. package/dist/cjs/layouts/sidebar.native.js.map +1 -1
  154. package/dist/cjs/layouts/tags.cjs +321 -138
  155. package/dist/cjs/layouts/tags.native.js +355 -158
  156. package/dist/cjs/layouts/tags.native.js.map +1 -1
  157. package/dist/cjs/layouts/timeline.cjs +129 -56
  158. package/dist/cjs/layouts/timeline.native.js +179 -55
  159. package/dist/cjs/layouts/timeline.native.js.map +1 -1
  160. package/dist/cjs/layouts/toolbar.cjs +56 -20
  161. package/dist/cjs/layouts/toolbar.native.js +62 -25
  162. package/dist/cjs/layouts/toolbar.native.js.map +1 -1
  163. package/dist/cjs/shared/i18n.cjs +46 -0
  164. package/dist/cjs/shared/i18n.native.js +52 -0
  165. package/dist/cjs/shared/i18n.native.js.map +1 -0
  166. package/dist/cjs/shared/textRidesText.cjs +57 -0
  167. package/dist/cjs/shared/textRidesText.native.js +81 -0
  168. package/dist/cjs/shared/textRidesText.native.js.map +1 -0
  169. package/dist/cjs/shared/useReturnFocusOnClose.cjs +7 -1
  170. package/dist/cjs/shared/useReturnFocusOnClose.native.js +7 -1
  171. package/dist/cjs/shared/useReturnFocusOnClose.native.js.map +1 -1
  172. package/dist/cjs/surfaces.cjs +93 -16
  173. package/dist/cjs/surfaces.native.js +95 -16
  174. package/dist/cjs/surfaces.native.js.map +1 -1
  175. package/dist/cjs/tamagui.cjs +38 -39
  176. package/dist/cjs/tamagui.native.js +37 -38
  177. package/dist/cjs/tamagui.native.js.map +1 -1
  178. package/dist/cjs/views/Calendar.cjs +101 -64
  179. package/dist/cjs/views/Calendar.native.js +105 -70
  180. package/dist/cjs/views/Calendar.native.js.map +1 -1
  181. package/dist/cjs/views/Dashboard.cjs +399 -107
  182. package/dist/cjs/views/Dashboard.native.js +408 -110
  183. package/dist/cjs/views/Dashboard.native.js.map +1 -1
  184. package/dist/cjs/views/Gantt.cjs +256 -59
  185. package/dist/cjs/views/Gantt.native.js +264 -39
  186. package/dist/cjs/views/Gantt.native.js.map +1 -1
  187. package/dist/cjs/views/ImageGrid.cjs +138 -73
  188. package/dist/cjs/views/ImageGrid.native.js +155 -71
  189. package/dist/cjs/views/ImageGrid.native.js.map +1 -1
  190. package/dist/cjs/views/Kanban.cjs +53 -31
  191. package/dist/cjs/views/Kanban.native.js +55 -41
  192. package/dist/cjs/views/Kanban.native.js.map +1 -1
  193. package/dist/cjs/views/List.cjs +280 -93
  194. package/dist/cjs/views/List.native.js +280 -101
  195. package/dist/cjs/views/List.native.js.map +1 -1
  196. package/dist/cjs/views/ReportBuilder.cjs +539 -172
  197. package/dist/cjs/views/ReportBuilder.native.js +592 -169
  198. package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
  199. package/dist/cjs/views/TreeView.cjs +142 -52
  200. package/dist/cjs/views/TreeView.native.js +170 -55
  201. package/dist/cjs/views/TreeView.native.js.map +1 -1
  202. package/dist/esm/Accordion/index.mjs +216 -73
  203. package/dist/esm/Accordion/index.mjs.map +1 -1
  204. package/dist/esm/Accordion/index.native.js +257 -78
  205. package/dist/esm/Accordion/index.native.js.map +1 -1
  206. package/dist/esm/Alert/index.mjs +206 -58
  207. package/dist/esm/Alert/index.mjs.map +1 -1
  208. package/dist/esm/Alert/index.native.js +213 -62
  209. package/dist/esm/Alert/index.native.js.map +1 -1
  210. package/dist/esm/AnimateHeight/index.mjs +140 -0
  211. package/dist/esm/AnimateHeight/index.mjs.map +1 -0
  212. package/dist/esm/AnimateHeight/index.native.js +147 -0
  213. package/dist/esm/AnimateHeight/index.native.js.map +1 -0
  214. package/dist/esm/Avatar/getInitials.mjs +32 -1
  215. package/dist/esm/Avatar/getInitials.mjs.map +1 -1
  216. package/dist/esm/Avatar/getInitials.native.js +32 -1
  217. package/dist/esm/Avatar/getInitials.native.js.map +1 -1
  218. package/dist/esm/Avatar/index.mjs +249 -68
  219. package/dist/esm/Avatar/index.mjs.map +1 -1
  220. package/dist/esm/Avatar/index.native.js +255 -74
  221. package/dist/esm/Avatar/index.native.js.map +1 -1
  222. package/dist/esm/Badge/index.mjs +110 -76
  223. package/dist/esm/Badge/index.mjs.map +1 -1
  224. package/dist/esm/Badge/index.native.js +111 -77
  225. package/dist/esm/Badge/index.native.js.map +1 -1
  226. package/dist/esm/Button.mjs +16 -0
  227. package/dist/esm/Button.mjs.map +1 -0
  228. package/dist/esm/Button.native.js +17 -0
  229. package/dist/esm/Button.native.js.map +1 -0
  230. package/dist/esm/Carousel/index.mjs +185 -106
  231. package/dist/esm/Carousel/index.mjs.map +1 -1
  232. package/dist/esm/Carousel/index.native.js +213 -108
  233. package/dist/esm/Carousel/index.native.js.map +1 -1
  234. package/dist/esm/Chip/index.mjs +356 -2
  235. package/dist/esm/Chip/index.mjs.map +1 -1
  236. package/dist/esm/Chip/index.native.js +370 -2
  237. package/dist/esm/Chip/index.native.js.map +1 -1
  238. package/dist/esm/DotIndicator/index.mjs +130 -14
  239. package/dist/esm/DotIndicator/index.mjs.map +1 -1
  240. package/dist/esm/DotIndicator/index.native.js +134 -14
  241. package/dist/esm/DotIndicator/index.native.js.map +1 -1
  242. package/dist/esm/DropdownMenu/index.mjs +112 -46
  243. package/dist/esm/DropdownMenu/index.mjs.map +1 -1
  244. package/dist/esm/DropdownMenu/index.native.js +115 -48
  245. package/dist/esm/DropdownMenu/index.native.js.map +1 -1
  246. package/dist/esm/ErrorBoundary/index.mjs +1 -1
  247. package/dist/esm/ErrorBoundary/index.native.js +1 -1
  248. package/dist/esm/Pagination.mjs +41 -12
  249. package/dist/esm/Pagination.mjs.map +1 -1
  250. package/dist/esm/Pagination.native.js +45 -12
  251. package/dist/esm/Pagination.native.js.map +1 -1
  252. package/dist/esm/ProgressSteps/index.mjs +165 -109
  253. package/dist/esm/ProgressSteps/index.mjs.map +1 -1
  254. package/dist/esm/ProgressSteps/index.native.js +173 -117
  255. package/dist/esm/ProgressSteps/index.native.js.map +1 -1
  256. package/dist/esm/Quote/index.mjs +59 -40
  257. package/dist/esm/Quote/index.mjs.map +1 -1
  258. package/dist/esm/Quote/index.native.js +70 -46
  259. package/dist/esm/Quote/index.native.js.map +1 -1
  260. package/dist/esm/SheetModal/index.mjs +144 -7
  261. package/dist/esm/SheetModal/index.mjs.map +1 -1
  262. package/dist/esm/SheetModal/index.native.js +41 -28
  263. package/dist/esm/SheetModal/index.native.js.map +1 -1
  264. package/dist/esm/Skeleton/index.mjs +213 -2
  265. package/dist/esm/Skeleton/index.mjs.map +1 -1
  266. package/dist/esm/Skeleton/index.native.js +220 -2
  267. package/dist/esm/Skeleton/index.native.js.map +1 -1
  268. package/dist/esm/SkipLink/index.mjs +93 -59
  269. package/dist/esm/SkipLink/index.mjs.map +1 -1
  270. package/dist/esm/SkipLink/index.native.js +94 -68
  271. package/dist/esm/SkipLink/index.native.js.map +1 -1
  272. package/dist/esm/Tabs/index.mjs +137 -96
  273. package/dist/esm/Tabs/index.mjs.map +1 -1
  274. package/dist/esm/Tabs/index.native.js +162 -109
  275. package/dist/esm/Tabs/index.native.js.map +1 -1
  276. package/dist/esm/Toast/index.mjs +227 -68
  277. package/dist/esm/Toast/index.mjs.map +1 -1
  278. package/dist/esm/Toast/index.native.js +230 -68
  279. package/dist/esm/Toast/index.native.js.map +1 -1
  280. package/dist/esm/Toast/store.mjs +75 -11
  281. package/dist/esm/Toast/store.mjs.map +1 -1
  282. package/dist/esm/Toast/store.native.js +100 -11
  283. package/dist/esm/Toast/store.native.js.map +1 -1
  284. package/dist/esm/Tooltip/index.mjs +147 -42
  285. package/dist/esm/Tooltip/index.mjs.map +1 -1
  286. package/dist/esm/Tooltip/index.native.js +184 -44
  287. package/dist/esm/Tooltip/index.native.js.map +1 -1
  288. package/dist/esm/Video/PlayerChrome.mjs +377 -0
  289. package/dist/esm/Video/PlayerChrome.mjs.map +1 -0
  290. package/dist/esm/Video/PlayerChrome.native.js +407 -0
  291. package/dist/esm/Video/PlayerChrome.native.js.map +1 -0
  292. package/dist/esm/Video/VideoFrame.mjs +14 -5
  293. package/dist/esm/Video/VideoFrame.mjs.map +1 -1
  294. package/dist/esm/Video/VideoFrame.native.js +16 -5
  295. package/dist/esm/Video/VideoFrame.native.js.map +1 -1
  296. package/dist/esm/Video/index.mjs +227 -11
  297. package/dist/esm/Video/index.mjs.map +1 -1
  298. package/dist/esm/Video/index.native.js +28 -13
  299. package/dist/esm/Video/index.native.js.map +1 -1
  300. package/dist/esm/Wheel/index.mjs +143 -92
  301. package/dist/esm/Wheel/index.mjs.map +1 -1
  302. package/dist/esm/Wheel/index.native.js +148 -95
  303. package/dist/esm/Wheel/index.native.js.map +1 -1
  304. package/dist/esm/actions/DestructiveAction.mjs +1 -1
  305. package/dist/esm/actions/DestructiveAction.native.js +1 -1
  306. package/dist/esm/actions/DestructiveAction.native.js.map +1 -1
  307. package/dist/esm/charts/BarChart.mjs +8 -4
  308. package/dist/esm/charts/BarChart.mjs.map +1 -1
  309. package/dist/esm/charts/BarChart.native.js +8 -4
  310. package/dist/esm/charts/BarChart.native.js.map +1 -1
  311. package/dist/esm/charts/LineChart.mjs +1 -1
  312. package/dist/esm/charts/LineChart.native.js +1 -1
  313. package/dist/esm/charts/PieChart.mjs +1 -1
  314. package/dist/esm/charts/PieChart.native.js +1 -1
  315. package/dist/esm/charts/PieChart.native.js.map +1 -1
  316. package/dist/esm/charts/Sparkline.mjs +1 -1
  317. package/dist/esm/charts/Sparkline.native.js +1 -1
  318. package/dist/esm/charts/index.mjs +2 -1
  319. package/dist/esm/charts/index.mjs.map +1 -1
  320. package/dist/esm/charts/index.native.js +2 -1
  321. package/dist/esm/charts/index.native.js.map +1 -1
  322. package/dist/esm/code/CodeBlock/index.mjs +34 -7
  323. package/dist/esm/code/CodeBlock/index.mjs.map +1 -1
  324. package/dist/esm/code/CodeBlock/index.native.js +36 -9
  325. package/dist/esm/code/CodeBlock/index.native.js.map +1 -1
  326. package/dist/esm/feedback/ConfirmDialog.mjs +93 -6
  327. package/dist/esm/feedback/ConfirmDialog.mjs.map +1 -1
  328. package/dist/esm/feedback/ConfirmDialog.native.js +124 -6
  329. package/dist/esm/feedback/ConfirmDialog.native.js.map +1 -1
  330. package/dist/esm/feedback/NotifyHost.mjs +1 -1
  331. package/dist/esm/feedback/NotifyHost.native.js +1 -1
  332. package/dist/esm/icons/themed.mjs +5 -2
  333. package/dist/esm/icons/themed.mjs.map +1 -1
  334. package/dist/esm/icons/themed.native.js +5 -2
  335. package/dist/esm/icons/themed.native.js.map +1 -1
  336. package/dist/esm/images/Image/ImageFrame.mjs +216 -0
  337. package/dist/esm/images/Image/ImageFrame.mjs.map +1 -0
  338. package/dist/esm/images/Image/ImageFrame.native.js +219 -0
  339. package/dist/esm/images/Image/ImageFrame.native.js.map +1 -0
  340. package/dist/esm/images/Image/index.mjs +94 -41
  341. package/dist/esm/images/Image/index.mjs.map +1 -1
  342. package/dist/esm/images/Image/index.native.js +148 -110
  343. package/dist/esm/images/Image/index.native.js.map +1 -1
  344. package/dist/esm/images/Image/shared.mjs +76 -0
  345. package/dist/esm/images/Image/shared.mjs.map +1 -0
  346. package/dist/esm/images/Image/shared.native.js +76 -0
  347. package/dist/esm/images/Image/shared.native.js.map +1 -0
  348. package/dist/esm/index.mjs +4 -1
  349. package/dist/esm/index.mjs.map +1 -1
  350. package/dist/esm/index.native.js +4 -1
  351. package/dist/esm/index.native.js.map +1 -1
  352. package/dist/esm/knobImmuneExports.mjs +70 -0
  353. package/dist/esm/knobImmuneExports.mjs.map +1 -0
  354. package/dist/esm/knobImmuneExports.native.js +70 -0
  355. package/dist/esm/knobImmuneExports.native.js.map +1 -0
  356. package/dist/esm/layouts/AsyncBoundary.mjs +165 -38
  357. package/dist/esm/layouts/AsyncBoundary.mjs.map +1 -1
  358. package/dist/esm/layouts/AsyncBoundary.native.js +168 -39
  359. package/dist/esm/layouts/AsyncBoundary.native.js.map +1 -1
  360. package/dist/esm/layouts/EmptyState.mjs +132 -0
  361. package/dist/esm/layouts/EmptyState.mjs.map +1 -0
  362. package/dist/esm/layouts/EmptyState.native.js +137 -0
  363. package/dist/esm/layouts/EmptyState.native.js.map +1 -0
  364. package/dist/esm/layouts/PageTemplates.mjs +13 -5
  365. package/dist/esm/layouts/PageTemplates.mjs.map +1 -1
  366. package/dist/esm/layouts/PageTemplates.native.js +13 -5
  367. package/dist/esm/layouts/PageTemplates.native.js.map +1 -1
  368. package/dist/esm/layouts/PaneScaffold.mjs +277 -17
  369. package/dist/esm/layouts/PaneScaffold.mjs.map +1 -1
  370. package/dist/esm/layouts/PaneScaffold.native.js +298 -17
  371. package/dist/esm/layouts/PaneScaffold.native.js.map +1 -1
  372. package/dist/esm/layouts/ViewSwitcher.mjs +66 -24
  373. package/dist/esm/layouts/ViewSwitcher.mjs.map +1 -1
  374. package/dist/esm/layouts/ViewSwitcher.native.js +79 -31
  375. package/dist/esm/layouts/ViewSwitcher.native.js.map +1 -1
  376. package/dist/esm/layouts/attachments.mjs +351 -175
  377. package/dist/esm/layouts/attachments.mjs.map +1 -1
  378. package/dist/esm/layouts/attachments.native.js +371 -187
  379. package/dist/esm/layouts/attachments.native.js.map +1 -1
  380. package/dist/esm/layouts/breadcrumbs.mjs +163 -53
  381. package/dist/esm/layouts/breadcrumbs.mjs.map +1 -1
  382. package/dist/esm/layouts/breadcrumbs.native.js +187 -68
  383. package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
  384. package/dist/esm/layouts/page.mjs +72 -112
  385. package/dist/esm/layouts/page.mjs.map +1 -1
  386. package/dist/esm/layouts/page.native.js +83 -131
  387. package/dist/esm/layouts/page.native.js.map +1 -1
  388. package/dist/esm/layouts/pageHeadingScope.mjs +8 -3
  389. package/dist/esm/layouts/pageHeadingScope.mjs.map +1 -1
  390. package/dist/esm/layouts/pageHeadingScope.native.js +10 -3
  391. package/dist/esm/layouts/pageHeadingScope.native.js.map +1 -1
  392. package/dist/esm/layouts/sidebar.mjs +152 -68
  393. package/dist/esm/layouts/sidebar.mjs.map +1 -1
  394. package/dist/esm/layouts/sidebar.native.js +120 -49
  395. package/dist/esm/layouts/sidebar.native.js.map +1 -1
  396. package/dist/esm/layouts/tags.mjs +323 -140
  397. package/dist/esm/layouts/tags.mjs.map +1 -1
  398. package/dist/esm/layouts/tags.native.js +357 -160
  399. package/dist/esm/layouts/tags.native.js.map +1 -1
  400. package/dist/esm/layouts/timeline.mjs +129 -45
  401. package/dist/esm/layouts/timeline.mjs.map +1 -1
  402. package/dist/esm/layouts/timeline.native.js +179 -55
  403. package/dist/esm/layouts/timeline.native.js.map +1 -1
  404. package/dist/esm/layouts/toolbar.mjs +57 -21
  405. package/dist/esm/layouts/toolbar.mjs.map +1 -1
  406. package/dist/esm/layouts/toolbar.native.js +63 -26
  407. package/dist/esm/layouts/toolbar.native.js.map +1 -1
  408. package/dist/esm/shared/i18n.mjs +10 -0
  409. package/dist/esm/shared/i18n.mjs.map +1 -0
  410. package/dist/esm/shared/i18n.native.js +13 -0
  411. package/dist/esm/shared/i18n.native.js.map +1 -0
  412. package/dist/esm/shared/textRidesText.mjs +31 -0
  413. package/dist/esm/shared/textRidesText.mjs.map +1 -0
  414. package/dist/esm/shared/textRidesText.native.js +52 -0
  415. package/dist/esm/shared/textRidesText.native.js.map +1 -0
  416. package/dist/esm/shared/useReturnFocusOnClose.mjs +7 -1
  417. package/dist/esm/shared/useReturnFocusOnClose.mjs.map +1 -1
  418. package/dist/esm/shared/useReturnFocusOnClose.native.js +7 -1
  419. package/dist/esm/shared/useReturnFocusOnClose.native.js.map +1 -1
  420. package/dist/esm/surfaces.mjs +94 -17
  421. package/dist/esm/surfaces.mjs.map +1 -1
  422. package/dist/esm/surfaces.native.js +96 -17
  423. package/dist/esm/surfaces.native.js.map +1 -1
  424. package/dist/esm/tamagui.mjs +2 -3
  425. package/dist/esm/tamagui.mjs.map +1 -1
  426. package/dist/esm/tamagui.native.js +2 -3
  427. package/dist/esm/tamagui.native.js.map +1 -1
  428. package/dist/esm/views/Calendar.mjs +101 -64
  429. package/dist/esm/views/Calendar.mjs.map +1 -1
  430. package/dist/esm/views/Calendar.native.js +105 -70
  431. package/dist/esm/views/Calendar.native.js.map +1 -1
  432. package/dist/esm/views/Dashboard.mjs +396 -107
  433. package/dist/esm/views/Dashboard.mjs.map +1 -1
  434. package/dist/esm/views/Dashboard.native.js +405 -110
  435. package/dist/esm/views/Dashboard.native.js.map +1 -1
  436. package/dist/esm/views/Gantt.mjs +256 -59
  437. package/dist/esm/views/Gantt.mjs.map +1 -1
  438. package/dist/esm/views/Gantt.native.js +264 -39
  439. package/dist/esm/views/Gantt.native.js.map +1 -1
  440. package/dist/esm/views/ImageGrid.mjs +138 -73
  441. package/dist/esm/views/ImageGrid.mjs.map +1 -1
  442. package/dist/esm/views/ImageGrid.native.js +155 -71
  443. package/dist/esm/views/ImageGrid.native.js.map +1 -1
  444. package/dist/esm/views/Kanban.mjs +52 -30
  445. package/dist/esm/views/Kanban.mjs.map +1 -1
  446. package/dist/esm/views/Kanban.native.js +54 -40
  447. package/dist/esm/views/Kanban.native.js.map +1 -1
  448. package/dist/esm/views/List.mjs +268 -95
  449. package/dist/esm/views/List.mjs.map +1 -1
  450. package/dist/esm/views/List.native.js +280 -104
  451. package/dist/esm/views/List.native.js.map +1 -1
  452. package/dist/esm/views/ReportBuilder.mjs +533 -166
  453. package/dist/esm/views/ReportBuilder.mjs.map +1 -1
  454. package/dist/esm/views/ReportBuilder.native.js +585 -162
  455. package/dist/esm/views/ReportBuilder.native.js.map +1 -1
  456. package/dist/esm/views/TreeView.mjs +142 -52
  457. package/dist/esm/views/TreeView.mjs.map +1 -1
  458. package/dist/esm/views/TreeView.native.js +170 -55
  459. package/dist/esm/views/TreeView.native.js.map +1 -1
  460. package/dist/jsx/Accordion/index.mjs +216 -73
  461. package/dist/jsx/Accordion/index.mjs.map +1 -1
  462. package/dist/jsx/Accordion/index.native.js +254 -75
  463. package/dist/jsx/Accordion/index.native.js.map +1 -1
  464. package/dist/jsx/Alert/index.mjs +206 -58
  465. package/dist/jsx/Alert/index.mjs.map +1 -1
  466. package/dist/jsx/Alert/index.native.js +211 -60
  467. package/dist/jsx/Alert/index.native.js.map +1 -1
  468. package/dist/jsx/AnimateHeight/index.mjs +140 -0
  469. package/dist/jsx/AnimateHeight/index.mjs.map +1 -0
  470. package/dist/jsx/AnimateHeight/index.native.js +176 -0
  471. package/dist/jsx/AnimateHeight/index.native.js.map +1 -0
  472. package/dist/jsx/Avatar/getInitials.mjs +32 -1
  473. package/dist/jsx/Avatar/getInitials.mjs.map +1 -1
  474. package/dist/jsx/Avatar/getInitials.native.js +34 -0
  475. package/dist/jsx/Avatar/getInitials.native.js.map +1 -1
  476. package/dist/jsx/Avatar/index.mjs +249 -68
  477. package/dist/jsx/Avatar/index.mjs.map +1 -1
  478. package/dist/jsx/Avatar/index.native.js +252 -68
  479. package/dist/jsx/Avatar/index.native.js.map +1 -1
  480. package/dist/jsx/Badge/index.mjs +110 -76
  481. package/dist/jsx/Badge/index.mjs.map +1 -1
  482. package/dist/jsx/Badge/index.native.js +110 -76
  483. package/dist/jsx/Badge/index.native.js.map +1 -1
  484. package/dist/jsx/Button.mjs +16 -0
  485. package/dist/jsx/Button.mjs.map +1 -0
  486. package/dist/jsx/Button.native.js +45 -0
  487. package/dist/jsx/Button.native.js.map +1 -0
  488. package/dist/jsx/Carousel/index.mjs +185 -106
  489. package/dist/jsx/Carousel/index.mjs.map +1 -1
  490. package/dist/jsx/Carousel/index.native.js +212 -107
  491. package/dist/jsx/Carousel/index.native.js.map +1 -1
  492. package/dist/jsx/Chip/index.mjs +356 -2
  493. package/dist/jsx/Chip/index.mjs.map +1 -1
  494. package/dist/jsx/Chip/index.native.js +374 -5
  495. package/dist/jsx/Chip/index.native.js.map +1 -1
  496. package/dist/jsx/DotIndicator/index.mjs +130 -14
  497. package/dist/jsx/DotIndicator/index.mjs.map +1 -1
  498. package/dist/jsx/DotIndicator/index.native.js +133 -13
  499. package/dist/jsx/DotIndicator/index.native.js.map +1 -1
  500. package/dist/jsx/DropdownMenu/index.mjs +112 -46
  501. package/dist/jsx/DropdownMenu/index.mjs.map +1 -1
  502. package/dist/jsx/DropdownMenu/index.native.js +113 -46
  503. package/dist/jsx/DropdownMenu/index.native.js.map +1 -1
  504. package/dist/jsx/ErrorBoundary/index.mjs +1 -1
  505. package/dist/jsx/ErrorBoundary/index.native.js +2 -2
  506. package/dist/jsx/ErrorBoundary/index.native.js.map +1 -1
  507. package/dist/jsx/Pagination.mjs +41 -12
  508. package/dist/jsx/Pagination.mjs.map +1 -1
  509. package/dist/jsx/Pagination.native.js +44 -11
  510. package/dist/jsx/Pagination.native.js.map +1 -1
  511. package/dist/jsx/ProgressSteps/index.mjs +165 -109
  512. package/dist/jsx/ProgressSteps/index.mjs.map +1 -1
  513. package/dist/jsx/ProgressSteps/index.native.js +171 -115
  514. package/dist/jsx/ProgressSteps/index.native.js.map +1 -1
  515. package/dist/jsx/Quote/index.mjs +59 -40
  516. package/dist/jsx/Quote/index.mjs.map +1 -1
  517. package/dist/jsx/Quote/index.native.js +69 -45
  518. package/dist/jsx/Quote/index.native.js.map +1 -1
  519. package/dist/jsx/SheetModal/index.mjs +144 -7
  520. package/dist/jsx/SheetModal/index.mjs.map +1 -1
  521. package/dist/jsx/SheetModal/index.native.js +42 -29
  522. package/dist/jsx/SheetModal/index.native.js.map +1 -1
  523. package/dist/jsx/Skeleton/index.mjs +213 -2
  524. package/dist/jsx/Skeleton/index.mjs.map +1 -1
  525. package/dist/jsx/Skeleton/index.native.js +223 -4
  526. package/dist/jsx/Skeleton/index.native.js.map +1 -1
  527. package/dist/jsx/SkipLink/index.mjs +93 -59
  528. package/dist/jsx/SkipLink/index.mjs.map +1 -1
  529. package/dist/jsx/SkipLink/index.native.js +92 -66
  530. package/dist/jsx/SkipLink/index.native.js.map +1 -1
  531. package/dist/jsx/Tabs/index.mjs +137 -96
  532. package/dist/jsx/Tabs/index.mjs.map +1 -1
  533. package/dist/jsx/Tabs/index.native.js +161 -108
  534. package/dist/jsx/Tabs/index.native.js.map +1 -1
  535. package/dist/jsx/Toast/index.mjs +227 -68
  536. package/dist/jsx/Toast/index.mjs.map +1 -1
  537. package/dist/jsx/Toast/index.native.js +232 -67
  538. package/dist/jsx/Toast/index.native.js.map +1 -1
  539. package/dist/jsx/Toast/store.mjs +75 -11
  540. package/dist/jsx/Toast/store.mjs.map +1 -1
  541. package/dist/jsx/Toast/store.native.js +108 -10
  542. package/dist/jsx/Toast/store.native.js.map +1 -1
  543. package/dist/jsx/Tooltip/index.mjs +147 -42
  544. package/dist/jsx/Tooltip/index.mjs.map +1 -1
  545. package/dist/jsx/Tooltip/index.native.js +195 -43
  546. package/dist/jsx/Tooltip/index.native.js.map +1 -1
  547. package/dist/jsx/Video/PlayerChrome.mjs +377 -0
  548. package/dist/jsx/Video/PlayerChrome.mjs.map +1 -0
  549. package/dist/jsx/Video/PlayerChrome.native.js +436 -0
  550. package/dist/jsx/Video/PlayerChrome.native.js.map +1 -0
  551. package/dist/jsx/Video/VideoFrame.mjs +14 -5
  552. package/dist/jsx/Video/VideoFrame.mjs.map +1 -1
  553. package/dist/jsx/Video/VideoFrame.native.js +16 -5
  554. package/dist/jsx/Video/VideoFrame.native.js.map +1 -1
  555. package/dist/jsx/Video/index.mjs +227 -11
  556. package/dist/jsx/Video/index.mjs.map +1 -1
  557. package/dist/jsx/Video/index.native.js +28 -13
  558. package/dist/jsx/Video/index.native.js.map +1 -1
  559. package/dist/jsx/Wheel/index.mjs +143 -92
  560. package/dist/jsx/Wheel/index.mjs.map +1 -1
  561. package/dist/jsx/Wheel/index.native.js +149 -96
  562. package/dist/jsx/Wheel/index.native.js.map +1 -1
  563. package/dist/jsx/actions/DestructiveAction.mjs +1 -1
  564. package/dist/jsx/actions/DestructiveAction.native.js +2 -2
  565. package/dist/jsx/actions/DestructiveAction.native.js.map +1 -1
  566. package/dist/jsx/charts/BarChart.mjs +8 -4
  567. package/dist/jsx/charts/BarChart.mjs.map +1 -1
  568. package/dist/jsx/charts/BarChart.native.js +9 -5
  569. package/dist/jsx/charts/BarChart.native.js.map +1 -1
  570. package/dist/jsx/charts/LineChart.mjs +1 -1
  571. package/dist/jsx/charts/LineChart.native.js +2 -2
  572. package/dist/jsx/charts/LineChart.native.js.map +1 -1
  573. package/dist/jsx/charts/PieChart.mjs +1 -1
  574. package/dist/jsx/charts/PieChart.native.js +2 -2
  575. package/dist/jsx/charts/PieChart.native.js.map +1 -1
  576. package/dist/jsx/charts/Sparkline.mjs +1 -1
  577. package/dist/jsx/charts/Sparkline.native.js +2 -2
  578. package/dist/jsx/charts/Sparkline.native.js.map +1 -1
  579. package/dist/jsx/charts/index.mjs +2 -1
  580. package/dist/jsx/charts/index.mjs.map +1 -1
  581. package/dist/jsx/charts/index.native.js +4 -0
  582. package/dist/jsx/charts/index.native.js.map +1 -1
  583. package/dist/jsx/code/CodeBlock/index.mjs +34 -7
  584. package/dist/jsx/code/CodeBlock/index.mjs.map +1 -1
  585. package/dist/jsx/code/CodeBlock/index.native.js +36 -9
  586. package/dist/jsx/code/CodeBlock/index.native.js.map +1 -1
  587. package/dist/jsx/feedback/ConfirmDialog.mjs +93 -6
  588. package/dist/jsx/feedback/ConfirmDialog.mjs.map +1 -1
  589. package/dist/jsx/feedback/ConfirmDialog.native.js +123 -5
  590. package/dist/jsx/feedback/ConfirmDialog.native.js.map +1 -1
  591. package/dist/jsx/feedback/NotifyHost.mjs +1 -1
  592. package/dist/jsx/feedback/NotifyHost.native.js +2 -2
  593. package/dist/jsx/feedback/NotifyHost.native.js.map +1 -1
  594. package/dist/jsx/icons/themed.mjs +5 -2
  595. package/dist/jsx/icons/themed.mjs.map +1 -1
  596. package/dist/jsx/icons/themed.native.js +4 -1
  597. package/dist/jsx/icons/themed.native.js.map +1 -1
  598. package/dist/jsx/images/Image/ImageFrame.mjs +216 -0
  599. package/dist/jsx/images/Image/ImageFrame.mjs.map +1 -0
  600. package/dist/jsx/images/Image/ImageFrame.native.js +248 -0
  601. package/dist/jsx/images/Image/ImageFrame.native.js.map +1 -0
  602. package/dist/jsx/images/Image/index.mjs +94 -41
  603. package/dist/jsx/images/Image/index.mjs.map +1 -1
  604. package/dist/jsx/images/Image/index.native.js +146 -108
  605. package/dist/jsx/images/Image/index.native.js.map +1 -1
  606. package/dist/jsx/images/Image/shared.mjs +76 -0
  607. package/dist/jsx/images/Image/shared.mjs.map +1 -0
  608. package/dist/jsx/images/Image/shared.native.js +109 -0
  609. package/dist/jsx/images/Image/shared.native.js.map +1 -0
  610. package/dist/jsx/index.js +4 -1
  611. package/dist/jsx/index.js.map +1 -1
  612. package/dist/jsx/index.mjs +4 -1
  613. package/dist/jsx/index.mjs.map +1 -1
  614. package/dist/jsx/index.native.js +7 -0
  615. package/dist/jsx/index.native.js.map +1 -1
  616. package/dist/jsx/knobImmuneExports.mjs +70 -0
  617. package/dist/jsx/knobImmuneExports.mjs.map +1 -0
  618. package/dist/jsx/knobImmuneExports.native.js +98 -0
  619. package/dist/jsx/knobImmuneExports.native.js.map +1 -0
  620. package/dist/jsx/layouts/AsyncBoundary.mjs +165 -38
  621. package/dist/jsx/layouts/AsyncBoundary.mjs.map +1 -1
  622. package/dist/jsx/layouts/AsyncBoundary.native.js +166 -37
  623. package/dist/jsx/layouts/AsyncBoundary.native.js.map +1 -1
  624. package/dist/jsx/layouts/EmptyState.mjs +132 -0
  625. package/dist/jsx/layouts/EmptyState.mjs.map +1 -0
  626. package/dist/jsx/layouts/EmptyState.native.js +165 -0
  627. package/dist/jsx/layouts/EmptyState.native.js.map +1 -0
  628. package/dist/jsx/layouts/PageTemplates.mjs +13 -5
  629. package/dist/jsx/layouts/PageTemplates.mjs.map +1 -1
  630. package/dist/jsx/layouts/PageTemplates.native.js +13 -5
  631. package/dist/jsx/layouts/PageTemplates.native.js.map +1 -1
  632. package/dist/jsx/layouts/PaneScaffold.mjs +277 -17
  633. package/dist/jsx/layouts/PaneScaffold.mjs.map +1 -1
  634. package/dist/jsx/layouts/PaneScaffold.native.js +294 -13
  635. package/dist/jsx/layouts/PaneScaffold.native.js.map +1 -1
  636. package/dist/jsx/layouts/ViewSwitcher.mjs +66 -24
  637. package/dist/jsx/layouts/ViewSwitcher.mjs.map +1 -1
  638. package/dist/jsx/layouts/ViewSwitcher.native.js +78 -30
  639. package/dist/jsx/layouts/ViewSwitcher.native.js.map +1 -1
  640. package/dist/jsx/layouts/attachments.mjs +351 -175
  641. package/dist/jsx/layouts/attachments.mjs.map +1 -1
  642. package/dist/jsx/layouts/attachments.native.js +370 -186
  643. package/dist/jsx/layouts/attachments.native.js.map +1 -1
  644. package/dist/jsx/layouts/breadcrumbs.mjs +163 -53
  645. package/dist/jsx/layouts/breadcrumbs.mjs.map +1 -1
  646. package/dist/jsx/layouts/breadcrumbs.native.js +184 -65
  647. package/dist/jsx/layouts/breadcrumbs.native.js.map +1 -1
  648. package/dist/jsx/layouts/page.mjs +72 -112
  649. package/dist/jsx/layouts/page.mjs.map +1 -1
  650. package/dist/jsx/layouts/page.native.js +82 -130
  651. package/dist/jsx/layouts/page.native.js.map +1 -1
  652. package/dist/jsx/layouts/pageHeadingScope.mjs +8 -3
  653. package/dist/jsx/layouts/pageHeadingScope.mjs.map +1 -1
  654. package/dist/jsx/layouts/pageHeadingScope.native.js +10 -2
  655. package/dist/jsx/layouts/pageHeadingScope.native.js.map +1 -1
  656. package/dist/jsx/layouts/sidebar.mjs +152 -68
  657. package/dist/jsx/layouts/sidebar.mjs.map +1 -1
  658. package/dist/jsx/layouts/sidebar.native.js +118 -47
  659. package/dist/jsx/layouts/sidebar.native.js.map +1 -1
  660. package/dist/jsx/layouts/tags.mjs +323 -140
  661. package/dist/jsx/layouts/tags.mjs.map +1 -1
  662. package/dist/jsx/layouts/tags.native.js +355 -158
  663. package/dist/jsx/layouts/tags.native.js.map +1 -1
  664. package/dist/jsx/layouts/timeline.mjs +129 -45
  665. package/dist/jsx/layouts/timeline.mjs.map +1 -1
  666. package/dist/jsx/layouts/timeline.native.js +179 -55
  667. package/dist/jsx/layouts/timeline.native.js.map +1 -1
  668. package/dist/jsx/layouts/toolbar.mjs +57 -21
  669. package/dist/jsx/layouts/toolbar.mjs.map +1 -1
  670. package/dist/jsx/layouts/toolbar.native.js +62 -25
  671. package/dist/jsx/layouts/toolbar.native.js.map +1 -1
  672. package/dist/jsx/shared/i18n.mjs +10 -0
  673. package/dist/jsx/shared/i18n.mjs.map +1 -0
  674. package/dist/jsx/shared/i18n.native.js +52 -0
  675. package/dist/jsx/shared/i18n.native.js.map +1 -0
  676. package/dist/jsx/shared/textRidesText.mjs +31 -0
  677. package/dist/jsx/shared/textRidesText.mjs.map +1 -0
  678. package/dist/jsx/shared/textRidesText.native.js +81 -0
  679. package/dist/jsx/shared/textRidesText.native.js.map +1 -0
  680. package/dist/jsx/shared/useReturnFocusOnClose.mjs +7 -1
  681. package/dist/jsx/shared/useReturnFocusOnClose.mjs.map +1 -1
  682. package/dist/jsx/shared/useReturnFocusOnClose.native.js +7 -1
  683. package/dist/jsx/shared/useReturnFocusOnClose.native.js.map +1 -1
  684. package/dist/jsx/surfaces.mjs +94 -17
  685. package/dist/jsx/surfaces.mjs.map +1 -1
  686. package/dist/jsx/surfaces.native.js +95 -16
  687. package/dist/jsx/surfaces.native.js.map +1 -1
  688. package/dist/jsx/tamagui.mjs +2 -3
  689. package/dist/jsx/tamagui.mjs.map +1 -1
  690. package/dist/jsx/tamagui.native.js +37 -38
  691. package/dist/jsx/tamagui.native.js.map +1 -1
  692. package/dist/jsx/views/Calendar.mjs +101 -64
  693. package/dist/jsx/views/Calendar.mjs.map +1 -1
  694. package/dist/jsx/views/Calendar.native.js +105 -70
  695. package/dist/jsx/views/Calendar.native.js.map +1 -1
  696. package/dist/jsx/views/Dashboard.mjs +396 -107
  697. package/dist/jsx/views/Dashboard.mjs.map +1 -1
  698. package/dist/jsx/views/Dashboard.native.js +408 -110
  699. package/dist/jsx/views/Dashboard.native.js.map +1 -1
  700. package/dist/jsx/views/Gantt.mjs +256 -59
  701. package/dist/jsx/views/Gantt.mjs.map +1 -1
  702. package/dist/jsx/views/Gantt.native.js +264 -39
  703. package/dist/jsx/views/Gantt.native.js.map +1 -1
  704. package/dist/jsx/views/ImageGrid.mjs +138 -73
  705. package/dist/jsx/views/ImageGrid.mjs.map +1 -1
  706. package/dist/jsx/views/ImageGrid.native.js +155 -71
  707. package/dist/jsx/views/ImageGrid.native.js.map +1 -1
  708. package/dist/jsx/views/Kanban.mjs +52 -30
  709. package/dist/jsx/views/Kanban.mjs.map +1 -1
  710. package/dist/jsx/views/Kanban.native.js +55 -41
  711. package/dist/jsx/views/Kanban.native.js.map +1 -1
  712. package/dist/jsx/views/List.mjs +268 -95
  713. package/dist/jsx/views/List.mjs.map +1 -1
  714. package/dist/jsx/views/List.native.js +280 -101
  715. package/dist/jsx/views/List.native.js.map +1 -1
  716. package/dist/jsx/views/ReportBuilder.mjs +533 -166
  717. package/dist/jsx/views/ReportBuilder.mjs.map +1 -1
  718. package/dist/jsx/views/ReportBuilder.native.js +592 -169
  719. package/dist/jsx/views/ReportBuilder.native.js.map +1 -1
  720. package/dist/jsx/views/TreeView.mjs +142 -52
  721. package/dist/jsx/views/TreeView.mjs.map +1 -1
  722. package/dist/jsx/views/TreeView.native.js +170 -55
  723. package/dist/jsx/views/TreeView.native.js.map +1 -1
  724. package/package.json +18 -18
  725. package/src/Accordion/Accordion.lc50.spec.tsx +69 -0
  726. package/src/Accordion/Accordion.spec.tsx +36 -0
  727. package/src/Accordion/Accordion.stories.tsx +82 -36
  728. package/src/Accordion/index.tsx +296 -75
  729. package/src/Alert/Alert.spec.tsx +137 -1
  730. package/src/Alert/Alert.stories.tsx +10 -11
  731. package/src/Alert/index.tsx +244 -62
  732. package/src/AnimateHeight/AnimateHeight.spec.tsx +152 -0
  733. package/src/AnimateHeight/index.tsx +237 -0
  734. package/src/Avatar/Avatar.spec.tsx +73 -2
  735. package/src/Avatar/Avatar.stories.tsx +106 -4
  736. package/src/Avatar/getInitials.ts +29 -0
  737. package/src/Avatar/index.tsx +323 -105
  738. package/src/Badge/Badge.spec.tsx +83 -0
  739. package/src/Badge/Badge.stories.tsx +15 -1
  740. package/src/Badge/index.tsx +138 -84
  741. package/src/Button.spec.tsx +181 -0
  742. package/src/Button.stories.tsx +92 -0
  743. package/src/Button.tsx +43 -0
  744. package/src/Carousel/Carousel.spec.tsx +152 -0
  745. package/src/Carousel/index.tsx +239 -102
  746. package/src/Chip/Chip.spec.tsx +141 -0
  747. package/src/Chip/Chip.stories.tsx +163 -10
  748. package/src/Chip/index.tsx +452 -11
  749. package/src/DialogContent.stories.tsx +8 -6
  750. package/src/DotIndicator/DotIndicator.stories.tsx +18 -0
  751. package/src/DotIndicator/dotIndicator.spec.tsx +57 -2
  752. package/src/DotIndicator/index.tsx +159 -24
  753. package/src/DropdownMenu/DropdownMenu.spec.tsx +172 -0
  754. package/src/DropdownMenu/DropdownMenu.stories.tsx +35 -0
  755. package/src/DropdownMenu/index.tsx +172 -46
  756. package/src/ErrorBoundary/index.tsx +1 -1
  757. package/src/Pagination.api.spec.tsx +41 -0
  758. package/src/Pagination.tsx +49 -8
  759. package/src/PopoverContent.stories.tsx +4 -2
  760. package/src/ProgressSteps/ProgressSteps.spec.tsx +48 -1
  761. package/src/ProgressSteps/ProgressSteps.stories.tsx +48 -0
  762. package/src/ProgressSteps/index.tsx +224 -133
  763. package/src/Quote/Quote.lc50.spec.tsx +53 -0
  764. package/src/Quote/Quote.spec.tsx +9 -2
  765. package/src/Quote/Quote.stories.tsx +1 -1
  766. package/src/Quote/index.tsx +77 -60
  767. package/src/SheetModal/index.native.tsx +41 -39
  768. package/src/SheetModal/index.tsx +149 -18
  769. package/src/Skeleton/Skeleton.stories.tsx +109 -93
  770. package/src/Skeleton/SkeletonText.stories.tsx +11 -0
  771. package/src/Skeleton/index.tsx +257 -8
  772. package/src/SkipLink/SkipLink.spec.tsx +35 -0
  773. package/src/SkipLink/SkipLink.stories.tsx +1 -1
  774. package/src/SkipLink/index.tsx +120 -71
  775. package/src/Tabs/Tabs.spec.tsx +65 -0
  776. package/src/Tabs/Tabs.stories.tsx +32 -0
  777. package/src/Tabs/index.tsx +188 -133
  778. package/src/Toast/Toast.spec.tsx +208 -8
  779. package/src/Toast/Toast.stories.tsx +97 -16
  780. package/src/Toast/index.tsx +322 -78
  781. package/src/Toast/store.ts +150 -16
  782. package/src/Tooltip/Tooltip.lc50.spec.tsx +52 -0
  783. package/src/Tooltip/Tooltip.spec.tsx +99 -0
  784. package/src/Tooltip/Tooltip.stories.tsx +23 -0
  785. package/src/Tooltip/index.tsx +200 -44
  786. package/src/Video/PlayerChrome.tsx +412 -0
  787. package/src/Video/Video.spec.tsx +47 -4
  788. package/src/Video/Video.stories.tsx +2 -1
  789. package/src/Video/VideoFrame.tsx +15 -3
  790. package/src/Video/index.native.tsx +20 -12
  791. package/src/Video/index.tsx +285 -21
  792. package/src/Video/types.ts +7 -1
  793. package/src/Wheel/Wheel.spec.tsx +217 -2
  794. package/src/Wheel/Wheel.stories.tsx +39 -13
  795. package/src/Wheel/index.tsx +205 -134
  796. package/src/actions/DestructiveAction.tsx +1 -1
  797. package/src/charts/BarChart.tsx +14 -3
  798. package/src/charts/LineChart.tsx +1 -1
  799. package/src/charts/PieChart.tsx +1 -1
  800. package/src/charts/Sparkline.tsx +1 -1
  801. package/src/charts/charts.spec.tsx +25 -0
  802. package/src/charts/index.ts +9 -0
  803. package/src/code/CodeBlock/index.tsx +43 -7
  804. package/src/export-surface.spec.tsx +137 -0
  805. package/src/feedback/ConfirmDialog.spec.tsx +36 -0
  806. package/src/feedback/ConfirmDialog.stories.tsx +20 -1
  807. package/src/feedback/ConfirmDialog.tsx +121 -9
  808. package/src/feedback/NotifyHost.tsx +1 -1
  809. package/src/icons/themed.tsx +7 -2
  810. package/src/images/Image/Image.spec.tsx +136 -73
  811. package/src/images/Image/Image.stories.tsx +113 -9
  812. package/src/images/Image/ImageFrame.tsx +288 -0
  813. package/src/images/Image/index.native.tsx +177 -144
  814. package/src/images/Image/index.tsx +103 -51
  815. package/src/images/Image/shared.ts +88 -0
  816. package/src/images/Image/types.ts +32 -1
  817. package/src/index.ts +18 -0
  818. package/src/knobImmuneExports.ts +97 -0
  819. package/src/layouts/AsyncBoundary.spec.tsx +77 -0
  820. package/src/layouts/AsyncBoundary.stories.tsx +33 -1
  821. package/src/layouts/AsyncBoundary.tsx +183 -46
  822. package/src/layouts/Attachments.stories.tsx +28 -14
  823. package/src/layouts/Breadcrumbs.stories.tsx +22 -1
  824. package/src/layouts/EmptyState.stories.tsx +94 -26
  825. package/src/layouts/EmptyState.tsx +169 -0
  826. package/src/layouts/PageHeader.stories.tsx +68 -15
  827. package/src/layouts/PageTemplates.tsx +11 -6
  828. package/src/layouts/PaneScaffold.stories.tsx +132 -37
  829. package/src/layouts/PaneScaffold.tsx +354 -18
  830. package/src/layouts/ScreenToolbar.stories.tsx +36 -11
  831. package/src/layouts/Sidebar.stories.tsx +30 -7
  832. package/src/layouts/Tags.stories.tsx +31 -32
  833. package/src/layouts/Timeline.stories.tsx +2 -2
  834. package/src/layouts/Toolbar.stories.tsx +19 -0
  835. package/src/layouts/ViewSwitcher.stories.tsx +11 -3
  836. package/src/layouts/ViewSwitcher.tsx +101 -48
  837. package/src/layouts/attachments.tsx +394 -186
  838. package/src/layouts/breadcrumbs.tsx +213 -75
  839. package/src/layouts/layouts.spec.tsx +32 -0
  840. package/src/layouts/page.tsx +103 -164
  841. package/src/layouts/pageHeadingScope.tsx +28 -2
  842. package/src/layouts/sidebar.tsx +184 -91
  843. package/src/layouts/tags-trigger.spec.tsx +8 -8
  844. package/src/layouts/tags.tsx +356 -159
  845. package/src/layouts/timeline-comments.spec.tsx +17 -0
  846. package/src/layouts/timeline.tsx +179 -65
  847. package/src/layouts/toolbar.tsx +78 -27
  848. package/src/shared/i18n.ts +26 -0
  849. package/src/shared/textRidesText.ts +57 -0
  850. package/src/shared/useReturnFocusOnClose.ts +7 -1
  851. package/src/surfaces.tsx +83 -22
  852. package/src/tamagui.spec.ts +19 -4
  853. package/src/tamagui.ts +14 -6
  854. package/src/views/Calendar.stories.tsx +2 -1
  855. package/src/views/Calendar.tsx +129 -81
  856. package/src/views/Dashboard.stories.tsx +132 -1
  857. package/src/views/Dashboard.tsx +440 -127
  858. package/src/views/Gantt.stories.tsx +6 -5
  859. package/src/views/Gantt.tsx +330 -61
  860. package/src/views/ImageGrid.stories.tsx +81 -17
  861. package/src/views/ImageGrid.tsx +176 -96
  862. package/src/views/Kanban.native.tsx +73 -42
  863. package/src/views/Kanban.stories.tsx +42 -26
  864. package/src/views/Kanban.tsx +68 -40
  865. package/src/views/List.stories.tsx +107 -29
  866. package/src/views/List.tsx +335 -109
  867. package/src/views/ReportBuilder.stories.tsx +28 -1
  868. package/src/views/ReportBuilder.tsx +647 -275
  869. package/src/views/TreeView.stories.tsx +19 -0
  870. package/src/views/TreeView.tsx +194 -59
  871. package/types/Accordion/index.d.ts +10 -2
  872. package/types/Accordion/index.d.ts.map +1 -1
  873. package/types/Alert/index.d.ts +8 -2
  874. package/types/Alert/index.d.ts.map +1 -1
  875. package/types/AnimateHeight/index.d.ts +48 -0
  876. package/types/AnimateHeight/index.d.ts.map +1 -0
  877. package/types/Avatar/getInitials.d.ts +26 -0
  878. package/types/Avatar/getInitials.d.ts.map +1 -1
  879. package/types/Avatar/index.d.ts +34 -11
  880. package/types/Avatar/index.d.ts.map +1 -1
  881. package/types/Badge/index.d.ts +17 -12
  882. package/types/Badge/index.d.ts.map +1 -1
  883. package/types/Button.d.ts +42 -0
  884. package/types/Button.d.ts.map +1 -0
  885. package/types/Carousel/index.d.ts.map +1 -1
  886. package/types/Chip/index.d.ts +41 -1
  887. package/types/Chip/index.d.ts.map +1 -1
  888. package/types/DotIndicator/index.d.ts +4 -3
  889. package/types/DotIndicator/index.d.ts.map +1 -1
  890. package/types/DropdownMenu/index.d.ts +39 -5
  891. package/types/DropdownMenu/index.d.ts.map +1 -1
  892. package/types/ErrorBoundary/index.d.ts +1 -1
  893. package/types/Pagination.d.ts.map +1 -1
  894. package/types/ProgressSteps/index.d.ts +20 -5
  895. package/types/ProgressSteps/index.d.ts.map +1 -1
  896. package/types/Quote/index.d.ts +4 -3
  897. package/types/Quote/index.d.ts.map +1 -1
  898. package/types/SheetModal/index.d.ts +7 -10
  899. package/types/SheetModal/index.d.ts.map +1 -1
  900. package/types/SheetModal/index.native.d.ts +6 -13
  901. package/types/SheetModal/index.native.d.ts.map +1 -1
  902. package/types/Skeleton/index.d.ts +40 -1
  903. package/types/Skeleton/index.d.ts.map +1 -1
  904. package/types/SkipLink/index.d.ts +5 -6
  905. package/types/SkipLink/index.d.ts.map +1 -1
  906. package/types/Tabs/index.d.ts +12 -10
  907. package/types/Tabs/index.d.ts.map +1 -1
  908. package/types/Toast/index.d.ts +32 -9
  909. package/types/Toast/index.d.ts.map +1 -1
  910. package/types/Toast/store.d.ts +59 -4
  911. package/types/Toast/store.d.ts.map +1 -1
  912. package/types/Tooltip/index.d.ts +50 -5
  913. package/types/Tooltip/index.d.ts.map +1 -1
  914. package/types/Video/PlayerChrome.d.ts +24 -0
  915. package/types/Video/PlayerChrome.d.ts.map +1 -0
  916. package/types/Video/VideoFrame.d.ts.map +1 -1
  917. package/types/Video/index.d.ts +3 -2
  918. package/types/Video/index.d.ts.map +1 -1
  919. package/types/Video/index.native.d.ts +3 -2
  920. package/types/Video/index.native.d.ts.map +1 -1
  921. package/types/Video/types.d.ts +7 -1
  922. package/types/Video/types.d.ts.map +1 -1
  923. package/types/Wheel/index.d.ts +10 -1
  924. package/types/Wheel/index.d.ts.map +1 -1
  925. package/types/charts/BarChart.d.ts +7 -1
  926. package/types/charts/BarChart.d.ts.map +1 -1
  927. package/types/charts/index.d.ts +1 -0
  928. package/types/charts/index.d.ts.map +1 -1
  929. package/types/code/CodeBlock/index.d.ts.map +1 -1
  930. package/types/feedback/ConfirmDialog.d.ts +6 -0
  931. package/types/feedback/ConfirmDialog.d.ts.map +1 -1
  932. package/types/icons/themed.d.ts.map +1 -1
  933. package/types/images/Image/ImageFrame.d.ts +40 -0
  934. package/types/images/Image/ImageFrame.d.ts.map +1 -0
  935. package/types/images/Image/index.d.ts +1 -1
  936. package/types/images/Image/index.d.ts.map +1 -1
  937. package/types/images/Image/index.native.d.ts +1 -1
  938. package/types/images/Image/index.native.d.ts.map +1 -1
  939. package/types/images/Image/shared.d.ts +13 -0
  940. package/types/images/Image/shared.d.ts.map +1 -0
  941. package/types/images/Image/types.d.ts +27 -1
  942. package/types/images/Image/types.d.ts.map +1 -1
  943. package/types/index.d.ts +6 -0
  944. package/types/index.d.ts.map +1 -1
  945. package/types/knobImmuneExports.d.ts +21 -0
  946. package/types/knobImmuneExports.d.ts.map +1 -0
  947. package/types/layouts/AsyncBoundary.d.ts +20 -2
  948. package/types/layouts/AsyncBoundary.d.ts.map +1 -1
  949. package/types/layouts/EmptyState.d.ts +26 -0
  950. package/types/layouts/EmptyState.d.ts.map +1 -0
  951. package/types/layouts/PageTemplates.d.ts +5 -3
  952. package/types/layouts/PageTemplates.d.ts.map +1 -1
  953. package/types/layouts/PaneScaffold.d.ts +27 -5
  954. package/types/layouts/PaneScaffold.d.ts.map +1 -1
  955. package/types/layouts/ViewSwitcher.d.ts +7 -4
  956. package/types/layouts/ViewSwitcher.d.ts.map +1 -1
  957. package/types/layouts/attachments.d.ts +4 -2
  958. package/types/layouts/attachments.d.ts.map +1 -1
  959. package/types/layouts/breadcrumbs.d.ts +13 -5
  960. package/types/layouts/breadcrumbs.d.ts.map +1 -1
  961. package/types/layouts/page.d.ts +16 -27
  962. package/types/layouts/page.d.ts.map +1 -1
  963. package/types/layouts/pageHeadingScope.d.ts +14 -1
  964. package/types/layouts/pageHeadingScope.d.ts.map +1 -1
  965. package/types/layouts/sidebar.d.ts +3 -1
  966. package/types/layouts/sidebar.d.ts.map +1 -1
  967. package/types/layouts/tags.d.ts +4 -1
  968. package/types/layouts/tags.d.ts.map +1 -1
  969. package/types/layouts/timeline.d.ts +7 -5
  970. package/types/layouts/timeline.d.ts.map +1 -1
  971. package/types/layouts/toolbar.d.ts +1 -1
  972. package/types/layouts/toolbar.d.ts.map +1 -1
  973. package/types/shared/i18n.d.ts +14 -0
  974. package/types/shared/i18n.d.ts.map +1 -0
  975. package/types/shared/textRidesText.d.ts +20 -0
  976. package/types/shared/textRidesText.d.ts.map +1 -0
  977. package/types/shared/useReturnFocusOnClose.d.ts.map +1 -1
  978. package/types/surfaces.d.ts +0 -14
  979. package/types/surfaces.d.ts.map +1 -1
  980. package/types/tamagui.d.ts +2 -3
  981. package/types/tamagui.d.ts.map +1 -1
  982. package/types/views/Calendar.d.ts.map +1 -1
  983. package/types/views/Dashboard.d.ts +68 -6
  984. package/types/views/Dashboard.d.ts.map +1 -1
  985. package/types/views/Gantt.d.ts +5 -0
  986. package/types/views/Gantt.d.ts.map +1 -1
  987. package/types/views/ImageGrid.d.ts +4 -0
  988. package/types/views/ImageGrid.d.ts.map +1 -1
  989. package/types/views/Kanban.d.ts.map +1 -1
  990. package/types/views/Kanban.native.d.ts +12 -1
  991. package/types/views/Kanban.native.d.ts.map +1 -1
  992. package/types/views/List.d.ts +45 -6
  993. package/types/views/List.d.ts.map +1 -1
  994. package/types/views/ReportBuilder.d.ts +8 -54
  995. package/types/views/ReportBuilder.d.ts.map +1 -1
  996. package/types/views/TreeView.d.ts +13 -11
  997. package/types/views/TreeView.d.ts.map +1 -1
@@ -1,5 +1,7 @@
1
1
  import { BarChart } from "../charts/BarChart";
2
2
  import { componentColors } from "../componentColors";
3
+ import { DropdownMenu } from "../DropdownMenu";
4
+ import { useDirection } from "../hooks/useDirection";
3
5
  import { AsyncBoundary, AsyncSkeleton, resolveAsyncStatus } from "../layouts/AsyncBoundary";
4
6
  import { EmptyState } from "../layouts/page";
5
7
  import {
@@ -9,127 +11,83 @@ import {
9
11
  formatNumber,
10
12
  formatPercent,
11
13
  formatTimeOfDay,
14
+ hairline,
15
+ keyboardFocusRingProps,
12
16
  pressTargetStyle,
13
17
  useResolvedKnobs,
18
+ ensureKeyboardModalityTracking,
19
+ wasKeyboardFocus,
14
20
  } from "@multiplatform.one/theme";
15
- // House Button (not raw tamagui): carries the DG-LAY-04 / D-02 ≥44px press
16
- // floor — the raw tamagui Button rendered these toolbar actions at 28px.
17
21
  import { Button } from "@multiplatform.one/forms";
18
- import React, { useState, useMemo, useCallback } from "react";
19
- import { useTranslation } from "react-i18next";
20
- import { Card, ScrollView, Text, XStack, YStack, type YStackProps } from "tamagui";
21
-
22
- // ============================================================================
23
- // Types
24
- // ============================================================================
22
+ import {
23
+ CaretDownIcon,
24
+ CaretLeftIcon,
25
+ CaretRightIcon,
26
+ CaretUpIcon,
27
+ ChartBarIcon,
28
+ DownloadSimpleIcon,
29
+ } from "@phosphor-icons/react";
30
+ import { useHotkey } from "@tanstack/react-hotkeys";
31
+ import React, { useState, useMemo, useCallback, useId, useRef } from "react";
32
+ import { useTranslation } from "../shared/i18n";
33
+ import { ScrollView, Text, XStack, YStack, type YStackProps } from "tamagui";
34
+
35
+ const AGGREGATIONS = ["count", "sum", "avg", "min", "max"] as const;
25
36
 
26
- /**
27
- * A column definition for the report builder.
28
- */
29
37
  export interface ReportColumn {
30
- /** Field name / accessor key */
31
38
  fieldname: string;
32
- /** Display label */
33
39
  label: string;
34
- /** Field type (e.g. 'Data', 'Int', 'Currency') */
35
40
  fieldtype: string;
36
- /** Whether this column is enabled by default */
37
41
  enabled: boolean;
38
42
  }
39
43
 
40
- /**
41
- * Group-by configuration with aggregation.
42
- */
43
44
  export interface GroupByConfig {
44
- /** Field to group by */
45
45
  field: string;
46
- /** Aggregation function */
47
- aggregation: "count" | "sum" | "avg" | "min" | "max";
48
- /** Field to aggregate (for sum/avg/min/max) */
46
+ aggregation: (typeof AGGREGATIONS)[number];
49
47
  aggregationField?: string;
50
48
  }
51
49
 
52
- /**
53
- * Props for the generic ReportBuilder component.
54
- */
55
50
  export interface ReportBuilderProps extends Omit<YStackProps, "children"> {
56
- /** Column definitions */
57
51
  columns: ReportColumn[];
58
- /** Data rows */
59
52
  data: Record<string, unknown>[];
60
- /** Initial or active group-by configuration */
61
53
  groupBy?: GroupByConfig;
62
- /** Called when group-by changes */
63
54
  onGroupByChange?: (config: GroupByConfig | null) => void;
64
- /** Called when columns toggle */
65
55
  onColumnsChange?: (enabledFieldnames: string[]) => void;
66
- /** Called for data export */
67
56
  onExport?: (data: Record<string, unknown>[]) => void;
68
- /** Row press handler — rows become interactive when provided */
69
57
  onRowPress?: (row: Record<string, unknown>, index: number) => void;
70
- /** Show a simple bar chart for grouped data (default: false) */
71
58
  showChart?: boolean;
72
- /** Whether report rows are loading — renders a table-shaped skeleton (LC-20 / DG-ST-02) */
73
59
  isLoading?: boolean;
74
- /**
75
- * Failed load (DG-ST-01 / Axiom 6). Wins over the empty chrome and hides
76
- * the toolbar/chart so counts can't lie (DG-ST-04). Pass a string, Error,
77
- * custom node, or `true` for the default error UI.
78
- */
79
60
  error?: boolean | string | Error | React.ReactNode | null;
80
- /** Retry handler for the default error chrome */
81
61
  onRetry?: () => void;
82
- /**
83
- * True when the caller has filters narrowing `data`. Zero rows then render
84
- * as "no results" instead of the true-empty chrome (DG-TBL-06 / Axiom 6:
85
- * empty ≠ no-results).
86
- */
87
62
  hasActiveFilters?: boolean;
88
63
  }
89
64
 
90
- // ============================================================================
91
- // Constants
92
- // ============================================================================
93
-
94
65
  const numericFieldTypes = new Set(["Int", "Float", "Currency", "Percent", "Rating", "Duration"]);
95
66
 
96
- /** Dense report copy rides two steps below the size knob (medium keeps $2). */
97
67
  const reportTextSizeMap: Record<string, "$1" | "$2" | "$3"> = {
98
68
  $3: "$1",
99
69
  $4: "$2",
100
70
  $5: "$3",
101
71
  };
102
72
 
103
- const aggregationLabels: Record<GroupByConfig["aggregation"], string> = {
104
- count: "Count",
105
- sum: "Sum",
106
- avg: "Average",
107
- min: "Min",
108
- max: "Max",
109
- };
110
-
111
- // ============================================================================
112
- // Helpers
113
- // ============================================================================
73
+ type SortDir = "asc" | "desc";
74
+ type SortState = { field: string; dir: SortDir } | null;
75
+ type FocusItem =
76
+ | { type: "group"; key: string }
77
+ | { type: "row"; row: Record<string, unknown>; index: number };
114
78
 
115
79
  function isNumericFieldType(fieldtype: string): boolean {
116
80
  return numericFieldTypes.has(fieldtype);
117
81
  }
118
82
 
119
83
  function formatCellValue(value: unknown, fieldtype: string): string {
120
- if (value === null || value === undefined) return "\u2014"; // em dash
84
+ if (value === null || value === undefined) return "\u2014";
121
85
  if (typeof value === "boolean") return value ? "Yes" : "No";
122
86
 
123
87
  switch (fieldtype) {
124
88
  case "Check":
125
89
  return value ? "Yes" : "No";
126
- // Report cells take the fixed-precision variants of the house number
127
- // registers (LC-12 render channel): money keeps its two digits so a
128
- // column stays aligned, floats keep report precision, ints stay whole.
129
90
  case "Currency":
130
- // No symbol travels with a report column, so the money register
131
- // renders the amount alone — still the money register, not a
132
- // hand-rolled one.
133
91
  return formatCurrency(value as number);
134
92
  case "Float":
135
93
  return formatNumber(value as number, { maximumFractionDigits: 4 });
@@ -139,8 +97,6 @@ function formatCellValue(value: unknown, fieldtype: string): string {
139
97
  return formatPercent(value as number, { precision: 1 });
140
98
  case "Rating":
141
99
  return `${formatNumber(Number(value) * 5, { precision: 1 })} / 5`;
142
- // Date-class cells take the house absolute register instead of letting
143
- // the wire string ("2026-01-15") reach the reader.
144
100
  case "Date":
145
101
  return formatAbsoluteDate(value as string);
146
102
  case "Datetime":
@@ -152,9 +108,18 @@ function formatCellValue(value: unknown, fieldtype: string): string {
152
108
  }
153
109
  }
154
110
 
155
- // ============================================================================
156
- // Sub-components
157
- // ============================================================================
111
+ function compareValues(a: unknown, b: unknown, fieldtype: string): number {
112
+ if (a == null && b == null) return 0;
113
+ if (a == null) return 1;
114
+ if (b == null) return -1;
115
+ if (isNumericFieldType(fieldtype)) {
116
+ return (Number(a) || 0) - (Number(b) || 0);
117
+ }
118
+ if (fieldtype === "Date" || fieldtype === "Datetime" || fieldtype === "Time") {
119
+ return String(a).localeCompare(String(b));
120
+ }
121
+ return String(a).localeCompare(String(b), undefined, { numeric: true, sensitivity: "base" });
122
+ }
158
123
 
159
124
  function SimpleBarChart({
160
125
  data,
@@ -166,44 +131,23 @@ function SimpleBarChart({
166
131
  const { knobProps } = useResolvedKnobs();
167
132
  if (data.length === 0) return null;
168
133
 
169
- // One measure across group rows = a single series: the universal BarChart
170
- // defaults every bar to the theme identity from the canonical chart
171
- // palette (LC-27); per-bar hue variation would imply information the data
172
- // doesn't carry. The chart is universal (d3 math + react-native-svg), so
173
- // the report chart now renders on native too.
174
134
  return (
175
- <Card
176
- size={knobProps.sizeToken}
177
- {...{ backgroundColor: componentColors.surface.background }}
135
+ <YStack
136
+ {...knobProps.surface}
137
+ {...knobProps.containerRadius}
178
138
  padding="$2"
179
139
  overflow="hidden"
180
140
  >
181
141
  <BarChart data={data} height={height} />
182
- </Card>
142
+ </YStack>
183
143
  );
184
144
  }
185
145
 
186
- // ============================================================================
187
- // Main Component
188
- // ============================================================================
189
-
190
146
  /**
191
- * Generic report builder component.
192
- *
193
- * Accepts columns and data purely through props. Supports column toggling,
194
- * group-by with aggregation, collapsible groups, optional chart, and export.
195
- * Uses Tamagui `Card` for panel containers and theme-aware tokens throughout.
196
- *
197
- * @example
198
- * ```tsx
199
- * <ReportBuilder
200
- * columns={columns}
201
- * data={data}
202
- * groupBy={{ field: 'status', aggregation: 'count' }}
203
- * showChart
204
- * onExport={(data) => downloadCsv(data)}
205
- * />
206
- * ```
147
+ * Generic report builder — Frappe Report View / Query Report chrome:
148
+ * column picker, group-by + aggregation, sortable headers, totals strip,
149
+ * optional grouped chart, export. Rows are a stacked group (LC-72
150
+ * CONTAINER-CLIP); selected = fill, keyboard focus = one inset ring (LC-71).
207
151
  */
208
152
  export function ReportBuilder({
209
153
  columns,
@@ -218,17 +162,23 @@ export function ReportBuilder({
218
162
  error = null,
219
163
  onRetry,
220
164
  hasActiveFilters = false,
165
+ height,
166
+ minHeight,
221
167
  ...stackProps
222
168
  }: ReportBuilderProps) {
223
169
  const { t } = useTranslation();
224
170
  const { knobProps } = useResolvedKnobs();
225
- // Report chrome copy follows the size knob through the dense-table scale
226
- // (LC-18 / SB-M-804); medium stays at the previous $2.
227
171
  const reportFontSize = reportTextSizeMap[knobProps.sizeToken] ?? "$2";
228
- // Error wins (DG-ST-01); initial load renders the table-shaped skeleton twin.
172
+ const nestedPx = knobProps.nestedControl.px;
173
+ const isRTL = useDirection() === "rtl";
174
+ const CollapsedCaretIcon = isRTL ? CaretLeftIcon : CaretRightIcon;
229
175
  const hasError = resolveAsyncStatus({ error }) === "error";
230
176
  const isInitialLoading = !hasError && isLoading && data.length === 0;
231
- // Column management
177
+ const bounded = height != null || minHeight != null;
178
+ const tableId = useId();
179
+ const gridRef = useRef<HTMLDivElement>(null);
180
+ if (typeof document !== "undefined") ensureKeyboardModalityTracking();
181
+
232
182
  const [enabledColumnSet, setEnabledColumnSet] = useState<Set<string>>(
233
183
  () => new Set(columns.filter((c) => c.enabled).map((c) => c.fieldname)),
234
184
  );
@@ -238,16 +188,17 @@ export function ReportBuilder({
238
188
  [columns, enabledColumnSet],
239
189
  );
240
190
 
241
- const _numericColumns = useMemo(
191
+ const numericColumns = useMemo(
242
192
  () => columns.filter((c) => isNumericFieldType(c.fieldtype)),
243
193
  [columns],
244
194
  );
245
195
 
246
- const _toggleColumn = useCallback(
196
+ const toggleColumn = useCallback(
247
197
  (fieldname: string) => {
248
198
  setEnabledColumnSet((prev) => {
249
199
  const next = new Set(prev);
250
200
  if (next.has(fieldname)) {
201
+ if (next.size <= 1) return prev;
251
202
  next.delete(fieldname);
252
203
  } else {
253
204
  next.add(fieldname);
@@ -259,12 +210,10 @@ export function ReportBuilder({
259
210
  [onColumnsChange],
260
211
  );
261
212
 
262
- // Group By
263
213
  const [internalGroupBy, setInternalGroupBy] = useState<GroupByConfig | null>(groupByProp ?? null);
264
-
265
214
  const groupBy = groupByProp !== undefined ? groupByProp : internalGroupBy;
266
215
 
267
- const _handleGroupByChange = useCallback(
216
+ const handleGroupByChange = useCallback(
268
217
  (config: GroupByConfig | null) => {
269
218
  setInternalGroupBy(config);
270
219
  onGroupByChange?.(config);
@@ -273,6 +222,21 @@ export function ReportBuilder({
273
222
  );
274
223
 
275
224
  const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(() => new Set());
225
+ const [sort, setSort] = useState<SortState>(null);
226
+ const [chartVisible, setChartVisible] = useState(showChart);
227
+ const [focusedIndex, setFocusedIndex] = useState(-1);
228
+
229
+ const sortedData = useMemo(() => {
230
+ if (!sort) return data;
231
+ const col = columns.find((c) => c.fieldname === sort.field);
232
+ const fieldtype = col?.fieldtype ?? "Data";
233
+ const copy = data.slice();
234
+ copy.sort((a, b) => {
235
+ const cmp = compareValues(a[sort.field], b[sort.field], fieldtype);
236
+ return sort.dir === "asc" ? cmp : -cmp;
237
+ });
238
+ return copy;
239
+ }, [data, sort, columns]);
276
240
 
277
241
  const groupedData = useMemo(() => {
278
242
  if (!groupBy) return null;
@@ -280,8 +244,8 @@ export function ReportBuilder({
280
244
  const groups: Record<string, { rows: Record<string, unknown>[]; aggregationValue: number }> =
281
245
  {};
282
246
 
283
- for (const row of data) {
284
- const key = String(row[groupBy.field] ?? "(empty)");
247
+ for (const row of sortedData) {
248
+ const key = String(row[groupBy.field] ?? t("(empty)"));
285
249
  if (!groups[key]) {
286
250
  groups[key] = { rows: [], aggregationValue: 0 };
287
251
  }
@@ -326,33 +290,62 @@ export function ReportBuilder({
326
290
  }
327
291
 
328
292
  return groups;
329
- }, [groupBy, data]);
293
+ }, [groupBy, sortedData, t]);
330
294
 
331
- const chartData = useMemo(() => {
332
- if (!groupedData) return [];
333
- return Object.entries(groupedData).map(([label, group]) => ({
334
- label,
335
- value: group.aggregationValue,
336
- }));
337
- }, [groupedData]);
295
+ const groupEntries = useMemo(
296
+ () => (groupedData ? Object.entries(groupedData) : []),
297
+ [groupedData],
298
+ );
338
299
 
339
- const [chartVisible, setChartVisible] = useState(false);
300
+ const chartData = useMemo(
301
+ () => groupEntries.map(([label, group]) => ({ label, value: group.aggregationValue })),
302
+ [groupEntries],
303
+ );
304
+
305
+ const totals = useMemo(() => {
306
+ return enabledColumns
307
+ .filter((col) => isNumericFieldType(col.fieldtype))
308
+ .map((col) => ({
309
+ col,
310
+ value: sortedData.reduce((acc, row) => acc + (Number(row[col.fieldname]) || 0), 0),
311
+ }));
312
+ }, [enabledColumns, sortedData]);
313
+
314
+ const focusItems = useMemo((): FocusItem[] => {
315
+ if (groupBy && groupedData) {
316
+ const items: FocusItem[] = [];
317
+ for (const [key, group] of groupEntries) {
318
+ items.push({ type: "group", key });
319
+ if (!collapsedGroups.has(key)) {
320
+ group.rows.forEach((row, index) => items.push({ type: "row", row, index }));
321
+ }
322
+ }
323
+ return items;
324
+ }
325
+ return sortedData.map((row, index) => ({ type: "row" as const, row, index }));
326
+ }, [groupBy, groupedData, groupEntries, collapsedGroups, sortedData]);
327
+
328
+ const effectiveFocused = focusedIndex >= focusItems.length ? -1 : focusedIndex;
340
329
 
341
330
  const toggleGroup = useCallback((groupKey: string) => {
342
331
  setCollapsedGroups((prev) => {
343
332
  const next = new Set(prev);
344
- if (next.has(groupKey)) {
345
- next.delete(groupKey);
346
- } else {
347
- next.add(groupKey);
348
- }
333
+ if (next.has(groupKey)) next.delete(groupKey);
334
+ else next.add(groupKey);
349
335
  return next;
350
336
  });
351
337
  }, []);
352
338
 
353
- // Export
339
+ const cycleSort = useCallback((field: string) => {
340
+ setSort((prev) => {
341
+ if (prev?.field !== field) return { field, dir: "asc" };
342
+ if (prev.dir === "asc") return { field, dir: "desc" };
343
+ return null;
344
+ });
345
+ }, []);
346
+
354
347
  const handleExport = useCallback(() => {
355
- const exportData = data.map((row) => {
348
+ const exportData = sortedData.map((row) => {
356
349
  const filtered: Record<string, unknown> = {};
357
350
  for (const col of enabledColumns) {
358
351
  filtered[col.fieldname] = row[col.fieldname];
@@ -360,118 +353,333 @@ export function ReportBuilder({
360
353
  return filtered;
361
354
  });
362
355
  onExport?.(exportData);
363
- }, [data, enabledColumns, onExport]);
356
+ }, [sortedData, enabledColumns, onExport]);
364
357
 
365
- // Render helpers
366
- const renderHeaderRow = () => (
367
- <XStack
368
- padding="$2"
369
- {...{ backgroundColor: componentColors.surface.background }}
370
- borderBottomWidth={1}
371
- borderBottomColor="$borderColor"
372
- >
373
- {enabledColumns.map((col) => (
374
- <Text
375
- key={col.fieldname}
376
- flex={1}
377
- fontWeight="600"
378
- fontSize={reportFontSize}
379
- color="$color"
380
- paddingHorizontal="$2"
381
- numberOfLines={1}
382
- >
383
- {col.label}
384
- </Text>
385
- ))}
386
- </XStack>
358
+ const selectGroupField = useCallback(
359
+ (fieldname: string | null) => {
360
+ if (!fieldname) {
361
+ handleGroupByChange(null);
362
+ return;
363
+ }
364
+ handleGroupByChange({
365
+ field: fieldname,
366
+ aggregation: groupBy?.aggregation ?? "count",
367
+ aggregationField: groupBy?.aggregationField,
368
+ });
369
+ },
370
+ [groupBy, handleGroupByChange],
387
371
  );
388
372
 
389
- const renderDataRow = (row: Record<string, unknown>, index: number, isGrouped = false) => (
390
- <XStack
391
- key={`row-${String(row.name ?? index)}`}
392
- padding="$2"
393
- borderBottomWidth={1}
394
- borderBottomColor={componentColors.divider}
395
- backgroundColor={
396
- index % 2 === 0
397
- ? "$background"
398
- : { backgroundColor: componentColors.surface.background }.backgroundColor
373
+ const selectAggregation = useCallback(
374
+ (aggregation: GroupByConfig["aggregation"]) => {
375
+ if (!groupBy) return;
376
+ handleGroupByChange({
377
+ ...groupBy,
378
+ aggregation,
379
+ aggregationField:
380
+ aggregation === "count"
381
+ ? undefined
382
+ : (groupBy.aggregationField ?? numericColumns[0]?.fieldname),
383
+ });
384
+ },
385
+ [groupBy, handleGroupByChange, numericColumns],
386
+ );
387
+
388
+ const aggregationLabels: Record<GroupByConfig["aggregation"], string> = {
389
+ count: t("Count"),
390
+ sum: t("Sum"),
391
+ avg: t("Average"),
392
+ min: t("Min"),
393
+ max: t("Max"),
394
+ };
395
+
396
+ const handleContainerFocus = useCallback(() => {
397
+ if (!wasKeyboardFocus()) return;
398
+ setFocusedIndex((prev) => (prev < 0 ? 0 : prev));
399
+ }, []);
400
+
401
+ const scrollToFocused = useCallback(
402
+ (index: number) => {
403
+ document.getElementById(`${tableId}-item-${index}`)?.scrollIntoView({ block: "nearest" });
404
+ },
405
+ [tableId],
406
+ );
407
+
408
+ const hotkeyOpts = { target: gridRef as React.RefObject<HTMLElement | null> };
409
+
410
+ useHotkey(
411
+ "ArrowDown",
412
+ () => {
413
+ setFocusedIndex((prev) => {
414
+ const next = prev < 0 ? 0 : Math.min(prev + 1, focusItems.length - 1);
415
+ scrollToFocused(next);
416
+ return next;
417
+ });
418
+ },
419
+ hotkeyOpts,
420
+ );
421
+ useHotkey(
422
+ "ArrowUp",
423
+ () => {
424
+ setFocusedIndex((prev) => {
425
+ const next = prev < 0 ? focusItems.length - 1 : Math.max(prev - 1, 0);
426
+ scrollToFocused(next);
427
+ return next;
428
+ });
429
+ },
430
+ hotkeyOpts,
431
+ );
432
+ useHotkey(
433
+ "Home",
434
+ () => {
435
+ if (focusItems.length > 0) {
436
+ setFocusedIndex(0);
437
+ scrollToFocused(0);
438
+ }
439
+ },
440
+ hotkeyOpts,
441
+ );
442
+ useHotkey(
443
+ "End",
444
+ () => {
445
+ if (focusItems.length > 0) {
446
+ const last = focusItems.length - 1;
447
+ setFocusedIndex(last);
448
+ scrollToFocused(last);
399
449
  }
400
- hoverStyle={{ backgroundColor: componentColors.surface.background }}
401
- {...(isGrouped ? { paddingInlineStart: knobProps.panelPadding.padding } : {})}
402
- {...(onRowPress ? { cursor: "pointer", onPress: () => onRowPress(row, index) } : {})}
450
+ },
451
+ hotkeyOpts,
452
+ );
453
+ useHotkey(
454
+ "Enter",
455
+ () => {
456
+ const item = focusItems[effectiveFocused];
457
+ if (!item) return;
458
+ if (item.type === "group") toggleGroup(item.key);
459
+ else onRowPress?.(item.row, item.index);
460
+ },
461
+ hotkeyOpts,
462
+ );
463
+ useHotkey(
464
+ "ArrowLeft",
465
+ () => {
466
+ const item = focusItems[effectiveFocused];
467
+ if (item?.type === "group" && !collapsedGroups.has(item.key)) toggleGroup(item.key);
468
+ },
469
+ hotkeyOpts,
470
+ );
471
+ useHotkey(
472
+ "ArrowRight",
473
+ () => {
474
+ const item = focusItems[effectiveFocused];
475
+ if (item?.type === "group" && collapsedGroups.has(item.key)) toggleGroup(item.key);
476
+ },
477
+ hotkeyOpts,
478
+ );
479
+
480
+ const rowRing = (isFocused: boolean) =>
481
+ isFocused && wasKeyboardFocus() ? keyboardFocusRingProps : { outlineWidth: 0 as const };
482
+
483
+ const cellAlign = (col: ReportColumn) =>
484
+ isNumericFieldType(col.fieldtype) ? ("right" as const) : ("left" as const);
485
+
486
+ const renderHeaderRow = () => (
487
+ <XStack
488
+ role="row"
489
+ minHeight={nestedPx}
490
+ alignItems="center"
491
+ backgroundColor={componentColors.surface.background}
492
+ {...hairline.bottom}
403
493
  >
404
- {enabledColumns.map((col) => (
405
- <Text
406
- key={col.fieldname}
407
- flex={1}
408
- fontSize={reportFontSize}
409
- color="$color"
410
- paddingHorizontal="$2"
411
- numberOfLines={1}
412
- >
413
- {formatCellValue(row[col.fieldname], col.fieldtype)}
414
- </Text>
415
- ))}
494
+ {enabledColumns.map((col) => {
495
+ const active = sort?.field === col.fieldname;
496
+ const SortIcon = active && sort?.dir === "desc" ? CaretDownIcon : CaretUpIcon;
497
+ return (
498
+ <XStack
499
+ key={col.fieldname}
500
+ role="columnheader"
501
+ aria-sort={
502
+ active ? (sort?.dir === "asc" ? "ascending" : "descending") : "none"
503
+ }
504
+ flex={1}
505
+ minWidth={0}
506
+ minHeight={nestedPx}
507
+ hitSlop={knobProps.nestedControl.hitSlop}
508
+ alignItems="center"
509
+ justifyContent={cellAlign(col) === "right" ? "flex-end" : "flex-start"}
510
+ gap="$1"
511
+ paddingHorizontal="$2"
512
+ cursor="pointer"
513
+ tabIndex={-1}
514
+ onPress={() => cycleSort(col.fieldname)}
515
+ hoverStyle={{ backgroundColor: componentColors.interactive.background }}
516
+ >
517
+ <Text
518
+ fontWeight="600"
519
+ fontSize={reportFontSize}
520
+ color="$color"
521
+ numberOfLines={1}
522
+ textAlign={cellAlign(col)}
523
+ >
524
+ {col.label}
525
+ </Text>
526
+ <SortIcon
527
+ size={10}
528
+ weight="bold"
529
+ color={active ? componentColors.text.primary : componentColors.text.muted}
530
+ opacity={active ? 1 : 0.35}
531
+ />
532
+ </XStack>
533
+ );
534
+ })}
416
535
  </XStack>
417
536
  );
418
537
 
419
- const renderGroupedRows = () => {
420
- if (!groupedData || !groupBy) return null;
538
+ const renderDataRow = (
539
+ row: Record<string, unknown>,
540
+ index: number,
541
+ focusIdx: number,
542
+ isLast: boolean,
543
+ isGrouped = false,
544
+ ) => {
545
+ const isFocused = effectiveFocused === focusIdx;
546
+ return (
547
+ <XStack
548
+ key={`${tableId}-row-${String(row.name ?? index)}`}
549
+ id={`${tableId}-item-${focusIdx}`}
550
+ role="row"
551
+ aria-selected={isFocused}
552
+ tabIndex={-1}
553
+ {...(isFocused ? { "data-focused": true } : {})}
554
+ minHeight={nestedPx}
555
+ alignItems="center"
556
+ backgroundColor={isFocused ? "$accentBackground" : "transparent"}
557
+ {...rowRing(isFocused)}
558
+ hoverStyle={{
559
+ backgroundColor: isFocused ? "$accentBackground" : componentColors.interactive.background,
560
+ }}
561
+ {...(isLast ? {} : hairline.bottom)}
562
+ {...(isGrouped ? { paddingInlineStart: knobProps.panelPadding.padding } : {})}
563
+ {...(onRowPress
564
+ ? {
565
+ cursor: "pointer",
566
+ hitSlop: knobProps.nestedControl.hitSlop,
567
+ onPress: () => {
568
+ setFocusedIndex(focusIdx);
569
+ gridRef.current?.focus();
570
+ onRowPress(row, index);
571
+ },
572
+ }
573
+ : {})}
574
+ >
575
+ {enabledColumns.map((col) => (
576
+ <Text
577
+ key={col.fieldname}
578
+ role="cell"
579
+ flex={1}
580
+ minWidth={0}
581
+ fontSize={reportFontSize}
582
+ color="$color"
583
+ paddingHorizontal="$2"
584
+ numberOfLines={1}
585
+ textAlign={cellAlign(col)}
586
+ >
587
+ {formatCellValue(row[col.fieldname], col.fieldtype)}
588
+ </Text>
589
+ ))}
590
+ </XStack>
591
+ );
592
+ };
421
593
 
594
+ const renderGroupedRows = () => {
595
+ if (!groupBy) return null;
422
596
  const groupByCol = columns.find((c) => c.fieldname === groupBy.field);
423
597
  const aggLabel = aggregationLabels[groupBy.aggregation];
424
598
  const aggFieldCol = groupBy.aggregationField
425
599
  ? columns.find((c) => c.fieldname === groupBy.aggregationField)
426
600
  : null;
427
601
 
428
- return Object.entries(groupedData).map(([groupKey, group]) => {
602
+ let cursor = 0;
603
+ return groupEntries.map(([groupKey, group], groupIndex) => {
429
604
  const isCollapsed = collapsedGroups.has(groupKey);
430
- // Group aggregates are the same number class as the cells below them,
431
- // so they take the same register (LC-12 render channel) instead of
432
- // dropping into raw digits.
605
+ const headerFocus = cursor;
606
+ cursor += 1;
433
607
  const aggDisplay =
434
608
  groupBy.aggregation === "count"
435
609
  ? `${aggLabel}: ${formatNumber(group.aggregationValue, { maximumFractionDigits: 0 })}`
436
610
  : `${aggLabel}(${aggFieldCol?.label ?? groupBy.aggregationField ?? ""}): ${formatNumber(
437
611
  group.aggregationValue,
438
612
  )}`;
439
-
613
+ const isFocused = effectiveFocused === headerFocus;
614
+ const header = (
615
+ <XStack
616
+ key={`group-${groupKey}`}
617
+ id={`${tableId}-item-${headerFocus}`}
618
+ role="row"
619
+ aria-expanded={!isCollapsed}
620
+ aria-selected={isFocused}
621
+ tabIndex={-1}
622
+ {...(isFocused ? { "data-focused": true } : {})}
623
+ minHeight={nestedPx}
624
+ hitSlop={knobProps.nestedControl.hitSlop}
625
+ paddingHorizontal="$2"
626
+ backgroundColor={isFocused ? "$accentBackground" : componentColors.interactive.background}
627
+ {...(groupIndex === groupEntries.length - 1 && isCollapsed ? {} : hairline.bottom)}
628
+ alignItems="center"
629
+ gap="$2"
630
+ cursor="pointer"
631
+ {...rowRing(isFocused)}
632
+ onPress={() => {
633
+ setFocusedIndex(headerFocus);
634
+ gridRef.current?.focus();
635
+ toggleGroup(groupKey);
636
+ }}
637
+ hoverStyle={{
638
+ backgroundColor: isFocused ? "$accentBackground" : componentColors.interactive.hover,
639
+ }}
640
+ >
641
+ {isCollapsed ? (
642
+ <CollapsedCaretIcon size={12} weight="bold" />
643
+ ) : (
644
+ <CaretDownIcon size={12} weight="bold" />
645
+ )}
646
+ <Text fontWeight="600" fontSize={reportFontSize} color="$accentColor" numberOfLines={1}>
647
+ {groupByCol?.label ?? groupBy.field}: {groupKey}
648
+ </Text>
649
+ <Text fontSize={reportFontSize} color={componentColors.text.muted}>
650
+ ({group.rows.length}{" "}
651
+ {group.rows.length === 1 ? t("record") : t("records")})
652
+ </Text>
653
+ <XStack flex={1} />
654
+ <Text fontWeight="500" fontSize={reportFontSize} color="$accentColor" numberOfLines={1}>
655
+ {aggDisplay}
656
+ </Text>
657
+ </XStack>
658
+ );
659
+ const rows = isCollapsed
660
+ ? null
661
+ : group.rows.map((row, index) => {
662
+ const focusIdx = cursor;
663
+ cursor += 1;
664
+ const lastInTable =
665
+ groupIndex === groupEntries.length - 1 && index === group.rows.length - 1;
666
+ return renderDataRow(row, index, focusIdx, lastInTable, true);
667
+ });
440
668
  return (
441
669
  <YStack key={groupKey}>
442
- <XStack
443
- padding="$2"
444
- paddingHorizontal={knobProps.panelPadding.padding}
445
- backgroundColor={componentColors.interactive.background}
446
- borderBottomWidth={1}
447
- borderBottomColor="$borderColor"
448
- alignItems="center"
449
- gap="$2"
450
- cursor="pointer"
451
- onPress={() => toggleGroup(groupKey)}
452
- hoverStyle={{ backgroundColor: componentColors.interactive.hover }}
453
- >
454
- <Text fontSize={reportFontSize}>{isCollapsed ? "▶" : "▼"}</Text>
455
- <Text fontWeight="600" fontSize={reportFontSize} color="$accentColor">
456
- {groupByCol?.label ?? groupBy.field}: {groupKey}
457
- </Text>
458
- <Text fontSize={reportFontSize} color={componentColors.text.muted}>
459
- ({group.rows.length} {group.rows.length === 1 ? "record" : "records"})
460
- </Text>
461
- <XStack flex={1} />
462
- <Text fontWeight="500" fontSize={reportFontSize} color="$accentColor">
463
- {aggDisplay}
464
- </Text>
465
- </XStack>
466
-
467
- {!isCollapsed && group.rows.map((row, index) => renderDataRow(row, index, true))}
670
+ {header}
671
+ {rows}
468
672
  </YStack>
469
673
  );
470
674
  });
471
675
  };
472
676
 
473
- // Failed load: error chrome replaces the report; toolbar/chart/table hide
474
- // so the column count and stale rows can't lie (DG-ST-01 / DG-ST-04).
677
+ const groupByCol = groupBy ? columns.find((c) => c.fieldname === groupBy.field) : undefined;
678
+ const aggregationFieldCol = groupBy?.aggregationField
679
+ ? columns.find((c) => c.fieldname === groupBy.aggregationField)
680
+ : undefined;
681
+ const chartAvailable = Boolean(groupedData && chartData.length > 0);
682
+
475
683
  if (hasError) {
476
684
  return (
477
685
  <AsyncBoundary
@@ -487,83 +695,247 @@ export function ReportBuilder({
487
695
  }
488
696
 
489
697
  return (
490
- <YStack {...knobProps.gap} {...stackProps}>
491
- {/* Toolbar */}
492
- <Card
493
- size={knobProps.sizeToken}
494
- {...knobProps.borderRadius}
495
- borderWidth={1}
496
- borderColor="$borderColor"
698
+ <YStack
699
+ testID="report-builder"
700
+ {...knobProps.gap}
701
+ height={height}
702
+ minHeight={minHeight}
703
+ {...stackProps}
704
+ >
705
+ <XStack
706
+ {...knobProps.surface}
707
+ {...knobProps.containerRadius}
708
+ {...knobProps.panelPadding}
709
+ {...knobProps.gap}
710
+ alignItems="center"
711
+ flexWrap="wrap"
497
712
  >
498
- <XStack {...knobProps.panelPadding} {...knobProps.gap} alignItems="center" flexWrap="wrap">
499
- {/* Column toggle info */}
500
- <Text fontSize={reportFontSize} color={componentColors.text.muted}>
501
- {enabledColumns.length} / {columns.length} columns
502
- </Text>
713
+ <DropdownMenu>
714
+ <DropdownMenu.Trigger asChild>
715
+ <Button size={knobProps.sizeToken} chromeless {...pressTargetStyle()}>
716
+ {t("Columns ({{enabled}}/{{total}})", {
717
+ enabled: enabledColumns.length,
718
+ total: columns.length,
719
+ })}
720
+ </Button>
721
+ </DropdownMenu.Trigger>
722
+ <DropdownMenu.Content maxHeight={360}>
723
+ <DropdownMenu.Label>{t("Report columns")}</DropdownMenu.Label>
724
+ {columns.map((column) => {
725
+ const checked = enabledColumnSet.has(column.fieldname);
726
+ const lastEnabled = checked && enabledColumnSet.size === 1;
727
+ return (
728
+ <DropdownMenu.CheckboxItem
729
+ key={column.fieldname}
730
+ checked={checked}
731
+ disabled={lastEnabled}
732
+ disabledReason={
733
+ lastEnabled ? t("At least one column stays visible") : undefined
734
+ }
735
+ onCheckedChange={() => toggleColumn(column.fieldname)}
736
+ >
737
+ {column.label}
738
+ </DropdownMenu.CheckboxItem>
739
+ );
740
+ })}
741
+ </DropdownMenu.Content>
742
+ </DropdownMenu>
743
+
744
+ <DropdownMenu>
745
+ <DropdownMenu.Trigger asChild>
746
+ <Button size={knobProps.sizeToken} chromeless {...pressTargetStyle()}>
747
+ {groupByCol
748
+ ? t("Group by: {{field}}", { field: groupByCol.label })
749
+ : t("Group by")}
750
+ </Button>
751
+ </DropdownMenu.Trigger>
752
+ <DropdownMenu.Content maxHeight={360}>
753
+ <DropdownMenu.CheckboxItem
754
+ checked={!groupBy}
755
+ closeOnSelect
756
+ onCheckedChange={() => selectGroupField(null)}
757
+ >
758
+ {t("No grouping")}
759
+ </DropdownMenu.CheckboxItem>
760
+ <DropdownMenu.Separator />
761
+ {columns.map((column) => (
762
+ <DropdownMenu.CheckboxItem
763
+ key={column.fieldname}
764
+ checked={groupBy?.field === column.fieldname}
765
+ closeOnSelect
766
+ onCheckedChange={() => selectGroupField(column.fieldname)}
767
+ >
768
+ {column.label}
769
+ </DropdownMenu.CheckboxItem>
770
+ ))}
771
+ </DropdownMenu.Content>
772
+ </DropdownMenu>
773
+
774
+ {groupBy && (
775
+ <DropdownMenu>
776
+ <DropdownMenu.Trigger asChild>
777
+ <Button size={knobProps.sizeToken} chromeless {...pressTargetStyle()}>
778
+ {aggregationLabels[groupBy.aggregation]}
779
+ </Button>
780
+ </DropdownMenu.Trigger>
781
+ <DropdownMenu.Content>
782
+ {AGGREGATIONS.map((aggregation) => {
783
+ const needsNumeric = aggregation !== "count" && numericColumns.length === 0;
784
+ return (
785
+ <DropdownMenu.CheckboxItem
786
+ key={aggregation}
787
+ checked={groupBy.aggregation === aggregation}
788
+ closeOnSelect
789
+ disabled={needsNumeric}
790
+ disabledReason={
791
+ needsNumeric ? t("No numeric fields to aggregate") : undefined
792
+ }
793
+ onCheckedChange={() => selectAggregation(aggregation)}
794
+ >
795
+ {aggregationLabels[aggregation]}
796
+ </DropdownMenu.CheckboxItem>
797
+ );
798
+ })}
799
+ </DropdownMenu.Content>
800
+ </DropdownMenu>
801
+ )}
503
802
 
504
- <XStack flex={1} />
803
+ {groupBy && groupBy.aggregation !== "count" && numericColumns.length > 0 && (
804
+ <DropdownMenu>
805
+ <DropdownMenu.Trigger asChild>
806
+ <Button size={knobProps.sizeToken} chromeless {...pressTargetStyle()}>
807
+ {t("of {{field}}", {
808
+ field: aggregationFieldCol?.label ?? groupBy.aggregationField ?? t("field"),
809
+ })}
810
+ </Button>
811
+ </DropdownMenu.Trigger>
812
+ <DropdownMenu.Content maxHeight={360}>
813
+ {numericColumns.map((column) => (
814
+ <DropdownMenu.CheckboxItem
815
+ key={column.fieldname}
816
+ checked={groupBy.aggregationField === column.fieldname}
817
+ closeOnSelect
818
+ onCheckedChange={() =>
819
+ handleGroupByChange({ ...groupBy, aggregationField: column.fieldname })
820
+ }
821
+ >
822
+ {column.label}
823
+ </DropdownMenu.CheckboxItem>
824
+ ))}
825
+ </DropdownMenu.Content>
826
+ </DropdownMenu>
827
+ )}
505
828
 
506
- {/* Chart toggle */}
507
- {showChart && groupedData && (
508
- <Button
509
- size={knobProps.sizeToken}
510
- onPress={() => setChartVisible((v) => !v)}
511
- theme={chartVisible ? "active" : undefined}
512
- {...pressTargetStyle()}
513
- >
514
- Chart
515
- </Button>
516
- )}
829
+ <XStack flex={1} />
830
+
831
+ {chartAvailable && (
832
+ <Button
833
+ size={knobProps.sizeToken}
834
+ chromeless
835
+ icon={ChartBarIcon}
836
+ aria-pressed={chartVisible}
837
+ onPress={() => setChartVisible((v) => !v)}
838
+ theme={chartVisible ? "active" : undefined}
839
+ {...pressTargetStyle()}
840
+ >
841
+ {t("Chart")}
842
+ </Button>
843
+ )}
517
844
 
518
- {/* Export */}
519
- {onExport && (
520
- <Button size={knobProps.sizeToken} onPress={handleExport} {...pressTargetStyle()}>
521
- Export
522
- </Button>
523
- )}
524
- </XStack>
525
- </Card>
845
+ {onExport && (
846
+ <Button
847
+ size={knobProps.sizeToken}
848
+ chromeless
849
+ icon={DownloadSimpleIcon}
850
+ onPress={handleExport}
851
+ {...pressTargetStyle()}
852
+ >
853
+ {t("Export")}
854
+ </Button>
855
+ )}
856
+ </XStack>
526
857
 
527
- {/* Chart area */}
528
- {chartVisible && groupedData && chartData.length > 0 && (
858
+ {chartVisible && chartAvailable && (
529
859
  <YStack {...knobProps.gap}>
530
860
  <SimpleBarChart data={chartData} />
531
861
  </YStack>
532
862
  )}
533
863
 
534
- {/* Report table */}
535
- <Card
536
- size={knobProps.sizeToken}
537
- {...knobProps.borderRadius}
538
- borderWidth={1}
539
- borderColor="$borderColor"
540
- flex={1}
864
+ <YStack
865
+ {...knobProps.surface}
866
+ {...knobProps.containerRadius}
867
+ overflow="hidden"
868
+ flex={bounded ? 1 : undefined}
869
+ minHeight={bounded ? 0 : undefined}
541
870
  >
542
871
  {isInitialLoading ? (
543
- /* Skeleton twin inside the live table card (LC-20 / DG-ST-02) */
544
872
  <AsyncSkeleton layout="table" padding="$2" />
545
873
  ) : (
546
- <ScrollView flex={1}>
547
- <YStack minWidth="100%">
548
- {renderHeaderRow()}
549
- {groupBy && groupedData
550
- ? renderGroupedRows()
551
- : data.map((row, index) => renderDataRow(row, index))}
552
-
553
- {/* Zero rows: distinguish "filters matched nothing" from a truly
554
- empty dataset (DG-TBL-06 / Axiom 6: empty ≠ no-results) */}
555
- {data.length === 0 && (
556
- <EmptyState
557
- compact
558
- aria-live="polite"
559
- data-async-state={hasActiveFilters ? "no-results" : "empty"}
560
- title={hasActiveFilters ? t("No results found") : t("No data to display")}
561
- />
562
- )}
563
- </YStack>
564
- </ScrollView>
874
+ <YStack
875
+ ref={gridRef as any}
876
+ flex={bounded ? 1 : undefined}
877
+ minHeight={bounded ? 0 : undefined}
878
+ role="grid"
879
+ aria-rowcount={sortedData.length}
880
+ aria-colcount={enabledColumns.length}
881
+ aria-label={t("Report")}
882
+ aria-activedescendant={
883
+ effectiveFocused >= 0 ? `${tableId}-item-${effectiveFocused}` : undefined
884
+ }
885
+ tabIndex={0}
886
+ outlineWidth={0}
887
+ onFocus={handleContainerFocus}
888
+ >
889
+ <ScrollView flex={bounded ? 1 : undefined}>
890
+ <YStack minWidth="100%">
891
+ {renderHeaderRow()}
892
+ {groupBy && groupedData
893
+ ? renderGroupedRows()
894
+ : sortedData.map((row, index) =>
895
+ renderDataRow(row, index, index, index === sortedData.length - 1),
896
+ )}
897
+
898
+ {data.length === 0 && (
899
+ <EmptyState
900
+ compact
901
+ aria-live="polite"
902
+ data-async-state={hasActiveFilters ? "no-results" : "empty"}
903
+ title={hasActiveFilters ? t("No results found") : t("No data to display")}
904
+ />
905
+ )}
906
+ </YStack>
907
+ </ScrollView>
908
+ {data.length > 0 && (
909
+ <XStack
910
+ role="row"
911
+ minHeight={nestedPx}
912
+ alignItems="center"
913
+ paddingHorizontal="$2"
914
+ {...hairline.top}
915
+ backgroundColor={componentColors.surface.background}
916
+ gap="$3"
917
+ flexWrap="wrap"
918
+ >
919
+ <Text fontSize={reportFontSize} fontWeight="600" color={componentColors.text.muted}>
920
+ {t("Totals")}
921
+ </Text>
922
+ {totals.map(({ col, value }) => (
923
+ <Text key={col.fieldname} fontSize={reportFontSize} color="$color">
924
+ {col.label}:{" "}
925
+ <Text fontSize={reportFontSize} fontWeight="600">
926
+ {formatCellValue(value, col.fieldtype)}
927
+ </Text>
928
+ </Text>
929
+ ))}
930
+ <XStack flex={1} />
931
+ <Text fontSize={reportFontSize} color={componentColors.text.muted}>
932
+ {t("{{count}} row(s)", { count: data.length })}
933
+ </Text>
934
+ </XStack>
935
+ )}
936
+ </YStack>
565
937
  )}
566
- </Card>
938
+ </YStack>
567
939
  </YStack>
568
940
  );
569
941
  }