@wordpress/dataviews 6.0.0 → 7.0.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 (194) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/README.md +42 -14
  3. package/build/components/dataviews/index.js +38 -6
  4. package/build/components/dataviews/index.js.map +1 -1
  5. package/build/components/dataviews-context/index.js +4 -1
  6. package/build/components/dataviews-context/index.js.map +1 -1
  7. package/build/components/dataviews-item-actions/index.js +1 -10
  8. package/build/components/dataviews-item-actions/index.js.map +1 -1
  9. package/build/components/dataviews-pagination/index.js +1 -1
  10. package/build/components/dataviews-pagination/index.js.map +1 -1
  11. package/build/components/dataviews-view-config/index.js +8 -5
  12. package/build/components/dataviews-view-config/index.js.map +1 -1
  13. package/build/components/dataviews-view-config/infinite-scroll-toggle.js +47 -0
  14. package/build/components/dataviews-view-config/infinite-scroll-toggle.js.map +1 -0
  15. package/build/dataform-controls/array.js +70 -0
  16. package/build/dataform-controls/array.js.map +1 -0
  17. package/build/dataform-controls/boolean.js +15 -7
  18. package/build/dataform-controls/boolean.js.map +1 -1
  19. package/build/dataform-controls/email.js +14 -7
  20. package/build/dataform-controls/email.js.map +1 -1
  21. package/build/dataform-controls/index.js +3 -1
  22. package/build/dataform-controls/index.js.map +1 -1
  23. package/build/dataform-controls/integer.js +14 -7
  24. package/build/dataform-controls/integer.js.map +1 -1
  25. package/build/dataform-controls/text.js +14 -7
  26. package/build/dataform-controls/text.js.map +1 -1
  27. package/build/dataforms-layouts/card/index.js +137 -0
  28. package/build/dataforms-layouts/card/index.js.map +1 -0
  29. package/build/dataforms-layouts/data-form-layout.js +2 -2
  30. package/build/dataforms-layouts/data-form-layout.js.map +1 -1
  31. package/build/dataforms-layouts/index.js +4 -0
  32. package/build/dataforms-layouts/index.js.map +1 -1
  33. package/build/dataforms-layouts/panel/dropdown.js +124 -0
  34. package/build/dataforms-layouts/panel/dropdown.js.map +1 -0
  35. package/build/dataforms-layouts/panel/index.js +34 -149
  36. package/build/dataforms-layouts/panel/index.js.map +1 -1
  37. package/build/dataforms-layouts/panel/modal.js +125 -0
  38. package/build/dataforms-layouts/panel/modal.js.map +1 -0
  39. package/build/dataforms-layouts/regular/index.js +10 -21
  40. package/build/dataforms-layouts/regular/index.js.map +1 -1
  41. package/build/dataviews-layouts/grid/index.js +24 -7
  42. package/build/dataviews-layouts/grid/index.js.map +1 -1
  43. package/build/dataviews-layouts/grid/preview-size-picker.js +11 -11
  44. package/build/dataviews-layouts/grid/preview-size-picker.js.map +1 -1
  45. package/build/dataviews-layouts/list/index.js +45 -27
  46. package/build/dataviews-layouts/list/index.js.map +1 -1
  47. package/build/dataviews-layouts/table/column-header-menu.js +3 -0
  48. package/build/dataviews-layouts/table/column-header-menu.js.map +1 -1
  49. package/build/dataviews-layouts/table/index.js +23 -8
  50. package/build/dataviews-layouts/table/index.js.map +1 -1
  51. package/build/field-types/array.js +2 -2
  52. package/build/field-types/array.js.map +1 -1
  53. package/build/normalize-form-fields.js +52 -13
  54. package/build/normalize-form-fields.js.map +1 -1
  55. package/build/types.js.map +1 -1
  56. package/build-module/components/dataviews/index.js +40 -8
  57. package/build-module/components/dataviews/index.js.map +1 -1
  58. package/build-module/components/dataviews-context/index.js +4 -1
  59. package/build-module/components/dataviews-context/index.js.map +1 -1
  60. package/build-module/components/dataviews-item-actions/index.js +1 -10
  61. package/build-module/components/dataviews-item-actions/index.js.map +1 -1
  62. package/build-module/components/dataviews-pagination/index.js +1 -1
  63. package/build-module/components/dataviews-pagination/index.js.map +1 -1
  64. package/build-module/components/dataviews-view-config/index.js +8 -5
  65. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  66. package/build-module/components/dataviews-view-config/infinite-scroll-toggle.js +39 -0
  67. package/build-module/components/dataviews-view-config/infinite-scroll-toggle.js.map +1 -0
  68. package/build-module/dataform-controls/array.js +63 -0
  69. package/build-module/dataform-controls/array.js.map +1 -0
  70. package/build-module/dataform-controls/boolean.js +15 -7
  71. package/build-module/dataform-controls/boolean.js.map +1 -1
  72. package/build-module/dataform-controls/email.js +15 -8
  73. package/build-module/dataform-controls/email.js.map +1 -1
  74. package/build-module/dataform-controls/index.js +3 -1
  75. package/build-module/dataform-controls/index.js.map +1 -1
  76. package/build-module/dataform-controls/integer.js +15 -8
  77. package/build-module/dataform-controls/integer.js.map +1 -1
  78. package/build-module/dataform-controls/text.js +15 -8
  79. package/build-module/dataform-controls/text.js.map +1 -1
  80. package/build-module/dataforms-layouts/card/index.js +128 -0
  81. package/build-module/dataforms-layouts/card/index.js.map +1 -0
  82. package/build-module/dataforms-layouts/data-form-layout.js +2 -2
  83. package/build-module/dataforms-layouts/data-form-layout.js.map +1 -1
  84. package/build-module/dataforms-layouts/index.js +4 -0
  85. package/build-module/dataforms-layouts/index.js.map +1 -1
  86. package/build-module/dataforms-layouts/panel/dropdown.js +118 -0
  87. package/build-module/dataforms-layouts/panel/dropdown.js.map +1 -0
  88. package/build-module/dataforms-layouts/panel/index.js +37 -152
  89. package/build-module/dataforms-layouts/panel/index.js.map +1 -1
  90. package/build-module/dataforms-layouts/panel/modal.js +119 -0
  91. package/build-module/dataforms-layouts/panel/modal.js.map +1 -0
  92. package/build-module/dataforms-layouts/regular/index.js +10 -21
  93. package/build-module/dataforms-layouts/regular/index.js.map +1 -1
  94. package/build-module/dataviews-layouts/grid/index.js +25 -8
  95. package/build-module/dataviews-layouts/grid/index.js.map +1 -1
  96. package/build-module/dataviews-layouts/grid/preview-size-picker.js +11 -11
  97. package/build-module/dataviews-layouts/grid/preview-size-picker.js.map +1 -1
  98. package/build-module/dataviews-layouts/list/index.js +47 -29
  99. package/build-module/dataviews-layouts/list/index.js.map +1 -1
  100. package/build-module/dataviews-layouts/table/column-header-menu.js +3 -0
  101. package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -1
  102. package/build-module/dataviews-layouts/table/index.js +23 -8
  103. package/build-module/dataviews-layouts/table/index.js.map +1 -1
  104. package/build-module/field-types/array.js +2 -2
  105. package/build-module/field-types/array.js.map +1 -1
  106. package/build-module/normalize-form-fields.js +50 -13
  107. package/build-module/normalize-form-fields.js.map +1 -1
  108. package/build-module/types.js.map +1 -1
  109. package/build-style/style-rtl.css +53 -16
  110. package/build-style/style.css +53 -16
  111. package/build-types/components/dataform/stories/index.story.d.ts +41 -17
  112. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  113. package/build-types/components/dataviews/index.d.ts +5 -2
  114. package/build-types/components/dataviews/index.d.ts.map +1 -1
  115. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  116. package/build-types/components/dataviews/stories/index.story.d.ts +2 -1
  117. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  118. package/build-types/components/dataviews-context/index.d.ts +4 -1
  119. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  120. package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
  121. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  122. package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts +2 -0
  123. package/build-types/components/dataviews-view-config/infinite-scroll-toggle.d.ts.map +1 -0
  124. package/build-types/dataform-controls/array.d.ts +6 -0
  125. package/build-types/dataform-controls/array.d.ts.map +1 -0
  126. package/build-types/dataform-controls/boolean.d.ts.map +1 -1
  127. package/build-types/dataform-controls/email.d.ts.map +1 -1
  128. package/build-types/dataform-controls/index.d.ts.map +1 -1
  129. package/build-types/dataform-controls/integer.d.ts.map +1 -1
  130. package/build-types/dataform-controls/text.d.ts.map +1 -1
  131. package/build-types/dataforms-layouts/card/index.d.ts +13 -0
  132. package/build-types/dataforms-layouts/card/index.d.ts.map +1 -0
  133. package/build-types/dataforms-layouts/index.d.ts.map +1 -1
  134. package/build-types/dataforms-layouts/panel/dropdown.d.ts +14 -0
  135. package/build-types/dataforms-layouts/panel/dropdown.d.ts.map +1 -0
  136. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -1
  137. package/build-types/dataforms-layouts/panel/modal.d.ts +13 -0
  138. package/build-types/dataforms-layouts/panel/modal.d.ts.map +1 -0
  139. package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -1
  140. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -1
  141. package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts +1 -1
  142. package/build-types/dataviews-layouts/grid/preview-size-picker.d.ts.map +1 -1
  143. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -1
  144. package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -1
  145. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  146. package/build-types/field-types/boolean.d.ts +1 -1
  147. package/build-types/normalize-form-fields.d.ts +10 -3
  148. package/build-types/normalize-form-fields.d.ts.map +1 -1
  149. package/build-types/test/normalize-form-fields.d.ts +2 -0
  150. package/build-types/test/normalize-form-fields.d.ts.map +1 -0
  151. package/build-types/types.d.ts +54 -6
  152. package/build-types/types.d.ts.map +1 -1
  153. package/build-wp/index.js +3062 -1147
  154. package/package.json +15 -15
  155. package/src/components/dataform/stories/index.story.tsx +478 -91
  156. package/src/components/dataviews/index.tsx +50 -14
  157. package/src/components/dataviews/stories/fixtures.tsx +98 -7
  158. package/src/components/dataviews/stories/index.story.tsx +137 -4
  159. package/src/components/dataviews/style.scss +4 -0
  160. package/src/components/dataviews-context/index.ts +6 -2
  161. package/src/components/dataviews-item-actions/index.tsx +7 -16
  162. package/src/components/dataviews-pagination/index.tsx +1 -1
  163. package/src/components/dataviews-view-config/index.tsx +13 -5
  164. package/src/components/dataviews-view-config/infinite-scroll-toggle.tsx +39 -0
  165. package/src/dataform-controls/array.tsx +85 -0
  166. package/src/dataform-controls/boolean.tsx +24 -10
  167. package/src/dataform-controls/email.tsx +24 -11
  168. package/src/dataform-controls/index.tsx +3 -1
  169. package/src/dataform-controls/integer.tsx +27 -13
  170. package/src/dataform-controls/text.tsx +24 -11
  171. package/src/dataforms-layouts/card/index.tsx +154 -0
  172. package/src/dataforms-layouts/card/style.scss +3 -0
  173. package/src/dataforms-layouts/data-form-layout.tsx +2 -2
  174. package/src/dataforms-layouts/index.tsx +5 -0
  175. package/src/dataforms-layouts/panel/dropdown.tsx +160 -0
  176. package/src/dataforms-layouts/panel/index.tsx +49 -189
  177. package/src/dataforms-layouts/panel/modal.tsx +165 -0
  178. package/src/dataforms-layouts/panel/style.scss +4 -0
  179. package/src/dataforms-layouts/regular/index.tsx +20 -23
  180. package/src/dataviews-layouts/grid/index.tsx +32 -5
  181. package/src/dataviews-layouts/grid/preview-size-picker.tsx +15 -13
  182. package/src/dataviews-layouts/grid/style.scss +3 -1
  183. package/src/dataviews-layouts/list/index.tsx +65 -31
  184. package/src/dataviews-layouts/list/style.scss +7 -3
  185. package/src/dataviews-layouts/table/column-header-menu.tsx +4 -0
  186. package/src/dataviews-layouts/table/index.tsx +27 -1
  187. package/src/field-types/array.tsx +1 -1
  188. package/src/normalize-form-fields.ts +63 -17
  189. package/src/test/dataform.tsx +181 -3
  190. package/src/test/dataviews.tsx +38 -0
  191. package/src/test/filter-and-sort-data-view.js +123 -64
  192. package/src/test/normalize-form-fields.ts +247 -0
  193. package/src/types.ts +72 -6
  194. package/tsconfig.tsbuildinfo +1 -1
@@ -41,8 +41,10 @@ describe( 'filters', () => {
41
41
  },
42
42
  fields
43
43
  );
44
- expect( result ).toHaveLength( 1 );
45
- expect( result[ 0 ].title ).toBe( 'Neptune' );
44
+ expect( result ).toHaveLength( 4 );
45
+ expect(
46
+ result.find( ( item ) => item.title === 'Neptune' )
47
+ ).toBeDefined();
46
48
  } );
47
49
 
48
50
  it( 'should search using searchable fields (description)', () => {
@@ -89,13 +91,11 @@ describe( 'filters', () => {
89
91
  fieldsWithArraySearch
90
92
  );
91
93
 
92
- // Should find items with "satellite" in categories
93
- expect( result ).toHaveLength( 3 );
94
- expect( result.map( ( r ) => r.title ).sort() ).toEqual( [
95
- 'Europa',
96
- 'Io',
97
- 'Moon',
98
- ] );
94
+ // Should find items with "Moon" in categories
95
+ expect( result ).toHaveLength( 10 );
96
+ expect( result.map( ( r ) => r.title ).sort() ).toContain( 'Europa' );
97
+ expect( result.map( ( r ) => r.title ).sort() ).toContain( 'Io' );
98
+ expect( result.map( ( r ) => r.title ).sort() ).toContain( 'Moon' );
99
99
  } );
100
100
 
101
101
  it( 'should search over array fields case-insensitively', () => {
@@ -154,16 +154,23 @@ describe( 'filters', () => {
154
154
  },
155
155
  fields
156
156
  );
157
- expect( result ).toHaveLength( 9 );
157
+ expect( result ).toHaveLength( 16 );
158
158
  expect( result[ 0 ].title ).toBe( 'Moon' );
159
159
  expect( result[ 1 ].title ).toBe( 'Io' );
160
160
  expect( result[ 2 ].title ).toBe( 'Europa' );
161
- expect( result[ 3 ].title ).toBe( 'Mercury' );
162
- expect( result[ 4 ].title ).toBe( 'Venus' );
163
- expect( result[ 5 ].title ).toBe( 'Earth' );
164
- expect( result[ 6 ].title ).toBe( 'Mars' );
165
- expect( result[ 7 ].title ).toBe( 'Jupiter' );
166
- expect( result[ 8 ].title ).toBe( 'Saturn' );
161
+ expect( result[ 3 ].title ).toBe( 'Ganymede' );
162
+ expect( result[ 4 ].title ).toBe( 'Callisto' );
163
+ expect( result[ 5 ].title ).toBe( 'Amalthea' );
164
+ expect( result[ 6 ].title ).toBe( 'Himalia' );
165
+ expect( result[ 7 ].title ).toBe( 'Triton' );
166
+ expect( result[ 8 ].title ).toBe( 'Nereid' );
167
+ expect( result[ 9 ].title ).toBe( 'Proteus' );
168
+ expect( result[ 10 ].title ).toBe( 'Mercury' );
169
+ expect( result[ 11 ].title ).toBe( 'Venus' );
170
+ expect( result[ 12 ].title ).toBe( 'Earth' );
171
+ expect( result[ 13 ].title ).toBe( 'Mars' );
172
+ expect( result[ 14 ].title ).toBe( 'Jupiter' );
173
+ expect( result[ 15 ].title ).toBe( 'Saturn' );
167
174
  } );
168
175
 
169
176
  it( 'should search using IS ANY filter for STRING values', () => {
@@ -199,10 +206,17 @@ describe( 'filters', () => {
199
206
  },
200
207
  fields
201
208
  );
202
- expect( result ).toHaveLength( 3 );
209
+ expect( result ).toHaveLength( 10 );
203
210
  expect( result[ 0 ].title ).toBe( 'Moon' );
204
211
  expect( result[ 1 ].title ).toBe( 'Io' );
205
212
  expect( result[ 2 ].title ).toBe( 'Europa' );
213
+ expect( result[ 3 ].title ).toBe( 'Ganymede' );
214
+ expect( result[ 4 ].title ).toBe( 'Callisto' );
215
+ expect( result[ 5 ].title ).toBe( 'Amalthea' );
216
+ expect( result[ 6 ].title ).toBe( 'Himalia' );
217
+ expect( result[ 7 ].title ).toBe( 'Triton' );
218
+ expect( result[ 8 ].title ).toBe( 'Nereid' );
219
+ expect( result[ 9 ].title ).toBe( 'Proteus' );
206
220
  } );
207
221
 
208
222
  it( 'should search using IS ANY filter for ARRAY values', () => {
@@ -238,14 +252,21 @@ describe( 'filters', () => {
238
252
  },
239
253
  fields
240
254
  );
241
- expect( result ).toHaveLength( 7 );
255
+ expect( result ).toHaveLength( 14 );
242
256
  expect( result[ 0 ].title ).toBe( 'Moon' );
243
257
  expect( result[ 1 ].title ).toBe( 'Io' );
244
258
  expect( result[ 2 ].title ).toBe( 'Europa' );
245
- expect( result[ 3 ].title ).toBe( 'Neptune' );
246
- expect( result[ 4 ].title ).toBe( 'Jupiter' );
247
- expect( result[ 5 ].title ).toBe( 'Saturn' );
248
- expect( result[ 6 ].title ).toBe( 'Uranus' );
259
+ expect( result[ 3 ].title ).toBe( 'Ganymede' );
260
+ expect( result[ 4 ].title ).toBe( 'Callisto' );
261
+ expect( result[ 5 ].title ).toBe( 'Amalthea' );
262
+ expect( result[ 6 ].title ).toBe( 'Himalia' );
263
+ expect( result[ 7 ].title ).toBe( 'Neptune' );
264
+ expect( result[ 8 ].title ).toBe( 'Triton' );
265
+ expect( result[ 9 ].title ).toBe( 'Nereid' );
266
+ expect( result[ 10 ].title ).toBe( 'Proteus' );
267
+ expect( result[ 11 ].title ).toBe( 'Jupiter' );
268
+ expect( result[ 12 ].title ).toBe( 'Saturn' );
269
+ expect( result[ 13 ].title ).toBe( 'Uranus' );
249
270
  } );
250
271
 
251
272
  it( 'should search using IS ALL filter', () => {
@@ -287,10 +308,17 @@ describe( 'filters', () => {
287
308
  },
288
309
  fields
289
310
  );
290
- expect( result ).toHaveLength( 3 );
311
+ expect( result ).toHaveLength( 10 );
291
312
  expect( result[ 0 ].title ).toBe( 'Moon' );
292
313
  expect( result[ 1 ].title ).toBe( 'Io' );
293
314
  expect( result[ 2 ].title ).toBe( 'Europa' );
315
+ expect( result[ 3 ].title ).toBe( 'Ganymede' );
316
+ expect( result[ 4 ].title ).toBe( 'Callisto' );
317
+ expect( result[ 5 ].title ).toBe( 'Amalthea' );
318
+ expect( result[ 6 ].title ).toBe( 'Himalia' );
319
+ expect( result[ 7 ].title ).toBe( 'Triton' );
320
+ expect( result[ 8 ].title ).toBe( 'Nereid' );
321
+ expect( result[ 9 ].title ).toBe( 'Proteus' );
294
322
  } );
295
323
 
296
324
  it( 'should search using IS filter and return all values if filter.value is undefined', () => {
@@ -307,18 +335,25 @@ describe( 'filters', () => {
307
335
  },
308
336
  fields
309
337
  );
310
- expect( result ).toHaveLength( 11 );
338
+ expect( result ).toHaveLength( 18 );
311
339
  expect( result[ 0 ].title ).toBe( 'Moon' );
312
340
  expect( result[ 1 ].title ).toBe( 'Io' );
313
341
  expect( result[ 2 ].title ).toBe( 'Europa' );
314
- expect( result[ 3 ].title ).toBe( 'Neptune' );
315
- expect( result[ 4 ].title ).toBe( 'Mercury' );
316
- expect( result[ 5 ].title ).toBe( 'Venus' );
317
- expect( result[ 6 ].title ).toBe( 'Earth' );
318
- expect( result[ 7 ].title ).toBe( 'Mars' );
319
- expect( result[ 8 ].title ).toBe( 'Jupiter' );
320
- expect( result[ 9 ].title ).toBe( 'Saturn' );
321
- expect( result[ 10 ].title ).toBe( 'Uranus' );
342
+ expect( result[ 3 ].title ).toBe( 'Ganymede' );
343
+ expect( result[ 4 ].title ).toBe( 'Callisto' );
344
+ expect( result[ 5 ].title ).toBe( 'Amalthea' );
345
+ expect( result[ 6 ].title ).toBe( 'Himalia' );
346
+ expect( result[ 7 ].title ).toBe( 'Neptune' );
347
+ expect( result[ 8 ].title ).toBe( 'Triton' );
348
+ expect( result[ 9 ].title ).toBe( 'Nereid' );
349
+ expect( result[ 10 ].title ).toBe( 'Proteus' );
350
+ expect( result[ 11 ].title ).toBe( 'Mercury' );
351
+ expect( result[ 12 ].title ).toBe( 'Venus' );
352
+ expect( result[ 13 ].title ).toBe( 'Earth' );
353
+ expect( result[ 14 ].title ).toBe( 'Mars' );
354
+ expect( result[ 15 ].title ).toBe( 'Jupiter' );
355
+ expect( result[ 16 ].title ).toBe( 'Saturn' );
356
+ expect( result[ 17 ].title ).toBe( 'Uranus' );
322
357
  } );
323
358
 
324
359
  it( 'should filter using LESS THAN operator for integer', () => {
@@ -423,11 +458,23 @@ describe( 'filters', () => {
423
458
  },
424
459
  fields
425
460
  );
426
- expect( result.map( ( r ) => r.description ) ).toEqual( [
427
- 'The Moon is Earth’s only natural satellite, orbiting at an average distance of 384,400 kilometers with a synchronous rotation that leads to fixed lunar phases as seen from Earth. Its cratered surface and subtle glow define night skies, inspiring exploration missions and influencing tides and biological rhythms worldwide.',
428
- 'Moon of Jupiter',
429
- 'Moon of Jupiter',
430
- 'La planète Vénus',
461
+ // Should return items that don't contain "Solar system" in description
462
+ expect( result ).toHaveLength( 11 );
463
+ expect(
464
+ result.filter( ( r ) => r.description.includes( 'Solar system' ) )
465
+ ).toHaveLength( 0 );
466
+ expect( result.map( ( r ) => r.title ).sort() ).toEqual( [
467
+ 'Amalthea',
468
+ 'Callisto',
469
+ 'Europa',
470
+ 'Ganymede',
471
+ 'Himalia',
472
+ 'Io',
473
+ 'Moon',
474
+ 'Nereid',
475
+ 'Proteus',
476
+ 'Triton',
477
+ 'Venus',
431
478
  ] );
432
479
  } );
433
480
 
@@ -595,7 +642,7 @@ describe( 'filters', () => {
595
642
  },
596
643
  fields
597
644
  );
598
- expect( result.length ).toBe( 9 );
645
+ expect( result.length ).toBe( 16 );
599
646
  expect( result.map( ( r ) => r.title ) ).not.toContain( 'Neptune' );
600
647
  } );
601
648
 
@@ -808,7 +855,7 @@ describe( 'sorting', () => {
808
855
  fields
809
856
  );
810
857
 
811
- expect( result ).toHaveLength( 11 );
858
+ expect( result ).toHaveLength( 18 );
812
859
 
813
860
  expect( result[ 0 ].type ).toBe( 'Gas giant' );
814
861
  expect( result[ 0 ].title ).toBe( 'Saturn' );
@@ -820,21 +867,31 @@ describe( 'sorting', () => {
820
867
  expect( result[ 3 ].type ).toBe( 'Ice giant' );
821
868
  expect( result[ 3 ].title ).toBe( 'Neptune' );
822
869
 
823
- expect( result[ 4 ].type ).toBe( 'Satellite' );
824
- expect( result[ 4 ].title ).toBe( 'Moon' );
825
- expect( result[ 5 ].type ).toBe( 'Satellite' );
826
- expect( result[ 5 ].title ).toBe( 'Io' );
827
- expect( result[ 6 ].type ).toBe( 'Satellite' );
828
- expect( result[ 6 ].title ).toBe( 'Europa' );
829
-
830
- expect( result[ 7 ].type ).toBe( 'Terrestrial' );
831
- expect( result[ 7 ].title ).toBe( 'Venus' );
832
- expect( result[ 8 ].type ).toBe( 'Terrestrial' );
833
- expect( result[ 8 ].title ).toBe( 'Mercury' );
834
- expect( result[ 9 ].type ).toBe( 'Terrestrial' );
835
- expect( result[ 9 ].title ).toBe( 'Mars' );
836
- expect( result[ 10 ].type ).toBe( 'Terrestrial' );
837
- expect( result[ 10 ].title ).toBe( 'Earth' );
870
+ // All satellites should be grouped together
871
+ const satelliteItems = result.filter(
872
+ ( item ) => item.type === 'Satellite'
873
+ );
874
+ expect( satelliteItems ).toHaveLength( 10 );
875
+ expect( satelliteItems[ 0 ].title ).toBe( 'Triton' );
876
+ expect( satelliteItems[ 1 ].title ).toBe( 'Proteus' );
877
+ expect( satelliteItems[ 2 ].title ).toBe( 'Nereid' );
878
+ expect( satelliteItems[ 3 ].title ).toBe( 'Moon' );
879
+ expect( satelliteItems[ 4 ].title ).toBe( 'Io' );
880
+ expect( satelliteItems[ 5 ].title ).toBe( 'Himalia' );
881
+ expect( satelliteItems[ 6 ].title ).toBe( 'Ganymede' );
882
+ expect( satelliteItems[ 7 ].title ).toBe( 'Europa' );
883
+ expect( satelliteItems[ 8 ].title ).toBe( 'Callisto' );
884
+ expect( satelliteItems[ 9 ].title ).toBe( 'Amalthea' );
885
+
886
+ // All terrestrial planets should be grouped together
887
+ const terrestrialItems = result.filter(
888
+ ( item ) => item.type === 'Terrestrial'
889
+ );
890
+ expect( terrestrialItems ).toHaveLength( 4 );
891
+ expect( terrestrialItems[ 0 ].title ).toBe( 'Venus' );
892
+ expect( terrestrialItems[ 1 ].title ).toBe( 'Mercury' );
893
+ expect( terrestrialItems[ 2 ].title ).toBe( 'Mars' );
894
+ expect( terrestrialItems[ 3 ].title ).toBe( 'Earth' );
838
895
  } );
839
896
 
840
897
  it( 'should sort integer field types', () => {
@@ -846,7 +903,7 @@ describe( 'sorting', () => {
846
903
  fields
847
904
  );
848
905
 
849
- expect( result ).toHaveLength( 11 );
906
+ expect( result ).toHaveLength( 18 );
850
907
  expect( result[ 0 ].title ).toBe( 'Saturn' );
851
908
  expect( result[ 1 ].title ).toBe( 'Jupiter' );
852
909
  expect( result[ 2 ].title ).toBe( 'Uranus' );
@@ -880,11 +937,12 @@ describe( 'sorting', () => {
880
937
  },
881
938
  fields
882
939
  );
883
- expect( resultDesc ).toHaveLength( 11 );
940
+ expect( resultDesc ).toHaveLength( 18 );
884
941
  expect( resultDesc[ 0 ].title ).toBe( 'Europa' );
885
942
  expect( resultDesc[ 1 ].title ).toBe( 'Earth' );
886
- expect( resultDesc[ 9 ].title ).toBe( 'Io' );
887
- expect( resultDesc[ 10 ].title ).toBe( 'Jupiter' );
943
+ // Skip intermediate items
944
+ expect( resultDesc[ resultDesc.length - 2 ].title ).toBe( 'Io' );
945
+ expect( resultDesc[ resultDesc.length - 1 ].title ).toBe( 'Jupiter' );
888
946
 
889
947
  const { data: resultAsc } = filterSortAndPaginate(
890
948
  data,
@@ -893,11 +951,12 @@ describe( 'sorting', () => {
893
951
  },
894
952
  fields
895
953
  );
896
- expect( resultAsc ).toHaveLength( 11 );
954
+ expect( resultAsc ).toHaveLength( 18 );
897
955
  expect( resultAsc[ 0 ].title ).toBe( 'Jupiter' );
898
956
  expect( resultAsc[ 1 ].title ).toBe( 'Io' );
899
- expect( resultAsc[ 9 ].title ).toBe( 'Earth' );
900
- expect( resultAsc[ 10 ].title ).toBe( 'Europa' );
957
+ // Skip intermediate items
958
+ expect( resultAsc[ resultAsc.length - 2 ].title ).toBe( 'Earth' );
959
+ expect( resultAsc[ resultAsc.length - 1 ].title ).toBe( 'Europa' );
901
960
  } );
902
961
 
903
962
  it( 'should sort untyped fields if the value is a number', () => {
@@ -914,7 +973,7 @@ describe( 'sorting', () => {
914
973
  )
915
974
  );
916
975
 
917
- expect( result ).toHaveLength( 11 );
976
+ expect( result ).toHaveLength( 18 );
918
977
  expect( result[ 0 ].title ).toBe( 'Saturn' );
919
978
  expect( result[ 1 ].title ).toBe( 'Jupiter' );
920
979
  expect( result[ 2 ].title ).toBe( 'Uranus' );
@@ -979,10 +1038,10 @@ describe( 'pagination', () => {
979
1038
  );
980
1039
  expect( result ).toHaveLength( 2 );
981
1040
  expect( result[ 0 ].title ).toBe( 'Europa' );
982
- expect( result[ 1 ].title ).toBe( 'Neptune' );
1041
+ expect( result[ 1 ].title ).toBe( 'Ganymede' );
983
1042
  expect( paginationInfo ).toStrictEqual( {
984
1043
  totalItems: data.length,
985
- totalPages: 6,
1044
+ totalPages: 9,
986
1045
  } );
987
1046
  } );
988
1047
  } );
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import normalizeFormFields from '../normalize-form-fields';
5
+ import type { Form } from '../types';
6
+
7
+ describe( 'normalizeFormFields', () => {
8
+ describe( 'empty form', () => {
9
+ it( 'returns empty array for undefined fields', () => {
10
+ const form: Form = {};
11
+ const result = normalizeFormFields( form );
12
+ expect( result ).toEqual( [] );
13
+ } );
14
+
15
+ it( 'returns empty array for empty fields', () => {
16
+ const form: Form = { fields: [] };
17
+ const result = normalizeFormFields( form );
18
+ expect( result ).toEqual( [] );
19
+ } );
20
+ } );
21
+
22
+ describe( 'default layout', () => {
23
+ it( 'applies default layout when layout is not specified', () => {
24
+ const form: Form = {
25
+ fields: [ 'field1', 'field2' ],
26
+ };
27
+ const result = normalizeFormFields( form );
28
+ expect( result ).toEqual( [
29
+ {
30
+ id: 'field1',
31
+ layout: { type: 'regular', labelPosition: 'top' },
32
+ },
33
+ {
34
+ id: 'field2',
35
+ layout: { type: 'regular', labelPosition: 'top' },
36
+ },
37
+ ] );
38
+ } );
39
+
40
+ it( 'handles mixed string and object field specifications', () => {
41
+ const form: Form = {
42
+ fields: [
43
+ 'field1',
44
+ {
45
+ id: 'field2',
46
+ label: 'Field 2',
47
+ },
48
+ ],
49
+ };
50
+ const result = normalizeFormFields( form );
51
+ expect( result ).toEqual( [
52
+ {
53
+ id: 'field1',
54
+ layout: { type: 'regular', labelPosition: 'top' },
55
+ },
56
+ {
57
+ id: 'field2',
58
+ label: 'Field 2',
59
+ layout: { type: 'regular', labelPosition: 'top' },
60
+ },
61
+ ] );
62
+ } );
63
+ } );
64
+
65
+ describe( 'layout types', () => {
66
+ it( 'regular: with default layout options', () => {
67
+ const form: Form = {
68
+ layout: { type: 'regular' },
69
+ fields: [ 'field1' ],
70
+ };
71
+ const result = normalizeFormFields( form );
72
+ expect( result ).toEqual( [
73
+ {
74
+ id: 'field1',
75
+ layout: { type: 'regular', labelPosition: 'top' },
76
+ },
77
+ ] );
78
+ } );
79
+
80
+ it( 'regular: with layout options', () => {
81
+ const form: Form = {
82
+ layout: { type: 'regular', labelPosition: 'side' },
83
+ fields: [ 'field1' ],
84
+ };
85
+ const result = normalizeFormFields( form );
86
+ expect( result ).toEqual( [
87
+ {
88
+ id: 'field1',
89
+ layout: { type: 'regular', labelPosition: 'side' },
90
+ },
91
+ ] );
92
+ } );
93
+
94
+ it( 'panel: with default layout options', () => {
95
+ const form: Form = {
96
+ layout: { type: 'panel' },
97
+ fields: [ 'field1' ],
98
+ };
99
+ const result = normalizeFormFields( form );
100
+ expect( result ).toEqual( [
101
+ {
102
+ id: 'field1',
103
+ layout: {
104
+ type: 'panel',
105
+ labelPosition: 'side',
106
+ openAs: 'dropdown',
107
+ },
108
+ },
109
+ ] );
110
+ } );
111
+
112
+ it( 'panel: with layout options', () => {
113
+ const form: Form = {
114
+ layout: { type: 'panel', labelPosition: 'top' },
115
+ fields: [ 'field1' ],
116
+ };
117
+ const result = normalizeFormFields( form );
118
+ expect( result ).toEqual( [
119
+ {
120
+ id: 'field1',
121
+ layout: {
122
+ type: 'panel',
123
+ labelPosition: 'top',
124
+ openAs: 'dropdown',
125
+ },
126
+ },
127
+ ] );
128
+ } );
129
+
130
+ it( 'card: with default layout options', () => {
131
+ const form: Form = {
132
+ layout: { type: 'card' },
133
+ fields: [ 'field1' ],
134
+ };
135
+ const result = normalizeFormFields( form );
136
+ expect( result ).toEqual( [
137
+ {
138
+ id: 'field1',
139
+ layout: {
140
+ type: 'card',
141
+ withHeader: true,
142
+ isOpened: true,
143
+ },
144
+ },
145
+ ] );
146
+ } );
147
+
148
+ it( 'card: enforces isOpened=true when withHeader=false', () => {
149
+ const form: Form = {
150
+ // @ts-ignore - Test intentionally uses invalid type to verify runtime behavior.
151
+ layout: { type: 'card', withHeader: false, isOpened: false },
152
+ fields: [ 'field1' ],
153
+ };
154
+ const result = normalizeFormFields( form );
155
+ expect( result ).toEqual( [
156
+ {
157
+ id: 'field1',
158
+ layout: {
159
+ type: 'card',
160
+ withHeader: false,
161
+ isOpened: true,
162
+ },
163
+ },
164
+ ] );
165
+ } );
166
+
167
+ it( 'card: respects isOpened when withHeader=true', () => {
168
+ const form: Form = {
169
+ layout: { type: 'card', withHeader: true, isOpened: false },
170
+ fields: [ 'field1' ],
171
+ };
172
+ const result = normalizeFormFields( form );
173
+ expect( result ).toEqual( [
174
+ {
175
+ id: 'field1',
176
+ layout: {
177
+ type: 'card',
178
+ withHeader: true,
179
+ isOpened: false,
180
+ },
181
+ },
182
+ ] );
183
+ } );
184
+ } );
185
+
186
+ describe( 'layout overrides', () => {
187
+ it( 'fields can override form layout', () => {
188
+ const form: Form = {
189
+ layout: { type: 'regular', labelPosition: 'top' },
190
+ fields: [
191
+ 'field1',
192
+ {
193
+ id: 'field2',
194
+ layout: { type: 'panel', labelPosition: 'side' },
195
+ },
196
+ ],
197
+ };
198
+ const result = normalizeFormFields( form );
199
+ expect( result ).toEqual( [
200
+ {
201
+ id: 'field1',
202
+ layout: { type: 'regular', labelPosition: 'top' },
203
+ },
204
+ {
205
+ id: 'field2',
206
+ layout: {
207
+ type: 'panel',
208
+ labelPosition: 'side',
209
+ openAs: 'dropdown',
210
+ },
211
+ },
212
+ ] );
213
+ } );
214
+
215
+ it( 'fields do not partially override form layout', () => {
216
+ const form: Form = {
217
+ layout: { type: 'card', withHeader: false, isOpened: true },
218
+ fields: [
219
+ 'field1',
220
+ {
221
+ id: 'field2',
222
+ layout: { type: 'card', isOpened: false },
223
+ },
224
+ ],
225
+ };
226
+ const result = normalizeFormFields( form );
227
+ expect( result ).toEqual( [
228
+ {
229
+ id: 'field1',
230
+ layout: {
231
+ type: 'card',
232
+ withHeader: false,
233
+ isOpened: true,
234
+ },
235
+ },
236
+ {
237
+ id: 'field2',
238
+ layout: {
239
+ type: 'card',
240
+ withHeader: true,
241
+ isOpened: false,
242
+ },
243
+ },
244
+ ] );
245
+ } );
246
+ } );
247
+ } );
package/src/types.ts CHANGED
@@ -443,6 +443,11 @@ interface ViewBase {
443
443
  * The field to group by.
444
444
  */
445
445
  groupByField?: string;
446
+
447
+ /**
448
+ * Whether infinite scroll is enabled.
449
+ */
450
+ infiniteScrollEnabled?: boolean;
446
451
  }
447
452
 
448
453
  export interface ColumnStyle {
@@ -482,6 +487,11 @@ export interface ViewTable extends ViewBase {
482
487
  * The density of the view.
483
488
  */
484
489
  density?: Density;
490
+
491
+ /**
492
+ * Whether the view allows column moving.
493
+ */
494
+ enableMoving?: boolean;
485
495
  };
486
496
  }
487
497
 
@@ -661,17 +671,74 @@ export interface SupportedLayouts {
661
671
  table?: Omit< ViewTable, 'type' >;
662
672
  }
663
673
 
674
+ /**
675
+ * DataForm layouts.
676
+ */
677
+ export type LayoutType = 'regular' | 'panel' | 'card';
678
+ export type LabelPosition = 'top' | 'side' | 'none';
679
+
680
+ export type RegularLayout = {
681
+ type: 'regular';
682
+ labelPosition?: LabelPosition;
683
+ };
684
+ export type NormalizedRegularLayout = {
685
+ type: 'regular';
686
+ labelPosition: LabelPosition;
687
+ };
688
+
689
+ export type PanelLayout = {
690
+ type: 'panel';
691
+ labelPosition?: LabelPosition;
692
+ openAs?: 'dropdown' | 'modal';
693
+ };
694
+ export type NormalizedPanelLayout = {
695
+ type: 'panel';
696
+ labelPosition: LabelPosition;
697
+ openAs: 'dropdown' | 'modal';
698
+ };
699
+
700
+ export type CardLayout =
701
+ | {
702
+ type: 'card';
703
+ withHeader: false;
704
+ // isOpened cannot be false if withHeader is false as well.
705
+ // Otherwise, the card would not be visible.
706
+ isOpened?: true;
707
+ }
708
+ | {
709
+ type: 'card';
710
+ withHeader?: true | undefined;
711
+ isOpened?: boolean;
712
+ };
713
+ export type NormalizedCardLayout =
714
+ | {
715
+ type: 'card';
716
+ withHeader: false;
717
+ // isOpened cannot be false if withHeader is false as well.
718
+ // Otherwise, the card would not be visible.
719
+ isOpened: true;
720
+ }
721
+ | {
722
+ type: 'card';
723
+ withHeader: true;
724
+ isOpened: boolean;
725
+ };
726
+
727
+ export type Layout = RegularLayout | PanelLayout | CardLayout;
728
+ export type NormalizedLayout =
729
+ | NormalizedRegularLayout
730
+ | NormalizedPanelLayout
731
+ | NormalizedCardLayout;
732
+
664
733
  export type SimpleFormField = {
665
734
  id: string;
666
- layout?: 'regular' | 'panel';
667
- labelPosition?: 'side' | 'top' | 'none';
735
+ layout?: Layout;
668
736
  };
669
737
 
670
738
  export type CombinedFormField = {
671
739
  id: string;
672
740
  label?: string;
673
- layout?: 'regular' | 'panel';
674
- labelPosition?: 'side' | 'top' | 'none';
741
+ layout?: Layout;
675
742
  children: Array< FormField | string >;
676
743
  };
677
744
 
@@ -681,9 +748,8 @@ export type FormField = SimpleFormField | CombinedFormField;
681
748
  * The form configuration.
682
749
  */
683
750
  export type Form = {
684
- type?: 'regular' | 'panel';
751
+ layout?: Layout;
685
752
  fields?: Array< FormField | string >;
686
- labelPosition?: 'side' | 'top' | 'none';
687
753
  };
688
754
 
689
755
  export interface DataFormProps< Item > {