@wordpress/dataviews 11.0.0 → 11.1.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 (303) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +140 -93
  3. package/build/components/dataviews-filters/filter.js +25 -267
  4. package/build/components/dataviews-filters/filter.js.map +2 -2
  5. package/build/components/dataviews-filters/input-widget.js +1 -4
  6. package/build/components/dataviews-filters/input-widget.js.map +2 -2
  7. package/build/components/dataviews-filters/use-filters.js +3 -3
  8. package/build/components/dataviews-filters/use-filters.js.map +2 -2
  9. package/build/constants.js +5 -142
  10. package/build/constants.js.map +2 -2
  11. package/build/dataform-controls/number.js +2 -1
  12. package/build/dataform-controls/number.js.map +2 -2
  13. package/build/dataform-controls/textarea.js +3 -1
  14. package/build/dataform-controls/textarea.js.map +2 -2
  15. package/build/dataform-controls/utils/get-custom-validity.js +8 -0
  16. package/build/dataform-controls/utils/get-custom-validity.js.map +2 -2
  17. package/build/dataform-controls/utils/validated-input.js +4 -2
  18. package/build/dataform-controls/utils/validated-input.js.map +2 -2
  19. package/build/dataform-controls/utils/validated-number.js +4 -2
  20. package/build/dataform-controls/utils/validated-number.js.map +2 -2
  21. package/build/dataform-layouts/panel/modal.js +14 -5
  22. package/build/dataform-layouts/panel/modal.js.map +2 -2
  23. package/build/dataviews-layouts/grid/composite-grid.js +39 -37
  24. package/build/dataviews-layouts/grid/composite-grid.js.map +3 -3
  25. package/build/dataviews-layouts/table/index.js +8 -3
  26. package/build/dataviews-layouts/table/index.js.map +2 -2
  27. package/build/field-types/array.js +27 -14
  28. package/build/field-types/array.js.map +3 -3
  29. package/build/field-types/boolean.js +13 -10
  30. package/build/field-types/boolean.js.map +3 -3
  31. package/build/field-types/color.js +14 -11
  32. package/build/field-types/color.js.map +3 -3
  33. package/build/field-types/date.js +11 -8
  34. package/build/field-types/date.js.map +3 -3
  35. package/build/field-types/datetime.js +7 -5
  36. package/build/field-types/datetime.js.map +3 -3
  37. package/build/field-types/email.js +20 -11
  38. package/build/field-types/email.js.map +3 -3
  39. package/build/field-types/index.js +12 -14
  40. package/build/field-types/index.js.map +3 -3
  41. package/build/field-types/integer.js +63 -14
  42. package/build/field-types/integer.js.map +3 -3
  43. package/build/field-types/media.js +5 -5
  44. package/build/field-types/media.js.map +2 -2
  45. package/build/field-types/no-type.js +9 -6
  46. package/build/field-types/no-type.js.map +3 -3
  47. package/build/field-types/number.js +51 -15
  48. package/build/field-types/number.js.map +3 -3
  49. package/build/field-types/password.js +13 -5
  50. package/build/field-types/password.js.map +3 -3
  51. package/build/field-types/telephone.js +13 -5
  52. package/build/field-types/telephone.js.map +3 -3
  53. package/build/field-types/text.js +13 -5
  54. package/build/field-types/text.js.map +3 -3
  55. package/build/field-types/url.js +13 -5
  56. package/build/field-types/url.js.map +3 -3
  57. package/build/field-types/utils/get-is-valid.js +89 -0
  58. package/build/field-types/utils/get-is-valid.js.map +7 -0
  59. package/build/field-types/utils/is-valid-elements.js +35 -0
  60. package/build/field-types/utils/is-valid-elements.js.map +7 -0
  61. package/build/field-types/utils/is-valid-max-length.js +36 -0
  62. package/build/field-types/utils/is-valid-max-length.js.map +7 -0
  63. package/build/field-types/utils/is-valid-max.js +36 -0
  64. package/build/field-types/utils/is-valid-max.js.map +7 -0
  65. package/build/field-types/utils/is-valid-min-length.js +36 -0
  66. package/build/field-types/utils/is-valid-min-length.js.map +7 -0
  67. package/build/field-types/utils/is-valid-min.js +36 -0
  68. package/build/field-types/utils/is-valid-min.js.map +7 -0
  69. package/build/field-types/utils/is-valid-pattern.js +41 -0
  70. package/build/field-types/utils/is-valid-pattern.js.map +7 -0
  71. package/build/field-types/utils/is-valid-required-for-array.js +32 -0
  72. package/build/field-types/utils/is-valid-required-for-array.js.map +7 -0
  73. package/build/field-types/utils/is-valid-required-for-bool.js +30 -0
  74. package/build/field-types/utils/is-valid-required-for-bool.js.map +7 -0
  75. package/build/field-types/utils/is-valid-required.js +30 -0
  76. package/build/field-types/utils/is-valid-required.js.map +7 -0
  77. package/build/hooks/use-form-validity.js +52 -102
  78. package/build/hooks/use-form-validity.js.map +2 -2
  79. package/build/types/field-api.js.map +1 -1
  80. package/build/types/private.js.map +1 -1
  81. package/build/utils/filter-sort-and-paginate.js +5 -0
  82. package/build/utils/filter-sort-and-paginate.js.map +3 -3
  83. package/build/utils/operators.js +399 -0
  84. package/build/utils/operators.js.map +7 -0
  85. package/build-module/components/dataviews-filters/filter.js +26 -292
  86. package/build-module/components/dataviews-filters/filter.js.map +2 -2
  87. package/build-module/components/dataviews-filters/input-widget.js +1 -4
  88. package/build-module/components/dataviews-filters/input-widget.js.map +2 -2
  89. package/build-module/components/dataviews-filters/use-filters.js +6 -3
  90. package/build-module/components/dataviews-filters/use-filters.js.map +2 -2
  91. package/build-module/constants.js +5 -139
  92. package/build-module/constants.js.map +2 -2
  93. package/build-module/dataform-controls/number.js +2 -1
  94. package/build-module/dataform-controls/number.js.map +2 -2
  95. package/build-module/dataform-controls/textarea.js +3 -1
  96. package/build-module/dataform-controls/textarea.js.map +2 -2
  97. package/build-module/dataform-controls/utils/get-custom-validity.js +8 -0
  98. package/build-module/dataform-controls/utils/get-custom-validity.js.map +2 -2
  99. package/build-module/dataform-controls/utils/validated-input.js +4 -2
  100. package/build-module/dataform-controls/utils/validated-input.js.map +2 -2
  101. package/build-module/dataform-controls/utils/validated-number.js +4 -2
  102. package/build-module/dataform-controls/utils/validated-number.js.map +2 -2
  103. package/build-module/dataform-layouts/panel/modal.js +14 -5
  104. package/build-module/dataform-layouts/panel/modal.js.map +2 -2
  105. package/build-module/dataviews-layouts/grid/composite-grid.js +40 -38
  106. package/build-module/dataviews-layouts/grid/composite-grid.js.map +3 -3
  107. package/build-module/dataviews-layouts/table/index.js +8 -3
  108. package/build-module/dataviews-layouts/table/index.js.map +2 -2
  109. package/build-module/field-types/array.js +17 -14
  110. package/build-module/field-types/array.js.map +2 -2
  111. package/build-module/field-types/boolean.js +13 -10
  112. package/build-module/field-types/boolean.js.map +2 -2
  113. package/build-module/field-types/color.js +14 -11
  114. package/build-module/field-types/color.js.map +2 -2
  115. package/build-module/field-types/date.js +11 -8
  116. package/build-module/field-types/date.js.map +2 -2
  117. package/build-module/field-types/datetime.js +7 -5
  118. package/build-module/field-types/datetime.js.map +2 -2
  119. package/build-module/field-types/email.js +20 -11
  120. package/build-module/field-types/email.js.map +2 -2
  121. package/build-module/field-types/index.js +12 -14
  122. package/build-module/field-types/index.js.map +2 -2
  123. package/build-module/field-types/integer.js +58 -13
  124. package/build-module/field-types/integer.js.map +2 -2
  125. package/build-module/field-types/media.js +5 -5
  126. package/build-module/field-types/media.js.map +2 -2
  127. package/build-module/field-types/no-type.js +10 -7
  128. package/build-module/field-types/no-type.js.map +2 -2
  129. package/build-module/field-types/number.js +47 -15
  130. package/build-module/field-types/number.js.map +2 -2
  131. package/build-module/field-types/password.js +13 -5
  132. package/build-module/field-types/password.js.map +2 -2
  133. package/build-module/field-types/telephone.js +13 -5
  134. package/build-module/field-types/telephone.js.map +2 -2
  135. package/build-module/field-types/text.js +13 -5
  136. package/build-module/field-types/text.js.map +2 -2
  137. package/build-module/field-types/url.js +13 -5
  138. package/build-module/field-types/url.js.map +2 -2
  139. package/build-module/field-types/utils/get-is-valid.js +68 -0
  140. package/build-module/field-types/utils/get-is-valid.js.map +7 -0
  141. package/build-module/field-types/utils/is-valid-elements.js +14 -0
  142. package/build-module/field-types/utils/is-valid-elements.js.map +7 -0
  143. package/build-module/field-types/utils/is-valid-max-length.js +15 -0
  144. package/build-module/field-types/utils/is-valid-max-length.js.map +7 -0
  145. package/build-module/field-types/utils/is-valid-max.js +15 -0
  146. package/build-module/field-types/utils/is-valid-max.js.map +7 -0
  147. package/build-module/field-types/utils/is-valid-min-length.js +15 -0
  148. package/build-module/field-types/utils/is-valid-min-length.js.map +7 -0
  149. package/build-module/field-types/utils/is-valid-min.js +15 -0
  150. package/build-module/field-types/utils/is-valid-min.js.map +7 -0
  151. package/build-module/field-types/utils/is-valid-pattern.js +20 -0
  152. package/build-module/field-types/utils/is-valid-pattern.js.map +7 -0
  153. package/build-module/field-types/utils/is-valid-required-for-array.js +11 -0
  154. package/build-module/field-types/utils/is-valid-required-for-array.js.map +7 -0
  155. package/build-module/field-types/utils/is-valid-required-for-bool.js +9 -0
  156. package/build-module/field-types/utils/is-valid-required-for-bool.js.map +7 -0
  157. package/build-module/field-types/utils/is-valid-required.js +9 -0
  158. package/build-module/field-types/utils/is-valid-required.js.map +7 -0
  159. package/build-module/hooks/use-form-validity.js +52 -102
  160. package/build-module/hooks/use-form-validity.js.map +2 -2
  161. package/build-module/utils/filter-sort-and-paginate.js +5 -0
  162. package/build-module/utils/filter-sort-and-paginate.js.map +2 -2
  163. package/build-module/utils/operators.js +394 -0
  164. package/build-module/utils/operators.js.map +7 -0
  165. package/build-style/style-rtl.css +13 -80
  166. package/build-style/style.css +13 -80
  167. package/build-types/components/dataviews-filters/filter.d.ts.map +1 -1
  168. package/build-types/components/dataviews-filters/input-widget.d.ts.map +1 -1
  169. package/build-types/components/dataviews-filters/use-filters.d.ts.map +1 -1
  170. package/build-types/constants.d.ts +6 -12
  171. package/build-types/constants.d.ts.map +1 -1
  172. package/build-types/dataform-controls/number.d.ts.map +1 -1
  173. package/build-types/dataform-controls/textarea.d.ts.map +1 -1
  174. package/build-types/dataform-controls/utils/get-custom-validity.d.ts +2 -2
  175. package/build-types/dataform-controls/utils/get-custom-validity.d.ts.map +1 -1
  176. package/build-types/dataform-controls/utils/validated-input.d.ts.map +1 -1
  177. package/build-types/dataform-controls/utils/validated-number.d.ts.map +1 -1
  178. package/build-types/dataform-layouts/panel/modal.d.ts.map +1 -1
  179. package/build-types/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
  180. package/build-types/dataviews-layouts/table/index.d.ts.map +1 -1
  181. package/build-types/field-types/array.d.ts +9 -2
  182. package/build-types/field-types/array.d.ts.map +1 -1
  183. package/build-types/field-types/boolean.d.ts +9 -2
  184. package/build-types/field-types/boolean.d.ts.map +1 -1
  185. package/build-types/field-types/color.d.ts +9 -2
  186. package/build-types/field-types/color.d.ts.map +1 -1
  187. package/build-types/field-types/date.d.ts +6 -4
  188. package/build-types/field-types/date.d.ts.map +1 -1
  189. package/build-types/field-types/datetime.d.ts +6 -4
  190. package/build-types/field-types/datetime.d.ts.map +1 -1
  191. package/build-types/field-types/email.d.ts +15 -2
  192. package/build-types/field-types/email.d.ts.map +1 -1
  193. package/build-types/field-types/index.d.ts.map +1 -1
  194. package/build-types/field-types/integer.d.ts +17 -4
  195. package/build-types/field-types/integer.d.ts.map +1 -1
  196. package/build-types/field-types/media.d.ts +1 -4
  197. package/build-types/field-types/media.d.ts.map +1 -1
  198. package/build-types/field-types/no-type.d.ts +6 -4
  199. package/build-types/field-types/no-type.d.ts.map +1 -1
  200. package/build-types/field-types/number.d.ts +17 -4
  201. package/build-types/field-types/number.d.ts.map +1 -1
  202. package/build-types/field-types/password.d.ts +12 -4
  203. package/build-types/field-types/password.d.ts.map +1 -1
  204. package/build-types/field-types/telephone.d.ts +12 -4
  205. package/build-types/field-types/telephone.d.ts.map +1 -1
  206. package/build-types/field-types/text.d.ts +12 -4
  207. package/build-types/field-types/text.d.ts.map +1 -1
  208. package/build-types/field-types/url.d.ts +12 -4
  209. package/build-types/field-types/url.d.ts.map +1 -1
  210. package/build-types/field-types/utils/get-is-valid.d.ts +7 -0
  211. package/build-types/field-types/utils/get-is-valid.d.ts.map +1 -0
  212. package/build-types/field-types/utils/is-valid-elements.d.ts +6 -0
  213. package/build-types/field-types/utils/is-valid-elements.d.ts.map +1 -0
  214. package/build-types/field-types/utils/is-valid-max-length.d.ts +6 -0
  215. package/build-types/field-types/utils/is-valid-max-length.d.ts.map +1 -0
  216. package/build-types/field-types/utils/is-valid-max.d.ts +6 -0
  217. package/build-types/field-types/utils/is-valid-max.d.ts.map +1 -0
  218. package/build-types/field-types/utils/is-valid-min-length.d.ts +6 -0
  219. package/build-types/field-types/utils/is-valid-min-length.d.ts.map +1 -0
  220. package/build-types/field-types/utils/is-valid-min.d.ts +6 -0
  221. package/build-types/field-types/utils/is-valid-min.d.ts.map +1 -0
  222. package/build-types/field-types/utils/is-valid-pattern.d.ts +6 -0
  223. package/build-types/field-types/utils/is-valid-pattern.d.ts.map +1 -0
  224. package/build-types/field-types/utils/is-valid-required-for-array.d.ts +6 -0
  225. package/build-types/field-types/utils/is-valid-required-for-array.d.ts.map +1 -0
  226. package/build-types/field-types/utils/is-valid-required-for-bool.d.ts +6 -0
  227. package/build-types/field-types/utils/is-valid-required-for-bool.d.ts.map +1 -0
  228. package/build-types/field-types/utils/is-valid-required.d.ts +6 -0
  229. package/build-types/field-types/utils/is-valid-required.d.ts.map +1 -0
  230. package/build-types/hooks/use-form-validity.d.ts.map +1 -1
  231. package/build-types/stories/dataform.story.d.ts +9 -1
  232. package/build-types/stories/dataform.story.d.ts.map +1 -1
  233. package/build-types/stories/dataviews-picker.story.d.ts.map +1 -1
  234. package/build-types/stories/dataviews.story.d.ts +27 -2
  235. package/build-types/stories/dataviews.story.d.ts.map +1 -1
  236. package/build-types/stories/field-types.story.d.ts +39 -2
  237. package/build-types/stories/field-types.story.d.ts.map +1 -1
  238. package/build-types/types/field-api.d.ts +72 -4
  239. package/build-types/types/field-api.d.ts.map +1 -1
  240. package/build-types/types/private.d.ts +13 -3
  241. package/build-types/types/private.d.ts.map +1 -1
  242. package/build-types/utils/filter-sort-and-paginate.d.ts.map +1 -1
  243. package/build-types/utils/operators.d.ts +16 -0
  244. package/build-types/utils/operators.d.ts.map +1 -0
  245. package/build-wp/index.js +1548 -1452
  246. package/package.json +17 -16
  247. package/src/components/dataviews/style.scss +3 -28
  248. package/src/components/dataviews-filters/filter.tsx +34 -321
  249. package/src/components/dataviews-filters/input-widget.tsx +7 -5
  250. package/src/components/dataviews-filters/use-filters.ts +6 -3
  251. package/src/components/dataviews-footer/style.scss +1 -7
  252. package/src/constants.ts +6 -140
  253. package/src/dataform-controls/number.tsx +3 -3
  254. package/src/dataform-controls/textarea.tsx +7 -1
  255. package/src/dataform-controls/utils/get-custom-validity.ts +10 -2
  256. package/src/dataform-controls/utils/validated-input.tsx +8 -2
  257. package/src/dataform-controls/utils/validated-number.tsx +3 -1
  258. package/src/dataform-layouts/panel/modal.tsx +14 -5
  259. package/src/dataviews-layouts/activity/style.scss +1 -1
  260. package/src/dataviews-layouts/grid/composite-grid.tsx +64 -57
  261. package/src/dataviews-layouts/grid/style.scss +3 -12
  262. package/src/dataviews-layouts/table/index.tsx +9 -3
  263. package/src/dataviews-layouts/table/style.scss +4 -15
  264. package/src/dataviews-layouts/utils/grid-items.scss +1 -9
  265. package/src/field-types/array.tsx +26 -19
  266. package/src/field-types/boolean.tsx +22 -15
  267. package/src/field-types/color.tsx +22 -15
  268. package/src/field-types/date.tsx +14 -11
  269. package/src/field-types/datetime.tsx +6 -4
  270. package/src/field-types/email.tsx +24 -15
  271. package/src/field-types/index.tsx +12 -14
  272. package/src/field-types/integer.tsx +83 -17
  273. package/src/field-types/media.tsx +4 -4
  274. package/src/field-types/no-type.tsx +9 -6
  275. package/src/field-types/number.tsx +82 -16
  276. package/src/field-types/password.tsx +12 -4
  277. package/src/field-types/telephone.tsx +12 -4
  278. package/src/field-types/text.tsx +12 -4
  279. package/src/field-types/url.tsx +12 -4
  280. package/src/field-types/utils/get-is-valid.ts +103 -0
  281. package/src/field-types/utils/is-valid-elements.ts +20 -0
  282. package/src/field-types/utils/is-valid-max-length.ts +23 -0
  283. package/src/field-types/utils/is-valid-max.ts +23 -0
  284. package/src/field-types/utils/is-valid-min-length.ts +23 -0
  285. package/src/field-types/utils/is-valid-min.ts +23 -0
  286. package/src/field-types/utils/is-valid-pattern.ts +29 -0
  287. package/src/field-types/utils/is-valid-required-for-array.ts +18 -0
  288. package/src/field-types/utils/is-valid-required-for-bool.ts +13 -0
  289. package/src/field-types/utils/is-valid-required.ts +13 -0
  290. package/src/hooks/use-form-validity.ts +78 -156
  291. package/src/stories/dataform.story.tsx +126 -30
  292. package/src/stories/dataviews-picker.story.tsx +27 -17
  293. package/src/stories/dataviews.story.tsx +79 -30
  294. package/src/stories/field-types.story.tsx +86 -4
  295. package/src/test/filter-sort-and-paginate.js +2 -1
  296. package/src/test/normalize-fields.ts +87 -11
  297. package/src/test/use-form-validity.ts +796 -31
  298. package/src/types/field-api.ts +90 -4
  299. package/src/types/private.ts +26 -8
  300. package/src/utils/filter-sort-and-paginate.ts +5 -0
  301. package/src/utils/operators.tsx +448 -0
  302. package/tsconfig.json +1 -0
  303. package/tsconfig.tsbuildinfo +1 -1
@@ -6,7 +6,11 @@ import { __ } from '@wordpress/i18n';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import type { DataViewRenderFieldProps, Rules, SortDirection } from '../types';
9
+ import type {
10
+ DataViewRenderFieldProps,
11
+ NormalizedField,
12
+ SortDirection,
13
+ } from '../types';
10
14
  import type { FieldType } from '../types/private';
11
15
  import {
12
16
  OPERATOR_IS_ALL,
@@ -14,32 +18,31 @@ import {
14
18
  OPERATOR_IS_NONE,
15
19
  OPERATOR_IS_NOT_ALL,
16
20
  } from '../constants';
21
+ import isValidRequiredForArray from './utils/is-valid-required-for-array';
22
+ import isValidElements from './utils/is-valid-elements';
17
23
 
18
24
  function render( { item, field }: DataViewRenderFieldProps< any > ) {
19
25
  const value = field.getValue( { item } ) || [];
20
26
  return value.join( ', ' );
21
27
  }
22
28
 
23
- const isValid: Rules< any > = {
24
- elements: true,
25
- custom: ( item: any, normalizedField ) => {
26
- const value = normalizedField.getValue( { item } );
29
+ function isValidCustom< Item >( item: Item, field: NormalizedField< Item > ) {
30
+ const value = field.getValue( { item } );
27
31
 
28
- if (
29
- ! [ undefined, '', null ].includes( value ) &&
30
- ! Array.isArray( value )
31
- ) {
32
- return __( 'Value must be an array.' );
33
- }
32
+ if (
33
+ ! [ undefined, '', null ].includes( value ) &&
34
+ ! Array.isArray( value )
35
+ ) {
36
+ return __( 'Value must be an array.' );
37
+ }
34
38
 
35
- // Only allow strings for now. Can be extended to other types in the future.
36
- if ( ! value.every( ( v: any ) => typeof v === 'string' ) ) {
37
- return __( 'Every value must be a string.' );
38
- }
39
+ // Only allow strings for now. Can be extended to other types in the future.
40
+ if ( ! value.every( ( v: any ) => typeof v === 'string' ) ) {
41
+ return __( 'Every value must be a string.' );
42
+ }
39
43
 
40
- return null;
41
- },
42
- };
44
+ return null;
45
+ }
43
46
 
44
47
  const sort = ( a: any, b: any, direction: SortDirection ) => {
45
48
  // Sort arrays by length, then alphabetically by joined string
@@ -63,7 +66,6 @@ export default {
63
66
  render,
64
67
  Edit: 'array',
65
68
  sort,
66
- isValid,
67
69
  enableSorting: true,
68
70
  enableGlobalSearch: false,
69
71
  defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
@@ -74,4 +76,9 @@ export default {
74
76
  OPERATOR_IS_NOT_ALL,
75
77
  ],
76
78
  getFormat: () => ( {} ),
79
+ validate: {
80
+ required: isValidRequiredForArray,
81
+ elements: isValidElements,
82
+ custom: isValidCustom,
83
+ },
77
84
  } satisfies FieldType< any >;
@@ -6,10 +6,16 @@ import { __ } from '@wordpress/i18n';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import type { DataViewRenderFieldProps, Rules, SortDirection } from '../types';
9
+ import type {
10
+ DataViewRenderFieldProps,
11
+ NormalizedField,
12
+ SortDirection,
13
+ } from '../types';
10
14
  import type { FieldType } from '../types/private';
11
15
  import RenderFromElements from './utils/render-from-elements';
12
16
  import { OPERATOR_IS, OPERATOR_IS_NOT } from '../constants';
17
+ import isValidElements from './utils/is-valid-elements';
18
+ import isValidRequiredForBool from './utils/is-valid-required-for-bool';
13
19
 
14
20
  function render( { item, field }: DataViewRenderFieldProps< any > ) {
15
21
  if ( field.hasElements ) {
@@ -27,21 +33,18 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
27
33
  return null;
28
34
  }
29
35
 
30
- const isValid: Rules< any > = {
31
- elements: true,
32
- custom: ( item: any, normalizedField ) => {
33
- const value = normalizedField.getValue( { item } );
36
+ function isValidCustom< Item >( item: Item, field: NormalizedField< Item > ) {
37
+ const value = field.getValue( { item } );
34
38
 
35
- if (
36
- ! [ undefined, '', null ].includes( value ) &&
37
- ! [ true, false ].includes( value )
38
- ) {
39
- return __( 'Value must be true, false, or undefined' );
40
- }
39
+ if (
40
+ ! [ undefined, '', null ].includes( value ) &&
41
+ ! [ true, false ].includes( value )
42
+ ) {
43
+ return __( 'Value must be true, false, or undefined' );
44
+ }
41
45
 
42
- return null;
43
- },
44
- };
46
+ return null;
47
+ }
45
48
 
46
49
  const sort = ( a: any, b: any, direction: SortDirection ) => {
47
50
  const boolA = Boolean( a );
@@ -65,7 +68,11 @@ export default {
65
68
  render,
66
69
  Edit: 'checkbox',
67
70
  sort,
68
- isValid,
71
+ validate: {
72
+ required: isValidRequiredForBool,
73
+ elements: isValidElements,
74
+ custom: isValidCustom,
75
+ },
69
76
  enableSorting: true,
70
77
  enableGlobalSearch: false,
71
78
  defaultOperators: [ OPERATOR_IS, OPERATOR_IS_NOT ],
@@ -11,7 +11,11 @@ import { __ } from '@wordpress/i18n';
11
11
  /**
12
12
  * Internal dependencies
13
13
  */
14
- import type { DataViewRenderFieldProps, Rules, SortDirection } from '../types';
14
+ import type {
15
+ DataViewRenderFieldProps,
16
+ NormalizedField,
17
+ SortDirection,
18
+ } from '../types';
15
19
  import type { FieldType } from '../types/private';
16
20
  import RenderFromElements from './utils/render-from-elements';
17
21
  import {
@@ -20,6 +24,8 @@ import {
20
24
  OPERATOR_IS_NONE,
21
25
  OPERATOR_IS_NOT,
22
26
  } from '../constants';
27
+ import isValidElements from './utils/is-valid-elements';
28
+ import isValidRequired from './utils/is-valid-required';
23
29
 
24
30
  function render( { item, field }: DataViewRenderFieldProps< any > ) {
25
31
  if ( field.hasElements ) {
@@ -50,21 +56,18 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
50
56
  );
51
57
  }
52
58
 
53
- const isValid: Rules< any > = {
54
- elements: true,
55
- custom: ( item: any, normalizedField ) => {
56
- const value = normalizedField.getValue( { item } );
59
+ function isValidCustom< Item >( item: Item, field: NormalizedField< Item > ) {
60
+ const value = field.getValue( { item } );
57
61
 
58
- if (
59
- ! [ undefined, '', null ].includes( value ) &&
60
- ! colord( value ).isValid()
61
- ) {
62
- return __( 'Value must be a valid color.' );
63
- }
62
+ if (
63
+ ! [ undefined, '', null ].includes( value ) &&
64
+ ! colord( value ).isValid()
65
+ ) {
66
+ return __( 'Value must be a valid color.' );
67
+ }
64
68
 
65
- return null;
66
- },
67
- };
69
+ return null;
70
+ }
68
71
 
69
72
  const sort = ( a: any, b: any, direction: SortDirection ) => {
70
73
  // Convert colors to HSL for better sorting
@@ -99,7 +102,6 @@ export default {
99
102
  render,
100
103
  Edit: 'color',
101
104
  sort,
102
- isValid,
103
105
  enableSorting: true,
104
106
  enableGlobalSearch: false,
105
107
  defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
@@ -110,4 +112,9 @@ export default {
110
112
  OPERATOR_IS_NONE,
111
113
  ],
112
114
  getFormat: () => ( {} ),
115
+ validate: {
116
+ required: isValidRequired,
117
+ elements: isValidElements,
118
+ custom: isValidCustom,
119
+ },
113
120
  } satisfies FieldType< any >;
@@ -14,6 +14,7 @@ import type {
14
14
  } from '../types';
15
15
  import type { FieldType } from '../types/private';
16
16
  import RenderFromElements from './utils/render-from-elements';
17
+ import isValidElements from './utils/is-valid-elements';
17
18
  import {
18
19
  OPERATOR_ON,
19
20
  OPERATOR_NOT_ON,
@@ -26,18 +27,20 @@ import {
26
27
  OPERATOR_BETWEEN,
27
28
  DAYS_OF_WEEK,
28
29
  } from '../constants';
30
+ import isValidRequired from './utils/is-valid-required';
29
31
 
30
32
  function getFormat< Item >( field: Field< Item > ): Required< FormatDate > {
33
+ const fieldFormat = field.format as FormatDate | undefined;
31
34
  return {
32
35
  date:
33
- field.format?.date !== undefined &&
34
- typeof field.format.date === 'string'
35
- ? field.format.date
36
+ fieldFormat?.date !== undefined &&
37
+ typeof fieldFormat.date === 'string'
38
+ ? fieldFormat.date
36
39
  : getSettings().formats.date,
37
40
  weekStartsOn:
38
- field.format?.weekStartsOn !== undefined &&
39
- DAYS_OF_WEEK.includes( field.format?.weekStartsOn )
40
- ? field.format.weekStartsOn
41
+ fieldFormat?.weekStartsOn !== undefined &&
42
+ DAYS_OF_WEEK.includes( fieldFormat?.weekStartsOn )
43
+ ? fieldFormat.weekStartsOn
41
44
  : getSettings().l10n.startOfWeek,
42
45
  };
43
46
  }
@@ -59,7 +62,7 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
59
62
  // but TypeScript is unable to infer this, hence the type assertion.
60
63
  let format: Required< FormatDate >;
61
64
  if ( field.type !== 'date' ) {
62
- format = getFormat( field as Field< any > );
65
+ format = getFormat( {} as Field< any > );
63
66
  } else {
64
67
  format = field.format as Required< FormatDate >;
65
68
  }
@@ -79,10 +82,6 @@ export default {
79
82
  render,
80
83
  Edit: 'date',
81
84
  sort,
82
- isValid: {
83
- elements: true,
84
- custom: () => null,
85
- },
86
85
  enableSorting: true,
87
86
  enableGlobalSearch: false,
88
87
  defaultOperators: [
@@ -108,4 +107,8 @@ export default {
108
107
  OPERATOR_BETWEEN,
109
108
  ],
110
109
  getFormat,
110
+ validate: {
111
+ required: isValidRequired,
112
+ elements: isValidElements,
113
+ },
111
114
  } satisfies FieldType< any >;
@@ -5,6 +5,7 @@ import type { DataViewRenderFieldProps, SortDirection } from '../types';
5
5
  import type { FieldType } from '../types/private';
6
6
  import RenderFromElements from './utils/render-from-elements';
7
7
  import parseDateTime from './utils/parse-date-time';
8
+ import isValidElements from './utils/is-valid-elements';
8
9
  import {
9
10
  OPERATOR_ON,
10
11
  OPERATOR_NOT_ON,
@@ -15,6 +16,7 @@ import {
15
16
  OPERATOR_IN_THE_PAST,
16
17
  OPERATOR_OVER,
17
18
  } from '../constants';
19
+ import isValidRequired from './utils/is-valid-required';
18
20
 
19
21
  function render( { item, field }: DataViewRenderFieldProps< any > ) {
20
22
  if ( field.elements ) {
@@ -46,10 +48,6 @@ export default {
46
48
  render,
47
49
  Edit: 'datetime',
48
50
  sort,
49
- isValid: {
50
- elements: true,
51
- custom: () => null,
52
- },
53
51
  enableSorting: true,
54
52
  enableGlobalSearch: false,
55
53
  defaultOperators: [
@@ -73,4 +71,8 @@ export default {
73
71
  OPERATOR_OVER,
74
72
  ],
75
73
  getFormat: () => ( {} ),
74
+ validate: {
75
+ required: isValidRequired,
76
+ elements: isValidElements,
77
+ },
76
78
  } satisfies FieldType< any >;
@@ -6,7 +6,7 @@ import { __ } from '@wordpress/i18n';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import type { Rules } from '../types';
9
+ import type { NormalizedField } from '../types';
10
10
  import type { FieldType } from '../types/private';
11
11
  import {
12
12
  OPERATOR_IS,
@@ -21,34 +21,35 @@ import {
21
21
  } from '../constants';
22
22
  import render from './utils/render-default';
23
23
  import sort from './utils/sort-text';
24
+ import isValidRequired from './utils/is-valid-required';
25
+ import isValidMinLength from './utils/is-valid-min-length';
26
+ import isValidMaxLength from './utils/is-valid-max-length';
27
+ import isValidPattern from './utils/is-valid-pattern';
28
+ import isValidElements from './utils/is-valid-elements';
24
29
 
25
30
  // Email validation regex based on HTML5 spec
26
31
  // https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
27
32
  const emailRegex =
28
33
  /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
29
34
 
30
- const isValid: Rules< any > = {
31
- elements: true,
32
- custom: ( item: any, normalizedField ) => {
33
- const value = normalizedField.getValue( { item } );
35
+ function isValidCustom< Item >( item: Item, field: NormalizedField< Item > ) {
36
+ const value = field.getValue( { item } );
34
37
 
35
- if (
36
- ! [ undefined, '', null ].includes( value ) &&
37
- ! emailRegex.test( value )
38
- ) {
39
- return __( 'Value must be a valid email address.' );
40
- }
38
+ if (
39
+ ! [ undefined, '', null ].includes( value ) &&
40
+ ! emailRegex.test( value )
41
+ ) {
42
+ return __( 'Value must be a valid email address.' );
43
+ }
41
44
 
42
- return null;
43
- },
44
- };
45
+ return null;
46
+ }
45
47
 
46
48
  export default {
47
49
  type: 'email',
48
50
  render,
49
51
  Edit: 'email',
50
52
  sort,
51
- isValid,
52
53
  enableSorting: true,
53
54
  enableGlobalSearch: false,
54
55
  defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
@@ -65,4 +66,12 @@ export default {
65
66
  OPERATOR_IS_NOT_ALL,
66
67
  ],
67
68
  getFormat: () => ( {} ),
69
+ validate: {
70
+ required: isValidRequired,
71
+ pattern: isValidPattern,
72
+ minLength: isValidMinLength,
73
+ maxLength: isValidMaxLength,
74
+ elements: isValidElements,
75
+ custom: isValidCustom,
76
+ },
68
77
  } satisfies FieldType< any >;
@@ -27,6 +27,7 @@ import { default as telephone } from './telephone';
27
27
  import { default as color } from './color';
28
28
  import { default as url } from './url';
29
29
  import { default as noType } from './no-type';
30
+ import getIsValid from './utils/get-is-valid';
30
31
 
31
32
  /**
32
33
  *
@@ -70,7 +71,7 @@ export default function normalizeFields< Item >(
70
71
  fields: Field< Item >[]
71
72
  ): NormalizedField< Item >[] {
72
73
  return fields.map( ( field ) => {
73
- const defaultProps = getFieldTypeByName< Item >( field.type );
74
+ const fieldType = getFieldTypeByName< Item >( field.type );
74
75
 
75
76
  const getValue = field.getValue || getValueFromId( field.id );
76
77
  const sort = function ( a: any, b: any, direction: SortDirection ) {
@@ -78,7 +79,7 @@ export default function normalizeFields< Item >(
78
79
  const bValue = getValue( { item: b } );
79
80
  return field.sort
80
81
  ? field.sort( aValue, bValue, direction )
81
- : defaultProps.sort( aValue, bValue, direction );
82
+ : fieldType.sort( aValue, bValue, direction );
82
83
  };
83
84
 
84
85
  return {
@@ -96,23 +97,20 @@ export default function normalizeFields< Item >(
96
97
  enableHiding: field.enableHiding ?? true,
97
98
  readOnly: field.readOnly ?? false,
98
99
  // The type provides defaults for the following props
99
- type: defaultProps.type,
100
- render: field.render ?? defaultProps.render,
101
- Edit: getControl( field, defaultProps.Edit ),
100
+ type: fieldType.type,
101
+ render: field.render ?? fieldType.render,
102
+ Edit: getControl( field, fieldType.Edit ),
102
103
  sort,
103
- enableSorting: field.enableSorting ?? defaultProps.enableSorting,
104
+ enableSorting: field.enableSorting ?? fieldType.enableSorting,
104
105
  enableGlobalSearch:
105
- field.enableGlobalSearch ?? defaultProps.enableGlobalSearch,
106
- isValid: {
107
- ...defaultProps.isValid,
108
- ...field.isValid,
109
- },
106
+ field.enableGlobalSearch ?? fieldType.enableGlobalSearch,
107
+ isValid: getIsValid( field, fieldType ),
110
108
  filterBy: getFilterBy(
111
109
  field,
112
- defaultProps.defaultOperators,
113
- defaultProps.validOperators
110
+ fieldType.defaultOperators,
111
+ fieldType.validOperators
114
112
  ),
115
- format: defaultProps.getFormat( field ),
113
+ format: fieldType.getFormat( field ),
116
114
  };
117
115
  } );
118
116
  }
@@ -6,7 +6,12 @@ import { __ } from '@wordpress/i18n';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import type { Rules } from '../types';
9
+ import type {
10
+ DataViewRenderFieldProps,
11
+ Field,
12
+ FormatInteger,
13
+ NormalizedField,
14
+ } from '../types';
10
15
  import type { FieldType } from '../types/private';
11
16
  import {
12
17
  OPERATOR_IS,
@@ -21,30 +26,84 @@ import {
21
26
  OPERATOR_IS_NOT_ALL,
22
27
  OPERATOR_BETWEEN,
23
28
  } from '../constants';
24
- import render from './utils/render-default';
29
+ import RenderFromElements from './utils/render-from-elements';
25
30
  import sort from './utils/sort-number';
31
+ import isValidRequired from './utils/is-valid-required';
32
+ import isValidMin from './utils/is-valid-min';
33
+ import isValidMax from './utils/is-valid-max';
34
+ import isValidElements from './utils/is-valid-elements';
26
35
 
27
- const isValid: Rules< any > = {
28
- elements: true,
29
- custom: ( item: any, normalizedField ) => {
30
- const value = normalizedField.getValue( { item } );
31
- if (
32
- ! [ undefined, '', null ].includes( value ) &&
33
- ! Number.isInteger( value )
34
- ) {
35
- return __( 'Value must be an integer.' );
36
- }
36
+ function getFormat< Item >( field: Field< Item > ): Required< FormatInteger > {
37
+ const fieldFormat = field.format as FormatInteger | undefined;
38
+ return {
39
+ separatorThousand:
40
+ fieldFormat?.separatorThousand !== undefined &&
41
+ typeof fieldFormat.separatorThousand === 'string'
42
+ ? fieldFormat.separatorThousand
43
+ : ',',
44
+ };
45
+ }
37
46
 
38
- return null;
39
- },
40
- };
47
+ export function formatInteger(
48
+ value: number,
49
+ format: Required< FormatInteger >
50
+ ): string {
51
+ if ( ! Number.isFinite( value ) ) {
52
+ return String( value );
53
+ }
54
+ const { separatorThousand } = format;
55
+ const integerValue = Math.trunc( value );
56
+ if ( ! separatorThousand ) {
57
+ return String( integerValue );
58
+ }
59
+ // Add thousand separators.
60
+ return String( integerValue ).replace(
61
+ /\B(?=(\d{3})+(?!\d))/g,
62
+ separatorThousand
63
+ );
64
+ }
65
+
66
+ function render( { item, field }: DataViewRenderFieldProps< any > ) {
67
+ if ( field.hasElements ) {
68
+ return <RenderFromElements item={ item } field={ field } />;
69
+ }
70
+
71
+ const value = field.getValue( { item } );
72
+ if ( [ null, undefined ].includes( value ) ) {
73
+ return '';
74
+ }
75
+
76
+ // If the field type is integer, we've already normalized the format,
77
+ // and so it's safe to tell TypeScript to trust us ("as Required<FormatInteger>").
78
+ //
79
+ // There're no runtime paths where this render function is called with a non-integer field,
80
+ // but TypeScript is unable to infer this, hence the type assertion.
81
+ let format: Required< FormatInteger >;
82
+ if ( field.type !== 'integer' ) {
83
+ format = getFormat( field as Field< any > );
84
+ } else {
85
+ format = field.format as Required< FormatInteger >;
86
+ }
87
+
88
+ return formatInteger( Number( value ), format );
89
+ }
90
+
91
+ function isValidCustom< Item >( item: Item, field: NormalizedField< Item > ) {
92
+ const value = field.getValue( { item } );
93
+ if (
94
+ ! [ undefined, '', null ].includes( value ) &&
95
+ ! Number.isInteger( value )
96
+ ) {
97
+ return __( 'Value must be an integer.' );
98
+ }
99
+ return null;
100
+ }
41
101
 
42
102
  export default {
43
103
  type: 'integer',
44
104
  render,
45
105
  Edit: 'integer',
46
106
  sort,
47
- isValid,
48
107
  enableSorting: true,
49
108
  enableGlobalSearch: false,
50
109
  defaultOperators: [
@@ -71,5 +130,12 @@ export default {
71
130
  OPERATOR_IS_ALL,
72
131
  OPERATOR_IS_NOT_ALL,
73
132
  ],
74
- getFormat: () => ( {} ),
133
+ getFormat,
134
+ validate: {
135
+ required: isValidRequired,
136
+ min: isValidMin,
137
+ max: isValidMax,
138
+ elements: isValidElements,
139
+ custom: isValidCustom,
140
+ },
75
141
  } satisfies FieldType< any >;
@@ -8,13 +8,13 @@ export default {
8
8
  render: () => null,
9
9
  Edit: null,
10
10
  sort: () => 0,
11
- isValid: {
12
- elements: true,
13
- custom: () => null,
14
- },
15
11
  enableSorting: false,
16
12
  enableGlobalSearch: false,
17
13
  defaultOperators: [],
18
14
  validOperators: [],
19
15
  getFormat: () => ( {} ),
16
+ // cannot validate any constraint, so
17
+ // the only available validation for the field author
18
+ // would be providing a custom validator.
19
+ validate: {},
20
20
  } satisfies FieldType< any >;
@@ -3,10 +3,13 @@
3
3
  */
4
4
  import type { SortDirection } from '../types';
5
5
  import type { FieldType } from '../types/private';
6
- import { ALL_OPERATORS, OPERATOR_IS, OPERATOR_IS_NOT } from '../constants';
6
+ import { OPERATOR_IS, OPERATOR_IS_NOT } from '../constants';
7
+ import { getAllOperatorNames } from '../utils/operators';
7
8
  import render from './utils/render-default';
8
9
  import sortText from './utils/sort-text';
9
10
  import sortNumber from './utils/sort-number';
11
+ import isValidRequired from './utils/is-valid-required';
12
+ import isValidElements from './utils/is-valid-elements';
10
13
 
11
14
  const sort = ( a: any, b: any, direction: SortDirection ) => {
12
15
  if ( typeof a === 'number' && typeof b === 'number' ) {
@@ -21,13 +24,13 @@ export default {
21
24
  render,
22
25
  Edit: null,
23
26
  sort,
24
- isValid: {
25
- elements: true,
26
- custom: () => null,
27
- },
28
27
  enableSorting: true,
29
28
  enableGlobalSearch: false,
30
29
  defaultOperators: [ OPERATOR_IS, OPERATOR_IS_NOT ],
31
- validOperators: ALL_OPERATORS,
30
+ validOperators: getAllOperatorNames(),
32
31
  getFormat: () => ( {} ),
32
+ validate: {
33
+ required: isValidRequired,
34
+ elements: isValidElements,
35
+ },
33
36
  } satisfies FieldType< any >;