@multiplatform.one/table 7.7.6 → 7.10.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 (384) hide show
  1. package/dist/cjs/components/ColumnHeaderFilter/index.cjs +74 -38
  2. package/dist/cjs/components/ColumnHeaderFilter/index.native.js +97 -51
  3. package/dist/cjs/components/ColumnHeaderFilter/index.native.js.map +1 -1
  4. package/dist/cjs/components/DataTable/DataTableCardControls.cjs +0 -1
  5. package/dist/cjs/components/DataTable/DataTableCardControls.native.js +0 -1
  6. package/dist/cjs/components/DataTable/DataTableCardControls.native.js.map +1 -1
  7. package/dist/cjs/components/DataTable/DataTableMobileCards.cjs +100 -33
  8. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js +139 -38
  9. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  10. package/dist/cjs/components/DataTable/DataTableRoot.cjs +33 -6
  11. package/dist/cjs/components/DataTable/DataTableRoot.native.js +29 -4
  12. package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
  13. package/dist/cjs/components/DataTable/DataTableStateContext.native.js.map +1 -1
  14. package/dist/cjs/components/DataTable/index.native.js +59 -93
  15. package/dist/cjs/components/DataTable/index.native.js.map +1 -1
  16. package/dist/cjs/components/DataTableBulkActions/index.cjs +0 -4
  17. package/dist/cjs/components/DataTableBulkActions/index.native.js +0 -4
  18. package/dist/cjs/components/DataTableBulkActions/index.native.js.map +1 -1
  19. package/dist/cjs/components/DataTableCell/index.cjs +16 -1
  20. package/dist/cjs/components/DataTableCell/index.native.js +16 -1
  21. package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
  22. package/dist/cjs/components/DataTableDateFilter/index.cjs +0 -7
  23. package/dist/cjs/components/DataTableDateFilter/index.native.js +0 -7
  24. package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
  25. package/dist/cjs/components/DataTableFilterButton/index.cjs +0 -1
  26. package/dist/cjs/components/DataTableFilterButton/index.native.js +0 -1
  27. package/dist/cjs/components/DataTableFilterChips/FilterChip.cjs +2 -1
  28. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js +4 -1
  29. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  30. package/dist/cjs/components/DataTableFilters/index.cjs +0 -1
  31. package/dist/cjs/components/DataTableFilters/index.native.js +0 -1
  32. package/dist/cjs/components/DataTableGrouping/index.cjs +0 -8
  33. package/dist/cjs/components/DataTableGrouping/index.native.js +0 -8
  34. package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
  35. package/dist/cjs/components/DataTablePagination/index.cjs +29 -13
  36. package/dist/cjs/components/DataTablePagination/index.native.js +30 -14
  37. package/dist/cjs/components/DataTablePagination/index.native.js.map +1 -1
  38. package/dist/cjs/components/DataTableSearch/index.cjs +0 -3
  39. package/dist/cjs/components/DataTableSearch/index.native.js +0 -3
  40. package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
  41. package/dist/cjs/components/DataTableToolbar/index.cjs +0 -1
  42. package/dist/cjs/components/DataTableToolbar/index.native.js +0 -1
  43. package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
  44. package/dist/cjs/components/DataTableViewOptions/index.cjs +0 -5
  45. package/dist/cjs/components/DataTableViewOptions/index.native.js +0 -5
  46. package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
  47. package/dist/cjs/components/FilterManager.cjs +0 -1
  48. package/dist/cjs/components/FilterManager.native.js +0 -1
  49. package/dist/cjs/components/FilterManager.native.js.map +1 -1
  50. package/dist/cjs/components/FilterOperatorValueEditor/index.cjs +2 -2
  51. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js +2 -2
  52. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  53. package/dist/cjs/components/TableInput/index.cjs +2 -1
  54. package/dist/cjs/components/TableInput/index.native.js +4 -2
  55. package/dist/cjs/components/TableInput/index.native.js.map +1 -1
  56. package/dist/cjs/hooks/useDataTable.cjs +24 -8
  57. package/dist/cjs/hooks/useDataTable.native.js +28 -8
  58. package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
  59. package/dist/cjs/index.cjs +12 -0
  60. package/dist/cjs/index.native.js +12 -0
  61. package/dist/cjs/index.native.js.map +1 -1
  62. package/dist/cjs/shared/devWarn.cjs +70 -0
  63. package/dist/cjs/shared/devWarn.native.js +84 -0
  64. package/dist/cjs/shared/devWarn.native.js.map +1 -0
  65. package/dist/cjs/utils/columnAlign.cjs +4 -1
  66. package/dist/cjs/utils/columnAlign.native.js +4 -1
  67. package/dist/cjs/utils/columnAlign.native.js.map +1 -1
  68. package/dist/cjs/utils/filterFields.cjs +5 -0
  69. package/dist/cjs/utils/filterFields.native.js +5 -0
  70. package/dist/cjs/utils/filterFields.native.js.map +1 -1
  71. package/dist/cjs/utils/filterUtils.cjs +30 -0
  72. package/dist/cjs/utils/filterUtils.native.js +50 -0
  73. package/dist/cjs/utils/filterUtils.native.js.map +1 -1
  74. package/dist/cjs/utils/money.cjs +137 -0
  75. package/dist/cjs/utils/money.native.js +165 -0
  76. package/dist/cjs/utils/money.native.js.map +1 -0
  77. package/dist/cjs/utils/rowAccumulator.cjs +48 -0
  78. package/dist/cjs/utils/rowAccumulator.native.js +51 -0
  79. package/dist/cjs/utils/rowAccumulator.native.js.map +1 -0
  80. package/dist/esm/components/ColumnHeaderFilter/index.mjs +78 -42
  81. package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
  82. package/dist/esm/components/ColumnHeaderFilter/index.native.js +101 -55
  83. package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
  84. package/dist/esm/components/DataTable/DataTableCardControls.mjs +0 -1
  85. package/dist/esm/components/DataTable/DataTableCardControls.mjs.map +1 -1
  86. package/dist/esm/components/DataTable/DataTableCardControls.native.js +0 -1
  87. package/dist/esm/components/DataTable/DataTableCardControls.native.js.map +1 -1
  88. package/dist/esm/components/DataTable/DataTableMobileCards.mjs +99 -34
  89. package/dist/esm/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  90. package/dist/esm/components/DataTable/DataTableMobileCards.native.js +138 -39
  91. package/dist/esm/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  92. package/dist/esm/components/DataTable/DataTableRoot.mjs +33 -6
  93. package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
  94. package/dist/esm/components/DataTable/DataTableRoot.native.js +29 -4
  95. package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
  96. package/dist/esm/components/DataTable/DataTableStateContext.mjs.map +1 -1
  97. package/dist/esm/components/DataTable/DataTableStateContext.native.js.map +1 -1
  98. package/dist/esm/components/DataTable/index.native.js +60 -94
  99. package/dist/esm/components/DataTable/index.native.js.map +1 -1
  100. package/dist/esm/components/DataTableBulkActions/index.mjs +0 -4
  101. package/dist/esm/components/DataTableBulkActions/index.mjs.map +1 -1
  102. package/dist/esm/components/DataTableBulkActions/index.native.js +0 -4
  103. package/dist/esm/components/DataTableBulkActions/index.native.js.map +1 -1
  104. package/dist/esm/components/DataTableCell/index.mjs +17 -2
  105. package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
  106. package/dist/esm/components/DataTableCell/index.native.js +17 -2
  107. package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
  108. package/dist/esm/components/DataTableDateFilter/index.mjs +0 -7
  109. package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
  110. package/dist/esm/components/DataTableDateFilter/index.native.js +0 -7
  111. package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
  112. package/dist/esm/components/DataTableFilterButton/index.mjs +0 -1
  113. package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
  114. package/dist/esm/components/DataTableFilterButton/index.native.js +0 -1
  115. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs +3 -2
  116. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs.map +1 -1
  117. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js +5 -2
  118. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  119. package/dist/esm/components/DataTableFilters/index.mjs +0 -1
  120. package/dist/esm/components/DataTableFilters/index.mjs.map +1 -1
  121. package/dist/esm/components/DataTableFilters/index.native.js +0 -1
  122. package/dist/esm/components/DataTableGrouping/index.mjs +0 -8
  123. package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
  124. package/dist/esm/components/DataTableGrouping/index.native.js +0 -8
  125. package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
  126. package/dist/esm/components/DataTablePagination/index.mjs +30 -14
  127. package/dist/esm/components/DataTablePagination/index.mjs.map +1 -1
  128. package/dist/esm/components/DataTablePagination/index.native.js +31 -15
  129. package/dist/esm/components/DataTablePagination/index.native.js.map +1 -1
  130. package/dist/esm/components/DataTableSearch/index.mjs +0 -3
  131. package/dist/esm/components/DataTableSearch/index.mjs.map +1 -1
  132. package/dist/esm/components/DataTableSearch/index.native.js +0 -3
  133. package/dist/esm/components/DataTableSearch/index.native.js.map +1 -1
  134. package/dist/esm/components/DataTableToolbar/index.mjs +0 -1
  135. package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
  136. package/dist/esm/components/DataTableToolbar/index.native.js +0 -1
  137. package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
  138. package/dist/esm/components/DataTableViewOptions/index.mjs +0 -5
  139. package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
  140. package/dist/esm/components/DataTableViewOptions/index.native.js +0 -5
  141. package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
  142. package/dist/esm/components/FilterManager.mjs +0 -1
  143. package/dist/esm/components/FilterManager.mjs.map +1 -1
  144. package/dist/esm/components/FilterManager.native.js +0 -1
  145. package/dist/esm/components/FilterManager.native.js.map +1 -1
  146. package/dist/esm/components/FilterOperatorValueEditor/index.mjs +2 -2
  147. package/dist/esm/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  148. package/dist/esm/components/FilterOperatorValueEditor/index.native.js +2 -2
  149. package/dist/esm/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  150. package/dist/esm/components/TableInput/index.mjs +3 -2
  151. package/dist/esm/components/TableInput/index.mjs.map +1 -1
  152. package/dist/esm/components/TableInput/index.native.js +5 -3
  153. package/dist/esm/components/TableInput/index.native.js.map +1 -1
  154. package/dist/esm/hooks/useDataTable.mjs +24 -8
  155. package/dist/esm/hooks/useDataTable.mjs.map +1 -1
  156. package/dist/esm/hooks/useDataTable.native.js +28 -8
  157. package/dist/esm/hooks/useDataTable.native.js.map +1 -1
  158. package/dist/esm/index.mjs +3 -1
  159. package/dist/esm/index.mjs.map +1 -1
  160. package/dist/esm/index.native.js +3 -1
  161. package/dist/esm/index.native.js.map +1 -1
  162. package/dist/esm/shared/devWarn.mjs +43 -0
  163. package/dist/esm/shared/devWarn.mjs.map +1 -0
  164. package/dist/esm/shared/devWarn.native.js +54 -0
  165. package/dist/esm/shared/devWarn.native.js.map +1 -0
  166. package/dist/esm/utils/columnAlign.mjs +4 -1
  167. package/dist/esm/utils/columnAlign.mjs.map +1 -1
  168. package/dist/esm/utils/columnAlign.native.js +4 -1
  169. package/dist/esm/utils/columnAlign.native.js.map +1 -1
  170. package/dist/esm/utils/filterFields.mjs +5 -0
  171. package/dist/esm/utils/filterFields.mjs.map +1 -1
  172. package/dist/esm/utils/filterFields.native.js +5 -0
  173. package/dist/esm/utils/filterFields.native.js.map +1 -1
  174. package/dist/esm/utils/filterUtils.mjs +30 -0
  175. package/dist/esm/utils/filterUtils.mjs.map +1 -1
  176. package/dist/esm/utils/filterUtils.native.js +50 -0
  177. package/dist/esm/utils/filterUtils.native.js.map +1 -1
  178. package/dist/esm/utils/money.mjs +104 -0
  179. package/dist/esm/utils/money.mjs.map +1 -0
  180. package/dist/esm/utils/money.native.js +129 -0
  181. package/dist/esm/utils/money.native.js.map +1 -0
  182. package/dist/esm/utils/rowAccumulator.mjs +23 -0
  183. package/dist/esm/utils/rowAccumulator.mjs.map +1 -0
  184. package/dist/esm/utils/rowAccumulator.native.js +23 -0
  185. package/dist/esm/utils/rowAccumulator.native.js.map +1 -0
  186. package/dist/jsx/components/ColumnHeaderFilter/index.mjs +78 -42
  187. package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
  188. package/dist/jsx/components/ColumnHeaderFilter/index.native.js +97 -51
  189. package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
  190. package/dist/jsx/components/DataTable/DataTableCardControls.mjs +0 -1
  191. package/dist/jsx/components/DataTable/DataTableCardControls.mjs.map +1 -1
  192. package/dist/jsx/components/DataTable/DataTableCardControls.native.js +0 -1
  193. package/dist/jsx/components/DataTable/DataTableCardControls.native.js.map +1 -1
  194. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs +99 -34
  195. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  196. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js +139 -38
  197. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  198. package/dist/jsx/components/DataTable/DataTableRoot.mjs +33 -6
  199. package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
  200. package/dist/jsx/components/DataTable/DataTableRoot.native.js +29 -4
  201. package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
  202. package/dist/jsx/components/DataTable/DataTableStateContext.mjs.map +1 -1
  203. package/dist/jsx/components/DataTable/DataTableStateContext.native.js.map +1 -1
  204. package/dist/jsx/components/DataTable/index.native.js +59 -93
  205. package/dist/jsx/components/DataTable/index.native.js.map +1 -1
  206. package/dist/jsx/components/DataTableBulkActions/index.mjs +0 -4
  207. package/dist/jsx/components/DataTableBulkActions/index.mjs.map +1 -1
  208. package/dist/jsx/components/DataTableBulkActions/index.native.js +0 -4
  209. package/dist/jsx/components/DataTableBulkActions/index.native.js.map +1 -1
  210. package/dist/jsx/components/DataTableCell/index.mjs +17 -2
  211. package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
  212. package/dist/jsx/components/DataTableCell/index.native.js +16 -1
  213. package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
  214. package/dist/jsx/components/DataTableDateFilter/index.mjs +0 -7
  215. package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
  216. package/dist/jsx/components/DataTableDateFilter/index.native.js +0 -7
  217. package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
  218. package/dist/jsx/components/DataTableFilterButton/index.mjs +0 -1
  219. package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
  220. package/dist/jsx/components/DataTableFilterButton/index.native.js +0 -1
  221. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs +3 -2
  222. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs.map +1 -1
  223. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js +4 -1
  224. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  225. package/dist/jsx/components/DataTableFilters/index.mjs +0 -1
  226. package/dist/jsx/components/DataTableFilters/index.mjs.map +1 -1
  227. package/dist/jsx/components/DataTableFilters/index.native.js +0 -1
  228. package/dist/jsx/components/DataTableGrouping/index.mjs +0 -8
  229. package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
  230. package/dist/jsx/components/DataTableGrouping/index.native.js +0 -8
  231. package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
  232. package/dist/jsx/components/DataTablePagination/index.mjs +30 -14
  233. package/dist/jsx/components/DataTablePagination/index.mjs.map +1 -1
  234. package/dist/jsx/components/DataTablePagination/index.native.js +30 -14
  235. package/dist/jsx/components/DataTablePagination/index.native.js.map +1 -1
  236. package/dist/jsx/components/DataTableSearch/index.mjs +0 -3
  237. package/dist/jsx/components/DataTableSearch/index.mjs.map +1 -1
  238. package/dist/jsx/components/DataTableSearch/index.native.js +0 -3
  239. package/dist/jsx/components/DataTableSearch/index.native.js.map +1 -1
  240. package/dist/jsx/components/DataTableToolbar/index.mjs +0 -1
  241. package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
  242. package/dist/jsx/components/DataTableToolbar/index.native.js +0 -1
  243. package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
  244. package/dist/jsx/components/DataTableViewOptions/index.mjs +0 -5
  245. package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
  246. package/dist/jsx/components/DataTableViewOptions/index.native.js +0 -5
  247. package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
  248. package/dist/jsx/components/FilterManager.mjs +0 -1
  249. package/dist/jsx/components/FilterManager.mjs.map +1 -1
  250. package/dist/jsx/components/FilterManager.native.js +0 -1
  251. package/dist/jsx/components/FilterManager.native.js.map +1 -1
  252. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs +2 -2
  253. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  254. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js +2 -2
  255. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  256. package/dist/jsx/components/TableInput/index.mjs +3 -2
  257. package/dist/jsx/components/TableInput/index.mjs.map +1 -1
  258. package/dist/jsx/components/TableInput/index.native.js +4 -2
  259. package/dist/jsx/components/TableInput/index.native.js.map +1 -1
  260. package/dist/jsx/hooks/useDataTable.mjs +24 -8
  261. package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
  262. package/dist/jsx/hooks/useDataTable.native.js +28 -8
  263. package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
  264. package/dist/jsx/index.js +3 -1
  265. package/dist/jsx/index.js.map +1 -1
  266. package/dist/jsx/index.mjs +3 -1
  267. package/dist/jsx/index.mjs.map +1 -1
  268. package/dist/jsx/index.native.js +12 -0
  269. package/dist/jsx/index.native.js.map +1 -1
  270. package/dist/jsx/shared/devWarn.mjs +43 -0
  271. package/dist/jsx/shared/devWarn.mjs.map +1 -0
  272. package/dist/jsx/shared/devWarn.native.js +84 -0
  273. package/dist/jsx/shared/devWarn.native.js.map +1 -0
  274. package/dist/jsx/utils/columnAlign.mjs +4 -1
  275. package/dist/jsx/utils/columnAlign.mjs.map +1 -1
  276. package/dist/jsx/utils/columnAlign.native.js +4 -1
  277. package/dist/jsx/utils/columnAlign.native.js.map +1 -1
  278. package/dist/jsx/utils/filterFields.mjs +5 -0
  279. package/dist/jsx/utils/filterFields.mjs.map +1 -1
  280. package/dist/jsx/utils/filterFields.native.js +5 -0
  281. package/dist/jsx/utils/filterFields.native.js.map +1 -1
  282. package/dist/jsx/utils/filterUtils.mjs +30 -0
  283. package/dist/jsx/utils/filterUtils.mjs.map +1 -1
  284. package/dist/jsx/utils/filterUtils.native.js +50 -0
  285. package/dist/jsx/utils/filterUtils.native.js.map +1 -1
  286. package/dist/jsx/utils/money.mjs +104 -0
  287. package/dist/jsx/utils/money.mjs.map +1 -0
  288. package/dist/jsx/utils/money.native.js +165 -0
  289. package/dist/jsx/utils/money.native.js.map +1 -0
  290. package/dist/jsx/utils/rowAccumulator.mjs +23 -0
  291. package/dist/jsx/utils/rowAccumulator.mjs.map +1 -0
  292. package/dist/jsx/utils/rowAccumulator.native.js +51 -0
  293. package/dist/jsx/utils/rowAccumulator.native.js.map +1 -0
  294. package/package.json +12 -12
  295. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.spec.tsx +142 -7
  296. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.stories.tsx +46 -9
  297. package/src/components/ColumnHeaderFilter/index.tsx +104 -47
  298. package/src/components/DataTable/DataTable.spec.tsx +5 -3
  299. package/src/components/DataTable/DataTable.stories.tsx +186 -14
  300. package/src/components/DataTable/DataTableCardControls.tsx +11 -13
  301. package/src/components/DataTable/DataTableMobileCards.tsx +162 -39
  302. package/src/components/DataTable/DataTableRoot.tsx +40 -14
  303. package/src/components/DataTable/DataTableStateContext.ts +7 -0
  304. package/src/components/DataTable/cardLayout.spec.tsx +19 -8
  305. package/src/components/DataTable/columnWidthLayout.spec.tsx +195 -0
  306. package/src/components/DataTable/dataTableMobileCards.spec.tsx +50 -2
  307. package/src/components/DataTable/headerSorting.spec.tsx +25 -0
  308. package/src/components/DataTable/index.native.tsx +80 -124
  309. package/src/components/DataTable/moneyColumn.spec.tsx +151 -0
  310. package/src/components/DataTable/nativeCardParity.spec.tsx +95 -0
  311. package/src/components/DataTable/rowAccumulator.spec.tsx +171 -0
  312. package/src/components/DataTableBulkActions/index.tsx +0 -4
  313. package/src/components/DataTableCell/index.tsx +28 -2
  314. package/src/components/DataTableColumnPinning/DataTableColumnPinning.stories.tsx +0 -4
  315. package/src/components/DataTableDateFilter/index.tsx +0 -7
  316. package/src/components/DataTableFilterButton/index.tsx +1 -1
  317. package/src/components/DataTableFilterChips/FilterChip.spec.tsx +6 -0
  318. package/src/components/DataTableFilterChips/FilterChip.tsx +3 -2
  319. package/src/components/DataTableFilters/index.tsx +1 -1
  320. package/src/components/DataTableGrouping/DataTableGrouping.stories.tsx +0 -4
  321. package/src/components/DataTableGrouping/index.tsx +1 -13
  322. package/src/components/DataTablePagination/DataTablePagination.stories.tsx +14 -1
  323. package/src/components/DataTablePagination/DataTablePagination.width.spec.tsx +51 -0
  324. package/src/components/DataTablePagination/index.tsx +60 -16
  325. package/src/components/DataTableSearch/index.tsx +2 -3
  326. package/src/components/DataTableToolbar/DataTableToolbar.stories.tsx +2 -4
  327. package/src/components/DataTableToolbar/index.tsx +1 -5
  328. package/src/components/DataTableViewOptions/index.tsx +2 -13
  329. package/src/components/FilterManager.tsx +1 -3
  330. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.spec.tsx +1 -1
  331. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.stories.tsx +1 -0
  332. package/src/components/FilterOperatorValueEditor/index.tsx +10 -2
  333. package/src/components/TableInput/index.native.tsx +3 -2
  334. package/src/components/TableInput/index.tsx +3 -2
  335. package/src/hooks/useDataTable.ts +43 -7
  336. package/src/index.ts +13 -0
  337. package/src/shared/devWarn.ts +97 -0
  338. package/src/types.ts +71 -2
  339. package/src/utils/columnAlign.ts +9 -1
  340. package/src/utils/filterFields.ts +23 -1
  341. package/src/utils/filterUtils.ts +50 -1
  342. package/src/utils/money.spec.ts +156 -0
  343. package/src/utils/money.ts +202 -0
  344. package/src/utils/rowAccumulator.ts +136 -0
  345. package/types/components/ColumnHeaderFilter/index.d.ts +9 -2
  346. package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
  347. package/types/components/DataTable/DataTableCardControls.d.ts.map +1 -1
  348. package/types/components/DataTable/DataTableMobileCards.d.ts +42 -8
  349. package/types/components/DataTable/DataTableMobileCards.d.ts.map +1 -1
  350. package/types/components/DataTable/DataTableRoot.d.ts +1 -1
  351. package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
  352. package/types/components/DataTable/DataTableStateContext.d.ts +7 -0
  353. package/types/components/DataTable/DataTableStateContext.d.ts.map +1 -1
  354. package/types/components/DataTable/index.native.d.ts +1 -1
  355. package/types/components/DataTable/index.native.d.ts.map +1 -1
  356. package/types/components/DataTableBulkActions/index.d.ts.map +1 -1
  357. package/types/components/DataTableCell/index.d.ts.map +1 -1
  358. package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
  359. package/types/components/DataTableFilterChips/FilterChip.d.ts.map +1 -1
  360. package/types/components/DataTableGrouping/index.d.ts.map +1 -1
  361. package/types/components/DataTablePagination/index.d.ts.map +1 -1
  362. package/types/components/DataTableSearch/index.d.ts.map +1 -1
  363. package/types/components/DataTableToolbar/index.d.ts.map +1 -1
  364. package/types/components/DataTableViewOptions/index.d.ts.map +1 -1
  365. package/types/components/FilterManager.d.ts.map +1 -1
  366. package/types/components/FilterOperatorValueEditor/index.d.ts.map +1 -1
  367. package/types/components/TableInput/index.d.ts.map +1 -1
  368. package/types/components/TableInput/index.native.d.ts.map +1 -1
  369. package/types/hooks/useDataTable.d.ts +1 -1
  370. package/types/hooks/useDataTable.d.ts.map +1 -1
  371. package/types/index.d.ts +3 -0
  372. package/types/index.d.ts.map +1 -1
  373. package/types/shared/devWarn.d.ts +50 -0
  374. package/types/shared/devWarn.d.ts.map +1 -0
  375. package/types/types.d.ts +71 -3
  376. package/types/types.d.ts.map +1 -1
  377. package/types/utils/columnAlign.d.ts.map +1 -1
  378. package/types/utils/filterFields.d.ts.map +1 -1
  379. package/types/utils/filterUtils.d.ts +1 -1
  380. package/types/utils/filterUtils.d.ts.map +1 -1
  381. package/types/utils/money.d.ts +94 -0
  382. package/types/utils/money.d.ts.map +1 -0
  383. package/types/utils/rowAccumulator.d.ts +107 -0
  384. package/types/utils/rowAccumulator.d.ts.map +1 -0
@@ -16,8 +16,11 @@ import {
16
16
  DataTableFilters,
17
17
  DataTablePagination,
18
18
  DataTableToolbar,
19
+ formatMoney,
20
+ type RowAccumulator,
21
+ sumMoneyByCurrency,
19
22
  } from "../../index";
20
- import { DataTable } from "./index";
23
+ import { DataTable, useDataTableState } from "./index";
21
24
 
22
25
  const meta: Meta<typeof DataTable> = {
23
26
  title: "Table/DataTable",
@@ -204,11 +207,7 @@ const columns: DataTableColumn<User>[] = [
204
207
  columnHelper.display({
205
208
  id: "actions",
206
209
  header: "Actions",
207
- cell: (_info) => (
208
- <Button size="$2" variant="outlined">
209
- Edit
210
- </Button>
211
- ),
210
+ cell: (_info) => <Button size="$2">Edit</Button>,
212
211
  enableSorting: false,
213
212
  enableColumnFilter: false,
214
213
  }) as DataTableColumn<User>,
@@ -321,14 +320,7 @@ const AdvancedTableStory = () => {
321
320
  enableGlobalSearch={true}
322
321
  enableViews={true}
323
322
  renderToolbar={(props) => (
324
- <DataTableToolbar
325
- {...props}
326
- customActions={
327
- <Button size="$3" variant="outlined">
328
- Export CSV
329
- </Button>
330
- }
331
- />
323
+ <DataTableToolbar {...props} customActions={<Button size="$3">Export CSV</Button>} />
332
324
  )}
333
325
  renderFilters={(props) => (
334
326
  <DataTableFilters {...props} availableColumns={columnsWithCounts} maxFilters={5} />
@@ -3090,3 +3082,183 @@ export const CustomCellAlignment: Story = {
3090
3082
  },
3091
3083
  },
3092
3084
  };
3085
+
3086
+ // ---------------------------------------------------------------------------
3087
+ // Running balance (MPO-250) — a column that is a function of every row before
3088
+ // it. The fold runs BEFORE pagination, so page two continues instead of
3089
+ // restarting at zero, and its final value paints a footer total.
3090
+ // ---------------------------------------------------------------------------
3091
+
3092
+ interface Posting extends DataTableData {
3093
+ id: string;
3094
+ date: string;
3095
+ payee: string;
3096
+ /** Cents. Integers here; a real ledger uses the "money" column type. */
3097
+ amount: number;
3098
+ /** Derived by the accumulator — declared so a column can name it. */
3099
+ running?: number;
3100
+ }
3101
+
3102
+ const registerPostings: Posting[] = [
3103
+ { id: "P-01", date: "2026-01-02", payee: "Opening deposit", amount: 250_000 },
3104
+ { id: "P-02", date: "2026-01-04", payee: "Rent", amount: -180_000 },
3105
+ { id: "P-03", date: "2026-01-05", payee: "Grocers", amount: -8_450 },
3106
+ { id: "P-04", date: "2026-01-07", payee: "Payroll", amount: 412_300 },
3107
+ { id: "P-05", date: "2026-01-09", payee: "Utilities", amount: -14_600 },
3108
+ { id: "P-06", date: "2026-01-11", payee: "Coffee roaster", amount: -1_875 },
3109
+ { id: "P-07", date: "2026-01-14", payee: "Refund", amount: 3_200 },
3110
+ { id: "P-08", date: "2026-01-16", payee: "Insurance", amount: -62_000 },
3111
+ { id: "P-09", date: "2026-01-19", payee: "Consulting", amount: 150_000 },
3112
+ { id: "P-10", date: "2026-01-21", payee: "Hardware", amount: -47_990 },
3113
+ { id: "P-11", date: "2026-01-24", payee: "Payroll", amount: 412_300 },
3114
+ { id: "P-12", date: "2026-01-27", payee: "Taxes", amount: -305_000 },
3115
+ ];
3116
+
3117
+ const cents = (value: number | undefined) =>
3118
+ value == null ? "" : formatCurrency(value / 100, { symbol: "$", fractionDigits: "auto" });
3119
+
3120
+ /**
3121
+ * The fold. A module constant, not an inline literal — the table refolds
3122
+ * whenever this identity changes.
3123
+ */
3124
+ const registerBalance: RowAccumulator<Posting, number> = {
3125
+ initial: 0,
3126
+ reduce: (carried, row) => carried + row.amount,
3127
+ derive: (carried) => ({ running: carried }),
3128
+ order: (a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0),
3129
+ total: (carried) => carried,
3130
+ };
3131
+
3132
+ /** Reads the fold's end value off the table state — the total row. */
3133
+ const RegisterTotal = () => {
3134
+ const context = useDataTableState();
3135
+ return <Text fontWeight="700">{cents(context?.computed.foldTotal as number | undefined)}</Text>;
3136
+ };
3137
+
3138
+ const registerColumns: DataTableColumn<Posting>[] = [
3139
+ { id: "date", accessorKey: "date", header: "Date", width: 120 },
3140
+ { id: "payee", accessorKey: "payee", header: "Payee", sortable: true },
3141
+ {
3142
+ id: "amount",
3143
+ accessorKey: "amount",
3144
+ header: "Amount",
3145
+ align: "right",
3146
+ cell: (info) => <Text>{cents(info.getValue() as number)}</Text>,
3147
+ footer: () => <Text fontWeight="700">Total</Text>,
3148
+ },
3149
+ {
3150
+ id: "running",
3151
+ accessorKey: "running",
3152
+ header: "Balance",
3153
+ align: "right",
3154
+ // Not sortable on purpose: sorting a fold column reorders it WITHOUT
3155
+ // refolding, so the figures stop reading down the column as a
3156
+ // progression. The contract is on RowAccumulator.
3157
+ sortable: false,
3158
+ cell: (info) => <Text fontWeight="600">{cents(info.getValue() as number)}</Text>,
3159
+ footer: () => <RegisterTotal />,
3160
+ },
3161
+ ];
3162
+
3163
+ export const RunningBalance: Story = {
3164
+ render: () => (
3165
+ <DataTable
3166
+ data={registerPostings}
3167
+ columns={registerColumns as DataTableColumn<Record<string, any>>[]}
3168
+ rowAccumulator={registerBalance as RowAccumulator<Record<string, any>>}
3169
+ layout="table"
3170
+ columnLayout="auto"
3171
+ enableFiltering={false}
3172
+ enableGlobalSearch={false}
3173
+ initialState={{ pagination: { pageIndex: 0, pageSize: 5 } }}
3174
+ aria-label="Account register with a running balance"
3175
+ />
3176
+ ),
3177
+ parameters: {
3178
+ docs: {
3179
+ description: {
3180
+ story:
3181
+ "A running balance is a FOLD over the rows in a total order, so it has to be computed before the table paginates. Page through this table: the Balance column continues onto page two rather than restarting, because `rowAccumulator` runs once over the whole row set before the row model. Its `total` is read once at the end and painted in the footer through `useDataTableState().computed.foldTotal`. Sorting on Payee reorders rows for display and does NOT refold — the balance stays attached to its own row.",
3182
+ },
3183
+ },
3184
+ },
3185
+ };
3186
+
3187
+ // ---------------------------------------------------------------------------
3188
+ // Money column (MPO-252) — a Currency field is a decimal STRING. It sorts
3189
+ // numerically, filters with the numeric operators, formats from the ROW's own
3190
+ // currency, and totals per currency because two currencies never convert.
3191
+ // ---------------------------------------------------------------------------
3192
+
3193
+ interface Charge extends DataTableData {
3194
+ id: string;
3195
+ vendor: string;
3196
+ amount: string;
3197
+ currency: string;
3198
+ }
3199
+
3200
+ const charges: Charge[] = [
3201
+ { id: "C-1", vendor: "Coffee roaster", amount: "9.00", currency: "USD" },
3202
+ { id: "C-2", vendor: "Bookshop", amount: "10.00", currency: "USD" },
3203
+ { id: "C-3", vendor: "Chai stall", amount: "250.75", currency: "INR" },
3204
+ { id: "C-4", vendor: "Refund", amount: "-455.87", currency: "USD" },
3205
+ { id: "C-5", vendor: "Hosting", amount: "1200.00", currency: "INR" },
3206
+ { id: "C-6", vendor: "Domain", amount: "9.99", currency: "USD" },
3207
+ ];
3208
+
3209
+ /** One figure per currency — the mixed-currency rule, rendered. */
3210
+ const ChargeTotals = () => {
3211
+ const totals = sumMoneyByCurrency(
3212
+ charges,
3213
+ (row) => row.amount,
3214
+ (row) => row.currency,
3215
+ );
3216
+ return (
3217
+ <YStack>
3218
+ {Object.entries(totals).map(([code, total]) => (
3219
+ <Text key={code} fontWeight="700">
3220
+ {formatMoney(total, code)}
3221
+ </Text>
3222
+ ))}
3223
+ </YStack>
3224
+ );
3225
+ };
3226
+
3227
+ const chargeColumns: DataTableColumn<Charge>[] = [
3228
+ { id: "vendor", accessorKey: "vendor", header: "Vendor" },
3229
+ { id: "currency", accessorKey: "currency", header: "Currency" },
3230
+ {
3231
+ id: "amount",
3232
+ accessorKey: "amount",
3233
+ header: "Amount",
3234
+ field: "money",
3235
+ // Safe now: the money type carries an exact decimal comparator, so
3236
+ // "9.00" sorts BELOW "10.00". As a "text" column this was silently wrong.
3237
+ sortable: true,
3238
+ filterable: true,
3239
+ fieldProps: { currencyField: "currency" },
3240
+ footer: () => <ChargeTotals />,
3241
+ },
3242
+ ];
3243
+
3244
+ export const MoneyColumn: Story = {
3245
+ render: () => (
3246
+ <DataTable
3247
+ data={charges}
3248
+ columns={chargeColumns as DataTableColumn<Record<string, any>>[]}
3249
+ layout="table"
3250
+ columnLayout="auto"
3251
+ enablePagination={false}
3252
+ readOnly
3253
+ aria-label="Charges with a money column"
3254
+ />
3255
+ ),
3256
+ parameters: {
3257
+ docs: {
3258
+ description: {
3259
+ story:
3260
+ '`field: "money"` types a column as a decimal STRING rather than as text. Sort on Amount: `9.00` orders below `10.00`, which the text fallback got backwards in silence. The column filter offers `is less than` / `is greater than` / `between` instead of `contains`. Each row formats in its OWN currency (`fieldProps.currencyField`), and the footer totals PER currency — two currencies are two figures and neither converts, because there is no rate in the table.',
3261
+ },
3262
+ },
3263
+ },
3264
+ };
@@ -89,7 +89,6 @@ export function DataTableCardControls({
89
89
  <DropdownMenu.Trigger asChild>
90
90
  <Button
91
91
  size={knobProps.sizeToken}
92
- variant="outlined"
93
92
  icon={<CaretUpDownIcon size={chrome.iconPx} />}
94
93
  aria-label={t("Sort rows")}
95
94
  disabled={disabled}
@@ -134,18 +133,17 @@ export function DataTableCardControls({
134
133
  </DropdownMenu.Content>
135
134
  </DropdownMenu>
136
135
  )}
137
- {enableFiltering &&
138
- availableColumns.length > 0 && (
139
- // DataTableFilters (chrome) has no disabled API — the wrapper is the
140
- // LC-40 carrier and interaction gate for the disabled table.
141
- <View
142
- {...(disabled
143
- ? { ...disabledState.chromeKnobProps, pointerEvents: "none" as const }
144
- : {})}
145
- >
146
- <DataTableFilters compact availableColumns={availableColumns} />
147
- </View>
148
- )}
136
+ {enableFiltering && availableColumns.length > 0 && (
137
+ // DataTableFilters (chrome) has no disabled API — the wrapper is the
138
+ // LC-40 carrier and interaction gate for the disabled table.
139
+ <View
140
+ {...(disabled
141
+ ? { ...disabledState.chromeKnobProps, pointerEvents: "none" as const }
142
+ : {})}
143
+ >
144
+ <DataTableFilters compact availableColumns={availableColumns} />
145
+ </View>
146
+ )}
149
147
  </XStack>
150
148
  );
151
149
  }
@@ -5,14 +5,18 @@
5
5
  * resolved layout is "cards" (below the `$sm` breakpoint with
6
6
  * layout="auto", or forced via layout="cards").
7
7
  *
8
- * Card anatomy (knobs system): `surface` + `cardSurface` fragments own
9
- * the card frame; the first visible column renders as the card title in
10
- * the header row (with selection checkbox / row number / delete), and
11
- * the remaining visible columns render as label/value rows. Column
12
- * visibility and order from table state apply unchanged — cells come
13
- * from `row.getVisibleCells()`. Values render through the same cell
14
- * renderers as the grid, inside `TableCellContext` so fields stay
15
- * chromeless (useIsInTableCell).
8
+ * Card anatomy: the first visible column is the card title in the header
9
+ * row (with selection checkbox / row number / delete). The remaining
10
+ * visible columns are NOT a stack of label/value rows any more — see
11
+ * `classifyCardField`. Column visibility and order from table state apply
12
+ * unchanged — cells come from `row.getVisibleCells()`. Values render
13
+ * through the same cell renderers as the grid, inside `TableCellContext`
14
+ * so fields stay chromeless (useIsInTableCell).
15
+ *
16
+ * The card is FLAT: no border, no elevation. A card list is drawn inside
17
+ * a panel that already has its own frame, and an outlined, shadowed card
18
+ * inside it reads as a box inside a box. The `cardSurface` fill and the
19
+ * gap between cards are what separate one row from the next.
16
20
  */
17
21
 
18
22
  import { TrashIcon } from "@phosphor-icons/react";
@@ -21,10 +25,10 @@ import { Button, Checkbox } from "@multiplatform.one/forms";
21
25
  import { hairline, useResolvedKnobs } from "@multiplatform.one/theme";
22
26
  import type React from "react";
23
27
  import { useCallback } from "react";
24
- import { Text, View, XStack } from "tamagui";
28
+ import { Text, View, VisuallyHidden, XStack } from "tamagui";
25
29
  import { useTranslation } from "react-i18next";
26
30
  import { TableCellContext } from "@multiplatform.one/table-primitives";
27
- import type { DataTableColumn } from "../../types";
31
+ import type { DataTableColumn, DataTableField } from "../../types";
28
32
  import { withInterp } from "../../utils/withInterp";
29
33
  import { rowIntentProps } from "./dataTableChrome";
30
34
 
@@ -34,13 +38,74 @@ import { rowIntentProps } from "./dataTableChrome";
34
38
  * header is a render function or a bare glyph (the liked heart) — without
35
39
  * it a card field row would print the raw column id (`_liked_by`).
36
40
  */
37
- function getColumnLabel(cell: any): string {
41
+ export function getColumnLabel(cell: any): string {
38
42
  const columnDef = cell.column.columnDef as DataTableColumn;
39
43
  const metaLabel = columnDef.meta?.label;
40
44
  if (typeof metaLabel === "string" && metaLabel) return metaLabel;
41
45
  return typeof columnDef.header === "string" ? columnDef.header : columnDef.id || cell.column.id;
42
46
  }
43
47
 
48
+ /** Fields that draw their own control, which names itself and needs a target. */
49
+ const selfNamingFields = new Set<DataTableField>([
50
+ "checkbox",
51
+ "switch",
52
+ "rating",
53
+ "progress",
54
+ "image",
55
+ "signature",
56
+ "fileupload",
57
+ "colorpicker",
58
+ "barcode",
59
+ "geolocation",
60
+ ]);
61
+
62
+ /** Column ids whose value is a state badge. A badge names itself. */
63
+ const indicatorIds = new Set(["status", "priority", "workflow_state", "state"]);
64
+
65
+ const dateLike = /^\d{4}-\d{2}-\d{2}([T ]|$)|^\d{1,2}\/\d{1,2}\/\d{2,4}$/;
66
+ const numberLike = /^[+\-−]?[\d,\s]*\d(\.\d+)?%?$/;
67
+
68
+ export type CardFieldKind = "skip" | "control" | "bare" | "figure";
69
+
70
+ /**
71
+ * Whether a card field prints the column's name, and where it goes.
72
+ *
73
+ * A card is not the grid with its header repeated down the page. In the
74
+ * grid the header is written ONCE for a whole column of values; on a card
75
+ * it is written once per value, so a 12-column table prints 12 labels per
76
+ * record. That is what a label costs here, and most labels do not earn it.
77
+ *
78
+ * skip the raw value is absent. A field with nothing in it is not a
79
+ * fact — "Rejected —" spends a row saying nothing.
80
+ * control a button, a switch, a rating. The control names itself and
81
+ * needs its own tap target, so it keeps a row and takes no label.
82
+ * bare a string that is neither a number nor a date. "DIVIDEND
83
+ * CREDIT" and "Income:Dividends" say what they are; "Payee" and
84
+ * "Account" in front of them are the header printed twice. The
85
+ * name is kept for assistive tech via VisuallyHidden, which
86
+ * costs no layout.
87
+ * figure a number, a date, a boolean. "1,204" alone cannot be read, so
88
+ * these DO keep their label — inline beside the figure, not in a
89
+ * 40%-wide column of its own.
90
+ */
91
+ export function classifyCardField(cell: any): CardFieldKind {
92
+ const def = cell.column.columnDef as DataTableColumn;
93
+ const id = String(cell.column.id ?? "");
94
+ const role = def.meta?.role;
95
+ if (role === "hidden" || role === "skip") return "skip";
96
+ if (role === "actions" || id.startsWith("_") || (def.field && selfNamingFields.has(def.field))) {
97
+ return "control";
98
+ }
99
+ const raw = typeof cell.getValue === "function" ? cell.getValue() : undefined;
100
+ if (raw == null || (typeof raw === "string" && raw.trim() === "")) return "skip";
101
+ if (role === "indicator" || indicatorIds.has(id)) return "bare";
102
+ if (typeof raw === "string") {
103
+ const value = raw.trim();
104
+ return numberLike.test(value) || dateLike.test(value) ? "figure" : "bare";
105
+ }
106
+ return "figure";
107
+ }
108
+
44
109
  export interface DataTableMobileCardsProps<TData> {
45
110
  tableRows: any[];
46
111
  enableRowSelection?: boolean;
@@ -98,6 +163,15 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
98
163
  const { knobProps } = useResolvedKnobs({ component: "DataTable", compact });
99
164
  const tableZebraOn = knobProps.tableZebra === "on";
100
165
 
166
+ const renderCell = useCallback(
167
+ (cell: any, index: number, rowData: TData) => (
168
+ <TableCellContext.Provider value={{ inTableCell: true, isHeader: false }}>
169
+ {renderCellContent(cell, index, rowData)}
170
+ </TableCellContext.Provider>
171
+ ),
172
+ [renderCellContent],
173
+ );
174
+
101
175
  const renderMobileCard = useCallback(
102
176
  (row: any, index: number) => {
103
177
  const rowData = row.original as TData;
@@ -105,14 +179,22 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
105
179
  const [titleCell, ...detailCells] = visibleCells;
106
180
  const showDelete = showDeleteRow && !readOnly;
107
181
 
182
+ const bare: any[] = [];
183
+ const figures: any[] = [];
184
+ const controls: any[] = [];
185
+ for (const cell of detailCells) {
186
+ const kind = classifyCardField(cell);
187
+ if (kind === "bare") bare.push(cell);
188
+ else if (kind === "figure") figures.push(cell);
189
+ else if (kind === "control") controls.push(cell);
190
+ }
191
+ const hasBody = bare.length > 0 || figures.length > 0 || controls.length > 0;
192
+
108
193
  return (
109
194
  <View
110
195
  key={`${row.id}-${index}`}
111
196
  testID="data-table-card"
112
- {...knobProps.surface}
113
197
  {...knobProps.cardSurface}
114
- elevation={knobProps.elevation}
115
- borderColor="$color6"
116
198
  {...(tableZebraOn && index % 2 === 1 ? { backgroundColor: "$color2" } : {})}
117
199
  {...({
118
200
  "data-table-zebra": tableZebraOn ? (index % 2 === 0 ? "even" : "odd") : "off",
@@ -124,7 +206,7 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
124
206
  <XStack
125
207
  alignItems="center"
126
208
  gap="$2"
127
- {...(detailCells.length > 0
209
+ {...(hasBody
128
210
  ? {
129
211
  paddingBottom: "$2",
130
212
  marginBottom: "$2",
@@ -156,11 +238,10 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
156
238
  flex={1}
157
239
  minWidth={0}
158
240
  aria-label={getColumnLabel(titleCell)}
241
+ accessibilityLabel={getColumnLabel(titleCell)}
159
242
  {...({ "data-card-slot": "title" } as any)}
160
243
  >
161
- <TableCellContext.Provider value={{ inTableCell: true, isHeader: false }}>
162
- {renderCellContent(titleCell, index, rowData)}
163
- </TableCellContext.Provider>
244
+ {renderCell(titleCell, index, rowData)}
164
245
  </View>
165
246
  ) : (
166
247
  <View flex={1} />
@@ -185,29 +266,71 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
185
266
  )}
186
267
  </XStack>
187
268
 
188
- {/* Field rows: remaining visible columns as label/value pairs */}
189
- {detailCells.map((cell: any) => (
190
- <View
191
- key={cell.id}
192
- flexDirection="row"
269
+ {/* Self-naming values, wrapped into one flow. No printed labels:
270
+ the name goes to assistive tech only, at no layout cost. */}
271
+ {bare.length > 0 ? (
272
+ <XStack
273
+ flexWrap="wrap"
193
274
  alignItems="center"
194
- paddingVertical="$1.5"
195
275
  gap="$2"
276
+ {...({ "data-card-slot": "meta" } as any)}
196
277
  >
197
- <Text
198
- fontSize={knobProps.sizeToken}
199
- color="$color10"
200
- fontWeight="500"
201
- width="40%"
202
- flexShrink={0}
203
- >
204
- {getColumnLabel(cell)}
205
- </Text>
206
- <View flex={1} minWidth={0}>
207
- <TableCellContext.Provider value={{ inTableCell: true, isHeader: false }}>
208
- {renderCellContent(cell, index, rowData)}
209
- </TableCellContext.Provider>
210
- </View>
278
+ {bare.map((cell: any, i: number) => (
279
+ <XStack key={cell.id} alignItems="center" gap="$2" flexShrink={1} minWidth={0}>
280
+ <VisuallyHidden>{`${getColumnLabel(cell)}: `}</VisuallyHidden>
281
+ <View flexShrink={1} minWidth={0}>
282
+ {renderCell(cell, index, rowData)}
283
+ </View>
284
+ {/* The separator TRAILS its value, so a line that wraps
285
+ starts with content instead of a stray dot. */}
286
+ {i < bare.length - 1 ? (
287
+ <Text
288
+ fontSize={knobProps.sizeToken}
289
+ color="$color8"
290
+ aria-hidden
291
+ accessibilityElementsHidden
292
+ importantForAccessibility="no-hide-descendants"
293
+ >
294
+ ·
295
+ </Text>
296
+ ) : null}
297
+ </XStack>
298
+ ))}
299
+ </XStack>
300
+ ) : null}
301
+
302
+ {/* Figures keep their name, inline beside the value. */}
303
+ {figures.length > 0 ? (
304
+ <XStack
305
+ flexWrap="wrap"
306
+ alignItems="center"
307
+ gap="$3"
308
+ paddingTop={bare.length > 0 ? "$1.5" : 0}
309
+ {...({ "data-card-slot": "figure" } as any)}
310
+ >
311
+ {figures.map((cell: any) => (
312
+ <XStack key={cell.id} alignItems="center" gap="$1.5" flexShrink={1} minWidth={0}>
313
+ <Text fontSize={knobProps.sizeToken} color="$color10" fontWeight="500">
314
+ {getColumnLabel(cell)}
315
+ </Text>
316
+ <View flexShrink={1} minWidth={0}>
317
+ {renderCell(cell, index, rowData)}
318
+ </View>
319
+ </XStack>
320
+ ))}
321
+ </XStack>
322
+ ) : null}
323
+
324
+ {/* Controls keep a row of their own — they are tap targets. */}
325
+ {controls.map((cell: any) => (
326
+ <View
327
+ key={cell.id}
328
+ paddingTop="$2"
329
+ minWidth={0}
330
+ {...({ "data-card-slot": "control" } as any)}
331
+ >
332
+ <VisuallyHidden>{`${getColumnLabel(cell)}: `}</VisuallyHidden>
333
+ {renderCell(cell, index, rowData)}
211
334
  </View>
212
335
  ))}
213
336
  </View>
@@ -221,7 +344,7 @@ export function DataTableMobileCards<TData extends Record<string, any>>({
221
344
  disabled,
222
345
  dataLength,
223
346
  minRows,
224
- renderCellContent,
347
+ renderCell,
225
348
  onDeleteRow,
226
349
  compact,
227
350
  knobProps,
@@ -62,6 +62,7 @@ import { DataTableDocumentList } from "./DataTableDocumentList";
62
62
  import { DataTableVirtualized } from "./DataTableVirtualized";
63
63
  import { dataTableChrome, resolveDataTableIntent, rowIntentProps } from "./dataTableChrome";
64
64
  import { tableCellKeyboardProps, tableRowStateProps } from "./rowStateChrome";
65
+ import { warnColumnWidthIgnored } from "../../shared/devWarn";
65
66
  import { alignToFlex, getDefaultColumnAlign } from "../../utils/columnAlign";
66
67
  import { mapFieldToFilterType } from "../../utils/filterFields";
67
68
  import { INFINITE_TRIGGER_ROWS } from "../../utils/paginationDefaults";
@@ -125,6 +126,7 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
125
126
  pageSizeOptions,
126
127
  paginationMode = "pages",
127
128
  loadPage,
129
+ rowAccumulator,
128
130
  enableColumnVisibility = true,
129
131
  enableColumnOrdering = false,
130
132
  enableColumnResizing = false,
@@ -176,6 +178,7 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
176
178
  "aria-describedby": ariaDescribedBy,
177
179
  ...props
178
180
  }: DataTableRootProps<TData>) {
181
+ warnColumnWidthIgnored({ columnLayout, enableColumnResizing, columns });
179
182
  const { t } = useTranslation();
180
183
  const { sm } = useMedia();
181
184
  // Resolved responsive layout: cards below `$sm` (W11 compact class) unless
@@ -224,6 +227,7 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
224
227
  enablePagination,
225
228
  paginationMode,
226
229
  loadPage,
230
+ rowAccumulator,
227
231
  enableColumnVisibility,
228
232
  enableColumnOrdering,
229
233
  enableColumnResizing,
@@ -1670,22 +1674,21 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
1670
1674
  {sortDirection === "asc" && (
1671
1675
  <CaretDownIcon
1672
1676
  size={chrome.iconPx}
1673
- color={
1674
- sortDirection ? "var(--color10)" : "var(--color8)"
1675
- }
1677
+ color="var(--color11)"
1676
1678
  />
1677
1679
  )}
1678
1680
  {sortDirection === "desc" && (
1679
1681
  <CaretDownIcon
1680
1682
  size={chrome.iconPx}
1681
- color={
1682
- sortDirection ? "var(--color10)" : "var(--color8)"
1683
- }
1683
+ color="var(--color11)"
1684
1684
  style={{ transform: "rotate(180deg)" }}
1685
1685
  />
1686
1686
  )}
1687
1687
  {sortDirection === false && (
1688
- <CaretUpDownIcon size={chrome.iconPx} color="$color8" />
1688
+ <CaretUpDownIcon
1689
+ size={chrome.iconPx}
1690
+ color="var(--color11)"
1691
+ />
1689
1692
  )}
1690
1693
  </View>
1691
1694
  </Tooltip>
@@ -2082,13 +2085,36 @@ export function DataTableRoot<TData extends Record<string, any> = Record<string,
2082
2085
  <Table.Foot>
2083
2086
  {footerGroups.map((footerGroup: any) => (
2084
2087
  <Table.Row key={footerGroup.id}>
2085
- {footerGroup.headers.map((header: any) => (
2086
- <Table.Cell key={header.id}>
2087
- {header.isPlaceholder
2088
- ? null
2089
- : flexRender(header.column.columnDef.footer, header.getContext())}
2090
- </Table.Cell>
2091
- ))}
2088
+ {footerGroup.headers.map((header: any) => {
2089
+ const columnAlign = resolveColumnAlign({
2090
+ ...(header.column.columnDef as DataTableColumn),
2091
+ id: header.column.id,
2092
+ });
2093
+ return (
2094
+ <Table.Cell
2095
+ key={header.id}
2096
+ justifyContent={alignToFlex(columnAlign)}
2097
+ data-align={columnAlign}
2098
+ >
2099
+ {header.isPlaceholder ? null : (
2100
+ <View
2101
+ width="100%"
2102
+ minWidth={0}
2103
+ flexDirection="row"
2104
+ alignItems="center"
2105
+ justifyContent={alignToFlex(columnAlign)}
2106
+ data-cell-align={columnAlign}
2107
+ style={isWeb ? { textAlign: columnAlign } : undefined}
2108
+ >
2109
+ {flexRender(
2110
+ header.column.columnDef.footer,
2111
+ header.getContext(),
2112
+ )}
2113
+ </View>
2114
+ )}
2115
+ </Table.Cell>
2116
+ );
2117
+ })}
2092
2118
  </Table.Row>
2093
2119
  ))}
2094
2120
  </Table.Foot>
@@ -62,6 +62,13 @@ export interface DataTableStateContextValue<TData = any> {
62
62
  totalRows: number;
63
63
  hasActiveFilters: boolean;
64
64
  activeFilterCount: number;
65
+ /**
66
+ * The row accumulator's `total(finalAccumulator, rowCount)` — the fold
67
+ * read once at the end (MPO-250). A column's TanStack `footer` renderer
68
+ * reads it from here to paint a total row; the table already renders a
69
+ * footer whenever any column defines one.
70
+ */
71
+ foldTotal?: unknown;
65
72
  [key: string]: any;
66
73
  };
67
74
  }