@wordpress/dataviews 14.0.0 → 14.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 (249) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +16 -5
  3. package/build/components/dataform-controls/array.cjs +2 -0
  4. package/build/components/dataform-controls/array.cjs.map +2 -2
  5. package/build/components/dataform-controls/checkbox.cjs +3 -1
  6. package/build/components/dataform-controls/checkbox.cjs.map +2 -2
  7. package/build/components/dataform-controls/color.cjs +8 -2
  8. package/build/components/dataform-controls/color.cjs.map +2 -2
  9. package/build/components/dataform-controls/date.cjs +31 -9
  10. package/build/components/dataform-controls/date.cjs.map +3 -3
  11. package/build/components/dataform-controls/datetime.cjs +9 -2
  12. package/build/components/dataform-controls/datetime.cjs.map +3 -3
  13. package/build/components/dataform-controls/password.cjs +4 -1
  14. package/build/components/dataform-controls/password.cjs.map +2 -2
  15. package/build/components/dataform-controls/radio.cjs +3 -1
  16. package/build/components/dataform-controls/radio.cjs.map +2 -2
  17. package/build/components/dataform-controls/select.cjs +3 -1
  18. package/build/components/dataform-controls/select.cjs.map +2 -2
  19. package/build/components/dataform-controls/textarea.cjs +2 -0
  20. package/build/components/dataform-controls/textarea.cjs.map +2 -2
  21. package/build/components/dataform-controls/toggle-group.cjs +3 -1
  22. package/build/components/dataform-controls/toggle-group.cjs.map +2 -2
  23. package/build/components/dataform-controls/toggle.cjs +3 -1
  24. package/build/components/dataform-controls/toggle.cjs.map +2 -2
  25. package/build/components/dataform-controls/utils/relative-date-control.cjs +5 -2
  26. package/build/components/dataform-controls/utils/relative-date-control.cjs.map +2 -2
  27. package/build/components/dataform-controls/utils/use-disabled-date-matchers.cjs +48 -0
  28. package/build/components/dataform-controls/utils/use-disabled-date-matchers.cjs.map +7 -0
  29. package/build/components/dataform-controls/utils/validated-input.cjs +2 -0
  30. package/build/components/dataform-controls/utils/validated-input.cjs.map +2 -2
  31. package/build/components/dataform-controls/utils/validated-number.cjs +3 -1
  32. package/build/components/dataform-controls/utils/validated-number.cjs.map +2 -2
  33. package/build/components/dataform-layouts/panel/summary-button.cjs +0 -1
  34. package/build/components/dataform-layouts/panel/summary-button.cjs.map +2 -2
  35. package/build/components/dataviews-context/index.cjs.map +1 -1
  36. package/build/components/dataviews-filters/input-widget.cjs +4 -0
  37. package/build/components/dataviews-filters/input-widget.cjs.map +2 -2
  38. package/build/components/dataviews-layouts/picker-grid/index.cjs +1 -4
  39. package/build/components/dataviews-layouts/picker-grid/index.cjs.map +2 -2
  40. package/build/components/dataviews-layouts/picker-table/index.cjs +15 -12
  41. package/build/components/dataviews-layouts/picker-table/index.cjs.map +2 -2
  42. package/build/components/dataviews-layouts/table/index.cjs +0 -1
  43. package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
  44. package/build/components/dataviews-pagination/index.cjs +1 -0
  45. package/build/components/dataviews-pagination/index.cjs.map +2 -2
  46. package/build/dataviews/index.cjs +10 -8
  47. package/build/dataviews/index.cjs.map +2 -2
  48. package/build/dataviews-picker/index.cjs +16 -9
  49. package/build/dataviews-picker/index.cjs.map +2 -2
  50. package/build/field-types/date.cjs +4 -1
  51. package/build/field-types/date.cjs.map +2 -2
  52. package/build/field-types/datetime.cjs +4 -1
  53. package/build/field-types/datetime.cjs.map +2 -2
  54. package/build/field-types/index.cjs +1 -0
  55. package/build/field-types/index.cjs.map +2 -2
  56. package/build/field-types/utils/get-is-valid.cjs +29 -24
  57. package/build/field-types/utils/get-is-valid.cjs.map +2 -2
  58. package/build/field-types/utils/is-valid-date-boundary.cjs +64 -0
  59. package/build/field-types/utils/is-valid-date-boundary.cjs.map +7 -0
  60. package/build/types/dataviews.cjs.map +1 -1
  61. package/build/types/field-api.cjs.map +1 -1
  62. package/build-module/components/dataform-controls/array.mjs +2 -0
  63. package/build-module/components/dataform-controls/array.mjs.map +2 -2
  64. package/build-module/components/dataform-controls/checkbox.mjs +3 -1
  65. package/build-module/components/dataform-controls/checkbox.mjs.map +2 -2
  66. package/build-module/components/dataform-controls/color.mjs +8 -2
  67. package/build-module/components/dataform-controls/color.mjs.map +2 -2
  68. package/build-module/components/dataform-controls/date.mjs +31 -9
  69. package/build-module/components/dataform-controls/date.mjs.map +2 -2
  70. package/build-module/components/dataform-controls/datetime.mjs +9 -2
  71. package/build-module/components/dataform-controls/datetime.mjs.map +2 -2
  72. package/build-module/components/dataform-controls/password.mjs +4 -1
  73. package/build-module/components/dataform-controls/password.mjs.map +2 -2
  74. package/build-module/components/dataform-controls/radio.mjs +3 -1
  75. package/build-module/components/dataform-controls/radio.mjs.map +2 -2
  76. package/build-module/components/dataform-controls/select.mjs +3 -1
  77. package/build-module/components/dataform-controls/select.mjs.map +2 -2
  78. package/build-module/components/dataform-controls/textarea.mjs +2 -0
  79. package/build-module/components/dataform-controls/textarea.mjs.map +2 -2
  80. package/build-module/components/dataform-controls/toggle-group.mjs +3 -1
  81. package/build-module/components/dataform-controls/toggle-group.mjs.map +2 -2
  82. package/build-module/components/dataform-controls/toggle.mjs +3 -1
  83. package/build-module/components/dataform-controls/toggle.mjs.map +2 -2
  84. package/build-module/components/dataform-controls/utils/relative-date-control.mjs +5 -2
  85. package/build-module/components/dataform-controls/utils/relative-date-control.mjs.map +2 -2
  86. package/build-module/components/dataform-controls/utils/use-disabled-date-matchers.mjs +27 -0
  87. package/build-module/components/dataform-controls/utils/use-disabled-date-matchers.mjs.map +7 -0
  88. package/build-module/components/dataform-controls/utils/validated-input.mjs +2 -0
  89. package/build-module/components/dataform-controls/utils/validated-input.mjs.map +2 -2
  90. package/build-module/components/dataform-controls/utils/validated-number.mjs +3 -1
  91. package/build-module/components/dataform-controls/utils/validated-number.mjs.map +2 -2
  92. package/build-module/components/dataform-layouts/panel/summary-button.mjs +0 -1
  93. package/build-module/components/dataform-layouts/panel/summary-button.mjs.map +2 -2
  94. package/build-module/components/dataviews-context/index.mjs.map +1 -1
  95. package/build-module/components/dataviews-filters/input-widget.mjs +4 -0
  96. package/build-module/components/dataviews-filters/input-widget.mjs.map +2 -2
  97. package/build-module/components/dataviews-layouts/picker-grid/index.mjs +1 -4
  98. package/build-module/components/dataviews-layouts/picker-grid/index.mjs.map +2 -2
  99. package/build-module/components/dataviews-layouts/picker-table/index.mjs +15 -12
  100. package/build-module/components/dataviews-layouts/picker-table/index.mjs.map +2 -2
  101. package/build-module/components/dataviews-layouts/table/index.mjs +0 -1
  102. package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
  103. package/build-module/components/dataviews-pagination/index.mjs +1 -0
  104. package/build-module/components/dataviews-pagination/index.mjs.map +2 -2
  105. package/build-module/dataviews/index.mjs +10 -8
  106. package/build-module/dataviews/index.mjs.map +2 -2
  107. package/build-module/dataviews-picker/index.mjs +16 -9
  108. package/build-module/dataviews-picker/index.mjs.map +2 -2
  109. package/build-module/field-types/date.mjs +4 -1
  110. package/build-module/field-types/date.mjs.map +2 -2
  111. package/build-module/field-types/datetime.mjs +4 -1
  112. package/build-module/field-types/datetime.mjs.map +2 -2
  113. package/build-module/field-types/index.mjs +1 -0
  114. package/build-module/field-types/index.mjs.map +2 -2
  115. package/build-module/field-types/utils/get-is-valid.mjs +29 -24
  116. package/build-module/field-types/utils/get-is-valid.mjs.map +2 -2
  117. package/build-module/field-types/utils/is-valid-date-boundary.mjs +38 -0
  118. package/build-module/field-types/utils/is-valid-date-boundary.mjs.map +7 -0
  119. package/build-style/style-rtl.css +14 -15
  120. package/build-style/style.css +14 -15
  121. package/build-types/components/dataform-controls/array.d.ts.map +1 -1
  122. package/build-types/components/dataform-controls/checkbox.d.ts.map +1 -1
  123. package/build-types/components/dataform-controls/color.d.ts.map +1 -1
  124. package/build-types/components/dataform-controls/date.d.ts.map +1 -1
  125. package/build-types/components/dataform-controls/datetime.d.ts.map +1 -1
  126. package/build-types/components/dataform-controls/password.d.ts.map +1 -1
  127. package/build-types/components/dataform-controls/radio.d.ts.map +1 -1
  128. package/build-types/components/dataform-controls/select.d.ts.map +1 -1
  129. package/build-types/components/dataform-controls/textarea.d.ts.map +1 -1
  130. package/build-types/components/dataform-controls/toggle-group.d.ts.map +1 -1
  131. package/build-types/components/dataform-controls/toggle.d.ts.map +1 -1
  132. package/build-types/components/dataform-controls/utils/relative-date-control.d.ts.map +1 -1
  133. package/build-types/components/dataform-controls/utils/use-disabled-date-matchers.d.ts +16 -0
  134. package/build-types/components/dataform-controls/utils/use-disabled-date-matchers.d.ts.map +1 -0
  135. package/build-types/components/dataform-controls/utils/validated-input.d.ts.map +1 -1
  136. package/build-types/components/dataform-controls/utils/validated-number.d.ts.map +1 -1
  137. package/build-types/components/dataform-layouts/panel/summary-button.d.ts.map +1 -1
  138. package/build-types/components/dataviews-context/index.d.ts +2 -2
  139. package/build-types/components/dataviews-context/index.d.ts.map +1 -1
  140. package/build-types/components/dataviews-filters/input-widget.d.ts.map +1 -1
  141. package/build-types/components/dataviews-layouts/index.d.ts +6 -6
  142. package/build-types/components/dataviews-layouts/picker-grid/index.d.ts.map +1 -1
  143. package/build-types/components/dataviews-layouts/picker-table/index.d.ts.map +1 -1
  144. package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
  145. package/build-types/components/dataviews-pagination/index.d.ts.map +1 -1
  146. package/build-types/components/dataviews-search/index.d.ts +1 -1
  147. package/build-types/components/dataviews-search/index.d.ts.map +1 -1
  148. package/build-types/constants.d.ts +2 -2
  149. package/build-types/dataform/stories/index.story.d.ts +11 -1
  150. package/build-types/dataform/stories/index.story.d.ts.map +1 -1
  151. package/build-types/dataform/stories/layout-regular.d.ts +2 -1
  152. package/build-types/dataform/stories/layout-regular.d.ts.map +1 -1
  153. package/build-types/dataform/stories/validation.d.ts.map +1 -1
  154. package/build-types/dataviews/index.d.ts +1 -1
  155. package/build-types/dataviews/index.d.ts.map +1 -1
  156. package/build-types/dataviews-picker/index.d.ts +3 -2
  157. package/build-types/dataviews-picker/index.d.ts.map +1 -1
  158. package/build-types/dataviews-picker/stories/index.story.d.ts.map +1 -1
  159. package/build-types/field-types/array.d.ts +1 -1
  160. package/build-types/field-types/array.d.ts.map +1 -1
  161. package/build-types/field-types/boolean.d.ts +1 -1
  162. package/build-types/field-types/boolean.d.ts.map +1 -1
  163. package/build-types/field-types/color.d.ts +1 -1
  164. package/build-types/field-types/color.d.ts.map +1 -1
  165. package/build-types/field-types/date.d.ts +3 -0
  166. package/build-types/field-types/date.d.ts.map +1 -1
  167. package/build-types/field-types/datetime.d.ts +3 -0
  168. package/build-types/field-types/datetime.d.ts.map +1 -1
  169. package/build-types/field-types/email.d.ts +1 -1
  170. package/build-types/field-types/email.d.ts.map +1 -1
  171. package/build-types/field-types/index.d.ts.map +1 -1
  172. package/build-types/field-types/integer.d.ts +1 -1
  173. package/build-types/field-types/integer.d.ts.map +1 -1
  174. package/build-types/field-types/number.d.ts +1 -1
  175. package/build-types/field-types/number.d.ts.map +1 -1
  176. package/build-types/field-types/stories/index.story.d.ts +37 -15
  177. package/build-types/field-types/stories/index.story.d.ts.map +1 -1
  178. package/build-types/field-types/utils/get-is-valid.d.ts.map +1 -1
  179. package/build-types/field-types/utils/is-valid-date-boundary.d.ts +7 -0
  180. package/build-types/field-types/utils/is-valid-date-boundary.d.ts.map +1 -0
  181. package/build-types/types/dataviews.d.ts +8 -0
  182. package/build-types/types/dataviews.d.ts.map +1 -1
  183. package/build-types/types/field-api.d.ts +24 -9
  184. package/build-types/types/field-api.d.ts.map +1 -1
  185. package/build-wp/index.js +1141 -990
  186. package/package.json +16 -16
  187. package/src/components/dataform-controls/array.tsx +2 -0
  188. package/src/components/dataform-controls/checkbox.tsx +2 -0
  189. package/src/components/dataform-controls/color.tsx +7 -0
  190. package/src/components/dataform-controls/date.tsx +30 -4
  191. package/src/components/dataform-controls/datetime.tsx +17 -0
  192. package/src/components/dataform-controls/password.tsx +3 -0
  193. package/src/components/dataform-controls/radio.tsx +2 -0
  194. package/src/components/dataform-controls/select.tsx +2 -0
  195. package/src/components/dataform-controls/textarea.tsx +2 -0
  196. package/src/components/dataform-controls/toggle-group.tsx +2 -0
  197. package/src/components/dataform-controls/toggle.tsx +2 -0
  198. package/src/components/dataform-controls/utils/relative-date-control.tsx +3 -0
  199. package/src/components/dataform-controls/utils/use-disabled-date-matchers.ts +48 -0
  200. package/src/components/dataform-controls/utils/validated-input.tsx +2 -0
  201. package/src/components/dataform-controls/utils/validated-number.tsx +2 -0
  202. package/src/components/dataform-layouts/panel/style.scss +4 -5
  203. package/src/components/dataform-layouts/panel/summary-button.tsx +0 -1
  204. package/src/components/dataviews-context/index.ts +2 -2
  205. package/src/components/dataviews-filters/input-widget.tsx +4 -0
  206. package/src/components/dataviews-filters/style.scss +2 -2
  207. package/src/components/dataviews-layouts/activity/style.scss +3 -3
  208. package/src/components/dataviews-layouts/grid/style.scss +1 -1
  209. package/src/components/dataviews-layouts/list/style.scss +1 -1
  210. package/src/components/dataviews-layouts/picker-grid/index.tsx +2 -6
  211. package/src/components/dataviews-layouts/picker-grid/style.scss +1 -1
  212. package/src/components/dataviews-layouts/picker-table/index.tsx +9 -7
  213. package/src/components/dataviews-layouts/picker-table/style.scss +1 -1
  214. package/src/components/dataviews-layouts/table/index.tsx +0 -2
  215. package/src/components/dataviews-pagination/index.tsx +1 -0
  216. package/src/dataform/stories/content.story.tsx +1 -1
  217. package/src/dataform/stories/data-adapter.tsx +6 -6
  218. package/src/dataform/stories/index.story.tsx +7 -0
  219. package/src/dataform/stories/layout-card.tsx +5 -5
  220. package/src/dataform/stories/layout-details.tsx +5 -5
  221. package/src/dataform/stories/layout-panel.tsx +9 -9
  222. package/src/dataform/stories/layout-regular.tsx +31 -10
  223. package/src/dataform/stories/layout-row.tsx +9 -9
  224. package/src/dataform/stories/validation.tsx +25 -10
  225. package/src/dataviews/index.tsx +11 -7
  226. package/src/dataviews/stories/empty.tsx +4 -4
  227. package/src/dataviews/stories/free-composition.tsx +2 -2
  228. package/src/dataviews/stories/infinite-scroll.tsx +4 -4
  229. package/src/dataviews/stories/layout-custom.tsx +1 -1
  230. package/src/dataviews/stories/layout-grid.tsx +1 -1
  231. package/src/dataviews/stories/layout-list.tsx +1 -1
  232. package/src/dataviews/stories/layout-table.tsx +1 -1
  233. package/src/dataviews/stories/minimal-ui.tsx +1 -1
  234. package/src/dataviews/stories/with-card.tsx +4 -4
  235. package/src/dataviews/style.scss +1 -1
  236. package/src/dataviews/test/dataviews.tsx +73 -6
  237. package/src/dataviews-picker/index.tsx +17 -7
  238. package/src/dataviews-picker/stories/index.story.tsx +1 -5
  239. package/src/dataviews-picker/test/dataviews-picker.tsx +79 -2
  240. package/src/field-types/date.tsx +3 -0
  241. package/src/field-types/datetime.tsx +3 -0
  242. package/src/field-types/index.tsx +4 -0
  243. package/src/field-types/stories/index.story.tsx +67 -6
  244. package/src/field-types/test/normalize-fields.ts +44 -0
  245. package/src/field-types/utils/get-is-valid.ts +44 -31
  246. package/src/field-types/utils/is-valid-date-boundary.ts +80 -0
  247. package/src/hooks/test/use-form-validity.ts +479 -0
  248. package/src/types/dataviews.ts +9 -0
  249. package/src/types/field-api.ts +27 -9
@@ -66,12 +66,17 @@ const meta = {
66
66
  'Add 10 more elements to push over the threshold and trigger Combobox rendering',
67
67
  if: { arg: 'Edit', eq: 'adaptiveSelect' },
68
68
  },
69
+ disabled: {
70
+ control: { type: 'boolean' },
71
+ description: 'Whether the field controls are disabled.',
72
+ },
69
73
  },
70
74
  args: {
71
75
  type: 'regular',
72
76
  Edit: 'default',
73
77
  asyncElements: false,
74
78
  manyElements: false,
79
+ disabled: false,
75
80
  },
76
81
  };
77
82
  export default meta;
@@ -590,6 +595,7 @@ interface FieldTypeStoryProps {
590
595
  Edit: ControlTypes;
591
596
  asyncElements: boolean;
592
597
  manyElements: boolean;
598
+ disabled: boolean;
593
599
  }
594
600
 
595
601
  const FieldTypeStory = ( {
@@ -598,17 +604,27 @@ const FieldTypeStory = ( {
598
604
  Edit,
599
605
  asyncElements,
600
606
  manyElements,
607
+ disabled,
601
608
  }: FieldTypeStoryProps ) => {
602
609
  const storyFields = useMemo( () => {
603
610
  let fieldsToProcess = _fields;
604
611
 
605
- if ( Edit !== 'default' ) {
606
- fieldsToProcess = _fields.map( ( field: Field< DataType > ) => ( {
612
+ if ( disabled ) {
613
+ fieldsToProcess = fieldsToProcess.map( ( field ) => ( {
607
614
  ...field,
608
- Edit,
615
+ isDisabled: true,
609
616
  } ) );
610
617
  }
611
618
 
619
+ if ( Edit !== 'default' ) {
620
+ fieldsToProcess = fieldsToProcess.map(
621
+ ( field: Field< DataType > ) => ( {
622
+ ...field,
623
+ Edit,
624
+ } )
625
+ );
626
+ }
627
+
612
628
  // Expand elements when adaptiveSelect is selected and manyElements is toggled
613
629
  if ( Edit === 'adaptiveSelect' && manyElements ) {
614
630
  fieldsToProcess = fieldsToProcess.map( ( field ) => {
@@ -648,7 +664,7 @@ const FieldTypeStory = ( {
648
664
  }
649
665
 
650
666
  return fieldsToProcess;
651
- }, [ _fields, Edit, asyncElements, manyElements ] );
667
+ }, [ _fields, Edit, asyncElements, manyElements, disabled ] );
652
668
  const form = useMemo(
653
669
  () => ( {
654
670
  layout: { type },
@@ -699,7 +715,7 @@ const FieldTypeStory = ( {
699
715
  },
700
716
  ] }
701
717
  defaultLayouts={ {
702
- table: {},
718
+ table: true,
703
719
  } }
704
720
  selection={ selectedIds.map( ( id ) => id.toString() ) }
705
721
  onChangeSelection={ ( newSelection ) =>
@@ -756,11 +772,13 @@ export const AllComponent = ( {
756
772
  Edit,
757
773
  asyncElements,
758
774
  manyElements,
775
+ disabled,
759
776
  }: {
760
777
  type: PanelTypes;
761
778
  Edit: ControlTypes;
762
779
  asyncElements: boolean;
763
780
  manyElements: boolean;
781
+ disabled: boolean;
764
782
  } ) => {
765
783
  return (
766
784
  <FieldTypeStory
@@ -769,6 +787,7 @@ export const AllComponent = ( {
769
787
  Edit={ Edit }
770
788
  asyncElements={ asyncElements }
771
789
  manyElements={ manyElements }
790
+ disabled={ disabled }
772
791
  />
773
792
  );
774
793
  };
@@ -779,11 +798,13 @@ export const TextComponent = ( {
779
798
  Edit,
780
799
  asyncElements,
781
800
  manyElements,
801
+ disabled,
782
802
  }: {
783
803
  type: PanelTypes;
784
804
  Edit: ControlTypes;
785
805
  asyncElements: boolean;
786
806
  manyElements: boolean;
807
+ disabled: boolean;
787
808
  } ) => {
788
809
  const textFields = useMemo(
789
810
  () => fields.filter( ( field ) => field.type === 'text' ),
@@ -797,6 +818,7 @@ export const TextComponent = ( {
797
818
  Edit={ Edit }
798
819
  asyncElements={ asyncElements }
799
820
  manyElements={ manyElements }
821
+ disabled={ disabled }
800
822
  />
801
823
  );
802
824
  };
@@ -808,12 +830,14 @@ export const IntegerComponent = ( {
808
830
  asyncElements,
809
831
  manyElements,
810
832
  formatSeparatorThousand,
833
+ disabled,
811
834
  }: {
812
835
  type: PanelTypes;
813
836
  Edit: ControlTypes;
814
837
  asyncElements: boolean;
815
838
  manyElements: boolean;
816
839
  formatSeparatorThousand?: string;
840
+ disabled: boolean;
817
841
  } ) => {
818
842
  const integerFields = useMemo(
819
843
  () =>
@@ -840,6 +864,7 @@ export const IntegerComponent = ( {
840
864
  Edit={ Edit }
841
865
  asyncElements={ asyncElements }
842
866
  manyElements={ manyElements }
867
+ disabled={ disabled }
843
868
  />
844
869
  );
845
870
  };
@@ -863,6 +888,7 @@ export const NumberComponent = ( {
863
888
  formatSeparatorThousand,
864
889
  formatSeparatorDecimal,
865
890
  formatDecimals,
891
+ disabled,
866
892
  }: {
867
893
  type: PanelTypes;
868
894
  Edit: ControlTypes;
@@ -871,6 +897,7 @@ export const NumberComponent = ( {
871
897
  formatSeparatorThousand?: string;
872
898
  formatSeparatorDecimal?: string;
873
899
  formatDecimals?: number;
900
+ disabled: boolean;
874
901
  } ) => {
875
902
  const numberFields = useMemo(
876
903
  () =>
@@ -913,6 +940,7 @@ export const NumberComponent = ( {
913
940
  Edit={ Edit }
914
941
  asyncElements={ asyncElements }
915
942
  manyElements={ manyElements }
943
+ disabled={ disabled }
916
944
  />
917
945
  );
918
946
  };
@@ -945,11 +973,13 @@ export const BooleanComponent = ( {
945
973
  Edit,
946
974
  asyncElements,
947
975
  manyElements,
976
+ disabled,
948
977
  }: {
949
978
  type: PanelTypes;
950
979
  Edit: ControlTypes;
951
980
  asyncElements: boolean;
952
981
  manyElements: boolean;
982
+ disabled: boolean;
953
983
  } ) => {
954
984
  const booleanFields = useMemo(
955
985
  () => fields.filter( ( field ) => field.type === 'boolean' ),
@@ -963,6 +993,7 @@ export const BooleanComponent = ( {
963
993
  Edit={ Edit }
964
994
  asyncElements={ asyncElements }
965
995
  manyElements={ manyElements }
996
+ disabled={ disabled }
966
997
  />
967
998
  );
968
999
  };
@@ -975,6 +1006,7 @@ export const DateTimeComponent = ( {
975
1006
  manyElements,
976
1007
  formatDatetime,
977
1008
  formatWeekStartsOn,
1009
+ disabled,
978
1010
  }: {
979
1011
  type: PanelTypes;
980
1012
  Edit: ControlTypes;
@@ -982,6 +1014,7 @@ export const DateTimeComponent = ( {
982
1014
  manyElements: boolean;
983
1015
  formatDatetime?: string;
984
1016
  formatWeekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
1017
+ disabled: boolean;
985
1018
  } ) => {
986
1019
  const datetimeFields = useMemo(
987
1020
  () =>
@@ -1006,7 +1039,7 @@ export const DateTimeComponent = ( {
1006
1039
  }
1007
1040
  return field;
1008
1041
  } ),
1009
- [ fields, formatDatetime, formatWeekStartsOn ]
1042
+ [ formatDatetime, formatWeekStartsOn ]
1010
1043
  );
1011
1044
 
1012
1045
  return (
@@ -1016,6 +1049,7 @@ export const DateTimeComponent = ( {
1016
1049
  Edit={ Edit }
1017
1050
  asyncElements={ asyncElements }
1018
1051
  manyElements={ manyElements }
1052
+ disabled={ disabled }
1019
1053
  />
1020
1054
  );
1021
1055
  };
@@ -1054,6 +1088,7 @@ export const DateComponent = ( {
1054
1088
  manyElements,
1055
1089
  formatDate,
1056
1090
  formatWeekStartsOn,
1091
+ disabled,
1057
1092
  }: {
1058
1093
  type: PanelTypes;
1059
1094
  Edit: ControlTypes;
@@ -1061,6 +1096,7 @@ export const DateComponent = ( {
1061
1096
  manyElements: boolean;
1062
1097
  formatDate?: string;
1063
1098
  formatWeekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
1099
+ disabled: boolean;
1064
1100
  } ) => {
1065
1101
  const dateFields = useMemo(
1066
1102
  () =>
@@ -1095,6 +1131,7 @@ export const DateComponent = ( {
1095
1131
  Edit={ Edit }
1096
1132
  asyncElements={ asyncElements }
1097
1133
  manyElements={ manyElements }
1134
+ disabled={ disabled }
1098
1135
  />
1099
1136
  );
1100
1137
  };
@@ -1131,11 +1168,13 @@ export const EmailComponent = ( {
1131
1168
  Edit,
1132
1169
  asyncElements,
1133
1170
  manyElements,
1171
+ disabled,
1134
1172
  }: {
1135
1173
  type: PanelTypes;
1136
1174
  Edit: ControlTypes;
1137
1175
  asyncElements: boolean;
1138
1176
  manyElements: boolean;
1177
+ disabled: boolean;
1139
1178
  } ) => {
1140
1179
  const emailFields = useMemo(
1141
1180
  () => fields.filter( ( field ) => field.type === 'email' ),
@@ -1149,6 +1188,7 @@ export const EmailComponent = ( {
1149
1188
  Edit={ Edit }
1150
1189
  asyncElements={ asyncElements }
1151
1190
  manyElements={ manyElements }
1191
+ disabled={ disabled }
1152
1192
  />
1153
1193
  );
1154
1194
  };
@@ -1159,11 +1199,13 @@ export const TelephoneComponent = ( {
1159
1199
  Edit,
1160
1200
  asyncElements,
1161
1201
  manyElements,
1202
+ disabled,
1162
1203
  }: {
1163
1204
  type: PanelTypes;
1164
1205
  Edit: ControlTypes;
1165
1206
  asyncElements: boolean;
1166
1207
  manyElements: boolean;
1208
+ disabled: boolean;
1167
1209
  } ) => {
1168
1210
  const telephoneFields = fields.filter( ( field ) =>
1169
1211
  field.id.startsWith( 'telephone' )
@@ -1176,6 +1218,7 @@ export const TelephoneComponent = ( {
1176
1218
  Edit={ Edit }
1177
1219
  asyncElements={ asyncElements }
1178
1220
  manyElements={ manyElements }
1221
+ disabled={ disabled }
1179
1222
  />
1180
1223
  );
1181
1224
  };
@@ -1186,11 +1229,13 @@ export const UrlComponent = ( {
1186
1229
  Edit,
1187
1230
  asyncElements,
1188
1231
  manyElements,
1232
+ disabled,
1189
1233
  }: {
1190
1234
  type: PanelTypes;
1191
1235
  Edit: ControlTypes;
1192
1236
  asyncElements: boolean;
1193
1237
  manyElements: boolean;
1238
+ disabled: boolean;
1194
1239
  } ) => {
1195
1240
  const urlFields = useMemo(
1196
1241
  () => fields.filter( ( field ) => field.type === 'url' ),
@@ -1204,6 +1249,7 @@ export const UrlComponent = ( {
1204
1249
  Edit={ Edit }
1205
1250
  asyncElements={ asyncElements }
1206
1251
  manyElements={ manyElements }
1252
+ disabled={ disabled }
1207
1253
  />
1208
1254
  );
1209
1255
  };
@@ -1214,11 +1260,13 @@ export const ColorComponent = ( {
1214
1260
  Edit,
1215
1261
  asyncElements,
1216
1262
  manyElements,
1263
+ disabled,
1217
1264
  }: {
1218
1265
  type: PanelTypes;
1219
1266
  Edit: ControlTypes;
1220
1267
  asyncElements: boolean;
1221
1268
  manyElements: boolean;
1269
+ disabled: boolean;
1222
1270
  } ) => {
1223
1271
  const colorFields = useMemo(
1224
1272
  () => fields.filter( ( field ) => field.type === 'color' ),
@@ -1232,6 +1280,7 @@ export const ColorComponent = ( {
1232
1280
  Edit={ Edit }
1233
1281
  asyncElements={ asyncElements }
1234
1282
  manyElements={ manyElements }
1283
+ disabled={ disabled }
1235
1284
  />
1236
1285
  );
1237
1286
  };
@@ -1242,11 +1291,13 @@ export const MediaComponent = ( {
1242
1291
  Edit,
1243
1292
  asyncElements,
1244
1293
  manyElements,
1294
+ disabled,
1245
1295
  }: {
1246
1296
  type: PanelTypes;
1247
1297
  Edit: ControlTypes;
1248
1298
  asyncElements: boolean;
1249
1299
  manyElements: boolean;
1300
+ disabled: boolean;
1250
1301
  } ) => {
1251
1302
  const mediaFields = useMemo(
1252
1303
  () => fields.filter( ( field ) => field.type === 'media' ),
@@ -1260,6 +1311,7 @@ export const MediaComponent = ( {
1260
1311
  Edit={ Edit }
1261
1312
  asyncElements={ asyncElements }
1262
1313
  manyElements={ manyElements }
1314
+ disabled={ disabled }
1263
1315
  />
1264
1316
  );
1265
1317
  };
@@ -1270,11 +1322,13 @@ export const ArrayComponent = ( {
1270
1322
  Edit,
1271
1323
  asyncElements,
1272
1324
  manyElements,
1325
+ disabled,
1273
1326
  }: {
1274
1327
  type: PanelTypes;
1275
1328
  Edit: ControlTypes;
1276
1329
  asyncElements: boolean;
1277
1330
  manyElements: boolean;
1331
+ disabled: boolean;
1278
1332
  } ) => {
1279
1333
  const arrayTextFields = useMemo(
1280
1334
  () => fields.filter( ( field ) => field.type === 'array' ),
@@ -1288,6 +1342,7 @@ export const ArrayComponent = ( {
1288
1342
  Edit={ Edit }
1289
1343
  asyncElements={ asyncElements }
1290
1344
  manyElements={ manyElements }
1345
+ disabled={ disabled }
1291
1346
  />
1292
1347
  );
1293
1348
  };
@@ -1298,11 +1353,13 @@ export const PasswordComponent = ( {
1298
1353
  Edit,
1299
1354
  asyncElements,
1300
1355
  manyElements,
1356
+ disabled,
1301
1357
  }: {
1302
1358
  type: PanelTypes;
1303
1359
  Edit: ControlTypes;
1304
1360
  asyncElements: boolean;
1305
1361
  manyElements: boolean;
1362
+ disabled: boolean;
1306
1363
  } ) => {
1307
1364
  const passwordFields = fields.filter( ( field ) =>
1308
1365
  field.id.startsWith( 'password' )
@@ -1315,6 +1372,7 @@ export const PasswordComponent = ( {
1315
1372
  Edit={ Edit }
1316
1373
  asyncElements={ asyncElements }
1317
1374
  manyElements={ manyElements }
1375
+ disabled={ disabled }
1318
1376
  />
1319
1377
  );
1320
1378
  };
@@ -1325,11 +1383,13 @@ export const NoTypeComponent = ( {
1325
1383
  Edit,
1326
1384
  asyncElements,
1327
1385
  manyElements,
1386
+ disabled,
1328
1387
  }: {
1329
1388
  type: PanelTypes;
1330
1389
  Edit: ControlTypes;
1331
1390
  asyncElements: boolean;
1332
1391
  manyElements: boolean;
1392
+ disabled: boolean;
1333
1393
  } ) => {
1334
1394
  const noTypeFields = useMemo(
1335
1395
  () => fields.filter( ( field ) => field.type === undefined ),
@@ -1343,6 +1403,7 @@ export const NoTypeComponent = ( {
1343
1403
  Edit={ Edit }
1344
1404
  asyncElements={ asyncElements }
1345
1405
  manyElements={ manyElements }
1406
+ disabled={ disabled }
1346
1407
  />
1347
1408
  );
1348
1409
  };
@@ -339,6 +339,50 @@ describe( 'normalizeFields: default getValue', () => {
339
339
  } );
340
340
  } );
341
341
 
342
+ describe( 'validation normalization', () => {
343
+ it( 'ignores string min/max rules on numeric fields', () => {
344
+ const fields: Field< {} >[] = [
345
+ {
346
+ id: 'price',
347
+ type: 'number',
348
+ isValid: {
349
+ min: '1',
350
+ max: '10',
351
+ },
352
+ },
353
+ ];
354
+ const normalizedFields = normalizeFields( fields );
355
+ expect( normalizedFields[ 0 ].isValid.min ).toBeUndefined();
356
+ expect( normalizedFields[ 0 ].isValid.max ).toBeUndefined();
357
+ } );
358
+
359
+ it( 'ignores numeric min/max rules on date-like fields', () => {
360
+ const fields: Field< {} >[] = [
361
+ {
362
+ id: 'publishDate',
363
+ type: 'date',
364
+ isValid: {
365
+ min: 1,
366
+ max: 10,
367
+ },
368
+ },
369
+ {
370
+ id: 'publishedAt',
371
+ type: 'datetime',
372
+ isValid: {
373
+ min: 1,
374
+ max: 10,
375
+ },
376
+ },
377
+ ];
378
+ const normalizedFields = normalizeFields( fields );
379
+ expect( normalizedFields[ 0 ].isValid.min ).toBeUndefined();
380
+ expect( normalizedFields[ 0 ].isValid.max ).toBeUndefined();
381
+ expect( normalizedFields[ 1 ].isValid.min ).toBeUndefined();
382
+ expect( normalizedFields[ 1 ].isValid.max ).toBeUndefined();
383
+ } );
384
+ } );
385
+
342
386
  describe( 'format normalization', () => {
343
387
  it( 'applies default format when not provided for date fields', () => {
344
388
  const fields: Field< {} >[] = [
@@ -4,13 +4,42 @@
4
4
  import type { Field, NormalizedRules } from '../../types';
5
5
  import type { FieldType } from '../../types/private';
6
6
 
7
+ function supportsNumericRangeConstraint( type?: string ) {
8
+ return type === 'integer' || type === 'number';
9
+ }
10
+
11
+ function supportsDateRangeConstraint( type?: string ) {
12
+ return type === 'date' || type === 'datetime';
13
+ }
14
+
15
+ function normalizeRangeRule< Item >(
16
+ value: number | string | undefined,
17
+ fieldType: FieldType< Item >,
18
+ key: 'min' | 'max'
19
+ ): NormalizedRules< Item >[ 'min' ] {
20
+ const validator = fieldType.validate[ key ];
21
+ if (
22
+ validator &&
23
+ ( ( typeof value === 'number' &&
24
+ supportsNumericRangeConstraint( fieldType.type ) ) ||
25
+ ( typeof value === 'string' &&
26
+ supportsDateRangeConstraint( fieldType.type ) ) )
27
+ ) {
28
+ return { constraint: value, validate: validator } as NonNullable<
29
+ NormalizedRules< Item >[ typeof key ]
30
+ >;
31
+ }
32
+ return undefined;
33
+ }
34
+
7
35
  export default function getIsValid< Item >(
8
36
  field: Field< Item >,
9
37
  fieldType: FieldType< Item >
10
38
  ): NormalizedRules< Item > {
39
+ const rules = field.isValid;
11
40
  let required;
12
41
  if (
13
- field.isValid?.required === true &&
42
+ rules?.required === true &&
14
43
  fieldType.validate.required !== undefined
15
44
  ) {
16
45
  required = {
@@ -21,9 +50,9 @@ export default function getIsValid< Item >(
21
50
 
22
51
  let elements;
23
52
  if (
24
- ( field.isValid?.elements === true ||
53
+ ( rules?.elements === true ||
25
54
  // elements is enabled unless the field opts-out
26
- ( field.isValid?.elements === undefined &&
55
+ ( rules?.elements === undefined &&
27
56
  ( !! field.elements || !! field.getElements ) ) ) &&
28
57
  fieldType.validate.elements !== undefined
29
58
  ) {
@@ -33,62 +62,46 @@ export default function getIsValid< Item >(
33
62
  };
34
63
  }
35
64
 
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
- }
65
+ const min = normalizeRangeRule( rules?.min, fieldType, 'min' );
66
+ const max = normalizeRangeRule( rules?.max, fieldType, 'max' );
57
67
 
68
+ const minLengthValue = rules?.minLength;
58
69
  let minLength;
59
70
  if (
60
- typeof field.isValid?.minLength === 'number' &&
71
+ typeof minLengthValue === 'number' &&
61
72
  fieldType.validate.minLength !== undefined
62
73
  ) {
63
74
  minLength = {
64
- constraint: field.isValid.minLength,
75
+ constraint: minLengthValue,
65
76
  validate: fieldType.validate.minLength,
66
77
  };
67
78
  }
68
79
 
80
+ const maxLengthValue = rules?.maxLength;
69
81
  let maxLength;
70
82
  if (
71
- typeof field.isValid?.maxLength === 'number' &&
83
+ typeof maxLengthValue === 'number' &&
72
84
  fieldType.validate.maxLength !== undefined
73
85
  ) {
74
86
  maxLength = {
75
- constraint: field.isValid.maxLength,
87
+ constraint: maxLengthValue,
76
88
  validate: fieldType.validate.maxLength,
77
89
  };
78
90
  }
79
91
 
92
+ const patternValue = rules?.pattern;
80
93
  let pattern;
81
94
  if (
82
- field.isValid?.pattern !== undefined &&
95
+ patternValue !== undefined &&
83
96
  fieldType.validate.pattern !== undefined
84
97
  ) {
85
98
  pattern = {
86
- constraint: field.isValid?.pattern,
99
+ constraint: patternValue,
87
100
  validate: fieldType.validate.pattern,
88
101
  };
89
102
  }
90
103
 
91
- const custom = field.isValid?.custom ?? fieldType.validate.custom;
104
+ const custom = rules?.custom ?? fieldType.validate.custom;
92
105
 
93
106
  return {
94
107
  required,
@@ -0,0 +1,80 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { isValid as isValidDate } from 'date-fns';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import { getDate } from '@wordpress/date';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import type { NormalizedField } from '../../types';
15
+
16
+ type Boundary = 'min' | 'max';
17
+
18
+ function parseDateLike( value?: string ) {
19
+ if ( ! value ) {
20
+ return null;
21
+ }
22
+
23
+ // Pre-check to avoid passing unparseable strings to getDate,
24
+ // which uses moment.js and emits deprecation warnings.
25
+ if ( ! isValidDate( new Date( value ) ) ) {
26
+ return null;
27
+ }
28
+
29
+ const parsed = getDate( value );
30
+ return parsed && isValidDate( parsed ) ? parsed : null;
31
+ }
32
+
33
+ function validateDateLikeBoundary< Item >(
34
+ item: Item,
35
+ field: NormalizedField< Item >,
36
+ boundary: Boundary
37
+ ): boolean {
38
+ const constraint = field.isValid[ boundary ]?.constraint;
39
+ if ( typeof constraint !== 'string' ) {
40
+ return false;
41
+ }
42
+
43
+ const value = field.getValue( { item } );
44
+ const boundaryValue = Array.isArray( value )
45
+ ? value[ boundary === 'min' ? 0 : value.length - 1 ]
46
+ : value;
47
+
48
+ if (
49
+ boundaryValue === undefined ||
50
+ boundaryValue === null ||
51
+ boundaryValue === ''
52
+ ) {
53
+ return true;
54
+ }
55
+
56
+ const parsedConstraint = parseDateLike( constraint );
57
+ const parsedValue = parseDateLike( String( boundaryValue ) );
58
+
59
+ return (
60
+ !! parsedConstraint &&
61
+ !! parsedValue &&
62
+ ( boundary === 'min'
63
+ ? parsedValue.getTime() >= parsedConstraint.getTime()
64
+ : parsedValue.getTime() <= parsedConstraint.getTime() )
65
+ );
66
+ }
67
+
68
+ export function isValidMinDate< Item >(
69
+ item: Item,
70
+ field: NormalizedField< Item >
71
+ ): boolean {
72
+ return validateDateLikeBoundary( item, field, 'min' );
73
+ }
74
+
75
+ export function isValidMaxDate< Item >(
76
+ item: Item,
77
+ field: NormalizedField< Item >
78
+ ): boolean {
79
+ return validateDateLikeBoundary( item, field, 'max' );
80
+ }