@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,12 @@ import { __ } from '@wordpress/i18n';
6
6
  /**
7
7
  * Internal dependencies
8
8
  */
9
- import type { DataViewRenderFieldProps, Rules } from '../types';
9
+ import type {
10
+ DataViewRenderFieldProps,
11
+ Field,
12
+ FormatNumber,
13
+ NormalizedField,
14
+ } from '../types';
10
15
  import type { FieldType } from '../types/private';
11
16
  import {
12
17
  OPERATOR_IS,
@@ -23,6 +28,52 @@ import {
23
28
  } from '../constants';
24
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';
35
+
36
+ function getFormat< Item >( field: Field< Item > ): Required< FormatNumber > {
37
+ const fieldFormat = field.format as FormatNumber | undefined;
38
+ return {
39
+ separatorThousand:
40
+ fieldFormat?.separatorThousand !== undefined &&
41
+ typeof fieldFormat.separatorThousand === 'string'
42
+ ? fieldFormat.separatorThousand
43
+ : ',',
44
+ separatorDecimal:
45
+ fieldFormat?.separatorDecimal !== undefined &&
46
+ typeof fieldFormat.separatorDecimal === 'string'
47
+ ? fieldFormat.separatorDecimal
48
+ : '.',
49
+ decimals:
50
+ fieldFormat?.decimals !== undefined &&
51
+ typeof fieldFormat.decimals === 'number' &&
52
+ fieldFormat.decimals >= 0 &&
53
+ fieldFormat.decimals <= 100 &&
54
+ Number.isInteger( fieldFormat.decimals )
55
+ ? fieldFormat.decimals
56
+ : 2,
57
+ };
58
+ }
59
+
60
+ export function formatNumber(
61
+ value: number,
62
+ format: Required< FormatNumber >
63
+ ): string {
64
+ if ( ! Number.isFinite( value ) ) {
65
+ return String( value );
66
+ }
67
+ const { separatorThousand, separatorDecimal, decimals } = format;
68
+ const fixedValue = value.toFixed( decimals );
69
+ const [ integerPart, decimalPart ] = fixedValue.split( '.' );
70
+ const formattedInteger = separatorThousand
71
+ ? integerPart.replace( /\B(?=(\d{3})+(?!\d))/g, separatorThousand )
72
+ : integerPart;
73
+ return decimals === 0
74
+ ? formattedInteger
75
+ : formattedInteger + separatorDecimal + decimalPart;
76
+ }
26
77
 
27
78
  function isEmpty( value: unknown ): value is '' | undefined | null {
28
79
  return value === '' || value === undefined || value === null;
@@ -34,32 +85,40 @@ function render( { item, field }: DataViewRenderFieldProps< any > ) {
34
85
  }
35
86
 
36
87
  const value = field.getValue( { item } );
37
- if ( ! [ null, undefined ].includes( value ) ) {
38
- return Number( value ).toFixed( 2 );
88
+ if ( [ null, undefined ].includes( value ) ) {
89
+ return '';
39
90
  }
40
91
 
41
- return null;
92
+ // If the field type is number, we've already normalized the format,
93
+ // and so it's safe to tell TypeScript to trust us ("as Required<FormatNumber>").
94
+ //
95
+ // There're no runtime paths where this render function is called with a non-number field,
96
+ // but TypeScript is unable to infer this, hence the type assertion.
97
+ let format: Required< FormatNumber >;
98
+ if ( field.type !== 'number' ) {
99
+ format = getFormat( field as Field< any > );
100
+ } else {
101
+ format = field.format as Required< FormatNumber >;
102
+ }
103
+
104
+ return formatNumber( Number( value ), format );
42
105
  }
43
106
 
44
- const isValid: Rules< any > = {
45
- elements: true,
46
- custom: ( item: any, normalizedField ) => {
47
- const value = normalizedField.getValue( { item } );
107
+ function isValidCustom< Item >( item: Item, field: NormalizedField< Item > ) {
108
+ const value = field.getValue( { item } );
48
109
 
49
- if ( ! isEmpty( value ) && ! Number.isFinite( value ) ) {
50
- return __( 'Value must be a number.' );
51
- }
110
+ if ( ! isEmpty( value ) && ! Number.isFinite( value ) ) {
111
+ return __( 'Value must be a number.' );
112
+ }
52
113
 
53
- return null;
54
- },
55
- };
114
+ return null;
115
+ }
56
116
 
57
117
  export default {
58
118
  type: 'number',
59
119
  render,
60
120
  Edit: 'number',
61
121
  sort,
62
- isValid,
63
122
  enableSorting: true,
64
123
  enableGlobalSearch: false,
65
124
  defaultOperators: [
@@ -86,5 +145,12 @@ export default {
86
145
  OPERATOR_IS_ALL,
87
146
  OPERATOR_IS_NOT_ALL,
88
147
  ],
89
- getFormat: () => ( {} ),
148
+ getFormat,
149
+ validate: {
150
+ required: isValidRequired,
151
+ min: isValidMin,
152
+ max: isValidMax,
153
+ elements: isValidElements,
154
+ custom: isValidCustom,
155
+ },
90
156
  } satisfies FieldType< any >;
@@ -4,6 +4,11 @@
4
4
  import type { DataViewRenderFieldProps } from '../types';
5
5
  import type { FieldType } from '../types/private';
6
6
  import RenderFromElements from './utils/render-from-elements';
7
+ import isValidRequired from './utils/is-valid-required';
8
+ import isValidMinLength from './utils/is-valid-min-length';
9
+ import isValidMaxLength from './utils/is-valid-max-length';
10
+ import isValidPattern from './utils/is-valid-pattern';
11
+ import isValidElements from './utils/is-valid-elements';
7
12
 
8
13
  function render( { item, field }: DataViewRenderFieldProps< any > ) {
9
14
  return field.hasElements ? (
@@ -18,13 +23,16 @@ export default {
18
23
  render,
19
24
  Edit: 'password',
20
25
  sort: () => 0, // Passwords should not be sortable for security reasons
21
- isValid: {
22
- elements: true,
23
- custom: () => null,
24
- },
25
26
  enableSorting: false,
26
27
  enableGlobalSearch: false,
27
28
  defaultOperators: [],
28
29
  validOperators: [],
29
30
  getFormat: () => ( {} ),
31
+ validate: {
32
+ required: isValidRequired,
33
+ pattern: isValidPattern,
34
+ minLength: isValidMinLength,
35
+ maxLength: isValidMaxLength,
36
+ elements: isValidElements,
37
+ },
30
38
  } satisfies FieldType< any >;
@@ -15,16 +15,17 @@ import {
15
15
  } from '../constants';
16
16
  import render from './utils/render-default';
17
17
  import sort from './utils/sort-text';
18
+ import isValidRequired from './utils/is-valid-required';
19
+ import isValidMinLength from './utils/is-valid-min-length';
20
+ import isValidMaxLength from './utils/is-valid-max-length';
21
+ import isValidPattern from './utils/is-valid-pattern';
22
+ import isValidElements from './utils/is-valid-elements';
18
23
 
19
24
  export default {
20
25
  type: 'telephone',
21
26
  render,
22
27
  Edit: 'telephone',
23
28
  sort,
24
- isValid: {
25
- elements: true,
26
- custom: () => null,
27
- },
28
29
  enableSorting: true,
29
30
  enableGlobalSearch: false,
30
31
  defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
@@ -41,4 +42,11 @@ export default {
41
42
  OPERATOR_IS_NOT_ALL,
42
43
  ],
43
44
  getFormat: () => ( {} ),
45
+ validate: {
46
+ required: isValidRequired,
47
+ pattern: isValidPattern,
48
+ minLength: isValidMinLength,
49
+ maxLength: isValidMaxLength,
50
+ elements: isValidElements,
51
+ },
44
52
  } satisfies FieldType< any >;
@@ -15,16 +15,17 @@ import {
15
15
  } from '../constants';
16
16
  import render from './utils/render-default';
17
17
  import sort from './utils/sort-text';
18
+ import isValidRequired from './utils/is-valid-required';
19
+ import isValidMinLength from './utils/is-valid-min-length';
20
+ import isValidMaxLength from './utils/is-valid-max-length';
21
+ import isValidPattern from './utils/is-valid-pattern';
22
+ import isValidElements from './utils/is-valid-elements';
18
23
 
19
24
  export default {
20
25
  type: 'text',
21
26
  render,
22
27
  Edit: 'text',
23
28
  sort,
24
- isValid: {
25
- elements: true,
26
- custom: () => null,
27
- },
28
29
  enableSorting: true,
29
30
  enableGlobalSearch: false,
30
31
  defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
@@ -42,4 +43,11 @@ export default {
42
43
  OPERATOR_IS_NOT_ALL,
43
44
  ],
44
45
  getFormat: () => ( {} ),
46
+ validate: {
47
+ required: isValidRequired,
48
+ pattern: isValidPattern,
49
+ minLength: isValidMinLength,
50
+ maxLength: isValidMaxLength,
51
+ elements: isValidElements,
52
+ },
45
53
  } satisfies FieldType< any >;
@@ -15,16 +15,17 @@ import {
15
15
  } from '../constants';
16
16
  import render from './utils/render-default';
17
17
  import sort from './utils/sort-text';
18
+ import isValidRequired from './utils/is-valid-required';
19
+ import isValidMinLength from './utils/is-valid-min-length';
20
+ import isValidMaxLength from './utils/is-valid-max-length';
21
+ import isValidPattern from './utils/is-valid-pattern';
22
+ import isValidElements from './utils/is-valid-elements';
18
23
 
19
24
  export default {
20
25
  type: 'url',
21
26
  render,
22
27
  Edit: 'url',
23
28
  sort,
24
- isValid: {
25
- elements: true,
26
- custom: () => null,
27
- },
28
29
  enableSorting: true,
29
30
  enableGlobalSearch: false,
30
31
  defaultOperators: [ OPERATOR_IS_ANY, OPERATOR_IS_NONE ],
@@ -41,4 +42,11 @@ export default {
41
42
  OPERATOR_IS_NOT_ALL,
42
43
  ],
43
44
  getFormat: () => ( {} ),
45
+ validate: {
46
+ required: isValidRequired,
47
+ pattern: isValidPattern,
48
+ minLength: isValidMinLength,
49
+ maxLength: isValidMaxLength,
50
+ elements: isValidElements,
51
+ },
44
52
  } satisfies FieldType< any >;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { Field, NormalizedRules } from '../../types';
5
+ import type { FieldType } from '../../types/private';
6
+
7
+ export default function getIsValid< Item >(
8
+ field: Field< Item >,
9
+ fieldType: FieldType< Item >
10
+ ): NormalizedRules< Item > {
11
+ let required;
12
+ if (
13
+ field.isValid?.required === true &&
14
+ fieldType.validate.required !== undefined
15
+ ) {
16
+ required = {
17
+ constraint: true,
18
+ validate: fieldType.validate.required,
19
+ };
20
+ }
21
+
22
+ let elements;
23
+ if (
24
+ ( field.isValid?.elements === true ||
25
+ // elements is enabled unless the field opts-out
26
+ ( field.isValid?.elements === undefined &&
27
+ ( !! field.elements || !! field.getElements ) ) ) &&
28
+ fieldType.validate.elements !== undefined
29
+ ) {
30
+ elements = {
31
+ constraint: true,
32
+ validate: fieldType.validate.elements,
33
+ };
34
+ }
35
+
36
+ let min;
37
+ if (
38
+ typeof field.isValid?.min === 'number' &&
39
+ fieldType.validate.min !== undefined
40
+ ) {
41
+ min = {
42
+ constraint: field.isValid.min,
43
+ validate: fieldType.validate.min,
44
+ };
45
+ }
46
+
47
+ let max;
48
+ if (
49
+ typeof field.isValid?.max === 'number' &&
50
+ fieldType.validate.max !== undefined
51
+ ) {
52
+ max = {
53
+ constraint: field.isValid.max,
54
+ validate: fieldType.validate.max,
55
+ };
56
+ }
57
+
58
+ let minLength;
59
+ if (
60
+ typeof field.isValid?.minLength === 'number' &&
61
+ fieldType.validate.minLength !== undefined
62
+ ) {
63
+ minLength = {
64
+ constraint: field.isValid.minLength,
65
+ validate: fieldType.validate.minLength,
66
+ };
67
+ }
68
+
69
+ let maxLength;
70
+ if (
71
+ typeof field.isValid?.maxLength === 'number' &&
72
+ fieldType.validate.maxLength !== undefined
73
+ ) {
74
+ maxLength = {
75
+ constraint: field.isValid.maxLength,
76
+ validate: fieldType.validate.maxLength,
77
+ };
78
+ }
79
+
80
+ let pattern;
81
+ if (
82
+ field.isValid?.pattern !== undefined &&
83
+ fieldType.validate.pattern !== undefined
84
+ ) {
85
+ pattern = {
86
+ constraint: field.isValid?.pattern,
87
+ validate: fieldType.validate.pattern,
88
+ };
89
+ }
90
+
91
+ const custom = field.isValid?.custom ?? fieldType.validate.custom;
92
+
93
+ return {
94
+ required,
95
+ elements,
96
+ min,
97
+ max,
98
+ minLength,
99
+ maxLength,
100
+ pattern,
101
+ custom,
102
+ };
103
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidElements< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ): boolean {
10
+ const elements = field.elements ?? [];
11
+ const validValues = elements.map( ( el ) => el.value );
12
+ if ( validValues.length === 0 ) {
13
+ return true;
14
+ }
15
+
16
+ const value = field.getValue( { item } );
17
+
18
+ // Covers both array and non-array values.
19
+ return [].concat( value ).every( ( v ) => validValues.includes( v ) );
20
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidMaxLength< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ): boolean {
10
+ if ( typeof field.isValid.maxLength?.constraint !== 'number' ) {
11
+ return false;
12
+ }
13
+
14
+ const value = field.getValue( { item } );
15
+
16
+ // Empty values are considered valid for maxLength validation
17
+ // (use required validation to enforce non-empty values)
18
+ if ( [ undefined, '', null ].includes( value ) ) {
19
+ return true;
20
+ }
21
+
22
+ return String( value ).length <= field.isValid.maxLength.constraint;
23
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidMax< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ): boolean {
10
+ if ( typeof field.isValid.max?.constraint !== 'number' ) {
11
+ return false;
12
+ }
13
+
14
+ const value = field.getValue( { item } );
15
+
16
+ // Empty values are considered valid for max validation
17
+ // (use required validation to enforce non-empty values)
18
+ if ( [ undefined, '', null ].includes( value ) ) {
19
+ return true;
20
+ }
21
+
22
+ return Number( value ) <= field.isValid.max.constraint;
23
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidMinLength< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ): boolean {
10
+ if ( typeof field.isValid.minLength?.constraint !== 'number' ) {
11
+ return false;
12
+ }
13
+
14
+ const value = field.getValue( { item } );
15
+
16
+ // Empty values are considered valid for minLength validation
17
+ // (use required validation to enforce non-empty values)
18
+ if ( [ undefined, '', null ].includes( value ) ) {
19
+ return true;
20
+ }
21
+
22
+ return String( value ).length >= field.isValid.minLength.constraint;
23
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidMin< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ): boolean {
10
+ if ( typeof field.isValid.min?.constraint !== 'number' ) {
11
+ return false;
12
+ }
13
+
14
+ const value = field.getValue( { item } );
15
+
16
+ // Empty values are considered valid for min validation
17
+ // (use required validation to enforce non-empty values)
18
+ if ( [ undefined, '', null ].includes( value ) ) {
19
+ return true;
20
+ }
21
+
22
+ return Number( value ) >= field.isValid.min.constraint;
23
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidPattern< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ): boolean {
10
+ if ( field.isValid.pattern?.constraint === undefined ) {
11
+ return true;
12
+ }
13
+
14
+ try {
15
+ const regexp = new RegExp( field.isValid.pattern.constraint );
16
+
17
+ const value = field.getValue( { item } );
18
+
19
+ // Empty values are considered valid for pattern validation
20
+ // (use required validation to enforce non-empty values)
21
+ if ( [ undefined, '', null ].includes( value ) ) {
22
+ return true;
23
+ }
24
+
25
+ return regexp.test( String( value ) );
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidRequiredForArray< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ) {
10
+ const value = field.getValue( { item } );
11
+ return (
12
+ Array.isArray( value ) &&
13
+ value.length > 0 &&
14
+ value.every(
15
+ ( element: any ) => ! [ undefined, '', null ].includes( element )
16
+ )
17
+ );
18
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidRequiredForBool< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ) {
10
+ const value = field.getValue( { item } );
11
+
12
+ return value === true;
13
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import type { NormalizedField } from '../../types';
5
+
6
+ export default function isValidRequired< Item >(
7
+ item: Item,
8
+ field: NormalizedField< Item >
9
+ ) {
10
+ const value = field.getValue( { item } );
11
+
12
+ return ! [ undefined, '', null ].includes( value );
13
+ }