@wordpress/dataviews 7.0.1-next.0f6f9d12c.0 → 7.0.1-next.f34ab90e9.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/build/components/dataviews-item-actions/index.js +1 -10
  3. package/build/components/dataviews-item-actions/index.js.map +1 -1
  4. package/build/dataform-controls/boolean.js +15 -7
  5. package/build/dataform-controls/boolean.js.map +1 -1
  6. package/build/dataform-controls/email.js +14 -7
  7. package/build/dataform-controls/email.js.map +1 -1
  8. package/build/dataform-controls/integer.js +14 -7
  9. package/build/dataform-controls/integer.js.map +1 -1
  10. package/build/dataform-controls/text.js +14 -7
  11. package/build/dataform-controls/text.js.map +1 -1
  12. package/build/dataforms-layouts/panel/dropdown.js +124 -0
  13. package/build/dataforms-layouts/panel/dropdown.js.map +1 -0
  14. package/build/dataforms-layouts/panel/index.js +19 -127
  15. package/build/dataforms-layouts/panel/index.js.map +1 -1
  16. package/build/dataforms-layouts/panel/modal.js +125 -0
  17. package/build/dataforms-layouts/panel/modal.js.map +1 -0
  18. package/build/normalize-form-fields.js +3 -2
  19. package/build/normalize-form-fields.js.map +1 -1
  20. package/build/types.js.map +1 -1
  21. package/build-module/components/dataviews-item-actions/index.js +1 -10
  22. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  23. package/build-module/dataform-controls/boolean.js +15 -7
  24. package/build-module/dataform-controls/boolean.js.map +1 -1
  25. package/build-module/dataform-controls/email.js +15 -8
  26. package/build-module/dataform-controls/email.js.map +1 -1
  27. package/build-module/dataform-controls/integer.js +15 -8
  28. package/build-module/dataform-controls/integer.js.map +1 -1
  29. package/build-module/dataform-controls/text.js +15 -8
  30. package/build-module/dataform-controls/text.js.map +1 -1
  31. package/build-module/dataforms-layouts/panel/dropdown.js +118 -0
  32. package/build-module/dataforms-layouts/panel/dropdown.js.map +1 -0
  33. package/build-module/dataforms-layouts/panel/index.js +23 -131
  34. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  35. package/build-module/dataforms-layouts/panel/modal.js +119 -0
  36. package/build-module/dataforms-layouts/panel/modal.js.map +1 -0
  37. package/build-module/normalize-form-fields.js +3 -2
  38. package/build-module/normalize-form-fields.js.map +1 -1
  39. package/build-module/types.js.map +1 -1
  40. package/build-style/style-rtl.css +4 -0
  41. package/build-style/style.css +4 -0
  42. package/build-types/components/dataform/stories/index.story.d.ts +58 -25
  43. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  44. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  45. package/build-types/dataform-controls/boolean.d.ts.map +1 -1
  46. package/build-types/dataform-controls/email.d.ts.map +1 -1
  47. package/build-types/dataform-controls/integer.d.ts.map +1 -1
  48. package/build-types/dataform-controls/text.d.ts.map +1 -1
  49. package/build-types/dataforms-layouts/panel/dropdown.d.ts +14 -0
  50. package/build-types/dataforms-layouts/panel/dropdown.d.ts.map +1 -0
  51. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  52. package/build-types/dataforms-layouts/panel/modal.d.ts +13 -0
  53. package/build-types/dataforms-layouts/panel/modal.d.ts.map +1 -0
  54. package/build-types/normalize-form-fields.d.ts.map +1 -1
  55. package/build-types/types.d.ts +2 -0
  56. package/build-types/types.d.ts.map +1 -1
  57. package/build-wp/index.js +394 -178
  58. package/package.json +15 -15
  59. package/src/components/dataform/stories/index.story.tsx +354 -219
  60. package/src/components/dataviews-item-actions/index.tsx +7 -16
  61. package/src/dataform-controls/boolean.tsx +24 -10
  62. package/src/dataform-controls/email.tsx +24 -11
  63. package/src/dataform-controls/integer.tsx +27 -13
  64. package/src/dataform-controls/text.tsx +24 -11
  65. package/src/dataforms-layouts/panel/dropdown.tsx +160 -0
  66. package/src/dataforms-layouts/panel/index.tsx +28 -172
  67. package/src/dataforms-layouts/panel/modal.tsx +165 -0
  68. package/src/dataforms-layouts/panel/style.scss +4 -0
  69. package/src/normalize-form-fields.ts +1 -0
  70. package/src/test/dataform.tsx +169 -0
  71. package/src/test/normalize-form-fields.ts +15 -3
  72. package/src/types.ts +2 -0
  73. package/tsconfig.tsbuildinfo +1 -1
@@ -179,17 +179,6 @@ export default function ItemActions< Item >( {
179
179
  );
180
180
  }
181
181
 
182
- // If all actions are primary, there is no need to render the dropdown.
183
- if ( primaryActions.length === eligibleActions.length ) {
184
- return (
185
- <PrimaryActions
186
- item={ item }
187
- actions={ primaryActions }
188
- registry={ registry }
189
- />
190
- );
191
- }
192
-
193
182
  return (
194
183
  <HStack
195
184
  spacing={ 1 }
@@ -205,11 +194,13 @@ export default function ItemActions< Item >( {
205
194
  actions={ primaryActions }
206
195
  registry={ registry }
207
196
  />
208
- <CompactItemActions
209
- item={ item }
210
- actions={ eligibleActions }
211
- registry={ registry }
212
- />
197
+ { primaryActions.length < eligibleActions.length && (
198
+ <CompactItemActions
199
+ item={ item }
200
+ actions={ eligibleActions }
201
+ registry={ registry }
202
+ />
203
+ ) }
213
204
  </HStack>
214
205
  );
215
206
  }
@@ -2,6 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { privateApis } from '@wordpress/components';
5
+ import { useState } from '@wordpress/element';
5
6
 
6
7
  /**
7
8
  * Internal dependencies
@@ -18,23 +19,36 @@ export default function Boolean< Item >( {
18
19
  hideLabelFromVision,
19
20
  }: DataFormControlProps< Item > ) {
20
21
  const { id, getValue, label } = field;
22
+ const [ customValidity, setCustomValidity ] =
23
+ useState<
24
+ React.ComponentProps<
25
+ typeof ValidatedToggleControl
26
+ >[ 'customValidity' ]
27
+ >( undefined );
21
28
 
22
29
  return (
23
30
  <ValidatedToggleControl
24
31
  required={ !! field.isValid.required }
25
- customValidator={ ( newValue: any ) => {
26
- if ( field.isValid?.custom ) {
27
- return field.isValid.custom(
28
- {
29
- ...data,
30
- [ id ]: newValue,
31
- },
32
- field
33
- );
32
+ onValidate={ ( newValue: any ) => {
33
+ const message = field.isValid?.custom?.(
34
+ {
35
+ ...data,
36
+ [ id ]: newValue,
37
+ },
38
+ field
39
+ );
40
+
41
+ if ( message ) {
42
+ setCustomValidity( {
43
+ type: 'invalid',
44
+ message,
45
+ } );
46
+ return;
34
47
  }
35
48
 
36
- return null;
49
+ setCustomValidity( undefined );
37
50
  } }
51
+ customValidity={ customValidity }
38
52
  hidden={ hideLabelFromVision }
39
53
  __nextHasNoMarginBottom
40
54
  label={ label }
@@ -2,7 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { privateApis } from '@wordpress/components';
5
- import { useCallback } from '@wordpress/element';
5
+ import { useCallback, useState } from '@wordpress/element';
6
6
 
7
7
  /**
8
8
  * Internal dependencies
@@ -20,6 +20,12 @@ export default function Email< Item >( {
20
20
  }: DataFormControlProps< Item > ) {
21
21
  const { id, label, placeholder, description } = field;
22
22
  const value = field.getValue( { item: data } );
23
+ const [ customValidity, setCustomValidity ] =
24
+ useState<
25
+ React.ComponentProps<
26
+ typeof ValidatedTextControl
27
+ >[ 'customValidity' ]
28
+ >( undefined );
23
29
 
24
30
  const onChangeControl = useCallback(
25
31
  ( newValue: string ) =>
@@ -32,19 +38,26 @@ export default function Email< Item >( {
32
38
  return (
33
39
  <ValidatedTextControl
34
40
  required={ !! field.isValid?.required }
35
- customValidator={ ( newValue: any ) => {
36
- if ( field.isValid?.custom ) {
37
- return field.isValid.custom(
38
- {
39
- ...data,
40
- [ id ]: newValue,
41
- },
42
- field
43
- );
41
+ onValidate={ ( newValue: any ) => {
42
+ const message = field.isValid?.custom?.(
43
+ {
44
+ ...data,
45
+ [ id ]: newValue,
46
+ },
47
+ field
48
+ );
49
+
50
+ if ( message ) {
51
+ setCustomValidity( {
52
+ type: 'invalid',
53
+ message,
54
+ } );
55
+ return;
44
56
  }
45
57
 
46
- return null;
58
+ setCustomValidity( undefined );
47
59
  } }
60
+ customValidity={ customValidity }
48
61
  type="email"
49
62
  label={ label }
50
63
  placeholder={ placeholder }
@@ -7,7 +7,7 @@ import {
7
7
  __experimentalNumberControl as NumberControl,
8
8
  privateApis,
9
9
  } from '@wordpress/components';
10
- import { useCallback } from '@wordpress/element';
10
+ import { useCallback, useState } from '@wordpress/element';
11
11
  import { __ } from '@wordpress/i18n';
12
12
 
13
13
  /**
@@ -84,6 +84,13 @@ export default function Integer< Item >( {
84
84
  }: DataFormControlProps< Item > ) {
85
85
  const { id, label, description } = field;
86
86
  const value = field.getValue( { item: data } ) ?? '';
87
+ const [ customValidity, setCustomValidity ] =
88
+ useState<
89
+ React.ComponentProps<
90
+ typeof ValidatedNumberControl
91
+ >[ 'customValidity' ]
92
+ >( undefined );
93
+
87
94
  const onChangeControl = useCallback(
88
95
  ( newValue: string | undefined ) => {
89
96
  onChange( {
@@ -112,21 +119,28 @@ export default function Integer< Item >( {
112
119
  return (
113
120
  <ValidatedNumberControl
114
121
  required={ !! field.isValid?.required }
115
- customValidator={ ( newValue: any ) => {
116
- if ( field.isValid?.custom ) {
117
- return field.isValid.custom(
118
- {
119
- ...data,
120
- [ id ]: [ undefined, '', null ].includes( newValue )
121
- ? undefined
122
- : Number( newValue ),
123
- },
124
- field
125
- );
122
+ onValidate={ ( newValue: any ) => {
123
+ const message = field.isValid?.custom?.(
124
+ {
125
+ ...data,
126
+ [ id ]: [ undefined, '', null ].includes( newValue )
127
+ ? undefined
128
+ : Number( newValue ),
129
+ },
130
+ field
131
+ );
132
+
133
+ if ( message ) {
134
+ setCustomValidity( {
135
+ type: 'invalid',
136
+ message,
137
+ } );
138
+ return;
126
139
  }
127
140
 
128
- return null;
141
+ setCustomValidity( undefined );
129
142
  } }
143
+ customValidity={ customValidity }
130
144
  label={ label }
131
145
  help={ description }
132
146
  value={ value }
@@ -2,7 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { privateApis } from '@wordpress/components';
5
- import { useCallback } from '@wordpress/element';
5
+ import { useCallback, useState } from '@wordpress/element';
6
6
 
7
7
  /**
8
8
  * Internal dependencies
@@ -20,6 +20,12 @@ export default function Text< Item >( {
20
20
  }: DataFormControlProps< Item > ) {
21
21
  const { id, label, placeholder, description } = field;
22
22
  const value = field.getValue( { item: data } );
23
+ const [ customValidity, setCustomValidity ] =
24
+ useState<
25
+ React.ComponentProps<
26
+ typeof ValidatedTextControl
27
+ >[ 'customValidity' ]
28
+ >( undefined );
23
29
 
24
30
  const onChangeControl = useCallback(
25
31
  ( newValue: string ) =>
@@ -32,19 +38,26 @@ export default function Text< Item >( {
32
38
  return (
33
39
  <ValidatedTextControl
34
40
  required={ !! field.isValid?.required }
35
- customValidator={ ( newValue: any ) => {
36
- if ( field.isValid?.custom ) {
37
- return field.isValid.custom(
38
- {
39
- ...data,
40
- [ id ]: newValue,
41
- },
42
- field
43
- );
41
+ onValidate={ ( newValue: any ) => {
42
+ const message = field.isValid?.custom?.(
43
+ {
44
+ ...data,
45
+ [ id ]: newValue,
46
+ },
47
+ field
48
+ );
49
+
50
+ if ( message ) {
51
+ setCustomValidity( {
52
+ type: 'invalid',
53
+ message,
54
+ } );
55
+ return;
44
56
  }
45
57
 
46
- return null;
58
+ setCustomValidity( undefined );
47
59
  } }
60
+ customValidity={ customValidity }
48
61
  label={ label }
49
62
  placeholder={ placeholder }
50
63
  value={ value ?? '' }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ __experimentalVStack as VStack,
6
+ __experimentalHStack as HStack,
7
+ __experimentalHeading as Heading,
8
+ __experimentalSpacer as Spacer,
9
+ Dropdown,
10
+ Button,
11
+ } from '@wordpress/components';
12
+ import { sprintf, __, _x } from '@wordpress/i18n';
13
+ import { useMemo } from '@wordpress/element';
14
+ import { closeSmall } from '@wordpress/icons';
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ import type { Form, FormField, NormalizedField } from '../../types';
20
+ import { DataFormLayout } from '../data-form-layout';
21
+ import { isCombinedField } from '../is-combined-field';
22
+ import { DEFAULT_LAYOUT } from '../../normalize-form-fields';
23
+
24
+ function DropdownHeader( {
25
+ title,
26
+ onClose,
27
+ }: {
28
+ title?: string;
29
+ onClose: () => void;
30
+ } ) {
31
+ return (
32
+ <VStack
33
+ className="dataforms-layouts-panel__dropdown-header"
34
+ spacing={ 4 }
35
+ >
36
+ <HStack alignment="center">
37
+ { title && (
38
+ <Heading level={ 2 } size={ 13 }>
39
+ { title }
40
+ </Heading>
41
+ ) }
42
+ <Spacer />
43
+ { onClose && (
44
+ <Button
45
+ label={ __( 'Close' ) }
46
+ icon={ closeSmall }
47
+ onClick={ onClose }
48
+ size="small"
49
+ />
50
+ ) }
51
+ </HStack>
52
+ </VStack>
53
+ );
54
+ }
55
+
56
+ function PanelDropdown< Item >( {
57
+ fieldDefinition,
58
+ popoverAnchor,
59
+ labelPosition = 'side',
60
+ data,
61
+ onChange,
62
+ field,
63
+ }: {
64
+ fieldDefinition: NormalizedField< Item >;
65
+ popoverAnchor: HTMLElement | null;
66
+ labelPosition: 'side' | 'top' | 'none';
67
+ data: Item;
68
+ onChange: ( value: any ) => void;
69
+ field: FormField;
70
+ } ) {
71
+ const fieldLabel = isCombinedField( field )
72
+ ? field.label
73
+ : fieldDefinition?.label;
74
+
75
+ const form: Form = useMemo(
76
+ (): Form => ( {
77
+ layout: DEFAULT_LAYOUT,
78
+ fields: isCombinedField( field )
79
+ ? field.children
80
+ : // If not explicit children return the field id itself.
81
+ [ { id: field.id } ],
82
+ } ),
83
+ [ field ]
84
+ );
85
+
86
+ // Memoize popoverProps to avoid returning a new object every time.
87
+ const popoverProps = useMemo(
88
+ () => ( {
89
+ // Anchor the popover to the middle of the entire row so that it doesn't
90
+ // move around when the label changes.
91
+ anchor: popoverAnchor,
92
+ placement: 'left-start',
93
+ offset: 36,
94
+ shift: true,
95
+ } ),
96
+ [ popoverAnchor ]
97
+ );
98
+
99
+ return (
100
+ <Dropdown
101
+ contentClassName="dataforms-layouts-panel__field-dropdown"
102
+ popoverProps={ popoverProps }
103
+ focusOnMount
104
+ toggleProps={ {
105
+ size: 'compact',
106
+ variant: 'tertiary',
107
+ tooltipPosition: 'middle left',
108
+ } }
109
+ renderToggle={ ( { isOpen, onToggle } ) => (
110
+ <Button
111
+ className="dataforms-layouts-panel__field-control"
112
+ size="compact"
113
+ variant={
114
+ [ 'none', 'top' ].includes( labelPosition )
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 }
125
+ disabled={ fieldDefinition.readOnly === true }
126
+ accessibleWhenDisabled
127
+ >
128
+ <fieldDefinition.render
129
+ item={ data }
130
+ field={ fieldDefinition }
131
+ />
132
+ </Button>
133
+ ) }
134
+ renderContent={ ( { onClose } ) => (
135
+ <>
136
+ <DropdownHeader title={ fieldLabel } onClose={ onClose } />
137
+ <DataFormLayout
138
+ data={ data }
139
+ form={ form }
140
+ onChange={ onChange }
141
+ >
142
+ { ( FieldLayout, nestedField ) => (
143
+ <FieldLayout
144
+ key={ nestedField.id }
145
+ data={ data }
146
+ field={ nestedField }
147
+ onChange={ onChange }
148
+ hideLabelFromVision={
149
+ ( form?.fields ?? [] ).length < 2
150
+ }
151
+ />
152
+ ) }
153
+ </DataFormLayout>
154
+ </>
155
+ ) }
156
+ />
157
+ );
158
+ }
159
+
160
+ export default PanelDropdown;
@@ -9,166 +9,22 @@ import clsx from 'clsx';
9
9
  import {
10
10
  __experimentalVStack as VStack,
11
11
  __experimentalHStack as HStack,
12
- __experimentalHeading as Heading,
13
- __experimentalSpacer as Spacer,
14
- Dropdown,
15
- Button,
16
12
  } from '@wordpress/components';
17
- import { sprintf, __, _x } from '@wordpress/i18n';
18
- import { useState, useMemo, useContext } from '@wordpress/element';
19
- import { closeSmall } from '@wordpress/icons';
13
+ import { useState, useContext } from '@wordpress/element';
20
14
 
21
15
  /**
22
16
  * Internal dependencies
23
17
  */
24
18
  import type {
25
- Form,
26
- FormField,
27
19
  FieldLayoutProps,
28
20
  NormalizedPanelLayout,
29
- NormalizedField,
30
21
  SimpleFormField,
31
22
  } from '../../types';
32
23
  import DataFormContext from '../../components/dataform-context';
33
- import { DataFormLayout } from '../data-form-layout';
34
24
  import { isCombinedField } from '../is-combined-field';
35
- import { DEFAULT_LAYOUT, normalizeLayout } from '../../normalize-form-fields';
36
-
37
- function DropdownHeader( {
38
- title,
39
- onClose,
40
- }: {
41
- title?: string;
42
- onClose: () => void;
43
- } ) {
44
- return (
45
- <VStack
46
- className="dataforms-layouts-panel__dropdown-header"
47
- spacing={ 4 }
48
- >
49
- <HStack alignment="center">
50
- { title && (
51
- <Heading level={ 2 } size={ 13 }>
52
- { title }
53
- </Heading>
54
- ) }
55
- <Spacer />
56
- { onClose && (
57
- <Button
58
- label={ __( 'Close' ) }
59
- icon={ closeSmall }
60
- onClick={ onClose }
61
- size="small"
62
- />
63
- ) }
64
- </HStack>
65
- </VStack>
66
- );
67
- }
68
-
69
- function PanelDropdown< Item >( {
70
- fieldDefinition,
71
- popoverAnchor,
72
- labelPosition = 'side',
73
- data,
74
- onChange,
75
- field,
76
- }: {
77
- fieldDefinition: NormalizedField< Item >;
78
- popoverAnchor: HTMLElement | null;
79
- labelPosition: 'side' | 'top' | 'none';
80
- data: Item;
81
- onChange: ( value: any ) => void;
82
- field: FormField;
83
- } ) {
84
- const fieldLabel = isCombinedField( field )
85
- ? field.label
86
- : fieldDefinition?.label;
87
-
88
- const form: Form = useMemo(
89
- (): Form => ( {
90
- layout: DEFAULT_LAYOUT,
91
- fields: isCombinedField( field )
92
- ? field.children
93
- : // If not explicit children return the field id itself.
94
- [ { id: field.id } ],
95
- } ),
96
- [ field ]
97
- );
98
-
99
- // Memoize popoverProps to avoid returning a new object every time.
100
- const popoverProps = useMemo(
101
- () => ( {
102
- // Anchor the popover to the middle of the entire row so that it doesn't
103
- // move around when the label changes.
104
- anchor: popoverAnchor,
105
- placement: 'left-start',
106
- offset: 36,
107
- shift: true,
108
- } ),
109
- [ popoverAnchor ]
110
- );
111
-
112
- return (
113
- <Dropdown
114
- contentClassName="dataforms-layouts-panel__field-dropdown"
115
- popoverProps={ popoverProps }
116
- focusOnMount
117
- toggleProps={ {
118
- size: 'compact',
119
- variant: 'tertiary',
120
- tooltipPosition: 'middle left',
121
- } }
122
- renderToggle={ ( { isOpen, onToggle } ) => (
123
- <Button
124
- className="dataforms-layouts-panel__field-control"
125
- size="compact"
126
- variant={
127
- [ 'none', 'top' ].includes( labelPosition )
128
- ? 'link'
129
- : 'tertiary'
130
- }
131
- aria-expanded={ isOpen }
132
- aria-label={ sprintf(
133
- // translators: %s: Field name.
134
- _x( 'Edit %s', 'field' ),
135
- fieldLabel || ''
136
- ) }
137
- onClick={ onToggle }
138
- disabled={ fieldDefinition.readOnly === true }
139
- accessibleWhenDisabled
140
- >
141
- <fieldDefinition.render
142
- item={ data }
143
- field={ fieldDefinition }
144
- />
145
- </Button>
146
- ) }
147
- renderContent={ ( { onClose } ) => (
148
- <>
149
- <DropdownHeader title={ fieldLabel } onClose={ onClose } />
150
- <DataFormLayout
151
- data={ data }
152
- form={ form }
153
- onChange={ onChange }
154
- >
155
- { ( FieldLayout, nestedField ) => (
156
- <FieldLayout
157
- key={ nestedField.id }
158
- data={ data }
159
- field={ nestedField }
160
- onChange={ onChange }
161
- hideLabelFromVision={
162
- ( form?.fields ?? [] ).length < 2
163
- }
164
- />
165
- ) }
166
- </DataFormLayout>
167
- </>
168
- ) }
169
- />
170
- );
171
- }
25
+ import { normalizeLayout } from '../../normalize-form-fields';
26
+ import PanelDropdown from './dropdown';
27
+ import PanelModal from './modal';
172
28
 
173
29
  export default function FormPanelField< Item >( {
174
30
  data,
@@ -192,6 +48,7 @@ export default function FormPanelField< Item >( {
192
48
  typeof simpleChildren[ 0 ] === 'string'
193
49
  ? simpleChildren[ 0 ]
194
50
  : simpleChildren[ 0 ].id;
51
+
195
52
  return _field.id === firstChildFieldId;
196
53
  }
197
54
 
@@ -222,6 +79,26 @@ export default function FormPanelField< Item >( {
222
79
  ? field.label
223
80
  : fieldDefinition?.label;
224
81
 
82
+ const renderedControl =
83
+ layout.openAs === 'modal' ? (
84
+ <PanelModal
85
+ field={ field }
86
+ fieldDefinition={ fieldDefinition }
87
+ data={ data }
88
+ onChange={ onChange }
89
+ labelPosition={ labelPosition }
90
+ />
91
+ ) : (
92
+ <PanelDropdown
93
+ field={ field }
94
+ popoverAnchor={ popoverAnchor }
95
+ fieldDefinition={ fieldDefinition }
96
+ data={ data }
97
+ onChange={ onChange }
98
+ labelPosition={ labelPosition }
99
+ />
100
+ );
101
+
225
102
  if ( labelPosition === 'top' ) {
226
103
  return (
227
104
  <VStack className="dataforms-layouts-panel__field" spacing={ 0 }>
@@ -232,14 +109,7 @@ export default function FormPanelField< Item >( {
232
109
  { fieldLabel }
233
110
  </div>
234
111
  <div className="dataforms-layouts-panel__field-control">
235
- <PanelDropdown
236
- field={ field }
237
- popoverAnchor={ popoverAnchor }
238
- fieldDefinition={ fieldDefinition }
239
- data={ data }
240
- onChange={ onChange }
241
- labelPosition={ labelPosition }
242
- />
112
+ { renderedControl }
243
113
  </div>
244
114
  </VStack>
245
115
  );
@@ -248,14 +118,7 @@ export default function FormPanelField< Item >( {
248
118
  if ( labelPosition === 'none' ) {
249
119
  return (
250
120
  <div className="dataforms-layouts-panel__field">
251
- <PanelDropdown
252
- field={ field }
253
- popoverAnchor={ popoverAnchor }
254
- fieldDefinition={ fieldDefinition }
255
- data={ data }
256
- onChange={ onChange }
257
- labelPosition={ labelPosition }
258
- />
121
+ { renderedControl }
259
122
  </div>
260
123
  );
261
124
  }
@@ -268,14 +131,7 @@ export default function FormPanelField< Item >( {
268
131
  >
269
132
  <div className={ labelClassName }>{ fieldLabel }</div>
270
133
  <div className="dataforms-layouts-panel__field-control">
271
- <PanelDropdown
272
- field={ field }
273
- popoverAnchor={ popoverAnchor }
274
- fieldDefinition={ fieldDefinition }
275
- data={ data }
276
- onChange={ onChange }
277
- labelPosition={ labelPosition }
278
- />
134
+ { renderedControl }
279
135
  </div>
280
136
  </HStack>
281
137
  );