@wordpress/dataviews 8.0.1-next.e256d081a.0 → 9.0.1-next.6870dfe5b.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 (269) hide show
  1. package/CHANGELOG.md +24 -1
  2. package/README.md +96 -1
  3. package/build/components/dataform-context/index.js +1 -0
  4. package/build/components/dataform-context/index.js.map +1 -1
  5. package/build/components/dataviews/index.js +11 -1
  6. package/build/components/dataviews/index.js.map +1 -1
  7. package/build/components/dataviews-context/index.js +1 -0
  8. package/build/components/dataviews-context/index.js.map +1 -1
  9. package/build/components/dataviews-layout/index.js +2 -1
  10. package/build/components/dataviews-layout/index.js.map +1 -1
  11. package/build/components/dataviews-picker/footer.js +145 -0
  12. package/build/components/dataviews-picker/footer.js.map +1 -0
  13. package/build/components/dataviews-picker/index.js +201 -0
  14. package/build/components/dataviews-picker/index.js.map +1 -0
  15. package/build/components/dataviews-selection-checkbox/index.js +4 -2
  16. package/build/components/dataviews-selection-checkbox/index.js.map +1 -1
  17. package/build/components/dataviews-view-config/index.js +1 -0
  18. package/build/components/dataviews-view-config/index.js.map +1 -1
  19. package/build/constants.js +4 -1
  20. package/build/constants.js.map +1 -1
  21. package/build/dataform-controls/checkbox.js +23 -2
  22. package/build/dataform-controls/checkbox.js.map +1 -1
  23. package/build/dataform-controls/color.js +128 -0
  24. package/build/dataform-controls/color.js.map +1 -0
  25. package/build/dataform-controls/email.js +10 -45
  26. package/build/dataform-controls/email.js.map +1 -1
  27. package/build/dataform-controls/index.js +8 -2
  28. package/build/dataform-controls/index.js.map +1 -1
  29. package/build/dataform-controls/telephone.js +34 -0
  30. package/build/dataform-controls/telephone.js.map +1 -0
  31. package/build/dataform-controls/text.js +7 -48
  32. package/build/dataform-controls/text.js.map +1 -1
  33. package/build/dataform-controls/{boolean.js → toggle.js} +6 -4
  34. package/build/dataform-controls/toggle.js.map +1 -0
  35. package/build/dataform-controls/url.js +34 -0
  36. package/build/dataform-controls/url.js.map +1 -0
  37. package/build/dataform-controls/utils/validated-text.js +76 -0
  38. package/build/dataform-controls/utils/validated-text.js.map +1 -0
  39. package/build/dataforms-layouts/card/index.js +6 -7
  40. package/build/dataforms-layouts/card/index.js.map +1 -1
  41. package/build/dataforms-layouts/data-form-layout.js +16 -4
  42. package/build/dataforms-layouts/data-form-layout.js.map +1 -1
  43. package/build/dataforms-layouts/index.js +31 -1
  44. package/build/dataforms-layouts/index.js.map +1 -1
  45. package/build/dataforms-layouts/row/index.js +113 -0
  46. package/build/dataforms-layouts/row/index.js.map +1 -0
  47. package/build/dataviews-layouts/grid/index.js +16 -11
  48. package/build/dataviews-layouts/grid/index.js.map +1 -1
  49. package/build/dataviews-layouts/index.js +9 -1
  50. package/build/dataviews-layouts/index.js.map +1 -1
  51. package/build/dataviews-layouts/picker-grid/index.js +357 -0
  52. package/build/dataviews-layouts/picker-grid/index.js.map +1 -0
  53. package/build/dataviews-layouts/utils/grid-items.js +37 -0
  54. package/build/dataviews-layouts/utils/grid-items.js.map +1 -0
  55. package/build/dataviews-layouts/utils/preview-size-picker.js +81 -0
  56. package/build/dataviews-layouts/utils/preview-size-picker.js.map +1 -0
  57. package/build/field-types/boolean.js +1 -1
  58. package/build/field-types/boolean.js.map +1 -1
  59. package/build/field-types/color.js +113 -0
  60. package/build/field-types/color.js.map +1 -0
  61. package/build/field-types/index.js +12 -0
  62. package/build/field-types/index.js.map +1 -1
  63. package/build/field-types/telephone.js +57 -0
  64. package/build/field-types/telephone.js.map +1 -0
  65. package/build/field-types/url.js +57 -0
  66. package/build/field-types/url.js.map +1 -0
  67. package/build/normalize-form-fields.js +6 -0
  68. package/build/normalize-form-fields.js.map +1 -1
  69. package/build/types.js.map +1 -1
  70. package/build/validation.js +1 -1
  71. package/build/validation.js.map +1 -1
  72. package/build-module/components/dataform-context/index.js +1 -0
  73. package/build-module/components/dataform-context/index.js.map +1 -1
  74. package/build-module/components/dataviews/index.js +11 -1
  75. package/build-module/components/dataviews/index.js.map +1 -1
  76. package/build-module/components/dataviews-context/index.js +1 -0
  77. package/build-module/components/dataviews-context/index.js.map +1 -1
  78. package/build-module/components/dataviews-layout/index.js +2 -1
  79. package/build-module/components/dataviews-layout/index.js.map +1 -1
  80. package/build-module/components/dataviews-picker/footer.js +136 -0
  81. package/build-module/components/dataviews-picker/footer.js.map +1 -0
  82. package/build-module/components/dataviews-picker/index.js +191 -0
  83. package/build-module/components/dataviews-picker/index.js.map +1 -0
  84. package/build-module/components/dataviews-selection-checkbox/index.js +4 -2
  85. package/build-module/components/dataviews-selection-checkbox/index.js.map +1 -1
  86. package/build-module/components/dataviews-view-config/index.js +1 -0
  87. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  88. package/build-module/constants.js +3 -0
  89. package/build-module/constants.js.map +1 -1
  90. package/build-module/dataform-controls/checkbox.js +25 -3
  91. package/build-module/dataform-controls/checkbox.js.map +1 -1
  92. package/build-module/dataform-controls/color.js +122 -0
  93. package/build-module/dataform-controls/color.js.map +1 -0
  94. package/build-module/dataform-controls/email.js +9 -45
  95. package/build-module/dataform-controls/email.js.map +1 -1
  96. package/build-module/dataform-controls/index.js +8 -2
  97. package/build-module/dataform-controls/index.js.map +1 -1
  98. package/build-module/dataform-controls/telephone.js +27 -0
  99. package/build-module/dataform-controls/telephone.js.map +1 -0
  100. package/build-module/dataform-controls/text.js +6 -48
  101. package/build-module/dataform-controls/text.js.map +1 -1
  102. package/build-module/dataform-controls/{boolean.js → toggle.js} +5 -3
  103. package/build-module/dataform-controls/toggle.js.map +1 -0
  104. package/build-module/dataform-controls/url.js +27 -0
  105. package/build-module/dataform-controls/url.js.map +1 -0
  106. package/build-module/dataform-controls/utils/validated-text.js +70 -0
  107. package/build-module/dataform-controls/utils/validated-text.js.map +1 -0
  108. package/build-module/dataforms-layouts/card/index.js +6 -7
  109. package/build-module/dataforms-layouts/card/index.js.map +1 -1
  110. package/build-module/dataforms-layouts/data-form-layout.js +14 -4
  111. package/build-module/dataforms-layouts/data-form-layout.js.map +1 -1
  112. package/build-module/dataforms-layouts/index.js +32 -1
  113. package/build-module/dataforms-layouts/index.js.map +1 -1
  114. package/build-module/dataforms-layouts/row/index.js +106 -0
  115. package/build-module/dataforms-layouts/row/index.js.map +1 -0
  116. package/build-module/dataviews-layouts/grid/index.js +16 -11
  117. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  118. package/build-module/dataviews-layouts/index.js +10 -2
  119. package/build-module/dataviews-layouts/index.js.map +1 -1
  120. package/build-module/dataviews-layouts/picker-grid/index.js +348 -0
  121. package/build-module/dataviews-layouts/picker-grid/index.js.map +1 -0
  122. package/build-module/dataviews-layouts/utils/grid-items.js +29 -0
  123. package/build-module/dataviews-layouts/utils/grid-items.js.map +1 -0
  124. package/build-module/dataviews-layouts/utils/preview-size-picker.js +73 -0
  125. package/build-module/dataviews-layouts/utils/preview-size-picker.js.map +1 -0
  126. package/build-module/field-types/boolean.js +1 -1
  127. package/build-module/field-types/boolean.js.map +1 -1
  128. package/build-module/field-types/color.js +107 -0
  129. package/build-module/field-types/color.js.map +1 -0
  130. package/build-module/field-types/index.js +12 -0
  131. package/build-module/field-types/index.js.map +1 -1
  132. package/build-module/field-types/telephone.js +51 -0
  133. package/build-module/field-types/telephone.js.map +1 -0
  134. package/build-module/field-types/url.js +51 -0
  135. package/build-module/field-types/url.js.map +1 -0
  136. package/build-module/normalize-form-fields.js +6 -0
  137. package/build-module/normalize-form-fields.js.map +1 -1
  138. package/build-module/types.js.map +1 -1
  139. package/build-module/validation.js +1 -1
  140. package/build-module/validation.js.map +1 -1
  141. package/build-style/style-rtl.css +252 -12
  142. package/build-style/style.css +252 -12
  143. package/build-types/components/dataform/stories/index.story.d.ts +19 -4
  144. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  145. package/build-types/components/dataform-context/index.d.ts.map +1 -1
  146. package/build-types/components/dataviews/index.d.ts +1 -1
  147. package/build-types/components/dataviews/index.d.ts.map +1 -1
  148. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  149. package/build-types/components/dataviews-context/index.d.ts +1 -0
  150. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  151. package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
  152. package/build-types/components/dataviews-picker/footer.d.ts +4 -0
  153. package/build-types/components/dataviews-picker/footer.d.ts.map +1 -0
  154. package/build-types/components/dataviews-picker/index.d.ts +55 -0
  155. package/build-types/components/dataviews-picker/index.d.ts.map +1 -0
  156. package/build-types/components/dataviews-picker/stories/index.story.d.ts +42 -0
  157. package/build-types/components/dataviews-picker/stories/index.story.d.ts.map +1 -0
  158. package/build-types/components/dataviews-selection-checkbox/index.d.ts +2 -1
  159. package/build-types/components/dataviews-selection-checkbox/index.d.ts.map +1 -1
  160. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  161. package/build-types/constants.d.ts +1 -0
  162. package/build-types/constants.d.ts.map +1 -1
  163. package/build-types/dataform-controls/checkbox.d.ts.map +1 -1
  164. package/build-types/dataform-controls/color.d.ts +6 -0
  165. package/build-types/dataform-controls/color.d.ts.map +1 -0
  166. package/build-types/dataform-controls/email.d.ts.map +1 -1
  167. package/build-types/dataform-controls/index.d.ts.map +1 -1
  168. package/build-types/dataform-controls/telephone.d.ts +6 -0
  169. package/build-types/dataform-controls/telephone.d.ts.map +1 -0
  170. package/build-types/dataform-controls/text.d.ts.map +1 -1
  171. package/build-types/dataform-controls/toggle.d.ts +6 -0
  172. package/build-types/dataform-controls/toggle.d.ts.map +1 -0
  173. package/build-types/dataform-controls/url.d.ts +6 -0
  174. package/build-types/dataform-controls/url.d.ts.map +1 -0
  175. package/build-types/dataform-controls/utils/validated-text.d.ts +16 -0
  176. package/build-types/dataform-controls/utils/validated-text.d.ts.map +1 -0
  177. package/build-types/dataforms-layouts/card/index.d.ts +0 -3
  178. package/build-types/dataforms-layouts/card/index.d.ts.map +1 -1
  179. package/build-types/dataforms-layouts/data-form-layout.d.ts +4 -1
  180. package/build-types/dataforms-layouts/data-form-layout.d.ts.map +1 -1
  181. package/build-types/dataforms-layouts/index.d.ts +10 -0
  182. package/build-types/dataforms-layouts/index.d.ts.map +1 -1
  183. package/build-types/dataforms-layouts/row/index.d.ts +6 -0
  184. package/build-types/dataforms-layouts/row/index.d.ts.map +1 -0
  185. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  186. package/build-types/dataviews-layouts/index.d.ts +12 -1
  187. package/build-types/dataviews-layouts/index.d.ts.map +1 -1
  188. package/build-types/dataviews-layouts/picker-grid/index.d.ts +4 -0
  189. package/build-types/dataviews-layouts/picker-grid/index.d.ts.map +1 -0
  190. package/build-types/dataviews-layouts/utils/grid-items.d.ts +5 -0
  191. package/build-types/dataviews-layouts/utils/grid-items.d.ts.map +1 -0
  192. package/build-types/dataviews-layouts/utils/preview-size-picker.d.ts +2 -0
  193. package/build-types/dataviews-layouts/utils/preview-size-picker.d.ts.map +1 -0
  194. package/build-types/field-types/color.d.ts +20 -0
  195. package/build-types/field-types/color.d.ts.map +1 -0
  196. package/build-types/field-types/index.d.ts.map +1 -1
  197. package/build-types/field-types/stories/index.story.d.ts +81 -0
  198. package/build-types/field-types/stories/index.story.d.ts.map +1 -0
  199. package/build-types/field-types/telephone.d.ts +20 -0
  200. package/build-types/field-types/telephone.d.ts.map +1 -0
  201. package/build-types/field-types/url.d.ts +20 -0
  202. package/build-types/field-types/url.d.ts.map +1 -0
  203. package/build-types/normalize-form-fields.d.ts.map +1 -1
  204. package/build-types/test/dataviews-picker.d.ts +2 -0
  205. package/build-types/test/dataviews-picker.d.ts.map +1 -0
  206. package/build-types/types.d.ts +36 -5
  207. package/build-types/types.d.ts.map +1 -1
  208. package/build-types/validation.d.ts.map +1 -1
  209. package/build-wp/index.js +5061 -4013
  210. package/package.json +16 -15
  211. package/src/components/dataform/stories/index.story.tsx +333 -11
  212. package/src/components/dataform-context/index.tsx +1 -0
  213. package/src/components/dataviews/index.tsx +25 -1
  214. package/src/components/dataviews/stories/fixtures.tsx +1 -1
  215. package/src/components/dataviews/stories/index.story.tsx +14 -0
  216. package/src/components/dataviews/style.scss +4 -2
  217. package/src/components/dataviews-context/index.ts +3 -0
  218. package/src/components/dataviews-layout/index.tsx +4 -2
  219. package/src/components/dataviews-picker/footer.tsx +207 -0
  220. package/src/components/dataviews-picker/index.tsx +284 -0
  221. package/src/components/dataviews-picker/stories/index.story.tsx +251 -0
  222. package/src/components/dataviews-picker/style.scss +10 -0
  223. package/src/components/dataviews-selection-checkbox/index.tsx +3 -0
  224. package/src/components/dataviews-view-config/index.tsx +1 -0
  225. package/src/constants.ts +3 -0
  226. package/src/dataform-controls/checkbox.tsx +33 -3
  227. package/src/dataform-controls/color.tsx +139 -0
  228. package/src/dataform-controls/email.tsx +10 -52
  229. package/src/dataform-controls/index.tsx +8 -2
  230. package/src/dataform-controls/telephone.tsx +30 -0
  231. package/src/dataform-controls/text.tsx +2 -57
  232. package/src/dataform-controls/{boolean.tsx → toggle.tsx} +3 -2
  233. package/src/dataform-controls/url.tsx +30 -0
  234. package/src/dataform-controls/utils/validated-text.tsx +96 -0
  235. package/src/dataforms-layouts/card/index.tsx +5 -4
  236. package/src/dataforms-layouts/card/style.scss +7 -0
  237. package/src/dataforms-layouts/data-form-layout.tsx +15 -3
  238. package/src/dataforms-layouts/index.tsx +35 -0
  239. package/src/dataforms-layouts/row/index.tsx +115 -0
  240. package/src/dataforms-layouts/row/style.scss +3 -0
  241. package/src/dataviews-layouts/grid/index.tsx +38 -33
  242. package/src/dataviews-layouts/grid/style.scss +42 -20
  243. package/src/dataviews-layouts/index.ts +16 -2
  244. package/src/dataviews-layouts/picker-grid/index.tsx +490 -0
  245. package/src/dataviews-layouts/picker-grid/style.scss +171 -0
  246. package/src/dataviews-layouts/utils/grid-items.scss +21 -0
  247. package/src/dataviews-layouts/utils/grid-items.tsx +35 -0
  248. package/src/dataviews-layouts/utils/preview-size-picker.tsx +87 -0
  249. package/src/field-types/boolean.tsx +1 -1
  250. package/src/field-types/color.tsx +115 -0
  251. package/src/field-types/index.tsx +15 -0
  252. package/src/field-types/stories/index.story.tsx +719 -0
  253. package/src/field-types/telephone.tsx +71 -0
  254. package/src/field-types/url.tsx +71 -0
  255. package/src/normalize-form-fields.ts +6 -0
  256. package/src/style.scss +4 -0
  257. package/src/test/dataform.tsx +2 -2
  258. package/src/test/dataviews-picker.tsx +478 -0
  259. package/src/test/dataviews.tsx +86 -0
  260. package/src/types.ts +56 -4
  261. package/src/validation.ts +3 -0
  262. package/tsconfig.tsbuildinfo +1 -1
  263. package/build/dataform-controls/boolean.js.map +0 -1
  264. package/build-module/dataform-controls/boolean.js.map +0 -1
  265. package/build-types/components/stories/index.story.d.ts +0 -63
  266. package/build-types/components/stories/index.story.d.ts.map +0 -1
  267. package/build-types/dataform-controls/boolean.d.ts +0 -6
  268. package/build-types/dataform-controls/boolean.d.ts.map +0 -1
  269. package/src/components/stories/index.story.tsx +0 -372
@@ -1,24 +1,6 @@
1
- .dataviews-view-grid {
2
- margin-bottom: auto;
3
- display: grid;
4
- gap: $grid-unit-40;
5
- grid-template-rows: max-content;
6
- grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
7
- padding: 0 $grid-unit-60 $grid-unit-30;
8
- container-type: inline-size;
9
- /**
10
- * Breakpoints were adjusted from media queries breakpoints to account for
11
- * the sidebar width. This was done to match the existing styles we had.
12
- */
13
- @container (max-width: 480px) {
14
- padding-left: $grid-unit-30;
15
- padding-right: $grid-unit-30;
16
- }
17
-
18
- @media not (prefers-reduced-motion) {
19
- transition: padding ease-out 0.1s;
20
- }
1
+ @import "../utils/grid-items.scss";
21
2
 
3
+ .dataviews-view-grid {
22
4
  .dataviews-view-grid__card {
23
5
  height: 100%;
24
6
  justify-content: flex-start;
@@ -139,9 +121,15 @@
139
121
  top: -9999em;
140
122
  left: $grid-unit-10;
141
123
  z-index: z-index(".dataviews-view-grid__card .dataviews-selection-checkbox");
124
+ opacity: 0;
125
+
126
+ @media not (prefers-reduced-motion) {
127
+ transition: opacity 0.1s linear;
128
+ }
142
129
 
143
130
  @media (hover: none) {
144
131
  // Show checkboxes on devices that do not support hover.
132
+ opacity: 1;
145
133
  top: $grid-unit-10;
146
134
  }
147
135
  }
@@ -149,9 +137,37 @@
149
137
  .dataviews-view-grid__card:hover .dataviews-selection-checkbox,
150
138
  .dataviews-view-grid__card:focus-within .dataviews-selection-checkbox,
151
139
  .dataviews-view-grid__card.is-selected .dataviews-selection-checkbox {
140
+ opacity: 1;
152
141
  top: $grid-unit-10;
153
142
  }
154
143
 
144
+ .dataviews-view-grid__card .dataviews-view-grid__media-actions {
145
+ position: absolute;
146
+ top: $grid-unit-05;
147
+ opacity: 0;
148
+ right: $grid-unit-05;
149
+
150
+ .dataviews-all-actions-button {
151
+ background-color: $white;
152
+ }
153
+
154
+ @media not (prefers-reduced-motion) {
155
+ transition: opacity 0.1s linear;
156
+ }
157
+
158
+ @media (hover: none) {
159
+ // Show actions on devices that do not support hover.
160
+ opacity: 1;
161
+ top: $grid-unit-05;
162
+ }
163
+ }
164
+
165
+ .dataviews-view-grid__card:hover .dataviews-view-grid__media-actions,
166
+ .dataviews-view-grid__card:focus-within .dataviews-view-grid__media-actions,
167
+ .dataviews-view-grid__card .dataviews-view-grid__media-actions:has(.dataviews-all-actions-button[aria-expanded="true"]) {
168
+ opacity: 1;
169
+ }
170
+
155
171
  .dataviews-view-grid__media--clickable {
156
172
  cursor: pointer;
157
173
  }
@@ -162,4 +178,10 @@
162
178
  color: $gray-900;
163
179
  margin: 0 0 $grid-unit-10 0;
164
180
  padding: 0 $grid-unit-60;
181
+ container-type: inline-size;
182
+
183
+ @container (max-width: 430px) {
184
+ padding-left: $grid-unit-30;
185
+ padding-right: $grid-unit-30;
186
+ }
165
187
  }
@@ -15,8 +15,14 @@ import {
15
15
  import ViewTable from './table';
16
16
  import ViewGrid from './grid';
17
17
  import ViewList from './list';
18
- import { LAYOUT_GRID, LAYOUT_LIST, LAYOUT_TABLE } from '../constants';
19
- import PreviewSizePicker from './grid/preview-size-picker';
18
+ import ViewPickerGrid from './picker-grid';
19
+ import {
20
+ LAYOUT_GRID,
21
+ LAYOUT_LIST,
22
+ LAYOUT_TABLE,
23
+ LAYOUT_PICKER_GRID,
24
+ } from '../constants';
25
+ import PreviewSizePicker from './utils/preview-size-picker';
20
26
  import DensityPicker from './table/density-picker';
21
27
 
22
28
  export const VIEW_LAYOUTS = [
@@ -40,4 +46,12 @@ export const VIEW_LAYOUTS = [
40
46
  component: ViewList,
41
47
  icon: isRTL() ? formatListBulletsRTL : formatListBullets,
42
48
  },
49
+ {
50
+ type: LAYOUT_PICKER_GRID,
51
+ label: __( 'Grid' ),
52
+ component: ViewPickerGrid,
53
+ icon: category,
54
+ viewConfigOptions: PreviewSizePicker,
55
+ isPicker: true,
56
+ },
43
57
  ];
@@ -0,0 +1,490 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+ import type { ReactNode } from 'react';
6
+
7
+ /**
8
+ * WordPress dependencies
9
+ */
10
+ import {
11
+ __experimentalHStack as HStack,
12
+ __experimentalVStack as VStack,
13
+ Spinner,
14
+ Flex,
15
+ FlexItem,
16
+ privateApis as componentsPrivateApis,
17
+ Composite,
18
+ } from '@wordpress/components';
19
+ import { __, sprintf } from '@wordpress/i18n';
20
+ import { useInstanceId } from '@wordpress/compose';
21
+ import { useContext } from '@wordpress/element';
22
+
23
+ /**
24
+ * Internal dependencies
25
+ */
26
+ import { unlock } from '../../lock-unlock';
27
+ import DataViewsSelectionCheckbox from '../../components/dataviews-selection-checkbox';
28
+ import DataViewsContext from '../../components/dataviews-context';
29
+ import { useIsMultiselectPicker } from '../../components/dataviews-picker/footer';
30
+ import type {
31
+ NormalizedField,
32
+ ViewPickerGrid as ViewPickerGridType,
33
+ ViewPickerGridProps,
34
+ } from '../../types';
35
+ import type { SetSelection } from '../../private-types';
36
+ import { GridItems } from '../utils/grid-items';
37
+ const { Badge } = unlock( componentsPrivateApis );
38
+
39
+ interface GridItemProps< Item > {
40
+ view: ViewPickerGridType;
41
+ multiselect?: boolean;
42
+ selection: string[];
43
+ onChangeSelection: SetSelection;
44
+ getItemId: ( item: Item ) => string;
45
+ item: Item;
46
+ titleField?: NormalizedField< Item >;
47
+ mediaField?: NormalizedField< Item >;
48
+ descriptionField?: NormalizedField< Item >;
49
+ regularFields: NormalizedField< Item >[];
50
+ badgeFields: NormalizedField< Item >[];
51
+ config: {
52
+ sizes: string;
53
+ };
54
+ posinset?: number;
55
+ setsize?: number;
56
+ }
57
+
58
+ function GridItem< Item >( {
59
+ view,
60
+ multiselect,
61
+ selection,
62
+ onChangeSelection,
63
+ getItemId,
64
+ item,
65
+ mediaField,
66
+ titleField,
67
+ descriptionField,
68
+ regularFields,
69
+ badgeFields,
70
+ config,
71
+ posinset,
72
+ setsize,
73
+ }: GridItemProps< Item > ) {
74
+ const { showTitle = true, showMedia = true, showDescription = true } = view;
75
+ const id = getItemId( item );
76
+ const isSelected = selection.includes( id );
77
+ const renderedMediaField = mediaField?.render ? (
78
+ <mediaField.render
79
+ item={ item }
80
+ field={ mediaField }
81
+ config={ config }
82
+ />
83
+ ) : null;
84
+ const renderedTitleField =
85
+ showTitle && titleField?.render ? (
86
+ <titleField.render item={ item } field={ titleField } />
87
+ ) : null;
88
+
89
+ return (
90
+ <Composite.Item
91
+ key={ id }
92
+ render={ ( { children, ...props } ) => (
93
+ <VStack spacing={ 0 } children={ children } { ...props } />
94
+ ) }
95
+ role="option"
96
+ aria-posinset={ posinset }
97
+ aria-setsize={ setsize }
98
+ className={ clsx( 'dataviews-view-picker-grid__card', {
99
+ 'is-selected': isSelected,
100
+ } ) }
101
+ aria-selected={ isSelected }
102
+ onClick={ () => {
103
+ if ( isSelected ) {
104
+ onChangeSelection(
105
+ selection.filter( ( itemId ) => id !== itemId )
106
+ );
107
+ } else {
108
+ const newSelection = multiselect
109
+ ? [ ...selection, id ]
110
+ : [ id ];
111
+ onChangeSelection( newSelection );
112
+ }
113
+ } }
114
+ >
115
+ { showMedia && renderedMediaField && (
116
+ <div className="dataviews-view-picker-grid__media">
117
+ { renderedMediaField }
118
+ </div>
119
+ ) }
120
+ { showMedia && renderedMediaField && (
121
+ <DataViewsSelectionCheckbox
122
+ item={ item }
123
+ selection={ selection }
124
+ onChangeSelection={ onChangeSelection }
125
+ getItemId={ getItemId }
126
+ titleField={ titleField }
127
+ disabled={ false }
128
+ aria-hidden
129
+ tabIndex={ -1 }
130
+ />
131
+ ) }
132
+ <HStack
133
+ justify="space-between"
134
+ className="dataviews-view-picker-grid__title-actions"
135
+ >
136
+ <div className="dataviews-view-picker-grid__title-field dataviews-title-field">
137
+ { renderedTitleField }
138
+ </div>
139
+ </HStack>
140
+ <VStack spacing={ 1 }>
141
+ { showDescription && descriptionField?.render && (
142
+ <descriptionField.render
143
+ item={ item }
144
+ field={ descriptionField }
145
+ />
146
+ ) }
147
+ { !! badgeFields?.length && (
148
+ <HStack
149
+ className="dataviews-view-picker-grid__badge-fields"
150
+ spacing={ 2 }
151
+ wrap
152
+ alignment="top"
153
+ justify="flex-start"
154
+ >
155
+ { badgeFields.map( ( field ) => {
156
+ return (
157
+ <Badge
158
+ key={ field.id }
159
+ className="dataviews-view-picker-grid__field-value"
160
+ >
161
+ <field.render
162
+ item={ item }
163
+ field={ field }
164
+ />
165
+ </Badge>
166
+ );
167
+ } ) }
168
+ </HStack>
169
+ ) }
170
+ { !! regularFields?.length && (
171
+ <VStack
172
+ className="dataviews-view-picker-grid__fields"
173
+ spacing={ 1 }
174
+ >
175
+ { regularFields.map( ( field ) => {
176
+ return (
177
+ <Flex
178
+ className="dataviews-view-picker-grid__field"
179
+ key={ field.id }
180
+ gap={ 1 }
181
+ justify="flex-start"
182
+ expanded
183
+ style={ { height: 'auto' } }
184
+ direction="row"
185
+ >
186
+ <>
187
+ <FlexItem className="dataviews-view-picker-grid__field-name">
188
+ { field.header }
189
+ </FlexItem>
190
+ <FlexItem
191
+ className="dataviews-view-picker-grid__field-value"
192
+ style={ { maxHeight: 'none' } }
193
+ >
194
+ <field.render
195
+ item={ item }
196
+ field={ field }
197
+ />
198
+ </FlexItem>
199
+ </>
200
+ </Flex>
201
+ );
202
+ } ) }
203
+ </VStack>
204
+ ) }
205
+ </VStack>
206
+ </Composite.Item>
207
+ );
208
+ }
209
+
210
+ function GridGroup< Item >( {
211
+ groupName,
212
+ groupField,
213
+ children,
214
+ }: {
215
+ groupName: string;
216
+ groupField: NormalizedField< Item >;
217
+ children: ReactNode;
218
+ } ) {
219
+ const headerId = useInstanceId(
220
+ GridGroup,
221
+ 'dataviews-view-picker-grid-group__header'
222
+ );
223
+ return (
224
+ <VStack
225
+ key={ groupName }
226
+ spacing={ 2 }
227
+ role="group"
228
+ aria-labelledby={ headerId }
229
+ >
230
+ <h3
231
+ className="dataviews-view-picker-grid-group__header"
232
+ id={ headerId }
233
+ >
234
+ { sprintf(
235
+ // translators: 1: The label of the field e.g. "Date". 2: The value of the field, e.g.: "May 2022".
236
+ __( '%1$s: %2$s' ),
237
+ groupField.label,
238
+ groupName
239
+ ) }
240
+ </h3>
241
+ { children }
242
+ </VStack>
243
+ );
244
+ }
245
+
246
+ function ViewPickerGrid< Item >( {
247
+ actions,
248
+ data,
249
+ fields,
250
+ getItemId,
251
+ isLoading,
252
+ onChangeSelection,
253
+ selection,
254
+ view,
255
+ className,
256
+ empty,
257
+ }: ViewPickerGridProps< Item > ) {
258
+ const { resizeObserverRef, paginationInfo, itemListLabel } =
259
+ useContext( DataViewsContext );
260
+ const titleField = fields.find(
261
+ ( field ) => field.id === view?.titleField
262
+ );
263
+ const mediaField = fields.find(
264
+ ( field ) => field.id === view?.mediaField
265
+ );
266
+ const descriptionField = fields.find(
267
+ ( field ) => field.id === view?.descriptionField
268
+ );
269
+ const otherFields = view.fields ?? [];
270
+ const { regularFields, badgeFields } = otherFields.reduce(
271
+ (
272
+ accumulator: Record< string, NormalizedField< Item >[] >,
273
+ fieldId
274
+ ) => {
275
+ const field = fields.find( ( f ) => f.id === fieldId );
276
+ if ( ! field ) {
277
+ return accumulator;
278
+ }
279
+ // If the field is a badge field, add it to the badgeFields array
280
+ // otherwise add it to the rest visibleFields array.
281
+ const key = view.layout?.badgeFields?.includes( fieldId )
282
+ ? 'badgeFields'
283
+ : 'regularFields';
284
+ accumulator[ key ].push( field );
285
+ return accumulator;
286
+ },
287
+ { regularFields: [], badgeFields: [] }
288
+ );
289
+ const hasData = !! data?.length;
290
+ const usedPreviewSize = view.layout?.previewSize;
291
+ const isMultiselect = useIsMultiselectPicker( actions );
292
+
293
+ /*
294
+ * This is the maximum width that an image can achieve in the grid. The reasoning is:
295
+ * The biggest min image width available is 430px (see /dataviews-layouts/grid/preview-size-picker.tsx).
296
+ * Because the grid is responsive, once there is room for another column, the images shrink to accommodate it.
297
+ * So each image will never grow past 2*430px plus a little more to account for the gaps.
298
+ */
299
+ const size = '900px';
300
+
301
+ const groupField = view.groupByField
302
+ ? fields.find( ( f ) => f.id === view.groupByField )
303
+ : null;
304
+
305
+ // Group data by groupByField if specified
306
+ const dataByGroup = groupField
307
+ ? data.reduce( ( groups: Map< string, typeof data >, item ) => {
308
+ const groupName = groupField.getValue( { item } );
309
+ if ( ! groups.has( groupName ) ) {
310
+ groups.set( groupName, [] );
311
+ }
312
+ groups.get( groupName )?.push( item );
313
+ return groups;
314
+ }, new Map< string, typeof data >() )
315
+ : null;
316
+
317
+ const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
318
+
319
+ const currentPage = view?.page ?? 1;
320
+ const perPage = view?.perPage ?? 0;
321
+ const setSize = isInfiniteScroll ? paginationInfo?.totalItems : undefined;
322
+
323
+ return (
324
+ <>
325
+ {
326
+ // Render multiple groups.
327
+ hasData && groupField && dataByGroup && (
328
+ <Composite
329
+ virtualFocus
330
+ orientation="horizontal"
331
+ role="listbox"
332
+ aria-multiselectable={ isMultiselect }
333
+ className={ clsx(
334
+ 'dataviews-view-picker-grid',
335
+ className
336
+ ) }
337
+ aria-label={ itemListLabel }
338
+ render={ ( { children, ...props } ) => (
339
+ <VStack
340
+ spacing={ 4 }
341
+ children={ children }
342
+ { ...props }
343
+ />
344
+ ) }
345
+ >
346
+ { Array.from( dataByGroup.entries() ).map(
347
+ ( [ groupName, groupItems ] ) => (
348
+ <GridGroup
349
+ key={ groupName }
350
+ groupName={ groupName }
351
+ groupField={ groupField }
352
+ >
353
+ <GridItems
354
+ previewSize={ usedPreviewSize }
355
+ style={ {
356
+ gridTemplateColumns:
357
+ usedPreviewSize &&
358
+ `repeat(auto-fill, minmax(${ usedPreviewSize }px, 1fr))`,
359
+ } }
360
+ aria-busy={ isLoading }
361
+ ref={
362
+ resizeObserverRef as React.RefObject< HTMLDivElement >
363
+ }
364
+ >
365
+ { groupItems.map( ( item ) => {
366
+ const posInSet =
367
+ ( currentPage - 1 ) * perPage +
368
+ data.indexOf( item ) +
369
+ 1;
370
+ return (
371
+ <GridItem
372
+ key={ getItemId( item ) }
373
+ view={ view }
374
+ multiselect={
375
+ isMultiselect
376
+ }
377
+ selection={ selection }
378
+ onChangeSelection={
379
+ onChangeSelection
380
+ }
381
+ getItemId={ getItemId }
382
+ item={ item }
383
+ mediaField={ mediaField }
384
+ titleField={ titleField }
385
+ descriptionField={
386
+ descriptionField
387
+ }
388
+ regularFields={
389
+ regularFields
390
+ }
391
+ badgeFields={ badgeFields }
392
+ config={ {
393
+ sizes: size,
394
+ } }
395
+ posinset={ posInSet }
396
+ setsize={ setSize }
397
+ />
398
+ );
399
+ } ) }
400
+ </GridItems>
401
+ </GridGroup>
402
+ )
403
+ ) }
404
+ </Composite>
405
+ )
406
+ }
407
+
408
+ {
409
+ // Render a single grid with all data.
410
+ hasData && ! dataByGroup && (
411
+ <Composite
412
+ render={
413
+ <GridItems
414
+ className={ clsx(
415
+ 'dataviews-view-picker-grid',
416
+ className
417
+ ) }
418
+ previewSize={ usedPreviewSize }
419
+ aria-busy={ isLoading }
420
+ ref={
421
+ resizeObserverRef as React.RefObject< HTMLDivElement >
422
+ }
423
+ />
424
+ }
425
+ virtualFocus
426
+ orientation="horizontal"
427
+ role="listbox"
428
+ aria-multiselectable={ isMultiselect }
429
+ aria-label={ itemListLabel }
430
+ >
431
+ { data.map( ( item, index ) => {
432
+ let posinset = isInfiniteScroll
433
+ ? index + 1
434
+ : undefined;
435
+
436
+ if ( ! isInfiniteScroll ) {
437
+ // When infinite scroll isn't active, take pagination into account
438
+ // when calculating the posinset.
439
+ posinset =
440
+ ( currentPage - 1 ) * perPage + index + 1;
441
+ }
442
+
443
+ return (
444
+ <GridItem
445
+ key={ getItemId( item ) }
446
+ view={ view }
447
+ multiselect={ isMultiselect }
448
+ selection={ selection }
449
+ onChangeSelection={ onChangeSelection }
450
+ getItemId={ getItemId }
451
+ item={ item }
452
+ mediaField={ mediaField }
453
+ titleField={ titleField }
454
+ descriptionField={ descriptionField }
455
+ regularFields={ regularFields }
456
+ badgeFields={ badgeFields }
457
+ config={ {
458
+ sizes: size,
459
+ } }
460
+ posinset={ posinset }
461
+ setsize={ setSize }
462
+ />
463
+ );
464
+ } ) }
465
+ </Composite>
466
+ )
467
+ }
468
+ {
469
+ // Render empty state.
470
+ ! hasData && (
471
+ <div
472
+ className={ clsx( {
473
+ 'dataviews-loading': isLoading,
474
+ 'dataviews-no-results': ! isLoading,
475
+ } ) }
476
+ >
477
+ <p>{ isLoading ? <Spinner /> : empty }</p>
478
+ </div>
479
+ )
480
+ }
481
+ { hasData && isLoading && (
482
+ <p className="dataviews-loading-more">
483
+ <Spinner />
484
+ </p>
485
+ ) }
486
+ </>
487
+ );
488
+ }
489
+
490
+ export default ViewPickerGrid;