@wordpress/dataviews 12.1.1-next.v.202602241322.0 → 13.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 (132) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/README.md +132 -14
  3. package/build/components/dataform-layouts/card/index.cjs +12 -7
  4. package/build/components/dataform-layouts/card/index.cjs.map +2 -2
  5. package/build/components/dataform-layouts/panel/utils/get-label-content.cjs +2 -2
  6. package/build/components/dataform-layouts/panel/utils/get-label-content.cjs.map +2 -2
  7. package/build/components/dataviews-context/index.cjs +1 -0
  8. package/build/components/dataviews-context/index.cjs.map +2 -2
  9. package/build/components/dataviews-filters/toggle.cjs +6 -2
  10. package/build/components/dataviews-filters/toggle.cjs.map +2 -2
  11. package/build/components/dataviews-footer/index.cjs +28 -12
  12. package/build/components/dataviews-footer/index.cjs.map +3 -3
  13. package/build/components/dataviews-item-actions/index.cjs +0 -1
  14. package/build/components/dataviews-item-actions/index.cjs.map +2 -2
  15. package/build/components/dataviews-layout/index.cjs +4 -0
  16. package/build/components/dataviews-layout/index.cjs.map +2 -2
  17. package/build/components/dataviews-layouts/activity/index.cjs +41 -26
  18. package/build/components/dataviews-layouts/activity/index.cjs.map +3 -3
  19. package/build/components/dataviews-layouts/grid/composite-grid.cjs +2 -0
  20. package/build/components/dataviews-layouts/grid/composite-grid.cjs.map +2 -2
  21. package/build/components/dataviews-layouts/grid/index.cjs +19 -14
  22. package/build/components/dataviews-layouts/grid/index.cjs.map +3 -3
  23. package/build/components/dataviews-layouts/list/index.cjs +25 -12
  24. package/build/components/dataviews-layouts/list/index.cjs.map +2 -2
  25. package/build/components/dataviews-layouts/table/index.cjs +40 -19
  26. package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
  27. package/build/dataviews/index.cjs +9 -2
  28. package/build/dataviews/index.cjs.map +3 -3
  29. package/build/dataviews-picker/index.cjs +1 -0
  30. package/build/dataviews-picker/index.cjs.map +2 -2
  31. package/build/hooks/use-data.cjs +46 -0
  32. package/build/hooks/use-data.cjs.map +7 -0
  33. package/build/hooks/use-delayed-loading.cjs +47 -0
  34. package/build/hooks/use-delayed-loading.cjs.map +7 -0
  35. package/build-module/components/dataform-layouts/card/index.mjs +12 -7
  36. package/build-module/components/dataform-layouts/card/index.mjs.map +2 -2
  37. package/build-module/components/dataform-layouts/panel/utils/get-label-content.mjs +3 -3
  38. package/build-module/components/dataform-layouts/panel/utils/get-label-content.mjs.map +2 -2
  39. package/build-module/components/dataviews-context/index.mjs +1 -0
  40. package/build-module/components/dataviews-context/index.mjs.map +2 -2
  41. package/build-module/components/dataviews-filters/toggle.mjs +6 -2
  42. package/build-module/components/dataviews-filters/toggle.mjs.map +2 -2
  43. package/build-module/components/dataviews-footer/index.mjs +28 -12
  44. package/build-module/components/dataviews-footer/index.mjs.map +2 -2
  45. package/build-module/components/dataviews-item-actions/index.mjs +0 -1
  46. package/build-module/components/dataviews-item-actions/index.mjs.map +2 -2
  47. package/build-module/components/dataviews-layout/index.mjs +4 -0
  48. package/build-module/components/dataviews-layout/index.mjs.map +2 -2
  49. package/build-module/components/dataviews-layouts/activity/index.mjs +41 -26
  50. package/build-module/components/dataviews-layouts/activity/index.mjs.map +2 -2
  51. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs +2 -0
  52. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs.map +2 -2
  53. package/build-module/components/dataviews-layouts/grid/index.mjs +19 -14
  54. package/build-module/components/dataviews-layouts/grid/index.mjs.map +2 -2
  55. package/build-module/components/dataviews-layouts/list/index.mjs +25 -12
  56. package/build-module/components/dataviews-layouts/list/index.mjs.map +2 -2
  57. package/build-module/components/dataviews-layouts/table/index.mjs +40 -19
  58. package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
  59. package/build-module/dataviews/index.mjs +9 -2
  60. package/build-module/dataviews/index.mjs.map +2 -2
  61. package/build-module/dataviews-picker/index.mjs +1 -0
  62. package/build-module/dataviews-picker/index.mjs.map +2 -2
  63. package/build-module/hooks/use-data.mjs +25 -0
  64. package/build-module/hooks/use-data.mjs.map +7 -0
  65. package/build-module/hooks/use-delayed-loading.mjs +22 -0
  66. package/build-module/hooks/use-delayed-loading.mjs.map +7 -0
  67. package/build-style/style-rtl.css +91 -19
  68. package/build-style/style.css +91 -19
  69. package/build-types/components/dataform-layouts/card/index.d.ts.map +1 -1
  70. package/build-types/components/dataform-layouts/panel/utils/get-label-content.d.ts +1 -1
  71. package/build-types/components/dataform-layouts/panel/utils/get-label-content.d.ts.map +1 -1
  72. package/build-types/components/dataviews-context/index.d.ts +1 -0
  73. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  74. package/build-types/components/dataviews-filters/toggle.d.ts.map +1 -1
  75. package/build-types/components/dataviews-footer/index.d.ts +1 -1
  76. package/build-types/components/dataviews-footer/index.d.ts.map +1 -1
  77. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  78. package/build-types/components/dataviews-layout/index.d.ts +1 -1
  79. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  80. package/build-types/components/dataviews-layouts/activity/index.d.ts.map +1 -1
  81. package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts +2 -1
  82. package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
  83. package/build-types/components/dataviews-layouts/grid/index.d.ts.map +1 -1
  84. package/build-types/components/dataviews-layouts/list/index.d.ts.map +1 -1
  85. package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
  86. package/build-types/dataform/stories/layout-panel.d.ts.map +1 -1
  87. package/build-types/dataviews/index.d.ts.map +1 -1
  88. package/build-types/dataviews/stories/empty.d.ts.map +1 -1
  89. package/build-types/dataviews/stories/free-composition.d.ts.map +1 -1
  90. package/build-types/dataviews/stories/layout-table.d.ts.map +1 -1
  91. package/build-types/dataviews/stories/minimal-ui.d.ts.map +1 -1
  92. package/build-types/dataviews/stories/with-card.d.ts.map +1 -1
  93. package/build-types/dataviews-picker/index.d.ts.map +1 -1
  94. package/build-types/hooks/use-data.d.ts +12 -0
  95. package/build-types/hooks/use-data.d.ts.map +1 -0
  96. package/build-types/hooks/use-delayed-loading.d.ts +4 -0
  97. package/build-types/hooks/use-delayed-loading.d.ts.map +1 -0
  98. package/build-wp/index.js +263 -135
  99. package/package.json +16 -19
  100. package/src/components/dataform-layouts/card/index.tsx +8 -9
  101. package/src/components/dataform-layouts/card/style.scss +1 -0
  102. package/src/components/dataform-layouts/panel/style.scss +2 -0
  103. package/src/components/dataform-layouts/panel/utils/get-label-content.tsx +3 -5
  104. package/src/components/dataform-layouts/regular/style.scss +3 -2
  105. package/src/components/dataviews-context/index.ts +2 -0
  106. package/src/components/dataviews-filters/toggle.tsx +9 -2
  107. package/src/components/dataviews-footer/index.tsx +39 -12
  108. package/src/components/dataviews-footer/style.scss +6 -1
  109. package/src/components/dataviews-item-actions/index.tsx +0 -3
  110. package/src/components/dataviews-item-actions/style.scss +7 -0
  111. package/src/components/dataviews-layout/index.tsx +5 -0
  112. package/src/components/dataviews-layouts/activity/index.tsx +29 -22
  113. package/src/components/dataviews-layouts/activity/style.scss +5 -0
  114. package/src/components/dataviews-layouts/grid/composite-grid.tsx +4 -0
  115. package/src/components/dataviews-layouts/grid/index.tsx +19 -22
  116. package/src/components/dataviews-layouts/grid/style.scss +5 -0
  117. package/src/components/dataviews-layouts/list/index.tsx +39 -21
  118. package/src/components/dataviews-layouts/list/style.scss +5 -9
  119. package/src/components/dataviews-layouts/table/index.tsx +48 -22
  120. package/src/components/dataviews-layouts/table/style.scss +6 -0
  121. package/src/dataform/stories/layout-card.tsx +2 -2
  122. package/src/dataform/stories/layout-panel.tsx +5 -1
  123. package/src/dataviews/index.tsx +10 -2
  124. package/src/dataviews/stories/empty.tsx +1 -7
  125. package/src/dataviews/stories/free-composition.tsx +0 -5
  126. package/src/dataviews/stories/layout-table.tsx +1 -7
  127. package/src/dataviews/stories/minimal-ui.tsx +0 -5
  128. package/src/dataviews/stories/with-card.tsx +1 -7
  129. package/src/dataviews/style.scss +25 -0
  130. package/src/dataviews-picker/index.tsx +1 -0
  131. package/src/hooks/use-data.ts +45 -0
  132. package/src/hooks/use-delayed-loading.ts +21 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/dataviews",
3
- "version": "12.1.1-next.v.202602241322.0+bce7cff88",
3
+ "version": "13.0.0",
4
4
  "description": "DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -53,23 +53,20 @@
53
53
  "sideEffects": false,
54
54
  "dependencies": {
55
55
  "@ariakit/react": "^0.4.21",
56
- "@wordpress/base-styles": "^6.16.1-next.v.202602241322.0+bce7cff88",
57
- "@wordpress/components": "^32.3.1-next.v.202602241322.0+bce7cff88",
58
- "@wordpress/compose": "^7.40.1-next.v.202602241322.0+bce7cff88",
59
- "@wordpress/data": "^10.40.1-next.v.202602241322.0+bce7cff88",
60
- "@wordpress/date": "^5.40.1-next.v.202602241322.0+bce7cff88",
61
- "@wordpress/deprecated": "^4.40.1-next.v.202602241322.0+bce7cff88",
62
- "@wordpress/dom": "^4.40.1-next.v.202602241322.0+bce7cff88",
63
- "@wordpress/element": "^6.40.1-next.v.202602241322.0+bce7cff88",
64
- "@wordpress/i18n": "^6.13.1-next.v.202602241322.0+bce7cff88",
65
- "@wordpress/icons": "^11.7.1-next.v.202602241322.0+bce7cff88",
66
- "@wordpress/keycodes": "^4.40.1-next.v.202602241322.0+bce7cff88",
67
- "@wordpress/primitives": "^4.40.1-next.v.202602241322.0+bce7cff88",
68
- "@wordpress/private-apis": "^1.40.1-next.v.202602241322.0+bce7cff88",
69
- "@wordpress/theme": "^0.8.1-next.v.202602241322.0+bce7cff88",
70
- "@wordpress/ui": "^0.7.2-next.v.202602241322.0+bce7cff88",
71
- "@wordpress/url": "^4.40.1-next.v.202602241322.0+bce7cff88",
72
- "@wordpress/warning": "^3.40.1-next.v.202602241322.0+bce7cff88",
56
+ "@wordpress/base-styles": "^6.17.0",
57
+ "@wordpress/components": "^32.3.0",
58
+ "@wordpress/compose": "^7.41.0",
59
+ "@wordpress/data": "^10.41.0",
60
+ "@wordpress/date": "^5.41.0",
61
+ "@wordpress/deprecated": "^4.41.0",
62
+ "@wordpress/element": "^6.41.0",
63
+ "@wordpress/i18n": "^6.14.0",
64
+ "@wordpress/icons": "^11.8.0",
65
+ "@wordpress/keycodes": "^4.41.0",
66
+ "@wordpress/primitives": "^4.41.0",
67
+ "@wordpress/private-apis": "^1.41.0",
68
+ "@wordpress/ui": "^0.8.0",
69
+ "@wordpress/warning": "^3.41.0",
73
70
  "clsx": "^2.1.1",
74
71
  "colord": "^2.7.0",
75
72
  "date-fns": "^4.1.0",
@@ -95,5 +92,5 @@
95
92
  "scripts": {
96
93
  "build:wp": "node build.cjs"
97
94
  },
98
- "gitHead": "943dde7f0b600ce238726c36284bc9f70ce0ffa4"
95
+ "gitHead": "8bfc179b9aed74c0a6dd6e8edf7a49e40e4f87cc"
99
96
  }
@@ -16,7 +16,6 @@ import {
16
16
  useRef,
17
17
  useState,
18
18
  } from '@wordpress/element';
19
- import { __ } from '@wordpress/i18n';
20
19
  import { chevronDown, chevronUp } from '@wordpress/icons';
21
20
 
22
21
  /**
@@ -99,10 +98,9 @@ export default function FormCardField< Item >( {
99
98
  const { fields } = useContext( DataFormContext );
100
99
  const layout = field.layout as NormalizedCardLayout;
101
100
  const cardBodyRef = useRef< HTMLDivElement >( null );
102
- const bodyId = useInstanceId(
103
- FormCardField,
104
- 'dataforms-layouts-card-card-body'
105
- );
101
+ const instanceId = useInstanceId( FormCardField );
102
+ const bodyId = `dataforms-layouts-card-card-body-${ instanceId }`;
103
+ const titleId = `dataforms-layouts-card-card-title-${ instanceId }`;
106
104
 
107
105
  const form: NormalizedForm = useMemo(
108
106
  () => ( {
@@ -240,7 +238,10 @@ export default function FormCardField< Item >( {
240
238
  alignItems: 'center',
241
239
  } }
242
240
  >
243
- <span className="dataforms-layouts-card__field-header-label">
241
+ <span
242
+ id={ titleId }
243
+ className="dataforms-layouts-card__field-header-label"
244
+ >
244
245
  { label }
245
246
  </span>
246
247
  { validationBadge }
@@ -266,9 +267,7 @@ export default function FormCardField< Item >( {
266
267
  icon={ isOpen ? chevronUp : chevronDown }
267
268
  aria-expanded={ isOpen }
268
269
  aria-controls={ bodyId }
269
- aria-label={
270
- isOpen ? __( 'Collapse' ) : __( 'Expand' )
271
- }
270
+ aria-labelledby={ titleId }
272
271
  />
273
272
  ) }
274
273
  </OriginalCardHeader>
@@ -21,4 +21,5 @@
21
21
  display: flex;
22
22
  flex-direction: row;
23
23
  gap: $grid-unit-20;
24
+ align-items: center;
24
25
  }
@@ -92,6 +92,7 @@
92
92
  line-height: $grid-unit-05 * 5;
93
93
  hyphens: auto;
94
94
  color: $gray-700;
95
+ text-transform: capitalize;
95
96
 
96
97
  .components-base-control__label {
97
98
  display: inline;
@@ -126,6 +127,7 @@
126
127
  display: flex;
127
128
  align-items: center;
128
129
  overflow: hidden;
130
+ word-break: break-word;
129
131
  font-weight: var(--wpds-font-weight-medium);
130
132
 
131
133
  > * {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { BaseControl, Icon, Tooltip } from '@wordpress/components';
4
+ import { Icon, Tooltip } from '@wordpress/components';
5
5
  import { error as errorIcon } from '@wordpress/icons';
6
6
 
7
7
  function getLabelContent(
@@ -13,13 +13,11 @@ function getLabelContent(
13
13
  <Tooltip text={ errorMessage } placement="top">
14
14
  <span className="dataforms-layouts-panel__field-label-error-content">
15
15
  <Icon icon={ errorIcon } size={ 16 } />
16
- <BaseControl.VisualLabel>
17
- { fieldLabel }
18
- </BaseControl.VisualLabel>
16
+ { fieldLabel }
19
17
  </span>
20
18
  </Tooltip>
21
19
  ) : (
22
- <BaseControl.VisualLabel>{ fieldLabel }</BaseControl.VisualLabel>
20
+ fieldLabel
23
21
  );
24
22
  }
25
23
 
@@ -8,8 +8,9 @@
8
8
  align-items: flex-start !important;
9
9
 
10
10
  .components-base-control__label,
11
- .components-input-control__label {
12
- color: $gray-700;
11
+ .components-input-control__label,
12
+ .components-form-token-field__label {
13
+ color: $gray-900;
13
14
  }
14
15
  }
15
16
 
@@ -56,6 +56,7 @@ type DataViewsContextType< Item > = {
56
56
  setIsShowingFilter: ( value: boolean ) => void;
57
57
  config: { perPageSizes: number[] };
58
58
  empty?: ReactNode;
59
+ hasInitiallyLoaded?: boolean;
59
60
  hasInfiniteScrollHandler: boolean;
60
61
  itemListLabel?: string;
61
62
  onReset?: ( () => void ) | false;
@@ -84,6 +85,7 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
84
85
  filters: [],
85
86
  isShowingFilter: false,
86
87
  setIsShowingFilter: () => {},
88
+ hasInitiallyLoaded: false,
87
89
  hasInfiniteScrollHandler: false,
88
90
  config: {
89
91
  perPageSizes: [],
@@ -31,13 +31,13 @@ function FiltersToggle() {
31
31
  },
32
32
  [ onChangeView, setIsShowingFilter ]
33
33
  );
34
- const visibleFilters = filters.filter( ( filter ) => filter.isVisible );
35
34
 
36
- const hasVisibleFilters = !! visibleFilters.length;
37
35
  if ( filters.length === 0 ) {
38
36
  return null;
39
37
  }
40
38
 
39
+ const hasVisibleFilters = filters.some( ( filter ) => filter.isVisible );
40
+
41
41
  const addFilterButtonProps = {
42
42
  label: __( 'Add filter' ),
43
43
  'aria-expanded': false,
@@ -54,12 +54,19 @@ function FiltersToggle() {
54
54
  setIsShowingFilter( ! isShowingFilter );
55
55
  },
56
56
  };
57
+ // When there are primary or locked filters, the filter bar is always
58
+ // visible and cannot be hidden, so the toggle button should be disabled.
59
+ const hasPrimaryOrLockedFilters = filters.some(
60
+ ( filter ) => filter.isPrimary || filter.isLocked
61
+ );
57
62
  const buttonComponent = (
58
63
  <Button
59
64
  ref={ buttonRef }
60
65
  className="dataviews-filters__visibility-toggle"
61
66
  size="compact"
62
67
  icon={ funnel }
68
+ disabled={ hasPrimaryOrLockedFilters }
69
+ accessibleWhenDisabled
63
70
  { ...( hasVisibleFilters
64
71
  ? toggleFiltersButtonProps
65
72
  : addFilterButtonProps ) }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -14,6 +19,7 @@ import {
14
19
  useSomeItemHasAPossibleBulkAction,
15
20
  } from '../dataviews-bulk-actions';
16
21
  import { LAYOUT_GRID, LAYOUT_TABLE } from '../../constants';
22
+ import { useDelayedLoading } from '../../hooks/use-delayed-loading';
17
23
 
18
24
  const EMPTY_ARRAY: [] = [];
19
25
 
@@ -23,30 +29,51 @@ export default function DataViewsFooter() {
23
29
  paginationInfo: { totalItems = 0, totalPages },
24
30
  data,
25
31
  actions = EMPTY_ARRAY,
32
+ isLoading,
33
+ hasInitiallyLoaded,
34
+ hasInfiniteScrollHandler,
26
35
  } = useContext( DataViewsContext );
36
+
37
+ const isRefreshing =
38
+ !! isLoading &&
39
+ hasInitiallyLoaded &&
40
+ ! hasInfiniteScrollHandler &&
41
+ !! data?.length;
42
+
43
+ const isDelayedRefreshing = useDelayedLoading( !! isRefreshing );
44
+
27
45
  const hasBulkActions =
28
46
  useSomeItemHasAPossibleBulkAction( actions, data ) &&
29
47
  [ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type );
30
48
 
31
49
  if (
32
- ! totalItems ||
33
- ! totalPages ||
34
- ( totalPages <= 1 && ! hasBulkActions )
50
+ ! isRefreshing &&
51
+ ( ! totalItems ||
52
+ ! totalPages ||
53
+ ( totalPages <= 1 && ! hasBulkActions ) )
35
54
  ) {
36
55
  return null;
37
56
  }
38
57
  return (
39
- !! totalItems && (
40
- <Stack
41
- direction="row"
42
- justify="end"
43
- align="center"
58
+ ( !! totalItems || isRefreshing ) && (
59
+ <div
44
60
  className="dataviews-footer"
45
- gap="sm"
61
+ // @ts-ignore
62
+ inert={ isRefreshing ? 'true' : undefined }
46
63
  >
47
- { hasBulkActions && <BulkActionsFooter /> }
48
- <DataViewsPagination />
49
- </Stack>
64
+ <Stack
65
+ direction="row"
66
+ justify="end"
67
+ align="center"
68
+ className={ clsx( 'dataviews-footer__content', {
69
+ 'is-refreshing': isDelayedRefreshing,
70
+ } ) }
71
+ gap="sm"
72
+ >
73
+ { hasBulkActions && <BulkActionsFooter /> }
74
+ <DataViewsPagination />
75
+ </Stack>
76
+ </div>
50
77
  )
51
78
  );
52
79
  }
@@ -1,6 +1,7 @@
1
1
  @use "@wordpress/base-styles/colors" as *;
2
2
  @use "@wordpress/base-styles/variables" as *;
3
3
  @use "@wordpress/base-styles/z-index" as *;
4
+ @use "../../dataviews/style" as *;
4
5
 
5
6
  .dataviews-footer {
6
7
  position: sticky;
@@ -16,10 +17,14 @@
16
17
  }
17
18
 
18
19
  z-index: z-index(".dataviews-footer");
20
+
21
+ .is-refreshing {
22
+ @include dataviews-refreshing();
23
+ }
19
24
  }
20
25
 
21
26
  @container (max-width: 560px) {
22
- .dataviews-footer {
27
+ .dataviews-footer__content {
23
28
  flex-direction: column !important;
24
29
 
25
30
  .dataviews-bulk-actions-footer__container {
@@ -171,9 +171,6 @@ export function ActionsMenuGroup< Item >( {
171
171
  return (
172
172
  <Menu.Group>
173
173
  { renderActionGroup( primaryActions ) }
174
- { primaryActions.length > 0 && regularActions.length > 0 && (
175
- <Menu.Separator />
176
- ) }
177
174
  { renderActionGroup( regularActions ) }
178
175
  </Menu.Group>
179
176
  );
@@ -5,3 +5,10 @@
5
5
  .dataviews-action-modal {
6
6
  z-index: z-index(".dataviews-action-modal");
7
7
  }
8
+
9
+ // TODO: the way forward here would be to use the new unstyle button coming
10
+ // from wordpress/ui package, but we're not ready to use it yet.
11
+ // See https://github.com/WordPress/gutenberg/pull/75721/
12
+ .dataviews-item-actions .components-button:not(.dataviews-all-actions-button) {
13
+ padding: 0 $grid-unit-05;
14
+ }
@@ -27,6 +27,7 @@ export default function DataViewsLayout( { className }: DataViewsLayoutProps ) {
27
27
  fields,
28
28
  getItemId,
29
29
  getItemLevel,
30
+ hasInitiallyLoaded,
30
31
  isLoading,
31
32
  view,
32
33
  onChangeView,
@@ -40,6 +41,10 @@ export default function DataViewsLayout( { className }: DataViewsLayoutProps ) {
40
41
  empty = <p>{ __( 'No results' ) }</p>,
41
42
  } = useContext( DataViewsContext );
42
43
 
44
+ if ( ! hasInitiallyLoaded ) {
45
+ return null;
46
+ }
47
+
43
48
  const ViewComponent = VIEW_LAYOUTS.find(
44
49
  ( v ) => v.type === view.type && defaultLayouts[ v.type ]
45
50
  )?.component as ComponentType< ViewBaseProps< any > >;
@@ -16,41 +16,40 @@ import type { ViewActivityProps } from '../../../types';
16
16
  import getDataByGroup from '../utils/get-data-by-group';
17
17
  import ActivityGroup from './activity-group';
18
18
  import ActivityItems from './activity-items';
19
+ import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
19
20
 
20
21
  export default function ViewActivity< Item >(
21
22
  props: ViewActivityProps< Item >
22
23
  ) {
23
24
  const { empty, data, fields, isLoading, view, className } = props;
24
25
 
25
- // Handle empty/loading states
26
- const hasData = data?.length;
26
+ const isDelayedLoading = useDelayedLoading( !! isLoading );
27
+ const hasData = !! data?.length;
28
+
29
+ // Check if data should be grouped
30
+ const groupField = view.groupBy?.field
31
+ ? fields.find( ( field ) => field.id === view.groupBy?.field )
32
+ : null;
33
+ const dataByGroup =
34
+ hasData && groupField ? getDataByGroup( data, groupField ) : null;
35
+
36
+ const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
27
37
  if ( ! hasData ) {
28
38
  return (
29
39
  <div
30
- className={ clsx( {
31
- 'dataviews-loading': isLoading,
32
- 'dataviews-no-results': ! hasData && ! isLoading,
40
+ className={ clsx( 'dataviews-no-results', {
41
+ 'is-refreshing': isDelayedLoading,
33
42
  } ) }
34
43
  >
35
- { ! hasData &&
36
- ( isLoading ? (
37
- <p>
38
- <Spinner />
39
- </p>
40
- ) : (
41
- empty
42
- ) ) }
44
+ { empty }
43
45
  </div>
44
46
  );
45
47
  }
46
48
 
47
- const wrapperClassName = clsx( 'dataviews-view-activity', className );
48
-
49
- // Check if data should be grouped
50
- const groupField = view.groupBy?.field
51
- ? fields.find( ( field ) => field.id === view.groupBy?.field )
52
- : null;
53
- const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
49
+ const isInert = ! isInfiniteScroll && !! isLoading;
50
+ const wrapperClassName = clsx( 'dataviews-view-activity', className, {
51
+ 'is-refreshing': ! isInfiniteScroll && isDelayedLoading,
52
+ } );
54
53
 
55
54
  // Convert dataByGroup entries into array.
56
55
  const groupedEntries = dataByGroup
@@ -60,7 +59,13 @@ export default function ViewActivity< Item >(
60
59
  // Render grouped activity
61
60
  if ( hasData && groupField && dataByGroup ) {
62
61
  return (
63
- <Stack direction="column" gap="sm" className={ wrapperClassName }>
62
+ <Stack
63
+ direction="column"
64
+ gap="sm"
65
+ className={ wrapperClassName }
66
+ // @ts-ignore
67
+ inert={ isInert ? 'true' : undefined }
68
+ >
64
69
  { groupedEntries.map(
65
70
  ( [ groupName, groupData ]: [ string, Item[] ] ) => (
66
71
  <ActivityGroup< Item >
@@ -87,10 +92,12 @@ export default function ViewActivity< Item >(
87
92
  <div
88
93
  className={ wrapperClassName }
89
94
  role={ view.infiniteScrollEnabled ? 'feed' : undefined }
95
+ // @ts-ignore
96
+ inert={ isInert ? 'true' : undefined }
90
97
  >
91
98
  <ActivityItems< Item > { ...props } />
92
99
  </div>
93
- { hasData && isLoading && (
100
+ { isInfiniteScroll && isLoading && (
94
101
  <p className="dataviews-loading-more">
95
102
  <Spinner />
96
103
  </p>
@@ -1,5 +1,6 @@
1
1
  @use "@wordpress/base-styles/colors" as *;
2
2
  @use "@wordpress/base-styles/variables" as *;
3
+ @use "../../../dataviews/style" as *;
3
4
 
4
5
  .dataviews-view-activity {
5
6
  margin: 0 0 auto;
@@ -211,6 +212,10 @@
211
212
  }
212
213
  }
213
214
 
215
+ &.is-refreshing {
216
+ @include dataviews-refreshing();
217
+ }
218
+
214
219
  & + .dataviews-pagination {
215
220
  justify-content: space-between;
216
221
  }
@@ -293,6 +293,7 @@ interface CompositeGridProps< Item > {
293
293
  data: Item[];
294
294
  isInfiniteScroll: boolean;
295
295
  className?: string;
296
+ inert?: string;
296
297
  isLoading?: boolean;
297
298
  view: ViewGridType;
298
299
  fields: NormalizedField< Item >[];
@@ -313,6 +314,7 @@ export default function CompositeGrid< Item >( {
313
314
  data,
314
315
  isInfiniteScroll,
315
316
  className,
317
+ inert,
316
318
  isLoading,
317
319
  view,
318
320
  fields,
@@ -375,6 +377,8 @@ export default function CompositeGrid< Item >( {
375
377
  aria-busy={ isLoading }
376
378
  aria-rowcount={ isInfiniteScroll ? undefined : totalRows }
377
379
  ref={ resizeObserverRef }
380
+ // @ts-ignore
381
+ inert={ inert }
378
382
  >
379
383
  { chunk( data, gridColumns ).map( ( row, i ) => (
380
384
  <Composite.Row
@@ -16,6 +16,7 @@ import { Stack } from '@wordpress/ui';
16
16
  import type { ViewGridProps } from '../../../types';
17
17
  import getDataByGroup from '../utils/get-data-by-group';
18
18
  import CompositeGrid from './composite-grid';
19
+ import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
19
20
 
20
21
  function ViewGrid< Item >( {
21
22
  actions,
@@ -32,14 +33,29 @@ function ViewGrid< Item >( {
32
33
  className,
33
34
  empty,
34
35
  }: ViewGridProps< Item > ) {
36
+ const isDelayedLoading = useDelayedLoading( !! isLoading );
35
37
  const hasData = !! data?.length;
36
38
  const groupField = view.groupBy?.field
37
39
  ? fields.find( ( f ) => f.id === view.groupBy?.field )
38
40
  : null;
39
41
  const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
40
42
  const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
43
+ if ( ! hasData ) {
44
+ return (
45
+ <div
46
+ className={ clsx( 'dataviews-no-results', {
47
+ 'is-refreshing': isDelayedLoading,
48
+ } ) }
49
+ >
50
+ { empty }
51
+ </div>
52
+ );
53
+ }
41
54
  const gridProps = {
42
- className,
55
+ className: clsx( className, {
56
+ 'is-refreshing': ! isInfiniteScroll && isDelayedLoading,
57
+ } ),
58
+ inert: ! isInfiniteScroll && !! isLoading ? 'true' : undefined,
43
59
  isLoading,
44
60
  view,
45
61
  fields,
@@ -87,7 +103,7 @@ function ViewGrid< Item >( {
87
103
  }
88
104
  {
89
105
  // Render a single grid with all data.
90
- hasData && ! dataByGroup && (
106
+ ! dataByGroup && (
91
107
  <CompositeGrid
92
108
  { ...gridProps }
93
109
  data={ data }
@@ -95,26 +111,7 @@ function ViewGrid< Item >( {
95
111
  />
96
112
  )
97
113
  }
98
- {
99
- // Render empty state.
100
- ! hasData && (
101
- <div
102
- className={ clsx( {
103
- 'dataviews-loading': isLoading,
104
- 'dataviews-no-results': ! isLoading,
105
- } ) }
106
- >
107
- { isLoading ? (
108
- <p>
109
- <Spinner />
110
- </p>
111
- ) : (
112
- empty
113
- ) }
114
- </div>
115
- )
116
- }
117
- { hasData && isLoading && (
114
+ { isInfiniteScroll && isLoading && (
118
115
  <p className="dataviews-loading-more">
119
116
  <Spinner />
120
117
  </p>
@@ -3,6 +3,7 @@
3
3
  @use "@wordpress/base-styles/variables" as *;
4
4
  @use "@wordpress/base-styles/z-index" as *;
5
5
  @use "../utils/grid-items.scss" as *;
6
+ @use "../../../dataviews/style" as *;
6
7
 
7
8
  .dataviews-view-grid {
8
9
  padding: 0 $grid-unit-30 $grid-unit-30;
@@ -164,6 +165,10 @@
164
165
  padding-bottom: $grid-unit-15;
165
166
  }
166
167
  }
168
+
169
+ &.is-refreshing {
170
+ @include dataviews-refreshing();
171
+ }
167
172
  }
168
173
 
169
174
  .dataviews-view-grid__field-value:empty,