@wordpress/dataviews 9.0.1-next.6f42e1382.0 → 9.0.1-next.a730c9c8c.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 +7 -1
- package/README.md +106 -11
- package/build/components/dataviews-filters/input-widget.js +48 -4
- package/build/components/dataviews-filters/input-widget.js.map +1 -1
- package/build/dataform-controls/array.js +9 -7
- package/build/dataform-controls/array.js.map +1 -1
- package/build/dataform-controls/checkbox.js +31 -20
- package/build/dataform-controls/checkbox.js.map +1 -1
- package/build/dataform-controls/color.js +29 -24
- package/build/dataform-controls/color.js.map +1 -1
- package/build/dataform-controls/date.js +32 -24
- package/build/dataform-controls/date.js.map +1 -1
- package/build/dataform-controls/datetime.js +133 -19
- package/build/dataform-controls/datetime.js.map +1 -1
- package/build/dataform-controls/email.js +7 -1
- package/build/dataform-controls/email.js.map +1 -1
- package/build/dataform-controls/index.js +23 -0
- package/build/dataform-controls/index.js.map +1 -1
- package/build/dataform-controls/integer.js +47 -34
- package/build/dataform-controls/integer.js.map +1 -1
- package/build/dataform-controls/radio.js +42 -9
- package/build/dataform-controls/radio.js.map +1 -1
- package/build/dataform-controls/relative-date-control.js +6 -10
- package/build/dataform-controls/relative-date-control.js.map +1 -1
- package/build/dataform-controls/select.js +41 -10
- package/build/dataform-controls/select.js.map +1 -1
- package/build/dataform-controls/telephone.js +7 -1
- package/build/dataform-controls/telephone.js.map +1 -1
- package/build/dataform-controls/text.js +14 -2
- package/build/dataform-controls/text.js.map +1 -1
- package/build/dataform-controls/textarea.js +33 -20
- package/build/dataform-controls/textarea.js.map +1 -1
- package/build/dataform-controls/toggle-group.js +36 -6
- package/build/dataform-controls/toggle-group.js.map +1 -1
- package/build/dataform-controls/toggle.js +33 -22
- package/build/dataform-controls/toggle.js.map +1 -1
- package/build/dataform-controls/url.js +7 -1
- package/build/dataform-controls/url.js.map +1 -1
- package/build/dataform-controls/utils/validated-input.js +34 -32
- package/build/dataform-controls/utils/validated-input.js.map +1 -1
- package/build/dataforms-layouts/panel/dropdown.js +10 -14
- package/build/dataforms-layouts/panel/dropdown.js.map +1 -1
- package/build/dataforms-layouts/panel/index.js +24 -11
- package/build/dataforms-layouts/panel/index.js.map +1 -1
- package/build/dataforms-layouts/panel/modal.js +22 -27
- package/build/dataforms-layouts/panel/modal.js.map +1 -1
- package/build/dataforms-layouts/panel/summary-button.js +67 -0
- package/build/dataforms-layouts/panel/summary-button.js.map +1 -0
- package/build/normalize-fields.js +17 -0
- package/build/normalize-fields.js.map +1 -1
- package/build/types.js.map +1 -1
- package/build-module/components/dataviews-filters/input-widget.js +48 -4
- package/build-module/components/dataviews-filters/input-widget.js.map +1 -1
- package/build-module/dataform-controls/array.js +9 -7
- package/build-module/dataform-controls/array.js.map +1 -1
- package/build-module/dataform-controls/checkbox.js +31 -21
- package/build-module/dataform-controls/checkbox.js.map +1 -1
- package/build-module/dataform-controls/color.js +28 -24
- package/build-module/dataform-controls/color.js.map +1 -1
- package/build-module/dataform-controls/date.js +32 -24
- package/build-module/dataform-controls/date.js.map +1 -1
- package/build-module/dataform-controls/datetime.js +135 -21
- package/build-module/dataform-controls/datetime.js.map +1 -1
- package/build-module/dataform-controls/email.js +7 -1
- package/build-module/dataform-controls/email.js.map +1 -1
- package/build-module/dataform-controls/index.js +23 -0
- package/build-module/dataform-controls/index.js.map +1 -1
- package/build-module/dataform-controls/integer.js +46 -34
- package/build-module/dataform-controls/integer.js.map +1 -1
- package/build-module/dataform-controls/radio.js +44 -11
- package/build-module/dataform-controls/radio.js.map +1 -1
- package/build-module/dataform-controls/relative-date-control.js +6 -10
- package/build-module/dataform-controls/relative-date-control.js.map +1 -1
- package/build-module/dataform-controls/select.js +43 -12
- package/build-module/dataform-controls/select.js.map +1 -1
- package/build-module/dataform-controls/telephone.js +7 -1
- package/build-module/dataform-controls/telephone.js.map +1 -1
- package/build-module/dataform-controls/text.js +14 -2
- package/build-module/dataform-controls/text.js.map +1 -1
- package/build-module/dataform-controls/textarea.js +32 -20
- package/build-module/dataform-controls/textarea.js.map +1 -1
- package/build-module/dataform-controls/toggle-group.js +38 -8
- package/build-module/dataform-controls/toggle-group.js.map +1 -1
- package/build-module/dataform-controls/toggle.js +33 -23
- package/build-module/dataform-controls/toggle.js.map +1 -1
- package/build-module/dataform-controls/url.js +7 -1
- package/build-module/dataform-controls/url.js.map +1 -1
- package/build-module/dataform-controls/utils/validated-input.js +34 -33
- package/build-module/dataform-controls/utils/validated-input.js.map +1 -1
- package/build-module/dataforms-layouts/panel/dropdown.js +10 -15
- package/build-module/dataforms-layouts/panel/dropdown.js.map +1 -1
- package/build-module/dataforms-layouts/panel/index.js +24 -11
- package/build-module/dataforms-layouts/panel/index.js.map +1 -1
- package/build-module/dataforms-layouts/panel/modal.js +22 -28
- package/build-module/dataforms-layouts/panel/modal.js.map +1 -1
- package/build-module/dataforms-layouts/panel/summary-button.js +60 -0
- package/build-module/dataforms-layouts/panel/summary-button.js.map +1 -0
- package/build-module/normalize-fields.js +15 -0
- package/build-module/normalize-fields.js.map +1 -1
- package/build-module/types.js.map +1 -1
- package/build-types/components/dataform/stories/index.story.d.ts +3 -0
- package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
- package/build-types/components/dataviews/stories/fixtures.d.ts +4 -2
- package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/input-widget.d.ts.map +1 -1
- package/build-types/dataform-controls/array.d.ts.map +1 -1
- package/build-types/dataform-controls/checkbox.d.ts.map +1 -1
- package/build-types/dataform-controls/color.d.ts.map +1 -1
- package/build-types/dataform-controls/date.d.ts.map +1 -1
- 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 +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/radio.d.ts.map +1 -1
- package/build-types/dataform-controls/relative-date-control.d.ts +6 -5
- package/build-types/dataform-controls/relative-date-control.d.ts.map +1 -1
- package/build-types/dataform-controls/select.d.ts.map +1 -1
- package/build-types/dataform-controls/telephone.d.ts.map +1 -1
- package/build-types/dataform-controls/text.d.ts +1 -1
- package/build-types/dataform-controls/text.d.ts.map +1 -1
- package/build-types/dataform-controls/textarea.d.ts +1 -1
- package/build-types/dataform-controls/textarea.d.ts.map +1 -1
- package/build-types/dataform-controls/toggle-group.d.ts.map +1 -1
- package/build-types/dataform-controls/toggle.d.ts.map +1 -1
- package/build-types/dataform-controls/url.d.ts.map +1 -1
- package/build-types/dataform-controls/utils/validated-input.d.ts +4 -4
- package/build-types/dataform-controls/utils/validated-input.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/dropdown.d.ts +2 -1
- package/build-types/dataforms-layouts/panel/dropdown.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/modal.d.ts +2 -1
- package/build-types/dataforms-layouts/panel/modal.d.ts.map +1 -1
- package/build-types/dataforms-layouts/panel/summary-button.d.ts +15 -0
- package/build-types/dataforms-layouts/panel/summary-button.d.ts.map +1 -0
- package/build-types/field-types/stories/index.story.d.ts.map +1 -1
- package/build-types/normalize-fields.d.ts +3 -0
- package/build-types/normalize-fields.d.ts.map +1 -1
- package/build-types/types.d.ts +66 -3
- package/build-types/types.d.ts.map +1 -1
- package/build-wp/index.js +1468 -1422
- package/package.json +16 -15
- package/src/components/dataform/stories/index.story.tsx +436 -7
- package/src/components/dataviews/stories/fixtures.tsx +99 -41
- package/src/components/dataviews/stories/index.story.tsx +1 -1
- package/src/components/dataviews-filters/input-widget.tsx +44 -5
- package/src/components/dataviews-picker/stories/index.story.tsx +1 -1
- package/src/dataform-controls/array.tsx +4 -6
- package/src/dataform-controls/checkbox.tsx +41 -24
- package/src/dataform-controls/color.tsx +33 -24
- package/src/dataform-controls/date.tsx +47 -21
- package/src/dataform-controls/datetime.tsx +171 -23
- package/src/dataform-controls/email.tsx +9 -1
- package/src/dataform-controls/index.tsx +26 -0
- package/src/dataform-controls/integer.tsx +82 -49
- package/src/dataform-controls/radio.tsx +53 -11
- package/src/dataform-controls/relative-date-control.tsx +11 -10
- package/src/dataform-controls/select.tsx +53 -10
- package/src/dataform-controls/telephone.tsx +9 -1
- package/src/dataform-controls/text.tsx +18 -1
- package/src/dataform-controls/textarea.tsx +38 -24
- package/src/dataform-controls/toggle-group.tsx +50 -10
- package/src/dataform-controls/toggle.tsx +41 -24
- package/src/dataform-controls/url.tsx +9 -1
- package/src/dataform-controls/utils/validated-input.tsx +50 -50
- package/src/dataforms-layouts/panel/dropdown.tsx +12 -23
- package/src/dataforms-layouts/panel/index.tsx +39 -16
- package/src/dataforms-layouts/panel/modal.tsx +24 -30
- package/src/dataforms-layouts/panel/summary-button.tsx +92 -0
- package/src/field-types/stories/index.story.tsx +89 -1
- package/src/normalize-fields.ts +18 -0
- package/src/test/filter-and-sort-data-view.js +148 -138
- package/src/test/normalize-fields.ts +114 -0
- package/src/types.ts +73 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import deepMerge from 'deepmerge';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* WordPress dependencies
|
|
3
8
|
*/
|
|
4
|
-
import {
|
|
5
|
-
Icon,
|
|
6
|
-
privateApis,
|
|
7
|
-
__experimentalInputControlPrefixWrapper as InputControlPrefixWrapper,
|
|
8
|
-
__experimentalInputControlSuffixWrapper as InputControlSuffixWrapper,
|
|
9
|
-
} from '@wordpress/components';
|
|
9
|
+
import { privateApis } from '@wordpress/components';
|
|
10
10
|
import { useCallback, useState } from '@wordpress/element';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -24,11 +24,11 @@ export type DataFormValidatedTextControlProps< Item > =
|
|
|
24
24
|
*/
|
|
25
25
|
type?: 'text' | 'email' | 'tel' | 'url' | 'password';
|
|
26
26
|
/**
|
|
27
|
-
* Optional
|
|
27
|
+
* Optional prefix element to display before the input.
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
prefix?: React.ReactElement;
|
|
30
30
|
/**
|
|
31
|
-
* Optional
|
|
31
|
+
* Optional suffix element to display after the input.
|
|
32
32
|
*/
|
|
33
33
|
suffix?: React.ReactElement;
|
|
34
34
|
};
|
|
@@ -39,11 +39,12 @@ export default function ValidatedText< Item >( {
|
|
|
39
39
|
onChange,
|
|
40
40
|
hideLabelFromVision,
|
|
41
41
|
type,
|
|
42
|
-
|
|
42
|
+
prefix,
|
|
43
43
|
suffix,
|
|
44
44
|
}: DataFormValidatedTextControlProps< Item > ) {
|
|
45
|
-
const {
|
|
46
|
-
|
|
45
|
+
const { label, placeholder, description, getValue, setValue, isValid } =
|
|
46
|
+
field;
|
|
47
|
+
const value = getValue( { item: data } );
|
|
47
48
|
const [ customValidity, setCustomValidity ] =
|
|
48
49
|
useState<
|
|
49
50
|
React.ComponentProps<
|
|
@@ -53,34 +54,45 @@ export default function ValidatedText< Item >( {
|
|
|
53
54
|
|
|
54
55
|
const onChangeControl = useCallback(
|
|
55
56
|
( newValue: string ) =>
|
|
56
|
-
onChange(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
onChange(
|
|
58
|
+
setValue( {
|
|
59
|
+
item: data,
|
|
60
|
+
value: newValue,
|
|
61
|
+
} )
|
|
62
|
+
),
|
|
63
|
+
[ data, setValue, onChange ]
|
|
60
64
|
);
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
{
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
const onValidateControl = useCallback(
|
|
67
|
+
( newValue: any ) => {
|
|
68
|
+
const message = isValid?.custom?.(
|
|
69
|
+
deepMerge(
|
|
70
|
+
data,
|
|
71
|
+
setValue( {
|
|
72
|
+
item: data,
|
|
73
|
+
value: newValue,
|
|
74
|
+
} ) as Partial< Item >
|
|
75
|
+
),
|
|
76
|
+
field
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
if ( message ) {
|
|
80
|
+
setCustomValidity( {
|
|
81
|
+
type: 'invalid',
|
|
82
|
+
message,
|
|
83
|
+
} );
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
} );
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
87
|
+
setCustomValidity( undefined );
|
|
88
|
+
},
|
|
89
|
+
[ data, field, isValid, setValue ]
|
|
90
|
+
);
|
|
81
91
|
|
|
82
|
-
|
|
83
|
-
|
|
92
|
+
return (
|
|
93
|
+
<ValidatedInputControl
|
|
94
|
+
required={ !! isValid?.required }
|
|
95
|
+
onValidate={ onValidateControl }
|
|
84
96
|
customValidity={ customValidity }
|
|
85
97
|
label={ label }
|
|
86
98
|
placeholder={ placeholder }
|
|
@@ -89,20 +101,8 @@ export default function ValidatedText< Item >( {
|
|
|
89
101
|
onChange={ onChangeControl }
|
|
90
102
|
hideLabelFromVision={ hideLabelFromVision }
|
|
91
103
|
type={ type }
|
|
92
|
-
prefix={
|
|
93
|
-
|
|
94
|
-
<InputControlPrefixWrapper variant="icon">
|
|
95
|
-
<Icon icon={ icon } />
|
|
96
|
-
</InputControlPrefixWrapper>
|
|
97
|
-
) : undefined
|
|
98
|
-
}
|
|
99
|
-
suffix={
|
|
100
|
-
suffix ? (
|
|
101
|
-
<InputControlSuffixWrapper variant="control">
|
|
102
|
-
{ suffix }
|
|
103
|
-
</InputControlSuffixWrapper>
|
|
104
|
-
) : undefined
|
|
105
|
-
}
|
|
104
|
+
prefix={ prefix }
|
|
105
|
+
suffix={ suffix }
|
|
106
106
|
__next40pxDefaultSize
|
|
107
107
|
/>
|
|
108
108
|
);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
Dropdown,
|
|
10
10
|
Button,
|
|
11
11
|
} from '@wordpress/components';
|
|
12
|
-
import {
|
|
12
|
+
import { __ } from '@wordpress/i18n';
|
|
13
13
|
import { useMemo } from '@wordpress/element';
|
|
14
14
|
import { closeSmall } from '@wordpress/icons';
|
|
15
15
|
|
|
@@ -20,6 +20,7 @@ import type { Form, FormField, NormalizedField } from '../../types';
|
|
|
20
20
|
import { DataFormLayout } from '../data-form-layout';
|
|
21
21
|
import { isCombinedField } from '../is-combined-field';
|
|
22
22
|
import { DEFAULT_LAYOUT } from '../../normalize-form-fields';
|
|
23
|
+
import SummaryButton from './summary-button';
|
|
23
24
|
|
|
24
25
|
function DropdownHeader( {
|
|
25
26
|
title,
|
|
@@ -55,6 +56,7 @@ function DropdownHeader( {
|
|
|
55
56
|
|
|
56
57
|
function PanelDropdown< Item >( {
|
|
57
58
|
fieldDefinition,
|
|
59
|
+
summaryFields,
|
|
58
60
|
popoverAnchor,
|
|
59
61
|
labelPosition = 'side',
|
|
60
62
|
data,
|
|
@@ -62,6 +64,7 @@ function PanelDropdown< Item >( {
|
|
|
62
64
|
field,
|
|
63
65
|
}: {
|
|
64
66
|
fieldDefinition: NormalizedField< Item >;
|
|
67
|
+
summaryFields: NormalizedField< Item >[];
|
|
65
68
|
popoverAnchor: HTMLElement | null;
|
|
66
69
|
labelPosition: 'side' | 'top' | 'none';
|
|
67
70
|
data: Item;
|
|
@@ -107,29 +110,15 @@ function PanelDropdown< Item >( {
|
|
|
107
110
|
tooltipPosition: 'middle left',
|
|
108
111
|
} }
|
|
109
112
|
renderToggle={ ( { isOpen, onToggle } ) => (
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
? 'link'
|
|
116
|
-
: 'tertiary'
|
|
117
|
-
}
|
|
118
|
-
aria-expanded={ isOpen }
|
|
119
|
-
aria-label={ sprintf(
|
|
120
|
-
// translators: %s: Field name.
|
|
121
|
-
_x( 'Edit %s', 'field' ),
|
|
122
|
-
fieldLabel || ''
|
|
123
|
-
) }
|
|
124
|
-
onClick={ onToggle }
|
|
113
|
+
<SummaryButton
|
|
114
|
+
summaryFields={ summaryFields }
|
|
115
|
+
data={ data }
|
|
116
|
+
labelPosition={ labelPosition }
|
|
117
|
+
fieldLabel={ fieldLabel }
|
|
125
118
|
disabled={ fieldDefinition.readOnly === true }
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
item={ data }
|
|
130
|
-
field={ fieldDefinition }
|
|
131
|
-
/>
|
|
132
|
-
</Button>
|
|
119
|
+
onClick={ onToggle }
|
|
120
|
+
aria-expanded={ isOpen }
|
|
121
|
+
/>
|
|
133
122
|
) }
|
|
134
123
|
renderContent={ ( { onClose } ) => (
|
|
135
124
|
<>
|
|
@@ -32,28 +32,49 @@ export default function FormPanelField< Item >( {
|
|
|
32
32
|
onChange,
|
|
33
33
|
}: FieldLayoutProps< Item > ) {
|
|
34
34
|
const { fields } = useContext( DataFormContext );
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
( child ): child is string | SimpleFormField =>
|
|
40
|
-
typeof child === 'string' || ! isCombinedField( child )
|
|
35
|
+
const getSummaryFields = () => {
|
|
36
|
+
if ( ! isCombinedField( field ) ) {
|
|
37
|
+
const fieldDef = fields.find(
|
|
38
|
+
( _field ) => _field.id === field.id
|
|
41
39
|
);
|
|
40
|
+
return fieldDef ? [ fieldDef ] : [];
|
|
41
|
+
}
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// Use summary field(s) if specified for combined fields
|
|
44
|
+
if ( field.summary ) {
|
|
45
|
+
const summaryIds = Array.isArray( field.summary )
|
|
46
|
+
? field.summary
|
|
47
|
+
: [ field.summary ];
|
|
48
|
+
return summaryIds
|
|
49
|
+
.map( ( summaryId ) =>
|
|
50
|
+
fields.find( ( _field ) => _field.id === summaryId )
|
|
51
|
+
)
|
|
52
|
+
.filter( ( _field ) => _field !== undefined );
|
|
53
|
+
}
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
// Default to the first simple child
|
|
56
|
+
const simpleChildren = field.children.filter(
|
|
57
|
+
( child ): child is string | SimpleFormField =>
|
|
58
|
+
typeof child === 'string' || ! isCombinedField( child )
|
|
59
|
+
);
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
if ( simpleChildren.length === 0 ) {
|
|
62
|
+
return [];
|
|
53
63
|
}
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
const firstChildFieldId =
|
|
66
|
+
typeof simpleChildren[ 0 ] === 'string'
|
|
67
|
+
? simpleChildren[ 0 ]
|
|
68
|
+
: simpleChildren[ 0 ].id;
|
|
69
|
+
|
|
70
|
+
const fieldDef = fields.find(
|
|
71
|
+
( _field ) => _field.id === firstChildFieldId
|
|
72
|
+
);
|
|
73
|
+
return fieldDef ? [ fieldDef ] : [];
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const summaryFields = getSummaryFields();
|
|
77
|
+
const fieldDefinition = summaryFields[ 0 ]; // For backward compatibility
|
|
57
78
|
|
|
58
79
|
// Use internal state instead of a ref to make sure that the component
|
|
59
80
|
// re-renders when the popover's anchor updates.
|
|
@@ -84,6 +105,7 @@ export default function FormPanelField< Item >( {
|
|
|
84
105
|
<PanelModal
|
|
85
106
|
field={ field }
|
|
86
107
|
fieldDefinition={ fieldDefinition }
|
|
108
|
+
summaryFields={ summaryFields }
|
|
87
109
|
data={ data }
|
|
88
110
|
onChange={ onChange }
|
|
89
111
|
labelPosition={ labelPosition }
|
|
@@ -93,6 +115,7 @@ export default function FormPanelField< Item >( {
|
|
|
93
115
|
field={ field }
|
|
94
116
|
popoverAnchor={ popoverAnchor }
|
|
95
117
|
fieldDefinition={ fieldDefinition }
|
|
118
|
+
summaryFields={ summaryFields }
|
|
96
119
|
data={ data }
|
|
97
120
|
onChange={ onChange }
|
|
98
121
|
labelPosition={ labelPosition }
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import deepMerge from 'deepmerge';
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* WordPress dependencies
|
|
3
8
|
*/
|
|
@@ -7,7 +12,7 @@ import {
|
|
|
7
12
|
Button,
|
|
8
13
|
Modal,
|
|
9
14
|
} from '@wordpress/components';
|
|
10
|
-
import { __
|
|
15
|
+
import { __ } from '@wordpress/i18n';
|
|
11
16
|
import { useState, useMemo } from '@wordpress/element';
|
|
12
17
|
|
|
13
18
|
/**
|
|
@@ -17,6 +22,7 @@ import type { Form, FormField, NormalizedField } from '../../types';
|
|
|
17
22
|
import { DataFormLayout } from '../data-form-layout';
|
|
18
23
|
import { isCombinedField } from '../is-combined-field';
|
|
19
24
|
import { DEFAULT_LAYOUT } from '../../normalize-form-fields';
|
|
25
|
+
import SummaryButton from './summary-button';
|
|
20
26
|
|
|
21
27
|
function ModalContent< Item >( {
|
|
22
28
|
data,
|
|
@@ -32,19 +38,19 @@ function ModalContent< Item >( {
|
|
|
32
38
|
onClose: () => void;
|
|
33
39
|
} ) {
|
|
34
40
|
const [ changes, setChanges ] = useState< Partial< Item > >( {} );
|
|
41
|
+
const modalData = useMemo( () => {
|
|
42
|
+
return deepMerge( data, changes );
|
|
43
|
+
}, [ data, changes ] );
|
|
35
44
|
|
|
36
45
|
const onApply = () => {
|
|
37
46
|
onChange( changes );
|
|
38
47
|
onClose();
|
|
39
48
|
};
|
|
40
49
|
|
|
41
|
-
const handleOnChange = (
|
|
42
|
-
setChanges( ( prev ) => (
|
|
50
|
+
const handleOnChange = ( newValue: Partial< Item > ) => {
|
|
51
|
+
setChanges( ( prev ) => deepMerge( prev, newValue ) );
|
|
43
52
|
};
|
|
44
53
|
|
|
45
|
-
// Merge original data with local changes for display
|
|
46
|
-
const displayData = { ...data, ...changes };
|
|
47
|
-
|
|
48
54
|
return (
|
|
49
55
|
<Modal
|
|
50
56
|
className="dataforms-layouts-panel__modal"
|
|
@@ -54,14 +60,14 @@ function ModalContent< Item >( {
|
|
|
54
60
|
size="medium"
|
|
55
61
|
>
|
|
56
62
|
<DataFormLayout
|
|
57
|
-
data={
|
|
63
|
+
data={ modalData }
|
|
58
64
|
form={ form }
|
|
59
65
|
onChange={ handleOnChange }
|
|
60
66
|
>
|
|
61
67
|
{ ( FieldLayout, nestedField ) => (
|
|
62
68
|
<FieldLayout
|
|
63
69
|
key={ nestedField.id }
|
|
64
|
-
data={
|
|
70
|
+
data={ modalData }
|
|
65
71
|
field={ nestedField }
|
|
66
72
|
onChange={ handleOnChange }
|
|
67
73
|
hideLabelFromVision={
|
|
@@ -96,12 +102,14 @@ function ModalContent< Item >( {
|
|
|
96
102
|
|
|
97
103
|
function PanelModal< Item >( {
|
|
98
104
|
fieldDefinition,
|
|
105
|
+
summaryFields,
|
|
99
106
|
labelPosition,
|
|
100
107
|
data,
|
|
101
108
|
onChange,
|
|
102
109
|
field,
|
|
103
110
|
}: {
|
|
104
111
|
fieldDefinition: NormalizedField< Item >;
|
|
112
|
+
summaryFields: NormalizedField< Item >[];
|
|
105
113
|
labelPosition: 'side' | 'top' | 'none';
|
|
106
114
|
data: Item;
|
|
107
115
|
onChange: ( value: any ) => void;
|
|
@@ -126,29 +134,15 @@ function PanelModal< Item >( {
|
|
|
126
134
|
|
|
127
135
|
return (
|
|
128
136
|
<>
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
? 'link'
|
|
135
|
-
: 'tertiary'
|
|
136
|
-
}
|
|
137
|
-
aria-expanded={ isOpen }
|
|
138
|
-
aria-label={ sprintf(
|
|
139
|
-
// translators: %s: Field name.
|
|
140
|
-
_x( 'Edit %s', 'field' ),
|
|
141
|
-
fieldLabel || ''
|
|
142
|
-
) }
|
|
143
|
-
onClick={ () => setIsOpen( true ) }
|
|
137
|
+
<SummaryButton
|
|
138
|
+
summaryFields={ summaryFields }
|
|
139
|
+
data={ data }
|
|
140
|
+
labelPosition={ labelPosition }
|
|
141
|
+
fieldLabel={ fieldLabel }
|
|
144
142
|
disabled={ fieldDefinition.readOnly === true }
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
item={ data }
|
|
149
|
-
field={ fieldDefinition }
|
|
150
|
-
/>
|
|
151
|
-
</Button>
|
|
143
|
+
onClick={ () => setIsOpen( true ) }
|
|
144
|
+
aria-expanded={ isOpen }
|
|
145
|
+
/>
|
|
152
146
|
{ isOpen && (
|
|
153
147
|
<ModalContent
|
|
154
148
|
data={ data }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { Button } from '@wordpress/components';
|
|
5
|
+
import { sprintf, _x } from '@wordpress/i18n';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import type { NormalizedField } from '../../types';
|
|
11
|
+
|
|
12
|
+
function SummaryButton< Item >( {
|
|
13
|
+
summaryFields,
|
|
14
|
+
data,
|
|
15
|
+
labelPosition,
|
|
16
|
+
fieldLabel,
|
|
17
|
+
disabled,
|
|
18
|
+
onClick,
|
|
19
|
+
'aria-expanded': ariaExpanded,
|
|
20
|
+
}: {
|
|
21
|
+
summaryFields: NormalizedField< Item >[];
|
|
22
|
+
data: Item;
|
|
23
|
+
labelPosition: 'side' | 'top' | 'none';
|
|
24
|
+
fieldLabel?: string;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
onClick: () => void;
|
|
27
|
+
'aria-expanded'?: boolean;
|
|
28
|
+
} ) {
|
|
29
|
+
return (
|
|
30
|
+
<Button
|
|
31
|
+
className="dataforms-layouts-panel__summary-button"
|
|
32
|
+
size="compact"
|
|
33
|
+
variant={
|
|
34
|
+
[ 'none', 'top' ].includes( labelPosition )
|
|
35
|
+
? 'link'
|
|
36
|
+
: 'tertiary'
|
|
37
|
+
}
|
|
38
|
+
aria-expanded={ ariaExpanded }
|
|
39
|
+
aria-label={ sprintf(
|
|
40
|
+
// translators: %s: Field name.
|
|
41
|
+
_x( 'Edit %s', 'field' ),
|
|
42
|
+
fieldLabel || ''
|
|
43
|
+
) }
|
|
44
|
+
onClick={ onClick }
|
|
45
|
+
disabled={ disabled }
|
|
46
|
+
accessibleWhenDisabled
|
|
47
|
+
style={
|
|
48
|
+
summaryFields.length > 1
|
|
49
|
+
? {
|
|
50
|
+
minHeight: 'auto',
|
|
51
|
+
height: 'auto',
|
|
52
|
+
alignItems: 'flex-start',
|
|
53
|
+
}
|
|
54
|
+
: undefined
|
|
55
|
+
}
|
|
56
|
+
>
|
|
57
|
+
{ summaryFields.length > 1 ? (
|
|
58
|
+
<div
|
|
59
|
+
style={ {
|
|
60
|
+
display: 'flex',
|
|
61
|
+
flexDirection: 'column',
|
|
62
|
+
alignItems: 'flex-start',
|
|
63
|
+
width: '100%',
|
|
64
|
+
gap: '2px',
|
|
65
|
+
} }
|
|
66
|
+
>
|
|
67
|
+
{ summaryFields.map( ( summaryField ) => (
|
|
68
|
+
<div
|
|
69
|
+
key={ summaryField.id }
|
|
70
|
+
style={ { width: '100%' } }
|
|
71
|
+
>
|
|
72
|
+
<summaryField.render
|
|
73
|
+
item={ data }
|
|
74
|
+
field={ summaryField }
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
) ) }
|
|
78
|
+
</div>
|
|
79
|
+
) : (
|
|
80
|
+
summaryFields.map( ( summaryField ) => (
|
|
81
|
+
<summaryField.render
|
|
82
|
+
key={ summaryField.id }
|
|
83
|
+
item={ data }
|
|
84
|
+
field={ summaryField }
|
|
85
|
+
/>
|
|
86
|
+
) )
|
|
87
|
+
) }
|
|
88
|
+
</Button>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default SummaryButton;
|
|
@@ -5,7 +5,11 @@ import { useState, useMemo } from '@wordpress/element';
|
|
|
5
5
|
import {
|
|
6
6
|
__experimentalHStack as HStack,
|
|
7
7
|
__experimentalVStack as VStack,
|
|
8
|
+
Icon,
|
|
9
|
+
__experimentalInputControlPrefixWrapper as InputControlPrefixWrapper,
|
|
10
|
+
__experimentalInputControlSuffixWrapper as InputControlSuffixWrapper,
|
|
8
11
|
} from '@wordpress/components';
|
|
12
|
+
import { starFilled } from '@wordpress/icons';
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Internal dependencies
|
|
@@ -56,10 +60,32 @@ const meta = {
|
|
|
56
60
|
};
|
|
57
61
|
export default meta;
|
|
58
62
|
|
|
63
|
+
const DollarPrefix = () => (
|
|
64
|
+
<InputControlPrefixWrapper>
|
|
65
|
+
<span>$</span>
|
|
66
|
+
</InputControlPrefixWrapper>
|
|
67
|
+
);
|
|
68
|
+
const StarIconPrefix = () => (
|
|
69
|
+
<InputControlPrefixWrapper variant="icon">
|
|
70
|
+
<Icon icon={ starFilled } />
|
|
71
|
+
</InputControlPrefixWrapper>
|
|
72
|
+
);
|
|
73
|
+
const PercentSuffix = () => (
|
|
74
|
+
<InputControlSuffixWrapper>
|
|
75
|
+
<span>%</span>
|
|
76
|
+
</InputControlSuffixWrapper>
|
|
77
|
+
);
|
|
78
|
+
const USDSuffix = () => (
|
|
79
|
+
<InputControlSuffixWrapper>
|
|
80
|
+
<span>USD</span>
|
|
81
|
+
</InputControlSuffixWrapper>
|
|
82
|
+
);
|
|
83
|
+
|
|
59
84
|
type DataType = {
|
|
60
85
|
id: number;
|
|
61
86
|
text: string;
|
|
62
87
|
textWithElements: string;
|
|
88
|
+
textWithRadio: string;
|
|
63
89
|
textWithTextarea: string;
|
|
64
90
|
integer: number;
|
|
65
91
|
integerWithElements: number;
|
|
@@ -86,13 +112,18 @@ type DataType = {
|
|
|
86
112
|
arrayWithElements: string[];
|
|
87
113
|
notype: string;
|
|
88
114
|
notypeWithElements: string;
|
|
115
|
+
priceWithPrefix?: string;
|
|
116
|
+
ratingWithIcon?: string;
|
|
117
|
+
percentageWithSuffix?: string;
|
|
118
|
+
priceWithBoth?: string;
|
|
89
119
|
};
|
|
90
120
|
|
|
91
121
|
const data: DataType[] = [
|
|
92
122
|
{
|
|
93
123
|
id: 1,
|
|
94
124
|
text: 'Text',
|
|
95
|
-
textWithElements: '
|
|
125
|
+
textWithElements: 'item1',
|
|
126
|
+
textWithRadio: 'item2',
|
|
96
127
|
textWithTextarea: 'Textarea',
|
|
97
128
|
integer: 1,
|
|
98
129
|
integerWithElements: 1,
|
|
@@ -120,6 +151,10 @@ const data: DataType[] = [
|
|
|
120
151
|
arrayWithElements: [ 'item1', 'item2', 'item3' ],
|
|
121
152
|
notype: 'No type',
|
|
122
153
|
notypeWithElements: 'No type',
|
|
154
|
+
priceWithPrefix: '25.99',
|
|
155
|
+
ratingWithIcon: '4.5',
|
|
156
|
+
percentageWithSuffix: '85',
|
|
157
|
+
priceWithBoth: '199.99',
|
|
123
158
|
},
|
|
124
159
|
];
|
|
125
160
|
|
|
@@ -141,6 +176,18 @@ const fields: Field< DataType >[] = [
|
|
|
141
176
|
{ value: 'item3', label: 'Item 3' },
|
|
142
177
|
],
|
|
143
178
|
},
|
|
179
|
+
{
|
|
180
|
+
id: 'textWithRadio',
|
|
181
|
+
type: 'text',
|
|
182
|
+
label: 'Text (with radio)',
|
|
183
|
+
description: 'Help for text with radio.',
|
|
184
|
+
Edit: 'radio',
|
|
185
|
+
elements: [
|
|
186
|
+
{ value: 'item1', label: 'Item 1' },
|
|
187
|
+
{ value: 'item2', label: 'Item 2' },
|
|
188
|
+
{ value: 'item3', label: 'Item 3' },
|
|
189
|
+
],
|
|
190
|
+
},
|
|
144
191
|
{
|
|
145
192
|
id: 'textWithTextarea',
|
|
146
193
|
type: 'text',
|
|
@@ -395,6 +442,47 @@ const fields: Field< DataType >[] = [
|
|
|
395
442
|
{ value: 'item3', label: 'Item 3' },
|
|
396
443
|
],
|
|
397
444
|
},
|
|
445
|
+
{
|
|
446
|
+
id: 'priceWithPrefix',
|
|
447
|
+
label: 'Text with Prefix',
|
|
448
|
+
type: 'text',
|
|
449
|
+
description: 'Text field with dollar sign prefix.',
|
|
450
|
+
Edit: {
|
|
451
|
+
control: 'text',
|
|
452
|
+
prefix: DollarPrefix,
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: 'ratingWithIcon',
|
|
457
|
+
label: 'Text with Icon Prefix',
|
|
458
|
+
type: 'text',
|
|
459
|
+
description: 'Text field with star icon prefix.',
|
|
460
|
+
Edit: {
|
|
461
|
+
control: 'text',
|
|
462
|
+
prefix: StarIconPrefix,
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
id: 'percentageWithSuffix',
|
|
467
|
+
label: 'Text with Suffix',
|
|
468
|
+
type: 'text',
|
|
469
|
+
description: 'Text field with percent sign suffix.',
|
|
470
|
+
Edit: {
|
|
471
|
+
control: 'text',
|
|
472
|
+
suffix: PercentSuffix,
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
id: 'priceWithBoth',
|
|
477
|
+
label: 'Text with Prefix and Suffix',
|
|
478
|
+
type: 'text',
|
|
479
|
+
description: 'Text field with both dollar prefix and USD suffix.',
|
|
480
|
+
Edit: {
|
|
481
|
+
control: 'text',
|
|
482
|
+
prefix: DollarPrefix,
|
|
483
|
+
suffix: USDSuffix,
|
|
484
|
+
},
|
|
485
|
+
},
|
|
398
486
|
];
|
|
399
487
|
|
|
400
488
|
type PanelTypes = 'regular' | 'panel';
|
package/src/normalize-fields.ts
CHANGED
|
@@ -37,6 +37,22 @@ const getValueFromId =
|
|
|
37
37
|
return value;
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
export const setValueFromId =
|
|
41
|
+
( id: string ) =>
|
|
42
|
+
( { value }: { value: any } ) => {
|
|
43
|
+
const path = id.split( '.' );
|
|
44
|
+
const result: any = {};
|
|
45
|
+
let current = result;
|
|
46
|
+
|
|
47
|
+
for ( const segment of path.slice( 0, -1 ) ) {
|
|
48
|
+
current[ segment ] = {};
|
|
49
|
+
current = current[ segment ];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
current[ path.at( -1 )! ] = value;
|
|
53
|
+
return result;
|
|
54
|
+
};
|
|
55
|
+
|
|
40
56
|
function getFilterBy< Item >(
|
|
41
57
|
field: Field< Item >,
|
|
42
58
|
fieldTypeDefinition: FieldTypeDefinition< Item >
|
|
@@ -128,6 +144,7 @@ export function normalizeFields< Item >(
|
|
|
128
144
|
field.type
|
|
129
145
|
);
|
|
130
146
|
const getValue = field.getValue || getValueFromId( field.id );
|
|
147
|
+
const setValue = field.setValue || setValueFromId( field.id );
|
|
131
148
|
|
|
132
149
|
const sort =
|
|
133
150
|
field.sort ??
|
|
@@ -166,6 +183,7 @@ export function normalizeFields< Item >(
|
|
|
166
183
|
label: field.label || field.id,
|
|
167
184
|
header: field.header || field.label || field.id,
|
|
168
185
|
getValue,
|
|
186
|
+
setValue,
|
|
169
187
|
render,
|
|
170
188
|
sort,
|
|
171
189
|
isValid,
|