@wordpress/dataviews 5.0.0 → 6.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 +31 -1
- package/README.md +55 -27
- package/build/components/dataviews/index.js +13 -4
- package/build/components/dataviews/index.js.map +1 -1
- package/build/components/dataviews-context/index.js +3 -1
- package/build/components/dataviews-context/index.js.map +1 -1
- package/build/components/dataviews-filters/filter.js +15 -8
- package/build/components/dataviews-filters/filter.js.map +1 -1
- package/build/components/dataviews-filters/index.js +16 -5
- package/build/components/dataviews-filters/index.js.map +1 -1
- package/build/components/dataviews-filters/input-widget.js +7 -1
- package/build/components/dataviews-filters/input-widget.js.map +1 -1
- package/build/components/dataviews-filters/reset-filters.js +2 -2
- package/build/components/dataviews-filters/reset-filters.js.map +1 -1
- package/build/components/dataviews-layout/index.js +5 -2
- package/build/components/dataviews-layout/index.js.map +1 -1
- package/build/components/dataviews-view-config/index.js +4 -3
- package/build/components/dataviews-view-config/index.js.map +1 -1
- package/build/dataform-controls/boolean.js +15 -1
- package/build/dataform-controls/boolean.js.map +1 -1
- package/build/dataform-controls/date.js +385 -0
- package/build/dataform-controls/date.js.map +1 -0
- package/build/dataform-controls/datetime.js +5 -84
- package/build/dataform-controls/datetime.js.map +1 -1
- package/build/dataform-controls/email.js +15 -1
- package/build/dataform-controls/email.js.map +1 -1
- package/build/dataform-controls/index.js +2 -0
- package/build/dataform-controls/index.js.map +1 -1
- package/build/dataform-controls/integer.js +23 -4
- package/build/dataform-controls/integer.js.map +1 -1
- package/build/dataform-controls/relative-date-control.js +109 -0
- package/build/dataform-controls/relative-date-control.js.map +1 -0
- package/build/dataform-controls/select.js +12 -5
- package/build/dataform-controls/select.js.map +1 -1
- package/build/dataform-controls/text.js +15 -1
- package/build/dataform-controls/text.js.map +1 -1
- package/build/dataviews-layouts/grid/index.js +40 -23
- package/build/dataviews-layouts/grid/index.js.map +1 -1
- package/build/dataviews-layouts/grid/preview-size-picker.js +39 -85
- package/build/dataviews-layouts/grid/preview-size-picker.js.map +1 -1
- package/build/dataviews-layouts/list/index.js +7 -3
- package/build/dataviews-layouts/list/index.js.map +1 -1
- package/build/dataviews-layouts/table/column-primary.js +18 -3
- package/build/dataviews-layouts/table/column-primary.js.map +1 -1
- package/build/dataviews-layouts/table/index.js +57 -5
- package/build/dataviews-layouts/table/index.js.map +1 -1
- package/build/field-types/array.js +27 -18
- package/build/field-types/array.js.map +1 -1
- package/build/field-types/boolean.js +11 -7
- package/build/field-types/boolean.js.map +1 -1
- package/build/field-types/date.js +21 -12
- package/build/field-types/date.js.map +1 -1
- package/build/field-types/datetime.js +19 -10
- package/build/field-types/datetime.js.map +1 -1
- package/build/field-types/email.js +22 -18
- package/build/field-types/email.js.map +1 -1
- package/build/field-types/index.js +16 -6
- package/build/field-types/index.js.map +1 -1
- package/build/field-types/integer.js +22 -17
- package/build/field-types/integer.js.map +1 -1
- package/build/field-types/media.js +19 -10
- package/build/field-types/media.js.map +1 -1
- package/build/field-types/text.js +19 -10
- package/build/field-types/text.js.map +1 -1
- package/build/filter-and-sort-data-view.js +6 -4
- package/build/filter-and-sort-data-view.js.map +1 -1
- package/build/normalize-fields.js +4 -5
- package/build/normalize-fields.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build/validation.js +15 -2
- package/build/validation.js.map +1 -1
- package/build-module/components/dataviews/index.js +15 -6
- package/build-module/components/dataviews/index.js.map +1 -1
- package/build-module/components/dataviews-context/index.js +3 -1
- package/build-module/components/dataviews-context/index.js.map +1 -1
- package/build-module/components/dataviews-filters/filter.js +15 -8
- package/build-module/components/dataviews-filters/filter.js.map +1 -1
- package/build-module/components/dataviews-filters/index.js +16 -5
- package/build-module/components/dataviews-filters/index.js.map +1 -1
- package/build-module/components/dataviews-filters/input-widget.js +7 -1
- package/build-module/components/dataviews-filters/input-widget.js.map +1 -1
- package/build-module/components/dataviews-filters/reset-filters.js +2 -2
- package/build-module/components/dataviews-filters/reset-filters.js.map +1 -1
- package/build-module/components/dataviews-layout/index.js +5 -2
- package/build-module/components/dataviews-layout/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/index.js +4 -3
- package/build-module/components/dataviews-view-config/index.js.map +1 -1
- package/build-module/dataform-controls/boolean.js +17 -2
- package/build-module/dataform-controls/boolean.js.map +1 -1
- package/build-module/dataform-controls/date.js +376 -0
- package/build-module/dataform-controls/date.js.map +1 -0
- package/build-module/dataform-controls/datetime.js +3 -84
- package/build-module/dataform-controls/datetime.js.map +1 -1
- package/build-module/dataform-controls/email.js +17 -2
- package/build-module/dataform-controls/email.js.map +1 -1
- package/build-module/dataform-controls/index.js +2 -0
- package/build-module/dataform-controls/index.js.map +1 -1
- package/build-module/dataform-controls/integer.js +24 -5
- package/build-module/dataform-controls/integer.js.map +1 -1
- package/build-module/dataform-controls/relative-date-control.js +100 -0
- package/build-module/dataform-controls/relative-date-control.js.map +1 -0
- package/build-module/dataform-controls/select.js +12 -5
- package/build-module/dataform-controls/select.js.map +1 -1
- package/build-module/dataform-controls/text.js +17 -2
- package/build-module/dataform-controls/text.js.map +1 -1
- package/build-module/dataviews-layouts/grid/index.js +41 -24
- package/build-module/dataviews-layouts/grid/index.js.map +1 -1
- package/build-module/dataviews-layouts/grid/preview-size-picker.js +40 -85
- package/build-module/dataviews-layouts/grid/preview-size-picker.js.map +1 -1
- package/build-module/dataviews-layouts/list/index.js +7 -3
- package/build-module/dataviews-layouts/list/index.js.map +1 -1
- package/build-module/dataviews-layouts/table/column-primary.js +18 -3
- package/build-module/dataviews-layouts/table/column-primary.js.map +1 -1
- package/build-module/dataviews-layouts/table/index.js +58 -6
- package/build-module/dataviews-layouts/table/index.js.map +1 -1
- package/build-module/field-types/array.js +27 -18
- package/build-module/field-types/array.js.map +1 -1
- package/build-module/field-types/boolean.js +11 -7
- package/build-module/field-types/boolean.js.map +1 -1
- package/build-module/field-types/date.js +21 -12
- package/build-module/field-types/date.js.map +1 -1
- package/build-module/field-types/datetime.js +19 -10
- package/build-module/field-types/datetime.js.map +1 -1
- package/build-module/field-types/email.js +22 -18
- package/build-module/field-types/email.js.map +1 -1
- package/build-module/field-types/index.js +16 -6
- package/build-module/field-types/index.js.map +1 -1
- package/build-module/field-types/integer.js +22 -17
- package/build-module/field-types/integer.js.map +1 -1
- package/build-module/field-types/media.js +19 -10
- package/build-module/field-types/media.js.map +1 -1
- package/build-module/field-types/text.js +19 -10
- package/build-module/field-types/text.js.map +1 -1
- package/build-module/filter-and-sort-data-view.js +6 -4
- package/build-module/filter-and-sort-data-view.js.map +1 -1
- package/build-module/normalize-fields.js +4 -5
- package/build-module/normalize-fields.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-module/validation.js +15 -2
- package/build-module/validation.js.map +1 -1
- package/build-style/style-rtl.css +78 -43
- package/build-style/style.css +78 -43
- package/build-types/components/dataform/stories/index.story.d.ts +21 -0
- package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews/index.d.ts +3 -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 +16 -3
- package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews-context/index.d.ts +4 -2
- package/build-types/components/dataviews-context/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/filter.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/input-widget.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/reset-filters.d.ts.map +1 -1
- package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/constants.d.ts +2 -2
- package/build-types/dataform-controls/boolean.d.ts.map +1 -1
- package/build-types/dataform-controls/date.d.ts +3 -0
- package/build-types/dataform-controls/date.d.ts.map +1 -0
- package/build-types/dataform-controls/datetime.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/relative-date-control.d.ts +46 -0
- package/build-types/dataform-controls/relative-date-control.d.ts.map +1 -0
- package/build-types/dataform-controls/select.d.ts.map +1 -1
- package/build-types/dataform-controls/text.d.ts.map +1 -1
- package/build-types/dataviews-layouts/grid/index.d.ts +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 +0 -1
- package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts.map +1 -1
- package/build-types/dataviews-layouts/index.d.ts +3 -3
- package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/table/column-primary.d.ts.map +1 -1
- package/build-types/dataviews-layouts/table/index.d.ts +1 -1
- package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
- package/build-types/field-types/array.d.ts.map +1 -1
- package/build-types/field-types/boolean.d.ts +5 -4
- package/build-types/field-types/boolean.d.ts.map +1 -1
- package/build-types/field-types/date.d.ts +9 -5
- package/build-types/field-types/date.d.ts.map +1 -1
- package/build-types/field-types/datetime.d.ts +4 -3
- package/build-types/field-types/datetime.d.ts.map +1 -1
- package/build-types/field-types/email.d.ts +4 -3
- package/build-types/field-types/email.d.ts.map +1 -1
- package/build-types/field-types/index.d.ts.map +1 -1
- package/build-types/field-types/integer.d.ts +4 -3
- package/build-types/field-types/integer.d.ts.map +1 -1
- package/build-types/field-types/media.d.ts +4 -3
- package/build-types/field-types/media.d.ts.map +1 -1
- package/build-types/field-types/text.d.ts +4 -3
- package/build-types/field-types/text.d.ts.map +1 -1
- package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
- package/build-types/normalize-fields.d.ts.map +1 -1
- package/build-types/types.d.ts +20 -7
- package/build-types/types.d.ts.map +1 -1
- package/build-types/validation.d.ts.map +1 -1
- package/build-wp/index.js +1561 -670
- package/package.json +15 -14
- package/src/components/dataform/stories/index.story.tsx +229 -2
- package/src/components/dataviews/index.tsx +30 -10
- package/src/components/dataviews/stories/fixtures.tsx +3 -1
- package/src/components/dataviews/stories/index.story.tsx +49 -29
- package/src/components/dataviews/stories/style.css +6 -0
- package/src/components/dataviews-context/index.ts +8 -2
- package/src/components/dataviews-filters/filter.tsx +17 -7
- package/src/components/dataviews-filters/index.tsx +17 -2
- package/src/components/dataviews-filters/input-widget.tsx +7 -1
- package/src/components/dataviews-filters/reset-filters.tsx +4 -2
- package/src/components/dataviews-filters/style.scss +8 -2
- package/src/components/dataviews-layout/index.tsx +3 -0
- package/src/components/dataviews-view-config/index.tsx +5 -3
- package/src/dataform-controls/boolean.tsx +19 -2
- package/src/dataform-controls/date.tsx +499 -0
- package/src/dataform-controls/datetime.tsx +5 -91
- package/src/dataform-controls/email.tsx +19 -2
- package/src/dataform-controls/index.tsx +2 -0
- package/src/dataform-controls/integer.tsx +30 -4
- package/src/dataform-controls/relative-date-control.tsx +106 -0
- package/src/dataform-controls/select.tsx +23 -13
- package/src/dataform-controls/style.scss +19 -2
- package/src/dataform-controls/text.tsx +19 -2
- package/src/dataviews-layouts/grid/index.tsx +46 -24
- package/src/dataviews-layouts/grid/preview-size-picker.tsx +48 -73
- package/src/dataviews-layouts/grid/style.scss +15 -28
- package/src/dataviews-layouts/list/index.tsx +7 -4
- package/src/dataviews-layouts/list/style.scss +3 -3
- package/src/dataviews-layouts/table/column-primary.tsx +29 -5
- package/src/dataviews-layouts/table/index.tsx +134 -42
- package/src/dataviews-layouts/table/style.scss +45 -1
- package/src/field-types/array.tsx +33 -21
- package/src/field-types/boolean.tsx +15 -9
- package/src/field-types/date.ts +51 -15
- package/src/field-types/datetime.tsx +19 -13
- package/src/field-types/email.tsx +26 -21
- package/src/field-types/index.tsx +18 -8
- package/src/field-types/integer.tsx +26 -22
- package/src/field-types/media.tsx +19 -13
- package/src/field-types/text.tsx +19 -13
- package/src/filter-and-sort-data-view.ts +11 -4
- package/src/normalize-fields.ts +4 -8
- package/src/test/dataviews.tsx +129 -0
- package/src/test/filter-and-sort-data-view.js +52 -2
- package/src/test/validation.ts +4 -15
- package/src/types.ts +28 -8
- package/src/validation.ts +30 -1
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/dataviews",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -46,18 +46,19 @@
|
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"@ariakit/react": "^0.4.15",
|
|
48
48
|
"@babel/runtime": "7.25.7",
|
|
49
|
-
"@wordpress/base-styles": "^6.
|
|
50
|
-
"@wordpress/components": "^30.
|
|
51
|
-
"@wordpress/compose": "^7.
|
|
52
|
-
"@wordpress/data": "^10.
|
|
53
|
-
"@wordpress/date": "^5.
|
|
54
|
-
"@wordpress/element": "^6.
|
|
55
|
-
"@wordpress/i18n": "^6.
|
|
56
|
-
"@wordpress/icons": "^10.
|
|
57
|
-
"@wordpress/
|
|
58
|
-
"@wordpress/
|
|
59
|
-
"@wordpress/
|
|
60
|
-
"@wordpress/
|
|
49
|
+
"@wordpress/base-styles": "^6.4.0",
|
|
50
|
+
"@wordpress/components": "^30.1.0",
|
|
51
|
+
"@wordpress/compose": "^7.28.0",
|
|
52
|
+
"@wordpress/data": "^10.28.0",
|
|
53
|
+
"@wordpress/date": "^5.28.0",
|
|
54
|
+
"@wordpress/element": "^6.28.0",
|
|
55
|
+
"@wordpress/i18n": "^6.1.0",
|
|
56
|
+
"@wordpress/icons": "^10.28.0",
|
|
57
|
+
"@wordpress/keycodes": "^4.28.0",
|
|
58
|
+
"@wordpress/primitives": "^4.28.0",
|
|
59
|
+
"@wordpress/private-apis": "^1.28.0",
|
|
60
|
+
"@wordpress/url": "^4.28.0",
|
|
61
|
+
"@wordpress/warning": "^3.28.0",
|
|
61
62
|
"clsx": "^2.1.1",
|
|
62
63
|
"date-fns": "^4.1.0",
|
|
63
64
|
"fast-deep-equal": "^3.1.3",
|
|
@@ -73,5 +74,5 @@
|
|
|
73
74
|
"scripts": {
|
|
74
75
|
"build:wp": "node build"
|
|
75
76
|
},
|
|
76
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "28cc2098f5ee28f89096b638533796538f495f72"
|
|
77
78
|
}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import { useMemo, useState } from '@wordpress/element';
|
|
4
|
+
import { useCallback, useMemo, useState } from '@wordpress/element';
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
__experimentalVStack as VStack,
|
|
8
|
+
privateApis,
|
|
9
|
+
} from '@wordpress/components';
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* Internal dependencies
|
|
8
13
|
*/
|
|
9
14
|
import DataForm from '../index';
|
|
10
|
-
import
|
|
15
|
+
import { isItemValid } from '../../../validation';
|
|
16
|
+
import type { Field, Form, DataFormControlProps } from '../../../types';
|
|
17
|
+
import { unlock } from '../../../lock-unlock';
|
|
18
|
+
|
|
19
|
+
const { ValidatedTextControl } = unlock( privateApis );
|
|
11
20
|
|
|
12
21
|
type SamplePost = {
|
|
13
22
|
title: string;
|
|
@@ -62,6 +71,7 @@ const fields = [
|
|
|
62
71
|
label: 'Date as options',
|
|
63
72
|
type: 'datetime' as const,
|
|
64
73
|
elements: [
|
|
74
|
+
{ value: '', label: 'Select a date' },
|
|
65
75
|
{ value: '1970-02-23T12:00:00', label: "Jane's birth date" },
|
|
66
76
|
{ value: '1950-02-23T12:00:00', label: "John's birth date" },
|
|
67
77
|
],
|
|
@@ -259,3 +269,220 @@ export const CombinedFields = {
|
|
|
259
269
|
type: 'panel',
|
|
260
270
|
},
|
|
261
271
|
};
|
|
272
|
+
|
|
273
|
+
function CustomEditControl< Item >( {
|
|
274
|
+
data,
|
|
275
|
+
field,
|
|
276
|
+
onChange,
|
|
277
|
+
hideLabelFromVision,
|
|
278
|
+
}: DataFormControlProps< Item > ) {
|
|
279
|
+
const { id, label, placeholder, description } = field;
|
|
280
|
+
const value = field.getValue( { item: data } );
|
|
281
|
+
|
|
282
|
+
const onChangeControl = useCallback(
|
|
283
|
+
( newValue: string ) =>
|
|
284
|
+
onChange( {
|
|
285
|
+
[ id ]: newValue,
|
|
286
|
+
} ),
|
|
287
|
+
[ id, onChange ]
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<ValidatedTextControl
|
|
292
|
+
required={ !! field.isValid?.required }
|
|
293
|
+
label={ label }
|
|
294
|
+
placeholder={ placeholder }
|
|
295
|
+
value={ value ?? '' }
|
|
296
|
+
help={ description }
|
|
297
|
+
onChange={ onChangeControl }
|
|
298
|
+
__next40pxDefaultSize
|
|
299
|
+
__nextHasNoMarginBottom
|
|
300
|
+
hideLabelFromVision={ hideLabelFromVision }
|
|
301
|
+
/>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const DataFormValidationComponent = ( { required }: { required: boolean } ) => {
|
|
306
|
+
type ValidatedItem = {
|
|
307
|
+
text: string;
|
|
308
|
+
email: string;
|
|
309
|
+
integer: number;
|
|
310
|
+
boolean: boolean;
|
|
311
|
+
customEdit: string;
|
|
312
|
+
customValidation: string;
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const [ post, setPost ] = useState< ValidatedItem >( {
|
|
316
|
+
text: 'Hello, World!',
|
|
317
|
+
email: 'hi@example.com',
|
|
318
|
+
integer: 2,
|
|
319
|
+
boolean: true,
|
|
320
|
+
customEdit: 'custom control',
|
|
321
|
+
customValidation: 'potato',
|
|
322
|
+
} );
|
|
323
|
+
|
|
324
|
+
const _fields: Field< ValidatedItem >[] = [
|
|
325
|
+
{
|
|
326
|
+
id: 'text',
|
|
327
|
+
type: 'text' as const,
|
|
328
|
+
label: 'Text',
|
|
329
|
+
isValid: {
|
|
330
|
+
required,
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
id: 'email',
|
|
335
|
+
type: 'email' as const,
|
|
336
|
+
label: 'e-mail',
|
|
337
|
+
isValid: {
|
|
338
|
+
required,
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
id: 'integer',
|
|
343
|
+
type: 'integer' as const,
|
|
344
|
+
label: 'Integer',
|
|
345
|
+
isValid: {
|
|
346
|
+
required,
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
id: 'boolean',
|
|
351
|
+
type: 'boolean' as const,
|
|
352
|
+
label: 'Boolean',
|
|
353
|
+
isValid: {
|
|
354
|
+
required,
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: 'customEdit',
|
|
359
|
+
label: 'Custom Control',
|
|
360
|
+
Edit: CustomEditControl,
|
|
361
|
+
isValid: {
|
|
362
|
+
required,
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
id: 'customValidation',
|
|
367
|
+
type: 'text',
|
|
368
|
+
label: 'Custom validation',
|
|
369
|
+
isValid: {
|
|
370
|
+
required,
|
|
371
|
+
custom: ( value: ValidatedItem ) => {
|
|
372
|
+
if (
|
|
373
|
+
! [ 'tomato', 'potato' ].includes(
|
|
374
|
+
value.customValidation
|
|
375
|
+
)
|
|
376
|
+
) {
|
|
377
|
+
return 'Value must be one of "tomato", "potato"';
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return null;
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
];
|
|
385
|
+
|
|
386
|
+
const form = {
|
|
387
|
+
fields: [
|
|
388
|
+
'text',
|
|
389
|
+
'email',
|
|
390
|
+
'integer',
|
|
391
|
+
'boolean',
|
|
392
|
+
'customEdit',
|
|
393
|
+
'customValidation',
|
|
394
|
+
],
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const canSave = isItemValid( post, _fields, form );
|
|
398
|
+
|
|
399
|
+
return (
|
|
400
|
+
<form>
|
|
401
|
+
<VStack alignment="left">
|
|
402
|
+
<DataForm< ValidatedItem >
|
|
403
|
+
data={ post }
|
|
404
|
+
fields={ _fields }
|
|
405
|
+
form={ form }
|
|
406
|
+
onChange={ ( edits ) =>
|
|
407
|
+
setPost( ( prev ) => ( {
|
|
408
|
+
...prev,
|
|
409
|
+
...edits,
|
|
410
|
+
} ) )
|
|
411
|
+
}
|
|
412
|
+
/>
|
|
413
|
+
<Button
|
|
414
|
+
__next40pxDefaultSize
|
|
415
|
+
accessibleWhenDisabled
|
|
416
|
+
disabled={ ! canSave }
|
|
417
|
+
variant="primary"
|
|
418
|
+
>
|
|
419
|
+
Submit
|
|
420
|
+
</Button>
|
|
421
|
+
</VStack>
|
|
422
|
+
</form>
|
|
423
|
+
);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
export const Validation = {
|
|
427
|
+
title: 'DataForm/Validation',
|
|
428
|
+
render: DataFormValidationComponent,
|
|
429
|
+
argTypes: {
|
|
430
|
+
required: {
|
|
431
|
+
control: { type: 'boolean' },
|
|
432
|
+
description: 'Whether or not the fields are required.',
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
args: {
|
|
436
|
+
required: true,
|
|
437
|
+
},
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const DataFormVisibilityComponent = () => {
|
|
441
|
+
type Post = {
|
|
442
|
+
name: string;
|
|
443
|
+
email: string;
|
|
444
|
+
isActive: boolean;
|
|
445
|
+
};
|
|
446
|
+
const [ data, setData ] = useState( {
|
|
447
|
+
name: '',
|
|
448
|
+
email: '',
|
|
449
|
+
isActive: true,
|
|
450
|
+
} );
|
|
451
|
+
|
|
452
|
+
const _fields = [
|
|
453
|
+
{ id: 'isActive', label: 'Is module active?', type: 'boolean' },
|
|
454
|
+
{
|
|
455
|
+
id: 'name',
|
|
456
|
+
label: 'Name',
|
|
457
|
+
type: 'text',
|
|
458
|
+
isVisible: ( post ) => post.isActive === true,
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
id: 'email',
|
|
462
|
+
label: 'Email',
|
|
463
|
+
type: 'email',
|
|
464
|
+
isVisible: ( post ) => post.isActive === true,
|
|
465
|
+
},
|
|
466
|
+
] satisfies Field< Post >[];
|
|
467
|
+
const form = {
|
|
468
|
+
fields: [ 'isActive', 'name', 'email' ],
|
|
469
|
+
};
|
|
470
|
+
return (
|
|
471
|
+
<DataForm< Post >
|
|
472
|
+
data={ data }
|
|
473
|
+
fields={ _fields }
|
|
474
|
+
form={ form }
|
|
475
|
+
onChange={ ( edits ) =>
|
|
476
|
+
setData( ( prev ) => ( {
|
|
477
|
+
...prev,
|
|
478
|
+
...edits,
|
|
479
|
+
} ) )
|
|
480
|
+
}
|
|
481
|
+
/>
|
|
482
|
+
);
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
export const Visibility = {
|
|
486
|
+
title: 'DataForm/Visibility',
|
|
487
|
+
render: DataFormVisibilityComponent,
|
|
488
|
+
};
|
|
@@ -7,8 +7,14 @@ import type { ReactNode, ComponentProps, ReactElement } from 'react';
|
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
9
|
import { __experimentalHStack as HStack } from '@wordpress/components';
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
useContext,
|
|
12
|
+
useMemo,
|
|
13
|
+
useRef,
|
|
14
|
+
useState,
|
|
15
|
+
useEffect,
|
|
16
|
+
} from '@wordpress/element';
|
|
17
|
+
import { useResizeObserver } from '@wordpress/compose';
|
|
12
18
|
|
|
13
19
|
/**
|
|
14
20
|
* Internal dependencies
|
|
@@ -59,7 +65,8 @@ type DataViewsProps< Item > = {
|
|
|
59
65
|
header?: ReactNode;
|
|
60
66
|
getItemLevel?: ( item: Item ) => number;
|
|
61
67
|
children?: ReactNode;
|
|
62
|
-
perPageSizes?: [
|
|
68
|
+
perPageSizes?: number[];
|
|
69
|
+
empty?: ReactNode;
|
|
63
70
|
} & ( Item extends ItemWithId
|
|
64
71
|
? { getItemId?: ( item: Item ) => string }
|
|
65
72
|
: { getItemId: ( item: Item ) => string } );
|
|
@@ -133,7 +140,8 @@ function DataViews< Item >( {
|
|
|
133
140
|
isItemClickable = defaultIsItemClickable,
|
|
134
141
|
header,
|
|
135
142
|
children,
|
|
136
|
-
perPageSizes,
|
|
143
|
+
perPageSizes = [ 10, 20, 50, 100 ],
|
|
144
|
+
empty,
|
|
137
145
|
}: DataViewsProps< Item > ) {
|
|
138
146
|
const containerRef = useRef< HTMLDivElement | null >( null );
|
|
139
147
|
const [ containerWidth, setContainerWidth ] = useState( 0 );
|
|
@@ -168,10 +176,23 @@ function DataViews< Item >( {
|
|
|
168
176
|
}, [ selection, data, getItemId ] );
|
|
169
177
|
|
|
170
178
|
const filters = useFilters( _fields, view );
|
|
171
|
-
const
|
|
172
|
-
(
|
|
179
|
+
const hasPrimaryOrLockedFilters = useMemo(
|
|
180
|
+
() =>
|
|
181
|
+
( filters || [] ).some(
|
|
182
|
+
( filter ) => filter.isPrimary || filter.isLocked
|
|
183
|
+
),
|
|
184
|
+
[ filters ]
|
|
185
|
+
);
|
|
186
|
+
const [ isShowingFilter, setIsShowingFilter ] = useState< boolean >(
|
|
187
|
+
hasPrimaryOrLockedFilters
|
|
173
188
|
);
|
|
174
189
|
|
|
190
|
+
useEffect( () => {
|
|
191
|
+
if ( hasPrimaryOrLockedFilters && ! isShowingFilter ) {
|
|
192
|
+
setIsShowingFilter( true );
|
|
193
|
+
}
|
|
194
|
+
}, [ hasPrimaryOrLockedFilters, isShowingFilter ] );
|
|
195
|
+
|
|
175
196
|
return (
|
|
176
197
|
<DataViewsContext.Provider
|
|
177
198
|
value={ {
|
|
@@ -193,17 +214,16 @@ function DataViews< Item >( {
|
|
|
193
214
|
renderItemLink,
|
|
194
215
|
containerWidth,
|
|
195
216
|
containerRef,
|
|
217
|
+
resizeObserverRef,
|
|
196
218
|
defaultLayouts,
|
|
197
219
|
filters,
|
|
198
220
|
isShowingFilter,
|
|
199
221
|
setIsShowingFilter,
|
|
200
222
|
perPageSizes,
|
|
223
|
+
empty,
|
|
201
224
|
} }
|
|
202
225
|
>
|
|
203
|
-
<div
|
|
204
|
-
className="dataviews-wrapper"
|
|
205
|
-
ref={ useMergeRefs( [ containerRef, resizeObserverRef ] ) }
|
|
206
|
-
>
|
|
226
|
+
<div className="dataviews-wrapper" ref={ containerRef }>
|
|
207
227
|
{ children ?? (
|
|
208
228
|
<DefaultUI
|
|
209
229
|
header={ header }
|
|
@@ -41,7 +41,8 @@ export const data: SpaceObject[] = [
|
|
|
41
41
|
{
|
|
42
42
|
id: 1,
|
|
43
43
|
title: 'Moon',
|
|
44
|
-
description:
|
|
44
|
+
description:
|
|
45
|
+
'The Moon is Earth’s only natural satellite, orbiting at an average distance of 384,400 kilometers with a synchronous rotation that leads to fixed lunar phases as seen from Earth. Its cratered surface and subtle glow define night skies, inspiring exploration missions and influencing tides and biological rhythms worldwide.',
|
|
45
46
|
image: 'https://live.staticflickr.com/7398/9458193857_e1256123e3_z.jpg',
|
|
46
47
|
type: 'Satellite',
|
|
47
48
|
isPlanet: false,
|
|
@@ -759,5 +760,6 @@ export const fields: Field< SpaceObject >[] = [
|
|
|
759
760
|
{ value: 'Gas giant', label: 'Gas giant' },
|
|
760
761
|
],
|
|
761
762
|
type: 'array',
|
|
763
|
+
enableGlobalSearch: true,
|
|
762
764
|
},
|
|
763
765
|
];
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
__experimentalText as Text,
|
|
21
21
|
__experimentalHStack as HStack,
|
|
22
22
|
__experimentalVStack as VStack,
|
|
23
|
+
Button,
|
|
23
24
|
} from '@wordpress/components';
|
|
24
25
|
import { __, _n } from '@wordpress/i18n';
|
|
25
26
|
|
|
@@ -53,7 +54,7 @@ const defaultLayouts = {
|
|
|
53
54
|
[ LAYOUT_LIST ]: {},
|
|
54
55
|
};
|
|
55
56
|
|
|
56
|
-
export const Default = () => {
|
|
57
|
+
export const Default = ( { perPageSizes = [ 10, 25, 50, 100 ] } ) => {
|
|
57
58
|
const [ view, setView ] = useState< View >( {
|
|
58
59
|
...DEFAULT_VIEW,
|
|
59
60
|
fields: [ 'categories' ],
|
|
@@ -86,10 +87,22 @@ export const Default = () => {
|
|
|
86
87
|
) }
|
|
87
88
|
isItemClickable={ () => true }
|
|
88
89
|
defaultLayouts={ defaultLayouts }
|
|
90
|
+
perPageSizes={ perPageSizes }
|
|
89
91
|
/>
|
|
90
92
|
);
|
|
91
93
|
};
|
|
92
94
|
|
|
95
|
+
Default.args = {
|
|
96
|
+
perPageSizes: [ 10, 25, 50, 100 ],
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
Default.argTypes = {
|
|
100
|
+
perPageSizes: {
|
|
101
|
+
control: 'object',
|
|
102
|
+
description: 'Array of available page sizes',
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
93
106
|
export const Empty = () => {
|
|
94
107
|
const [ view, setView ] = useState< View >( {
|
|
95
108
|
...DEFAULT_VIEW,
|
|
@@ -110,6 +123,27 @@ export const Empty = () => {
|
|
|
110
123
|
);
|
|
111
124
|
};
|
|
112
125
|
|
|
126
|
+
export const CustomEmpty = () => {
|
|
127
|
+
const [ view, setView ] = useState< View >( {
|
|
128
|
+
...DEFAULT_VIEW,
|
|
129
|
+
fields: [ 'title', 'description', 'categories' ],
|
|
130
|
+
} );
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<DataViews
|
|
134
|
+
getItemId={ ( item ) => item.id.toString() }
|
|
135
|
+
paginationInfo={ { totalItems: 0, totalPages: 0 } }
|
|
136
|
+
data={ [] }
|
|
137
|
+
view={ view }
|
|
138
|
+
fields={ fields }
|
|
139
|
+
onChangeView={ setView }
|
|
140
|
+
actions={ actions }
|
|
141
|
+
defaultLayouts={ defaultLayouts }
|
|
142
|
+
empty={ view.search ? 'No sites found' : 'No sites' }
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
113
147
|
export const FieldsNoSortableNoHidable = () => {
|
|
114
148
|
const [ view, setView ] = useState< View >( {
|
|
115
149
|
...DEFAULT_VIEW,
|
|
@@ -261,6 +295,19 @@ export const FreeComposition = () => {
|
|
|
261
295
|
table: {},
|
|
262
296
|
grid: {},
|
|
263
297
|
} }
|
|
298
|
+
empty={
|
|
299
|
+
<VStack
|
|
300
|
+
justify="space-around"
|
|
301
|
+
alignment="center"
|
|
302
|
+
className="free-composition-dataviews-empty"
|
|
303
|
+
>
|
|
304
|
+
<Text size={ 18 } as="p">
|
|
305
|
+
No planets
|
|
306
|
+
</Text>
|
|
307
|
+
<Text variant="muted">{ `Try a different search because “${ view.search }” returned no results.` }</Text>
|
|
308
|
+
<Button variant="secondary">Create new planet</Button>
|
|
309
|
+
</VStack>
|
|
310
|
+
}
|
|
264
311
|
>
|
|
265
312
|
<PlanetOverview planets={ planets } />
|
|
266
313
|
</DataViews>
|
|
@@ -300,34 +347,7 @@ export const WithCard = () => {
|
|
|
300
347
|
);
|
|
301
348
|
};
|
|
302
349
|
|
|
303
|
-
export const
|
|
304
|
-
const [ view, setView ] = useState< View >( {
|
|
305
|
-
...DEFAULT_VIEW,
|
|
306
|
-
fields: [ 'categories' ],
|
|
307
|
-
titleField: 'title',
|
|
308
|
-
descriptionField: 'description',
|
|
309
|
-
mediaField: 'image',
|
|
310
|
-
perPage: 3,
|
|
311
|
-
} );
|
|
312
|
-
const { data: shownData, paginationInfo } = useMemo( () => {
|
|
313
|
-
return filterSortAndPaginate( data, view, fields );
|
|
314
|
-
}, [ view ] );
|
|
315
|
-
return (
|
|
316
|
-
<DataViews
|
|
317
|
-
getItemId={ ( item ) => item.id.toString() }
|
|
318
|
-
paginationInfo={ paginationInfo }
|
|
319
|
-
data={ shownData }
|
|
320
|
-
view={ view }
|
|
321
|
-
fields={ fields }
|
|
322
|
-
onChangeView={ setView }
|
|
323
|
-
actions={ actions.filter( ( action ) => ! action.supportsBulk ) }
|
|
324
|
-
defaultLayouts={ defaultLayouts }
|
|
325
|
-
perPageSizes={ [ 3, 6, 12, 24 ] }
|
|
326
|
-
/>
|
|
327
|
-
);
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
export const GroupedGridLayout = () => {
|
|
350
|
+
export const GroupByLayout = () => {
|
|
331
351
|
const [ view, setView ] = useState< View >( {
|
|
332
352
|
type: LAYOUT_GRID,
|
|
333
353
|
search: '',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import type { ComponentProps, ReactElement } from 'react';
|
|
4
|
+
import type { ComponentProps, ReactElement, ReactNode } from 'react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
@@ -47,11 +47,15 @@ type DataViewsContextType< Item > = {
|
|
|
47
47
|
isItemClickable: ( item: Item ) => boolean;
|
|
48
48
|
containerWidth: number;
|
|
49
49
|
containerRef: React.MutableRefObject< HTMLDivElement | null >;
|
|
50
|
+
resizeObserverRef:
|
|
51
|
+
| ( ( element?: HTMLDivElement | null ) => void )
|
|
52
|
+
| React.RefObject< HTMLDivElement >;
|
|
50
53
|
defaultLayouts: SupportedLayouts;
|
|
51
54
|
filters: NormalizedFilter[];
|
|
52
55
|
isShowingFilter: boolean;
|
|
53
56
|
setIsShowingFilter: ( value: boolean ) => void;
|
|
54
|
-
perPageSizes
|
|
57
|
+
perPageSizes: number[];
|
|
58
|
+
empty?: ReactNode;
|
|
55
59
|
};
|
|
56
60
|
|
|
57
61
|
const DataViewsContext = createContext< DataViewsContextType< any > >( {
|
|
@@ -72,10 +76,12 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
|
|
|
72
76
|
renderItemLink: undefined,
|
|
73
77
|
containerWidth: 0,
|
|
74
78
|
containerRef: createRef(),
|
|
79
|
+
resizeObserverRef: () => {},
|
|
75
80
|
defaultLayouts: { list: {}, grid: {}, table: {} },
|
|
76
81
|
filters: [],
|
|
77
82
|
isShowingFilter: false,
|
|
78
83
|
setIsShowingFilter: () => {},
|
|
84
|
+
perPageSizes: [],
|
|
79
85
|
} );
|
|
80
86
|
|
|
81
87
|
export default DataViewsContext;
|
|
@@ -309,9 +309,9 @@ const FilterText = ( {
|
|
|
309
309
|
|
|
310
310
|
return createInterpolateElement(
|
|
311
311
|
sprintf(
|
|
312
|
-
/* translators: 1: Filter name. 2: Min value. 3: Max value. e.g.: "Item count between (inc): 10
|
|
312
|
+
/* translators: 1: Filter name. 2: Min value. 3: Max value. e.g.: "Item count between (inc): 10 and 180". */
|
|
313
313
|
__(
|
|
314
|
-
'<Name>%1$s between (inc): </Name><Value>%2$s
|
|
314
|
+
'<Name>%1$s between (inc): </Name><Value>%2$s and %3$s</Value>'
|
|
315
315
|
),
|
|
316
316
|
filter.name,
|
|
317
317
|
label[ 0 ],
|
|
@@ -497,8 +497,9 @@ export default function Filter( {
|
|
|
497
497
|
}
|
|
498
498
|
|
|
499
499
|
const isPrimary = filter.isPrimary;
|
|
500
|
-
const
|
|
501
|
-
const
|
|
500
|
+
const isLocked = filterInView?.isLocked;
|
|
501
|
+
const hasValues = ! isLocked && filterInView?.value !== undefined;
|
|
502
|
+
const canResetOrRemove = ! isLocked && ( ! isPrimary || hasValues );
|
|
502
503
|
return (
|
|
503
504
|
<Dropdown
|
|
504
505
|
defaultOpen={ openedFilter === filter.field }
|
|
@@ -523,17 +524,26 @@ export default function Filter( {
|
|
|
523
524
|
{
|
|
524
525
|
'has-reset': canResetOrRemove,
|
|
525
526
|
'has-values': hasValues,
|
|
527
|
+
'is-not-clickable': isLocked,
|
|
526
528
|
}
|
|
527
529
|
) }
|
|
528
530
|
role="button"
|
|
529
|
-
tabIndex={ 0 }
|
|
530
|
-
onClick={
|
|
531
|
+
tabIndex={ isLocked ? -1 : 0 }
|
|
532
|
+
onClick={ () => {
|
|
533
|
+
if ( ! isLocked ) {
|
|
534
|
+
onToggle();
|
|
535
|
+
}
|
|
536
|
+
} }
|
|
531
537
|
onKeyDown={ ( event ) => {
|
|
532
|
-
if (
|
|
538
|
+
if (
|
|
539
|
+
! isLocked &&
|
|
540
|
+
[ ENTER, SPACE ].includes( event.key )
|
|
541
|
+
) {
|
|
533
542
|
onToggle();
|
|
534
543
|
event.preventDefault();
|
|
535
544
|
}
|
|
536
545
|
} }
|
|
546
|
+
aria-disabled={ isLocked }
|
|
537
547
|
aria-pressed={ isOpen }
|
|
538
548
|
aria-expanded={ isOpen }
|
|
539
549
|
ref={ toggleRef }
|
|
@@ -36,6 +36,10 @@ export function useFilters( fields: NormalizedField< any >[], view: View ) {
|
|
|
36
36
|
|
|
37
37
|
const operators = field.filterBy.operators;
|
|
38
38
|
const isPrimary = !! field.filterBy?.isPrimary;
|
|
39
|
+
const isLocked =
|
|
40
|
+
view.filters?.some(
|
|
41
|
+
( f ) => f.field === field.id && !! f.isLocked
|
|
42
|
+
) ?? false;
|
|
39
43
|
filters.push( {
|
|
40
44
|
field: field.id,
|
|
41
45
|
name: field.label,
|
|
@@ -45,6 +49,7 @@ export function useFilters( fields: NormalizedField< any >[], view: View ) {
|
|
|
45
49
|
),
|
|
46
50
|
operators,
|
|
47
51
|
isVisible:
|
|
52
|
+
isLocked ||
|
|
48
53
|
isPrimary ||
|
|
49
54
|
!! view.filters?.some(
|
|
50
55
|
( f ) =>
|
|
@@ -52,11 +57,21 @@ export function useFilters( fields: NormalizedField< any >[], view: View ) {
|
|
|
52
57
|
ALL_OPERATORS.includes( f.operator )
|
|
53
58
|
),
|
|
54
59
|
isPrimary,
|
|
60
|
+
isLocked,
|
|
55
61
|
} );
|
|
56
62
|
} );
|
|
57
|
-
|
|
58
|
-
//
|
|
63
|
+
|
|
64
|
+
// Sort filters by:
|
|
65
|
+
// - locked filters go first
|
|
66
|
+
// - primary filters go next
|
|
67
|
+
// - then, sort by name
|
|
59
68
|
filters.sort( ( a, b ) => {
|
|
69
|
+
if ( a.isLocked && ! b.isLocked ) {
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
if ( ! a.isLocked && b.isLocked ) {
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
60
75
|
if ( a.isPrimary && ! b.isPrimary ) {
|
|
61
76
|
return -1;
|
|
62
77
|
}
|
|
@@ -62,7 +62,13 @@ export default function InputWidget( {
|
|
|
62
62
|
..._filter,
|
|
63
63
|
operator:
|
|
64
64
|
currentFilter.operator || filter.operators[ 0 ],
|
|
65
|
-
|
|
65
|
+
// Consider empty strings as undefined:
|
|
66
|
+
//
|
|
67
|
+
// - undefined as value means the filter is unset: the filter widget displays no value and the search returns all records
|
|
68
|
+
// - empty string as value means "search empty string": returns only the records that have an empty string as value
|
|
69
|
+
//
|
|
70
|
+
// In practice, this means the filter will not be able to find an empty string as the value.
|
|
71
|
+
value: nextValue === '' ? undefined : nextValue,
|
|
66
72
|
}
|
|
67
73
|
: _filter
|
|
68
74
|
),
|