@wordpress/dataviews 2.2.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +23 -8
  3. package/build/components/dataform/index.js +78 -0
  4. package/build/components/dataform/index.js.map +1 -0
  5. package/build/components/dataviews/index.js +115 -0
  6. package/build/components/dataviews/index.js.map +1 -0
  7. package/build/{bulk-actions.js → components/dataviews-bulk-actions/index.js} +39 -16
  8. package/build/components/dataviews-bulk-actions/index.js.map +1 -0
  9. package/build/{bulk-actions-toolbar.js → components/dataviews-bulk-actions-toolbar/index.js} +36 -20
  10. package/build/components/dataviews-bulk-actions-toolbar/index.js.map +1 -0
  11. package/build/components/dataviews-context/index.js +36 -0
  12. package/build/components/dataviews-context/index.js.map +1 -0
  13. package/build/{add-filter.js → components/dataviews-filters/add-filter.js} +3 -3
  14. package/build/components/dataviews-filters/add-filter.js.map +1 -0
  15. package/build/{filter-summary.js → components/dataviews-filters/filter-summary.js} +15 -14
  16. package/build/components/dataviews-filters/filter-summary.js.map +1 -0
  17. package/build/{filters.js → components/dataviews-filters/index.js} +15 -16
  18. package/build/components/dataviews-filters/index.js.map +1 -0
  19. package/build/{reset-filters.js → components/dataviews-filters/reset-filters.js} +1 -1
  20. package/build/components/dataviews-filters/reset-filters.js.map +1 -0
  21. package/build/{search-widget.js → components/dataviews-filters/search-widget.js} +21 -19
  22. package/build/components/dataviews-filters/search-widget.js.map +1 -0
  23. package/build/{item-actions.js → components/dataviews-item-actions/index.js} +3 -3
  24. package/build/components/dataviews-item-actions/index.js.map +1 -0
  25. package/build/components/dataviews-layout/index.js +53 -0
  26. package/build/components/dataviews-layout/index.js.map +1 -0
  27. package/build/{pagination.js → components/dataviews-pagination/index.js} +18 -15
  28. package/build/components/dataviews-pagination/index.js.map +1 -0
  29. package/build/{search.js → components/dataviews-search/index.js} +10 -6
  30. package/build/components/dataviews-search/index.js.map +1 -0
  31. package/build/components/dataviews-selection-checkbox/index.js +52 -0
  32. package/build/components/dataviews-selection-checkbox/index.js.map +1 -0
  33. package/build/{view-actions.js → components/dataviews-view-config/index.js} +94 -80
  34. package/build/components/dataviews-view-config/index.js.map +1 -0
  35. package/build/filter-and-sort-data-view.js +4 -1
  36. package/build/filter-and-sort-data-view.js.map +1 -1
  37. package/build/index.js +8 -1
  38. package/build/index.js.map +1 -1
  39. package/build/layouts/grid/density-picker.js +143 -0
  40. package/build/layouts/grid/density-picker.js.map +1 -0
  41. package/build/{view-grid.js → layouts/grid/index.js} +40 -53
  42. package/build/layouts/grid/index.js.map +1 -0
  43. package/build/layouts/index.js +52 -0
  44. package/build/layouts/index.js.map +1 -0
  45. package/build/{view-list.js → layouts/list/index.js} +31 -27
  46. package/build/layouts/list/index.js.map +1 -0
  47. package/build/layouts/table/column-header-menu.js +196 -0
  48. package/build/layouts/table/column-header-menu.js.map +1 -0
  49. package/build/layouts/table/index.js +350 -0
  50. package/build/layouts/table/index.js.map +1 -0
  51. package/build/normalize-fields.js +1 -1
  52. package/build/normalize-fields.js.map +1 -1
  53. package/build/private-types.js +6 -0
  54. package/build/private-types.js.map +1 -0
  55. package/build/types.js.map +1 -1
  56. package/build/utils.js.map +1 -1
  57. package/build-module/components/dataform/index.js +72 -0
  58. package/build-module/components/dataform/index.js.map +1 -0
  59. package/build-module/components/dataviews/index.js +108 -0
  60. package/build-module/components/dataviews/index.js.map +1 -0
  61. package/build-module/{bulk-actions.js → components/dataviews-bulk-actions/index.js} +39 -17
  62. package/build-module/components/dataviews-bulk-actions/index.js.map +1 -0
  63. package/build-module/{bulk-actions-toolbar.js → components/dataviews-bulk-actions-toolbar/index.js} +35 -20
  64. package/build-module/components/dataviews-bulk-actions-toolbar/index.js.map +1 -0
  65. package/build-module/components/dataviews-context/index.js +30 -0
  66. package/build-module/components/dataviews-context/index.js.map +1 -0
  67. package/build-module/{add-filter.js → components/dataviews-filters/add-filter.js} +3 -3
  68. package/build-module/components/dataviews-filters/add-filter.js.map +1 -0
  69. package/build-module/{filter-summary.js → components/dataviews-filters/filter-summary.js} +15 -14
  70. package/build-module/components/dataviews-filters/filter-summary.js.map +1 -0
  71. package/build-module/{filters.js → components/dataviews-filters/index.js} +16 -17
  72. package/build-module/components/dataviews-filters/index.js.map +1 -0
  73. package/build-module/{reset-filters.js → components/dataviews-filters/reset-filters.js} +1 -1
  74. package/build-module/components/dataviews-filters/reset-filters.js.map +1 -0
  75. package/build-module/{search-widget.js → components/dataviews-filters/search-widget.js} +21 -19
  76. package/build-module/components/dataviews-filters/search-widget.js.map +1 -0
  77. package/build-module/{item-actions.js → components/dataviews-item-actions/index.js} +3 -3
  78. package/build-module/components/dataviews-item-actions/index.js.map +1 -0
  79. package/build-module/components/dataviews-layout/index.js +45 -0
  80. package/build-module/components/dataviews-layout/index.js.map +1 -0
  81. package/build-module/{pagination.js → components/dataviews-pagination/index.js} +19 -17
  82. package/build-module/components/dataviews-pagination/index.js.map +1 -0
  83. package/build-module/{search.js → components/dataviews-search/index.js} +10 -7
  84. package/build-module/components/dataviews-search/index.js.map +1 -0
  85. package/build-module/components/dataviews-selection-checkbox/index.js +45 -0
  86. package/build-module/components/dataviews-selection-checkbox/index.js.map +1 -0
  87. package/build-module/{view-actions.js → components/dataviews-view-config/index.js} +98 -84
  88. package/build-module/components/dataviews-view-config/index.js.map +1 -0
  89. package/build-module/filter-and-sort-data-view.js +4 -1
  90. package/build-module/filter-and-sort-data-view.js.map +1 -1
  91. package/build-module/index.js +2 -1
  92. package/build-module/index.js.map +1 -1
  93. package/build-module/layouts/grid/density-picker.js +138 -0
  94. package/build-module/layouts/grid/density-picker.js.map +1 -0
  95. package/build-module/{view-grid.js → layouts/grid/index.js} +37 -50
  96. package/build-module/layouts/grid/index.js.map +1 -0
  97. package/build-module/layouts/index.js +43 -0
  98. package/build-module/layouts/index.js.map +1 -0
  99. package/build-module/{view-list.js → layouts/list/index.js} +29 -25
  100. package/build-module/layouts/list/index.js.map +1 -0
  101. package/build-module/layouts/table/column-header-menu.js +190 -0
  102. package/build-module/layouts/table/column-header-menu.js.map +1 -0
  103. package/build-module/layouts/table/index.js +344 -0
  104. package/build-module/layouts/table/index.js.map +1 -0
  105. package/build-module/normalize-fields.js +1 -1
  106. package/build-module/normalize-fields.js.map +1 -1
  107. package/build-module/private-types.js +2 -0
  108. package/build-module/private-types.js.map +1 -0
  109. package/build-module/types.js.map +1 -1
  110. package/build-module/utils.js.map +1 -1
  111. package/build-style/style-rtl.css +607 -561
  112. package/build-style/style.css +607 -561
  113. package/build-types/components/dataform/index.d.ts +17 -0
  114. package/build-types/components/dataform/index.d.ts.map +1 -0
  115. package/build-types/components/dataform/stories/index.story.d.ts +11 -0
  116. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -0
  117. package/build-types/components/dataviews/index.d.ts +33 -0
  118. package/build-types/components/dataviews/index.d.ts.map +1 -0
  119. package/build-types/{stories → components/dataviews/stories}/fixtures.d.ts +18 -17
  120. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -0
  121. package/build-types/components/dataviews/stories/index.story.d.ts +46 -0
  122. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -0
  123. package/build-types/components/dataviews-bulk-actions/index.d.ts +5 -0
  124. package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -0
  125. package/build-types/components/dataviews-bulk-actions-toolbar/index.d.ts +2 -0
  126. package/build-types/components/dataviews-bulk-actions-toolbar/index.d.ts.map +1 -0
  127. package/build-types/components/dataviews-context/index.d.ts +26 -0
  128. package/build-types/components/dataviews-context/index.d.ts.map +1 -0
  129. package/build-types/{add-filter.d.ts → components/dataviews-filters/add-filter.d.ts} +1 -2
  130. package/build-types/components/dataviews-filters/add-filter.d.ts.map +1 -0
  131. package/build-types/{filter-summary.d.ts → components/dataviews-filters/filter-summary.d.ts} +1 -1
  132. package/build-types/components/dataviews-filters/filter-summary.d.ts.map +1 -0
  133. package/build-types/components/dataviews-filters/index.d.ts +4 -0
  134. package/build-types/components/dataviews-filters/index.d.ts.map +1 -0
  135. package/build-types/{reset-filters.d.ts → components/dataviews-filters/reset-filters.d.ts} +1 -2
  136. package/build-types/components/dataviews-filters/reset-filters.d.ts.map +1 -0
  137. package/build-types/{search-widget.d.ts → components/dataviews-filters/search-widget.d.ts} +1 -2
  138. package/build-types/components/dataviews-filters/search-widget.d.ts.map +1 -0
  139. package/build-types/components/dataviews-item-actions/index.d.ts +35 -0
  140. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -0
  141. package/build-types/components/dataviews-layout/index.d.ts +2 -0
  142. package/build-types/components/dataviews-layout/index.d.ts.map +1 -0
  143. package/build-types/components/dataviews-pagination/index.d.ts +4 -0
  144. package/build-types/components/dataviews-pagination/index.d.ts.map +1 -0
  145. package/build-types/components/dataviews-search/index.d.ts +6 -0
  146. package/build-types/components/dataviews-search/index.d.ts.map +1 -0
  147. package/build-types/components/dataviews-selection-checkbox/index.d.ts +16 -0
  148. package/build-types/components/dataviews-selection-checkbox/index.d.ts.map +1 -0
  149. package/build-types/components/dataviews-view-config/index.d.ts +8 -0
  150. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -0
  151. package/build-types/filter-and-sort-data-view.d.ts +2 -2
  152. package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
  153. package/build-types/index.d.ts +2 -1
  154. package/build-types/index.d.ts.map +1 -1
  155. package/build-types/layouts/grid/density-picker.d.ts +5 -0
  156. package/build-types/layouts/grid/density-picker.d.ts.map +1 -0
  157. package/build-types/layouts/grid/index.d.ts +3 -0
  158. package/build-types/layouts/grid/index.d.ts.map +1 -0
  159. package/build-types/{layouts.d.ts → layouts/index.d.ts} +6 -5
  160. package/build-types/layouts/index.d.ts.map +1 -0
  161. package/build-types/layouts/list/index.d.ts +3 -0
  162. package/build-types/layouts/list/index.d.ts.map +1 -0
  163. package/build-types/layouts/table/column-header-menu.d.ts +17 -0
  164. package/build-types/layouts/table/column-header-menu.d.ts.map +1 -0
  165. package/build-types/layouts/table/index.d.ts +4 -0
  166. package/build-types/layouts/table/index.d.ts.map +1 -0
  167. package/build-types/normalize-fields.d.ts +2 -2
  168. package/build-types/normalize-fields.d.ts.map +1 -1
  169. package/build-types/private-types.d.ts +3 -0
  170. package/build-types/private-types.d.ts.map +1 -0
  171. package/build-types/types.d.ts +106 -46
  172. package/build-types/types.d.ts.map +1 -1
  173. package/build-types/utils.d.ts +2 -2
  174. package/build-types/utils.d.ts.map +1 -1
  175. package/package.json +10 -10
  176. package/src/components/dataform/index.tsx +106 -0
  177. package/src/components/dataform/stories/index.story.tsx +42 -0
  178. package/src/components/dataviews/index.tsx +149 -0
  179. package/src/{stories → components/dataviews/stories}/fixtures.js +23 -11
  180. package/src/components/dataviews/stories/index.story.js +65 -0
  181. package/src/components/dataviews/style.scss +97 -0
  182. package/src/{bulk-actions.tsx → components/dataviews-bulk-actions/index.tsx} +58 -36
  183. package/src/components/dataviews-bulk-actions/style.scss +7 -0
  184. package/src/{bulk-actions-toolbar.tsx → components/dataviews-bulk-actions-toolbar/index.tsx} +48 -36
  185. package/src/components/dataviews-bulk-actions-toolbar/style.scss +45 -0
  186. package/src/components/dataviews-context/index.ts +49 -0
  187. package/src/{add-filter.tsx → components/dataviews-filters/add-filter.tsx} +4 -4
  188. package/src/{filter-summary.tsx → components/dataviews-filters/filter-summary.tsx} +36 -22
  189. package/src/{filters.tsx → components/dataviews-filters/index.tsx} +11 -25
  190. package/src/{reset-filters.tsx → components/dataviews-filters/reset-filters.tsx} +2 -2
  191. package/src/{search-widget.tsx → components/dataviews-filters/search-widget.tsx} +20 -20
  192. package/src/components/dataviews-filters/style.scss +252 -0
  193. package/src/{item-actions.tsx → components/dataviews-item-actions/index.tsx} +16 -17
  194. package/src/components/dataviews-item-actions/style.scss +3 -0
  195. package/src/components/dataviews-layout/index.tsx +51 -0
  196. package/src/{pagination.tsx → components/dataviews-pagination/index.tsx} +15 -23
  197. package/src/components/dataviews-pagination/style.scss +26 -0
  198. package/src/{search.tsx → components/dataviews-search/index.tsx} +5 -10
  199. package/src/components/dataviews-selection-checkbox/index.tsx +65 -0
  200. package/src/components/dataviews-selection-checkbox/style.scss +14 -0
  201. package/src/{view-actions.tsx → components/dataviews-view-config/index.tsx} +116 -119
  202. package/src/filter-and-sort-data-view.ts +13 -3
  203. package/src/index.ts +2 -1
  204. package/src/layouts/grid/density-picker.tsx +136 -0
  205. package/src/{view-grid.tsx → layouts/grid/index.tsx} +45 -63
  206. package/src/layouts/grid/style.scss +140 -0
  207. package/src/layouts/index.ts +66 -0
  208. package/src/{view-list.tsx → layouts/list/index.tsx} +40 -30
  209. package/src/layouts/list/style.scss +189 -0
  210. package/src/layouts/table/column-header-menu.tsx +268 -0
  211. package/src/layouts/table/index.tsx +471 -0
  212. package/src/layouts/table/style.scss +201 -0
  213. package/src/normalize-fields.ts +6 -4
  214. package/src/private-types.tsx +2 -0
  215. package/src/style.scss +11 -919
  216. package/src/test/filter-and-sort-data-view.js +17 -2
  217. package/src/types.ts +113 -55
  218. package/src/utils.ts +2 -4
  219. package/tsconfig.tsbuildinfo +1 -1
  220. package/build/add-filter.js.map +0 -1
  221. package/build/bulk-actions-toolbar.js.map +0 -1
  222. package/build/bulk-actions.js.map +0 -1
  223. package/build/dataviews.js +0 -136
  224. package/build/dataviews.js.map +0 -1
  225. package/build/filter-summary.js.map +0 -1
  226. package/build/filters.js.map +0 -1
  227. package/build/item-actions.js.map +0 -1
  228. package/build/layouts.js +0 -38
  229. package/build/layouts.js.map +0 -1
  230. package/build/pagination.js.map +0 -1
  231. package/build/reset-filters.js.map +0 -1
  232. package/build/search-widget.js.map +0 -1
  233. package/build/search.js.map +0 -1
  234. package/build/single-selection-checkbox.js +0 -63
  235. package/build/single-selection-checkbox.js.map +0 -1
  236. package/build/view-actions.js.map +0 -1
  237. package/build/view-grid.js.map +0 -1
  238. package/build/view-list.js.map +0 -1
  239. package/build/view-table.js +0 -409
  240. package/build/view-table.js.map +0 -1
  241. package/build-module/add-filter.js.map +0 -1
  242. package/build-module/bulk-actions-toolbar.js.map +0 -1
  243. package/build-module/bulk-actions.js.map +0 -1
  244. package/build-module/dataviews.js +0 -129
  245. package/build-module/dataviews.js.map +0 -1
  246. package/build-module/filter-summary.js.map +0 -1
  247. package/build-module/filters.js.map +0 -1
  248. package/build-module/item-actions.js.map +0 -1
  249. package/build-module/layouts.js +0 -30
  250. package/build-module/layouts.js.map +0 -1
  251. package/build-module/pagination.js.map +0 -1
  252. package/build-module/reset-filters.js.map +0 -1
  253. package/build-module/search-widget.js.map +0 -1
  254. package/build-module/search.js.map +0 -1
  255. package/build-module/single-selection-checkbox.js +0 -56
  256. package/build-module/single-selection-checkbox.js.map +0 -1
  257. package/build-module/view-actions.js.map +0 -1
  258. package/build-module/view-grid.js.map +0 -1
  259. package/build-module/view-list.js.map +0 -1
  260. package/build-module/view-table.js +0 -402
  261. package/build-module/view-table.js.map +0 -1
  262. package/build-types/add-filter.d.ts.map +0 -1
  263. package/build-types/bulk-actions-toolbar.d.ts +0 -12
  264. package/build-types/bulk-actions-toolbar.d.ts.map +0 -1
  265. package/build-types/bulk-actions.d.ts +0 -14
  266. package/build-types/bulk-actions.d.ts.map +0 -1
  267. package/build-types/dataviews.d.ts +0 -24
  268. package/build-types/dataviews.d.ts.map +0 -1
  269. package/build-types/filter-summary.d.ts.map +0 -1
  270. package/build-types/filters.d.ts +0 -13
  271. package/build-types/filters.d.ts.map +0 -1
  272. package/build-types/item-actions.d.ts +0 -35
  273. package/build-types/item-actions.d.ts.map +0 -1
  274. package/build-types/layouts.d.ts.map +0 -1
  275. package/build-types/pagination.d.ts +0 -16
  276. package/build-types/pagination.d.ts.map +0 -1
  277. package/build-types/reset-filters.d.ts.map +0 -1
  278. package/build-types/search-widget.d.ts.map +0 -1
  279. package/build-types/search.d.ts +0 -13
  280. package/build-types/search.d.ts.map +0 -1
  281. package/build-types/single-selection-checkbox.d.ts +0 -17
  282. package/build-types/single-selection-checkbox.d.ts.map +0 -1
  283. package/build-types/stories/fixtures.d.ts.map +0 -1
  284. package/build-types/stories/index.story.d.ts +0 -15
  285. package/build-types/stories/index.story.d.ts.map +0 -1
  286. package/build-types/view-actions.d.ts +0 -12
  287. package/build-types/view-actions.d.ts.map +0 -1
  288. package/build-types/view-grid.d.ts +0 -4
  289. package/build-types/view-grid.d.ts.map +0 -1
  290. package/build-types/view-list.d.ts +0 -4
  291. package/build-types/view-list.d.ts.map +0 -1
  292. package/build-types/view-table.d.ts +0 -5
  293. package/build-types/view-table.d.ts.map +0 -1
  294. package/src/dataviews.tsx +0 -189
  295. package/src/layouts.ts +0 -39
  296. package/src/single-selection-checkbox.tsx +0 -80
  297. package/src/stories/index.story.js +0 -64
  298. package/src/view-table.tsx +0 -603
@@ -1,603 +0,0 @@
1
- /**
2
- * External dependencies
3
- */
4
- import clsx from 'clsx';
5
- import type { ReactNode, Ref, PropsWithoutRef, RefAttributes } from 'react';
6
-
7
- /**
8
- * WordPress dependencies
9
- */
10
- import { __ } from '@wordpress/i18n';
11
- import { unseen, funnel } from '@wordpress/icons';
12
- import {
13
- Button,
14
- Icon,
15
- privateApis as componentsPrivateApis,
16
- CheckboxControl,
17
- Spinner,
18
- } from '@wordpress/components';
19
- import {
20
- forwardRef,
21
- useEffect,
22
- useId,
23
- useRef,
24
- useState,
25
- useMemo,
26
- Children,
27
- Fragment,
28
- } from '@wordpress/element';
29
-
30
- /**
31
- * Internal dependencies
32
- */
33
- import SingleSelectionCheckbox from './single-selection-checkbox';
34
- import { unlock } from './lock-unlock';
35
- import ItemActions from './item-actions';
36
- import { sanitizeOperators } from './utils';
37
- import {
38
- SORTING_DIRECTIONS,
39
- sortArrows,
40
- sortLabels,
41
- sortValues,
42
- } from './constants';
43
- import {
44
- useSomeItemHasAPossibleBulkAction,
45
- useHasAPossibleBulkAction,
46
- } from './bulk-actions';
47
- import type {
48
- Action,
49
- AnyItem,
50
- NormalizedField,
51
- SortDirection,
52
- ViewTable as ViewTableType,
53
- ViewTableProps,
54
- } from './types';
55
-
56
- const {
57
- DropdownMenuV2: DropdownMenu,
58
- DropdownMenuGroupV2: DropdownMenuGroup,
59
- DropdownMenuItemV2: DropdownMenuItem,
60
- DropdownMenuRadioItemV2: DropdownMenuRadioItem,
61
- DropdownMenuItemLabelV2: DropdownMenuItemLabel,
62
- DropdownMenuSeparatorV2: DropdownMenuSeparator,
63
- } = unlock( componentsPrivateApis );
64
-
65
- interface HeaderMenuProps< Item extends AnyItem > {
66
- field: NormalizedField< Item >;
67
- view: ViewTableType;
68
- onChangeView: ( view: ViewTableType ) => void;
69
- onHide: ( field: NormalizedField< Item > ) => void;
70
- setOpenedFilter: ( fieldId: string ) => void;
71
- }
72
-
73
- interface BulkSelectionCheckboxProps< Item extends AnyItem > {
74
- selection: string[];
75
- onSelectionChange: ( items: Item[] ) => void;
76
- data: Item[];
77
- actions: Action< Item >[];
78
- getItemId: ( item: Item ) => string;
79
- }
80
-
81
- interface TableRowProps< Item extends AnyItem > {
82
- hasBulkActions: boolean;
83
- item: Item;
84
- actions: Action< Item >[];
85
- id: string;
86
- visibleFields: NormalizedField< Item >[];
87
- primaryField?: NormalizedField< Item >;
88
- selection: string[];
89
- getItemId: ( item: Item ) => string;
90
- onSelectionChange: ( items: Item[] ) => void;
91
- data: Item[];
92
- }
93
-
94
- function WithDropDownMenuSeparators( { children }: { children: ReactNode } ) {
95
- return Children.toArray( children )
96
- .filter( Boolean )
97
- .map( ( child, i ) => (
98
- <Fragment key={ i }>
99
- { i > 0 && <DropdownMenuSeparator /> }
100
- { child }
101
- </Fragment>
102
- ) );
103
- }
104
-
105
- const _HeaderMenu = forwardRef( function HeaderMenu< Item extends AnyItem >(
106
- {
107
- field,
108
- view,
109
- onChangeView,
110
- onHide,
111
- setOpenedFilter,
112
- }: HeaderMenuProps< Item >,
113
- ref: Ref< HTMLButtonElement >
114
- ) {
115
- const isHidable = field.enableHiding !== false;
116
- const isSortable = field.enableSorting !== false;
117
- const isSorted = view.sort?.field === field.id;
118
- const operators = sanitizeOperators( field );
119
- // Filter can be added:
120
- // 1. If the field is not already part of a view's filters.
121
- // 2. If the field meets the type and operator requirements.
122
- // 3. If it's not primary. If it is, it should be already visible.
123
- const canAddFilter =
124
- ! view.filters?.some( ( _filter ) => field.id === _filter.field ) &&
125
- !! field.elements?.length &&
126
- !! operators.length &&
127
- ! field.filterBy?.isPrimary;
128
- if ( ! isSortable && ! isHidable && ! canAddFilter ) {
129
- return field.header;
130
- }
131
- return (
132
- <DropdownMenu
133
- align="start"
134
- trigger={
135
- <Button
136
- size="compact"
137
- className="dataviews-view-table-header-button"
138
- ref={ ref }
139
- variant="tertiary"
140
- >
141
- { field.header }
142
- { view.sort && isSorted && (
143
- <span aria-hidden="true">
144
- { sortArrows[ view.sort.direction ] }
145
- </span>
146
- ) }
147
- </Button>
148
- }
149
- style={ { minWidth: '240px' } }
150
- >
151
- <WithDropDownMenuSeparators>
152
- { isSortable && (
153
- <DropdownMenuGroup>
154
- { SORTING_DIRECTIONS.map(
155
- ( direction: SortDirection ) => {
156
- const isChecked =
157
- view.sort &&
158
- isSorted &&
159
- view.sort.direction === direction;
160
-
161
- const value = `${ field.id }-${ direction }`;
162
-
163
- return (
164
- <DropdownMenuRadioItem
165
- key={ value }
166
- // All sorting radio items share the same name, so that
167
- // selecting a sorting option automatically deselects the
168
- // previously selected one, even if it is displayed in
169
- // another submenu. The field and direction are passed via
170
- // the `value` prop.
171
- name="view-table-sorting"
172
- value={ value }
173
- checked={ isChecked }
174
- onChange={ () => {
175
- onChangeView( {
176
- ...view,
177
- sort: {
178
- field: field.id,
179
- direction,
180
- },
181
- } );
182
- } }
183
- >
184
- <DropdownMenuItemLabel>
185
- { sortLabels[ direction ] }
186
- </DropdownMenuItemLabel>
187
- </DropdownMenuRadioItem>
188
- );
189
- }
190
- ) }
191
- </DropdownMenuGroup>
192
- ) }
193
- { canAddFilter && (
194
- <DropdownMenuGroup>
195
- <DropdownMenuItem
196
- prefix={ <Icon icon={ funnel } /> }
197
- onClick={ () => {
198
- setOpenedFilter( field.id );
199
- onChangeView( {
200
- ...view,
201
- page: 1,
202
- filters: [
203
- ...( view.filters || [] ),
204
- {
205
- field: field.id,
206
- value: undefined,
207
- operator: operators[ 0 ],
208
- },
209
- ],
210
- } );
211
- } }
212
- >
213
- <DropdownMenuItemLabel>
214
- { __( 'Add filter' ) }
215
- </DropdownMenuItemLabel>
216
- </DropdownMenuItem>
217
- </DropdownMenuGroup>
218
- ) }
219
- { isHidable && (
220
- <DropdownMenuItem
221
- prefix={ <Icon icon={ unseen } /> }
222
- onClick={ () => {
223
- onHide( field );
224
- onChangeView( {
225
- ...view,
226
- hiddenFields: view.hiddenFields.concat(
227
- field.id
228
- ),
229
- } );
230
- } }
231
- >
232
- <DropdownMenuItemLabel>
233
- { __( 'Hide' ) }
234
- </DropdownMenuItemLabel>
235
- </DropdownMenuItem>
236
- ) }
237
- </WithDropDownMenuSeparators>
238
- </DropdownMenu>
239
- );
240
- } );
241
-
242
- // @ts-expect-error Lift the `Item` type argument through the forwardRef.
243
- const HeaderMenu: < Item extends AnyItem >(
244
- props: PropsWithoutRef< HeaderMenuProps< Item > > &
245
- RefAttributes< HTMLButtonElement >
246
- ) => ReturnType< typeof _HeaderMenu > = _HeaderMenu;
247
-
248
- function BulkSelectionCheckbox< Item extends AnyItem >( {
249
- selection,
250
- onSelectionChange,
251
- data,
252
- actions,
253
- getItemId,
254
- }: BulkSelectionCheckboxProps< Item > ) {
255
- const selectableItems = useMemo( () => {
256
- return data.filter( ( item ) => {
257
- return actions.some(
258
- ( action ) =>
259
- action.supportsBulk &&
260
- ( ! action.isEligible || action.isEligible( item ) )
261
- );
262
- } );
263
- }, [ data, actions ] );
264
- const selectedItems = data.filter(
265
- ( item ) =>
266
- selection.includes( getItemId( item ) ) &&
267
- selectableItems.includes( item )
268
- );
269
- const areAllSelected = selectedItems.length === selectableItems.length;
270
- return (
271
- <CheckboxControl
272
- className="dataviews-view-table-selection-checkbox"
273
- __nextHasNoMarginBottom
274
- checked={ areAllSelected }
275
- indeterminate={ ! areAllSelected && !! selectedItems.length }
276
- onChange={ () => {
277
- if ( areAllSelected ) {
278
- onSelectionChange( [] );
279
- } else {
280
- onSelectionChange( selectableItems );
281
- }
282
- } }
283
- aria-label={
284
- areAllSelected ? __( 'Deselect all' ) : __( 'Select all' )
285
- }
286
- />
287
- );
288
- }
289
-
290
- function TableRow< Item extends AnyItem >( {
291
- hasBulkActions,
292
- item,
293
- actions,
294
- id,
295
- visibleFields,
296
- primaryField,
297
- selection,
298
- getItemId,
299
- onSelectionChange,
300
- data,
301
- }: TableRowProps< Item > ) {
302
- const hasPossibleBulkAction = useHasAPossibleBulkAction( actions, item );
303
- const isSelected = hasPossibleBulkAction && selection.includes( id );
304
-
305
- const [ isHovered, setIsHovered ] = useState( false );
306
-
307
- const handleMouseEnter = () => {
308
- setIsHovered( true );
309
- };
310
-
311
- const handleMouseLeave = () => {
312
- setIsHovered( false );
313
- };
314
-
315
- // Will be set to true if `onTouchStart` fires. This happens before
316
- // `onClick` and can be used to exclude touchscreen devices from certain
317
- // behaviours.
318
- const isTouchDevice = useRef( false );
319
-
320
- return (
321
- <tr
322
- className={ clsx( 'dataviews-view-table__row', {
323
- 'is-selected': hasPossibleBulkAction && isSelected,
324
- 'is-hovered': isHovered,
325
- 'has-bulk-actions': hasPossibleBulkAction,
326
- } ) }
327
- onMouseEnter={ handleMouseEnter }
328
- onMouseLeave={ handleMouseLeave }
329
- onTouchStart={ () => {
330
- isTouchDevice.current = true;
331
- } }
332
- onClick={ () => {
333
- if ( ! hasPossibleBulkAction ) {
334
- return;
335
- }
336
- if (
337
- ! isTouchDevice.current &&
338
- document.getSelection()?.type !== 'Range'
339
- ) {
340
- if ( ! isSelected ) {
341
- onSelectionChange(
342
- data.filter( ( _item ) => {
343
- const itemId = getItemId?.( _item );
344
- return (
345
- itemId === id ||
346
- selection.includes( itemId )
347
- );
348
- } )
349
- );
350
- } else {
351
- onSelectionChange(
352
- data.filter( ( _item ) => {
353
- const itemId = getItemId?.( _item );
354
- return (
355
- itemId !== id &&
356
- selection.includes( itemId )
357
- );
358
- } )
359
- );
360
- }
361
- }
362
- } }
363
- >
364
- { hasBulkActions && (
365
- <td
366
- className="dataviews-view-table__checkbox-column"
367
- style={ {
368
- width: '1%',
369
- } }
370
- >
371
- <div className="dataviews-view-table__cell-content-wrapper">
372
- <SingleSelectionCheckbox
373
- item={ item }
374
- selection={ selection }
375
- onSelectionChange={ onSelectionChange }
376
- getItemId={ getItemId }
377
- data={ data }
378
- primaryField={ primaryField }
379
- disabled={ ! hasPossibleBulkAction }
380
- />
381
- </div>
382
- </td>
383
- ) }
384
- { visibleFields.map( ( field ) => (
385
- <td
386
- key={ field.id }
387
- style={ {
388
- width: field.width || undefined,
389
- minWidth: field.minWidth || undefined,
390
- maxWidth: field.maxWidth || undefined,
391
- } }
392
- >
393
- <div
394
- className={ clsx(
395
- 'dataviews-view-table__cell-content-wrapper',
396
- {
397
- 'dataviews-view-table__primary-field':
398
- primaryField?.id === field.id,
399
- }
400
- ) }
401
- >
402
- { field.render( {
403
- item,
404
- } ) }
405
- </div>
406
- </td>
407
- ) ) }
408
- { !! actions?.length && (
409
- // Disable reason: we are not making the element interactive,
410
- // but preventing any click events from bubbling up to the
411
- // table row. This allows us to add a click handler to the row
412
- // itself (to toggle row selection) without erroneously
413
- // intercepting click events from ItemActions.
414
-
415
- /* eslint-disable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */
416
- <td
417
- className="dataviews-view-table__actions-column"
418
- onClick={ ( e ) => e.stopPropagation() }
419
- >
420
- <ItemActions item={ item } actions={ actions } />
421
- </td>
422
- /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */
423
- ) }
424
- </tr>
425
- );
426
- }
427
-
428
- function ViewTable< Item extends AnyItem >( {
429
- actions,
430
- data,
431
- fields,
432
- getItemId,
433
- isLoading = false,
434
- onChangeView,
435
- onSelectionChange,
436
- selection,
437
- setOpenedFilter,
438
- view,
439
- }: ViewTableProps< Item > ) {
440
- const headerMenuRefs = useRef<
441
- Map< string, { node: HTMLButtonElement; fallback: string } >
442
- >( new Map() );
443
- const headerMenuToFocusRef = useRef< HTMLButtonElement >();
444
- const [ nextHeaderMenuToFocus, setNextHeaderMenuToFocus ] =
445
- useState< HTMLButtonElement >();
446
- const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
447
-
448
- useEffect( () => {
449
- if ( headerMenuToFocusRef.current ) {
450
- headerMenuToFocusRef.current.focus();
451
- headerMenuToFocusRef.current = undefined;
452
- }
453
- } );
454
-
455
- const tableNoticeId = useId();
456
-
457
- if ( nextHeaderMenuToFocus ) {
458
- // If we need to force focus, we short-circuit rendering here
459
- // to prevent any additional work while we handle that.
460
- // Clearing out the focus directive is necessary to make sure
461
- // future renders don't cause unexpected focus jumps.
462
- headerMenuToFocusRef.current = nextHeaderMenuToFocus;
463
- setNextHeaderMenuToFocus( undefined );
464
- return;
465
- }
466
-
467
- const onHide = ( field: NormalizedField< Item > ) => {
468
- const hidden = headerMenuRefs.current.get( field.id );
469
- const fallback = hidden
470
- ? headerMenuRefs.current.get( hidden.fallback )
471
- : undefined;
472
- setNextHeaderMenuToFocus( fallback?.node );
473
- };
474
- const visibleFields = fields.filter(
475
- ( field ) =>
476
- ! view.hiddenFields.includes( field.id ) &&
477
- ! [ view.layout.mediaField ].includes( field.id )
478
- );
479
- const hasData = !! data?.length;
480
-
481
- const primaryField = fields.find(
482
- ( field ) => field.id === view.layout.primaryField
483
- );
484
-
485
- return (
486
- <>
487
- <table
488
- className="dataviews-view-table"
489
- aria-busy={ isLoading }
490
- aria-describedby={ tableNoticeId }
491
- >
492
- <thead>
493
- <tr className="dataviews-view-table__row">
494
- { hasBulkActions && (
495
- <th
496
- className="dataviews-view-table__checkbox-column"
497
- style={ {
498
- width: '1%',
499
- } }
500
- data-field-id="selection"
501
- scope="col"
502
- >
503
- <BulkSelectionCheckbox
504
- selection={ selection }
505
- onSelectionChange={ onSelectionChange }
506
- data={ data }
507
- actions={ actions }
508
- getItemId={ getItemId }
509
- />
510
- </th>
511
- ) }
512
- { visibleFields.map( ( field, index ) => (
513
- <th
514
- key={ field.id }
515
- style={ {
516
- width: field.width || undefined,
517
- minWidth: field.minWidth || undefined,
518
- maxWidth: field.maxWidth || undefined,
519
- } }
520
- data-field-id={ field.id }
521
- aria-sort={
522
- view.sort?.field === field.id
523
- ? sortValues[ view.sort.direction ]
524
- : undefined
525
- }
526
- scope="col"
527
- >
528
- <HeaderMenu
529
- ref={ ( node ) => {
530
- if ( node ) {
531
- headerMenuRefs.current.set(
532
- field.id,
533
- {
534
- node,
535
- fallback:
536
- visibleFields[
537
- index > 0
538
- ? index - 1
539
- : 1
540
- ]?.id,
541
- }
542
- );
543
- } else {
544
- headerMenuRefs.current.delete(
545
- field.id
546
- );
547
- }
548
- } }
549
- field={ field }
550
- view={ view }
551
- onChangeView={ onChangeView }
552
- onHide={ onHide }
553
- setOpenedFilter={ setOpenedFilter }
554
- />
555
- </th>
556
- ) ) }
557
- { !! actions?.length && (
558
- <th
559
- data-field-id="actions"
560
- className="dataviews-view-table__actions-column"
561
- >
562
- <span className="dataviews-view-table-header">
563
- { __( 'Actions' ) }
564
- </span>
565
- </th>
566
- ) }
567
- </tr>
568
- </thead>
569
- <tbody>
570
- { hasData &&
571
- data.map( ( item, index ) => (
572
- <TableRow
573
- key={ getItemId( item ) }
574
- item={ item }
575
- hasBulkActions={ hasBulkActions }
576
- actions={ actions }
577
- id={ getItemId( item ) || index.toString() }
578
- visibleFields={ visibleFields }
579
- primaryField={ primaryField }
580
- selection={ selection }
581
- getItemId={ getItemId }
582
- onSelectionChange={ onSelectionChange }
583
- data={ data }
584
- />
585
- ) ) }
586
- </tbody>
587
- </table>
588
- <div
589
- className={ clsx( {
590
- 'dataviews-loading': isLoading,
591
- 'dataviews-no-results': ! hasData && ! isLoading,
592
- } ) }
593
- id={ tableNoticeId }
594
- >
595
- { ! hasData && (
596
- <p>{ isLoading ? <Spinner /> : __( 'No results' ) }</p>
597
- ) }
598
- </div>
599
- </>
600
- );
601
- }
602
-
603
- export default ViewTable;