@wordpress/dataviews 4.7.0 → 4.8.2-next.082ed6819.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 (211) hide show
  1. package/CHANGELOG.md +9 -2
  2. package/README.md +793 -97
  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 +10 -7
  8. package/build/components/dataviews/index.js.map +1 -1
  9. package/build/components/dataviews-context/index.js +2 -1
  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 +5 -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/components/form-field-visibility/index.js +32 -0
  20. package/build/components/form-field-visibility/index.js.map +1 -0
  21. package/build/dataforms-layouts/data-form-layout.js +59 -0
  22. package/build/dataforms-layouts/data-form-layout.js.map +1 -0
  23. package/build/dataforms-layouts/index.js +4 -4
  24. package/build/dataforms-layouts/index.js.map +1 -1
  25. package/build/dataforms-layouts/is-combined-field.js +14 -0
  26. package/build/dataforms-layouts/is-combined-field.js.map +1 -0
  27. package/build/dataforms-layouts/panel/index.js +158 -67
  28. package/build/dataforms-layouts/panel/index.js.map +1 -1
  29. package/build/dataforms-layouts/regular/index.js +86 -14
  30. package/build/dataforms-layouts/regular/index.js.map +1 -1
  31. package/build/dataviews-layouts/grid/index.js +18 -7
  32. package/build/dataviews-layouts/grid/index.js.map +1 -1
  33. package/build/dataviews-layouts/grid/{density-picker.js → preview-size-picker.js} +40 -24
  34. package/build/dataviews-layouts/grid/preview-size-picker.js.map +1 -0
  35. package/build/dataviews-layouts/index.js +6 -2
  36. package/build/dataviews-layouts/index.js.map +1 -1
  37. package/build/dataviews-layouts/list/index.js +3 -2
  38. package/build/dataviews-layouts/list/index.js.map +1 -1
  39. package/build/dataviews-layouts/table/density-picker.js +51 -0
  40. package/build/dataviews-layouts/table/density-picker.js.map +1 -0
  41. package/build/dataviews-layouts/table/index.js +26 -6
  42. package/build/dataviews-layouts/table/index.js.map +1 -1
  43. package/build/dataviews-layouts/utils/get-clickable-item-props.js +25 -0
  44. package/build/dataviews-layouts/utils/get-clickable-item-props.js.map +1 -0
  45. package/build/normalize-fields.js +16 -24
  46. package/build/normalize-fields.js.map +1 -1
  47. package/build/normalize-form-fields.js +36 -0
  48. package/build/normalize-form-fields.js.map +1 -0
  49. package/build/types.js.map +1 -1
  50. package/build/validation.js +9 -0
  51. package/build/validation.js.map +1 -1
  52. package/build-module/components/dataform/index.js +20 -8
  53. package/build-module/components/dataform/index.js.map +1 -1
  54. package/build-module/components/dataform-context/index.js +25 -0
  55. package/build-module/components/dataform-context/index.js.map +1 -0
  56. package/build-module/components/dataviews/index.js +11 -8
  57. package/build-module/components/dataviews/index.js.map +1 -1
  58. package/build-module/components/dataviews-context/index.js +2 -1
  59. package/build-module/components/dataviews-context/index.js.map +1 -1
  60. package/build-module/components/dataviews-filters/index.js +50 -32
  61. package/build-module/components/dataviews-filters/index.js.map +1 -1
  62. package/build-module/components/dataviews-item-actions/index.js +46 -20
  63. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  64. package/build-module/components/dataviews-layout/index.js +5 -3
  65. package/build-module/components/dataviews-layout/index.js.map +1 -1
  66. package/build-module/components/dataviews-view-config/index.js +5 -16
  67. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  68. package/build-module/components/form-field-visibility/index.js +26 -0
  69. package/build-module/components/form-field-visibility/index.js.map +1 -0
  70. package/build-module/dataforms-layouts/data-form-layout.js +52 -0
  71. package/build-module/dataforms-layouts/data-form-layout.js.map +1 -0
  72. package/build-module/dataforms-layouts/index.js +7 -7
  73. package/build-module/dataforms-layouts/index.js.map +1 -1
  74. package/build-module/dataforms-layouts/is-combined-field.js +8 -0
  75. package/build-module/dataforms-layouts/is-combined-field.js.map +1 -0
  76. package/build-module/dataforms-layouts/panel/index.js +157 -66
  77. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  78. package/build-module/dataforms-layouts/regular/index.js +87 -15
  79. package/build-module/dataforms-layouts/regular/index.js.map +1 -1
  80. package/build-module/dataviews-layouts/grid/index.js +18 -7
  81. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  82. package/build-module/dataviews-layouts/grid/{density-picker.js → preview-size-picker.js} +38 -24
  83. package/build-module/dataviews-layouts/grid/preview-size-picker.js.map +1 -0
  84. package/build-module/dataviews-layouts/index.js +6 -2
  85. package/build-module/dataviews-layouts/index.js.map +1 -1
  86. package/build-module/dataviews-layouts/list/index.js +3 -2
  87. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  88. package/build-module/dataviews-layouts/table/density-picker.js +43 -0
  89. package/build-module/dataviews-layouts/table/density-picker.js.map +1 -0
  90. package/build-module/dataviews-layouts/table/index.js +26 -6
  91. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  92. package/build-module/dataviews-layouts/utils/get-clickable-item-props.js +19 -0
  93. package/build-module/dataviews-layouts/utils/get-clickable-item-props.js.map +1 -0
  94. package/build-module/normalize-fields.js +15 -23
  95. package/build-module/normalize-fields.js.map +1 -1
  96. package/build-module/normalize-form-fields.js +30 -0
  97. package/build-module/normalize-form-fields.js.map +1 -0
  98. package/build-module/types.js.map +1 -1
  99. package/build-module/validation.js +9 -0
  100. package/build-module/validation.js.map +1 -1
  101. package/build-style/style-rtl.css +65 -10
  102. package/build-style/style.css +65 -10
  103. package/build-types/components/dataform/index.d.ts +1 -1
  104. package/build-types/components/dataform/index.d.ts.map +1 -1
  105. package/build-types/components/dataform/stories/index.story.d.ts +18 -7
  106. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  107. package/build-types/components/dataform-context/index.d.ts +13 -0
  108. package/build-types/components/dataform-context/index.d.ts.map +1 -0
  109. package/build-types/components/dataviews/index.d.ts +3 -1
  110. package/build-types/components/dataviews/index.d.ts.map +1 -1
  111. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  112. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  113. package/build-types/components/dataviews-context/index.d.ts +2 -1
  114. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  115. package/build-types/components/dataviews-filters/index.d.ts +1 -1
  116. package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
  117. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  118. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  119. package/build-types/components/dataviews-view-config/index.d.ts +1 -3
  120. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  121. package/build-types/components/form-field-visibility/index.d.ts +11 -0
  122. package/build-types/components/form-field-visibility/index.d.ts.map +1 -0
  123. package/build-types/dataforms-layouts/data-form-layout.d.ts +16 -0
  124. package/build-types/dataforms-layouts/data-form-layout.d.ts.map +1 -0
  125. package/build-types/dataforms-layouts/index.d.ts +3 -3
  126. package/build-types/dataforms-layouts/index.d.ts.map +1 -1
  127. package/build-types/dataforms-layouts/is-combined-field.d.ts +6 -0
  128. package/build-types/dataforms-layouts/is-combined-field.d.ts.map +1 -0
  129. package/build-types/dataforms-layouts/panel/index.d.ts +5 -2
  130. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  131. package/build-types/dataforms-layouts/regular/index.d.ts +5 -2
  132. package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -1
  133. package/build-types/dataviews-layouts/grid/index.d.ts +1 -1
  134. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  135. package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts +3 -0
  136. package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts.map +1 -0
  137. package/build-types/dataviews-layouts/index.d.ts +5 -0
  138. package/build-types/dataviews-layouts/index.d.ts.map +1 -1
  139. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  140. package/build-types/dataviews-layouts/table/density-picker.d.ts +2 -0
  141. package/build-types/dataviews-layouts/table/density-picker.d.ts.map +1 -0
  142. package/build-types/dataviews-layouts/table/index.d.ts +1 -1
  143. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  144. package/build-types/dataviews-layouts/utils/get-clickable-item-props.d.ts +14 -0
  145. package/build-types/dataviews-layouts/utils/get-clickable-item-props.d.ts.map +1 -0
  146. package/build-types/lock-unlock.d.ts +1 -1
  147. package/build-types/lock-unlock.d.ts.map +1 -1
  148. package/build-types/normalize-fields.d.ts +1 -9
  149. package/build-types/normalize-fields.d.ts.map +1 -1
  150. package/build-types/normalize-form-fields.d.ts +12 -0
  151. package/build-types/normalize-form-fields.d.ts.map +1 -0
  152. package/build-types/types.d.ts +37 -22
  153. package/build-types/types.d.ts.map +1 -1
  154. package/build-types/validation.d.ts +10 -1
  155. package/build-types/validation.d.ts.map +1 -1
  156. package/package.json +10 -10
  157. package/src/components/dataform/index.tsx +22 -5
  158. package/src/components/dataform/stories/index.story.tsx +105 -50
  159. package/src/components/dataform-context/index.tsx +30 -0
  160. package/src/components/dataviews/index.tsx +12 -7
  161. package/src/components/dataviews/stories/fixtures.tsx +1 -0
  162. package/src/components/dataviews/stories/index.story.tsx +16 -3
  163. package/src/components/dataviews/style.scss +9 -3
  164. package/src/components/dataviews-context/index.ts +4 -2
  165. package/src/components/dataviews-filters/index.tsx +73 -38
  166. package/src/components/dataviews-item-actions/index.tsx +73 -25
  167. package/src/components/dataviews-layout/index.tsx +4 -2
  168. package/src/components/dataviews-view-config/index.tsx +7 -23
  169. package/src/components/form-field-visibility/index.tsx +32 -0
  170. package/src/dataforms-layouts/data-form-layout.tsx +87 -0
  171. package/src/dataforms-layouts/index.tsx +7 -7
  172. package/src/dataforms-layouts/is-combined-field.ts +10 -0
  173. package/src/dataforms-layouts/panel/index.tsx +190 -93
  174. package/src/dataforms-layouts/panel/style.scss +4 -0
  175. package/src/dataforms-layouts/regular/index.tsx +99 -29
  176. package/src/dataforms-layouts/regular/style.scss +30 -0
  177. package/src/dataviews-layouts/grid/index.tsx +34 -8
  178. package/src/dataviews-layouts/grid/{density-picker.tsx → preview-size-picker.tsx} +39 -26
  179. package/src/dataviews-layouts/grid/style.scss +8 -1
  180. package/src/dataviews-layouts/index.ts +4 -0
  181. package/src/dataviews-layouts/list/index.tsx +31 -27
  182. package/src/dataviews-layouts/table/density-picker.tsx +57 -0
  183. package/src/dataviews-layouts/table/index.tsx +46 -5
  184. package/src/dataviews-layouts/table/style.scss +32 -0
  185. package/src/dataviews-layouts/utils/get-clickable-item-props.ts +22 -0
  186. package/src/normalize-fields.ts +18 -35
  187. package/src/normalize-form-fields.ts +42 -0
  188. package/src/style.scss +1 -1
  189. package/src/test/normalize-fields.ts +45 -0
  190. package/src/types.ts +43 -21
  191. package/src/validation.ts +10 -1
  192. package/tsconfig.tsbuildinfo +1 -1
  193. package/build/components/dataform-combined-edit/index.js +0 -67
  194. package/build/components/dataform-combined-edit/index.js.map +0 -1
  195. package/build/dataforms-layouts/get-visible-fields.js +0 -21
  196. package/build/dataforms-layouts/get-visible-fields.js.map +0 -1
  197. package/build/dataviews-layouts/grid/density-picker.js.map +0 -1
  198. package/build-module/components/dataform-combined-edit/index.js +0 -60
  199. package/build-module/components/dataform-combined-edit/index.js.map +0 -1
  200. package/build-module/dataforms-layouts/get-visible-fields.js +0 -14
  201. package/build-module/dataforms-layouts/get-visible-fields.js.map +0 -1
  202. package/build-module/dataviews-layouts/grid/density-picker.js.map +0 -1
  203. package/build-types/components/dataform-combined-edit/index.d.ts +0 -7
  204. package/build-types/components/dataform-combined-edit/index.d.ts.map +0 -1
  205. package/build-types/dataforms-layouts/get-visible-fields.d.ts +0 -3
  206. package/build-types/dataforms-layouts/get-visible-fields.d.ts.map +0 -1
  207. package/build-types/dataviews-layouts/grid/density-picker.d.ts +0 -5
  208. package/build-types/dataviews-layouts/grid/density-picker.d.ts.map +0 -1
  209. package/src/components/dataform-combined-edit/index.tsx +0 -66
  210. package/src/components/dataform-combined-edit/style.scss +0 -12
  211. package/src/dataforms-layouts/get-visible-fields.ts +0 -29
@@ -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,28 +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
-
23
- interface FormFieldProps< Item > {
24
- data: Item;
25
- field: NormalizedField< Item >;
26
- onChange: ( value: any ) => void;
27
- }
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';
28
29
 
29
30
  function DropdownHeader( {
30
31
  title,
31
32
  onClose,
32
33
  }: {
33
- title: string;
34
+ title?: string;
34
35
  onClose: () => void;
35
36
  } ) {
36
37
  return (
@@ -39,9 +40,11 @@ function DropdownHeader( {
39
40
  spacing={ 4 }
40
41
  >
41
42
  <HStack alignment="center">
42
- <Heading level={ 2 } size={ 13 }>
43
- { title }
44
- </Heading>
43
+ { title && (
44
+ <Heading level={ 2 } size={ 13 }>
45
+ { title }
46
+ </Heading>
47
+ ) }
45
48
  <Spacer />
46
49
  { onClose && (
47
50
  <Button
@@ -56,16 +59,45 @@ function DropdownHeader( {
56
59
  );
57
60
  }
58
61
 
59
- function FormField< Item >( {
62
+ function PanelDropdown< Item >( {
63
+ fieldDefinition,
64
+ popoverAnchor,
65
+ labelPosition = 'side',
60
66
  data,
61
- field,
62
67
  onChange,
63
- }: FormFieldProps< Item > ) {
64
- // Use internal state instead of a ref to make sure that the component
65
- // re-renders when the popover's anchor updates.
66
- const [ popoverAnchor, setPopoverAnchor ] = useState< HTMLElement | null >(
67
- null
68
- );
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
+
69
101
  // Memoize popoverProps to avoid returning a new object every time.
70
102
  const popoverProps = useMemo(
71
103
  () => ( {
@@ -80,90 +112,155 @@ function FormField< Item >( {
80
112
  );
81
113
 
82
114
  return (
83
- <HStack
84
- ref={ setPopoverAnchor }
85
- className="dataforms-layouts-panel__field"
86
- >
87
- <div className="dataforms-layouts-panel__field-label">
88
- { field.label }
89
- </div>
90
- <div>
91
- <Dropdown
92
- contentClassName="dataforms-layouts-panel__field-dropdown"
93
- popoverProps={ popoverProps }
94
- focusOnMount
95
- toggleProps={ {
96
- size: 'compact',
97
- variant: 'tertiary',
98
- tooltipPosition: 'middle left',
99
- } }
100
- renderToggle={ ( { isOpen, onToggle } ) => (
101
- <Button
102
- className="dataforms-layouts-panel__field-control"
103
- size="compact"
104
- variant="tertiary"
105
- aria-expanded={ isOpen }
106
- aria-label={ sprintf(
107
- // translators: %s: Field name.
108
- _x( 'Edit %s', 'field' ),
109
- field.label
110
- ) }
111
- onClick={ onToggle }
112
- >
113
- <field.render item={ data } />
114
- </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
115
138
  ) }
116
- renderContent={ ( { onClose } ) => (
117
- <>
118
- <DropdownHeader
119
- title={ field.label }
120
- onClose={ onClose }
121
- />
122
- <field.Edit
123
- 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 }
124
155
  data={ data }
125
- field={ field }
156
+ field={ nestedField }
126
157
  onChange={ onChange }
127
- hideLabelFromVision
158
+ hideLabelFromVision={
159
+ ( form?.fields ?? [] ).length < 2
160
+ }
128
161
  />
129
- </>
130
- ) }
131
- />
132
- </div>
133
- </HStack>
162
+ ) }
163
+ </DataFormLayout>
164
+ </>
165
+ ) }
166
+ />
134
167
  );
135
168
  }
136
169
 
137
- export default function FormPanel< Item >( {
170
+ export default function FormPanelField< Item >( {
138
171
  data,
139
- fields,
140
- form,
172
+ field,
141
173
  onChange,
142
- }: DataFormProps< Item > ) {
143
- const visibleFields = useMemo(
144
- () =>
145
- normalizeFields(
146
- getVisibleFields< Item >(
147
- fields,
148
- form.fields,
149
- form.combinedFields
150
- )
151
- ),
152
- [ 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
153
197
  );
154
198
 
155
- return (
156
- <VStack spacing={ 2 }>
157
- { visibleFields.map( ( field ) => {
158
- return (
159
- <FormField
160
- key={ field.id }
161
- 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
162
218
  field={ field }
219
+ popoverAnchor={ popoverAnchor }
220
+ fieldDefinition={ fieldDefinition }
221
+ data={ data }
163
222
  onChange={ onChange }
223
+ labelPosition={ labelPosition }
164
224
  />
165
- );
166
- } ) }
167
- </VStack>
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>
168
265
  );
169
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
+ }
@@ -1,46 +1,116 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { __experimentalVStack as VStack } from '@wordpress/components';
5
- import { useMemo } from '@wordpress/element';
4
+ import { useContext, useMemo } from '@wordpress/element';
5
+ import {
6
+ __experimentalHStack as HStack,
7
+ __experimentalVStack as VStack,
8
+ __experimentalHeading as Heading,
9
+ __experimentalSpacer as Spacer,
10
+ } from '@wordpress/components';
6
11
 
7
12
  /**
8
13
  * Internal dependencies
9
14
  */
10
- import { normalizeFields } from '../../normalize-fields';
11
- import { getVisibleFields } from '../get-visible-fields';
12
- import type { DataFormProps } from '../../types';
15
+ import type { Form, FieldLayoutProps } from '../../types';
16
+ import DataFormContext from '../../components/dataform-context';
17
+ import { DataFormLayout } from '../data-form-layout';
18
+ import { isCombinedField } from '../is-combined-field';
13
19
 
14
- export default function FormRegular< Item >( {
20
+ function Header( { title }: { title: string } ) {
21
+ return (
22
+ <VStack className="dataforms-layouts-regular__header" spacing={ 4 }>
23
+ <HStack alignment="center">
24
+ <Heading level={ 2 } size={ 13 }>
25
+ { title }
26
+ </Heading>
27
+ <Spacer />
28
+ </HStack>
29
+ </VStack>
30
+ );
31
+ }
32
+
33
+ export default function FormRegularField< Item >( {
15
34
  data,
16
- fields,
17
- form,
35
+ field,
18
36
  onChange,
19
- }: DataFormProps< Item > ) {
20
- const visibleFields = useMemo(
21
- () =>
22
- normalizeFields(
23
- getVisibleFields< Item >(
24
- fields,
25
- form.fields,
26
- form.combinedFields
27
- )
28
- ),
29
- [ fields, form.fields, form.combinedFields ]
37
+ hideLabelFromVision,
38
+ }: FieldLayoutProps< Item > ) {
39
+ const { fields } = useContext( DataFormContext );
40
+
41
+ const form = useMemo( () => {
42
+ if ( isCombinedField( field ) ) {
43
+ return {
44
+ fields: field.children.map( ( child ) => {
45
+ if ( typeof child === 'string' ) {
46
+ return {
47
+ id: child,
48
+ };
49
+ }
50
+ return child;
51
+ } ),
52
+ type: 'regular' as const,
53
+ };
54
+ }
55
+
56
+ return {
57
+ type: 'regular' as const,
58
+ fields: [],
59
+ };
60
+ }, [ field ] );
61
+
62
+ if ( isCombinedField( field ) ) {
63
+ return (
64
+ <>
65
+ { ! hideLabelFromVision && field.label && (
66
+ <Header title={ field.label } />
67
+ ) }
68
+ <DataFormLayout
69
+ data={ data }
70
+ form={ form as Form }
71
+ onChange={ onChange }
72
+ />
73
+ </>
74
+ );
75
+ }
76
+
77
+ const labelPosition = field.labelPosition ?? 'top';
78
+ const fieldDefinition = fields.find(
79
+ ( fieldDef ) => fieldDef.id === field.id
30
80
  );
31
81
 
32
- return (
33
- <VStack spacing={ 4 }>
34
- { visibleFields.map( ( field ) => {
35
- return (
36
- <field.Edit
37
- key={ field.id }
82
+ if ( ! fieldDefinition ) {
83
+ return null;
84
+ }
85
+ if ( labelPosition === 'side' ) {
86
+ return (
87
+ <HStack className="dataforms-layouts-regular__field">
88
+ <div className="dataforms-layouts-regular__field-label">
89
+ { fieldDefinition.label }
90
+ </div>
91
+ <div className="dataforms-layouts-regular__field-control">
92
+ <fieldDefinition.Edit
93
+ key={ fieldDefinition.id }
38
94
  data={ data }
39
- field={ field }
95
+ field={ fieldDefinition }
40
96
  onChange={ onChange }
97
+ hideLabelFromVision
41
98
  />
42
- );
43
- } ) }
44
- </VStack>
99
+ </div>
100
+ </HStack>
101
+ );
102
+ }
103
+
104
+ return (
105
+ <div className="dataforms-layouts-regular__field">
106
+ <fieldDefinition.Edit
107
+ data={ data }
108
+ field={ fieldDefinition }
109
+ onChange={ onChange }
110
+ hideLabelFromVision={
111
+ labelPosition === 'none' ? true : hideLabelFromVision
112
+ }
113
+ />
114
+ </div>
45
115
  );
46
116
  }
@@ -0,0 +1,30 @@
1
+ .dataforms-layouts-regular__field {
2
+ width: 100%;
3
+ min-height: $grid-unit-40;
4
+ justify-content: flex-start !important;
5
+ align-items: flex-start !important;
6
+ }
7
+
8
+ .dataforms-layouts-regular__field .components-base-control__label {
9
+ font-size: inherit;
10
+ font-weight: normal;
11
+ text-transform: none;
12
+ }
13
+
14
+ .dataforms-layouts-regular__field-label {
15
+ width: 38%;
16
+ flex-shrink: 0;
17
+ min-height: $grid-unit-40;
18
+ display: flex;
19
+ align-items: center;
20
+ padding: 6px 0; // Matches button to ensure alignment
21
+ line-height: $grid-unit-05 * 5;
22
+ hyphens: auto;
23
+ }
24
+
25
+ .dataforms-layouts-regular__field-control {
26
+ flex-grow: 1;
27
+ min-height: $grid-unit-40;
28
+ display: flex;
29
+ align-items: center;
30
+ }
@@ -24,11 +24,15 @@ import SingleSelectionCheckbox from '../../components/dataviews-selection-checkb
24
24
  import { useHasAPossibleBulkAction } from '../../components/dataviews-bulk-actions';
25
25
  import type { Action, NormalizedField, ViewGridProps } from '../../types';
26
26
  import type { SetSelection } from '../../private-types';
27
+ import getClickableItemProps from '../utils/get-clickable-item-props';
28
+ import { useUpdatedPreviewSizeOnViewportChange } from './preview-size-picker';
27
29
 
28
30
  interface GridItemProps< Item > {
29
31
  selection: string[];
30
32
  onChangeSelection: SetSelection;
31
33
  getItemId: ( item: Item ) => string;
34
+ onClickItem: ( item: Item ) => void;
35
+ isItemClickable: ( item: Item ) => boolean;
32
36
  item: Item;
33
37
  actions: Action< Item >[];
34
38
  mediaField?: NormalizedField< Item >;
@@ -41,6 +45,8 @@ interface GridItemProps< Item > {
41
45
  function GridItem< Item >( {
42
46
  selection,
43
47
  onChangeSelection,
48
+ onClickItem,
49
+ isItemClickable,
44
50
  getItemId,
45
51
  item,
46
52
  actions,
@@ -59,6 +65,21 @@ function GridItem< Item >( {
59
65
  const renderedPrimaryField = primaryField?.render ? (
60
66
  <primaryField.render item={ item } />
61
67
  ) : null;
68
+
69
+ const clickableMediaItemProps = getClickableItemProps(
70
+ item,
71
+ isItemClickable,
72
+ onClickItem,
73
+ 'dataviews-view-grid__media'
74
+ );
75
+
76
+ const clickablePrimaryItemProps = getClickableItemProps(
77
+ item,
78
+ isItemClickable,
79
+ onClickItem,
80
+ 'dataviews-view-grid__primary-field'
81
+ );
82
+
62
83
  return (
63
84
  <VStack
64
85
  spacing={ 0 }
@@ -81,9 +102,7 @@ function GridItem< Item >( {
81
102
  }
82
103
  } }
83
104
  >
84
- <div className="dataviews-view-grid__media">
85
- { renderedMediaField }
86
- </div>
105
+ <div { ...clickableMediaItemProps }>{ renderedMediaField }</div>
87
106
  <SingleSelectionCheckbox
88
107
  item={ item }
89
108
  selection={ selection }
@@ -96,9 +115,9 @@ function GridItem< Item >( {
96
115
  justify="space-between"
97
116
  className="dataviews-view-grid__title-actions"
98
117
  >
99
- <HStack className="dataviews-view-grid__primary-field">
118
+ <div { ...clickablePrimaryItemProps }>
100
119
  { renderedPrimaryField }
101
- </HStack>
120
+ </div>
102
121
  <ItemActions item={ item } actions={ actions } isCompact />
103
122
  </HStack>
104
123
  { !! badgeFields?.length && (
@@ -170,9 +189,10 @@ export default function ViewGrid< Item >( {
170
189
  getItemId,
171
190
  isLoading,
172
191
  onChangeSelection,
192
+ onClickItem,
193
+ isItemClickable,
173
194
  selection,
174
195
  view,
175
- density,
176
196
  }: ViewGridProps< Item > ) {
177
197
  const mediaField = fields.find(
178
198
  ( field ) => field.id === view.layout?.mediaField
@@ -203,8 +223,12 @@ export default function ViewGrid< Item >( {
203
223
  { visibleFields: [], badgeFields: [] }
204
224
  );
205
225
  const hasData = !! data?.length;
206
- const gridStyle = density
207
- ? { gridTemplateColumns: `repeat(${ density }, minmax(0, 1fr))` }
226
+ const updatedPreviewSize = useUpdatedPreviewSizeOnViewportChange();
227
+ const usedPreviewSize = updatedPreviewSize || view.layout?.previewSize;
228
+ const gridStyle = usedPreviewSize
229
+ ? {
230
+ gridTemplateColumns: `repeat(${ usedPreviewSize }, minmax(0, 1fr))`,
231
+ }
208
232
  : {};
209
233
  return (
210
234
  <>
@@ -223,6 +247,8 @@ export default function ViewGrid< Item >( {
223
247
  key={ getItemId( item ) }
224
248
  selection={ selection }
225
249
  onChangeSelection={ onChangeSelection }
250
+ onClickItem={ onClickItem }
251
+ isItemClickable={ isItemClickable }
226
252
  getItemId={ getItemId }
227
253
  item={ item }
228
254
  actions={ actions }