@wordpress/dataviews 1.2.0 → 2.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 (150) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +33 -30
  3. package/build/add-filter.js +30 -22
  4. package/build/add-filter.js.map +1 -1
  5. package/build/bulk-actions-toolbar.js +74 -69
  6. package/build/bulk-actions-toolbar.js.map +1 -1
  7. package/build/bulk-actions.js +69 -56
  8. package/build/bulk-actions.js.map +1 -1
  9. package/build/constants.js +17 -10
  10. package/build/constants.js.map +1 -1
  11. package/build/dataviews.js +63 -56
  12. package/build/dataviews.js.map +1 -1
  13. package/build/filter-summary.js +105 -95
  14. package/build/filter-summary.js.map +1 -1
  15. package/build/filters.js +18 -17
  16. package/build/filters.js.map +1 -1
  17. package/build/index.js.map +1 -1
  18. package/build/item-actions.js +78 -65
  19. package/build/item-actions.js.map +1 -1
  20. package/build/layouts.js.map +1 -1
  21. package/build/pagination.js +60 -57
  22. package/build/pagination.js.map +1 -1
  23. package/build/reset-filters.js +9 -4
  24. package/build/reset-filters.js.map +1 -1
  25. package/build/search-widget.js +108 -89
  26. package/build/search-widget.js.map +1 -1
  27. package/build/search.js +13 -6
  28. package/build/search.js.map +1 -1
  29. package/build/single-selection-checkbox.js +2 -2
  30. package/build/single-selection-checkbox.js.map +1 -1
  31. package/build/types.js.map +1 -1
  32. package/build/utils.js +3 -15
  33. package/build/utils.js.map +1 -1
  34. package/build/view-actions.js +168 -120
  35. package/build/view-actions.js.map +1 -1
  36. package/build/view-grid.js +113 -99
  37. package/build/view-grid.js.map +1 -1
  38. package/build/view-list.js +153 -132
  39. package/build/view-list.js.map +1 -1
  40. package/build/view-table.js +220 -192
  41. package/build/view-table.js.map +1 -1
  42. package/build-module/add-filter.js +30 -22
  43. package/build-module/add-filter.js.map +1 -1
  44. package/build-module/bulk-actions-toolbar.js +76 -69
  45. package/build-module/bulk-actions-toolbar.js.map +1 -1
  46. package/build-module/bulk-actions.js +71 -56
  47. package/build-module/bulk-actions.js.map +1 -1
  48. package/build-module/constants.js +16 -9
  49. package/build-module/constants.js.map +1 -1
  50. package/build-module/dataviews.js +64 -56
  51. package/build-module/dataviews.js.map +1 -1
  52. package/build-module/filter-summary.js +106 -96
  53. package/build-module/filter-summary.js.map +1 -1
  54. package/build-module/filters.js +18 -17
  55. package/build-module/filters.js.map +1 -1
  56. package/build-module/index.js.map +1 -1
  57. package/build-module/item-actions.js +80 -65
  58. package/build-module/item-actions.js.map +1 -1
  59. package/build-module/layouts.js.map +1 -1
  60. package/build-module/pagination.js +61 -58
  61. package/build-module/pagination.js.map +1 -1
  62. package/build-module/reset-filters.js +9 -4
  63. package/build-module/reset-filters.js.map +1 -1
  64. package/build-module/search-widget.js +109 -89
  65. package/build-module/search-widget.js.map +1 -1
  66. package/build-module/search.js +13 -6
  67. package/build-module/search.js.map +1 -1
  68. package/build-module/single-selection-checkbox.js +2 -3
  69. package/build-module/single-selection-checkbox.js.map +1 -1
  70. package/build-module/types.js.map +1 -1
  71. package/build-module/utils.js +2 -13
  72. package/build-module/utils.js.map +1 -1
  73. package/build-module/view-actions.js +170 -121
  74. package/build-module/view-actions.js.map +1 -1
  75. package/build-module/view-grid.js +115 -99
  76. package/build-module/view-grid.js.map +1 -1
  77. package/build-module/view-list.js +154 -132
  78. package/build-module/view-list.js.map +1 -1
  79. package/build-module/view-table.js +223 -194
  80. package/build-module/view-table.js.map +1 -1
  81. package/build-style/style-rtl.css +109 -20
  82. package/build-style/style.css +109 -20
  83. package/build-types/add-filter.d.ts +9 -6
  84. package/build-types/add-filter.d.ts.map +1 -1
  85. package/build-types/bulk-actions-toolbar.d.ts +11 -7
  86. package/build-types/bulk-actions-toolbar.d.ts.map +1 -1
  87. package/build-types/bulk-actions.d.ts.map +1 -1
  88. package/build-types/constants.d.ts +19 -32
  89. package/build-types/constants.d.ts.map +1 -1
  90. package/build-types/dataviews.d.ts +21 -14
  91. package/build-types/dataviews.d.ts.map +1 -1
  92. package/build-types/filter-summary.d.ts +13 -5
  93. package/build-types/filter-summary.d.ts.map +1 -1
  94. package/build-types/filters.d.ts +11 -1
  95. package/build-types/filters.d.ts.map +1 -1
  96. package/build-types/index.d.ts +3 -3
  97. package/build-types/index.d.ts.map +1 -1
  98. package/build-types/item-actions.d.ts +5 -7
  99. package/build-types/item-actions.d.ts.map +1 -1
  100. package/build-types/layouts.d.ts +8 -4
  101. package/build-types/layouts.d.ts.map +1 -1
  102. package/build-types/reset-filters.d.ts +12 -5
  103. package/build-types/reset-filters.d.ts.map +1 -1
  104. package/build-types/search-widget.d.ts +9 -1
  105. package/build-types/search-widget.d.ts.map +1 -1
  106. package/build-types/search.d.ts +11 -1
  107. package/build-types/search.d.ts.map +1 -1
  108. package/build-types/types.d.ts +78 -10
  109. package/build-types/types.d.ts.map +1 -1
  110. package/build-types/utils.d.ts +2 -1
  111. package/build-types/utils.d.ts.map +1 -1
  112. package/build-types/view-actions.d.ts +10 -1
  113. package/build-types/view-actions.d.ts.map +1 -1
  114. package/build-types/view-grid.d.ts +1 -12
  115. package/build-types/view-grid.d.ts.map +1 -1
  116. package/build-types/view-list.d.ts +2 -14
  117. package/build-types/view-list.d.ts.map +1 -1
  118. package/build-types/view-table.d.ts +3 -12
  119. package/build-types/view-table.d.ts.map +1 -1
  120. package/package.json +11 -12
  121. package/src/{add-filter.js → add-filter.tsx} +17 -1
  122. package/src/{bulk-actions-toolbar.js → bulk-actions-toolbar.tsx} +68 -40
  123. package/src/bulk-actions.tsx +5 -1
  124. package/src/constants.ts +12 -5
  125. package/src/{dataviews.js → dataviews.tsx} +41 -12
  126. package/src/{filter-summary.js → filter-summary.tsx} +35 -6
  127. package/src/{filters.js → filters.tsx} +18 -6
  128. package/src/item-actions.tsx +20 -15
  129. package/src/pagination.tsx +1 -1
  130. package/src/{reset-filters.js → reset-filters.tsx} +17 -2
  131. package/src/{search-widget.js → search-widget.tsx} +27 -7
  132. package/src/{search.js → search.tsx} +22 -5
  133. package/src/style.scss +97 -23
  134. package/src/types.ts +105 -10
  135. package/src/{utils.js → utils.ts} +5 -13
  136. package/src/{view-actions.js → view-actions.tsx} +105 -49
  137. package/src/view-grid.tsx +4 -20
  138. package/src/view-list.tsx +12 -23
  139. package/src/{view-table.js → view-table.tsx} +91 -32
  140. package/tsconfig.json +0 -3
  141. package/tsconfig.tsbuildinfo +1 -1
  142. package/build/dropdown-menu-helper.js +0 -71
  143. package/build/dropdown-menu-helper.js.map +0 -1
  144. package/build-module/dropdown-menu-helper.js +0 -64
  145. package/build-module/dropdown-menu-helper.js.map +0 -1
  146. package/build-types/dropdown-menu-helper.d.ts +0 -6
  147. package/build-types/dropdown-menu-helper.d.ts.map +0 -1
  148. package/src/dropdown-menu-helper.js +0 -61
  149. /package/src/{index.js → index.ts} +0 -0
  150. /package/src/{layouts.js → layouts.ts} +0 -0
@@ -30,14 +30,11 @@ const {
30
30
  kebabCase,
31
31
  } = unlock( componentsPrivateApis );
32
32
 
33
- interface ButtonTriggerProps< Item extends AnyItem > {
34
- action: Action< Item >;
35
- onClick: MouseEventHandler;
36
- }
37
-
38
- interface DropdownMenuItemTriggerProps< Item extends AnyItem > {
33
+ export interface ActionTriggerProps< Item extends AnyItem > {
39
34
  action: Action< Item >;
40
35
  onClick: MouseEventHandler;
36
+ isBusy?: boolean;
37
+ items: Item[];
41
38
  }
42
39
 
43
40
  interface ActionModalProps< Item extends AnyItem > {
@@ -48,9 +45,7 @@ interface ActionModalProps< Item extends AnyItem > {
48
45
 
49
46
  interface ActionWithModalProps< Item extends AnyItem >
50
47
  extends ActionModalProps< Item > {
51
- ActionTrigger: (
52
- props: ButtonTriggerProps< Item > | DropdownMenuItemTriggerProps< Item >
53
- ) => ReactElement;
48
+ ActionTrigger: ( props: ActionTriggerProps< Item > ) => ReactElement;
54
49
  isBusy?: boolean;
55
50
  }
56
51
 
@@ -62,7 +57,7 @@ interface ActionsDropdownMenuGroupProps< Item extends AnyItem > {
62
57
  interface ItemActionsProps< Item extends AnyItem > {
63
58
  item: Item;
64
59
  actions: Action< Item >[];
65
- isCompact: boolean;
60
+ isCompact?: boolean;
66
61
  }
67
62
 
68
63
  interface CompactItemActionsProps< Item extends AnyItem > {
@@ -73,10 +68,13 @@ interface CompactItemActionsProps< Item extends AnyItem > {
73
68
  function ButtonTrigger< Item extends AnyItem >( {
74
69
  action,
75
70
  onClick,
76
- }: ButtonTriggerProps< Item > ) {
71
+ items,
72
+ }: ActionTriggerProps< Item > ) {
73
+ const label =
74
+ typeof action.label === 'string' ? action.label : action.label( items );
77
75
  return (
78
76
  <Button
79
- label={ action.label }
77
+ label={ label }
80
78
  icon={ action.icon }
81
79
  isDestructive={ action.isDestructive }
82
80
  size="compact"
@@ -88,13 +86,16 @@ function ButtonTrigger< Item extends AnyItem >( {
88
86
  function DropdownMenuItemTrigger< Item extends AnyItem >( {
89
87
  action,
90
88
  onClick,
91
- }: DropdownMenuItemTriggerProps< Item > ) {
89
+ items,
90
+ }: ActionTriggerProps< Item > ) {
91
+ const label =
92
+ typeof action.label === 'string' ? action.label : action.label( items );
92
93
  return (
93
94
  <DropdownMenuItem
94
95
  onClick={ onClick }
95
96
  hideOnClick={ ! ( 'RenderModal' in action ) }
96
97
  >
97
- <DropdownMenuItemLabel>{ action.label }</DropdownMenuItemLabel>
98
+ <DropdownMenuItemLabel>{ label }</DropdownMenuItemLabel>
98
99
  </DropdownMenuItem>
99
100
  );
100
101
  }
@@ -104,9 +105,11 @@ export function ActionModal< Item extends AnyItem >( {
104
105
  items,
105
106
  closeModal,
106
107
  }: ActionModalProps< Item > ) {
108
+ const label =
109
+ typeof action.label === 'string' ? action.label : action.label( items );
107
110
  return (
108
111
  <Modal
109
- title={ action.modalHeader || action.label }
112
+ title={ action.modalHeader || label }
110
113
  __experimentalHideHeader={ !! action.hideModalHeader }
111
114
  onRequestClose={ closeModal ?? ( () => {} ) }
112
115
  overlayClassName={ `dataviews-action-modal dataviews-action-modal__${ kebabCase(
@@ -174,6 +177,7 @@ export function ActionsDropdownMenuGroup< Item extends AnyItem >( {
174
177
  key={ action.id }
175
178
  action={ action }
176
179
  onClick={ () => action.callback( [ item ] ) }
180
+ items={ [ item ] }
177
181
  />
178
182
  );
179
183
  } ) }
@@ -230,6 +234,7 @@ export default function ItemActions< Item extends AnyItem >( {
230
234
  key={ action.id }
231
235
  action={ action }
232
236
  onClick={ () => action.callback( [ item ] ) }
237
+ items={ [ item ] }
233
238
  />
234
239
  );
235
240
  } ) }
@@ -74,7 +74,7 @@ const Pagination = memo( function Pagination( {
74
74
  page: +newValue,
75
75
  } );
76
76
  } }
77
- size={ 'compact' }
77
+ size="compact"
78
78
  __nextHasNoMarginBottom
79
79
  />
80
80
  ),
@@ -4,8 +4,23 @@
4
4
  import { Button } from '@wordpress/components';
5
5
  import { __ } from '@wordpress/i18n';
6
6
 
7
- export default function ResetFilter( { filters, view, onChangeView } ) {
8
- const isPrimary = ( field ) =>
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { NormalizedFilter, View } from './types';
11
+
12
+ interface ResetFilterProps {
13
+ filters: NormalizedFilter[];
14
+ view: View;
15
+ onChangeView: ( view: View ) => void;
16
+ }
17
+
18
+ export default function ResetFilter( {
19
+ filters,
20
+ view,
21
+ onChangeView,
22
+ }: ResetFilterProps ) {
23
+ const isPrimary = ( field: string ) =>
9
24
  filters.some(
10
25
  ( _filter ) => _filter.field === field && _filter.isPrimary
11
26
  );
@@ -22,6 +22,7 @@ import { SVG, Circle } from '@wordpress/primitives';
22
22
  * Internal dependencies
23
23
  */
24
24
  import { unlock } from './lock-unlock';
25
+ import type { Filter, NormalizedFilter, View } from './types';
25
26
 
26
27
  const {
27
28
  CompositeV2: Composite,
@@ -29,6 +30,12 @@ const {
29
30
  useCompositeStoreV2: useCompositeStore,
30
31
  } = unlock( componentsPrivateApis );
31
32
 
33
+ interface SearchWidgetProps {
34
+ view: View;
35
+ filter: NormalizedFilter;
36
+ onChangeView: ( view: View ) => void;
37
+ }
38
+
32
39
  const radioCheck = (
33
40
  <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
34
41
  <Circle cx={ 12 } cy={ 12 } r={ 3 }></Circle>
@@ -39,8 +46,11 @@ function normalizeSearchInput( input = '' ) {
39
46
  return removeAccents( input.trim().toLowerCase() );
40
47
  }
41
48
 
42
- const EMPTY_ARRAY = [];
43
- const getCurrentValue = ( filterDefinition, currentFilter ) => {
49
+ const EMPTY_ARRAY: [] = [];
50
+ const getCurrentValue = (
51
+ filterDefinition: NormalizedFilter,
52
+ currentFilter?: Filter
53
+ ) => {
44
54
  if ( filterDefinition.singleSelection ) {
45
55
  return currentFilter?.value;
46
56
  }
@@ -56,7 +66,11 @@ const getCurrentValue = ( filterDefinition, currentFilter ) => {
56
66
  return EMPTY_ARRAY;
57
67
  };
58
68
 
59
- const getNewValue = ( filterDefinition, currentFilter, value ) => {
69
+ const getNewValue = (
70
+ filterDefinition: NormalizedFilter,
71
+ currentFilter: Filter | undefined,
72
+ value: any
73
+ ) => {
60
74
  if ( filterDefinition.singleSelection ) {
61
75
  return value;
62
76
  }
@@ -70,7 +84,7 @@ const getNewValue = ( filterDefinition, currentFilter, value ) => {
70
84
  return [ value ];
71
85
  };
72
86
 
73
- function ListBox( { view, filter, onChangeView } ) {
87
+ function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
74
88
  const compositeStore = useCompositeStore( {
75
89
  virtualFocus: true,
76
90
  focusLoop: true,
@@ -184,7 +198,7 @@ function ListBox( { view, filter, onChangeView } ) {
184
198
  );
185
199
  }
186
200
 
187
- function ComboboxList( { view, filter, onChangeView } ) {
201
+ function ComboboxList( { view, filter, onChangeView }: SearchWidgetProps ) {
188
202
  const [ searchValue, setSearchValue ] = useState( '' );
189
203
  const deferredSearchValue = useDeferredValue( searchValue );
190
204
  const currentFilter = view.filters.find(
@@ -234,7 +248,13 @@ function ComboboxList( { view, filter, onChangeView } ) {
234
248
  setValue={ setSearchValue }
235
249
  >
236
250
  <div className="dataviews-search-widget-filter-combobox__wrapper">
237
- <Ariakit.ComboboxLabel render={ <VisuallyHidden /> }>
251
+ <Ariakit.ComboboxLabel
252
+ render={
253
+ <VisuallyHidden>
254
+ { __( 'Search items' ) }
255
+ </VisuallyHidden>
256
+ }
257
+ >
238
258
  { __( 'Search items' ) }
239
259
  </Ariakit.ComboboxLabel>
240
260
  <Ariakit.Combobox
@@ -290,7 +310,7 @@ function ComboboxList( { view, filter, onChangeView } ) {
290
310
  );
291
311
  }
292
312
 
293
- export default function SearchWidget( props ) {
313
+ export default function SearchWidget( props: SearchWidgetProps ) {
294
314
  const Widget = props.filter.elements.length > 10 ? ComboboxList : ListBox;
295
315
  return <Widget { ...props } />;
296
316
  }
@@ -6,20 +6,37 @@ import { useEffect, useRef, memo } from '@wordpress/element';
6
6
  import { SearchControl } from '@wordpress/components';
7
7
  import { useDebouncedInput } from '@wordpress/compose';
8
8
 
9
- const Search = memo( function Search( { label, view, onChangeView } ) {
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import type { View } from './types';
13
+
14
+ interface SearchProps {
15
+ label?: string;
16
+ view: View;
17
+ onChangeView: ( view: View ) => void;
18
+ }
19
+
20
+ const Search = memo( function Search( {
21
+ label,
22
+ view,
23
+ onChangeView,
24
+ }: SearchProps ) {
10
25
  const [ search, setSearch, debouncedSearch ] = useDebouncedInput(
11
26
  view.search
12
27
  );
13
28
  useEffect( () => {
14
- setSearch( view.search );
15
- }, [ view ] );
29
+ setSearch( view.search ?? '' );
30
+ }, [ view.search, setSearch ] );
16
31
  const onChangeViewRef = useRef( onChangeView );
32
+ const viewRef = useRef( view );
17
33
  useEffect( () => {
18
34
  onChangeViewRef.current = onChangeView;
19
- }, [ onChangeView ] );
35
+ viewRef.current = view;
36
+ }, [ onChangeView, view ] );
20
37
  useEffect( () => {
21
38
  onChangeViewRef.current( {
22
- ...view,
39
+ ...viewRef.current,
23
40
  page: 1,
24
41
  search: debouncedSearch,
25
42
  } );
package/src/style.scss CHANGED
@@ -3,15 +3,20 @@
3
3
  overflow: auto;
4
4
  box-sizing: border-box;
5
5
  scroll-padding-bottom: $grid-unit-80;
6
+ /* stylelint-disable-next-line property-no-unknown -- '@container' not globally permitted */
7
+ container: dataviews-wrapper / inline-size;
8
+ display: flex;
9
+ flex-direction: column;
6
10
  }
7
11
 
8
12
  .dataviews-filters__view-actions {
9
13
  box-sizing: border-box;
10
- padding: $grid-unit-15 $grid-unit-40 0;
11
- margin-bottom: $grid-unit-15;
14
+ padding: $grid-unit-20 $grid-unit-60;
12
15
  flex-shrink: 0;
13
16
  position: sticky;
14
17
  left: 0;
18
+ transition: padding ease-out 0.1s;
19
+ @include reduce-motion("transition");
15
20
 
16
21
  .components-search-control {
17
22
  .components-base-control__field {
@@ -21,8 +26,6 @@
21
26
  }
22
27
 
23
28
  .dataviews-filters__container {
24
- padding-right: $grid-unit-40;
25
-
26
29
  .dataviews-filters__reset-button[aria-disabled="true"] {
27
30
  &,
28
31
  &:hover {
@@ -44,10 +47,12 @@
44
47
  bottom: 0;
45
48
  left: 0;
46
49
  background-color: $white;
47
- padding: $grid-unit-15 $grid-unit-40;
50
+ padding: $grid-unit-15 $grid-unit-60;
48
51
  border-top: $border-width solid $gray-100;
49
52
  color: $gray-700;
50
53
  flex-shrink: 0;
54
+ transition: padding ease-out 0.1s;
55
+ @include reduce-motion("transition");
51
56
  }
52
57
 
53
58
  .dataviews-pagination__page-selection {
@@ -68,6 +73,7 @@
68
73
  border-collapse: collapse;
69
74
  position: relative;
70
75
  color: $gray-700;
76
+ margin-bottom: auto;
71
77
 
72
78
  a {
73
79
  text-decoration: none;
@@ -100,9 +106,18 @@
100
106
  gap: $grid-unit-05;
101
107
  }
102
108
 
109
+ th,
110
+ td {
111
+ &:first-child,
112
+ &:last-child {
113
+ transition: padding ease-out 0.1s;
114
+ @include reduce-motion("transition");
115
+ }
116
+ }
117
+
103
118
  td:first-child,
104
119
  th:first-child {
105
- padding-left: $grid-unit-40;
120
+ padding-left: $grid-unit-60;
106
121
 
107
122
  .dataviews-view-table-header-button,
108
123
  .dataviews-view-table-header {
@@ -112,7 +127,7 @@
112
127
 
113
128
  td:last-child,
114
129
  th:last-child {
115
- padding-right: $grid-unit-40;
130
+ padding-right: $grid-unit-60;
116
131
  }
117
132
 
118
133
  &:last-child {
@@ -278,10 +293,16 @@
278
293
  }
279
294
 
280
295
  .dataviews-view-grid {
281
- margin-bottom: $grid-unit-30;
282
- grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
296
+ margin-bottom: auto;
297
+ grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
283
298
  grid-template-rows: max-content;
284
- padding: 0 $grid-unit-40;
299
+ padding: 0 $grid-unit-60 $grid-unit-30;
300
+ transition: padding ease-out 0.1s;
301
+ @include reduce-motion("transition");
302
+
303
+ @include break-mobile() {
304
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important; // Todo: eliminate !important dependency
305
+ }
285
306
 
286
307
  @include break-xlarge() {
287
308
  grid-template-columns: repeat(3, minmax(0, 1fr)) !important; // Todo: eliminate !important dependency
@@ -396,7 +417,7 @@
396
417
  }
397
418
 
398
419
  .dataviews-view-list {
399
- margin: 0;
420
+ margin: 0 0 auto;
400
421
 
401
422
  li {
402
423
  margin: 0;
@@ -412,15 +433,27 @@
412
433
  }
413
434
  }
414
435
 
415
- .dataviews-view-list__item-actions .components-button {
416
- opacity: 0;
436
+ .dataviews-view-list__item-actions {
437
+ .components-button {
438
+ opacity: 0;
439
+ position: fixed;
440
+ }
417
441
  }
418
442
 
419
443
  &.is-selected,
420
444
  &.is-hovered,
421
445
  &:focus-within {
422
- .dataviews-view-list__item-actions .components-button {
423
- opacity: 1;
446
+ .dataviews-view-list__item-actions {
447
+ padding-right: $grid-unit-40;
448
+
449
+ .components-button {
450
+ opacity: 1;
451
+ position: static;
452
+ }
453
+ }
454
+
455
+ .dataviews-view-list__item {
456
+ padding-right: 0;
424
457
  }
425
458
  }
426
459
 
@@ -449,15 +482,14 @@
449
482
  color: $gray-900;
450
483
 
451
484
  .dataviews-view-list__primary-field,
452
- .dataviews-view-list__fields,
453
- .components-button {
485
+ .dataviews-view-list__fields {
454
486
  color: var(--wp-admin-theme-color);
455
487
  }
456
488
  }
457
489
  }
458
490
 
459
491
  .dataviews-view-list__item {
460
- padding: $grid-unit-20 0 $grid-unit-20 $grid-unit-40;
492
+ padding: $grid-unit-20 0 $grid-unit-20 $grid-unit-30;
461
493
  width: 100%;
462
494
  scroll-margin: $grid-unit-10 0;
463
495
 
@@ -475,6 +507,7 @@
475
507
  }
476
508
  .dataviews-view-list__primary-field {
477
509
  min-height: $grid-unit-05 * 5;
510
+ line-height: $grid-unit-05 * 5;
478
511
  overflow: hidden;
479
512
  }
480
513
  }
@@ -518,18 +551,20 @@
518
551
  gap: $grid-unit-10;
519
552
  flex-wrap: wrap;
520
553
  font-size: 12px;
521
- line-height: $grid-unit-20;
522
554
 
523
555
  .dataviews-view-list__field {
524
556
  &:has(.dataviews-view-list__field-value:empty) {
525
557
  display: none;
526
558
  }
527
559
  }
528
- }
529
560
 
561
+ .dataviews-view-list__field-value {
562
+ line-height: $grid-unit-05 * 5;
563
+ display: inline-flex;
564
+ }
565
+ }
530
566
  .dataviews-view-list__item-actions {
531
- padding-top: $grid-unit-20;
532
- padding-right: $grid-unit-40;
567
+ padding-right: $grid-unit-30;
533
568
  }
534
569
 
535
570
  & + .dataviews-pagination {
@@ -544,11 +579,13 @@
544
579
 
545
580
  .dataviews-no-results,
546
581
  .dataviews-loading {
547
- padding: 0 $grid-unit-40;
582
+ padding: 0 $grid-unit-60;
548
583
  flex-grow: 1;
549
584
  display: flex;
550
585
  align-items: center;
551
586
  justify-content: center;
587
+ transition: padding ease-out 0.1s;
588
+ @include reduce-motion("transition");
552
589
  }
553
590
 
554
591
  .dataviews-view-table-selection-checkbox {
@@ -559,6 +596,11 @@
559
596
  }
560
597
 
561
598
  line-height: 0;
599
+ flex-shrink: 0;
600
+
601
+ .components-checkbox-control__input-container {
602
+ margin: 0;
603
+ }
562
604
  }
563
605
 
564
606
  .dataviews-filters__custom-menu-radio-item-prefix {
@@ -802,6 +844,38 @@
802
844
  }
803
845
  }
804
846
 
847
+ /* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
848
+ @container (max-width: 430px) {
849
+ .dataviews-pagination,
850
+ .dataviews-filters__view-actions {
851
+ padding: $grid-unit-15 $grid-unit-30;
852
+ }
853
+
854
+ .dataviews-filters__view-actions {
855
+ .components-search-control {
856
+ .components-base-control__field {
857
+ max-width: 112px;
858
+ }
859
+ }
860
+ }
861
+
862
+ .dataviews-view-table tr td:first-child,
863
+ .dataviews-view-table tr th:first-child {
864
+ padding-left: $grid-unit-30;
865
+ }
866
+
867
+ .dataviews-view-table tr td:last-child,
868
+ .dataviews-view-table tr th:last-child {
869
+ padding-right: $grid-unit-30;
870
+ }
871
+
872
+ .dataviews-view-grid,
873
+ .dataviews-no-results,
874
+ .dataviews-loading {
875
+ padding-left: $grid-unit-30;
876
+ padding-right: $grid-unit-30;
877
+ }
878
+ }
805
879
 
806
880
  .dataviews-bulk-actions-toolbar-wrapper {
807
881
  display: flex;
package/src/types.ts CHANGED
@@ -8,9 +8,10 @@ export type SortDirection = 'asc' | 'desc';
8
8
  /**
9
9
  * Generic option type.
10
10
  */
11
- interface Option< Value extends any = any > {
11
+ export interface Option< Value extends any = any > {
12
12
  value: Value;
13
13
  label: string;
14
+ description?: string;
14
15
  }
15
16
 
16
17
  interface FilterByConfig {
@@ -28,7 +29,13 @@ interface FilterByConfig {
28
29
  isPrimary?: boolean;
29
30
  }
30
31
 
31
- type Operator = 'is' | 'isNot' | 'isAny' | 'isNone' | 'isAll' | 'isNotAll';
32
+ export type Operator =
33
+ | 'is'
34
+ | 'isNot'
35
+ | 'isAny'
36
+ | 'isNone'
37
+ | 'isAll'
38
+ | 'isNotAll';
32
39
 
33
40
  export type AnyItem = Record< string, any >;
34
41
 
@@ -128,6 +135,43 @@ export interface Filter {
128
135
  value: any;
129
136
  }
130
137
 
138
+ export interface NormalizedFilter {
139
+ /**
140
+ * The field to filter by.
141
+ */
142
+ field: string;
143
+
144
+ /**
145
+ * The field name.
146
+ */
147
+ name: string;
148
+
149
+ /**
150
+ * The list of options to pick from when using the field as a filter.
151
+ */
152
+ elements: Option[];
153
+
154
+ /**
155
+ * Is a single selection filter.
156
+ */
157
+ singleSelection: boolean;
158
+
159
+ /**
160
+ * The list of operators supported by the field.
161
+ */
162
+ operators: Operator[];
163
+
164
+ /**
165
+ * Whether the filter is visible.
166
+ */
167
+ isVisible: boolean;
168
+
169
+ /**
170
+ * Whether it is a primary filter.
171
+ */
172
+ isPrimary: boolean;
173
+ }
174
+
131
175
  interface ViewBase {
132
176
  /**
133
177
  * The layout of the view.
@@ -175,6 +219,22 @@ interface ViewBase {
175
219
  hiddenFields: string[];
176
220
  }
177
221
 
222
+ export interface ViewTable extends ViewBase {
223
+ type: 'table';
224
+
225
+ layout: {
226
+ /**
227
+ * The field to use as the primary field.
228
+ */
229
+ primaryField?: string;
230
+
231
+ /**
232
+ * The field to use as the media field.
233
+ */
234
+ mediaField?: string;
235
+ };
236
+ }
237
+
178
238
  export interface ViewList extends ViewBase {
179
239
  type: 'list';
180
240
 
@@ -182,12 +242,12 @@ export interface ViewList extends ViewBase {
182
242
  /**
183
243
  * The field to use as the primary field.
184
244
  */
185
- primaryField: string;
245
+ primaryField?: string;
186
246
 
187
247
  /**
188
248
  * The field to use as the media field.
189
249
  */
190
- mediaField: string;
250
+ mediaField?: string;
191
251
  };
192
252
  }
193
253
 
@@ -198,26 +258,26 @@ export interface ViewGrid extends ViewBase {
198
258
  /**
199
259
  * The field to use as the primary field.
200
260
  */
201
- primaryField: string;
261
+ primaryField?: string;
202
262
 
203
263
  /**
204
264
  * The field to use as the media field.
205
265
  */
206
- mediaField: string;
266
+ mediaField?: string;
207
267
 
208
268
  /**
209
269
  * The fields to use as columns.
210
270
  */
211
- columnFields: string[];
271
+ columnFields?: string[];
212
272
 
213
273
  /**
214
274
  * The fields to use as badge fields.
215
275
  */
216
- badgeFields: string[];
276
+ badgeFields?: string[];
217
277
  };
218
278
  }
219
279
 
220
- export type View = ViewList | ViewGrid | ViewBase;
280
+ export type View = ViewList | ViewGrid | ViewTable;
221
281
 
222
282
  interface ActionBase< Item extends AnyItem > {
223
283
  /**
@@ -227,8 +287,10 @@ interface ActionBase< Item extends AnyItem > {
227
287
 
228
288
  /**
229
289
  * The label of the action.
290
+ * In case we want to adjust the label based on the selected items,
291
+ * a function can be provided.
230
292
  */
231
- label: string;
293
+ label: string | ( ( items: Item[] ) => string );
232
294
 
233
295
  /**
234
296
  * The icon of the action. (Either a string or an SVG element)
@@ -312,3 +374,36 @@ export interface ActionButton< Item extends AnyItem >
312
374
  export type Action< Item extends AnyItem > =
313
375
  | ActionModal< Item >
314
376
  | ActionButton< Item >;
377
+
378
+ export interface ViewBaseProps< Item extends AnyItem > {
379
+ actions: Action< Item >[];
380
+ data: Item[];
381
+ fields: NormalizedField< Item >[];
382
+ getItemId: ( item: Item ) => string;
383
+ isLoading?: boolean;
384
+ onChangeView( view: View ): void;
385
+ onSelectionChange: ( items: Item[] ) => void;
386
+ selection: string[];
387
+ setOpenedFilter: ( fieldId: string ) => void;
388
+ view: View;
389
+ }
390
+
391
+ export interface ViewTableProps< Item extends AnyItem >
392
+ extends ViewBaseProps< Item > {
393
+ view: ViewTable;
394
+ }
395
+
396
+ export interface ViewListProps< Item extends AnyItem >
397
+ extends ViewBaseProps< Item > {
398
+ view: ViewList;
399
+ }
400
+
401
+ export interface ViewGridProps< Item extends AnyItem >
402
+ extends ViewBaseProps< Item > {
403
+ view: ViewGrid;
404
+ }
405
+
406
+ export type ViewProps< Item extends AnyItem > =
407
+ | ViewTableProps< Item >
408
+ | ViewGridProps< Item >
409
+ | ViewListProps< Item >;