@multiplatform.one/table 7.10.0 → 7.15.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 (307) hide show
  1. package/README.md +61 -1
  2. package/dist/cjs/components/ChildTable/index.cjs +8 -2
  3. package/dist/cjs/components/ChildTable/index.native.js +8 -2
  4. package/dist/cjs/components/ChildTable/index.native.js.map +1 -1
  5. package/dist/cjs/components/ColumnHeaderFilter/index.cjs +77 -111
  6. package/dist/cjs/components/ColumnHeaderFilter/index.native.js +89 -129
  7. package/dist/cjs/components/ColumnHeaderFilter/index.native.js.map +1 -1
  8. package/dist/cjs/components/DataTable/DataTableCardControls.cjs +90 -54
  9. package/dist/cjs/components/DataTable/DataTableCardControls.native.js +93 -56
  10. package/dist/cjs/components/DataTable/DataTableCardControls.native.js.map +1 -1
  11. package/dist/cjs/components/DataTable/DataTableRoot.cjs +68 -9
  12. package/dist/cjs/components/DataTable/DataTableRoot.native.js +78 -11
  13. package/dist/cjs/components/DataTable/DataTableRoot.native.js.map +1 -1
  14. package/dist/cjs/components/DataTableCell/CellModalEditor.cjs +72 -70
  15. package/dist/cjs/components/DataTableCell/index.cjs +2 -2
  16. package/dist/cjs/components/DataTableCell/index.native.js +2 -11
  17. package/dist/cjs/components/DataTableCell/index.native.js.map +1 -1
  18. package/dist/cjs/components/DataTableDateFilter/index.cjs +135 -158
  19. package/dist/cjs/components/DataTableDateFilter/index.native.js +153 -183
  20. package/dist/cjs/components/DataTableDateFilter/index.native.js.map +1 -1
  21. package/dist/cjs/components/DataTableExport/index.cjs +122 -139
  22. package/dist/cjs/components/DataTableExport/index.native.js +135 -157
  23. package/dist/cjs/components/DataTableExport/index.native.js.map +1 -1
  24. package/dist/cjs/components/DataTableFilterButton/index.cjs +14 -0
  25. package/dist/cjs/components/DataTableFilterButton/index.native.js +15 -0
  26. package/dist/cjs/components/DataTableFilterButton/index.native.js.map +1 -1
  27. package/dist/cjs/components/DataTableGrouping/index.cjs +192 -212
  28. package/dist/cjs/components/DataTableGrouping/index.native.js +209 -230
  29. package/dist/cjs/components/DataTableGrouping/index.native.js.map +1 -1
  30. package/dist/cjs/components/DataTableSearch/index.cjs +103 -115
  31. package/dist/cjs/components/DataTableSearch/index.native.js +111 -123
  32. package/dist/cjs/components/DataTableSearch/index.native.js.map +1 -1
  33. package/dist/cjs/components/DataTableToolbar/index.cjs +161 -101
  34. package/dist/cjs/components/DataTableToolbar/index.native.js +168 -109
  35. package/dist/cjs/components/DataTableToolbar/index.native.js.map +1 -1
  36. package/dist/cjs/components/DataTableViewOptions/index.cjs +38 -54
  37. package/dist/cjs/components/DataTableViewOptions/index.native.js +40 -56
  38. package/dist/cjs/components/DataTableViewOptions/index.native.js.map +1 -1
  39. package/dist/cjs/components/FilterOperatorValueEditor/index.cjs +3 -11
  40. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js +3 -11
  41. package/dist/cjs/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  42. package/dist/cjs/components/SimpleTable/index.cjs +2 -6
  43. package/dist/cjs/components/SimpleTable/index.native.js +2 -6
  44. package/dist/cjs/components/SimpleTable/index.native.js.map +1 -1
  45. package/dist/cjs/components/TableInput/RowDetailEditor.cjs +190 -0
  46. package/dist/cjs/components/TableInput/RowDetailEditor.native.js +172 -0
  47. package/dist/cjs/components/TableInput/RowDetailEditor.native.js.map +1 -0
  48. package/dist/cjs/components/TableInput/index.cjs +42 -5
  49. package/dist/cjs/components/TableInput/index.native.js +64 -1
  50. package/dist/cjs/components/TableInput/index.native.js.map +1 -1
  51. package/dist/cjs/components/TableInput/shared.cjs +8 -0
  52. package/dist/cjs/components/TableInput/shared.native.js +10 -0
  53. package/dist/cjs/components/TableInput/shared.native.js.map +1 -1
  54. package/dist/cjs/hooks/useDataTable.cjs +43 -2
  55. package/dist/cjs/hooks/useDataTable.native.js +49 -3
  56. package/dist/cjs/hooks/useDataTable.native.js.map +1 -1
  57. package/dist/cjs/index.native.js.map +1 -1
  58. package/dist/cjs/utils/rowPress.cjs +4 -1
  59. package/dist/cjs/utils/rowPress.native.js +4 -1
  60. package/dist/cjs/utils/rowPress.native.js.map +1 -1
  61. package/dist/esm/components/ChildTable/index.mjs +8 -2
  62. package/dist/esm/components/ChildTable/index.mjs.map +1 -1
  63. package/dist/esm/components/ChildTable/index.native.js +8 -2
  64. package/dist/esm/components/ChildTable/index.native.js.map +1 -1
  65. package/dist/esm/components/ColumnHeaderFilter/index.mjs +80 -114
  66. package/dist/esm/components/ColumnHeaderFilter/index.mjs.map +1 -1
  67. package/dist/esm/components/ColumnHeaderFilter/index.native.js +92 -132
  68. package/dist/esm/components/ColumnHeaderFilter/index.native.js.map +1 -1
  69. package/dist/esm/components/DataTable/DataTableCardControls.mjs +89 -54
  70. package/dist/esm/components/DataTable/DataTableCardControls.mjs.map +1 -1
  71. package/dist/esm/components/DataTable/DataTableCardControls.native.js +92 -56
  72. package/dist/esm/components/DataTable/DataTableCardControls.native.js.map +1 -1
  73. package/dist/esm/components/DataTable/DataTableRoot.mjs +70 -11
  74. package/dist/esm/components/DataTable/DataTableRoot.mjs.map +1 -1
  75. package/dist/esm/components/DataTable/DataTableRoot.native.js +80 -13
  76. package/dist/esm/components/DataTable/DataTableRoot.native.js.map +1 -1
  77. package/dist/esm/components/DataTableCell/CellModalEditor.mjs +76 -74
  78. package/dist/esm/components/DataTableCell/CellModalEditor.mjs.map +1 -1
  79. package/dist/esm/components/DataTableCell/index.mjs +3 -3
  80. package/dist/esm/components/DataTableCell/index.mjs.map +1 -1
  81. package/dist/esm/components/DataTableCell/index.native.js +3 -12
  82. package/dist/esm/components/DataTableCell/index.native.js.map +1 -1
  83. package/dist/esm/components/DataTableDateFilter/index.mjs +137 -160
  84. package/dist/esm/components/DataTableDateFilter/index.mjs.map +1 -1
  85. package/dist/esm/components/DataTableDateFilter/index.native.js +155 -185
  86. package/dist/esm/components/DataTableDateFilter/index.native.js.map +1 -1
  87. package/dist/esm/components/DataTableExport/index.mjs +124 -141
  88. package/dist/esm/components/DataTableExport/index.mjs.map +1 -1
  89. package/dist/esm/components/DataTableExport/index.native.js +137 -159
  90. package/dist/esm/components/DataTableExport/index.native.js.map +1 -1
  91. package/dist/esm/components/DataTableFilterButton/index.mjs +14 -1
  92. package/dist/esm/components/DataTableFilterButton/index.mjs.map +1 -1
  93. package/dist/esm/components/DataTableFilterButton/index.native.js +15 -1
  94. package/dist/esm/components/DataTableFilterButton/index.native.js.map +1 -1
  95. package/dist/esm/components/DataTableGrouping/index.mjs +194 -214
  96. package/dist/esm/components/DataTableGrouping/index.mjs.map +1 -1
  97. package/dist/esm/components/DataTableGrouping/index.native.js +211 -232
  98. package/dist/esm/components/DataTableGrouping/index.native.js.map +1 -1
  99. package/dist/esm/components/DataTableSearch/index.mjs +105 -117
  100. package/dist/esm/components/DataTableSearch/index.mjs.map +1 -1
  101. package/dist/esm/components/DataTableSearch/index.native.js +113 -125
  102. package/dist/esm/components/DataTableSearch/index.native.js.map +1 -1
  103. package/dist/esm/components/DataTableToolbar/index.mjs +165 -106
  104. package/dist/esm/components/DataTableToolbar/index.mjs.map +1 -1
  105. package/dist/esm/components/DataTableToolbar/index.native.js +172 -114
  106. package/dist/esm/components/DataTableToolbar/index.native.js.map +1 -1
  107. package/dist/esm/components/DataTableViewOptions/index.mjs +40 -56
  108. package/dist/esm/components/DataTableViewOptions/index.mjs.map +1 -1
  109. package/dist/esm/components/DataTableViewOptions/index.native.js +42 -58
  110. package/dist/esm/components/DataTableViewOptions/index.native.js.map +1 -1
  111. package/dist/esm/components/FilterOperatorValueEditor/index.mjs +3 -11
  112. package/dist/esm/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  113. package/dist/esm/components/FilterOperatorValueEditor/index.native.js +3 -11
  114. package/dist/esm/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  115. package/dist/esm/components/SimpleTable/index.mjs +3 -7
  116. package/dist/esm/components/SimpleTable/index.mjs.map +1 -1
  117. package/dist/esm/components/SimpleTable/index.native.js +3 -7
  118. package/dist/esm/components/SimpleTable/index.native.js.map +1 -1
  119. package/dist/esm/components/TableInput/RowDetailEditor.mjs +165 -0
  120. package/dist/esm/components/TableInput/RowDetailEditor.mjs.map +1 -0
  121. package/dist/esm/components/TableInput/RowDetailEditor.native.js +144 -0
  122. package/dist/esm/components/TableInput/RowDetailEditor.native.js.map +1 -0
  123. package/dist/esm/components/TableInput/index.mjs +42 -5
  124. package/dist/esm/components/TableInput/index.mjs.map +1 -1
  125. package/dist/esm/components/TableInput/index.native.js +64 -1
  126. package/dist/esm/components/TableInput/index.native.js.map +1 -1
  127. package/dist/esm/components/TableInput/shared.mjs +7 -1
  128. package/dist/esm/components/TableInput/shared.mjs.map +1 -1
  129. package/dist/esm/components/TableInput/shared.native.js +9 -1
  130. package/dist/esm/components/TableInput/shared.native.js.map +1 -1
  131. package/dist/esm/hooks/useDataTable.mjs +43 -2
  132. package/dist/esm/hooks/useDataTable.mjs.map +1 -1
  133. package/dist/esm/hooks/useDataTable.native.js +49 -3
  134. package/dist/esm/hooks/useDataTable.native.js.map +1 -1
  135. package/dist/esm/index.mjs.map +1 -1
  136. package/dist/esm/index.native.js.map +1 -1
  137. package/dist/esm/utils/rowPress.mjs +4 -1
  138. package/dist/esm/utils/rowPress.mjs.map +1 -1
  139. package/dist/esm/utils/rowPress.native.js +4 -1
  140. package/dist/esm/utils/rowPress.native.js.map +1 -1
  141. package/dist/jsx/components/ChildTable/index.mjs +8 -2
  142. package/dist/jsx/components/ChildTable/index.mjs.map +1 -1
  143. package/dist/jsx/components/ChildTable/index.native.js +8 -2
  144. package/dist/jsx/components/ChildTable/index.native.js.map +1 -1
  145. package/dist/jsx/components/ColumnHeaderFilter/index.mjs +80 -114
  146. package/dist/jsx/components/ColumnHeaderFilter/index.mjs.map +1 -1
  147. package/dist/jsx/components/ColumnHeaderFilter/index.native.js +89 -129
  148. package/dist/jsx/components/ColumnHeaderFilter/index.native.js.map +1 -1
  149. package/dist/jsx/components/DataTable/DataTableCardControls.mjs +89 -54
  150. package/dist/jsx/components/DataTable/DataTableCardControls.mjs.map +1 -1
  151. package/dist/jsx/components/DataTable/DataTableCardControls.native.js +93 -56
  152. package/dist/jsx/components/DataTable/DataTableCardControls.native.js.map +1 -1
  153. package/dist/jsx/components/DataTable/DataTableRoot.mjs +70 -11
  154. package/dist/jsx/components/DataTable/DataTableRoot.mjs.map +1 -1
  155. package/dist/jsx/components/DataTable/DataTableRoot.native.js +78 -11
  156. package/dist/jsx/components/DataTable/DataTableRoot.native.js.map +1 -1
  157. package/dist/jsx/components/DataTableCell/CellModalEditor.mjs +76 -74
  158. package/dist/jsx/components/DataTableCell/CellModalEditor.mjs.map +1 -1
  159. package/dist/jsx/components/DataTableCell/index.mjs +3 -3
  160. package/dist/jsx/components/DataTableCell/index.mjs.map +1 -1
  161. package/dist/jsx/components/DataTableCell/index.native.js +2 -11
  162. package/dist/jsx/components/DataTableCell/index.native.js.map +1 -1
  163. package/dist/jsx/components/DataTableDateFilter/index.mjs +137 -160
  164. package/dist/jsx/components/DataTableDateFilter/index.mjs.map +1 -1
  165. package/dist/jsx/components/DataTableDateFilter/index.native.js +153 -183
  166. package/dist/jsx/components/DataTableDateFilter/index.native.js.map +1 -1
  167. package/dist/jsx/components/DataTableExport/index.mjs +124 -141
  168. package/dist/jsx/components/DataTableExport/index.mjs.map +1 -1
  169. package/dist/jsx/components/DataTableExport/index.native.js +135 -157
  170. package/dist/jsx/components/DataTableExport/index.native.js.map +1 -1
  171. package/dist/jsx/components/DataTableFilterButton/index.mjs +14 -1
  172. package/dist/jsx/components/DataTableFilterButton/index.mjs.map +1 -1
  173. package/dist/jsx/components/DataTableFilterButton/index.native.js +15 -0
  174. package/dist/jsx/components/DataTableFilterButton/index.native.js.map +1 -1
  175. package/dist/jsx/components/DataTableGrouping/index.mjs +194 -214
  176. package/dist/jsx/components/DataTableGrouping/index.mjs.map +1 -1
  177. package/dist/jsx/components/DataTableGrouping/index.native.js +209 -230
  178. package/dist/jsx/components/DataTableGrouping/index.native.js.map +1 -1
  179. package/dist/jsx/components/DataTableSearch/index.mjs +105 -117
  180. package/dist/jsx/components/DataTableSearch/index.mjs.map +1 -1
  181. package/dist/jsx/components/DataTableSearch/index.native.js +111 -123
  182. package/dist/jsx/components/DataTableSearch/index.native.js.map +1 -1
  183. package/dist/jsx/components/DataTableToolbar/index.mjs +165 -106
  184. package/dist/jsx/components/DataTableToolbar/index.mjs.map +1 -1
  185. package/dist/jsx/components/DataTableToolbar/index.native.js +168 -109
  186. package/dist/jsx/components/DataTableToolbar/index.native.js.map +1 -1
  187. package/dist/jsx/components/DataTableViewOptions/index.mjs +40 -56
  188. package/dist/jsx/components/DataTableViewOptions/index.mjs.map +1 -1
  189. package/dist/jsx/components/DataTableViewOptions/index.native.js +40 -56
  190. package/dist/jsx/components/DataTableViewOptions/index.native.js.map +1 -1
  191. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs +3 -11
  192. package/dist/jsx/components/FilterOperatorValueEditor/index.mjs.map +1 -1
  193. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js +3 -11
  194. package/dist/jsx/components/FilterOperatorValueEditor/index.native.js.map +1 -1
  195. package/dist/jsx/components/SimpleTable/index.mjs +3 -7
  196. package/dist/jsx/components/SimpleTable/index.mjs.map +1 -1
  197. package/dist/jsx/components/SimpleTable/index.native.js +2 -6
  198. package/dist/jsx/components/SimpleTable/index.native.js.map +1 -1
  199. package/dist/jsx/components/TableInput/RowDetailEditor.mjs +165 -0
  200. package/dist/jsx/components/TableInput/RowDetailEditor.mjs.map +1 -0
  201. package/dist/jsx/components/TableInput/RowDetailEditor.native.js +172 -0
  202. package/dist/jsx/components/TableInput/RowDetailEditor.native.js.map +1 -0
  203. package/dist/jsx/components/TableInput/index.mjs +42 -5
  204. package/dist/jsx/components/TableInput/index.mjs.map +1 -1
  205. package/dist/jsx/components/TableInput/index.native.js +64 -1
  206. package/dist/jsx/components/TableInput/index.native.js.map +1 -1
  207. package/dist/jsx/components/TableInput/shared.mjs +7 -1
  208. package/dist/jsx/components/TableInput/shared.mjs.map +1 -1
  209. package/dist/jsx/components/TableInput/shared.native.js +10 -0
  210. package/dist/jsx/components/TableInput/shared.native.js.map +1 -1
  211. package/dist/jsx/hooks/useDataTable.mjs +43 -2
  212. package/dist/jsx/hooks/useDataTable.mjs.map +1 -1
  213. package/dist/jsx/hooks/useDataTable.native.js +49 -3
  214. package/dist/jsx/hooks/useDataTable.native.js.map +1 -1
  215. package/dist/jsx/index.js.map +1 -1
  216. package/dist/jsx/index.mjs.map +1 -1
  217. package/dist/jsx/index.native.js.map +1 -1
  218. package/dist/jsx/utils/rowPress.mjs +4 -1
  219. package/dist/jsx/utils/rowPress.mjs.map +1 -1
  220. package/dist/jsx/utils/rowPress.native.js +4 -1
  221. package/dist/jsx/utils/rowPress.native.js.map +1 -1
  222. package/package.json +16 -16
  223. package/src/components/ChildTable/childTable.cellHidden.spec.tsx +57 -0
  224. package/src/components/ChildTable/childTable.rowDetail.spec.tsx +120 -0
  225. package/src/components/ChildTable/index.tsx +16 -0
  226. package/src/components/ColumnHeaderFilter/index.tsx +89 -116
  227. package/src/components/DataTable/DataTable.stories.tsx +130 -6
  228. package/src/components/DataTable/DataTableCardControls.stories.tsx +61 -2
  229. package/src/components/DataTable/DataTableCardControls.tsx +92 -66
  230. package/src/components/DataTable/DataTableRoot.tsx +109 -18
  231. package/src/components/DataTable/cardLayout.spec.tsx +4 -3
  232. package/src/components/DataTable/cardToolbar.spec.tsx +238 -0
  233. package/src/components/DataTable/chromeInterplay.spec.tsx +7 -5
  234. package/src/components/DataTable/columnWidthLayout.spec.tsx +189 -0
  235. package/src/components/DataTable/dataTableCardControls.spec.tsx +3 -2
  236. package/src/components/DataTable/dataTableMobileCards.spec.tsx +1 -4
  237. package/src/components/DataTable/footerLayout.spec.tsx +250 -0
  238. package/src/components/DataTable/headerContainment.spec.tsx +91 -0
  239. package/src/components/DataTable/pinningGeometry.spec.tsx +66 -1
  240. package/src/components/DataTable/rowPress.spec.tsx +2 -6
  241. package/src/components/DataTableBulkActions/DataTableBulkActions.stories.tsx +5 -4
  242. package/src/components/DataTableCell/CellModalEditor.tsx +95 -75
  243. package/src/components/DataTableCell/cellDraftPolicy.spec.tsx +12 -2
  244. package/src/components/DataTableCell/cellModalEditor.spec.tsx +75 -49
  245. package/src/components/DataTableCell/dataTableCell.spec.tsx +31 -14
  246. package/src/components/DataTableCell/index.tsx +3 -2
  247. package/src/components/DataTableDateFilter/DataTableDateFilter.spec.tsx +6 -3
  248. package/src/components/DataTableDateFilter/index.tsx +151 -180
  249. package/src/components/DataTableExport/DataTableExport.spec.tsx +42 -18
  250. package/src/components/DataTableExport/index.tsx +135 -142
  251. package/src/components/DataTableFilterButton/index.tsx +9 -0
  252. package/src/components/DataTableGrouping/index.tsx +193 -195
  253. package/src/components/DataTableSearch/index.tsx +111 -109
  254. package/src/components/DataTableToolbar/index.tsx +179 -107
  255. package/src/components/DataTableViewOptions/DataTableViewOptions.stories.tsx +52 -0
  256. package/src/components/DataTableViewOptions/index.tsx +32 -40
  257. package/src/components/FilterOperatorValueEditor/FilterOperatorValueEditor.spec.tsx +64 -2
  258. package/src/components/FilterOperatorValueEditor/index.tsx +0 -8
  259. package/src/components/SimpleTable/index.tsx +3 -2
  260. package/src/components/SimpleTable/simpleTable.spec.tsx +15 -0
  261. package/src/components/Table/accessibility.spec.tsx +7 -19
  262. package/src/components/TableInput/RowDetailEditor.native.tsx +134 -0
  263. package/src/components/TableInput/RowDetailEditor.tsx +173 -0
  264. package/src/components/TableInput/index.native.tsx +49 -1
  265. package/src/components/TableInput/index.tsx +65 -10
  266. package/src/components/TableInput/shared.ts +29 -0
  267. package/src/components/tableDropdowns.spec.tsx +172 -0
  268. package/src/hooks/useDataTable.spec.ts +153 -0
  269. package/src/hooks/useDataTable.ts +38 -2
  270. package/src/index.ts +1 -0
  271. package/src/types.ts +14 -12
  272. package/src/utils/rowPress.ts +3 -0
  273. package/types/components/ChildTable/index.d.ts +10 -0
  274. package/types/components/ChildTable/index.d.ts.map +1 -1
  275. package/types/components/ColumnHeaderFilter/index.d.ts +1 -1
  276. package/types/components/ColumnHeaderFilter/index.d.ts.map +1 -1
  277. package/types/components/DataTable/DataTableCardControls.d.ts +3 -0
  278. package/types/components/DataTable/DataTableCardControls.d.ts.map +1 -1
  279. package/types/components/DataTable/DataTableRoot.d.ts.map +1 -1
  280. package/types/components/DataTableCell/CellModalEditor.d.ts +10 -7
  281. package/types/components/DataTableCell/CellModalEditor.d.ts.map +1 -1
  282. package/types/components/DataTableCell/index.d.ts.map +1 -1
  283. package/types/components/DataTableDateFilter/index.d.ts.map +1 -1
  284. package/types/components/DataTableFilterButton/index.d.ts +2 -1
  285. package/types/components/DataTableFilterButton/index.d.ts.map +1 -1
  286. package/types/components/DataTableGrouping/index.d.ts.map +1 -1
  287. package/types/components/DataTableSearch/index.d.ts.map +1 -1
  288. package/types/components/DataTableToolbar/index.d.ts +1 -0
  289. package/types/components/DataTableToolbar/index.d.ts.map +1 -1
  290. package/types/components/FilterOperatorValueEditor/index.d.ts.map +1 -1
  291. package/types/components/SimpleTable/index.d.ts.map +1 -1
  292. package/types/components/TableInput/RowDetailEditor.d.ts +24 -0
  293. package/types/components/TableInput/RowDetailEditor.d.ts.map +1 -0
  294. package/types/components/TableInput/RowDetailEditor.native.d.ts +11 -0
  295. package/types/components/TableInput/RowDetailEditor.native.d.ts.map +1 -0
  296. package/types/components/TableInput/index.d.ts +11 -2
  297. package/types/components/TableInput/index.d.ts.map +1 -1
  298. package/types/components/TableInput/index.native.d.ts +8 -1
  299. package/types/components/TableInput/index.native.d.ts.map +1 -1
  300. package/types/components/TableInput/shared.d.ts +11 -0
  301. package/types/components/TableInput/shared.d.ts.map +1 -1
  302. package/types/hooks/useDataTable.d.ts.map +1 -1
  303. package/types/index.d.ts +1 -0
  304. package/types/index.d.ts.map +1 -1
  305. package/types/types.d.ts +14 -12
  306. package/types/types.d.ts.map +1 -1
  307. package/types/utils/rowPress.d.ts.map +1 -1
@@ -1,10 +1,10 @@
1
1
  /**
2
- * ColumnHeaderFilter - Filter popover for individual column headers
2
+ * ColumnHeaderFilter - Filter panel for individual column headers
3
3
  * AG Grid style column filtering with operators and value inputs
4
4
  */
5
5
 
6
6
  import { FunnelIcon } from "@phosphor-icons/react";
7
- import { Button } from "@multiplatform.one/forms";
7
+ import { Button, FloatingPanel } from "@multiplatform.one/forms";
8
8
  import {
9
9
  ensureCompositeFocusRing,
10
10
  MIN_PRESS_TARGET,
@@ -14,9 +14,9 @@ import {
14
14
  useResolvedKnobs,
15
15
  useGlyphColor,
16
16
  } from "@multiplatform.one/theme";
17
- import { useId, useRef, useState } from "react";
17
+ import { useState } from "react";
18
18
  import { Tooltip } from "@multiplatform.one/components";
19
- import { Popover, Text, View, XStack, YStack, isWeb, type TamaguiElement } from "tamagui";
19
+ import { Text, View, XStack, YStack } from "tamagui";
20
20
  import { t } from "../../shared/t";
21
21
  import type { DataTableColumnType, FilterOperator } from "../../types";
22
22
  import { iconSizeForToken } from "../../utils/chromeIcons";
@@ -67,11 +67,6 @@ export function ColumnHeaderFilter({
67
67
  const idleColor = useGlyphColor("$color11");
68
68
  const activeColor = useAccentOnSurface();
69
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
70
  ensureCompositeFocusRing();
76
71
  const iconPx = iconSizeForToken(String(knobProps.sizeToken));
77
72
  const [open, setOpen] = useState(false);
@@ -110,118 +105,96 @@ export function ColumnHeaderFilter({
110
105
  onFilterChange(undefined);
111
106
  };
112
107
 
113
- return (
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
122
- paints — hover/press fills on this box spread across the full
123
- 44px floor and bled into the neighboring header rows via the
124
- negative outsets. Painted hover and keyboard focus feedback
125
- ride the glyph-scale ring inside
126
- (Chip dismiss anatomy). */}
127
- <View
128
- ref={triggerRef}
129
- cursor="pointer"
130
- {...pressTargetStyle()}
131
- alignItems="center"
132
- justifyContent="center"
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}`}
155
- >
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>
171
- </View>
172
- </Popover.Trigger>
173
- </Tooltip>
174
- </Popover.Anchor>
175
-
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;
108
+ // The panel owns the pointer toggle (mousedown) and the keyboard-synthesized
109
+ // click. The trigger only stops the click reaching the header's sort press
110
+ // and opens on Enter/Space, which a role=button div does not synthesize.
111
+ const trigger = (
112
+ <Tooltip content={isFiltered ? t("Edit filter") : t("Filter this column")}>
113
+ {/* LC-54 amendment (2026-08-13): the grown press target NEVER
114
+ paints — hover/press fills on this box spread across the full
115
+ 44px floor and bled into the neighboring header rows via the
116
+ negative outsets. Painted hover and keyboard focus feedback
117
+ ride the glyph-scale ring inside
118
+ (Chip dismiss anatomy). */}
119
+ <View
120
+ cursor="pointer"
121
+ {...pressTargetStyle()}
122
+ alignItems="center"
123
+ justifyContent="center"
124
+ marginVertical={-FILTER_TRIGGER_OUTSET}
125
+ marginHorizontal={-FILTER_TRIGGER_OUTSET}
126
+ hitSlop={pressTargetHitSlop(FILTER_TRIGGER_VISUAL)}
127
+ // Enabled glyphs keep readable ink; hue and weight distinguish
128
+ // an applied filter from the secondary-color idle affordance.
129
+ // Shared unpainted press-floor / painted glyph-ring anatomy.
130
+ className="mp-chip-dismiss"
131
+ tabIndex={0}
132
+ onKeyDown={
133
+ ((event: { key?: string; preventDefault(): void; stopPropagation(): void }) => {
134
+ if (event.key !== "Enter" && event.key !== " ") return;
135
+ event.preventDefault();
136
+ event.stopPropagation();
137
+ handleOpenChange(true);
138
+ }) as unknown as () => void
139
+ }
140
+ onPress={(e) => {
141
+ e.stopPropagation();
187
142
  }}
188
- {...knobProps.elevatedSurface}
189
- {...knobProps.panelPadding}
190
- minWidth={240}
191
- transition={knobProps.transition}
192
- enterStyle={{ y: -5, opacity: 0 }}
193
- exitStyle={{ y: -5, opacity: 0 }}
143
+ role="button"
144
+ aria-label={`Filter column ${columnLabel}`}
145
+ aria-haspopup="dialog"
146
+ aria-expanded={open}
194
147
  >
195
- <Popover.Arrow scope={popoverScope} borderColor="$borderColor" backgroundColor="$color1" />
148
+ <View
149
+ className="mp-chip-dismiss-ring"
150
+ padding="$1"
151
+ borderRadius="$2"
152
+ alignItems="center"
153
+ justifyContent="center"
154
+ hoverStyle={{ backgroundColor: "$color4" }}
155
+ pressStyle={{ backgroundColor: "$color5" }}
156
+ >
157
+ <FunnelIcon size={iconPx} color={glyphColor} weight={isFiltered ? "fill" : "regular"} />
158
+ </View>
159
+ </View>
160
+ </Tooltip>
161
+ );
196
162
 
197
- <YStack {...knobProps.gap}>
198
- <Text {...knobProps.label} fontWeight="400" color="$color11">
199
- {t("Filter: {{column}}", { column: columnLabel })}
200
- </Text>
163
+ return (
164
+ <FloatingPanel
165
+ open={open}
166
+ onOpenChange={handleOpenChange}
167
+ trigger={trigger}
168
+ triggerSizing="content"
169
+ widthMode="fit-content"
170
+ >
171
+ <YStack {...knobProps.gap} minWidth={240} data-dismiss-class="compose">
172
+ <Text {...knobProps.label} fontWeight="400" color="$color11">
173
+ {t("Filter: {{column}}", { column: columnLabel })}
174
+ </Text>
201
175
 
202
- {/* Shared operator/value editor (LC-16 — same one the toolbar filter uses) */}
203
- <FilterOperatorValueEditor
204
- fieldType={columnType}
205
- operator={operator}
206
- value={value}
207
- onOperatorChange={setOperator}
208
- onValueChange={setValue}
209
- options={options}
210
- />
176
+ {/* Shared operator/value editor (LC-16 — same one the toolbar filter uses) */}
177
+ <FilterOperatorValueEditor
178
+ fieldType={columnType}
179
+ operator={operator}
180
+ value={value}
181
+ onOperatorChange={setOperator}
182
+ onValueChange={setValue}
183
+ options={options}
184
+ />
211
185
 
212
- {/* Actions */}
213
- <XStack {...knobProps.gap} justifyContent="flex-end">
214
- {isFiltered && (
215
- <Button size={knobProps.sizeToken} onPress={handleClear}>
216
- {t("Clear")}
217
- </Button>
218
- )}
219
- <Button size={knobProps.sizeToken} onPress={handleApply}>
220
- {t("Apply")}
186
+ {/* Actions */}
187
+ <XStack {...knobProps.gap} justifyContent="flex-end">
188
+ {isFiltered && (
189
+ <Button size={knobProps.sizeToken} onPress={handleClear}>
190
+ {t("Clear")}
221
191
  </Button>
222
- </XStack>
223
- </YStack>
224
- </Popover.Content>
225
- </Popover>
192
+ )}
193
+ <Button size={knobProps.sizeToken} onPress={handleApply}>
194
+ {t("Apply")}
195
+ </Button>
196
+ </XStack>
197
+ </YStack>
198
+ </FloatingPanel>
226
199
  );
227
200
  }
@@ -605,6 +605,36 @@ export const WithColumnPinning: Story = {
605
605
  },
606
606
  };
607
607
 
608
+ function RtlDocument({ children }: { children: React.ReactNode }) {
609
+ React.useEffect(() => {
610
+ const previous = document.documentElement.getAttribute("dir");
611
+ document.documentElement.setAttribute("dir", "rtl");
612
+ return () => {
613
+ if (previous === null) document.documentElement.removeAttribute("dir");
614
+ else document.documentElement.setAttribute("dir", previous);
615
+ };
616
+ }, []);
617
+ return <>{children}</>;
618
+ }
619
+
620
+ export const WithColumnPinningRTL: Story = {
621
+ name: "With Column Pinning RTL",
622
+ args: WithColumnPinning.args,
623
+ render: (args) => (
624
+ <RtlDocument>
625
+ <DataTable {...args} />
626
+ </RtlDocument>
627
+ ),
628
+ parameters: {
629
+ docs: {
630
+ description: {
631
+ story:
632
+ "WithColumnPinning under a right-to-left document. Pinned columns stick to the inline start and end, which are the right and left edges here, and each sticky inset is the summed width of the pinned cells before it (MPO-236).",
633
+ },
634
+ },
635
+ },
636
+ };
637
+
608
638
  export const WithKeyboardNavigation: Story = {
609
639
  args: {
610
640
  data: sampleData,
@@ -2951,15 +2981,11 @@ export const CompoundComposition: Story = {
2951
2981
  */
2952
2982
  const RowPressStory = () => {
2953
2983
  const data = useMemo(() => generateUsers(8), []);
2954
- // Explicit ids on every column: DataTable seeds columnOrder from
2955
- // `col.id || ""`, so mixing id-less accessor columns with id'd display
2956
- // columns would reorder the id'd ones first.
2957
2984
  const rowPressColumns = useMemo<DataTableColumn<User>[]>(
2958
2985
  () => [
2959
- { id: "firstName", accessorKey: "firstName", header: "First Name" },
2960
- { id: "department", accessorKey: "department", header: "Department" },
2986
+ { accessorKey: "firstName", header: "First Name" },
2987
+ { accessorKey: "department", header: "Department" },
2961
2988
  {
2962
- id: "salary",
2963
2989
  accessorKey: "salary",
2964
2990
  header: "Salary",
2965
2991
  align: "right",
@@ -3262,3 +3288,101 @@ export const MoneyColumn: Story = {
3262
3288
  },
3263
3289
  },
3264
3290
  };
3291
+
3292
+ const widthRows = [
3293
+ { id: "1", rank: 1, label: "A long account label to inspect clipping", score: 92 },
3294
+ { id: "2", rank: 2, label: "Another account", score: 85 },
3295
+ ];
3296
+ const declaredWidthColumns: DataTableColumn<(typeof widthRows)[number]>[] = [
3297
+ { accessorKey: "rank", header: "Rank", width: 48, footer: "2" },
3298
+ {
3299
+ accessorKey: "label",
3300
+ header: "Account",
3301
+ width: 320,
3302
+ minWidth: 200,
3303
+ maxWidth: 400,
3304
+ footer: "Two accounts",
3305
+ },
3306
+ { accessorKey: "score", header: "Score", width: 80, footer: "177" },
3307
+ ];
3308
+
3309
+ export const ColumnWidthContract: Story = {
3310
+ render: function ColumnWidthExample(args) {
3311
+ const [columnLayout, setColumnLayout] = React.useState<"equal" | "scroll" | "auto">("scroll");
3312
+ const [resizing, setResizing] = React.useState(false);
3313
+ return (
3314
+ <YStack gap="$3" width="100%">
3315
+ <Text>Declared widths: Rank 48px, Account 320px (200–400px), Score 80px.</Text>
3316
+ <View flexDirection="row" flexWrap="wrap" gap="$2">
3317
+ {(["equal", "scroll", "auto"] as const).map((mode) => (
3318
+ <Button
3319
+ key={mode}
3320
+ aria-pressed={columnLayout === mode}
3321
+ onPress={() => setColumnLayout(mode)}
3322
+ >
3323
+ {mode}
3324
+ </Button>
3325
+ ))}
3326
+ <Button aria-pressed={resizing} onPress={() => setResizing((enabled) => !enabled)}>
3327
+ Resizing {resizing ? "on" : "off"}
3328
+ </Button>
3329
+ </View>
3330
+ <Text>
3331
+ Pin Rank then Account with their header controls to inspect offsets. Switch to equal with
3332
+ resizing off to compare pinned fixed widths and unpinned equal widths. In scroll, narrow
3333
+ the viewport to inspect horizontal overflow and footer alignment.
3334
+ </Text>
3335
+ <DataTable
3336
+ {...args}
3337
+ data={widthRows}
3338
+ columns={declaredWidthColumns as DataTableColumn<Record<string, any>>[]}
3339
+ layout="table"
3340
+ columnLayout={columnLayout}
3341
+ enableColumnResizing={resizing}
3342
+ enableColumnPinning
3343
+ enablePagination={false}
3344
+ readOnly
3345
+ />
3346
+ </YStack>
3347
+ );
3348
+ },
3349
+ };
3350
+
3351
+ const narrowHeaderRows = [
3352
+ { id: "1", account: "acme-website", quantity: 142, status: "Live", owner: "Rivera" },
3353
+ { id: "2", account: "tamagui-docs", quantity: 89, status: "Draft", owner: "Okafor" },
3354
+ { id: "3", account: "mobile-app", quantity: 34, status: "Live", owner: "Lindqvist" },
3355
+ ];
3356
+
3357
+ const narrowHeaderColumns: DataTableColumn<(typeof narrowHeaderRows)[number]>[] = [
3358
+ { id: "account", accessorKey: "account", header: "Customer account (input)", width: 104 },
3359
+ {
3360
+ id: "quantity",
3361
+ accessorKey: "quantity",
3362
+ header: "Quantity (stepper)",
3363
+ align: "right",
3364
+ width: 104,
3365
+ },
3366
+ { id: "status", accessorKey: "status", header: "Status (select)", width: 104 },
3367
+ { id: "owner", accessorKey: "owner", header: "Responsibilities", width: 104 },
3368
+ ];
3369
+
3370
+ /**
3371
+ * MPO-336 / LC-10: every column is narrower than its header label plus the
3372
+ * sort and filter glyphs. Each label wraps inside its own header cell, a
3373
+ * single long word breaks rather than overflowing, and the glyphs stay in
3374
+ * their column. Quantity is right-aligned (numbers, DG-TBL-01), the case
3375
+ * that used to spill left over the previous column.
3376
+ */
3377
+ export const NarrowHeaders: Story = {
3378
+ args: {
3379
+ data: narrowHeaderRows,
3380
+ columns: narrowHeaderColumns as DataTableColumn<Record<string, any>>[],
3381
+ layout: "table",
3382
+ columnLayout: "scroll",
3383
+ enableSorting: true,
3384
+ enableFiltering: true,
3385
+ enablePagination: false,
3386
+ readOnly: true,
3387
+ },
3388
+ };
@@ -4,7 +4,7 @@
4
4
  * The grid puts sorting and per-column filtering in the column headers. The
5
5
  * card layout has no headers, so this toolbar restores both: a sort menu that
6
6
  * cycles none → asc → desc per sortable column (the same cycle as a header
7
- * click) and the compact DataTableFilters chrome. Both drive the same table
7
+ * click) and the canonical all-field Filter. Both drive the same table
8
8
  * state as the grid — there is no parallel state.
9
9
  *
10
10
  * It only exists in `layout="cards"`, which is why these stories pin the
@@ -69,7 +69,7 @@ function CardTable(props: Record<string, any>) {
69
69
  );
70
70
  }
71
71
 
72
- /** Both affordances: Sort menu on the left, Add Filter chrome beside it. */
72
+ /** Default cards keep Filter and Sort together. */
73
73
  export const Default = {
74
74
  name: "Main",
75
75
  render: () => <CardTable enableSorting enableFiltering />,
@@ -114,3 +114,62 @@ export const NoControls = {
114
114
  </YStack>
115
115
  ),
116
116
  };
117
+
118
+ export const MobileControls = {
119
+ args: { width: 390, search: true, views: true, fetching: true, longSort: true, disabled: false },
120
+ argTypes: {
121
+ width: { control: "select", options: [320, 390] },
122
+ search: { control: "boolean" },
123
+ views: { control: "boolean" },
124
+ fetching: { control: "boolean" },
125
+ longSort: { control: "boolean" },
126
+ disabled: { control: "boolean" },
127
+ },
128
+ render: (args: {
129
+ width: number;
130
+ search: boolean;
131
+ views: boolean;
132
+ fetching: boolean;
133
+ longSort: boolean;
134
+ disabled: boolean;
135
+ }) => (
136
+ <YStack width={args.width} maxWidth="100%" padding="$3">
137
+ <DataTable
138
+ key={String(args.longSort)}
139
+ data={people.map((person) => ({ ...person, year: person.id < 3 ? 2023 : 2024 }))}
140
+ columns={[
141
+ {
142
+ accessorKey: "firstName",
143
+ header: "Name with a long distinguishing classification suffix",
144
+ },
145
+ { accessorKey: "age", header: "Age" },
146
+ ]}
147
+ filterableFields={[{ id: "year", label: "Year", type: "number" }]}
148
+ layout="cards"
149
+ enableGlobalSearch={args.search}
150
+ enableViews={args.views}
151
+ isFetching={args.fetching}
152
+ disabled={args.disabled}
153
+ initialState={{
154
+ filters: [{ id: "year", columnId: "year", value: { operator: "is", value: "2023" } }],
155
+ sorting: args.longSort ? [{ id: "firstName", desc: false }] : [],
156
+ activeViewId: "long",
157
+ views: [
158
+ {
159
+ id: "long",
160
+ name: "Saved view with a long distinguishing classification suffix",
161
+ columns: {},
162
+ filters: [],
163
+ sorting: [],
164
+ pagination: { pageIndex: 0, pageSize: 10 },
165
+ },
166
+ ],
167
+ }}
168
+ />
169
+ </YStack>
170
+ ),
171
+ };
172
+
173
+ export const CustomToolbarFallback = {
174
+ render: () => <CardTable renderToolbar={() => <Paragraph>Custom toolbar</Paragraph>} />,
175
+ };
@@ -44,31 +44,109 @@ function getColumnLabel(column: any): string {
44
44
  return typeof column.columnDef.header === "string" ? column.columnDef.header : column.id;
45
45
  }
46
46
 
47
- export function DataTableCardControls({
47
+ export function DataTableCardSortControl({
48
48
  table,
49
- enableSorting = false,
50
- enableFiltering = false,
51
- availableColumns = [],
52
49
  compact = false,
53
50
  disabled = false,
54
- }: DataTableCardControlsProps) {
51
+ contained = false,
52
+ }: Pick<DataTableCardControlsProps, "table" | "compact" | "disabled"> & { contained?: boolean }) {
55
53
  const { t } = useTranslation();
56
- const { knobProps, disabledState } = useResolvedKnobs({ component: "DataTable", compact });
54
+ const { knobProps } = useResolvedKnobs({ component: "DataTable", compact });
57
55
  const chrome = dataTableChrome(String(knobProps.sizeToken));
58
56
  const [sortMenuOpen, setSortMenuOpen] = useState(false);
59
-
60
- const sortableColumns = enableSorting
61
- ? table.getVisibleLeafColumns().filter((col: any) => col.getCanSort())
62
- : [];
63
-
57
+ const sortableColumns = table.getVisibleLeafColumns().filter((col: any) => col.getCanSort());
64
58
  const activeSort = table.getState().sorting?.[0];
65
59
  const activeSortColumn = activeSort ? table.getColumn(activeSort.id) : undefined;
66
60
  const sortLabel = activeSortColumn
67
61
  ? `${getColumnLabel(activeSortColumn)} ${activeSort.desc ? "\u2193" : "\u2191"}`
68
62
  : t("Sort");
63
+ if (!sortableColumns.length) return null;
64
+ const menu = (
65
+ <DropdownMenu
66
+ open={disabled ? false : sortMenuOpen}
67
+ onOpenChange={(open: boolean) => {
68
+ if (disabled) return;
69
+ setSortMenuOpen(open);
70
+ }}
71
+ >
72
+ <DropdownMenu.Trigger asChild>
73
+ <Button
74
+ size={knobProps.sizeToken}
75
+ icon={<CaretUpDownIcon size={chrome.iconPx} />}
76
+ aria-label={t("Sort rows")}
77
+ {...(contained
78
+ ? {
79
+ minWidth: 0,
80
+ maxWidth: "100%" as const,
81
+ "aria-description": activeSortColumn ? sortLabel : undefined,
82
+ }
83
+ : {})}
84
+ disabled={disabled}
85
+ >
86
+ {sortLabel}
87
+ </Button>
88
+ </DropdownMenu.Trigger>
89
+ <DropdownMenu.Content>
90
+ <DropdownMenu.Label>{t("Sort by")}</DropdownMenu.Label>
91
+ {sortableColumns.map((column: any) => {
92
+ const sorted = column.getIsSorted();
93
+ return (
94
+ <DropdownMenu.Item
95
+ key={column.id}
96
+ closeOnSelect={false}
97
+ icon={
98
+ sorted === "asc" ? (
99
+ <CaretDownIcon size={chrome.iconPx} />
100
+ ) : sorted === "desc" ? (
101
+ <CaretDownIcon size={chrome.iconPx} style={{ transform: "rotate(180deg)" }} />
102
+ ) : (
103
+ <CaretUpDownIcon size={chrome.iconPx} />
104
+ )
105
+ }
106
+ aria-label={withInterp(t("Sort by {{column}}", { column: getColumnLabel(column) }), {
107
+ column: getColumnLabel(column),
108
+ })}
109
+ onSelect={() => {
110
+ // Same cycle as the grid header click: none → asc → desc → none.
111
+ if (sorted === false) column.toggleSorting(false);
112
+ else if (sorted === "asc") column.toggleSorting(true);
113
+ else column.clearSorting();
114
+ }}
115
+ >
116
+ {getColumnLabel(column)}
117
+ </DropdownMenu.Item>
118
+ );
119
+ })}
120
+ </DropdownMenu.Content>
121
+ </DropdownMenu>
122
+ );
123
+ return contained ? (
124
+ <View
125
+ data-table-card-sort=""
126
+ flexBasis="auto"
127
+ flexGrow={0}
128
+ flexShrink={1}
129
+ minWidth={0}
130
+ maxWidth="50%"
131
+ >
132
+ {menu}
133
+ </View>
134
+ ) : (
135
+ menu
136
+ );
137
+ }
69
138
 
139
+ export function DataTableCardControls({
140
+ table,
141
+ enableSorting = false,
142
+ enableFiltering = false,
143
+ availableColumns = [],
144
+ compact = false,
145
+ disabled = false,
146
+ }: DataTableCardControlsProps) {
147
+ const { t } = useTranslation();
148
+ const { disabledState } = useResolvedKnobs({ component: "DataTable", compact });
70
149
  if (!enableSorting && !enableFiltering) return null;
71
-
72
150
  return (
73
151
  <XStack
74
152
  alignItems="center"
@@ -78,60 +156,8 @@ export function DataTableCardControls({
78
156
  role="toolbar"
79
157
  aria-label={t("Card list controls")}
80
158
  >
81
- {enableSorting && sortableColumns.length > 0 && (
82
- <DropdownMenu
83
- open={disabled ? false : sortMenuOpen}
84
- onOpenChange={(open: boolean) => {
85
- if (disabled) return;
86
- setSortMenuOpen(open);
87
- }}
88
- >
89
- <DropdownMenu.Trigger asChild>
90
- <Button
91
- size={knobProps.sizeToken}
92
- icon={<CaretUpDownIcon size={chrome.iconPx} />}
93
- aria-label={t("Sort rows")}
94
- disabled={disabled}
95
- >
96
- {sortLabel}
97
- </Button>
98
- </DropdownMenu.Trigger>
99
- <DropdownMenu.Content>
100
- <DropdownMenu.Label>{t("Sort by")}</DropdownMenu.Label>
101
- {sortableColumns.map((column: any) => {
102
- const sorted = column.getIsSorted();
103
- return (
104
- <DropdownMenu.Item
105
- key={column.id}
106
- closeOnSelect={false}
107
- icon={
108
- sorted === "asc" ? (
109
- <CaretDownIcon size={chrome.iconPx} />
110
- ) : sorted === "desc" ? (
111
- <CaretDownIcon size={chrome.iconPx} style={{ transform: "rotate(180deg)" }} />
112
- ) : (
113
- <CaretUpDownIcon size={chrome.iconPx} />
114
- )
115
- }
116
- aria-label={withInterp(
117
- t("Sort by {{column}}", { column: getColumnLabel(column) }),
118
- {
119
- column: getColumnLabel(column),
120
- },
121
- )}
122
- onSelect={() => {
123
- // Same cycle as the grid header click: none → asc → desc → none.
124
- if (sorted === false) column.toggleSorting(false);
125
- else if (sorted === "asc") column.toggleSorting(true);
126
- else column.clearSorting();
127
- }}
128
- >
129
- {getColumnLabel(column)}
130
- </DropdownMenu.Item>
131
- );
132
- })}
133
- </DropdownMenu.Content>
134
- </DropdownMenu>
159
+ {enableSorting && (
160
+ <DataTableCardSortControl table={table} compact={compact} disabled={disabled} />
135
161
  )}
136
162
  {enableFiltering && availableColumns.length > 0 && (
137
163
  // DataTableFilters (chrome) has no disabled API — the wrapper is the