@wordpress/dataviews 0.5.5 → 0.7.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 (45) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +156 -111
  3. package/build/add-filter.js +0 -2
  4. package/build/add-filter.js.map +1 -1
  5. package/build/dataviews.js +1 -4
  6. package/build/dataviews.js.map +1 -1
  7. package/build/reset-filters.js +2 -1
  8. package/build/reset-filters.js.map +1 -1
  9. package/build/search-widget.js +89 -4
  10. package/build/search-widget.js.map +1 -1
  11. package/build/view-actions.js.map +1 -1
  12. package/build/view-grid.js +5 -12
  13. package/build/view-grid.js.map +1 -1
  14. package/build/view-list.js +1 -1
  15. package/build/view-list.js.map +1 -1
  16. package/build/view-table.js +2 -4
  17. package/build/view-table.js.map +1 -1
  18. package/build-module/add-filter.js +0 -2
  19. package/build-module/add-filter.js.map +1 -1
  20. package/build-module/dataviews.js +2 -5
  21. package/build-module/dataviews.js.map +1 -1
  22. package/build-module/reset-filters.js +2 -1
  23. package/build-module/reset-filters.js.map +1 -1
  24. package/build-module/search-widget.js +91 -6
  25. package/build-module/search-widget.js.map +1 -1
  26. package/build-module/view-actions.js.map +1 -1
  27. package/build-module/view-grid.js +6 -13
  28. package/build-module/view-grid.js.map +1 -1
  29. package/build-module/view-list.js +2 -2
  30. package/build-module/view-list.js.map +1 -1
  31. package/build-module/view-table.js +3 -5
  32. package/build-module/view-table.js.map +1 -1
  33. package/build-style/style-rtl.css +47 -33
  34. package/build-style/style.css +47 -33
  35. package/package.json +11 -11
  36. package/src/add-filter.js +0 -2
  37. package/src/dataviews.js +47 -52
  38. package/src/reset-filters.js +2 -1
  39. package/src/search-widget.js +131 -6
  40. package/src/stories/index.story.js +12 -16
  41. package/src/style.scss +81 -61
  42. package/src/view-actions.js +1 -1
  43. package/src/view-grid.js +5 -11
  44. package/src/view-list.js +2 -1
  45. package/src/view-table.js +4 -3
package/src/dataviews.js CHANGED
@@ -1,10 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import {
5
- __experimentalVStack as VStack,
6
- __experimentalHStack as HStack,
7
- } from '@wordpress/components';
4
+ import { __experimentalHStack as HStack } from '@wordpress/components';
8
5
  import { useMemo, useState, useCallback, useEffect } from '@wordpress/element';
9
6
 
10
7
  /**
@@ -92,69 +89,67 @@ export default function DataViews( {
92
89
  );
93
90
  return (
94
91
  <div className="dataviews-wrapper">
95
- <VStack spacing={ 3 } justify="flex-start">
92
+ <HStack
93
+ alignment="top"
94
+ justify="start"
95
+ className="dataviews-filters__view-actions"
96
+ >
96
97
  <HStack
97
- alignment="top"
98
98
  justify="start"
99
- className="dataviews-filters__view-actions"
99
+ className="dataviews-filters__container"
100
+ wrap
100
101
  >
101
- <HStack
102
- justify="start"
103
- className="dataviews-filters__container"
104
- wrap
105
- >
106
- { search && (
107
- <Search
108
- label={ searchLabel }
109
- view={ view }
110
- onChangeView={ onChangeView }
111
- />
112
- ) }
113
- <Filters
114
- fields={ _fields }
102
+ { search && (
103
+ <Search
104
+ label={ searchLabel }
115
105
  view={ view }
116
106
  onChangeView={ onChangeView }
117
- openedFilter={ openedFilter }
118
- setOpenedFilter={ setOpenedFilter }
119
107
  />
120
- </HStack>
121
- { [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type ) &&
122
- hasPossibleBulkAction && (
123
- <BulkActions
124
- actions={ actions }
125
- data={ data }
126
- onSelectionChange={ onSetSelection }
127
- selection={ selection }
128
- getItemId={ getItemId }
129
- />
130
- ) }
131
- <ViewActions
108
+ ) }
109
+ <Filters
132
110
  fields={ _fields }
133
111
  view={ view }
134
112
  onChangeView={ onChangeView }
135
- supportedLayouts={ supportedLayouts }
113
+ openedFilter={ openedFilter }
114
+ setOpenedFilter={ setOpenedFilter }
136
115
  />
137
116
  </HStack>
138
- <ViewComponent
117
+ { [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type ) &&
118
+ hasPossibleBulkAction && (
119
+ <BulkActions
120
+ actions={ actions }
121
+ data={ data }
122
+ onSelectionChange={ onSetSelection }
123
+ selection={ selection }
124
+ getItemId={ getItemId }
125
+ />
126
+ ) }
127
+ <ViewActions
139
128
  fields={ _fields }
140
129
  view={ view }
141
130
  onChangeView={ onChangeView }
142
- actions={ actions }
143
- data={ data }
144
- getItemId={ getItemId }
145
- isLoading={ isLoading }
146
- onSelectionChange={ onSetSelection }
147
- onDetailsChange={ onDetailsChange }
148
- selection={ selection }
149
- deferredRendering={ deferredRendering }
150
- setOpenedFilter={ setOpenedFilter }
151
- />
152
- <Pagination
153
- view={ view }
154
- onChangeView={ onChangeView }
155
- paginationInfo={ paginationInfo }
131
+ supportedLayouts={ supportedLayouts }
156
132
  />
157
- </VStack>
133
+ </HStack>
134
+ <ViewComponent
135
+ fields={ _fields }
136
+ view={ view }
137
+ onChangeView={ onChangeView }
138
+ actions={ actions }
139
+ data={ data }
140
+ getItemId={ getItemId }
141
+ isLoading={ isLoading }
142
+ onSelectionChange={ onSetSelection }
143
+ onDetailsChange={ onDetailsChange }
144
+ selection={ selection }
145
+ deferredRendering={ deferredRendering }
146
+ setOpenedFilter={ setOpenedFilter }
147
+ />
148
+ <Pagination
149
+ view={ view }
150
+ onChangeView={ onChangeView }
151
+ paginationInfo={ paginationInfo }
152
+ />
158
153
  </div>
159
154
  );
160
155
  }
@@ -21,6 +21,7 @@ export default function ResetFilter( { filters, view, onChangeView } ) {
21
21
  __experimentalIsFocusable
22
22
  size="compact"
23
23
  variant="tertiary"
24
+ className="dataviews-filters__reset-button"
24
25
  onClick={ () => {
25
26
  onChangeView( {
26
27
  ...view,
@@ -30,7 +31,7 @@ export default function ResetFilter( { filters, view, onChangeView } ) {
30
31
  } );
31
32
  } }
32
33
  >
33
- { __( 'Reset filters' ) }
34
+ { __( 'Reset' ) }
34
35
  </Button>
35
36
  );
36
37
  }
@@ -8,12 +8,27 @@ import removeAccents from 'remove-accents';
8
8
  /**
9
9
  * WordPress dependencies
10
10
  */
11
- import { __ } from '@wordpress/i18n';
11
+ import { __, sprintf } from '@wordpress/i18n';
12
12
  import { useState, useMemo, useDeferredValue } from '@wordpress/element';
13
- import { VisuallyHidden, Icon } from '@wordpress/components';
13
+ import {
14
+ VisuallyHidden,
15
+ Icon,
16
+ privateApis as componentsPrivateApis,
17
+ } from '@wordpress/components';
14
18
  import { search } from '@wordpress/icons';
15
19
  import { SVG, Circle } from '@wordpress/primitives';
16
20
 
21
+ /**
22
+ * Internal dependencies
23
+ */
24
+ import { unlock } from './lock-unlock';
25
+
26
+ const {
27
+ CompositeV2: Composite,
28
+ CompositeItemV2: CompositeItem,
29
+ useCompositeStoreV2: useCompositeStore,
30
+ } = unlock( componentsPrivateApis );
31
+
17
32
  const radioCheck = (
18
33
  <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
19
34
  <Circle cx={ 12 } cy={ 12 } r={ 3 }></Circle>
@@ -24,7 +39,112 @@ function normalizeSearchInput( input = '' ) {
24
39
  return removeAccents( input.trim().toLowerCase() );
25
40
  }
26
41
 
27
- export default function SearchWidget( { filter, view, onChangeView } ) {
42
+ function ListBox( { view, filter, onChangeView } ) {
43
+ const compositeStore = useCompositeStore( {
44
+ virtualFocus: true,
45
+ focusLoop: true,
46
+ // When we have no or just one operators, we can set the first item as active.
47
+ // We do that by passing `undefined` to `defaultActiveId`. Otherwise, we set it to `null`,
48
+ // so the first item is not selected, since the focus is on the operators control.
49
+ defaultActiveId: filter.operators?.length === 1 ? undefined : null,
50
+ } );
51
+ const selectedFilter = view.filters.find(
52
+ ( _filter ) => _filter.field === filter.field
53
+ );
54
+ const selectedValues = selectedFilter?.value;
55
+ return (
56
+ <Composite
57
+ store={ compositeStore }
58
+ role="listbox"
59
+ className="dataviews-search-widget-listbox"
60
+ aria-label={ sprintf(
61
+ /* translators: List of items for a filter. 1: Filter name. e.g.: "List of: Author". */
62
+ __( 'List of: %1$s' ),
63
+ filter.name
64
+ ) }
65
+ onFocusVisible={ () => {
66
+ if ( ! compositeStore.getState().activeId ) {
67
+ compositeStore.move( compositeStore.first() );
68
+ }
69
+ } }
70
+ render={ <Ariakit.CompositeTypeahead store={ compositeStore } /> }
71
+ >
72
+ { filter.elements.map( ( element ) => (
73
+ <Ariakit.CompositeHover
74
+ store={ compositeStore }
75
+ key={ element.value }
76
+ render={
77
+ <CompositeItem
78
+ render={
79
+ <div
80
+ aria-label={ element.label }
81
+ role="option"
82
+ className="dataviews-search-widget-listitem"
83
+ />
84
+ }
85
+ onClick={ () => {
86
+ const currentFilter = view.filters.find(
87
+ ( _filter ) =>
88
+ _filter.field === filter.field
89
+ );
90
+ const newFilters = currentFilter
91
+ ? [
92
+ ...view.filters.map(
93
+ ( _filter ) => {
94
+ if (
95
+ _filter.field ===
96
+ filter.field
97
+ ) {
98
+ return {
99
+ ..._filter,
100
+ operator:
101
+ currentFilter.operator ||
102
+ filter
103
+ .operators[ 0 ],
104
+ value: element.value,
105
+ };
106
+ }
107
+ return _filter;
108
+ }
109
+ ),
110
+ ]
111
+ : [
112
+ ...view.filters,
113
+ {
114
+ field: filter.field,
115
+ operator: filter.operators[ 0 ],
116
+ value: element.value,
117
+ },
118
+ ];
119
+ onChangeView( {
120
+ ...view,
121
+ page: 1,
122
+ filters: newFilters,
123
+ } );
124
+ } }
125
+ />
126
+ }
127
+ >
128
+ <span className="dataviews-search-widget-listitem-check">
129
+ { selectedValues === element.value && (
130
+ <Icon icon={ radioCheck } />
131
+ ) }
132
+ </span>
133
+ <span>
134
+ { element.label }
135
+ { !! element.description && (
136
+ <span className="dataviews-search-widget-listitem-description">
137
+ { element.description }
138
+ </span>
139
+ ) }
140
+ </span>
141
+ </Ariakit.CompositeHover>
142
+ ) ) }
143
+ </Composite>
144
+ );
145
+ }
146
+
147
+ function ComboboxList( { view, filter, onChangeView } ) {
28
148
  const [ searchValue, setSearchValue ] = useState( '' );
29
149
  const deferredSearchValue = useDeferredValue( searchValue );
30
150
  const selectedFilter = view.filters.find(
@@ -97,12 +217,12 @@ export default function SearchWidget( { filter, view, onChangeView } ) {
97
217
  <Ariakit.ComboboxItem
98
218
  key={ element.value }
99
219
  value={ element.value }
100
- className="dataviews-search-widget-filter-combobox-item"
220
+ className="dataviews-search-widget-listitem"
101
221
  hideOnClick={ false }
102
222
  setValueOnClick={ false }
103
223
  focusOnHover
104
224
  >
105
- <span className="dataviews-search-widget-filter-combobox-item-check">
225
+ <span className="dataviews-search-widget-listitem-check">
106
226
  { selectedValues === element.value && (
107
227
  <Icon icon={ radioCheck } />
108
228
  ) }
@@ -113,7 +233,7 @@ export default function SearchWidget( { filter, view, onChangeView } ) {
113
233
  value={ element.label }
114
234
  />
115
235
  { !! element.description && (
116
- <span className="dataviews-search-widget-filter-combobox-item-description">
236
+ <span className="dataviews-search-widget-listitem-description">
117
237
  { element.description }
118
238
  </span>
119
239
  ) }
@@ -126,3 +246,8 @@ export default function SearchWidget( { filter, view, onChangeView } ) {
126
246
  </Ariakit.ComboboxProvider>
127
247
  );
128
248
  }
249
+
250
+ export default function SearchWidget( props ) {
251
+ const Widget = props.filter.elements.length > 10 ? ComboboxList : ListBox;
252
+ return <Widget { ...props } />;
253
+ }
@@ -6,9 +6,9 @@ import { useState, useMemo, useCallback } from '@wordpress/element';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import { DataViews, LAYOUT_GRID, LAYOUT_TABLE } from '../index';
10
-
9
+ import { DataViews } from '../index';
11
10
  import { DEFAULT_VIEW, actions, data } from './fixtures';
11
+ import { LAYOUT_GRID, LAYOUT_TABLE } from '../constants';
12
12
 
13
13
  const meta = {
14
14
  title: 'DataViews (Experimental)/DataViews',
@@ -17,7 +17,9 @@ const meta = {
17
17
  export default meta;
18
18
 
19
19
  const defaultConfigPerViewType = {
20
- [ LAYOUT_TABLE ]: {},
20
+ [ LAYOUT_TABLE ]: {
21
+ primaryField: 'title',
22
+ },
21
23
  [ LAYOUT_GRID ]: {
22
24
  mediaField: 'image',
23
25
  primaryField: 'title',
@@ -100,23 +102,19 @@ export const Default = ( props ) => {
100
102
  };
101
103
  }, [ view ] );
102
104
  const onChangeView = useCallback(
103
- ( viewUpdater ) => {
104
- let updatedView =
105
- typeof viewUpdater === 'function'
106
- ? viewUpdater( view )
107
- : viewUpdater;
108
- if ( updatedView.type !== view.type ) {
109
- updatedView = {
110
- ...updatedView,
105
+ ( newView ) => {
106
+ if ( newView.type !== view.type ) {
107
+ newView = {
108
+ ...newView,
111
109
  layout: {
112
- ...defaultConfigPerViewType[ updatedView.type ],
110
+ ...defaultConfigPerViewType[ newView.type ],
113
111
  },
114
112
  };
115
113
  }
116
114
 
117
- setView( updatedView );
115
+ setView( newView );
118
116
  },
119
- [ view, setView ]
117
+ [ view.type, setView ]
120
118
  );
121
119
  return (
122
120
  <DataViews
@@ -131,7 +129,5 @@ export const Default = ( props ) => {
131
129
  };
132
130
  Default.args = {
133
131
  actions,
134
- getItemId: ( item ) => item.id,
135
- isLoading: false,
136
132
  supportedLayouts: [ LAYOUT_TABLE, LAYOUT_GRID ],
137
133
  };
package/src/style.scss CHANGED
@@ -4,14 +4,15 @@
4
4
  overflow: auto;
5
5
  box-sizing: border-box;
6
6
  scroll-padding-bottom: $grid-unit-80;
7
-
8
- > div {
9
- min-height: 100%;
10
- }
11
7
  }
12
8
 
13
9
  .dataviews-filters__view-actions {
14
10
  padding: $grid-unit-15 $grid-unit-40 0;
11
+ margin-bottom: $grid-unit-15;
12
+ flex-shrink: 0;
13
+ position: sticky;
14
+ left: 0;
15
+
15
16
  .components-search-control {
16
17
  .components-base-control__field {
17
18
  max-width: 240px;
@@ -21,6 +22,17 @@
21
22
 
22
23
  .dataviews-filters__container {
23
24
  padding-right: $grid-unit-40;
25
+
26
+ .dataviews-filters__reset-button[aria-disabled="true"] {
27
+ &,
28
+ &:hover {
29
+ opacity: 0;
30
+ }
31
+
32
+ &:focus {
33
+ opacity: 1;
34
+ }
35
+ }
24
36
  }
25
37
 
26
38
  .dataviews-filters-button {
@@ -28,14 +40,14 @@
28
40
  }
29
41
 
30
42
  .dataviews-pagination {
31
- margin-top: auto;
32
43
  position: sticky;
33
44
  bottom: 0;
34
- background-color: rgba($white, 0.8);
35
- backdrop-filter: blur(6px);
45
+ left: 0;
46
+ background-color: $white;
36
47
  padding: $grid-unit-15 $grid-unit-40;
37
48
  border-top: $border-width solid $gray-100;
38
49
  color: $gray-700;
50
+ flex-shrink: 0;
39
51
  }
40
52
 
41
53
  .dataviews-pagination__page-selection {
@@ -49,10 +61,6 @@
49
61
  margin: $grid-unit-40 0 $grid-unit-20;
50
62
  }
51
63
 
52
- .dataviews-view-table-wrapper {
53
- overflow-x: auto;
54
- }
55
-
56
64
  .dataviews-view-table {
57
65
  width: 100%;
58
66
  text-indent: 0;
@@ -68,7 +76,7 @@
68
76
  }
69
77
  th {
70
78
  text-align: left;
71
- color: var(--wp-components-color-foreground, $gray-900);
79
+ color: $gray-900;
72
80
  font-weight: normal;
73
81
  font-size: $default-font-size;
74
82
  }
@@ -146,17 +154,18 @@
146
154
  }
147
155
  }
148
156
  thead {
157
+ position: sticky;
158
+ inset-block-start: 0;
159
+ z-index: z-index(".dataviews-view-table thead");
160
+
149
161
  tr {
150
162
  border: 0;
151
163
  }
152
164
  th {
153
- position: sticky;
154
- top: -1px;
155
165
  background-color: $white;
156
166
  box-shadow: inset 0 -#{$border-width} 0 $gray-100;
157
167
  padding-top: $grid-unit-10;
158
168
  padding-bottom: $grid-unit-10;
159
- z-index: 1;
160
169
  font-size: 11px;
161
170
  text-transform: uppercase;
162
171
  font-weight: 500;
@@ -473,6 +482,10 @@
473
482
  .dataviews-no-results,
474
483
  .dataviews-loading {
475
484
  padding: 0 $grid-unit-40;
485
+ flex-grow: 1;
486
+ display: flex;
487
+ align-items: center;
488
+ justify-content: center;
476
489
  }
477
490
 
478
491
  .dataviews-view-table-selection-checkbox label {
@@ -500,9 +513,6 @@
500
513
  margin-left: $grid-unit-10;
501
514
  }
502
515
 
503
- .dataviews-view-grid__card.has-no-pointer-events * {
504
- pointer-events: none;
505
- }
506
516
  .dataviews-filter-summary__popover {
507
517
  .components-popover__content {
508
518
  width: 230px;
@@ -517,56 +527,62 @@
517
527
  overflow: auto;
518
528
  border-top: 1px solid $gray-200;
519
529
 
520
- .dataviews-search-widget-filter-combobox-item {
521
- display: flex;
522
- align-items: center;
523
- gap: $grid-unit-10;
524
- border-radius: $radius-block-ui;
525
- box-sizing: border-box;
526
- padding: $grid-unit-10 $grid-unit-15;
527
- cursor: default;
528
- margin-block-end: 2px;
529
-
530
- &:last-child {
531
- margin-block-end: 0;
530
+ .dataviews-search-widget-filter-combobox-item-value {
531
+ [data-user-value] {
532
+ font-weight: 600;
532
533
  }
534
+ }
535
+ }
533
536
 
534
- &:hover,
535
- &[data-active-item],
536
- &:focus {
537
- background-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9));
538
- color: $white;
537
+ .dataviews-search-widget-listbox {
538
+ max-height: $grid-unit * 23;
539
+ padding: $grid-unit-05;
540
+ overflow: auto;
541
+ }
539
542
 
540
- .dataviews-search-widget-filter-combobox-item-check {
541
- fill: $white;
542
- }
543
+ .dataviews-search-widget-listitem {
544
+ display: flex;
545
+ align-items: center;
546
+ gap: $grid-unit-10;
547
+ border-radius: $radius-block-ui;
548
+ box-sizing: border-box;
549
+ padding: $grid-unit-10 $grid-unit-15;
550
+ cursor: default;
551
+ margin-block-end: 2px;
543
552
 
544
- .dataviews-search-widget-filter-combobox-item-description {
545
- color: $white;
546
- }
547
- }
553
+ &:last-child {
554
+ margin-block-end: 0;
555
+ }
548
556
 
549
- .dataviews-search-widget-filter-combobox-item-check {
550
- width: 24px;
551
- height: 24px;
552
- flex-shrink: 0;
553
- }
557
+ &:hover,
558
+ &[data-active-item],
559
+ &:focus {
560
+ background-color: var(--wp-admin-theme-color);
561
+ color: $white;
554
562
 
555
- .dataviews-search-widget-filter-combobox-item-value {
556
- [data-user-value] {
557
- font-weight: 600;
558
- }
563
+ .dataviews-search-widget-listitem-check {
564
+ fill: $white;
559
565
  }
560
566
 
561
- .dataviews-search-widget-filter-combobox-item-description {
562
- display: block;
563
- overflow: hidden;
564
- text-overflow: ellipsis;
565
- font-size: $helptext-font-size;
566
- line-height: 16px;
567
- color: $gray-700;
567
+ .dataviews-search-widget-listitem-description {
568
+ color: $white;
568
569
  }
569
570
  }
571
+
572
+ .dataviews-search-widget-listitem-check {
573
+ width: 24px;
574
+ height: 24px;
575
+ flex-shrink: 0;
576
+ }
577
+
578
+ .dataviews-search-widget-listitem-description {
579
+ display: block;
580
+ overflow: hidden;
581
+ text-overflow: ellipsis;
582
+ font-size: $helptext-font-size;
583
+ line-height: 16px;
584
+ color: $gray-700;
585
+ }
570
586
  }
571
587
 
572
588
  .dataviews-search-widget-filter-combobox__wrapper {
@@ -594,7 +610,7 @@
594
610
 
595
611
  &:focus {
596
612
  background: $white;
597
- box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba));
613
+ box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
598
614
  }
599
615
 
600
616
  &::placeholder {
@@ -622,8 +638,12 @@
622
638
  }
623
639
 
624
640
  .dataviews-filter-summary__operators-container {
625
- padding: $grid-unit-10 $grid-unit-10 $grid-unit-05;
626
- padding-bottom: 0;
641
+ padding: $grid-unit-10 $grid-unit-10 0;
642
+
643
+ &:has(+ .dataviews-search-widget-listbox) {
644
+ border-bottom: 1px solid $gray-200;
645
+ padding-bottom: $grid-unit-10;
646
+ }
627
647
 
628
648
  &:empty {
629
649
  display: none;
@@ -56,7 +56,7 @@ function ViewTypeMenu( { view, onChangeView, supportedLayouts } ) {
56
56
  value={ availableView.type }
57
57
  name="view-actions-available-view"
58
58
  checked={ availableView.type === view.type }
59
- hideOnClick={ true }
59
+ hideOnClick
60
60
  onChange={ ( e ) => {
61
61
  onChangeView( {
62
62
  ...view,
package/src/view-grid.js CHANGED
@@ -11,10 +11,10 @@ import {
11
11
  __experimentalHStack as HStack,
12
12
  __experimentalVStack as VStack,
13
13
  Tooltip,
14
+ Spinner,
14
15
  } from '@wordpress/components';
15
16
  import { __ } from '@wordpress/i18n';
16
17
  import { useAsyncList } from '@wordpress/compose';
17
- import { useState } from '@wordpress/element';
18
18
 
19
19
  /**
20
20
  * Internal dependencies
@@ -35,7 +35,6 @@ function GridItem( {
35
35
  primaryField,
36
36
  visibleFields,
37
37
  } ) {
38
- const [ hasNoPointerEvents, setHasNoPointerEvents ] = useState( false );
39
38
  const hasBulkAction = useHasAPossibleBulkAction( actions, item );
40
39
  const id = getItemId( item );
41
40
  const isSelected = selection.includes( id );
@@ -45,11 +44,11 @@ function GridItem( {
45
44
  key={ id }
46
45
  className={ classnames( 'dataviews-view-grid__card', {
47
46
  'is-selected': hasBulkAction && isSelected,
48
- 'has-no-pointer-events': hasNoPointerEvents,
49
47
  } ) }
50
- onMouseDown={ ( event ) => {
48
+ onClickCapture={ ( event ) => {
51
49
  if ( hasBulkAction && ( event.ctrlKey || event.metaKey ) ) {
52
- setHasNoPointerEvents( true );
50
+ event.stopPropagation();
51
+ event.preventDefault();
53
52
  if ( ! isSelected ) {
54
53
  onSelectionChange(
55
54
  data.filter( ( _item ) => {
@@ -73,11 +72,6 @@ function GridItem( {
73
72
  }
74
73
  }
75
74
  } }
76
- onClick={ () => {
77
- if ( hasNoPointerEvents ) {
78
- setHasNoPointerEvents( false );
79
- }
80
- } }
81
75
  >
82
76
  <div className="dataviews-view-grid__media">
83
77
  { mediaField?.render( { item } ) }
@@ -190,7 +184,7 @@ export default function ViewGrid( {
190
184
  'dataviews-no-results': ! isLoading,
191
185
  } ) }
192
186
  >
193
- <p>{ isLoading ? __( 'Loading…' ) : __( 'No results' ) }</p>
187
+ <p>{ isLoading ? <Spinner /> : __( 'No results' ) }</p>
194
188
  </div>
195
189
  ) }
196
190
  </>
package/src/view-list.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  __experimentalHStack as HStack,
12
12
  __experimentalVStack as VStack,
13
13
  Button,
14
+ Spinner,
14
15
  } from '@wordpress/components';
15
16
  import { ENTER, SPACE } from '@wordpress/keycodes';
16
17
  import { info } from '@wordpress/icons';
@@ -60,7 +61,7 @@ export default function ViewList( {
60
61
  } ) }
61
62
  >
62
63
  { ! hasData && (
63
- <p>{ isLoading ? __( 'Loading…' ) : __( 'No results' ) }</p>
64
+ <p>{ isLoading ? <Spinner /> : __( 'No results' ) }</p>
64
65
  ) }
65
66
  </div>
66
67
  );