@sealcode/sealgen 0.18.10 → 0.19.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 (378) hide show
  1. package/.eslintrc.cjs +7 -2
  2. package/.xunit +74 -69
  3. package/@types/add-crud.d.sync-conflict-20250918-184311-TFDLWFG.ts +1 -0
  4. package/@types/builders/colors-builder.d.sync-conflict-20250918-184323-TFDLWFG.ts +10 -0
  5. package/@types/builders/colors-builder.d.ts +1 -1
  6. package/@types/builders/fonts-builder.d.sync-conflict-20250918-184322-TFDLWFG.ts +7 -0
  7. package/@types/builders/fonts-builder.d.ts +1 -1
  8. package/@types/controllers/table-add-button.d.ts +6 -0
  9. package/@types/controllers/table-add-button.stimulus.d.ts +6 -0
  10. package/@types/crud-field-snippets.d.sync-conflict-20250918-184323-TFDLWFG.ts +1 -0
  11. package/@types/crud-field-snippets.d.ts +1 -3
  12. package/@types/forms/controls/array.d.sync-conflict-20250918-184306-TFDLWFG.ts +33 -0
  13. package/@types/forms/controls/array.d.ts +1 -3
  14. package/@types/forms/controls/array.sync-conflict-20250918-222045-TFDLWFG.d.ts +33 -0
  15. package/@types/forms/controls/autocomplete.d.sync-conflict-20250918-222042-TFDLWFG.ts +22 -0
  16. package/@types/forms/controls/autocomplete.d.ts +1 -1
  17. package/@types/forms/controls/checkbox-group.d.sync-conflict-20250918-184319-TFDLWFG.ts +21 -0
  18. package/@types/forms/controls/checkbox-group.d.ts +3 -3
  19. package/@types/forms/controls/checkboxed-list-input.d.sync-conflict-20250918-184323-TFDLWFG.ts +21 -0
  20. package/@types/forms/controls/checkboxed-list-input.d.ts +3 -3
  21. package/@types/forms/controls/controls.d.ts +2 -2
  22. package/@types/forms/controls/derived-frame.d.sync-conflict-20250918-184314-TFDLWFG.ts +19 -0
  23. package/@types/forms/controls/derived-frame.d.ts +0 -2
  24. package/@types/forms/controls/dropdown.d.sync-conflict-20250918-222044-TFDLWFG.ts +30 -0
  25. package/@types/forms/controls/dropdown.d.ts +1 -1
  26. package/@types/forms/controls/file.d.sync-conflict-20250918-222045-TFDLWFG.ts +13 -0
  27. package/@types/forms/controls/file.d.ts +1 -2
  28. package/@types/forms/controls/form-control.d.sync-conflict-20250918-184322-TFDLWFG.ts +19 -0
  29. package/@types/forms/controls/form-control.d.sync-conflict-20250918-222046-TFDLWFG.ts +19 -0
  30. package/@types/forms/controls/form-control.d.ts +7 -4
  31. package/@types/forms/controls/image.d.ts +19 -0
  32. package/@types/forms/controls/image.test.d.ts +1 -0
  33. package/@types/forms/controls/multiple-files.d.sync-conflict-20250918-184318-TFDLWFG.ts +42 -0
  34. package/@types/forms/controls/multiple-files.d.ts +3 -1
  35. package/@types/forms/controls/multiple-images.d.ts +19 -0
  36. package/@types/forms/controls/number.d.sync-conflict-20250918-222046-TFDLWFG.ts +13 -0
  37. package/@types/forms/controls/number.d.ts +1 -1
  38. package/@types/forms/controls/photo.d.sync-conflict-20250918-184321-TFDLWFG.ts +19 -0
  39. package/@types/forms/controls/photo.d.ts +3 -5
  40. package/@types/forms/controls/simple-input.d.sync-conflict-20250918-184310-TFDLWFG.ts +33 -0
  41. package/@types/forms/controls/simple-input.d.sync-conflict-20250918-222042-TFDLWFG.ts +33 -0
  42. package/@types/forms/controls/simple-input.d.ts +5 -4
  43. package/@types/forms/controls/simple-input.sync-conflict-20250918-222045-TFDLWFG.d.ts +33 -0
  44. package/@types/forms/controls/single-reference.d.ts +3 -2
  45. package/@types/forms/controls/table.d.sync-conflict-20250918-184302-TFDLWFG.ts +39 -0
  46. package/@types/forms/controls/table.d.ts +8 -3
  47. package/@types/forms/controls/table.sync-conflict-20250918-222042-TFDLWFG.d.ts +39 -0
  48. package/@types/forms/controls/textarea.d.sync-conflict-20250918-222045-TFDLWFG.ts +25 -0
  49. package/@types/forms/controls/textarea.d.ts +3 -3
  50. package/@types/forms/fields/boolean.d.sync-conflict-20250918-184325-TFDLWFG.ts +22 -0
  51. package/@types/forms/fields/boolean.d.ts +6 -1
  52. package/@types/forms/fields/boolean.sync-conflict-20250918-222042-TFDLWFG.d.ts +22 -0
  53. package/@types/forms/fields/checkboxed-list.d.sync-conflict-20250918-184325-TFDLWFG.ts +23 -0
  54. package/@types/forms/fields/checkboxed-list.d.ts +3 -1
  55. package/@types/forms/fields/collection-field.d.sync-conflict-20250918-184319-TFDLWFG.ts +22 -0
  56. package/@types/forms/fields/collection-field.d.sync-conflict-20250918-222047-TFDLWFG.ts +22 -0
  57. package/@types/forms/fields/collection-field.d.ts +8 -1
  58. package/@types/forms/fields/color.d.ts +4 -0
  59. package/@types/forms/fields/coordinates.d.sync-conflict-20250918-222044-TFDLWFG.ts +14 -0
  60. package/@types/forms/fields/coordinates.d.ts +14 -0
  61. package/@types/forms/fields/date.d.ts +13 -0
  62. package/@types/forms/fields/datetime.d.sync-conflict-20250918-222050-TFDLWFG.ts +4 -0
  63. package/@types/forms/fields/datetime.d.ts +14 -0
  64. package/@types/forms/fields/deep-reverse-single-reference-list.d.ts +24 -0
  65. package/@types/forms/fields/deep-reverse-single-reference-table.d.ts +16 -0
  66. package/@types/forms/fields/email.d.sync-conflict-20250918-184303-TFDLWFG.ts +8 -0
  67. package/@types/forms/fields/email.d.ts +3 -0
  68. package/@types/forms/fields/enum-multiple-sealious.d.ts +16 -0
  69. package/@types/forms/fields/enum-multiple-sealious.sync-conflict-20250918-222047-TFDLWFG.d.ts +16 -0
  70. package/@types/forms/fields/field.d.sync-conflict-20250918-184306-TFDLWFG.ts +70 -0
  71. package/@types/forms/fields/field.d.ts +37 -5
  72. package/@types/forms/fields/fields.d.sync-conflict-20250918-184314-TFDLWFG.ts +29 -0
  73. package/@types/forms/fields/fields.d.ts +23 -8
  74. package/@types/forms/fields/file.d.sync-conflict-20250918-184310-TFDLWFG.ts +23 -0
  75. package/@types/forms/fields/file.d.sync-conflict-20250918-222046-TFDLWFG.ts +23 -0
  76. package/@types/forms/fields/file.d.ts +11 -5
  77. package/@types/forms/fields/file.sync-conflict-20250918-222049-TFDLWFG.d.ts +23 -0
  78. package/@types/forms/fields/float.d.ts +4 -0
  79. package/@types/forms/fields/get-field-for-sealious.d.sync-conflict-20250918-222046-TFDLWFG.ts +29 -0
  80. package/@types/forms/fields/get-field-for-sealious.d.ts +31 -0
  81. package/@types/forms/fields/get-field-for-sealious.sync-conflict-20250918-222042-TFDLWFG.d.ts +29 -0
  82. package/@types/forms/fields/html.d.ts +6 -0
  83. package/@types/forms/fields/image.d.sync-conflict-20250918-222042-TFDLWFG.ts +5 -0
  84. package/@types/forms/fields/image.d.ts +5 -0
  85. package/@types/forms/fields/int.d.ts +6 -0
  86. package/@types/forms/fields/json.d.ts +13 -0
  87. package/@types/forms/fields/markdown.d.ts +6 -0
  88. package/@types/forms/fields/multiple-files.d.sync-conflict-20250918-184304-TFDLWFG.ts +16 -0
  89. package/@types/forms/fields/multiple-files.d.ts +3 -1
  90. package/@types/forms/fields/number.d.sync-conflict-20250918-184317-TFDLWFG.ts +25 -0
  91. package/@types/forms/fields/number.d.sync-conflict-20250918-222047-TFDLWFG.ts +25 -0
  92. package/@types/forms/fields/number.d.ts +3 -1
  93. package/@types/forms/fields/password.d.ts +6 -0
  94. package/@types/forms/fields/pick-from-list-sealious.d.ts +11 -0
  95. package/@types/forms/fields/pick-from-list.d.sync-conflict-20250918-184322-TFDLWFG.ts +15 -0
  96. package/@types/forms/fields/pick-from-list.d.ts +4 -3
  97. package/@types/forms/fields/proxy-field.d.sync-conflict-20250918-184307-TFDLWFG.ts +15 -0
  98. package/@types/forms/fields/proxy-field.d.ts +3 -1
  99. package/@types/forms/fields/regexp.d.sync-conflict-20250918-184305-TFDLWFG.ts +21 -0
  100. package/@types/forms/fields/regexp.d.sync-conflict-20250918-222045-TFDLWFG.ts +21 -0
  101. package/@types/forms/fields/regexp.d.ts +6 -1
  102. package/@types/forms/fields/regexp.sync-conflict-20250918-222047-TFDLWFG.d.ts +21 -0
  103. package/@types/forms/fields/simple-form-field.d.sync-conflict-20250918-184309-TFDLWFG.ts +29 -0
  104. package/@types/forms/fields/simple-form-field.d.sync-conflict-20250918-222044-TFDLWFG.ts +29 -0
  105. package/@types/forms/fields/simple-form-field.d.ts +23 -3
  106. package/@types/forms/fields/simple-form-field.sync-conflict-20250918-222049-TFDLWFG.d.ts +29 -0
  107. package/@types/forms/fields/single-reference.d.ts +19 -0
  108. package/@types/forms/fields/single-reference.sync-conflict-20250918-222043-TFDLWFG.d.ts +10 -0
  109. package/@types/forms/fields/structured-array.d.sync-conflict-20250918-184302-TFDLWFG.ts +27 -0
  110. package/@types/forms/fields/structured-array.d.sync-conflict-20250918-222049-TFDLWFG.ts +27 -0
  111. package/@types/forms/fields/structured-array.d.ts +19 -10
  112. package/@types/forms/fields/structured-array.sync-conflict-20250918-222047-TFDLWFG.d.ts +27 -0
  113. package/@types/forms/fields/table.d.sync-conflict-20250918-184303-TFDLWFG.ts +16 -0
  114. package/@types/forms/fields/table.d.ts +3 -0
  115. package/@types/forms/fields/text.d.ts +6 -0
  116. package/@types/forms/fields/url.d.ts +6 -0
  117. package/@types/forms/form-types.d.sync-conflict-20250918-222045-TFDLWFG.ts +26 -0
  118. package/@types/forms/form-types.d.ts +2 -0
  119. package/@types/forms/form.d.sync-conflict-20250918-184315-TFDLWFG.ts +32 -0
  120. package/@types/forms/form.d.sync-conflict-20250918-222049-TFDLWFG.ts +32 -0
  121. package/@types/forms/form.d.ts +10 -8
  122. package/@types/forms/form.sync-conflict-20250918-222049-TFDLWFG.d.ts +33 -0
  123. package/@types/forms/form.test.d.sync-conflict-20250918-184318-TFDLWFG.ts +6 -0
  124. package/@types/forms/form.test.d.sync-conflict-20250918-222047-TFDLWFG.ts +6 -0
  125. package/@types/forms/form.test.d.ts +2 -2
  126. package/@types/forms/multiform.d.sync-conflict-20250918-184308-TFDLWFG.ts +23 -0
  127. package/@types/forms/multiform.d.ts +1 -2
  128. package/@types/forms/multiform.sync-conflict-20250918-222044-TFDLWFG.d.ts +23 -0
  129. package/@types/index.d.sync-conflict-20250918-184316-TFDLWFG.ts +46 -0
  130. package/@types/index.d.ts +2 -2
  131. package/@types/mount.d.sync-conflict-20250918-184320-TFDLWFG.ts +6 -0
  132. package/@types/mount.d.ts +0 -1
  133. package/@types/page/list.d.sync-conflict-20250918-184318-TFDLWFG.ts +48 -0
  134. package/@types/page/list.d.sync-conflict-20250918-222046-TFDLWFG.ts +48 -0
  135. package/@types/page/list.d.ts +2 -2
  136. package/@types/page/list.sync-conflict-20250918-222048-TFDLWFG.d.ts +48 -0
  137. package/@types/page/mountable-with-fields.d.sync-conflict-20250918-184321-TFDLWFG.ts +42 -0
  138. package/@types/page/mountable-with-fields.d.sync-conflict-20250918-222046-TFDLWFG.ts +42 -0
  139. package/@types/page/mountable-with-fields.d.ts +3 -3
  140. package/@types/page/mountable-with-fields.sync-conflict-20250918-222044-TFDLWFG.d.ts +42 -0
  141. package/@types/page/mountable.d.sync-conflict-20250918-184306-TFDLWFG.ts +10 -0
  142. package/@types/page/mountable.d.ts +0 -1
  143. package/@types/page/page.d.sync-conflict-20250918-184320-TFDLWFG.ts +18 -0
  144. package/@types/page/page.d.ts +0 -1
  145. package/@types/page/props-parser.d.sync-conflict-20250918-184305-TFDLWFG.ts +15 -0
  146. package/@types/page/props-parser.d.ts +0 -1
  147. package/@types/page/stateful-page.d.sync-conflict-20250918-184326-TFDLWFG.ts +62 -0
  148. package/@types/page/stateful-page.d.ts +0 -1
  149. package/@types/templates/shared/shared-crud-form-fields.d.sync-conflict-20250918-184306-TFDLWFG.ts +1 -0
  150. package/@types/templates/shared/shared-crud-form-fields.d.ts +0 -67
  151. package/@types/test_utils/test-on-real-app.d.sync-conflict-20250918-184320-TFDLWFG.ts +26 -0
  152. package/@types/test_utils/test-on-real-app.d.ts +0 -1
  153. package/@types/utils/extract-fields-from-collection.d.sync-conflict-20250918-184312-TFDLWFG.ts +18 -0
  154. package/@types/utils/extract-fields-from-collection.d.ts +5 -1
  155. package/@types/utils/extract-fields-from-collection.sync-conflict-20250918-222045-TFDLWFG.d.ts +18 -0
  156. package/@types/utils/wrap-attributes.d.ts +3 -0
  157. package/README.md +5 -0
  158. package/assets/file-icon.svg +5 -0
  159. package/lib/add-crud.js +80 -89
  160. package/lib/add-list-route.test.js +1 -1
  161. package/lib/add-route.js +0 -7
  162. package/lib/build.js +3 -1
  163. package/lib/cli.js +2 -5
  164. package/lib/controllers/table-add-button.stimulus.js +35 -0
  165. package/lib/forms/controls/array.js +20 -16
  166. package/lib/forms/controls/big-radio-group.js +2 -2
  167. package/lib/forms/controls/checkbox-group.js +7 -7
  168. package/lib/forms/controls/checkboxed-list-input.js +9 -2
  169. package/lib/forms/controls/controls.js +2 -2
  170. package/lib/forms/controls/derived-frame.js +5 -1
  171. package/lib/forms/controls/derived.js +1 -1
  172. package/lib/forms/controls/dropdown.js +4 -1
  173. package/lib/forms/controls/editable-collection-subset.js +2 -2
  174. package/lib/forms/controls/file.js +26 -2
  175. package/lib/forms/controls/file.test.js +2 -2
  176. package/lib/forms/controls/hidden-input.js +4 -1
  177. package/lib/forms/controls/{photo.js → image.js} +6 -7
  178. package/lib/forms/controls/{photo.test.js → image.test.js} +6 -21
  179. package/lib/forms/controls/multiple-files.js +10 -1
  180. package/lib/forms/controls/{multiple-photos.js → multiple-images.js} +3 -3
  181. package/lib/forms/controls/simple-input.js +13 -12
  182. package/lib/forms/controls/single-reference.js +4 -0
  183. package/lib/forms/controls/table.js +66 -24
  184. package/lib/forms/controls/textarea.js +4 -2
  185. package/lib/forms/controls/tickable.js +13 -5
  186. package/lib/forms/fields/boolean.js +14 -0
  187. package/lib/forms/fields/checkboxed-list.js +4 -0
  188. package/lib/forms/fields/collection-field.js +9 -0
  189. package/lib/forms/fields/color.js +10 -0
  190. package/lib/forms/fields/coordinates.js +49 -0
  191. package/lib/forms/fields/date.js +34 -0
  192. package/lib/forms/fields/datetime.js +46 -0
  193. package/lib/forms/fields/deep-reverse-single-reference-list.js +81 -0
  194. package/lib/forms/fields/deep-reverse-single-reference-table.js +122 -0
  195. package/lib/forms/fields/email.js +7 -0
  196. package/lib/forms/fields/enum-multiple-sealious.js +32 -0
  197. package/lib/forms/fields/field.js +32 -4
  198. package/lib/forms/fields/field.test.js +5 -5
  199. package/lib/forms/fields/fields.js +23 -8
  200. package/lib/forms/fields/file.js +33 -9
  201. package/lib/forms/fields/file.test.js +4 -16
  202. package/lib/forms/fields/float.js +10 -0
  203. package/lib/forms/fields/get-field-for-sealious.js +213 -0
  204. package/lib/forms/fields/html.js +14 -0
  205. package/lib/forms/fields/image.js +13 -0
  206. package/lib/forms/fields/int.js +23 -0
  207. package/lib/forms/fields/json.js +31 -0
  208. package/lib/forms/fields/markdown.js +14 -0
  209. package/lib/forms/fields/multiple-files.js +4 -0
  210. package/lib/forms/fields/number.js +6 -0
  211. package/lib/forms/fields/password.js +13 -0
  212. package/lib/forms/fields/pick-from-list-sealious.js +17 -0
  213. package/lib/forms/fields/pick-from-list.js +6 -2
  214. package/lib/forms/fields/proxy-field.js +3 -0
  215. package/lib/forms/fields/regexp.js +14 -0
  216. package/lib/forms/fields/simple-form-field.js +60 -2
  217. package/lib/forms/fields/single-reference.js +44 -0
  218. package/lib/forms/fields/structured-array.js +63 -12
  219. package/lib/forms/fields/table.js +28 -1
  220. package/lib/forms/fields/text.js +17 -0
  221. package/lib/forms/fields/url.js +17 -0
  222. package/lib/forms/form.js +30 -13
  223. package/lib/forms/form.test.js +3 -4
  224. package/lib/forms/multiform.js +4 -2
  225. package/lib/forms/multiform.test.js +3 -3
  226. package/lib/generate-stimulus.js +1 -0
  227. package/lib/index.js +1 -0
  228. package/lib/make-hidden-inputs.js +1 -1
  229. package/lib/mount.js +11 -0
  230. package/lib/notifier.js +0 -1
  231. package/lib/page/list.js +15 -8
  232. package/lib/page/mountable-with-fields.js +14 -6
  233. package/lib/page/mountable-with-fields.test.js +1 -1
  234. package/lib/templates/form.js +8 -9
  235. package/lib/templates/multiform.js +4 -4
  236. package/lib/templates/page.js +0 -2
  237. package/lib/templates/shared/collection-create-form.js +28 -40
  238. package/lib/templates/shared/collection-edit-form.js +40 -77
  239. package/lib/templates/shared/collection-list.js +12 -20
  240. package/lib/templates/shared/shared-crud-form-fields.js +27 -95
  241. package/lib/test_utils/test-on-real-app.js +3 -3
  242. package/lib/utils/extract-fields-from-collection.js +60 -20
  243. package/lib/utils/make-slug.js +1 -1
  244. package/lib/utils/wrap-attributes.js +20 -0
  245. package/package.json +4 -3
  246. package/src/add-crud.ts +86 -97
  247. package/src/add-list-route.test.ts +1 -1
  248. package/src/add-route.ts +0 -7
  249. package/src/build.ts +3 -1
  250. package/src/cli.ts +3 -5
  251. package/src/controllers/table-add-button.stimulus.ts +35 -0
  252. package/src/forms/controls/array.ts +23 -20
  253. package/src/forms/controls/autocomplete.ts +1 -1
  254. package/src/forms/controls/big-radio-group.ts +2 -2
  255. package/src/forms/controls/checkbox-group.ts +9 -9
  256. package/src/forms/controls/checkboxed-list-input.ts +27 -15
  257. package/src/forms/controls/controls.ts +2 -2
  258. package/src/forms/controls/derived-frame.ts +5 -1
  259. package/src/forms/controls/derived.ts +1 -1
  260. package/src/forms/controls/dropdown.ts +5 -2
  261. package/src/forms/controls/editable-collection-subset.ts +2 -2
  262. package/src/forms/controls/file.test.ts +4 -2
  263. package/src/forms/controls/file.ts +31 -5
  264. package/src/forms/controls/form-control.ts +7 -2
  265. package/src/forms/controls/hidden-input.ts +4 -1
  266. package/src/forms/controls/{photo.test.ts → image.test.ts} +5 -22
  267. package/src/forms/controls/{photo.ts → image.ts} +3 -5
  268. package/src/forms/controls/multiple-files.ts +18 -1
  269. package/src/forms/controls/{multiple-photos.ts → multiple-images.ts} +1 -1
  270. package/src/forms/controls/number.ts +1 -1
  271. package/src/forms/controls/simple-input.ts +18 -34
  272. package/src/forms/controls/single-reference.ts +10 -2
  273. package/src/forms/controls/table.ts +90 -31
  274. package/src/forms/controls/textarea.ts +6 -4
  275. package/src/forms/controls/tickable.ts +13 -5
  276. package/src/forms/fields/boolean.ts +23 -1
  277. package/src/forms/fields/checkboxed-list.ts +11 -2
  278. package/src/forms/fields/collection-field.ts +16 -1
  279. package/src/forms/fields/color.ts +9 -0
  280. package/src/forms/fields/coordinates.ts +66 -0
  281. package/src/forms/fields/date.ts +50 -0
  282. package/src/forms/fields/datetime.ts +66 -0
  283. package/src/forms/fields/deep-reverse-single-reference-list.ts +136 -0
  284. package/src/forms/fields/deep-reverse-single-reference-table.ts +213 -0
  285. package/src/forms/fields/email.ts +9 -0
  286. package/src/forms/fields/enum-multiple-sealious.ts +48 -0
  287. package/src/forms/fields/field.test.ts +5 -5
  288. package/src/forms/fields/field.ts +94 -8
  289. package/src/forms/fields/fields.ts +23 -8
  290. package/src/forms/fields/file.test.ts +4 -16
  291. package/src/forms/fields/file.ts +43 -15
  292. package/src/forms/fields/float.ts +9 -0
  293. package/src/forms/fields/get-field-for-sealious.ts +304 -0
  294. package/src/forms/fields/html.ts +15 -0
  295. package/src/forms/fields/image.ts +12 -0
  296. package/src/forms/fields/int.ts +25 -0
  297. package/src/forms/fields/json.ts +48 -0
  298. package/src/forms/fields/markdown.ts +15 -0
  299. package/src/forms/fields/multiple-files.ts +10 -1
  300. package/src/forms/fields/number.ts +8 -1
  301. package/src/forms/fields/password.ts +17 -0
  302. package/src/forms/fields/pick-from-list-sealious.ts +22 -0
  303. package/src/forms/fields/pick-from-list.ts +7 -3
  304. package/src/forms/fields/proxy-field.ts +6 -1
  305. package/src/forms/fields/regexp.ts +27 -1
  306. package/src/forms/fields/simple-form-field.ts +95 -7
  307. package/src/forms/fields/single-reference.ts +62 -0
  308. package/src/forms/fields/structured-array.ts +115 -18
  309. package/src/forms/fields/table.ts +32 -1
  310. package/src/forms/fields/text.ts +18 -0
  311. package/src/forms/fields/url.ts +20 -0
  312. package/src/forms/form-types.ts +2 -0
  313. package/src/forms/form.test.ts +3 -4
  314. package/src/forms/form.ts +37 -16
  315. package/src/forms/forms.css +0 -85
  316. package/src/forms/multiform.test.ts +3 -3
  317. package/src/forms/multiform.ts +2 -0
  318. package/src/generate-stimulus.ts +1 -0
  319. package/src/index.ts +2 -1
  320. package/src/make-hidden-inputs.ts +1 -1
  321. package/src/mount.ts +14 -0
  322. package/src/notifier.ts +0 -1
  323. package/src/page/list.ts +15 -8
  324. package/src/page/mountable-with-fields.test.ts +1 -1
  325. package/src/page/mountable-with-fields.ts +18 -9
  326. package/src/register-external.ts +1 -1
  327. package/src/templates/form.ts +8 -9
  328. package/src/templates/multiform.ts +4 -4
  329. package/src/templates/page.ts +0 -2
  330. package/src/templates/shared/collection-create-form.ts +30 -66
  331. package/src/templates/shared/collection-edit-form.ts +41 -102
  332. package/src/templates/shared/collection-list.ts +12 -20
  333. package/src/templates/shared/item-delete.ts +0 -1
  334. package/src/templates/shared/shared-crud-form-fields.ts +37 -171
  335. package/src/test_utils/test-on-real-app.ts +4 -3
  336. package/src/utils/extract-fields-from-collection.ts +76 -25
  337. package/src/utils/make-slug.ts +1 -1
  338. package/src/utils/wrap-attributes.ts +17 -0
  339. package/lib/add-verbose-crud.js +0 -119
  340. package/lib/crud-field-snippets.js +0 -52
  341. package/lib/find-css-includes.js +0 -3
  342. package/lib/forms/controls/reverse-single-reference.js +0 -1
  343. package/lib/forms/fields/enum-multiple.js +0 -47
  344. package/lib/forms/fields/enum-multiple.test.js +0 -27
  345. package/lib/forms/fields/enum.js +0 -41
  346. package/lib/forms/fields/enum.test.js +0 -21
  347. package/lib/forms/fields/reverse-single-reference.js +0 -17
  348. package/lib/templates/shared/handlers/boolean.js +0 -14
  349. package/lib/templates/shared/handlers/date.js +0 -8
  350. package/lib/templates/shared/handlers/deep-reverse-single-reference.js +0 -209
  351. package/lib/templates/shared/handlers/default.js +0 -49
  352. package/lib/templates/shared/handlers/enum.js +0 -19
  353. package/lib/templates/shared/handlers/file.js +0 -23
  354. package/lib/templates/shared/handlers/image.js +0 -32
  355. package/lib/templates/shared/handlers/int.js +0 -11
  356. package/lib/templates/shared/handlers/jdd.js +0 -10
  357. package/lib/templates/shared/handlers/single-reference.js +0 -12
  358. package/lib/templates/shared/handlers/structured-array.js +0 -33
  359. package/src/add-verbose-crud.ts +0 -138
  360. package/src/crud-field-snippets.ts +0 -57
  361. package/src/find-css-includes.ts +0 -3
  362. package/src/forms/controls/reverse-single-reference.ts +0 -50
  363. package/src/forms/fields/enum-multiple.test.ts +0 -31
  364. package/src/forms/fields/enum-multiple.ts +0 -62
  365. package/src/forms/fields/enum.test.ts +0 -25
  366. package/src/forms/fields/enum.ts +0 -56
  367. package/src/forms/fields/reverse-single-reference.ts +0 -20
  368. package/src/templates/shared/handlers/boolean.ts +0 -18
  369. package/src/templates/shared/handlers/date.ts +0 -12
  370. package/src/templates/shared/handlers/deep-reverse-single-reference.ts +0 -244
  371. package/src/templates/shared/handlers/default.ts +0 -64
  372. package/src/templates/shared/handlers/enum.ts +0 -23
  373. package/src/templates/shared/handlers/file.ts +0 -27
  374. package/src/templates/shared/handlers/image.ts +0 -45
  375. package/src/templates/shared/handlers/int.ts +0 -15
  376. package/src/templates/shared/handlers/jdd.ts +0 -14
  377. package/src/templates/shared/handlers/single-reference.ts +0 -16
  378. package/src/templates/shared/handlers/structured-array.ts +0 -42
@@ -2,11 +2,37 @@ import { FormDataValue } from "../form-types.js";
2
2
  import { Context } from "koa";
3
3
  import { predicates } from "@sealcode/ts-predicates";
4
4
  import { FieldParseResult, FormField } from "./field.js";
5
+ import { SimpleInput } from "../controls/simple-input.js";
6
+ import { FormControl } from "../controls/controls.js";
7
+ import { CollectionItem } from "sealious";
8
+ import { FormControlContext } from "../controls/form-control.js";
5
9
 
6
- export class SimpleFormField<Required extends boolean> extends FormField<
7
- Required,
8
- string | null
9
- > {
10
+ export abstract class SimpleFormField<
11
+ Required extends boolean,
12
+ DefaultControl extends FormControl = SimpleInput,
13
+ Parsed = string
14
+ > extends FormField<Required, Parsed, DefaultControl> {
15
+ predicate = predicates.string;
16
+
17
+ constructor(required: Required, public type: string = "text") {
18
+ super(required);
19
+ }
20
+
21
+ async sealiousValueToForm(
22
+ ctx: Context,
23
+ value: unknown
24
+ ): Promise<FormDataValue> {
25
+ if (value === null) {
26
+ return "";
27
+ }
28
+ return String(value) as FormDataValue;
29
+ }
30
+ }
31
+
32
+ export class TextBasedSimpleField<
33
+ Required extends boolean,
34
+ DefaultControl extends FormControl = SimpleInput
35
+ > extends SimpleFormField<Required, DefaultControl, string | null> {
10
36
  async parse(
11
37
  _: Context,
12
38
  raw_value: FormDataValue
@@ -18,13 +44,75 @@ export class SimpleFormField<Required extends boolean> extends FormField<
18
44
  };
19
45
  }
20
46
 
21
- predicate = predicates.string;
47
+ async getSealiousCreateValue(
48
+ fctx: FormControlContext
49
+ ): Promise<string | null> {
50
+ const { parsed } = await this.getParsedValue(
51
+ fctx.ctx,
52
+ fctx.data.raw_values
53
+ );
54
+ return parsed || "";
55
+ }
56
+
57
+ async postSealiousCreate(
58
+ ctx: Context,
59
+ created_item: CollectionItem<any>
60
+ ): Promise<void> {}
61
+
62
+ async postSealiousEdit(
63
+ ctx: Context,
64
+ edited_item: CollectionItem<any>
65
+ ): Promise<void> {}
66
+
67
+ getControl(): DefaultControl {
68
+ return new SimpleInput(this, {
69
+ label: this.name,
70
+ type: this.type,
71
+ }) as unknown as DefaultControl;
72
+ }
22
73
 
23
74
  public getEmptyValue(): string {
24
75
  return "";
25
76
  }
77
+ }
26
78
 
27
- constructor(required: Required) {
28
- super(required);
79
+ export class NumberBasedSimpleField<
80
+ Required extends boolean,
81
+ DefaultControl extends FormControl = SimpleInput
82
+ > extends SimpleFormField<Required, DefaultControl, number> {
83
+ async parse(
84
+ _: Context,
85
+ raw_value: FormDataValue
86
+ ): Promise<FieldParseResult<number>> {
87
+ return {
88
+ parsed_value: parseFloat(raw_value as string) || 0,
89
+ parsable: true,
90
+ error: null,
91
+ };
92
+ }
93
+
94
+ async getSealiousCreateValue(
95
+ fctx: FormControlContext
96
+ ): Promise<number | undefined> {
97
+ const { parsed } = await this.getParsedValue(
98
+ fctx.ctx,
99
+ fctx.data.raw_values
100
+ );
101
+ return parsed || 0;
102
+ }
103
+
104
+ async postSealiousCreate(): Promise<void> {}
105
+
106
+ async postSealiousEdit(): Promise<void> {}
107
+
108
+ getControl(): DefaultControl {
109
+ return new SimpleInput(this, {
110
+ label: this.name,
111
+ type: this.type,
112
+ }) as unknown as DefaultControl;
113
+ }
114
+
115
+ public getEmptyValue(): number {
116
+ return 0;
29
117
  }
30
118
  }
@@ -0,0 +1,62 @@
1
+ import { Collection, FieldTypes as SealiousFieldTypes } from "sealious";
2
+ import { CollectionField } from "./collection-field.js";
3
+ import { SingleReferenceDropdown } from "../controls/single-reference.js";
4
+ import { FormControlContext } from "../controls/form-control.js";
5
+ import { Context } from "koa";
6
+ import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
7
+ import { toPascalCase } from "js-convert-case";
8
+
9
+ export class SingleReference<
10
+ TargetCollection extends Collection,
11
+ Required extends boolean,
12
+ F extends SealiousFieldTypes.SingleReference
13
+ > extends CollectionField<F, Required> {
14
+ getControl(): SingleReferenceDropdown<TargetCollection, F, Required> {
15
+ return new SingleReferenceDropdown(this, {
16
+ label: this.name,
17
+ getLabel: (item) => item.id,
18
+ });
19
+ }
20
+
21
+ async getSealiousCreateValue(
22
+ fctx: FormControlContext
23
+ ): Promise<string | undefined> {
24
+ const { parsed } = await this.getParsedValue(
25
+ fctx.ctx,
26
+ fctx.data.raw_values
27
+ );
28
+ return parsed || undefined;
29
+ }
30
+
31
+ async sealiousValueToForm(ctx: Context, value: string | null) {
32
+ return value || undefined;
33
+ }
34
+
35
+ generateImportsForFieldList(field_info: ExtractedFieldInfo) {
36
+ if (!field_info.target) {
37
+ throw new Error("Expected 'target' attribute in field info");
38
+ }
39
+ return [
40
+ {
41
+ what: toPascalCase(field_info.target),
42
+ from: "src/back/collections/collections.js",
43
+ },
44
+ ];
45
+ }
46
+
47
+ generateFieldDeclaration(
48
+ field_info: ExtractedFieldInfo,
49
+ vars: { form_field_types: string; sealious_field: string }
50
+ ): string {
51
+ if (!field_info.target) {
52
+ throw new Error("Expected 'target' attribute in field info");
53
+ }
54
+ return `new ${vars.form_field_types}.${
55
+ this.constructor.name
56
+ }<typeof ${toPascalCase(field_info.target)}, ${String(
57
+ field_info.is_required
58
+ )}, typeof ${vars.sealious_field}>(${String(field_info.is_required)}, ${
59
+ vars.sealious_field
60
+ })`;
61
+ }
62
+ }
@@ -1,27 +1,124 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-return */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-call */
5
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
1
6
  import { Context } from "koa";
2
- import { Field, FieldsetOutput, FieldTypes } from "sealious";
7
+ import {
8
+ Field as SealiousField,
9
+ FieldTypes as SealiousFieldTypes,
10
+ FieldsetInput,
11
+ } from "sealious";
3
12
  import { FormDataValue } from "../form-types.js";
4
- import { FormField } from "./field.js";
13
+ import { Table as TableControl } from "../controls/table.js";
14
+ import {
15
+ sealiousToFormField,
16
+ SealiousToFormField,
17
+ } from "./get-field-for-sealious.js";
18
+ import { FormControl, FormControlContext } from "../controls/form-control.js";
19
+ import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
20
+ import { Table } from "./table.js";
5
21
 
6
- export class StructuredArrayField<
7
- Fields extends Record<string, Field<unknown>>
8
- > extends FormField<
9
- true,
10
- FieldTypes.ArrayStorageInput<FieldsetOutput<Fields>>
11
- > {
12
- constructor(public sealious_field: FieldTypes.StructuredArray<Fields>) {
13
- super(true);
14
- }
22
+ export class StructuredArray<
23
+ SealiousFields extends Record<string, SealiousField<unknown>>
24
+ > extends Table<{
25
+ [name in keyof SealiousFields]: SealiousToFormField<SealiousFields[name]>;
26
+ }> {
27
+ public sealious_field: SealiousFieldTypes.StructuredArray<SealiousFields>;
15
28
 
16
- async parse(_context: Context, value: FormDataValue) {
17
- return {
18
- parsable: <const>true,
19
- error: null,
20
- parsed_value: (value as FieldsetOutput<Fields>) || [],
29
+ constructor(
30
+ sealious_field: SealiousFieldTypes.StructuredArray<SealiousFields>
31
+ ) {
32
+ const columns = Object.fromEntries(
33
+ Object.entries(sealious_field.subfields).map(
34
+ ([key, sealious_field]) => [
35
+ key,
36
+ sealiousToFormField(sealious_field),
37
+ ]
38
+ )
39
+ ) as {
40
+ [name in keyof SealiousFields]: SealiousToFormField<
41
+ SealiousFields[name]
42
+ >;
21
43
  };
44
+ super(columns);
45
+ this.sealious_field = sealious_field;
46
+ }
47
+
48
+ getControl(): TableControl<{
49
+ [name in keyof SealiousFields]: SealiousToFormField<
50
+ SealiousFields[name]
51
+ >;
52
+ }> {
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
55
+ return new TableControl<{
56
+ [name in keyof SealiousFields]: SealiousToFormField<
57
+ SealiousFields[name]
58
+ >;
59
+ }>(this as any, {
60
+ label: this.name,
61
+ subfield_controls: Object.fromEntries(
62
+ Object.entries(this.columns).map(([column_name, subfield]) => [
63
+ column_name as keyof SealiousFields,
64
+ subfield.getControl(),
65
+ ])
66
+ ) as unknown as Record<keyof SealiousFields, FormControl>,
67
+ allow_adding: true,
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
70
+ make_new_row: () => ({} as any),
71
+ });
72
+ }
73
+
74
+ generateFieldDeclaration(
75
+ _field_info: ExtractedFieldInfo,
76
+ vars: { form_field_types: string; sealious_field: string }
77
+ ): string {
78
+ return `new ${vars.form_field_types}.${this.constructor.name}(${vars.sealious_field})`;
79
+ }
80
+
81
+ async getSealiousCreateValue(
82
+ fctx: FormControlContext
83
+ ): Promise<
84
+ SealiousFieldTypes.ArrayStorageInput<FieldsetInput<SealiousFields>>
85
+ > {
86
+ const { parsed } = await this.getParsedValue(
87
+ fctx.ctx,
88
+ fctx.data.raw_values
89
+ );
90
+ return (
91
+ (parsed as SealiousFieldTypes.ArrayStorageInput<
92
+ FieldsetInput<SealiousFields>
93
+ >) || this.getEmptyValue()
94
+ );
22
95
  }
23
96
 
24
- getEmptyValue() {
25
- return [] as FieldTypes.ArrayStorageInput<FieldsetOutput<Fields>>;
97
+ async sealiousValueToForm(
98
+ ctx: Context,
99
+ sealiousValue: Record<string, FormDataValue | null>[] | null
100
+ ): Promise<FormDataValue> {
101
+ return Promise.all(
102
+ (sealiousValue || []).map(async (element) =>
103
+ Object.fromEntries(
104
+ await Promise.all(
105
+ Object.entries(element).map(async ([key, value]) => {
106
+ const form_subfield = this.columns[key];
107
+ if (!form_subfield) {
108
+ return [key, ""];
109
+ }
110
+ return [
111
+ key,
112
+ await form_subfield.sealiousValueToForm(
113
+ ctx,
114
+ value,
115
+ {} as any
116
+ ),
117
+ ];
118
+ })
119
+ )
120
+ )
121
+ )
122
+ );
26
123
  }
27
124
  }
@@ -2,6 +2,11 @@ import { is, predicates } from "@sealcode/ts-predicates";
2
2
  import { Context } from "koa";
3
3
  import { FormDataValue } from "../form-types.js";
4
4
  import { FieldParseResult, FormField } from "./field.js";
5
+ import {
6
+ Table as TableControl,
7
+ TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER,
8
+ } from "../controls/table.js";
9
+ import { FormControl } from "../controls/form-control.js";
5
10
 
6
11
  export type ExtractFormFieldParsed<Field extends FormField> =
7
12
  Field extends FormField<
@@ -34,6 +39,16 @@ export class Table<F extends Record<string, FormField>> extends FormField<
34
39
  return [];
35
40
  }
36
41
 
42
+ setName(name: string) {
43
+ super.setName(name);
44
+ for (const [column_name, field] of Object.entries(this.columns)) {
45
+ field.setName(
46
+ `${this.name}[${TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER}][${column_name}]`
47
+ );
48
+ }
49
+ return this;
50
+ }
51
+
37
52
  async parse(
38
53
  ctx: Context,
39
54
  raw_value: FormDataValue
@@ -51,7 +66,6 @@ export class Table<F extends Record<string, FormField>> extends FormField<
51
66
  const row_data = raw_value[row_number];
52
67
  const parsed_row: Record<string, unknown> = {};
53
68
  if (!is(row_data, predicates.object)) {
54
- console.log("table.ts<fields>:55", this.name);
55
69
  throw new Error(`Expected object, got ${String(row_data)}`);
56
70
  }
57
71
  for (const key in row_data) {
@@ -89,4 +103,21 @@ export class Table<F extends Record<string, FormField>> extends FormField<
89
103
  const ret = { parsed_value: result, parsable: true, error: null };
90
104
  return ret as FieldParseResult<TableFieldParsed<F>>;
91
105
  }
106
+
107
+ getControl(): TableControl<F> {
108
+ return new TableControl<F>(this, {
109
+ label: this.name,
110
+ subfield_controls: Object.fromEntries(
111
+ Object.entries(this.columns).map(([column_name, field]) => [
112
+ column_name as keyof F,
113
+ field.getControl(),
114
+ ])
115
+ ) as Record<keyof F, FormControl>,
116
+ allow_adding: true,
117
+ make_new_row: async () =>
118
+ Object.fromEntries(
119
+ Object.keys(this.columns).map((key) => [key, ""])
120
+ ) as Record<keyof F, string>,
121
+ });
122
+ }
92
123
  }
@@ -0,0 +1,18 @@
1
+ import { FormControlContext } from "../controls/form-control.js";
2
+ import { TextBasedSimpleField } from "./simple-form-field.js";
3
+
4
+ export class Text<
5
+ Required extends boolean
6
+ > extends TextBasedSimpleField<Required> {
7
+ constructor(required: Required) {
8
+ super(required, "text");
9
+ }
10
+
11
+ async getSealiousCreateValue(fctx: FormControlContext): Promise<string> {
12
+ const { parsed } = await this.getParsedValue(
13
+ fctx.ctx,
14
+ fctx.data.raw_values
15
+ );
16
+ return parsed || this.getEmptyValue();
17
+ }
18
+ }
@@ -0,0 +1,20 @@
1
+ import { FormControlContext } from "../controls/form-control.js";
2
+ import { TextBasedSimpleField } from "./simple-form-field.js";
3
+
4
+ export class URLField<
5
+ Required extends boolean
6
+ > extends TextBasedSimpleField<Required> {
7
+ constructor(required: Required) {
8
+ super(required, "text");
9
+ }
10
+
11
+ async getSealiousCreateValue(
12
+ fctx: FormControlContext
13
+ ): Promise<string | null> {
14
+ const { parsed } = await this.getParsedValue(
15
+ fctx.ctx,
16
+ fctx.data.raw_values
17
+ );
18
+ return parsed || null;
19
+ }
20
+ }
@@ -1,6 +1,7 @@
1
1
  import { FilePointer } from "@sealcode/file-manager";
2
2
  import type { FlatTemplatable } from "tempstream";
3
3
  import type { FormField } from "./fields/field.js";
4
+ import { FieldMessages } from "./controls/form-control.js";
4
5
 
5
6
  export type FormDataPrimitive =
6
7
  | string
@@ -28,6 +29,7 @@ export type FormMessage = { type: "info" | "success" | "error"; text: string };
28
29
  export type FormData<Fieldnames extends string = string> = {
29
30
  raw_values: Record<Fieldnames, FormDataValue>;
30
31
  messages: FormMessage[];
32
+ field_messages: FieldMessages<Fieldnames>;
31
33
  };
32
34
 
33
35
  export type FormReaction =
@@ -9,11 +9,11 @@ import { getBrowser } from "../utils/browser-creator.js";
9
9
  import { assertThrowsAsync } from "../utils/utils.js";
10
10
  import { FormDataValue } from "./form-types.js";
11
11
  import getPort from "get-port";
12
- import { SimpleFormField } from "./fields/simple-form-field.js";
12
+ import { TextBasedSimpleField } from "./fields/simple-form-field.js";
13
13
  import { expect as PlaywritghtExpect } from "@playwright/test";
14
14
 
15
15
  const fields = {
16
- text: new Fields.SimpleFormField(true),
16
+ text: new Fields.TextBasedSimpleField(true),
17
17
  };
18
18
 
19
19
  export function form_factory(canAccessFun?: Mountable["canAccess"]): Form<typeof fields, void> {
@@ -139,7 +139,6 @@ describe("form test", () => {
139
139
  async (
140
140
  ctx: Koa.Context
141
141
  ): Promise<{ canAccess: boolean; message: string }> => {
142
- console.log("CAN ACCESS? FALSE");
143
142
  return { canAccess: false, message: "" };
144
143
  }
145
144
  ),
@@ -370,7 +369,7 @@ describe("form test", () => {
370
369
  const router = new Router();
371
370
 
372
371
  const fields = {
373
- title: new SimpleFormField(true),
372
+ title: new TextBasedSimpleField(true),
374
373
  };
375
374
 
376
375
  mount(
package/src/forms/form.ts CHANGED
@@ -2,7 +2,7 @@ import { Context } from "koa";
2
2
  import { randomUUID } from "crypto";
3
3
 
4
4
  import Router from "@koa/router";
5
- import { FlatTemplatable, tempstream } from "tempstream";
5
+ import { tempstream } from "tempstream";
6
6
  import {
7
7
  hasFieldOfType,
8
8
  hasShape,
@@ -22,6 +22,10 @@ import {
22
22
  MountableWithFields,
23
23
  PageErrorMessage,
24
24
  } from "../page/mountable-with-fields.js";
25
+ import { Readable } from "stream";
26
+ import { FormField } from "../index.js";
27
+ import { FieldMessages } from "./controls/form-control.js";
28
+ import { Errors as SealiousErrors } from "sealious";
25
29
 
26
30
  export abstract class Form<
27
31
  F extends Fields,
@@ -43,11 +47,11 @@ export abstract class Form<
43
47
  async renderError(
44
48
  _: Context,
45
49
  error: PageErrorMessage
46
- ): Promise<FlatTemplatable> {
50
+ ): Promise<JSX.Element | Readable> {
47
51
  return tempstream/* HTML */ `<div>${error.message}</div>`;
48
52
  }
49
53
 
50
- makeSubmitButton(): FlatTemplatable {
54
+ makeSubmitButton(): JSX.Element {
51
55
  return /* HTML */ `<input
52
56
  type="submit"
53
57
  value="${this.submitButtonText}"
@@ -60,7 +64,7 @@ export abstract class Form<
60
64
  ctx: Context,
61
65
  data: FormData,
62
66
  show_field_errors: boolean
63
- ): Promise<FlatTemplatable> {
67
+ ): Promise<JSX.Element | Readable> {
64
68
  return tempstream/* HTML */ `<div class="form-container">
65
69
  ${this.makeOpenFormTag(ctx)}
66
70
  ${!this.controls.some((control) => control.role == "messages")
@@ -81,7 +85,7 @@ export abstract class Form<
81
85
  return [];
82
86
  }
83
87
 
84
- public makeOpenFormTag(ctx: Context): FlatTemplatable {
88
+ public makeOpenFormTag(ctx: Context): JSX.Element {
85
89
  return tempstream`<form enctype="multipart/form-data" method="POST" id="${
86
90
  this.form_id
87
91
  }" action="${this.action}" class="${this.makeFormClasses(ctx).then(
@@ -91,14 +95,14 @@ export abstract class Form<
91
95
  }></form><div class="form">`;
92
96
  }
93
97
 
94
- public makeCloseFormTag(): FlatTemplatable {
98
+ public makeCloseFormTag(): JSX.Element {
95
99
  return `</div>`;
96
100
  }
97
101
 
98
102
  public async onValuesInvalid(
99
103
  ctx: Context,
100
104
  form_messages: FormMessage[],
101
- _field_errors: Partial<Record<keyof Fields, string>>
105
+ field_errors: FieldMessages<keyof Fields>
102
106
  ): Promise<FormReaction> {
103
107
  const messages = form_messages.length
104
108
  ? form_messages
@@ -110,8 +114,9 @@ export abstract class Form<
110
114
  {
111
115
  raw_values: await this.extractRawValues(ctx),
112
116
  messages,
117
+ field_messages: field_errors,
113
118
  },
114
- "show_field_errors" && true
119
+ true
115
120
  ),
116
121
  messages,
117
122
  };
@@ -123,12 +128,21 @@ export abstract class Form<
123
128
  error: unknown
124
129
  ): Promise<FormReaction> {
125
130
  let error_message = "Unknown error has occured";
131
+ let field_messages: FieldMessages = {};
126
132
  if (
127
133
  is(error, predicates.object) &&
128
134
  hasShape({ message: predicates.string }, error)
129
135
  ) {
130
136
  error_message = error.message;
131
137
  }
138
+ if (error instanceof SealiousErrors.FieldsError) {
139
+ field_messages = Object.fromEntries(
140
+ Object.entries(error.field_messages).map(([key, value]) => {
141
+ const message = value?.message || "";
142
+ return [key, { type: "error", message }];
143
+ })
144
+ );
145
+ }
132
146
  const messages = [<const>{ type: "error", text: error_message }];
133
147
  return {
134
148
  action: "stay",
@@ -137,8 +151,9 @@ export abstract class Form<
137
151
  {
138
152
  raw_values: data.raw_values,
139
153
  messages,
154
+ field_messages,
140
155
  },
141
- "show_field_errors" && true
156
+ true
142
157
  ),
143
158
  };
144
159
  }
@@ -163,8 +178,9 @@ export abstract class Form<
163
178
  {
164
179
  raw_values: await this.getInitialValues(ctx),
165
180
  messages,
181
+ field_messages: {},
166
182
  },
167
- "show_field_errors" && false
183
+ false
168
184
  ),
169
185
  messages,
170
186
  };
@@ -181,10 +197,6 @@ export abstract class Form<
181
197
  raw_values
182
198
  );
183
199
  if (!valid) {
184
- console.debug("Form values invalid: ", {
185
- form_messages,
186
- field_errors,
187
- });
188
200
  return this.onValuesInvalid(ctx, form_messages, field_errors);
189
201
  }
190
202
  try {
@@ -192,12 +204,14 @@ export abstract class Form<
192
204
  const result = await this.onSubmit(ctx, {
193
205
  raw_values,
194
206
  messages: [],
207
+ field_messages: {},
195
208
  });
196
209
  return this.onSuccess(
197
210
  ctx,
198
211
  {
199
212
  raw_values: await this.getRawValuesOnSuccess(ctx),
200
213
  messages: [],
214
+ field_messages: {},
201
215
  },
202
216
  result
203
217
  );
@@ -222,6 +236,7 @@ export abstract class Form<
222
236
  text: message,
223
237
  },
224
238
  ],
239
+ field_messages: {},
225
240
  },
226
241
  e
227
242
  );
@@ -257,12 +272,12 @@ export abstract class Form<
257
272
  {
258
273
  raw_values: await this.extractRawValues(ctx),
259
274
  messages: [],
275
+ field_messages: {},
260
276
  },
261
- "show_field_errors" && false
277
+ false
262
278
  );
263
279
  });
264
280
  router.post(path, async (ctx) => {
265
- console.log("REGULAR FORM HANDLE");
266
281
  const reaction =
267
282
  (ctx.override_reaction as FormReaction | undefined) ||
268
283
  (await this.handlePost(ctx));
@@ -283,4 +298,10 @@ export abstract class Form<
283
298
  ? ctx.$body
284
299
  : this.getInitialValues(ctx);
285
300
  }
301
+
302
+ static initFieldNames(fields: Record<string, FormField>): void {
303
+ for (const [field_name, field] of Object.entries(fields)) {
304
+ field.setName(field_name);
305
+ }
306
+ }
286
307
  }