@multiplatform.one/table 6.4.2 → 6.6.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 (295) hide show
  1. package/dist/cjs/components/ChildTable/index.native.js +1 -1
  2. package/dist/cjs/components/ChildTable/index.native.js.map +1 -1
  3. package/dist/cjs/components/ColumnHeaderFilter/index.cjs +1 -0
  4. package/dist/cjs/components/ColumnHeaderFilter/index.native.js +2 -1
  5. package/dist/cjs/components/ColumnHeaderFilter/index.native.js.map +1 -1
  6. package/dist/cjs/components/DataTable/DataTableCardControls.native.js +1 -1
  7. package/dist/cjs/components/DataTable/DataTableCardControls.native.js.map +1 -1
  8. package/dist/cjs/components/DataTable/DataTableContext.native.js.map +1 -1
  9. package/dist/cjs/components/DataTable/DataTableMobileCards.cjs +9 -3
  10. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js +12 -3
  11. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  12. package/dist/cjs/components/DataTable/DataTableRoot.cjs +133 -13
  13. package/dist/cjs/components/DataTable/DataTableRoot.native.js +166 -20
  14. package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
  15. package/dist/cjs/components/DataTable/DataTableStateContext.native.js.map +1 -1
  16. package/dist/cjs/components/DataTable/DataTableVirtualized.cjs +3 -1
  17. package/dist/cjs/components/DataTable/DataTableVirtualized.native.js +3 -1
  18. package/dist/cjs/components/DataTable/DataTableVirtualized.native.js.map +1 -1
  19. package/dist/cjs/components/DataTable/index.native.js +50 -13
  20. package/dist/cjs/components/DataTable/index.native.js.map +1 -1
  21. package/dist/cjs/components/DataTableBulkActions/index.cjs +16 -1
  22. package/dist/cjs/components/DataTableBulkActions/index.native.js +20 -1
  23. package/dist/cjs/components/DataTableBulkActions/index.native.js.map +1 -1
  24. package/dist/cjs/components/DataTableCell/CellModalEditor.cjs +4 -8
  25. package/dist/cjs/components/DataTableCell/CellOptionsEditor.native.js.map +1 -1
  26. package/dist/cjs/components/DataTableCell/index.cjs +1 -33
  27. package/dist/cjs/components/DataTableCell/index.native.js +1 -34
  28. package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
  29. package/dist/cjs/components/DataTableColumnPinning/index.cjs +2 -2
  30. package/dist/cjs/components/DataTableColumnPinning/index.native.js +2 -2
  31. package/dist/cjs/components/DataTableColumnPinning/index.native.js.map +1 -1
  32. package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
  33. package/dist/cjs/components/DataTableExport/index.cjs +1 -0
  34. package/dist/cjs/components/DataTableExport/index.native.js +1 -0
  35. package/dist/cjs/components/DataTableExport/index.native.js.map +1 -1
  36. package/dist/cjs/components/DataTableFilterButton/index.cjs +1 -1
  37. package/dist/cjs/components/DataTableFilterButton/index.native.js +5 -2
  38. package/dist/cjs/components/DataTableFilterButton/index.native.js.map +1 -1
  39. package/dist/cjs/components/DataTableFilterChips/index.cjs +1 -1
  40. package/dist/cjs/components/DataTableFilterChips/index.native.js +1 -1
  41. package/dist/cjs/components/DataTableFilterChips/index.native.js.map +1 -1
  42. package/dist/cjs/components/DataTableFilters/index.native.js.map +1 -1
  43. package/dist/cjs/components/DataTableGrouping/index.cjs +17 -1
  44. package/dist/cjs/components/DataTableGrouping/index.native.js +17 -1
  45. package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
  46. package/dist/cjs/components/DataTablePagination/index.native.js.map +1 -1
  47. package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
  48. package/dist/cjs/components/DataTableToolbar/index.cjs +1 -0
  49. package/dist/cjs/components/DataTableToolbar/index.native.js +2 -1
  50. package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
  51. package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
  52. package/dist/cjs/components/FilterManager.cjs +18 -14
  53. package/dist/cjs/components/FilterManager.native.js +18 -14
  54. package/dist/cjs/components/FilterManager.native.js.map +1 -1
  55. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  56. package/dist/cjs/components/KnobDialog.native.js.map +1 -1
  57. package/dist/cjs/components/SavedFilterDropdown.native.js.map +1 -1
  58. package/dist/cjs/components/SimpleTable/index.cjs +1 -1
  59. package/dist/cjs/components/SimpleTable/index.native.js +1 -1
  60. package/dist/cjs/components/SimpleTable/index.native.js.map +1 -1
  61. package/dist/cjs/components/TableInput/index.native.js +4 -1
  62. package/dist/cjs/components/TableInput/index.native.js.map +1 -1
  63. package/dist/cjs/components/TableInput/shared.native.js.map +1 -1
  64. package/dist/cjs/hooks/useDataTable.cjs +17 -1
  65. package/dist/cjs/hooks/useDataTable.native.js +19 -1
  66. package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
  67. package/dist/cjs/hooks/useDataTableKeyboard.native.js.map +1 -1
  68. package/dist/cjs/hooks/useDragScroll.native.js.map +1 -1
  69. package/dist/cjs/hooks/useInfiniteRows.native.js.map +1 -1
  70. package/dist/cjs/hooks/useSavedFilters.native.js.map +1 -1
  71. package/dist/cjs/hooks/useTableColumnPinning.native.js.map +1 -1
  72. package/dist/cjs/hooks/useTableFiltering.native.js.map +1 -1
  73. package/dist/cjs/hooks/useTableGrouping.native.js.map +1 -1
  74. package/dist/cjs/hooks/useTableKeyboard.native.js.map +1 -1
  75. package/dist/cjs/hooks/useTablePagination.native.js.map +1 -1
  76. package/dist/cjs/hooks/useTableSearch.native.js.map +1 -1
  77. package/dist/cjs/hooks/useTableSelection.native.js.map +1 -1
  78. package/dist/cjs/hooks/useTableSorting.native.js.map +1 -1
  79. package/dist/cjs/hooks/useTableUrlSync.native.js.map +1 -1
  80. package/dist/cjs/hooks/useTableViews.native.js.map +1 -1
  81. package/dist/cjs/shared/t.native.js.map +1 -1
  82. package/dist/cjs/shims/primitives.native.js.map +1 -1
  83. package/dist/cjs/shims/tableCellContext.native.js.map +1 -1
  84. package/dist/cjs/types.native.js.map +1 -1
  85. package/dist/cjs/utils/columnAlign.native.js.map +1 -1
  86. package/dist/cjs/utils/filterFields.native.js.map +1 -1
  87. package/dist/cjs/utils/filterUtils.native.js.map +1 -1
  88. package/dist/cjs/utils/paginationDefaults.native.js.map +1 -1
  89. package/dist/cjs/utils/rowPress.cjs +44 -0
  90. package/dist/cjs/utils/rowPress.native.js +56 -0
  91. package/dist/cjs/utils/rowPress.native.js.map +1 -0
  92. package/dist/cjs/utils/urlStateUtils.native.js.map +1 -1
  93. package/dist/cjs/utils/viewData.native.js.map +1 -1
  94. package/dist/cjs/utils/withInterp.native.js.map +1 -1
  95. package/dist/esm/components/ColumnHeaderFilter/index.mjs +1 -0
  96. package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
  97. package/dist/esm/components/ColumnHeaderFilter/index.native.js +1 -0
  98. package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
  99. package/dist/esm/components/DataTable/DataTableMobileCards.mjs +9 -3
  100. package/dist/esm/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  101. package/dist/esm/components/DataTable/DataTableMobileCards.native.js +12 -3
  102. package/dist/esm/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  103. package/dist/esm/components/DataTable/DataTableRoot.mjs +133 -13
  104. package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
  105. package/dist/esm/components/DataTable/DataTableRoot.native.js +159 -13
  106. package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
  107. package/dist/esm/components/DataTable/DataTableVirtualized.mjs +3 -1
  108. package/dist/esm/components/DataTable/DataTableVirtualized.mjs.map +1 -1
  109. package/dist/esm/components/DataTable/DataTableVirtualized.native.js +3 -1
  110. package/dist/esm/components/DataTable/DataTableVirtualized.native.js.map +1 -1
  111. package/dist/esm/components/DataTable/index.native.js +40 -3
  112. package/dist/esm/components/DataTable/index.native.js.map +1 -1
  113. package/dist/esm/components/DataTableBulkActions/index.mjs +16 -1
  114. package/dist/esm/components/DataTableBulkActions/index.mjs.map +1 -1
  115. package/dist/esm/components/DataTableBulkActions/index.native.js +20 -1
  116. package/dist/esm/components/DataTableBulkActions/index.native.js.map +1 -1
  117. package/dist/esm/components/DataTableCell/CellModalEditor.mjs +4 -8
  118. package/dist/esm/components/DataTableCell/CellModalEditor.mjs.map +1 -1
  119. package/dist/esm/components/DataTableCell/index.mjs +1 -33
  120. package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
  121. package/dist/esm/components/DataTableCell/index.native.js +1 -34
  122. package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
  123. package/dist/esm/components/DataTableColumnPinning/index.mjs +2 -2
  124. package/dist/esm/components/DataTableColumnPinning/index.mjs.map +1 -1
  125. package/dist/esm/components/DataTableColumnPinning/index.native.js +2 -2
  126. package/dist/esm/components/DataTableColumnPinning/index.native.js.map +1 -1
  127. package/dist/esm/components/DataTableExport/index.mjs +1 -0
  128. package/dist/esm/components/DataTableExport/index.mjs.map +1 -1
  129. package/dist/esm/components/DataTableExport/index.native.js +1 -0
  130. package/dist/esm/components/DataTableExport/index.native.js.map +1 -1
  131. package/dist/esm/components/DataTableFilterButton/index.mjs +1 -1
  132. package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
  133. package/dist/esm/components/DataTableFilterButton/index.native.js +4 -1
  134. package/dist/esm/components/DataTableFilterButton/index.native.js.map +1 -1
  135. package/dist/esm/components/DataTableFilterChips/index.mjs +1 -1
  136. package/dist/esm/components/DataTableFilterChips/index.mjs.map +1 -1
  137. package/dist/esm/components/DataTableFilterChips/index.native.js +1 -1
  138. package/dist/esm/components/DataTableGrouping/index.mjs +18 -3
  139. package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
  140. package/dist/esm/components/DataTableGrouping/index.native.js +18 -3
  141. package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
  142. package/dist/esm/components/DataTableToolbar/index.mjs +1 -0
  143. package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
  144. package/dist/esm/components/DataTableToolbar/index.native.js +1 -0
  145. package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
  146. package/dist/esm/components/FilterManager.mjs +18 -14
  147. package/dist/esm/components/FilterManager.mjs.map +1 -1
  148. package/dist/esm/components/FilterManager.native.js +18 -14
  149. package/dist/esm/components/FilterManager.native.js.map +1 -1
  150. package/dist/esm/components/SimpleTable/index.mjs +1 -1
  151. package/dist/esm/components/SimpleTable/index.mjs.map +1 -1
  152. package/dist/esm/components/SimpleTable/index.native.js +1 -1
  153. package/dist/esm/components/TableInput/index.native.js +3 -0
  154. package/dist/esm/components/TableInput/index.native.js.map +1 -1
  155. package/dist/esm/hooks/useDataTable.mjs +17 -1
  156. package/dist/esm/hooks/useDataTable.mjs.map +1 -1
  157. package/dist/esm/hooks/useDataTable.native.js +19 -1
  158. package/dist/esm/hooks/useDataTable.native.js.map +1 -1
  159. package/dist/esm/hooks/useTableGrouping.mjs.map +1 -1
  160. package/dist/esm/utils/rowPress.mjs +19 -0
  161. package/dist/esm/utils/rowPress.mjs.map +1 -0
  162. package/dist/esm/utils/rowPress.native.js +28 -0
  163. package/dist/esm/utils/rowPress.native.js.map +1 -0
  164. package/dist/jsx/components/ColumnHeaderFilter/index.mjs +1 -0
  165. package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
  166. package/dist/jsx/components/ColumnHeaderFilter/index.native.js +1 -0
  167. package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
  168. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs +9 -3
  169. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  170. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js +12 -3
  171. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  172. package/dist/jsx/components/DataTable/DataTableRoot.mjs +133 -13
  173. package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
  174. package/dist/jsx/components/DataTable/DataTableRoot.native.js +159 -13
  175. package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
  176. package/dist/jsx/components/DataTable/DataTableVirtualized.mjs +3 -1
  177. package/dist/jsx/components/DataTable/DataTableVirtualized.mjs.map +1 -1
  178. package/dist/jsx/components/DataTable/DataTableVirtualized.native.js +3 -1
  179. package/dist/jsx/components/DataTable/DataTableVirtualized.native.js.map +1 -1
  180. package/dist/jsx/components/DataTable/index.native.js +40 -3
  181. package/dist/jsx/components/DataTable/index.native.js.map +1 -1
  182. package/dist/jsx/components/DataTableBulkActions/index.mjs +16 -1
  183. package/dist/jsx/components/DataTableBulkActions/index.mjs.map +1 -1
  184. package/dist/jsx/components/DataTableBulkActions/index.native.js +20 -1
  185. package/dist/jsx/components/DataTableBulkActions/index.native.js.map +1 -1
  186. package/dist/jsx/components/DataTableCell/CellModalEditor.mjs +4 -8
  187. package/dist/jsx/components/DataTableCell/CellModalEditor.mjs.map +1 -1
  188. package/dist/jsx/components/DataTableCell/index.mjs +1 -33
  189. package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
  190. package/dist/jsx/components/DataTableCell/index.native.js +1 -34
  191. package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
  192. package/dist/jsx/components/DataTableColumnPinning/index.mjs +2 -2
  193. package/dist/jsx/components/DataTableColumnPinning/index.mjs.map +1 -1
  194. package/dist/jsx/components/DataTableColumnPinning/index.native.js +2 -2
  195. package/dist/jsx/components/DataTableColumnPinning/index.native.js.map +1 -1
  196. package/dist/jsx/components/DataTableExport/index.mjs +1 -0
  197. package/dist/jsx/components/DataTableExport/index.mjs.map +1 -1
  198. package/dist/jsx/components/DataTableExport/index.native.js +1 -0
  199. package/dist/jsx/components/DataTableExport/index.native.js.map +1 -1
  200. package/dist/jsx/components/DataTableFilterButton/index.mjs +1 -1
  201. package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
  202. package/dist/jsx/components/DataTableFilterButton/index.native.js +4 -1
  203. package/dist/jsx/components/DataTableFilterButton/index.native.js.map +1 -1
  204. package/dist/jsx/components/DataTableFilterChips/index.mjs +1 -1
  205. package/dist/jsx/components/DataTableFilterChips/index.mjs.map +1 -1
  206. package/dist/jsx/components/DataTableFilterChips/index.native.js +1 -1
  207. package/dist/jsx/components/DataTableGrouping/index.mjs +18 -3
  208. package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
  209. package/dist/jsx/components/DataTableGrouping/index.native.js +17 -1
  210. package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
  211. package/dist/jsx/components/DataTableToolbar/index.mjs +1 -0
  212. package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
  213. package/dist/jsx/components/DataTableToolbar/index.native.js +1 -0
  214. package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
  215. package/dist/jsx/components/FilterManager.mjs +18 -14
  216. package/dist/jsx/components/FilterManager.mjs.map +1 -1
  217. package/dist/jsx/components/FilterManager.native.js +18 -14
  218. package/dist/jsx/components/FilterManager.native.js.map +1 -1
  219. package/dist/jsx/components/SimpleTable/index.mjs +1 -1
  220. package/dist/jsx/components/SimpleTable/index.mjs.map +1 -1
  221. package/dist/jsx/components/SimpleTable/index.native.js +1 -1
  222. package/dist/jsx/components/SimpleTable/index.native.js.map +1 -1
  223. package/dist/jsx/components/TableInput/index.native.js +3 -0
  224. package/dist/jsx/components/TableInput/index.native.js.map +1 -1
  225. package/dist/jsx/hooks/useDataTable.mjs +17 -1
  226. package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
  227. package/dist/jsx/hooks/useDataTable.native.js +19 -1
  228. package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
  229. package/dist/jsx/hooks/useTableGrouping.mjs.map +1 -1
  230. package/dist/jsx/utils/rowPress.mjs +19 -0
  231. package/dist/jsx/utils/rowPress.mjs.map +1 -0
  232. package/dist/jsx/utils/rowPress.native.js +56 -0
  233. package/dist/jsx/utils/rowPress.native.js.map +1 -0
  234. package/package.json +12 -12
  235. package/src/components/ColumnHeaderFilter/index.tsx +1 -0
  236. package/src/components/DataTable/DataTable.spec.tsx +4 -1
  237. package/src/components/DataTable/DataTable.stories.tsx +190 -5
  238. package/src/components/DataTable/DataTableMobileCards.tsx +30 -4
  239. package/src/components/DataTable/DataTableRoot.tsx +195 -8
  240. package/src/components/DataTable/DataTableVirtualized.tsx +8 -0
  241. package/src/components/DataTable/cardLayout.spec.tsx +4 -1
  242. package/src/components/DataTable/customCellAlign.spec.tsx +124 -0
  243. package/src/components/DataTable/disabledContract.spec.tsx +4 -3
  244. package/src/components/DataTable/index.native.tsx +47 -1
  245. package/src/components/DataTable/rowPress.spec.tsx +229 -0
  246. package/src/components/DataTable/selectionSemantics.spec.tsx +156 -0
  247. package/src/components/DataTableBulkActions/index.tsx +16 -2
  248. package/src/components/DataTableBulkActions/selectionCountI18n.spec.tsx +94 -0
  249. package/src/components/DataTableCell/CellModalEditor.tsx +3 -1
  250. package/src/components/DataTableCell/DataTableCell.stories.tsx +1 -5
  251. package/src/components/DataTableCell/cellDraftPolicy.spec.tsx +10 -2
  252. package/src/components/DataTableCell/dataTableCell.spec.tsx +10 -2
  253. package/src/components/DataTableCell/index.tsx +5 -36
  254. package/src/components/DataTableColumnPinning/DataTableColumnPinning.stories.tsx +49 -17
  255. package/src/components/DataTableDateFilter/DataTableDateFilter.stories.tsx +4 -3
  256. package/src/components/DataTableExport/DataTableExport.stories.tsx +3 -2
  257. package/src/components/DataTableExport/index.tsx +1 -0
  258. package/src/components/DataTableFilterButton/index.tsx +4 -1
  259. package/src/components/DataTableGrouping/DataTableGrouping.spec.tsx +59 -2
  260. package/src/components/DataTableGrouping/DataTableGrouping.stories.tsx +17 -5
  261. package/src/components/DataTableGrouping/index.tsx +1 -0
  262. package/src/components/DataTablePagination/DataTablePagination.stories.tsx +34 -20
  263. package/src/components/DataTableToolbar/index.tsx +1 -0
  264. package/src/components/DataTableViewOptions/DataTableViewOptions.stories.tsx +2 -1
  265. package/src/components/FilterManager.tsx +21 -13
  266. package/src/components/TableInput/index.native.tsx +3 -0
  267. package/src/components/__scratch__/scratch.spec.tsx +46 -0
  268. package/src/hooks/useDataTable.ts +27 -1
  269. package/src/types.ts +25 -0
  270. package/src/utils/rowPress.ts +58 -0
  271. package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
  272. package/types/components/DataTable/DataTableMobileCards.d.ts +13 -1
  273. package/types/components/DataTable/DataTableMobileCards.d.ts.map +1 -1
  274. package/types/components/DataTable/DataTableRoot.d.ts +1 -1
  275. package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
  276. package/types/components/DataTable/DataTableVirtualized.d.ts +7 -1
  277. package/types/components/DataTable/DataTableVirtualized.d.ts.map +1 -1
  278. package/types/components/DataTable/index.native.d.ts +1 -1
  279. package/types/components/DataTable/index.native.d.ts.map +1 -1
  280. package/types/components/DataTableBulkActions/index.d.ts.map +1 -1
  281. package/types/components/DataTableCell/CellModalEditor.d.ts.map +1 -1
  282. package/types/components/DataTableCell/index.d.ts.map +1 -1
  283. package/types/components/DataTableColumnPinning/index.d.ts.map +1 -1
  284. package/types/components/DataTableFilterButton/index.d.ts.map +1 -1
  285. package/types/components/DataTableGrouping/index.d.ts +8 -0
  286. package/types/components/DataTableGrouping/index.d.ts.map +1 -1
  287. package/types/components/DataTableToolbar/index.d.ts.map +1 -1
  288. package/types/components/FilterManager.d.ts +7 -1
  289. package/types/components/FilterManager.d.ts.map +1 -1
  290. package/types/components/TableInput/index.native.d.ts.map +1 -1
  291. package/types/hooks/useDataTable.d.ts.map +1 -1
  292. package/types/types.d.ts +23 -0
  293. package/types/types.d.ts.map +1 -1
  294. package/types/utils/rowPress.d.ts +20 -0
  295. package/types/utils/rowPress.d.ts.map +1 -0
@@ -2,8 +2,14 @@ import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
2
2
  import { fn } from "storybook/test";
3
3
  import { createColumnHelper } from "@tanstack/react-table";
4
4
  import React, { useMemo } from "react";
5
+ import {
6
+ formatAbsoluteDate,
7
+ formatCurrency,
8
+ type GuardrailSpecimenParameter,
9
+ } from "@multiplatform.one/theme";
5
10
  import { Button } from "@multiplatform.one/forms";
6
- import { Avatar, Text, View, YStack } from "tamagui";
11
+ import { Avatar } from "@multiplatform.one/components";
12
+ import { Text, View, YStack } from "tamagui";
7
13
  import {
8
14
  type DataTableColumn,
9
15
  type DataTableData,
@@ -84,7 +90,7 @@ const columns: DataTableColumn<User>[] = [
84
90
  columnHelper.accessor("avatar", {
85
91
  header: "Avatar",
86
92
  cell: (info) => (
87
- <Avatar circular size="$3">
93
+ <Avatar circular size="$3" backgroundColor="$gray6">
88
94
  <Avatar.Image alt="User avatar" src={info.getValue()} />
89
95
  <Avatar.Fallback backgroundColor="$gray6" />
90
96
  </Avatar>
@@ -143,7 +149,11 @@ const columns: DataTableColumn<User>[] = [
143
149
  // Salary Column
144
150
  columnHelper.accessor("salary", {
145
151
  header: "Salary",
146
- cell: (info) => <Text>${info.getValue().toLocaleString()}</Text>,
152
+ cell: (info) => (
153
+ <Text>
154
+ {formatCurrency(info.getValue() as number, { symbol: "$", fractionDigits: "auto" })}
155
+ </Text>
156
+ ),
147
157
  filterFn: "inNumberRange",
148
158
  }) as DataTableColumn<User>,
149
159
 
@@ -179,14 +189,14 @@ const columns: DataTableColumn<User>[] = [
179
189
  // Join Date Column
180
190
  columnHelper.accessor("joinDate", {
181
191
  header: "Join Date",
182
- cell: (info) => <Text>{new Date(info.getValue()).toLocaleDateString()}</Text>,
192
+ cell: (info) => <Text>{formatAbsoluteDate(info.getValue() as string)}</Text>,
183
193
  filterFn: "includesString",
184
194
  }) as DataTableColumn<User>,
185
195
 
186
196
  // Last Login Column
187
197
  columnHelper.accessor("lastLogin", {
188
198
  header: "Last Login",
189
- cell: (info) => <Text>{new Date(info.getValue()).toLocaleDateString()}</Text>,
199
+ cell: (info) => <Text>{formatAbsoluteDate(info.getValue() as string)}</Text>,
190
200
  filterFn: "includesString",
191
201
  }) as DataTableColumn<User>,
192
202
 
@@ -802,10 +812,14 @@ const editableColumns: DataTableColumn<EditablePerson>[] = [
802
812
  header: "Category",
803
813
  field: "select",
804
814
  fieldProps: {
815
+ // >5 options: shorter single-select lists trip `select-too-few-options` (DG-CTRL-01).
805
816
  options: [
806
817
  { label: "Electronics", value: "electronics" },
807
818
  { label: "Clothing", value: "clothing" },
808
819
  { label: "Food", value: "food" },
820
+ { label: "Books", value: "books" },
821
+ { label: "Toys", value: "toys" },
822
+ { label: "Garden", value: "garden" },
809
823
  ],
810
824
  },
811
825
  },
@@ -858,6 +872,15 @@ export const EditableTable: Story = {
858
872
  * state (see ReadOnly).
859
873
  */
860
874
  export const Disabled: Story = {
875
+ parameters: {
876
+ // LC-57 allowlist: this story IS the whole-table disabled-dial demo — every
877
+ // piece of chrome rests disabled by design, and per-control reasons would
878
+ // say nothing beyond what the story title already does.
879
+ guardrailSpecimen: {
880
+ warns: ["bare-disabled"],
881
+ reason: "Disabled-dial specimen: the entire table (all chrome) rests disabled by design.",
882
+ } satisfies GuardrailSpecimenParameter,
883
+ },
861
884
  args: {
862
885
  data: editableData as unknown as Record<string, any>[],
863
886
  columns: editableColumns as DataTableColumn<Record<string, any>>[],
@@ -1278,6 +1301,7 @@ const selectFieldData: SelectFieldRow[] = [
1278
1301
  { id: 3, category: "food", priority: "low", status: "inactive" },
1279
1302
  ];
1280
1303
 
1304
+ // >5 options per list: shorter single-select lists trip `select-too-few-options` (DG-CTRL-01).
1281
1305
  const selectFieldColumns: DataTableColumn<SelectFieldRow>[] = [
1282
1306
  {
1283
1307
  accessorKey: "category",
@@ -1288,6 +1312,9 @@ const selectFieldColumns: DataTableColumn<SelectFieldRow>[] = [
1288
1312
  { label: "Electronics", value: "electronics" },
1289
1313
  { label: "Clothing", value: "clothing" },
1290
1314
  { label: "Food", value: "food" },
1315
+ { label: "Books", value: "books" },
1316
+ { label: "Toys", value: "toys" },
1317
+ { label: "Garden", value: "garden" },
1291
1318
  ],
1292
1319
  },
1293
1320
  },
@@ -1297,9 +1324,12 @@ const selectFieldColumns: DataTableColumn<SelectFieldRow>[] = [
1297
1324
  field: "select",
1298
1325
  fieldProps: {
1299
1326
  options: [
1327
+ { label: "Highest", value: "highest" },
1300
1328
  { label: "High", value: "high" },
1301
1329
  { label: "Medium", value: "medium" },
1302
1330
  { label: "Low", value: "low" },
1331
+ { label: "Lowest", value: "lowest" },
1332
+ { label: "Deferred", value: "deferred" },
1303
1333
  ],
1304
1334
  },
1305
1335
  },
@@ -1312,6 +1342,9 @@ const selectFieldColumns: DataTableColumn<SelectFieldRow>[] = [
1312
1342
  { label: "Active", value: "active" },
1313
1343
  { label: "Pending", value: "pending" },
1314
1344
  { label: "Inactive", value: "inactive" },
1345
+ { label: "Draft", value: "draft" },
1346
+ { label: "Archived", value: "archived" },
1347
+ { label: "Blocked", value: "blocked" },
1315
1348
  ],
1316
1349
  },
1317
1350
  },
@@ -2105,12 +2138,14 @@ const searchableColumns: DataTableColumn<SearchableRow>[] = [
2105
2138
  header: "Department",
2106
2139
  field: "select",
2107
2140
  fieldProps: {
2141
+ // >5 options: shorter single-select lists trip `select-too-few-options` (DG-CTRL-01).
2108
2142
  options: [
2109
2143
  { label: "Engineering", value: "Engineering" },
2110
2144
  { label: "Marketing", value: "Marketing" },
2111
2145
  { label: "Sales", value: "Sales" },
2112
2146
  { label: "HR", value: "HR" },
2113
2147
  { label: "Finance", value: "Finance" },
2148
+ { label: "Legal", value: "Legal" },
2114
2149
  ],
2115
2150
  },
2116
2151
  },
@@ -2773,10 +2808,14 @@ const hiddenFilterColumns: DataTableColumn<User>[] = [
2773
2808
  header: "Status",
2774
2809
  field: "select",
2775
2810
  fieldProps: {
2811
+ // >5 options: shorter single-select lists trip `select-too-few-options` (DG-CTRL-01).
2776
2812
  options: [
2777
2813
  { label: "Active", value: "active" },
2778
2814
  { label: "Inactive", value: "inactive" },
2779
2815
  { label: "Pending", value: "pending" },
2816
+ { label: "Draft", value: "draft" },
2817
+ { label: "Archived", value: "archived" },
2818
+ { label: "Blocked", value: "blocked" },
2780
2819
  ],
2781
2820
  },
2782
2821
  },
@@ -2875,3 +2914,149 @@ const CompoundCompositionStory = () => {
2875
2914
  export const CompoundComposition: Story = {
2876
2915
  render: () => <CompoundCompositionStory />,
2877
2916
  };
2917
+
2918
+ // ============================================================================
2919
+ // ROW PRESS (onRowPress — first-class row activation)
2920
+ // ============================================================================
2921
+
2922
+ /**
2923
+ * onRowPress makes each row ONE pressable unit (LC-49/LC-50): click/tap
2924
+ * anywhere in the row activates, the row set exposes a single roving tab
2925
+ * stop (ArrowUp/Down + Home/End move it, Enter AND Space activate), and
2926
+ * `rowLabel` names each row for AT. Inner interactive controls — the
2927
+ * selection checkboxes and the per-row Edit button here — stay isolated:
2928
+ * pressing them never fires the row press.
2929
+ */
2930
+ const RowPressStory = () => {
2931
+ const data = useMemo(() => generateUsers(8), []);
2932
+ // Explicit ids on every column: DataTable seeds columnOrder from
2933
+ // `col.id || ""`, so mixing id-less accessor columns with id'd display
2934
+ // columns would reorder the id'd ones first.
2935
+ const rowPressColumns = useMemo<DataTableColumn<User>[]>(
2936
+ () => [
2937
+ { id: "firstName", accessorKey: "firstName", header: "First Name" },
2938
+ { id: "department", accessorKey: "department", header: "Department" },
2939
+ {
2940
+ id: "salary",
2941
+ accessorKey: "salary",
2942
+ header: "Salary",
2943
+ align: "right",
2944
+ cell: (info) => (
2945
+ <Text fontWeight="600">
2946
+ {formatCurrency(info.getValue() as number, { symbol: "$", fractionDigits: "auto" })}
2947
+ </Text>
2948
+ ),
2949
+ },
2950
+ {
2951
+ id: "row_actions",
2952
+ header: "Actions",
2953
+ cell: () => (
2954
+ <Button size="$2" onPress={fn()}>
2955
+ Edit
2956
+ </Button>
2957
+ ),
2958
+ },
2959
+ ],
2960
+ [],
2961
+ );
2962
+ return (
2963
+ <DataTable
2964
+ data={data}
2965
+ columns={rowPressColumns as DataTableColumn<Record<string, any>>[]}
2966
+ enableRowSelection
2967
+ enableFiltering={false}
2968
+ enableGlobalSearch={false}
2969
+ enablePagination={false}
2970
+ onRowPress={fn()}
2971
+ rowLabel={(row) => (row as User).firstName}
2972
+ aria-label="Row press table"
2973
+ />
2974
+ );
2975
+ };
2976
+
2977
+ export const RowPress: Story = {
2978
+ render: () => <RowPressStory />,
2979
+ parameters: {
2980
+ docs: {
2981
+ description: {
2982
+ story:
2983
+ 'First-class row activation: `onRowPress(row, index)` fires on click/tap anywhere in a row and on Enter/Space while the row is focused. One roving tab stop per row set (LC-49), arrow keys move it, and inner controls (selection checkboxes, buttons) never trigger the row press. `rowLabel` names rows and their selection checkboxes ("Select row User3").',
2984
+ },
2985
+ },
2986
+ },
2987
+ };
2988
+
2989
+ // ============================================================================
2990
+ // CUSTOM-CELL ALIGNMENT (DG-TBL-01 for custom renderers)
2991
+ // ============================================================================
2992
+
2993
+ /**
2994
+ * Custom `cell` renderers inherit the column `align` through the table's
2995
+ * alignment container — no self-alignment. In the semantic-table
2996
+ * displayMode (columnLayout="auto") the cell box is display:table-cell
2997
+ * where flex justifyContent is a no-op; the wrapper restores the column
2998
+ * line for custom content (numerics share one right edge, LC-44).
2999
+ */
3000
+ const CustomCellAlignmentStory = () => {
3001
+ const data = useMemo(() => generateUsers(6), []);
3002
+ const alignColumns = useMemo<DataTableColumn<User>[]>(
3003
+ () => [
3004
+ {
3005
+ id: "firstName",
3006
+ accessorKey: "firstName",
3007
+ header: "Name (left)",
3008
+ cell: (info) => <Text fontWeight="600">{String(info.getValue())}</Text>,
3009
+ },
3010
+ {
3011
+ id: "age",
3012
+ accessorKey: "age",
3013
+ header: "Age (right)",
3014
+ align: "right",
3015
+ cell: (info) => <Text>{String(info.getValue())}</Text>,
3016
+ },
3017
+ {
3018
+ id: "salary",
3019
+ accessorKey: "salary",
3020
+ header: "Salary (right)",
3021
+ align: "right",
3022
+ cell: (info) => (
3023
+ <Text fontWeight="600">
3024
+ {formatCurrency(info.getValue() as number, { symbol: "$", fractionDigits: "auto" })}
3025
+ </Text>
3026
+ ),
3027
+ },
3028
+ {
3029
+ id: "status",
3030
+ accessorKey: "status",
3031
+ header: "Status (center)",
3032
+ align: "center",
3033
+ cell: (info) => <Text>{String(info.getValue())}</Text>,
3034
+ },
3035
+ ],
3036
+ [],
3037
+ );
3038
+ return (
3039
+ <DataTable
3040
+ data={data}
3041
+ columns={alignColumns as DataTableColumn<Record<string, any>>[]}
3042
+ columnLayout="auto"
3043
+ enableFiltering={false}
3044
+ enableGlobalSearch={false}
3045
+ enablePagination={false}
3046
+ readOnly
3047
+ aria-label="Custom cell alignment table"
3048
+ />
3049
+ );
3050
+ };
3051
+
3052
+ export const CustomCellAlignment: Story = {
3053
+ render: () => <CustomCellAlignmentStory />,
3054
+ parameters: {
3055
+ docs: {
3056
+ description: {
3057
+ story:
3058
+ "Column `align` applies to CUSTOM cell renderers exactly like built-in field cells: the table wraps flexRender output in an alignment container (`data-cell-align`), so numeric custom cells right-align to one shared edge without any consumer alignment code.",
3059
+ },
3060
+ },
3061
+ },
3062
+ };
@@ -50,6 +50,18 @@ export interface DataTableMobileCardsProps<TData> {
50
50
  selectAllIndeterminate?: boolean;
51
51
  onToggleSelectAll?: () => void;
52
52
  compact?: boolean;
53
+ /**
54
+ * Accessible name for a row's selection checkbox ("Select row {identity}",
55
+ * built by DataTableRoot so cards and grid share one naming source).
56
+ */
57
+ selectRowLabel?: (row: any, rowIndex: number) => string;
58
+ /**
59
+ * onRowPress support: press/keyboard/AT props for one pressable row
60
+ * (built by DataTableRoot). Cards live outside the table tree, so they
61
+ * take the `card` variant (role="button") with the same activation,
62
+ * roving focus, and inner-control isolation as grid rows.
63
+ */
64
+ getRowPressProps?: (row: any, rowIndex: number, variant?: "row" | "card") => Record<string, any>;
53
65
  }
54
66
 
55
67
  export function DataTableMobileCards<TData extends Record<string, any>>({
@@ -68,6 +80,8 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
68
80
  selectAllIndeterminate = false,
69
81
  onToggleSelectAll,
70
82
  compact = false,
83
+ selectRowLabel,
84
+ getRowPressProps,
71
85
  }: DataTableMobileCardsProps<TData>) {
72
86
  const { t } = useTranslation();
73
87
  const { knobProps } = useResolvedKnobs();
@@ -92,6 +106,7 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
92
106
  {...({
93
107
  "data-table-zebra": tableZebraOn ? (index % 2 === 0 ? "even" : "odd") : "off",
94
108
  } as any)}
109
+ {...(getRowPressProps ? (getRowPressProps(row, index, "card") as any) : {})}
95
110
  >
96
111
  {/* Card header: selection + primary-column title + row number + delete */}
97
112
  <XStack
@@ -115,9 +130,11 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
115
130
  }}
116
131
  disabled={disabled}
117
132
  checkboxProps={{
118
- "aria-label": withInterp(t("Select row {{row}}", { row: index + 1 }), {
119
- row: index + 1,
120
- }),
133
+ "aria-label":
134
+ selectRowLabel?.(row, index) ??
135
+ withInterp(t("Select row {{row}}", { row: index + 1 }), {
136
+ row: index + 1,
137
+ }),
121
138
  }}
122
139
  compact={compact}
123
140
  />
@@ -198,11 +215,20 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
198
215
  knobProps,
199
216
  tableZebraOn,
200
217
  t,
218
+ selectRowLabel,
219
+ getRowPressProps,
201
220
  ],
202
221
  );
203
222
 
204
223
  return (
205
- <View flexDirection="column" {...knobProps.gap} testID="data-table-cards">
224
+ <View
225
+ flexDirection="column"
226
+ {...knobProps.gap}
227
+ testID="data-table-cards"
228
+ // Roving-focus DOM scope for onRowPress arrow keys (LC-49) — keeps
229
+ // ArrowUp/Down/Home/End inside THIS table's card list.
230
+ {...(getRowPressProps ? ({ "data-row-press-scope": "true" } as any) : {})}
231
+ >
206
232
  {enableRowSelection && tableRows.length > 0 && (
207
233
  <XStack alignItems="center" gap="$2" paddingBottom="$2">
208
234
  <Checkbox
@@ -62,6 +62,7 @@ import { DataTableVirtualized } from "./DataTableVirtualized";
62
62
  import { alignToFlex, getDefaultColumnAlign } from "../../utils/columnAlign";
63
63
  import { mapFieldToFilterType } from "../../utils/filterFields";
64
64
  import { INFINITE_TRIGGER_ROWS } from "../../utils/paginationDefaults";
65
+ import { isInteractiveInnerTarget } from "../../utils/rowPress";
65
66
  import { bidiIsolate, withInterp } from "../../utils/withInterp";
66
67
 
67
68
  const SELECTION_COL_WIDTH = 40;
@@ -134,6 +135,8 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
134
135
  maxPinnedColumns = 3,
135
136
  enableGrouping = false,
136
137
  enableKeyboardNavigation = false,
138
+ onRowPress,
139
+ rowLabel,
137
140
  enableRowSelection = false,
138
141
  selectAllScope: selectAllScopeProp,
139
142
  bulkActions,
@@ -473,6 +476,159 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
473
476
  : undefined,
474
477
  });
475
478
 
479
+ const isSSR = typeof window === "undefined";
480
+
481
+ // ---- Row press (onRowPress): the ROW is one pressable unit ----
482
+
483
+ const rowPressActive = Boolean(onRowPress) && !disabled;
484
+ // LC-49 roving anchor: the row set exposes exactly one tab stop — the
485
+ // focused row while focus is inside the set, else the first row.
486
+ const [rowPressAnchor, setRowPressAnchor] = useState(0);
487
+ const effectiveRowPressAnchor = Math.min(rowPressAnchor, Math.max(tableRows.length - 1, 0));
488
+
489
+ // Row identity for accessible names (DG-A11Y-06): consumer accessor →
490
+ // first visible column's cell value → undefined (caller picks its own
491
+ // positional fallback). Shared by the row-press label and the selection
492
+ // checkbox name so "which row is this control for" reads the same
493
+ // everywhere.
494
+ const deriveRowIdentity = useCallback(
495
+ (row: any): string | undefined => {
496
+ const fromAccessor = rowLabel?.(row.original as TData);
497
+ if (fromAccessor) return fromAccessor;
498
+ let firstCellValue: unknown;
499
+ try {
500
+ firstCellValue = row.getVisibleCells()[0]?.getValue();
501
+ } catch {
502
+ firstCellValue = undefined;
503
+ }
504
+ if (
505
+ (typeof firstCellValue === "string" && firstCellValue.length > 0) ||
506
+ typeof firstCellValue === "number"
507
+ ) {
508
+ return String(firstCellValue);
509
+ }
510
+ return undefined;
511
+ },
512
+ [rowLabel],
513
+ );
514
+
515
+ // Accessible name per pressable row: identity, else positional "Row {{row}}".
516
+ const deriveRowLabel = useCallback(
517
+ (row: any, rowIndex: number): string =>
518
+ deriveRowIdentity(row) ??
519
+ withInterp(t("Row {{row}}", { row: rowIndex + 1 }), { row: rowIndex + 1 }),
520
+ [deriveRowIdentity, t],
521
+ );
522
+
523
+ // Selection-toggle name: row identity beats a bare index ("Select row
524
+ // Bulbasaur", falling back to "Select row 3") so AT and automation can
525
+ // target a specific row's checkbox by name.
526
+ const deriveSelectRowLabel = useCallback(
527
+ (row: any, rowIndex: number): string => {
528
+ const identity = deriveRowIdentity(row) ?? String(rowIndex + 1);
529
+ return withInterp(t("Select row {{row}}", { row: identity }), { row: identity });
530
+ },
531
+ [deriveRowIdentity, t],
532
+ );
533
+
534
+ const activateRowPress = useCallback(
535
+ (row: any, rowIndex: number) => {
536
+ onRowPress?.(row.original as TData, rowIndex);
537
+ },
538
+ [onRowPress],
539
+ );
540
+
541
+ /**
542
+ * Press/keyboard/AT props for one pressable row (grid `<tr>`, virtualized
543
+ * row host, or mobile card). Spread LAST so the roving tabIndex overrides
544
+ * the static -1 the grid row carries otherwise.
545
+ *
546
+ * - Pointer: activation skips presses originating on inner interactive
547
+ * elements (isInteractiveInnerTarget — the stopPropagation contract's
548
+ * defensive arm).
549
+ * - Keyboard (LC-50): Enter AND Space each synthesize exactly one
550
+ * activation (repeat + defaultPrevented guarded); arrows/Home/End rove
551
+ * within the row set; Shift+Tab exits (no key trap).
552
+ */
553
+ const getRowPressProps = useCallback(
554
+ (row: any, rowIndex: number, variant: "row" | "card" = "row") => {
555
+ if (!rowPressActive) return {};
556
+ const handlePress = (event: any) => {
557
+ if (event?.defaultPrevented) return;
558
+ const targetEl = event?.target ?? event?.nativeEvent?.target;
559
+ if (isWeb && typeof Element !== "undefined" && targetEl instanceof Element) {
560
+ const boundary = targetEl.closest('[data-row-press="true"]');
561
+ if (isInteractiveInnerTarget(targetEl, boundary)) return;
562
+ }
563
+ activateRowPress(row, rowIndex);
564
+ };
565
+ return {
566
+ "aria-label": deriveRowLabel(row, rowIndex),
567
+ onPress: handlePress,
568
+ cursor: "pointer" as const,
569
+ pressStyle: { backgroundColor: "$color4" },
570
+ ...(variant === "card" ? { role: "button" as const } : {}),
571
+ ...(isWeb && !isSSR
572
+ ? {
573
+ tabIndex: rowIndex === effectiveRowPressAnchor ? 0 : -1,
574
+ focusVisibleStyle: ensureFocusVisibleRing({ outlineOffset: -2 }),
575
+ "data-row-press": "true",
576
+ onFocus: (e: React.FocusEvent) => {
577
+ // Only a focused ROW moves the anchor; focus on an inner
578
+ // control (own tab stop) leaves the roving state alone.
579
+ if (e.target === e.currentTarget) setRowPressAnchor(rowIndex);
580
+ },
581
+ onBlur: (e: React.FocusEvent) => {
582
+ const next = e.relatedTarget;
583
+ if (!(next instanceof Element) || !next.closest('[data-row-press="true"]')) {
584
+ setRowPressAnchor(0);
585
+ }
586
+ },
587
+ onKeyDown: (e: React.KeyboardEvent) => {
588
+ if (e.defaultPrevented) return;
589
+ // Keys on focused inner controls belong to those controls.
590
+ if (e.target !== e.currentTarget) return;
591
+ const key = e.key;
592
+ if (key === "Enter" || key === " " || key === "Spacebar") {
593
+ // preventDefault stops Space page-scroll; stopPropagation
594
+ // keeps the container-level keyboard nav (Excel mode) from
595
+ // double-activating the same physical key.
596
+ e.preventDefault();
597
+ e.stopPropagation();
598
+ if (e.repeat) return;
599
+ activateRowPress(row, rowIndex);
600
+ return;
601
+ }
602
+ if (key === "ArrowDown" || key === "ArrowUp" || key === "Home" || key === "End") {
603
+ e.preventDefault();
604
+ e.stopPropagation();
605
+ const rowEl = e.currentTarget as HTMLElement;
606
+ const scope =
607
+ rowEl.closest('[data-row-press-scope="true"]') ?? rowEl.ownerDocument;
608
+ const pressRows = Array.from(
609
+ scope.querySelectorAll('[data-row-press="true"]'),
610
+ ) as HTMLElement[];
611
+ const currentIdx = pressRows.indexOf(rowEl);
612
+ if (currentIdx < 0) return;
613
+ const nextIdx =
614
+ key === "Home"
615
+ ? 0
616
+ : key === "End"
617
+ ? pressRows.length - 1
618
+ : Math.min(
619
+ Math.max(currentIdx + (key === "ArrowDown" ? 1 : -1), 0),
620
+ pressRows.length - 1,
621
+ );
622
+ pressRows[nextIdx]?.focus();
623
+ }
624
+ },
625
+ }
626
+ : {}),
627
+ };
628
+ },
629
+ [rowPressActive, deriveRowLabel, activateRowPress, effectiveRowPressAnchor, isSSR],
630
+ );
631
+
476
632
  const handleCellChange = useCallback(
477
633
  async (rowIndex: number, columnId: string, newValue: any) => {
478
634
  if (readOnly || disabled) return;
@@ -519,7 +675,28 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
519
675
  const value = cell.getValue();
520
676
 
521
677
  if (columnDef.cell && !columnDef.field) {
522
- return flexRender(columnDef.cell, cell.getContext());
678
+ // DG-TBL-01 for CUSTOM cell renderers: the cell box's own
679
+ // justifyContent no-ops in the semantic-table displayMode
680
+ // (display: table-cell is not a flex container), so the column's
681
+ // resolved alignment rides this full-width flex container instead —
682
+ // consumers never self-align. The built-in DataTableCell branch
683
+ // below aligns internally (CellWrapper) and stays unwrapped.
684
+ const customAlign = resolveColumnAlign({
685
+ ...(columnDef as DataTableColumn),
686
+ id: cell.column.id,
687
+ });
688
+ return (
689
+ <View
690
+ width="100%"
691
+ minWidth={0}
692
+ flexDirection="row"
693
+ alignItems="center"
694
+ justifyContent={alignToFlex(customAlign)}
695
+ {...({ "data-cell-align": customAlign } as any)}
696
+ >
697
+ {flexRender(columnDef.cell, cell.getContext())}
698
+ </View>
699
+ );
523
700
  }
524
701
 
525
702
  const columnField = getColumnField(columnDef);
@@ -556,8 +733,6 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
556
733
  [handleCellChange, readOnly, disabled, knobProps.sizeToken, isCompact],
557
734
  );
558
735
 
559
- const isSSR = typeof window === "undefined";
560
-
561
736
  const extraColumnsBefore =
562
737
  (enableRowSelection ? 1 : 0) + (showRowNumbers ? 1 : 0) + (enableRowExpansion ? 1 : 0);
563
738
  const extraColumnsAfter = showDeleteRow && !readOnly ? 1 : 0;
@@ -651,10 +826,9 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
651
826
  disabled={disabled}
652
827
  checkboxProps={{
653
828
  // Row identity in the name so repeated per-row actions are
654
- // differentiated for screen readers (DG-A11Y-06).
655
- "aria-label": withInterp(t("Select row {{row}}", { row: rowIndex + 1 }), {
656
- row: rowIndex + 1,
657
- }),
829
+ // differentiated for screen readers (DG-A11Y-06). The
830
+ // aria-label rides the role="checkbox" frame itself.
831
+ "aria-label": deriveSelectRowLabel(row, rowIndex),
658
832
  }}
659
833
  compact={isCompact}
660
834
  />
@@ -840,6 +1014,7 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
840
1014
  minRows,
841
1015
  isCompact,
842
1016
  t,
1017
+ deriveSelectRowLabel,
843
1018
  ExpandCaretIcon,
844
1019
  expandedCaretRotation,
845
1020
  clipBodyCells,
@@ -1084,6 +1259,8 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
1084
1259
  selectAllIndeterminate={selectAllIndeterminate}
1085
1260
  onToggleSelectAll={toggleSelectAll}
1086
1261
  compact={isCompact}
1262
+ selectRowLabel={deriveSelectRowLabel}
1263
+ {...(rowPressActive ? { getRowPressProps } : {})}
1087
1264
  />
1088
1265
  </>
1089
1266
  ) : (
@@ -1099,7 +1276,13 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
1099
1276
  }}
1100
1277
  flexDirection="column"
1101
1278
  width="100%"
1102
- flexGrow={1}
1279
+ // Grow 0 / shrink 1 / basis auto: the grid frame hugs its
1280
+ // rows and only compresses (into internal scroll) when the
1281
+ // parent is shorter. flexGrow 1 stretched the frame to fill
1282
+ // tall parents, painting a dead zone between the last row
1283
+ // and the frame's bottom border on short pages (the frame
1284
+ // claimed data area that held no data — Axiom 6/LC-37).
1285
+ flexGrow={0}
1103
1286
  flexShrink={1}
1104
1287
  flexBasis="auto"
1105
1288
  minHeight={0}
@@ -1144,6 +1327,8 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
1144
1327
  // to it instead of the scrolling content View. Content
1145
1328
  // fits the max-content box, so nothing needs the clip.
1146
1329
  {...(hScroll && enableColumnPinning ? { overflow: "visible" as any } : {})}
1330
+ // Roving-focus DOM scope for onRowPress arrow keys (LC-49).
1331
+ {...(rowPressActive ? ({ "data-row-press-scope": "true" } as any) : {})}
1147
1332
  >
1148
1333
  {/* Table Header */}
1149
1334
  <Table.Head zIndex="$1" aria-label={t("Table headers")}>
@@ -1553,6 +1738,7 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
1553
1738
  extraColumnsAfter={extraColumnsAfter}
1554
1739
  table={table}
1555
1740
  hasInfiniteTail={hasInfiniteTail}
1741
+ {...(rowPressActive ? { getRowPressProps } : {})}
1556
1742
  />
1557
1743
  </Table.Cell>
1558
1744
  </Table.Row>
@@ -1646,6 +1832,7 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
1646
1832
  : "odd"
1647
1833
  : "off",
1648
1834
  } as any)}
1835
+ {...(getRowPressProps(row, index) as any)}
1649
1836
  >
1650
1837
  {renderRowContent(row, index, isLastRow)}
1651
1838
  </Table.Row>
@@ -42,6 +42,12 @@ export interface DataTableVirtualizedProps {
42
42
  * scroll range so appended pages grow geometry seamlessly.
43
43
  */
44
44
  hasInfiniteTail?: boolean;
45
+ /**
46
+ * onRowPress support: press/keyboard/AT props for one pressable row
47
+ * (built by DataTableRoot; spread on the row host so virtual rows keep
48
+ * the same activation + roving-focus contract as grid rows).
49
+ */
50
+ getRowPressProps?: (row: any, rowIndex: number, variant?: "row" | "card") => Record<string, any>;
45
51
  }
46
52
 
47
53
  export function DataTableVirtualized({
@@ -60,6 +66,7 @@ export function DataTableVirtualized({
60
66
  getColSizeProps,
61
67
  renderRowContent,
62
68
  hasInfiniteTail = false,
69
+ getRowPressProps,
63
70
  }: DataTableVirtualizedProps) {
64
71
  return (
65
72
  <div
@@ -188,6 +195,7 @@ export function DataTableVirtualized({
188
195
  }
189
196
  role="row"
190
197
  aria-rowindex={virtualRow.index + 1}
198
+ {...(getRowPressProps ? (getRowPressProps(row, virtualRow.index) as any) : {})}
191
199
  >
192
200
  {/* div cells (role="cell" via the primitive): a real <td> is
193
201
  not a valid child of the absolutely-positioned div rows */}