@wordpress/dataviews 0.6.0 → 0.8.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 (86) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +48 -15
  3. package/build/add-filter.js +0 -2
  4. package/build/add-filter.js.map +1 -1
  5. package/build/bulk-actions.js +41 -3
  6. package/build/bulk-actions.js.map +1 -1
  7. package/build/constants.js +28 -7
  8. package/build/constants.js.map +1 -1
  9. package/build/dataviews.js +34 -21
  10. package/build/dataviews.js.map +1 -1
  11. package/build/filter-summary.js +33 -12
  12. package/build/filter-summary.js.map +1 -1
  13. package/build/filters.js +10 -2
  14. package/build/filters.js.map +1 -1
  15. package/build/item-actions.js +20 -39
  16. package/build/item-actions.js.map +1 -1
  17. package/build/pagination.js +4 -3
  18. package/build/pagination.js.map +1 -1
  19. package/build/reset-filters.js +2 -1
  20. package/build/reset-filters.js.map +1 -1
  21. package/build/search-widget.js +117 -8
  22. package/build/search-widget.js.map +1 -1
  23. package/build/single-selection-checkbox.js +7 -2
  24. package/build/single-selection-checkbox.js.map +1 -1
  25. package/build/utils.js +24 -2
  26. package/build/utils.js.map +1 -1
  27. package/build/view-actions.js.map +1 -1
  28. package/build/view-grid.js +12 -13
  29. package/build/view-grid.js.map +1 -1
  30. package/build/view-list.js +1 -1
  31. package/build/view-list.js.map +1 -1
  32. package/build/view-table.js +111 -47
  33. package/build/view-table.js.map +1 -1
  34. package/build-module/add-filter.js +0 -2
  35. package/build-module/add-filter.js.map +1 -1
  36. package/build-module/bulk-actions.js +40 -4
  37. package/build-module/bulk-actions.js.map +1 -1
  38. package/build-module/constants.js +27 -6
  39. package/build-module/constants.js.map +1 -1
  40. package/build-module/dataviews.js +35 -22
  41. package/build-module/dataviews.js.map +1 -1
  42. package/build-module/filter-summary.js +34 -13
  43. package/build-module/filter-summary.js.map +1 -1
  44. package/build-module/filters.js +11 -3
  45. package/build-module/filters.js.map +1 -1
  46. package/build-module/item-actions.js +20 -39
  47. package/build-module/item-actions.js.map +1 -1
  48. package/build-module/pagination.js +4 -3
  49. package/build-module/pagination.js.map +1 -1
  50. package/build-module/reset-filters.js +2 -1
  51. package/build-module/reset-filters.js.map +1 -1
  52. package/build-module/search-widget.js +120 -11
  53. package/build-module/search-widget.js.map +1 -1
  54. package/build-module/single-selection-checkbox.js +7 -2
  55. package/build-module/single-selection-checkbox.js.map +1 -1
  56. package/build-module/utils.js +25 -3
  57. package/build-module/utils.js.map +1 -1
  58. package/build-module/view-actions.js.map +1 -1
  59. package/build-module/view-grid.js +13 -14
  60. package/build-module/view-grid.js.map +1 -1
  61. package/build-module/view-list.js +2 -2
  62. package/build-module/view-list.js.map +1 -1
  63. package/build-module/view-table.js +113 -49
  64. package/build-module/view-table.js.map +1 -1
  65. package/build-style/style-rtl.css +76 -46
  66. package/build-style/style.css +76 -46
  67. package/package.json +11 -11
  68. package/src/add-filter.js +0 -2
  69. package/src/bulk-actions.js +54 -4
  70. package/src/constants.js +35 -6
  71. package/src/dataviews.js +66 -49
  72. package/src/filter-summary.js +76 -23
  73. package/src/filters.js +16 -5
  74. package/src/item-actions.js +19 -55
  75. package/src/pagination.js +8 -3
  76. package/src/reset-filters.js +2 -1
  77. package/src/search-widget.js +182 -15
  78. package/src/single-selection-checkbox.js +7 -1
  79. package/src/stories/fixtures.js +12 -1
  80. package/src/stories/index.story.js +43 -4
  81. package/src/style.scss +108 -73
  82. package/src/utils.js +38 -4
  83. package/src/view-actions.js +1 -1
  84. package/src/view-grid.js +13 -12
  85. package/src/view-list.js +2 -1
  86. package/src/view-table.js +162 -81
package/src/style.scss CHANGED
@@ -1,20 +1,19 @@
1
1
  .dataviews-wrapper {
2
- width: 100%;
3
2
  height: 100%;
4
3
  overflow: auto;
5
4
  box-sizing: border-box;
6
5
  scroll-padding-bottom: $grid-unit-80;
7
-
8
- > div {
9
- min-height: 100%;
10
- }
11
6
  }
12
7
 
13
8
  .dataviews-filters__view-actions {
9
+ box-sizing: border-box;
14
10
  padding: $grid-unit-15 $grid-unit-40 0;
15
- .components-search-control {
16
- flex-grow: 1;
11
+ margin-bottom: $grid-unit-15;
12
+ flex-shrink: 0;
13
+ position: sticky;
14
+ left: 0;
17
15
 
16
+ .components-search-control {
18
17
  .components-base-control__field {
19
18
  max-width: 240px;
20
19
  }
@@ -22,11 +21,18 @@
22
21
  }
23
22
 
24
23
  .dataviews-filters__container {
25
- padding: 0 $grid-unit-40;
26
- }
24
+ padding-right: $grid-unit-40;
27
25
 
28
- .dataviews-filters__view-actions.components-h-stack {
29
- align-items: center;
26
+ .dataviews-filters__reset-button[aria-disabled="true"] {
27
+ &,
28
+ &:hover {
29
+ opacity: 0;
30
+ }
31
+
32
+ &:focus {
33
+ opacity: 1;
34
+ }
35
+ }
30
36
  }
31
37
 
32
38
  .dataviews-filters-button {
@@ -34,22 +40,25 @@
34
40
  }
35
41
 
36
42
  .dataviews-pagination {
37
- margin-top: auto;
38
43
  position: sticky;
39
44
  bottom: 0;
40
- background-color: rgba($white, 0.8);
41
- backdrop-filter: blur(6px);
45
+ left: 0;
46
+ background-color: $white;
42
47
  padding: $grid-unit-15 $grid-unit-40;
43
48
  border-top: $border-width solid $gray-100;
44
49
  color: $gray-700;
50
+ flex-shrink: 0;
45
51
  }
46
52
 
47
- .dataviews-filters-options {
48
- margin: $grid-unit-40 0 $grid-unit-20;
53
+ .dataviews-pagination__page-selection {
54
+ font-size: 11px;
55
+ text-transform: uppercase;
56
+ font-weight: 500;
57
+ color: $gray-900;
49
58
  }
50
59
 
51
- .dataviews-view-table-wrapper {
52
- overflow-x: auto;
60
+ .dataviews-filters-options {
61
+ margin: $grid-unit-40 0 $grid-unit-20;
53
62
  }
54
63
 
55
64
  .dataviews-view-table {
@@ -114,11 +123,11 @@
114
123
  border-bottom: 0;
115
124
  }
116
125
 
117
- &:hover {
126
+ &.is-hovered {
118
127
  background-color: #f8f8f8;
119
128
  }
120
129
 
121
- .components-checkbox-control__input {
130
+ .components-checkbox-control__input.components-checkbox-control__input {
122
131
  opacity: 0;
123
132
 
124
133
  &:checked,
@@ -128,9 +137,15 @@
128
137
  }
129
138
  }
130
139
 
140
+ .dataviews-item-actions .components-button:not(.dataviews-all-actions-button) {
141
+ opacity: 0;
142
+ }
143
+
131
144
  &:focus-within,
145
+ &.is-hovered,
132
146
  &:hover {
133
- .components-checkbox-control__input {
147
+ .components-checkbox-control__input,
148
+ .dataviews-item-actions .components-button:not(.dataviews-all-actions-button) {
134
149
  opacity: 1;
135
150
  }
136
151
  }
@@ -145,17 +160,18 @@
145
160
  }
146
161
  }
147
162
  thead {
163
+ position: sticky;
164
+ inset-block-start: 0;
165
+ z-index: z-index(".dataviews-view-table thead");
166
+
148
167
  tr {
149
168
  border: 0;
150
169
  }
151
170
  th {
152
- position: sticky;
153
- top: -1px;
154
171
  background-color: $white;
155
172
  box-shadow: inset 0 -#{$border-width} 0 $gray-100;
156
173
  padding-top: $grid-unit-10;
157
174
  padding-bottom: $grid-unit-10;
158
- z-index: 1;
159
175
  font-size: 11px;
160
176
  text-transform: uppercase;
161
177
  font-weight: 500;
@@ -202,6 +218,12 @@
202
218
  .dataviews-view-table__actions-column {
203
219
  width: 1%;
204
220
  }
221
+
222
+ &:has(tr.is-selected) {
223
+ .components-checkbox-control__input {
224
+ opacity: 1;
225
+ }
226
+ }
205
227
  }
206
228
 
207
229
  .dataviews-view-list__primary-field,
@@ -212,7 +234,6 @@
212
234
  color: $gray-900;
213
235
  text-overflow: ellipsis;
214
236
  white-space: nowrap;
215
- overflow: hidden;
216
237
  display: block;
217
238
  width: 100%;
218
239
 
@@ -228,6 +249,7 @@
228
249
  &:hover {
229
250
  color: $gray-900;
230
251
  }
252
+ @include link-reset();
231
253
  }
232
254
 
233
255
  button.components-button.is-link {
@@ -466,6 +488,10 @@
466
488
  .dataviews-no-results,
467
489
  .dataviews-loading {
468
490
  padding: 0 $grid-unit-40;
491
+ flex-grow: 1;
492
+ display: flex;
493
+ align-items: center;
494
+ justify-content: center;
469
495
  }
470
496
 
471
497
  .dataviews-view-table-selection-checkbox label {
@@ -493,9 +519,6 @@
493
519
  margin-left: $grid-unit-10;
494
520
  }
495
521
 
496
- .dataviews-view-grid__card.has-no-pointer-events * {
497
- pointer-events: none;
498
- }
499
522
  .dataviews-filter-summary__popover {
500
523
  .components-popover__content {
501
524
  width: 230px;
@@ -510,56 +533,62 @@
510
533
  overflow: auto;
511
534
  border-top: 1px solid $gray-200;
512
535
 
513
- .dataviews-search-widget-filter-combobox-item {
514
- display: flex;
515
- align-items: center;
516
- gap: $grid-unit-10;
517
- border-radius: $radius-block-ui;
518
- box-sizing: border-box;
519
- padding: $grid-unit-10 $grid-unit-15;
520
- cursor: default;
521
- margin-block-end: 2px;
522
-
523
- &:last-child {
524
- margin-block-end: 0;
536
+ .dataviews-search-widget-filter-combobox-item-value {
537
+ [data-user-value] {
538
+ font-weight: 600;
525
539
  }
540
+ }
541
+ }
526
542
 
527
- &:hover,
528
- &[data-active-item],
529
- &:focus {
530
- background-color: var(--wp-admin-theme-color);
531
- color: $white;
543
+ .dataviews-search-widget-listbox {
544
+ max-height: $grid-unit * 23;
545
+ padding: $grid-unit-05;
546
+ overflow: auto;
547
+ }
532
548
 
533
- .dataviews-search-widget-filter-combobox-item-check {
534
- fill: $white;
535
- }
549
+ .dataviews-search-widget-listitem {
550
+ display: flex;
551
+ align-items: center;
552
+ gap: $grid-unit-10;
553
+ border-radius: $radius-block-ui;
554
+ box-sizing: border-box;
555
+ padding: $grid-unit-10 $grid-unit-15;
556
+ cursor: default;
557
+ margin-block-end: 2px;
536
558
 
537
- .dataviews-search-widget-filter-combobox-item-description {
538
- color: $white;
539
- }
540
- }
559
+ &:last-child {
560
+ margin-block-end: 0;
561
+ }
541
562
 
542
- .dataviews-search-widget-filter-combobox-item-check {
543
- width: 24px;
544
- height: 24px;
545
- flex-shrink: 0;
546
- }
563
+ &:hover,
564
+ &[data-active-item],
565
+ &:focus {
566
+ background-color: var(--wp-admin-theme-color);
567
+ color: $white;
547
568
 
548
- .dataviews-search-widget-filter-combobox-item-value {
549
- [data-user-value] {
550
- font-weight: 600;
551
- }
569
+ .dataviews-search-widget-listitem-check {
570
+ fill: $white;
552
571
  }
553
572
 
554
- .dataviews-search-widget-filter-combobox-item-description {
555
- display: block;
556
- overflow: hidden;
557
- text-overflow: ellipsis;
558
- font-size: $helptext-font-size;
559
- line-height: 16px;
560
- color: $gray-700;
573
+ .dataviews-search-widget-listitem-description {
574
+ color: $white;
561
575
  }
562
576
  }
577
+
578
+ .dataviews-search-widget-listitem-check {
579
+ width: 24px;
580
+ height: 24px;
581
+ flex-shrink: 0;
582
+ }
583
+
584
+ .dataviews-search-widget-listitem-description {
585
+ display: block;
586
+ overflow: hidden;
587
+ text-overflow: ellipsis;
588
+ font-size: $helptext-font-size;
589
+ line-height: 16px;
590
+ color: $gray-700;
591
+ }
563
592
  }
564
593
 
565
594
  .dataviews-search-widget-filter-combobox__wrapper {
@@ -615,8 +644,12 @@
615
644
  }
616
645
 
617
646
  .dataviews-filter-summary__operators-container {
618
- padding: $grid-unit-10 $grid-unit-10 $grid-unit-05;
619
- padding-bottom: 0;
647
+ padding: $grid-unit-10 $grid-unit-10 0;
648
+
649
+ &:has(+ .dataviews-search-widget-listbox) {
650
+ border-bottom: 1px solid $gray-200;
651
+ padding-bottom: $grid-unit-10;
652
+ }
620
653
 
621
654
  &:empty {
622
655
  display: none;
@@ -648,7 +681,8 @@
648
681
  }
649
682
 
650
683
  &:hover,
651
- &:focus-visible {
684
+ &:focus-visible,
685
+ &[aria-expanded="true"] {
652
686
  background: $gray-200;
653
687
  color: $gray-900;
654
688
  }
@@ -657,8 +691,9 @@
657
691
  color: var(--wp-admin-theme-color);
658
692
  background: rgba(var(--wp-admin-theme-color--rgb), 0.04);
659
693
 
660
- &:hover {
661
- background: rgba(var(--wp-admin-theme-color--rgb), 0.08);
694
+ &:hover,
695
+ &[aria-expanded="true"] {
696
+ background: rgba(var(--wp-admin-theme-color--rgb), 0.12);
662
697
  }
663
698
  }
664
699
 
package/src/utils.js CHANGED
@@ -1,7 +1,13 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { OPERATORS } from './constants';
4
+ import {
5
+ ALL_OPERATORS,
6
+ OPERATOR_IS,
7
+ OPERATOR_IS_NOT,
8
+ OPERATOR_IS_ANY,
9
+ OPERATOR_IS_NONE,
10
+ } from './constants';
5
11
 
6
12
  /**
7
13
  * Helper util to sort data by text fields, when sorting is done client side.
@@ -57,10 +63,38 @@ export function getPaginationResults( { data, view } ) {
57
63
 
58
64
  export const sanitizeOperators = ( field ) => {
59
65
  let operators = field.filterBy?.operators;
66
+
67
+ // Assign default values.
60
68
  if ( ! operators || ! Array.isArray( operators ) ) {
61
- operators = Object.keys( OPERATORS );
69
+ operators = [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ];
70
+ }
71
+
72
+ // Transform legacy in, notIn operators to is, isNot.
73
+ // To be removed in the future.
74
+ if ( operators.includes( 'in' ) ) {
75
+ operators = operators.filter( ( operator ) => operator !== 'is' );
76
+ operators.push( 'is' );
77
+ }
78
+ if ( operators.includes( 'notIn' ) ) {
79
+ operators = operators.filter( ( operator ) => operator !== 'notIn' );
80
+ operators.push( 'isNot' );
62
81
  }
63
- return operators.filter( ( operator ) =>
64
- Object.keys( OPERATORS ).includes( operator )
82
+
83
+ // Make sure only valid operators are used.
84
+ operators = operators.filter( ( operator ) =>
85
+ ALL_OPERATORS.includes( operator )
65
86
  );
87
+
88
+ // Do not allow mixing single & multiselection operators.
89
+ // Remove multiselection operators if any of the single selection ones is present.
90
+ if (
91
+ operators.includes( OPERATOR_IS ) ||
92
+ operators.includes( OPERATOR_IS_NOT )
93
+ ) {
94
+ operators = operators.filter( ( operator ) =>
95
+ [ OPERATOR_IS, OPERATOR_IS_NOT ].includes( operator )
96
+ );
97
+ }
98
+
99
+ return operators;
66
100
  };
@@ -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
@@ -22,6 +22,8 @@ import { useState } from '@wordpress/element';
22
22
  import ItemActions from './item-actions';
23
23
  import SingleSelectionCheckbox from './single-selection-checkbox';
24
24
 
25
+ import { useHasAPossibleBulkAction } from './bulk-actions';
26
+
25
27
  function GridItem( {
26
28
  selection,
27
29
  data,
@@ -33,7 +35,7 @@ function GridItem( {
33
35
  primaryField,
34
36
  visibleFields,
35
37
  } ) {
36
- const [ hasNoPointerEvents, setHasNoPointerEvents ] = useState( false );
38
+ const hasBulkAction = useHasAPossibleBulkAction( actions, item );
37
39
  const id = getItemId( item );
38
40
  const isSelected = selection.includes( id );
39
41
  return (
@@ -41,12 +43,15 @@ function GridItem( {
41
43
  spacing={ 0 }
42
44
  key={ id }
43
45
  className={ classnames( 'dataviews-view-grid__card', {
44
- 'is-selected': isSelected,
45
- 'has-no-pointer-events': hasNoPointerEvents,
46
+ 'is-selected': hasBulkAction && isSelected,
46
47
  } ) }
47
- onMouseDown={ ( event ) => {
48
+ onClickCapture={ ( event ) => {
48
49
  if ( event.ctrlKey || event.metaKey ) {
49
- setHasNoPointerEvents( true );
50
+ event.stopPropagation();
51
+ event.preventDefault();
52
+ if ( ! hasBulkAction ) {
53
+ return;
54
+ }
50
55
  if ( ! isSelected ) {
51
56
  onSelectionChange(
52
57
  data.filter( ( _item ) => {
@@ -70,11 +75,6 @@ function GridItem( {
70
75
  }
71
76
  }
72
77
  } }
73
- onClick={ () => {
74
- if ( hasNoPointerEvents ) {
75
- setHasNoPointerEvents( false );
76
- }
77
- } }
78
78
  >
79
79
  <div className="dataviews-view-grid__media">
80
80
  { mediaField?.render( { item } ) }
@@ -91,6 +91,7 @@ function GridItem( {
91
91
  getItemId={ getItemId }
92
92
  data={ data }
93
93
  primaryField={ primaryField }
94
+ disabled={ ! hasBulkAction }
94
95
  />
95
96
  <HStack className="dataviews-view-grid__primary-field">
96
97
  { primaryField?.render( { item } ) }
@@ -186,7 +187,7 @@ export default function ViewGrid( {
186
187
  'dataviews-no-results': ! isLoading,
187
188
  } ) }
188
189
  >
189
- <p>{ isLoading ? __( 'Loading…' ) : __( 'No results' ) }</p>
190
+ <p>{ isLoading ? <Spinner /> : __( 'No results' ) }</p>
190
191
  </div>
191
192
  ) }
192
193
  </>
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
  );