@wordpress/dataviews 8.0.1-next.e256d081a.0 → 9.0.1-next.6870dfe5b.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 +24 -1
- package/README.md +96 -1
- package/build/components/dataform-context/index.js +1 -0
- package/build/components/dataform-context/index.js.map +1 -1
- package/build/components/dataviews/index.js +11 -1
- package/build/components/dataviews/index.js.map +1 -1
- package/build/components/dataviews-context/index.js +1 -0
- package/build/components/dataviews-context/index.js.map +1 -1
- package/build/components/dataviews-layout/index.js +2 -1
- package/build/components/dataviews-layout/index.js.map +1 -1
- package/build/components/dataviews-picker/footer.js +145 -0
- package/build/components/dataviews-picker/footer.js.map +1 -0
- package/build/components/dataviews-picker/index.js +201 -0
- package/build/components/dataviews-picker/index.js.map +1 -0
- package/build/components/dataviews-selection-checkbox/index.js +4 -2
- package/build/components/dataviews-selection-checkbox/index.js.map +1 -1
- package/build/components/dataviews-view-config/index.js +1 -0
- package/build/components/dataviews-view-config/index.js.map +1 -1
- package/build/constants.js +4 -1
- package/build/constants.js.map +1 -1
- package/build/dataform-controls/checkbox.js +23 -2
- package/build/dataform-controls/checkbox.js.map +1 -1
- package/build/dataform-controls/color.js +128 -0
- package/build/dataform-controls/color.js.map +1 -0
- package/build/dataform-controls/email.js +10 -45
- package/build/dataform-controls/email.js.map +1 -1
- package/build/dataform-controls/index.js +8 -2
- package/build/dataform-controls/index.js.map +1 -1
- package/build/dataform-controls/telephone.js +34 -0
- package/build/dataform-controls/telephone.js.map +1 -0
- package/build/dataform-controls/text.js +7 -48
- package/build/dataform-controls/text.js.map +1 -1
- package/build/dataform-controls/{boolean.js → toggle.js} +6 -4
- package/build/dataform-controls/toggle.js.map +1 -0
- package/build/dataform-controls/url.js +34 -0
- package/build/dataform-controls/url.js.map +1 -0
- package/build/dataform-controls/utils/validated-text.js +76 -0
- package/build/dataform-controls/utils/validated-text.js.map +1 -0
- package/build/dataforms-layouts/card/index.js +6 -7
- package/build/dataforms-layouts/card/index.js.map +1 -1
- package/build/dataforms-layouts/data-form-layout.js +16 -4
- package/build/dataforms-layouts/data-form-layout.js.map +1 -1
- package/build/dataforms-layouts/index.js +31 -1
- package/build/dataforms-layouts/index.js.map +1 -1
- package/build/dataforms-layouts/row/index.js +113 -0
- package/build/dataforms-layouts/row/index.js.map +1 -0
- package/build/dataviews-layouts/grid/index.js +16 -11
- package/build/dataviews-layouts/grid/index.js.map +1 -1
- package/build/dataviews-layouts/index.js +9 -1
- package/build/dataviews-layouts/index.js.map +1 -1
- package/build/dataviews-layouts/picker-grid/index.js +357 -0
- package/build/dataviews-layouts/picker-grid/index.js.map +1 -0
- package/build/dataviews-layouts/utils/grid-items.js +37 -0
- package/build/dataviews-layouts/utils/grid-items.js.map +1 -0
- package/build/dataviews-layouts/utils/preview-size-picker.js +81 -0
- package/build/dataviews-layouts/utils/preview-size-picker.js.map +1 -0
- package/build/field-types/boolean.js +1 -1
- package/build/field-types/boolean.js.map +1 -1
- package/build/field-types/color.js +113 -0
- package/build/field-types/color.js.map +1 -0
- package/build/field-types/index.js +12 -0
- package/build/field-types/index.js.map +1 -1
- package/build/field-types/telephone.js +57 -0
- package/build/field-types/telephone.js.map +1 -0
- package/build/field-types/url.js +57 -0
- package/build/field-types/url.js.map +1 -0
- package/build/normalize-form-fields.js +6 -0
- package/build/normalize-form-fields.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build/validation.js +1 -1
- package/build/validation.js.map +1 -1
- package/build-module/components/dataform-context/index.js +1 -0
- package/build-module/components/dataform-context/index.js.map +1 -1
- package/build-module/components/dataviews/index.js +11 -1
- package/build-module/components/dataviews/index.js.map +1 -1
- package/build-module/components/dataviews-context/index.js +1 -0
- package/build-module/components/dataviews-context/index.js.map +1 -1
- package/build-module/components/dataviews-layout/index.js +2 -1
- package/build-module/components/dataviews-layout/index.js.map +1 -1
- package/build-module/components/dataviews-picker/footer.js +136 -0
- package/build-module/components/dataviews-picker/footer.js.map +1 -0
- package/build-module/components/dataviews-picker/index.js +191 -0
- package/build-module/components/dataviews-picker/index.js.map +1 -0
- package/build-module/components/dataviews-selection-checkbox/index.js +4 -2
- package/build-module/components/dataviews-selection-checkbox/index.js.map +1 -1
- package/build-module/components/dataviews-view-config/index.js +1 -0
- package/build-module/components/dataviews-view-config/index.js.map +1 -1
- package/build-module/constants.js +3 -0
- package/build-module/constants.js.map +1 -1
- package/build-module/dataform-controls/checkbox.js +25 -3
- package/build-module/dataform-controls/checkbox.js.map +1 -1
- package/build-module/dataform-controls/color.js +122 -0
- package/build-module/dataform-controls/color.js.map +1 -0
- package/build-module/dataform-controls/email.js +9 -45
- package/build-module/dataform-controls/email.js.map +1 -1
- package/build-module/dataform-controls/index.js +8 -2
- package/build-module/dataform-controls/index.js.map +1 -1
- package/build-module/dataform-controls/telephone.js +27 -0
- package/build-module/dataform-controls/telephone.js.map +1 -0
- package/build-module/dataform-controls/text.js +6 -48
- package/build-module/dataform-controls/text.js.map +1 -1
- package/build-module/dataform-controls/{boolean.js → toggle.js} +5 -3
- package/build-module/dataform-controls/toggle.js.map +1 -0
- package/build-module/dataform-controls/url.js +27 -0
- package/build-module/dataform-controls/url.js.map +1 -0
- package/build-module/dataform-controls/utils/validated-text.js +70 -0
- package/build-module/dataform-controls/utils/validated-text.js.map +1 -0
- package/build-module/dataforms-layouts/card/index.js +6 -7
- package/build-module/dataforms-layouts/card/index.js.map +1 -1
- package/build-module/dataforms-layouts/data-form-layout.js +14 -4
- package/build-module/dataforms-layouts/data-form-layout.js.map +1 -1
- package/build-module/dataforms-layouts/index.js +32 -1
- package/build-module/dataforms-layouts/index.js.map +1 -1
- package/build-module/dataforms-layouts/row/index.js +106 -0
- package/build-module/dataforms-layouts/row/index.js.map +1 -0
- package/build-module/dataviews-layouts/grid/index.js +16 -11
- package/build-module/dataviews-layouts/grid/index.js.map +1 -1
- package/build-module/dataviews-layouts/index.js +10 -2
- package/build-module/dataviews-layouts/index.js.map +1 -1
- package/build-module/dataviews-layouts/picker-grid/index.js +348 -0
- package/build-module/dataviews-layouts/picker-grid/index.js.map +1 -0
- package/build-module/dataviews-layouts/utils/grid-items.js +29 -0
- package/build-module/dataviews-layouts/utils/grid-items.js.map +1 -0
- package/build-module/dataviews-layouts/utils/preview-size-picker.js +73 -0
- package/build-module/dataviews-layouts/utils/preview-size-picker.js.map +1 -0
- package/build-module/field-types/boolean.js +1 -1
- package/build-module/field-types/boolean.js.map +1 -1
- package/build-module/field-types/color.js +107 -0
- package/build-module/field-types/color.js.map +1 -0
- package/build-module/field-types/index.js +12 -0
- package/build-module/field-types/index.js.map +1 -1
- package/build-module/field-types/telephone.js +51 -0
- package/build-module/field-types/telephone.js.map +1 -0
- package/build-module/field-types/url.js +51 -0
- package/build-module/field-types/url.js.map +1 -0
- package/build-module/normalize-form-fields.js +6 -0
- package/build-module/normalize-form-fields.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-module/validation.js +1 -1
- package/build-module/validation.js.map +1 -1
- package/build-style/style-rtl.css +252 -12
- package/build-style/style.css +252 -12
- package/build-types/components/dataform/stories/index.story.d.ts +19 -4
- package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataform-context/index.d.ts.map +1 -1
- package/build-types/components/dataviews/index.d.ts +1 -1
- package/build-types/components/dataviews/index.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews-context/index.d.ts +1 -0
- package/build-types/components/dataviews-context/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
- package/build-types/components/dataviews-picker/footer.d.ts +4 -0
- package/build-types/components/dataviews-picker/footer.d.ts.map +1 -0
- package/build-types/components/dataviews-picker/index.d.ts +55 -0
- package/build-types/components/dataviews-picker/index.d.ts.map +1 -0
- package/build-types/components/dataviews-picker/stories/index.story.d.ts +42 -0
- package/build-types/components/dataviews-picker/stories/index.story.d.ts.map +1 -0
- package/build-types/components/dataviews-selection-checkbox/index.d.ts +2 -1
- package/build-types/components/dataviews-selection-checkbox/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 +1 -0
- package/build-types/constants.d.ts.map +1 -1
- package/build-types/dataform-controls/checkbox.d.ts.map +1 -1
- package/build-types/dataform-controls/color.d.ts +6 -0
- package/build-types/dataform-controls/color.d.ts.map +1 -0
- 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/telephone.d.ts +6 -0
- package/build-types/dataform-controls/telephone.d.ts.map +1 -0
- package/build-types/dataform-controls/text.d.ts.map +1 -1
- package/build-types/dataform-controls/toggle.d.ts +6 -0
- package/build-types/dataform-controls/toggle.d.ts.map +1 -0
- package/build-types/dataform-controls/url.d.ts +6 -0
- package/build-types/dataform-controls/url.d.ts.map +1 -0
- package/build-types/dataform-controls/utils/validated-text.d.ts +16 -0
- package/build-types/dataform-controls/utils/validated-text.d.ts.map +1 -0
- package/build-types/dataforms-layouts/card/index.d.ts +0 -3
- package/build-types/dataforms-layouts/card/index.d.ts.map +1 -1
- package/build-types/dataforms-layouts/data-form-layout.d.ts +4 -1
- package/build-types/dataforms-layouts/data-form-layout.d.ts.map +1 -1
- package/build-types/dataforms-layouts/index.d.ts +10 -0
- package/build-types/dataforms-layouts/index.d.ts.map +1 -1
- package/build-types/dataforms-layouts/row/index.d.ts +6 -0
- package/build-types/dataforms-layouts/row/index.d.ts.map +1 -0
- package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/index.d.ts +12 -1
- package/build-types/dataviews-layouts/index.d.ts.map +1 -1
- package/build-types/dataviews-layouts/picker-grid/index.d.ts +4 -0
- package/build-types/dataviews-layouts/picker-grid/index.d.ts.map +1 -0
- package/build-types/dataviews-layouts/utils/grid-items.d.ts +5 -0
- package/build-types/dataviews-layouts/utils/grid-items.d.ts.map +1 -0
- package/build-types/dataviews-layouts/utils/preview-size-picker.d.ts +2 -0
- package/build-types/dataviews-layouts/utils/preview-size-picker.d.ts.map +1 -0
- package/build-types/field-types/color.d.ts +20 -0
- package/build-types/field-types/color.d.ts.map +1 -0
- package/build-types/field-types/index.d.ts.map +1 -1
- package/build-types/field-types/stories/index.story.d.ts +81 -0
- package/build-types/field-types/stories/index.story.d.ts.map +1 -0
- package/build-types/field-types/telephone.d.ts +20 -0
- package/build-types/field-types/telephone.d.ts.map +1 -0
- package/build-types/field-types/url.d.ts +20 -0
- package/build-types/field-types/url.d.ts.map +1 -0
- package/build-types/normalize-form-fields.d.ts.map +1 -1
- package/build-types/test/dataviews-picker.d.ts +2 -0
- package/build-types/test/dataviews-picker.d.ts.map +1 -0
- package/build-types/types.d.ts +36 -5
- package/build-types/types.d.ts.map +1 -1
- package/build-types/validation.d.ts.map +1 -1
- package/build-wp/index.js +5061 -4013
- package/package.json +16 -15
- package/src/components/dataform/stories/index.story.tsx +333 -11
- package/src/components/dataform-context/index.tsx +1 -0
- package/src/components/dataviews/index.tsx +25 -1
- package/src/components/dataviews/stories/fixtures.tsx +1 -1
- package/src/components/dataviews/stories/index.story.tsx +14 -0
- package/src/components/dataviews/style.scss +4 -2
- package/src/components/dataviews-context/index.ts +3 -0
- package/src/components/dataviews-layout/index.tsx +4 -2
- package/src/components/dataviews-picker/footer.tsx +207 -0
- package/src/components/dataviews-picker/index.tsx +284 -0
- package/src/components/dataviews-picker/stories/index.story.tsx +251 -0
- package/src/components/dataviews-picker/style.scss +10 -0
- package/src/components/dataviews-selection-checkbox/index.tsx +3 -0
- package/src/components/dataviews-view-config/index.tsx +1 -0
- package/src/constants.ts +3 -0
- package/src/dataform-controls/checkbox.tsx +33 -3
- package/src/dataform-controls/color.tsx +139 -0
- package/src/dataform-controls/email.tsx +10 -52
- package/src/dataform-controls/index.tsx +8 -2
- package/src/dataform-controls/telephone.tsx +30 -0
- package/src/dataform-controls/text.tsx +2 -57
- package/src/dataform-controls/{boolean.tsx → toggle.tsx} +3 -2
- package/src/dataform-controls/url.tsx +30 -0
- package/src/dataform-controls/utils/validated-text.tsx +96 -0
- package/src/dataforms-layouts/card/index.tsx +5 -4
- package/src/dataforms-layouts/card/style.scss +7 -0
- package/src/dataforms-layouts/data-form-layout.tsx +15 -3
- package/src/dataforms-layouts/index.tsx +35 -0
- package/src/dataforms-layouts/row/index.tsx +115 -0
- package/src/dataforms-layouts/row/style.scss +3 -0
- package/src/dataviews-layouts/grid/index.tsx +38 -33
- package/src/dataviews-layouts/grid/style.scss +42 -20
- package/src/dataviews-layouts/index.ts +16 -2
- package/src/dataviews-layouts/picker-grid/index.tsx +490 -0
- package/src/dataviews-layouts/picker-grid/style.scss +171 -0
- package/src/dataviews-layouts/utils/grid-items.scss +21 -0
- package/src/dataviews-layouts/utils/grid-items.tsx +35 -0
- package/src/dataviews-layouts/utils/preview-size-picker.tsx +87 -0
- package/src/field-types/boolean.tsx +1 -1
- package/src/field-types/color.tsx +115 -0
- package/src/field-types/index.tsx +15 -0
- package/src/field-types/stories/index.story.tsx +719 -0
- package/src/field-types/telephone.tsx +71 -0
- package/src/field-types/url.tsx +71 -0
- package/src/normalize-form-fields.ts +6 -0
- package/src/style.scss +4 -0
- package/src/test/dataform.tsx +2 -2
- package/src/test/dataviews-picker.tsx +478 -0
- package/src/test/dataviews.tsx +86 -0
- package/src/types.ts +56 -4
- package/src/validation.ts +3 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/build/dataform-controls/boolean.js.map +0 -1
- package/build-module/dataform-controls/boolean.js.map +0 -1
- package/build-types/components/stories/index.story.d.ts +0 -63
- package/build-types/components/stories/index.story.d.ts.map +0 -1
- package/build-types/dataform-controls/boolean.d.ts +0 -6
- package/build-types/dataform-controls/boolean.d.ts.map +0 -1
- package/src/components/stories/index.story.tsx +0 -372
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import type {
|
|
10
|
+
DataViewRenderFieldProps,
|
|
11
|
+
SortDirection,
|
|
12
|
+
NormalizedField,
|
|
13
|
+
FieldTypeDefinition,
|
|
14
|
+
} from '../types';
|
|
15
|
+
import { renderFromElements } from '../utils';
|
|
16
|
+
import {
|
|
17
|
+
OPERATOR_IS,
|
|
18
|
+
OPERATOR_IS_ALL,
|
|
19
|
+
OPERATOR_IS_NOT_ALL,
|
|
20
|
+
OPERATOR_IS_ANY,
|
|
21
|
+
OPERATOR_IS_NONE,
|
|
22
|
+
OPERATOR_IS_NOT,
|
|
23
|
+
OPERATOR_CONTAINS,
|
|
24
|
+
OPERATOR_NOT_CONTAINS,
|
|
25
|
+
OPERATOR_STARTS_WITH,
|
|
26
|
+
} from '../constants';
|
|
27
|
+
|
|
28
|
+
function sort( valueA: any, valueB: any, direction: SortDirection ) {
|
|
29
|
+
return direction === 'asc'
|
|
30
|
+
? valueA.localeCompare( valueB )
|
|
31
|
+
: valueB.localeCompare( valueA );
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
sort,
|
|
36
|
+
isValid: {
|
|
37
|
+
custom: ( item: any, field: NormalizedField< any > ) => {
|
|
38
|
+
const value = field.getValue( { item } );
|
|
39
|
+
if ( field?.elements ) {
|
|
40
|
+
const validValues = field.elements.map( ( f ) => f.value );
|
|
41
|
+
if ( ! validValues.includes( value ) ) {
|
|
42
|
+
return __( 'Value must be one of the elements.' );
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
Edit: 'telephone',
|
|
50
|
+
render: ( { item, field }: DataViewRenderFieldProps< any > ) => {
|
|
51
|
+
return field.elements
|
|
52
|
+
? renderFromElements( { item, field } )
|
|
53
|
+
: field.getValue( { item } );
|
|
54
|
+
},
|
|
55
|
+
enableSorting: true,
|
|
56
|
+
filterBy: {
|
|
57
|
+
defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
|
|
58
|
+
validOperators: [
|
|
59
|
+
OPERATOR_IS,
|
|
60
|
+
OPERATOR_IS_NOT,
|
|
61
|
+
OPERATOR_CONTAINS,
|
|
62
|
+
OPERATOR_NOT_CONTAINS,
|
|
63
|
+
OPERATOR_STARTS_WITH,
|
|
64
|
+
// Multiple selection
|
|
65
|
+
OPERATOR_IS_ANY,
|
|
66
|
+
OPERATOR_IS_NONE,
|
|
67
|
+
OPERATOR_IS_ALL,
|
|
68
|
+
OPERATOR_IS_NOT_ALL,
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
} satisfies FieldTypeDefinition< any >;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import type {
|
|
10
|
+
DataViewRenderFieldProps,
|
|
11
|
+
SortDirection,
|
|
12
|
+
NormalizedField,
|
|
13
|
+
FieldTypeDefinition,
|
|
14
|
+
} from '../types';
|
|
15
|
+
import { renderFromElements } from '../utils';
|
|
16
|
+
import {
|
|
17
|
+
OPERATOR_IS,
|
|
18
|
+
OPERATOR_IS_ALL,
|
|
19
|
+
OPERATOR_IS_NOT_ALL,
|
|
20
|
+
OPERATOR_IS_ANY,
|
|
21
|
+
OPERATOR_IS_NONE,
|
|
22
|
+
OPERATOR_IS_NOT,
|
|
23
|
+
OPERATOR_CONTAINS,
|
|
24
|
+
OPERATOR_NOT_CONTAINS,
|
|
25
|
+
OPERATOR_STARTS_WITH,
|
|
26
|
+
} from '../constants';
|
|
27
|
+
|
|
28
|
+
function sort( valueA: any, valueB: any, direction: SortDirection ) {
|
|
29
|
+
return direction === 'asc'
|
|
30
|
+
? valueA.localeCompare( valueB )
|
|
31
|
+
: valueB.localeCompare( valueA );
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default {
|
|
35
|
+
sort,
|
|
36
|
+
isValid: {
|
|
37
|
+
custom: ( item: any, field: NormalizedField< any > ) => {
|
|
38
|
+
const value = field.getValue( { item } );
|
|
39
|
+
if ( field?.elements ) {
|
|
40
|
+
const validValues = field.elements.map( ( f ) => f.value );
|
|
41
|
+
if ( ! validValues.includes( value ) ) {
|
|
42
|
+
return __( 'Value must be one of the elements.' );
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null;
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
Edit: 'url',
|
|
50
|
+
render: ( { item, field }: DataViewRenderFieldProps< any > ) => {
|
|
51
|
+
return field.elements
|
|
52
|
+
? renderFromElements( { item, field } )
|
|
53
|
+
: field.getValue( { item } );
|
|
54
|
+
},
|
|
55
|
+
enableSorting: true,
|
|
56
|
+
filterBy: {
|
|
57
|
+
defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
|
|
58
|
+
validOperators: [
|
|
59
|
+
OPERATOR_IS,
|
|
60
|
+
OPERATOR_IS_NOT,
|
|
61
|
+
OPERATOR_CONTAINS,
|
|
62
|
+
OPERATOR_NOT_CONTAINS,
|
|
63
|
+
OPERATOR_STARTS_WITH,
|
|
64
|
+
// Multiple selection
|
|
65
|
+
OPERATOR_IS_ANY,
|
|
66
|
+
OPERATOR_IS_NONE,
|
|
67
|
+
OPERATOR_IS_ALL,
|
|
68
|
+
OPERATOR_IS_NOT_ALL,
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
} satisfies FieldTypeDefinition< any >;
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
NormalizedRegularLayout,
|
|
9
9
|
NormalizedPanelLayout,
|
|
10
10
|
NormalizedCardLayout,
|
|
11
|
+
NormalizedRowLayout,
|
|
11
12
|
} from './types';
|
|
12
13
|
|
|
13
14
|
interface NormalizedFormField {
|
|
@@ -59,6 +60,11 @@ export function normalizeLayout( layout?: Layout ): NormalizedLayout {
|
|
|
59
60
|
: true,
|
|
60
61
|
} satisfies NormalizedCardLayout;
|
|
61
62
|
}
|
|
63
|
+
} else if ( layout?.type === 'row' ) {
|
|
64
|
+
normalizedLayout = {
|
|
65
|
+
type: 'row',
|
|
66
|
+
alignment: layout?.alignment ?? 'center',
|
|
67
|
+
} satisfies NormalizedRowLayout;
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
return normalizedLayout;
|
package/src/style.scss
CHANGED
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
@import "./components/dataviews-footer/style.scss";
|
|
5
5
|
@import "./components/dataviews-pagination/style.scss";
|
|
6
6
|
@import "./components/dataviews-item-actions/style.scss";
|
|
7
|
+
@import "./components/dataviews-picker/style.scss";
|
|
7
8
|
@import "./components/dataviews-selection-checkbox/style.scss";
|
|
8
9
|
@import "./components/dataviews-view-config/style.scss";
|
|
9
10
|
|
|
10
11
|
@import "./dataviews-layouts/grid/style.scss";
|
|
11
12
|
@import "./dataviews-layouts/list/style.scss";
|
|
12
13
|
@import "./dataviews-layouts/table/style.scss";
|
|
14
|
+
@import "./dataviews-layouts/picker-grid/style.scss";
|
|
13
15
|
|
|
14
16
|
@import "./dataform-controls/style.scss";
|
|
15
17
|
@import "./dataforms-layouts/panel/style.scss";
|
|
16
18
|
@import "./dataforms-layouts/regular/style.scss";
|
|
19
|
+
@import "./dataforms-layouts/card/style.scss";
|
|
20
|
+
@import "./dataforms-layouts/row/style.scss";
|
package/src/test/dataform.tsx
CHANGED
|
@@ -139,7 +139,7 @@ describe( 'DataForm component', () => {
|
|
|
139
139
|
expect( onChange ).toHaveBeenCalledTimes( newValue.length );
|
|
140
140
|
for ( let i = 0; i < newValue.length; i++ ) {
|
|
141
141
|
expect( onChange ).toHaveBeenNthCalledWith( i + 1, {
|
|
142
|
-
title: newValue
|
|
142
|
+
title: newValue.slice( 0, i + 1 ),
|
|
143
143
|
} );
|
|
144
144
|
}
|
|
145
145
|
} );
|
|
@@ -408,7 +408,7 @@ describe( 'DataForm component', () => {
|
|
|
408
408
|
expect( onChange ).toHaveBeenCalledTimes( newValue.length );
|
|
409
409
|
for ( let i = 0; i < newValue.length; i++ ) {
|
|
410
410
|
expect( onChange ).toHaveBeenNthCalledWith( i + 1, {
|
|
411
|
-
title: newValue
|
|
411
|
+
title: newValue.slice( 0, i + 1 ),
|
|
412
412
|
} );
|
|
413
413
|
}
|
|
414
414
|
} );
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { render, screen, within } from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* WordPress dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { useMemo, useState } from '@wordpress/element';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Internal dependencies
|
|
14
|
+
*/
|
|
15
|
+
import DataViewsPicker from '../components/dataviews-picker';
|
|
16
|
+
import { LAYOUT_PICKER_GRID } from '../constants';
|
|
17
|
+
import type { ActionButton, View, ViewPickerGrid } from '../types';
|
|
18
|
+
import { filterSortAndPaginate } from '../filter-and-sort-data-view';
|
|
19
|
+
|
|
20
|
+
type Data = {
|
|
21
|
+
id: number;
|
|
22
|
+
title: string;
|
|
23
|
+
author?: number;
|
|
24
|
+
order?: number;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const onChangeSelection = jest.fn();
|
|
28
|
+
|
|
29
|
+
const data: Data[] = [
|
|
30
|
+
{
|
|
31
|
+
id: 1,
|
|
32
|
+
title: 'Hello World',
|
|
33
|
+
author: 1,
|
|
34
|
+
order: 1,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 2,
|
|
38
|
+
title: 'Homepage',
|
|
39
|
+
author: 2,
|
|
40
|
+
order: 1,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 3,
|
|
44
|
+
title: 'Posts',
|
|
45
|
+
author: 2,
|
|
46
|
+
order: 1,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
const singleSelectCallback = jest.fn();
|
|
51
|
+
const singleSelectActions: ActionButton< Data >[] = [
|
|
52
|
+
{
|
|
53
|
+
id: 'confirm',
|
|
54
|
+
label: 'Confirm',
|
|
55
|
+
supportsBulk: false,
|
|
56
|
+
isPrimary: true,
|
|
57
|
+
callback: singleSelectCallback,
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const multiSelectCallback = jest.fn();
|
|
62
|
+
const multiSelectActions: ActionButton< Data >[] = [
|
|
63
|
+
{
|
|
64
|
+
id: 'confirm',
|
|
65
|
+
label: 'Confirm',
|
|
66
|
+
supportsBulk: true,
|
|
67
|
+
isPrimary: true,
|
|
68
|
+
icon: 'check',
|
|
69
|
+
callback: multiSelectCallback,
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
function Picker( {
|
|
74
|
+
view: additionalView,
|
|
75
|
+
actions,
|
|
76
|
+
label,
|
|
77
|
+
multiselect,
|
|
78
|
+
...props
|
|
79
|
+
}: {
|
|
80
|
+
actions?: ActionButton< Data >[];
|
|
81
|
+
view?: Partial< View >;
|
|
82
|
+
label?: string;
|
|
83
|
+
multiselect?: boolean;
|
|
84
|
+
} ) {
|
|
85
|
+
const [ view, setView ] = useState< View >( {
|
|
86
|
+
type: LAYOUT_PICKER_GRID,
|
|
87
|
+
fields: [],
|
|
88
|
+
titleField: 'title',
|
|
89
|
+
mediaField: 'image',
|
|
90
|
+
search: '',
|
|
91
|
+
page: 1,
|
|
92
|
+
perPage: 10,
|
|
93
|
+
filters: [],
|
|
94
|
+
...additionalView,
|
|
95
|
+
} as ViewPickerGrid );
|
|
96
|
+
|
|
97
|
+
const [ selection, setSelection ] = useState< string[] >( [] );
|
|
98
|
+
|
|
99
|
+
const { data: shownData, paginationInfo } = useMemo( () => {
|
|
100
|
+
return filterSortAndPaginate( data, view, [] );
|
|
101
|
+
}, [ view ] );
|
|
102
|
+
|
|
103
|
+
const dataViewProps = {
|
|
104
|
+
actions,
|
|
105
|
+
picker: true,
|
|
106
|
+
getItemId: ( item: Data ) => item.id.toString(),
|
|
107
|
+
paginationInfo,
|
|
108
|
+
data: shownData,
|
|
109
|
+
view,
|
|
110
|
+
defaultLayouts: { [ LAYOUT_PICKER_GRID ]: {} },
|
|
111
|
+
fields: [],
|
|
112
|
+
onChangeView: setView,
|
|
113
|
+
multiselect,
|
|
114
|
+
selection,
|
|
115
|
+
itemListLabel: label,
|
|
116
|
+
onChangeSelection: ( newSelection: string[] ) => {
|
|
117
|
+
onChangeSelection( newSelection );
|
|
118
|
+
setSelection( newSelection );
|
|
119
|
+
},
|
|
120
|
+
...props,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return <DataViewsPicker { ...dataViewProps } />;
|
|
124
|
+
}
|
|
125
|
+
describe( 'DataViews Picker', () => {
|
|
126
|
+
describe( 'Grid layout', () => {
|
|
127
|
+
it( 'renders the grid as a `listbox` role, with items as `option` roles', () => {
|
|
128
|
+
render( <Picker /> );
|
|
129
|
+
|
|
130
|
+
// Grid should have listbox role
|
|
131
|
+
expect( screen.getByRole( 'listbox' ) ).toBeInTheDocument();
|
|
132
|
+
|
|
133
|
+
// Each data item should have option role
|
|
134
|
+
const options = screen.getAllByRole( 'option' );
|
|
135
|
+
expect( options ).toHaveLength( data.length );
|
|
136
|
+
} );
|
|
137
|
+
|
|
138
|
+
it( 'supports specifying a `label` which is rendered as an aria-label', () => {
|
|
139
|
+
const testLabel = 'Select an item from the grid';
|
|
140
|
+
render( <Picker label={ testLabel } /> );
|
|
141
|
+
|
|
142
|
+
// Grid should have the specified aria-label
|
|
143
|
+
expect(
|
|
144
|
+
screen.getByRole( 'listbox', { name: testLabel } )
|
|
145
|
+
).toBeInTheDocument();
|
|
146
|
+
} );
|
|
147
|
+
|
|
148
|
+
it( 'implements single tab-stop composite pattern with aria-activedescendant', async () => {
|
|
149
|
+
render( <Picker /> );
|
|
150
|
+
|
|
151
|
+
// Grid should be tabbable as the main composite widget
|
|
152
|
+
const grid = screen.getByRole( 'listbox' );
|
|
153
|
+
expect( grid ).toHaveAttribute( 'tabindex', '0' );
|
|
154
|
+
|
|
155
|
+
// Individual options exist but are managed by composite pattern
|
|
156
|
+
const options = screen.getAllByRole( 'option' );
|
|
157
|
+
expect( options.length ).toBeGreaterThan( 0 );
|
|
158
|
+
|
|
159
|
+
const user = userEvent.setup();
|
|
160
|
+
|
|
161
|
+
const viewOptionsButton = screen.getByRole( 'button', {
|
|
162
|
+
name: 'View options',
|
|
163
|
+
} );
|
|
164
|
+
|
|
165
|
+
// Focus the viewOptions button, which is just before the grid.
|
|
166
|
+
viewOptionsButton.focus();
|
|
167
|
+
expect( viewOptionsButton ).toHaveFocus();
|
|
168
|
+
|
|
169
|
+
// Tab to the grid (single tab-stop for the entire grid)
|
|
170
|
+
await user.keyboard( '{Tab}' );
|
|
171
|
+
expect( grid ).toHaveFocus();
|
|
172
|
+
|
|
173
|
+
// Test aria-activedescendant behavior
|
|
174
|
+
// Trigger navigation to establish aria-activedescendant
|
|
175
|
+
await user.keyboard( '{ArrowRight}' );
|
|
176
|
+
await user.keyboard( '{ArrowLeft}' );
|
|
177
|
+
const firstActiveDescendant = grid.getAttribute(
|
|
178
|
+
'aria-activedescendant'
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
expect( firstActiveDescendant ).toBeTruthy();
|
|
182
|
+
expect( firstActiveDescendant ).toBe( options[ 0 ].id );
|
|
183
|
+
|
|
184
|
+
// Navigate with arrow keys to test aria-activedescendant changes
|
|
185
|
+
await user.keyboard( '{ArrowRight}' );
|
|
186
|
+
expect( grid ).toHaveFocus();
|
|
187
|
+
|
|
188
|
+
// Check that aria-activedescendant changed after navigation
|
|
189
|
+
const secondActiveDescendant = grid.getAttribute(
|
|
190
|
+
'aria-activedescendant'
|
|
191
|
+
);
|
|
192
|
+
expect( secondActiveDescendant ).toBeTruthy();
|
|
193
|
+
expect( secondActiveDescendant ).toBe( options[ 1 ].id );
|
|
194
|
+
expect( secondActiveDescendant ).not.toBe( firstActiveDescendant );
|
|
195
|
+
|
|
196
|
+
// Navigate to third option
|
|
197
|
+
await user.keyboard( '{ArrowRight}' );
|
|
198
|
+
expect( grid ).toHaveFocus();
|
|
199
|
+
|
|
200
|
+
const thirdActiveDescendant = grid.getAttribute(
|
|
201
|
+
'aria-activedescendant'
|
|
202
|
+
);
|
|
203
|
+
expect( thirdActiveDescendant ).toBeTruthy();
|
|
204
|
+
expect( thirdActiveDescendant ).toBe( options[ 2 ].id );
|
|
205
|
+
expect( thirdActiveDescendant ).not.toBe( firstActiveDescendant );
|
|
206
|
+
expect( thirdActiveDescendant ).not.toBe( secondActiveDescendant );
|
|
207
|
+
|
|
208
|
+
// Navigate back to first option
|
|
209
|
+
await user.keyboard( '{ArrowLeft}' );
|
|
210
|
+
expect( grid ).toHaveFocus();
|
|
211
|
+
|
|
212
|
+
await user.keyboard( '{ArrowLeft}' );
|
|
213
|
+
expect( grid ).toHaveFocus();
|
|
214
|
+
|
|
215
|
+
// Verify aria-activedescendant is back to first option
|
|
216
|
+
const backToFirstActiveDescendant = grid.getAttribute(
|
|
217
|
+
'aria-activedescendant'
|
|
218
|
+
);
|
|
219
|
+
expect( backToFirstActiveDescendant ).toBe( firstActiveDescendant );
|
|
220
|
+
expect( backToFirstActiveDescendant ).toBe( options[ 0 ].id );
|
|
221
|
+
|
|
222
|
+
// Tab should move focus away from the grid entirely
|
|
223
|
+
await user.keyboard( '{Tab}' );
|
|
224
|
+
expect( grid ).not.toHaveFocus();
|
|
225
|
+
|
|
226
|
+
// Shift+Tab should move back to the grid
|
|
227
|
+
await user.keyboard( '{Shift>}{Tab}{/Shift}' );
|
|
228
|
+
expect( grid ).toHaveFocus();
|
|
229
|
+
|
|
230
|
+
// aria-activedescendant should be maintained when returning to grid
|
|
231
|
+
expect( grid.getAttribute( 'aria-activedescendant' ) ).toBeTruthy();
|
|
232
|
+
} );
|
|
233
|
+
|
|
234
|
+
describe( 'Single selection', () => {
|
|
235
|
+
it( 'maintains only a single selected item and calls the `onChangeSelection` callback when the selection changes', async () => {
|
|
236
|
+
render( <Picker actions={ singleSelectActions } /> );
|
|
237
|
+
|
|
238
|
+
const user = userEvent.setup();
|
|
239
|
+
const listbox = screen.getByRole( 'listbox' );
|
|
240
|
+
const options = within( listbox ).getAllByRole( 'option' );
|
|
241
|
+
|
|
242
|
+
// Click first item
|
|
243
|
+
await user.click( options[ 0 ] );
|
|
244
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
245
|
+
'aria-selected',
|
|
246
|
+
'true'
|
|
247
|
+
);
|
|
248
|
+
expect( options[ 1 ] ).toHaveAttribute(
|
|
249
|
+
'aria-selected',
|
|
250
|
+
'false'
|
|
251
|
+
);
|
|
252
|
+
expect( options[ 2 ] ).toHaveAttribute(
|
|
253
|
+
'aria-selected',
|
|
254
|
+
'false'
|
|
255
|
+
);
|
|
256
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
257
|
+
data[ 0 ].id.toString(),
|
|
258
|
+
] );
|
|
259
|
+
|
|
260
|
+
// Click second item - should deselect first
|
|
261
|
+
await user.click( options[ 1 ] );
|
|
262
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
263
|
+
'aria-selected',
|
|
264
|
+
'false'
|
|
265
|
+
);
|
|
266
|
+
expect( options[ 1 ] ).toHaveAttribute(
|
|
267
|
+
'aria-selected',
|
|
268
|
+
'true'
|
|
269
|
+
);
|
|
270
|
+
expect( options[ 2 ] ).toHaveAttribute(
|
|
271
|
+
'aria-selected',
|
|
272
|
+
'false'
|
|
273
|
+
);
|
|
274
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
275
|
+
data[ 1 ].id.toString(),
|
|
276
|
+
] );
|
|
277
|
+
} );
|
|
278
|
+
|
|
279
|
+
it( 'calls the action callback when the action button is clicked', async () => {
|
|
280
|
+
render( <Picker actions={ singleSelectActions } /> );
|
|
281
|
+
|
|
282
|
+
const user = userEvent.setup();
|
|
283
|
+
const options = screen.getAllByRole( 'option' );
|
|
284
|
+
|
|
285
|
+
// Select first item
|
|
286
|
+
await user.click( options[ 0 ] );
|
|
287
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
288
|
+
'aria-selected',
|
|
289
|
+
'true'
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
// Find the action button with correct label within the action buttons container
|
|
293
|
+
const confirmButton = screen.getByRole( 'button', {
|
|
294
|
+
name: 'Confirm',
|
|
295
|
+
} );
|
|
296
|
+
expect( confirmButton ).toBeInTheDocument();
|
|
297
|
+
|
|
298
|
+
// Clear any previous calls and click the action button
|
|
299
|
+
singleSelectCallback.mockClear();
|
|
300
|
+
await user.click( confirmButton );
|
|
301
|
+
|
|
302
|
+
// Verify the callback was called with correct parameters
|
|
303
|
+
expect( singleSelectCallback ).toHaveBeenCalledTimes( 1 );
|
|
304
|
+
} );
|
|
305
|
+
} );
|
|
306
|
+
|
|
307
|
+
describe( 'Multi selection', () => {
|
|
308
|
+
it( 'adds the `aria-multiselectable` attribute to the listbox', () => {
|
|
309
|
+
render( <Picker actions={ multiSelectActions } /> );
|
|
310
|
+
|
|
311
|
+
const listbox = screen.getByRole( 'listbox' );
|
|
312
|
+
expect( listbox ).toHaveAttribute(
|
|
313
|
+
'aria-multiselectable',
|
|
314
|
+
'true'
|
|
315
|
+
);
|
|
316
|
+
} );
|
|
317
|
+
|
|
318
|
+
it( 'supports multiple selected items and calls the `onChangeSelection` callback when the selection changes', async () => {
|
|
319
|
+
// Test multi-selection by clicking multiple items
|
|
320
|
+
render( <Picker actions={ multiSelectActions } /> );
|
|
321
|
+
|
|
322
|
+
const user = userEvent.setup();
|
|
323
|
+
const listbox = screen.getByRole( 'listbox' );
|
|
324
|
+
const options = within( listbox ).getAllByRole( 'option' );
|
|
325
|
+
|
|
326
|
+
// Click first item
|
|
327
|
+
await user.click( options[ 0 ] );
|
|
328
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
329
|
+
'aria-selected',
|
|
330
|
+
'true'
|
|
331
|
+
);
|
|
332
|
+
expect( options[ 1 ] ).toHaveAttribute(
|
|
333
|
+
'aria-selected',
|
|
334
|
+
'false'
|
|
335
|
+
);
|
|
336
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
337
|
+
data[ 0 ].id.toString(),
|
|
338
|
+
] );
|
|
339
|
+
|
|
340
|
+
// Click second item - both should remain selected in multi-select mode
|
|
341
|
+
await user.click( options[ 1 ] );
|
|
342
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
343
|
+
'aria-selected',
|
|
344
|
+
'true'
|
|
345
|
+
);
|
|
346
|
+
expect( options[ 1 ] ).toHaveAttribute(
|
|
347
|
+
'aria-selected',
|
|
348
|
+
'true'
|
|
349
|
+
);
|
|
350
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
351
|
+
data[ 0 ].id.toString(),
|
|
352
|
+
data[ 1 ].id.toString(),
|
|
353
|
+
] );
|
|
354
|
+
|
|
355
|
+
// Click first item again to deselect it
|
|
356
|
+
await user.click( options[ 0 ] );
|
|
357
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
358
|
+
'aria-selected',
|
|
359
|
+
'false'
|
|
360
|
+
);
|
|
361
|
+
expect( options[ 1 ] ).toHaveAttribute(
|
|
362
|
+
'aria-selected',
|
|
363
|
+
'true'
|
|
364
|
+
);
|
|
365
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
366
|
+
data[ 1 ].id.toString(),
|
|
367
|
+
] );
|
|
368
|
+
} );
|
|
369
|
+
|
|
370
|
+
it( 'calls the action callback when the action button is clicked', async () => {
|
|
371
|
+
render( <Picker actions={ multiSelectActions } /> );
|
|
372
|
+
|
|
373
|
+
const user = userEvent.setup();
|
|
374
|
+
const options = screen.getAllByRole( 'option' );
|
|
375
|
+
|
|
376
|
+
// Select multiple items
|
|
377
|
+
await user.click( options[ 0 ] );
|
|
378
|
+
await user.click( options[ 1 ] );
|
|
379
|
+
|
|
380
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
381
|
+
'aria-selected',
|
|
382
|
+
'true'
|
|
383
|
+
);
|
|
384
|
+
expect( options[ 1 ] ).toHaveAttribute(
|
|
385
|
+
'aria-selected',
|
|
386
|
+
'true'
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// Third item should remain unselected
|
|
390
|
+
expect( options[ 2 ] ).toHaveAttribute(
|
|
391
|
+
'aria-selected',
|
|
392
|
+
'false'
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
// Find the action button with correct label within the action buttons container
|
|
396
|
+
const confirmButton = screen.getByRole( 'button', {
|
|
397
|
+
name: 'Confirm',
|
|
398
|
+
} );
|
|
399
|
+
expect( confirmButton ).toBeInTheDocument();
|
|
400
|
+
|
|
401
|
+
// Clear any previous calls and click the action button
|
|
402
|
+
multiSelectCallback.mockClear();
|
|
403
|
+
await user.click( confirmButton );
|
|
404
|
+
|
|
405
|
+
// Verify the callback was called with correct parameters for multi-selection
|
|
406
|
+
expect( multiSelectCallback ).toHaveBeenCalledTimes( 1 );
|
|
407
|
+
} );
|
|
408
|
+
|
|
409
|
+
it( 'maintains the selected items when navigating between pages for a paginated view', async () => {
|
|
410
|
+
// Create a component with pagination (2 items per page)
|
|
411
|
+
render(
|
|
412
|
+
<Picker
|
|
413
|
+
actions={ multiSelectActions }
|
|
414
|
+
view={ {
|
|
415
|
+
type: LAYOUT_PICKER_GRID,
|
|
416
|
+
fields: [],
|
|
417
|
+
titleField: 'title',
|
|
418
|
+
mediaField: 'image',
|
|
419
|
+
search: '',
|
|
420
|
+
page: 1,
|
|
421
|
+
perPage: 2, // Only 2 items per page to force pagination
|
|
422
|
+
filters: [],
|
|
423
|
+
} }
|
|
424
|
+
/>
|
|
425
|
+
);
|
|
426
|
+
|
|
427
|
+
const user = userEvent.setup();
|
|
428
|
+
const listbox = screen.getByRole( 'listbox' );
|
|
429
|
+
|
|
430
|
+
// Page 1: Select first item
|
|
431
|
+
let options = within( listbox ).getAllByRole( 'option' );
|
|
432
|
+
expect( options ).toHaveLength( 2 ); // Should show 2 items per page
|
|
433
|
+
|
|
434
|
+
await user.click( options[ 0 ] );
|
|
435
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
436
|
+
'aria-selected',
|
|
437
|
+
'true'
|
|
438
|
+
);
|
|
439
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
440
|
+
data[ 0 ].id.toString(),
|
|
441
|
+
] );
|
|
442
|
+
|
|
443
|
+
// Navigate to page 2
|
|
444
|
+
const nextButton = screen.getByRole( 'button', {
|
|
445
|
+
name: /next/i,
|
|
446
|
+
} );
|
|
447
|
+
await user.click( nextButton );
|
|
448
|
+
|
|
449
|
+
// Page 2: Select another item
|
|
450
|
+
options = within( listbox ).getAllByRole( 'option' );
|
|
451
|
+
expect( options ).toHaveLength( 1 ); // Page 2 should have 1 item (item 3)
|
|
452
|
+
|
|
453
|
+
await user.click( options[ 0 ] );
|
|
454
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
455
|
+
'aria-selected',
|
|
456
|
+
'true'
|
|
457
|
+
);
|
|
458
|
+
expect( onChangeSelection ).toHaveBeenCalledWith( [
|
|
459
|
+
data[ 0 ].id.toString(),
|
|
460
|
+
data[ 2 ].id.toString(),
|
|
461
|
+
] );
|
|
462
|
+
|
|
463
|
+
// Go back to page 1
|
|
464
|
+
const prevButton = screen.getByRole( 'button', {
|
|
465
|
+
name: /previous/i,
|
|
466
|
+
} );
|
|
467
|
+
await user.click( prevButton );
|
|
468
|
+
|
|
469
|
+
// Verify first item is still selected
|
|
470
|
+
options = within( listbox ).getAllByRole( 'option' );
|
|
471
|
+
expect( options[ 0 ] ).toHaveAttribute(
|
|
472
|
+
'aria-selected',
|
|
473
|
+
'true'
|
|
474
|
+
);
|
|
475
|
+
} );
|
|
476
|
+
} );
|
|
477
|
+
} );
|
|
478
|
+
} );
|