@wordpress/dataviews 2.1.0 → 3.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 (159) hide show
  1. package/CHANGELOG.md +24 -5
  2. package/README.md +5 -5
  3. package/build/add-filter.js +1 -1
  4. package/build/add-filter.js.map +1 -1
  5. package/build/bulk-actions-toolbar.js +5 -2
  6. package/build/bulk-actions-toolbar.js.map +1 -1
  7. package/build/bulk-actions.js +11 -21
  8. package/build/bulk-actions.js.map +1 -1
  9. package/build/dataform.js +78 -0
  10. package/build/dataform.js.map +1 -0
  11. package/build/dataviews.js +26 -31
  12. package/build/dataviews.js.map +1 -1
  13. package/build/filter-and-sort-data-view.js +4 -1
  14. package/build/filter-and-sort-data-view.js.map +1 -1
  15. package/build/filter-summary.js +6 -5
  16. package/build/filter-summary.js.map +1 -1
  17. package/build/filters.js +1 -1
  18. package/build/filters.js.map +1 -1
  19. package/build/index.js +7 -0
  20. package/build/index.js.map +1 -1
  21. package/build/item-actions.js +17 -6
  22. package/build/item-actions.js.map +1 -1
  23. package/build/lock-unlock.js +1 -1
  24. package/build/lock-unlock.js.map +1 -1
  25. package/build/normalize-fields.js.map +1 -1
  26. package/build/pagination.js +2 -2
  27. package/build/pagination.js.map +1 -1
  28. package/build/private-types.js +6 -0
  29. package/build/private-types.js.map +1 -0
  30. package/build/reset-filters.js +1 -1
  31. package/build/reset-filters.js.map +1 -1
  32. package/build/search-widget.js +8 -6
  33. package/build/search-widget.js.map +1 -1
  34. package/build/single-selection-checkbox.js +5 -16
  35. package/build/single-selection-checkbox.js.map +1 -1
  36. package/build/types.js.map +1 -1
  37. package/build/utils.js.map +1 -1
  38. package/build/view-actions.js +76 -65
  39. package/build/view-actions.js.map +1 -1
  40. package/build/view-grid.js +7 -19
  41. package/build/view-grid.js.map +1 -1
  42. package/build/view-list.js +15 -8
  43. package/build/view-list.js.map +1 -1
  44. package/build/view-table.js +22 -25
  45. package/build/view-table.js.map +1 -1
  46. package/build-module/add-filter.js +1 -1
  47. package/build-module/add-filter.js.map +1 -1
  48. package/build-module/bulk-actions-toolbar.js +5 -2
  49. package/build-module/bulk-actions-toolbar.js.map +1 -1
  50. package/build-module/bulk-actions.js +12 -22
  51. package/build-module/bulk-actions.js.map +1 -1
  52. package/build-module/dataform.js +72 -0
  53. package/build-module/dataform.js.map +1 -0
  54. package/build-module/dataviews.js +24 -31
  55. package/build-module/dataviews.js.map +1 -1
  56. package/build-module/filter-and-sort-data-view.js +4 -1
  57. package/build-module/filter-and-sort-data-view.js.map +1 -1
  58. package/build-module/filter-summary.js +6 -5
  59. package/build-module/filter-summary.js.map +1 -1
  60. package/build-module/filters.js +1 -1
  61. package/build-module/filters.js.map +1 -1
  62. package/build-module/index.js +1 -0
  63. package/build-module/index.js.map +1 -1
  64. package/build-module/item-actions.js +17 -6
  65. package/build-module/item-actions.js.map +1 -1
  66. package/build-module/lock-unlock.js +1 -1
  67. package/build-module/lock-unlock.js.map +1 -1
  68. package/build-module/normalize-fields.js.map +1 -1
  69. package/build-module/pagination.js +2 -2
  70. package/build-module/pagination.js.map +1 -1
  71. package/build-module/private-types.js +2 -0
  72. package/build-module/private-types.js.map +1 -0
  73. package/build-module/reset-filters.js +1 -1
  74. package/build-module/reset-filters.js.map +1 -1
  75. package/build-module/search-widget.js +8 -6
  76. package/build-module/search-widget.js.map +1 -1
  77. package/build-module/single-selection-checkbox.js +5 -16
  78. package/build-module/single-selection-checkbox.js.map +1 -1
  79. package/build-module/types.js.map +1 -1
  80. package/build-module/utils.js.map +1 -1
  81. package/build-module/view-actions.js +80 -68
  82. package/build-module/view-actions.js.map +1 -1
  83. package/build-module/view-grid.js +7 -19
  84. package/build-module/view-grid.js.map +1 -1
  85. package/build-module/view-list.js +15 -8
  86. package/build-module/view-list.js.map +1 -1
  87. package/build-module/view-table.js +22 -25
  88. package/build-module/view-table.js.map +1 -1
  89. package/build-style/style-rtl.css +8 -24
  90. package/build-style/style.css +8 -24
  91. package/build-types/bulk-actions-toolbar.d.ts +5 -4
  92. package/build-types/bulk-actions-toolbar.d.ts.map +1 -1
  93. package/build-types/bulk-actions.d.ts +7 -6
  94. package/build-types/bulk-actions.d.ts.map +1 -1
  95. package/build-types/dataform.d.ts +17 -0
  96. package/build-types/dataform.d.ts.map +1 -0
  97. package/build-types/dataviews.d.ts +15 -6
  98. package/build-types/dataviews.d.ts.map +1 -1
  99. package/build-types/filter-and-sort-data-view.d.ts +2 -2
  100. package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
  101. package/build-types/filter-summary.d.ts.map +1 -1
  102. package/build-types/filters.d.ts +3 -3
  103. package/build-types/filters.d.ts.map +1 -1
  104. package/build-types/index.d.ts +1 -0
  105. package/build-types/index.d.ts.map +1 -1
  106. package/build-types/item-actions.d.ts +10 -10
  107. package/build-types/item-actions.d.ts.map +1 -1
  108. package/build-types/normalize-fields.d.ts +2 -2
  109. package/build-types/normalize-fields.d.ts.map +1 -1
  110. package/build-types/private-types.d.ts +3 -0
  111. package/build-types/private-types.d.ts.map +1 -0
  112. package/build-types/single-selection-checkbox.d.ts +5 -5
  113. package/build-types/single-selection-checkbox.d.ts.map +1 -1
  114. package/build-types/stories/fixtures.d.ts +14 -1
  115. package/build-types/stories/fixtures.d.ts.map +1 -1
  116. package/build-types/stories/index.story.d.ts +15 -1
  117. package/build-types/stories/index.story.d.ts.map +1 -1
  118. package/build-types/types.d.ts +73 -38
  119. package/build-types/types.d.ts.map +1 -1
  120. package/build-types/utils.d.ts +2 -2
  121. package/build-types/utils.d.ts.map +1 -1
  122. package/build-types/view-actions.d.ts +4 -4
  123. package/build-types/view-actions.d.ts.map +1 -1
  124. package/build-types/view-grid.d.ts +2 -2
  125. package/build-types/view-grid.d.ts.map +1 -1
  126. package/build-types/view-list.d.ts +2 -2
  127. package/build-types/view-list.d.ts.map +1 -1
  128. package/build-types/view-table.d.ts +2 -2
  129. package/build-types/view-table.d.ts.map +1 -1
  130. package/package.json +10 -9
  131. package/src/add-filter.tsx +1 -1
  132. package/src/bulk-actions-toolbar.tsx +18 -14
  133. package/src/bulk-actions.tsx +31 -45
  134. package/src/dataform.tsx +106 -0
  135. package/src/dataviews.tsx +55 -60
  136. package/src/filter-and-sort-data-view.ts +13 -3
  137. package/src/filter-summary.tsx +18 -12
  138. package/src/filters.tsx +4 -4
  139. package/src/index.ts +1 -0
  140. package/src/item-actions.tsx +27 -24
  141. package/src/lock-unlock.ts +1 -1
  142. package/src/normalize-fields.ts +5 -3
  143. package/src/pagination.tsx +2 -2
  144. package/src/private-types.tsx +2 -0
  145. package/src/reset-filters.tsx +1 -1
  146. package/src/search-widget.tsx +6 -6
  147. package/src/single-selection-checkbox.tsx +14 -29
  148. package/src/stories/fixtures.js +17 -1
  149. package/src/stories/index.story.js +15 -28
  150. package/src/style.scss +10 -22
  151. package/src/test/filter-and-sort-data-view.js +16 -1
  152. package/src/types.ts +75 -47
  153. package/src/utils.ts +2 -4
  154. package/src/view-actions.tsx +105 -102
  155. package/src/view-grid.tsx +21 -38
  156. package/src/view-list.tsx +22 -22
  157. package/src/view-table.tsx +45 -45
  158. package/tsconfig.json +1 -0
  159. package/tsconfig.tsbuildinfo +1 -1
package/src/types.ts CHANGED
@@ -3,6 +3,11 @@
3
3
  */
4
4
  import type { ReactElement, ReactNode } from 'react';
5
5
 
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type { SetSelection } from './private-types';
10
+
6
11
  export type SortDirection = 'asc' | 'desc';
7
12
 
8
13
  /**
@@ -37,12 +42,19 @@ export type Operator =
37
42
  | 'isAll'
38
43
  | 'isNotAll';
39
44
 
40
- export type AnyItem = Record< string, any >;
45
+ export type ItemRecord = Record< string, unknown >;
46
+
47
+ export type FieldType = 'text';
41
48
 
42
49
  /**
43
50
  * A dataview field for a specific property of a data type.
44
51
  */
45
- export interface Field< Item extends AnyItem > {
52
+ export type Field< Item > = {
53
+ /**
54
+ * Type of the fields.
55
+ */
56
+ type?: FieldType;
57
+
46
58
  /**
47
59
  * The unique identifier of the field.
48
60
  */
@@ -54,10 +66,9 @@ export interface Field< Item extends AnyItem > {
54
66
  header?: string;
55
67
 
56
68
  /**
57
- * Callback used to retrieve the value of the field from the item.
58
- * Defaults to `item[ field.id ]`.
69
+ * Placeholder for the field.
59
70
  */
60
- getValue?: ( args: { item: Item } ) => any;
71
+ placeholder?: string;
61
72
 
62
73
  /**
63
74
  * Callback used to render the field. Defaults to `field.getValue`.
@@ -103,17 +114,41 @@ export interface Field< Item extends AnyItem > {
103
114
  * Filter config for the field.
104
115
  */
105
116
  filterBy?: FilterByConfig | undefined;
106
- }
107
-
108
- export type NormalizedField< Item extends AnyItem > = Field< Item > &
109
- Required< Pick< Field< Item >, 'header' | 'getValue' | 'render' > >;
117
+ } & ( Item extends ItemRecord
118
+ ? {
119
+ /**
120
+ * Callback used to retrieve the value of the field from the item.
121
+ * Defaults to `item[ field.id ]`.
122
+ */
123
+ getValue?: ( args: { item: Item } ) => any;
124
+ }
125
+ : {
126
+ /**
127
+ * Callback used to retrieve the value of the field from the item.
128
+ * Defaults to `item[ field.id ]`.
129
+ */
130
+ getValue: ( args: { item: Item } ) => any;
131
+ } );
132
+
133
+ export type NormalizedField< Item > = Field< Item > & {
134
+ header: string;
135
+ getValue: ( args: { item: Item } ) => any;
136
+ render: ( args: { item: Item } ) => ReactNode;
137
+ };
110
138
 
111
139
  /**
112
140
  * A collection of dataview fields for a data type.
113
141
  */
114
- export type Fields< Item extends AnyItem > = Field< Item >[];
142
+ export type Fields< Item > = Field< Item >[];
115
143
 
116
- export type Data< Item extends AnyItem > = Item[];
144
+ export type Data< Item > = Item[];
145
+
146
+ /**
147
+ * The form configuration.
148
+ */
149
+ export type Form = {
150
+ visibleFields?: string[];
151
+ };
117
152
 
118
153
  /**
119
154
  * The filters applied to the dataset.
@@ -186,7 +221,7 @@ interface ViewBase {
186
221
  /**
187
222
  * The filters to apply.
188
223
  */
189
- filters: Filter[];
224
+ filters?: Filter[];
190
225
 
191
226
  /**
192
227
  * The sorting configuration.
@@ -216,13 +251,13 @@ interface ViewBase {
216
251
  /**
217
252
  * The hidden fields.
218
253
  */
219
- hiddenFields: string[];
254
+ fields?: string[];
220
255
  }
221
256
 
222
257
  export interface ViewTable extends ViewBase {
223
258
  type: 'table';
224
259
 
225
- layout: {
260
+ layout?: {
226
261
  /**
227
262
  * The field to use as the primary field.
228
263
  */
@@ -238,7 +273,7 @@ export interface ViewTable extends ViewBase {
238
273
  export interface ViewList extends ViewBase {
239
274
  type: 'list';
240
275
 
241
- layout: {
276
+ layout?: {
242
277
  /**
243
278
  * The field to use as the primary field.
244
279
  */
@@ -254,7 +289,7 @@ export interface ViewList extends ViewBase {
254
289
  export interface ViewGrid extends ViewBase {
255
290
  type: 'grid';
256
291
 
257
- layout: {
292
+ layout?: {
258
293
  /**
259
294
  * The field to use as the primary field.
260
295
  */
@@ -279,7 +314,7 @@ export interface ViewGrid extends ViewBase {
279
314
 
280
315
  export type View = ViewList | ViewGrid | ViewTable;
281
316
 
282
- interface ActionBase< Item extends AnyItem > {
317
+ interface ActionBase< Item > {
283
318
  /**
284
319
  * The unique identifier of the action.
285
320
  */
@@ -325,30 +360,17 @@ interface ActionBase< Item extends AnyItem > {
325
360
  supportsBulk?: boolean;
326
361
  }
327
362
 
328
- export interface ActionModal< Item extends AnyItem >
329
- extends ActionBase< Item > {
330
- /**
331
- * The callback to execute when the action has finished.
332
- */
333
- onActionPerformed: ( ( items: Item[] ) => void ) | undefined;
334
-
335
- /**
336
- * The callback to execute when the action is triggered.
337
- */
338
- onActionStart: ( ( items: Item[] ) => void ) | undefined;
339
-
363
+ export interface ActionModal< Item > extends ActionBase< Item > {
340
364
  /**
341
365
  * Modal to render when the action is triggered.
342
366
  */
343
367
  RenderModal: ( {
344
368
  items,
345
369
  closeModal,
346
- onActionStart,
347
370
  onActionPerformed,
348
371
  }: {
349
372
  items: Item[];
350
373
  closeModal?: () => void;
351
- onActionStart?: ( items: Item[] ) => void;
352
374
  onActionPerformed?: ( items: Item[] ) => void;
353
375
  } ) => ReactElement;
354
376
 
@@ -363,47 +385,53 @@ export interface ActionModal< Item extends AnyItem >
363
385
  modalHeader?: string;
364
386
  }
365
387
 
366
- export interface ActionButton< Item extends AnyItem >
367
- extends ActionBase< AnyItem > {
388
+ export interface ActionButton< Item > extends ActionBase< Item > {
368
389
  /**
369
390
  * The callback to execute when the action is triggered.
370
391
  */
371
- callback: ( items: Item[] ) => void;
392
+ callback: (
393
+ items: Item[],
394
+ context: {
395
+ registry: any;
396
+ onActionPerformed?: ( items: Item[] ) => void;
397
+ }
398
+ ) => void;
372
399
  }
373
400
 
374
- export type Action< Item extends AnyItem > =
375
- | ActionModal< Item >
376
- | ActionButton< Item >;
401
+ export type Action< Item > = ActionModal< Item > | ActionButton< Item >;
377
402
 
378
- export interface ViewBaseProps< Item extends AnyItem > {
403
+ export interface ViewBaseProps< Item > {
379
404
  actions: Action< Item >[];
380
405
  data: Item[];
381
406
  fields: NormalizedField< Item >[];
382
407
  getItemId: ( item: Item ) => string;
383
408
  isLoading?: boolean;
384
- onChangeView( view: View ): void;
385
- onSelectionChange: ( items: Item[] ) => void;
409
+ onChangeView: ( view: View ) => void;
410
+ onSelectionChange: SetSelection;
386
411
  selection: string[];
387
412
  setOpenedFilter: ( fieldId: string ) => void;
388
413
  view: View;
389
414
  }
390
415
 
391
- export interface ViewTableProps< Item extends AnyItem >
392
- extends ViewBaseProps< Item > {
416
+ export interface ViewTableProps< Item > extends ViewBaseProps< Item > {
393
417
  view: ViewTable;
394
418
  }
395
419
 
396
- export interface ViewListProps< Item extends AnyItem >
397
- extends ViewBaseProps< Item > {
420
+ export interface ViewListProps< Item > extends ViewBaseProps< Item > {
398
421
  view: ViewList;
399
422
  }
400
423
 
401
- export interface ViewGridProps< Item extends AnyItem >
402
- extends ViewBaseProps< Item > {
424
+ export interface ViewGridProps< Item > extends ViewBaseProps< Item > {
403
425
  view: ViewGrid;
404
426
  }
405
427
 
406
- export type ViewProps< Item extends AnyItem > =
428
+ export type ViewProps< Item > =
407
429
  | ViewTableProps< Item >
408
430
  | ViewGridProps< Item >
409
431
  | ViewListProps< Item >;
432
+
433
+ export interface SupportedLayouts {
434
+ list?: Omit< ViewList, 'type' >;
435
+ grid?: Omit< ViewGrid, 'type' >;
436
+ table?: Omit< ViewTable, 'type' >;
437
+ }
package/src/utils.ts CHANGED
@@ -8,11 +8,9 @@ import {
8
8
  OPERATOR_IS_ANY,
9
9
  OPERATOR_IS_NONE,
10
10
  } from './constants';
11
- import type { AnyItem, NormalizedField } from './types';
11
+ import type { NormalizedField } from './types';
12
12
 
13
- export function sanitizeOperators< Item extends AnyItem >(
14
- field: NormalizedField< Item >
15
- ) {
13
+ export function sanitizeOperators< Item >( field: NormalizedField< Item > ) {
16
14
  let operators = field.filterBy?.operators;
17
15
 
18
16
  // Assign default values.
@@ -9,10 +9,11 @@ import type { ChangeEvent } from 'react';
9
9
  import {
10
10
  Button,
11
11
  privateApis as componentsPrivateApis,
12
+ __experimentalHStack as HStack,
12
13
  } from '@wordpress/components';
13
- import { __ } from '@wordpress/i18n';
14
+ import { __, _x } from '@wordpress/i18n';
14
15
  import { memo } from '@wordpress/element';
15
- import { settings } from '@wordpress/icons';
16
+ import { cog } from '@wordpress/icons';
16
17
 
17
18
  /**
18
19
  * Internal dependencies
@@ -20,7 +21,7 @@ import { settings } from '@wordpress/icons';
20
21
  import { unlock } from './lock-unlock';
21
22
  import { SORTING_DIRECTIONS, sortLabels } from './constants';
22
23
  import { VIEW_LAYOUTS } from './layouts';
23
- import type { AnyItem, NormalizedField, View } from './types';
24
+ import type { NormalizedField, View, SupportedLayouts } from './types';
24
25
 
25
26
  const {
26
27
  DropdownMenuV2: DropdownMenu,
@@ -34,7 +35,7 @@ const {
34
35
  interface ViewTypeMenuProps {
35
36
  view: View;
36
37
  onChangeView: ( view: View ) => void;
37
- supportedLayouts?: string[];
38
+ defaultLayouts?: SupportedLayouts;
38
39
  }
39
40
 
40
41
  interface PageSizeMenuProps {
@@ -42,84 +43,64 @@ interface PageSizeMenuProps {
42
43
  onChangeView: ( view: View ) => void;
43
44
  }
44
45
 
45
- interface FieldsVisibilityMenuProps< Item extends AnyItem > {
46
+ interface FieldsVisibilityMenuProps< Item > {
46
47
  view: View;
47
48
  onChangeView: ( view: View ) => void;
48
49
  fields: NormalizedField< Item >[];
49
50
  }
50
51
 
51
- interface SortMenuProps< Item extends AnyItem > {
52
+ interface SortMenuProps< Item > {
52
53
  fields: NormalizedField< Item >[];
53
54
  view: View;
54
55
  onChangeView: ( view: View ) => void;
55
56
  }
56
57
 
57
- interface ViewActionsProps< Item extends AnyItem > {
58
+ interface ViewActionsProps< Item > {
58
59
  fields: NormalizedField< Item >[];
59
60
  view: View;
60
61
  onChangeView: ( view: View ) => void;
61
- supportedLayouts?: string[];
62
+ defaultLayouts?: SupportedLayouts;
62
63
  }
63
64
 
64
65
  function ViewTypeMenu( {
65
66
  view,
66
67
  onChangeView,
67
- supportedLayouts,
68
+ defaultLayouts = { list: {}, grid: {}, table: {} },
68
69
  }: ViewTypeMenuProps ) {
69
- let _availableViews = VIEW_LAYOUTS;
70
- if ( supportedLayouts ) {
71
- _availableViews = _availableViews.filter( ( _view ) =>
72
- supportedLayouts.includes( _view.type )
73
- );
74
- }
75
- if ( _availableViews.length === 1 ) {
70
+ const availableLayouts = Object.keys( defaultLayouts );
71
+ if ( availableLayouts.length <= 1 ) {
76
72
  return null;
77
73
  }
78
- const activeView = _availableViews.find( ( v ) => view.type === v.type );
79
- return (
80
- <DropdownMenu
81
- trigger={
82
- <DropdownMenuItem
83
- suffix={
84
- <span aria-hidden="true">{ activeView?.label }</span>
74
+ return availableLayouts.map( ( layout ) => {
75
+ const config = VIEW_LAYOUTS.find( ( v ) => v.type === layout );
76
+ if ( ! config ) {
77
+ return null;
78
+ }
79
+ return (
80
+ <DropdownMenuRadioItem
81
+ key={ layout }
82
+ value={ layout }
83
+ name="view-actions-available-view"
84
+ checked={ layout === view.type }
85
+ hideOnClick
86
+ onChange={ ( e: ChangeEvent< HTMLInputElement > ) => {
87
+ switch ( e.target.value ) {
88
+ case 'list':
89
+ case 'grid':
90
+ case 'table':
91
+ return onChangeView( {
92
+ ...view,
93
+ type: e.target.value,
94
+ ...defaultLayouts[ e.target.value ],
95
+ } );
85
96
  }
86
- >
87
- <DropdownMenuItemLabel>
88
- { __( 'Layout' ) }
89
- </DropdownMenuItemLabel>
90
- </DropdownMenuItem>
91
- }
92
- >
93
- { _availableViews.map( ( availableView ) => {
94
- return (
95
- <DropdownMenuRadioItem
96
- key={ availableView.type }
97
- value={ availableView.type }
98
- name="view-actions-available-view"
99
- checked={ availableView.type === view.type }
100
- hideOnClick
101
- onChange={ ( e: ChangeEvent< HTMLInputElement > ) => {
102
- switch ( e.target.value ) {
103
- case 'list':
104
- case 'grid':
105
- case 'table':
106
- return onChangeView( {
107
- ...view,
108
- type: e.target.value,
109
- layout: {},
110
- } );
111
- }
112
- throw new Error( 'Invalid dataview' );
113
- } }
114
- >
115
- <DropdownMenuItemLabel>
116
- { availableView.label }
117
- </DropdownMenuItemLabel>
118
- </DropdownMenuRadioItem>
119
- );
120
- } ) }
121
- </DropdownMenu>
122
- );
97
+ throw new Error( 'Invalid dataview' );
98
+ } }
99
+ >
100
+ <DropdownMenuItemLabel>{ config.label }</DropdownMenuItemLabel>
101
+ </DropdownMenuRadioItem>
102
+ );
103
+ } );
123
104
  }
124
105
 
125
106
  const PAGE_SIZE_VALUES = [ 10, 20, 50, 100 ];
@@ -161,15 +142,17 @@ function PageSizeMenu( { view, onChangeView }: PageSizeMenuProps ) {
161
142
  );
162
143
  }
163
144
 
164
- function FieldsVisibilityMenu< Item extends AnyItem >( {
145
+ function FieldsVisibilityMenu< Item >( {
165
146
  view,
166
147
  onChangeView,
167
148
  fields,
168
149
  }: FieldsVisibilityMenuProps< Item > ) {
169
150
  const hidableFields = fields.filter(
170
151
  ( field ) =>
171
- field.enableHiding !== false && field.id !== view.layout.mediaField
152
+ field.enableHiding !== false &&
153
+ field.id !== view?.layout?.mediaField
172
154
  );
155
+ const viewFields = view.fields || fields.map( ( field ) => field.id );
173
156
  if ( ! hidableFields?.length ) {
174
157
  return null;
175
158
  }
@@ -188,20 +171,15 @@ function FieldsVisibilityMenu< Item extends AnyItem >( {
188
171
  <DropdownMenuCheckboxItem
189
172
  key={ field.id }
190
173
  value={ field.id }
191
- checked={ ! view.hiddenFields?.includes( field.id ) }
174
+ checked={ viewFields.includes( field.id ) }
192
175
  onChange={ () => {
193
176
  onChangeView( {
194
177
  ...view,
195
- hiddenFields: view.hiddenFields?.includes(
196
- field.id
197
- )
198
- ? view.hiddenFields.filter(
178
+ fields: viewFields.includes( field.id )
179
+ ? viewFields.filter(
199
180
  ( id ) => id !== field.id
200
181
  )
201
- : [
202
- ...( view.hiddenFields || [] ),
203
- field.id,
204
- ],
182
+ : [ ...viewFields, field.id ],
205
183
  } );
206
184
  } }
207
185
  >
@@ -215,7 +193,7 @@ function FieldsVisibilityMenu< Item extends AnyItem >( {
215
193
  );
216
194
  }
217
195
 
218
- function SortMenu< Item extends AnyItem >( {
196
+ function SortMenu< Item >( {
219
197
  fields,
220
198
  view,
221
199
  onChangeView,
@@ -303,41 +281,66 @@ function SortMenu< Item extends AnyItem >( {
303
281
  );
304
282
  }
305
283
 
306
- function _ViewActions< Item extends AnyItem >( {
284
+ function _ViewActions< Item >( {
307
285
  fields,
308
286
  view,
309
287
  onChangeView,
310
- supportedLayouts,
288
+ defaultLayouts,
311
289
  }: ViewActionsProps< Item > ) {
290
+ const activeView = VIEW_LAYOUTS.find( ( v ) => view.type === v.type );
312
291
  return (
313
- <DropdownMenu
314
- trigger={
315
- <Button
316
- size="compact"
317
- icon={ settings }
318
- label={ __( 'View options' ) }
319
- />
320
- }
321
- >
322
- <DropdownMenuGroup>
323
- <ViewTypeMenu
324
- view={ view }
325
- onChangeView={ onChangeView }
326
- supportedLayouts={ supportedLayouts }
327
- />
328
- <SortMenu
329
- fields={ fields }
330
- view={ view }
331
- onChangeView={ onChangeView }
332
- />
333
- <FieldsVisibilityMenu
334
- fields={ fields }
335
- view={ view }
336
- onChangeView={ onChangeView }
337
- />
338
- <PageSizeMenu view={ view } onChangeView={ onChangeView } />
339
- </DropdownMenuGroup>
340
- </DropdownMenu>
292
+ <>
293
+ <HStack
294
+ spacing={ 1 }
295
+ expanded={ false }
296
+ style={ { flexShrink: 0 } }
297
+ >
298
+ <DropdownMenu
299
+ trigger={
300
+ <Button
301
+ size="compact"
302
+ icon={ activeView?.icon }
303
+ label={ __( 'Layout' ) }
304
+ />
305
+ }
306
+ >
307
+ <ViewTypeMenu
308
+ view={ view }
309
+ onChangeView={ onChangeView }
310
+ defaultLayouts={ defaultLayouts }
311
+ />
312
+ </DropdownMenu>
313
+ <DropdownMenu
314
+ trigger={
315
+ <Button
316
+ size="compact"
317
+ icon={ cog }
318
+ label={ _x(
319
+ 'View options',
320
+ 'View is used as a noun'
321
+ ) }
322
+ />
323
+ }
324
+ >
325
+ <DropdownMenuGroup>
326
+ <SortMenu
327
+ fields={ fields }
328
+ view={ view }
329
+ onChangeView={ onChangeView }
330
+ />
331
+ <FieldsVisibilityMenu
332
+ fields={ fields }
333
+ view={ view }
334
+ onChangeView={ onChangeView }
335
+ />
336
+ <PageSizeMenu
337
+ view={ view }
338
+ onChangeView={ onChangeView }
339
+ />
340
+ </DropdownMenuGroup>
341
+ </DropdownMenu>
342
+ </HStack>
343
+ </>
341
344
  );
342
345
  }
343
346
 
package/src/view-grid.tsx CHANGED
@@ -22,12 +22,12 @@ import { __ } from '@wordpress/i18n';
22
22
  import ItemActions from './item-actions';
23
23
  import SingleSelectionCheckbox from './single-selection-checkbox';
24
24
  import { useHasAPossibleBulkAction } from './bulk-actions';
25
- import type { Action, AnyItem, NormalizedField, ViewGridProps } from './types';
25
+ import type { Action, NormalizedField, ViewGridProps } from './types';
26
+ import type { SetSelection } from './private-types';
26
27
 
27
- interface GridItemProps< Item extends AnyItem > {
28
+ interface GridItemProps< Item > {
28
29
  selection: string[];
29
- data: Item[];
30
- onSelectionChange: ( items: Item[] ) => void;
30
+ onSelectionChange: SetSelection;
31
31
  getItemId: ( item: Item ) => string;
32
32
  item: Item;
33
33
  actions: Action< Item >[];
@@ -38,9 +38,8 @@ interface GridItemProps< Item extends AnyItem > {
38
38
  columnFields?: string[];
39
39
  }
40
40
 
41
- function GridItem< Item extends AnyItem >( {
41
+ function GridItem< Item >( {
42
42
  selection,
43
- data,
44
43
  onSelectionChange,
45
44
  getItemId,
46
45
  item,
@@ -68,27 +67,11 @@ function GridItem< Item extends AnyItem >( {
68
67
  if ( ! hasBulkAction ) {
69
68
  return;
70
69
  }
71
- if ( ! isSelected ) {
72
- onSelectionChange(
73
- data.filter( ( _item ) => {
74
- const itemId = getItemId?.( _item );
75
- return (
76
- itemId === id ||
77
- selection.includes( itemId )
78
- );
79
- } )
80
- );
81
- } else {
82
- onSelectionChange(
83
- data.filter( ( _item ) => {
84
- const itemId = getItemId?.( _item );
85
- return (
86
- itemId !== id &&
87
- selection.includes( itemId )
88
- );
89
- } )
90
- );
91
- }
70
+ onSelectionChange(
71
+ selection.includes( id )
72
+ ? selection.filter( ( itemId ) => id !== itemId )
73
+ : [ ...selection, id ]
74
+ );
92
75
  }
93
76
  } }
94
77
  >
@@ -104,7 +87,6 @@ function GridItem< Item extends AnyItem >( {
104
87
  selection={ selection }
105
88
  onSelectionChange={ onSelectionChange }
106
89
  getItemId={ getItemId }
107
- data={ data }
108
90
  primaryField={ primaryField }
109
91
  disabled={ ! hasBulkAction }
110
92
  />
@@ -187,7 +169,7 @@ function GridItem< Item extends AnyItem >( {
187
169
  );
188
170
  }
189
171
 
190
- export default function ViewGrid< Item extends AnyItem >( {
172
+ export default function ViewGrid< Item >( {
191
173
  actions,
192
174
  data,
193
175
  fields,
@@ -198,24 +180,26 @@ export default function ViewGrid< Item extends AnyItem >( {
198
180
  view,
199
181
  }: ViewGridProps< Item > ) {
200
182
  const mediaField = fields.find(
201
- ( field ) => field.id === view.layout.mediaField
183
+ ( field ) => field.id === view.layout?.mediaField
202
184
  );
203
185
  const primaryField = fields.find(
204
- ( field ) => field.id === view.layout.primaryField
186
+ ( field ) => field.id === view.layout?.primaryField
205
187
  );
188
+ const viewFields = view.fields || fields.map( ( field ) => field.id );
206
189
  const { visibleFields, badgeFields } = fields.reduce(
207
190
  ( accumulator: Record< string, NormalizedField< Item >[] >, field ) => {
208
191
  if (
209
- view.hiddenFields.includes( field.id ) ||
210
- [ view.layout.mediaField, view.layout.primaryField ].includes(
211
- field.id
212
- )
192
+ ! viewFields.includes( field.id ) ||
193
+ [
194
+ view.layout?.mediaField,
195
+ view?.layout?.primaryField,
196
+ ].includes( field.id )
213
197
  ) {
214
198
  return accumulator;
215
199
  }
216
200
  // If the field is a badge field, add it to the badgeFields array
217
201
  // otherwise add it to the rest visibleFields array.
218
- const key = view.layout.badgeFields?.includes( field.id )
202
+ const key = view.layout?.badgeFields?.includes( field.id )
219
203
  ? 'badgeFields'
220
204
  : 'visibleFields';
221
205
  accumulator[ key ].push( field );
@@ -239,7 +223,6 @@ export default function ViewGrid< Item extends AnyItem >( {
239
223
  <GridItem
240
224
  key={ getItemId( item ) }
241
225
  selection={ selection }
242
- data={ data }
243
226
  onSelectionChange={ onSelectionChange }
244
227
  getItemId={ getItemId }
245
228
  item={ item }
@@ -248,7 +231,7 @@ export default function ViewGrid< Item extends AnyItem >( {
248
231
  primaryField={ primaryField }
249
232
  visibleFields={ visibleFields }
250
233
  badgeFields={ badgeFields }
251
- columnFields={ view.layout.columnFields }
234
+ columnFields={ view.layout?.columnFields }
252
235
  />
253
236
  );
254
237
  } ) }