@wordpress/dataviews 13.0.0 → 13.1.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 (156) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +2 -1
  3. package/build/components/dataform-controls/date.cjs +11 -1
  4. package/build/components/dataform-controls/date.cjs.map +2 -2
  5. package/build/components/dataform-controls/datetime.cjs +23 -32
  6. package/build/components/dataform-controls/datetime.cjs.map +2 -2
  7. package/build/components/dataform-controls/utils/relative-date-control.cjs +2 -1
  8. package/build/components/dataform-controls/utils/relative-date-control.cjs.map +2 -2
  9. package/build/components/dataform-layouts/normalize-form.cjs +19 -1
  10. package/build/components/dataform-layouts/normalize-form.cjs.map +2 -2
  11. package/build/components/dataform-layouts/panel/index.cjs +1 -1
  12. package/build/components/dataform-layouts/panel/index.cjs.map +2 -2
  13. package/build/components/dataform-layouts/panel/modal.cjs +4 -3
  14. package/build/components/dataform-layouts/panel/modal.cjs.map +2 -2
  15. package/build/components/dataviews-layout/index.cjs +12 -3
  16. package/build/components/dataviews-layout/index.cjs.map +2 -2
  17. package/build/components/dataviews-layouts/grid/composite-grid.cjs +5 -1
  18. package/build/components/dataviews-layouts/grid/composite-grid.cjs.map +2 -2
  19. package/build/components/dataviews-layouts/index.cjs +3 -3
  20. package/build/components/dataviews-layouts/index.cjs.map +3 -3
  21. package/build/components/dataviews-layouts/picker-grid/index.cjs +13 -2
  22. package/build/components/dataviews-layouts/picker-grid/index.cjs.map +2 -2
  23. package/build/components/dataviews-layouts/table/index.cjs +98 -89
  24. package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
  25. package/build/components/dataviews-layouts/table/{use-is-horizontal-scroll-end.cjs → use-scroll-state.cjs} +29 -33
  26. package/build/components/dataviews-layouts/table/use-scroll-state.cjs.map +7 -0
  27. package/build/components/dataviews-layouts/utils/density-picker.cjs.map +2 -2
  28. package/build/components/dataviews-layouts/utils/grid-config-options.cjs +45 -0
  29. package/build/components/dataviews-layouts/utils/grid-config-options.cjs.map +7 -0
  30. package/build/dataviews/index.cjs +12 -8
  31. package/build/dataviews/index.cjs.map +2 -2
  32. package/build/dataviews-picker/index.cjs +1 -1
  33. package/build/dataviews-picker/index.cjs.map +2 -2
  34. package/build/types/dataform.cjs.map +1 -1
  35. package/build/types/dataviews.cjs.map +1 -1
  36. package/build-module/components/dataform-controls/date.mjs +11 -1
  37. package/build-module/components/dataform-controls/date.mjs.map +2 -2
  38. package/build-module/components/dataform-controls/datetime.mjs +24 -33
  39. package/build-module/components/dataform-controls/datetime.mjs.map +2 -2
  40. package/build-module/components/dataform-controls/utils/relative-date-control.mjs +2 -1
  41. package/build-module/components/dataform-controls/utils/relative-date-control.mjs.map +2 -2
  42. package/build-module/components/dataform-layouts/normalize-form.mjs +19 -1
  43. package/build-module/components/dataform-layouts/normalize-form.mjs.map +2 -2
  44. package/build-module/components/dataform-layouts/panel/index.mjs +1 -1
  45. package/build-module/components/dataform-layouts/panel/index.mjs.map +2 -2
  46. package/build-module/components/dataform-layouts/panel/modal.mjs +4 -3
  47. package/build-module/components/dataform-layouts/panel/modal.mjs.map +2 -2
  48. package/build-module/components/dataviews-layout/index.mjs +12 -3
  49. package/build-module/components/dataviews-layout/index.mjs.map +2 -2
  50. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs +5 -1
  51. package/build-module/components/dataviews-layouts/grid/composite-grid.mjs.map +2 -2
  52. package/build-module/components/dataviews-layouts/index.mjs +3 -3
  53. package/build-module/components/dataviews-layouts/index.mjs.map +2 -2
  54. package/build-module/components/dataviews-layouts/picker-grid/index.mjs +13 -2
  55. package/build-module/components/dataviews-layouts/picker-grid/index.mjs.map +2 -2
  56. package/build-module/components/dataviews-layouts/table/index.mjs +98 -89
  57. package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
  58. package/build-module/components/dataviews-layouts/table/use-scroll-state.mjs +46 -0
  59. package/build-module/components/dataviews-layouts/table/use-scroll-state.mjs.map +7 -0
  60. package/build-module/components/dataviews-layouts/utils/density-picker.mjs.map +2 -2
  61. package/build-module/components/dataviews-layouts/utils/grid-config-options.mjs +14 -0
  62. package/build-module/components/dataviews-layouts/utils/grid-config-options.mjs.map +7 -0
  63. package/build-module/dataviews/index.mjs +12 -8
  64. package/build-module/dataviews/index.mjs.map +2 -2
  65. package/build-module/dataviews-picker/index.mjs +1 -1
  66. package/build-module/dataviews-picker/index.mjs.map +2 -2
  67. package/build-style/style-rtl.css +47 -5
  68. package/build-style/style.css +47 -5
  69. package/build-types/components/dataform-controls/date.d.ts.map +1 -1
  70. package/build-types/components/dataform-controls/datetime.d.ts.map +1 -1
  71. package/build-types/components/dataform-controls/utils/relative-date-control.d.ts.map +1 -1
  72. package/build-types/components/dataform-layouts/normalize-form.d.ts.map +1 -1
  73. package/build-types/components/dataform-layouts/panel/modal.d.ts.map +1 -1
  74. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  75. package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
  76. package/build-types/components/dataviews-layouts/index.d.ts +3 -3
  77. package/build-types/components/dataviews-layouts/index.d.ts.map +1 -1
  78. package/build-types/components/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
  79. package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
  80. package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts +25 -0
  81. package/build-types/components/dataviews-layouts/table/use-scroll-state.d.ts.map +1 -0
  82. package/build-types/components/dataviews-layouts/utils/density-picker.d.ts.map +1 -1
  83. package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts +2 -0
  84. package/build-types/components/dataviews-layouts/utils/grid-config-options.d.ts.map +1 -0
  85. package/build-types/dataform/stories/index.story.d.ts +26 -1
  86. package/build-types/dataform/stories/index.story.d.ts.map +1 -1
  87. package/build-types/dataform/stories/layout-panel.d.ts +3 -1
  88. package/build-types/dataform/stories/layout-panel.d.ts.map +1 -1
  89. package/build-types/dataviews/index.d.ts.map +1 -1
  90. package/build-types/dataviews/stories/empty.d.ts +1 -2
  91. package/build-types/dataviews/stories/empty.d.ts.map +1 -1
  92. package/build-types/dataviews/stories/free-composition.d.ts.map +1 -1
  93. package/build-types/dataviews/stories/index.story.d.ts +18 -10
  94. package/build-types/dataviews/stories/index.story.d.ts.map +1 -1
  95. package/build-types/dataviews/stories/infinite-scroll.d.ts.map +1 -1
  96. package/build-types/dataviews/stories/layout-activity.d.ts.map +1 -1
  97. package/build-types/dataviews/stories/layout-custom.d.ts +3 -1
  98. package/build-types/dataviews/stories/layout-custom.d.ts.map +1 -1
  99. package/build-types/dataviews/stories/layout-grid.d.ts.map +1 -1
  100. package/build-types/dataviews/stories/layout-list.d.ts.map +1 -1
  101. package/build-types/dataviews/stories/layout-table.d.ts.map +1 -1
  102. package/build-types/dataviews/stories/with-card.d.ts +3 -1
  103. package/build-types/dataviews/stories/with-card.d.ts.map +1 -1
  104. package/build-types/types/dataform.d.ts +17 -2
  105. package/build-types/types/dataform.d.ts.map +1 -1
  106. package/build-types/types/dataviews.d.ts +8 -0
  107. package/build-types/types/dataviews.d.ts.map +1 -1
  108. package/build-wp/index.js +883 -866
  109. package/package.json +19 -19
  110. package/src/components/dataform-controls/date.tsx +11 -1
  111. package/src/components/dataform-controls/datetime.tsx +28 -44
  112. package/src/components/dataform-controls/utils/relative-date-control.tsx +2 -1
  113. package/src/components/dataform-layouts/normalize-form.ts +24 -1
  114. package/src/components/dataform-layouts/panel/index.tsx +1 -1
  115. package/src/components/dataform-layouts/panel/modal.tsx +7 -3
  116. package/src/components/dataform-layouts/panel/style.scss +1 -1
  117. package/src/components/dataform-layouts/test/normalize-form.ts +98 -5
  118. package/src/components/dataviews-layout/index.tsx +41 -19
  119. package/src/components/dataviews-layout/style.scss +8 -0
  120. package/src/components/dataviews-layouts/grid/composite-grid.tsx +7 -1
  121. package/src/components/dataviews-layouts/grid/style.scss +18 -2
  122. package/src/components/dataviews-layouts/index.ts +3 -3
  123. package/src/components/dataviews-layouts/picker-grid/index.tsx +17 -2
  124. package/src/components/dataviews-layouts/picker-grid/style.scss +10 -0
  125. package/src/components/dataviews-layouts/table/index.tsx +11 -5
  126. package/src/components/dataviews-layouts/table/style.scss +13 -0
  127. package/src/components/dataviews-layouts/table/use-scroll-state.ts +79 -0
  128. package/src/components/dataviews-layouts/utils/density-picker.tsx +12 -2
  129. package/src/components/dataviews-layouts/utils/grid-config-options.tsx +14 -0
  130. package/src/components/dataviews-layouts/utils/grid-items.scss +9 -1
  131. package/src/dataform/stories/index.story.tsx +15 -0
  132. package/src/dataform/stories/layout-panel.tsx +19 -4
  133. package/src/dataviews/index.tsx +17 -9
  134. package/src/dataviews/stories/empty.tsx +1 -3
  135. package/src/dataviews/stories/free-composition.tsx +32 -34
  136. package/src/dataviews/stories/index.story.tsx +31 -8
  137. package/src/dataviews/stories/infinite-scroll.tsx +0 -6
  138. package/src/dataviews/stories/layout-activity.tsx +1 -0
  139. package/src/dataviews/stories/layout-custom.tsx +7 -3
  140. package/src/dataviews/stories/layout-grid.tsx +1 -0
  141. package/src/dataviews/stories/layout-list.tsx +1 -0
  142. package/src/dataviews/stories/layout-table.tsx +1 -0
  143. package/src/dataviews/stories/style.css +0 -5
  144. package/src/dataviews/stories/with-card.tsx +6 -2
  145. package/src/dataviews/style.scss +0 -1
  146. package/src/dataviews/test/dataviews.tsx +42 -1
  147. package/src/dataviews-picker/index.tsx +1 -1
  148. package/src/style.scss +1 -0
  149. package/src/types/dataform.ts +15 -2
  150. package/src/types/dataviews.ts +10 -0
  151. package/build/components/dataviews-layouts/table/use-is-horizontal-scroll-end.cjs.map +0 -7
  152. package/build-module/components/dataviews-layouts/table/use-is-horizontal-scroll-end.mjs +0 -50
  153. package/build-module/components/dataviews-layouts/table/use-is-horizontal-scroll-end.mjs.map +0 -7
  154. package/build-types/components/dataviews-layouts/table/use-is-horizontal-scroll-end.d.ts +0 -19
  155. package/build-types/components/dataviews-layouts/table/use-is-horizontal-scroll-end.d.ts.map +0 -1
  156. package/src/components/dataviews-layouts/table/use-is-horizontal-scroll-end.ts +0 -82
@@ -336,7 +336,14 @@ function ViewPickerGrid< Item >( {
336
336
  aria-multiselectable={ isMultiselect }
337
337
  className={ clsx(
338
338
  'dataviews-view-picker-grid',
339
- className
339
+ className,
340
+ {
341
+ [ `has-${ view.layout?.density }-density` ]:
342
+ view.layout?.density &&
343
+ [ 'compact', 'comfortable' ].includes(
344
+ view.layout.density
345
+ ),
346
+ }
340
347
  ) }
341
348
  aria-label={ itemListLabel }
342
349
  render={ ( { children, ...props } ) => (
@@ -421,7 +428,15 @@ function ViewPickerGrid< Item >( {
421
428
  <GridItems
422
429
  className={ clsx(
423
430
  'dataviews-view-picker-grid',
424
- className
431
+ className,
432
+ {
433
+ [ `has-${ view.layout?.density }-density` ]:
434
+ view.layout?.density &&
435
+ [
436
+ 'compact',
437
+ 'comfortable',
438
+ ].includes( view.layout.density ),
439
+ }
425
440
  ) }
426
441
  previewSize={ usedPreviewSize }
427
442
  aria-busy={ isLoading }
@@ -5,6 +5,16 @@
5
5
  @use "../utils/grid-items.scss" as *;
6
6
 
7
7
  .dataviews-view-picker-grid {
8
+ // When grouped, the density class is on the parent Composite,
9
+ // and the gap is on child .dataviews-view-grid-items elements.
10
+ &.has-compact-density .dataviews-view-grid-items {
11
+ gap: $grid-unit-20;
12
+ }
13
+
14
+ &.has-comfortable-density .dataviews-view-grid-items {
15
+ gap: $grid-unit-40;
16
+ }
17
+
8
18
  .dataviews-view-picker-grid__card {
9
19
  height: 100%;
10
20
  justify-content: flex-start;
@@ -39,7 +39,7 @@ import type {
39
39
  import type { SetSelection } from '../../../types/private';
40
40
  import ColumnHeaderMenu from './column-header-menu';
41
41
  import ColumnPrimary from './column-primary';
42
- import { useIsHorizontalScrollEnd } from './use-is-horizontal-scroll-end';
42
+ import { useScrollState } from './use-scroll-state';
43
43
  import getDataByGroup from '../utils/get-data-by-group';
44
44
  import { PropertiesSection } from '../../dataviews-view-config/properties-section';
45
45
  import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
@@ -323,9 +323,9 @@ function ViewTable< Item >( {
323
323
 
324
324
  const tableNoticeId = useId();
325
325
 
326
- const isHorizontalScrollEnd = useIsHorizontalScrollEnd( {
326
+ const { isHorizontalScrollEnd, isVerticallyScrolled } = useScrollState( {
327
327
  scrollContainerRef: containerRef,
328
- enabled: !! actions?.length,
328
+ enabledHorizontal: !! actions?.length,
329
329
  } );
330
330
 
331
331
  const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
@@ -444,7 +444,7 @@ function ViewTable< Item >( {
444
444
  className={ clsx(
445
445
  `dataviews-view-table__col-${ column }`,
446
446
  {
447
- 'dataviews-view-table__col-first-expand':
447
+ 'dataviews-view-table__col-expand':
448
448
  ! hasPrimaryColumn &&
449
449
  index === columns.length - 1,
450
450
  }
@@ -464,7 +464,13 @@ function ViewTable< Item >( {
464
464
  <PropertiesSection showLabel={ false } />
465
465
  </Popover>
466
466
  ) }
467
- <thead onContextMenu={ handleHeaderContextMenu }>
467
+ <thead
468
+ className={ clsx( {
469
+ 'dataviews-view-table__thead--stuck':
470
+ isVerticallyScrolled,
471
+ } ) }
472
+ onContextMenu={ handleHeaderContextMenu }
473
+ >
468
474
  <tr className="dataviews-view-table__row">
469
475
  { hasBulkActions && (
470
476
  <th
@@ -134,6 +134,19 @@
134
134
  z-index: z-index(".dataviews-view-table thead");
135
135
  background-color: inherit;
136
136
 
137
+ &.dataviews-view-table__thead--stuck {
138
+ &::after {
139
+ display: block;
140
+ content: "";
141
+ position: absolute;
142
+ bottom: 0;
143
+ left: 0;
144
+ right: 0;
145
+ height: 1px;
146
+ background-color: $gray-100;
147
+ }
148
+ }
149
+
137
150
  tr {
138
151
  border: 0;
139
152
  }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { MutableRefObject } from 'react';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { useCallback, useEffect, useState } from '@wordpress/element';
10
+ import { isRTL } from '@wordpress/i18n';
11
+
12
+ const isScrolledToEnd = ( element: Element ) => {
13
+ if ( isRTL() ) {
14
+ const scrollLeft = Math.abs( element.scrollLeft );
15
+ return scrollLeft <= 1;
16
+ }
17
+
18
+ return element.scrollLeft + element.clientWidth >= element.scrollWidth - 1;
19
+ };
20
+
21
+ /**
22
+ * A hook to track the scroll state of a container element.
23
+ *
24
+ * Returns whether the container has been scrolled vertically (for sticky header styling)
25
+ * and whether it has reached the horizontal scroll end (for sticky actions column styling).
26
+ *
27
+ * The current way receives "refs" as arguments, but it lacks a mechanism to detect when a ref has changed.
28
+ * As a result, when the "ref" is updated and attached to a new div, the computation should trigger again.
29
+ * However, this isn't possible in the current setup because the hook is unaware that the ref has changed.
30
+ *
31
+ * See https://github.com/Automattic/wp-calypso/pull/103005#discussion_r2077567912.
32
+ *
33
+ * @param {Object} params The parameters for the hook.
34
+ * @param {MutableRefObject<HTMLDivElement | null>} params.scrollContainerRef The ref to the scroll container element.
35
+ * @param {boolean} [params.enabledHorizontal=false] Whether to track horizontal scroll end.
36
+ * @return {{ isHorizontalScrollEnd: boolean, isVerticallyScrolled: boolean }} The scroll state.
37
+ */
38
+ export function useScrollState( {
39
+ scrollContainerRef,
40
+ enabledHorizontal = false,
41
+ }: {
42
+ scrollContainerRef: React.MutableRefObject< HTMLDivElement | null >;
43
+ enabledHorizontal?: boolean;
44
+ } ): { isHorizontalScrollEnd: boolean; isVerticallyScrolled: boolean } {
45
+ const [ isHorizontalScrollEnd, setIsHorizontalScrollEnd ] =
46
+ useState( false );
47
+ const [ isVerticallyScrolled, setIsVerticallyScrolled ] = useState( false );
48
+
49
+ const handleScroll = useCallback( () => {
50
+ const scrollContainer = scrollContainerRef.current;
51
+ if ( ! scrollContainer ) {
52
+ return;
53
+ }
54
+
55
+ if ( enabledHorizontal ) {
56
+ setIsHorizontalScrollEnd( isScrolledToEnd( scrollContainer ) );
57
+ }
58
+
59
+ setIsVerticallyScrolled( scrollContainer.scrollTop > 0 );
60
+ }, [ scrollContainerRef, enabledHorizontal ] );
61
+ useEffect( () => {
62
+ if ( typeof window === 'undefined' || ! scrollContainerRef.current ) {
63
+ return () => {};
64
+ }
65
+
66
+ const scrollContainer = scrollContainerRef.current;
67
+
68
+ handleScroll();
69
+ scrollContainer.addEventListener( 'scroll', handleScroll );
70
+ window.addEventListener( 'resize', handleScroll );
71
+
72
+ return () => {
73
+ scrollContainer.removeEventListener( 'scroll', handleScroll );
74
+ window.removeEventListener( 'resize', handleScroll );
75
+ };
76
+ }, [ scrollContainerRef, enabledHorizontal, handleScroll ] );
77
+
78
+ return { isHorizontalScrollEnd, isVerticallyScrolled };
79
+ }
@@ -12,11 +12,21 @@ import { useContext } from '@wordpress/element';
12
12
  * Internal dependencies
13
13
  */
14
14
  import DataViewsContext from '../../dataviews-context';
15
- import type { ViewTable, ViewList, Density } from '../../../types';
15
+ import type {
16
+ ViewTable,
17
+ ViewList,
18
+ ViewGrid,
19
+ ViewPickerGrid,
20
+ Density,
21
+ } from '../../../types';
16
22
 
17
23
  export default function DensityPicker() {
18
24
  const context = useContext( DataViewsContext );
19
- const view = context.view as ViewTable | ViewList;
25
+ const view = context.view as
26
+ | ViewTable
27
+ | ViewList
28
+ | ViewGrid
29
+ | ViewPickerGrid;
20
30
  return (
21
31
  <ToggleGroupControl
22
32
  size="__unstable-large"
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import DensityPicker from './density-picker';
5
+ import PreviewSizePicker from './preview-size-picker';
6
+
7
+ export default function GridConfigOptions() {
8
+ return (
9
+ <>
10
+ <DensityPicker />
11
+ <PreviewSizePicker />
12
+ </>
13
+ );
14
+ }
@@ -3,7 +3,7 @@
3
3
  .dataviews-view-grid-items {
4
4
  margin-bottom: auto;
5
5
  display: grid;
6
- gap: $grid-unit-40;
6
+ gap: $grid-unit-30;
7
7
  grid-template-rows: max-content;
8
8
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
9
9
  padding: 0 $grid-unit-30 $grid-unit-30;
@@ -12,4 +12,12 @@
12
12
  @media not (prefers-reduced-motion) {
13
13
  transition: padding ease-out 0.1s;
14
14
  }
15
+
16
+ &.has-compact-density {
17
+ gap: $grid-unit-20;
18
+ }
19
+
20
+ &.has-comfortable-density {
21
+ gap: $grid-unit-40;
22
+ }
15
23
  }
@@ -67,6 +67,21 @@ export const LayoutPanel = {
67
67
  description: 'Chooses when the edit icon is visible.',
68
68
  options: [ 'default', 'always', 'on-hover' ],
69
69
  },
70
+ applyLabel: {
71
+ control: { type: 'text' },
72
+ description:
73
+ 'Custom text for the modal apply button. Defaults to "Apply".',
74
+ if: { arg: 'openAs', eq: 'modal' },
75
+ },
76
+ cancelLabel: {
77
+ control: { type: 'text' },
78
+ description:
79
+ 'Custom text for the modal cancel button. Defaults to "Cancel".',
80
+ if: { arg: 'openAs', eq: 'modal' },
81
+ },
82
+ },
83
+ args: {
84
+ openAs: 'default',
70
85
  },
71
86
  };
72
87
 
@@ -275,7 +275,7 @@ const getPanelLayoutFromStoryArgs = ( {
275
275
  }: {
276
276
  summary?: string[];
277
277
  labelPosition?: 'default' | 'top' | 'side' | 'none';
278
- openAs?: 'default' | 'dropdown' | 'modal';
278
+ openAs?: PanelLayout[ 'openAs' ];
279
279
  editVisibility?: 'default' | EditVisibility;
280
280
  } ): Layout | undefined => {
281
281
  const panelLayout: PanelLayout = {
@@ -286,7 +286,7 @@ const getPanelLayoutFromStoryArgs = ( {
286
286
  panelLayout.labelPosition = labelPosition;
287
287
  }
288
288
 
289
- if ( openAs !== 'default' ) {
289
+ if ( openAs ) {
290
290
  panelLayout.openAs = openAs;
291
291
  }
292
292
 
@@ -303,13 +303,17 @@ const getPanelLayoutFromStoryArgs = ( {
303
303
 
304
304
  const LayoutPanelComponent = ( {
305
305
  labelPosition,
306
- openAs,
306
+ openAs: openAsArg,
307
307
  editVisibility,
308
+ applyLabel,
309
+ cancelLabel,
308
310
  }: {
309
311
  type: 'default' | 'regular' | 'panel' | 'card';
310
312
  labelPosition: 'default' | 'top' | 'side' | 'none';
311
313
  openAs: 'default' | 'dropdown' | 'modal';
312
314
  editVisibility: 'default' | EditVisibility;
315
+ applyLabel?: string;
316
+ cancelLabel?: string;
313
317
  } ) => {
314
318
  const [ post, setPost ] = useState< SamplePost >( {
315
319
  title: 'Hello, World!',
@@ -335,6 +339,17 @@ const LayoutPanelComponent = ( {
335
339
  } );
336
340
 
337
341
  const form: Form = useMemo( () => {
342
+ let openAs: PanelLayout[ 'openAs' ];
343
+ if ( openAsArg === 'modal' && ( applyLabel || cancelLabel ) ) {
344
+ openAs = {
345
+ type: 'modal',
346
+ applyLabel: applyLabel || undefined,
347
+ cancelLabel: cancelLabel || undefined,
348
+ };
349
+ } else if ( openAsArg !== 'default' ) {
350
+ openAs = openAsArg;
351
+ }
352
+
338
353
  return {
339
354
  layout: getPanelLayoutFromStoryArgs( {
340
355
  labelPosition,
@@ -392,7 +407,7 @@ const LayoutPanelComponent = ( {
392
407
  },
393
408
  ],
394
409
  };
395
- }, [ labelPosition, openAs, editVisibility ] );
410
+ }, [ labelPosition, openAsArg, applyLabel, cancelLabel, editVisibility ] );
396
411
 
397
412
  return (
398
413
  <DataForm< SamplePost >
@@ -195,9 +195,19 @@ function DataViews< Item >( {
195
195
  }
196
196
  }, [ hasPrimaryOrLockedFilters, isShowingFilter ] );
197
197
 
198
+ const {
199
+ data: displayData,
200
+ paginationInfo: displayPaginationInfo,
201
+ hasInitiallyLoaded,
202
+ } = useData( data, isLoading, paginationInfo );
203
+
198
204
  // Attach scroll event listener for infinite scroll
199
205
  useEffect( () => {
200
- if ( ! view.infiniteScrollEnabled || ! containerRef.current ) {
206
+ if (
207
+ ! hasInitiallyLoaded ||
208
+ ! view.infiniteScrollEnabled ||
209
+ ! containerRef.current
210
+ ) {
201
211
  return;
202
212
  }
203
213
 
@@ -220,7 +230,11 @@ function DataViews< Item >( {
220
230
  container.removeEventListener( 'scroll', handleScroll );
221
231
  handleScroll.cancel(); // Cancel any pending throttled calls
222
232
  };
223
- }, [ infiniteScrollHandler, view.infiniteScrollEnabled ] );
233
+ }, [
234
+ hasInitiallyLoaded,
235
+ infiniteScrollHandler,
236
+ view.infiniteScrollEnabled,
237
+ ] );
224
238
 
225
239
  // Filter out DataViewsPicker layouts.
226
240
  const defaultLayouts = useMemo(
@@ -237,12 +251,6 @@ function DataViews< Item >( {
237
251
  [ defaultLayoutsProperty ]
238
252
  );
239
253
 
240
- const {
241
- data: displayData,
242
- paginationInfo: displayPaginationInfo,
243
- hasInitiallyLoaded,
244
- } = useData( data, isLoading, paginationInfo );
245
-
246
254
  if ( ! defaultLayouts[ view.type ] ) {
247
255
  return null;
248
256
  }
@@ -280,7 +288,7 @@ function DataViews< Item >( {
280
288
  onReset,
281
289
  } }
282
290
  >
283
- <div className="dataviews-wrapper" ref={ containerRef }>
291
+ <div className="dataviews-wrapper">
284
292
  { children ?? (
285
293
  <DefaultUI
286
294
  header={ header }
@@ -47,11 +47,9 @@ const CustomEmptyComponent = () => (
47
47
 
48
48
  const EmptyComponent = ( {
49
49
  customEmpty,
50
- containerHeight,
51
50
  isLoading,
52
51
  }: {
53
52
  customEmpty?: boolean;
54
- containerHeight?: 'auto' | '50vh' | '100vh';
55
53
  isLoading?: boolean;
56
54
  } ) => {
57
55
  const [ view, setView ] = useState< View >( {
@@ -69,7 +67,7 @@ const EmptyComponent = ( {
69
67
  style={ {
70
68
  display: 'flex',
71
69
  flexDirection: 'column',
72
- height: containerHeight,
70
+ height: '100%',
73
71
  } }
74
72
  >
75
73
  <DataViews
@@ -102,9 +102,9 @@ function PlanetOverview( { planets }: { planets: SpaceObject[] } ) {
102
102
  </Stack>
103
103
  </CardBody>
104
104
  </Card>
105
- <DataViews.Layout className="free-composition-dataviews-layout" />
106
105
  </Stack>
107
106
  </div>
107
+ <DataViews.Layout className="free-composition-dataviews-layout" />
108
108
  </>
109
109
  );
110
110
  }
@@ -132,7 +132,7 @@ export const FreeCompositionComponent = () => {
132
132
  type: LAYOUT_TABLE,
133
133
  search: '',
134
134
  page: 1,
135
- perPage: 10,
135
+ perPage: 20,
136
136
  layout: {
137
137
  enableMoving: false,
138
138
  },
@@ -152,38 +152,36 @@ export const FreeCompositionComponent = () => {
152
152
  );
153
153
 
154
154
  return (
155
- <div className="free-composition">
156
- <DataViews
157
- getItemId={ ( item ) => item.id.toString() }
158
- paginationInfo={ paginationInfo }
159
- data={ processedData }
160
- view={ view }
161
- fields={ fields }
162
- actions={ actions }
163
- onChangeView={ setView }
164
- defaultLayouts={ {
165
- table: {},
166
- grid: {},
167
- } }
168
- empty={
169
- <Stack
170
- direction="column"
171
- gap="sm"
172
- justify="space-around"
173
- align="center"
174
- className="free-composition-dataviews-empty"
175
- >
176
- <Text size={ 18 } as="p">
177
- No planets
178
- </Text>
179
- <Text variant="muted">{ `Try a different search because “${ view.search }” returned no results.` }</Text>
180
- <Button variant="secondary">Create new planet</Button>
181
- </Stack>
182
- }
183
- >
184
- <PlanetOverview planets={ planets } />
185
- </DataViews>
186
- </div>
155
+ <DataViews
156
+ getItemId={ ( item ) => item.id.toString() }
157
+ paginationInfo={ paginationInfo }
158
+ data={ processedData }
159
+ view={ view }
160
+ fields={ fields }
161
+ actions={ actions }
162
+ onChangeView={ setView }
163
+ defaultLayouts={ {
164
+ table: {},
165
+ grid: {},
166
+ } }
167
+ empty={
168
+ <Stack
169
+ direction="column"
170
+ gap="sm"
171
+ justify="space-around"
172
+ align="center"
173
+ className="free-composition-dataviews-empty"
174
+ >
175
+ <Text size={ 18 } as="p">
176
+ No planets
177
+ </Text>
178
+ <Text variant="muted">{ `Try a different search because “${ view.search }” returned no results.` }</Text>
179
+ <Button variant="secondary">Create new planet</Button>
180
+ </Stack>
181
+ }
182
+ >
183
+ <PlanetOverview planets={ planets } />
184
+ </DataViews>
187
185
  );
188
186
  };
189
187
 
@@ -23,6 +23,16 @@ import './style.css';
23
23
  const meta = {
24
24
  title: 'DataViews/DataViews',
25
25
  component: DataViews,
26
+ args: {
27
+ containerHeight: 'auto',
28
+ },
29
+ argTypes: {
30
+ containerHeight: {
31
+ control: 'select',
32
+ options: [ 'auto', '600px', '80vh' ],
33
+ description: 'Height of the container',
34
+ },
35
+ },
26
36
  // Use fullscreen layout and a wrapper div with padding to resolve conflicts
27
37
  // between Ariakit's Dialog (usePreventBodyScroll) and Storybook's body padding
28
38
  // (sb-main-padding class). This ensures consistent layout in DataViews stories
@@ -31,9 +41,17 @@ const meta = {
31
41
  layout: 'fullscreen',
32
42
  },
33
43
  decorators: [
34
- ( Story ) => (
44
+ ( Story, { args, parameters }: { args: any; parameters: any } ) => (
35
45
  <div style={ { padding: '1rem' } }>
36
- <Story />
46
+ <div
47
+ style={ {
48
+ height:
49
+ parameters.containerHeight ?? args.containerHeight,
50
+ minHeight: 0,
51
+ } }
52
+ >
53
+ <Story containerHeight={ args.containerHeight } />
54
+ </div>
37
55
  </div>
38
56
  ),
39
57
  ],
@@ -212,7 +230,6 @@ export const Empty = {
212
230
  render: EmptyComponent,
213
231
  args: {
214
232
  customEmpty: false,
215
- containerHeight: '50vh',
216
233
  isLoading: false,
217
234
  },
218
235
  argTypes: {
@@ -220,11 +237,6 @@ export const Empty = {
220
237
  control: 'boolean',
221
238
  description: 'Use custom empty state with planet illustration',
222
239
  },
223
- containerHeight: {
224
- control: 'select',
225
- options: [ 'auto', '50vh', '100vh' ],
226
- description: 'Height of the container',
227
- },
228
240
  isLoading: {
229
241
  control: 'boolean',
230
242
  description: 'Show loading state',
@@ -253,4 +265,15 @@ export const WithCard = {
253
265
 
254
266
  export const InfiniteScroll = {
255
267
  render: InfiniteScrollComponent,
268
+ parameters: {
269
+ containerHeight: '600px',
270
+ },
271
+ argTypes: {
272
+ containerHeight: {
273
+ control: false,
274
+ table: {
275
+ disable: true,
276
+ },
277
+ },
278
+ },
256
279
  };
@@ -106,12 +106,6 @@ const InfiniteScroll = () => {
106
106
 
107
107
  return (
108
108
  <>
109
- <style>{ `
110
- .dataviews-wrapper {
111
- height: 600px;
112
- overflow: auto;
113
- }
114
- ` }</style>
115
109
  <Text
116
110
  style={ {
117
111
  marginBottom: '16px',
@@ -642,6 +642,7 @@ const LayoutActivityComponent = ( {
642
642
  <div
643
643
  style={
644
644
  {
645
+ height: '100%',
645
646
  maxWidth: fullWidth ? undefined : '400px',
646
647
  '--wp-dataviews-color-background': backgroundColor,
647
648
  } as React.CSSProperties
@@ -104,7 +104,11 @@ function PosterGrid( { items }: { items: typeof data } ) {
104
104
  * - Render a completely custom layout (poster grid) instead of `<DataViews.Layout />`
105
105
  * - Still leverage DataViews sub-components for search and pagination
106
106
  */
107
- export const LayoutCustomComponent = () => {
107
+ export const LayoutCustomComponent = ( {
108
+ containerHeight,
109
+ }: {
110
+ containerHeight: string;
111
+ } ) => {
108
112
  const [ view, setView ] = useState< View >( {
109
113
  type: LAYOUT_TABLE,
110
114
  search: '',
@@ -128,11 +132,11 @@ export const LayoutCustomComponent = () => {
128
132
  onChangeView={ setView }
129
133
  defaultLayouts={ { table: {} } }
130
134
  >
131
- <div style={ { padding: '2px' } }>
135
+ <div style={ { padding: '2px', height: containerHeight } }>
132
136
  <DataViews.Search />
133
137
  <PosterGrid items={ processedData } />
134
- <DataViews.Pagination />
135
138
  </div>
139
+ <DataViews.Pagination />
136
140
  </DataViews>
137
141
  );
138
142
  };
@@ -63,6 +63,7 @@ export const LayoutTableComponent = ( {
63
63
  <div
64
64
  style={
65
65
  {
66
+ height: '100%',
66
67
  '--wp-dataviews-color-background': backgroundColor,
67
68
  } as React.CSSProperties
68
69
  }
@@ -65,6 +65,7 @@ export const LayoutTableComponent = ( {
65
65
  <div
66
66
  style={
67
67
  {
68
+ height: '100%',
68
69
  maxWidth: fullWidth ? undefined : '400px',
69
70
  '--wp-dataviews-color-background': backgroundColor,
70
71
  } as React.CSSProperties
@@ -64,6 +64,7 @@ export const LayoutTableComponent = ( {
64
64
  <div
65
65
  style={
66
66
  {
67
+ height: '100%',
67
68
  '--wp-dataviews-color-background': backgroundColor,
68
69
  } as React.CSSProperties
69
70
  }
@@ -3,11 +3,6 @@
3
3
  text-wrap: pretty;
4
4
  }
5
5
 
6
- .free-composition {
7
- height: 600px;
8
- overflow: auto;
9
- }
10
-
11
6
  .free-composition-heading,
12
7
  .free-composition-header {
13
8
  padding: 16px 48px;