@wordpress/dataviews 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -1
- package/README.md +42 -14
- package/build/components/dataviews/index.js +38 -6
- package/build/components/dataviews/index.js.map +1 -1
- package/build/components/dataviews-context/index.js +4 -1
- package/build/components/dataviews-context/index.js.map +1 -1
- package/build/components/dataviews-item-actions/index.js +1 -10
- package/build/components/dataviews-item-actions/index.js.map +1 -1
- package/build/components/dataviews-pagination/index.js +1 -1
- package/build/components/dataviews-pagination/index.js.map +1 -1
- package/build/components/dataviews-view-config/index.js +8 -5
- package/build/components/dataviews-view-config/index.js.map +1 -1
- package/build/components/dataviews-view-config/infinite-scroll-toggle.js +47 -0
- package/build/components/dataviews-view-config/infinite-scroll-toggle.js.map +1 -0
- package/build/dataform-controls/array.js +70 -0
- package/build/dataform-controls/array.js.map +1 -0
- package/build/dataform-controls/boolean.js +15 -7
- package/build/dataform-controls/boolean.js.map +1 -1
- package/build/dataform-controls/email.js +14 -7
- package/build/dataform-controls/email.js.map +1 -1
- package/build/dataform-controls/index.js +3 -1
- package/build/dataform-controls/index.js.map +1 -1
- package/build/dataform-controls/integer.js +14 -7
- package/build/dataform-controls/integer.js.map +1 -1
- package/build/dataform-controls/text.js +14 -7
- package/build/dataform-controls/text.js.map +1 -1
- package/build/dataforms-layouts/card/index.js +137 -0
- package/build/dataforms-layouts/card/index.js.map +1 -0
- package/build/dataforms-layouts/data-form-layout.js +2 -2
- package/build/dataforms-layouts/data-form-layout.js.map +1 -1
- package/build/dataforms-layouts/index.js +4 -0
- package/build/dataforms-layouts/index.js.map +1 -1
- package/build/dataforms-layouts/panel/dropdown.js +124 -0
- package/build/dataforms-layouts/panel/dropdown.js.map +1 -0
- package/build/dataforms-layouts/panel/index.js +34 -149
- package/build/dataforms-layouts/panel/index.js.map +1 -1
- package/build/dataforms-layouts/panel/modal.js +125 -0
- package/build/dataforms-layouts/panel/modal.js.map +1 -0
- package/build/dataforms-layouts/regular/index.js +10 -21
- package/build/dataforms-layouts/regular/index.js.map +1 -1
- package/build/dataviews-layouts/grid/index.js +24 -7
- package/build/dataviews-layouts/grid/index.js.map +1 -1
- package/build/dataviews-layouts/grid/preview-size-picker.js +11 -11
- package/build/dataviews-layouts/grid/preview-size-picker.js.map +1 -1
- package/build/dataviews-layouts/list/index.js +45 -27
- package/build/dataviews-layouts/list/index.js.map +1 -1
- package/build/dataviews-layouts/table/column-header-menu.js +3 -0
- package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
- package/build/dataviews-layouts/table/index.js +23 -8
- package/build/dataviews-layouts/table/index.js.map +1 -1
- package/build/field-types/array.js +2 -2
- package/build/field-types/array.js.map +1 -1
- package/build/normalize-form-fields.js +52 -13
- package/build/normalize-form-fields.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build-module/components/dataviews/index.js +40 -8
- package/build-module/components/dataviews/index.js.map +1 -1
- package/build-module/components/dataviews-context/index.js +4 -1
- package/build-module/components/dataviews-context/index.js.map +1 -1
- package/build-module/components/dataviews-item-actions/index.js +1 -10
- package/build-module/components/dataviews-item-actions/index.js.map +1 -1
- package/build-module/components/dataviews-pagination/index.js +1 -1
- package/build-module/components/dataviews-pagination/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/index.js +8 -5
- package/build-module/components/dataviews-view-config/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/infinite-scroll-toggle.js +39 -0
- package/build-module/components/dataviews-view-config/infinite-scroll-toggle.js.map +1 -0
- package/build-module/dataform-controls/array.js +63 -0
- package/build-module/dataform-controls/array.js.map +1 -0
- package/build-module/dataform-controls/boolean.js +15 -7
- package/build-module/dataform-controls/boolean.js.map +1 -1
- package/build-module/dataform-controls/email.js +15 -8
- package/build-module/dataform-controls/email.js.map +1 -1
- package/build-module/dataform-controls/index.js +3 -1
- package/build-module/dataform-controls/index.js.map +1 -1
- package/build-module/dataform-controls/integer.js +15 -8
- package/build-module/dataform-controls/integer.js.map +1 -1
- package/build-module/dataform-controls/text.js +15 -8
- package/build-module/dataform-controls/text.js.map +1 -1
- package/build-module/dataforms-layouts/card/index.js +128 -0
- package/build-module/dataforms-layouts/card/index.js.map +1 -0
- package/build-module/dataforms-layouts/data-form-layout.js +2 -2
- package/build-module/dataforms-layouts/data-form-layout.js.map +1 -1
- package/build-module/dataforms-layouts/index.js +4 -0
- package/build-module/dataforms-layouts/index.js.map +1 -1
- package/build-module/dataforms-layouts/panel/dropdown.js +118 -0
- package/build-module/dataforms-layouts/panel/dropdown.js.map +1 -0
- package/build-module/dataforms-layouts/panel/index.js +37 -152
- package/build-module/dataforms-layouts/panel/index.js.map +1 -1
- package/build-module/dataforms-layouts/panel/modal.js +119 -0
- package/build-module/dataforms-layouts/panel/modal.js.map +1 -0
- package/build-module/dataforms-layouts/regular/index.js +10 -21
- package/build-module/dataforms-layouts/regular/index.js.map +1 -1
- package/build-module/dataviews-layouts/grid/index.js +25 -8
- package/build-module/dataviews-layouts/grid/index.js.map +1 -1
- package/build-module/dataviews-layouts/grid/preview-size-picker.js +11 -11
- package/build-module/dataviews-layouts/grid/preview-size-picker.js.map +1 -1
- package/build-module/dataviews-layouts/list/index.js +47 -29
- package/build-module/dataviews-layouts/list/index.js.map +1 -1
- package/build-module/dataviews-layouts/table/column-header-menu.js +3 -0
- package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
- package/build-module/dataviews-layouts/table/index.js +23 -8
- package/build-module/dataviews-layouts/table/index.js.map +1 -1
- package/build-module/field-types/array.js +2 -2
- package/build-module/field-types/array.js.map +1 -1
- package/build-module/normalize-form-fields.js +50 -13
- package/build-module/normalize-form-fields.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-style/style-rtl.css +53 -16
- package/build-style/style.css +53 -16
- package/build-types/components/dataform/stories/index.story.d.ts +41 -17
- package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews/index.d.ts +5 -2
- package/build-types/components/dataviews/index.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/index.story.d.ts +2 -1
- package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews-context/index.d.ts +4 -1
- package/build-types/components/dataviews-context/index.d.ts.map +1 -1
- package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts +2 -0
- package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts.map +1 -0
- package/build-types/dataform-controls/array.d.ts +6 -0
- package/build-types/dataform-controls/array.d.ts.map +1 -0
- package/build-types/dataform-controls/boolean.d.ts.map +1 -1
- package/build-types/dataform-controls/email.d.ts.map +1 -1
- package/build-types/dataform-controls/index.d.ts.map +1 -1
- package/build-types/dataform-controls/integer.d.ts.map +1 -1
- package/build-types/dataform-controls/text.d.ts.map +1 -1
- package/build-types/dataforms-layouts/card/index.d.ts +13 -0
- package/build-types/dataforms-layouts/card/index.d.ts.map +1 -0
- package/build-types/dataforms-layouts/index.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/dropdown.d.ts +14 -0
- package/build-types/dataforms-layouts/panel/dropdown.d.ts.map +1 -0
- package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/modal.d.ts +13 -0
- package/build-types/dataforms-layouts/panel/modal.d.ts.map +1 -0
- package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts +1 -1
- package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts.map +1 -1
- package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
- package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
- package/build-types/field-types/boolean.d.ts +1 -1
- package/build-types/normalize-form-fields.d.ts +10 -3
- package/build-types/normalize-form-fields.d.ts.map +1 -1
- package/build-types/test/normalize-form-fields.d.ts +2 -0
- package/build-types/test/normalize-form-fields.d.ts.map +1 -0
- package/build-types/types.d.ts +54 -6
- package/build-types/types.d.ts.map +1 -1
- package/build-wp/index.js +3062 -1147
- package/package.json +15 -15
- package/src/components/dataform/stories/index.story.tsx +478 -91
- package/src/components/dataviews/index.tsx +50 -14
- package/src/components/dataviews/stories/fixtures.tsx +98 -7
- package/src/components/dataviews/stories/index.story.tsx +137 -4
- package/src/components/dataviews/style.scss +4 -0
- package/src/components/dataviews-context/index.ts +6 -2
- package/src/components/dataviews-item-actions/index.tsx +7 -16
- package/src/components/dataviews-pagination/index.tsx +1 -1
- package/src/components/dataviews-view-config/index.tsx +13 -5
- package/src/components/dataviews-view-config/infinite-scroll-toggle.tsx +39 -0
- package/src/dataform-controls/array.tsx +85 -0
- package/src/dataform-controls/boolean.tsx +24 -10
- package/src/dataform-controls/email.tsx +24 -11
- package/src/dataform-controls/index.tsx +3 -1
- package/src/dataform-controls/integer.tsx +27 -13
- package/src/dataform-controls/text.tsx +24 -11
- package/src/dataforms-layouts/card/index.tsx +154 -0
- package/src/dataforms-layouts/card/style.scss +3 -0
- package/src/dataforms-layouts/data-form-layout.tsx +2 -2
- package/src/dataforms-layouts/index.tsx +5 -0
- package/src/dataforms-layouts/panel/dropdown.tsx +160 -0
- package/src/dataforms-layouts/panel/index.tsx +49 -189
- package/src/dataforms-layouts/panel/modal.tsx +165 -0
- package/src/dataforms-layouts/panel/style.scss +4 -0
- package/src/dataforms-layouts/regular/index.tsx +20 -23
- package/src/dataviews-layouts/grid/index.tsx +32 -5
- package/src/dataviews-layouts/grid/preview-size-picker.tsx +15 -13
- package/src/dataviews-layouts/grid/style.scss +3 -1
- package/src/dataviews-layouts/list/index.tsx +65 -31
- package/src/dataviews-layouts/list/style.scss +7 -3
- package/src/dataviews-layouts/table/column-header-menu.tsx +4 -0
- package/src/dataviews-layouts/table/index.tsx +27 -1
- package/src/field-types/array.tsx +1 -1
- package/src/normalize-form-fields.ts +63 -17
- package/src/test/dataform.tsx +181 -3
- package/src/test/dataviews.tsx +38 -0
- package/src/test/filter-and-sort-data-view.js +123 -64
- package/src/test/normalize-form-fields.ts +247 -0
- package/src/types.ts +72 -6
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -9,12 +9,12 @@ import type { ReactNode, ComponentProps, ReactElement } from 'react';
|
|
|
9
9
|
import { __experimentalHStack as HStack } from '@wordpress/components';
|
|
10
10
|
import {
|
|
11
11
|
useContext,
|
|
12
|
+
useEffect,
|
|
12
13
|
useMemo,
|
|
13
14
|
useRef,
|
|
14
15
|
useState,
|
|
15
|
-
useEffect,
|
|
16
16
|
} from '@wordpress/element';
|
|
17
|
-
import { useResizeObserver } from '@wordpress/compose';
|
|
17
|
+
import { useResizeObserver, throttle } from '@wordpress/compose';
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Internal dependencies
|
|
@@ -51,6 +51,7 @@ type DataViewsProps< Item > = {
|
|
|
51
51
|
paginationInfo: {
|
|
52
52
|
totalItems: number;
|
|
53
53
|
totalPages: number;
|
|
54
|
+
infiniteScrollHandler?: () => void;
|
|
54
55
|
};
|
|
55
56
|
defaultLayouts: SupportedLayouts;
|
|
56
57
|
selection?: string[];
|
|
@@ -65,7 +66,11 @@ type DataViewsProps< Item > = {
|
|
|
65
66
|
header?: ReactNode;
|
|
66
67
|
getItemLevel?: ( item: Item ) => number;
|
|
67
68
|
children?: ReactNode;
|
|
68
|
-
|
|
69
|
+
config?:
|
|
70
|
+
| false
|
|
71
|
+
| {
|
|
72
|
+
perPageSizes: number[];
|
|
73
|
+
};
|
|
69
74
|
empty?: ReactNode;
|
|
70
75
|
} & ( Item extends ItemWithId
|
|
71
76
|
? { getItemId?: ( item: Item ) => string }
|
|
@@ -85,7 +90,7 @@ function DefaultUI( {
|
|
|
85
90
|
search = true,
|
|
86
91
|
searchLabel = undefined,
|
|
87
92
|
}: DefaultUIProps ) {
|
|
88
|
-
const { isShowingFilter } = useContext( DataViewsContext );
|
|
93
|
+
const { isShowingFilter, config } = useContext( DataViewsContext );
|
|
89
94
|
return (
|
|
90
95
|
<>
|
|
91
96
|
<HStack
|
|
@@ -102,14 +107,16 @@ function DefaultUI( {
|
|
|
102
107
|
{ search && <DataViewsSearch label={ searchLabel } /> }
|
|
103
108
|
<FiltersToggle />
|
|
104
109
|
</HStack>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
{ ( config || header ) && (
|
|
111
|
+
<HStack
|
|
112
|
+
spacing={ 1 }
|
|
113
|
+
expanded={ false }
|
|
114
|
+
style={ { flexShrink: 0 } }
|
|
115
|
+
>
|
|
116
|
+
config && <DataViewsViewConfig />
|
|
117
|
+
{ header }
|
|
118
|
+
</HStack>
|
|
119
|
+
) }
|
|
113
120
|
</HStack>
|
|
114
121
|
{ isShowingFilter && (
|
|
115
122
|
<DataViewsFilters className="dataviews-filters__container" />
|
|
@@ -140,9 +147,10 @@ function DataViews< Item >( {
|
|
|
140
147
|
isItemClickable = defaultIsItemClickable,
|
|
141
148
|
header,
|
|
142
149
|
children,
|
|
143
|
-
|
|
150
|
+
config = { perPageSizes: [ 10, 20, 50, 100 ] },
|
|
144
151
|
empty,
|
|
145
152
|
}: DataViewsProps< Item > ) {
|
|
153
|
+
const { infiniteScrollHandler } = paginationInfo;
|
|
146
154
|
const containerRef = useRef< HTMLDivElement | null >( null );
|
|
147
155
|
const [ containerWidth, setContainerWidth ] = useState( 0 );
|
|
148
156
|
const resizeObserverRef = useResizeObserver(
|
|
@@ -193,6 +201,33 @@ function DataViews< Item >( {
|
|
|
193
201
|
}
|
|
194
202
|
}, [ hasPrimaryOrLockedFilters, isShowingFilter ] );
|
|
195
203
|
|
|
204
|
+
// Attach scroll event listener for infinite scroll
|
|
205
|
+
useEffect( () => {
|
|
206
|
+
if ( ! view.infiniteScrollEnabled || ! containerRef.current ) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const handleScroll = throttle( ( event: unknown ) => {
|
|
211
|
+
const target = ( event as Event ).target as HTMLElement;
|
|
212
|
+
const scrollTop = target.scrollTop;
|
|
213
|
+
const scrollHeight = target.scrollHeight;
|
|
214
|
+
const clientHeight = target.clientHeight;
|
|
215
|
+
|
|
216
|
+
// Check if user has scrolled near the bottom
|
|
217
|
+
if ( scrollTop + clientHeight >= scrollHeight - 100 ) {
|
|
218
|
+
infiniteScrollHandler?.();
|
|
219
|
+
}
|
|
220
|
+
}, 100 ); // Throttle to 100ms
|
|
221
|
+
|
|
222
|
+
const container = containerRef.current;
|
|
223
|
+
container.addEventListener( 'scroll', handleScroll );
|
|
224
|
+
|
|
225
|
+
return () => {
|
|
226
|
+
container.removeEventListener( 'scroll', handleScroll );
|
|
227
|
+
handleScroll.cancel(); // Cancel any pending throttled calls
|
|
228
|
+
};
|
|
229
|
+
}, [ infiniteScrollHandler, view.infiniteScrollEnabled ] );
|
|
230
|
+
|
|
196
231
|
return (
|
|
197
232
|
<DataViewsContext.Provider
|
|
198
233
|
value={ {
|
|
@@ -219,8 +254,9 @@ function DataViews< Item >( {
|
|
|
219
254
|
filters,
|
|
220
255
|
isShowingFilter,
|
|
221
256
|
setIsShowingFilter,
|
|
222
|
-
|
|
257
|
+
config,
|
|
223
258
|
empty,
|
|
259
|
+
hasInfiniteScrollHandler: !! infiniteScrollHandler,
|
|
224
260
|
} }
|
|
225
261
|
>
|
|
226
262
|
<div className="dataviews-wrapper" ref={ containerRef }>
|
|
@@ -80,6 +80,58 @@ export const data: SpaceObject[] = [
|
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
id: 4,
|
|
83
|
+
title: 'Ganymede',
|
|
84
|
+
description: 'Largest moon of Jupiter',
|
|
85
|
+
image: 'https://live.staticflickr.com/7816/33436473218_a836235935_k.jpg',
|
|
86
|
+
type: 'Satellite',
|
|
87
|
+
isPlanet: false,
|
|
88
|
+
categories: [ 'Solar system', 'Satellite', 'Jupiter', 'Moon' ],
|
|
89
|
+
satellites: 0,
|
|
90
|
+
date: '2022-01-04',
|
|
91
|
+
datetime: '2022-01-04T12:30:00Z',
|
|
92
|
+
email: 'ganymede@example.com',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 5,
|
|
96
|
+
title: 'Callisto',
|
|
97
|
+
description: 'Outermost Galilean moon of Jupiter',
|
|
98
|
+
image: 'https://live.staticflickr.com/804/27604150528_4512448a9c_c.jpg',
|
|
99
|
+
type: 'Satellite',
|
|
100
|
+
isPlanet: false,
|
|
101
|
+
categories: [ 'Solar system', 'Satellite', 'Jupiter', 'Moon' ],
|
|
102
|
+
satellites: 0,
|
|
103
|
+
date: '2021-01-05',
|
|
104
|
+
datetime: '2021-01-05T14:15:30Z',
|
|
105
|
+
email: 'callisto@example.com',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 6,
|
|
109
|
+
title: 'Amalthea',
|
|
110
|
+
description: 'Small irregular moon of Jupiter',
|
|
111
|
+
image: 'https://upload.wikimedia.org/wikipedia/commons/6/62/Amalthea.gif',
|
|
112
|
+
type: 'Satellite',
|
|
113
|
+
isPlanet: false,
|
|
114
|
+
categories: [ 'Solar system', 'Satellite', 'Jupiter', 'Moon' ],
|
|
115
|
+
satellites: 0,
|
|
116
|
+
date: '2020-01-06',
|
|
117
|
+
datetime: '2020-01-06T10:45:15Z',
|
|
118
|
+
email: 'amalthea@example.com',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 7,
|
|
122
|
+
title: 'Himalia',
|
|
123
|
+
description: 'Largest irregular moon of Jupiter',
|
|
124
|
+
image: 'https://upload.wikimedia.org/wikipedia/commons/c/c2/Cassini-Huygens_Image_of_Himalia.png',
|
|
125
|
+
type: 'Satellite',
|
|
126
|
+
isPlanet: false,
|
|
127
|
+
categories: [ 'Solar system', 'Satellite', 'Jupiter', 'Moon' ],
|
|
128
|
+
satellites: 0,
|
|
129
|
+
date: '2019-01-07',
|
|
130
|
+
datetime: '2019-01-07T16:20:45Z',
|
|
131
|
+
email: 'himalia@example.com',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: 8,
|
|
83
135
|
title: 'Neptune',
|
|
84
136
|
description: 'Ice giant in the Solar system',
|
|
85
137
|
image: 'https://live.staticflickr.com/65535/29523683990_000ff4720c_z.jpg',
|
|
@@ -92,7 +144,46 @@ export const data: SpaceObject[] = [
|
|
|
92
144
|
email: 'neptune@example.com',
|
|
93
145
|
},
|
|
94
146
|
{
|
|
95
|
-
id:
|
|
147
|
+
id: 9,
|
|
148
|
+
title: 'Triton',
|
|
149
|
+
description: 'Largest moon of Neptune',
|
|
150
|
+
image: 'https://live.staticflickr.com/65535/50728384241_02c5126c30_h.jpg',
|
|
151
|
+
type: 'Satellite',
|
|
152
|
+
isPlanet: false,
|
|
153
|
+
categories: [ 'Solar system', 'Satellite', 'Neptune', 'Moon' ],
|
|
154
|
+
satellites: 0,
|
|
155
|
+
date: '2021-02-01',
|
|
156
|
+
datetime: '2021-02-01T11:30:00Z',
|
|
157
|
+
email: 'triton@example.com',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
id: 10,
|
|
161
|
+
title: 'Nereid',
|
|
162
|
+
description: 'Irregular moon of Neptune',
|
|
163
|
+
image: 'https://upload.wikimedia.org/wikipedia/commons/b/b0/Nereid-Voyager2.jpg',
|
|
164
|
+
type: 'Satellite',
|
|
165
|
+
isPlanet: false,
|
|
166
|
+
categories: [ 'Solar system', 'Satellite', 'Neptune', 'Moon' ],
|
|
167
|
+
satellites: 0,
|
|
168
|
+
date: '2020-02-02',
|
|
169
|
+
datetime: '2020-02-02T15:45:30Z',
|
|
170
|
+
email: 'nereid@example.com',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: 11,
|
|
174
|
+
title: 'Proteus',
|
|
175
|
+
description: 'Second-largest moon of Neptune',
|
|
176
|
+
image: 'https://live.staticflickr.com/65535/50727825808_bf427e007b_c.jpg',
|
|
177
|
+
type: 'Satellite',
|
|
178
|
+
isPlanet: false,
|
|
179
|
+
categories: [ 'Solar system', 'Satellite', 'Neptune', 'Moon' ],
|
|
180
|
+
satellites: 0,
|
|
181
|
+
date: '2019-02-03',
|
|
182
|
+
datetime: '2019-02-03T09:20:15Z',
|
|
183
|
+
email: 'proteus@example.com',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 12,
|
|
96
187
|
title: 'Mercury',
|
|
97
188
|
description: 'Terrestrial planet in the Solar system',
|
|
98
189
|
image: 'https://live.staticflickr.com/813/40199101735_e5e92ffd11_z.jpg',
|
|
@@ -105,7 +196,7 @@ export const data: SpaceObject[] = [
|
|
|
105
196
|
email: 'mercury@example.com',
|
|
106
197
|
},
|
|
107
198
|
{
|
|
108
|
-
id:
|
|
199
|
+
id: 13,
|
|
109
200
|
title: 'Venus',
|
|
110
201
|
description: 'La planète Vénus',
|
|
111
202
|
image: 'https://live.staticflickr.com/8025/7544560662_900e717727_z.jpg',
|
|
@@ -118,7 +209,7 @@ export const data: SpaceObject[] = [
|
|
|
118
209
|
email: 'venus@example.com',
|
|
119
210
|
},
|
|
120
211
|
{
|
|
121
|
-
id:
|
|
212
|
+
id: 14,
|
|
122
213
|
title: 'Earth',
|
|
123
214
|
description: 'Terrestrial planet in the Solar system',
|
|
124
215
|
image: 'https://live.staticflickr.com/3762/9460163562_964fe6af07_z.jpg',
|
|
@@ -131,7 +222,7 @@ export const data: SpaceObject[] = [
|
|
|
131
222
|
email: 'earth@example.com',
|
|
132
223
|
},
|
|
133
224
|
{
|
|
134
|
-
id:
|
|
225
|
+
id: 15,
|
|
135
226
|
title: 'Mars',
|
|
136
227
|
description: 'Terrestrial planet in the Solar system',
|
|
137
228
|
image: 'https://live.staticflickr.com/8151/7651156426_e047f4d219_z.jpg',
|
|
@@ -144,7 +235,7 @@ export const data: SpaceObject[] = [
|
|
|
144
235
|
email: 'mars@example.com',
|
|
145
236
|
},
|
|
146
237
|
{
|
|
147
|
-
id:
|
|
238
|
+
id: 16,
|
|
148
239
|
title: 'Jupiter',
|
|
149
240
|
description: 'Gas giant in the Solar system',
|
|
150
241
|
image: 'https://staging-jubilee.flickr.com/2853/9458010071_6e6fc41408_z.jpg',
|
|
@@ -157,7 +248,7 @@ export const data: SpaceObject[] = [
|
|
|
157
248
|
email: 'jupiter@example.com',
|
|
158
249
|
},
|
|
159
250
|
{
|
|
160
|
-
id:
|
|
251
|
+
id: 17,
|
|
161
252
|
title: 'Saturn',
|
|
162
253
|
description: 'Gas giant in the Solar system',
|
|
163
254
|
image: 'https://live.staticflickr.com/5524/9464658509_fc2d83dff5_z.jpg',
|
|
@@ -170,7 +261,7 @@ export const data: SpaceObject[] = [
|
|
|
170
261
|
email: 'saturn@example.com',
|
|
171
262
|
},
|
|
172
263
|
{
|
|
173
|
-
id:
|
|
264
|
+
id: 18,
|
|
174
265
|
title: 'Uranus',
|
|
175
266
|
description: 'Ice giant in the Solar system',
|
|
176
267
|
image: 'https://live.staticflickr.com/65535/5553350875_3072df91e2_c.jpg',
|
|
@@ -9,6 +9,8 @@ import type { Meta } from '@storybook/react';
|
|
|
9
9
|
import {
|
|
10
10
|
useState,
|
|
11
11
|
useMemo,
|
|
12
|
+
useCallback,
|
|
13
|
+
useEffect,
|
|
12
14
|
createInterpolateElement,
|
|
13
15
|
} from '@wordpress/element';
|
|
14
16
|
import {
|
|
@@ -37,7 +39,7 @@ import {
|
|
|
37
39
|
} from './fixtures';
|
|
38
40
|
import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../../../constants';
|
|
39
41
|
import { filterSortAndPaginate } from '../../../filter-and-sort-data-view';
|
|
40
|
-
import type { View } from '../../../types';
|
|
42
|
+
import type { Field, View } from '../../../types';
|
|
41
43
|
|
|
42
44
|
import './style.css';
|
|
43
45
|
|
|
@@ -87,7 +89,7 @@ export const Default = ( { perPageSizes = [ 10, 25, 50, 100 ] } ) => {
|
|
|
87
89
|
) }
|
|
88
90
|
isItemClickable={ () => true }
|
|
89
91
|
defaultLayouts={ defaultLayouts }
|
|
90
|
-
|
|
92
|
+
config={ { perPageSizes } }
|
|
91
93
|
/>
|
|
92
94
|
);
|
|
93
95
|
};
|
|
@@ -144,19 +146,23 @@ export const CustomEmpty = () => {
|
|
|
144
146
|
);
|
|
145
147
|
};
|
|
146
148
|
|
|
147
|
-
export const
|
|
149
|
+
export const MinimalUI = () => {
|
|
148
150
|
const [ view, setView ] = useState< View >( {
|
|
149
151
|
...DEFAULT_VIEW,
|
|
150
152
|
fields: [ 'title', 'description', 'categories' ],
|
|
153
|
+
layout: {
|
|
154
|
+
enableMoving: false,
|
|
155
|
+
},
|
|
151
156
|
} );
|
|
152
157
|
const { data: shownData, paginationInfo } = useMemo( () => {
|
|
153
158
|
return filterSortAndPaginate( data, view, fields );
|
|
154
159
|
}, [ view ] );
|
|
155
160
|
|
|
156
|
-
const _fields = fields.map( ( field ) => ( {
|
|
161
|
+
const _fields: Field< SpaceObject >[] = fields.map( ( field ) => ( {
|
|
157
162
|
...field,
|
|
158
163
|
enableSorting: false,
|
|
159
164
|
enableHiding: false,
|
|
165
|
+
filterBy: false,
|
|
160
166
|
} ) );
|
|
161
167
|
|
|
162
168
|
return (
|
|
@@ -166,6 +172,8 @@ export const FieldsNoSortableNoHidable = () => {
|
|
|
166
172
|
data={ shownData }
|
|
167
173
|
view={ view }
|
|
168
174
|
fields={ _fields }
|
|
175
|
+
config={ false }
|
|
176
|
+
search={ false }
|
|
169
177
|
onChangeView={ setView }
|
|
170
178
|
defaultLayouts={ {
|
|
171
179
|
table: {},
|
|
@@ -383,3 +391,128 @@ export const GroupByLayout = () => {
|
|
|
383
391
|
/>
|
|
384
392
|
);
|
|
385
393
|
};
|
|
394
|
+
|
|
395
|
+
export const InfiniteScroll = () => {
|
|
396
|
+
const [ view, setView ] = useState< View >( {
|
|
397
|
+
type: LAYOUT_GRID,
|
|
398
|
+
search: '',
|
|
399
|
+
page: 1,
|
|
400
|
+
perPage: 6, // Start with a small number to demonstrate pagination
|
|
401
|
+
filters: [],
|
|
402
|
+
fields: [ 'satellites' ],
|
|
403
|
+
titleField: 'title',
|
|
404
|
+
descriptionField: 'description',
|
|
405
|
+
mediaField: 'image',
|
|
406
|
+
infiniteScrollEnabled: true, // Enable infinite scroll by default
|
|
407
|
+
} );
|
|
408
|
+
const { data: shownData } = useMemo( () => {
|
|
409
|
+
return filterSortAndPaginate( data, view, fields );
|
|
410
|
+
}, [ view ] );
|
|
411
|
+
|
|
412
|
+
// Custom pagination handler that simulates server-side pagination
|
|
413
|
+
const [ allLoadedRecords, setAllLoadedRecords ] = useState< SpaceObject[] >(
|
|
414
|
+
[]
|
|
415
|
+
);
|
|
416
|
+
const [ isLoadingMore, setIsLoadingMore ] = useState( false );
|
|
417
|
+
|
|
418
|
+
const totalItems = data.length;
|
|
419
|
+
const totalPages = Math.ceil( totalItems / 6 ); // perPage is 6.
|
|
420
|
+
const currentPage = view.page || 1;
|
|
421
|
+
const hasMoreData = currentPage < totalPages;
|
|
422
|
+
const getItemId = ( item: {
|
|
423
|
+
id: any;
|
|
424
|
+
title?: string;
|
|
425
|
+
description?: string;
|
|
426
|
+
image?: string;
|
|
427
|
+
type?: string;
|
|
428
|
+
isPlanet?: boolean;
|
|
429
|
+
categories?: string[];
|
|
430
|
+
satellites?: number;
|
|
431
|
+
date?: string;
|
|
432
|
+
datetime?: string;
|
|
433
|
+
email?: string;
|
|
434
|
+
} ) => item.id.toString();
|
|
435
|
+
|
|
436
|
+
const infiniteScrollHandler = useCallback( () => {
|
|
437
|
+
if ( isLoadingMore || currentPage >= totalPages ) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
setIsLoadingMore( true );
|
|
442
|
+
|
|
443
|
+
setView( {
|
|
444
|
+
...view,
|
|
445
|
+
page: currentPage + 1,
|
|
446
|
+
} );
|
|
447
|
+
}, [ isLoadingMore, currentPage, totalPages, view ] );
|
|
448
|
+
|
|
449
|
+
// Initialize data on first load or when view changes significantly
|
|
450
|
+
useEffect( () => {
|
|
451
|
+
if ( currentPage === 1 || ! view.infiniteScrollEnabled ) {
|
|
452
|
+
// First page - replace all data
|
|
453
|
+
setAllLoadedRecords( shownData );
|
|
454
|
+
} else {
|
|
455
|
+
// Subsequent pages - append to existing data
|
|
456
|
+
setAllLoadedRecords( ( prev ) => {
|
|
457
|
+
const existingIds = new Set( prev.map( getItemId ) );
|
|
458
|
+
const newRecords = shownData.filter(
|
|
459
|
+
( record ) => ! existingIds.has( getItemId( record ) )
|
|
460
|
+
);
|
|
461
|
+
return [ ...prev, ...newRecords ];
|
|
462
|
+
} );
|
|
463
|
+
}
|
|
464
|
+
setIsLoadingMore( false );
|
|
465
|
+
}, [
|
|
466
|
+
view.search,
|
|
467
|
+
view.filters,
|
|
468
|
+
view.perPage,
|
|
469
|
+
currentPage,
|
|
470
|
+
view.infiniteScrollEnabled,
|
|
471
|
+
] );
|
|
472
|
+
|
|
473
|
+
const paginationInfo = {
|
|
474
|
+
totalItems,
|
|
475
|
+
totalPages,
|
|
476
|
+
infiniteScrollHandler,
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
return (
|
|
480
|
+
<>
|
|
481
|
+
<style>{ `
|
|
482
|
+
.dataviews-wrapper {
|
|
483
|
+
height: 600px;
|
|
484
|
+
overflow: auto;
|
|
485
|
+
}
|
|
486
|
+
` }</style>
|
|
487
|
+
<Text
|
|
488
|
+
style={ {
|
|
489
|
+
marginBottom: '16px',
|
|
490
|
+
padding: '8px',
|
|
491
|
+
background: '#f0f0f0',
|
|
492
|
+
borderRadius: '4px',
|
|
493
|
+
display: 'block',
|
|
494
|
+
} }
|
|
495
|
+
>
|
|
496
|
+
{ __( 'Infinite Scroll Demo' ) }: { allLoadedRecords.length } of{ ' ' }
|
|
497
|
+
{ totalItems } items loaded.
|
|
498
|
+
{ isLoadingMore && __( 'Loading more…' ) }
|
|
499
|
+
{ ! hasMoreData && __( 'All items loaded!' ) }
|
|
500
|
+
</Text>
|
|
501
|
+
<DataViews
|
|
502
|
+
getItemId={ ( item ) => item.id.toString() }
|
|
503
|
+
paginationInfo={ paginationInfo }
|
|
504
|
+
data={ allLoadedRecords }
|
|
505
|
+
view={ view }
|
|
506
|
+
fields={ fields }
|
|
507
|
+
onChangeView={ setView }
|
|
508
|
+
actions={ actions }
|
|
509
|
+
isLoading={ isLoadingMore }
|
|
510
|
+
defaultLayouts={ {
|
|
511
|
+
[ LAYOUT_GRID ]: {},
|
|
512
|
+
[ LAYOUT_LIST ]: {},
|
|
513
|
+
[ LAYOUT_TABLE ]: {},
|
|
514
|
+
} }
|
|
515
|
+
/>
|
|
516
|
+
</>
|
|
517
|
+
);
|
|
518
|
+
};
|
|
@@ -54,8 +54,9 @@ type DataViewsContextType< Item > = {
|
|
|
54
54
|
filters: NormalizedFilter[];
|
|
55
55
|
isShowingFilter: boolean;
|
|
56
56
|
setIsShowingFilter: ( value: boolean ) => void;
|
|
57
|
-
perPageSizes: number[];
|
|
57
|
+
config: false | { perPageSizes: number[] };
|
|
58
58
|
empty?: ReactNode;
|
|
59
|
+
hasInfiniteScrollHandler: boolean;
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
const DataViewsContext = createContext< DataViewsContextType< any > >( {
|
|
@@ -81,7 +82,10 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
|
|
|
81
82
|
filters: [],
|
|
82
83
|
isShowingFilter: false,
|
|
83
84
|
setIsShowingFilter: () => {},
|
|
84
|
-
|
|
85
|
+
hasInfiniteScrollHandler: false,
|
|
86
|
+
config: {
|
|
87
|
+
perPageSizes: [],
|
|
88
|
+
},
|
|
85
89
|
} );
|
|
86
90
|
|
|
87
91
|
export default DataViewsContext;
|
|
@@ -179,17 +179,6 @@ export default function ItemActions< Item >( {
|
|
|
179
179
|
);
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
// If all actions are primary, there is no need to render the dropdown.
|
|
183
|
-
if ( primaryActions.length === eligibleActions.length ) {
|
|
184
|
-
return (
|
|
185
|
-
<PrimaryActions
|
|
186
|
-
item={ item }
|
|
187
|
-
actions={ primaryActions }
|
|
188
|
-
registry={ registry }
|
|
189
|
-
/>
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
182
|
return (
|
|
194
183
|
<HStack
|
|
195
184
|
spacing={ 1 }
|
|
@@ -205,11 +194,13 @@ export default function ItemActions< Item >( {
|
|
|
205
194
|
actions={ primaryActions }
|
|
206
195
|
registry={ registry }
|
|
207
196
|
/>
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
197
|
+
{ primaryActions.length < eligibleActions.length && (
|
|
198
|
+
<CompactItemActions
|
|
199
|
+
item={ item }
|
|
200
|
+
actions={ eligibleActions }
|
|
201
|
+
registry={ registry }
|
|
202
|
+
/>
|
|
203
|
+
) }
|
|
213
204
|
</HStack>
|
|
214
205
|
);
|
|
215
206
|
}
|
|
@@ -22,7 +22,7 @@ export function DataViewsPagination() {
|
|
|
22
22
|
paginationInfo: { totalItems = 0, totalPages },
|
|
23
23
|
} = useContext( DataViewsContext );
|
|
24
24
|
|
|
25
|
-
if ( ! totalItems || ! totalPages ) {
|
|
25
|
+
if ( ! totalItems || ! totalPages || view.infiniteScrollEnabled ) {
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -47,6 +47,7 @@ import { SORTING_DIRECTIONS, sortIcons, sortLabels } from '../../constants';
|
|
|
47
47
|
import { VIEW_LAYOUTS } from '../../dataviews-layouts';
|
|
48
48
|
import type { NormalizedField, View } from '../../types';
|
|
49
49
|
import DataViewsContext from '../dataviews-context';
|
|
50
|
+
import InfiniteScrollToggle from './infinite-scroll-toggle';
|
|
50
51
|
import { unlock } from '../../lock-unlock';
|
|
51
52
|
|
|
52
53
|
const { Menu } = unlock( componentsPrivateApis );
|
|
@@ -102,12 +103,11 @@ export function ViewTypeMenu() {
|
|
|
102
103
|
if ( 'layout' in viewWithoutLayout ) {
|
|
103
104
|
delete viewWithoutLayout.layout;
|
|
104
105
|
}
|
|
105
|
-
// @ts-expect-error
|
|
106
106
|
return onChangeView( {
|
|
107
107
|
...viewWithoutLayout,
|
|
108
108
|
type: e.target.value,
|
|
109
109
|
...defaultLayouts[ e.target.value ],
|
|
110
|
-
} );
|
|
110
|
+
} as View );
|
|
111
111
|
}
|
|
112
112
|
warning( 'Invalid dataview' );
|
|
113
113
|
} }
|
|
@@ -214,8 +214,15 @@ function SortDirectionControl() {
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
function ItemsPerPageControl() {
|
|
217
|
-
const { view,
|
|
218
|
-
|
|
217
|
+
const { view, config, onChangeView } = useContext( DataViewsContext );
|
|
218
|
+
const { infiniteScrollEnabled } = view;
|
|
219
|
+
if (
|
|
220
|
+
! config ||
|
|
221
|
+
! config.perPageSizes ||
|
|
222
|
+
config.perPageSizes.length < 2 ||
|
|
223
|
+
config.perPageSizes.length > 6 ||
|
|
224
|
+
infiniteScrollEnabled
|
|
225
|
+
) {
|
|
219
226
|
return null;
|
|
220
227
|
}
|
|
221
228
|
|
|
@@ -240,7 +247,7 @@ function ItemsPerPageControl() {
|
|
|
240
247
|
} );
|
|
241
248
|
} }
|
|
242
249
|
>
|
|
243
|
-
{ perPageSizes.map( ( value ) => {
|
|
250
|
+
{ config.perPageSizes.map( ( value ) => {
|
|
244
251
|
return (
|
|
245
252
|
<ToggleGroupControlOption
|
|
246
253
|
key={ value }
|
|
@@ -801,6 +808,7 @@ export function DataviewsViewConfigDropdown() {
|
|
|
801
808
|
{ !! activeLayout?.viewConfigOptions && (
|
|
802
809
|
<activeLayout.viewConfigOptions />
|
|
803
810
|
) }
|
|
811
|
+
<InfiniteScrollToggle />
|
|
804
812
|
<ItemsPerPageControl />
|
|
805
813
|
</SettingsSection>
|
|
806
814
|
<SettingsSection title={ __( 'Properties' ) }>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { ToggleControl } from '@wordpress/components';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { useContext } from '@wordpress/element';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal dependencies
|
|
10
|
+
*/
|
|
11
|
+
import DataViewsContext from '../dataviews-context';
|
|
12
|
+
|
|
13
|
+
export default function InfiniteScrollToggle() {
|
|
14
|
+
const context = useContext( DataViewsContext );
|
|
15
|
+
const { view, onChangeView } = context;
|
|
16
|
+
const infiniteScrollEnabled = view.infiniteScrollEnabled ?? false;
|
|
17
|
+
|
|
18
|
+
// Only render the toggle if an infinite scroll handler is available
|
|
19
|
+
if ( ! context.hasInfiniteScrollHandler ) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<ToggleControl
|
|
25
|
+
__nextHasNoMarginBottom
|
|
26
|
+
label={ __( 'Enable infinite scroll' ) }
|
|
27
|
+
help={ __(
|
|
28
|
+
'Automatically load more content as you scroll, instead of showing pagination links.'
|
|
29
|
+
) }
|
|
30
|
+
checked={ infiniteScrollEnabled }
|
|
31
|
+
onChange={ ( newValue ) => {
|
|
32
|
+
onChangeView( {
|
|
33
|
+
...view,
|
|
34
|
+
infiniteScrollEnabled: newValue,
|
|
35
|
+
} );
|
|
36
|
+
} }
|
|
37
|
+
/>
|
|
38
|
+
);
|
|
39
|
+
}
|