@sealcode/sealgen 0.18.8 → 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 (374) hide show
  1. package/.eslintrc.cjs +7 -2
  2. package/.xunit +75 -0
  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 -2
  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 -1
  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 -3
  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 -0
  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 -2
  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 -7
  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 -1
  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/page/list.d.sync-conflict-20250918-184318-TFDLWFG.ts +48 -0
  133. package/@types/page/list.d.sync-conflict-20250918-222046-TFDLWFG.ts +48 -0
  134. package/@types/page/list.d.ts +2 -2
  135. package/@types/page/list.sync-conflict-20250918-222048-TFDLWFG.d.ts +48 -0
  136. package/@types/page/mountable-with-fields.d.sync-conflict-20250918-184321-TFDLWFG.ts +42 -0
  137. package/@types/page/mountable-with-fields.d.sync-conflict-20250918-222046-TFDLWFG.ts +42 -0
  138. package/@types/page/mountable-with-fields.d.ts +3 -3
  139. package/@types/page/mountable-with-fields.sync-conflict-20250918-222044-TFDLWFG.d.ts +42 -0
  140. package/@types/page/mountable.d.sync-conflict-20250918-184306-TFDLWFG.ts +10 -0
  141. package/@types/page/page.d.sync-conflict-20250918-184320-TFDLWFG.ts +18 -0
  142. package/@types/page/props-parser.d.sync-conflict-20250918-184305-TFDLWFG.ts +15 -0
  143. package/@types/page/props-parser.d.ts +0 -1
  144. package/@types/page/stateful-page.d.sync-conflict-20250918-184326-TFDLWFG.ts +62 -0
  145. package/@types/templates/shared/shared-crud-form-fields.d.sync-conflict-20250918-184306-TFDLWFG.ts +1 -0
  146. package/@types/templates/shared/shared-crud-form-fields.d.ts +0 -67
  147. package/@types/test_utils/test-on-real-app.d.sync-conflict-20250918-184320-TFDLWFG.ts +26 -0
  148. package/@types/test_utils/test-on-real-app.d.ts +0 -1
  149. package/@types/utils/extract-fields-from-collection.d.sync-conflict-20250918-184312-TFDLWFG.ts +18 -0
  150. package/@types/utils/extract-fields-from-collection.d.ts +5 -1
  151. package/@types/utils/extract-fields-from-collection.sync-conflict-20250918-222045-TFDLWFG.d.ts +18 -0
  152. package/@types/utils/wrap-attributes.d.ts +3 -0
  153. package/README.md +5 -0
  154. package/assets/file-icon.svg +5 -0
  155. package/lib/add-crud.js +80 -89
  156. package/lib/add-list-route.test.js +1 -1
  157. package/lib/add-route.js +0 -7
  158. package/lib/build.js +3 -1
  159. package/lib/cli.js +2 -5
  160. package/lib/controllers/table-add-button.stimulus.js +35 -0
  161. package/lib/forms/controls/array.js +20 -16
  162. package/lib/forms/controls/big-radio-group.js +2 -2
  163. package/lib/forms/controls/checkbox-group.js +7 -7
  164. package/lib/forms/controls/checkboxed-list-input.js +9 -2
  165. package/lib/forms/controls/controls.js +2 -2
  166. package/lib/forms/controls/derived-frame.js +5 -1
  167. package/lib/forms/controls/derived.js +1 -1
  168. package/lib/forms/controls/dropdown.js +4 -1
  169. package/lib/forms/controls/editable-collection-subset.js +2 -2
  170. package/lib/forms/controls/file.js +26 -2
  171. package/lib/forms/controls/file.test.js +2 -2
  172. package/lib/forms/controls/hidden-input.js +4 -1
  173. package/lib/forms/controls/{photo.js → image.js} +6 -7
  174. package/lib/forms/controls/{photo.test.js → image.test.js} +6 -21
  175. package/lib/forms/controls/multiple-files.js +10 -1
  176. package/lib/forms/controls/{multiple-photos.js → multiple-images.js} +3 -3
  177. package/lib/forms/controls/simple-input.js +13 -12
  178. package/lib/forms/controls/single-reference.js +4 -0
  179. package/lib/forms/controls/table.js +66 -24
  180. package/lib/forms/controls/textarea.js +4 -2
  181. package/lib/forms/controls/tickable.js +13 -5
  182. package/lib/forms/fields/boolean.js +14 -0
  183. package/lib/forms/fields/checkboxed-list.js +4 -0
  184. package/lib/forms/fields/collection-field.js +9 -0
  185. package/lib/forms/fields/color.js +10 -0
  186. package/lib/forms/fields/coordinates.js +49 -0
  187. package/lib/forms/fields/date.js +34 -0
  188. package/lib/forms/fields/datetime.js +46 -0
  189. package/lib/forms/fields/deep-reverse-single-reference-list.js +81 -0
  190. package/lib/forms/fields/deep-reverse-single-reference-table.js +122 -0
  191. package/lib/forms/fields/email.js +7 -0
  192. package/lib/forms/fields/enum-multiple-sealious.js +32 -0
  193. package/lib/forms/fields/field.js +32 -4
  194. package/lib/forms/fields/field.test.js +5 -5
  195. package/lib/forms/fields/fields.js +23 -8
  196. package/lib/forms/fields/file.js +33 -9
  197. package/lib/forms/fields/file.test.js +4 -16
  198. package/lib/forms/fields/float.js +10 -0
  199. package/lib/forms/fields/get-field-for-sealious.js +213 -0
  200. package/lib/forms/fields/html.js +14 -0
  201. package/lib/forms/fields/image.js +13 -0
  202. package/lib/forms/fields/int.js +23 -0
  203. package/lib/forms/fields/json.js +31 -0
  204. package/lib/forms/fields/markdown.js +14 -0
  205. package/lib/forms/fields/multiple-files.js +4 -0
  206. package/lib/forms/fields/number.js +6 -0
  207. package/lib/forms/fields/password.js +13 -0
  208. package/lib/forms/fields/pick-from-list-sealious.js +17 -0
  209. package/lib/forms/fields/pick-from-list.js +6 -2
  210. package/lib/forms/fields/proxy-field.js +3 -0
  211. package/lib/forms/fields/regexp.js +14 -0
  212. package/lib/forms/fields/simple-form-field.js +60 -2
  213. package/lib/forms/fields/single-reference.js +44 -0
  214. package/lib/forms/fields/structured-array.js +63 -12
  215. package/lib/forms/fields/table.js +28 -1
  216. package/lib/forms/fields/text.js +17 -0
  217. package/lib/forms/fields/url.js +17 -0
  218. package/lib/forms/form.js +30 -13
  219. package/lib/forms/form.test.js +3 -4
  220. package/lib/forms/multiform.js +4 -2
  221. package/lib/forms/multiform.test.js +3 -3
  222. package/lib/generate-stimulus.js +1 -0
  223. package/lib/index.js +1 -0
  224. package/lib/make-hidden-inputs.js +1 -1
  225. package/lib/mount.js +11 -0
  226. package/lib/notifier.js +0 -1
  227. package/lib/page/list.js +15 -8
  228. package/lib/page/mountable-with-fields.js +14 -6
  229. package/lib/page/mountable-with-fields.test.js +1 -1
  230. package/lib/templates/form.js +8 -9
  231. package/lib/templates/multiform.js +4 -4
  232. package/lib/templates/page.js +0 -2
  233. package/lib/templates/shared/collection-create-form.js +28 -40
  234. package/lib/templates/shared/collection-edit-form.js +40 -77
  235. package/lib/templates/shared/collection-list.js +12 -20
  236. package/lib/templates/shared/shared-crud-form-fields.js +27 -95
  237. package/lib/test_utils/test-on-real-app.js +3 -3
  238. package/lib/utils/extract-fields-from-collection.js +60 -20
  239. package/lib/utils/make-slug.js +1 -1
  240. package/lib/utils/wrap-attributes.js +20 -0
  241. package/package.json +5 -4
  242. package/src/add-crud.ts +86 -97
  243. package/src/add-list-route.test.ts +1 -1
  244. package/src/add-route.ts +0 -7
  245. package/src/build.ts +3 -1
  246. package/src/cli.ts +3 -5
  247. package/src/controllers/table-add-button.stimulus.ts +35 -0
  248. package/src/forms/controls/array.ts +23 -20
  249. package/src/forms/controls/autocomplete.ts +1 -1
  250. package/src/forms/controls/big-radio-group.ts +2 -2
  251. package/src/forms/controls/checkbox-group.ts +9 -9
  252. package/src/forms/controls/checkboxed-list-input.ts +27 -15
  253. package/src/forms/controls/controls.ts +2 -2
  254. package/src/forms/controls/derived-frame.ts +5 -1
  255. package/src/forms/controls/derived.ts +1 -1
  256. package/src/forms/controls/dropdown.ts +5 -2
  257. package/src/forms/controls/editable-collection-subset.ts +2 -2
  258. package/src/forms/controls/file.test.ts +4 -2
  259. package/src/forms/controls/file.ts +31 -5
  260. package/src/forms/controls/form-control.ts +7 -2
  261. package/src/forms/controls/hidden-input.ts +4 -1
  262. package/src/forms/controls/{photo.test.ts → image.test.ts} +5 -22
  263. package/src/forms/controls/{photo.ts → image.ts} +3 -5
  264. package/src/forms/controls/multiple-files.ts +18 -1
  265. package/src/forms/controls/{multiple-photos.ts → multiple-images.ts} +1 -1
  266. package/src/forms/controls/number.ts +1 -1
  267. package/src/forms/controls/simple-input.ts +18 -34
  268. package/src/forms/controls/single-reference.ts +10 -2
  269. package/src/forms/controls/table.ts +90 -31
  270. package/src/forms/controls/textarea.ts +6 -4
  271. package/src/forms/controls/tickable.ts +13 -5
  272. package/src/forms/fields/boolean.ts +23 -1
  273. package/src/forms/fields/checkboxed-list.ts +11 -2
  274. package/src/forms/fields/collection-field.ts +16 -1
  275. package/src/forms/fields/color.ts +9 -0
  276. package/src/forms/fields/coordinates.ts +66 -0
  277. package/src/forms/fields/date.ts +50 -0
  278. package/src/forms/fields/datetime.ts +66 -0
  279. package/src/forms/fields/deep-reverse-single-reference-list.ts +136 -0
  280. package/src/forms/fields/deep-reverse-single-reference-table.ts +213 -0
  281. package/src/forms/fields/email.ts +9 -0
  282. package/src/forms/fields/enum-multiple-sealious.ts +48 -0
  283. package/src/forms/fields/field.test.ts +5 -5
  284. package/src/forms/fields/field.ts +94 -8
  285. package/src/forms/fields/fields.ts +23 -8
  286. package/src/forms/fields/file.test.ts +4 -16
  287. package/src/forms/fields/file.ts +43 -15
  288. package/src/forms/fields/float.ts +9 -0
  289. package/src/forms/fields/get-field-for-sealious.ts +304 -0
  290. package/src/forms/fields/html.ts +15 -0
  291. package/src/forms/fields/image.ts +12 -0
  292. package/src/forms/fields/int.ts +25 -0
  293. package/src/forms/fields/json.ts +48 -0
  294. package/src/forms/fields/markdown.ts +15 -0
  295. package/src/forms/fields/multiple-files.ts +10 -1
  296. package/src/forms/fields/number.ts +8 -1
  297. package/src/forms/fields/password.ts +17 -0
  298. package/src/forms/fields/pick-from-list-sealious.ts +22 -0
  299. package/src/forms/fields/pick-from-list.ts +7 -3
  300. package/src/forms/fields/proxy-field.ts +6 -1
  301. package/src/forms/fields/regexp.ts +27 -1
  302. package/src/forms/fields/simple-form-field.ts +95 -7
  303. package/src/forms/fields/single-reference.ts +62 -0
  304. package/src/forms/fields/structured-array.ts +115 -18
  305. package/src/forms/fields/table.ts +32 -1
  306. package/src/forms/fields/text.ts +18 -0
  307. package/src/forms/fields/url.ts +20 -0
  308. package/src/forms/form-types.ts +2 -0
  309. package/src/forms/form.test.ts +3 -4
  310. package/src/forms/form.ts +37 -16
  311. package/src/forms/forms.css +0 -85
  312. package/src/forms/multiform.test.ts +3 -3
  313. package/src/forms/multiform.ts +2 -0
  314. package/src/generate-stimulus.ts +1 -0
  315. package/src/index.ts +2 -1
  316. package/src/make-hidden-inputs.ts +1 -1
  317. package/src/mount.ts +14 -0
  318. package/src/notifier.ts +0 -1
  319. package/src/page/list.ts +15 -8
  320. package/src/page/mountable-with-fields.test.ts +1 -1
  321. package/src/page/mountable-with-fields.ts +18 -9
  322. package/src/register-external.ts +1 -1
  323. package/src/templates/form.ts +8 -9
  324. package/src/templates/multiform.ts +4 -4
  325. package/src/templates/page.ts +0 -2
  326. package/src/templates/shared/collection-create-form.ts +30 -66
  327. package/src/templates/shared/collection-edit-form.ts +41 -102
  328. package/src/templates/shared/collection-list.ts +12 -20
  329. package/src/templates/shared/item-delete.ts +0 -1
  330. package/src/templates/shared/shared-crud-form-fields.ts +37 -171
  331. package/src/test_utils/test-on-real-app.ts +4 -3
  332. package/src/utils/extract-fields-from-collection.ts +76 -25
  333. package/src/utils/make-slug.ts +1 -1
  334. package/src/utils/wrap-attributes.ts +17 -0
  335. package/lib/add-verbose-crud.js +0 -119
  336. package/lib/crud-field-snippets.js +0 -52
  337. package/lib/find-css-includes.js +0 -3
  338. package/lib/forms/controls/reverse-single-reference.js +0 -1
  339. package/lib/forms/fields/enum-multiple.js +0 -47
  340. package/lib/forms/fields/enum-multiple.test.js +0 -27
  341. package/lib/forms/fields/enum.js +0 -41
  342. package/lib/forms/fields/enum.test.js +0 -21
  343. package/lib/forms/fields/reverse-single-reference.js +0 -17
  344. package/lib/templates/shared/handlers/boolean.js +0 -14
  345. package/lib/templates/shared/handlers/date.js +0 -8
  346. package/lib/templates/shared/handlers/deep-reverse-single-reference.js +0 -209
  347. package/lib/templates/shared/handlers/default.js +0 -49
  348. package/lib/templates/shared/handlers/enum.js +0 -19
  349. package/lib/templates/shared/handlers/file.js +0 -23
  350. package/lib/templates/shared/handlers/image.js +0 -32
  351. package/lib/templates/shared/handlers/int.js +0 -11
  352. package/lib/templates/shared/handlers/jdd.js +0 -10
  353. package/lib/templates/shared/handlers/single-reference.js +0 -12
  354. package/lib/templates/shared/handlers/structured-array.js +0 -33
  355. package/src/add-verbose-crud.ts +0 -138
  356. package/src/crud-field-snippets.ts +0 -57
  357. package/src/find-css-includes.ts +0 -3
  358. package/src/forms/controls/reverse-single-reference.ts +0 -50
  359. package/src/forms/fields/enum-multiple.test.ts +0 -31
  360. package/src/forms/fields/enum-multiple.ts +0 -62
  361. package/src/forms/fields/enum.test.ts +0 -25
  362. package/src/forms/fields/enum.ts +0 -56
  363. package/src/forms/fields/reverse-single-reference.ts +0 -20
  364. package/src/templates/shared/handlers/boolean.ts +0 -18
  365. package/src/templates/shared/handlers/date.ts +0 -12
  366. package/src/templates/shared/handlers/deep-reverse-single-reference.ts +0 -244
  367. package/src/templates/shared/handlers/default.ts +0 -64
  368. package/src/templates/shared/handlers/enum.ts +0 -23
  369. package/src/templates/shared/handlers/file.ts +0 -27
  370. package/src/templates/shared/handlers/image.ts +0 -45
  371. package/src/templates/shared/handlers/int.ts +0 -15
  372. package/src/templates/shared/handlers/jdd.ts +0 -14
  373. package/src/templates/shared/handlers/single-reference.ts +0 -16
  374. package/src/templates/shared/handlers/structured-array.ts +0 -42
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
2
2
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
3
3
  /* eslint-disable @typescript-eslint/no-explicit-any */
4
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
4
5
  import Router from "@koa/router";
5
6
  import { hasShape, is, predicates } from "@sealcode/ts-predicates";
6
7
  import { Context } from "koa";
@@ -10,19 +11,14 @@ import { FormField } from "../fields/field.js";
10
11
  import {
11
12
  ExtractFormFieldParsed,
12
13
  Table as TableField,
13
- TableFieldParsed,
14
14
  } from "../fields/table.js";
15
15
  import { FormReaction } from "../form-types.js";
16
16
  import { Form } from "../form.js";
17
17
  import { FormControl, FormControlContext } from "./form-control.js";
18
18
 
19
19
  export type TableControlOptions<F extends Record<string, FormField>> = {
20
- render_fields: {
21
- [field_name in keyof F]: (
22
- fctx: FormControlContext,
23
- name: string,
24
- value: string
25
- ) => FlatTemplatable | Promise<FlatTemplatable>;
20
+ subfield_controls: {
21
+ [field_name in keyof F]: FormControl;
26
22
  };
27
23
  allow_removing?: boolean;
28
24
  label_add?: string;
@@ -38,7 +34,8 @@ export type TableControlOptions<F extends Record<string, FormField>> = {
38
34
  }
39
35
  );
40
36
 
41
- const TO_REPLACE = "____$$$$";
37
+ export const TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER =
38
+ "TABLE_ROW_INDEX________________";
42
39
 
43
40
  export class Table<F extends Record<string, FormField>> extends FormControl {
44
41
  role = <const>"input";
@@ -50,15 +47,41 @@ export class Table<F extends Record<string, FormField>> extends FormControl {
50
47
  }
51
48
 
52
49
  async render(fctx: FormControlContext): Promise<FlatTemplatable> {
53
- let { parsed: rows } = await this.table_field.getValue(
54
- fctx.ctx,
55
- fctx.data
56
- );
50
+ let rows = fctx.data.raw_values?.[this.table_field.name] as any[];
57
51
  if (!rows) {
58
52
  rows = [];
59
53
  }
60
54
 
61
- const make_row = (
55
+ const get_row_fctx = (
56
+ row:
57
+ | {
58
+ [field_name in keyof F]: ExtractFormFieldParsed<
59
+ F[field_name]
60
+ >;
61
+ }
62
+ | null,
63
+ row_index: number | string
64
+ ) => {
65
+ return typeof row_index == "number"
66
+ ? {
67
+ data: {
68
+ raw_values:
69
+ (Object.fromEntries(
70
+ Object.entries(
71
+ row as Record<string, unknown>
72
+ ).map(([key, value]) => [
73
+ this.table_field.columns[key].name,
74
+ value,
75
+ ])
76
+ ) as any) || {},
77
+ messages: [],
78
+ field_messages: {},
79
+ },
80
+ }
81
+ : {};
82
+ };
83
+
84
+ const make_row = async (
62
85
  row:
63
86
  | {
64
87
  [field_name in keyof F]: ExtractFormFieldParsed<
@@ -69,14 +92,26 @@ export class Table<F extends Record<string, FormField>> extends FormControl {
69
92
  row_index: number | string
70
93
  ) => {
71
94
  return /* HTML */ tempstream`<tr>
72
- ${Object.entries(this.table_field.columns).map(([key]) => {
73
- return tempstream`<td>${this.options.render_fields[key](
74
- fctx,
75
- `${this.table_field.name}[${row_index}][${key}]`,
76
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
77
- (row?.[key] as string) || ""
78
- )}</td>`;
79
- })}
95
+ ${(
96
+ await Promise.all(
97
+ Object.entries(this.table_field.columns).map(
98
+ ([column_name]) => {
99
+ const inner_fctx = get_row_fctx(
100
+ row,
101
+ row_index
102
+ );
103
+ return tempstream`<td>${this.options.subfield_controls[
104
+ column_name
105
+ ].render({ ...fctx, ...inner_fctx })}</td>`;
106
+ }
107
+ )
108
+ )
109
+ ).map((html) =>
110
+ html.replaceAll(
111
+ TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER,
112
+ row_index.toString()
113
+ )
114
+ )}
80
115
  ${
81
116
  this.options.allow_removing
82
117
  ? /* HTML */ `<td>
@@ -136,27 +171,25 @@ export class Table<F extends Record<string, FormField>> extends FormControl {
136
171
  ${rows?.map((row, index) => make_row(row, index))}
137
172
  </tbody>
138
173
  </table>
139
- <template> ${make_row(null, TO_REPLACE)} </template>
174
+ <template>
175
+ ${make_row(null, TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER)}
176
+ </template>
140
177
 
141
178
  ${
142
179
  /* because of https://github.com/ljharb/qs/issues/252 we have to
143
180
  put the indexes in the field names */
144
181
  this.options.allow_adding
145
182
  ? /* HTML */ `<button
146
- onclick="const template = this.closest('turbo-frame').querySelector('template');
147
- const tbody = this.closest('turbo-frame').querySelector('tbody');
148
- const orig_template = template.innerHTML;
149
- template.innerHTML = orig_template.replaceAll('${TO_REPLACE}', tbody.querySelectorAll('tr').length);
150
- tbody.appendChild(template.cloneNode(true).content);
151
- template.innerHTML = orig_template;"
183
+ data-controller="table-add-button"
184
+ data-action="click->table-add-button#addRow"
185
+ data-table-placeholder="${TABLE_COLUMN_FIELD_INDEX_PLACEHOLDER}"
152
186
  >
153
- add
187
+ ${this.options.label_add || "add"}
154
188
  </button>
155
189
  <noscript>
156
190
  <input
157
191
  type="submit"
158
- value="${this.options.label_add ||
159
- "add"}"
192
+ value="add"
160
193
  form="${fctx.form_id}"
161
194
  formnovalidate
162
195
  formaction="${this.getActionURL(
@@ -249,6 +282,7 @@ template.innerHTML = orig_template;"
249
282
  {
250
283
  raw_values: await form.extractRawValues(ctx),
251
284
  messages: [],
285
+ field_messages: {},
252
286
  },
253
287
  false
254
288
  ),
@@ -256,4 +290,29 @@ template.innerHTML = orig_template;"
256
290
  await next();
257
291
  });
258
292
  }
293
+
294
+ setAllowRemoving(value: boolean) {
295
+ this.options.allow_removing = value;
296
+ return this;
297
+ }
298
+
299
+ setAllowAdding(value: boolean) {
300
+ this.options.allow_adding = value;
301
+ return this;
302
+ }
303
+
304
+ setLabel(value: string) {
305
+ this.options.label = value;
306
+ return this;
307
+ }
308
+
309
+ setRemoveLabel(value: string) {
310
+ this.options.label_remove = value;
311
+ return this;
312
+ }
313
+
314
+ setAddLabel(value: string) {
315
+ this.options.label_add = value;
316
+ return this;
317
+ }
259
318
  }
@@ -4,9 +4,9 @@ import { FormDataValue } from "../form-types.js";
4
4
  import { FormControlContext } from "./form-control.js";
5
5
  import { SimpleInput, SimpleInputOptions } from "./simple-input.js";
6
6
 
7
- export class Textarea extends SimpleInput<string | null> {
7
+ export class Textarea extends SimpleInput {
8
8
  constructor(
9
- public field: FormField<boolean, string | null>,
9
+ public field: FormField<boolean>,
10
10
  public options: SimpleInputOptions & {
11
11
  label?: string;
12
12
  rows?: number;
@@ -49,7 +49,9 @@ export class Textarea extends SimpleInput<string | null> {
49
49
  attributes: string,
50
50
  data: Record<string, FormDataValue>
51
51
  ) {
52
- const { parsed: value } = await this.field.getValue(ctx, data);
53
- return /* HTML */ `<textarea ${attributes}>${value || ""}</textarea>`;
52
+ const { parsed: value } = await this.field.getParsedValue(ctx, data);
53
+ return /* HTML */ `<textarea ${attributes}>
54
+ ${String(value) || ""}</textarea
55
+ >`;
54
56
  }
55
57
  }
@@ -70,11 +70,19 @@ export abstract class Tickable<T> extends FormFieldControl {
70
70
  parsed: _parsed,
71
71
  valid,
72
72
  message,
73
- } = await this.field.getValue(fctx.ctx, fctx.data, true);
73
+ } = await this.field.getParsedValue(
74
+ fctx.ctx,
75
+ fctx.data.raw_values,
76
+ true
77
+ );
74
78
  const parsed = _parsed === null ? this.options.default_value : _parsed;
75
79
 
76
- const value = this.getValueAttribute(fctx.ctx, fctx.data, parsed);
77
- const id = this.makeInputID(fctx.ctx, fctx.data, parsed);
80
+ const value = this.getValueAttribute(
81
+ fctx.ctx,
82
+ fctx.data.raw_values,
83
+ parsed
84
+ );
85
+ const id = this.makeInputID(fctx.ctx, fctx.data.raw_values, parsed);
78
86
  const label =
79
87
  this.options.label != undefined
80
88
  ? this.options.label
@@ -86,7 +94,7 @@ export abstract class Tickable<T> extends FormFieldControl {
86
94
 
87
95
  return inputWrapper(
88
96
  this.type,
89
- this.getWrapperClasses(fctx.ctx, fctx.data, parsed),
97
+ this.getWrapperClasses(fctx.ctx, fctx.data.raw_values, parsed),
90
98
 
91
99
  /* HTML */ `
92
100
  <input
@@ -96,7 +104,7 @@ export abstract class Tickable<T> extends FormFieldControl {
96
104
  this.field.name}"
97
105
  ${value ? `value="${attribute(value)}"` : ""}
98
106
  ${fctx.form_id ? `form="${fctx.form_id}"` : ""}
99
- ${this.isChecked(fctx.ctx, fctx.data, parsed)
107
+ ${this.isChecked(fctx.ctx, fctx.data.raw_values, parsed)
100
108
  ? "checked"
101
109
  : ""}
102
110
  ${readonly ? "readonly" : ""}
@@ -1,14 +1,17 @@
1
1
  import { is, predicates } from "@sealcode/ts-predicates";
2
2
  import { Context } from "koa";
3
+ import { Checkbox } from "../controls/checkbox.js";
3
4
  import { FormDataValue } from "../form-types.js";
4
5
  import { FieldParseResult, FormField } from "./field.js";
6
+ import { FormControlContext } from "../controls/form-control.js";
5
7
 
6
8
  const truthy = ["true", "on", "yes", "1"];
7
9
  const falsy = ["false", "off", "no", "0"];
8
10
 
9
11
  export class Boolean<Required extends boolean> extends FormField<
10
12
  Required,
11
- boolean
13
+ boolean,
14
+ Checkbox
12
15
  > {
13
16
  predicate = predicates.boolean;
14
17
  constructor(required: Required, public error_message: string = "") {
@@ -60,4 +63,23 @@ export class Boolean<Required extends boolean> extends FormField<
60
63
  public getEmptyValue(): boolean {
61
64
  return false;
62
65
  }
66
+
67
+ public getControl(): Checkbox {
68
+ return new Checkbox(this, { label: this.name });
69
+ }
70
+
71
+ async getSealiousCreateValue(fctx: FormControlContext): Promise<boolean> {
72
+ const { parsed } = await this.getParsedValue(
73
+ fctx.ctx,
74
+ fctx.data.raw_values
75
+ );
76
+ return !!parsed;
77
+ }
78
+
79
+ async sealiousValueToForm(
80
+ _: Context,
81
+ value: boolean | null
82
+ ): Promise<FormDataValue> {
83
+ return value ? "true" : "false";
84
+ }
63
85
  }
@@ -1,5 +1,6 @@
1
1
  import { is, predicates } from "@sealcode/ts-predicates";
2
2
  import { Context } from "koa";
3
+ import { CheckboxedListInput } from "../controls/checkboxed-list-input.js";
3
4
  import { FormDataValue } from "../form-types.js";
4
5
  import {
5
6
  FieldParseResult,
@@ -13,9 +14,13 @@ export type CheckboxedListItem = {
13
14
  group?: string;
14
15
  };
15
16
 
16
- export class CheckboxedListField<Required extends boolean> extends FormField<
17
+ export class CheckboxedListField<
18
+ Required extends boolean,
19
+ Values extends string
20
+ > extends FormField<
17
21
  Required,
18
- Record<string, "on">
22
+ Record<Values, "on">,
23
+ CheckboxedListInput<Values>
19
24
  > {
20
25
  constructor(
21
26
  public required: Required,
@@ -67,4 +72,8 @@ export class CheckboxedListField<Required extends boolean> extends FormField<
67
72
  public getEmptyValue(): Record<string, "on"> {
68
73
  return {};
69
74
  }
75
+
76
+ getControl(): CheckboxedListInput<Values> {
77
+ return new CheckboxedListInput(this, { label: this.name });
78
+ }
70
79
  }
@@ -1,6 +1,7 @@
1
1
  import { predicates } from "@sealcode/ts-predicates";
2
2
  import { Context } from "koa";
3
3
  import { Depromisify, ExtractFieldDecoded, Field } from "sealious";
4
+ import { SimpleInput } from "../controls/controls.js";
4
5
  import { FormDataValue } from "../form-types.js";
5
6
 
6
7
  import {
@@ -8,12 +9,13 @@ import {
8
9
  FormField,
9
10
  FormFieldValidationResponse,
10
11
  } from "./field.js";
12
+ import { ExtractedFieldInfo } from "../../utils/extract-fields-from-collection.js";
11
13
 
12
14
  export class CollectionField<
13
15
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
16
  F extends Field<any>,
15
17
  Required extends boolean
16
- > extends FormField<Required, ExtractFieldDecoded<F> | null> {
18
+ > extends FormField<Required, ExtractFieldDecoded<F> | null, SimpleInput> {
17
19
  constructor(required: Required, public sealiousField: F) {
18
20
  super(required);
19
21
  }
@@ -62,4 +64,17 @@ export class CollectionField<
62
64
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
63
65
  return "" as unknown as ExtractFieldDecoded<F>;
64
66
  }
67
+
68
+ getControl(): SimpleInput {
69
+ return new SimpleInput(this);
70
+ }
71
+
72
+ generateFieldDeclaration(
73
+ field_info: ExtractedFieldInfo,
74
+ vars: { form_field_types: string; sealious_field: string }
75
+ ): string {
76
+ return `new ${vars.form_field_types}.${this.constructor.name}(${String(
77
+ field_info.is_required
78
+ )}, ${vars.sealious_field})`;
79
+ }
65
80
  }
@@ -0,0 +1,9 @@
1
+ import { TextBasedSimpleField } from "./simple-form-field.js";
2
+
3
+ export class Color<
4
+ Required extends boolean
5
+ > extends TextBasedSimpleField<Required> {
6
+ constructor(required: Required) {
7
+ super(required, "color");
8
+ }
9
+ }
@@ -0,0 +1,66 @@
1
+ import { Context } from "koa";
2
+ import { FormControl, FormControlContext } from "../controls/form-control.js";
3
+ import { SimpleInput } from "../controls/simple-input.js";
4
+ import { FormDataValue } from "../form-types.js";
5
+ import { FieldParseResult } from "./field.js";
6
+ import { SimpleFormField } from "./simple-form-field.js";
7
+
8
+ export class Coordinates<
9
+ Required extends boolean,
10
+ DefaultControl extends FormControl = SimpleInput
11
+ > extends SimpleFormField<Required, DefaultControl, [number, number]> {
12
+ async parse(
13
+ _: Context,
14
+ raw_value: FormDataValue
15
+ ): Promise<FieldParseResult<[number, number]>> {
16
+ if (typeof raw_value == "string") {
17
+ return {
18
+ parsed_value: raw_value
19
+ ?.split(",")
20
+ .map((e) => parseFloat(e)) as [number, number],
21
+ parsable: true,
22
+ error: null,
23
+ };
24
+ }
25
+ if (Array.isArray(raw_value)) {
26
+ return {
27
+ parsed_value: raw_value.map((e) => parseFloat(e)) as [
28
+ number,
29
+ number
30
+ ],
31
+ parsable: true,
32
+ error: null,
33
+ };
34
+ }
35
+ return {
36
+ parsed_value: null,
37
+ parsable: false,
38
+ error: "should be an array or string",
39
+ };
40
+ }
41
+
42
+ async getSealiousCreateValue(
43
+ fctx: FormControlContext
44
+ ): Promise<[number, number] | undefined> {
45
+ const { parsed } = await this.getParsedValue(
46
+ fctx.ctx,
47
+ fctx.data.raw_values
48
+ );
49
+ return parsed || undefined;
50
+ }
51
+
52
+ async postSealiousCreate(): Promise<void> {}
53
+
54
+ async postSealiousEdit(): Promise<void> {}
55
+
56
+ getControl(): DefaultControl {
57
+ return new SimpleInput(this, {
58
+ label: this.name,
59
+ type: this.type,
60
+ }) as unknown as DefaultControl;
61
+ }
62
+
63
+ public getEmptyValue(): [number, number] {
64
+ return [0, 0];
65
+ }
66
+ }
@@ -0,0 +1,50 @@
1
+ import { Context } from "koa";
2
+ import { FormControlContext } from "../controls/form-control.js";
3
+ import { SimpleInput, SimpleInputOptions } from "../controls/simple-input.js";
4
+ import { FormDataValue } from "../form-types.js";
5
+ import { FieldParseResult } from "./field.js";
6
+ import { SimpleFormField } from "./simple-form-field.js";
7
+
8
+ export class DateField<Required extends boolean> extends SimpleFormField<
9
+ Required,
10
+ SimpleInput,
11
+ Date
12
+ > {
13
+ constructor(required: Required) {
14
+ super(required, "date");
15
+ }
16
+
17
+ public getEmptyValue(): Date {
18
+ return new Date("1970-01-01 00:00");
19
+ }
20
+
21
+ async parse(
22
+ ctx: Context,
23
+ raw_value: FormDataValue
24
+ ): Promise<FieldParseResult<Date>> {
25
+ return {
26
+ error: null,
27
+ parsable: true,
28
+ parsed_value: new Date(raw_value as string),
29
+ };
30
+ }
31
+
32
+ getControl(): SimpleInput<SimpleInputOptions> {
33
+ return new SimpleInput(this, { label: this.name, type: this.type });
34
+ }
35
+
36
+ async getSealiousCreateValue(
37
+ fctx: FormControlContext
38
+ ): Promise<string | null> {
39
+ const { parsed } = await this.getParsedValue(
40
+ fctx.ctx,
41
+ fctx.data.raw_values
42
+ );
43
+ if (!parsed) {
44
+ return null;
45
+ }
46
+ return `${parsed.getFullYear()}-${(parsed.getMonth() + 1)
47
+ .toString()
48
+ .padStart(2, "0")}-${parsed.getDate().toString().padStart(2, "0")}`;
49
+ }
50
+ }
@@ -0,0 +1,66 @@
1
+ import { Context } from "koa";
2
+ import { SimpleInput } from "../controls/controls.js";
3
+ import { FormControlContext } from "../controls/form-control.js";
4
+ import { FormDataValue } from "../form-types.js";
5
+ import { FieldParseResult } from "./field.js";
6
+ import { SimpleFormField } from "./simple-form-field.js";
7
+
8
+ function pad(n: number) {
9
+ return String(n).padStart(2, "0");
10
+ }
11
+
12
+ export class DateTime<Required extends boolean> extends SimpleFormField<
13
+ Required,
14
+ SimpleInput,
15
+ Date | null
16
+ > {
17
+ constructor(required: Required) {
18
+ super(required, "datetime-local");
19
+ }
20
+
21
+ public getEmptyValue(): Date | null {
22
+ return null;
23
+ }
24
+
25
+ async parse(
26
+ ctx: Context,
27
+ raw_value: FormDataValue
28
+ ): Promise<FieldParseResult<Date | null>> {
29
+ const parsed_value = new Date(raw_value as string);
30
+ return { parsable: true, error: null, parsed_value };
31
+ }
32
+
33
+ async getSealiousCreateValue(
34
+ fctx: FormControlContext
35
+ ): Promise<number | null> {
36
+ const { parsed } = await this.getParsedValue(
37
+ fctx.ctx,
38
+ fctx.data.raw_values
39
+ );
40
+ if (parsed == null) {
41
+ return null;
42
+ }
43
+ return new Date(parsed).getTime();
44
+ }
45
+
46
+ getControl(): SimpleInput {
47
+ return new SimpleInput(this, {
48
+ label: this.name,
49
+ type: this.type,
50
+ });
51
+ }
52
+
53
+ async sealiousValueToForm(
54
+ ctx: Context,
55
+ value: number | null
56
+ ): Promise<FormDataValue> {
57
+ if (value == null) {
58
+ return "";
59
+ }
60
+ const d = new Date(value);
61
+
62
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(
63
+ d.getDate()
64
+ )}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
65
+ }
66
+ }