@wordpress/dataviews 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -5
- package/build/components/dataform/index.js +10 -61
- package/build/components/dataform/index.js.map +1 -1
- package/build/components/dataviews/index.js +16 -5
- package/build/components/dataviews/index.js.map +1 -1
- package/build/components/dataviews-bulk-actions/index.js +3 -0
- package/build/components/dataviews-bulk-actions/index.js.map +1 -1
- package/build/components/dataviews-filters/add-filter.js +34 -17
- package/build/components/dataviews-filters/add-filter.js.map +1 -1
- package/build/components/dataviews-filters/index.js +106 -43
- package/build/components/dataviews-filters/index.js.map +1 -1
- package/build/components/dataviews-layout/index.js +2 -2
- package/build/components/dataviews-layout/index.js.map +1 -1
- package/build/components/dataviews-search/index.js +8 -5
- package/build/components/dataviews-search/index.js.map +1 -1
- package/build/components/dataviews-view-config/index.js +225 -190
- package/build/components/dataviews-view-config/index.js.map +1 -1
- package/build/constants.js +6 -1
- package/build/constants.js.map +1 -1
- package/build/dataforms-layouts/index.js +24 -0
- package/build/dataforms-layouts/index.js.map +1 -0
- package/build/dataforms-layouts/panel/index.js +129 -0
- package/build/dataforms-layouts/panel/index.js.map +1 -0
- package/build/dataforms-layouts/regular/index.js +39 -0
- package/build/dataforms-layouts/regular/index.js.map +1 -0
- package/build/{layouts → dataviews-layouts}/grid/density-picker.js +1 -1
- package/build/dataviews-layouts/grid/density-picker.js.map +1 -0
- package/build/{layouts → dataviews-layouts}/grid/index.js +8 -8
- package/build/dataviews-layouts/grid/index.js.map +1 -0
- package/build/dataviews-layouts/index.js.map +1 -0
- package/build/dataviews-layouts/list/index.js.map +1 -0
- package/build/{layouts → dataviews-layouts}/table/column-header-menu.js +1 -1
- package/build/dataviews-layouts/table/column-header-menu.js.map +1 -0
- package/build/dataviews-layouts/table/index.js.map +1 -0
- package/build/field-types/index.js +46 -0
- package/build/field-types/index.js.map +1 -0
- package/build/field-types/integer.js +94 -0
- package/build/field-types/integer.js.map +1 -0
- package/build/field-types/text.js +87 -0
- package/build/field-types/text.js.map +1 -0
- package/build/filter-and-sort-data-view.js +2 -11
- package/build/filter-and-sort-data-view.js.map +1 -1
- package/build/index.js +9 -2
- package/build/index.js.map +1 -1
- package/build/normalize-fields.js +35 -1
- package/build/normalize-fields.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build/validation.js +22 -0
- package/build/validation.js.map +1 -0
- package/build-module/components/dataform/index.js +10 -61
- package/build-module/components/dataform/index.js.map +1 -1
- package/build-module/components/dataviews/index.js +14 -5
- package/build-module/components/dataviews/index.js.map +1 -1
- package/build-module/components/dataviews-bulk-actions/index.js +3 -0
- package/build-module/components/dataviews-bulk-actions/index.js.map +1 -1
- package/build-module/components/dataviews-filters/add-filter.js +33 -17
- package/build-module/components/dataviews-filters/add-filter.js.map +1 -1
- package/build-module/components/dataviews-filters/index.js +105 -45
- package/build-module/components/dataviews-filters/index.js.map +1 -1
- package/build-module/components/dataviews-layout/index.js +1 -1
- package/build-module/components/dataviews-layout/index.js.map +1 -1
- package/build-module/components/dataviews-search/index.js +8 -5
- package/build-module/components/dataviews-search/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/index.js +228 -193
- package/build-module/components/dataviews-view-config/index.js.map +1 -1
- package/build-module/constants.js +5 -0
- package/build-module/constants.js.map +1 -1
- package/build-module/dataforms-layouts/index.js +16 -0
- package/build-module/dataforms-layouts/index.js.map +1 -0
- package/build-module/dataforms-layouts/panel/index.js +124 -0
- package/build-module/dataforms-layouts/panel/index.js.map +1 -0
- package/build-module/dataforms-layouts/regular/index.js +32 -0
- package/build-module/dataforms-layouts/regular/index.js.map +1 -0
- package/build-module/{layouts → dataviews-layouts}/grid/density-picker.js +2 -2
- package/build-module/dataviews-layouts/grid/density-picker.js.map +1 -0
- package/build-module/{layouts → dataviews-layouts}/grid/index.js +8 -8
- package/build-module/dataviews-layouts/grid/index.js.map +1 -0
- package/build-module/dataviews-layouts/index.js.map +1 -0
- package/build-module/dataviews-layouts/list/index.js.map +1 -0
- package/build-module/{layouts → dataviews-layouts}/table/column-header-menu.js +1 -1
- package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -0
- package/build-module/dataviews-layouts/table/index.js.map +1 -0
- package/build-module/field-types/index.js +40 -0
- package/build-module/field-types/index.js.map +1 -0
- package/build-module/field-types/integer.js +87 -0
- package/build-module/field-types/integer.js.map +1 -0
- package/build-module/field-types/text.js +80 -0
- package/build-module/field-types/text.js.map +1 -0
- package/build-module/filter-and-sort-data-view.js +2 -11
- package/build-module/filter-and-sort-data-view.js.map +1 -1
- package/build-module/index.js +2 -1
- package/build-module/index.js.map +1 -1
- package/build-module/normalize-fields.js +34 -2
- package/build-module/normalize-fields.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-module/validation.js +15 -0
- package/build-module/validation.js.map +1 -0
- package/build-style/style-rtl.css +175 -6
- package/build-style/style.css +175 -6
- package/build-types/components/dataform/index.d.ts +2 -13
- package/build-types/components/dataform/index.d.ts.map +1 -1
- package/build-types/components/dataform/stories/index.story.d.ts +12 -1
- package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews/index.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/fixtures.d.ts +6 -0
- package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
- package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/add-filter.d.ts +3 -0
- package/build-types/components/dataviews-filters/add-filter.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/index.d.ts +11 -1
- package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
- package/build-types/components/dataviews-search/index.d.ts.map +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts +1 -1
- package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
- package/build-types/constants.d.ts +4 -0
- package/build-types/constants.d.ts.map +1 -1
- package/build-types/dataforms-layouts/index.d.ts +9 -0
- package/build-types/dataforms-layouts/index.d.ts.map +1 -0
- package/build-types/dataforms-layouts/panel/index.d.ts +3 -0
- package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -0
- package/build-types/dataforms-layouts/regular/index.d.ts +3 -0
- package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -0
- package/build-types/dataviews-layouts/grid/density-picker.d.ts.map +1 -0
- package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -0
- package/build-types/dataviews-layouts/index.d.ts.map +1 -0
- package/build-types/dataviews-layouts/list/index.d.ts.map +1 -0
- package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -0
- package/build-types/dataviews-layouts/table/index.d.ts.map +1 -0
- package/build-types/field-types/index.d.ts +20 -0
- package/build-types/field-types/index.d.ts.map +1 -0
- package/build-types/field-types/integer.d.ts +14 -0
- package/build-types/field-types/integer.d.ts.map +1 -0
- package/build-types/field-types/text.d.ts +14 -0
- package/build-types/field-types/text.d.ts.map +1 -0
- package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
- package/build-types/index.d.ts +2 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/normalize-fields.d.ts +0 -3
- package/build-types/normalize-fields.d.ts.map +1 -1
- package/build-types/types.d.ts +38 -3
- package/build-types/types.d.ts.map +1 -1
- package/build-types/validation.d.ts +3 -0
- package/build-types/validation.d.ts.map +1 -0
- package/package.json +12 -11
- package/src/components/dataform/index.tsx +8 -97
- package/src/components/dataform/stories/index.story.tsx +40 -3
- package/src/components/dataviews/index.tsx +20 -8
- package/src/components/dataviews/stories/fixtures.js +1 -0
- package/src/components/dataviews/style.scss +5 -2
- package/src/components/dataviews-bulk-actions/index.tsx +5 -0
- package/src/components/dataviews-filters/add-filter.tsx +37 -21
- package/src/components/dataviews-filters/index.tsx +149 -61
- package/src/components/dataviews-filters/style.scss +30 -0
- package/src/components/dataviews-layout/index.tsx +1 -1
- package/src/components/dataviews-search/index.tsx +8 -5
- package/src/components/dataviews-view-config/index.tsx +272 -258
- package/src/components/dataviews-view-config/style.scss +44 -0
- package/src/constants.ts +5 -0
- package/src/dataforms-layouts/index.tsx +20 -0
- package/src/dataforms-layouts/panel/index.tsx +164 -0
- package/src/dataforms-layouts/panel/style.scss +59 -0
- package/src/dataforms-layouts/regular/index.tsx +41 -0
- package/src/{layouts → dataviews-layouts}/grid/density-picker.tsx +2 -2
- package/src/{layouts → dataviews-layouts}/grid/index.tsx +8 -8
- package/src/{layouts → dataviews-layouts}/grid/style.scss +29 -0
- package/src/{layouts → dataviews-layouts}/list/style.scss +4 -1
- package/src/{layouts → dataviews-layouts}/table/column-header-menu.tsx +1 -1
- package/src/field-types/index.tsx +45 -0
- package/src/field-types/integer.tsx +103 -0
- package/src/field-types/text.tsx +95 -0
- package/src/filter-and-sort-data-view.ts +1 -15
- package/src/index.ts +2 -1
- package/src/normalize-fields.ts +44 -3
- package/src/style.scss +6 -3
- package/src/test/filter-and-sort-data-view.js +46 -3
- package/src/test/validation.ts +131 -0
- package/src/types.ts +50 -3
- package/src/validation.ts +18 -0
- package/tsconfig.json +2 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/build/layouts/grid/density-picker.js.map +0 -1
- package/build/layouts/grid/index.js.map +0 -1
- package/build/layouts/index.js.map +0 -1
- package/build/layouts/list/index.js.map +0 -1
- package/build/layouts/table/column-header-menu.js.map +0 -1
- package/build/layouts/table/index.js.map +0 -1
- package/build-module/layouts/grid/density-picker.js.map +0 -1
- package/build-module/layouts/grid/index.js.map +0 -1
- package/build-module/layouts/index.js.map +0 -1
- package/build-module/layouts/list/index.js.map +0 -1
- package/build-module/layouts/table/column-header-menu.js.map +0 -1
- package/build-module/layouts/table/index.js.map +0 -1
- package/build-types/layouts/grid/density-picker.d.ts.map +0 -1
- package/build-types/layouts/grid/index.d.ts.map +0 -1
- package/build-types/layouts/index.d.ts.map +0 -1
- package/build-types/layouts/list/index.d.ts.map +0 -1
- package/build-types/layouts/table/column-header-menu.d.ts.map +0 -1
- package/build-types/layouts/table/index.d.ts.map +0 -1
- /package/build/{layouts → dataviews-layouts}/index.js +0 -0
- /package/build/{layouts → dataviews-layouts}/list/index.js +0 -0
- /package/build/{layouts → dataviews-layouts}/table/index.js +0 -0
- /package/build-module/{layouts → dataviews-layouts}/index.js +0 -0
- /package/build-module/{layouts → dataviews-layouts}/list/index.js +0 -0
- /package/build-module/{layouts → dataviews-layouts}/table/index.js +0 -0
- /package/build-types/{layouts → dataviews-layouts}/grid/density-picker.d.ts +0 -0
- /package/build-types/{layouts → dataviews-layouts}/grid/index.d.ts +0 -0
- /package/build-types/{layouts → dataviews-layouts}/index.d.ts +0 -0
- /package/build-types/{layouts → dataviews-layouts}/list/index.d.ts +0 -0
- /package/build-types/{layouts → dataviews-layouts}/table/column-header-menu.d.ts +0 -0
- /package/build-types/{layouts → dataviews-layouts}/table/index.d.ts +0 -0
- /package/src/{layouts → dataviews-layouts}/index.ts +0 -0
- /package/src/{layouts → dataviews-layouts}/list/index.tsx +0 -0
- /package/src/{layouts → dataviews-layouts}/table/index.tsx +0 -0
- /package/src/{layouts → dataviews-layouts}/table/style.scss +0 -0
package/src/normalize-fields.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal dependencies
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
4
|
+
import getFieldTypeDefinition from './field-types';
|
|
5
|
+
import type { Field, NormalizedField } from './types';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Apply default values and normalize the fields config.
|
|
@@ -13,15 +14,55 @@ export function normalizeFields< Item >(
|
|
|
13
14
|
fields: Field< Item >[]
|
|
14
15
|
): NormalizedField< Item >[] {
|
|
15
16
|
return fields.map( ( field ) => {
|
|
17
|
+
const fieldTypeDefinition = getFieldTypeDefinition( field.type );
|
|
18
|
+
|
|
16
19
|
const getValue =
|
|
17
20
|
field.getValue ||
|
|
18
|
-
( ( { item }: { item:
|
|
21
|
+
( ( { item }: { item: Item } ) => item[ field.id as keyof Item ] );
|
|
22
|
+
|
|
23
|
+
const sort =
|
|
24
|
+
field.sort ??
|
|
25
|
+
function sort( a, b, direction ) {
|
|
26
|
+
return fieldTypeDefinition.sort(
|
|
27
|
+
getValue( { item: a } ),
|
|
28
|
+
getValue( { item: b } ),
|
|
29
|
+
direction
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const isValid =
|
|
34
|
+
field.isValid ??
|
|
35
|
+
function isValid( item, context ) {
|
|
36
|
+
return fieldTypeDefinition.isValid(
|
|
37
|
+
getValue( { item } ),
|
|
38
|
+
context
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const Edit = field.Edit || fieldTypeDefinition.Edit;
|
|
43
|
+
|
|
44
|
+
const renderFromElements = ( { item }: { item: Item } ) => {
|
|
45
|
+
const value = getValue( { item } );
|
|
46
|
+
const label = field?.elements?.find( ( element ) => {
|
|
47
|
+
// Intentionally using == here to allow for type coercion.
|
|
48
|
+
// eslint-disable-next-line eqeqeq
|
|
49
|
+
return element.value == value;
|
|
50
|
+
} )?.label;
|
|
51
|
+
|
|
52
|
+
return label || value;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const render =
|
|
56
|
+
field.render || ( field.elements ? renderFromElements : getValue );
|
|
19
57
|
|
|
20
58
|
return {
|
|
21
59
|
...field,
|
|
22
60
|
label: field.label || field.id,
|
|
23
61
|
getValue,
|
|
24
|
-
render
|
|
62
|
+
render,
|
|
63
|
+
sort,
|
|
64
|
+
isValid,
|
|
65
|
+
Edit,
|
|
25
66
|
};
|
|
26
67
|
} );
|
|
27
68
|
}
|
package/src/style.scss
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
@import "./components/dataviews-pagination/style.scss";
|
|
6
6
|
@import "./components/dataviews-item-actions/style.scss";
|
|
7
7
|
@import "./components/dataviews-selection-checkbox/style.scss";
|
|
8
|
+
@import "./components/dataviews-view-config/style.scss";
|
|
8
9
|
|
|
9
|
-
@import "./layouts/grid/style.scss";
|
|
10
|
-
@import "./layouts/list/style.scss";
|
|
11
|
-
@import "./layouts/table/style.scss";
|
|
10
|
+
@import "./dataviews-layouts/grid/style.scss";
|
|
11
|
+
@import "./dataviews-layouts/list/style.scss";
|
|
12
|
+
@import "./dataviews-layouts/table/style.scss";
|
|
13
|
+
|
|
14
|
+
@import "./dataforms-layouts/panel/style.scss";
|
|
@@ -233,7 +233,22 @@ describe( 'filters', () => {
|
|
|
233
233
|
} );
|
|
234
234
|
|
|
235
235
|
describe( 'sorting', () => {
|
|
236
|
-
it( 'should sort
|
|
236
|
+
it( 'should sort integer field types', () => {
|
|
237
|
+
const { data: result } = filterSortAndPaginate(
|
|
238
|
+
data,
|
|
239
|
+
{
|
|
240
|
+
sort: { field: 'satellites', direction: 'desc' },
|
|
241
|
+
},
|
|
242
|
+
fields
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
expect( result ).toHaveLength( 11 );
|
|
246
|
+
expect( result[ 0 ].title ).toBe( 'Saturn' );
|
|
247
|
+
expect( result[ 1 ].title ).toBe( 'Jupiter' );
|
|
248
|
+
expect( result[ 2 ].title ).toBe( 'Uranus' );
|
|
249
|
+
} );
|
|
250
|
+
|
|
251
|
+
it( 'should sort text field types', () => {
|
|
237
252
|
const { data: result } = filterSortAndPaginate(
|
|
238
253
|
data,
|
|
239
254
|
{
|
|
@@ -253,13 +268,18 @@ describe( 'sorting', () => {
|
|
|
253
268
|
expect( result[ 1 ].title ).toBe( 'Neptune' );
|
|
254
269
|
} );
|
|
255
270
|
|
|
256
|
-
it( 'should sort
|
|
271
|
+
it( 'should sort untyped fields if the value is a number', () => {
|
|
257
272
|
const { data: result } = filterSortAndPaginate(
|
|
258
273
|
data,
|
|
259
274
|
{
|
|
260
275
|
sort: { field: 'satellites', direction: 'desc' },
|
|
261
276
|
},
|
|
262
|
-
fields
|
|
277
|
+
// Remove type information for satellites field to test sorting untyped fields.
|
|
278
|
+
fields.map( ( field ) =>
|
|
279
|
+
field.id === 'satellites'
|
|
280
|
+
? { ...field, type: undefined }
|
|
281
|
+
: field
|
|
282
|
+
)
|
|
263
283
|
);
|
|
264
284
|
|
|
265
285
|
expect( result ).toHaveLength( 11 );
|
|
@@ -267,6 +287,29 @@ describe( 'sorting', () => {
|
|
|
267
287
|
expect( result[ 1 ].title ).toBe( 'Jupiter' );
|
|
268
288
|
expect( result[ 2 ].title ).toBe( 'Uranus' );
|
|
269
289
|
} );
|
|
290
|
+
|
|
291
|
+
it( 'should sort untyped fields if the value is string', () => {
|
|
292
|
+
const { data: result } = filterSortAndPaginate(
|
|
293
|
+
data,
|
|
294
|
+
{
|
|
295
|
+
sort: { field: 'title', direction: 'desc' },
|
|
296
|
+
filters: [
|
|
297
|
+
{
|
|
298
|
+
field: 'type',
|
|
299
|
+
operator: 'isAny',
|
|
300
|
+
value: [ 'Ice giant' ],
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
},
|
|
304
|
+
// Remove type information for the title field to test sorting untyped fields.
|
|
305
|
+
fields.map( ( field ) =>
|
|
306
|
+
field.id === 'title' ? { ...field, type: undefined } : field
|
|
307
|
+
)
|
|
308
|
+
);
|
|
309
|
+
expect( result ).toHaveLength( 2 );
|
|
310
|
+
expect( result[ 0 ].title ).toBe( 'Uranus' );
|
|
311
|
+
expect( result[ 1 ].title ).toBe( 'Neptune' );
|
|
312
|
+
} );
|
|
270
313
|
} );
|
|
271
314
|
|
|
272
315
|
describe( 'pagination', () => {
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { isItemValid } from '../validation';
|
|
5
|
+
import type { Field } from '../types';
|
|
6
|
+
|
|
7
|
+
describe( 'validation', () => {
|
|
8
|
+
it( 'fields not visible in form are not validated', () => {
|
|
9
|
+
const item = { id: 1, valid_order: 2, invalid_order: 'd' };
|
|
10
|
+
const fields: Field< {} >[] = [
|
|
11
|
+
{
|
|
12
|
+
id: 'valid_order',
|
|
13
|
+
type: 'integer',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'invalid_order',
|
|
17
|
+
type: 'integer',
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
const form = { fields: [ 'valid_order' ] };
|
|
21
|
+
const result = isItemValid( item, fields, form );
|
|
22
|
+
expect( result ).toBe( true );
|
|
23
|
+
} );
|
|
24
|
+
|
|
25
|
+
it( 'integer field is valid if value is integer', () => {
|
|
26
|
+
const item = { id: 1, order: 2, title: 'hi' };
|
|
27
|
+
const fields: Field< {} >[] = [
|
|
28
|
+
{
|
|
29
|
+
type: 'integer',
|
|
30
|
+
id: 'order',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
const form = { fields: [ 'order' ] };
|
|
34
|
+
const result = isItemValid( item, fields, form );
|
|
35
|
+
expect( result ).toBe( true );
|
|
36
|
+
} );
|
|
37
|
+
|
|
38
|
+
it( 'integer field is invalid if value is not integer', () => {
|
|
39
|
+
const item = { id: 1, order: 'd' };
|
|
40
|
+
const fields: Field< {} >[] = [
|
|
41
|
+
{
|
|
42
|
+
id: 'order',
|
|
43
|
+
type: 'integer',
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
const form = { fields: [ 'order' ] };
|
|
47
|
+
const result = isItemValid( item, fields, form );
|
|
48
|
+
expect( result ).toBe( false );
|
|
49
|
+
} );
|
|
50
|
+
|
|
51
|
+
it( 'integer field is invalid if value is empty', () => {
|
|
52
|
+
const item = { id: 1, order: '' };
|
|
53
|
+
const fields: Field< {} >[] = [
|
|
54
|
+
{
|
|
55
|
+
id: 'order',
|
|
56
|
+
type: 'integer',
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
const form = { fields: [ 'order' ] };
|
|
60
|
+
const result = isItemValid( item, fields, form );
|
|
61
|
+
expect( result ).toBe( false );
|
|
62
|
+
} );
|
|
63
|
+
|
|
64
|
+
it( 'integer field is invalid if value is not one of the elements', () => {
|
|
65
|
+
const item = { id: 1, author: 3 };
|
|
66
|
+
const fields: Field< {} >[] = [
|
|
67
|
+
{
|
|
68
|
+
id: 'author',
|
|
69
|
+
type: 'integer',
|
|
70
|
+
elements: [
|
|
71
|
+
{ value: 1, label: 'Jane' },
|
|
72
|
+
{ value: 2, label: 'John' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
const form = { fields: [ 'author' ] };
|
|
77
|
+
const result = isItemValid( item, fields, form );
|
|
78
|
+
expect( result ).toBe( false );
|
|
79
|
+
} );
|
|
80
|
+
|
|
81
|
+
it( 'text field is invalid if value is not one of the elements', () => {
|
|
82
|
+
const item = { id: 1, author: 'not-in-elements' };
|
|
83
|
+
const fields: Field< {} >[] = [
|
|
84
|
+
{
|
|
85
|
+
id: 'author',
|
|
86
|
+
type: 'text',
|
|
87
|
+
elements: [
|
|
88
|
+
{ value: 'jane', label: 'Jane' },
|
|
89
|
+
{ value: 'john', label: 'John' },
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
const form = { fields: [ 'author' ] };
|
|
94
|
+
const result = isItemValid( item, fields, form );
|
|
95
|
+
expect( result ).toBe( false );
|
|
96
|
+
} );
|
|
97
|
+
|
|
98
|
+
it( 'untyped field is invalid if value is not one of the elements', () => {
|
|
99
|
+
const item = { id: 1, author: 'not-in-elements' };
|
|
100
|
+
const fields: Field< {} >[] = [
|
|
101
|
+
{
|
|
102
|
+
id: 'author',
|
|
103
|
+
elements: [
|
|
104
|
+
{ value: 'jane', label: 'Jane' },
|
|
105
|
+
{ value: 'john', label: 'John' },
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
const form = { fields: [ 'author' ] };
|
|
110
|
+
const result = isItemValid( item, fields, form );
|
|
111
|
+
expect( result ).toBe( false );
|
|
112
|
+
} );
|
|
113
|
+
|
|
114
|
+
it( 'fields can provide its own isValid function', () => {
|
|
115
|
+
const item = { id: 1, order: 'd' };
|
|
116
|
+
const fields: Field< {} >[] = [
|
|
117
|
+
{
|
|
118
|
+
id: 'order',
|
|
119
|
+
type: 'integer',
|
|
120
|
+
elements: [
|
|
121
|
+
{ value: 'a', label: 'A' },
|
|
122
|
+
{ value: 'b', label: 'B' },
|
|
123
|
+
],
|
|
124
|
+
isValid: () => true, // Overrides the validation provided for integer types.
|
|
125
|
+
},
|
|
126
|
+
];
|
|
127
|
+
const form = { fields: [ 'order' ] };
|
|
128
|
+
const result = isItemValid( item, fields, form );
|
|
129
|
+
expect( result ).toBe( true );
|
|
130
|
+
} );
|
|
131
|
+
} );
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
ReactElement,
|
|
6
|
+
ComponentType,
|
|
7
|
+
Dispatch,
|
|
8
|
+
SetStateAction,
|
|
9
|
+
} from 'react';
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* Internal dependencies
|
|
@@ -44,7 +49,11 @@ export type Operator =
|
|
|
44
49
|
|
|
45
50
|
export type ItemRecord = Record< string, unknown >;
|
|
46
51
|
|
|
47
|
-
export type FieldType = 'text';
|
|
52
|
+
export type FieldType = 'text' | 'integer';
|
|
53
|
+
|
|
54
|
+
export type ValidationContext = {
|
|
55
|
+
elements?: Option[];
|
|
56
|
+
};
|
|
48
57
|
|
|
49
58
|
/**
|
|
50
59
|
* A dataview field for a specific property of a data type.
|
|
@@ -65,6 +74,11 @@ export type Field< Item > = {
|
|
|
65
74
|
*/
|
|
66
75
|
label?: string;
|
|
67
76
|
|
|
77
|
+
/**
|
|
78
|
+
* A description of the field.
|
|
79
|
+
*/
|
|
80
|
+
description?: string;
|
|
81
|
+
|
|
68
82
|
/**
|
|
69
83
|
* Placeholder for the field.
|
|
70
84
|
*/
|
|
@@ -75,6 +89,21 @@ export type Field< Item > = {
|
|
|
75
89
|
*/
|
|
76
90
|
render?: ComponentType< { item: Item } >;
|
|
77
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Callback used to render an edit control for the field.
|
|
94
|
+
*/
|
|
95
|
+
Edit?: ComponentType< DataFormControlProps< Item > >;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Callback used to sort the field.
|
|
99
|
+
*/
|
|
100
|
+
sort?: ( a: Item, b: Item, direction: SortDirection ) => number;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Callback used to validate the field.
|
|
104
|
+
*/
|
|
105
|
+
isValid?: ( item: Item, context?: ValidationContext ) => boolean;
|
|
106
|
+
|
|
78
107
|
/**
|
|
79
108
|
* Whether the field is sortable.
|
|
80
109
|
*/
|
|
@@ -119,6 +148,9 @@ export type NormalizedField< Item > = Field< Item > & {
|
|
|
119
148
|
label: string;
|
|
120
149
|
getValue: ( args: { item: Item } ) => any;
|
|
121
150
|
render: ComponentType< { item: Item } >;
|
|
151
|
+
Edit: ComponentType< DataFormControlProps< Item > >;
|
|
152
|
+
sort: ( a: Item, b: Item, direction: SortDirection ) => number;
|
|
153
|
+
isValid: ( item: Item, context?: ValidationContext ) => boolean;
|
|
122
154
|
};
|
|
123
155
|
|
|
124
156
|
/**
|
|
@@ -132,7 +164,15 @@ export type Data< Item > = Item[];
|
|
|
132
164
|
* The form configuration.
|
|
133
165
|
*/
|
|
134
166
|
export type Form = {
|
|
135
|
-
|
|
167
|
+
type?: 'regular' | 'panel';
|
|
168
|
+
fields?: string[];
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export type DataFormControlProps< Item > = {
|
|
172
|
+
data: Item;
|
|
173
|
+
field: NormalizedField< Item >;
|
|
174
|
+
onChange: Dispatch< SetStateAction< Item > >;
|
|
175
|
+
hideLabelFromVision?: boolean;
|
|
136
176
|
};
|
|
137
177
|
|
|
138
178
|
/**
|
|
@@ -459,3 +499,10 @@ export interface SupportedLayouts {
|
|
|
459
499
|
grid?: Omit< ViewGrid, 'type' >;
|
|
460
500
|
table?: Omit< ViewTable, 'type' >;
|
|
461
501
|
}
|
|
502
|
+
|
|
503
|
+
export interface DataFormProps< Item > {
|
|
504
|
+
data: Item;
|
|
505
|
+
fields: Field< Item >[];
|
|
506
|
+
form: Form;
|
|
507
|
+
onChange: Dispatch< SetStateAction< Item > >;
|
|
508
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { normalizeFields } from './normalize-fields';
|
|
5
|
+
import type { Field, Form } from './types';
|
|
6
|
+
|
|
7
|
+
export function isItemValid< Item >(
|
|
8
|
+
item: Item,
|
|
9
|
+
fields: Field< Item >[],
|
|
10
|
+
form: Form
|
|
11
|
+
): boolean {
|
|
12
|
+
const _fields = normalizeFields(
|
|
13
|
+
fields.filter( ( { id } ) => !! form.fields?.includes( id ) )
|
|
14
|
+
);
|
|
15
|
+
return _fields.every( ( field ) => {
|
|
16
|
+
return field.isValid( item, { elements: field.elements } );
|
|
17
|
+
} );
|
|
18
|
+
}
|