@wordpress/dataviews 4.9.1-next.cd6172eb0.0 → 4.10.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 (163) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +33 -58
  3. package/build/components/dataviews/index.js +1 -0
  4. package/build/components/dataviews/index.js.map +1 -1
  5. package/build/components/dataviews-bulk-actions/index.js +30 -2
  6. package/build/components/dataviews-bulk-actions/index.js.map +1 -1
  7. package/build/components/dataviews-filters/add-filter.js +1 -0
  8. package/build/components/dataviews-filters/add-filter.js.map +1 -1
  9. package/build/components/dataviews-filters/filter-summary.js +1 -0
  10. package/build/components/dataviews-filters/filter-summary.js.map +1 -1
  11. package/build/components/dataviews-filters/index.js +1 -0
  12. package/build/components/dataviews-filters/index.js.map +1 -1
  13. package/build/components/dataviews-filters/reset-filters.js +1 -0
  14. package/build/components/dataviews-filters/reset-filters.js.map +1 -1
  15. package/build/components/dataviews-filters/search-widget.js +1 -0
  16. package/build/components/dataviews-filters/search-widget.js.map +1 -1
  17. package/build/components/dataviews-item-actions/index.js +59 -75
  18. package/build/components/dataviews-item-actions/index.js.map +1 -1
  19. package/build/components/dataviews-layout/index.js +1 -0
  20. package/build/components/dataviews-layout/index.js.map +1 -1
  21. package/build/components/dataviews-pagination/index.js +1 -0
  22. package/build/components/dataviews-pagination/index.js.map +1 -1
  23. package/build/components/dataviews-selection-checkbox/index.js +4 -3
  24. package/build/components/dataviews-selection-checkbox/index.js.map +1 -1
  25. package/build/components/dataviews-view-config/index.js +195 -126
  26. package/build/components/dataviews-view-config/index.js.map +1 -1
  27. package/build/dataforms-layouts/data-form-layout.js +1 -0
  28. package/build/dataforms-layouts/data-form-layout.js.map +1 -1
  29. package/build/dataforms-layouts/index.js +1 -0
  30. package/build/dataforms-layouts/index.js.map +1 -1
  31. package/build/dataforms-layouts/panel/index.js +1 -0
  32. package/build/dataforms-layouts/panel/index.js.map +1 -1
  33. package/build/dataforms-layouts/regular/index.js +1 -0
  34. package/build/dataforms-layouts/regular/index.js.map +1 -1
  35. package/build/dataviews-layouts/grid/index.js +102 -66
  36. package/build/dataviews-layouts/grid/index.js.map +1 -1
  37. package/build/dataviews-layouts/index.js +0 -60
  38. package/build/dataviews-layouts/index.js.map +1 -1
  39. package/build/dataviews-layouts/list/index.js +44 -17
  40. package/build/dataviews-layouts/list/index.js.map +1 -1
  41. package/build/dataviews-layouts/table/column-header-menu.js +20 -24
  42. package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
  43. package/build/dataviews-layouts/table/column-primary.js +55 -0
  44. package/build/dataviews-layouts/table/column-primary.js.map +1 -0
  45. package/build/dataviews-layouts/table/index.js +74 -88
  46. package/build/dataviews-layouts/table/index.js.map +1 -1
  47. package/build/dataviews-layouts/utils/get-clickable-item-props.js +2 -2
  48. package/build/dataviews-layouts/utils/get-clickable-item-props.js.map +1 -1
  49. package/build/filter-and-sort-data-view.js +1 -0
  50. package/build/filter-and-sort-data-view.js.map +1 -1
  51. package/build/normalize-fields.js +1 -0
  52. package/build/normalize-fields.js.map +1 -1
  53. package/build/normalize-form-fields.js +1 -0
  54. package/build/normalize-form-fields.js.map +1 -1
  55. package/build/types.js.map +1 -1
  56. package/build/utils.js +1 -0
  57. package/build/utils.js.map +1 -1
  58. package/build/validation.js +1 -0
  59. package/build/validation.js.map +1 -1
  60. package/build-module/components/dataviews/index.js +1 -0
  61. package/build-module/components/dataviews/index.js.map +1 -1
  62. package/build-module/components/dataviews-bulk-actions/index.js +31 -3
  63. package/build-module/components/dataviews-bulk-actions/index.js.map +1 -1
  64. package/build-module/components/dataviews-filters/add-filter.js +1 -0
  65. package/build-module/components/dataviews-filters/add-filter.js.map +1 -1
  66. package/build-module/components/dataviews-filters/filter-summary.js +1 -0
  67. package/build-module/components/dataviews-filters/filter-summary.js.map +1 -1
  68. package/build-module/components/dataviews-filters/index.js +1 -0
  69. package/build-module/components/dataviews-filters/index.js.map +1 -1
  70. package/build-module/components/dataviews-filters/reset-filters.js +1 -0
  71. package/build-module/components/dataviews-filters/reset-filters.js.map +1 -1
  72. package/build-module/components/dataviews-filters/search-widget.js +1 -0
  73. package/build-module/components/dataviews-filters/search-widget.js.map +1 -1
  74. package/build-module/components/dataviews-item-actions/index.js +60 -75
  75. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  76. package/build-module/components/dataviews-layout/index.js +1 -0
  77. package/build-module/components/dataviews-layout/index.js.map +1 -1
  78. package/build-module/components/dataviews-pagination/index.js +1 -0
  79. package/build-module/components/dataviews-pagination/index.js.map +1 -1
  80. package/build-module/components/dataviews-selection-checkbox/index.js +4 -3
  81. package/build-module/components/dataviews-selection-checkbox/index.js.map +1 -1
  82. package/build-module/components/dataviews-view-config/index.js +199 -130
  83. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  84. package/build-module/dataforms-layouts/data-form-layout.js +1 -0
  85. package/build-module/dataforms-layouts/data-form-layout.js.map +1 -1
  86. package/build-module/dataforms-layouts/index.js +1 -0
  87. package/build-module/dataforms-layouts/index.js.map +1 -1
  88. package/build-module/dataforms-layouts/panel/index.js +1 -0
  89. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  90. package/build-module/dataforms-layouts/regular/index.js +1 -0
  91. package/build-module/dataforms-layouts/regular/index.js.map +1 -1
  92. package/build-module/dataviews-layouts/grid/index.js +103 -67
  93. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  94. package/build-module/dataviews-layouts/index.js +0 -57
  95. package/build-module/dataviews-layouts/index.js.map +1 -1
  96. package/build-module/dataviews-layouts/list/index.js +44 -17
  97. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  98. package/build-module/dataviews-layouts/table/column-header-menu.js +20 -24
  99. package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
  100. package/build-module/dataviews-layouts/table/column-primary.js +48 -0
  101. package/build-module/dataviews-layouts/table/column-primary.js.map +1 -0
  102. package/build-module/dataviews-layouts/table/index.js +77 -91
  103. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  104. package/build-module/dataviews-layouts/utils/get-clickable-item-props.js +2 -2
  105. package/build-module/dataviews-layouts/utils/get-clickable-item-props.js.map +1 -1
  106. package/build-module/filter-and-sort-data-view.js +1 -0
  107. package/build-module/filter-and-sort-data-view.js.map +1 -1
  108. package/build-module/normalize-fields.js +1 -0
  109. package/build-module/normalize-fields.js.map +1 -1
  110. package/build-module/normalize-form-fields.js +1 -0
  111. package/build-module/normalize-form-fields.js.map +1 -1
  112. package/build-module/types.js.map +1 -1
  113. package/build-module/utils.js +1 -0
  114. package/build-module/utils.js.map +1 -1
  115. package/build-module/validation.js +1 -0
  116. package/build-module/validation.js.map +1 -1
  117. package/build-style/style-rtl.css +87 -75
  118. package/build-style/style.css +87 -75
  119. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  120. package/build-types/components/dataviews/stories/index.story.d.ts +0 -1
  121. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  122. package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
  123. package/build-types/components/dataviews-item-actions/index.d.ts +7 -9
  124. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  125. package/build-types/components/dataviews-selection-checkbox/index.d.ts +2 -2
  126. package/build-types/components/dataviews-selection-checkbox/index.d.ts.map +1 -1
  127. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  128. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  129. package/build-types/dataviews-layouts/index.d.ts +0 -4
  130. package/build-types/dataviews-layouts/index.d.ts.map +1 -1
  131. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  132. package/build-types/dataviews-layouts/table/column-header-menu.d.ts +1 -0
  133. package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
  134. package/build-types/dataviews-layouts/table/column-primary.d.ts +14 -0
  135. package/build-types/dataviews-layouts/table/column-primary.d.ts.map +1 -0
  136. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  137. package/build-types/dataviews-layouts/utils/get-clickable-item-props.d.ts +3 -3
  138. package/build-types/dataviews-layouts/utils/get-clickable-item-props.d.ts.map +1 -1
  139. package/build-types/types.d.ts +20 -39
  140. package/build-types/types.d.ts.map +1 -1
  141. package/build-wp/index.js +1185 -1317
  142. package/build.js +1 -1
  143. package/package.json +10 -10
  144. package/src/components/dataviews/stories/fixtures.tsx +0 -3
  145. package/src/components/dataviews/stories/index.story.tsx +14 -106
  146. package/src/components/dataviews/style.scss +33 -33
  147. package/src/components/dataviews-bulk-actions/index.tsx +43 -3
  148. package/src/components/dataviews-item-actions/index.tsx +84 -99
  149. package/src/components/dataviews-selection-checkbox/index.tsx +4 -4
  150. package/src/components/dataviews-view-config/index.tsx +301 -195
  151. package/src/components/dataviews-view-config/style.scss +17 -0
  152. package/src/dataviews-layouts/grid/index.tsx +136 -101
  153. package/src/dataviews-layouts/grid/style.scss +16 -25
  154. package/src/dataviews-layouts/index.ts +0 -88
  155. package/src/dataviews-layouts/list/index.tsx +62 -32
  156. package/src/dataviews-layouts/list/style.scss +5 -4
  157. package/src/dataviews-layouts/table/column-header-menu.tsx +94 -86
  158. package/src/dataviews-layouts/table/column-primary.tsx +58 -0
  159. package/src/dataviews-layouts/table/index.tsx +88 -133
  160. package/src/dataviews-layouts/table/style.scss +4 -0
  161. package/src/dataviews-layouts/utils/get-clickable-item-props.ts +9 -3
  162. package/src/types.ts +21 -46
  163. package/tsconfig.tsbuildinfo +1 -1
@@ -23,29 +23,27 @@ import {
23
23
  __experimentalText as Text,
24
24
  privateApis as componentsPrivateApis,
25
25
  BaseControl,
26
+ Icon,
26
27
  } from '@wordpress/components';
27
28
  import { __, _x, sprintf } from '@wordpress/i18n';
28
29
  import { memo, useContext, useMemo } from '@wordpress/element';
29
- import { chevronDown, chevronUp, cog, seen, unseen } from '@wordpress/icons';
30
+ import {
31
+ chevronDown,
32
+ chevronUp,
33
+ cog,
34
+ seen,
35
+ unseen,
36
+ lock,
37
+ } from '@wordpress/icons';
30
38
  import warning from '@wordpress/warning';
31
39
  import { useInstanceId } from '@wordpress/compose';
32
40
 
33
41
  /**
34
42
  * Internal dependencies
35
43
  */
36
- import {
37
- SORTING_DIRECTIONS,
38
- LAYOUT_TABLE,
39
- sortIcons,
40
- sortLabels,
41
- } from '../../constants';
42
- import {
43
- VIEW_LAYOUTS,
44
- getNotHidableFieldIds,
45
- getVisibleFieldIds,
46
- getHiddenFieldIds,
47
- } from '../../dataviews-layouts';
48
- import type { SupportedLayouts, View, Field } from '../../types';
44
+ import { SORTING_DIRECTIONS, sortIcons, sortLabels } from '../../constants';
45
+ import { VIEW_LAYOUTS } from '../../dataviews-layouts';
46
+ import type { NormalizedField, SupportedLayouts, View } from '../../types';
49
47
  import DataViewsContext from '../dataviews-context';
50
48
  import { unlock } from '../../lock-unlock';
51
49
 
@@ -55,7 +53,11 @@ interface ViewTypeMenuProps {
55
53
  defaultLayouts?: SupportedLayouts;
56
54
  }
57
55
 
58
- const DATAVIEWS_CONFIG_POPOVER_PROPS = { placement: 'bottom-end', offset: 9 };
56
+ const DATAVIEWS_CONFIG_POPOVER_PROPS = {
57
+ className: 'dataviews-config__popover',
58
+ placement: 'bottom-end',
59
+ offset: 9,
60
+ };
59
61
 
60
62
  function ViewTypeMenu( {
61
63
  defaultLayouts = { list: {}, grid: {}, table: {} },
@@ -93,8 +95,13 @@ function ViewTypeMenu( {
93
95
  case 'list':
94
96
  case 'grid':
95
97
  case 'table':
98
+ const viewWithoutLayout = { ...view };
99
+ if ( 'layout' in viewWithoutLayout ) {
100
+ delete viewWithoutLayout.layout;
101
+ }
102
+ // @ts-expect-error
96
103
  return onChangeView( {
97
- ...view,
104
+ ...viewWithoutLayout,
98
105
  type: e.target.value,
99
106
  ...defaultLayouts[ e.target.value ],
100
107
  } );
@@ -237,236 +244,331 @@ function ItemsPerPageControl() {
237
244
  );
238
245
  }
239
246
 
240
- interface FieldItemProps {
241
- id: any;
242
- label: string;
243
- index: number;
244
- isVisible: boolean;
245
- isHidable: boolean;
246
- }
247
-
248
247
  function FieldItem( {
249
- field: { id, label, index, isVisible, isHidable },
250
- fields,
251
- view,
252
- onChangeView,
248
+ field,
249
+ isVisible,
250
+ isFirst,
251
+ isLast,
252
+ canMove = true,
253
+ onToggleVisibility,
254
+ onMoveUp,
255
+ onMoveDown,
253
256
  }: {
254
- field: FieldItemProps;
255
- fields: Field< any >[];
256
- view: View;
257
- onChangeView: ( view: View ) => void;
257
+ field: NormalizedField< any >;
258
+ isVisible: boolean;
259
+ isFirst?: boolean;
260
+ isLast?: boolean;
261
+ canMove?: boolean;
262
+ onToggleVisibility?: () => void;
263
+ onMoveUp?: () => void;
264
+ onMoveDown?: () => void;
258
265
  } ) {
259
- const visibleFieldIds = getVisibleFieldIds( view, fields );
266
+ const focusVisibilityField = () => {
267
+ // Focus the visibility button to avoid focus loss.
268
+ // Our code is safe against the component being unmounted, so we don't need to worry about cleaning the timeout.
269
+ // eslint-disable-next-line @wordpress/react-no-unsafe-timeout
270
+ setTimeout( () => {
271
+ const element = document.querySelector(
272
+ `.dataviews-field-control__field-${ field.id } .dataviews-field-control__field-visibility-button`
273
+ );
274
+ if ( element instanceof HTMLElement ) {
275
+ element.focus();
276
+ }
277
+ }, 50 );
278
+ };
260
279
 
261
280
  return (
262
- <Item key={ id }>
281
+ <Item>
263
282
  <HStack
264
283
  expanded
265
- className={ `dataviews-field-control__field dataviews-field-control__field-${ id }` }
284
+ className={ `dataviews-field-control__field dataviews-field-control__field-${ field.id }` }
285
+ justify="flex-start"
266
286
  >
267
- <span>{ label }</span>
287
+ <span className="dataviews-field-control__icon">
288
+ { ! canMove && ! field.enableHiding && (
289
+ <Icon icon={ lock } />
290
+ ) }
291
+ </span>
292
+ <span className="dataviews-field-control__label">
293
+ { field.label }
294
+ </span>
268
295
  <HStack
269
296
  justify="flex-end"
270
297
  expanded={ false }
271
298
  className="dataviews-field-control__actions"
272
299
  >
273
- { view.type === LAYOUT_TABLE && isVisible && (
300
+ { isVisible && (
274
301
  <>
275
302
  <Button
276
- disabled={ index < 1 }
303
+ disabled={ isFirst || ! canMove }
277
304
  accessibleWhenDisabled
278
305
  size="compact"
279
- onClick={ () => {
280
- onChangeView( {
281
- ...view,
282
- fields: [
283
- ...( visibleFieldIds.slice(
284
- 0,
285
- index - 1
286
- ) ?? [] ),
287
- id,
288
- visibleFieldIds[ index - 1 ],
289
- ...visibleFieldIds.slice(
290
- index + 1
291
- ),
292
- ],
293
- } );
294
- } }
306
+ onClick={ onMoveUp }
295
307
  icon={ chevronUp }
296
- label={ sprintf(
297
- /* translators: %s: field label */
298
- __( 'Move %s up' ),
299
- label
300
- ) }
308
+ label={
309
+ isFirst || ! canMove
310
+ ? __( "This field can't be moved up" )
311
+ : sprintf(
312
+ /* translators: %s: field label */
313
+ __( 'Move %s up' ),
314
+ field.label
315
+ )
316
+ }
301
317
  />
302
318
  <Button
303
- disabled={ index >= visibleFieldIds.length - 1 }
319
+ disabled={ isLast || ! canMove }
304
320
  accessibleWhenDisabled
305
321
  size="compact"
306
- onClick={ () => {
307
- onChangeView( {
308
- ...view,
309
- fields: [
310
- ...( visibleFieldIds.slice(
311
- 0,
312
- index
313
- ) ?? [] ),
314
- visibleFieldIds[ index + 1 ],
315
- id,
316
- ...visibleFieldIds.slice(
317
- index + 2
318
- ),
319
- ],
320
- } );
321
- } }
322
+ onClick={ onMoveDown }
322
323
  icon={ chevronDown }
323
- label={ sprintf(
324
- /* translators: %s: field label */
325
- __( 'Move %s down' ),
326
- label
327
- ) }
328
- />{ ' ' }
324
+ label={
325
+ isLast || ! canMove
326
+ ? __( "This field can't be moved down" )
327
+ : sprintf(
328
+ /* translators: %s: field label */
329
+ __( 'Move %s down' ),
330
+ field.label
331
+ )
332
+ }
333
+ />
329
334
  </>
330
335
  ) }
331
- <Button
332
- className="dataviews-field-control__field-visibility-button"
333
- disabled={ ! isHidable }
334
- accessibleWhenDisabled
335
- size="compact"
336
- onClick={ () => {
337
- onChangeView( {
338
- ...view,
339
- fields: isVisible
340
- ? visibleFieldIds.filter(
341
- ( fieldId ) => fieldId !== id
336
+ { onToggleVisibility && (
337
+ <Button
338
+ className="dataviews-field-control__field-visibility-button"
339
+ disabled={ ! field.enableHiding }
340
+ accessibleWhenDisabled
341
+ size="compact"
342
+ onClick={ () => {
343
+ onToggleVisibility();
344
+ focusVisibilityField();
345
+ } }
346
+ icon={ isVisible ? unseen : seen }
347
+ label={
348
+ isVisible
349
+ ? sprintf(
350
+ /* translators: %s: field label */
351
+ _x( 'Hide %s', 'field' ),
352
+ field.label
342
353
  )
343
- : [ ...visibleFieldIds, id ],
344
- } );
345
- // Focus the visibility button to avoid focus loss.
346
- // Our code is safe against the component being unmounted, so we don't need to worry about cleaning the timeout.
347
- // eslint-disable-next-line @wordpress/react-no-unsafe-timeout
348
- setTimeout( () => {
349
- const element = document.querySelector(
350
- `.dataviews-field-control__field-${ id } .dataviews-field-control__field-visibility-button`
351
- );
352
- if ( element instanceof HTMLElement ) {
353
- element.focus();
354
- }
355
- }, 50 );
356
- } }
357
- icon={ isVisible ? unseen : seen }
358
- label={
359
- isVisible
360
- ? sprintf(
361
- /* translators: %s: field label */
362
- _x( 'Hide %s', 'field' ),
363
- label
364
- )
365
- : sprintf(
366
- /* translators: %s: field label */
367
- _x( 'Show %s', 'field' ),
368
- label
369
- )
370
- }
371
- />
354
+ : sprintf(
355
+ /* translators: %s: field label */
356
+ _x( 'Show %s', 'field' ),
357
+ field.label
358
+ )
359
+ }
360
+ />
361
+ ) }
372
362
  </HStack>
373
363
  </HStack>
374
364
  </Item>
375
365
  );
376
366
  }
377
367
 
378
- function FieldControl() {
379
- const { view, fields, onChangeView } = useContext( DataViewsContext );
368
+ function RegularFieldItem( {
369
+ index,
370
+ field,
371
+ view,
372
+ onChangeView,
373
+ }: {
374
+ index?: number;
375
+ field: NormalizedField< any >;
376
+ view: View;
377
+ onChangeView: ( view: View ) => void;
378
+ } ) {
379
+ const visibleFieldIds = view.fields ?? [];
380
+ const isVisible =
381
+ index !== undefined && visibleFieldIds.includes( field.id );
380
382
 
381
- const visibleFieldIds = useMemo(
382
- () => getVisibleFieldIds( view, fields ),
383
- [ view, fields ]
384
- );
385
- const hiddenFieldIds = useMemo(
386
- () => getHiddenFieldIds( view, fields ),
387
- [ view, fields ]
388
- );
389
- const notHidableFieldIds = useMemo(
390
- () => getNotHidableFieldIds( view ),
391
- [ view ]
383
+ return (
384
+ <FieldItem
385
+ field={ field }
386
+ isVisible={ isVisible }
387
+ isFirst={ index !== undefined && index < 1 }
388
+ isLast={
389
+ index !== undefined && index === visibleFieldIds.length - 1
390
+ }
391
+ onToggleVisibility={ () => {
392
+ onChangeView( {
393
+ ...view,
394
+ fields: isVisible
395
+ ? visibleFieldIds.filter(
396
+ ( fieldId ) => fieldId !== field.id
397
+ )
398
+ : [ ...visibleFieldIds, field.id ],
399
+ } );
400
+ } }
401
+ onMoveUp={
402
+ index !== undefined
403
+ ? () => {
404
+ onChangeView( {
405
+ ...view,
406
+ fields: [
407
+ ...( visibleFieldIds.slice(
408
+ 0,
409
+ index - 1
410
+ ) ?? [] ),
411
+ field.id,
412
+ visibleFieldIds[ index - 1 ],
413
+ ...visibleFieldIds.slice( index + 1 ),
414
+ ],
415
+ } );
416
+ }
417
+ : undefined
418
+ }
419
+ onMoveDown={
420
+ index !== undefined
421
+ ? () => {
422
+ onChangeView( {
423
+ ...view,
424
+ fields: [
425
+ ...( visibleFieldIds.slice( 0, index ) ??
426
+ [] ),
427
+ visibleFieldIds[ index + 1 ],
428
+ field.id,
429
+ ...visibleFieldIds.slice( index + 2 ),
430
+ ],
431
+ } );
432
+ }
433
+ : undefined
434
+ }
435
+ />
392
436
  );
437
+ }
393
438
 
394
- const visibleFields = fields
395
- .filter( ( { id } ) => visibleFieldIds.includes( id ) )
396
- .map( ( { id, label, enableHiding } ) => {
397
- return {
398
- id,
399
- label,
400
- index: visibleFieldIds.indexOf( id ),
401
- isVisible: true,
402
- isHidable: notHidableFieldIds.includes( id )
403
- ? false
404
- : enableHiding,
405
- };
406
- } );
407
- if ( view.type === LAYOUT_TABLE && view.layout?.combinedFields ) {
408
- view.layout.combinedFields.forEach( ( { id, label } ) => {
409
- visibleFields.push( {
410
- id,
411
- label,
412
- index: visibleFieldIds.indexOf( id ),
413
- isVisible: true,
414
- isHidable: notHidableFieldIds.includes( id ),
415
- } );
416
- } );
417
- }
418
- visibleFields.sort( ( a, b ) => a.index - b.index );
439
+ function isDefined< T >( item: T | undefined ): item is T {
440
+ return !! item;
441
+ }
419
442
 
420
- const hiddenFields = fields
421
- .filter( ( { id } ) => hiddenFieldIds.includes( id ) )
422
- .map( ( { id, label, enableHiding }, index ) => {
423
- return {
424
- id,
425
- label,
426
- index,
427
- isVisible: false,
428
- isHidable: enableHiding,
429
- };
430
- } );
443
+ function FieldControl() {
444
+ const { view, fields, onChangeView } = useContext( DataViewsContext );
445
+
446
+ const togglableFields = [
447
+ view?.titleField,
448
+ view?.mediaField,
449
+ view?.descriptionField,
450
+ ].filter( Boolean );
451
+ const visibleFieldIds = view.fields ?? [];
452
+ const hiddenFields = fields.filter(
453
+ ( f ) =>
454
+ ! visibleFieldIds.includes( f.id ) &&
455
+ ! togglableFields.includes( f.id )
456
+ );
457
+ const visibleFields = visibleFieldIds
458
+ .map( ( fieldId ) => fields.find( ( f ) => f.id === fieldId ) )
459
+ .filter( isDefined );
431
460
 
432
461
  if ( ! visibleFields?.length && ! hiddenFields?.length ) {
433
462
  return null;
434
463
  }
464
+ const titleField = fields.find( ( f ) => f.id === view.titleField );
465
+ const mediaField = fields.find( ( f ) => f.id === view.mediaField );
466
+ const descriptionField = fields.find(
467
+ ( f ) => f.id === view.descriptionField
468
+ );
469
+ const lockedFields = [
470
+ {
471
+ field: titleField,
472
+ isVisibleFlag: 'showTitle',
473
+ },
474
+ {
475
+ field: mediaField,
476
+ isVisibleFlag: 'showMedia',
477
+ },
478
+ {
479
+ field: descriptionField,
480
+ isVisibleFlag: 'showDescription',
481
+ },
482
+ ].filter( ( { field } ) => isDefined( field ) );
483
+ const visibleLockedFields = lockedFields.filter(
484
+ ( { field, isVisibleFlag } ) =>
485
+ // @ts-expect-error
486
+ isDefined( field ) && ( view[ isVisibleFlag ] ?? true )
487
+ ) as Array< { field: NormalizedField< any >; isVisibleFlag: string } >;
488
+ const hiddenLockedFields = lockedFields.filter(
489
+ ( { field, isVisibleFlag } ) =>
490
+ // @ts-expect-error
491
+ isDefined( field ) && ! ( view[ isVisibleFlag ] ?? true )
492
+ ) as Array< { field: NormalizedField< any >; isVisibleFlag: string } >;
435
493
 
436
494
  return (
437
- <VStack spacing={ 6 } className="dataviews-field-control">
438
- { !! visibleFields?.length && (
439
- <ItemGroup isBordered isSeparated>
440
- { visibleFields.map( ( field ) => (
441
- <FieldItem
442
- key={ field.id }
443
- field={ field }
444
- fields={ fields }
445
- view={ view }
446
- onChangeView={ onChangeView }
447
- />
448
- ) ) }
449
- </ItemGroup>
450
- ) }
451
- { !! hiddenFields?.length && (
452
- <>
453
- <VStack spacing={ 4 }>
454
- <BaseControl.VisualLabel style={ { margin: 0 } }>
455
- { __( 'Hidden' ) }
456
- </BaseControl.VisualLabel>
495
+ <VStack className="dataviews-field-control" spacing={ 6 }>
496
+ <VStack className="dataviews-view-config__properties" spacing={ 0 }>
497
+ { ( visibleLockedFields.length > 0 ||
498
+ !! visibleFields?.length ) && (
499
+ <ItemGroup isBordered isSeparated>
500
+ { visibleLockedFields.map(
501
+ ( { field, isVisibleFlag } ) => {
502
+ return (
503
+ <FieldItem
504
+ key={ field.id }
505
+ field={ field }
506
+ isVisible
507
+ onToggleVisibility={ () => {
508
+ onChangeView( {
509
+ ...view,
510
+ [ isVisibleFlag ]: false,
511
+ } );
512
+ } }
513
+ canMove={ false }
514
+ />
515
+ );
516
+ }
517
+ ) }
518
+
519
+ { visibleFields.map( ( field, index ) => (
520
+ <RegularFieldItem
521
+ key={ field.id }
522
+ field={ field }
523
+ view={ view }
524
+ onChangeView={ onChangeView }
525
+ index={ index }
526
+ />
527
+ ) ) }
528
+ </ItemGroup>
529
+ ) }
530
+ </VStack>
531
+
532
+ { ( !! hiddenFields?.length || !! hiddenLockedFields.length ) && (
533
+ <VStack spacing={ 4 }>
534
+ <BaseControl.VisualLabel style={ { margin: 0 } }>
535
+ { __( 'Hidden' ) }
536
+ </BaseControl.VisualLabel>
537
+ <VStack
538
+ className="dataviews-view-config__properties"
539
+ spacing={ 0 }
540
+ >
457
541
  <ItemGroup isBordered isSeparated>
542
+ { hiddenLockedFields.length > 0 &&
543
+ hiddenLockedFields.map(
544
+ ( { field, isVisibleFlag } ) => {
545
+ return (
546
+ <FieldItem
547
+ key={ field.id }
548
+ field={ field }
549
+ isVisible={ false }
550
+ onToggleVisibility={ () => {
551
+ onChangeView( {
552
+ ...view,
553
+ [ isVisibleFlag ]: true,
554
+ } );
555
+ } }
556
+ canMove={ false }
557
+ />
558
+ );
559
+ }
560
+ ) }
458
561
  { hiddenFields.map( ( field ) => (
459
- <FieldItem
562
+ <RegularFieldItem
460
563
  key={ field.id }
461
564
  field={ field }
462
- fields={ fields }
463
565
  view={ view }
464
566
  onChangeView={ onChangeView }
465
567
  />
466
568
  ) ) }
467
569
  </ItemGroup>
468
570
  </VStack>
469
- </>
571
+ </VStack>
470
572
  ) }
471
573
  </VStack>
472
574
  );
@@ -521,6 +623,7 @@ function DataviewsViewConfigDropdown() {
521
623
  );
522
624
  return (
523
625
  <Dropdown
626
+ expandOnMobile
524
627
  popoverProps={ {
525
628
  ...DATAVIEWS_CONFIG_POPOVER_PROPS,
526
629
  id: popoverId,
@@ -538,7 +641,10 @@ function DataviewsViewConfigDropdown() {
538
641
  );
539
642
  } }
540
643
  renderContent={ () => (
541
- <DropdownContentWrapper paddingSize="medium">
644
+ <DropdownContentWrapper
645
+ paddingSize="medium"
646
+ className="dataviews-config__popover-content-wrapper"
647
+ >
542
648
  <VStack className="dataviews-view-config" spacing={ 6 }>
543
649
  <SettingsSection title={ __( 'Appearance' ) }>
544
650
  <HStack expanded className="is-divided-in-two">
@@ -6,6 +6,14 @@
6
6
  line-height: $default-line-height;
7
7
  }
8
8
 
9
+ .dataviews-config__popover.is-expanded .dataviews-config__popover-content-wrapper {
10
+ overflow-y: scroll;
11
+ height: 100%;
12
+ .dataviews-view-config {
13
+ width: auto;
14
+ }
15
+ }
16
+
9
17
  .dataviews-view-config__sort-direction .components-toggle-group-control-option-base {
10
18
  text-transform: uppercase;
11
19
  }
@@ -67,3 +75,12 @@
67
75
  top: unset;
68
76
  }
69
77
  }
78
+
79
+ .dataviews-field-control__icon {
80
+ display: flex;
81
+ width: $icon-size;
82
+ }
83
+
84
+ .dataviews-field-control__label {
85
+ flex-grow: 1;
86
+ }