@wordpress/dataviews 4.1.0 → 4.2.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 (170) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +31 -23
  3. package/build/components/dataviews/index.js +9 -11
  4. package/build/components/dataviews/index.js.map +1 -1
  5. package/build/components/dataviews-filters/index.js +3 -0
  6. package/build/components/dataviews-filters/index.js.map +1 -1
  7. package/build/components/dataviews-filters/search-widget.js +2 -5
  8. package/build/components/dataviews-filters/search-widget.js.map +1 -1
  9. package/build/components/dataviews-pagination/index.js +23 -15
  10. package/build/components/dataviews-pagination/index.js.map +1 -1
  11. package/build/components/dataviews-view-config/index.js +26 -9
  12. package/build/components/dataviews-view-config/index.js.map +1 -1
  13. package/build/dataform-controls/datetime.js +49 -0
  14. package/build/dataform-controls/datetime.js.map +1 -0
  15. package/build/dataform-controls/index.js +50 -0
  16. package/build/dataform-controls/index.js.map +1 -0
  17. package/build/dataform-controls/integer.js +45 -0
  18. package/build/dataform-controls/integer.js.map +1 -0
  19. package/build/dataform-controls/radio.js +45 -0
  20. package/build/dataform-controls/radio.js.map +1 -0
  21. package/build/dataform-controls/select.js +58 -0
  22. package/build/dataform-controls/select.js.map +1 -0
  23. package/build/dataform-controls/text.js +45 -0
  24. package/build/dataform-controls/text.js.map +1 -0
  25. package/build/dataforms-layouts/panel/index.js +6 -3
  26. package/build/dataforms-layouts/panel/index.js.map +1 -1
  27. package/build/dataforms-layouts/regular/index.js +6 -3
  28. package/build/dataforms-layouts/regular/index.js.map +1 -1
  29. package/build/dataviews-layouts/grid/density-picker.js +23 -52
  30. package/build/dataviews-layouts/grid/density-picker.js.map +1 -1
  31. package/build/dataviews-layouts/grid/index.js +1 -1
  32. package/build/dataviews-layouts/grid/index.js.map +1 -1
  33. package/build/dataviews-layouts/list/index.js +6 -2
  34. package/build/dataviews-layouts/list/index.js.map +1 -1
  35. package/build/dataviews-layouts/table/column-header-menu.js +2 -5
  36. package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
  37. package/build/field-types/datetime.js +30 -0
  38. package/build/field-types/datetime.js.map +1 -0
  39. package/build/field-types/index.js +4 -0
  40. package/build/field-types/index.js.map +1 -1
  41. package/build/field-types/integer.js +1 -60
  42. package/build/field-types/integer.js.map +1 -1
  43. package/build/field-types/text.js +1 -60
  44. package/build/field-types/text.js.map +1 -1
  45. package/build/normalize-fields.js +6 -7
  46. package/build/normalize-fields.js.map +1 -1
  47. package/build/types.js.map +1 -1
  48. package/build-module/components/dataviews/index.js +9 -11
  49. package/build-module/components/dataviews/index.js.map +1 -1
  50. package/build-module/components/dataviews-filters/index.js +3 -0
  51. package/build-module/components/dataviews-filters/index.js.map +1 -1
  52. package/build-module/components/dataviews-filters/search-widget.js +2 -5
  53. package/build-module/components/dataviews-filters/search-widget.js.map +1 -1
  54. package/build-module/components/dataviews-pagination/index.js +23 -15
  55. package/build-module/components/dataviews-pagination/index.js.map +1 -1
  56. package/build-module/components/dataviews-view-config/index.js +27 -10
  57. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  58. package/build-module/dataform-controls/datetime.js +43 -0
  59. package/build-module/dataform-controls/datetime.js.map +1 -0
  60. package/build-module/dataform-controls/index.js +42 -0
  61. package/build-module/dataform-controls/index.js.map +1 -0
  62. package/build-module/dataform-controls/integer.js +38 -0
  63. package/build-module/dataform-controls/integer.js.map +1 -0
  64. package/build-module/dataform-controls/radio.js +38 -0
  65. package/build-module/dataform-controls/radio.js.map +1 -0
  66. package/build-module/dataform-controls/select.js +51 -0
  67. package/build-module/dataform-controls/select.js.map +1 -0
  68. package/build-module/dataform-controls/text.js +38 -0
  69. package/build-module/dataform-controls/text.js.map +1 -0
  70. package/build-module/dataforms-layouts/panel/index.js +6 -3
  71. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  72. package/build-module/dataforms-layouts/regular/index.js +6 -3
  73. package/build-module/dataforms-layouts/regular/index.js.map +1 -1
  74. package/build-module/dataviews-layouts/grid/density-picker.js +25 -56
  75. package/build-module/dataviews-layouts/grid/density-picker.js.map +1 -1
  76. package/build-module/dataviews-layouts/grid/index.js +1 -1
  77. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  78. package/build-module/dataviews-layouts/list/index.js +5 -2
  79. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  80. package/build-module/dataviews-layouts/table/column-header-menu.js +2 -5
  81. package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
  82. package/build-module/field-types/datetime.js +24 -0
  83. package/build-module/field-types/datetime.js.map +1 -0
  84. package/build-module/field-types/index.js +4 -0
  85. package/build-module/field-types/index.js.map +1 -1
  86. package/build-module/field-types/integer.js +2 -60
  87. package/build-module/field-types/integer.js.map +1 -1
  88. package/build-module/field-types/text.js +2 -60
  89. package/build-module/field-types/text.js.map +1 -1
  90. package/build-module/normalize-fields.js +7 -7
  91. package/build-module/normalize-fields.js.map +1 -1
  92. package/build-module/types.js.map +1 -1
  93. package/build-style/style-rtl.css +15 -18
  94. package/build-style/style.css +15 -18
  95. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  96. package/build-types/components/dataviews/index.d.ts.map +1 -1
  97. package/build-types/components/dataviews/stories/fixtures.d.ts +22 -3
  98. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  99. package/build-types/components/dataviews/stories/index.story.d.ts +9 -0
  100. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  101. package/build-types/components/dataviews-filters/index.d.ts +1 -1
  102. package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
  103. package/build-types/components/dataviews-filters/search-widget.d.ts.map +1 -1
  104. package/build-types/components/dataviews-pagination/index.d.ts.map +1 -1
  105. package/build-types/components/dataviews-view-config/index.d.ts +4 -3
  106. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  107. package/build-types/dataform-controls/datetime.d.ts +6 -0
  108. package/build-types/dataform-controls/datetime.d.ts.map +1 -0
  109. package/build-types/dataform-controls/index.d.ts +11 -0
  110. package/build-types/dataform-controls/index.d.ts.map +1 -0
  111. package/build-types/dataform-controls/integer.d.ts +6 -0
  112. package/build-types/dataform-controls/integer.d.ts.map +1 -0
  113. package/build-types/dataform-controls/radio.d.ts +6 -0
  114. package/build-types/dataform-controls/radio.d.ts.map +1 -0
  115. package/build-types/dataform-controls/select.d.ts +6 -0
  116. package/build-types/dataform-controls/select.d.ts.map +1 -0
  117. package/build-types/dataform-controls/text.d.ts +6 -0
  118. package/build-types/dataform-controls/text.d.ts.map +1 -0
  119. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  120. package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -1
  121. package/build-types/dataviews-layouts/grid/density-picker.d.ts.map +1 -1
  122. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  123. package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
  124. package/build-types/field-types/datetime.d.ts +13 -0
  125. package/build-types/field-types/datetime.d.ts.map +1 -0
  126. package/build-types/field-types/index.d.ts +1 -1
  127. package/build-types/field-types/index.d.ts.map +1 -1
  128. package/build-types/field-types/integer.d.ts +2 -3
  129. package/build-types/field-types/integer.d.ts.map +1 -1
  130. package/build-types/field-types/text.d.ts +2 -3
  131. package/build-types/field-types/text.d.ts.map +1 -1
  132. package/build-types/normalize-fields.d.ts.map +1 -1
  133. package/build-types/types.d.ts +41 -21
  134. package/build-types/types.d.ts.map +1 -1
  135. package/package.json +12 -12
  136. package/src/components/dataform/stories/index.story.tsx +43 -2
  137. package/src/components/dataviews/index.tsx +13 -13
  138. package/src/components/dataviews/stories/fixtures.js +29 -1
  139. package/src/components/dataviews/stories/index.story.js +7 -1
  140. package/src/components/dataviews/style.scss +0 -12
  141. package/src/components/dataviews-bulk-actions-toolbar/style.scss +1 -1
  142. package/src/components/dataviews-filters/index.tsx +3 -0
  143. package/src/components/dataviews-filters/search-widget.tsx +1 -8
  144. package/src/components/dataviews-filters/style.scss +1 -1
  145. package/src/components/dataviews-pagination/index.tsx +35 -16
  146. package/src/components/dataviews-pagination/style.scss +9 -4
  147. package/src/components/dataviews-view-config/index.tsx +45 -16
  148. package/src/dataform-controls/datetime.tsx +43 -0
  149. package/src/dataform-controls/index.tsx +61 -0
  150. package/src/dataform-controls/integer.tsx +38 -0
  151. package/src/dataform-controls/radio.tsx +42 -0
  152. package/src/dataform-controls/select.tsx +52 -0
  153. package/src/dataform-controls/style.scss +4 -0
  154. package/src/dataform-controls/text.tsx +40 -0
  155. package/src/dataforms-layouts/panel/index.tsx +6 -2
  156. package/src/dataforms-layouts/regular/index.tsx +6 -2
  157. package/src/dataviews-layouts/grid/density-picker.tsx +33 -67
  158. package/src/dataviews-layouts/grid/index.tsx +1 -1
  159. package/src/dataviews-layouts/grid/style.scss +0 -4
  160. package/src/dataviews-layouts/list/index.tsx +6 -2
  161. package/src/dataviews-layouts/table/column-header-menu.tsx +3 -5
  162. package/src/field-types/datetime.tsx +28 -0
  163. package/src/field-types/index.tsx +5 -0
  164. package/src/field-types/integer.tsx +2 -71
  165. package/src/field-types/text.tsx +2 -70
  166. package/src/normalize-fields.ts +8 -10
  167. package/src/style.scss +1 -0
  168. package/src/test/filter-and-sort-data-view.js +28 -0
  169. package/src/types.ts +54 -32
  170. package/tsconfig.tsbuildinfo +1 -1
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { trash } from '@wordpress/icons';
4
+ import { trash, image, Icon, category } from '@wordpress/icons';
5
5
  import {
6
6
  Button,
7
7
  __experimentalText as Text,
@@ -23,6 +23,7 @@ export const data = [
23
23
  type: 'Not a planet',
24
24
  categories: [ 'Space', 'NASA' ],
25
25
  satellites: 0,
26
+ date: '2021-01-01T00:00:00Z',
26
27
  },
27
28
  {
28
29
  id: 2,
@@ -32,6 +33,7 @@ export const data = [
32
33
  type: 'Not a planet',
33
34
  categories: [ 'Space' ],
34
35
  satellites: 0,
36
+ date: '2019-01-02T00:00:00Z',
35
37
  },
36
38
  {
37
39
  id: 3,
@@ -41,6 +43,7 @@ export const data = [
41
43
  type: 'Not a planet',
42
44
  categories: [ 'NASA' ],
43
45
  satellites: 0,
46
+ date: '2025-01-03T00:00:00Z',
44
47
  },
45
48
  {
46
49
  id: 4,
@@ -50,6 +53,7 @@ export const data = [
50
53
  type: 'Ice giant',
51
54
  categories: [ 'Space', 'Planet', 'Solar system' ],
52
55
  satellites: 14,
56
+ date: '2020-01-01T00:00:00Z',
53
57
  },
54
58
  {
55
59
  id: 5,
@@ -59,6 +63,7 @@ export const data = [
59
63
  type: 'Terrestrial',
60
64
  categories: [ 'Space', 'Planet', 'Solar system' ],
61
65
  satellites: 0,
66
+ date: '2020-01-02T01:00:00Z',
62
67
  },
63
68
  {
64
69
  id: 6,
@@ -68,6 +73,7 @@ export const data = [
68
73
  type: 'Terrestrial',
69
74
  categories: [ 'Space', 'Planet', 'Solar system' ],
70
75
  satellites: 0,
76
+ date: '2020-01-02T00:00:00Z',
71
77
  },
72
78
  {
73
79
  id: 7,
@@ -77,6 +83,7 @@ export const data = [
77
83
  type: 'Terrestrial',
78
84
  categories: [ 'Space', 'Planet', 'Solar system' ],
79
85
  satellites: 1,
86
+ date: '2023-01-03T00:00:00Z',
80
87
  },
81
88
  {
82
89
  id: 8,
@@ -86,6 +93,7 @@ export const data = [
86
93
  type: 'Terrestrial',
87
94
  categories: [ 'Space', 'Planet', 'Solar system' ],
88
95
  satellites: 2,
96
+ date: '2020-01-01T00:00:00Z',
89
97
  },
90
98
  {
91
99
  id: 9,
@@ -95,6 +103,7 @@ export const data = [
95
103
  type: 'Gas giant',
96
104
  categories: [ 'Space', 'Planet', 'Solar system' ],
97
105
  satellites: 95,
106
+ date: '2017-01-01T00:01:00Z',
98
107
  },
99
108
  {
100
109
  id: 10,
@@ -104,6 +113,7 @@ export const data = [
104
113
  type: 'Gas giant',
105
114
  categories: [ 'Space', 'Planet', 'Solar system' ],
106
115
  satellites: 146,
116
+ date: '2020-02-01T00:02:00Z',
107
117
  },
108
118
  {
109
119
  id: 11,
@@ -113,6 +123,7 @@ export const data = [
113
123
  type: 'Ice giant',
114
124
  categories: [ 'Space', 'Ice giant', 'Solar system' ],
115
125
  satellites: 28,
126
+ date: '2020-03-01T00:00:00Z',
116
127
  },
117
128
  ];
118
129
 
@@ -162,6 +173,12 @@ export const fields = [
162
173
  {
163
174
  label: 'Image',
164
175
  id: 'image',
176
+ header: (
177
+ <HStack spacing={ 1 } justify="start">
178
+ <Icon icon={ image } />
179
+ <span>Image</span>
180
+ </HStack>
181
+ ),
165
182
  render: ( { item } ) => {
166
183
  return (
167
184
  <img src={ item.image } alt="" style={ { width: '100%' } } />
@@ -175,6 +192,11 @@ export const fields = [
175
192
  enableHiding: false,
176
193
  enableGlobalSearch: true,
177
194
  },
195
+ {
196
+ id: 'date',
197
+ label: 'Date',
198
+ type: 'datetime',
199
+ },
178
200
  {
179
201
  label: 'Type',
180
202
  id: 'type',
@@ -201,6 +223,12 @@ export const fields = [
201
223
  {
202
224
  label: 'Categories',
203
225
  id: 'categories',
226
+ header: (
227
+ <HStack spacing={ 1 } justify="start">
228
+ <Icon icon={ category } />
229
+ <span>Categories</span>
230
+ </HStack>
231
+ ),
204
232
  elements: [
205
233
  { value: 'Space', label: 'Space' },
206
234
  { value: 'NASA', label: 'NASA' },
@@ -8,7 +8,7 @@ import { useState, useMemo } from '@wordpress/element';
8
8
  */
9
9
  import DataViews from '../index';
10
10
  import { DEFAULT_VIEW, actions, data, fields } from './fixtures';
11
- import { LAYOUT_GRID, LAYOUT_TABLE } from '../../../constants';
11
+ import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../../../constants';
12
12
  import { filterSortAndPaginate } from '../../../filter-and-sort-data-view';
13
13
 
14
14
  const meta = {
@@ -61,5 +61,11 @@ Default.args = {
61
61
  primaryField: 'title',
62
62
  },
63
63
  },
64
+ [ LAYOUT_LIST ]: {
65
+ layout: {
66
+ mediaField: 'image',
67
+ primaryField: 'title',
68
+ },
69
+ },
64
70
  },
65
71
  };
@@ -18,12 +18,6 @@
18
18
  left: 0;
19
19
  transition: padding ease-out 0.1s;
20
20
  @include reduce-motion("transition");
21
-
22
- .components-search-control {
23
- .components-base-control__field {
24
- max-width: 240px;
25
- }
26
- }
27
21
  }
28
22
 
29
23
  .dataviews-view-list__primary-field,
@@ -82,12 +76,6 @@
82
76
  .dataviews__view-actions,
83
77
  .dataviews-filters__container {
84
78
  padding: $grid-unit-15 $grid-unit-30;
85
-
86
- .components-search-control {
87
- .components-base-control__field {
88
- max-width: 112px;
89
- }
90
- }
91
79
  }
92
80
 
93
81
  .dataviews-view-grid,
@@ -12,7 +12,7 @@
12
12
 
13
13
  .components-accessible-toolbar {
14
14
  border-color: $gray-300;
15
- box-shadow: $shadow-popover;
15
+ box-shadow: $elevation-x-small;
16
16
 
17
17
  .components-toolbar-group {
18
18
  border-color: $gray-200;
@@ -95,6 +95,9 @@ export function FilterVisibilityToggle( {
95
95
  const visibleFilters = filters.filter( ( filter ) => filter.isVisible );
96
96
 
97
97
  const hasVisibleFilters = !! visibleFilters.length;
98
+ if ( filters.length === 0 ) {
99
+ return null;
100
+ }
98
101
  if ( ! hasVisibleFilters ) {
99
102
  return (
100
103
  <AddFilterDropdownMenu
@@ -184,14 +184,7 @@ function ListBox( { view, filter, onChangeView }: SearchWidgetProps ) {
184
184
  <Icon icon={ check } />
185
185
  ) }
186
186
  </span>
187
- <span>
188
- { element.label }
189
- { !! element.description && (
190
- <span className="dataviews-filters__search-widget-listitem-description">
191
- { element.description }
192
- </span>
193
- ) }
194
- </span>
187
+ <span>{ element.label }</span>
195
188
  </Ariakit.CompositeHover>
196
189
  ) ) }
197
190
  </Composite>
@@ -48,7 +48,7 @@
48
48
 
49
49
  .dataviews-filters__summary-chip {
50
50
  border-radius: $grid-unit-20;
51
- border: 1px solid transparent;
51
+ border: $border-width solid transparent;
52
52
  cursor: pointer;
53
53
  padding: $grid-unit-05 $grid-unit-15;
54
54
  min-height: $grid-unit-40;
@@ -21,10 +21,31 @@ function DataViewsPagination() {
21
21
  onChangeView,
22
22
  paginationInfo: { totalItems = 0, totalPages },
23
23
  } = useContext( DataViewsContext );
24
+
24
25
  if ( ! totalItems || ! totalPages ) {
25
26
  return null;
26
27
  }
28
+
27
29
  const currentPage = view.page ?? 1;
30
+ const pageSelectOptions = Array.from( Array( totalPages ) ).map(
31
+ ( _, i ) => {
32
+ const page = i + 1;
33
+ return {
34
+ value: page.toString(),
35
+ label: page.toString(),
36
+ 'aria-label':
37
+ currentPage === page
38
+ ? sprintf(
39
+ // translators: Current page number in total number of pages
40
+ __( 'Page %1$s of %2$s' ),
41
+ currentPage,
42
+ totalPages
43
+ )
44
+ : page.toString(),
45
+ };
46
+ }
47
+ );
48
+
28
49
  return (
29
50
  !! totalItems &&
30
51
  totalPages !== 1 && (
@@ -37,37 +58,35 @@ function DataViewsPagination() {
37
58
  <HStack
38
59
  justify="flex-start"
39
60
  expanded={ false }
40
- spacing={ 2 }
41
- className="dataviews-pagination__page-selection"
61
+ spacing={ 1 }
62
+ className="dataviews-pagination__page-select"
42
63
  >
43
64
  { createInterpolateElement(
44
65
  sprintf(
45
- // translators: %s: Total number of pages.
46
- _x( 'Page <CurrentPageControl /> of %s', 'paging' ),
66
+ // translators: 1: Current page number, 2: Total number of pages.
67
+ _x(
68
+ '<div>Page</div>%1$s<div>of %2$s</div>',
69
+ 'paging'
70
+ ),
71
+ '<CurrentPage />',
47
72
  totalPages
48
73
  ),
49
74
  {
50
- CurrentPageControl: (
75
+ div: <div aria-hidden />,
76
+ CurrentPage: (
51
77
  <SelectControl
52
78
  aria-label={ __( 'Current page' ) }
53
- value={ view.page?.toString() }
54
- options={ Array.from(
55
- Array( totalPages )
56
- ).map( ( _, i ) => {
57
- const page = i + 1;
58
- return {
59
- value: page.toString(),
60
- label: page.toString(),
61
- };
62
- } ) }
79
+ value={ currentPage.toString() }
80
+ options={ pageSelectOptions }
63
81
  onChange={ ( newValue ) => {
64
82
  onChangeView( {
65
83
  ...view,
66
84
  page: +newValue,
67
85
  } );
68
86
  } }
69
- size="compact"
87
+ size="small"
70
88
  __nextHasNoMarginBottom
89
+ variant="minimal"
71
90
  />
72
91
  ),
73
92
  }
@@ -5,17 +5,22 @@
5
5
  background-color: $white;
6
6
  padding: $grid-unit-15 $grid-unit-60;
7
7
  border-top: $border-width solid $gray-100;
8
- color: $gray-700;
9
8
  flex-shrink: 0;
10
9
  transition: padding ease-out 0.1s;
11
10
  @include reduce-motion("transition");
12
11
  }
13
12
 
14
- .dataviews-pagination__page-selection {
13
+ .dataviews-pagination__page-select {
15
14
  font-size: 11px;
16
- text-transform: uppercase;
17
15
  font-weight: 500;
18
- color: $gray-900;
16
+ text-transform: uppercase;
17
+
18
+ @include break-small() {
19
+ .components-select-control__input {
20
+ font-size: 11px !important;
21
+ font-weight: 500;
22
+ }
23
+ }
19
24
  }
20
25
 
21
26
  /* stylelint-disable-next-line scss/at-rule-no-unknown -- '@container' not globally permitted */
@@ -30,11 +30,17 @@ import warning from '@wordpress/warning';
30
30
  /**
31
31
  * Internal dependencies
32
32
  */
33
- import { SORTING_DIRECTIONS, sortIcons, sortLabels } from '../../constants';
33
+ import {
34
+ SORTING_DIRECTIONS,
35
+ LAYOUT_GRID,
36
+ sortIcons,
37
+ sortLabels,
38
+ } from '../../constants';
34
39
  import { VIEW_LAYOUTS, getMandatoryFields } from '../../dataviews-layouts';
35
40
  import type { SupportedLayouts } from '../../types';
36
41
  import DataViewsContext from '../dataviews-context';
37
42
  import { unlock } from '../../lock-unlock';
43
+ import DensityPicker from '../../dataviews-layouts/grid/density-picker';
38
44
 
39
45
  const {
40
46
  DropdownMenuV2: DropdownMenu,
@@ -101,10 +107,6 @@ function ViewTypeMenu( {
101
107
  );
102
108
  }
103
109
 
104
- interface ViewActionsProps {
105
- defaultLayouts?: SupportedLayouts;
106
- }
107
-
108
110
  function SortFieldControl() {
109
111
  const { view, fields, onChangeView } = useContext( DataViewsContext );
110
112
  const orderOptions = useMemo( () => {
@@ -140,7 +142,11 @@ function SortFieldControl() {
140
142
  }
141
143
 
142
144
  function SortDirectionControl() {
143
- const { view, onChangeView } = useContext( DataViewsContext );
145
+ const { view, fields, onChangeView } = useContext( DataViewsContext );
146
+ let value = view.sort?.direction;
147
+ if ( ! value && view.sort?.field ) {
148
+ value = 'desc';
149
+ }
144
150
  return (
145
151
  <ToggleGroupControl
146
152
  className="dataviews-view-config__sort-direction"
@@ -148,18 +154,20 @@ function SortDirectionControl() {
148
154
  __next40pxDefaultSize
149
155
  isBlock
150
156
  label={ __( 'Order' ) }
151
- value={ view.sort?.direction || 'desc' }
152
- disabled={ ! view?.sort?.field }
157
+ value={ value }
153
158
  onChange={ ( newDirection ) => {
154
- if ( ! view?.sort?.field ) {
155
- return;
156
- }
157
159
  if ( newDirection === 'asc' || newDirection === 'desc' ) {
158
160
  onChangeView( {
159
161
  ...view,
160
162
  sort: {
161
163
  direction: newDirection,
162
- field: view.sort.field,
164
+ field:
165
+ view.sort?.field ||
166
+ // If there is no field assigned as the sorting field assign the first sortable field.
167
+ fields.find(
168
+ ( field ) => field.enableSorting !== false
169
+ )?.id ||
170
+ '',
163
171
  },
164
172
  } );
165
173
  return;
@@ -239,7 +247,6 @@ function FieldControl() {
239
247
  <HStack expanded>
240
248
  <span>{ field.label }</span>
241
249
  <Button
242
- className="'dataviews-view-config__field-control-button"
243
250
  size="compact"
244
251
  onClick={ () =>
245
252
  onChangeView( {
@@ -304,7 +311,14 @@ function SettingsSection( {
304
311
  );
305
312
  }
306
313
 
307
- function DataviewsViewConfigContent() {
314
+ function DataviewsViewConfigContent( {
315
+ density,
316
+ setDensity,
317
+ }: {
318
+ density: number;
319
+ setDensity: React.Dispatch< React.SetStateAction< number > >;
320
+ } ) {
321
+ const { view } = useContext( DataViewsContext );
308
322
  return (
309
323
  <VStack className="dataviews-view-config" spacing={ 6 }>
310
324
  <SettingsSection title={ __( 'Appearance' ) }>
@@ -312,6 +326,12 @@ function DataviewsViewConfigContent() {
312
326
  <SortFieldControl />
313
327
  <SortDirectionControl />
314
328
  </HStack>
329
+ { view.type === LAYOUT_GRID && (
330
+ <DensityPicker
331
+ density={ density }
332
+ setDensity={ setDensity }
333
+ />
334
+ ) }
315
335
  <ItemsPerPageControl />
316
336
  </SettingsSection>
317
337
  <SettingsSection title={ __( 'Properties' ) }>
@@ -322,8 +342,14 @@ function DataviewsViewConfigContent() {
322
342
  }
323
343
 
324
344
  function _DataViewsViewConfig( {
345
+ density,
346
+ setDensity,
325
347
  defaultLayouts = { list: {}, grid: {}, table: {} },
326
- }: ViewActionsProps ) {
348
+ }: {
349
+ density: number;
350
+ setDensity: React.Dispatch< React.SetStateAction< number > >;
351
+ defaultLayouts?: SupportedLayouts;
352
+ } ) {
327
353
  const [ isShowingViewPopover, setIsShowingViewPopover ] =
328
354
  useState< boolean >( false );
329
355
 
@@ -345,7 +371,10 @@ function _DataViewsViewConfig( {
345
371
  } }
346
372
  focusOnMount
347
373
  >
348
- <DataviewsViewConfigContent />
374
+ <DataviewsViewConfigContent
375
+ density={ density }
376
+ setDensity={ setDensity }
377
+ />
349
378
  </Popover>
350
379
  ) }
351
380
  </div>
@@ -0,0 +1,43 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { BaseControl, TimePicker, VisuallyHidden } from '@wordpress/components';
5
+ import { useCallback } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { DataFormControlProps } from '../types';
11
+
12
+ export default function DateTime< Item >( {
13
+ data,
14
+ field,
15
+ onChange,
16
+ hideLabelFromVision,
17
+ }: DataFormControlProps< Item > ) {
18
+ const { id, label } = field;
19
+ const value = field.getValue( { item: data } );
20
+
21
+ const onChangeControl = useCallback(
22
+ ( newValue: string | null ) => onChange( { [ id ]: newValue } ),
23
+ [ id, onChange ]
24
+ );
25
+
26
+ return (
27
+ <fieldset className="dataviews-controls__datetime">
28
+ { ! hideLabelFromVision && (
29
+ <BaseControl.VisualLabel as="legend">
30
+ { label }
31
+ </BaseControl.VisualLabel>
32
+ ) }
33
+ { hideLabelFromVision && (
34
+ <VisuallyHidden as="legend">{ label }</VisuallyHidden>
35
+ ) }
36
+ <TimePicker
37
+ currentTime={ value }
38
+ onChange={ onChangeControl }
39
+ hideLabelFromVision
40
+ />
41
+ </fieldset>
42
+ );
43
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import type { ComponentType } from 'react';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import type {
10
+ DataFormControlProps,
11
+ Field,
12
+ FieldTypeDefinition,
13
+ } from '../types';
14
+ import datetime from './datetime';
15
+ import integer from './integer';
16
+ import radio from './radio';
17
+ import select from './select';
18
+ import text from './text';
19
+
20
+ interface FormControls {
21
+ [ key: string ]: ComponentType< DataFormControlProps< any > >;
22
+ }
23
+
24
+ const FORM_CONTROLS: FormControls = {
25
+ datetime,
26
+ integer,
27
+ radio,
28
+ select,
29
+ text,
30
+ };
31
+
32
+ export function getControl< Item >(
33
+ field: Field< Item >,
34
+ fieldTypeDefinition: FieldTypeDefinition< Item >
35
+ ) {
36
+ if ( typeof field.Edit === 'function' ) {
37
+ return field.Edit;
38
+ }
39
+
40
+ if ( typeof field.Edit === 'string' ) {
41
+ return getControlByType( field.Edit );
42
+ }
43
+
44
+ if ( field.elements ) {
45
+ return getControlByType( 'select' );
46
+ }
47
+
48
+ if ( typeof fieldTypeDefinition.Edit === 'string' ) {
49
+ return getControlByType( fieldTypeDefinition.Edit );
50
+ }
51
+
52
+ return fieldTypeDefinition.Edit;
53
+ }
54
+
55
+ export function getControlByType( type: string ) {
56
+ if ( Object.keys( FORM_CONTROLS ).includes( type ) ) {
57
+ return FORM_CONTROLS[ type ];
58
+ }
59
+
60
+ throw 'Control ' + type + ' not found';
61
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __experimentalNumberControl as NumberControl } from '@wordpress/components';
5
+ import { useCallback } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { DataFormControlProps } from '../types';
11
+
12
+ export default function Integer< Item >( {
13
+ data,
14
+ field,
15
+ onChange,
16
+ hideLabelFromVision,
17
+ }: DataFormControlProps< Item > ) {
18
+ const { id, label, description } = field;
19
+ const value = field.getValue( { item: data } ) ?? '';
20
+ const onChangeControl = useCallback(
21
+ ( newValue: string | undefined ) =>
22
+ onChange( {
23
+ [ id ]: Number( newValue ),
24
+ } ),
25
+ [ id, onChange ]
26
+ );
27
+
28
+ return (
29
+ <NumberControl
30
+ label={ label }
31
+ help={ description }
32
+ value={ value }
33
+ onChange={ onChangeControl }
34
+ __next40pxDefaultSize
35
+ hideLabelFromVision={ hideLabelFromVision }
36
+ />
37
+ );
38
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { RadioControl } from '@wordpress/components';
5
+ import { useCallback } from '@wordpress/element';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import type { DataFormControlProps } from '../types';
11
+
12
+ export default function Radio< Item >( {
13
+ data,
14
+ field,
15
+ onChange,
16
+ hideLabelFromVision,
17
+ }: DataFormControlProps< Item > ) {
18
+ const { id, label } = field;
19
+ const value = field.getValue( { item: data } );
20
+
21
+ const onChangeControl = useCallback(
22
+ ( newValue: string ) =>
23
+ onChange( {
24
+ [ id ]: newValue,
25
+ } ),
26
+ [ id, onChange ]
27
+ );
28
+
29
+ if ( field.elements ) {
30
+ return (
31
+ <RadioControl
32
+ label={ label }
33
+ onChange={ onChangeControl }
34
+ options={ field.elements }
35
+ selected={ value }
36
+ hideLabelFromVision={ hideLabelFromVision }
37
+ />
38
+ );
39
+ }
40
+
41
+ return null;
42
+ }