@wordpress/dataviews 4.8.0 → 4.9.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 (189) hide show
  1. package/CHANGELOG.md +7 -2
  2. package/README.md +206 -17
  3. package/build/components/dataform/index.js +20 -8
  4. package/build/components/dataform/index.js.map +1 -1
  5. package/build/components/dataform-context/index.js +33 -0
  6. package/build/components/dataform-context/index.js.map +1 -0
  7. package/build/components/dataviews/index.js +3 -7
  8. package/build/components/dataviews/index.js.map +1 -1
  9. package/build/components/dataviews-context/index.js +1 -2
  10. package/build/components/dataviews-context/index.js.map +1 -1
  11. package/build/components/dataviews-filters/index.js +49 -31
  12. package/build/components/dataviews-filters/index.js.map +1 -1
  13. package/build/components/dataviews-item-actions/index.js +46 -20
  14. package/build/components/dataviews-item-actions/index.js.map +1 -1
  15. package/build/components/dataviews-layout/index.js +1 -3
  16. package/build/components/dataviews-layout/index.js.map +1 -1
  17. package/build/components/dataviews-view-config/index.js +4 -15
  18. package/build/components/dataviews-view-config/index.js.map +1 -1
  19. package/build/dataforms-layouts/data-form-layout.js +59 -0
  20. package/build/dataforms-layouts/data-form-layout.js.map +1 -0
  21. package/build/dataforms-layouts/index.js +4 -4
  22. package/build/dataforms-layouts/index.js.map +1 -1
  23. package/build/dataforms-layouts/is-combined-field.js +14 -0
  24. package/build/dataforms-layouts/is-combined-field.js.map +1 -0
  25. package/build/dataforms-layouts/panel/index.js +157 -72
  26. package/build/dataforms-layouts/panel/index.js.map +1 -1
  27. package/build/dataforms-layouts/regular/index.js +85 -19
  28. package/build/dataforms-layouts/regular/index.js.map +1 -1
  29. package/build/dataviews-layouts/grid/index.js +9 -9
  30. package/build/dataviews-layouts/grid/index.js.map +1 -1
  31. package/build/dataviews-layouts/grid/{density-picker.js → preview-size-picker.js} +40 -24
  32. package/build/dataviews-layouts/grid/preview-size-picker.js.map +1 -0
  33. package/build/dataviews-layouts/index.js +6 -2
  34. package/build/dataviews-layouts/index.js.map +1 -1
  35. package/build/dataviews-layouts/list/index.js +3 -2
  36. package/build/dataviews-layouts/list/index.js.map +1 -1
  37. package/build/dataviews-layouts/table/density-picker.js +51 -0
  38. package/build/dataviews-layouts/table/density-picker.js.map +1 -0
  39. package/build/dataviews-layouts/table/index.js +4 -1
  40. package/build/dataviews-layouts/table/index.js.map +1 -1
  41. package/build/normalize-fields.js +0 -21
  42. package/build/normalize-fields.js.map +1 -1
  43. package/build/normalize-form-fields.js +36 -0
  44. package/build/normalize-form-fields.js.map +1 -0
  45. package/build/types.js.map +1 -1
  46. package/build/validation.js.map +1 -1
  47. package/build-module/components/dataform/index.js +20 -8
  48. package/build-module/components/dataform/index.js.map +1 -1
  49. package/build-module/components/dataform-context/index.js +25 -0
  50. package/build-module/components/dataform-context/index.js.map +1 -0
  51. package/build-module/components/dataviews/index.js +4 -8
  52. package/build-module/components/dataviews/index.js.map +1 -1
  53. package/build-module/components/dataviews-context/index.js +1 -2
  54. package/build-module/components/dataviews-context/index.js.map +1 -1
  55. package/build-module/components/dataviews-filters/index.js +50 -32
  56. package/build-module/components/dataviews-filters/index.js.map +1 -1
  57. package/build-module/components/dataviews-item-actions/index.js +46 -20
  58. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  59. package/build-module/components/dataviews-layout/index.js +1 -3
  60. package/build-module/components/dataviews-layout/index.js.map +1 -1
  61. package/build-module/components/dataviews-view-config/index.js +5 -16
  62. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  63. package/build-module/dataforms-layouts/data-form-layout.js +52 -0
  64. package/build-module/dataforms-layouts/data-form-layout.js.map +1 -0
  65. package/build-module/dataforms-layouts/index.js +7 -7
  66. package/build-module/dataforms-layouts/index.js.map +1 -1
  67. package/build-module/dataforms-layouts/is-combined-field.js +8 -0
  68. package/build-module/dataforms-layouts/is-combined-field.js.map +1 -0
  69. package/build-module/dataforms-layouts/panel/index.js +157 -71
  70. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  71. package/build-module/dataforms-layouts/regular/index.js +87 -20
  72. package/build-module/dataforms-layouts/regular/index.js.map +1 -1
  73. package/build-module/dataviews-layouts/grid/index.js +9 -9
  74. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  75. package/build-module/dataviews-layouts/grid/{density-picker.js → preview-size-picker.js} +38 -24
  76. package/build-module/dataviews-layouts/grid/preview-size-picker.js.map +1 -0
  77. package/build-module/dataviews-layouts/index.js +6 -2
  78. package/build-module/dataviews-layouts/index.js.map +1 -1
  79. package/build-module/dataviews-layouts/list/index.js +3 -2
  80. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  81. package/build-module/dataviews-layouts/table/density-picker.js +43 -0
  82. package/build-module/dataviews-layouts/table/density-picker.js.map +1 -0
  83. package/build-module/dataviews-layouts/table/index.js +4 -1
  84. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  85. package/build-module/normalize-fields.js +0 -20
  86. package/build-module/normalize-fields.js.map +1 -1
  87. package/build-module/normalize-form-fields.js +30 -0
  88. package/build-module/normalize-form-fields.js.map +1 -0
  89. package/build-module/types.js.map +1 -1
  90. package/build-module/validation.js.map +1 -1
  91. package/build-style/style-rtl.css +54 -13
  92. package/build-style/style.css +54 -13
  93. package/build-types/components/dataform/index.d.ts +1 -1
  94. package/build-types/components/dataform/index.d.ts.map +1 -1
  95. package/build-types/components/dataform/stories/index.story.d.ts +18 -7
  96. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  97. package/build-types/components/dataform-context/index.d.ts +13 -0
  98. package/build-types/components/dataform-context/index.d.ts.map +1 -0
  99. package/build-types/components/dataviews/index.d.ts.map +1 -1
  100. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  101. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  102. package/build-types/components/dataviews-context/index.d.ts +0 -1
  103. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  104. package/build-types/components/dataviews-filters/index.d.ts +1 -1
  105. package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
  106. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  107. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  108. package/build-types/components/dataviews-view-config/index.d.ts +1 -3
  109. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  110. package/build-types/dataforms-layouts/data-form-layout.d.ts +16 -0
  111. package/build-types/dataforms-layouts/data-form-layout.d.ts.map +1 -0
  112. package/build-types/dataforms-layouts/index.d.ts +3 -3
  113. package/build-types/dataforms-layouts/index.d.ts.map +1 -1
  114. package/build-types/dataforms-layouts/is-combined-field.d.ts +6 -0
  115. package/build-types/dataforms-layouts/is-combined-field.d.ts.map +1 -0
  116. package/build-types/dataforms-layouts/panel/index.d.ts +5 -2
  117. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  118. package/build-types/dataforms-layouts/regular/index.d.ts +5 -2
  119. package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -1
  120. package/build-types/dataviews-layouts/grid/index.d.ts +1 -1
  121. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  122. package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts +3 -0
  123. package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts.map +1 -0
  124. package/build-types/dataviews-layouts/index.d.ts +5 -0
  125. package/build-types/dataviews-layouts/index.d.ts.map +1 -1
  126. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  127. package/build-types/dataviews-layouts/table/density-picker.d.ts +2 -0
  128. package/build-types/dataviews-layouts/table/density-picker.d.ts.map +1 -0
  129. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  130. package/build-types/normalize-fields.d.ts +1 -9
  131. package/build-types/normalize-fields.d.ts.map +1 -1
  132. package/build-types/normalize-form-fields.d.ts +12 -0
  133. package/build-types/normalize-form-fields.d.ts.map +1 -0
  134. package/build-types/types.d.ts +31 -22
  135. package/build-types/types.d.ts.map +1 -1
  136. package/build-types/validation.d.ts +1 -1
  137. package/build-types/validation.d.ts.map +1 -1
  138. package/package.json +2 -2
  139. package/src/components/dataform/index.tsx +22 -5
  140. package/src/components/dataform/stories/index.story.tsx +88 -49
  141. package/src/components/dataform-context/index.tsx +30 -0
  142. package/src/components/dataviews/index.tsx +2 -6
  143. package/src/components/dataviews/stories/fixtures.tsx +1 -0
  144. package/src/components/dataviews/stories/index.story.tsx +16 -3
  145. package/src/components/dataviews-context/index.ts +0 -2
  146. package/src/components/dataviews-filters/index.tsx +73 -38
  147. package/src/components/dataviews-item-actions/index.tsx +73 -25
  148. package/src/components/dataviews-layout/index.tsx +0 -2
  149. package/src/components/dataviews-view-config/index.tsx +7 -23
  150. package/src/dataforms-layouts/data-form-layout.tsx +87 -0
  151. package/src/dataforms-layouts/index.tsx +7 -7
  152. package/src/dataforms-layouts/is-combined-field.ts +10 -0
  153. package/src/dataforms-layouts/panel/index.tsx +192 -101
  154. package/src/dataforms-layouts/panel/style.scss +4 -0
  155. package/src/dataforms-layouts/regular/index.tsx +101 -37
  156. package/src/dataforms-layouts/regular/style.scss +30 -0
  157. package/src/dataviews-layouts/grid/index.tsx +10 -8
  158. package/src/dataviews-layouts/grid/{density-picker.tsx → preview-size-picker.tsx} +39 -26
  159. package/src/dataviews-layouts/grid/style.scss +3 -1
  160. package/src/dataviews-layouts/index.ts +4 -0
  161. package/src/dataviews-layouts/list/index.tsx +31 -27
  162. package/src/dataviews-layouts/table/density-picker.tsx +57 -0
  163. package/src/dataviews-layouts/table/index.tsx +12 -2
  164. package/src/dataviews-layouts/table/style.scss +32 -0
  165. package/src/normalize-fields.ts +1 -33
  166. package/src/normalize-form-fields.ts +42 -0
  167. package/src/style.scss +1 -1
  168. package/src/types.ts +36 -21
  169. package/src/validation.ts +1 -1
  170. package/tsconfig.tsbuildinfo +1 -1
  171. package/build/components/dataform-combined-edit/index.js +0 -73
  172. package/build/components/dataform-combined-edit/index.js.map +0 -1
  173. package/build/dataforms-layouts/get-visible-fields.js +0 -21
  174. package/build/dataforms-layouts/get-visible-fields.js.map +0 -1
  175. package/build/dataviews-layouts/grid/density-picker.js.map +0 -1
  176. package/build-module/components/dataform-combined-edit/index.js +0 -66
  177. package/build-module/components/dataform-combined-edit/index.js.map +0 -1
  178. package/build-module/dataforms-layouts/get-visible-fields.js +0 -14
  179. package/build-module/dataforms-layouts/get-visible-fields.js.map +0 -1
  180. package/build-module/dataviews-layouts/grid/density-picker.js.map +0 -1
  181. package/build-types/components/dataform-combined-edit/index.d.ts +0 -7
  182. package/build-types/components/dataform-combined-edit/index.d.ts.map +0 -1
  183. package/build-types/dataforms-layouts/get-visible-fields.d.ts +0 -3
  184. package/build-types/dataforms-layouts/get-visible-fields.d.ts.map +0 -1
  185. package/build-types/dataviews-layouts/grid/density-picker.d.ts +0 -5
  186. package/build-types/dataviews-layouts/grid/density-picker.d.ts.map +0 -1
  187. package/src/components/dataform-combined-edit/index.tsx +0 -69
  188. package/src/components/dataform-combined-edit/style.scss +0 -16
  189. package/src/dataforms-layouts/get-visible-fields.ts +0 -29
@@ -35,7 +35,6 @@ import { useInstanceId } from '@wordpress/compose';
35
35
  */
36
36
  import {
37
37
  SORTING_DIRECTIONS,
38
- LAYOUT_GRID,
39
38
  LAYOUT_TABLE,
40
39
  sortIcons,
41
40
  sortLabels,
@@ -49,7 +48,6 @@ import {
49
48
  import type { SupportedLayouts, View, Field } from '../../types';
50
49
  import DataViewsContext from '../dataviews-context';
51
50
  import { unlock } from '../../lock-unlock';
52
- import DensityPicker from '../../dataviews-layouts/grid/density-picker';
53
51
 
54
52
  const { Menu } = unlock( componentsPrivateApis );
55
53
 
@@ -512,19 +510,15 @@ function SettingsSection( {
512
510
  );
513
511
  }
514
512
 
515
- function DataviewsViewConfigDropdown( {
516
- density,
517
- setDensity,
518
- }: {
519
- density: number;
520
- setDensity: React.Dispatch< React.SetStateAction< number > >;
521
- } ) {
513
+ function DataviewsViewConfigDropdown() {
522
514
  const { view } = useContext( DataViewsContext );
523
515
  const popoverId = useInstanceId(
524
516
  _DataViewsViewConfig,
525
517
  'dataviews-view-config-dropdown'
526
518
  );
527
-
519
+ const activeLayout = VIEW_LAYOUTS.find(
520
+ ( layout ) => layout.type === view.type
521
+ );
528
522
  return (
529
523
  <Dropdown
530
524
  popoverProps={ {
@@ -551,11 +545,8 @@ function DataviewsViewConfigDropdown( {
551
545
  <SortFieldControl />
552
546
  <SortDirectionControl />
553
547
  </HStack>
554
- { view.type === LAYOUT_GRID && (
555
- <DensityPicker
556
- density={ density }
557
- setDensity={ setDensity }
558
- />
548
+ { !! activeLayout?.viewConfigOptions && (
549
+ <activeLayout.viewConfigOptions />
559
550
  ) }
560
551
  <ItemsPerPageControl />
561
552
  </SettingsSection>
@@ -570,21 +561,14 @@ function DataviewsViewConfigDropdown( {
570
561
  }
571
562
 
572
563
  function _DataViewsViewConfig( {
573
- density,
574
- setDensity,
575
564
  defaultLayouts = { list: {}, grid: {}, table: {} },
576
565
  }: {
577
- density: number;
578
- setDensity: React.Dispatch< React.SetStateAction< number > >;
579
566
  defaultLayouts?: SupportedLayouts;
580
567
  } ) {
581
568
  return (
582
569
  <>
583
570
  <ViewTypeMenu defaultLayouts={ defaultLayouts } />
584
- <DataviewsViewConfigDropdown
585
- density={ density }
586
- setDensity={ setDensity }
587
- />
571
+ <DataviewsViewConfigDropdown />
588
572
  </>
589
573
  );
590
574
  }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __experimentalVStack as VStack } from '@wordpress/components';
5
+ import { useContext, useMemo } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { Form, FormField, SimpleFormField } from '../types';
11
+ import { getFormFieldLayout } from './index';
12
+ import DataFormContext from '../components/dataform-context';
13
+ import { isCombinedField } from './is-combined-field';
14
+ import normalizeFormFields from '../normalize-form-fields';
15
+
16
+ export function DataFormLayout< Item >( {
17
+ data,
18
+ form,
19
+ onChange,
20
+ children,
21
+ }: {
22
+ data: Item;
23
+ form: Form;
24
+ onChange: ( value: any ) => void;
25
+ children?: (
26
+ FieldLayout: ( props: {
27
+ data: Item;
28
+ field: FormField;
29
+ onChange: ( value: any ) => void;
30
+ hideLabelFromVision?: boolean;
31
+ } ) => React.JSX.Element | null,
32
+ field: FormField
33
+ ) => React.JSX.Element;
34
+ } ) {
35
+ const { fields: fieldDefinitions } = useContext( DataFormContext );
36
+
37
+ function getFieldDefinition( field: SimpleFormField | string ) {
38
+ const fieldId = typeof field === 'string' ? field : field.id;
39
+
40
+ return fieldDefinitions.find(
41
+ ( fieldDefinition ) => fieldDefinition.id === fieldId
42
+ );
43
+ }
44
+
45
+ const normalizedFormFields = useMemo(
46
+ () => normalizeFormFields( form ),
47
+ [ form ]
48
+ );
49
+
50
+ return (
51
+ <VStack spacing={ 2 }>
52
+ { normalizedFormFields.map( ( formField ) => {
53
+ const FieldLayout = getFormFieldLayout( formField.layout )
54
+ ?.component;
55
+
56
+ if ( ! FieldLayout ) {
57
+ return null;
58
+ }
59
+
60
+ const fieldDefinition = ! isCombinedField( formField )
61
+ ? getFieldDefinition( formField )
62
+ : undefined;
63
+
64
+ if (
65
+ fieldDefinition &&
66
+ fieldDefinition.isVisible &&
67
+ ! fieldDefinition.isVisible( data )
68
+ ) {
69
+ return null;
70
+ }
71
+
72
+ if ( children ) {
73
+ return children( FieldLayout, formField );
74
+ }
75
+
76
+ return (
77
+ <FieldLayout
78
+ key={ formField.id }
79
+ data={ data }
80
+ field={ formField }
81
+ onChange={ onChange }
82
+ />
83
+ );
84
+ } ) }
85
+ </VStack>
86
+ );
87
+ }
@@ -1,20 +1,20 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import FormRegular from './regular';
5
- import FormPanel from './panel';
4
+ import FormRegularField from './regular';
5
+ import FormPanelField from './panel';
6
6
 
7
- const FORM_LAYOUTS = [
7
+ const FORM_FIELD_LAYOUTS = [
8
8
  {
9
9
  type: 'regular',
10
- component: FormRegular,
10
+ component: FormRegularField,
11
11
  },
12
12
  {
13
13
  type: 'panel',
14
- component: FormPanel,
14
+ component: FormPanelField,
15
15
  },
16
16
  ];
17
17
 
18
- export function getFormLayout( type: string ) {
19
- return FORM_LAYOUTS.find( ( layout ) => layout.type === type );
18
+ export function getFormFieldLayout( type: string ) {
19
+ return FORM_FIELD_LAYOUTS.find( ( layout ) => layout.type === type );
20
20
  }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { FormField, CombinedFormField } from '../types';
5
+
6
+ export function isCombinedField(
7
+ field: FormField
8
+ ): field is CombinedFormField {
9
+ return ( field as CombinedFormField ).children !== undefined;
10
+ }
@@ -9,29 +9,29 @@ import {
9
9
  Dropdown,
10
10
  Button,
11
11
  } from '@wordpress/components';
12
- import { useState, useMemo } from '@wordpress/element';
13
12
  import { sprintf, __, _x } from '@wordpress/i18n';
13
+ import { useState, useMemo, useContext } from '@wordpress/element';
14
14
  import { closeSmall } from '@wordpress/icons';
15
15
 
16
16
  /**
17
17
  * Internal dependencies
18
18
  */
19
- import { normalizeFields } from '../../normalize-fields';
20
- import { getVisibleFields } from '../get-visible-fields';
21
- import type { DataFormProps, NormalizedField } from '../../types';
22
- import FormFieldVisibility from '../../components/form-field-visibility';
23
-
24
- interface FormFieldProps< Item > {
25
- data: Item;
26
- field: NormalizedField< Item >;
27
- onChange: ( value: any ) => void;
28
- }
19
+ import type {
20
+ Form,
21
+ FormField,
22
+ FieldLayoutProps,
23
+ NormalizedField,
24
+ SimpleFormField,
25
+ } from '../../types';
26
+ import DataFormContext from '../../components/dataform-context';
27
+ import { DataFormLayout } from '../data-form-layout';
28
+ import { isCombinedField } from '../is-combined-field';
29
29
 
30
30
  function DropdownHeader( {
31
31
  title,
32
32
  onClose,
33
33
  }: {
34
- title: string;
34
+ title?: string;
35
35
  onClose: () => void;
36
36
  } ) {
37
37
  return (
@@ -40,9 +40,11 @@ function DropdownHeader( {
40
40
  spacing={ 4 }
41
41
  >
42
42
  <HStack alignment="center">
43
- <Heading level={ 2 } size={ 13 }>
44
- { title }
45
- </Heading>
43
+ { title && (
44
+ <Heading level={ 2 } size={ 13 }>
45
+ { title }
46
+ </Heading>
47
+ ) }
46
48
  <Spacer />
47
49
  { onClose && (
48
50
  <Button
@@ -57,16 +59,45 @@ function DropdownHeader( {
57
59
  );
58
60
  }
59
61
 
60
- function FormField< Item >( {
62
+ function PanelDropdown< Item >( {
63
+ fieldDefinition,
64
+ popoverAnchor,
65
+ labelPosition = 'side',
61
66
  data,
62
- field,
63
67
  onChange,
64
- }: FormFieldProps< Item > ) {
65
- // Use internal state instead of a ref to make sure that the component
66
- // re-renders when the popover's anchor updates.
67
- const [ popoverAnchor, setPopoverAnchor ] = useState< HTMLElement | null >(
68
- null
69
- );
68
+ field,
69
+ }: {
70
+ fieldDefinition: NormalizedField< Item >;
71
+ popoverAnchor: HTMLElement | null;
72
+ labelPosition: 'side' | 'top' | 'none';
73
+ data: Item;
74
+ onChange: ( value: any ) => void;
75
+ field: FormField;
76
+ } ) {
77
+ const fieldLabel = isCombinedField( field )
78
+ ? field.label
79
+ : fieldDefinition?.label;
80
+ const form = useMemo( () => {
81
+ if ( isCombinedField( field ) ) {
82
+ return {
83
+ type: 'regular' as const,
84
+ fields: field.children.map( ( child ) => {
85
+ if ( typeof child === 'string' ) {
86
+ return {
87
+ id: child,
88
+ };
89
+ }
90
+ return child;
91
+ } ),
92
+ };
93
+ }
94
+ // If not explicit children return the field id itself.
95
+ return {
96
+ type: 'regular' as const,
97
+ fields: [ { id: field.id } ],
98
+ };
99
+ }, [ field ] );
100
+
70
101
  // Memoize popoverProps to avoid returning a new object every time.
71
102
  const popoverProps = useMemo(
72
103
  () => ( {
@@ -81,95 +112,155 @@ function FormField< Item >( {
81
112
  );
82
113
 
83
114
  return (
84
- <HStack
85
- ref={ setPopoverAnchor }
86
- className="dataforms-layouts-panel__field"
87
- >
88
- <div className="dataforms-layouts-panel__field-label">
89
- { field.label }
90
- </div>
91
- <div>
92
- <Dropdown
93
- contentClassName="dataforms-layouts-panel__field-dropdown"
94
- popoverProps={ popoverProps }
95
- focusOnMount
96
- toggleProps={ {
97
- size: 'compact',
98
- variant: 'tertiary',
99
- tooltipPosition: 'middle left',
100
- } }
101
- renderToggle={ ( { isOpen, onToggle } ) => (
102
- <Button
103
- className="dataforms-layouts-panel__field-control"
104
- size="compact"
105
- variant="tertiary"
106
- aria-expanded={ isOpen }
107
- aria-label={ sprintf(
108
- // translators: %s: Field name.
109
- _x( 'Edit %s', 'field' ),
110
- field.label
111
- ) }
112
- onClick={ onToggle }
113
- >
114
- <field.render item={ data } />
115
- </Button>
115
+ <Dropdown
116
+ contentClassName="dataforms-layouts-panel__field-dropdown"
117
+ popoverProps={ popoverProps }
118
+ focusOnMount
119
+ toggleProps={ {
120
+ size: 'compact',
121
+ variant: 'tertiary',
122
+ tooltipPosition: 'middle left',
123
+ } }
124
+ renderToggle={ ( { isOpen, onToggle } ) => (
125
+ <Button
126
+ className="dataforms-layouts-panel__field-control"
127
+ size="compact"
128
+ variant={
129
+ [ 'none', 'top' ].includes( labelPosition )
130
+ ? 'link'
131
+ : 'tertiary'
132
+ }
133
+ aria-expanded={ isOpen }
134
+ aria-label={ sprintf(
135
+ // translators: %s: Field name.
136
+ _x( 'Edit %s', 'field' ),
137
+ fieldLabel
116
138
  ) }
117
- renderContent={ ( { onClose } ) => (
118
- <>
119
- <DropdownHeader
120
- title={ field.label }
121
- onClose={ onClose }
122
- />
123
- <field.Edit
124
- key={ field.id }
139
+ onClick={ onToggle }
140
+ >
141
+ <fieldDefinition.render item={ data } />
142
+ </Button>
143
+ ) }
144
+ renderContent={ ( { onClose } ) => (
145
+ <>
146
+ <DropdownHeader title={ fieldLabel } onClose={ onClose } />
147
+ <DataFormLayout
148
+ data={ data }
149
+ form={ form as Form }
150
+ onChange={ onChange }
151
+ >
152
+ { ( FieldLayout, nestedField ) => (
153
+ <FieldLayout
154
+ key={ nestedField.id }
125
155
  data={ data }
126
- field={ field }
156
+ field={ nestedField }
127
157
  onChange={ onChange }
128
- hideLabelFromVision
158
+ hideLabelFromVision={
159
+ ( form?.fields ?? [] ).length < 2
160
+ }
129
161
  />
130
- </>
131
- ) }
132
- />
133
- </div>
134
- </HStack>
162
+ ) }
163
+ </DataFormLayout>
164
+ </>
165
+ ) }
166
+ />
135
167
  );
136
168
  }
137
169
 
138
- export default function FormPanel< Item >( {
170
+ export default function FormPanelField< Item >( {
139
171
  data,
140
- fields,
141
- form,
172
+ field,
142
173
  onChange,
143
- }: DataFormProps< Item > ) {
144
- const visibleFields = useMemo(
145
- () =>
146
- normalizeFields(
147
- getVisibleFields< Item >(
148
- fields,
149
- form.fields,
150
- form.combinedFields
151
- )
152
- ),
153
- [ fields, form.fields, form.combinedFields ]
174
+ }: FieldLayoutProps< Item > ) {
175
+ const { fields } = useContext( DataFormContext );
176
+ const fieldDefinition = fields.find( ( fieldDef ) => {
177
+ // Default to the first child if it is a combined field.
178
+ if ( isCombinedField( field ) ) {
179
+ const children = field.children.filter(
180
+ ( child ): child is string | SimpleFormField =>
181
+ typeof child === 'string' || ! isCombinedField( child )
182
+ );
183
+ const firstChildFieldId =
184
+ typeof children[ 0 ] === 'string'
185
+ ? children[ 0 ]
186
+ : children[ 0 ].id;
187
+ return fieldDef.id === firstChildFieldId;
188
+ }
189
+ return fieldDef.id === field.id;
190
+ } );
191
+ const labelPosition = field.labelPosition ?? 'side';
192
+
193
+ // Use internal state instead of a ref to make sure that the component
194
+ // re-renders when the popover's anchor updates.
195
+ const [ popoverAnchor, setPopoverAnchor ] = useState< HTMLElement | null >(
196
+ null
154
197
  );
155
198
 
156
- return (
157
- <VStack spacing={ 2 }>
158
- { visibleFields.map( ( field ) => {
159
- return (
160
- <FormFieldVisibility
161
- key={ field.id }
162
- data={ data }
199
+ if ( ! fieldDefinition ) {
200
+ return null;
201
+ }
202
+
203
+ const fieldLabel = isCombinedField( field )
204
+ ? field.label
205
+ : fieldDefinition?.label;
206
+
207
+ if ( labelPosition === 'top' ) {
208
+ return (
209
+ <VStack className="dataforms-layouts-panel__field" spacing={ 0 }>
210
+ <div
211
+ className="dataforms-layouts-panel__field-label"
212
+ style={ { paddingBottom: 0 } }
213
+ >
214
+ { fieldLabel }
215
+ </div>
216
+ <div className="dataforms-layouts-panel__field-control">
217
+ <PanelDropdown
163
218
  field={ field }
164
- >
165
- <FormField
166
- data={ data }
167
- field={ field }
168
- onChange={ onChange }
169
- />
170
- </FormFieldVisibility>
171
- );
172
- } ) }
173
- </VStack>
219
+ popoverAnchor={ popoverAnchor }
220
+ fieldDefinition={ fieldDefinition }
221
+ data={ data }
222
+ onChange={ onChange }
223
+ labelPosition={ labelPosition }
224
+ />
225
+ </div>
226
+ </VStack>
227
+ );
228
+ }
229
+
230
+ if ( labelPosition === 'none' ) {
231
+ return (
232
+ <div className="dataforms-layouts-panel__field">
233
+ <PanelDropdown
234
+ field={ field }
235
+ popoverAnchor={ popoverAnchor }
236
+ fieldDefinition={ fieldDefinition }
237
+ data={ data }
238
+ onChange={ onChange }
239
+ labelPosition={ labelPosition }
240
+ />
241
+ </div>
242
+ );
243
+ }
244
+
245
+ // Defaults to label position side.
246
+ return (
247
+ <HStack
248
+ ref={ setPopoverAnchor }
249
+ className="dataforms-layouts-panel__field"
250
+ >
251
+ <div className="dataforms-layouts-panel__field-label">
252
+ { fieldLabel }
253
+ </div>
254
+ <div className="dataforms-layouts-panel__field-control">
255
+ <PanelDropdown
256
+ field={ field }
257
+ popoverAnchor={ popoverAnchor }
258
+ fieldDefinition={ fieldDefinition }
259
+ data={ data }
260
+ onChange={ onChange }
261
+ labelPosition={ labelPosition }
262
+ />
263
+ </div>
264
+ </HStack>
174
265
  );
175
266
  }
@@ -44,3 +44,7 @@
44
44
  .dataforms-layouts-panel__dropdown-header {
45
45
  margin-bottom: $grid-unit-20;
46
46
  }
47
+
48
+ .components-popover.components-dropdown__content.dataforms-layouts-panel__field-dropdown {
49
+ z-index: z-index(".components-popover.components-dropdown__content.dataforms-layouts-panel__field-dropdown");
50
+ }