@wordpress/dataviews 17.1.0 → 17.1.2-next.v.202607070741.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.
- package/CHANGELOG.md +12 -1
- package/build/components/dataform-controls/select.cjs +0 -1
- package/build/components/dataform-controls/select.cjs.map +2 -2
- package/build/components/dataform-controls/toggle-group.cjs +0 -1
- package/build/components/dataform-controls/toggle-group.cjs.map +2 -2
- package/build/components/dataform-controls/utils/relative-date-control.cjs +0 -1
- package/build/components/dataform-controls/utils/relative-date-control.cjs.map +2 -2
- package/build/components/dataviews-footer/index.cjs +6 -2
- package/build/components/dataviews-footer/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/grid/preview-size-picker.cjs +0 -1
- package/build/components/dataviews-layouts/grid/preview-size-picker.cjs.map +2 -2
- package/build/components/dataviews-layouts/list/index.cjs +13 -1
- package/build/components/dataviews-layouts/list/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/utils/density-picker.cjs +0 -1
- package/build/components/dataviews-layouts/utils/density-picker.cjs.map +2 -2
- package/build/components/dataviews-layouts/utils/preview-size-picker.cjs +0 -1
- package/build/components/dataviews-layouts/utils/preview-size-picker.cjs.map +2 -2
- package/build/components/dataviews-pagination/index.cjs +12 -13
- package/build/components/dataviews-pagination/index.cjs.map +2 -2
- package/build/components/dataviews-view-config/index.cjs +0 -3
- package/build/components/dataviews-view-config/index.cjs.map +2 -2
- package/build/dataform/index.cjs.map +2 -2
- package/build/dataviews/index.cjs.map +2 -2
- package/build/dataviews-picker/index.cjs.map +2 -2
- package/build/hooks/use-infinite-scroll.cjs +2 -1
- package/build/hooks/use-infinite-scroll.cjs.map +2 -2
- package/build-module/components/dataform-controls/select.mjs +0 -1
- package/build-module/components/dataform-controls/select.mjs.map +2 -2
- package/build-module/components/dataform-controls/toggle-group.mjs +0 -1
- package/build-module/components/dataform-controls/toggle-group.mjs.map +2 -2
- package/build-module/components/dataform-controls/utils/relative-date-control.mjs +0 -1
- package/build-module/components/dataform-controls/utils/relative-date-control.mjs.map +2 -2
- package/build-module/components/dataviews-footer/index.mjs +9 -3
- package/build-module/components/dataviews-footer/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/grid/preview-size-picker.mjs +0 -1
- package/build-module/components/dataviews-layouts/grid/preview-size-picker.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/list/index.mjs +13 -1
- package/build-module/components/dataviews-layouts/list/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/utils/density-picker.mjs +0 -1
- package/build-module/components/dataviews-layouts/utils/density-picker.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/utils/preview-size-picker.mjs +0 -1
- package/build-module/components/dataviews-layouts/utils/preview-size-picker.mjs.map +2 -2
- package/build-module/components/dataviews-pagination/index.mjs +10 -12
- package/build-module/components/dataviews-pagination/index.mjs.map +2 -2
- package/build-module/components/dataviews-view-config/index.mjs +0 -3
- package/build-module/components/dataviews-view-config/index.mjs.map +2 -2
- package/build-module/dataform/index.mjs.map +2 -2
- package/build-module/dataviews/index.mjs.map +2 -2
- package/build-module/dataviews-picker/index.mjs.map +2 -2
- package/build-module/hooks/use-infinite-scroll.mjs +2 -1
- package/build-module/hooks/use-infinite-scroll.mjs.map +2 -2
- package/build-style/style-rtl.css +9 -2
- package/build-style/style.css +9 -2
- package/build-types/components/dataform-controls/select.d.ts.map +1 -1
- package/build-types/components/dataform-controls/toggle-group.d.ts.map +1 -1
- package/build-types/components/dataform-controls/utils/relative-date-control.d.ts.map +1 -1
- package/build-types/components/dataviews-footer/index.d.ts +1 -1
- package/build-types/components/dataviews-footer/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/grid/preview-size-picker.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/list/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/utils/density-picker.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/utils/preview-size-picker.d.ts.map +1 -1
- package/build-types/components/dataviews-pagination/index.d.ts +6 -1
- package/build-types/components/dataviews-pagination/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/dataform/index.d.ts +5 -0
- package/build-types/dataform/index.d.ts.map +1 -1
- package/build-types/dataviews/index.d.ts +5 -0
- package/build-types/dataviews/index.d.ts.map +1 -1
- package/build-types/dataviews/stories/async-infinite-scroll.d.ts +8 -0
- package/build-types/dataviews/stories/async-infinite-scroll.d.ts.map +1 -0
- package/build-types/dataviews/stories/index.story.d.ts +19 -0
- package/build-types/dataviews/stories/index.story.d.ts.map +1 -1
- package/build-types/dataviews-picker/index.d.ts +5 -0
- package/build-types/dataviews-picker/index.d.ts.map +1 -1
- package/build-types/hooks/use-infinite-scroll.d.ts.map +1 -1
- package/build-wp/index.js +1476 -1227
- package/package.json +17 -17
- package/src/components/dataform-controls/select.tsx +0 -1
- package/src/components/dataform-controls/toggle-group.tsx +0 -1
- package/src/components/dataform-controls/utils/relative-date-control.tsx +0 -1
- package/src/components/dataviews-footer/index.tsx +27 -26
- package/src/components/dataviews-layouts/grid/preview-size-picker.tsx +0 -1
- package/src/components/dataviews-layouts/list/index.tsx +14 -2
- package/src/components/dataviews-layouts/utils/density-picker.tsx +0 -1
- package/src/components/dataviews-layouts/utils/preview-size-picker.tsx +0 -1
- package/src/components/dataviews-pagination/index.tsx +82 -78
- package/src/components/dataviews-view-config/index.tsx +0 -3
- package/src/components/dataviews-view-config/style.scss +0 -1
- package/src/dataform/index.tsx +5 -0
- package/src/dataviews/index.tsx +5 -0
- package/src/dataviews/stories/async-infinite-scroll.tsx +115 -0
- package/src/dataviews/stories/index.story.tsx +27 -0
- package/src/dataviews/style.scss +5 -1
- package/src/dataviews-picker/index.tsx +5 -0
- package/src/hooks/use-infinite-scroll.ts +10 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/dataviews",
|
|
3
|
-
"version": "17.1.0",
|
|
3
|
+
"version": "17.1.2-next.v.202607070741.0+a51d59513",
|
|
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",
|
|
@@ -51,21 +51,21 @@
|
|
|
51
51
|
"types": "build-types",
|
|
52
52
|
"sideEffects": false,
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@ariakit/react": "^0.4.
|
|
55
|
-
"@wordpress/base-styles": "^10.
|
|
56
|
-
"@wordpress/components": "^
|
|
57
|
-
"@wordpress/compose": "^8.3.0",
|
|
58
|
-
"@wordpress/data": "^10.50.0",
|
|
59
|
-
"@wordpress/date": "^5.50.0",
|
|
60
|
-
"@wordpress/deprecated": "^4.50.0",
|
|
61
|
-
"@wordpress/element": "^8.2.0",
|
|
62
|
-
"@wordpress/i18n": "^6.23.0",
|
|
63
|
-
"@wordpress/icons": "^15.1.0",
|
|
64
|
-
"@wordpress/keycodes": "^4.50.0",
|
|
65
|
-
"@wordpress/primitives": "^4.50.0",
|
|
66
|
-
"@wordpress/private-apis": "^1.50.0",
|
|
67
|
-
"@wordpress/ui": "^0.
|
|
68
|
-
"@wordpress/warning": "^3.50.0",
|
|
54
|
+
"@ariakit/react": "^0.4.32",
|
|
55
|
+
"@wordpress/base-styles": "^10.3.1-next.v.202607070741.0+a51d59513",
|
|
56
|
+
"@wordpress/components": "^37.0.1-next.v.202607070741.0+a51d59513",
|
|
57
|
+
"@wordpress/compose": "^8.3.1-next.v.202607070741.0+a51d59513",
|
|
58
|
+
"@wordpress/data": "^10.50.1-next.v.202607070741.0+a51d59513",
|
|
59
|
+
"@wordpress/date": "^5.50.1-next.v.202607070741.0+a51d59513",
|
|
60
|
+
"@wordpress/deprecated": "^4.50.1-next.v.202607070741.0+a51d59513",
|
|
61
|
+
"@wordpress/element": "^8.2.1-next.v.202607070741.0+a51d59513",
|
|
62
|
+
"@wordpress/i18n": "^6.23.1-next.v.202607070741.0+a51d59513",
|
|
63
|
+
"@wordpress/icons": "^15.1.1-next.v.202607070741.0+a51d59513",
|
|
64
|
+
"@wordpress/keycodes": "^4.50.1-next.v.202607070741.0+a51d59513",
|
|
65
|
+
"@wordpress/primitives": "^4.50.1-next.v.202607070741.0+a51d59513",
|
|
66
|
+
"@wordpress/private-apis": "^1.50.1-next.v.202607070741.0+a51d59513",
|
|
67
|
+
"@wordpress/ui": "^0.18.1-next.v.202607070741.0+a51d59513",
|
|
68
|
+
"@wordpress/warning": "^3.50.1-next.v.202607070741.0+a51d59513",
|
|
69
69
|
"clsx": "^2.1.1",
|
|
70
70
|
"colord": "^2.9.3",
|
|
71
71
|
"date-fns": "^4.1.0",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"scripts": {
|
|
101
101
|
"build:wp": "node build.cjs"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "f637726e370c8b23695ed9af82adbe171ad235d8"
|
|
104
104
|
}
|
|
@@ -55,7 +55,6 @@ export default function ToggleGroup< Item >( {
|
|
|
55
55
|
required={ !! field.isValid?.required }
|
|
56
56
|
markWhenOptional={ markWhenOptional }
|
|
57
57
|
customValidity={ getCustomValidity( isValid, validity ) }
|
|
58
|
-
__next40pxDefaultSize
|
|
59
58
|
isBlock
|
|
60
59
|
label={ field.label }
|
|
61
60
|
help={ selectedOption?.description || field.description }
|
|
@@ -13,7 +13,9 @@ import { Stack } from '@wordpress/ui';
|
|
|
13
13
|
* Internal dependencies
|
|
14
14
|
*/
|
|
15
15
|
import DataViewsContext from '../dataviews-context';
|
|
16
|
-
import DataViewsPagination
|
|
16
|
+
import DataViewsPagination, {
|
|
17
|
+
hasPaginationControls,
|
|
18
|
+
} from '../dataviews-pagination';
|
|
17
19
|
import {
|
|
18
20
|
BulkActionsFooter,
|
|
19
21
|
useSomeItemHasAPossibleBulkAction,
|
|
@@ -41,34 +43,33 @@ export default function DataViewsFooter() {
|
|
|
41
43
|
useSomeItemHasAPossibleBulkAction( actions, data ) &&
|
|
42
44
|
[ LAYOUT_TABLE, LAYOUT_GRID ].includes( view.type );
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
) {
|
|
46
|
+
const hasPagination = hasPaginationControls( view, {
|
|
47
|
+
totalItems,
|
|
48
|
+
totalPages,
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
if ( ! totalItems || ( ! hasBulkActions && ! hasPagination ) ) {
|
|
50
52
|
return null;
|
|
51
53
|
}
|
|
54
|
+
|
|
52
55
|
return (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
<div
|
|
57
|
+
className="dataviews-footer"
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
inert={ isRefreshing ? 'true' : undefined }
|
|
60
|
+
>
|
|
61
|
+
<Stack
|
|
62
|
+
direction="row"
|
|
63
|
+
justify="end"
|
|
64
|
+
align="center"
|
|
65
|
+
className={ clsx( 'dataviews-footer__content', {
|
|
66
|
+
'is-refreshing': isDelayedRefreshing,
|
|
67
|
+
} ) }
|
|
68
|
+
gap="sm"
|
|
58
69
|
>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
className={ clsx( 'dataviews-footer__content', {
|
|
64
|
-
'is-refreshing': isDelayedRefreshing,
|
|
65
|
-
} ) }
|
|
66
|
-
gap="sm"
|
|
67
|
-
>
|
|
68
|
-
{ hasBulkActions && <BulkActionsFooter /> }
|
|
69
|
-
<DataViewsPagination />
|
|
70
|
-
</Stack>
|
|
71
|
-
</div>
|
|
72
|
-
)
|
|
70
|
+
{ hasBulkActions && <BulkActionsFooter /> }
|
|
71
|
+
<DataViewsPagination />
|
|
72
|
+
</Stack>
|
|
73
|
+
</div>
|
|
73
74
|
);
|
|
74
75
|
}
|
|
@@ -394,6 +394,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
394
394
|
} = props;
|
|
395
395
|
const baseId = useInstanceId( ViewList, 'view-list' );
|
|
396
396
|
const isDelayedLoading = useDelayedLoading( !! isLoading );
|
|
397
|
+
const { paginationInfo } = useContext( DataViewsContext );
|
|
397
398
|
|
|
398
399
|
const selectedItem = data?.findLast( ( item ) =>
|
|
399
400
|
selection.includes( getItemId( item ) )
|
|
@@ -535,6 +536,11 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
535
536
|
const dataByGroup =
|
|
536
537
|
hasData && groupField ? getDataByGroup( data, groupField ) : null;
|
|
537
538
|
const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
|
|
539
|
+
// Whether the server has more rows beyond the current window.
|
|
540
|
+
const hasMoreItems =
|
|
541
|
+
isInfiniteScroll &&
|
|
542
|
+
( view.startPosition ?? 1 ) + ( view.perPage ?? 0 ) <
|
|
543
|
+
paginationInfo.totalItems;
|
|
538
544
|
if ( ! hasData ) {
|
|
539
545
|
return (
|
|
540
546
|
<div
|
|
@@ -663,8 +669,14 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
663
669
|
);
|
|
664
670
|
} ) }
|
|
665
671
|
</Composite>
|
|
666
|
-
{ isInfiniteScroll && isLoading && (
|
|
667
|
-
|
|
672
|
+
{ ( hasMoreItems || ( isInfiniteScroll && isLoading ) ) && (
|
|
673
|
+
// Keep the spinner's height reserved while loading more so the
|
|
674
|
+
// scroll position doesn't bounce. Hidden, and silent to a11y,
|
|
675
|
+
// while idle.
|
|
676
|
+
<p
|
|
677
|
+
className="dataviews-loading-more"
|
|
678
|
+
aria-hidden={ ! isLoading }
|
|
679
|
+
>
|
|
668
680
|
<Spinner />
|
|
669
681
|
</p>
|
|
670
682
|
) }
|
|
@@ -11,18 +11,28 @@ import { Stack } from '@wordpress/ui';
|
|
|
11
11
|
* Internal dependencies
|
|
12
12
|
*/
|
|
13
13
|
import DataViewsContext from '../dataviews-context';
|
|
14
|
+
import type { View } from '../../types';
|
|
15
|
+
|
|
16
|
+
export function hasPaginationControls(
|
|
17
|
+
view: View,
|
|
18
|
+
paginationInfo: { totalItems: number; totalPages: number }
|
|
19
|
+
): boolean {
|
|
20
|
+
return (
|
|
21
|
+
! view.infiniteScrollEnabled &&
|
|
22
|
+
paginationInfo.totalItems > 0 &&
|
|
23
|
+
paginationInfo.totalPages > 1
|
|
24
|
+
);
|
|
25
|
+
}
|
|
14
26
|
|
|
15
27
|
export function DataViewsPagination() {
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
onChangeView,
|
|
19
|
-
paginationInfo: { totalItems = 0, totalPages },
|
|
20
|
-
} = useContext( DataViewsContext );
|
|
28
|
+
const { view, onChangeView, paginationInfo } =
|
|
29
|
+
useContext( DataViewsContext );
|
|
21
30
|
|
|
22
|
-
if ( !
|
|
31
|
+
if ( ! hasPaginationControls( view, paginationInfo ) ) {
|
|
23
32
|
return null;
|
|
24
33
|
}
|
|
25
34
|
|
|
35
|
+
const { totalPages } = paginationInfo;
|
|
26
36
|
const currentPage = view.page ?? 1;
|
|
27
37
|
const pageSelectOptions = Array.from( Array( totalPages ) ).map(
|
|
28
38
|
( _, i ) => {
|
|
@@ -44,84 +54,78 @@ export function DataViewsPagination() {
|
|
|
44
54
|
);
|
|
45
55
|
|
|
46
56
|
return (
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
<Stack
|
|
58
|
+
direction="row"
|
|
59
|
+
className="dataviews-pagination"
|
|
60
|
+
justify="end"
|
|
61
|
+
align="center"
|
|
62
|
+
gap="xl"
|
|
63
|
+
>
|
|
49
64
|
<Stack
|
|
50
65
|
direction="row"
|
|
51
|
-
|
|
52
|
-
justify="end"
|
|
66
|
+
justify="flex-start"
|
|
53
67
|
align="center"
|
|
54
|
-
gap="
|
|
68
|
+
gap="xs"
|
|
69
|
+
className="dataviews-pagination__page-select"
|
|
55
70
|
>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
{ createInterpolateElement(
|
|
72
|
+
sprintf(
|
|
73
|
+
// translators: 1: Current page number, 2: Total number of pages.
|
|
74
|
+
_x( '<div>Page</div>%1$s<div>of %2$d</div>', 'paging' ),
|
|
75
|
+
'<CurrentPage />',
|
|
76
|
+
totalPages
|
|
77
|
+
),
|
|
78
|
+
{
|
|
79
|
+
div: <div aria-hidden />,
|
|
80
|
+
// @ts-expect-error — Tag injected via sprintf argument, not visible in format string.
|
|
81
|
+
CurrentPage: (
|
|
82
|
+
<SelectControl
|
|
83
|
+
aria-label={ __( 'Current page' ) }
|
|
84
|
+
value={ currentPage.toString() }
|
|
85
|
+
options={ pageSelectOptions }
|
|
86
|
+
onChange={ ( newValue ) => {
|
|
87
|
+
onChangeView( {
|
|
88
|
+
...view,
|
|
89
|
+
page: +newValue,
|
|
90
|
+
} );
|
|
91
|
+
} }
|
|
92
|
+
size="small"
|
|
93
|
+
variant="minimal"
|
|
94
|
+
/>
|
|
72
95
|
),
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
label={ __( 'Previous page' ) }
|
|
105
|
-
icon={ isRTL() ? next : previous }
|
|
106
|
-
showTooltip
|
|
107
|
-
size="compact"
|
|
108
|
-
tooltipPosition="top"
|
|
109
|
-
/>
|
|
110
|
-
<Button
|
|
111
|
-
onClick={ () =>
|
|
112
|
-
onChangeView( { ...view, page: currentPage + 1 } )
|
|
113
|
-
}
|
|
114
|
-
disabled={ currentPage >= totalPages }
|
|
115
|
-
accessibleWhenDisabled
|
|
116
|
-
label={ __( 'Next page' ) }
|
|
117
|
-
icon={ isRTL() ? previous : next }
|
|
118
|
-
showTooltip
|
|
119
|
-
size="compact"
|
|
120
|
-
tooltipPosition="top"
|
|
121
|
-
/>
|
|
122
|
-
</Stack>
|
|
96
|
+
}
|
|
97
|
+
) }
|
|
98
|
+
</Stack>
|
|
99
|
+
<Stack direction="row" gap="xs" align="center">
|
|
100
|
+
<Button
|
|
101
|
+
onClick={ () =>
|
|
102
|
+
onChangeView( {
|
|
103
|
+
...view,
|
|
104
|
+
page: currentPage - 1,
|
|
105
|
+
} )
|
|
106
|
+
}
|
|
107
|
+
disabled={ currentPage === 1 }
|
|
108
|
+
accessibleWhenDisabled
|
|
109
|
+
label={ __( 'Previous page' ) }
|
|
110
|
+
icon={ isRTL() ? next : previous }
|
|
111
|
+
showTooltip
|
|
112
|
+
size="compact"
|
|
113
|
+
tooltipPosition="top"
|
|
114
|
+
/>
|
|
115
|
+
<Button
|
|
116
|
+
onClick={ () =>
|
|
117
|
+
onChangeView( { ...view, page: currentPage + 1 } )
|
|
118
|
+
}
|
|
119
|
+
disabled={ currentPage >= totalPages }
|
|
120
|
+
accessibleWhenDisabled
|
|
121
|
+
label={ __( 'Next page' ) }
|
|
122
|
+
icon={ isRTL() ? previous : next }
|
|
123
|
+
showTooltip
|
|
124
|
+
size="compact"
|
|
125
|
+
tooltipPosition="top"
|
|
126
|
+
/>
|
|
123
127
|
</Stack>
|
|
124
|
-
|
|
128
|
+
</Stack>
|
|
125
129
|
);
|
|
126
130
|
}
|
|
127
131
|
|
|
@@ -125,7 +125,6 @@ function SortFieldControl() {
|
|
|
125
125
|
|
|
126
126
|
return (
|
|
127
127
|
<SelectControl
|
|
128
|
-
__next40pxDefaultSize
|
|
129
128
|
label={ __( 'Sort by' ) }
|
|
130
129
|
value={ view.sort?.field }
|
|
131
130
|
options={ orderOptions }
|
|
@@ -160,7 +159,6 @@ function SortDirectionControl() {
|
|
|
160
159
|
return (
|
|
161
160
|
<ToggleGroupControl
|
|
162
161
|
className="dataviews-view-config__sort-direction"
|
|
163
|
-
__next40pxDefaultSize
|
|
164
162
|
isBlock
|
|
165
163
|
label={ __( 'Order' ) }
|
|
166
164
|
value={ value }
|
|
@@ -214,7 +212,6 @@ function ItemsPerPageControl() {
|
|
|
214
212
|
|
|
215
213
|
return (
|
|
216
214
|
<ToggleGroupControl
|
|
217
|
-
__next40pxDefaultSize
|
|
218
215
|
isBlock
|
|
219
216
|
label={ __( 'Items per page' ) }
|
|
220
217
|
value={ view.perPage || 10 }
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
.dataviews-view-config {
|
|
2
2
|
width: 320px;
|
|
3
|
-
/* stylelint-disable-next-line property-no-unknown -- the linter needs to be updated to accepted the container-type property */
|
|
4
3
|
container-type: inline-size;
|
|
5
4
|
font-size: var(--wpds-typography-font-size-md);
|
|
6
5
|
line-height: var(--wpds-typography-line-height-sm);
|
package/src/dataform/index.tsx
CHANGED
|
@@ -12,6 +12,11 @@ import { DataFormProvider } from '../components/dataform-context';
|
|
|
12
12
|
import { DataFormLayout } from '../components/dataform-layouts/data-form-layout';
|
|
13
13
|
import normalizeForm from '../components/dataform-layouts/normalize-form';
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* `DataForm` renders an auto-generated form for viewing and editing the fields
|
|
17
|
+
* of a data item, driven by a fields and form layout configuration. Use it to
|
|
18
|
+
* edit items of a dataset, often alongside `DataViews`.
|
|
19
|
+
*/
|
|
15
20
|
export default function DataForm< Item >( {
|
|
16
21
|
data,
|
|
17
22
|
form,
|
package/src/dataviews/index.tsx
CHANGED
|
@@ -310,6 +310,11 @@ function DataViews< Item >( {
|
|
|
310
310
|
);
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
+
/**
|
|
314
|
+
* `DataViews` renders a dataset using configurable layouts (table, grid, list)
|
|
315
|
+
* with built-in search, filtering, sorting, pagination, and actions. Use it to
|
|
316
|
+
* display and manage a collection of records.
|
|
317
|
+
*/
|
|
313
318
|
// Populate the DataViews sub components
|
|
314
319
|
const DataViewsSubComponents = DataViews as typeof DataViews & {
|
|
315
320
|
BulkActionToolbar: typeof BulkActionsFooter;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useState, useMemo, useEffect } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import DataViews from '../index';
|
|
10
|
+
import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../../constants';
|
|
11
|
+
import filterSortAndPaginate from '../../utils/filter-sort-and-paginate';
|
|
12
|
+
import type { View } from '../../types';
|
|
13
|
+
import { actions, data as fixtureData, fields } from './fixtures';
|
|
14
|
+
|
|
15
|
+
// The fixtures only contain ~50 rows; repeat them (with unique ids) so there
|
|
16
|
+
// are enough rows to page through several times.
|
|
17
|
+
const data = Array.from( { length: 8 }, ( _, batch ) =>
|
|
18
|
+
fixtureData.map( ( item ) => ( {
|
|
19
|
+
...item,
|
|
20
|
+
id: item.id + batch * 1000,
|
|
21
|
+
name: {
|
|
22
|
+
...item.name,
|
|
23
|
+
title: `${ item.name.title } #${ batch + 1 }`,
|
|
24
|
+
},
|
|
25
|
+
} ) )
|
|
26
|
+
).flat();
|
|
27
|
+
|
|
28
|
+
const PAGE = 20;
|
|
29
|
+
// Simulated per-page network latency.
|
|
30
|
+
const LOAD_DELAY_MS = 800;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* A realistic network-backed infinite-scroll consumer: the hook advances
|
|
34
|
+
* `view.startPosition`, and the consumer fetches that window asynchronously
|
|
35
|
+
* (toggling `isLoading`) while reporting the true server total.
|
|
36
|
+
*/
|
|
37
|
+
const AsyncInfiniteScroll = () => {
|
|
38
|
+
const [ view, setView ] = useState< View >( {
|
|
39
|
+
type: LAYOUT_LIST,
|
|
40
|
+
search: '',
|
|
41
|
+
startPosition: 1,
|
|
42
|
+
perPage: PAGE,
|
|
43
|
+
filters: [],
|
|
44
|
+
fields: [ 'satellites' ],
|
|
45
|
+
titleField: 'title',
|
|
46
|
+
descriptionField: 'description',
|
|
47
|
+
mediaField: 'image',
|
|
48
|
+
infiniteScrollEnabled: true,
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
// The "server": how many rows have been delivered so far, and whether a
|
|
52
|
+
// request for the current window is in flight.
|
|
53
|
+
const [ loadedCount, setLoadedCount ] = useState( PAGE );
|
|
54
|
+
const [ isLoading, setIsLoading ] = useState( false );
|
|
55
|
+
|
|
56
|
+
const startPosition = view.startPosition ?? 1;
|
|
57
|
+
const perPage = view.perPage ?? PAGE;
|
|
58
|
+
// Rows required to fill the window the hook is currently asking for.
|
|
59
|
+
const needed = Math.min( startPosition - 1 + perPage, data.length );
|
|
60
|
+
|
|
61
|
+
useEffect( () => {
|
|
62
|
+
if ( needed <= loadedCount ) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
setIsLoading( true );
|
|
66
|
+
const timer = setTimeout( () => {
|
|
67
|
+
setLoadedCount( needed );
|
|
68
|
+
setIsLoading( false );
|
|
69
|
+
}, LOAD_DELAY_MS );
|
|
70
|
+
return () => clearTimeout( timer );
|
|
71
|
+
}, [ needed, loadedCount ] );
|
|
72
|
+
|
|
73
|
+
const loadedData = useMemo(
|
|
74
|
+
() => data.slice( 0, loadedCount ),
|
|
75
|
+
[ loadedCount ]
|
|
76
|
+
);
|
|
77
|
+
const { data: shownData, paginationInfo } = useMemo(
|
|
78
|
+
() => filterSortAndPaginate( loadedData, view, fields ),
|
|
79
|
+
[ loadedData, view ]
|
|
80
|
+
);
|
|
81
|
+
// Report the true server total (not just what's loaded) so infinite scroll
|
|
82
|
+
// keeps requesting until the dataset is exhausted.
|
|
83
|
+
const serverPaginationInfo = useMemo(
|
|
84
|
+
() => ( { ...paginationInfo, totalItems: data.length } ),
|
|
85
|
+
[ paginationInfo ]
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div style={ { height: '100%' } }>
|
|
90
|
+
<style>{ `
|
|
91
|
+
.dataviews-wrapper {
|
|
92
|
+
height: 100%;
|
|
93
|
+
overflow: auto;
|
|
94
|
+
}
|
|
95
|
+
` }</style>
|
|
96
|
+
<DataViews
|
|
97
|
+
getItemId={ ( item ) => item.id.toString() }
|
|
98
|
+
paginationInfo={ serverPaginationInfo }
|
|
99
|
+
data={ shownData }
|
|
100
|
+
view={ view }
|
|
101
|
+
fields={ fields }
|
|
102
|
+
onChangeView={ setView }
|
|
103
|
+
isLoading={ isLoading }
|
|
104
|
+
actions={ actions }
|
|
105
|
+
defaultLayouts={ {
|
|
106
|
+
[ LAYOUT_TABLE ]: true,
|
|
107
|
+
[ LAYOUT_GRID ]: true,
|
|
108
|
+
[ LAYOUT_LIST ]: true,
|
|
109
|
+
} }
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export default AsyncInfiniteScroll;
|
|
@@ -13,6 +13,7 @@ import LayoutGridComponent from './layout-grid';
|
|
|
13
13
|
import LayoutListComponent from './layout-list';
|
|
14
14
|
import LayoutCustomComponent from './layout-custom';
|
|
15
15
|
import InfiniteScrollComponent from './infinite-scroll';
|
|
16
|
+
import AsyncInfiniteScrollComponent from './async-infinite-scroll';
|
|
16
17
|
import WithCardComponent from './with-card';
|
|
17
18
|
import FreeCompositionComponent from './free-composition';
|
|
18
19
|
import MinimalUIComponent from './minimal-ui';
|
|
@@ -24,6 +25,11 @@ const meta = {
|
|
|
24
25
|
tags: [ 'manifest' ],
|
|
25
26
|
title: 'DataViews/DataViews',
|
|
26
27
|
component: DataViews,
|
|
28
|
+
// Temporary: Due to an upstream bug, render the root explicitly so the
|
|
29
|
+
// components manifest extractor can resolve props from the JSX.
|
|
30
|
+
//
|
|
31
|
+
// See: https://github.com/storybookjs/storybook/issues/34877
|
|
32
|
+
render: ( args ) => <DataViews { ...args } />,
|
|
27
33
|
args: {
|
|
28
34
|
containerHeight: 'auto',
|
|
29
35
|
},
|
|
@@ -278,3 +284,24 @@ export const InfiniteScroll = {
|
|
|
278
284
|
},
|
|
279
285
|
},
|
|
280
286
|
};
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Infinite scroll where pages load asynchronously (with `isLoading`), like a
|
|
290
|
+
* real network-backed consumer that fetches one window at a time. Reproduces
|
|
291
|
+
* the scroll-position jump that the synchronous story does not.
|
|
292
|
+
*/
|
|
293
|
+
export const AsyncInfiniteScroll = {
|
|
294
|
+
render: AsyncInfiniteScrollComponent,
|
|
295
|
+
parameters: {
|
|
296
|
+
// Fill the viewport so the list bottom is the window bottom.
|
|
297
|
+
containerHeight: 'calc(100vh - 2rem)',
|
|
298
|
+
},
|
|
299
|
+
argTypes: {
|
|
300
|
+
containerHeight: {
|
|
301
|
+
control: false,
|
|
302
|
+
table: {
|
|
303
|
+
disable: true,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
};
|
package/src/dataviews/style.scss
CHANGED
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
min-height: 0;
|
|
18
18
|
box-sizing: border-box;
|
|
19
19
|
scroll-padding-bottom: 64px;
|
|
20
|
-
/* stylelint-disable-next-line property-no-unknown -- '@container' not globally permitted */
|
|
21
20
|
container: dataviews-wrapper / inline-size;
|
|
22
21
|
display: flex;
|
|
23
22
|
flex-direction: column;
|
|
@@ -70,6 +69,11 @@
|
|
|
70
69
|
|
|
71
70
|
.dataviews-loading-more {
|
|
72
71
|
text-align: center;
|
|
72
|
+
|
|
73
|
+
// Hidden but keeps its box so the reserved height stays constant.
|
|
74
|
+
&[aria-hidden="true"] {
|
|
75
|
+
visibility: hidden;
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
@container (max-width: 430px) {
|
|
@@ -269,6 +269,11 @@ function DataViewsPicker< Item >( {
|
|
|
269
269
|
);
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
/**
|
|
273
|
+
* `DataViewsPicker` renders a dataset allowing users to select one or multiple
|
|
274
|
+
* items. It shares the layouts, search, and filtering of `DataViews` but is
|
|
275
|
+
* geared toward choosing items rather than managing them.
|
|
276
|
+
*/
|
|
272
277
|
// Populate the DataViews sub components
|
|
273
278
|
const DataViewsPickerSubComponents =
|
|
274
279
|
DataViewsPicker as typeof DataViewsPicker & {
|