@multiplatform.one/table 7.7.4 → 7.8.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 (359) 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/DataTableRoot.cjs +33 -6
  8. package/dist/cjs/components/DataTable/DataTableRoot.native.js +29 -4
  9. package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
  10. package/dist/cjs/components/DataTable/DataTableStateContext.native.js.map +1 -1
  11. package/dist/cjs/components/DataTableBulkActions/index.cjs +0 -4
  12. package/dist/cjs/components/DataTableBulkActions/index.native.js +0 -4
  13. package/dist/cjs/components/DataTableBulkActions/index.native.js.map +1 -1
  14. package/dist/cjs/components/DataTableCell/index.cjs +16 -1
  15. package/dist/cjs/components/DataTableCell/index.native.js +16 -1
  16. package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
  17. package/dist/cjs/components/DataTableDateFilter/index.cjs +0 -7
  18. package/dist/cjs/components/DataTableDateFilter/index.native.js +0 -7
  19. package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
  20. package/dist/cjs/components/DataTableFilterButton/index.cjs +0 -1
  21. package/dist/cjs/components/DataTableFilterButton/index.native.js +0 -1
  22. package/dist/cjs/components/DataTableFilterChips/FilterChip.cjs +2 -1
  23. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js +4 -1
  24. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  25. package/dist/cjs/components/DataTableFilters/index.cjs +0 -1
  26. package/dist/cjs/components/DataTableFilters/index.native.js +0 -1
  27. package/dist/cjs/components/DataTableGrouping/index.cjs +0 -8
  28. package/dist/cjs/components/DataTableGrouping/index.native.js +0 -8
  29. package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
  30. package/dist/cjs/components/DataTablePagination/index.cjs +51 -15
  31. package/dist/cjs/components/DataTablePagination/index.native.js +54 -16
  32. package/dist/cjs/components/DataTablePagination/index.native.js.map +1 -1
  33. package/dist/cjs/components/DataTableSearch/index.cjs +0 -3
  34. package/dist/cjs/components/DataTableSearch/index.native.js +0 -3
  35. package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
  36. package/dist/cjs/components/DataTableToolbar/index.cjs +0 -1
  37. package/dist/cjs/components/DataTableToolbar/index.native.js +0 -1
  38. package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
  39. package/dist/cjs/components/DataTableViewOptions/index.cjs +0 -5
  40. package/dist/cjs/components/DataTableViewOptions/index.native.js +0 -5
  41. package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
  42. package/dist/cjs/components/FilterManager.cjs +0 -1
  43. package/dist/cjs/components/FilterManager.native.js +0 -1
  44. package/dist/cjs/components/FilterManager.native.js.map +1 -1
  45. package/dist/cjs/components/FilterOperatorValueEditor/index.cjs +2 -2
  46. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js +2 -2
  47. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  48. package/dist/cjs/components/TableInput/index.cjs +2 -1
  49. package/dist/cjs/components/TableInput/index.native.js +4 -2
  50. package/dist/cjs/components/TableInput/index.native.js.map +1 -1
  51. package/dist/cjs/hooks/useDataTable.cjs +24 -8
  52. package/dist/cjs/hooks/useDataTable.native.js +28 -8
  53. package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
  54. package/dist/cjs/index.cjs +12 -0
  55. package/dist/cjs/index.native.js +12 -0
  56. package/dist/cjs/index.native.js.map +1 -1
  57. package/dist/cjs/shared/devWarn.cjs +70 -0
  58. package/dist/cjs/shared/devWarn.native.js +84 -0
  59. package/dist/cjs/shared/devWarn.native.js.map +1 -0
  60. package/dist/cjs/utils/columnAlign.cjs +4 -1
  61. package/dist/cjs/utils/columnAlign.native.js +4 -1
  62. package/dist/cjs/utils/columnAlign.native.js.map +1 -1
  63. package/dist/cjs/utils/filterFields.cjs +5 -0
  64. package/dist/cjs/utils/filterFields.native.js +5 -0
  65. package/dist/cjs/utils/filterFields.native.js.map +1 -1
  66. package/dist/cjs/utils/filterUtils.cjs +30 -0
  67. package/dist/cjs/utils/filterUtils.native.js +50 -0
  68. package/dist/cjs/utils/filterUtils.native.js.map +1 -1
  69. package/dist/cjs/utils/money.cjs +137 -0
  70. package/dist/cjs/utils/money.native.js +165 -0
  71. package/dist/cjs/utils/money.native.js.map +1 -0
  72. package/dist/cjs/utils/rowAccumulator.cjs +48 -0
  73. package/dist/cjs/utils/rowAccumulator.native.js +51 -0
  74. package/dist/cjs/utils/rowAccumulator.native.js.map +1 -0
  75. package/dist/esm/components/ColumnHeaderFilter/index.mjs +78 -42
  76. package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
  77. package/dist/esm/components/ColumnHeaderFilter/index.native.js +101 -55
  78. package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
  79. package/dist/esm/components/DataTable/DataTableCardControls.mjs +0 -1
  80. package/dist/esm/components/DataTable/DataTableCardControls.mjs.map +1 -1
  81. package/dist/esm/components/DataTable/DataTableCardControls.native.js +0 -1
  82. package/dist/esm/components/DataTable/DataTableCardControls.native.js.map +1 -1
  83. package/dist/esm/components/DataTable/DataTableRoot.mjs +33 -6
  84. package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
  85. package/dist/esm/components/DataTable/DataTableRoot.native.js +29 -4
  86. package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
  87. package/dist/esm/components/DataTable/DataTableStateContext.mjs.map +1 -1
  88. package/dist/esm/components/DataTable/DataTableStateContext.native.js.map +1 -1
  89. package/dist/esm/components/DataTableBulkActions/index.mjs +0 -4
  90. package/dist/esm/components/DataTableBulkActions/index.mjs.map +1 -1
  91. package/dist/esm/components/DataTableBulkActions/index.native.js +0 -4
  92. package/dist/esm/components/DataTableBulkActions/index.native.js.map +1 -1
  93. package/dist/esm/components/DataTableCell/index.mjs +17 -2
  94. package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
  95. package/dist/esm/components/DataTableCell/index.native.js +17 -2
  96. package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
  97. package/dist/esm/components/DataTableDateFilter/index.mjs +0 -7
  98. package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
  99. package/dist/esm/components/DataTableDateFilter/index.native.js +0 -7
  100. package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
  101. package/dist/esm/components/DataTableFilterButton/index.mjs +0 -1
  102. package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
  103. package/dist/esm/components/DataTableFilterButton/index.native.js +0 -1
  104. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs +3 -2
  105. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs.map +1 -1
  106. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js +5 -2
  107. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  108. package/dist/esm/components/DataTableFilters/index.mjs +0 -1
  109. package/dist/esm/components/DataTableFilters/index.mjs.map +1 -1
  110. package/dist/esm/components/DataTableFilters/index.native.js +0 -1
  111. package/dist/esm/components/DataTableGrouping/index.mjs +0 -8
  112. package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
  113. package/dist/esm/components/DataTableGrouping/index.native.js +0 -8
  114. package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
  115. package/dist/esm/components/DataTablePagination/index.mjs +54 -18
  116. package/dist/esm/components/DataTablePagination/index.mjs.map +1 -1
  117. package/dist/esm/components/DataTablePagination/index.native.js +57 -19
  118. package/dist/esm/components/DataTablePagination/index.native.js.map +1 -1
  119. package/dist/esm/components/DataTableSearch/index.mjs +0 -3
  120. package/dist/esm/components/DataTableSearch/index.mjs.map +1 -1
  121. package/dist/esm/components/DataTableSearch/index.native.js +0 -3
  122. package/dist/esm/components/DataTableSearch/index.native.js.map +1 -1
  123. package/dist/esm/components/DataTableToolbar/index.mjs +0 -1
  124. package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
  125. package/dist/esm/components/DataTableToolbar/index.native.js +0 -1
  126. package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
  127. package/dist/esm/components/DataTableViewOptions/index.mjs +0 -5
  128. package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
  129. package/dist/esm/components/DataTableViewOptions/index.native.js +0 -5
  130. package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
  131. package/dist/esm/components/FilterManager.mjs +0 -1
  132. package/dist/esm/components/FilterManager.mjs.map +1 -1
  133. package/dist/esm/components/FilterManager.native.js +0 -1
  134. package/dist/esm/components/FilterManager.native.js.map +1 -1
  135. package/dist/esm/components/FilterOperatorValueEditor/index.mjs +2 -2
  136. package/dist/esm/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  137. package/dist/esm/components/FilterOperatorValueEditor/index.native.js +2 -2
  138. package/dist/esm/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  139. package/dist/esm/components/TableInput/index.mjs +3 -2
  140. package/dist/esm/components/TableInput/index.mjs.map +1 -1
  141. package/dist/esm/components/TableInput/index.native.js +5 -3
  142. package/dist/esm/components/TableInput/index.native.js.map +1 -1
  143. package/dist/esm/hooks/useDataTable.mjs +24 -8
  144. package/dist/esm/hooks/useDataTable.mjs.map +1 -1
  145. package/dist/esm/hooks/useDataTable.native.js +28 -8
  146. package/dist/esm/hooks/useDataTable.native.js.map +1 -1
  147. package/dist/esm/index.mjs +3 -1
  148. package/dist/esm/index.mjs.map +1 -1
  149. package/dist/esm/index.native.js +3 -1
  150. package/dist/esm/index.native.js.map +1 -1
  151. package/dist/esm/shared/devWarn.mjs +43 -0
  152. package/dist/esm/shared/devWarn.mjs.map +1 -0
  153. package/dist/esm/shared/devWarn.native.js +54 -0
  154. package/dist/esm/shared/devWarn.native.js.map +1 -0
  155. package/dist/esm/utils/columnAlign.mjs +4 -1
  156. package/dist/esm/utils/columnAlign.mjs.map +1 -1
  157. package/dist/esm/utils/columnAlign.native.js +4 -1
  158. package/dist/esm/utils/columnAlign.native.js.map +1 -1
  159. package/dist/esm/utils/filterFields.mjs +5 -0
  160. package/dist/esm/utils/filterFields.mjs.map +1 -1
  161. package/dist/esm/utils/filterFields.native.js +5 -0
  162. package/dist/esm/utils/filterFields.native.js.map +1 -1
  163. package/dist/esm/utils/filterUtils.mjs +30 -0
  164. package/dist/esm/utils/filterUtils.mjs.map +1 -1
  165. package/dist/esm/utils/filterUtils.native.js +50 -0
  166. package/dist/esm/utils/filterUtils.native.js.map +1 -1
  167. package/dist/esm/utils/money.mjs +104 -0
  168. package/dist/esm/utils/money.mjs.map +1 -0
  169. package/dist/esm/utils/money.native.js +129 -0
  170. package/dist/esm/utils/money.native.js.map +1 -0
  171. package/dist/esm/utils/rowAccumulator.mjs +23 -0
  172. package/dist/esm/utils/rowAccumulator.mjs.map +1 -0
  173. package/dist/esm/utils/rowAccumulator.native.js +23 -0
  174. package/dist/esm/utils/rowAccumulator.native.js.map +1 -0
  175. package/dist/jsx/components/ColumnHeaderFilter/index.mjs +78 -42
  176. package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
  177. package/dist/jsx/components/ColumnHeaderFilter/index.native.js +97 -51
  178. package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
  179. package/dist/jsx/components/DataTable/DataTableCardControls.mjs +0 -1
  180. package/dist/jsx/components/DataTable/DataTableCardControls.mjs.map +1 -1
  181. package/dist/jsx/components/DataTable/DataTableCardControls.native.js +0 -1
  182. package/dist/jsx/components/DataTable/DataTableCardControls.native.js.map +1 -1
  183. package/dist/jsx/components/DataTable/DataTableRoot.mjs +33 -6
  184. package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
  185. package/dist/jsx/components/DataTable/DataTableRoot.native.js +29 -4
  186. package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
  187. package/dist/jsx/components/DataTable/DataTableStateContext.mjs.map +1 -1
  188. package/dist/jsx/components/DataTable/DataTableStateContext.native.js.map +1 -1
  189. package/dist/jsx/components/DataTableBulkActions/index.mjs +0 -4
  190. package/dist/jsx/components/DataTableBulkActions/index.mjs.map +1 -1
  191. package/dist/jsx/components/DataTableBulkActions/index.native.js +0 -4
  192. package/dist/jsx/components/DataTableBulkActions/index.native.js.map +1 -1
  193. package/dist/jsx/components/DataTableCell/index.mjs +17 -2
  194. package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
  195. package/dist/jsx/components/DataTableCell/index.native.js +16 -1
  196. package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
  197. package/dist/jsx/components/DataTableDateFilter/index.mjs +0 -7
  198. package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
  199. package/dist/jsx/components/DataTableDateFilter/index.native.js +0 -7
  200. package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
  201. package/dist/jsx/components/DataTableFilterButton/index.mjs +0 -1
  202. package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
  203. package/dist/jsx/components/DataTableFilterButton/index.native.js +0 -1
  204. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs +3 -2
  205. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs.map +1 -1
  206. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js +4 -1
  207. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  208. package/dist/jsx/components/DataTableFilters/index.mjs +0 -1
  209. package/dist/jsx/components/DataTableFilters/index.mjs.map +1 -1
  210. package/dist/jsx/components/DataTableFilters/index.native.js +0 -1
  211. package/dist/jsx/components/DataTableGrouping/index.mjs +0 -8
  212. package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
  213. package/dist/jsx/components/DataTableGrouping/index.native.js +0 -8
  214. package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
  215. package/dist/jsx/components/DataTablePagination/index.mjs +54 -18
  216. package/dist/jsx/components/DataTablePagination/index.mjs.map +1 -1
  217. package/dist/jsx/components/DataTablePagination/index.native.js +54 -16
  218. package/dist/jsx/components/DataTablePagination/index.native.js.map +1 -1
  219. package/dist/jsx/components/DataTableSearch/index.mjs +0 -3
  220. package/dist/jsx/components/DataTableSearch/index.mjs.map +1 -1
  221. package/dist/jsx/components/DataTableSearch/index.native.js +0 -3
  222. package/dist/jsx/components/DataTableSearch/index.native.js.map +1 -1
  223. package/dist/jsx/components/DataTableToolbar/index.mjs +0 -1
  224. package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
  225. package/dist/jsx/components/DataTableToolbar/index.native.js +0 -1
  226. package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
  227. package/dist/jsx/components/DataTableViewOptions/index.mjs +0 -5
  228. package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
  229. package/dist/jsx/components/DataTableViewOptions/index.native.js +0 -5
  230. package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
  231. package/dist/jsx/components/FilterManager.mjs +0 -1
  232. package/dist/jsx/components/FilterManager.mjs.map +1 -1
  233. package/dist/jsx/components/FilterManager.native.js +0 -1
  234. package/dist/jsx/components/FilterManager.native.js.map +1 -1
  235. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs +2 -2
  236. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  237. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js +2 -2
  238. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  239. package/dist/jsx/components/TableInput/index.mjs +3 -2
  240. package/dist/jsx/components/TableInput/index.mjs.map +1 -1
  241. package/dist/jsx/components/TableInput/index.native.js +4 -2
  242. package/dist/jsx/components/TableInput/index.native.js.map +1 -1
  243. package/dist/jsx/hooks/useDataTable.mjs +24 -8
  244. package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
  245. package/dist/jsx/hooks/useDataTable.native.js +28 -8
  246. package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
  247. package/dist/jsx/index.js +3 -1
  248. package/dist/jsx/index.js.map +1 -1
  249. package/dist/jsx/index.mjs +3 -1
  250. package/dist/jsx/index.mjs.map +1 -1
  251. package/dist/jsx/index.native.js +12 -0
  252. package/dist/jsx/index.native.js.map +1 -1
  253. package/dist/jsx/shared/devWarn.mjs +43 -0
  254. package/dist/jsx/shared/devWarn.mjs.map +1 -0
  255. package/dist/jsx/shared/devWarn.native.js +84 -0
  256. package/dist/jsx/shared/devWarn.native.js.map +1 -0
  257. package/dist/jsx/utils/columnAlign.mjs +4 -1
  258. package/dist/jsx/utils/columnAlign.mjs.map +1 -1
  259. package/dist/jsx/utils/columnAlign.native.js +4 -1
  260. package/dist/jsx/utils/columnAlign.native.js.map +1 -1
  261. package/dist/jsx/utils/filterFields.mjs +5 -0
  262. package/dist/jsx/utils/filterFields.mjs.map +1 -1
  263. package/dist/jsx/utils/filterFields.native.js +5 -0
  264. package/dist/jsx/utils/filterFields.native.js.map +1 -1
  265. package/dist/jsx/utils/filterUtils.mjs +30 -0
  266. package/dist/jsx/utils/filterUtils.mjs.map +1 -1
  267. package/dist/jsx/utils/filterUtils.native.js +50 -0
  268. package/dist/jsx/utils/filterUtils.native.js.map +1 -1
  269. package/dist/jsx/utils/money.mjs +104 -0
  270. package/dist/jsx/utils/money.mjs.map +1 -0
  271. package/dist/jsx/utils/money.native.js +165 -0
  272. package/dist/jsx/utils/money.native.js.map +1 -0
  273. package/dist/jsx/utils/rowAccumulator.mjs +23 -0
  274. package/dist/jsx/utils/rowAccumulator.mjs.map +1 -0
  275. package/dist/jsx/utils/rowAccumulator.native.js +51 -0
  276. package/dist/jsx/utils/rowAccumulator.native.js.map +1 -0
  277. package/package.json +12 -12
  278. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.spec.tsx +142 -7
  279. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.stories.tsx +46 -9
  280. package/src/components/ColumnHeaderFilter/index.tsx +104 -47
  281. package/src/components/DataTable/DataTable.stories.tsx +186 -14
  282. package/src/components/DataTable/DataTableCardControls.tsx +11 -13
  283. package/src/components/DataTable/DataTableRoot.tsx +40 -14
  284. package/src/components/DataTable/DataTableStateContext.ts +7 -0
  285. package/src/components/DataTable/columnWidthLayout.spec.tsx +195 -0
  286. package/src/components/DataTable/headerSorting.spec.tsx +25 -0
  287. package/src/components/DataTable/moneyColumn.spec.tsx +151 -0
  288. package/src/components/DataTable/rowAccumulator.spec.tsx +171 -0
  289. package/src/components/DataTableBulkActions/index.tsx +0 -4
  290. package/src/components/DataTableCell/index.tsx +28 -2
  291. package/src/components/DataTableColumnPinning/DataTableColumnPinning.stories.tsx +0 -4
  292. package/src/components/DataTableDateFilter/index.tsx +0 -7
  293. package/src/components/DataTableFilterButton/index.tsx +1 -1
  294. package/src/components/DataTableFilterChips/FilterChip.spec.tsx +6 -0
  295. package/src/components/DataTableFilterChips/FilterChip.tsx +3 -2
  296. package/src/components/DataTableFilters/index.tsx +1 -1
  297. package/src/components/DataTableGrouping/DataTableGrouping.stories.tsx +0 -4
  298. package/src/components/DataTableGrouping/index.tsx +1 -13
  299. package/src/components/DataTablePagination/DataTablePagination.spec.tsx +9 -2
  300. package/src/components/DataTablePagination/DataTablePagination.stories.tsx +32 -0
  301. package/src/components/DataTablePagination/DataTablePagination.width.spec.tsx +109 -0
  302. package/src/components/DataTablePagination/index.tsx +100 -20
  303. package/src/components/DataTableSearch/index.tsx +2 -3
  304. package/src/components/DataTableToolbar/DataTableToolbar.stories.tsx +2 -4
  305. package/src/components/DataTableToolbar/index.tsx +1 -5
  306. package/src/components/DataTableViewOptions/index.tsx +2 -13
  307. package/src/components/FilterManager.tsx +1 -3
  308. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.spec.tsx +1 -1
  309. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.stories.tsx +1 -0
  310. package/src/components/FilterOperatorValueEditor/index.tsx +10 -2
  311. package/src/components/TableInput/index.native.tsx +3 -2
  312. package/src/components/TableInput/index.tsx +3 -2
  313. package/src/hooks/useDataTable.ts +43 -7
  314. package/src/index.ts +13 -0
  315. package/src/shared/devWarn.ts +97 -0
  316. package/src/types.ts +71 -2
  317. package/src/utils/columnAlign.ts +9 -1
  318. package/src/utils/filterFields.ts +23 -1
  319. package/src/utils/filterUtils.ts +50 -1
  320. package/src/utils/money.spec.ts +156 -0
  321. package/src/utils/money.ts +202 -0
  322. package/src/utils/rowAccumulator.ts +136 -0
  323. package/types/components/ColumnHeaderFilter/index.d.ts +9 -2
  324. package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
  325. package/types/components/DataTable/DataTableCardControls.d.ts.map +1 -1
  326. package/types/components/DataTable/DataTableRoot.d.ts +1 -1
  327. package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
  328. package/types/components/DataTable/DataTableStateContext.d.ts +7 -0
  329. package/types/components/DataTable/DataTableStateContext.d.ts.map +1 -1
  330. package/types/components/DataTableBulkActions/index.d.ts.map +1 -1
  331. package/types/components/DataTableCell/index.d.ts.map +1 -1
  332. package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
  333. package/types/components/DataTableFilterChips/FilterChip.d.ts.map +1 -1
  334. package/types/components/DataTableGrouping/index.d.ts.map +1 -1
  335. package/types/components/DataTablePagination/index.d.ts +1 -1
  336. package/types/components/DataTablePagination/index.d.ts.map +1 -1
  337. package/types/components/DataTableSearch/index.d.ts.map +1 -1
  338. package/types/components/DataTableToolbar/index.d.ts.map +1 -1
  339. package/types/components/DataTableViewOptions/index.d.ts.map +1 -1
  340. package/types/components/FilterManager.d.ts.map +1 -1
  341. package/types/components/FilterOperatorValueEditor/index.d.ts.map +1 -1
  342. package/types/components/TableInput/index.d.ts.map +1 -1
  343. package/types/components/TableInput/index.native.d.ts.map +1 -1
  344. package/types/hooks/useDataTable.d.ts +1 -1
  345. package/types/hooks/useDataTable.d.ts.map +1 -1
  346. package/types/index.d.ts +3 -0
  347. package/types/index.d.ts.map +1 -1
  348. package/types/shared/devWarn.d.ts +50 -0
  349. package/types/shared/devWarn.d.ts.map +1 -0
  350. package/types/types.d.ts +71 -3
  351. package/types/types.d.ts.map +1 -1
  352. package/types/utils/columnAlign.d.ts.map +1 -1
  353. package/types/utils/filterFields.d.ts.map +1 -1
  354. package/types/utils/filterUtils.d.ts +1 -1
  355. package/types/utils/filterUtils.d.ts.map +1 -1
  356. package/types/utils/money.d.ts +94 -0
  357. package/types/utils/money.d.ts.map +1 -0
  358. package/types/utils/rowAccumulator.d.ts +107 -0
  359. package/types/utils/rowAccumulator.d.ts.map +1 -0
@@ -228,11 +228,7 @@ export function DataTableToolbar(props: DataTableToolbarProps) {
228
228
  }}
229
229
  />
230
230
  <XStack {...knobProps.gap} justifyContent="flex-end">
231
- <Button
232
- size={controlSize}
233
- variant="outlined"
234
- onPress={() => setShowSaveViewDialog(false)}
235
- >
231
+ <Button size={controlSize} onPress={() => setShowSaveViewDialog(false)}>
236
232
  {t("Cancel")}
237
233
  </Button>
238
234
  <Button
@@ -119,7 +119,6 @@ export function DataTableViewOptions(props: DataTableViewOptionsProps) {
119
119
  <DropdownMenu.Trigger asChild>
120
120
  <Button
121
121
  size={knobProps.sizeToken}
122
- variant="outlined"
123
122
  icon={<GearIcon size={iconPx} />}
124
123
  aria-label={t("Open table view options")}
125
124
  >
@@ -176,7 +175,6 @@ export function DataTableViewOptions(props: DataTableViewOptionsProps) {
176
175
 
177
176
  <Button
178
177
  size={knobProps.sizeToken}
179
- variant="outlined"
180
178
  onPress={onResetToDefault}
181
179
  icon={<ArrowCounterClockwiseIcon size={iconPx} />}
182
180
  >
@@ -419,11 +417,7 @@ function ViewManagementSection({
419
417
  {/* Save Current View */}
420
418
  <Popover open={showSaveDialog} onOpenChange={setShowSaveDialog}>
421
419
  <Popover.Trigger asChild>
422
- <Button
423
- size={knobProps.sizeToken}
424
- variant="outlined"
425
- icon={<FloppyDiskIcon size={iconPx} />}
426
- >
420
+ <Button size={knobProps.sizeToken} icon={<FloppyDiskIcon size={iconPx} />}>
427
421
  {t("Save Current View")}
428
422
  </Button>
429
423
  </Popover.Trigger>
@@ -448,11 +442,7 @@ function ViewManagementSection({
448
442
  }}
449
443
  />
450
444
  <XStack gap="$2" justifyContent="flex-end">
451
- <Button
452
- size={knobProps.sizeToken}
453
- variant="outlined"
454
- onPress={() => setShowSaveDialog(false)}
455
- >
445
+ <Button size={knobProps.sizeToken} onPress={() => setShowSaveDialog(false)}>
456
446
  {t("Cancel")}
457
447
  </Button>
458
448
  <Button
@@ -489,7 +479,6 @@ function ViewManagementSection({
489
479
  <Text fontSize="$3">{view.name}</Text>
490
480
  <Button
491
481
  size={knobProps.sizeToken}
492
- variant="outlined"
493
482
  onPress={() => onLoadView(view.id)}
494
483
  disabled={activeViewId === view.id}
495
484
  >
@@ -136,9 +136,7 @@ export function FilterManager({
136
136
  <XStack gap="$3" justifyContent="flex-end">
137
137
  <KnobDialogClose asChild>
138
138
  {/* DG-ACT-05: the cancel action never renders disabled. */}
139
- <Button size={knobProps.sizeToken} variant="outlined">
140
- {t("Cancel")}
141
- </Button>
139
+ <Button size={knobProps.sizeToken}>{t("Cancel")}</Button>
142
140
  </KnobDialogClose>
143
141
  {/* Stays pressable on an empty name — handleSave surfaces the
144
142
  inline "Filter name is required" instead of a bare-disabled
@@ -19,7 +19,7 @@ const statusOptions = [
19
19
  { label: "Done", value: "done" },
20
20
  ];
21
21
 
22
- const fieldTypes: DataTableColumnType[] = ["text", "number", "date", "boolean", "select"];
22
+ const fieldTypes: DataTableColumnType[] = ["text", "number", "money", "date", "boolean", "select"];
23
23
 
24
24
  /** Every forms Select trigger in the tree, in render order (Condition first). */
25
25
  const selectTriggers = (container: HTMLElement) =>
@@ -44,6 +44,7 @@ const statusOptions = [
44
44
  const fieldTypeLabels: Record<DataTableColumnType, string> = {
45
45
  text: "Text",
46
46
  number: "Number",
47
+ money: "Money",
47
48
  date: "Date",
48
49
  boolean: "Boolean",
49
50
  select: "Select",
@@ -111,10 +111,18 @@ export function FilterOperatorValueEditor({
111
111
  label={t("Value")}
112
112
  value={value}
113
113
  onChangeText={onValueChange}
114
- placeholder={fieldType === "date" ? t("YYYY-MM-DD") : t("Enter value...")}
114
+ placeholder={
115
+ fieldType === "date"
116
+ ? t("YYYY-MM-DD")
117
+ : fieldType === "money"
118
+ ? t("0.00")
119
+ : t("Enter value...")
120
+ }
115
121
  size="$3"
116
122
  compact
117
- {...(fieldType === "number" && { keyboardType: "numeric" })}
123
+ {...((fieldType === "number" || fieldType === "money") && {
124
+ keyboardType: "numeric",
125
+ })}
118
126
  />
119
127
  )}
120
128
  </YStack>
@@ -23,7 +23,7 @@ import { TrashIcon, PlusIcon } from "@phosphor-icons/react";
23
23
  import { useTranslation } from "react-i18next";
24
24
  import { getTableCellPadding } from "@multiplatform.one/table-primitives";
25
25
  import { hairline, useResolvedKnobs } from "@multiplatform.one/theme";
26
- import { Text, View, XStack, YStack } from "tamagui";
26
+ import { Text, View, XStack, YStack, useTheme } from "tamagui";
27
27
  import type {
28
28
  DataTableColumn,
29
29
  DataTableData,
@@ -212,6 +212,7 @@ function TableInputInner<TData extends DataTableData>({
212
212
  compact,
213
213
  t,
214
214
  }: TableInputInnerProps<TData>) {
215
+ const theme = useTheme();
215
216
  const { knobProps } = useResolvedKnobs({ compact });
216
217
  const cellPad = getTableCellPadding(knobProps.space);
217
218
  const chromePx = knobProps.nestedControl.px;
@@ -332,7 +333,7 @@ function TableInputInner<TData extends DataTableData>({
332
333
  row: index + 1,
333
334
  })}
334
335
  >
335
- <TrashIcon size={16} color="$red10" />
336
+ <TrashIcon size={16} color={theme.red10?.val ?? "currentColor"} />
336
337
  </Button>
337
338
  </View>
338
339
  )}
@@ -38,7 +38,7 @@ import { TrashIcon, PlusIcon } from "@phosphor-icons/react";
38
38
  import { useTranslation } from "react-i18next";
39
39
  import { Table, getTableCellPadding } from "@multiplatform.one/table-primitives";
40
40
  import { hairline, useResolvedKnobs } from "@multiplatform.one/theme";
41
- import { Text, View, XStack, YStack, isWeb } from "tamagui";
41
+ import { Text, View, XStack, YStack, isWeb, useTheme } from "tamagui";
42
42
  import type {
43
43
  DataTableColumn,
44
44
  DataTableData,
@@ -240,6 +240,7 @@ function TableInputInner<TData extends DataTableData>({
240
240
  enableReorder,
241
241
  t,
242
242
  }: TableInputInnerProps<TData>) {
243
+ const theme = useTheme();
243
244
  const { knobProps } = useResolvedKnobs({ compact });
244
245
  const cellPad = getTableCellPadding(knobProps.space);
245
246
  const chromePx = knobProps.nestedControl.px;
@@ -471,7 +472,7 @@ function TableInputInner<TData extends DataTableData>({
471
472
  row: row.index + 1,
472
473
  })}
473
474
  >
474
- <TrashIcon size={16} color="$red10" />
475
+ <TrashIcon size={16} color={theme.red10?.val ?? "currentColor"} />
475
476
  </Button>
476
477
  );
477
478
  },
@@ -171,6 +171,7 @@ export const createUrlStrategy = {
171
171
  import React, { useMemo, useState, useCallback, useEffect, useRef } from "react";
172
172
  import type {
173
173
  DataTableData,
174
+ DataTableField,
174
175
  DataTableInfiniteState,
175
176
  DataTableState,
176
177
  UseDataTableOptions,
@@ -183,6 +184,8 @@ import {
183
184
  resolveFilterFields,
184
185
  } from "../utils/filterFields";
185
186
  import { applyFilterToValue } from "../utils/filterUtils";
187
+ import { accumulateRows } from "../utils/rowAccumulator";
188
+ import { moneyComparator } from "../utils/money";
186
189
  import { DEFAULT_PAGE_SIZE } from "../utils/paginationDefaults";
187
190
  import { deserializeTableState, serializeTableState } from "../utils/urlStateUtils";
188
191
  import { useInfiniteRows } from "./useInfiniteRows";
@@ -190,6 +193,13 @@ import { useTableFiltering } from "./useTableFiltering";
190
193
  import { useTableSorting } from "./useTableSorting";
191
194
  import { useTableViews } from "./useTableViews";
192
195
 
196
+ /**
197
+ * TanStack sort for a `money` column: exact decimal-string ordering, so
198
+ * "9.00" sorts below "10.00" (MPO-252).
199
+ */
200
+ const moneySortingFn = (rowA: any, rowB: any, columnId: string): number =>
201
+ moneyComparator(rowA.getValue(columnId), rowB.getValue(columnId));
202
+
193
203
  export function useDataTable<TData extends DataTableData = DataTableData>({
194
204
  data = [],
195
205
  columns = [],
@@ -208,6 +218,7 @@ export function useDataTable<TData extends DataTableData = DataTableData>({
208
218
  enablePagination: _enablePagination = true,
209
219
  paginationMode = "pages",
210
220
  loadPage,
221
+ rowAccumulator,
211
222
  enableColumnVisibility = true,
212
223
  enableColumnOrdering: _enableColumnOrdering = false,
213
224
  enableColumnResizing = false,
@@ -360,6 +371,21 @@ export function useDataTable<TData extends DataTableData = DataTableData>({
360
371
  // pre-filtered/sorted, so manual modes are forced on. In infinite mode the
361
372
  // pagination row model is never applied (rows accumulate instead of slice).
362
373
  const effectiveData = isLoaderMode ? infiniteRows.rows : data;
374
+
375
+ // ---- Row accumulator (MPO-250) ----
376
+ //
377
+ // The fold runs HERE — over the whole row set, before the advanced filters
378
+ // below and before TanStack's filter/sort/paginate models — because a
379
+ // derived column like a running balance depends on every row before it and
380
+ // would restart on page two otherwise. `order` (when given) is also the
381
+ // order the rows reach the table in: a fold order is the order its column
382
+ // reads down. Sorting on another column reorders for display and does NOT
383
+ // refold; see the contract on RowAccumulator.
384
+ const { rows: accumulatedData, total: foldTotal } = useMemo(
385
+ () => accumulateRows(effectiveData, rowAccumulator),
386
+ [effectiveData, rowAccumulator],
387
+ );
388
+
363
389
  const effectiveManualFiltering = manualFiltering || isLoaderMode;
364
390
  const effectiveManualSorting = manualSorting || isLoaderMode;
365
391
  const effectiveManualPagination = manualPagination || infiniteEnabled;
@@ -375,9 +401,9 @@ export function useDataTable<TData extends DataTableData = DataTableData>({
375
401
  // including hidden / non-column fields. Server-side tables (manualFiltering)
376
402
  // map the same filters to query params instead.
377
403
  const preFilteredData = useMemo(() => {
378
- if (effectiveManualFiltering) return effectiveData;
379
- return applyFiltersToData(effectiveData, filtering.advancedFilters, filterFields);
380
- }, [effectiveData, effectiveManualFiltering, filtering.advancedFilters, filterFields]);
404
+ if (effectiveManualFiltering) return accumulatedData;
405
+ return applyFiltersToData(accumulatedData, filtering.advancedFilters, filterFields);
406
+ }, [accumulatedData, effectiveManualFiltering, filtering.advancedFilters, filterFields]);
381
407
 
382
408
  // Column-funnel filters store FilterValue objects ({operator, value}) —
383
409
  // interpret them with the shared operator semantics instead of TanStack's
@@ -455,13 +481,20 @@ export function useDataTable<TData extends DataTableData = DataTableData>({
455
481
  const normalizedColumns = useMemo(
456
482
  () =>
457
483
  columns.map((column) => {
458
- const { sortable, filterable } = column as {
484
+ const { sortable, filterable, field } = column as {
459
485
  sortable?: boolean;
460
486
  filterable?: boolean;
487
+ field?: DataTableField;
461
488
  };
462
- if (sortable === undefined && filterable === undefined) return column;
489
+ // A money column holds a decimal STRING, and TanStack's auto sort
490
+ // would compare it as text — "9.00" above "10.00", silently wrong on
491
+ // every amount column (MPO-252). Give it the exact comparator so
492
+ // `sortable: true` is safe to turn on. An explicit sortingFn wins.
493
+ const needsMoneySort = field === "money" && column.sortingFn === undefined;
494
+ if (sortable === undefined && filterable === undefined && !needsMoneySort) return column;
463
495
  return {
464
496
  ...column,
497
+ ...(needsMoneySort ? { sortingFn: moneySortingFn } : {}),
465
498
  ...(sortable !== undefined && column.enableSorting === undefined
466
499
  ? { enableSorting: sortable }
467
500
  : {}),
@@ -596,9 +629,9 @@ export function useDataTable<TData extends DataTableData = DataTableData>({
596
629
  // ---- Computed Values ----
597
630
 
598
631
  const filteredData = useMemo(() => {
599
- if (effectiveManualFiltering) return effectiveData;
632
+ if (effectiveManualFiltering) return accumulatedData;
600
633
  return table.getFilteredRowModel().rows.map((row) => row.original);
601
- }, [effectiveData, table, effectiveManualFiltering]);
634
+ }, [accumulatedData, table, effectiveManualFiltering]);
602
635
 
603
636
  const paginatedData = useMemo(() => {
604
637
  if (effectiveManualPagination) return filteredData;
@@ -708,6 +741,9 @@ export function useDataTable<TData extends DataTableData = DataTableData>({
708
741
  activeFilterCount: filtering.activeFilterCount,
709
742
  filterFields,
710
743
  infinite,
744
+ // The fold read once at the end — a footer cell renders it through
745
+ // useDataTableState() (MPO-250).
746
+ foldTotal,
711
747
  };
712
748
 
713
749
  // ---- State Change Callback ----
package/src/index.ts CHANGED
@@ -157,6 +157,19 @@ export {
157
157
  resolveFilterFields,
158
158
  } from "./utils/filterFields";
159
159
  export * from "./utils/urlStateUtils";
160
+ export {
161
+ addMoney,
162
+ compareMoney,
163
+ formatMoney,
164
+ isMoneyString,
165
+ isNegativeMoney,
166
+ moneyComparator,
167
+ subtractMoney,
168
+ sumMoney,
169
+ sumMoneyByCurrency,
170
+ } from "./utils/money";
171
+ export { accumulateRows } from "./utils/rowAccumulator";
172
+ export type { RowAccumulator, RowAccumulatorResult } from "./utils/rowAccumulator";
160
173
  export {
161
174
  getDefaultColumnAlign,
162
175
  alignToFlex,
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Table DEV guardrails — same shape as the `@multiplatform.one/theme` §5
3
+ * catalog (`devWarn` / `warnBareDisabled` / `warnSizeRecipeEscape`): a
4
+ * module-level seen set, a `NODE_ENV === "production"` no-op, and helpers
5
+ * called inline during render.
6
+ *
7
+ * The prefix is `[table]`, not `[theme]`: the codes here are table-local and
8
+ * the story-hygiene harvester (`p-results/story-hygiene/verify.mjs`) collects
9
+ * on the `[theme]` prefix.
10
+ */
11
+
12
+ import type { DataTableProps } from "../types";
13
+
14
+ export type TableDevWarnCode =
15
+ /**
16
+ * A column declares a width (`width` or TanStack `size`) that the resolved
17
+ * `columnLayout` discards before it reaches the cell box.
18
+ */
19
+ "column-width-ignored";
20
+
21
+ export type TableDevWarnDetail = {
22
+ component?: string;
23
+ id?: string;
24
+ columns?: string;
25
+ columnLayout?: string;
26
+ suggest?: string;
27
+ };
28
+
29
+ const seen = new Set<string>();
30
+
31
+ function isDev(): boolean {
32
+ return process.env.NODE_ENV !== "production";
33
+ }
34
+
35
+ /** Emit a once-per-key console warning in non-production builds. */
36
+ export function tableDevWarn(code: TableDevWarnCode, detail: TableDevWarnDetail = {}): void {
37
+ if (!isDev()) return;
38
+ const key = [code, detail.component ?? "", detail.id ?? "", detail.columns ?? ""].join(":");
39
+ if (seen.has(key)) return;
40
+ seen.add(key);
41
+ const bits = [
42
+ detail.component ? `component=${detail.component}` : undefined,
43
+ detail.id ? `id=${detail.id}` : undefined,
44
+ detail.columns ? `columns=${detail.columns}` : undefined,
45
+ detail.columnLayout ? `columnLayout=${detail.columnLayout}` : undefined,
46
+ detail.suggest ? `suggest=${detail.suggest}` : undefined,
47
+ ].filter(Boolean);
48
+ const suffix = bits.length ? ` (${bits.join(", ")})` : "";
49
+ console.warn(`[table] ${code}${suffix}`);
50
+ }
51
+
52
+ /** @internal test helper */
53
+ export function __resetTableDevWarnSeen(): void {
54
+ seen.clear();
55
+ }
56
+
57
+ type WidthBearingColumn = {
58
+ id?: unknown;
59
+ accessorKey?: unknown;
60
+ width?: unknown;
61
+ size?: unknown;
62
+ };
63
+
64
+ function columnKey(column: WidthBearingColumn, index: number): string {
65
+ if (typeof column.id === "string" && column.id) return column.id;
66
+ if (typeof column.accessorKey === "string" && column.accessorKey) return column.accessorKey;
67
+ return `#${index}`;
68
+ }
69
+
70
+ /**
71
+ * MPO-236 — `columnLayout: "equal"` (the default) flexes every column to the
72
+ * same width, so a per-column `width` / `size` never reaches the cell box and
73
+ * the render is byte-identical to one with no widths at all.
74
+ *
75
+ * `enableColumnResizing` is the exemption: it swaps the cell flex to
76
+ * `flexBasis: "auto"`, under which a declared width does survive.
77
+ */
78
+ export function warnColumnWidthIgnored(args: {
79
+ columnLayout?: DataTableProps["columnLayout"];
80
+ enableColumnResizing?: boolean;
81
+ columns: readonly WidthBearingColumn[];
82
+ component?: string;
83
+ }): void {
84
+ if (!isDev()) return;
85
+ if (args.columnLayout !== "equal" || args.enableColumnResizing) return;
86
+ const offenders = args.columns
87
+ .map((column, index) => ({ column, index }))
88
+ .filter(({ column }) => typeof column.width === "number" || typeof column.size === "number")
89
+ .map(({ column, index }) => columnKey(column, index));
90
+ if (!offenders.length) return;
91
+ tableDevWarn("column-width-ignored", {
92
+ component: args.component ?? "DataTable",
93
+ columns: offenders.join(","),
94
+ columnLayout: "equal",
95
+ suggest: 'columnLayout="auto" or "scroll", or enableColumnResizing',
96
+ });
97
+ }
package/src/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ColumnDef, ColumnFiltersState, Row } from "@tanstack/react-table";
2
+ import type { RowAccumulator } from "./utils/rowAccumulator";
2
3
  import type { UrlStateStrategy } from "./hooks/useDataTable";
3
4
  import type { AnyFormApi } from "@multiplatform.one/forms";
4
5
  import type React from "react";
@@ -50,6 +51,12 @@ export type DataTableField =
50
51
  // Numeric inputs
51
52
  | "stepper"
52
53
  | "slider"
54
+ /**
55
+ * A Currency field: a decimal STRING, formatted for display and ordered
56
+ * numerically. Read-only presentation — money is edited through the form
57
+ * surfaces, not typed into a grid cell (MPO-252).
58
+ */
59
+ | "money"
53
60
  // Selection inputs
54
61
  | "select"
55
62
  | "combobox"
@@ -113,8 +120,17 @@ export interface DataTableFieldProps {
113
120
  step?: number;
114
121
  /** Precision for numeric fields */
115
122
  precision?: number;
116
- /** Currency code for currency fields */
123
+ /** Currency code for currency fields. A column-level constant. */
117
124
  currency?: string;
125
+ /**
126
+ * Row-data key holding this row's currency code, for a `money` column
127
+ * (MPO-252). A ledger genuinely mixes currencies row by row, so the row's
128
+ * own code WINS over the column-level `currency` constant; `currency` is
129
+ * the fallback for the rows that carry none.
130
+ */
131
+ currencyField?: string;
132
+ /** BCP-47 locale for money formatting. Defaults to the runtime's. */
133
+ locale?: string;
118
134
  /** Doctype for link fields (Frappe) */
119
135
  doctype?: string;
120
136
  /** Default country for phone input (ISO 3166-1 alpha-2) */
@@ -164,6 +180,12 @@ export type DataTableColumn<TData extends DataTableData = DataTableData> = Colum
164
180
  sortable?: boolean;
165
181
  searchable?: boolean;
166
182
  hidden?: boolean;
183
+ /**
184
+ * Column width intent, in px. Read by the view-options width slider and by
185
+ * saved views; the RENDERED cell box comes from TanStack `size`. Under the
186
+ * default `columnLayout: "equal"` neither one survives, and declaring
187
+ * either warns (see `columnLayout`).
188
+ */
167
189
  width?: number;
168
190
  minWidth?: number;
169
191
  maxWidth?: number;
@@ -423,9 +445,27 @@ export interface DataTableState {
423
445
 
424
446
  // Component Props Types
425
447
 
448
+ export type { RowAccumulator, RowAccumulatorResult } from "./utils/rowAccumulator";
449
+
426
450
  export interface DataTableProps<TData extends DataTableData = DataTableData> {
427
451
  data: TData[];
428
452
  columns: DataTableColumn<TData>[];
453
+ /**
454
+ * A fold over the ordered row set, run ONCE before filtering, sorting and
455
+ * pagination — the seam a running balance needs, because the value on row N
456
+ * depends on rows 1..N-1 and a column `cell` renderer only ever sees one
457
+ * row (MPO-250).
458
+ *
459
+ * The derived fields are merged onto each row, so a column names one in
460
+ * `accessorKey` like any other. Declare them on the row type. `total` is
461
+ * published as `computed.foldTotal` for a footer cell.
462
+ *
463
+ * Must be a STABLE reference (module constant or `useMemo`) — the fold
464
+ * re-runs when its identity changes. The full ordering contract, including
465
+ * what happens when the user sorts on another column, is documented on
466
+ * `RowAccumulator` in utils/rowAccumulator.ts.
467
+ */
468
+ rowAccumulator?: RowAccumulator<TData>;
429
469
 
430
470
  // State Management
431
471
  initialState?: Partial<DataTableState>;
@@ -528,6 +568,14 @@ export interface DataTableProps<TData extends DataTableData = DataTableData> {
528
568
  * - 'equal': All columns equal width, no horizontal scroll (default)
529
569
  * - 'auto': Content-based width, last column fills remainder, squishes if needed
530
570
  * - 'scroll': Content-based width, horizontal scroll when content exceeds container
571
+ *
572
+ * Under 'equal' a PER-COLUMN WIDTH IS IGNORED. Every cell gets
573
+ * `flexGrow: 1, flexBasis: 0`, so a column's `width` / `size` never reaches
574
+ * the cell box and the render is identical to one that declared no widths.
575
+ * Use 'auto' or 'scroll' when the widths must hold, or turn on
576
+ * `enableColumnResizing`, which switches the cells to `flexBasis: "auto"`.
577
+ * Declaring a width under 'equal' emits the `[table] column-width-ignored`
578
+ * dev warning rather than failing silently (MPO-236).
531
579
  */
532
580
  columnLayout?: "equal" | "auto" | "scroll";
533
581
 
@@ -762,12 +810,33 @@ export interface UseDataTableReturn<TData extends DataTableData = DataTableData>
762
810
  filterFields: ResolvedFilterField[];
763
811
  /** Present when paginationMode="infinite" */
764
812
  infinite?: DataTableInfiniteState;
813
+ /**
814
+ * `rowAccumulator.total(finalAccumulator, rowCount)` — the fold read once
815
+ * at the end, for a footer/total row. Undefined when the table has no
816
+ * accumulator or the accumulator declares no `total` (MPO-250).
817
+ */
818
+ foldTotal?: unknown;
765
819
  };
766
820
  }
767
821
 
768
822
  // Utility Types
769
823
 
770
- export type DataTableColumnType = "text" | "number" | "date" | "boolean" | "select";
824
+ /**
825
+ * Filter-editor / comparison type for a column.
826
+ *
827
+ * `"money"` (MPO-252) is a decimal STRING, not a number: a Frappe Currency
828
+ * field arrives as "-455.87" because a float would round it. It sorts and
829
+ * filters through the exact BigInt helpers in utils/money.ts, so `"9.00"`
830
+ * orders BELOW `"10.00"` — which the `"text"` fallback got backwards, in
831
+ * silence, on every amount column in the kit.
832
+ *
833
+ * The mixed-currency rule rides this type: TWO CURRENCIES ARE TWO FIGURES AND
834
+ * NEITHER CONVERTS. A money column formats from the row's own currency
835
+ * (`fieldProps.currencyField`), comparison is by magnitude only, and a total
836
+ * over mixed rows is `sumMoneyByCurrency` — one figure per code, never one
837
+ * number. There is no rate in the table and the kit will not invent one.
838
+ */
839
+ export type DataTableColumnType = "text" | "number" | "money" | "date" | "boolean" | "select";
771
840
 
772
841
  export interface DataTableColumnConfig {
773
842
  type: DataTableColumnType;
@@ -17,7 +17,15 @@ export type ColumnAlignInput = {
17
17
  meta?: { align?: ColumnAlign; role?: string };
18
18
  };
19
19
 
20
- const NUMERIC_FIELDS = new Set<DataTableField>(["stepper", "slider", "progress", "duration"]);
20
+ const NUMERIC_FIELDS = new Set<DataTableField>([
21
+ "stepper",
22
+ "slider",
23
+ "progress",
24
+ "duration",
25
+ // A money column right-aligns on its own, without needing a column-level
26
+ // `currency` constant — a ledger reads its code off each row (MPO-252).
27
+ "money",
28
+ ]);
21
29
 
22
30
  /** Booleans + icon-like metrics (EUI: center symbols). */
23
31
  const CENTER_FIELDS = new Set<DataTableField>(["checkbox", "switch", "rating"]);
@@ -41,6 +41,8 @@ export function mapFieldToFilterType(field?: DataTableField): DataTableColumnTyp
41
41
  case "rating":
42
42
  case "duration":
43
43
  return "number";
44
+ case "money":
45
+ return "money";
44
46
  case "datepicker":
45
47
  case "datetimepicker":
46
48
  case "timepicker":
@@ -117,7 +119,9 @@ export function getFilterFieldType(
117
119
  // ── Client-side application ───────────────────────────────────
118
120
 
119
121
  /** "select" fields compare as text; the others map 1:1. */
120
- function comparisonType(type: DataTableColumnType): "text" | "number" | "date" | "boolean" {
122
+ function comparisonType(
123
+ type: DataTableColumnType,
124
+ ): "text" | "number" | "money" | "date" | "boolean" {
121
125
  return type === "select" ? "text" : type;
122
126
  }
123
127
 
@@ -167,6 +171,22 @@ const NUMBER_OPERATORS: FilterOperator[] = [
167
171
  "isGreaterThanOrEqual",
168
172
  ];
169
173
 
174
+ /**
175
+ * Money takes the numeric operators PLUS the range pair — "every posting over
176
+ * 500" and "between 100 and 500" are the two questions asked of an amount
177
+ * column, and typing it "text" offered `contains` instead (MPO-252).
178
+ */
179
+ const MONEY_OPERATORS: FilterOperator[] = [
180
+ "is",
181
+ "isNot",
182
+ "isLessThan",
183
+ "isGreaterThan",
184
+ "isLessThanOrEqual",
185
+ "isGreaterThanOrEqual",
186
+ "isBetween",
187
+ "isNotBetween",
188
+ ];
189
+
170
190
  const DATE_OPERATORS: FilterOperator[] = [
171
191
  "is",
172
192
  "isNot",
@@ -185,6 +205,8 @@ export function operatorsForFilterType(type: DataTableColumnType): FilterOperato
185
205
  switch (type) {
186
206
  case "number":
187
207
  return NUMBER_OPERATORS;
208
+ case "money":
209
+ return MONEY_OPERATORS;
188
210
  case "date":
189
211
  return DATE_OPERATORS;
190
212
  case "boolean":