@wordpress/dataviews 4.2.0 → 4.3.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 (123) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +47 -7
  3. package/build/components/dataviews/index.js +3 -5
  4. package/build/components/dataviews/index.js.map +1 -1
  5. package/build/components/dataviews-bulk-actions/index.js +145 -141
  6. package/build/components/dataviews-bulk-actions/index.js.map +1 -1
  7. package/build/components/dataviews-filters/add-filter.js +4 -6
  8. package/build/components/dataviews-filters/add-filter.js.map +1 -1
  9. package/build/components/dataviews-filters/search-widget.js +28 -18
  10. package/build/components/dataviews-filters/search-widget.js.map +1 -1
  11. package/build/components/dataviews-footer/index.js +45 -0
  12. package/build/components/dataviews-footer/index.js.map +1 -0
  13. package/build/components/dataviews-item-actions/index.js +5 -8
  14. package/build/components/dataviews-item-actions/index.js.map +1 -1
  15. package/build/components/dataviews-pagination/index.js +4 -4
  16. package/build/components/dataviews-pagination/index.js.map +1 -1
  17. package/build/components/dataviews-view-config/index.js +171 -32
  18. package/build/components/dataviews-view-config/index.js.map +1 -1
  19. package/build/dataforms-layouts/panel/index.js +4 -1
  20. package/build/dataforms-layouts/panel/index.js.map +1 -1
  21. package/build/dataviews-layouts/index.js +48 -2
  22. package/build/dataviews-layouts/index.js.map +1 -1
  23. package/build/dataviews-layouts/list/index.js +124 -84
  24. package/build/dataviews-layouts/list/index.js.map +1 -1
  25. package/build/dataviews-layouts/table/column-header-menu.js +52 -54
  26. package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
  27. package/build/dataviews-layouts/table/index.js +7 -35
  28. package/build/dataviews-layouts/table/index.js.map +1 -1
  29. package/build/normalize-fields.js +4 -2
  30. package/build/normalize-fields.js.map +1 -1
  31. package/build/types.js.map +1 -1
  32. package/build-module/components/dataviews/index.js +3 -5
  33. package/build-module/components/dataviews/index.js.map +1 -1
  34. package/build-module/components/dataviews-bulk-actions/index.js +145 -143
  35. package/build-module/components/dataviews-bulk-actions/index.js.map +1 -1
  36. package/build-module/components/dataviews-filters/add-filter.js +4 -6
  37. package/build-module/components/dataviews-filters/add-filter.js.map +1 -1
  38. package/build-module/components/dataviews-filters/search-widget.js +28 -18
  39. package/build-module/components/dataviews-filters/search-widget.js.map +1 -1
  40. package/build-module/components/dataviews-footer/index.js +38 -0
  41. package/build-module/components/dataviews-footer/index.js.map +1 -0
  42. package/build-module/components/dataviews-item-actions/index.js +5 -8
  43. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  44. package/build-module/components/dataviews-pagination/index.js +5 -5
  45. package/build-module/components/dataviews-pagination/index.js.map +1 -1
  46. package/build-module/components/dataviews-view-config/index.js +177 -38
  47. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  48. package/build-module/dataforms-layouts/panel/index.js +4 -1
  49. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  50. package/build-module/dataviews-layouts/index.js +45 -1
  51. package/build-module/dataviews-layouts/index.js.map +1 -1
  52. package/build-module/dataviews-layouts/list/index.js +125 -83
  53. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  54. package/build-module/dataviews-layouts/table/column-header-menu.js +52 -54
  55. package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
  56. package/build-module/dataviews-layouts/table/index.js +9 -37
  57. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  58. package/build-module/normalize-fields.js +4 -2
  59. package/build-module/normalize-fields.js.map +1 -1
  60. package/build-module/types.js.map +1 -1
  61. package/build-style/style-rtl.css +79 -63
  62. package/build-style/style.css +79 -63
  63. package/build-types/components/dataviews/index.d.ts.map +1 -1
  64. package/build-types/components/dataviews/stories/fixtures.d.ts +27 -131
  65. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  66. package/build-types/components/dataviews/stories/index.story.d.ts +12 -53
  67. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  68. package/build-types/components/dataviews-bulk-actions/index.d.ts +11 -1
  69. package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
  70. package/build-types/components/dataviews-filters/add-filter.d.ts.map +1 -1
  71. package/build-types/components/dataviews-filters/search-widget.d.ts.map +1 -1
  72. package/build-types/components/dataviews-footer/index.d.ts +2 -0
  73. package/build-types/components/dataviews-footer/index.d.ts.map +1 -0
  74. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  75. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  76. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  77. package/build-types/dataviews-layouts/index.d.ts +4 -2
  78. package/build-types/dataviews-layouts/index.d.ts.map +1 -1
  79. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  80. package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
  81. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  82. package/build-types/normalize-fields.d.ts.map +1 -1
  83. package/build-types/types.d.ts +2 -0
  84. package/build-types/types.d.ts.map +1 -1
  85. package/package.json +11 -11
  86. package/src/components/dataviews/index.tsx +2 -6
  87. package/src/components/dataviews/stories/fixtures.tsx +690 -0
  88. package/src/components/dataviews/stories/index.story.tsx +164 -0
  89. package/src/components/dataviews/style.scss +2 -0
  90. package/src/components/dataviews-bulk-actions/index.tsx +264 -213
  91. package/src/components/dataviews-bulk-actions/style.scss +9 -4
  92. package/src/components/dataviews-filters/add-filter.tsx +7 -11
  93. package/src/components/dataviews-filters/search-widget.tsx +45 -17
  94. package/src/components/dataviews-filters/style.scss +12 -2
  95. package/src/components/dataviews-footer/index.tsx +50 -0
  96. package/src/components/dataviews-footer/style.scss +40 -0
  97. package/src/components/dataviews-item-actions/index.tsx +8 -14
  98. package/src/components/dataviews-pagination/index.tsx +5 -5
  99. package/src/components/dataviews-pagination/style.scss +0 -19
  100. package/src/components/dataviews-view-config/index.tsx +252 -53
  101. package/src/components/dataviews-view-config/style.scss +25 -0
  102. package/src/dataforms-layouts/panel/index.tsx +2 -0
  103. package/src/dataviews-layouts/grid/style.scss +1 -1
  104. package/src/dataviews-layouts/index.ts +63 -2
  105. package/src/dataviews-layouts/list/index.tsx +199 -127
  106. package/src/dataviews-layouts/list/style.scss +10 -4
  107. package/src/dataviews-layouts/table/column-header-menu.tsx +85 -87
  108. package/src/dataviews-layouts/table/index.tsx +8 -65
  109. package/src/dataviews-layouts/table/style.scss +0 -5
  110. package/src/normalize-fields.ts +2 -0
  111. package/src/style.scss +1 -1
  112. package/src/types.ts +2 -0
  113. package/tsconfig.tsbuildinfo +1 -1
  114. package/build/components/dataviews-bulk-actions-toolbar/index.js +0 -207
  115. package/build/components/dataviews-bulk-actions-toolbar/index.js.map +0 -1
  116. package/build-module/components/dataviews-bulk-actions-toolbar/index.js +0 -201
  117. package/build-module/components/dataviews-bulk-actions-toolbar/index.js.map +0 -1
  118. package/build-types/components/dataviews-bulk-actions-toolbar/index.d.ts +0 -2
  119. package/build-types/components/dataviews-bulk-actions-toolbar/index.d.ts.map +0 -1
  120. package/src/components/dataviews/stories/fixtures.js +0 -250
  121. package/src/components/dataviews/stories/index.story.js +0 -71
  122. package/src/components/dataviews-bulk-actions-toolbar/index.tsx +0 -288
  123. package/src/components/dataviews-bulk-actions-toolbar/style.scss +0 -45
@@ -8,6 +8,7 @@ import removeAccents from 'remove-accents';
8
8
  /**
9
9
  * WordPress dependencies
10
10
  */
11
+ import { useInstanceId } from '@wordpress/compose';
11
12
  import { __, sprintf } from '@wordpress/i18n';
12
13
  import { useState, useMemo, useDeferredValue } from '@wordpress/element';
13
14
  import {
@@ -27,7 +28,8 @@ import type { Filter, NormalizedFilter, View } from '../../types';
27
28
  const {
28
29
  CompositeV2: Composite,
29
30
  CompositeItemV2: CompositeItem,
30
- useCompositeStoreV2: useCompositeStore,
31
+ CompositeHoverV2: CompositeHover,
32
+ CompositeTypeaheadV2: CompositeTypeahead,
31
33
  } = unlock( componentsPrivateApis );
32
34
 
33
35
  interface SearchWidgetProps {
@@ -84,22 +86,37 @@ const getNewValue = (
84
86
  return [ value ];
85
87
  };
86
88
 
89
+ function generateFilterElementCompositeItemId(
90
+ prefix: string,
91
+ filterElementValue: string
92
+ ) {
93
+ return `${ prefix }-${ filterElementValue }`;
94
+ }
95
+
87
96
  function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
88
- const compositeStore = useCompositeStore( {
89
- virtualFocus: true,
90
- focusLoop: true,
91
- // When we have no or just one operator, we can set the first item as active.
92
- // We do that by passing `undefined` to `defaultActiveId`. Otherwise, we set it to `null`,
93
- // so the first item is not selected, since the focus is on the operators control.
94
- defaultActiveId: filter.operators?.length === 1 ? undefined : null,
95
- } );
97
+ const baseId = useInstanceId( ListBox, 'dataviews-filter-list-box' );
98
+
99
+ const [ activeCompositeId, setActiveCompositeId ] = useState<
100
+ string | null | undefined
101
+ >(
102
+ // When there are one or less operators, the first item is set as active
103
+ // (by setting the initial `activeId` to `undefined`).
104
+ // With 2 or more operators, the focus is moved on the operators control
105
+ // (by setting the initial `activeId` to `null`), meaning that there won't
106
+ // be an active item initially. Focus is then managed via the
107
+ // `onFocusVisible` callback.
108
+ filter.operators?.length === 1 ? undefined : null
109
+ );
96
110
  const currentFilter = view.filters?.find(
97
111
  ( f ) => f.field === filter.field
98
112
  );
99
113
  const currentValue = getCurrentValue( filter, currentFilter );
100
114
  return (
101
115
  <Composite
102
- store={ compositeStore }
116
+ virtualFocus
117
+ focusLoop
118
+ activeId={ activeCompositeId }
119
+ setActiveId={ setActiveCompositeId }
103
120
  role="listbox"
104
121
  className="dataviews-filters__search-widget-listbox"
105
122
  aria-label={ sprintf(
@@ -108,18 +125,29 @@ function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
108
125
  filter.name
109
126
  ) }
110
127
  onFocusVisible={ () => {
111
- if ( ! compositeStore.getState().activeId ) {
112
- compositeStore.move( compositeStore.first() );
128
+ // `onFocusVisible` needs the `Composite` component to be focusable,
129
+ // which is implicitly achieved via the `virtualFocus: true` option
130
+ // in the `useCompositeStore` hook.
131
+ if ( ! activeCompositeId && filter.elements.length ) {
132
+ setActiveCompositeId(
133
+ generateFilterElementCompositeItemId(
134
+ baseId,
135
+ filter.elements[ 0 ].value
136
+ )
137
+ );
113
138
  }
114
139
  } }
115
- render={ <Ariakit.CompositeTypeahead store={ compositeStore } /> }
140
+ render={ <CompositeTypeahead /> }
116
141
  >
117
142
  { filter.elements.map( ( element ) => (
118
- <Ariakit.CompositeHover
119
- store={ compositeStore }
143
+ <CompositeHover
120
144
  key={ element.value }
121
145
  render={
122
146
  <CompositeItem
147
+ id={ generateFilterElementCompositeItemId(
148
+ baseId,
149
+ element.value
150
+ ) }
123
151
  render={
124
152
  <div
125
153
  aria-label={ element.label }
@@ -185,7 +213,7 @@ function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
185
213
  ) }
186
214
  </span>
187
215
  <span>{ element.label }</span>
188
- </Ariakit.CompositeHover>
216
+ </CompositeHover>
189
217
  ) ) }
190
218
  </Composite>
191
219
  );
@@ -206,7 +234,6 @@ function ComboboxList( { view, filter, onChangeView }: SearchWidgetProps ) {
206
234
  }, [ filter.elements, deferredSearchValue ] );
207
235
  return (
208
236
  <Ariakit.ComboboxProvider
209
- resetValueOnSelect={ false }
210
237
  selectedValue={ currentValue }
211
238
  setSelectedValue={ ( value ) => {
212
239
  const newFilters = currentFilter
@@ -266,6 +293,7 @@ function ComboboxList( { view, filter, onChangeView }: SearchWidgetProps ) {
266
293
  { matches.map( ( element ) => {
267
294
  return (
268
295
  <Ariakit.ComboboxItem
296
+ resetValueOnSelect={ false }
269
297
  key={ element.value }
270
298
  value={ element.value }
271
299
  className="dataviews-filters__search-widget-listitem"
@@ -18,11 +18,19 @@
18
18
  }
19
19
 
20
20
  .dataviews-filters__summary-popover {
21
+ font-size: $default-font-size;
22
+ line-height: $default-line-height;
23
+
21
24
  .components-popover__content {
22
25
  width: 230px;
23
- padding: 0;
24
26
  border-radius: $grid-unit-05;
25
27
  }
28
+
29
+ &.components-dropdown__content {
30
+ .components-popover__content {
31
+ padding: 0;
32
+ }
33
+ }
26
34
  }
27
35
 
28
36
  .dataviews-filters__summary-operators-container {
@@ -57,6 +65,7 @@
57
65
  position: relative;
58
66
  display: flex;
59
67
  align-items: center;
68
+ box-sizing: border-box;
60
69
 
61
70
  &.has-reset {
62
71
  padding-inline-end: $button-size-small + $grid-unit-05;
@@ -160,7 +169,7 @@
160
169
  display: flex;
161
170
  align-items: center;
162
171
  gap: $grid-unit-10;
163
- border-radius: $radius-block-ui;
172
+ border-radius: $radius-small;
164
173
  box-sizing: border-box;
165
174
  padding: $grid-unit-10 $grid-unit-15;
166
175
  cursor: default;
@@ -275,6 +284,7 @@
275
284
  font-size: 11px;
276
285
  outline: var(--wp-admin-border-width-focus) solid $white;
277
286
  color: $white;
287
+ box-sizing: border-box;
278
288
  }
279
289
 
280
290
  .dataviews-search {
@@ -0,0 +1,50 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __experimentalHStack as HStack } from '@wordpress/components';
5
+ import { useContext } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import DataViewsContext from '../dataviews-context';
11
+ import DataViewsPagination from '../dataviews-pagination';
12
+ import {
13
+ BulkActionsFooter,
14
+ useSomeItemHasAPossibleBulkAction,
15
+ } from '../dataviews-bulk-actions';
16
+ import { LAYOUT_GRID, LAYOUT_TABLE } from '../../constants';
17
+
18
+ const EMPTY_ARRAY: [] = [];
19
+
20
+ export default function DataViewsFooter() {
21
+ const {
22
+ view,
23
+ paginationInfo: { totalItems = 0, totalPages },
24
+ data,
25
+ actions = EMPTY_ARRAY,
26
+ } = useContext( DataViewsContext );
27
+ const hasBulkActions =
28
+ useSomeItemHasAPossibleBulkAction( actions, data ) &&
29
+ [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type );
30
+
31
+ if (
32
+ ! totalItems ||
33
+ ! totalPages ||
34
+ ( totalPages <= 1 && ! hasBulkActions )
35
+ ) {
36
+ return null;
37
+ }
38
+ return (
39
+ !! totalItems && (
40
+ <HStack
41
+ expanded={ false }
42
+ justify="end"
43
+ className="dataviews-footer"
44
+ >
45
+ { hasBulkActions && <BulkActionsFooter /> }
46
+ <DataViewsPagination />
47
+ </HStack>
48
+ )
49
+ );
50
+ }
@@ -0,0 +1,40 @@
1
+ .dataviews-footer {
2
+ position: sticky;
3
+ bottom: 0;
4
+ left: 0;
5
+ background-color: $white;
6
+ padding: $grid-unit-15 $grid-unit-60;
7
+ border-top: $border-width solid $gray-100;
8
+ flex-shrink: 0;
9
+ transition: padding ease-out 0.1s;
10
+ @include reduce-motion("transition");
11
+ z-index: z-index(".dataviews-footer");
12
+ }
13
+
14
+
15
+ /* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
16
+ @container (max-width: 430px) {
17
+ .dataviews-footer {
18
+ padding: $grid-unit-15 $grid-unit-30;
19
+ }
20
+ }
21
+
22
+ /* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
23
+ @container (max-width: 560px) {
24
+ .dataviews-footer {
25
+ flex-direction: column !important;
26
+
27
+ .dataviews-bulk-actions-footer__container {
28
+ width: 100%;
29
+ }
30
+
31
+ .dataviews-bulk-actions-footer__item-count {
32
+ flex-grow: 1;
33
+ }
34
+
35
+ .dataviews-pagination {
36
+ width: 100%;
37
+ justify-content: space-between;
38
+ }
39
+ }
40
+ }
@@ -23,13 +23,7 @@ import { useRegistry } from '@wordpress/data';
23
23
  import { unlock } from '../../lock-unlock';
24
24
  import type { Action, ActionModal as ActionModalType } from '../../types';
25
25
 
26
- const {
27
- DropdownMenuV2: DropdownMenu,
28
- DropdownMenuGroupV2: DropdownMenuGroup,
29
- DropdownMenuItemV2: DropdownMenuItem,
30
- DropdownMenuItemLabelV2: DropdownMenuItemLabel,
31
- kebabCase,
32
- } = unlock( componentsPrivateApis );
26
+ const { DropdownMenuV2, kebabCase } = unlock( componentsPrivateApis );
33
27
 
34
28
  export interface ActionTriggerProps< Item > {
35
29
  action: Action< Item >;
@@ -91,12 +85,12 @@ function DropdownMenuItemTrigger< Item >( {
91
85
  const label =
92
86
  typeof action.label === 'string' ? action.label : action.label( items );
93
87
  return (
94
- <DropdownMenuItem
88
+ <DropdownMenuV2.Item
95
89
  onClick={ onClick }
96
90
  hideOnClick={ ! ( 'RenderModal' in action ) }
97
91
  >
98
- <DropdownMenuItemLabel>{ label }</DropdownMenuItemLabel>
99
- </DropdownMenuItem>
92
+ <DropdownMenuV2.ItemLabel>{ label }</DropdownMenuV2.ItemLabel>
93
+ </DropdownMenuV2.Item>
100
94
  );
101
95
  }
102
96
 
@@ -158,7 +152,7 @@ export function ActionsDropdownMenuGroup< Item >( {
158
152
  }: ActionsDropdownMenuGroupProps< Item > ) {
159
153
  const registry = useRegistry();
160
154
  return (
161
- <DropdownMenuGroup>
155
+ <DropdownMenuV2.Group>
162
156
  { actions.map( ( action ) => {
163
157
  if ( 'RenderModal' in action ) {
164
158
  return (
@@ -181,7 +175,7 @@ export function ActionsDropdownMenuGroup< Item >( {
181
175
  />
182
176
  );
183
177
  } ) }
184
- </DropdownMenuGroup>
178
+ </DropdownMenuV2.Group>
185
179
  );
186
180
  }
187
181
 
@@ -251,7 +245,7 @@ function CompactItemActions< Item >( {
251
245
  actions,
252
246
  }: CompactItemActionsProps< Item > ) {
253
247
  return (
254
- <DropdownMenu
248
+ <DropdownMenuV2
255
249
  trigger={
256
250
  <Button
257
251
  size="compact"
@@ -265,6 +259,6 @@ function CompactItemActions< Item >( {
265
259
  placement="bottom-end"
266
260
  >
267
261
  <ActionsDropdownMenuGroup actions={ actions } item={ item } />
268
- </DropdownMenu>
262
+ </DropdownMenuV2>
269
263
  );
270
264
  }
@@ -7,7 +7,7 @@ import {
7
7
  SelectControl,
8
8
  } from '@wordpress/components';
9
9
  import { createInterpolateElement, memo, useContext } from '@wordpress/element';
10
- import { sprintf, __, _x } from '@wordpress/i18n';
10
+ import { sprintf, __, _x, isRTL } from '@wordpress/i18n';
11
11
  import { next, previous } from '@wordpress/icons';
12
12
 
13
13
  /**
@@ -51,9 +51,9 @@ function DataViewsPagination() {
51
51
  totalPages !== 1 && (
52
52
  <HStack
53
53
  expanded={ false }
54
- spacing={ 6 }
55
- justify="end"
56
54
  className="dataviews-pagination"
55
+ justify="end"
56
+ spacing={ 6 }
57
57
  >
58
58
  <HStack
59
59
  justify="flex-start"
@@ -103,7 +103,7 @@ function DataViewsPagination() {
103
103
  disabled={ currentPage === 1 }
104
104
  accessibleWhenDisabled
105
105
  label={ __( 'Previous page' ) }
106
- icon={ previous }
106
+ icon={ isRTL() ? next : previous }
107
107
  showTooltip
108
108
  size="compact"
109
109
  tooltipPosition="top"
@@ -115,7 +115,7 @@ function DataViewsPagination() {
115
115
  disabled={ currentPage >= totalPages }
116
116
  accessibleWhenDisabled
117
117
  label={ __( 'Next page' ) }
118
- icon={ next }
118
+ icon={ isRTL() ? previous : next }
119
119
  showTooltip
120
120
  size="compact"
121
121
  tooltipPosition="top"
@@ -1,15 +1,3 @@
1
- .dataviews-pagination {
2
- position: sticky;
3
- bottom: 0;
4
- left: 0;
5
- background-color: $white;
6
- padding: $grid-unit-15 $grid-unit-60;
7
- border-top: $border-width solid $gray-100;
8
- flex-shrink: 0;
9
- transition: padding ease-out 0.1s;
10
- @include reduce-motion("transition");
11
- }
12
-
13
1
  .dataviews-pagination__page-select {
14
2
  font-size: 11px;
15
3
  font-weight: 500;
@@ -22,10 +10,3 @@
22
10
  }
23
11
  }
24
12
  }
25
-
26
- /* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
27
- @container (max-width: 430px) {
28
- .dataviews-pagination {
29
- padding: $grid-unit-15 $grid-unit-30;
30
- }
31
- }