@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
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { useState } from '@wordpress/element';
4
+ import { useMemo, useState } from '@wordpress/element';
5
+ import { ToggleControl } from '@wordpress/components';
5
6
 
6
7
  /**
7
8
  * Internal dependencies
8
9
  */
9
10
  import DataForm from '../index';
10
- import type { CombinedFormField, Field } from '../../../types';
11
+ import type { Field, Form } from '../../../types';
11
12
 
12
13
  type SamplePost = {
13
14
  title: string;
@@ -27,8 +28,13 @@ const meta = {
27
28
  type: {
28
29
  control: { type: 'select' },
29
30
  description:
30
- 'Chooses the layout of the form. "regular" is the default layout.',
31
- options: [ 'regular', 'panel' ],
31
+ 'Chooses the default layout of each field. "regular" is the default layout.',
32
+ options: [ 'default', 'regular', 'panel' ],
33
+ },
34
+ labelPosition: {
35
+ control: { type: 'select' },
36
+ description: 'Chooses the label position of the layout.',
37
+ options: [ 'default', 'top', 'side', 'none' ],
32
38
  },
33
39
  },
34
40
  };
@@ -97,9 +103,33 @@ const fields = [
97
103
  return item.status !== 'private';
98
104
  },
99
105
  },
106
+ {
107
+ id: 'sticky',
108
+ label: 'Sticky',
109
+ type: 'integer',
110
+ Edit: ( { field, onChange, data, hideLabelFromVision } ) => {
111
+ const { id, getValue } = field;
112
+ return (
113
+ <ToggleControl
114
+ __nextHasNoMarginBottom
115
+ label={ hideLabelFromVision ? '' : field.label }
116
+ checked={ getValue( { item: data } ) }
117
+ onChange={ () =>
118
+ onChange( { [ id ]: ! getValue( { item: data } ) } )
119
+ }
120
+ />
121
+ );
122
+ },
123
+ },
100
124
  ] as Field< SamplePost >[];
101
125
 
102
- export const Default = ( { type }: { type: 'panel' | 'regular' } ) => {
126
+ export const Default = ( {
127
+ type,
128
+ labelPosition,
129
+ }: {
130
+ type: 'default' | 'regular' | 'panel';
131
+ labelPosition: 'default' | 'top' | 'side' | 'none';
132
+ } ) => {
103
133
  const [ post, setPost ] = useState( {
104
134
  title: 'Hello, World!',
105
135
  order: 2,
@@ -108,29 +138,36 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => {
108
138
  reviewer: 'fulano',
109
139
  date: '2021-01-01T12:00:00',
110
140
  birthdate: '1950-02-23T12:00:00',
141
+ sticky: false,
111
142
  } );
112
143
 
113
- const form = {
114
- fields: [
115
- 'title',
116
- 'order',
117
- 'author',
118
- 'reviewer',
119
- 'status',
120
- 'password',
121
- 'date',
122
- 'birthdate',
123
- ],
124
- };
144
+ const form = useMemo(
145
+ () => ( {
146
+ type,
147
+ labelPosition,
148
+ fields: [
149
+ 'title',
150
+ 'order',
151
+ {
152
+ id: 'sticky',
153
+ layout: 'regular',
154
+ labelPosition: 'side',
155
+ },
156
+ 'author',
157
+ 'reviewer',
158
+ 'password',
159
+ 'date',
160
+ 'birthdate',
161
+ ],
162
+ } ),
163
+ [ type, labelPosition ]
164
+ ) as Form;
125
165
 
126
166
  return (
127
167
  <DataForm< SamplePost >
128
168
  data={ post }
129
169
  fields={ fields }
130
- form={ {
131
- ...form,
132
- type,
133
- } }
170
+ form={ form }
134
171
  onChange={ ( edits ) =>
135
172
  setPost( ( prev ) => ( {
136
173
  ...prev,
@@ -142,40 +179,45 @@ export const Default = ( { type }: { type: 'panel' | 'regular' } ) => {
142
179
  };
143
180
 
144
181
  const CombinedFieldsComponent = ( {
145
- type = 'regular',
146
- combinedFieldDirection = 'vertical',
182
+ type,
183
+ labelPosition,
147
184
  }: {
148
- type: 'panel' | 'regular';
149
- combinedFieldDirection: 'vertical' | 'horizontal';
185
+ type: 'default' | 'regular' | 'panel';
186
+ labelPosition: 'default' | 'top' | 'side' | 'none';
150
187
  } ) => {
151
- const [ post, setPost ] = useState( {
188
+ const [ post, setPost ] = useState< SamplePost >( {
152
189
  title: 'Hello, World!',
153
190
  order: 2,
154
191
  author: 1,
155
192
  status: 'draft',
193
+ reviewer: 'fulano',
194
+ date: '2021-01-01T12:00:00',
195
+ birthdate: '1950-02-23T12:00:00',
156
196
  } );
157
197
 
158
- const form = {
159
- fields: [ 'title', 'status_and_visibility', 'order', 'author' ],
160
- combinedFields: [
161
- {
162
- id: 'status_and_visibility',
163
- label: 'Status & Visibility',
164
- children: [ 'status', 'password' ],
165
- direction: combinedFieldDirection,
166
- render: ( { item } ) => item.status,
167
- },
168
- ] as CombinedFormField< any >[],
169
- };
198
+ const form = useMemo(
199
+ () => ( {
200
+ type,
201
+ labelPosition,
202
+ fields: [
203
+ 'title',
204
+ {
205
+ id: 'status',
206
+ label: 'Status & Visibility',
207
+ children: [ 'status', 'password' ],
208
+ },
209
+ 'order',
210
+ 'author',
211
+ ],
212
+ } ),
213
+ [ type, labelPosition ]
214
+ ) as Form;
170
215
 
171
216
  return (
172
- <DataForm
217
+ <DataForm< SamplePost >
173
218
  data={ post }
174
219
  fields={ fields }
175
- form={ {
176
- ...form,
177
- type,
178
- } }
220
+ form={ form }
179
221
  onChange={ ( edits ) =>
180
222
  setPost( ( prev ) => ( {
181
223
  ...prev,
@@ -191,11 +233,8 @@ export const CombinedFields = {
191
233
  render: CombinedFieldsComponent,
192
234
  argTypes: {
193
235
  ...meta.argTypes,
194
- combinedFieldDirection: {
195
- control: { type: 'select' },
196
- description:
197
- 'Chooses the direction of the combined field. "vertical" is the default layout.',
198
- options: [ 'vertical', 'horizontal' ],
199
- },
236
+ },
237
+ args: {
238
+ type: 'panel',
200
239
  },
201
240
  };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { createContext } from '@wordpress/element';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type { NormalizedField } from '../../types';
10
+
11
+ type DataFormContextType< Item > = {
12
+ fields: NormalizedField< Item >[];
13
+ };
14
+
15
+ const DataFormContext = createContext< DataFormContextType< any > >( {
16
+ fields: [],
17
+ } );
18
+
19
+ export function DataFormProvider< Item >( {
20
+ fields,
21
+ children,
22
+ }: React.PropsWithChildren< { fields: NormalizedField< Item >[] } > ) {
23
+ return (
24
+ <DataFormContext.Provider value={ { fields } }>
25
+ { children }
26
+ </DataFormContext.Provider>
27
+ );
28
+ }
29
+
30
+ export default DataFormContext;
@@ -16,7 +16,7 @@ import DataViewsContext from '../dataviews-context';
16
16
  import {
17
17
  default as DataViewsFilters,
18
18
  useFilters,
19
- FilterVisibilityToggle,
19
+ FiltersToggle,
20
20
  } from '../dataviews-filters';
21
21
  import DataViewsLayout from '../dataviews-layout';
22
22
  import DataViewsFooter from '../dataviews-footer';
@@ -75,7 +75,6 @@ export default function DataViews< Item >( {
75
75
  header,
76
76
  }: DataViewsProps< Item > ) {
77
77
  const [ selectionState, setSelectionState ] = useState< string[] >( [] );
78
- const [ density, setDensity ] = useState< number >( 0 );
79
78
  const isUncontrolled =
80
79
  selectionProperty === undefined || onChangeSelection === undefined;
81
80
  const selection = isUncontrolled ? selectionState : selectionProperty;
@@ -119,7 +118,6 @@ export default function DataViews< Item >( {
119
118
  getItemId,
120
119
  isItemClickable,
121
120
  onClickItem,
122
- density,
123
121
  } }
124
122
  >
125
123
  <div className="dataviews-wrapper">
@@ -135,7 +133,7 @@ export default function DataViews< Item >( {
135
133
  className="dataviews__search"
136
134
  >
137
135
  { search && <DataViewsSearch label={ searchLabel } /> }
138
- <FilterVisibilityToggle
136
+ <FiltersToggle
139
137
  filters={ filters }
140
138
  view={ view }
141
139
  onChangeView={ onChangeView }
@@ -151,8 +149,6 @@ export default function DataViews< Item >( {
151
149
  >
152
150
  <DataViewsViewConfig
153
151
  defaultLayouts={ defaultLayouts }
154
- density={ density }
155
- setDensity={ setDensity }
156
152
  />
157
153
  { header }
158
154
  </HStack>
@@ -558,6 +558,7 @@ export const themeFields: Field< Theme >[] = [
558
558
  },
559
559
  { id: 'requires', label: 'Requires at least' },
560
560
  { id: 'tested', label: 'Tested up to' },
561
+ { id: 'icon', label: 'Icon', render: () => <Icon icon={ image } /> },
561
562
  {
562
563
  id: 'tags',
563
564
  label: 'Tags',
@@ -65,6 +65,7 @@ export const Default = () => {
65
65
  const [ view, setView ] = useState< View >( {
66
66
  ...DEFAULT_VIEW,
67
67
  fields: [ 'title', 'description', 'categories' ],
68
+ layout: defaultLayouts[ DEFAULT_VIEW.type ].layout,
68
69
  } );
69
70
  const { data: shownData, paginationInfo } = useMemo( () => {
70
71
  return filterSortAndPaginate( data, view, fields );
@@ -136,16 +137,28 @@ export const FieldsNoSortableNoHidable = () => {
136
137
  export const CombinedFields = () => {
137
138
  const defaultLayoutsThemes = {
138
139
  table: {
139
- fields: [ 'theme', 'requires', 'tested' ],
140
+ fields: [ 'theme_with_combined', 'theme_with_simple' ],
140
141
  layout: {
141
142
  primaryField: 'name',
142
143
  combinedFields: [
143
144
  {
144
- id: 'theme',
145
+ id: 'name_tested',
145
146
  label: 'Theme',
146
- children: [ 'name', 'description' ],
147
+ children: [ 'name', 'tested' ],
147
148
  direction: 'vertical',
148
149
  },
150
+ {
151
+ id: 'theme_with_combined',
152
+ label: 'Combine combined fields',
153
+ children: [ 'icon', 'name_tested' ],
154
+ direction: 'horizontal',
155
+ },
156
+ {
157
+ id: 'theme_with_simple',
158
+ label: 'Combine simple fields',
159
+ children: [ 'icon', 'name' ],
160
+ direction: 'horizontal',
161
+ },
149
162
  ] as CombinedField[],
150
163
  styles: {
151
164
  theme: {
@@ -28,7 +28,6 @@ type DataViewsContextType< Item > = {
28
28
  getItemId: ( item: Item ) => string;
29
29
  onClickItem: ( item: Item ) => void;
30
30
  isItemClickable: ( item: Item ) => boolean;
31
- density: number;
32
31
  };
33
32
 
34
33
  const DataViewsContext = createContext< DataViewsContextType< any > >( {
@@ -47,7 +46,6 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
47
46
  getItemId: ( item ) => item.id,
48
47
  onClickItem: () => {},
49
48
  isItemClickable: () => false,
50
- density: 0,
51
49
  } );
52
50
 
53
51
  export default DataViewsContext;
@@ -7,6 +7,7 @@ import {
7
7
  useRef,
8
8
  useMemo,
9
9
  useCallback,
10
+ useEffect,
10
11
  } from '@wordpress/element';
11
12
  import { __experimentalHStack as HStack, Button } from '@wordpress/components';
12
13
  import { funnel } from '@wordpress/icons';
@@ -70,7 +71,7 @@ export function useFilters( fields: NormalizedField< any >[], view: View ) {
70
71
  }, [ fields, view ] );
71
72
  }
72
73
 
73
- export function FilterVisibilityToggle( {
74
+ export function FiltersToggle( {
74
75
  filters,
75
76
  view,
76
77
  onChangeView,
@@ -85,6 +86,7 @@ export function FilterVisibilityToggle( {
85
86
  isShowingFilter: boolean;
86
87
  setIsShowingFilter: React.Dispatch< React.SetStateAction< boolean > >;
87
88
  } ) {
89
+ const buttonRef = useRef< HTMLButtonElement >( null );
88
90
  const onChangeViewWithFilterVisibility = useCallback(
89
91
  ( _view: View ) => {
90
92
  onChangeView( _view );
@@ -98,48 +100,81 @@ export function FilterVisibilityToggle( {
98
100
  if ( filters.length === 0 ) {
99
101
  return null;
100
102
  }
101
- if ( ! hasVisibleFilters ) {
102
- return (
103
- <AddFilterMenu
104
- filters={ filters }
105
- view={ view }
106
- onChangeView={ onChangeViewWithFilterVisibility }
107
- setOpenedFilter={ setOpenedFilter }
108
- trigger={
109
- <Button
110
- className="dataviews-filters__visibility-toggle"
111
- size="compact"
112
- icon={ funnel }
113
- label={ __( 'Add filter' ) }
114
- isPressed={ false }
115
- aria-expanded={ false }
116
- />
117
- }
118
- />
119
- );
120
- }
103
+
104
+ const addFilterButtonProps = {
105
+ label: __( 'Add filter' ),
106
+ 'aria-expanded': false,
107
+ isPressed: false,
108
+ };
109
+ const toggleFiltersButtonProps = {
110
+ label: _x( 'Filter', 'verb' ),
111
+ 'aria-expanded': isShowingFilter,
112
+ isPressed: isShowingFilter,
113
+ onClick: () => {
114
+ if ( ! isShowingFilter ) {
115
+ setOpenedFilter( null );
116
+ }
117
+ setIsShowingFilter( ! isShowingFilter );
118
+ },
119
+ };
120
+ const buttonComponent = (
121
+ <Button
122
+ ref={ buttonRef }
123
+ className="dataviews-filters__visibility-toggle"
124
+ size="compact"
125
+ icon={ funnel }
126
+ { ...( hasVisibleFilters
127
+ ? toggleFiltersButtonProps
128
+ : addFilterButtonProps ) }
129
+ />
130
+ );
121
131
  return (
122
132
  <div className="dataviews-filters__container-visibility-toggle">
123
- <Button
124
- className="dataviews-filters__visibility-toggle"
125
- size="compact"
126
- icon={ funnel }
127
- label={ _x( 'Filter', 'verb' ) }
128
- onClick={ () => {
129
- if ( ! isShowingFilter ) {
130
- setOpenedFilter( null );
131
- }
132
- setIsShowingFilter( ! isShowingFilter );
133
- } }
134
- isPressed={ isShowingFilter }
135
- aria-expanded={ isShowingFilter }
136
- />
137
- { hasVisibleFilters && !! view.filters?.length && (
133
+ { ! hasVisibleFilters ? (
134
+ <AddFilterMenu
135
+ filters={ filters }
136
+ view={ view }
137
+ onChangeView={ onChangeViewWithFilterVisibility }
138
+ setOpenedFilter={ setOpenedFilter }
139
+ trigger={ buttonComponent }
140
+ />
141
+ ) : (
142
+ <FilterVisibilityToggle
143
+ buttonRef={ buttonRef }
144
+ filtersCount={ view.filters?.length }
145
+ >
146
+ { buttonComponent }
147
+ </FilterVisibilityToggle>
148
+ ) }
149
+ </div>
150
+ );
151
+ }
152
+
153
+ function FilterVisibilityToggle( {
154
+ buttonRef,
155
+ filtersCount,
156
+ children,
157
+ }: {
158
+ buttonRef: React.RefObject< HTMLButtonElement >;
159
+ filtersCount?: number;
160
+ children: React.ReactNode;
161
+ } ) {
162
+ // Focus the `add filter` button when unmounts.
163
+ useEffect(
164
+ () => () => {
165
+ buttonRef.current?.focus();
166
+ },
167
+ [ buttonRef ]
168
+ );
169
+ return (
170
+ <>
171
+ { children }
172
+ { !! filtersCount && (
138
173
  <span className="dataviews-filters-toggle__count">
139
- { view.filters?.length }
174
+ { filtersCount }
140
175
  </span>
141
176
  ) }
142
- </div>
177
+ </>
143
178
  );
144
179
  }
145
180
 
@@ -57,6 +57,13 @@ interface ItemActionsProps< Item > {
57
57
  interface CompactItemActionsProps< Item > {
58
58
  item: Item;
59
59
  actions: Action< Item >[];
60
+ isSmall?: boolean;
61
+ }
62
+
63
+ interface PrimaryActionsProps< Item > {
64
+ item: Item;
65
+ actions: Action< Item >[];
66
+ registry: ReturnType< typeof useRegistry >;
60
67
  }
61
68
 
62
69
  function ButtonTrigger< Item >( {
@@ -179,6 +186,13 @@ export function ActionsMenuGroup< Item >( {
179
186
  );
180
187
  }
181
188
 
189
+ function hasOnlyOneActionAndIsPrimary< Item >(
190
+ primaryActions: Action< Item >[],
191
+ actions: Action< Item >[]
192
+ ) {
193
+ return primaryActions.length === 1 && actions.length === 1;
194
+ }
195
+
182
196
  export default function ItemActions< Item >( {
183
197
  item,
184
198
  actions,
@@ -199,9 +213,27 @@ export default function ItemActions< Item >( {
199
213
  eligibleActions: _eligibleActions,
200
214
  };
201
215
  }, [ actions, item ] );
216
+
202
217
  if ( isCompact ) {
203
- return <CompactItemActions item={ item } actions={ eligibleActions } />;
218
+ return (
219
+ <CompactItemActions
220
+ item={ item }
221
+ actions={ eligibleActions }
222
+ isSmall
223
+ />
224
+ );
225
+ }
226
+
227
+ if ( hasOnlyOneActionAndIsPrimary( primaryActions, actions ) ) {
228
+ return (
229
+ <PrimaryActions
230
+ item={ item }
231
+ actions={ primaryActions }
232
+ registry={ registry }
233
+ />
234
+ );
204
235
  }
236
+
205
237
  return (
206
238
  <HStack
207
239
  spacing={ 1 }
@@ -212,29 +244,11 @@ export default function ItemActions< Item >( {
212
244
  width: 'auto',
213
245
  } }
214
246
  >
215
- { !! primaryActions.length &&
216
- primaryActions.map( ( action ) => {
217
- if ( 'RenderModal' in action ) {
218
- return (
219
- <ActionWithModal
220
- key={ action.id }
221
- action={ action }
222
- items={ [ item ] }
223
- ActionTrigger={ ButtonTrigger }
224
- />
225
- );
226
- }
227
- return (
228
- <ButtonTrigger
229
- key={ action.id }
230
- action={ action }
231
- onClick={ () => {
232
- action.callback( [ item ], { registry } );
233
- } }
234
- items={ [ item ] }
235
- />
236
- );
237
- } ) }
247
+ <PrimaryActions
248
+ item={ item }
249
+ actions={ primaryActions }
250
+ registry={ registry }
251
+ />
238
252
  <CompactItemActions item={ item } actions={ eligibleActions } />
239
253
  </HStack>
240
254
  );
@@ -243,12 +257,13 @@ export default function ItemActions< Item >( {
243
257
  function CompactItemActions< Item >( {
244
258
  item,
245
259
  actions,
260
+ isSmall,
246
261
  }: CompactItemActionsProps< Item > ) {
247
262
  return (
248
263
  <Menu
249
264
  trigger={
250
265
  <Button
251
- size="compact"
266
+ size={ isSmall ? 'small' : 'compact' }
252
267
  icon={ moreVertical }
253
268
  label={ __( 'Actions' ) }
254
269
  accessibleWhenDisabled
@@ -262,3 +277,36 @@ function CompactItemActions< Item >( {
262
277
  </Menu>
263
278
  );
264
279
  }
280
+
281
+ function PrimaryActions< Item >( {
282
+ item,
283
+ actions,
284
+ registry,
285
+ }: PrimaryActionsProps< Item > ) {
286
+ if ( ! Array.isArray( actions ) || actions.length === 0 ) {
287
+ return null;
288
+ }
289
+
290
+ return actions.map( ( action ) => {
291
+ if ( 'RenderModal' in action ) {
292
+ return (
293
+ <ActionWithModal
294
+ key={ action.id }
295
+ action={ action }
296
+ items={ [ item ] }
297
+ ActionTrigger={ ButtonTrigger }
298
+ />
299
+ );
300
+ }
301
+ return (
302
+ <ButtonTrigger
303
+ key={ action.id }
304
+ action={ action }
305
+ onClick={ () => {
306
+ action.callback( [ item ], { registry } );
307
+ } }
308
+ items={ [ item ] }
309
+ />
310
+ );
311
+ } );
312
+ }
@@ -27,7 +27,6 @@ export default function DataViewsLayout() {
27
27
  selection,
28
28
  onChangeSelection,
29
29
  setOpenedFilter,
30
- density,
31
30
  onClickItem,
32
31
  isItemClickable,
33
32
  } = useContext( DataViewsContext );
@@ -49,7 +48,6 @@ export default function DataViewsLayout() {
49
48
  onClickItem={ onClickItem }
50
49
  isItemClickable={ isItemClickable }
51
50
  view={ view }
52
- density={ density }
53
51
  />
54
52
  );
55
53
  }