@wordpress/dataviews 4.0.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 (285) hide show
  1. package/CHANGELOG.md +33 -5
  2. package/README.md +31 -23
  3. package/build/components/dataform/index.js +10 -61
  4. package/build/components/dataform/index.js.map +1 -1
  5. package/build/components/dataviews/index.js +23 -14
  6. package/build/components/dataviews/index.js.map +1 -1
  7. package/build/components/dataviews-bulk-actions/index.js +3 -0
  8. package/build/components/dataviews-bulk-actions/index.js.map +1 -1
  9. package/build/components/dataviews-filters/add-filter.js +34 -17
  10. package/build/components/dataviews-filters/add-filter.js.map +1 -1
  11. package/build/components/dataviews-filters/index.js +109 -43
  12. package/build/components/dataviews-filters/index.js.map +1 -1
  13. package/build/components/dataviews-filters/search-widget.js +2 -5
  14. package/build/components/dataviews-filters/search-widget.js.map +1 -1
  15. package/build/components/dataviews-layout/index.js +2 -2
  16. package/build/components/dataviews-layout/index.js.map +1 -1
  17. package/build/components/dataviews-pagination/index.js +23 -15
  18. package/build/components/dataviews-pagination/index.js.map +1 -1
  19. package/build/components/dataviews-search/index.js +8 -5
  20. package/build/components/dataviews-search/index.js.map +1 -1
  21. package/build/components/dataviews-view-config/index.js +240 -188
  22. package/build/components/dataviews-view-config/index.js.map +1 -1
  23. package/build/constants.js +6 -1
  24. package/build/constants.js.map +1 -1
  25. package/build/dataform-controls/datetime.js +49 -0
  26. package/build/dataform-controls/datetime.js.map +1 -0
  27. package/build/dataform-controls/index.js +50 -0
  28. package/build/dataform-controls/index.js.map +1 -0
  29. package/build/dataform-controls/integer.js +45 -0
  30. package/build/dataform-controls/integer.js.map +1 -0
  31. package/build/dataform-controls/radio.js +45 -0
  32. package/build/dataform-controls/radio.js.map +1 -0
  33. package/build/dataform-controls/select.js +58 -0
  34. package/build/dataform-controls/select.js.map +1 -0
  35. package/build/dataform-controls/text.js +45 -0
  36. package/build/dataform-controls/text.js.map +1 -0
  37. package/build/dataforms-layouts/index.js +24 -0
  38. package/build/dataforms-layouts/index.js.map +1 -0
  39. package/build/dataforms-layouts/panel/index.js +132 -0
  40. package/build/dataforms-layouts/panel/index.js.map +1 -0
  41. package/build/dataforms-layouts/regular/index.js +42 -0
  42. package/build/dataforms-layouts/regular/index.js.map +1 -0
  43. package/build/dataviews-layouts/grid/density-picker.js +114 -0
  44. package/build/dataviews-layouts/grid/density-picker.js.map +1 -0
  45. package/build/{layouts → dataviews-layouts}/grid/index.js +9 -9
  46. package/build/dataviews-layouts/grid/index.js.map +1 -0
  47. package/build/dataviews-layouts/index.js.map +1 -0
  48. package/build/{layouts → dataviews-layouts}/list/index.js +6 -2
  49. package/build/dataviews-layouts/list/index.js.map +1 -0
  50. package/build/{layouts → dataviews-layouts}/table/column-header-menu.js +3 -6
  51. package/build/dataviews-layouts/table/column-header-menu.js.map +1 -0
  52. package/build/dataviews-layouts/table/index.js.map +1 -0
  53. package/build/field-types/datetime.js +30 -0
  54. package/build/field-types/datetime.js.map +1 -0
  55. package/build/field-types/index.js +50 -0
  56. package/build/field-types/index.js.map +1 -0
  57. package/build/field-types/integer.js +35 -0
  58. package/build/field-types/integer.js.map +1 -0
  59. package/build/field-types/text.js +28 -0
  60. package/build/field-types/text.js.map +1 -0
  61. package/build/filter-and-sort-data-view.js +2 -11
  62. package/build/filter-and-sort-data-view.js.map +1 -1
  63. package/build/index.js +9 -2
  64. package/build/index.js.map +1 -1
  65. package/build/normalize-fields.js +34 -1
  66. package/build/normalize-fields.js.map +1 -1
  67. package/build/types.js.map +1 -1
  68. package/build/validation.js +22 -0
  69. package/build/validation.js.map +1 -0
  70. package/build-module/components/dataform/index.js +10 -61
  71. package/build-module/components/dataform/index.js.map +1 -1
  72. package/build-module/components/dataviews/index.js +21 -14
  73. package/build-module/components/dataviews/index.js.map +1 -1
  74. package/build-module/components/dataviews-bulk-actions/index.js +3 -0
  75. package/build-module/components/dataviews-bulk-actions/index.js.map +1 -1
  76. package/build-module/components/dataviews-filters/add-filter.js +33 -17
  77. package/build-module/components/dataviews-filters/add-filter.js.map +1 -1
  78. package/build-module/components/dataviews-filters/index.js +108 -45
  79. package/build-module/components/dataviews-filters/index.js.map +1 -1
  80. package/build-module/components/dataviews-filters/search-widget.js +2 -5
  81. package/build-module/components/dataviews-filters/search-widget.js.map +1 -1
  82. package/build-module/components/dataviews-layout/index.js +1 -1
  83. package/build-module/components/dataviews-layout/index.js.map +1 -1
  84. package/build-module/components/dataviews-pagination/index.js +23 -15
  85. package/build-module/components/dataviews-pagination/index.js.map +1 -1
  86. package/build-module/components/dataviews-search/index.js +8 -5
  87. package/build-module/components/dataviews-search/index.js.map +1 -1
  88. package/build-module/components/dataviews-view-config/index.js +243 -191
  89. package/build-module/components/dataviews-view-config/index.js.map +1 -1
  90. package/build-module/constants.js +5 -0
  91. package/build-module/constants.js.map +1 -1
  92. package/build-module/dataform-controls/datetime.js +43 -0
  93. package/build-module/dataform-controls/datetime.js.map +1 -0
  94. package/build-module/dataform-controls/index.js +42 -0
  95. package/build-module/dataform-controls/index.js.map +1 -0
  96. package/build-module/dataform-controls/integer.js +38 -0
  97. package/build-module/dataform-controls/integer.js.map +1 -0
  98. package/build-module/dataform-controls/radio.js +38 -0
  99. package/build-module/dataform-controls/radio.js.map +1 -0
  100. package/build-module/dataform-controls/select.js +51 -0
  101. package/build-module/dataform-controls/select.js.map +1 -0
  102. package/build-module/dataform-controls/text.js +38 -0
  103. package/build-module/dataform-controls/text.js.map +1 -0
  104. package/build-module/dataforms-layouts/index.js +16 -0
  105. package/build-module/dataforms-layouts/index.js.map +1 -0
  106. package/build-module/dataforms-layouts/panel/index.js +127 -0
  107. package/build-module/dataforms-layouts/panel/index.js.map +1 -0
  108. package/build-module/dataforms-layouts/regular/index.js +35 -0
  109. package/build-module/dataforms-layouts/regular/index.js.map +1 -0
  110. package/build-module/dataviews-layouts/grid/density-picker.js +107 -0
  111. package/build-module/dataviews-layouts/grid/density-picker.js.map +1 -0
  112. package/build-module/{layouts → dataviews-layouts}/grid/index.js +9 -9
  113. package/build-module/dataviews-layouts/grid/index.js.map +1 -0
  114. package/build-module/dataviews-layouts/index.js.map +1 -0
  115. package/build-module/{layouts → dataviews-layouts}/list/index.js +5 -2
  116. package/build-module/dataviews-layouts/list/index.js.map +1 -0
  117. package/build-module/{layouts → dataviews-layouts}/table/column-header-menu.js +3 -6
  118. package/build-module/dataviews-layouts/table/column-header-menu.js.map +1 -0
  119. package/build-module/dataviews-layouts/table/index.js.map +1 -0
  120. package/build-module/field-types/datetime.js +24 -0
  121. package/build-module/field-types/datetime.js.map +1 -0
  122. package/build-module/field-types/index.js +44 -0
  123. package/build-module/field-types/index.js.map +1 -0
  124. package/build-module/field-types/integer.js +29 -0
  125. package/build-module/field-types/integer.js.map +1 -0
  126. package/build-module/field-types/text.js +22 -0
  127. package/build-module/field-types/text.js.map +1 -0
  128. package/build-module/filter-and-sort-data-view.js +2 -11
  129. package/build-module/filter-and-sort-data-view.js.map +1 -1
  130. package/build-module/index.js +2 -1
  131. package/build-module/index.js.map +1 -1
  132. package/build-module/normalize-fields.js +33 -1
  133. package/build-module/normalize-fields.js.map +1 -1
  134. package/build-module/types.js.map +1 -1
  135. package/build-module/validation.js +15 -0
  136. package/build-module/validation.js.map +1 -0
  137. package/build-style/style-rtl.css +186 -20
  138. package/build-style/style.css +186 -20
  139. package/build-types/components/dataform/index.d.ts +2 -13
  140. package/build-types/components/dataform/index.d.ts.map +1 -1
  141. package/build-types/components/dataform/stories/index.story.d.ts +12 -1
  142. package/build-types/components/dataform/stories/index.story.d.ts.map +1 -1
  143. package/build-types/components/dataviews/index.d.ts.map +1 -1
  144. package/build-types/components/dataviews/stories/fixtures.d.ts +25 -0
  145. package/build-types/components/dataviews/stories/fixtures.d.ts.map +1 -1
  146. package/build-types/components/dataviews/stories/index.story.d.ts +9 -0
  147. package/build-types/components/dataviews/stories/index.story.d.ts.map +1 -1
  148. package/build-types/components/dataviews-bulk-actions/index.d.ts.map +1 -1
  149. package/build-types/components/dataviews-filters/add-filter.d.ts +3 -0
  150. package/build-types/components/dataviews-filters/add-filter.d.ts.map +1 -1
  151. package/build-types/components/dataviews-filters/index.d.ts +11 -1
  152. package/build-types/components/dataviews-filters/index.d.ts.map +1 -1
  153. package/build-types/components/dataviews-filters/search-widget.d.ts.map +1 -1
  154. package/build-types/components/dataviews-pagination/index.d.ts.map +1 -1
  155. package/build-types/components/dataviews-search/index.d.ts.map +1 -1
  156. package/build-types/components/dataviews-view-config/index.d.ts +4 -3
  157. package/build-types/components/dataviews-view-config/index.d.ts.map +1 -1
  158. package/build-types/constants.d.ts +4 -0
  159. package/build-types/constants.d.ts.map +1 -1
  160. package/build-types/dataform-controls/datetime.d.ts +6 -0
  161. package/build-types/dataform-controls/datetime.d.ts.map +1 -0
  162. package/build-types/dataform-controls/index.d.ts +11 -0
  163. package/build-types/dataform-controls/index.d.ts.map +1 -0
  164. package/build-types/dataform-controls/integer.d.ts +6 -0
  165. package/build-types/dataform-controls/integer.d.ts.map +1 -0
  166. package/build-types/dataform-controls/radio.d.ts +6 -0
  167. package/build-types/dataform-controls/radio.d.ts.map +1 -0
  168. package/build-types/dataform-controls/select.d.ts +6 -0
  169. package/build-types/dataform-controls/select.d.ts.map +1 -0
  170. package/build-types/dataform-controls/text.d.ts +6 -0
  171. package/build-types/dataform-controls/text.d.ts.map +1 -0
  172. package/build-types/dataforms-layouts/index.d.ts +9 -0
  173. package/build-types/dataforms-layouts/index.d.ts.map +1 -0
  174. package/build-types/dataforms-layouts/panel/index.d.ts +3 -0
  175. package/build-types/dataforms-layouts/panel/index.d.ts.map +1 -0
  176. package/build-types/dataforms-layouts/regular/index.d.ts +3 -0
  177. package/build-types/dataforms-layouts/regular/index.d.ts.map +1 -0
  178. package/build-types/dataviews-layouts/grid/density-picker.d.ts.map +1 -0
  179. package/build-types/dataviews-layouts/grid/index.d.ts.map +1 -0
  180. package/build-types/dataviews-layouts/index.d.ts.map +1 -0
  181. package/build-types/dataviews-layouts/list/index.d.ts.map +1 -0
  182. package/build-types/dataviews-layouts/table/column-header-menu.d.ts.map +1 -0
  183. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -0
  184. package/build-types/field-types/datetime.d.ts +13 -0
  185. package/build-types/field-types/datetime.d.ts.map +1 -0
  186. package/build-types/field-types/index.d.ts +20 -0
  187. package/build-types/field-types/index.d.ts.map +1 -0
  188. package/build-types/field-types/integer.d.ts +13 -0
  189. package/build-types/field-types/integer.d.ts.map +1 -0
  190. package/build-types/field-types/text.d.ts +13 -0
  191. package/build-types/field-types/text.d.ts.map +1 -0
  192. package/build-types/filter-and-sort-data-view.d.ts.map +1 -1
  193. package/build-types/index.d.ts +2 -1
  194. package/build-types/index.d.ts.map +1 -1
  195. package/build-types/normalize-fields.d.ts +0 -3
  196. package/build-types/normalize-fields.d.ts.map +1 -1
  197. package/build-types/types.d.ts +73 -18
  198. package/build-types/types.d.ts.map +1 -1
  199. package/build-types/validation.d.ts +3 -0
  200. package/build-types/validation.d.ts.map +1 -0
  201. package/package.json +12 -11
  202. package/src/components/dataform/index.tsx +8 -97
  203. package/src/components/dataform/stories/index.story.tsx +82 -4
  204. package/src/components/dataviews/index.tsx +26 -14
  205. package/src/components/dataviews/stories/fixtures.js +30 -1
  206. package/src/components/dataviews/stories/index.story.js +7 -1
  207. package/src/components/dataviews/style.scss +5 -14
  208. package/src/components/dataviews-bulk-actions/index.tsx +5 -0
  209. package/src/components/dataviews-bulk-actions-toolbar/style.scss +1 -1
  210. package/src/components/dataviews-filters/add-filter.tsx +37 -21
  211. package/src/components/dataviews-filters/index.tsx +152 -61
  212. package/src/components/dataviews-filters/search-widget.tsx +1 -8
  213. package/src/components/dataviews-filters/style.scss +31 -1
  214. package/src/components/dataviews-layout/index.tsx +1 -1
  215. package/src/components/dataviews-pagination/index.tsx +35 -16
  216. package/src/components/dataviews-pagination/style.scss +9 -4
  217. package/src/components/dataviews-search/index.tsx +8 -5
  218. package/src/components/dataviews-view-config/index.tsx +300 -257
  219. package/src/components/dataviews-view-config/style.scss +44 -0
  220. package/src/constants.ts +5 -0
  221. package/src/dataform-controls/datetime.tsx +43 -0
  222. package/src/dataform-controls/index.tsx +61 -0
  223. package/src/dataform-controls/integer.tsx +38 -0
  224. package/src/dataform-controls/radio.tsx +42 -0
  225. package/src/dataform-controls/select.tsx +52 -0
  226. package/src/dataform-controls/style.scss +4 -0
  227. package/src/dataform-controls/text.tsx +40 -0
  228. package/src/dataforms-layouts/index.tsx +20 -0
  229. package/src/dataforms-layouts/panel/index.tsx +168 -0
  230. package/src/dataforms-layouts/panel/style.scss +59 -0
  231. package/src/dataforms-layouts/regular/index.tsx +45 -0
  232. package/src/dataviews-layouts/grid/density-picker.tsx +102 -0
  233. package/src/{layouts → dataviews-layouts}/grid/index.tsx +9 -9
  234. package/src/{layouts → dataviews-layouts}/grid/style.scss +29 -4
  235. package/src/{layouts → dataviews-layouts}/list/index.tsx +6 -2
  236. package/src/{layouts → dataviews-layouts}/list/style.scss +4 -1
  237. package/src/{layouts → dataviews-layouts}/table/column-header-menu.tsx +4 -6
  238. package/src/field-types/datetime.tsx +28 -0
  239. package/src/field-types/index.tsx +50 -0
  240. package/src/field-types/integer.tsx +34 -0
  241. package/src/field-types/text.tsx +27 -0
  242. package/src/filter-and-sort-data-view.ts +1 -15
  243. package/src/index.ts +2 -1
  244. package/src/normalize-fields.ts +43 -4
  245. package/src/style.scss +7 -3
  246. package/src/test/filter-and-sort-data-view.js +74 -3
  247. package/src/test/validation.ts +131 -0
  248. package/src/types.ts +92 -23
  249. package/src/validation.ts +18 -0
  250. package/tsconfig.json +2 -1
  251. package/tsconfig.tsbuildinfo +1 -1
  252. package/build/layouts/grid/density-picker.js +0 -143
  253. package/build/layouts/grid/density-picker.js.map +0 -1
  254. package/build/layouts/grid/index.js.map +0 -1
  255. package/build/layouts/index.js.map +0 -1
  256. package/build/layouts/list/index.js.map +0 -1
  257. package/build/layouts/table/column-header-menu.js.map +0 -1
  258. package/build/layouts/table/index.js.map +0 -1
  259. package/build-module/layouts/grid/density-picker.js +0 -138
  260. package/build-module/layouts/grid/density-picker.js.map +0 -1
  261. package/build-module/layouts/grid/index.js.map +0 -1
  262. package/build-module/layouts/index.js.map +0 -1
  263. package/build-module/layouts/list/index.js.map +0 -1
  264. package/build-module/layouts/table/column-header-menu.js.map +0 -1
  265. package/build-module/layouts/table/index.js.map +0 -1
  266. package/build-types/layouts/grid/density-picker.d.ts.map +0 -1
  267. package/build-types/layouts/grid/index.d.ts.map +0 -1
  268. package/build-types/layouts/index.d.ts.map +0 -1
  269. package/build-types/layouts/list/index.d.ts.map +0 -1
  270. package/build-types/layouts/table/column-header-menu.d.ts.map +0 -1
  271. package/build-types/layouts/table/index.d.ts.map +0 -1
  272. package/src/layouts/grid/density-picker.tsx +0 -136
  273. /package/build/{layouts → dataviews-layouts}/index.js +0 -0
  274. /package/build/{layouts → dataviews-layouts}/table/index.js +0 -0
  275. /package/build-module/{layouts → dataviews-layouts}/index.js +0 -0
  276. /package/build-module/{layouts → dataviews-layouts}/table/index.js +0 -0
  277. /package/build-types/{layouts → dataviews-layouts}/grid/density-picker.d.ts +0 -0
  278. /package/build-types/{layouts → dataviews-layouts}/grid/index.d.ts +0 -0
  279. /package/build-types/{layouts → dataviews-layouts}/index.d.ts +0 -0
  280. /package/build-types/{layouts → dataviews-layouts}/list/index.d.ts +0 -0
  281. /package/build-types/{layouts → dataviews-layouts}/table/column-header-menu.d.ts +0 -0
  282. /package/build-types/{layouts → dataviews-layouts}/table/index.d.ts +0 -0
  283. /package/src/{layouts → dataviews-layouts}/index.ts +0 -0
  284. /package/src/{layouts → dataviews-layouts}/table/index.tsx +0 -0
  285. /package/src/{layouts → dataviews-layouts}/table/style.scss +0 -0
@@ -84,18 +84,18 @@ function GridItem< Item >( {
84
84
  <div className="dataviews-view-grid__media">
85
85
  { renderedMediaField }
86
86
  </div>
87
+ <SingleSelectionCheckbox
88
+ item={ item }
89
+ selection={ selection }
90
+ onChangeSelection={ onChangeSelection }
91
+ getItemId={ getItemId }
92
+ primaryField={ primaryField }
93
+ disabled={ ! hasBulkAction }
94
+ />
87
95
  <HStack
88
96
  justify="space-between"
89
97
  className="dataviews-view-grid__title-actions"
90
98
  >
91
- <SingleSelectionCheckbox
92
- item={ item }
93
- selection={ selection }
94
- onChangeSelection={ onChangeSelection }
95
- getItemId={ getItemId }
96
- primaryField={ primaryField }
97
- disabled={ ! hasBulkAction }
98
- />
99
99
  <HStack className="dataviews-view-grid__primary-field">
100
100
  { renderedPrimaryField }
101
101
  </HStack>
@@ -145,7 +145,7 @@ function GridItem< Item >( {
145
145
  >
146
146
  <>
147
147
  <FlexItem className="dataviews-view-grid__field-name">
148
- { field.label }
148
+ { field.header }
149
149
  </FlexItem>
150
150
  <FlexItem
151
151
  className="dataviews-view-grid__field-value"
@@ -9,6 +9,7 @@
9
9
  .dataviews-view-grid__card {
10
10
  height: 100%;
11
11
  justify-content: flex-start;
12
+ position: relative;
12
13
 
13
14
  .dataviews-view-grid__title-actions {
14
15
  padding: $grid-unit-10 0 $grid-unit-05;
@@ -22,6 +23,11 @@
22
23
  .dataviews-view-grid__fields .dataviews-view-grid__field .dataviews-view-grid__field-value {
23
24
  color: $gray-900;
24
25
  }
26
+
27
+ .dataviews-view-grid__media::after {
28
+ background-color: rgba(var(--wp-admin-theme-color--rgb), 0.08);
29
+ box-shadow: inset 0 0 0 $border-width var(--wp-admin-theme-color);
30
+ }
25
31
  }
26
32
  }
27
33
 
@@ -61,10 +67,20 @@
61
67
  padding: 0 0 $grid-unit-15;
62
68
  }
63
69
 
70
+ .dataviews-view-grid__field-value:not(:empty) {
71
+ min-height: $grid-unit-30;
72
+ line-height: $grid-unit-05 * 5;
73
+ padding-top: math.div($grid-unit-05, 2);
74
+ }
75
+
64
76
  .dataviews-view-grid__field {
65
77
  align-items: flex-start;
66
78
  min-height: $grid-unit-30;
67
79
 
80
+ &:not(:has(.dataviews-view-grid__field-value:not(:empty))) {
81
+ display: none;
82
+ }
83
+
68
84
  &:not(.is-column) {
69
85
  align-items: center;
70
86
 
@@ -130,11 +146,20 @@
130
146
  }
131
147
  }
132
148
 
133
- .dataviews-density-picker__range-control {
134
- width: 200px;
135
- }
136
-
137
149
  .dataviews-view-grid__field-value:empty,
138
150
  .dataviews-view-grid__field:empty {
139
151
  display: none;
140
152
  }
153
+
154
+ .dataviews-view-grid__card .dataviews-selection-checkbox {
155
+ position: absolute;
156
+ top: -9999em;
157
+ left: $grid-unit-10;
158
+ z-index: z-index(".dataviews-view-grid__card .dataviews-selection-checkbox");
159
+ }
160
+
161
+ .dataviews-view-grid__card:hover .dataviews-selection-checkbox,
162
+ .dataviews-view-grid__card:focus-within .dataviews-selection-checkbox,
163
+ .dataviews-view-grid__card.is-selected .dataviews-selection-checkbox {
164
+ top: $grid-unit-10;
165
+ }
@@ -2,6 +2,9 @@
2
2
  * External dependencies
3
3
  */
4
4
  import clsx from 'clsx';
5
+ // TODO: use the @wordpress/components one once public
6
+ // eslint-disable-next-line no-restricted-imports
7
+ import { useStoreState } from '@ariakit/react';
5
8
  // Import CompositeStore type, which is not exported from @wordpress/components.
6
9
  // eslint-disable-next-line no-restricted-imports
7
10
  import type { CompositeStore } from '@ariakit/react';
@@ -358,10 +361,11 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
358
361
 
359
362
  const store = useCompositeStore( {
360
363
  defaultActiveId: getItemDomId( selectedItem ),
361
- } );
364
+ } ) as CompositeStore; // TODO, remove once composite APIs are public
362
365
 
363
366
  // Manage focused item, when the active one is removed from the list.
364
- const isActiveIdInList = store.useState(
367
+ const isActiveIdInList = useStoreState(
368
+ store,
365
369
  ( state: { items: any[]; activeId: any } ) =>
366
370
  state.items.some(
367
371
  ( item: { id: any } ) => item.id === state.activeId
@@ -179,7 +179,10 @@
179
179
  }
180
180
 
181
181
  .dataviews-view-list__field-value {
182
- line-height: $grid-unit-05 * 6;
182
+ min-height: $grid-unit-30;
183
+ line-height: $grid-unit-05 * 5;
184
+ display: flex;
185
+ align-items: center;
183
186
  }
184
187
  }
185
188
 
@@ -72,7 +72,7 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
72
72
  );
73
73
  const index = view.fields?.indexOf( fieldId ) as number;
74
74
  if ( !! combinedField ) {
75
- return combinedField.label;
75
+ return combinedField.header || combinedField.label;
76
76
  }
77
77
  const field = fields.find( ( f ) => f.id === fieldId );
78
78
  if ( ! field ) {
@@ -91,9 +91,7 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
91
91
  !! field.elements?.length &&
92
92
  !! operators.length &&
93
93
  ! field.filterBy?.isPrimary;
94
- if ( ! isSortable && ! isHidable && ! canAddFilter ) {
95
- return field.label;
96
- }
94
+
97
95
  return (
98
96
  <DropdownMenu
99
97
  align="start"
@@ -104,7 +102,7 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
104
102
  ref={ ref }
105
103
  variant="tertiary"
106
104
  >
107
- { field.label }
105
+ { field.header }
108
106
  { view.sort && isSorted && (
109
107
  <span aria-hidden="true">
110
108
  { sortArrows[ view.sort.direction ] }
@@ -249,7 +247,7 @@ const _HeaderMenu = forwardRef( function HeaderMenu< Item >(
249
247
  } }
250
248
  >
251
249
  <DropdownMenuItemLabel>
252
- { __( 'Hide' ) }
250
+ { __( 'Hide column' ) }
253
251
  </DropdownMenuItemLabel>
254
252
  </DropdownMenuItem>
255
253
  ) }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { SortDirection, ValidationContext } from '../types';
5
+
6
+ function sort( a: any, b: any, direction: SortDirection ) {
7
+ const timeA = new Date( a ).getTime();
8
+ const timeB = new Date( b ).getTime();
9
+
10
+ return direction === 'asc' ? timeA - timeB : timeB - timeA;
11
+ }
12
+
13
+ function isValid( value: any, context?: ValidationContext ) {
14
+ if ( context?.elements ) {
15
+ const validValues = context?.elements.map( ( f ) => f.value );
16
+ if ( ! validValues.includes( value ) ) {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ return true;
22
+ }
23
+
24
+ export default {
25
+ sort,
26
+ isValid,
27
+ Edit: 'datetime',
28
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { FieldType, SortDirection, ValidationContext } from '../types';
5
+ import { default as integer } from './integer';
6
+ import { default as text } from './text';
7
+ import { default as datetime } from './datetime';
8
+
9
+ /**
10
+ *
11
+ * @param {FieldType} type The field type definition to get.
12
+ *
13
+ * @return A field type definition.
14
+ */
15
+ export default function getFieldTypeDefinition( type?: FieldType ) {
16
+ if ( 'integer' === type ) {
17
+ return integer;
18
+ }
19
+
20
+ if ( 'text' === type ) {
21
+ return text;
22
+ }
23
+
24
+ if ( 'datetime' === type ) {
25
+ return datetime;
26
+ }
27
+
28
+ return {
29
+ sort: ( a: any, b: any, direction: SortDirection ) => {
30
+ if ( typeof a === 'number' && typeof b === 'number' ) {
31
+ return direction === 'asc' ? a - b : b - a;
32
+ }
33
+
34
+ return direction === 'asc'
35
+ ? a.localeCompare( b )
36
+ : b.localeCompare( a );
37
+ },
38
+ isValid: ( value: any, context?: ValidationContext ) => {
39
+ if ( context?.elements ) {
40
+ const validValues = context?.elements?.map( ( f ) => f.value );
41
+ if ( ! validValues.includes( value ) ) {
42
+ return false;
43
+ }
44
+ }
45
+
46
+ return true;
47
+ },
48
+ Edit: () => null,
49
+ };
50
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { SortDirection, ValidationContext } from '../types';
5
+
6
+ function sort( a: any, b: any, direction: SortDirection ) {
7
+ return direction === 'asc' ? a - b : b - a;
8
+ }
9
+
10
+ function isValid( value: any, context?: ValidationContext ) {
11
+ // TODO: this implicitely means the value is required.
12
+ if ( value === '' ) {
13
+ return false;
14
+ }
15
+
16
+ if ( ! Number.isInteger( Number( value ) ) ) {
17
+ return false;
18
+ }
19
+
20
+ if ( context?.elements ) {
21
+ const validValues = context?.elements.map( ( f ) => f.value );
22
+ if ( ! validValues.includes( Number( value ) ) ) {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ return true;
28
+ }
29
+
30
+ export default {
31
+ sort,
32
+ isValid,
33
+ Edit: 'integer',
34
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { SortDirection, ValidationContext } from '../types';
5
+
6
+ function sort( valueA: any, valueB: any, direction: SortDirection ) {
7
+ return direction === 'asc'
8
+ ? valueA.localeCompare( valueB )
9
+ : valueB.localeCompare( valueA );
10
+ }
11
+
12
+ function isValid( value: any, context?: ValidationContext ) {
13
+ if ( context?.elements ) {
14
+ const validValues = context?.elements?.map( ( f ) => f.value );
15
+ if ( ! validValues.includes( value ) ) {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ return true;
21
+ }
22
+
23
+ export default {
24
+ sort,
25
+ isValid,
26
+ Edit: 'text',
27
+ };
@@ -140,21 +140,7 @@ export function filterSortAndPaginate< Item >(
140
140
  } );
141
141
  if ( fieldToSort ) {
142
142
  filteredData.sort( ( a, b ) => {
143
- const valueA = fieldToSort.getValue( { item: a } ) ?? '';
144
- const valueB = fieldToSort.getValue( { item: b } ) ?? '';
145
-
146
- if (
147
- typeof valueA === 'number' &&
148
- typeof valueB === 'number'
149
- ) {
150
- return view.sort?.direction === 'asc'
151
- ? valueA - valueB
152
- : valueB - valueA;
153
- }
154
-
155
- return view.sort?.direction === 'asc'
156
- ? valueA.localeCompare( valueB )
157
- : valueB.localeCompare( valueA );
143
+ return fieldToSort.sort( a, b, view.sort?.direction ?? 'desc' );
158
144
  } );
159
145
  }
160
146
  }
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { default as DataViews } from './components/dataviews';
2
2
  export { default as DataForm } from './components/dataform';
3
- export { VIEW_LAYOUTS } from './layouts';
3
+ export { VIEW_LAYOUTS } from './dataviews-layouts';
4
4
  export { filterSortAndPaginate } from './filter-and-sort-data-view';
5
5
  export type * from './types';
6
+ export { isItemValid } from './validation';
@@ -1,7 +1,9 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import type { Field, NormalizedField, ItemRecord } from './types';
4
+ import getFieldTypeDefinition from './field-types';
5
+ import type { Field, NormalizedField } from './types';
6
+ import { getControl } from './dataform-controls';
5
7
 
6
8
  /**
7
9
  * Apply default values and normalize the fields config.
@@ -13,15 +15,52 @@ export function normalizeFields< Item >(
13
15
  fields: Field< Item >[]
14
16
  ): NormalizedField< Item >[] {
15
17
  return fields.map( ( field ) => {
18
+ const fieldTypeDefinition = getFieldTypeDefinition( field.type );
19
+
16
20
  const getValue =
17
- field.getValue ||
18
- ( ( { item }: { item: ItemRecord } ) => item[ field.id ] );
21
+ field.getValue || ( ( { item } ) => ( item as any )[ field.id ] );
22
+
23
+ const sort =
24
+ field.sort ??
25
+ function sort( a, b, direction ) {
26
+ return fieldTypeDefinition.sort(
27
+ getValue( { item: a } ),
28
+ getValue( { item: b } ),
29
+ direction
30
+ );
31
+ };
32
+
33
+ const isValid =
34
+ field.isValid ??
35
+ function isValid( item, context ) {
36
+ return fieldTypeDefinition.isValid(
37
+ getValue( { item } ),
38
+ context
39
+ );
40
+ };
41
+
42
+ const Edit = getControl( field, fieldTypeDefinition );
43
+
44
+ const renderFromElements = ( { item }: { item: Item } ) => {
45
+ const value = getValue( { item } );
46
+ return (
47
+ field?.elements?.find( ( element ) => element.value === value )
48
+ ?.label || getValue( { item } )
49
+ );
50
+ };
51
+
52
+ const render =
53
+ field.render || ( field.elements ? renderFromElements : getValue );
19
54
 
20
55
  return {
21
56
  ...field,
22
57
  label: field.label || field.id,
58
+ header: field.header || field.label || field.id,
23
59
  getValue,
24
- render: field.render || getValue,
60
+ render,
61
+ sort,
62
+ isValid,
63
+ Edit,
25
64
  };
26
65
  } );
27
66
  }
package/src/style.scss CHANGED
@@ -5,7 +5,11 @@
5
5
  @import "./components/dataviews-pagination/style.scss";
6
6
  @import "./components/dataviews-item-actions/style.scss";
7
7
  @import "./components/dataviews-selection-checkbox/style.scss";
8
+ @import "./components/dataviews-view-config/style.scss";
8
9
 
9
- @import "./layouts/grid/style.scss";
10
- @import "./layouts/list/style.scss";
11
- @import "./layouts/table/style.scss";
10
+ @import "./dataviews-layouts/grid/style.scss";
11
+ @import "./dataviews-layouts/list/style.scss";
12
+ @import "./dataviews-layouts/table/style.scss";
13
+
14
+ @import "./dataform-controls/style.scss";
15
+ @import "./dataforms-layouts/panel/style.scss";
@@ -233,7 +233,22 @@ describe( 'filters', () => {
233
233
  } );
234
234
 
235
235
  describe( 'sorting', () => {
236
- it( 'should sort by string', () => {
236
+ it( 'should sort integer field types', () => {
237
+ const { data: result } = filterSortAndPaginate(
238
+ data,
239
+ {
240
+ sort: { field: 'satellites', direction: 'desc' },
241
+ },
242
+ fields
243
+ );
244
+
245
+ expect( result ).toHaveLength( 11 );
246
+ expect( result[ 0 ].title ).toBe( 'Saturn' );
247
+ expect( result[ 1 ].title ).toBe( 'Jupiter' );
248
+ expect( result[ 2 ].title ).toBe( 'Uranus' );
249
+ } );
250
+
251
+ it( 'should sort text field types', () => {
237
252
  const { data: result } = filterSortAndPaginate(
238
253
  data,
239
254
  {
@@ -253,13 +268,46 @@ describe( 'sorting', () => {
253
268
  expect( result[ 1 ].title ).toBe( 'Neptune' );
254
269
  } );
255
270
 
256
- it( 'should sort by number', () => {
271
+ it( 'should sort datetime field types', () => {
272
+ const { data: resultDesc } = filterSortAndPaginate(
273
+ data,
274
+ {
275
+ sort: { field: 'date', direction: 'desc' },
276
+ },
277
+ fields
278
+ );
279
+ expect( resultDesc ).toHaveLength( 11 );
280
+ expect( resultDesc[ 0 ].title ).toBe( 'NASA' );
281
+ expect( resultDesc[ 1 ].title ).toBe( 'Earth' );
282
+ expect( resultDesc[ 9 ].title ).toBe( 'Space' );
283
+ expect( resultDesc[ 10 ].title ).toBe( 'Jupiter' );
284
+
285
+ const { data: resultAsc } = filterSortAndPaginate(
286
+ data,
287
+ {
288
+ sort: { field: 'date', direction: 'asc' },
289
+ },
290
+ fields
291
+ );
292
+ expect( resultAsc ).toHaveLength( 11 );
293
+ expect( resultAsc[ 0 ].title ).toBe( 'Jupiter' );
294
+ expect( resultAsc[ 1 ].title ).toBe( 'Space' );
295
+ expect( resultAsc[ 9 ].title ).toBe( 'Earth' );
296
+ expect( resultAsc[ 10 ].title ).toBe( 'NASA' );
297
+ } );
298
+
299
+ it( 'should sort untyped fields if the value is a number', () => {
257
300
  const { data: result } = filterSortAndPaginate(
258
301
  data,
259
302
  {
260
303
  sort: { field: 'satellites', direction: 'desc' },
261
304
  },
262
- fields
305
+ // Remove type information for satellites field to test sorting untyped fields.
306
+ fields.map( ( field ) =>
307
+ field.id === 'satellites'
308
+ ? { ...field, type: undefined }
309
+ : field
310
+ )
263
311
  );
264
312
 
265
313
  expect( result ).toHaveLength( 11 );
@@ -267,6 +315,29 @@ describe( 'sorting', () => {
267
315
  expect( result[ 1 ].title ).toBe( 'Jupiter' );
268
316
  expect( result[ 2 ].title ).toBe( 'Uranus' );
269
317
  } );
318
+
319
+ it( 'should sort untyped fields if the value is string', () => {
320
+ const { data: result } = filterSortAndPaginate(
321
+ data,
322
+ {
323
+ sort: { field: 'title', direction: 'desc' },
324
+ filters: [
325
+ {
326
+ field: 'type',
327
+ operator: 'isAny',
328
+ value: [ 'Ice giant' ],
329
+ },
330
+ ],
331
+ },
332
+ // Remove type information for the title field to test sorting untyped fields.
333
+ fields.map( ( field ) =>
334
+ field.id === 'title' ? { ...field, type: undefined } : field
335
+ )
336
+ );
337
+ expect( result ).toHaveLength( 2 );
338
+ expect( result[ 0 ].title ).toBe( 'Uranus' );
339
+ expect( result[ 1 ].title ).toBe( 'Neptune' );
340
+ } );
270
341
  } );
271
342
 
272
343
  describe( 'pagination', () => {
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { isItemValid } from '../validation';
5
+ import type { Field } from '../types';
6
+
7
+ describe( 'validation', () => {
8
+ it( 'fields not visible in form are not validated', () => {
9
+ const item = { id: 1, valid_order: 2, invalid_order: 'd' };
10
+ const fields: Field< {} >[] = [
11
+ {
12
+ id: 'valid_order',
13
+ type: 'integer',
14
+ },
15
+ {
16
+ id: 'invalid_order',
17
+ type: 'integer',
18
+ },
19
+ ];
20
+ const form = { fields: [ 'valid_order' ] };
21
+ const result = isItemValid( item, fields, form );
22
+ expect( result ).toBe( true );
23
+ } );
24
+
25
+ it( 'integer field is valid if value is integer', () => {
26
+ const item = { id: 1, order: 2, title: 'hi' };
27
+ const fields: Field< {} >[] = [
28
+ {
29
+ type: 'integer',
30
+ id: 'order',
31
+ },
32
+ ];
33
+ const form = { fields: [ 'order' ] };
34
+ const result = isItemValid( item, fields, form );
35
+ expect( result ).toBe( true );
36
+ } );
37
+
38
+ it( 'integer field is invalid if value is not integer', () => {
39
+ const item = { id: 1, order: 'd' };
40
+ const fields: Field< {} >[] = [
41
+ {
42
+ id: 'order',
43
+ type: 'integer',
44
+ },
45
+ ];
46
+ const form = { fields: [ 'order' ] };
47
+ const result = isItemValid( item, fields, form );
48
+ expect( result ).toBe( false );
49
+ } );
50
+
51
+ it( 'integer field is invalid if value is empty', () => {
52
+ const item = { id: 1, order: '' };
53
+ const fields: Field< {} >[] = [
54
+ {
55
+ id: 'order',
56
+ type: 'integer',
57
+ },
58
+ ];
59
+ const form = { fields: [ 'order' ] };
60
+ const result = isItemValid( item, fields, form );
61
+ expect( result ).toBe( false );
62
+ } );
63
+
64
+ it( 'integer field is invalid if value is not one of the elements', () => {
65
+ const item = { id: 1, author: 3 };
66
+ const fields: Field< {} >[] = [
67
+ {
68
+ id: 'author',
69
+ type: 'integer',
70
+ elements: [
71
+ { value: 1, label: 'Jane' },
72
+ { value: 2, label: 'John' },
73
+ ],
74
+ },
75
+ ];
76
+ const form = { fields: [ 'author' ] };
77
+ const result = isItemValid( item, fields, form );
78
+ expect( result ).toBe( false );
79
+ } );
80
+
81
+ it( 'text field is invalid if value is not one of the elements', () => {
82
+ const item = { id: 1, author: 'not-in-elements' };
83
+ const fields: Field< {} >[] = [
84
+ {
85
+ id: 'author',
86
+ type: 'text',
87
+ elements: [
88
+ { value: 'jane', label: 'Jane' },
89
+ { value: 'john', label: 'John' },
90
+ ],
91
+ },
92
+ ];
93
+ const form = { fields: [ 'author' ] };
94
+ const result = isItemValid( item, fields, form );
95
+ expect( result ).toBe( false );
96
+ } );
97
+
98
+ it( 'untyped field is invalid if value is not one of the elements', () => {
99
+ const item = { id: 1, author: 'not-in-elements' };
100
+ const fields: Field< {} >[] = [
101
+ {
102
+ id: 'author',
103
+ elements: [
104
+ { value: 'jane', label: 'Jane' },
105
+ { value: 'john', label: 'John' },
106
+ ],
107
+ },
108
+ ];
109
+ const form = { fields: [ 'author' ] };
110
+ const result = isItemValid( item, fields, form );
111
+ expect( result ).toBe( false );
112
+ } );
113
+
114
+ it( 'fields can provide its own isValid function', () => {
115
+ const item = { id: 1, order: 'd' };
116
+ const fields: Field< {} >[] = [
117
+ {
118
+ id: 'order',
119
+ type: 'integer',
120
+ elements: [
121
+ { value: 'a', label: 'A' },
122
+ { value: 'b', label: 'B' },
123
+ ],
124
+ isValid: () => true, // Overrides the validation provided for integer types.
125
+ },
126
+ ];
127
+ const form = { fields: [ 'order' ] };
128
+ const result = isItemValid( item, fields, form );
129
+ expect( result ).toBe( true );
130
+ } );
131
+ } );