@wordpress/dataviews 1.1.0 → 1.2.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 (124) hide show
  1. package/CHANGELOG.md +11 -5
  2. package/build/bulk-actions-toolbar.js +182 -0
  3. package/build/bulk-actions-toolbar.js.map +1 -0
  4. package/build/bulk-actions.js +8 -8
  5. package/build/bulk-actions.js.map +1 -1
  6. package/build/dataviews.js +11 -4
  7. package/build/dataviews.js.map +1 -1
  8. package/build/filter-and-sort-data-view.js +2 -2
  9. package/build/filter-and-sort-data-view.js.map +1 -1
  10. package/build/filter-summary.js +3 -3
  11. package/build/filter-summary.js.map +1 -1
  12. package/build/item-actions.js +41 -22
  13. package/build/item-actions.js.map +1 -1
  14. package/build/lock-unlock.js.map +1 -1
  15. package/build/normalize-fields.js.map +1 -1
  16. package/build/pagination.js +13 -7
  17. package/build/pagination.js.map +1 -1
  18. package/build/single-selection-checkbox.js +4 -0
  19. package/build/single-selection-checkbox.js.map +1 -1
  20. package/build/types.js.map +1 -1
  21. package/build/view-grid.js +9 -10
  22. package/build/view-grid.js.map +1 -1
  23. package/build/view-list.js +134 -21
  24. package/build/view-list.js.map +1 -1
  25. package/build/view-table.js +9 -9
  26. package/build/view-table.js.map +1 -1
  27. package/build-module/bulk-actions-toolbar.js +175 -0
  28. package/build-module/bulk-actions-toolbar.js.map +1 -0
  29. package/build-module/bulk-actions.js +8 -8
  30. package/build-module/bulk-actions.js.map +1 -1
  31. package/build-module/dataviews.js +11 -4
  32. package/build-module/dataviews.js.map +1 -1
  33. package/build-module/filter-and-sort-data-view.js +2 -2
  34. package/build-module/filter-and-sort-data-view.js.map +1 -1
  35. package/build-module/filter-summary.js +3 -3
  36. package/build-module/filter-summary.js.map +1 -1
  37. package/build-module/item-actions.js +40 -24
  38. package/build-module/item-actions.js.map +1 -1
  39. package/build-module/lock-unlock.js.map +1 -1
  40. package/build-module/normalize-fields.js.map +1 -1
  41. package/build-module/pagination.js +14 -7
  42. package/build-module/pagination.js.map +1 -1
  43. package/build-module/single-selection-checkbox.js +5 -0
  44. package/build-module/single-selection-checkbox.js.map +1 -1
  45. package/build-module/types.js.map +1 -1
  46. package/build-module/view-grid.js +9 -10
  47. package/build-module/view-grid.js.map +1 -1
  48. package/build-module/view-list.js +135 -23
  49. package/build-module/view-list.js.map +1 -1
  50. package/build-module/view-table.js +9 -9
  51. package/build-module/view-table.js.map +1 -1
  52. package/build-style/style-rtl.css +62 -27
  53. package/build-style/style.css +62 -27
  54. package/build-types/add-filter.d.ts +8 -0
  55. package/build-types/add-filter.d.ts.map +1 -0
  56. package/build-types/bulk-actions-toolbar.d.ts +8 -0
  57. package/build-types/bulk-actions-toolbar.d.ts.map +1 -0
  58. package/build-types/bulk-actions.d.ts +14 -0
  59. package/build-types/bulk-actions.d.ts.map +1 -0
  60. package/build-types/dataviews.d.ts +15 -0
  61. package/build-types/dataviews.d.ts.map +1 -0
  62. package/build-types/dropdown-menu-helper.d.ts +6 -0
  63. package/build-types/dropdown-menu-helper.d.ts.map +1 -0
  64. package/build-types/filter-and-sort-data-view.d.ts +3 -3
  65. package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
  66. package/build-types/filter-summary.d.ts +6 -0
  67. package/build-types/filter-summary.d.ts.map +1 -0
  68. package/build-types/filters.d.ts +3 -0
  69. package/build-types/filters.d.ts.map +1 -0
  70. package/build-types/index.d.ts +4 -0
  71. package/build-types/index.d.ts.map +1 -0
  72. package/build-types/item-actions.d.ts +37 -0
  73. package/build-types/item-actions.d.ts.map +1 -0
  74. package/build-types/layouts.d.ts +20 -0
  75. package/build-types/layouts.d.ts.map +1 -0
  76. package/build-types/lock-unlock.d.ts +2 -0
  77. package/build-types/lock-unlock.d.ts.map +1 -0
  78. package/build-types/normalize-fields.d.ts +2 -2
  79. package/build-types/normalize-fields.d.ts.map +1 -1
  80. package/build-types/pagination.d.ts +16 -0
  81. package/build-types/pagination.d.ts.map +1 -0
  82. package/build-types/reset-filters.d.ts +6 -0
  83. package/build-types/reset-filters.d.ts.map +1 -0
  84. package/build-types/search-widget.d.ts +2 -0
  85. package/build-types/search-widget.d.ts.map +1 -0
  86. package/build-types/search.d.ts +3 -0
  87. package/build-types/search.d.ts.map +1 -0
  88. package/build-types/single-selection-checkbox.d.ts +17 -0
  89. package/build-types/single-selection-checkbox.d.ts.map +1 -0
  90. package/build-types/stories/fixtures.d.ts +114 -0
  91. package/build-types/stories/fixtures.d.ts.map +1 -0
  92. package/build-types/stories/index.story.d.ts +15 -0
  93. package/build-types/stories/index.story.d.ts.map +1 -0
  94. package/build-types/types.d.ts +152 -20
  95. package/build-types/types.d.ts.map +1 -1
  96. package/build-types/utils.d.ts +2 -0
  97. package/build-types/utils.d.ts.map +1 -0
  98. package/build-types/view-actions.d.ts +3 -0
  99. package/build-types/view-actions.d.ts.map +1 -0
  100. package/build-types/view-grid.d.ts +15 -0
  101. package/build-types/view-grid.d.ts.map +1 -0
  102. package/build-types/view-list.d.ts +16 -0
  103. package/build-types/view-list.d.ts.map +1 -0
  104. package/build-types/view-table.d.ts +14 -0
  105. package/build-types/view-table.d.ts.map +1 -0
  106. package/package.json +12 -12
  107. package/src/bulk-actions-toolbar.js +244 -0
  108. package/src/{bulk-actions.js → bulk-actions.tsx} +73 -17
  109. package/src/dataviews.js +14 -3
  110. package/src/filter-and-sort-data-view.ts +13 -8
  111. package/src/filter-summary.js +3 -3
  112. package/src/{item-actions.js → item-actions.tsx} +112 -28
  113. package/src/normalize-fields.ts +4 -2
  114. package/src/{pagination.js → pagination.tsx} +28 -7
  115. package/src/{single-selection-checkbox.js → single-selection-checkbox.tsx} +17 -2
  116. package/src/style.scss +77 -28
  117. package/src/types.ts +190 -20
  118. package/src/{view-grid.js → view-grid.tsx} +45 -16
  119. package/src/view-list.tsx +421 -0
  120. package/src/view-table.js +8 -8
  121. package/tsconfig.json +4 -2
  122. package/tsconfig.tsbuildinfo +1 -1
  123. package/src/view-list.js +0 -207
  124. /package/src/{lock-unlock.js → lock-unlock.ts} +0 -0
package/src/types.ts CHANGED
@@ -1,23 +1,41 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import type { ReactNode } from 'react';
4
+ import type { ReactElement, ReactNode } from 'react';
5
5
 
6
- type Item = Record< string, any >;
6
+ export type SortDirection = 'asc' | 'desc';
7
7
 
8
- interface Option {
9
- value: any;
8
+ /**
9
+ * Generic option type.
10
+ */
11
+ interface Option< Value extends any = any > {
12
+ value: Value;
10
13
  label: string;
11
14
  }
12
15
 
13
- interface filterByConfig {
16
+ interface FilterByConfig {
17
+ /**
18
+ * The list of operators supported by the field.
19
+ */
14
20
  operators?: Operator[];
21
+
22
+ /**
23
+ * Whether it is a primary filter.
24
+ *
25
+ * A primary filter is always visible and is not listed in the "Add filter" component,
26
+ * except for the list layout where it behaves like a secondary filter.
27
+ */
15
28
  isPrimary?: boolean;
16
29
  }
17
30
 
18
31
  type Operator = 'is' | 'isNot' | 'isAny' | 'isNone' | 'isAll' | 'isNotAll';
19
32
 
20
- export interface Field {
33
+ export type AnyItem = Record< string, any >;
34
+
35
+ /**
36
+ * A dataview field for a specific property of a data type.
37
+ */
38
+ export interface Field< Item extends AnyItem > {
21
39
  /**
22
40
  * The unique identifier of the field.
23
41
  */
@@ -32,58 +50,67 @@ export interface Field {
32
50
  * Callback used to retrieve the value of the field from the item.
33
51
  * Defaults to `item[ field.id ]`.
34
52
  */
35
- getValue?: ( { item }: { item: Item } ) => any;
53
+ getValue?: ( args: { item: Item } ) => any;
36
54
 
37
55
  /**
38
56
  * Callback used to render the field. Defaults to `field.getValue`.
39
57
  */
40
- render?: ( { item }: { item: Item } ) => ReactNode;
58
+ render?: ( args: { item: Item } ) => ReactNode;
41
59
 
42
60
  /**
43
61
  * The width of the field column.
44
62
  */
45
- width: string | number | undefined;
63
+ width?: string | number;
46
64
 
47
65
  /**
48
66
  * The minimum width of the field column.
49
67
  */
50
- maxWidth: string | number | undefined;
68
+ maxWidth?: string | number;
51
69
 
52
70
  /**
53
71
  * The maximum width of the field column.
54
72
  */
55
- minWidth: string | number | undefined;
73
+ minWidth?: string | number;
56
74
 
57
75
  /**
58
76
  * Whether the field is sortable.
59
77
  */
60
- enableSorting: boolean | undefined;
78
+ enableSorting?: boolean;
61
79
 
62
80
  /**
63
81
  * Whether the field is searchable.
64
82
  */
65
- enableGlobalSearch: boolean | undefined;
83
+ enableGlobalSearch?: boolean;
66
84
 
67
85
  /**
68
86
  * Whether the field is filterable.
69
87
  */
70
- enableHiding: boolean | undefined;
88
+ enableHiding?: boolean;
71
89
 
72
90
  /**
73
91
  * The list of options to pick from when using the field as a filter.
74
92
  */
75
- elements: Option[] | undefined;
93
+ elements?: Option[];
76
94
 
77
95
  /**
78
96
  * Filter config for the field.
79
97
  */
80
- filterBy: filterByConfig | undefined;
98
+ filterBy?: FilterByConfig | undefined;
81
99
  }
82
100
 
83
- export type NormalizedField = Required< Field >;
101
+ export type NormalizedField< Item extends AnyItem > = Field< Item > &
102
+ Required< Pick< Field< Item >, 'header' | 'getValue' | 'render' > >;
103
+
104
+ /**
105
+ * A collection of dataview fields for a data type.
106
+ */
107
+ export type Fields< Item extends AnyItem > = Field< Item >[];
84
108
 
85
- export type Data = Item[];
109
+ export type Data< Item extends AnyItem > = Item[];
86
110
 
111
+ /**
112
+ * The filters applied to the dataset.
113
+ */
87
114
  export interface Filter {
88
115
  /**
89
116
  * The field to filter by.
@@ -101,7 +128,7 @@ export interface Filter {
101
128
  value: any;
102
129
  }
103
130
 
104
- export interface View {
131
+ interface ViewBase {
105
132
  /**
106
133
  * The layout of the view.
107
134
  */
@@ -129,7 +156,7 @@ export interface View {
129
156
  /**
130
157
  * The direction to sort by.
131
158
  */
132
- direction: string;
159
+ direction: SortDirection;
133
160
  };
134
161
 
135
162
  /**
@@ -141,4 +168,147 @@ export interface View {
141
168
  * The number of items per page
142
169
  */
143
170
  perPage?: number;
171
+
172
+ /**
173
+ * The hidden fields.
174
+ */
175
+ hiddenFields: string[];
144
176
  }
177
+
178
+ export interface ViewList extends ViewBase {
179
+ type: 'list';
180
+
181
+ layout: {
182
+ /**
183
+ * The field to use as the primary field.
184
+ */
185
+ primaryField: string;
186
+
187
+ /**
188
+ * The field to use as the media field.
189
+ */
190
+ mediaField: string;
191
+ };
192
+ }
193
+
194
+ export interface ViewGrid extends ViewBase {
195
+ type: 'grid';
196
+
197
+ layout: {
198
+ /**
199
+ * The field to use as the primary field.
200
+ */
201
+ primaryField: string;
202
+
203
+ /**
204
+ * The field to use as the media field.
205
+ */
206
+ mediaField: string;
207
+
208
+ /**
209
+ * The fields to use as columns.
210
+ */
211
+ columnFields: string[];
212
+
213
+ /**
214
+ * The fields to use as badge fields.
215
+ */
216
+ badgeFields: string[];
217
+ };
218
+ }
219
+
220
+ export type View = ViewList | ViewGrid | ViewBase;
221
+
222
+ interface ActionBase< Item extends AnyItem > {
223
+ /**
224
+ * The unique identifier of the action.
225
+ */
226
+ id: string;
227
+
228
+ /**
229
+ * The label of the action.
230
+ */
231
+ label: string;
232
+
233
+ /**
234
+ * The icon of the action. (Either a string or an SVG element)
235
+ * This should be IconType from the components package
236
+ * but that import is breaking typescript build for the moment.
237
+ */
238
+ icon?: any;
239
+
240
+ /**
241
+ * Whether the action is disabled.
242
+ */
243
+ disabled?: boolean;
244
+
245
+ /**
246
+ * Whether the action is destructive.
247
+ */
248
+ isDestructive?: boolean;
249
+
250
+ /**
251
+ * Whether the action is a primary action.
252
+ */
253
+ isPrimary?: boolean;
254
+
255
+ /**
256
+ * Whether the item passed as an argument supports the current action.
257
+ */
258
+ isEligible?: ( item: Item ) => boolean;
259
+
260
+ /**
261
+ * Whether the action can be used as a bulk action.
262
+ */
263
+ supportsBulk?: boolean;
264
+ }
265
+
266
+ export interface ActionModal< Item extends AnyItem >
267
+ extends ActionBase< Item > {
268
+ /**
269
+ * The callback to execute when the action has finished.
270
+ */
271
+ onActionPerformed: ( ( items: Item[] ) => void ) | undefined;
272
+
273
+ /**
274
+ * The callback to execute when the action is triggered.
275
+ */
276
+ onActionStart: ( ( items: Item[] ) => void ) | undefined;
277
+
278
+ /**
279
+ * Modal to render when the action is triggered.
280
+ */
281
+ RenderModal: ( {
282
+ items,
283
+ closeModal,
284
+ onActionStart,
285
+ onActionPerformed,
286
+ }: {
287
+ items: Item[];
288
+ closeModal?: () => void;
289
+ onActionStart?: ( items: Item[] ) => void;
290
+ onActionPerformed?: ( items: Item[] ) => void;
291
+ } ) => ReactElement;
292
+
293
+ /**
294
+ * Whether to hide the modal header.
295
+ */
296
+ hideModalHeader?: boolean;
297
+
298
+ /**
299
+ * The header of the modal.
300
+ */
301
+ modalHeader?: string;
302
+ }
303
+
304
+ export interface ActionButton< Item extends AnyItem >
305
+ extends ActionBase< AnyItem > {
306
+ /**
307
+ * The callback to execute when the action is triggered.
308
+ */
309
+ callback: ( items: Item[] ) => void;
310
+ }
311
+
312
+ export type Action< Item extends AnyItem > =
313
+ | ActionModal< Item >
314
+ | ActionButton< Item >;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import classnames from 'classnames';
4
+ import clsx from 'clsx';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -21,10 +21,40 @@ import { __ } from '@wordpress/i18n';
21
21
  */
22
22
  import ItemActions from './item-actions';
23
23
  import SingleSelectionCheckbox from './single-selection-checkbox';
24
-
25
24
  import { useHasAPossibleBulkAction } from './bulk-actions';
25
+ import type {
26
+ Action,
27
+ AnyItem,
28
+ NormalizedField,
29
+ ViewGrid as ViewGridType,
30
+ } from './types';
31
+
32
+ interface GridItemProps< Item extends AnyItem > {
33
+ selection: string[];
34
+ data: Item[];
35
+ onSelectionChange: ( items: Item[] ) => void;
36
+ getItemId: ( item: Item ) => string;
37
+ item: Item;
38
+ actions: Action< Item >[];
39
+ mediaField?: NormalizedField< Item >;
40
+ primaryField?: NormalizedField< Item >;
41
+ visibleFields: NormalizedField< Item >[];
42
+ badgeFields: NormalizedField< Item >[];
43
+ columnFields: string[];
44
+ }
26
45
 
27
- function GridItem( {
46
+ interface ViewGridProps< Item extends AnyItem > {
47
+ actions: Action< Item >[];
48
+ data: Item[];
49
+ fields: NormalizedField< Item >[];
50
+ getItemId: ( item: Item ) => string;
51
+ isLoading: boolean;
52
+ onSelectionChange: ( items: Item[] ) => void;
53
+ selection: string[];
54
+ view: ViewGridType;
55
+ }
56
+
57
+ function GridItem< Item extends AnyItem >( {
28
58
  selection,
29
59
  data,
30
60
  onSelectionChange,
@@ -36,7 +66,7 @@ function GridItem( {
36
66
  visibleFields,
37
67
  badgeFields,
38
68
  columnFields,
39
- } ) {
69
+ }: GridItemProps< Item > ) {
40
70
  const hasBulkAction = useHasAPossibleBulkAction( actions, item );
41
71
  const id = getItemId( item );
42
72
  const isSelected = selection.includes( id );
@@ -44,7 +74,7 @@ function GridItem( {
44
74
  <VStack
45
75
  spacing={ 0 }
46
76
  key={ id }
47
- className={ classnames( 'dataviews-view-grid__card', {
77
+ className={ clsx( 'dataviews-view-grid__card', {
48
78
  'is-selected': hasBulkAction && isSelected,
49
79
  } ) }
50
80
  onClickCapture={ ( event ) => {
@@ -86,7 +116,6 @@ function GridItem( {
86
116
  className="dataviews-view-grid__title-actions"
87
117
  >
88
118
  <SingleSelectionCheckbox
89
- id={ id }
90
119
  item={ item }
91
120
  selection={ selection }
92
121
  onSelectionChange={ onSelectionChange }
@@ -105,7 +134,7 @@ function GridItem( {
105
134
  className="dataviews-view-grid__badge-fields"
106
135
  spacing={ 2 }
107
136
  wrap
108
- align="top"
137
+ alignment="top"
109
138
  justify="flex-start"
110
139
  >
111
140
  { badgeFields.map( ( field ) => {
@@ -137,7 +166,7 @@ function GridItem( {
137
166
  }
138
167
  return (
139
168
  <Flex
140
- className={ classnames(
169
+ className={ clsx(
141
170
  'dataviews-view-grid__field',
142
171
  columnFields?.includes( field.id )
143
172
  ? 'is-column'
@@ -174,16 +203,16 @@ function GridItem( {
174
203
  );
175
204
  }
176
205
 
177
- export default function ViewGrid( {
206
+ export default function ViewGrid< Item extends AnyItem >( {
207
+ actions,
178
208
  data,
179
209
  fields,
180
- view,
181
- actions,
182
- isLoading,
183
210
  getItemId,
184
- selection,
211
+ isLoading,
185
212
  onSelectionChange,
186
- } ) {
213
+ selection,
214
+ view,
215
+ }: ViewGridProps< Item > ) {
187
216
  const mediaField = fields.find(
188
217
  ( field ) => field.id === view.layout.mediaField
189
218
  );
@@ -191,7 +220,7 @@ export default function ViewGrid( {
191
220
  ( field ) => field.id === view.layout.primaryField
192
221
  );
193
222
  const { visibleFields, badgeFields } = fields.reduce(
194
- ( accumulator, field ) => {
223
+ ( accumulator: Record< string, NormalizedField< Item >[] >, field ) => {
195
224
  if (
196
225
  view.hiddenFields.includes( field.id ) ||
197
226
  [ view.layout.mediaField, view.layout.primaryField ].includes(
@@ -243,7 +272,7 @@ export default function ViewGrid( {
243
272
  ) }
244
273
  { ! hasData && (
245
274
  <div
246
- className={ classnames( {
275
+ className={ clsx( {
247
276
  'dataviews-loading': isLoading,
248
277
  'dataviews-no-results': ! isLoading,
249
278
  } ) }