@multiplatform.one/table 6.7.0 → 7.0.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 (473) hide show
  1. package/README.md +4 -3
  2. package/dist/cjs/components/ChildTable/index.cjs +2 -1
  3. package/dist/cjs/components/ChildTable/index.native.js +2 -1
  4. package/dist/cjs/components/ChildTable/index.native.js.map +1 -1
  5. package/dist/cjs/components/ColumnHeaderFilter/index.cjs +17 -9
  6. package/dist/cjs/components/ColumnHeaderFilter/index.native.js +32 -11
  7. package/dist/cjs/components/ColumnHeaderFilter/index.native.js.map +1 -1
  8. package/dist/cjs/components/DataTable/DataTableDocumentList.cjs +222 -0
  9. package/dist/cjs/components/DataTable/DataTableDocumentList.native.js +237 -0
  10. package/dist/cjs/components/DataTable/DataTableDocumentList.native.js.map +1 -0
  11. package/dist/cjs/components/DataTable/DataTableMobileCards.cjs +5 -2
  12. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js +6 -2
  13. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  14. package/dist/cjs/components/DataTable/DataTableRoot.cjs +92 -41
  15. package/dist/cjs/components/DataTable/DataTableRoot.native.js +97 -43
  16. package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
  17. package/dist/cjs/components/DataTable/DataTableVirtualized.cjs +8 -2
  18. package/dist/cjs/components/DataTable/DataTableVirtualized.native.js +9 -3
  19. package/dist/cjs/components/DataTable/DataTableVirtualized.native.js.map +1 -1
  20. package/dist/cjs/components/DataTable/documentListSlots.cjs +59 -0
  21. package/dist/cjs/components/DataTable/documentListSlots.native.js +85 -0
  22. package/dist/cjs/components/DataTable/documentListSlots.native.js.map +1 -0
  23. package/dist/cjs/components/DataTable/index.native.js +74 -59
  24. package/dist/cjs/components/DataTable/index.native.js.map +1 -1
  25. package/dist/cjs/components/DataTable/rowStateChrome.cjs +55 -0
  26. package/dist/cjs/components/DataTable/rowStateChrome.native.js +59 -0
  27. package/dist/cjs/components/DataTable/rowStateChrome.native.js.map +1 -0
  28. package/dist/cjs/components/DataTableCell/CellModalEditor.cjs +24 -3
  29. package/dist/cjs/components/DataTableCell/CellModalEditor.native.js +6 -1
  30. package/dist/cjs/components/DataTableCell/CellModalEditor.native.js.map +1 -1
  31. package/dist/cjs/components/DataTableCell/CellOptionsEditor.cjs +9 -2
  32. package/dist/cjs/components/DataTableCell/CellOptionsEditor.native.js +11 -2
  33. package/dist/cjs/components/DataTableCell/CellOptionsEditor.native.js.map +1 -1
  34. package/dist/cjs/components/DataTableCell/index.cjs +74 -63
  35. package/dist/cjs/components/DataTableCell/index.native.js +94 -82
  36. package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
  37. package/dist/cjs/components/DataTableColumnPinning/index.cjs +54 -37
  38. package/dist/cjs/components/DataTableColumnPinning/index.native.js +59 -38
  39. package/dist/cjs/components/DataTableColumnPinning/index.native.js.map +1 -1
  40. package/dist/cjs/components/DataTableDateFilter/index.cjs +33 -14
  41. package/dist/cjs/components/DataTableDateFilter/index.native.js +33 -12
  42. package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
  43. package/dist/cjs/components/DataTableExport/index.cjs +35 -7
  44. package/dist/cjs/components/DataTableExport/index.native.js +42 -7
  45. package/dist/cjs/components/DataTableExport/index.native.js.map +1 -1
  46. package/dist/cjs/components/DataTableFacetMenu/index.cjs +140 -0
  47. package/dist/cjs/components/DataTableFacetMenu/index.native.js +156 -0
  48. package/dist/cjs/components/DataTableFacetMenu/index.native.js.map +1 -0
  49. package/dist/cjs/components/DataTableFilterButton/index.cjs +51 -32
  50. package/dist/cjs/components/DataTableFilterButton/index.native.js +63 -40
  51. package/dist/cjs/components/DataTableFilterButton/index.native.js.map +1 -1
  52. package/dist/cjs/components/DataTableFilterChips/FilterChip.cjs +143 -0
  53. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js +148 -0
  54. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js.map +1 -0
  55. package/dist/cjs/components/DataTableFilterChips/index.cjs +9 -31
  56. package/dist/cjs/components/DataTableFilterChips/index.native.js +9 -32
  57. package/dist/cjs/components/DataTableFilterChips/index.native.js.map +1 -1
  58. package/dist/cjs/components/DataTableFilters/index.cjs +145 -502
  59. package/dist/cjs/components/DataTableFilters/index.native.js +171 -544
  60. package/dist/cjs/components/DataTableFilters/index.native.js.map +1 -1
  61. package/dist/cjs/components/DataTableGrouping/index.cjs +273 -108
  62. package/dist/cjs/components/DataTableGrouping/index.native.js +310 -157
  63. package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
  64. package/dist/cjs/components/DataTablePagination/index.cjs +147 -95
  65. package/dist/cjs/components/DataTablePagination/index.native.js +159 -106
  66. package/dist/cjs/components/DataTablePagination/index.native.js.map +1 -1
  67. package/dist/cjs/components/DataTableSearch/index.cjs +251 -210
  68. package/dist/cjs/components/DataTableSearch/index.native.js +292 -243
  69. package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
  70. package/dist/cjs/components/DataTableToolbar/index.cjs +141 -115
  71. package/dist/cjs/components/DataTableToolbar/index.native.js +163 -148
  72. package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
  73. package/dist/cjs/components/DataTableViewOptions/index.cjs +25 -21
  74. package/dist/cjs/components/DataTableViewOptions/index.native.js +6 -4
  75. package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
  76. package/dist/cjs/components/SimpleTable/index.cjs +336 -46
  77. package/dist/cjs/components/SimpleTable/index.native.js +356 -48
  78. package/dist/cjs/components/SimpleTable/index.native.js.map +1 -1
  79. package/dist/cjs/components/TableInput/index.cjs +147 -38
  80. package/dist/cjs/components/TableInput/index.native.js +54 -38
  81. package/dist/cjs/components/TableInput/index.native.js.map +1 -1
  82. package/dist/cjs/components/TableInput/shared.cjs +36 -1
  83. package/dist/cjs/components/TableInput/shared.native.js +35 -0
  84. package/dist/cjs/components/TableInput/shared.native.js.map +1 -1
  85. package/dist/cjs/hooks/useDataTable.cjs +33 -2
  86. package/dist/cjs/hooks/useDataTable.native.js +41 -2
  87. package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
  88. package/dist/cjs/hooks/useInfiniteRows.cjs +20 -3
  89. package/dist/cjs/hooks/useInfiniteRows.native.js +20 -3
  90. package/dist/cjs/hooks/useInfiniteRows.native.js.map +1 -1
  91. package/dist/cjs/index.cjs +2 -0
  92. package/dist/cjs/index.native.js +2 -0
  93. package/dist/cjs/index.native.js.map +1 -1
  94. package/dist/cjs/utils/filterUtils.cjs +12 -5
  95. package/dist/cjs/utils/filterUtils.native.js +20 -5
  96. package/dist/cjs/utils/filterUtils.native.js.map +1 -1
  97. package/dist/esm/components/ChildTable/index.mjs +2 -1
  98. package/dist/esm/components/ChildTable/index.mjs.map +1 -1
  99. package/dist/esm/components/ChildTable/index.native.js +2 -1
  100. package/dist/esm/components/ChildTable/index.native.js.map +1 -1
  101. package/dist/esm/components/ColumnHeaderFilter/index.mjs +17 -9
  102. package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
  103. package/dist/esm/components/ColumnHeaderFilter/index.native.js +32 -11
  104. package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
  105. package/dist/esm/components/DataTable/DataTableDocumentList.mjs +196 -0
  106. package/dist/esm/components/DataTable/DataTableDocumentList.mjs.map +1 -0
  107. package/dist/esm/components/DataTable/DataTableDocumentList.native.js +208 -0
  108. package/dist/esm/components/DataTable/DataTableDocumentList.native.js.map +1 -0
  109. package/dist/esm/components/DataTable/DataTableMobileCards.mjs +5 -2
  110. package/dist/esm/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  111. package/dist/esm/components/DataTable/DataTableMobileCards.native.js +6 -2
  112. package/dist/esm/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  113. package/dist/esm/components/DataTable/DataTableRoot.mjs +93 -42
  114. package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
  115. package/dist/esm/components/DataTable/DataTableRoot.native.js +98 -44
  116. package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
  117. package/dist/esm/components/DataTable/DataTableVirtualized.mjs +8 -2
  118. package/dist/esm/components/DataTable/DataTableVirtualized.mjs.map +1 -1
  119. package/dist/esm/components/DataTable/DataTableVirtualized.native.js +9 -3
  120. package/dist/esm/components/DataTable/DataTableVirtualized.native.js.map +1 -1
  121. package/dist/esm/components/DataTable/documentListSlots.mjs +33 -0
  122. package/dist/esm/components/DataTable/documentListSlots.mjs.map +1 -0
  123. package/dist/esm/components/DataTable/documentListSlots.native.js +56 -0
  124. package/dist/esm/components/DataTable/documentListSlots.native.js.map +1 -0
  125. package/dist/esm/components/DataTable/index.native.js +52 -37
  126. package/dist/esm/components/DataTable/index.native.js.map +1 -1
  127. package/dist/esm/components/DataTable/rowStateChrome.mjs +28 -0
  128. package/dist/esm/components/DataTable/rowStateChrome.mjs.map +1 -0
  129. package/dist/esm/components/DataTable/rowStateChrome.native.js +29 -0
  130. package/dist/esm/components/DataTable/rowStateChrome.native.js.map +1 -0
  131. package/dist/esm/components/DataTableCell/CellModalEditor.mjs +25 -4
  132. package/dist/esm/components/DataTableCell/CellModalEditor.mjs.map +1 -1
  133. package/dist/esm/components/DataTableCell/CellModalEditor.native.js +6 -1
  134. package/dist/esm/components/DataTableCell/CellModalEditor.native.js.map +1 -1
  135. package/dist/esm/components/DataTableCell/CellOptionsEditor.mjs +9 -2
  136. package/dist/esm/components/DataTableCell/CellOptionsEditor.mjs.map +1 -1
  137. package/dist/esm/components/DataTableCell/CellOptionsEditor.native.js +11 -2
  138. package/dist/esm/components/DataTableCell/CellOptionsEditor.native.js.map +1 -1
  139. package/dist/esm/components/DataTableCell/index.mjs +75 -64
  140. package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
  141. package/dist/esm/components/DataTableCell/index.native.js +95 -83
  142. package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
  143. package/dist/esm/components/DataTableColumnPinning/index.mjs +54 -37
  144. package/dist/esm/components/DataTableColumnPinning/index.mjs.map +1 -1
  145. package/dist/esm/components/DataTableColumnPinning/index.native.js +59 -38
  146. package/dist/esm/components/DataTableColumnPinning/index.native.js.map +1 -1
  147. package/dist/esm/components/DataTableDateFilter/index.mjs +34 -15
  148. package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
  149. package/dist/esm/components/DataTableDateFilter/index.native.js +34 -13
  150. package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
  151. package/dist/esm/components/DataTableExport/index.mjs +36 -8
  152. package/dist/esm/components/DataTableExport/index.mjs.map +1 -1
  153. package/dist/esm/components/DataTableExport/index.native.js +43 -8
  154. package/dist/esm/components/DataTableExport/index.native.js.map +1 -1
  155. package/dist/esm/components/DataTableFacetMenu/index.mjs +115 -0
  156. package/dist/esm/components/DataTableFacetMenu/index.mjs.map +1 -0
  157. package/dist/esm/components/DataTableFacetMenu/index.native.js +128 -0
  158. package/dist/esm/components/DataTableFacetMenu/index.native.js.map +1 -0
  159. package/dist/esm/components/DataTableFilterButton/index.mjs +54 -35
  160. package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
  161. package/dist/esm/components/DataTableFilterButton/index.native.js +66 -43
  162. package/dist/esm/components/DataTableFilterButton/index.native.js.map +1 -1
  163. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs +118 -0
  164. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs.map +1 -0
  165. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js +120 -0
  166. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js.map +1 -0
  167. package/dist/esm/components/DataTableFilterChips/index.mjs +9 -32
  168. package/dist/esm/components/DataTableFilterChips/index.mjs.map +1 -1
  169. package/dist/esm/components/DataTableFilterChips/index.native.js +9 -33
  170. package/dist/esm/components/DataTableFilterChips/index.native.js.map +1 -1
  171. package/dist/esm/components/DataTableFilters/index.mjs +149 -506
  172. package/dist/esm/components/DataTableFilters/index.mjs.map +1 -1
  173. package/dist/esm/components/DataTableFilters/index.native.js +175 -548
  174. package/dist/esm/components/DataTableFilters/index.native.js.map +1 -1
  175. package/dist/esm/components/DataTableGrouping/index.mjs +275 -110
  176. package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
  177. package/dist/esm/components/DataTableGrouping/index.native.js +287 -134
  178. package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
  179. package/dist/esm/components/DataTablePagination/index.mjs +148 -96
  180. package/dist/esm/components/DataTablePagination/index.mjs.map +1 -1
  181. package/dist/esm/components/DataTablePagination/index.native.js +160 -107
  182. package/dist/esm/components/DataTablePagination/index.native.js.map +1 -1
  183. package/dist/esm/components/DataTableSearch/index.mjs +256 -215
  184. package/dist/esm/components/DataTableSearch/index.mjs.map +1 -1
  185. package/dist/esm/components/DataTableSearch/index.native.js +297 -248
  186. package/dist/esm/components/DataTableSearch/index.native.js.map +1 -1
  187. package/dist/esm/components/DataTableToolbar/index.mjs +145 -119
  188. package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
  189. package/dist/esm/components/DataTableToolbar/index.native.js +167 -152
  190. package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
  191. package/dist/esm/components/DataTableViewOptions/index.mjs +26 -22
  192. package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
  193. package/dist/esm/components/DataTableViewOptions/index.native.js +7 -5
  194. package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
  195. package/dist/esm/components/SimpleTable/index.mjs +338 -48
  196. package/dist/esm/components/SimpleTable/index.mjs.map +1 -1
  197. package/dist/esm/components/SimpleTable/index.native.js +358 -50
  198. package/dist/esm/components/SimpleTable/index.native.js.map +1 -1
  199. package/dist/esm/components/TableInput/index.mjs +150 -41
  200. package/dist/esm/components/TableInput/index.mjs.map +1 -1
  201. package/dist/esm/components/TableInput/index.native.js +55 -39
  202. package/dist/esm/components/TableInput/index.native.js.map +1 -1
  203. package/dist/esm/components/TableInput/shared.mjs +34 -1
  204. package/dist/esm/components/TableInput/shared.mjs.map +1 -1
  205. package/dist/esm/components/TableInput/shared.native.js +34 -1
  206. package/dist/esm/components/TableInput/shared.native.js.map +1 -1
  207. package/dist/esm/hooks/useDataTable.mjs +33 -2
  208. package/dist/esm/hooks/useDataTable.mjs.map +1 -1
  209. package/dist/esm/hooks/useDataTable.native.js +41 -2
  210. package/dist/esm/hooks/useDataTable.native.js.map +1 -1
  211. package/dist/esm/hooks/useInfiniteRows.mjs +20 -3
  212. package/dist/esm/hooks/useInfiniteRows.mjs.map +1 -1
  213. package/dist/esm/hooks/useInfiniteRows.native.js +20 -3
  214. package/dist/esm/hooks/useInfiniteRows.native.js.map +1 -1
  215. package/dist/esm/index.mjs +2 -1
  216. package/dist/esm/index.mjs.map +1 -1
  217. package/dist/esm/index.native.js +2 -1
  218. package/dist/esm/index.native.js.map +1 -1
  219. package/dist/esm/utils/filterUtils.mjs +12 -5
  220. package/dist/esm/utils/filterUtils.mjs.map +1 -1
  221. package/dist/esm/utils/filterUtils.native.js +20 -5
  222. package/dist/esm/utils/filterUtils.native.js.map +1 -1
  223. package/dist/jsx/components/ChildTable/index.mjs +2 -1
  224. package/dist/jsx/components/ChildTable/index.mjs.map +1 -1
  225. package/dist/jsx/components/ChildTable/index.native.js +2 -1
  226. package/dist/jsx/components/ChildTable/index.native.js.map +1 -1
  227. package/dist/jsx/components/ColumnHeaderFilter/index.mjs +17 -9
  228. package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
  229. package/dist/jsx/components/ColumnHeaderFilter/index.native.js +32 -11
  230. package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
  231. package/dist/jsx/components/DataTable/DataTableDocumentList.mjs +196 -0
  232. package/dist/jsx/components/DataTable/DataTableDocumentList.mjs.map +1 -0
  233. package/dist/jsx/components/DataTable/DataTableDocumentList.native.js +237 -0
  234. package/dist/jsx/components/DataTable/DataTableDocumentList.native.js.map +1 -0
  235. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs +5 -2
  236. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  237. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js +6 -2
  238. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  239. package/dist/jsx/components/DataTable/DataTableRoot.mjs +93 -42
  240. package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
  241. package/dist/jsx/components/DataTable/DataTableRoot.native.js +97 -43
  242. package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
  243. package/dist/jsx/components/DataTable/DataTableVirtualized.mjs +8 -2
  244. package/dist/jsx/components/DataTable/DataTableVirtualized.mjs.map +1 -1
  245. package/dist/jsx/components/DataTable/DataTableVirtualized.native.js +9 -3
  246. package/dist/jsx/components/DataTable/DataTableVirtualized.native.js.map +1 -1
  247. package/dist/jsx/components/DataTable/documentListSlots.mjs +33 -0
  248. package/dist/jsx/components/DataTable/documentListSlots.mjs.map +1 -0
  249. package/dist/jsx/components/DataTable/documentListSlots.native.js +85 -0
  250. package/dist/jsx/components/DataTable/documentListSlots.native.js.map +1 -0
  251. package/dist/jsx/components/DataTable/index.native.js +74 -59
  252. package/dist/jsx/components/DataTable/index.native.js.map +1 -1
  253. package/dist/jsx/components/DataTable/rowStateChrome.mjs +28 -0
  254. package/dist/jsx/components/DataTable/rowStateChrome.mjs.map +1 -0
  255. package/dist/jsx/components/DataTable/rowStateChrome.native.js +59 -0
  256. package/dist/jsx/components/DataTable/rowStateChrome.native.js.map +1 -0
  257. package/dist/jsx/components/DataTableCell/CellModalEditor.mjs +25 -4
  258. package/dist/jsx/components/DataTableCell/CellModalEditor.mjs.map +1 -1
  259. package/dist/jsx/components/DataTableCell/CellModalEditor.native.js +6 -1
  260. package/dist/jsx/components/DataTableCell/CellModalEditor.native.js.map +1 -1
  261. package/dist/jsx/components/DataTableCell/CellOptionsEditor.mjs +9 -2
  262. package/dist/jsx/components/DataTableCell/CellOptionsEditor.mjs.map +1 -1
  263. package/dist/jsx/components/DataTableCell/CellOptionsEditor.native.js +11 -2
  264. package/dist/jsx/components/DataTableCell/CellOptionsEditor.native.js.map +1 -1
  265. package/dist/jsx/components/DataTableCell/index.mjs +75 -64
  266. package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
  267. package/dist/jsx/components/DataTableCell/index.native.js +94 -82
  268. package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
  269. package/dist/jsx/components/DataTableColumnPinning/index.mjs +54 -37
  270. package/dist/jsx/components/DataTableColumnPinning/index.mjs.map +1 -1
  271. package/dist/jsx/components/DataTableColumnPinning/index.native.js +59 -38
  272. package/dist/jsx/components/DataTableColumnPinning/index.native.js.map +1 -1
  273. package/dist/jsx/components/DataTableDateFilter/index.mjs +34 -15
  274. package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
  275. package/dist/jsx/components/DataTableDateFilter/index.native.js +33 -12
  276. package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
  277. package/dist/jsx/components/DataTableExport/index.mjs +36 -8
  278. package/dist/jsx/components/DataTableExport/index.mjs.map +1 -1
  279. package/dist/jsx/components/DataTableExport/index.native.js +42 -7
  280. package/dist/jsx/components/DataTableExport/index.native.js.map +1 -1
  281. package/dist/jsx/components/DataTableFacetMenu/index.mjs +115 -0
  282. package/dist/jsx/components/DataTableFacetMenu/index.mjs.map +1 -0
  283. package/dist/jsx/components/DataTableFacetMenu/index.native.js +156 -0
  284. package/dist/jsx/components/DataTableFacetMenu/index.native.js.map +1 -0
  285. package/dist/jsx/components/DataTableFilterButton/index.mjs +54 -35
  286. package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
  287. package/dist/jsx/components/DataTableFilterButton/index.native.js +63 -40
  288. package/dist/jsx/components/DataTableFilterButton/index.native.js.map +1 -1
  289. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs +118 -0
  290. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs.map +1 -0
  291. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js +148 -0
  292. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js.map +1 -0
  293. package/dist/jsx/components/DataTableFilterChips/index.mjs +9 -32
  294. package/dist/jsx/components/DataTableFilterChips/index.mjs.map +1 -1
  295. package/dist/jsx/components/DataTableFilterChips/index.native.js +9 -32
  296. package/dist/jsx/components/DataTableFilterChips/index.native.js.map +1 -1
  297. package/dist/jsx/components/DataTableFilters/index.mjs +149 -506
  298. package/dist/jsx/components/DataTableFilters/index.mjs.map +1 -1
  299. package/dist/jsx/components/DataTableFilters/index.native.js +171 -544
  300. package/dist/jsx/components/DataTableFilters/index.native.js.map +1 -1
  301. package/dist/jsx/components/DataTableGrouping/index.mjs +275 -110
  302. package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
  303. package/dist/jsx/components/DataTableGrouping/index.native.js +310 -157
  304. package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
  305. package/dist/jsx/components/DataTablePagination/index.mjs +148 -96
  306. package/dist/jsx/components/DataTablePagination/index.mjs.map +1 -1
  307. package/dist/jsx/components/DataTablePagination/index.native.js +159 -106
  308. package/dist/jsx/components/DataTablePagination/index.native.js.map +1 -1
  309. package/dist/jsx/components/DataTableSearch/index.mjs +256 -215
  310. package/dist/jsx/components/DataTableSearch/index.mjs.map +1 -1
  311. package/dist/jsx/components/DataTableSearch/index.native.js +292 -243
  312. package/dist/jsx/components/DataTableSearch/index.native.js.map +1 -1
  313. package/dist/jsx/components/DataTableToolbar/index.mjs +145 -119
  314. package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
  315. package/dist/jsx/components/DataTableToolbar/index.native.js +163 -148
  316. package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
  317. package/dist/jsx/components/DataTableViewOptions/index.mjs +26 -22
  318. package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
  319. package/dist/jsx/components/DataTableViewOptions/index.native.js +6 -4
  320. package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
  321. package/dist/jsx/components/SimpleTable/index.mjs +338 -48
  322. package/dist/jsx/components/SimpleTable/index.mjs.map +1 -1
  323. package/dist/jsx/components/SimpleTable/index.native.js +356 -48
  324. package/dist/jsx/components/SimpleTable/index.native.js.map +1 -1
  325. package/dist/jsx/components/TableInput/index.mjs +150 -41
  326. package/dist/jsx/components/TableInput/index.mjs.map +1 -1
  327. package/dist/jsx/components/TableInput/index.native.js +54 -38
  328. package/dist/jsx/components/TableInput/index.native.js.map +1 -1
  329. package/dist/jsx/components/TableInput/shared.mjs +34 -1
  330. package/dist/jsx/components/TableInput/shared.mjs.map +1 -1
  331. package/dist/jsx/components/TableInput/shared.native.js +35 -0
  332. package/dist/jsx/components/TableInput/shared.native.js.map +1 -1
  333. package/dist/jsx/hooks/useDataTable.mjs +33 -2
  334. package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
  335. package/dist/jsx/hooks/useDataTable.native.js +41 -2
  336. package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
  337. package/dist/jsx/hooks/useInfiniteRows.mjs +20 -3
  338. package/dist/jsx/hooks/useInfiniteRows.mjs.map +1 -1
  339. package/dist/jsx/hooks/useInfiniteRows.native.js +20 -3
  340. package/dist/jsx/hooks/useInfiniteRows.native.js.map +1 -1
  341. package/dist/jsx/index.js +2 -1
  342. package/dist/jsx/index.js.map +1 -1
  343. package/dist/jsx/index.mjs +2 -1
  344. package/dist/jsx/index.mjs.map +1 -1
  345. package/dist/jsx/index.native.js +2 -0
  346. package/dist/jsx/index.native.js.map +1 -1
  347. package/dist/jsx/utils/filterUtils.mjs +12 -5
  348. package/dist/jsx/utils/filterUtils.mjs.map +1 -1
  349. package/dist/jsx/utils/filterUtils.native.js +20 -5
  350. package/dist/jsx/utils/filterUtils.native.js.map +1 -1
  351. package/package.json +15 -15
  352. package/src/components/ChildTable/index.tsx +1 -0
  353. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.spec.tsx +85 -0
  354. package/src/components/ColumnHeaderFilter/index.tsx +28 -10
  355. package/src/components/DataTable/DataTable.stories.tsx +30 -0
  356. package/src/components/DataTable/DataTableDocumentList.tsx +224 -0
  357. package/src/components/DataTable/DataTableMobileCards.tsx +20 -8
  358. package/src/components/DataTable/DataTableRoot.tsx +135 -58
  359. package/src/components/DataTable/DataTableVirtualized.tsx +8 -11
  360. package/src/components/DataTable/cardLayout.spec.tsx +89 -0
  361. package/src/components/DataTable/documentListSlots.ts +57 -0
  362. package/src/components/DataTable/index.native.tsx +76 -50
  363. package/src/components/DataTable/keepPreviousData.spec.tsx +137 -0
  364. package/src/components/DataTable/rowRing.spec.tsx +118 -0
  365. package/src/components/DataTable/rowStateChrome.ts +38 -0
  366. package/src/components/DataTableCell/CellModalEditor.native.tsx +4 -0
  367. package/src/components/DataTableCell/CellModalEditor.tsx +31 -3
  368. package/src/components/DataTableCell/CellOptionsEditor.tsx +29 -12
  369. package/src/components/DataTableCell/DataTableCell.stories.tsx +3 -3
  370. package/src/components/DataTableCell/cellDraftPolicy.spec.tsx +131 -4
  371. package/src/components/DataTableCell/dataTableCell.spec.tsx +36 -1
  372. package/src/components/DataTableCell/index.tsx +121 -86
  373. package/src/components/DataTableColumnPinning/DataTableColumnPinning.spec.tsx +66 -0
  374. package/src/components/DataTableColumnPinning/index.tsx +32 -17
  375. package/src/components/DataTableDateFilter/DataTableDateFilter.spec.tsx +9 -1
  376. package/src/components/DataTableDateFilter/dateFilterZones.spec.ts +316 -0
  377. package/src/components/DataTableDateFilter/index.tsx +42 -22
  378. package/src/components/DataTableExport/exportDateZones.spec.tsx +348 -0
  379. package/src/components/DataTableExport/index.tsx +107 -63
  380. package/src/components/DataTableFacetMenu/DataTableFacetMenu.spec.tsx +264 -0
  381. package/src/components/DataTableFacetMenu/DataTableFacetMenu.stories.tsx +212 -0
  382. package/src/components/DataTableFacetMenu/index.tsx +202 -0
  383. package/src/components/DataTableFilterButton/index.tsx +66 -49
  384. package/src/components/DataTableFilterChips/DataTableFilterChips.spec.tsx +22 -0
  385. package/src/components/DataTableFilterChips/FilterChip.tsx +122 -0
  386. package/src/components/DataTableFilterChips/index.tsx +13 -29
  387. package/src/components/DataTableFilters/DataTableFilters.spec.tsx +56 -0
  388. package/src/components/DataTableFilters/index.tsx +169 -584
  389. package/src/components/DataTableGrouping/DataTableGrouping.spec.tsx +85 -0
  390. package/src/components/DataTableGrouping/index.tsx +270 -130
  391. package/src/components/DataTablePagination/DataTablePagination.spec.tsx +79 -4
  392. package/src/components/DataTablePagination/index.tsx +168 -112
  393. package/src/components/DataTableSearch/DataTableSearch.spec.tsx +40 -0
  394. package/src/components/DataTableSearch/DataTableSearch.stories.tsx +1 -1
  395. package/src/components/DataTableSearch/index.tsx +192 -163
  396. package/src/components/DataTableToolbar/DataTableToolbar.spec.tsx +48 -18
  397. package/src/components/DataTableToolbar/DataTableToolbar.stories.tsx +5 -45
  398. package/src/components/DataTableToolbar/index.tsx +128 -99
  399. package/src/components/DataTableViewOptions/index.tsx +29 -22
  400. package/src/components/SimpleTable/SimpleTable.stories.tsx +29 -5
  401. package/src/components/SimpleTable/index.tsx +442 -61
  402. package/src/components/SimpleTable/simpleTable.spec.tsx +140 -12
  403. package/src/components/TableInput/index.native.tsx +91 -81
  404. package/src/components/TableInput/index.tsx +191 -50
  405. package/src/components/TableInput/shared.ts +57 -0
  406. package/src/components/TableInput/tableInput.spec.tsx +104 -0
  407. package/src/hooks/useDataTable.spec.ts +100 -3
  408. package/src/hooks/useDataTable.ts +44 -1
  409. package/src/hooks/useInfiniteRows.spec.tsx +37 -0
  410. package/src/hooks/useInfiniteRows.ts +34 -4
  411. package/src/index.ts +7 -0
  412. package/src/types.ts +54 -3
  413. package/src/utils/filterUtils.ts +27 -5
  414. package/types/components/ChildTable/index.d.ts.map +1 -1
  415. package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
  416. package/types/components/DataTable/DataTableDocumentList.d.ts +32 -0
  417. package/types/components/DataTable/DataTableDocumentList.d.ts.map +1 -0
  418. package/types/components/DataTable/DataTableMobileCards.d.ts +3 -1
  419. package/types/components/DataTable/DataTableMobileCards.d.ts.map +1 -1
  420. package/types/components/DataTable/DataTableRoot.d.ts +1 -1
  421. package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
  422. package/types/components/DataTable/DataTableVirtualized.d.ts +1 -2
  423. package/types/components/DataTable/DataTableVirtualized.d.ts.map +1 -1
  424. package/types/components/DataTable/documentListSlots.d.ts +26 -0
  425. package/types/components/DataTable/documentListSlots.d.ts.map +1 -0
  426. package/types/components/DataTable/index.native.d.ts +1 -1
  427. package/types/components/DataTable/index.native.d.ts.map +1 -1
  428. package/types/components/DataTable/rowStateChrome.d.ts +18 -0
  429. package/types/components/DataTable/rowStateChrome.d.ts.map +1 -0
  430. package/types/components/DataTableCell/CellModalEditor.d.ts +6 -1
  431. package/types/components/DataTableCell/CellModalEditor.d.ts.map +1 -1
  432. package/types/components/DataTableCell/CellModalEditor.native.d.ts +1 -1
  433. package/types/components/DataTableCell/CellModalEditor.native.d.ts.map +1 -1
  434. package/types/components/DataTableCell/CellOptionsEditor.d.ts +11 -3
  435. package/types/components/DataTableCell/CellOptionsEditor.d.ts.map +1 -1
  436. package/types/components/DataTableCell/index.d.ts +1 -1
  437. package/types/components/DataTableCell/index.d.ts.map +1 -1
  438. package/types/components/DataTableColumnPinning/index.d.ts.map +1 -1
  439. package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
  440. package/types/components/DataTableExport/index.d.ts +17 -6
  441. package/types/components/DataTableExport/index.d.ts.map +1 -1
  442. package/types/components/DataTableFacetMenu/index.d.ts +84 -0
  443. package/types/components/DataTableFacetMenu/index.d.ts.map +1 -0
  444. package/types/components/DataTableFilterButton/index.d.ts.map +1 -1
  445. package/types/components/DataTableFilterChips/FilterChip.d.ts +15 -0
  446. package/types/components/DataTableFilterChips/FilterChip.d.ts.map +1 -0
  447. package/types/components/DataTableFilterChips/index.d.ts +5 -0
  448. package/types/components/DataTableFilterChips/index.d.ts.map +1 -1
  449. package/types/components/DataTableFilters/index.d.ts +11 -0
  450. package/types/components/DataTableFilters/index.d.ts.map +1 -1
  451. package/types/components/DataTableGrouping/index.d.ts.map +1 -1
  452. package/types/components/DataTablePagination/index.d.ts +5 -0
  453. package/types/components/DataTablePagination/index.d.ts.map +1 -1
  454. package/types/components/DataTableSearch/index.d.ts.map +1 -1
  455. package/types/components/DataTableToolbar/index.d.ts +2 -0
  456. package/types/components/DataTableToolbar/index.d.ts.map +1 -1
  457. package/types/components/SimpleTable/index.d.ts +27 -5
  458. package/types/components/SimpleTable/index.d.ts.map +1 -1
  459. package/types/components/TableInput/index.d.ts +6 -1
  460. package/types/components/TableInput/index.d.ts.map +1 -1
  461. package/types/components/TableInput/index.native.d.ts +6 -1
  462. package/types/components/TableInput/index.native.d.ts.map +1 -1
  463. package/types/components/TableInput/shared.d.ts +38 -0
  464. package/types/components/TableInput/shared.d.ts.map +1 -1
  465. package/types/hooks/useDataTable.d.ts +1 -1
  466. package/types/hooks/useDataTable.d.ts.map +1 -1
  467. package/types/hooks/useInfiniteRows.d.ts +8 -1
  468. package/types/hooks/useInfiniteRows.d.ts.map +1 -1
  469. package/types/index.d.ts +1 -0
  470. package/types/index.d.ts.map +1 -1
  471. package/types/types.d.ts +54 -3
  472. package/types/types.d.ts.map +1 -1
  473. package/types/utils/filterUtils.d.ts.map +1 -1
@@ -0,0 +1,348 @@
1
+ /**
2
+ * What the export writes for a date-bearing column, across timezones.
3
+ *
4
+ * Every date cell in the grid displays through `formatAbsoluteDate`, which
5
+ * renders a `Date` in LOCAL time. The export rendered the same value with
6
+ * `toISOString()` — the UTC instant — so the exported date part named a
7
+ * different calendar day than the cell it came from whenever the value's
8
+ * local time of day sat across the UTC date boundary: the day BEFORE east of
9
+ * Greenwich, the day after west of it. A CSV that disagrees with the grid is
10
+ * what people reconcile against, so the day is the assertion here.
11
+ *
12
+ * Two frozen instants, because the span from UTC−7 to UTC+14 is 21 hours —
13
+ * under a day — so no single instant has UTC disagreeing with both extremes.
14
+ * Each matrix is paired with a negative control that runs the old
15
+ * `toISOString()` formulation through the identical expectation and asserts
16
+ * the exact set of cells where it disagrees, so the matrix cannot pass
17
+ * vacuously on values every zone happens to render the same way.
18
+ */
19
+
20
+ import { fireEvent, screen, waitFor } from "@testing-library/react";
21
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
22
+ import { formatAbsoluteDate } from "@multiplatform.one/theme";
23
+ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
24
+ import { DataTableExport } from "./index";
25
+
26
+ // Spans UTC, two negative offsets and the far positive extreme (UTC+14), so a
27
+ // serializer that leans on the host zone fails somewhere in this list.
28
+ const ZONES = ["UTC", "America/Los_Angeles", "America/New_York", "Pacific/Kiritimati"] as const;
29
+ type Zone = (typeof ZONES)[number];
30
+
31
+ /** Late evening in Los Angeles; still the 15th everywhere else. */
32
+ const INSTANT_A = "2026-08-15T05:00:00.000Z";
33
+ /** The small hours of the 15th in Kiritimati; still the 14th everywhere else. */
34
+ const INSTANT_B = "2026-08-14T11:00:00.000Z";
35
+
36
+ /**
37
+ * What the export must write, per zone. The `day` column is a calendar day —
38
+ * a `datepicker` hands back local midnight — and the two instant columns are
39
+ * real timestamps, kept as full ISO-8601 but stamped with the local offset so
40
+ * the day they lead with is the day the cell shows.
41
+ */
42
+ const EXPECTED: Record<Zone, { day: string; instantA: string; instantB: string }> = {
43
+ UTC: {
44
+ day: "2026-08-15",
45
+ instantA: "2026-08-15T05:00:00.000Z",
46
+ instantB: "2026-08-14T11:00:00.000Z",
47
+ },
48
+ "America/Los_Angeles": {
49
+ day: "2026-08-15",
50
+ instantA: "2026-08-14T22:00:00.000-07:00",
51
+ instantB: "2026-08-14T04:00:00.000-07:00",
52
+ },
53
+ "America/New_York": {
54
+ day: "2026-08-15",
55
+ instantA: "2026-08-15T01:00:00.000-04:00",
56
+ instantB: "2026-08-14T07:00:00.000-04:00",
57
+ },
58
+ "Pacific/Kiritimati": {
59
+ day: "2026-08-15",
60
+ instantA: "2026-08-15T19:00:00.000+14:00",
61
+ instantB: "2026-08-15T01:00:00.000+14:00",
62
+ },
63
+ };
64
+
65
+ const mockCreateObjectURL = vi.fn(() => "mock-url");
66
+
67
+ beforeAll(() => {
68
+ Object.defineProperty(window.URL, "createObjectURL", {
69
+ writable: true,
70
+ value: mockCreateObjectURL,
71
+ });
72
+ Object.defineProperty(window.URL, "revokeObjectURL", { writable: true, value: vi.fn() });
73
+ });
74
+
75
+ const originalTZ = process.env.TZ;
76
+ afterEach(() => {
77
+ if (originalTZ === undefined) delete process.env.TZ;
78
+ else process.env.TZ = originalTZ;
79
+ });
80
+
81
+ function inZone<T>(timeZone: string, read: () => T): T {
82
+ const previous = process.env.TZ;
83
+ process.env.TZ = timeZone;
84
+ try {
85
+ return read();
86
+ } finally {
87
+ if (previous === undefined) delete process.env.TZ;
88
+ else process.env.TZ = previous;
89
+ }
90
+ }
91
+
92
+ /** The single data row of the CSV the component just wrote. */
93
+ async function exportRow(data: any[], columns: any[]): Promise<string[]> {
94
+ mockCreateObjectURL.mockClear();
95
+ renderWithProviders(<DataTableExport data={data} columns={columns} />);
96
+ fireEvent.click(screen.getByText("CSV"));
97
+ await waitFor(() => expect(mockCreateObjectURL).toHaveBeenCalledWith(expect.any(Blob)));
98
+ const blob = (mockCreateObjectURL.mock.calls.at(-1) as unknown as [Blob])[0];
99
+ const text = await blob.text();
100
+ return text.trim().split("\n")[1]!.split(",");
101
+ }
102
+
103
+ /** The old formulation, verbatim, for the negative controls. */
104
+ function legacyExportValue(value: any): string {
105
+ if (value == null) return "";
106
+ if (value instanceof Date) return value.toISOString();
107
+ if (typeof value === "object") return JSON.stringify(value);
108
+ return String(value);
109
+ }
110
+
111
+ const dayPart = (iso: string) => iso.slice(0, 10);
112
+
113
+ describe("DataTableExport date rendering across timezones", () => {
114
+ describe.each(ZONES)("%s", (zone) => {
115
+ beforeEach(() => {
116
+ process.env.TZ = zone;
117
+ });
118
+
119
+ it("writes the calendar day the cell displays, for days and for instants", async () => {
120
+ // What a DatePicker hands back: local midnight standing in for a day.
121
+ const day = new Date(2026, 7, 15);
122
+ const row = {
123
+ day,
124
+ instantA: new Date(INSTANT_A),
125
+ instantB: new Date(INSTANT_B),
126
+ // No declared field — the export cannot know the class, so it keeps a
127
+ // full instant, and still leads with the displayed day.
128
+ loose: new Date(INSTANT_A),
129
+ };
130
+ const columns = [
131
+ { accessorKey: "day", header: "Day", field: "datepicker" as const },
132
+ { accessorKey: "instantA", header: "A", field: "datetimepicker" as const },
133
+ { accessorKey: "instantB", header: "B", field: "datetimepicker" as const },
134
+ { accessorKey: "loose", header: "Loose" },
135
+ ];
136
+
137
+ const [dayCell, aCell, bCell, looseCell] = await exportRow([row], columns);
138
+
139
+ expect(dayCell).toBe(EXPECTED[zone].day);
140
+ expect(aCell).toBe(EXPECTED[zone].instantA);
141
+ expect(bCell).toBe(EXPECTED[zone].instantB);
142
+ expect(looseCell).toBe(EXPECTED[zone].instantA);
143
+ });
144
+
145
+ it("agrees with the display register on every date-bearing column", async () => {
146
+ const row = {
147
+ day: new Date(2026, 7, 15),
148
+ instantA: new Date(INSTANT_A),
149
+ instantB: new Date(INSTANT_B),
150
+ };
151
+ const columns = [
152
+ { accessorKey: "day", header: "Day", field: "datepicker" as const },
153
+ { accessorKey: "instantA", header: "A", field: "datetimepicker" as const },
154
+ { accessorKey: "instantB", header: "B", field: "datetimepicker" as const },
155
+ ];
156
+
157
+ const cells = await exportRow([row], columns);
158
+
159
+ // The exported day, read back through the house register, is the label
160
+ // the cell renders for the same value. Stated in the register's own
161
+ // terms rather than by re-deriving local parts the way the fix does.
162
+ for (const [index, key] of (["day", "instantA", "instantB"] as const).entries()) {
163
+ expect(formatAbsoluteDate(dayPart(cells[index]!), { year: "always" })).toBe(
164
+ formatAbsoluteDate(row[key], { year: "always" }),
165
+ );
166
+ }
167
+ });
168
+
169
+ it("keeps instants lossless — the exported string re-reads as the same moment", async () => {
170
+ const instants = [new Date(INSTANT_A), new Date(INSTANT_B)];
171
+ const cells = await exportRow(
172
+ [{ a: instants[0], b: instants[1] }],
173
+ [
174
+ { accessorKey: "a", header: "A", field: "datetimepicker" as const },
175
+ { accessorKey: "b", header: "B", field: "datetimepicker" as const },
176
+ ],
177
+ );
178
+
179
+ expect(cells.map((cell) => new Date(cell).getTime())).toEqual(
180
+ instants.map((instant) => instant.getTime()),
181
+ );
182
+ });
183
+ });
184
+
185
+ it("host guard: TZ actually moves the in-process reading", () => {
186
+ // Without this, a host that stopped honouring TZ would make every matrix
187
+ // above pass by rendering the same thing four times. The negative control
188
+ // cannot cover it — toISOString() is UTC on a broken host too, so it would
189
+ // keep "disagreeing" in exactly the right places.
190
+ expect(inZone("America/Los_Angeles", () => new Date(INSTANT_A).getDate())).toBe(14);
191
+ expect(inZone("Pacific/Kiritimati", () => new Date(INSTANT_B).getDate())).toBe(15);
192
+ expect(
193
+ inZone("Pacific/Kiritimati", () => new Date(2026, 7, 15).toISOString().slice(0, 10)),
194
+ ).toBe("2026-08-14");
195
+ });
196
+
197
+ it("negative control: the old toISOString() names the wrong day in exactly three cells", () => {
198
+ const disagreements: string[] = [];
199
+ for (const zone of ZONES) {
200
+ inZone(zone, () => {
201
+ const cells = {
202
+ day: { value: new Date(2026, 7, 15), want: EXPECTED[zone].day },
203
+ instantA: { value: new Date(INSTANT_A), want: dayPart(EXPECTED[zone].instantA) },
204
+ instantB: { value: new Date(INSTANT_B), want: dayPart(EXPECTED[zone].instantB) },
205
+ };
206
+ for (const [name, { value, want }] of Object.entries(cells)) {
207
+ const wrote = dayPart(legacyExportValue(value));
208
+ if (wrote !== want) disagreements.push(`${zone}/${name}: wrote ${wrote} want ${want}`);
209
+ }
210
+ });
211
+ }
212
+
213
+ // A calendar day written as UTC lands a day early east of Greenwich; an
214
+ // instant rendered in UTC lands a day late west of it. Nine of the twelve
215
+ // cells agree, which is why this shipped — and why the matrix above is
216
+ // discriminating rather than a restatement of toISOString().
217
+ expect(disagreements).toEqual([
218
+ "America/Los_Angeles/instantA: wrote 2026-08-15 want 2026-08-14",
219
+ "Pacific/Kiritimati/day: wrote 2026-08-14 want 2026-08-15",
220
+ "Pacific/Kiritimati/instantB: wrote 2026-08-14 want 2026-08-15",
221
+ ]);
222
+ });
223
+
224
+ it("negative control: the old formulation was lossless too — only the day was wrong", () => {
225
+ // Names what did NOT change, so the fix is not read as trading precision
226
+ // for a readable day. Both formulations denote the same instant; only one
227
+ // of them leads with the day the user was looking at.
228
+ for (const zone of ZONES) {
229
+ inZone(zone, () => {
230
+ const instant = new Date(INSTANT_B);
231
+ expect(new Date(legacyExportValue(instant)).getTime()).toBe(instant.getTime());
232
+ expect(new Date(EXPECTED[zone].instantB).getTime()).toBe(instant.getTime());
233
+ });
234
+ }
235
+ });
236
+ });
237
+
238
+ describe("DataTableExport date rendering, other channels", () => {
239
+ beforeEach(() => {
240
+ process.env.TZ = "Pacific/Kiritimati";
241
+ });
242
+
243
+ it("copies string values verbatim — the export never reinterprets source text", async () => {
244
+ const cells = await exportRow(
245
+ [{ wireDay: "2026-08-15", wireStamp: INSTANT_A, code: "5-1" }],
246
+ [
247
+ { accessorKey: "wireDay", header: "Day", field: "datepicker" as const },
248
+ { accessorKey: "wireStamp", header: "Stamp", field: "datetimepicker" as const },
249
+ { accessorKey: "code", header: "Code" },
250
+ ],
251
+ );
252
+
253
+ // A bare calendar day already names its day and the grid renders it in
254
+ // UTC, so the two already agree. `code` is the reason the export does not
255
+ // sniff strings for dates: "5-1" is a product code that Date.parse would
256
+ // happily read as the 1st of May.
257
+ expect(cells).toEqual(["2026-08-15", INSTANT_A, "5-1"]);
258
+ expect(new Date("5-1").getMonth()).toBe(4);
259
+ });
260
+
261
+ it("renders Dates nested in a range or a multi-date array, not their UTC day", async () => {
262
+ const cells = await exportRow(
263
+ [
264
+ {
265
+ range: { start: new Date(2026, 7, 15), end: new Date(2026, 7, 17) },
266
+ days: [new Date(2026, 7, 15), new Date(2026, 7, 16)],
267
+ },
268
+ ],
269
+ [
270
+ { accessorKey: "range", header: "Range", field: "daterangepicker" as const },
271
+ { accessorKey: "days", header: "Days", field: "multidatepicker" as const },
272
+ ],
273
+ );
274
+
275
+ // JSON.stringify reaches Date.prototype.toJSON, which is toISOString() —
276
+ // the same UTC shift, one level down. At +14 these each read a day early.
277
+ expect(cells.join(",")).toBe(
278
+ '"{""start"":""2026-08-15"",""end"":""2026-08-17""}","[""2026-08-15"",""2026-08-16""]"',
279
+ );
280
+ });
281
+
282
+ it("writes the displayed day in the JSON export, and leaves other types native", async () => {
283
+ mockCreateObjectURL.mockClear();
284
+ renderWithProviders(
285
+ <DataTableExport
286
+ data={[{ due: new Date(2026, 7, 15), at: new Date(INSTANT_B), qty: 3, ok: false }]}
287
+ columns={[
288
+ { accessorKey: "due", header: "Due", field: "datepicker" },
289
+ { accessorKey: "at", header: "At", field: "datetimepicker" },
290
+ { accessorKey: "qty", header: "Qty" },
291
+ { accessorKey: "ok", header: "Ok" },
292
+ ]}
293
+ exportFormats={[
294
+ {
295
+ id: "json",
296
+ label: "JSON",
297
+ icon: null,
298
+ extension: "json",
299
+ mimeType: "application/json",
300
+ description: "JSON",
301
+ enabled: true,
302
+ },
303
+ ]}
304
+ />,
305
+ );
306
+
307
+ fireEvent.click(screen.getByText("JSON"));
308
+ await waitFor(() => expect(mockCreateObjectURL).toHaveBeenCalledWith(expect.any(Blob)));
309
+ const blob = (mockCreateObjectURL.mock.calls.at(-1) as unknown as [Blob])[0];
310
+
311
+ expect(JSON.parse(await blob.text())).toEqual([
312
+ { due: "2026-08-15", at: "2026-08-15T01:00:00.000+14:00", qty: 3, ok: false },
313
+ ]);
314
+ });
315
+
316
+ it("prints the same day it exports", async () => {
317
+ const printDoc = document.implementation.createHTMLDocument("print");
318
+ const print = vi.fn();
319
+ vi.spyOn(window, "open").mockReturnValue({ document: printDoc, print } as any);
320
+
321
+ renderWithProviders(
322
+ <DataTableExport
323
+ data={[{ due: new Date(2026, 7, 15) }]}
324
+ columns={[{ accessorKey: "due", header: "Due", field: "datepicker" }]}
325
+ />,
326
+ );
327
+ fireEvent.click(screen.getByText("Print"));
328
+
329
+ await waitFor(() => expect(print).toHaveBeenCalled());
330
+ expect(printDoc.querySelector("td")?.textContent).toBe("2026-08-15");
331
+ vi.restoreAllMocks();
332
+ });
333
+
334
+ it("blanks an unparseable Date instead of failing the whole export", async () => {
335
+ // toISOString() throws RangeError on an invalid Date, which surfaced as
336
+ // "Export failed" for the entire file rather than one empty cell.
337
+ expect(() => legacyExportValue(new Date("nonsense"))).toThrow(RangeError);
338
+
339
+ const cells = await exportRow(
340
+ [{ due: new Date("nonsense"), name: "Widget" }],
341
+ [
342
+ { accessorKey: "due", header: "Due", field: "datepicker" as const },
343
+ { accessorKey: "name", header: "Name" },
344
+ ],
345
+ );
346
+ expect(cells).toEqual(["", "Widget"]);
347
+ });
348
+ });
@@ -6,10 +6,11 @@ import {
6
6
  GearIcon,
7
7
  } from "@phosphor-icons/react";
8
8
  import { downloadBlob } from "@multiplatform.one/platform";
9
- import { useResolvedKnobs } from "@multiplatform.one/theme";
9
+ import { formatCalendarDate, useResolvedKnobs } from "@multiplatform.one/theme";
10
10
  import { useState } from "react";
11
11
  import { Button, Checkbox, Input } from "@multiplatform.one/forms";
12
12
  import { Popover, ScrollView, Separator, Text, XStack, YStack } from "tamagui";
13
+ import type { DataTableField } from "../../types";
13
14
  import { getViewLeafRows } from "../../utils/viewData";
14
15
  import { useDataTableState } from "../DataTable/DataTableStateContext";
15
16
 
@@ -37,14 +38,25 @@ export interface ExportFormat {
37
38
  enabled: boolean;
38
39
  }
39
40
 
41
+ /**
42
+ * Column metadata the export needs. Structurally a subset of
43
+ * `DataTableColumn`, so table column defs pass straight through.
44
+ */
45
+ export interface ExportColumn {
46
+ accessorKey?: string;
47
+ header?: string;
48
+ id?: string;
49
+ cell?: (info: any) => any;
50
+ /**
51
+ * The column's editor type. Only read to tell a calendar day apart from an
52
+ * instant when serializing `Date` values — see `toExportValue`.
53
+ */
54
+ field?: DataTableField;
55
+ }
56
+
40
57
  export interface DataTableExportProps<T = any> {
41
58
  data?: T[];
42
- columns?: Array<{
43
- accessorKey?: string;
44
- header?: string;
45
- id?: string;
46
- cell?: (info: any) => any;
47
- }>;
59
+ columns?: ExportColumn[];
48
60
  filename?: string;
49
61
  exportFormats?: ExportFormat[];
50
62
  onExport?: (options: ExportOptions) => Promise<void>;
@@ -223,14 +235,14 @@ export function DataTableExport<T = any>(props: DataTableExportProps<T>) {
223
235
  // Extract column metadata from TanStack Table instance for context fallback.
224
236
  // Visible leaf columns only, in display order — hidden columns are excluded
225
237
  // from the export and column reordering/pinning is honored.
226
- function extractColumnsFromTable(
227
- table: any,
228
- ): Array<{ accessorKey?: string; header?: string; id?: string }> {
238
+ function extractColumnsFromTable(table: any): ExportColumn[] {
229
239
  try {
230
240
  return table.getVisibleLeafColumns().map((col: any) => ({
231
241
  id: col.id,
232
242
  accessorKey: col.id,
233
243
  header: typeof col.columnDef.header === "string" ? col.columnDef.header : col.id,
244
+ // Carried so date columns export the calendar day the cell renders.
245
+ field: col.columnDef.field,
234
246
  }));
235
247
  } catch {
236
248
  return [];
@@ -247,12 +259,7 @@ interface ExportOptionsPopoverProps {
247
259
  onPrint: () => void;
248
260
  disabled: boolean;
249
261
  isExporting: string | null;
250
- columns: Array<{
251
- accessorKey?: string;
252
- header?: string;
253
- id?: string;
254
- cell?: (info: any) => any;
255
- }>;
262
+ columns: ExportColumn[];
256
263
  }
257
264
 
258
265
  function ExportOptionsPopover({
@@ -437,12 +444,7 @@ function ExportOptionsPopover({
437
444
 
438
445
  async function defaultExport<T>(
439
446
  data: T[],
440
- columns: Array<{
441
- accessorKey?: string;
442
- header?: string;
443
- id?: string;
444
- cell?: (info: any) => any;
445
- }>,
447
+ columns: ExportColumn[],
446
448
  options: ExportOptions,
447
449
  ): Promise<void> {
448
450
  const { format, selectedColumns } = options;
@@ -466,18 +468,85 @@ async function defaultExport<T>(
466
468
  }
467
469
  }
468
470
 
471
+ /**
472
+ * Editor types whose value is a calendar DAY rather than an instant. A
473
+ * `datepicker` hands back `new Date(y, m, d)` — local midnight standing in for
474
+ * a day with no time in it — so the export writes the day and nothing else.
475
+ * Every other date editor (`datetimepicker`) means a real timestamp.
476
+ */
477
+ const CALENDAR_DAY_FIELDS: ReadonlySet<DataTableField> = new Set<DataTableField>([
478
+ "datepicker",
479
+ "daterangepicker",
480
+ "multidatepicker",
481
+ ]);
482
+
483
+ function isCalendarDayColumn(column?: ExportColumn): boolean {
484
+ return column?.field != null && CALENDAR_DAY_FIELDS.has(column.field);
485
+ }
486
+
487
+ const pad2 = (n: number) => String(n).padStart(2, "0");
488
+
489
+ /**
490
+ * Render a `Date` onto the LOCAL calendar, which is the calendar the grid
491
+ * shows: every date cell displays through `formatAbsoluteDate`, and that
492
+ * formats a `Date` in local time. `toISOString()` renders the UTC instant
493
+ * instead, so east of Greenwich the exported date part named the day BEFORE
494
+ * the one in the cell the user was looking at (and west of it, the day after).
495
+ *
496
+ * A calendar-day column emits the bare day. An instant keeps full ISO-8601 —
497
+ * still lossless and still `Date.parse`-able — but stamped with the local
498
+ * offset rather than `Z`, so the same instant now leads with the displayed
499
+ * day. At UTC the two renderings are byte-identical, which is why this only
500
+ * ever looked correct.
501
+ */
502
+ function serializeExportDate(value: Date, calendarDay: boolean): string {
503
+ if (Number.isNaN(value.getTime())) return "";
504
+ if (calendarDay) return formatCalendarDate(value, "date");
505
+ const offsetMinutes = -value.getTimezoneOffset();
506
+ const sign = offsetMinutes < 0 ? "-" : "+";
507
+ const abs = Math.abs(offsetMinutes);
508
+ const offset =
509
+ offsetMinutes === 0 ? "Z" : `${sign}${pad2(Math.trunc(abs / 60))}:${pad2(abs % 60)}`;
510
+ const ms = String(value.getMilliseconds()).padStart(3, "0");
511
+ return `${formatCalendarDate(value, "datetime").replace(" ", "T")}.${ms}${offset}`;
512
+ }
513
+
514
+ /**
515
+ * Replace every `Date` reachable inside an array or plain object (a picked
516
+ * `{start,end}` range, a multi-date array) before it reaches JSON.
517
+ * `JSON.stringify` calls `Date.prototype.toJSON`, which is `toISOString()` —
518
+ * the same UTC day-shift, one level down.
519
+ */
520
+ function withExportDates(value: any, calendarDay: boolean): any {
521
+ if (value instanceof Date) return serializeExportDate(value, calendarDay);
522
+ if (Array.isArray(value)) return value.map((item) => withExportDates(item, calendarDay));
523
+ if (value != null && typeof value === "object") {
524
+ const proto = Object.getPrototypeOf(value);
525
+ if (proto !== Object.prototype && proto !== null) return value;
526
+ return Object.fromEntries(
527
+ Object.entries(value).map(([key, item]) => [key, withExportDates(item, calendarDay)]),
528
+ );
529
+ }
530
+ return value;
531
+ }
532
+
469
533
  /**
470
534
  * Serialize a raw cell value for export. Nullish → empty string, but falsy
471
535
  * values like 0 and false survive (String(value || "") used to blank them).
472
- * Dates become ISO strings and plain objects JSON so nothing ever exports
473
- * as "[object Object]".
536
+ * Dates render on the calendar the cell displays and plain objects become
537
+ * JSON so nothing ever exports as "[object Object]".
538
+ *
539
+ * Values already held as strings are copied verbatim — the export never
540
+ * reinterprets source text. It only picks a rendering where the row leaves it
541
+ * no choice, which is when the value is a `Date`.
474
542
  */
475
- function toExportValue(value: any): string {
543
+ function toExportValue(value: any, column?: ExportColumn): string {
476
544
  if (value == null) return "";
477
- if (value instanceof Date) return value.toISOString();
545
+ const calendarDay = isCalendarDayColumn(column);
546
+ if (value instanceof Date) return serializeExportDate(value, calendarDay);
478
547
  if (typeof value === "object") {
479
548
  try {
480
- return JSON.stringify(value);
549
+ return JSON.stringify(withExportDates(value, calendarDay));
481
550
  } catch {
482
551
  return String(value);
483
552
  }
@@ -504,12 +573,7 @@ function guardCsvInjection(raw: any, value: string): string {
504
573
  // CSV Export
505
574
  async function exportAsCSV<T>(
506
575
  data: T[],
507
- columns: Array<{
508
- accessorKey?: string;
509
- header?: string;
510
- id?: string;
511
- cell?: (info: any) => any;
512
- }>,
576
+ columns: ExportColumn[],
513
577
  options: ExportOptions,
514
578
  ): Promise<void> {
515
579
  const { includeHeaders = true, filename = "export" } = options;
@@ -532,7 +596,7 @@ async function exportAsCSV<T>(
532
596
  // stringifies to "[object Object]") and bake presentation into the data,
533
597
  // so they are intentionally NOT invoked here.
534
598
  const raw = (row as any)[key];
535
- return escapeCsvField(guardCsvInjection(raw, toExportValue(raw)));
599
+ return escapeCsvField(guardCsvInjection(raw, toExportValue(raw, col)));
536
600
  });
537
601
  csvContent += `${values.join(",")}\n`;
538
602
  });
@@ -543,12 +607,7 @@ async function exportAsCSV<T>(
543
607
  // JSON Export
544
608
  async function exportAsJSON<T>(
545
609
  data: T[],
546
- columns: Array<{
547
- accessorKey?: string;
548
- header?: string;
549
- id?: string;
550
- cell?: (info: any) => any;
551
- }>,
610
+ columns: ExportColumn[],
552
611
  options: ExportOptions,
553
612
  ): Promise<void> {
554
613
  const { filename = "export" } = options;
@@ -557,7 +616,10 @@ async function exportAsJSON<T>(
557
616
  const obj: any = {};
558
617
  columns.forEach((col) => {
559
618
  const key = col.accessorKey || col.id || "";
560
- obj[key] = (row as any)[key];
619
+ // Non-date values stay native JSON types (numbers are numbers); only
620
+ // Dates are rendered, because JSON.stringify would otherwise reach
621
+ // Date.prototype.toJSON and emit the UTC day.
622
+ obj[key] = withExportDates((row as any)[key], isCalendarDayColumn(col));
561
623
  });
562
624
  return obj;
563
625
  });
@@ -583,12 +645,7 @@ async function exportAsJSON<T>(
583
645
  // />
584
646
  async function exportAsExcel<T>(
585
647
  _data: T[],
586
- _columns: Array<{
587
- accessorKey?: string;
588
- header?: string;
589
- id?: string;
590
- cell?: (info: any) => any;
591
- }>,
648
+ _columns: ExportColumn[],
592
649
  _options: ExportOptions,
593
650
  ): Promise<void> {
594
651
  throw new Error(
@@ -602,12 +659,7 @@ async function exportAsExcel<T>(
602
659
  // users can "Save as PDF" from there.
603
660
  async function exportAsPDF<T>(
604
661
  _data: T[],
605
- _columns: Array<{
606
- accessorKey?: string;
607
- header?: string;
608
- id?: string;
609
- cell?: (info: any) => any;
610
- }>,
662
+ _columns: ExportColumn[],
611
663
  _options: ExportOptions,
612
664
  ): Promise<void> {
613
665
  throw new Error(
@@ -618,15 +670,7 @@ async function exportAsPDF<T>(
618
670
  // Print functionality. Built with DOM nodes + textContent (never HTML string
619
671
  // interpolation) so cell values containing markup cannot inject into the
620
672
  // print document (XSS via `<img onerror>`-style data).
621
- async function printTable<T>(
622
- data: T[],
623
- columns: Array<{
624
- accessorKey?: string;
625
- header?: string;
626
- id?: string;
627
- cell?: (info: any) => any;
628
- }>,
629
- ): Promise<void> {
673
+ async function printTable<T>(data: T[], columns: ExportColumn[]): Promise<void> {
630
674
  const printWindow = window.open("", "_blank");
631
675
  if (!printWindow) {
632
676
  throw new Error("Print window was blocked. Allow popups for this site and try again.");
@@ -669,7 +713,7 @@ async function printTable<T>(
669
713
  const td = doc.createElement("td");
670
714
  // Same raw-value derivation as the CSV export — cell renderers return
671
715
  // JSX and must not reach the document.
672
- td.textContent = toExportValue((row as any)[key]);
716
+ td.textContent = toExportValue((row as any)[key], col);
673
717
  tr.appendChild(td);
674
718
  }
675
719
  tbody.appendChild(tr);