@multiplatform.one/table 7.7.6 → 7.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (384) hide show
  1. package/dist/cjs/components/ColumnHeaderFilter/index.cjs +74 -38
  2. package/dist/cjs/components/ColumnHeaderFilter/index.native.js +97 -51
  3. package/dist/cjs/components/ColumnHeaderFilter/index.native.js.map +1 -1
  4. package/dist/cjs/components/DataTable/DataTableCardControls.cjs +0 -1
  5. package/dist/cjs/components/DataTable/DataTableCardControls.native.js +0 -1
  6. package/dist/cjs/components/DataTable/DataTableCardControls.native.js.map +1 -1
  7. package/dist/cjs/components/DataTable/DataTableMobileCards.cjs +100 -33
  8. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js +139 -38
  9. package/dist/cjs/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  10. package/dist/cjs/components/DataTable/DataTableRoot.cjs +33 -6
  11. package/dist/cjs/components/DataTable/DataTableRoot.native.js +29 -4
  12. package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
  13. package/dist/cjs/components/DataTable/DataTableStateContext.native.js.map +1 -1
  14. package/dist/cjs/components/DataTable/index.native.js +59 -93
  15. package/dist/cjs/components/DataTable/index.native.js.map +1 -1
  16. package/dist/cjs/components/DataTableBulkActions/index.cjs +0 -4
  17. package/dist/cjs/components/DataTableBulkActions/index.native.js +0 -4
  18. package/dist/cjs/components/DataTableBulkActions/index.native.js.map +1 -1
  19. package/dist/cjs/components/DataTableCell/index.cjs +16 -1
  20. package/dist/cjs/components/DataTableCell/index.native.js +16 -1
  21. package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
  22. package/dist/cjs/components/DataTableDateFilter/index.cjs +0 -7
  23. package/dist/cjs/components/DataTableDateFilter/index.native.js +0 -7
  24. package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
  25. package/dist/cjs/components/DataTableFilterButton/index.cjs +0 -1
  26. package/dist/cjs/components/DataTableFilterButton/index.native.js +0 -1
  27. package/dist/cjs/components/DataTableFilterChips/FilterChip.cjs +2 -1
  28. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js +4 -1
  29. package/dist/cjs/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  30. package/dist/cjs/components/DataTableFilters/index.cjs +0 -1
  31. package/dist/cjs/components/DataTableFilters/index.native.js +0 -1
  32. package/dist/cjs/components/DataTableGrouping/index.cjs +0 -8
  33. package/dist/cjs/components/DataTableGrouping/index.native.js +0 -8
  34. package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
  35. package/dist/cjs/components/DataTablePagination/index.cjs +29 -13
  36. package/dist/cjs/components/DataTablePagination/index.native.js +30 -14
  37. package/dist/cjs/components/DataTablePagination/index.native.js.map +1 -1
  38. package/dist/cjs/components/DataTableSearch/index.cjs +0 -3
  39. package/dist/cjs/components/DataTableSearch/index.native.js +0 -3
  40. package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
  41. package/dist/cjs/components/DataTableToolbar/index.cjs +0 -1
  42. package/dist/cjs/components/DataTableToolbar/index.native.js +0 -1
  43. package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
  44. package/dist/cjs/components/DataTableViewOptions/index.cjs +0 -5
  45. package/dist/cjs/components/DataTableViewOptions/index.native.js +0 -5
  46. package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
  47. package/dist/cjs/components/FilterManager.cjs +0 -1
  48. package/dist/cjs/components/FilterManager.native.js +0 -1
  49. package/dist/cjs/components/FilterManager.native.js.map +1 -1
  50. package/dist/cjs/components/FilterOperatorValueEditor/index.cjs +2 -2
  51. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js +2 -2
  52. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  53. package/dist/cjs/components/TableInput/index.cjs +2 -1
  54. package/dist/cjs/components/TableInput/index.native.js +4 -2
  55. package/dist/cjs/components/TableInput/index.native.js.map +1 -1
  56. package/dist/cjs/hooks/useDataTable.cjs +24 -8
  57. package/dist/cjs/hooks/useDataTable.native.js +28 -8
  58. package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
  59. package/dist/cjs/index.cjs +12 -0
  60. package/dist/cjs/index.native.js +12 -0
  61. package/dist/cjs/index.native.js.map +1 -1
  62. package/dist/cjs/shared/devWarn.cjs +70 -0
  63. package/dist/cjs/shared/devWarn.native.js +84 -0
  64. package/dist/cjs/shared/devWarn.native.js.map +1 -0
  65. package/dist/cjs/utils/columnAlign.cjs +4 -1
  66. package/dist/cjs/utils/columnAlign.native.js +4 -1
  67. package/dist/cjs/utils/columnAlign.native.js.map +1 -1
  68. package/dist/cjs/utils/filterFields.cjs +5 -0
  69. package/dist/cjs/utils/filterFields.native.js +5 -0
  70. package/dist/cjs/utils/filterFields.native.js.map +1 -1
  71. package/dist/cjs/utils/filterUtils.cjs +30 -0
  72. package/dist/cjs/utils/filterUtils.native.js +50 -0
  73. package/dist/cjs/utils/filterUtils.native.js.map +1 -1
  74. package/dist/cjs/utils/money.cjs +137 -0
  75. package/dist/cjs/utils/money.native.js +165 -0
  76. package/dist/cjs/utils/money.native.js.map +1 -0
  77. package/dist/cjs/utils/rowAccumulator.cjs +48 -0
  78. package/dist/cjs/utils/rowAccumulator.native.js +51 -0
  79. package/dist/cjs/utils/rowAccumulator.native.js.map +1 -0
  80. package/dist/esm/components/ColumnHeaderFilter/index.mjs +78 -42
  81. package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
  82. package/dist/esm/components/ColumnHeaderFilter/index.native.js +101 -55
  83. package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
  84. package/dist/esm/components/DataTable/DataTableCardControls.mjs +0 -1
  85. package/dist/esm/components/DataTable/DataTableCardControls.mjs.map +1 -1
  86. package/dist/esm/components/DataTable/DataTableCardControls.native.js +0 -1
  87. package/dist/esm/components/DataTable/DataTableCardControls.native.js.map +1 -1
  88. package/dist/esm/components/DataTable/DataTableMobileCards.mjs +99 -34
  89. package/dist/esm/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  90. package/dist/esm/components/DataTable/DataTableMobileCards.native.js +138 -39
  91. package/dist/esm/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  92. package/dist/esm/components/DataTable/DataTableRoot.mjs +33 -6
  93. package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
  94. package/dist/esm/components/DataTable/DataTableRoot.native.js +29 -4
  95. package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
  96. package/dist/esm/components/DataTable/DataTableStateContext.mjs.map +1 -1
  97. package/dist/esm/components/DataTable/DataTableStateContext.native.js.map +1 -1
  98. package/dist/esm/components/DataTable/index.native.js +60 -94
  99. package/dist/esm/components/DataTable/index.native.js.map +1 -1
  100. package/dist/esm/components/DataTableBulkActions/index.mjs +0 -4
  101. package/dist/esm/components/DataTableBulkActions/index.mjs.map +1 -1
  102. package/dist/esm/components/DataTableBulkActions/index.native.js +0 -4
  103. package/dist/esm/components/DataTableBulkActions/index.native.js.map +1 -1
  104. package/dist/esm/components/DataTableCell/index.mjs +17 -2
  105. package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
  106. package/dist/esm/components/DataTableCell/index.native.js +17 -2
  107. package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
  108. package/dist/esm/components/DataTableDateFilter/index.mjs +0 -7
  109. package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
  110. package/dist/esm/components/DataTableDateFilter/index.native.js +0 -7
  111. package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
  112. package/dist/esm/components/DataTableFilterButton/index.mjs +0 -1
  113. package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
  114. package/dist/esm/components/DataTableFilterButton/index.native.js +0 -1
  115. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs +3 -2
  116. package/dist/esm/components/DataTableFilterChips/FilterChip.mjs.map +1 -1
  117. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js +5 -2
  118. package/dist/esm/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  119. package/dist/esm/components/DataTableFilters/index.mjs +0 -1
  120. package/dist/esm/components/DataTableFilters/index.mjs.map +1 -1
  121. package/dist/esm/components/DataTableFilters/index.native.js +0 -1
  122. package/dist/esm/components/DataTableGrouping/index.mjs +0 -8
  123. package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
  124. package/dist/esm/components/DataTableGrouping/index.native.js +0 -8
  125. package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
  126. package/dist/esm/components/DataTablePagination/index.mjs +30 -14
  127. package/dist/esm/components/DataTablePagination/index.mjs.map +1 -1
  128. package/dist/esm/components/DataTablePagination/index.native.js +31 -15
  129. package/dist/esm/components/DataTablePagination/index.native.js.map +1 -1
  130. package/dist/esm/components/DataTableSearch/index.mjs +0 -3
  131. package/dist/esm/components/DataTableSearch/index.mjs.map +1 -1
  132. package/dist/esm/components/DataTableSearch/index.native.js +0 -3
  133. package/dist/esm/components/DataTableSearch/index.native.js.map +1 -1
  134. package/dist/esm/components/DataTableToolbar/index.mjs +0 -1
  135. package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
  136. package/dist/esm/components/DataTableToolbar/index.native.js +0 -1
  137. package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
  138. package/dist/esm/components/DataTableViewOptions/index.mjs +0 -5
  139. package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
  140. package/dist/esm/components/DataTableViewOptions/index.native.js +0 -5
  141. package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
  142. package/dist/esm/components/FilterManager.mjs +0 -1
  143. package/dist/esm/components/FilterManager.mjs.map +1 -1
  144. package/dist/esm/components/FilterManager.native.js +0 -1
  145. package/dist/esm/components/FilterManager.native.js.map +1 -1
  146. package/dist/esm/components/FilterOperatorValueEditor/index.mjs +2 -2
  147. package/dist/esm/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  148. package/dist/esm/components/FilterOperatorValueEditor/index.native.js +2 -2
  149. package/dist/esm/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  150. package/dist/esm/components/TableInput/index.mjs +3 -2
  151. package/dist/esm/components/TableInput/index.mjs.map +1 -1
  152. package/dist/esm/components/TableInput/index.native.js +5 -3
  153. package/dist/esm/components/TableInput/index.native.js.map +1 -1
  154. package/dist/esm/hooks/useDataTable.mjs +24 -8
  155. package/dist/esm/hooks/useDataTable.mjs.map +1 -1
  156. package/dist/esm/hooks/useDataTable.native.js +28 -8
  157. package/dist/esm/hooks/useDataTable.native.js.map +1 -1
  158. package/dist/esm/index.mjs +3 -1
  159. package/dist/esm/index.mjs.map +1 -1
  160. package/dist/esm/index.native.js +3 -1
  161. package/dist/esm/index.native.js.map +1 -1
  162. package/dist/esm/shared/devWarn.mjs +43 -0
  163. package/dist/esm/shared/devWarn.mjs.map +1 -0
  164. package/dist/esm/shared/devWarn.native.js +54 -0
  165. package/dist/esm/shared/devWarn.native.js.map +1 -0
  166. package/dist/esm/utils/columnAlign.mjs +4 -1
  167. package/dist/esm/utils/columnAlign.mjs.map +1 -1
  168. package/dist/esm/utils/columnAlign.native.js +4 -1
  169. package/dist/esm/utils/columnAlign.native.js.map +1 -1
  170. package/dist/esm/utils/filterFields.mjs +5 -0
  171. package/dist/esm/utils/filterFields.mjs.map +1 -1
  172. package/dist/esm/utils/filterFields.native.js +5 -0
  173. package/dist/esm/utils/filterFields.native.js.map +1 -1
  174. package/dist/esm/utils/filterUtils.mjs +30 -0
  175. package/dist/esm/utils/filterUtils.mjs.map +1 -1
  176. package/dist/esm/utils/filterUtils.native.js +50 -0
  177. package/dist/esm/utils/filterUtils.native.js.map +1 -1
  178. package/dist/esm/utils/money.mjs +104 -0
  179. package/dist/esm/utils/money.mjs.map +1 -0
  180. package/dist/esm/utils/money.native.js +129 -0
  181. package/dist/esm/utils/money.native.js.map +1 -0
  182. package/dist/esm/utils/rowAccumulator.mjs +23 -0
  183. package/dist/esm/utils/rowAccumulator.mjs.map +1 -0
  184. package/dist/esm/utils/rowAccumulator.native.js +23 -0
  185. package/dist/esm/utils/rowAccumulator.native.js.map +1 -0
  186. package/dist/jsx/components/ColumnHeaderFilter/index.mjs +78 -42
  187. package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
  188. package/dist/jsx/components/ColumnHeaderFilter/index.native.js +97 -51
  189. package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
  190. package/dist/jsx/components/DataTable/DataTableCardControls.mjs +0 -1
  191. package/dist/jsx/components/DataTable/DataTableCardControls.mjs.map +1 -1
  192. package/dist/jsx/components/DataTable/DataTableCardControls.native.js +0 -1
  193. package/dist/jsx/components/DataTable/DataTableCardControls.native.js.map +1 -1
  194. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs +99 -34
  195. package/dist/jsx/components/DataTable/DataTableMobileCards.mjs.map +1 -1
  196. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js +139 -38
  197. package/dist/jsx/components/DataTable/DataTableMobileCards.native.js.map +1 -1
  198. package/dist/jsx/components/DataTable/DataTableRoot.mjs +33 -6
  199. package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
  200. package/dist/jsx/components/DataTable/DataTableRoot.native.js +29 -4
  201. package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
  202. package/dist/jsx/components/DataTable/DataTableStateContext.mjs.map +1 -1
  203. package/dist/jsx/components/DataTable/DataTableStateContext.native.js.map +1 -1
  204. package/dist/jsx/components/DataTable/index.native.js +59 -93
  205. package/dist/jsx/components/DataTable/index.native.js.map +1 -1
  206. package/dist/jsx/components/DataTableBulkActions/index.mjs +0 -4
  207. package/dist/jsx/components/DataTableBulkActions/index.mjs.map +1 -1
  208. package/dist/jsx/components/DataTableBulkActions/index.native.js +0 -4
  209. package/dist/jsx/components/DataTableBulkActions/index.native.js.map +1 -1
  210. package/dist/jsx/components/DataTableCell/index.mjs +17 -2
  211. package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
  212. package/dist/jsx/components/DataTableCell/index.native.js +16 -1
  213. package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
  214. package/dist/jsx/components/DataTableDateFilter/index.mjs +0 -7
  215. package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
  216. package/dist/jsx/components/DataTableDateFilter/index.native.js +0 -7
  217. package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
  218. package/dist/jsx/components/DataTableFilterButton/index.mjs +0 -1
  219. package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
  220. package/dist/jsx/components/DataTableFilterButton/index.native.js +0 -1
  221. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs +3 -2
  222. package/dist/jsx/components/DataTableFilterChips/FilterChip.mjs.map +1 -1
  223. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js +4 -1
  224. package/dist/jsx/components/DataTableFilterChips/FilterChip.native.js.map +1 -1
  225. package/dist/jsx/components/DataTableFilters/index.mjs +0 -1
  226. package/dist/jsx/components/DataTableFilters/index.mjs.map +1 -1
  227. package/dist/jsx/components/DataTableFilters/index.native.js +0 -1
  228. package/dist/jsx/components/DataTableGrouping/index.mjs +0 -8
  229. package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
  230. package/dist/jsx/components/DataTableGrouping/index.native.js +0 -8
  231. package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
  232. package/dist/jsx/components/DataTablePagination/index.mjs +30 -14
  233. package/dist/jsx/components/DataTablePagination/index.mjs.map +1 -1
  234. package/dist/jsx/components/DataTablePagination/index.native.js +30 -14
  235. package/dist/jsx/components/DataTablePagination/index.native.js.map +1 -1
  236. package/dist/jsx/components/DataTableSearch/index.mjs +0 -3
  237. package/dist/jsx/components/DataTableSearch/index.mjs.map +1 -1
  238. package/dist/jsx/components/DataTableSearch/index.native.js +0 -3
  239. package/dist/jsx/components/DataTableSearch/index.native.js.map +1 -1
  240. package/dist/jsx/components/DataTableToolbar/index.mjs +0 -1
  241. package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
  242. package/dist/jsx/components/DataTableToolbar/index.native.js +0 -1
  243. package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
  244. package/dist/jsx/components/DataTableViewOptions/index.mjs +0 -5
  245. package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
  246. package/dist/jsx/components/DataTableViewOptions/index.native.js +0 -5
  247. package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
  248. package/dist/jsx/components/FilterManager.mjs +0 -1
  249. package/dist/jsx/components/FilterManager.mjs.map +1 -1
  250. package/dist/jsx/components/FilterManager.native.js +0 -1
  251. package/dist/jsx/components/FilterManager.native.js.map +1 -1
  252. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs +2 -2
  253. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  254. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js +2 -2
  255. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  256. package/dist/jsx/components/TableInput/index.mjs +3 -2
  257. package/dist/jsx/components/TableInput/index.mjs.map +1 -1
  258. package/dist/jsx/components/TableInput/index.native.js +4 -2
  259. package/dist/jsx/components/TableInput/index.native.js.map +1 -1
  260. package/dist/jsx/hooks/useDataTable.mjs +24 -8
  261. package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
  262. package/dist/jsx/hooks/useDataTable.native.js +28 -8
  263. package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
  264. package/dist/jsx/index.js +3 -1
  265. package/dist/jsx/index.js.map +1 -1
  266. package/dist/jsx/index.mjs +3 -1
  267. package/dist/jsx/index.mjs.map +1 -1
  268. package/dist/jsx/index.native.js +12 -0
  269. package/dist/jsx/index.native.js.map +1 -1
  270. package/dist/jsx/shared/devWarn.mjs +43 -0
  271. package/dist/jsx/shared/devWarn.mjs.map +1 -0
  272. package/dist/jsx/shared/devWarn.native.js +84 -0
  273. package/dist/jsx/shared/devWarn.native.js.map +1 -0
  274. package/dist/jsx/utils/columnAlign.mjs +4 -1
  275. package/dist/jsx/utils/columnAlign.mjs.map +1 -1
  276. package/dist/jsx/utils/columnAlign.native.js +4 -1
  277. package/dist/jsx/utils/columnAlign.native.js.map +1 -1
  278. package/dist/jsx/utils/filterFields.mjs +5 -0
  279. package/dist/jsx/utils/filterFields.mjs.map +1 -1
  280. package/dist/jsx/utils/filterFields.native.js +5 -0
  281. package/dist/jsx/utils/filterFields.native.js.map +1 -1
  282. package/dist/jsx/utils/filterUtils.mjs +30 -0
  283. package/dist/jsx/utils/filterUtils.mjs.map +1 -1
  284. package/dist/jsx/utils/filterUtils.native.js +50 -0
  285. package/dist/jsx/utils/filterUtils.native.js.map +1 -1
  286. package/dist/jsx/utils/money.mjs +104 -0
  287. package/dist/jsx/utils/money.mjs.map +1 -0
  288. package/dist/jsx/utils/money.native.js +165 -0
  289. package/dist/jsx/utils/money.native.js.map +1 -0
  290. package/dist/jsx/utils/rowAccumulator.mjs +23 -0
  291. package/dist/jsx/utils/rowAccumulator.mjs.map +1 -0
  292. package/dist/jsx/utils/rowAccumulator.native.js +51 -0
  293. package/dist/jsx/utils/rowAccumulator.native.js.map +1 -0
  294. package/package.json +12 -12
  295. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.spec.tsx +142 -7
  296. package/src/components/ColumnHeaderFilter/ColumnHeaderFilter.stories.tsx +46 -9
  297. package/src/components/ColumnHeaderFilter/index.tsx +104 -47
  298. package/src/components/DataTable/DataTable.spec.tsx +5 -3
  299. package/src/components/DataTable/DataTable.stories.tsx +186 -14
  300. package/src/components/DataTable/DataTableCardControls.tsx +11 -13
  301. package/src/components/DataTable/DataTableMobileCards.tsx +162 -39
  302. package/src/components/DataTable/DataTableRoot.tsx +40 -14
  303. package/src/components/DataTable/DataTableStateContext.ts +7 -0
  304. package/src/components/DataTable/cardLayout.spec.tsx +19 -8
  305. package/src/components/DataTable/columnWidthLayout.spec.tsx +195 -0
  306. package/src/components/DataTable/dataTableMobileCards.spec.tsx +50 -2
  307. package/src/components/DataTable/headerSorting.spec.tsx +25 -0
  308. package/src/components/DataTable/index.native.tsx +80 -124
  309. package/src/components/DataTable/moneyColumn.spec.tsx +151 -0
  310. package/src/components/DataTable/nativeCardParity.spec.tsx +95 -0
  311. package/src/components/DataTable/rowAccumulator.spec.tsx +171 -0
  312. package/src/components/DataTableBulkActions/index.tsx +0 -4
  313. package/src/components/DataTableCell/index.tsx +28 -2
  314. package/src/components/DataTableColumnPinning/DataTableColumnPinning.stories.tsx +0 -4
  315. package/src/components/DataTableDateFilter/index.tsx +0 -7
  316. package/src/components/DataTableFilterButton/index.tsx +1 -1
  317. package/src/components/DataTableFilterChips/FilterChip.spec.tsx +6 -0
  318. package/src/components/DataTableFilterChips/FilterChip.tsx +3 -2
  319. package/src/components/DataTableFilters/index.tsx +1 -1
  320. package/src/components/DataTableGrouping/DataTableGrouping.stories.tsx +0 -4
  321. package/src/components/DataTableGrouping/index.tsx +1 -13
  322. package/src/components/DataTablePagination/DataTablePagination.stories.tsx +14 -1
  323. package/src/components/DataTablePagination/DataTablePagination.width.spec.tsx +51 -0
  324. package/src/components/DataTablePagination/index.tsx +60 -16
  325. package/src/components/DataTableSearch/index.tsx +2 -3
  326. package/src/components/DataTableToolbar/DataTableToolbar.stories.tsx +2 -4
  327. package/src/components/DataTableToolbar/index.tsx +1 -5
  328. package/src/components/DataTableViewOptions/index.tsx +2 -13
  329. package/src/components/FilterManager.tsx +1 -3
  330. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.spec.tsx +1 -1
  331. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.stories.tsx +1 -0
  332. package/src/components/FilterOperatorValueEditor/index.tsx +10 -2
  333. package/src/components/TableInput/index.native.tsx +3 -2
  334. package/src/components/TableInput/index.tsx +3 -2
  335. package/src/hooks/useDataTable.ts +43 -7
  336. package/src/index.ts +13 -0
  337. package/src/shared/devWarn.ts +97 -0
  338. package/src/types.ts +71 -2
  339. package/src/utils/columnAlign.ts +9 -1
  340. package/src/utils/filterFields.ts +23 -1
  341. package/src/utils/filterUtils.ts +50 -1
  342. package/src/utils/money.spec.ts +156 -0
  343. package/src/utils/money.ts +202 -0
  344. package/src/utils/rowAccumulator.ts +136 -0
  345. package/types/components/ColumnHeaderFilter/index.d.ts +9 -2
  346. package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
  347. package/types/components/DataTable/DataTableCardControls.d.ts.map +1 -1
  348. package/types/components/DataTable/DataTableMobileCards.d.ts +42 -8
  349. package/types/components/DataTable/DataTableMobileCards.d.ts.map +1 -1
  350. package/types/components/DataTable/DataTableRoot.d.ts +1 -1
  351. package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
  352. package/types/components/DataTable/DataTableStateContext.d.ts +7 -0
  353. package/types/components/DataTable/DataTableStateContext.d.ts.map +1 -1
  354. package/types/components/DataTable/index.native.d.ts +1 -1
  355. package/types/components/DataTable/index.native.d.ts.map +1 -1
  356. package/types/components/DataTableBulkActions/index.d.ts.map +1 -1
  357. package/types/components/DataTableCell/index.d.ts.map +1 -1
  358. package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
  359. package/types/components/DataTableFilterChips/FilterChip.d.ts.map +1 -1
  360. package/types/components/DataTableGrouping/index.d.ts.map +1 -1
  361. package/types/components/DataTablePagination/index.d.ts.map +1 -1
  362. package/types/components/DataTableSearch/index.d.ts.map +1 -1
  363. package/types/components/DataTableToolbar/index.d.ts.map +1 -1
  364. package/types/components/DataTableViewOptions/index.d.ts.map +1 -1
  365. package/types/components/FilterManager.d.ts.map +1 -1
  366. package/types/components/FilterOperatorValueEditor/index.d.ts.map +1 -1
  367. package/types/components/TableInput/index.d.ts.map +1 -1
  368. package/types/components/TableInput/index.native.d.ts.map +1 -1
  369. package/types/hooks/useDataTable.d.ts +1 -1
  370. package/types/hooks/useDataTable.d.ts.map +1 -1
  371. package/types/index.d.ts +3 -0
  372. package/types/index.d.ts.map +1 -1
  373. package/types/shared/devWarn.d.ts +50 -0
  374. package/types/shared/devWarn.d.ts.map +1 -0
  375. package/types/types.d.ts +71 -3
  376. package/types/types.d.ts.map +1 -1
  377. package/types/utils/columnAlign.d.ts.map +1 -1
  378. package/types/utils/filterFields.d.ts.map +1 -1
  379. package/types/utils/filterUtils.d.ts +1 -1
  380. package/types/utils/filterUtils.d.ts.map +1 -1
  381. package/types/utils/money.d.ts +94 -0
  382. package/types/utils/money.d.ts.map +1 -0
  383. package/types/utils/rowAccumulator.d.ts +107 -0
  384. package/types/utils/rowAccumulator.d.ts.map +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/table",
3
- "version": "7.7.6",
3
+ "version": "7.10.0",
4
4
  "description": "Advanced table components with filtering, pagination, sorting, and URL state management",
5
5
  "keywords": [
6
6
  "cross-platform",
@@ -80,13 +80,13 @@
80
80
  "@tanstack/react-table": "^8.21.3",
81
81
  "@tanstack/table-core": "^8.21.3",
82
82
  "tamagui": "2.7.6",
83
- "@multiplatform.one/components": "7.7.6",
84
- "@multiplatform.one/forms": "7.7.6",
85
- "@multiplatform.one/platform": "7.7.6",
86
- "@multiplatform.one/rich-text": "7.7.6",
87
- "@multiplatform.one/router": "7.7.6",
88
- "@multiplatform.one/table-primitives": "7.7.6",
89
- "@multiplatform.one/theme": "7.7.6"
83
+ "@multiplatform.one/rich-text": "7.10.0",
84
+ "@multiplatform.one/platform": "7.10.0",
85
+ "@multiplatform.one/router": "7.10.0",
86
+ "@multiplatform.one/theme": "7.10.0",
87
+ "@multiplatform.one/table-primitives": "7.10.0",
88
+ "@multiplatform.one/components": "7.10.0",
89
+ "@multiplatform.one/forms": "7.10.0"
90
90
  },
91
91
  "devDependencies": {
92
92
  "@tamagui/build": "2.7.6",
@@ -98,10 +98,10 @@
98
98
  "react": "19.2.5",
99
99
  "react-dom": "19.2.5",
100
100
  "vitest": "^4.1.5",
101
- "@multiplatform.one/config": "7.7.6",
102
- "@multiplatform.one/router": "7.7.6",
103
- "@multiplatform.one/storybook": "7.7.6",
104
- "@multiplatform.one/test-utils": "7.7.6"
101
+ "@multiplatform.one/router": "7.10.0",
102
+ "@multiplatform.one/config": "7.10.0",
103
+ "@multiplatform.one/storybook": "7.10.0",
104
+ "@multiplatform.one/test-utils": "7.10.0"
105
105
  },
106
106
  "peerDependencies": {
107
107
  "i18next": "^25.0.0",
@@ -1,6 +1,7 @@
1
- import { fireEvent } from "@testing-library/react";
1
+ import { createEvent, fireEvent, screen, waitFor } from "@testing-library/react";
2
2
  import { describe, expect, it, vi } from "vitest";
3
3
  import { renderWithProviders } from "@multiplatform.one/test-utils";
4
+ import { useTheme } from "tamagui";
4
5
  import { ColumnHeaderFilter } from "./index";
5
6
 
6
7
  const renderTrigger = (props: Partial<Parameters<typeof ColumnHeaderFilter>[0]> = {}) =>
@@ -18,6 +19,33 @@ const trigger = (container: HTMLElement) =>
18
19
  container.querySelector('[aria-label="Filter column Status"]') as HTMLElement;
19
20
 
20
21
  describe("ColumnHeaderFilter trigger", () => {
22
+ it.each(["Enter", " "])("opens with %s without triggering header shortcuts", (key) => {
23
+ const parentKeyDown = vi.fn();
24
+ const { container } = renderWithProviders(
25
+ <div onKeyDown={parentKeyDown}>
26
+ <ColumnHeaderFilter
27
+ columnId="status"
28
+ columnLabel="Status"
29
+ columnType="text"
30
+ onFilterChange={() => {}}
31
+ />
32
+ </div>,
33
+ );
34
+ const floor = trigger(container);
35
+ expect(floor.tabIndex).toBe(0);
36
+ const event = createEvent.keyDown(floor, { key, bubbles: true, cancelable: true });
37
+ fireEvent(floor, event);
38
+ expect(event.defaultPrevented).toBe(true);
39
+ expect(parentKeyDown).not.toHaveBeenCalled();
40
+ expect(document.body.textContent).toContain("Filter: Status");
41
+ });
42
+
43
+ it("keeps ordinary typing out of the opener", () => {
44
+ const { container } = renderTrigger();
45
+ fireEvent.keyDown(trigger(container), { key: "x" });
46
+ expect(document.body.textContent).not.toContain("Filter: Status");
47
+ });
48
+
21
49
  it("renders the funnel trigger with its column-scoped name", () => {
22
50
  const { container } = renderTrigger();
23
51
  expect(trigger(container)).not.toBeNull();
@@ -61,6 +89,8 @@ describe("ColumnHeaderFilter press-floor paint (LC-54 amendment)", () => {
61
89
  const { container } = renderTrigger();
62
90
  const floor = trigger(container);
63
91
  expect(floor.className).not.toMatch(paintedStateAtom);
92
+ expect(floor.className).toContain("mp-chip-dismiss");
93
+ expect(floor.firstElementChild?.className).toContain("mp-chip-dismiss-ring");
64
94
  });
65
95
 
66
96
  it("positive control: the glyph-scale ring is where the hover fill lives", () => {
@@ -75,11 +105,116 @@ describe("ColumnHeaderFilter press-floor paint (LC-54 amendment)", () => {
75
105
  expect(ring.querySelector("svg")).not.toBeNull();
76
106
  });
77
107
 
78
- it("an applied filter keeps full rest opacity (honest active state)", () => {
79
- // 0.7 compiles to the `_o-0--7` atom (dots escape as double dashes).
80
- const idle = renderTrigger();
81
- expect(trigger(idle.container).className).toMatch(/_o-0--7/);
82
- const filtered = renderTrigger({ isFiltered: true });
83
- expect(trigger(filtered.container).className).not.toMatch(/_o-0--7/);
108
+ for (const isFiltered of [false, true]) {
109
+ it(`keeps enabled glyph ink at full rest opacity (filtered=${isFiltered})`, () => {
110
+ let expectedInk = "";
111
+ function Sample() {
112
+ const theme = useTheme();
113
+ // This provider has no accent ramp; the active hook uses readable ink.
114
+ expectedInk = String(isFiltered ? theme.color12?.val : theme.color11?.val);
115
+ return (
116
+ <ColumnHeaderFilter
117
+ columnId="status"
118
+ columnLabel="Status"
119
+ columnType="text"
120
+ onFilterChange={() => {}}
121
+ isFiltered={isFiltered}
122
+ />
123
+ );
124
+ }
125
+ const { container } = renderWithProviders(<Sample />);
126
+ const svg = trigger(container).querySelector("svg")!;
127
+ expect(svg.getAttribute("fill")).toBe(expectedInk);
128
+ expect(svg.getAttribute("fill")).not.toContain("var(");
129
+ for (
130
+ let node = svg.parentElement;
131
+ node && node !== document.body;
132
+ node = node.parentElement
133
+ ) {
134
+ expect(Number(getComputedStyle(node).opacity || 1)).toBe(1);
135
+ }
136
+ });
137
+ }
138
+ });
139
+
140
+ describe("ColumnHeaderFilter applied draft", () => {
141
+ const input = () => screen.getByPlaceholderText("Enter value...") as HTMLInputElement;
142
+ const apply = () => fireEvent.click(screen.getByRole("button", { name: "Apply" }));
143
+ const sample = (filterValue: { operator: string; value: unknown } | undefined) => (
144
+ <ColumnHeaderFilter
145
+ columnId="status"
146
+ columnLabel="Status"
147
+ columnType="text"
148
+ filterValue={filterValue}
149
+ isFiltered={filterValue !== undefined}
150
+ onFilterChange={() => {}}
151
+ />
152
+ );
153
+
154
+ it("opens with the supplied operator and value", () => {
155
+ const { container } = renderTrigger({ filterValue: { operator: "is", value: "corp" } });
156
+ fireEvent.click(trigger(container));
157
+ expect(input().value).toBe("corp");
158
+ expect(screen.getByRole("combobox", { name: "Condition" }).textContent).toBe("Is");
159
+ });
160
+
161
+ it("keeps an open draft when an external filter update arrives", () => {
162
+ const result = renderWithProviders(sample({ operator: "contains", value: "corp" }));
163
+ fireEvent.click(trigger(result.container));
164
+ fireEvent.change(input(), { target: { value: "draft" } });
165
+ result.rerender(sample({ operator: "is", value: "external" }));
166
+ expect(input().value).toBe("draft");
167
+ expect(screen.getByRole("combobox", { name: "Condition" }).textContent).toBe("Contains");
168
+ });
169
+
170
+ it("reads the latest external filter when reopened", async () => {
171
+ const result = renderWithProviders(sample({ operator: "contains", value: "corp" }));
172
+ fireEvent.click(trigger(result.container));
173
+ apply();
174
+ await waitFor(() => expect(screen.queryByPlaceholderText("Enter value...")).toBeNull());
175
+ result.rerender(sample({ operator: "is", value: "external" }));
176
+ fireEvent.click(trigger(result.container));
177
+ expect(input().value).toBe("external");
178
+ expect(screen.getByRole("combobox", { name: "Condition" }).textContent).toBe("Is");
179
+ });
180
+
181
+ it("clears without closing, then applies the newly composed draft", () => {
182
+ const onFilterChange = vi.fn();
183
+ const { container } = renderTrigger({
184
+ isFiltered: true,
185
+ filterValue: { operator: "contains", value: "corp" },
186
+ onFilterChange,
187
+ });
188
+ fireEvent.click(trigger(container));
189
+ fireEvent.click(screen.getByRole("button", { name: "Clear" }));
190
+ expect(onFilterChange).toHaveBeenLastCalledWith(undefined);
191
+ expect(input().value).toBe("");
192
+ fireEvent.change(input(), { target: { value: "next" } });
193
+ apply();
194
+ expect(onFilterChange).toHaveBeenLastCalledWith({ operator: "contains", value: "next" });
195
+ });
196
+
197
+ it("resets to the default when the applied filter was removed while closed", async () => {
198
+ const result = renderWithProviders(sample({ operator: "is", value: "corp" }));
199
+ fireEvent.click(trigger(result.container));
200
+ fireEvent.change(input(), { target: { value: "draft" } });
201
+ apply();
202
+ await waitFor(() => expect(screen.queryByPlaceholderText("Enter value...")).toBeNull());
203
+ result.rerender(sample(undefined));
204
+ fireEvent.click(trigger(result.container));
205
+ expect(input().value).toBe("");
206
+ expect(screen.getByRole("combobox", { name: "Condition" }).textContent).toBe("Contains");
207
+ });
208
+
209
+ it("uses an offered numeric condition initially and after Clear", () => {
210
+ const onFilterChange = vi.fn();
211
+ const { container } = renderTrigger({ columnType: "number", isFiltered: true, onFilterChange });
212
+ fireEvent.click(trigger(container));
213
+ expect(screen.getByRole("combobox", { name: "Condition" }).textContent).toBe("Is");
214
+ fireEvent.click(screen.getByRole("button", { name: "Clear" }));
215
+ expect(screen.getByRole("combobox", { name: "Condition" }).textContent).toBe("Is");
216
+ fireEvent.change(input(), { target: { value: "50" } });
217
+ apply();
218
+ expect(onFilterChange).toHaveBeenLastCalledWith({ operator: "is", value: "50" });
84
219
  });
85
220
  });
@@ -1,8 +1,12 @@
1
1
  import type { Meta } from "@storybook/react-native-web-vite";
2
- import { YStack, Text } from "tamagui";
2
+ import { useState } from "react";
3
+ import { useResolvedKnobs } from "@multiplatform.one/theme";
4
+ import { YStack, XStack, Text } from "tamagui";
5
+ import { ColumnHeaderFilter, type ColumnFilterType } from "./index";
3
6
 
4
7
  const meta: Meta = {
5
8
  title: "Table/ColumnHeaderFilter",
9
+ component: ColumnHeaderFilter,
6
10
  parameters: {
7
11
  status: { type: "stable" },
8
12
  },
@@ -10,14 +14,47 @@ const meta: Meta = {
10
14
 
11
15
  export default meta;
12
16
 
13
- export const Default = {
14
- name: "Main",
15
- render: () => (
16
- <YStack padding="$4">
17
- <Text fontSize="$2" color="$color10">
18
- ColumnHeaderFilter provides AG Grid-style column filtering with operators and value inputs.
19
- It requires a DataTable column context. See DataTable stories for integrated usage.
17
+ function ControlledColumn({
18
+ initiallyFiltered = false,
19
+ columnType = "text",
20
+ }: {
21
+ initiallyFiltered?: boolean;
22
+ columnType?: ColumnFilterType;
23
+ }) {
24
+ const label = columnType === "number" ? "Amount" : "Invoice";
25
+ const { knobProps } = useResolvedKnobs();
26
+ const [filter, setFilter] = useState<{ operator: string; value: string } | undefined>(
27
+ initiallyFiltered ? { operator: "contains", value: "corp" } : undefined,
28
+ );
29
+ return (
30
+ <YStack {...knobProps.panelPadding} {...knobProps.gap}>
31
+ <XStack alignItems="center" {...knobProps.gap}>
32
+ <Text {...knobProps.label}>{label}</Text>
33
+ <ColumnHeaderFilter
34
+ columnId="invoice"
35
+ columnLabel={label}
36
+ columnType={columnType}
37
+ filterValue={filter}
38
+ isFiltered={filter !== undefined}
39
+ onFilterChange={setFilter}
40
+ />
41
+ </XStack>
42
+ <Text {...knobProps.body} aria-live="polite">
43
+ {filter ? `Applied: ${filter.operator} ${filter.value ?? ""}` : "No filter applied"}
20
44
  </Text>
21
45
  </YStack>
22
- ),
46
+ );
47
+ }
48
+
49
+ export const Default = {
50
+ name: "Main",
51
+ render: () => <ControlledColumn />,
52
+ };
53
+
54
+ export const Filtered = {
55
+ render: () => <ControlledColumn initiallyFiltered />,
56
+ };
57
+
58
+ export const NumberColumn = {
59
+ render: () => <ControlledColumn columnType="number" />,
23
60
  };
@@ -6,21 +6,30 @@
6
6
  import { FunnelIcon } from "@phosphor-icons/react";
7
7
  import { Button } from "@multiplatform.one/forms";
8
8
  import {
9
+ ensureCompositeFocusRing,
9
10
  MIN_PRESS_TARGET,
10
11
  pressTargetHitSlop,
11
12
  pressTargetStyle,
13
+ useAccentOnSurface,
12
14
  useResolvedKnobs,
15
+ useGlyphColor,
13
16
  } from "@multiplatform.one/theme";
14
- import { useState } from "react";
17
+ import { useId, useRef, useState } from "react";
15
18
  import { Tooltip } from "@multiplatform.one/components";
16
- import { Popover, Text, View, XStack, YStack } from "tamagui";
19
+ import { Popover, Text, View, XStack, YStack, isWeb, type TamaguiElement } from "tamagui";
17
20
  import { t } from "../../shared/t";
18
- import type { FilterOperator } from "../../types";
21
+ import type { DataTableColumnType, FilterOperator } from "../../types";
19
22
  import { iconSizeForToken } from "../../utils/chromeIcons";
20
- import { operatorNeedsNoValue } from "../../utils/filterFields";
23
+ import { defaultOperatorForFilterType, operatorNeedsNoValue } from "../../utils/filterFields";
21
24
  import { FilterOperatorValueEditor } from "../FilterOperatorValueEditor";
22
25
 
23
- export type ColumnFilterType = "text" | "number" | "date" | "boolean" | "select";
26
+ /**
27
+ * The funnel's column type IS the table's column type — one vocabulary, not a
28
+ * second copy (LC-16). Kept as a named alias because consumers import it.
29
+ * Adding `"money"` to DataTableColumnType therefore reaches the funnel too
30
+ * (MPO-252).
31
+ */
32
+ export type ColumnFilterType = DataTableColumnType;
24
33
 
25
34
  export interface ColumnHeaderFilterProps {
26
35
  columnId: string;
@@ -49,17 +58,38 @@ export function ColumnHeaderFilter({
49
58
  columnId: _columnId,
50
59
  columnLabel,
51
60
  columnType,
52
- filterValue: _filterValue,
61
+ filterValue,
53
62
  onFilterChange,
54
63
  options,
55
64
  isFiltered,
56
65
  }: ColumnHeaderFilterProps) {
57
66
  const { knobProps } = useResolvedKnobs();
67
+ const idleColor = useGlyphColor("$color11");
68
+ const activeColor = useAccentOnSurface();
69
+ const glyphColor = isFiltered ? activeColor : idleColor;
70
+ // The nested Tooltip has its own Popper context. Keep this trigger and
71
+ // editor anchored to the same instance rather than its nearest overlay.
72
+ const popoverScope = useId();
73
+ const triggerRef = useRef<TamaguiElement | null>(null);
74
+ const returnFocusRef = useRef(true);
75
+ ensureCompositeFocusRing();
58
76
  const iconPx = iconSizeForToken(String(knobProps.sizeToken));
59
77
  const [open, setOpen] = useState(false);
60
- const [operator, setOperator] = useState<FilterOperator>("contains");
78
+ const [operator, setOperator] = useState<FilterOperator>(() =>
79
+ defaultOperatorForFilterType(columnType),
80
+ );
61
81
  const [value, setValue] = useState<string>("");
62
82
 
83
+ const handleOpenChange = (next: boolean) => {
84
+ // Reopening reads the applied filter. External updates while editing
85
+ // leave the current draft alone, including the stay-open Clear flow.
86
+ if (next && !open) {
87
+ setOperator(filterValue?.operator ?? defaultOperatorForFilterType(columnType));
88
+ setValue(filterValue?.value == null ? "" : String(filterValue.value));
89
+ }
90
+ setOpen(next);
91
+ };
92
+
63
93
  // Apply is the explicit done affordance of this draft editor — commit-and-
64
94
  // close is its stated intent (LC-21 allows an explicit done/close control).
65
95
  const handleApply = () => {
@@ -76,58 +106,85 @@ export function ColumnHeaderFilter({
76
106
  // filter; outside click / Escape / Apply close.
77
107
  const handleClear = () => {
78
108
  setValue("");
79
- setOperator("contains");
109
+ setOperator(defaultOperatorForFilterType(columnType));
80
110
  onFilterChange(undefined);
81
111
  };
82
112
 
83
113
  return (
84
- <Popover open={open} onOpenChange={setOpen}>
85
- <Tooltip content={isFiltered ? t("Edit filter") : t("Filter this column")}>
86
- <Popover.Trigger asChild>
87
- {/* LC-54 amendment (2026-08-13): the grown press target NEVER
114
+ <Popover scope={popoverScope} open={open} onOpenChange={handleOpenChange} disableFocus>
115
+ {/* Inherit the nearest Popover before entering Tooltip. An explicit
116
+ scope makes Tamagui register web anchors only on mouse hover,
117
+ leaving keyboard opens without a reference. */}
118
+ <Popover.Anchor>
119
+ <Tooltip content={isFiltered ? t("Edit filter") : t("Filter this column")}>
120
+ <Popover.Trigger scope={popoverScope} asChild>
121
+ {/* LC-54 amendment (2026-08-13): the grown press target NEVER
88
122
  paints — hover/press fills on this box spread across the full
89
123
  44px floor and bled into the neighboring header rows via the
90
- negative outsets. Floor-wide feedback is subtree opacity; the
91
- painted hover chrome rides the glyph-scale ring inside
124
+ negative outsets. Painted hover and keyboard focus feedback
125
+ ride the glyph-scale ring inside
92
126
  (Chip dismiss anatomy). */}
93
- <View
94
- cursor="pointer"
95
- {...pressTargetStyle()}
96
- alignItems="center"
97
- justifyContent="center"
98
- marginVertical={-FILTER_TRIGGER_OUTSET}
99
- marginHorizontal={-FILTER_TRIGGER_OUTSET}
100
- hitSlop={pressTargetHitSlop(FILTER_TRIGGER_VISUAL)}
101
- // Axiom 6 HONEST STATE: an applied filter is an active signal —
102
- // it keeps full strength; only the idle affordance rests dimmed.
103
- opacity={isFiltered ? 1 : 0.7}
104
- hoverStyle={{ opacity: 1 }}
105
- pressStyle={{ opacity: 0.9 }}
106
- onPress={(e) => {
107
- e.stopPropagation();
108
- setOpen(true);
109
- }}
110
- role="button"
111
- aria-label={`Filter column ${columnLabel}`}
112
- >
113
127
  <View
114
- padding="$1"
115
- borderRadius="$2"
128
+ ref={triggerRef}
129
+ cursor="pointer"
130
+ {...pressTargetStyle()}
116
131
  alignItems="center"
117
132
  justifyContent="center"
118
- hoverStyle={{ backgroundColor: "$color4" }}
133
+ marginVertical={-FILTER_TRIGGER_OUTSET}
134
+ marginHorizontal={-FILTER_TRIGGER_OUTSET}
135
+ hitSlop={pressTargetHitSlop(FILTER_TRIGGER_VISUAL)}
136
+ // Enabled glyphs keep readable ink; hue and weight distinguish
137
+ // an applied filter from the secondary-color idle affordance.
138
+ // Shared unpainted press-floor / painted glyph-ring anatomy.
139
+ className="mp-chip-dismiss"
140
+ tabIndex={0}
141
+ onKeyDown={
142
+ ((event: { key?: string; preventDefault(): void; stopPropagation(): void }) => {
143
+ if (event.key !== "Enter" && event.key !== " ") return;
144
+ event.preventDefault();
145
+ event.stopPropagation();
146
+ handleOpenChange(true);
147
+ }) as unknown as () => void
148
+ }
149
+ onPress={(e) => {
150
+ e.stopPropagation();
151
+ handleOpenChange(true);
152
+ }}
153
+ role="button"
154
+ aria-label={`Filter column ${columnLabel}`}
119
155
  >
120
- <FunnelIcon
121
- size={iconPx}
122
- color={isFiltered ? "var(--accentColor)" : "var(--color10)"}
123
- weight={isFiltered ? "fill" : "regular"}
124
- />
156
+ <View
157
+ className="mp-chip-dismiss-ring"
158
+ padding="$1"
159
+ borderRadius="$2"
160
+ alignItems="center"
161
+ justifyContent="center"
162
+ hoverStyle={{ backgroundColor: "$color4" }}
163
+ pressStyle={{ backgroundColor: "$color5" }}
164
+ >
165
+ <FunnelIcon
166
+ size={iconPx}
167
+ color={glyphColor}
168
+ weight={isFiltered ? "fill" : "regular"}
169
+ />
170
+ </View>
125
171
  </View>
126
- </View>
127
- </Popover.Trigger>
128
- </Tooltip>
172
+ </Popover.Trigger>
173
+ </Tooltip>
174
+ </Popover.Anchor>
129
175
 
130
176
  <Popover.Content
177
+ scope={popoverScope}
178
+ onPointerDownOutside={() => {
179
+ returnFocusRef.current = false;
180
+ }}
181
+ onCloseAutoFocus={(event) => {
182
+ event.preventDefault();
183
+ if (isWeb && returnFocusRef.current) {
184
+ (triggerRef.current as HTMLElement | null)?.focus();
185
+ }
186
+ returnFocusRef.current = true;
187
+ }}
131
188
  {...knobProps.elevatedSurface}
132
189
  {...knobProps.panelPadding}
133
190
  minWidth={240}
@@ -135,7 +192,7 @@ export function ColumnHeaderFilter({
135
192
  enterStyle={{ y: -5, opacity: 0 }}
136
193
  exitStyle={{ y: -5, opacity: 0 }}
137
194
  >
138
- <Popover.Arrow borderColor="$borderColor" backgroundColor="$color1" />
195
+ <Popover.Arrow scope={popoverScope} borderColor="$borderColor" backgroundColor="$color1" />
139
196
 
140
197
  <YStack {...knobProps.gap}>
141
198
  <Text {...knobProps.label} fontWeight="400" color="$color11">
@@ -155,7 +212,7 @@ export function ColumnHeaderFilter({
155
212
  {/* Actions */}
156
213
  <XStack {...knobProps.gap} justifyContent="flex-end">
157
214
  {isFiltered && (
158
- <Button size={knobProps.sizeToken} variant="outlined" onPress={handleClear}>
215
+ <Button size={knobProps.sizeToken} onPress={handleClear}>
159
216
  {t("Clear")}
160
217
  </Button>
161
218
  )}
@@ -171,8 +171,10 @@ describe("DataTable", () => {
171
171
  />,
172
172
  );
173
173
 
174
- // In test env sm===false → mobile card view renders, column names appear as labels per row
175
- const firstNameLabels = getAllByText("First Name");
174
+ // In test env sm===false → mobile card view renders. A bare string field
175
+ // carries its column name in a VisuallyHidden node ("First Name: "), so
176
+ // the printed "First Name" of the grid header is deliberately absent.
177
+ const firstNameLabels = getAllByText("First Name:");
176
178
  expect(firstNameLabels.length).toBeGreaterThan(0);
177
179
  });
178
180
 
@@ -187,7 +189,7 @@ describe("DataTable", () => {
187
189
  );
188
190
 
189
191
  // In test env sm===false → mobile card view renders
190
- const firstNameLabels = getAllByText("First Name");
192
+ const firstNameLabels = getAllByText("First Name:");
191
193
  expect(firstNameLabels.length).toBeGreaterThan(0);
192
194
  });
193
195