@wordpress/dataviews 12.0.1-next.v.202602111440.0 → 12.0.1

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 (201) hide show
  1. package/CHANGELOG.md +37 -1
  2. package/README.md +3 -1
  3. package/build/components/dataform-controls/color.cjs +19 -30
  4. package/build/components/dataform-controls/color.cjs.map +3 -3
  5. package/build/components/dataform-controls/date.cjs.map +1 -1
  6. package/build/components/dataform-controls/datetime.cjs +12 -21
  7. package/build/components/dataform-controls/datetime.cjs.map +2 -2
  8. package/build/components/dataform-layouts/card/index.cjs +112 -164
  9. package/build/components/dataform-layouts/card/index.cjs.map +3 -3
  10. package/build/components/dataform-layouts/normalize-form.cjs +2 -1
  11. package/build/components/dataform-layouts/normalize-form.cjs.map +2 -2
  12. package/build/components/dataform-layouts/panel/summary-button.cjs +77 -49
  13. package/build/components/dataform-layouts/panel/summary-button.cjs.map +2 -2
  14. package/build/components/dataform-layouts/panel/utils/get-label-content.cjs +2 -2
  15. package/build/components/dataform-layouts/panel/utils/get-label-content.cjs.map +2 -2
  16. package/build/components/dataviews-bulk-actions/index.cjs +2 -2
  17. package/build/components/dataviews-bulk-actions/index.cjs.map +2 -2
  18. package/build/components/dataviews-context/index.cjs +1 -0
  19. package/build/components/dataviews-context/index.cjs.map +2 -2
  20. package/build/components/dataviews-filters/filter.cjs.map +1 -1
  21. package/build/components/dataviews-filters/toggle.cjs +6 -2
  22. package/build/components/dataviews-filters/toggle.cjs.map +2 -2
  23. package/build/components/dataviews-footer/index.cjs +28 -12
  24. package/build/components/dataviews-footer/index.cjs.map +3 -3
  25. package/build/components/dataviews-item-actions/index.cjs +0 -1
  26. package/build/components/dataviews-item-actions/index.cjs.map +2 -2
  27. package/build/components/dataviews-layout/index.cjs +12 -0
  28. package/build/components/dataviews-layout/index.cjs.map +2 -2
  29. package/build/components/dataviews-layouts/activity/index.cjs +41 -26
  30. package/build/components/dataviews-layouts/activity/index.cjs.map +3 -3
  31. package/build/components/dataviews-layouts/grid/composite-grid.cjs +2 -0
  32. package/build/components/dataviews-layouts/grid/composite-grid.cjs.map +2 -2
  33. package/build/components/dataviews-layouts/grid/index.cjs +19 -14
  34. package/build/components/dataviews-layouts/grid/index.cjs.map +3 -3
  35. package/build/components/dataviews-layouts/list/index.cjs +13 -9
  36. package/build/components/dataviews-layouts/list/index.cjs.map +2 -2
  37. package/build/components/dataviews-layouts/picker-table/index.cjs +1 -1
  38. package/build/components/dataviews-layouts/picker-table/index.cjs.map +2 -2
  39. package/build/components/dataviews-layouts/table/index.cjs +40 -19
  40. package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
  41. package/build/dataviews/index.cjs +9 -2
  42. package/build/dataviews/index.cjs.map +3 -3
  43. package/build/dataviews-picker/index.cjs +1 -0
  44. package/build/dataviews-picker/index.cjs.map +2 -2
  45. package/build/hooks/use-data.cjs +46 -0
  46. package/build/hooks/use-data.cjs.map +7 -0
  47. package/build/hooks/use-delayed-loading.cjs +47 -0
  48. package/build/hooks/use-delayed-loading.cjs.map +7 -0
  49. package/build/types/dataform.cjs.map +1 -1
  50. package/build-module/components/dataform-controls/color.mjs +24 -31
  51. package/build-module/components/dataform-controls/color.mjs.map +2 -2
  52. package/build-module/components/dataform-controls/date.mjs.map +1 -1
  53. package/build-module/components/dataform-controls/datetime.mjs +13 -22
  54. package/build-module/components/dataform-controls/datetime.mjs.map +2 -2
  55. package/build-module/components/dataform-layouts/card/index.mjs +113 -161
  56. package/build-module/components/dataform-layouts/card/index.mjs.map +3 -3
  57. package/build-module/components/dataform-layouts/normalize-form.mjs +2 -1
  58. package/build-module/components/dataform-layouts/normalize-form.mjs.map +2 -2
  59. package/build-module/components/dataform-layouts/panel/summary-button.mjs +78 -50
  60. package/build-module/components/dataform-layouts/panel/summary-button.mjs.map +2 -2
  61. package/build-module/components/dataform-layouts/panel/utils/get-label-content.mjs +3 -3
  62. package/build-module/components/dataform-layouts/panel/utils/get-label-content.mjs.map +2 -2
  63. package/build-module/components/dataviews-bulk-actions/index.mjs +2 -2
  64. package/build-module/components/dataviews-bulk-actions/index.mjs.map +2 -2
  65. package/build-module/components/dataviews-context/index.mjs +1 -0
  66. package/build-module/components/dataviews-context/index.mjs.map +2 -2
  67. package/build-module/components/dataviews-filters/filter.mjs.map +1 -1
  68. package/build-module/components/dataviews-filters/toggle.mjs +6 -2
  69. package/build-module/components/dataviews-filters/toggle.mjs.map +2 -2
  70. package/build-module/components/dataviews-footer/index.mjs +28 -12
  71. package/build-module/components/dataviews-footer/index.mjs.map +2 -2
  72. package/build-module/components/dataviews-item-actions/index.mjs +0 -1
  73. package/build-module/components/dataviews-item-actions/index.mjs.map +2 -2
  74. package/build-module/components/dataviews-layout/index.mjs +12 -0
  75. package/build-module/components/dataviews-layout/index.mjs.map +2 -2
  76. package/build-module/components/dataviews-layouts/activity/index.mjs +41 -26
  77. package/build-module/components/dataviews-layouts/activity/index.mjs.map +2 -2
  78. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs +2 -0
  79. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs.map +2 -2
  80. package/build-module/components/dataviews-layouts/grid/index.mjs +19 -14
  81. package/build-module/components/dataviews-layouts/grid/index.mjs.map +2 -2
  82. package/build-module/components/dataviews-layouts/list/index.mjs +13 -9
  83. package/build-module/components/dataviews-layouts/list/index.mjs.map +2 -2
  84. package/build-module/components/dataviews-layouts/picker-table/index.mjs +1 -1
  85. package/build-module/components/dataviews-layouts/picker-table/index.mjs.map +2 -2
  86. package/build-module/components/dataviews-layouts/table/index.mjs +40 -19
  87. package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
  88. package/build-module/dataviews/index.mjs +9 -2
  89. package/build-module/dataviews/index.mjs.map +2 -2
  90. package/build-module/dataviews-picker/index.mjs +1 -0
  91. package/build-module/dataviews-picker/index.mjs.map +2 -2
  92. package/build-module/hooks/use-data.mjs +25 -0
  93. package/build-module/hooks/use-data.mjs.map +7 -0
  94. package/build-module/hooks/use-delayed-loading.mjs +22 -0
  95. package/build-module/hooks/use-delayed-loading.mjs.map +7 -0
  96. package/build-style/style-rtl.css +109 -32
  97. package/build-style/style.css +109 -32
  98. package/build-types/components/dataform-controls/color.d.ts.map +1 -1
  99. package/build-types/components/dataform-controls/datetime.d.ts.map +1 -1
  100. package/build-types/components/dataform-controls/utils/use-disabled-date-matchers.d.ts +16 -0
  101. package/build-types/components/dataform-controls/utils/use-disabled-date-matchers.d.ts.map +1 -0
  102. package/build-types/components/dataform-layouts/card/index.d.ts +1 -10
  103. package/build-types/components/dataform-layouts/card/index.d.ts.map +1 -1
  104. package/build-types/components/dataform-layouts/normalize-form.d.ts.map +1 -1
  105. package/build-types/components/dataform-layouts/panel/summary-button.d.ts.map +1 -1
  106. package/build-types/components/dataform-layouts/panel/utils/get-label-content.d.ts +1 -1
  107. package/build-types/components/dataform-layouts/panel/utils/get-label-content.d.ts.map +1 -1
  108. package/build-types/components/dataviews-context/index.d.ts +1 -0
  109. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  110. package/build-types/components/dataviews-filters/filter.d.ts +1 -1
  111. package/build-types/components/dataviews-filters/filter.d.ts.map +1 -1
  112. package/build-types/components/dataviews-filters/toggle.d.ts.map +1 -1
  113. package/build-types/components/dataviews-footer/index.d.ts +1 -1
  114. package/build-types/components/dataviews-footer/index.d.ts.map +1 -1
  115. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  116. package/build-types/components/dataviews-layout/index.d.ts +1 -1
  117. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  118. package/build-types/components/dataviews-layouts/activity/index.d.ts.map +1 -1
  119. package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts +2 -1
  120. package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
  121. package/build-types/components/dataviews-layouts/grid/index.d.ts.map +1 -1
  122. package/build-types/components/dataviews-layouts/list/index.d.ts.map +1 -1
  123. package/build-types/components/dataviews-layouts/picker-activity/index.d.ts +3 -0
  124. package/build-types/components/dataviews-layouts/picker-activity/index.d.ts.map +1 -0
  125. package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
  126. package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts +25 -0
  127. package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts.map +1 -0
  128. package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts +2 -0
  129. package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts.map +1 -0
  130. package/build-types/components/dataviews-layouts/utils/use-infinite-scroll.d.ts +22 -0
  131. package/build-types/components/dataviews-layouts/utils/use-infinite-scroll.d.ts.map +1 -0
  132. package/build-types/dataform/stories/index.story.d.ts +9 -1
  133. package/build-types/dataform/stories/index.story.d.ts.map +1 -1
  134. package/build-types/dataform/stories/layout-panel.d.ts +3 -1
  135. package/build-types/dataform/stories/layout-panel.d.ts.map +1 -1
  136. package/build-types/dataviews/index.d.ts.map +1 -1
  137. package/build-types/dataviews/stories/empty.d.ts.map +1 -1
  138. package/build-types/dataviews/stories/free-composition.d.ts.map +1 -1
  139. package/build-types/dataviews/stories/layout-table.d.ts.map +1 -1
  140. package/build-types/dataviews/stories/minimal-ui.d.ts.map +1 -1
  141. package/build-types/dataviews/stories/with-card.d.ts.map +1 -1
  142. package/build-types/dataviews-picker/index.d.ts.map +1 -1
  143. package/build-types/field-types/utils/is-valid-date-boundary.d.ts +7 -0
  144. package/build-types/field-types/utils/is-valid-date-boundary.d.ts.map +1 -0
  145. package/build-types/hooks/test/use-data.d.ts +2 -0
  146. package/build-types/hooks/test/use-data.d.ts.map +1 -0
  147. package/build-types/hooks/use-data.d.ts +12 -0
  148. package/build-types/hooks/use-data.d.ts.map +1 -0
  149. package/build-types/hooks/use-delayed-loading.d.ts +4 -0
  150. package/build-types/hooks/use-delayed-loading.d.ts.map +1 -0
  151. package/build-types/hooks/use-infinite-scroll.d.ts +21 -0
  152. package/build-types/hooks/use-infinite-scroll.d.ts.map +1 -0
  153. package/build-types/hooks/use-selected-items.d.ts +19 -0
  154. package/build-types/hooks/use-selected-items.d.ts.map +1 -0
  155. package/build-types/types/dataform.d.ts +3 -0
  156. package/build-types/types/dataform.d.ts.map +1 -1
  157. package/build-wp/index.js +2568 -1864
  158. package/package.json +21 -21
  159. package/src/components/dataform-controls/color.tsx +29 -36
  160. package/src/components/dataform-controls/date.tsx +2 -2
  161. package/src/components/dataform-controls/datetime.tsx +19 -34
  162. package/src/components/dataform-controls/style.scss +4 -0
  163. package/src/components/dataform-layouts/card/index.tsx +118 -185
  164. package/src/components/dataform-layouts/normalize-form.ts +1 -0
  165. package/src/components/dataform-layouts/panel/style.scss +24 -20
  166. package/src/components/dataform-layouts/panel/summary-button.tsx +43 -12
  167. package/src/components/dataform-layouts/panel/utils/get-label-content.tsx +3 -5
  168. package/src/components/dataform-layouts/regular/style.scss +3 -2
  169. package/src/components/dataform-layouts/test/normalize-form.ts +5 -0
  170. package/src/components/dataviews-bulk-actions/index.tsx +2 -2
  171. package/src/components/dataviews-context/index.ts +2 -0
  172. package/src/components/dataviews-filters/filter.tsx +1 -1
  173. package/src/components/dataviews-filters/toggle.tsx +10 -3
  174. package/src/components/dataviews-footer/index.tsx +39 -12
  175. package/src/components/dataviews-footer/style.scss +6 -1
  176. package/src/components/dataviews-item-actions/index.tsx +0 -3
  177. package/src/components/dataviews-item-actions/style.scss +7 -0
  178. package/src/components/dataviews-layout/index.tsx +24 -0
  179. package/src/components/dataviews-layouts/activity/index.tsx +29 -22
  180. package/src/components/dataviews-layouts/activity/style.scss +5 -0
  181. package/src/components/dataviews-layouts/grid/composite-grid.tsx +5 -1
  182. package/src/components/dataviews-layouts/grid/index.tsx +19 -22
  183. package/src/components/dataviews-layouts/grid/style.scss +5 -0
  184. package/src/components/dataviews-layouts/list/index.tsx +18 -18
  185. package/src/components/dataviews-layouts/list/style.scss +5 -0
  186. package/src/components/dataviews-layouts/picker-table/index.tsx +1 -1
  187. package/src/components/dataviews-layouts/table/index.tsx +48 -22
  188. package/src/components/dataviews-layouts/table/style.scss +8 -2
  189. package/src/dataform/stories/index.story.tsx +5 -0
  190. package/src/dataform/stories/layout-panel.tsx +19 -2
  191. package/src/dataviews/index.tsx +11 -3
  192. package/src/dataviews/stories/empty.tsx +1 -7
  193. package/src/dataviews/stories/free-composition.tsx +0 -5
  194. package/src/dataviews/stories/layout-table.tsx +1 -7
  195. package/src/dataviews/stories/minimal-ui.tsx +0 -5
  196. package/src/dataviews/stories/with-card.tsx +1 -7
  197. package/src/dataviews/style.scss +25 -0
  198. package/src/dataviews-picker/index.tsx +2 -1
  199. package/src/hooks/use-data.ts +45 -0
  200. package/src/hooks/use-delayed-loading.ts +21 -0
  201. package/src/types/dataform.ts +4 -0
@@ -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,
@@ -33,6 +33,7 @@ import { Stack } from '@wordpress/ui';
33
33
  import { unlock } from '../../../lock-unlock';
34
34
  import { ActionsMenuGroup, ActionModal } from '../../dataviews-item-actions';
35
35
  import DataViewsContext from '../../dataviews-context';
36
+ import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
36
37
  import type {
37
38
  Action,
38
39
  NormalizedField,
@@ -389,6 +390,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
389
390
  empty,
390
391
  } = props;
391
392
  const baseId = useInstanceId( ViewList, 'view-list' );
393
+ const isDelayedLoading = useDelayedLoading( !! isLoading );
392
394
 
393
395
  const selectedItem = data?.findLast( ( item ) =>
394
396
  selection.includes( getItemId( item ) )
@@ -511,32 +513,25 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
511
513
  [ selectCompositeItem, activeItemIndex ]
512
514
  );
513
515
 
514
- const hasData = data?.length;
516
+ const hasData = !! data?.length;
517
+ const groupField = view.groupBy?.field
518
+ ? fields.find( ( field ) => field.id === view.groupBy?.field )
519
+ : null;
520
+ const dataByGroup =
521
+ hasData && groupField ? getDataByGroup( data, groupField ) : null;
522
+ const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
515
523
  if ( ! hasData ) {
516
524
  return (
517
525
  <div
518
- className={ clsx( {
519
- 'dataviews-loading': isLoading,
520
- 'dataviews-no-results': ! hasData && ! isLoading,
526
+ className={ clsx( 'dataviews-no-results', {
527
+ 'is-refreshing': isDelayedLoading,
521
528
  } ) }
522
529
  >
523
- { ! hasData &&
524
- ( isLoading ? (
525
- <p>
526
- <Spinner />
527
- </p>
528
- ) : (
529
- empty
530
- ) ) }
530
+ { empty }
531
531
  </div>
532
532
  );
533
533
  }
534
534
 
535
- const groupField = view.groupBy?.field
536
- ? fields.find( ( field ) => field.id === view.groupBy?.field )
537
- : null;
538
- const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
539
-
540
535
  // Render data grouped by field
541
536
  if ( hasData && groupField && dataByGroup ) {
542
537
  return (
@@ -614,10 +609,15 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
614
609
  [ 'compact', 'comfortable' ].includes(
615
610
  view.layout.density
616
611
  ),
612
+ 'is-refreshing': ! isInfiniteScroll && isDelayedLoading,
617
613
  } ) }
618
614
  role={ view.infiniteScrollEnabled ? 'feed' : 'grid' }
619
615
  activeId={ activeCompositeId }
620
616
  setActiveId={ setActiveCompositeId }
617
+ // @ts-ignore
618
+ inert={
619
+ ! isInfiniteScroll && !! isLoading ? 'true' : undefined
620
+ }
621
621
  >
622
622
  { data.map( ( item, index ) => {
623
623
  const id = generateCompositeItemIdPrefix( item );
@@ -646,7 +646,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
646
646
  );
647
647
  } ) }
648
648
  </Composite>
649
- { hasData && isLoading && (
649
+ { isInfiniteScroll && isLoading && (
650
650
  <p className="dataviews-loading-more">
651
651
  <Spinner />
652
652
  </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
  div.dataviews-view-list {
5
6
  list-style-type: none;
@@ -271,6 +272,10 @@ div.dataviews-view-list {
271
272
  }
272
273
  }
273
274
  }
275
+
276
+ &.is-refreshing {
277
+ @include dataviews-refreshing();
278
+ }
274
279
  }
275
280
 
276
281
  .dataviews-view-list__group-header {
@@ -224,7 +224,7 @@ function ViewPickerTable< Item >( {
224
224
  const headerMenuRefs = useRef<
225
225
  Map< string, { node: HTMLButtonElement; fallback: string } >
226
226
  >( new Map() );
227
- const headerMenuToFocusRef = useRef< HTMLButtonElement >();
227
+ const headerMenuToFocusRef = useRef< HTMLButtonElement >( undefined );
228
228
  const [ nextHeaderMenuToFocus, setNextHeaderMenuToFocus ] =
229
229
  useState< HTMLButtonElement >();
230
230
  const isMultiselect = useIsMultiselectPicker( actions ) ?? false;
@@ -42,6 +42,20 @@ import ColumnPrimary from './column-primary';
42
42
  import { useIsHorizontalScrollEnd } from './use-is-horizontal-scroll-end';
43
43
  import getDataByGroup from '../utils/get-data-by-group';
44
44
  import { PropertiesSection } from '../../dataviews-view-config/properties-section';
45
+ import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
46
+
47
+ function getEffectiveAlign(
48
+ explicitAlign: 'start' | 'center' | 'end' | undefined,
49
+ fieldType: string | undefined
50
+ ): 'start' | 'center' | 'end' | undefined {
51
+ if ( explicitAlign ) {
52
+ return explicitAlign;
53
+ }
54
+ if ( fieldType === 'integer' || fieldType === 'number' ) {
55
+ return 'end';
56
+ }
57
+ return undefined;
58
+ }
45
59
 
46
60
  interface TableColumnFieldProps< Item > {
47
61
  fields: NormalizedField< Item >[];
@@ -225,6 +239,8 @@ function TableRow< Item >( {
225
239
  // Explicit picks the supported styles.
226
240
  const { width, maxWidth, minWidth, align } =
227
241
  view.layout?.styles?.[ column ] ?? {};
242
+ const field = fields.find( ( f ) => f.id === column );
243
+ const effectiveAlign = getEffectiveAlign( align, field?.type );
228
244
 
229
245
  return (
230
246
  <td
@@ -239,7 +255,7 @@ function TableRow< Item >( {
239
255
  fields={ fields }
240
256
  item={ item }
241
257
  column={ column }
242
- align={ align }
258
+ align={ effectiveAlign }
243
259
  />
244
260
  </td>
245
261
  );
@@ -287,13 +303,13 @@ function ViewTable< Item >( {
287
303
  empty,
288
304
  }: ViewTableProps< Item > ) {
289
305
  const { containerRef } = useContext( DataViewsContext );
306
+ const isDelayedLoading = useDelayedLoading( isLoading );
290
307
  const headerMenuRefs = useRef<
291
308
  Map< string, { node: HTMLButtonElement; fallback: string } >
292
309
  >( new Map() );
293
- const headerMenuToFocusRef = useRef< HTMLButtonElement >();
310
+ const headerMenuToFocusRef = useRef< HTMLButtonElement >( undefined );
294
311
  const [ nextHeaderMenuToFocus, setNextHeaderMenuToFocus ] =
295
312
  useState< HTMLButtonElement >();
296
- const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
297
313
  const [ contextMenuAnchor, setContextMenuAnchor ] = useState< {
298
314
  getBoundingClientRect: () => DOMRect;
299
315
  } | null >( null );
@@ -312,6 +328,8 @@ function ViewTable< Item >( {
312
328
  enabled: !! actions?.length,
313
329
  } );
314
330
 
331
+ const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
332
+
315
333
  if ( nextHeaderMenuToFocus ) {
316
334
  // If we need to force focus, we short-circuit rendering here
317
335
  // to prevent any additional work while we handle that.
@@ -382,6 +400,18 @@ function ViewTable< Item >( {
382
400
  };
383
401
  const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
384
402
  const isRtl = isRTL();
403
+ if ( ! hasData ) {
404
+ return (
405
+ <div
406
+ className={ clsx( 'dataviews-no-results', {
407
+ 'is-refreshing': isDelayedLoading,
408
+ } ) }
409
+ id={ tableNoticeId }
410
+ >
411
+ { empty }
412
+ </div>
413
+ );
414
+ }
385
415
 
386
416
  return (
387
417
  <>
@@ -393,10 +423,13 @@ function ViewTable< Item >( {
393
423
  view.layout.density
394
424
  ),
395
425
  'has-bulk-actions': hasBulkActions,
426
+ 'is-refreshing': ! isInfiniteScroll && isDelayedLoading,
396
427
  } ) }
397
428
  aria-busy={ isLoading }
398
429
  aria-describedby={ tableNoticeId }
399
430
  role={ isInfiniteScroll ? 'feed' : undefined }
431
+ // @ts-ignore Reason: inert is a recent HTML attribute
432
+ inert={ ! isInfiniteScroll && isLoading ? 'true' : undefined }
400
433
  >
401
434
  <colgroup>
402
435
  { hasBulkActions && (
@@ -482,6 +515,13 @@ function ViewTable< Item >( {
482
515
  // Explicit picks the supported styles.
483
516
  const { width, maxWidth, minWidth, align } =
484
517
  view.layout?.styles?.[ column ] ?? {};
518
+ const field = fields.find(
519
+ ( f ) => f.id === column
520
+ );
521
+ const effectiveAlign = getEffectiveAlign(
522
+ align,
523
+ field?.type
524
+ );
485
525
  const canInsertOrMove =
486
526
  view.layout?.enableMoving ?? true;
487
527
  return (
@@ -491,7 +531,7 @@ function ViewTable< Item >( {
491
531
  width,
492
532
  maxWidth,
493
533
  minWidth,
494
- textAlign: align,
534
+ textAlign: effectiveAlign,
495
535
  } }
496
536
  aria-sort={
497
537
  view.sort?.direction &&
@@ -633,27 +673,13 @@ function ViewTable< Item >( {
633
673
  </tbody>
634
674
  ) }
635
675
  </table>
636
- <div
637
- className={ clsx( {
638
- 'dataviews-loading': isLoading,
639
- 'dataviews-no-results': ! hasData && ! isLoading,
640
- } ) }
641
- id={ tableNoticeId }
642
- >
643
- { ! hasData &&
644
- ( isLoading ? (
645
- <p>
646
- <Spinner />
647
- </p>
648
- ) : (
649
- empty
650
- ) ) }
651
- { hasData && isLoading && (
676
+ { isInfiniteScroll && isLoading && (
677
+ <div className="dataviews-loading" id={ tableNoticeId }>
652
678
  <p className="dataviews-loading-more">
653
679
  <Spinner />
654
680
  </p>
655
- ) }
656
- </div>
681
+ </div>
682
+ ) }
657
683
  </>
658
684
  );
659
685
  }
@@ -2,6 +2,7 @@
2
2
  @use "@wordpress/base-styles/mixins" as *;
3
3
  @use "@wordpress/base-styles/variables" as *;
4
4
  @use "@wordpress/base-styles/z-index" as *;
5
+ @use "../../../dataviews/style" as *;
5
6
 
6
7
  .dataviews-view-table {
7
8
  width: 100%;
@@ -155,12 +156,12 @@
155
156
 
156
157
  &:has(.dataviews-view-table-header-button):first-child {
157
158
  // Table cell padding minus the header button padding.
158
- padding-left: $grid-unit-50;
159
+ padding-left: $grid-unit-20;
159
160
  }
160
161
 
161
162
  &:has(.dataviews-view-table-header-button):last-child {
162
163
  // Table cell padding minus the header button padding.
163
- padding-right: $grid-unit-50;
164
+ padding-right: $grid-unit-20;
164
165
  }
165
166
  }
166
167
  }
@@ -176,6 +177,7 @@
176
177
 
177
178
  &.dataviews-view-table__cell-align-end {
178
179
  justify-content: flex-end;
180
+ font-variant-numeric: tabular-nums;
179
181
  }
180
182
 
181
183
  &.dataviews-view-table__cell-align-center {
@@ -309,3 +311,7 @@
309
311
  .dataviews-view-table col[class^="dataviews-view-table__col-"]:not(.dataviews-view-table__col-first-data) {
310
312
  width: 1%;
311
313
  }
314
+
315
+ .dataviews-view-table.is-refreshing {
316
+ @include dataviews-refreshing();
317
+ }
@@ -62,6 +62,11 @@ export const LayoutPanel = {
62
62
  description: 'Chooses how to open the panel.',
63
63
  options: [ 'default', 'dropdown', 'modal' ],
64
64
  },
65
+ editVisibility: {
66
+ control: { type: 'select' },
67
+ description: 'Chooses when the edit icon is visible.',
68
+ options: [ 'default', 'always', 'on-hover' ],
69
+ },
65
70
  },
66
71
  };
67
72
 
@@ -7,7 +7,13 @@ import { useMemo, useState } from '@wordpress/element';
7
7
  * Internal dependencies
8
8
  */
9
9
  import DataForm from '../index';
10
- import type { Field, Form, Layout, PanelLayout } from '../../types';
10
+ import type {
11
+ Field,
12
+ Form,
13
+ Layout,
14
+ PanelLayout,
15
+ EditVisibility,
16
+ } from '../../types';
11
17
 
12
18
  type SamplePost = {
13
19
  title: string;
@@ -261,10 +267,12 @@ const getPanelLayoutFromStoryArgs = ( {
261
267
  summary,
262
268
  labelPosition,
263
269
  openAs,
270
+ editVisibility,
264
271
  }: {
265
272
  summary?: string[];
266
273
  labelPosition?: 'default' | 'top' | 'side' | 'none';
267
274
  openAs?: 'default' | 'dropdown' | 'modal';
275
+ editVisibility?: 'default' | EditVisibility;
268
276
  } ): Layout | undefined => {
269
277
  const panelLayout: PanelLayout = {
270
278
  type: 'panel',
@@ -282,16 +290,22 @@ const getPanelLayoutFromStoryArgs = ( {
282
290
  panelLayout.summary = summary;
283
291
  }
284
292
 
293
+ if ( editVisibility !== 'default' ) {
294
+ panelLayout.editVisibility = editVisibility;
295
+ }
296
+
285
297
  return panelLayout;
286
298
  };
287
299
 
288
300
  const LayoutPanelComponent = ( {
289
301
  labelPosition,
290
302
  openAs,
303
+ editVisibility,
291
304
  }: {
292
305
  type: 'default' | 'regular' | 'panel' | 'card';
293
306
  labelPosition: 'default' | 'top' | 'side' | 'none';
294
307
  openAs: 'default' | 'dropdown' | 'modal';
308
+ editVisibility: 'default' | EditVisibility;
295
309
  } ) => {
296
310
  const [ post, setPost ] = useState< SamplePost >( {
297
311
  title: 'Hello, World!',
@@ -321,6 +335,7 @@ const LayoutPanelComponent = ( {
321
335
  layout: getPanelLayoutFromStoryArgs( {
322
336
  labelPosition,
323
337
  openAs,
338
+ editVisibility,
324
339
  } ),
325
340
  fields: [
326
341
  'title',
@@ -357,6 +372,7 @@ const LayoutPanelComponent = ( {
357
372
  summary: [ 'origin', 'destination', 'flight_status' ],
358
373
  labelPosition,
359
374
  openAs,
375
+ editVisibility,
360
376
  } ),
361
377
  },
362
378
  {
@@ -367,11 +383,12 @@ const LayoutPanelComponent = ( {
367
383
  summary: [ 'author', 'seat' ],
368
384
  labelPosition,
369
385
  openAs,
386
+ editVisibility,
370
387
  } ),
371
388
  },
372
389
  ],
373
390
  };
374
- }, [ labelPosition, openAs ] );
391
+ }, [ labelPosition, openAs, editVisibility ] );
375
392
 
376
393
  return (
377
394
  <DataForm< SamplePost >
@@ -31,6 +31,7 @@ import DataViewsViewConfig, {
31
31
  ViewTypeMenu,
32
32
  } from '../components/dataviews-view-config';
33
33
  import normalizeFields from '../field-types';
34
+ import useData from '../hooks/use-data';
34
35
  import type { Action, Field, View, SupportedLayouts } from '../types';
35
36
  import type { SelectionOrUpdater } from '../types/private';
36
37
  type ItemWithId = { id: string };
@@ -144,7 +145,7 @@ function DataViews< Item >( {
144
145
  onReset,
145
146
  }: DataViewsProps< Item > ) {
146
147
  const { infiniteScrollHandler } = paginationInfo;
147
- const containerRef = useRef< HTMLDivElement | null >( null );
148
+ const containerRef = useRef< HTMLDivElement >( null );
148
149
  const [ containerWidth, setContainerWidth ] = useState( 0 );
149
150
  const resizeObserverRef = useResizeObserver(
150
151
  ( resizeObserverEntries: any ) => {
@@ -236,6 +237,12 @@ function DataViews< Item >( {
236
237
  [ defaultLayoutsProperty ]
237
238
  );
238
239
 
240
+ const {
241
+ data: displayData,
242
+ paginationInfo: displayPaginationInfo,
243
+ hasInitiallyLoaded,
244
+ } = useData( data, isLoading, paginationInfo );
245
+
239
246
  if ( ! defaultLayouts[ view.type ] ) {
240
247
  return null;
241
248
  }
@@ -247,9 +254,9 @@ function DataViews< Item >( {
247
254
  onChangeView,
248
255
  fields: _fields,
249
256
  actions,
250
- data,
257
+ data: displayData,
251
258
  isLoading,
252
- paginationInfo,
259
+ paginationInfo: displayPaginationInfo,
253
260
  selection: _selection,
254
261
  onChangeSelection: setSelectionWithChange,
255
262
  openedFilter,
@@ -268,6 +275,7 @@ function DataViews< Item >( {
268
275
  setIsShowingFilter,
269
276
  config,
270
277
  empty,
278
+ hasInitiallyLoaded,
271
279
  hasInfiniteScrollHandler: !! infiniteScrollHandler,
272
280
  onReset,
273
281
  } }
@@ -59,13 +59,7 @@ const EmptyComponent = ( {
59
59
  search: '',
60
60
  page: 1,
61
61
  perPage: 10,
62
- layout: {
63
- styles: {
64
- satellites: {
65
- align: 'end' as const,
66
- },
67
- },
68
- },
62
+ layout: {},
69
63
  filters: [],
70
64
  fields: [ 'title', 'description', 'categories' ],
71
65
  } );
@@ -134,11 +134,6 @@ export const FreeCompositionComponent = () => {
134
134
  page: 1,
135
135
  perPage: 10,
136
136
  layout: {
137
- styles: {
138
- satellites: {
139
- align: 'end' as const,
140
- },
141
- },
142
137
  enableMoving: false,
143
138
  },
144
139
  filters: [],
@@ -32,13 +32,7 @@ export const LayoutTableComponent = ( {
32
32
  search: '',
33
33
  page: 1,
34
34
  perPage: 10,
35
- layout: {
36
- styles: {
37
- satellites: {
38
- align: 'end' as const,
39
- },
40
- },
41
- },
35
+ layout: {},
42
36
  filters: [],
43
37
  fields: [ 'categories' ],
44
38
  titleField: 'title',
@@ -23,11 +23,6 @@ const MinimalUIComponent = ( {
23
23
  page: 1,
24
24
  perPage: 10,
25
25
  layout: {
26
- styles: {
27
- satellites: {
28
- align: 'end' as const,
29
- },
30
- },
31
26
  enableMoving: false,
32
27
  },
33
28
  filters: [],
@@ -24,13 +24,7 @@ const WithCardComponent = () => {
24
24
  search: '',
25
25
  page: 1,
26
26
  perPage: 10,
27
- layout: {
28
- styles: {
29
- satellites: {
30
- align: 'end' as const,
31
- },
32
- },
33
- },
27
+ layout: {},
34
28
  filters: [],
35
29
  fields: [ 'categories' ],
36
30
  titleField: 'title',
@@ -2,6 +2,16 @@
2
2
  @use "@wordpress/base-styles/variables" as *;
3
3
  @use "@wordpress/base-styles/mixins" as *;
4
4
 
5
+ @mixin dataviews-refreshing {
6
+ opacity: 0.5;
7
+ pointer-events: none;
8
+
9
+ @media not (prefers-reduced-motion) {
10
+ opacity: 1;
11
+ animation: dataviews-pulse 1s ease-in-out infinite;
12
+ }
13
+ }
14
+
5
15
  .dataviews-wrapper,
6
16
  .dataviews-picker-wrapper {
7
17
  height: 100%;
@@ -44,6 +54,21 @@
44
54
  }
45
55
  }
46
56
 
57
+ .dataviews-no-results.is-refreshing {
58
+ @include dataviews-refreshing();
59
+ }
60
+
61
+ @keyframes dataviews-pulse {
62
+ 0%,
63
+ 100% {
64
+ opacity: 1;
65
+ }
66
+
67
+ 50% {
68
+ opacity: 0.5;
69
+ }
70
+ }
71
+
47
72
  .dataviews-loading-more {
48
73
  text-align: center;
49
74
  }
@@ -128,7 +128,7 @@ function DataViewsPicker< Item >( {
128
128
  empty,
129
129
  }: DataViewsPickerProps< Item > ) {
130
130
  const { infiniteScrollHandler } = paginationInfo;
131
- const containerRef = useRef< HTMLDivElement | null >( null );
131
+ const containerRef = useRef< HTMLDivElement >( null );
132
132
  const [ containerWidth, setContainerWidth ] = useState( 0 );
133
133
  const resizeObserverRef = useResizeObserver(
134
134
  ( resizeObserverEntries: any ) => {
@@ -237,6 +237,7 @@ function DataViewsPicker< Item >( {
237
237
  config,
238
238
  itemListLabel,
239
239
  empty,
240
+ hasInitiallyLoaded: true,
240
241
  hasInfiniteScrollHandler: !! infiniteScrollHandler,
241
242
  } }
242
243
  >