@wix/patterns-fields 1.108.0 → 1.109.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 (225) hide show
  1. package/dist/cjs/components/address/input/address-input.st.css.js +3 -3
  2. package/dist/cjs/components/address/input/address-input.st.css.js.map +1 -1
  3. package/dist/cjs/components/audio/actions/actions-menu/actions-menu.st.css.js +3 -3
  4. package/dist/cjs/components/audio/actions/actions-menu/actions-menu.st.css.js.map +1 -1
  5. package/dist/cjs/components/audio/audio-field/form-audio-field.st.css.js +4 -4
  6. package/dist/cjs/components/audio/audio-field/form-audio-field.st.css.js.map +1 -1
  7. package/dist/cjs/components/audio/audio-player/audio-player.st.css.js +2 -2
  8. package/dist/cjs/components/audio/audio-player/audio-player.st.css.js.map +1 -1
  9. package/dist/cjs/components/color-view/cell-color-view.st.css.js +3 -3
  10. package/dist/cjs/components/color-view/cell-color-view.st.css.js.map +1 -1
  11. package/dist/cjs/components/color-view/color-view.st.css.js +4 -4
  12. package/dist/cjs/components/color-view/color-view.st.css.js.map +1 -1
  13. package/dist/cjs/components/date-input/cell-date-input.js +21 -2
  14. package/dist/cjs/components/date-input/cell-date-input.js.map +1 -1
  15. package/dist/cjs/components/date-input/date-picker-internals.js +93 -3
  16. package/dist/cjs/components/date-input/date-picker-internals.js.map +1 -1
  17. package/dist/cjs/components/date-input/form-date-input.driver.js +2 -0
  18. package/dist/cjs/components/date-input/form-date-input.driver.js.map +1 -1
  19. package/dist/cjs/components/date-input/form-date-input.js +23 -6
  20. package/dist/cjs/components/date-input/form-date-input.js.map +1 -1
  21. package/dist/cjs/components/date-input/use-field-value-replacement.js +48 -0
  22. package/dist/cjs/components/date-input/use-field-value-replacement.js.map +1 -0
  23. package/dist/cjs/components/datetime-input/form-date-time.driver.js +3 -0
  24. package/dist/cjs/components/datetime-input/form-date-time.driver.js.map +1 -1
  25. package/dist/cjs/components/datetime-input/form-date-time.js +61 -24
  26. package/dist/cjs/components/datetime-input/form-date-time.js.map +1 -1
  27. package/dist/cjs/components/delete-dialog/delete-dialog.st.css.js +3 -3
  28. package/dist/cjs/components/delete-dialog/delete-dialog.st.css.js.map +1 -1
  29. package/dist/cjs/components/document/form-document-field.st.css.js +7 -7
  30. package/dist/cjs/components/document/form-document-field.st.css.js.map +1 -1
  31. package/dist/cjs/components/exclamation/exclamation.st.css.js +5 -5
  32. package/dist/cjs/components/exclamation/exclamation.st.css.js.map +1 -1
  33. package/dist/cjs/components/highlighted-text/highlighted-text.st.css.js +5 -5
  34. package/dist/cjs/components/highlighted-text/highlighted-text.st.css.js.map +1 -1
  35. package/dist/cjs/components/image/thumbnail-replace-overlay.st.css.js +3 -3
  36. package/dist/cjs/components/image/thumbnail-replace-overlay.st.css.js.map +1 -1
  37. package/dist/cjs/components/media-control/cell-media-edit-shell.st.css.js +2 -2
  38. package/dist/cjs/components/media-control/cell-media-edit-shell.st.css.js.map +1 -1
  39. package/dist/cjs/components/media-control/paste-url-button.st.css.js +4 -4
  40. package/dist/cjs/components/media-control/paste-url-button.st.css.js.map +1 -1
  41. package/dist/cjs/components/media-gallery/form-media-gallery-field.st.css.js +10 -10
  42. package/dist/cjs/components/media-gallery/form-media-gallery-field.st.css.js.map +1 -1
  43. package/dist/cjs/components/media-image/media-image.st.css.js +4 -4
  44. package/dist/cjs/components/media-image/media-image.st.css.js.map +1 -1
  45. package/dist/cjs/components/media-image/overlays/overlay.st.css.js +3 -3
  46. package/dist/cjs/components/media-image/overlays/overlay.st.css.js.map +1 -1
  47. package/dist/cjs/components/media-tag/web-media-tag/media-tag.st.css.js +2 -2
  48. package/dist/cjs/components/media-tag/web-media-tag/media-tag.st.css.js.map +1 -1
  49. package/dist/cjs/components/multi-document/cell-multi-document-edit.st.css.js +3 -3
  50. package/dist/cjs/components/multi-document/cell-multi-document-edit.st.css.js.map +1 -1
  51. package/dist/cjs/components/multi-document/multi-document-input/form-multi-document.st.css.js +5 -5
  52. package/dist/cjs/components/multi-document/multi-document-input/form-multi-document.st.css.js.map +1 -1
  53. package/dist/cjs/components/reference/cell-multi-reference-input.st.css.js +2 -2
  54. package/dist/cjs/components/reference/cell-multi-reference-input.st.css.js.map +1 -1
  55. package/dist/cjs/components/reference/cell-reference-input.st.css.js +3 -3
  56. package/dist/cjs/components/reference/cell-reference-input.st.css.js.map +1 -1
  57. package/dist/cjs/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js +4 -4
  58. package/dist/cjs/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js.map +1 -1
  59. package/dist/cjs/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js +3 -3
  60. package/dist/cjs/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js.map +1 -1
  61. package/dist/cjs/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.js +2 -2
  62. package/dist/cjs/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.js.map +1 -1
  63. package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js +3 -3
  64. package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js.map +1 -1
  65. package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js +3 -3
  66. package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js.map +1 -1
  67. package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.js +2 -2
  68. package/dist/cjs/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.js.map +1 -1
  69. package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.js +7 -7
  70. package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.js.map +1 -1
  71. package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.js +5 -5
  72. package/dist/cjs/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.js.map +1 -1
  73. package/dist/cjs/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.js +4 -4
  74. package/dist/cjs/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.js.map +1 -1
  75. package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.js +18 -18
  76. package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.js.map +1 -1
  77. package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.js +4 -4
  78. package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.js.map +1 -1
  79. package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js +18 -18
  80. package/dist/cjs/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js.map +1 -1
  81. package/dist/cjs/components/text/form-short-text.js +1 -1
  82. package/dist/cjs/components/text/form-short-text.js.map +1 -1
  83. package/dist/cjs/components/text/text-view.st.css.js +3 -3
  84. package/dist/cjs/components/text/text-view.st.css.js.map +1 -1
  85. package/dist/cjs/styles.global.css +1 -1
  86. package/dist/esm/components/address/input/address-input.st.css.js +2 -2
  87. package/dist/esm/components/address/input/address-input.st.css.js.map +1 -1
  88. package/dist/esm/components/audio/actions/actions-menu/actions-menu.st.css.js +2 -2
  89. package/dist/esm/components/audio/actions/actions-menu/actions-menu.st.css.js.map +1 -1
  90. package/dist/esm/components/audio/audio-field/form-audio-field.st.css.js +2 -2
  91. package/dist/esm/components/audio/audio-field/form-audio-field.st.css.js.map +1 -1
  92. package/dist/esm/components/audio/audio-player/audio-player.st.css.js +2 -2
  93. package/dist/esm/components/color-view/cell-color-view.st.css.js +2 -2
  94. package/dist/esm/components/color-view/color-view.st.css.js +2 -2
  95. package/dist/esm/components/date-input/cell-date-input.js +21 -2
  96. package/dist/esm/components/date-input/cell-date-input.js.map +1 -1
  97. package/dist/esm/components/date-input/date-picker-internals.js +67 -0
  98. package/dist/esm/components/date-input/date-picker-internals.js.map +1 -1
  99. package/dist/esm/components/date-input/form-date-input.driver.js +2 -0
  100. package/dist/esm/components/date-input/form-date-input.driver.js.map +1 -1
  101. package/dist/esm/components/date-input/form-date-input.js +25 -4
  102. package/dist/esm/components/date-input/form-date-input.js.map +1 -1
  103. package/dist/esm/components/date-input/use-field-value-replacement.js +48 -0
  104. package/dist/esm/components/date-input/use-field-value-replacement.js.map +1 -0
  105. package/dist/esm/components/datetime-input/form-date-time.driver.js +3 -0
  106. package/dist/esm/components/datetime-input/form-date-time.driver.js.map +1 -1
  107. package/dist/esm/components/datetime-input/form-date-time.js +51 -21
  108. package/dist/esm/components/datetime-input/form-date-time.js.map +1 -1
  109. package/dist/esm/components/delete-dialog/delete-dialog.st.css.js +2 -2
  110. package/dist/esm/components/delete-dialog/delete-dialog.st.css.js.map +1 -1
  111. package/dist/esm/components/document/form-document-field.st.css.js +2 -2
  112. package/dist/esm/components/exclamation/exclamation.st.css.js +2 -2
  113. package/dist/esm/components/highlighted-text/highlighted-text.st.css.js +3 -3
  114. package/dist/esm/components/image/thumbnail-replace-overlay.st.css.js +2 -2
  115. package/dist/esm/components/media-control/cell-media-edit-shell.st.css.js +2 -2
  116. package/dist/esm/components/media-control/cell-media-edit-shell.st.css.js.map +1 -1
  117. package/dist/esm/components/media-control/paste-url-button.st.css.js +2 -2
  118. package/dist/esm/components/media-gallery/form-media-gallery-field.st.css.js +2 -2
  119. package/dist/esm/components/media-gallery/form-media-gallery-field.st.css.js.map +1 -1
  120. package/dist/esm/components/media-image/media-image.st.css.js +3 -3
  121. package/dist/esm/components/media-image/overlays/overlay.st.css.js +2 -2
  122. package/dist/esm/components/media-image/overlays/overlay.st.css.js.map +1 -1
  123. package/dist/esm/components/media-tag/web-media-tag/media-tag.st.css.js +2 -2
  124. package/dist/esm/components/multi-document/cell-multi-document-edit.st.css.js +2 -2
  125. package/dist/esm/components/multi-document/multi-document-input/form-multi-document.st.css.js +2 -2
  126. package/dist/esm/components/multi-document/multi-document-input/form-multi-document.st.css.js.map +1 -1
  127. package/dist/esm/components/reference/cell-multi-reference-input.st.css.js +2 -2
  128. package/dist/esm/components/reference/cell-reference-input.st.css.js +2 -2
  129. package/dist/esm/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js +2 -2
  130. package/dist/esm/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.js.map +1 -1
  131. package/dist/esm/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.js +2 -2
  132. package/dist/esm/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.js +2 -2
  133. package/dist/esm/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js +2 -2
  134. package/dist/esm/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.js.map +1 -1
  135. package/dist/esm/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js +2 -2
  136. package/dist/esm/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.js.map +1 -1
  137. package/dist/esm/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.js +2 -2
  138. package/dist/esm/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.js +2 -2
  139. package/dist/esm/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.js +2 -2
  140. package/dist/esm/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.js +2 -2
  141. package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.js +2 -2
  142. package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.js +2 -2
  143. package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js +2 -2
  144. package/dist/esm/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.js.map +1 -1
  145. package/dist/esm/components/text/form-short-text.js +1 -1
  146. package/dist/esm/components/text/form-short-text.js.map +1 -1
  147. package/dist/esm/components/text/text-view.st.css.js +2 -2
  148. package/dist/esm/components/text/text-view.st.css.js.map +1 -1
  149. package/dist/esm/styles.global.css +1 -1
  150. package/dist/types/components/address/input/address-input.st.css.d.ts.map +1 -1
  151. package/dist/types/components/audio/actions/actions-menu/actions-menu.st.css.d.ts.map +1 -1
  152. package/dist/types/components/audio/audio-field/form-audio-field.st.css.d.ts.map +1 -1
  153. package/dist/types/components/date-input/cell-date-input.d.ts +4 -0
  154. package/dist/types/components/date-input/cell-date-input.d.ts.map +1 -1
  155. package/dist/types/components/date-input/date-picker-internals.d.ts +11 -1
  156. package/dist/types/components/date-input/date-picker-internals.d.ts.map +1 -1
  157. package/dist/types/components/date-input/form-date-input.d.ts.map +1 -1
  158. package/dist/types/components/date-input/form-date-input.driver.d.ts +2 -0
  159. package/dist/types/components/date-input/form-date-input.driver.d.ts.map +1 -1
  160. package/dist/types/components/date-input/use-field-value-replacement.d.ts +3 -0
  161. package/dist/types/components/date-input/use-field-value-replacement.d.ts.map +1 -0
  162. package/dist/types/components/datetime-input/form-date-time.d.ts.map +1 -1
  163. package/dist/types/components/datetime-input/form-date-time.driver.d.ts +3 -0
  164. package/dist/types/components/datetime-input/form-date-time.driver.d.ts.map +1 -1
  165. package/dist/types/components/delete-dialog/delete-dialog.st.css.d.ts.map +1 -1
  166. package/dist/types/components/media-control/cell-media-edit-shell.st.css.d.ts.map +1 -1
  167. package/dist/types/components/media-gallery/form-media-gallery-field.st.css.d.ts.map +1 -1
  168. package/dist/types/components/media-image/overlays/overlay.st.css.d.ts.map +1 -1
  169. package/dist/types/components/multi-document/multi-document-input/form-multi-document.st.css.d.ts.map +1 -1
  170. package/dist/types/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.d.ts.map +1 -1
  171. package/dist/types/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.d.ts.map +1 -1
  172. package/dist/types/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.d.ts.map +1 -1
  173. package/dist/types/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.d.ts.map +1 -1
  174. package/dist/types/components/text/text-view.st.css.d.ts.map +1 -1
  175. package/package.json +5 -5
  176. package/src/__tests__/components/date-input/cell-date-input.spec.tsx +100 -0
  177. package/src/__tests__/components/date-input/date-picker-internals.spec.tsx +69 -0
  178. package/src/__tests__/components/date-input/form-date-input.spec.tsx +141 -0
  179. package/src/__tests__/components/datetime-input/form-date-time.spec.tsx +194 -0
  180. package/src/__tests__/components/text/form-short-text.spec.tsx +27 -0
  181. package/src/__tests__/form-field.driver.tsx +31 -3
  182. package/src/__tests__/hooks/use-field-value-replacement.spec.tsx +68 -0
  183. package/src/components/address/input/address-input.st.css.ts +2 -2
  184. package/src/components/audio/actions/actions-menu/actions-menu.st.css.ts +2 -2
  185. package/src/components/audio/audio-field/form-audio-field.st.css.ts +2 -2
  186. package/src/components/audio/audio-player/audio-player.st.css.ts +2 -2
  187. package/src/components/color-view/cell-color-view.st.css.ts +2 -2
  188. package/src/components/color-view/color-view.st.css.ts +2 -2
  189. package/src/components/date-input/cell-date-input.tsx +28 -0
  190. package/src/components/date-input/date-picker-internals.ts +104 -3
  191. package/src/components/date-input/form-date-input.driver.ts +2 -0
  192. package/src/components/date-input/form-date-input.tsx +25 -3
  193. package/src/components/date-input/use-field-value-replacement.ts +63 -0
  194. package/src/components/datetime-input/form-date-time.driver.ts +3 -0
  195. package/src/components/datetime-input/form-date-time.tsx +55 -33
  196. package/src/components/delete-dialog/delete-dialog.st.css.ts +2 -2
  197. package/src/components/document/form-document-field.st.css.ts +2 -2
  198. package/src/components/exclamation/exclamation.st.css.ts +2 -2
  199. package/src/components/highlighted-text/highlighted-text.st.css.ts +3 -3
  200. package/src/components/image/thumbnail-replace-overlay.st.css.ts +2 -2
  201. package/src/components/media-control/cell-media-edit-shell.st.css.ts +2 -2
  202. package/src/components/media-control/paste-url-button.st.css.ts +2 -2
  203. package/src/components/media-gallery/form-media-gallery-field.st.css.ts +2 -2
  204. package/src/components/media-image/media-image.st.css.ts +3 -3
  205. package/src/components/media-image/overlays/overlay.st.css.ts +2 -2
  206. package/src/components/media-tag/web-media-tag/media-tag.st.css.ts +2 -2
  207. package/src/components/multi-document/cell-multi-document-edit.st.css.ts +2 -2
  208. package/src/components/multi-document/multi-document-input/form-multi-document.st.css.ts +2 -2
  209. package/src/components/reference/cell-multi-reference-input.st.css.ts +2 -2
  210. package/src/components/reference/cell-reference-input.st.css.ts +2 -2
  211. package/src/components/rich-content/rich-content-input/default-value-input/rich-content-default-value-input.st.css.ts +2 -2
  212. package/src/components/rich-content/rich-content-input/form-input/rich-content-form-input.st.css.ts +2 -2
  213. package/src/components/rich-content/rich-content-input/form-read-only-input/rich-content-form-read-only-input.st.css.ts +2 -2
  214. package/src/components/rich-content/rich-content-input/rich-content-common/fullscreen-modal/fullscreen-modal.st.css.ts +2 -2
  215. package/src/components/rich-content/rich-content-input/rich-content-common/publish-loader/publish-loader.st.css.ts +2 -2
  216. package/src/components/rich-content/rich-content-input/rich-content-common/toggle-fullscreen-button/toggle-fullscreen-button.st.css.ts +2 -2
  217. package/src/components/rich-content/rich-content-input/rich-content-editor/rich-content-editor.st.css.ts +2 -2
  218. package/src/components/rich-content/rich-content-input/rich-content-editor/rich-content-toolbar.st.css.ts +2 -2
  219. package/src/components/rich-content/rich-content-input/rich-content-viewer/rich-content-viewer.st.css.ts +2 -2
  220. package/src/components/rich-text/rich-text-input/rich-text-editor/rich-editor.st.css.ts +2 -2
  221. package/src/components/rich-text/rich-text-input/rich-text-editor/rich-text-editor.st.css.ts +2 -2
  222. package/src/components/rich-text/rich-text-input/rich-text-editor/toolbar/toolbar.st.css.ts +2 -2
  223. package/src/components/text/form-short-text.tsx +1 -1
  224. package/src/components/text/text-view.st.css.ts +2 -2
  225. package/src/styles.global.css +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/patterns-fields",
3
- "version": "1.108.0",
3
+ "version": "1.109.0",
4
4
  "license": "UNLICENSED",
5
5
  "author": {
6
6
  "name": "Kobi",
@@ -124,7 +124,7 @@
124
124
  "@wix/atlas": "^1.0.35",
125
125
  "@wix/data": "^1.0.323",
126
126
  "@wix/media": "^1.0.231",
127
- "@wix/patterns-fields-utils": "1.89.0",
127
+ "@wix/patterns-fields-utils": "1.90.0",
128
128
  "@wix/rich-content": "1.0.37",
129
129
  "@wix/sdk": "^1.17.2",
130
130
  "@wix/wix-ui-icons-common": "^3.189.0",
@@ -152,8 +152,8 @@
152
152
  "@types/lodash": "^4.17.20",
153
153
  "@types/react": "^16.14.68",
154
154
  "@wix/babel-cli": "^1.11.0",
155
- "@wix/bex-core": "2.386.0",
156
- "@wix/design-system": "^1.319.0",
155
+ "@wix/bex-core": "2.387.0",
156
+ "@wix/design-system": "^1.330.2",
157
157
  "@wix/eslint-config-yoshi": "^6.74.0",
158
158
  "@wix/jest-yoshi-preset": "^6.74.0",
159
159
  "@wix/wix-data-items-common": "^1.0.270",
@@ -212,5 +212,5 @@
212
212
  "optional": true
213
213
  }
214
214
  },
215
- "falconPackageHash": "7236b46723bb703c3913b3fb94d84a23b696119b21426b35217859d5"
215
+ "falconPackageHash": "04f04b0286935a0ade250fe58a8fe23286927d4a7ad06bf85bdc84e8"
216
216
  }
@@ -0,0 +1,100 @@
1
+ import '../../../testkit/test-polyfills';
2
+
3
+ import React from 'react';
4
+ import { fireEvent, render } from '@testing-library/react';
5
+
6
+ import { CellDateInput } from '../../../components/date-input/cell-date-input';
7
+
8
+ const setup = (value: Date | null = new Date(2024, 0, 15)) => {
9
+ const onChange = jest.fn();
10
+ const onEmpty = jest.fn();
11
+ const onEnter = jest.fn();
12
+ const { container } = render(
13
+ <CellDateInput
14
+ value={value}
15
+ onChange={onChange}
16
+ onEmpty={onEmpty}
17
+ onEnter={onEnter}
18
+ />,
19
+ );
20
+ const input = container.querySelector('input')!;
21
+ return { input, onChange, onEmpty, onEnter };
22
+ };
23
+
24
+ describe('CellDateInput', () => {
25
+ it('reports an emptied input through onEmpty instead of emitting a date', () => {
26
+ const { input, onChange, onEmpty } = setup();
27
+
28
+ fireEvent.change(input, { target: { value: '' } });
29
+
30
+ expect(onEmpty).toHaveBeenCalledTimes(1);
31
+ expect(onChange).not.toHaveBeenCalled();
32
+ });
33
+
34
+ it('reports Enter on an emptied input through onEnter with null', () => {
35
+ const { input, onChange, onEnter } = setup();
36
+
37
+ fireEvent.change(input, { target: { value: '' } });
38
+ fireEvent.keyDown(input, { key: 'Enter' });
39
+
40
+ expect(onEnter).toHaveBeenCalledWith(null);
41
+ expect(onChange).not.toHaveBeenCalled();
42
+ });
43
+
44
+ it('reports Enter on a typed date through onEnter with the date', () => {
45
+ const { input, onEnter } = setup();
46
+
47
+ fireEvent.change(input, { target: { value: '02/20/2024' } });
48
+ fireEvent.keyDown(input, { key: 'Enter' });
49
+
50
+ expect(onEnter).toHaveBeenCalledWith(new Date(2024, 1, 20));
51
+ });
52
+
53
+ describe('with onEnter and no onEmpty', () => {
54
+ const setupEnterOnly = () => {
55
+ const onEnter = jest.fn();
56
+ const { container } = render(
57
+ <CellDateInput value={new Date(2024, 0, 15)} onEnter={onEnter} />,
58
+ );
59
+ const input = container.querySelector('input')!;
60
+ return { input, onEnter };
61
+ };
62
+
63
+ it('reports Enter on a typed date through onEnter with the date', () => {
64
+ const { input, onEnter } = setupEnterOnly();
65
+
66
+ fireEvent.change(input, { target: { value: '02/20/2024' } });
67
+ fireEvent.keyDown(input, { key: 'Enter' });
68
+
69
+ expect(onEnter).toHaveBeenCalledWith(new Date(2024, 1, 20));
70
+ });
71
+
72
+ it('reports Enter on an emptied input through onEnter with null', () => {
73
+ const { input, onEnter } = setupEnterOnly();
74
+
75
+ fireEvent.change(input, { target: { value: '' } });
76
+ fireEvent.keyDown(input, { key: 'Enter' });
77
+
78
+ expect(onEnter).toHaveBeenCalledWith(null);
79
+ });
80
+ });
81
+
82
+ it('emits a typed date through onChange', () => {
83
+ const { input, onChange, onEmpty } = setup();
84
+
85
+ fireEvent.change(input, { target: { value: '02/20/2024' } });
86
+
87
+ expect(onChange).toHaveBeenCalledWith(new Date(2024, 1, 20));
88
+ expect(onEmpty).not.toHaveBeenCalled();
89
+ });
90
+
91
+ it('emits a day picked from the calendar while the input is empty', () => {
92
+ const { input, onChange, onEmpty } = setup(null);
93
+
94
+ fireEvent.click(input);
95
+ fireEvent.click(document.querySelector('[data-date]')!);
96
+
97
+ expect(onChange).toHaveBeenCalledWith(expect.any(Date));
98
+ expect(onEmpty).not.toHaveBeenCalled();
99
+ });
100
+ });
@@ -0,0 +1,69 @@
1
+ import '../../../testkit/test-polyfills';
2
+
3
+ import React from 'react';
4
+ import { act, fireEvent, render } from '@testing-library/react';
5
+ import { DatePicker } from '@wix/design-system';
6
+
7
+ import { onSameDayCalendarPick } from '../../../components/date-input/date-picker-internals';
8
+
9
+ const setup = () => {
10
+ const onChange = jest.fn();
11
+ const onPick = jest.fn();
12
+ const pickerRef = React.createRef<DatePicker>();
13
+ render(
14
+ <DatePicker
15
+ ref={pickerRef}
16
+ value={new Date(2024, 0, 15, 3, 30)}
17
+ onChange={onChange}
18
+ />,
19
+ );
20
+ const undo = onSameDayCalendarPick(pickerRef.current, onPick);
21
+ const clickDay = (day: number) => {
22
+ act(() => {
23
+ pickerRef.current!.openCalendar();
24
+ });
25
+ fireEvent.click(
26
+ document.querySelector(
27
+ `[data-outsideday='false'][data-date='2024-0-${day}']`,
28
+ )!,
29
+ );
30
+ };
31
+ return { onChange, onPick, undo, clickDay };
32
+ };
33
+
34
+ describe('onSameDayCalendarPick', () => {
35
+ it('reports a pick of the value day, which WDS skips', () => {
36
+ const { onChange, onPick, clickDay } = setup();
37
+
38
+ clickDay(15);
39
+
40
+ expect(onPick).toHaveBeenCalledTimes(1);
41
+ expect(onPick).toHaveBeenCalledWith(new Date(2024, 0, 15, 12));
42
+ expect(onChange).not.toHaveBeenCalled();
43
+ });
44
+
45
+ it('does not report a pick of another day, which WDS sends to onChange', () => {
46
+ const { onChange, onPick, clickDay } = setup();
47
+
48
+ clickDay(20);
49
+
50
+ expect(onPick).not.toHaveBeenCalled();
51
+ expect(onChange).toHaveBeenCalledWith(new Date(2024, 0, 20, 3, 30));
52
+ });
53
+
54
+ it('stops reporting once undone', () => {
55
+ const { onPick, undo, clickDay } = setup();
56
+
57
+ undo();
58
+ clickDay(15);
59
+
60
+ expect(onPick).not.toHaveBeenCalled();
61
+ });
62
+
63
+ it('does nothing without a picker', () => {
64
+ const onPick = jest.fn();
65
+
66
+ expect(() => onSameDayCalendarPick(null, onPick)()).not.toThrow();
67
+ expect(onPick).not.toHaveBeenCalled();
68
+ });
69
+ });
@@ -22,6 +22,147 @@ const setup = (
22
22
  };
23
23
 
24
24
  describe('FormDateInput field', () => {
25
+ it.each(['reset', 'setValue'] as const)(
26
+ 'clears stale errors on %s, even when restoring the same value',
27
+ async (method) => {
28
+ const driver = setup({ initialValue: '2026-09-16' });
29
+ const initialText = await driver.tk.getValue();
30
+ await driver.tk.enterText('not-a-date');
31
+ await driver.tk.blur();
32
+ await driver.submit();
33
+ expect(driver.onSubmit).not.toHaveBeenCalled();
34
+
35
+ await driver[method]('2026-09-16');
36
+ expect(await driver.tk.getValue()).toBe(initialText);
37
+ expect(await driver.tk.hasError()).toBe(false);
38
+ await driver.submit();
39
+ expect(driver.onSubmit).toHaveBeenCalledTimes(1);
40
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBe(
41
+ '2026-09-16',
42
+ );
43
+ },
44
+ );
45
+
46
+ it.each(['reset', 'setValue'] as const)(
47
+ 'shows and submits an externally replaced date via %s',
48
+ async (method) => {
49
+ const driver = setup({ initialValue: '2026-09-16' });
50
+ const initialText = await driver.tk.getValue();
51
+ await driver.tk.enterText('not-a-date');
52
+ await driver.tk.blur();
53
+
54
+ await driver[method]('2026-09-18');
55
+ expect(await driver.tk.getValue()).not.toBe(initialText);
56
+ expect(await driver.tk.getValue()).not.toBe('not-a-date');
57
+ expect(await driver.tk.hasError()).toBe(false);
58
+ await driver.submit();
59
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBe(
60
+ '2026-09-18',
61
+ );
62
+ },
63
+ );
64
+
65
+ it('keeps the error when another field is replaced or removed', async () => {
66
+ const driver = setup({ initialValue: '2026-09-16' });
67
+ await driver.tk.enterText('not-a-date');
68
+ await driver.tk.blur();
69
+ await driver.setValue('2026-09-18', 'anotherField');
70
+ await driver.unregister('anotherField');
71
+ await driver.submit();
72
+ expect(driver.onSubmit).not.toHaveBeenCalled();
73
+ });
74
+
75
+ it.each([false, true])(
76
+ 'resets invalid input to an empty value (required=%s)',
77
+ async (required) => {
78
+ const driver = setup({
79
+ field: makeField({ type: 'DATE', validation: { required } }),
80
+ });
81
+ await driver.tk.enterText('not-a-date');
82
+ await driver.tk.blur();
83
+ await driver.reset(null);
84
+ expect(await driver.tk.getValue()).toBe('');
85
+ await driver.submit();
86
+ expect(driver.onSubmit).toHaveBeenCalledTimes(required ? 0 : 1);
87
+ if (!required) {
88
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBeNull();
89
+ }
90
+ },
91
+ );
92
+
93
+ it.each([false, true])(
94
+ 'blocks submit for invalid text over a valid date (required=%s)',
95
+ async (required) => {
96
+ const driver = setup({
97
+ field: makeField({ type: 'DATE', validation: { required } }),
98
+ initialValue: '2026-09-16',
99
+ });
100
+
101
+ await driver.tk.enterText('not-a-date');
102
+ await driver.tk.blur();
103
+ expect(await driver.tk.hasError()).toBe(true);
104
+
105
+ await driver.submit();
106
+
107
+ expect(driver.onSubmit).not.toHaveBeenCalled();
108
+ },
109
+ );
110
+
111
+ it('allows submit after correcting an invalid date', async () => {
112
+ const driver = setup({ initialValue: '2026-09-16' });
113
+ await driver.tk.enterText('not-a-date');
114
+ await driver.tk.blur();
115
+ await driver.submit();
116
+ expect(driver.onSubmit).not.toHaveBeenCalled();
117
+
118
+ await driver.tk.enterText('09/17/2026');
119
+ await driver.tk.blur();
120
+ await driver.submit();
121
+
122
+ expect(await driver.tk.hasError()).toBe(false);
123
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBe(
124
+ '2026-09-17',
125
+ );
126
+ });
127
+
128
+ it.each([false, true])(
129
+ 'handles clearing an invalid date (required=%s)',
130
+ async (required) => {
131
+ const driver = setup({
132
+ field: makeField({ type: 'DATE', validation: { required } }),
133
+ initialValue: '2026-09-16',
134
+ });
135
+ await driver.tk.enterText('not-a-date');
136
+ await driver.tk.blur();
137
+ await driver.tk.enterText('');
138
+ await driver.tk.blur();
139
+ await driver.submit();
140
+
141
+ expect(await driver.tk.hasError()).toBe(required);
142
+ expect(driver.onSubmit).toHaveBeenCalledTimes(required ? 0 : 1);
143
+ if (!required) {
144
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBeNull();
145
+ }
146
+ },
147
+ );
148
+
149
+ it('allows submit after replacing invalid text with a calendar selection', async () => {
150
+ const driver = setup({ initialValue: '2026-09-16' });
151
+ await driver.tk.enterText('not-a-date');
152
+ await driver.tk.blur();
153
+ await driver.submit();
154
+ expect(driver.onSubmit).not.toHaveBeenCalled();
155
+
156
+ await driver.tk.calendarPopover.open();
157
+ await driver.tk.selectDate(new Date(2026, 8, 17));
158
+ await driver.submit();
159
+
160
+ expect(await driver.tk.hasError()).toBe(false);
161
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBe(
162
+ '2026-09-17',
163
+ );
164
+ });
165
+
25
166
  it('renders the field displayName as the label', async () => {
26
167
  const driver = setup();
27
168
 
@@ -22,6 +22,200 @@ const setup = (
22
22
  };
23
23
 
24
24
  describe('FormDateTime field', () => {
25
+ it.each(['reset', 'setValue'] as const)(
26
+ 'clears stale errors on %s, even when restoring the same value',
27
+ async (method) => {
28
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
29
+ const initialText = await driver.tk.getDateText();
30
+ await driver.tk.enterTimeText('not-a-time');
31
+ await driver.tk.blurTime();
32
+ await driver.tk.enterDateText('not-a-date');
33
+ await driver.tk.blurDate();
34
+ await driver.submit();
35
+ expect(driver.onSubmit).not.toHaveBeenCalled();
36
+
37
+ await driver[method]('2026-09-16T12:00:00.000Z');
38
+ expect(await driver.tk.getDateText()).toBe(initialText);
39
+ expect(await driver.tk.dateHasError()).toBe(false);
40
+ expect(await driver.tk.timeHasError()).toBe(false);
41
+ await driver.submit();
42
+ expect(driver.onSubmit).toHaveBeenCalledTimes(1);
43
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBe(
44
+ '2026-09-16T12:00:00.000Z',
45
+ );
46
+ },
47
+ );
48
+
49
+ it.each(['reset', 'setValue'] as const)(
50
+ 'shows and submits an externally replaced date via %s',
51
+ async (method) => {
52
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
53
+ const initialText = await driver.tk.getDateText();
54
+ await driver.tk.enterTimeText('not-a-time');
55
+ await driver.tk.blurTime();
56
+ await driver.tk.enterDateText('not-a-date');
57
+ await driver.tk.blurDate();
58
+
59
+ await driver[method]('2026-09-18T12:00:00.000Z');
60
+ expect(await driver.tk.getDateText()).not.toBe(initialText);
61
+ expect(await driver.tk.getDateText()).not.toBe('not-a-date');
62
+ expect(await driver.tk.dateHasError()).toBe(false);
63
+ expect(await driver.tk.timeHasError()).toBe(false);
64
+ await driver.submit();
65
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBe(
66
+ '2026-09-18T12:00:00.000Z',
67
+ );
68
+ },
69
+ );
70
+
71
+ it('keeps the error when another field is replaced or removed', async () => {
72
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
73
+ await driver.tk.enterDateText('not-a-date');
74
+ await driver.tk.blurDate();
75
+ await driver.setValue('2026-09-18T12:00:00.000Z', 'anotherField');
76
+ await driver.unregister('anotherField');
77
+ await driver.submit();
78
+ expect(driver.onSubmit).not.toHaveBeenCalled();
79
+ });
80
+
81
+ it.each([false, true])(
82
+ 'resets invalid input to an empty value (required=%s)',
83
+ async (required) => {
84
+ const driver = setup({
85
+ field: makeField({ type: 'DATETIME', validation: { required } }),
86
+ });
87
+ await driver.tk.enterDateText('not-a-date');
88
+ await driver.tk.blurDate();
89
+ await driver.reset(null);
90
+ expect(await driver.tk.getDateText()).toBe('');
91
+ await driver.submit();
92
+ expect(driver.onSubmit).toHaveBeenCalledTimes(required ? 0 : 1);
93
+ if (!required) {
94
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBeNull();
95
+ }
96
+ },
97
+ );
98
+
99
+ it.each([false, true])(
100
+ 'blocks submit for an invalid date (required=%s)',
101
+ async (required) => {
102
+ const driver = setup({
103
+ field: makeField({ type: 'DATETIME', validation: { required } }),
104
+ initialValue: '2026-09-16T12:00:00.000Z',
105
+ });
106
+ await driver.tk.enterDateText('not-a-date');
107
+ await driver.tk.blurDate();
108
+ expect(await driver.tk.dateHasError()).toBe(true);
109
+ expect(await driver.tk.timeHasError()).toBe(false);
110
+
111
+ await driver.submit();
112
+
113
+ expect(driver.onSubmit).not.toHaveBeenCalled();
114
+ expect(await driver.tk.timeHasError()).toBe(false);
115
+ },
116
+ );
117
+
118
+ it('allows submit after correcting an invalid date', async () => {
119
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
120
+ await driver.tk.enterDateText('not-a-date');
121
+ await driver.tk.blurDate();
122
+ await driver.submit();
123
+ expect(driver.onSubmit).not.toHaveBeenCalled();
124
+
125
+ await driver.tk.enterDateText('09/17/2026');
126
+ await driver.tk.blurDate();
127
+ await driver.submit();
128
+
129
+ expect(await driver.tk.dateHasError()).toBe(false);
130
+ expect(driver.onSubmit).toHaveBeenCalledTimes(1);
131
+ expect(
132
+ new Date(driver.onSubmit.mock.calls[0][0][driver.field.id]).getDate(),
133
+ ).toBe(17);
134
+ });
135
+
136
+ it('blocks an invalid time and allows submit after correcting it', async () => {
137
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
138
+ await driver.tk.enterTimeText('not-a-time');
139
+ await driver.tk.blurTime();
140
+ expect(await driver.tk.timeHasError()).toBe(true);
141
+ expect(await driver.tk.dateHasError()).toBe(false);
142
+ await driver.submit();
143
+ expect(driver.onSubmit).not.toHaveBeenCalled();
144
+ expect(await driver.tk.dateHasError()).toBe(false);
145
+
146
+ await driver.tk.enterTimeText('14:30');
147
+ await driver.tk.blurTime();
148
+ await driver.submit();
149
+
150
+ expect(await driver.tk.timeHasError()).toBe(false);
151
+ expect(driver.onSubmit).toHaveBeenCalledTimes(1);
152
+ });
153
+
154
+ it('does not clear an invalid date when the time changes', async () => {
155
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
156
+ await driver.tk.enterDateText('not-a-date');
157
+ await driver.tk.blurDate();
158
+ await driver.tk.enterTimeText('14:30');
159
+ await driver.tk.blurTime();
160
+
161
+ expect(await driver.tk.dateHasError()).toBe(true);
162
+ await driver.submit();
163
+ expect(driver.onSubmit).not.toHaveBeenCalled();
164
+ });
165
+
166
+ it('shows each input’s own message when both inputs are invalid', async () => {
167
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
168
+ await driver.tk.enterDateText('not-a-date');
169
+ await driver.tk.blurDate();
170
+ await driver.tk.enterTimeText('not-a-time');
171
+ await driver.tk.blurTime();
172
+ await driver.submit();
173
+
174
+ expect(driver.onSubmit).not.toHaveBeenCalled();
175
+ expect(await driver.tk.getDateErrorMessage()).toContain(
176
+ 'cairo.customFields.fieldType.date.invalid.value',
177
+ );
178
+ expect(await driver.tk.getTimeErrorMessage()).toBe(
179
+ 'CMS.formTime.invalidMessage',
180
+ );
181
+ });
182
+
183
+ it('does not clear an invalid time when the date changes', async () => {
184
+ const driver = setup({ initialValue: '2026-09-16T12:00:00.000Z' });
185
+ await driver.tk.enterTimeText('not-a-time');
186
+ await driver.tk.blurTime();
187
+ await driver.tk.enterDateText('09/17/2026');
188
+ await driver.tk.blurDate();
189
+
190
+ expect(await driver.tk.timeHasError()).toBe(true);
191
+ await driver.submit();
192
+ expect(driver.onSubmit).not.toHaveBeenCalled();
193
+ });
194
+
195
+ it.each([false, true])(
196
+ 'handles clearing an invalid date and time (required=%s)',
197
+ async (required) => {
198
+ const driver = setup({
199
+ field: makeField({ type: 'DATETIME', validation: { required } }),
200
+ initialValue: '2026-09-16T12:00:00.000Z',
201
+ });
202
+ await driver.tk.enterDateText('not-a-date');
203
+ await driver.tk.blurDate();
204
+ await driver.tk.enterTimeText('');
205
+ await driver.tk.blurTime();
206
+ await driver.tk.enterDateText('');
207
+ await driver.tk.blurDate();
208
+ await driver.submit();
209
+
210
+ expect(driver.onSubmit).toHaveBeenCalledTimes(required ? 0 : 1);
211
+ if (!required) {
212
+ expect(driver.onSubmit.mock.calls[0][0][driver.field.id]).toBeNull();
213
+ expect(await driver.tk.dateHasError()).toBe(false);
214
+ expect(await driver.tk.timeHasError()).toBe(false);
215
+ }
216
+ },
217
+ );
218
+
25
219
  it('renders the field displayName as the label', async () => {
26
220
  const driver = setup();
27
221
 
@@ -61,6 +61,33 @@ describe('FormShortText field', () => {
61
61
  expect(await driver.tk.getCharCountLeft()).toBe(7);
62
62
  });
63
63
 
64
+ it.each([undefined, null])(
65
+ 'shows the full character allowance when the initial value is %p',
66
+ async (initialValue) => {
67
+ const driver = new FormFieldDriver({
68
+ Component: FormShortText,
69
+ UniDriverFactory: FormShortTextDriver,
70
+ dataHook: (f) => `short-text-field-${f.id}`,
71
+ field: makeField({
72
+ validation: { required: true, stringLengthRange: { maxLength: 10 } },
73
+ }),
74
+ initialValue: initialValue as unknown as string,
75
+ });
76
+ driver.render();
77
+
78
+ expect(await driver.tk.getValue()).toBe('');
79
+ expect(await driver.tk.getCharCountLeft()).toBe(10);
80
+
81
+ await driver.tk.enterText('abc');
82
+
83
+ expect(await driver.tk.getCharCountLeft()).toBe(7);
84
+
85
+ await driver.tk.enterText('');
86
+
87
+ expect(await driver.tk.getCharCountLeft()).toBe(10);
88
+ },
89
+ );
90
+
64
91
  it('marks the field as required when validation.required is true', async () => {
65
92
  const driver = setup({
66
93
  field: makeField({ validation: { required: true } }),
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { act, fireEvent, render, RenderResult } from '@testing-library/react';
3
3
  import Chance from 'chance';
4
4
  import { useForm } from '@wix/bex-core/form';
5
- import type { Control, FieldValues } from '@wix/bex-core/form';
5
+ import type { Control, FieldValues, UseFormReturn } from '@wix/bex-core/form';
6
6
  import type { Field } from '@wix/bex-core';
7
7
  import { UniDriver } from '@wix/wix-ui-test-utils/unidriver';
8
8
  import type { BaseUniDriver } from '@wix/wix-ui-test-utils/base-driver';
@@ -12,7 +12,6 @@ import { PatternsFieldsTestProvider } from '../testkit/patterns-fields-test-prov
12
12
  import type { BaseInputProps } from '../types/base-input';
13
13
 
14
14
  const chance = new Chance();
15
- const noop = () => {};
16
15
  const SUBMIT_HOOK = 'form-field-driver-submit';
17
16
 
18
17
  type UniDriverFactory<U> = (
@@ -31,9 +30,11 @@ export interface FormFieldDriverOptions<U extends BaseUniDriver, T> {
31
30
 
32
31
  export class FormFieldDriver<U extends BaseUniDriver, T> {
33
32
  private _renderResult?: RenderResult;
33
+ private form?: UseFormReturn<FieldValues>;
34
34
  readonly field: Field;
35
35
  readonly initialValue: T;
36
36
  readonly onChange = jest.fn<void, [T]>();
37
+ readonly onSubmit = jest.fn<void, [FieldValues]>();
37
38
  private readonly opts: FormFieldDriverOptions<U, T>;
38
39
  private readonly _dataHook: string;
39
40
 
@@ -67,6 +68,24 @@ export class FormFieldDriver<U extends BaseUniDriver, T> {
67
68
  });
68
69
  }
69
70
 
71
+ async reset(value: T): Promise<void> {
72
+ await act(async () => {
73
+ this.form!.reset({ [this.field.id]: value });
74
+ });
75
+ }
76
+
77
+ async setValue(value: T, name = this.field.id): Promise<void> {
78
+ await act(async () => {
79
+ this.form!.setValue(name, value, { shouldValidate: true });
80
+ });
81
+ }
82
+
83
+ async unregister(name: string): Promise<void> {
84
+ await act(async () => {
85
+ this.form!.unregister(name);
86
+ });
87
+ }
88
+
70
89
  render() {
71
90
  const { Component } = this.opts;
72
91
  const { field, initialValue, _dataHook: dataHook, onChange } = this;
@@ -74,6 +93,10 @@ export class FormFieldDriver<U extends BaseUniDriver, T> {
74
93
  <TestForm
75
94
  field={field}
76
95
  initialValue={initialValue}
96
+ onSubmit={this.onSubmit}
97
+ onFormReady={(form) => {
98
+ this.form = form;
99
+ }}
77
100
  renderField={(control) => (
78
101
  <Component
79
102
  field={field}
@@ -93,20 +116,25 @@ export class FormFieldDriver<U extends BaseUniDriver, T> {
93
116
  interface TestFormProps<T> {
94
117
  field: Field;
95
118
  initialValue: T;
119
+ onSubmit: (values: FieldValues) => void;
120
+ onFormReady: (form: UseFormReturn<FieldValues>) => void;
96
121
  renderField: (control: Control<FieldValues>) => React.ReactElement;
97
122
  }
98
123
 
99
124
  const TestForm = <T,>({
100
125
  field,
101
126
  initialValue,
127
+ onSubmit,
128
+ onFormReady,
102
129
  renderField,
103
130
  }: TestFormProps<T>) => {
104
131
  const methods = useForm<FieldValues>({
105
132
  mode: 'onChange',
106
133
  defaultValues: { [field.id]: initialValue },
107
134
  });
135
+ onFormReady(methods);
108
136
  return (
109
- <form onSubmit={methods.handleSubmit(noop)}>
137
+ <form onSubmit={methods.handleSubmit(onSubmit)}>
110
138
  {renderField(methods.control)}
111
139
  <button type="submit" data-hook={SUBMIT_HOOK} />
112
140
  </form>