@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.
- package/.eslintrc.cjs +7 -2
- package/.xunit +74 -69
- package/@types/add-crud.d.sync-conflict-20250918-184311-TFDLWFG.ts +1 -0
- package/@types/builders/colors-builder.d.sync-conflict-20250918-184323-TFDLWFG.ts +10 -0
- package/@types/builders/colors-builder.d.ts +1 -1
- package/@types/builders/fonts-builder.d.sync-conflict-20250918-184322-TFDLWFG.ts +7 -0
- package/@types/builders/fonts-builder.d.ts +1 -1
- package/@types/controllers/table-add-button.d.ts +6 -0
- package/@types/controllers/table-add-button.stimulus.d.ts +6 -0
- package/@types/crud-field-snippets.d.sync-conflict-20250918-184323-TFDLWFG.ts +1 -0
- package/@types/crud-field-snippets.d.ts +1 -3
- package/@types/forms/controls/array.d.sync-conflict-20250918-184306-TFDLWFG.ts +33 -0
- package/@types/forms/controls/array.d.ts +1 -3
- package/@types/forms/controls/array.sync-conflict-20250918-222045-TFDLWFG.d.ts +33 -0
- package/@types/forms/controls/autocomplete.d.sync-conflict-20250918-222042-TFDLWFG.ts +22 -0
- package/@types/forms/controls/autocomplete.d.ts +1 -1
- package/@types/forms/controls/checkbox-group.d.sync-conflict-20250918-184319-TFDLWFG.ts +21 -0
- package/@types/forms/controls/checkbox-group.d.ts +3 -3
- package/@types/forms/controls/checkboxed-list-input.d.sync-conflict-20250918-184323-TFDLWFG.ts +21 -0
- package/@types/forms/controls/checkboxed-list-input.d.ts +3 -3
- package/@types/forms/controls/controls.d.ts +2 -2
- package/@types/forms/controls/derived-frame.d.sync-conflict-20250918-184314-TFDLWFG.ts +19 -0
- package/@types/forms/controls/derived-frame.d.ts +0 -2
- package/@types/forms/controls/dropdown.d.sync-conflict-20250918-222044-TFDLWFG.ts +30 -0
- package/@types/forms/controls/dropdown.d.ts +1 -1
- package/@types/forms/controls/file.d.sync-conflict-20250918-222045-TFDLWFG.ts +13 -0
- package/@types/forms/controls/file.d.ts +1 -2
- package/@types/forms/controls/form-control.d.sync-conflict-20250918-184322-TFDLWFG.ts +19 -0
- package/@types/forms/controls/form-control.d.sync-conflict-20250918-222046-TFDLWFG.ts +19 -0
- package/@types/forms/controls/form-control.d.ts +7 -4
- package/@types/forms/controls/image.d.ts +19 -0
- package/@types/forms/controls/image.test.d.ts +1 -0
- package/@types/forms/controls/multiple-files.d.sync-conflict-20250918-184318-TFDLWFG.ts +42 -0
- package/@types/forms/controls/multiple-files.d.ts +3 -1
- package/@types/forms/controls/multiple-images.d.ts +19 -0
- package/@types/forms/controls/number.d.sync-conflict-20250918-222046-TFDLWFG.ts +13 -0
- package/@types/forms/controls/number.d.ts +1 -1
- package/@types/forms/controls/photo.d.sync-conflict-20250918-184321-TFDLWFG.ts +19 -0
- package/@types/forms/controls/photo.d.ts +3 -5
- package/@types/forms/controls/simple-input.d.sync-conflict-20250918-184310-TFDLWFG.ts +33 -0
- package/@types/forms/controls/simple-input.d.sync-conflict-20250918-222042-TFDLWFG.ts +33 -0
- package/@types/forms/controls/simple-input.d.ts +5 -4
- package/@types/forms/controls/simple-input.sync-conflict-20250918-222045-TFDLWFG.d.ts +33 -0
- package/@types/forms/controls/single-reference.d.ts +3 -2
- package/@types/forms/controls/table.d.sync-conflict-20250918-184302-TFDLWFG.ts +39 -0
- package/@types/forms/controls/table.d.ts +8 -3
- package/@types/forms/controls/table.sync-conflict-20250918-222042-TFDLWFG.d.ts +39 -0
- package/@types/forms/controls/textarea.d.sync-conflict-20250918-222045-TFDLWFG.ts +25 -0
- package/@types/forms/controls/textarea.d.ts +3 -3
- package/@types/forms/fields/boolean.d.sync-conflict-20250918-184325-TFDLWFG.ts +22 -0
- package/@types/forms/fields/boolean.d.ts +6 -1
- package/@types/forms/fields/boolean.sync-conflict-20250918-222042-TFDLWFG.d.ts +22 -0
- package/@types/forms/fields/checkboxed-list.d.sync-conflict-20250918-184325-TFDLWFG.ts +23 -0
- package/@types/forms/fields/checkboxed-list.d.ts +3 -1
- package/@types/forms/fields/collection-field.d.sync-conflict-20250918-184319-TFDLWFG.ts +22 -0
- package/@types/forms/fields/collection-field.d.sync-conflict-20250918-222047-TFDLWFG.ts +22 -0
- package/@types/forms/fields/collection-field.d.ts +8 -1
- package/@types/forms/fields/color.d.ts +4 -0
- package/@types/forms/fields/coordinates.d.sync-conflict-20250918-222044-TFDLWFG.ts +14 -0
- package/@types/forms/fields/coordinates.d.ts +14 -0
- package/@types/forms/fields/date.d.ts +13 -0
- package/@types/forms/fields/datetime.d.sync-conflict-20250918-222050-TFDLWFG.ts +4 -0
- package/@types/forms/fields/datetime.d.ts +14 -0
- package/@types/forms/fields/deep-reverse-single-reference-list.d.ts +24 -0
- package/@types/forms/fields/deep-reverse-single-reference-table.d.ts +16 -0
- package/@types/forms/fields/email.d.sync-conflict-20250918-184303-TFDLWFG.ts +8 -0
- package/@types/forms/fields/email.d.ts +3 -0
- package/@types/forms/fields/enum-multiple-sealious.d.ts +16 -0
- package/@types/forms/fields/enum-multiple-sealious.sync-conflict-20250918-222047-TFDLWFG.d.ts +16 -0
- package/@types/forms/fields/field.d.sync-conflict-20250918-184306-TFDLWFG.ts +70 -0
- package/@types/forms/fields/field.d.ts +37 -5
- package/@types/forms/fields/fields.d.sync-conflict-20250918-184314-TFDLWFG.ts +29 -0
- package/@types/forms/fields/fields.d.ts +23 -8
- package/@types/forms/fields/file.d.sync-conflict-20250918-184310-TFDLWFG.ts +23 -0
- package/@types/forms/fields/file.d.sync-conflict-20250918-222046-TFDLWFG.ts +23 -0
- package/@types/forms/fields/file.d.ts +11 -5
- package/@types/forms/fields/file.sync-conflict-20250918-222049-TFDLWFG.d.ts +23 -0
- package/@types/forms/fields/float.d.ts +4 -0
- package/@types/forms/fields/get-field-for-sealious.d.sync-conflict-20250918-222046-TFDLWFG.ts +29 -0
- package/@types/forms/fields/get-field-for-sealious.d.ts +31 -0
- package/@types/forms/fields/get-field-for-sealious.sync-conflict-20250918-222042-TFDLWFG.d.ts +29 -0
- package/@types/forms/fields/html.d.ts +6 -0
- package/@types/forms/fields/image.d.sync-conflict-20250918-222042-TFDLWFG.ts +5 -0
- package/@types/forms/fields/image.d.ts +5 -0
- package/@types/forms/fields/int.d.ts +6 -0
- package/@types/forms/fields/json.d.ts +13 -0
- package/@types/forms/fields/markdown.d.ts +6 -0
- package/@types/forms/fields/multiple-files.d.sync-conflict-20250918-184304-TFDLWFG.ts +16 -0
- package/@types/forms/fields/multiple-files.d.ts +3 -1
- package/@types/forms/fields/number.d.sync-conflict-20250918-184317-TFDLWFG.ts +25 -0
- package/@types/forms/fields/number.d.sync-conflict-20250918-222047-TFDLWFG.ts +25 -0
- package/@types/forms/fields/number.d.ts +3 -1
- package/@types/forms/fields/password.d.ts +6 -0
- package/@types/forms/fields/pick-from-list-sealious.d.ts +11 -0
- package/@types/forms/fields/pick-from-list.d.sync-conflict-20250918-184322-TFDLWFG.ts +15 -0
- package/@types/forms/fields/pick-from-list.d.ts +4 -3
- package/@types/forms/fields/proxy-field.d.sync-conflict-20250918-184307-TFDLWFG.ts +15 -0
- package/@types/forms/fields/proxy-field.d.ts +3 -1
- package/@types/forms/fields/regexp.d.sync-conflict-20250918-184305-TFDLWFG.ts +21 -0
- package/@types/forms/fields/regexp.d.sync-conflict-20250918-222045-TFDLWFG.ts +21 -0
- package/@types/forms/fields/regexp.d.ts +6 -1
- package/@types/forms/fields/regexp.sync-conflict-20250918-222047-TFDLWFG.d.ts +21 -0
- package/@types/forms/fields/simple-form-field.d.sync-conflict-20250918-184309-TFDLWFG.ts +29 -0
- package/@types/forms/fields/simple-form-field.d.sync-conflict-20250918-222044-TFDLWFG.ts +29 -0
- package/@types/forms/fields/simple-form-field.d.ts +23 -3
- package/@types/forms/fields/simple-form-field.sync-conflict-20250918-222049-TFDLWFG.d.ts +29 -0
- package/@types/forms/fields/single-reference.d.ts +19 -0
- package/@types/forms/fields/single-reference.sync-conflict-20250918-222043-TFDLWFG.d.ts +10 -0
- package/@types/forms/fields/structured-array.d.sync-conflict-20250918-184302-TFDLWFG.ts +27 -0
- package/@types/forms/fields/structured-array.d.sync-conflict-20250918-222049-TFDLWFG.ts +27 -0
- package/@types/forms/fields/structured-array.d.ts +19 -10
- package/@types/forms/fields/structured-array.sync-conflict-20250918-222047-TFDLWFG.d.ts +27 -0
- package/@types/forms/fields/table.d.sync-conflict-20250918-184303-TFDLWFG.ts +16 -0
- package/@types/forms/fields/table.d.ts +3 -0
- package/@types/forms/fields/text.d.ts +6 -0
- package/@types/forms/fields/url.d.ts +6 -0
- package/@types/forms/form-types.d.sync-conflict-20250918-222045-TFDLWFG.ts +26 -0
- package/@types/forms/form-types.d.ts +2 -0
- package/@types/forms/form.d.sync-conflict-20250918-184315-TFDLWFG.ts +32 -0
- package/@types/forms/form.d.sync-conflict-20250918-222049-TFDLWFG.ts +32 -0
- package/@types/forms/form.d.ts +10 -8
- package/@types/forms/form.sync-conflict-20250918-222049-TFDLWFG.d.ts +33 -0
- package/@types/forms/form.test.d.sync-conflict-20250918-184318-TFDLWFG.ts +6 -0
- package/@types/forms/form.test.d.sync-conflict-20250918-222047-TFDLWFG.ts +6 -0
- package/@types/forms/form.test.d.ts +2 -2
- package/@types/forms/multiform.d.sync-conflict-20250918-184308-TFDLWFG.ts +23 -0
- package/@types/forms/multiform.d.ts +1 -2
- package/@types/forms/multiform.sync-conflict-20250918-222044-TFDLWFG.d.ts +23 -0
- package/@types/index.d.sync-conflict-20250918-184316-TFDLWFG.ts +46 -0
- package/@types/index.d.ts +2 -2
- package/@types/mount.d.sync-conflict-20250918-184320-TFDLWFG.ts +6 -0
- package/@types/mount.d.ts +0 -1
- package/@types/page/list.d.sync-conflict-20250918-184318-TFDLWFG.ts +48 -0
- package/@types/page/list.d.sync-conflict-20250918-222046-TFDLWFG.ts +48 -0
- package/@types/page/list.d.ts +2 -2
- package/@types/page/list.sync-conflict-20250918-222048-TFDLWFG.d.ts +48 -0
- package/@types/page/mountable-with-fields.d.sync-conflict-20250918-184321-TFDLWFG.ts +42 -0
- package/@types/page/mountable-with-fields.d.sync-conflict-20250918-222046-TFDLWFG.ts +42 -0
- package/@types/page/mountable-with-fields.d.ts +3 -3
- package/@types/page/mountable-with-fields.sync-conflict-20250918-222044-TFDLWFG.d.ts +42 -0
- package/@types/page/mountable.d.sync-conflict-20250918-184306-TFDLWFG.ts +10 -0
- package/@types/page/mountable.d.ts +0 -1
- package/@types/page/page.d.sync-conflict-20250918-184320-TFDLWFG.ts +18 -0
- package/@types/page/page.d.ts +0 -1
- package/@types/page/props-parser.d.sync-conflict-20250918-184305-TFDLWFG.ts +15 -0
- package/@types/page/props-parser.d.ts +0 -1
- package/@types/page/stateful-page.d.sync-conflict-20250918-184326-TFDLWFG.ts +62 -0
- package/@types/page/stateful-page.d.ts +0 -1
- package/@types/templates/shared/shared-crud-form-fields.d.sync-conflict-20250918-184306-TFDLWFG.ts +1 -0
- package/@types/templates/shared/shared-crud-form-fields.d.ts +0 -67
- package/@types/test_utils/test-on-real-app.d.sync-conflict-20250918-184320-TFDLWFG.ts +26 -0
- package/@types/test_utils/test-on-real-app.d.ts +0 -1
- package/@types/utils/extract-fields-from-collection.d.sync-conflict-20250918-184312-TFDLWFG.ts +18 -0
- package/@types/utils/extract-fields-from-collection.d.ts +5 -1
- package/@types/utils/extract-fields-from-collection.sync-conflict-20250918-222045-TFDLWFG.d.ts +18 -0
- package/@types/utils/wrap-attributes.d.ts +3 -0
- package/README.md +5 -0
- package/assets/file-icon.svg +5 -0
- package/lib/add-crud.js +80 -89
- package/lib/add-list-route.test.js +1 -1
- package/lib/add-route.js +0 -7
- package/lib/build.js +3 -1
- package/lib/cli.js +2 -5
- package/lib/controllers/table-add-button.stimulus.js +35 -0
- package/lib/forms/controls/array.js +20 -16
- package/lib/forms/controls/big-radio-group.js +2 -2
- package/lib/forms/controls/checkbox-group.js +7 -7
- package/lib/forms/controls/checkboxed-list-input.js +9 -2
- package/lib/forms/controls/controls.js +2 -2
- package/lib/forms/controls/derived-frame.js +5 -1
- package/lib/forms/controls/derived.js +1 -1
- package/lib/forms/controls/dropdown.js +4 -1
- package/lib/forms/controls/editable-collection-subset.js +2 -2
- package/lib/forms/controls/file.js +26 -2
- package/lib/forms/controls/file.test.js +2 -2
- package/lib/forms/controls/hidden-input.js +4 -1
- package/lib/forms/controls/{photo.js → image.js} +6 -7
- package/lib/forms/controls/{photo.test.js → image.test.js} +6 -21
- package/lib/forms/controls/multiple-files.js +10 -1
- package/lib/forms/controls/{multiple-photos.js → multiple-images.js} +3 -3
- package/lib/forms/controls/simple-input.js +13 -12
- package/lib/forms/controls/single-reference.js +4 -0
- package/lib/forms/controls/table.js +66 -24
- package/lib/forms/controls/textarea.js +4 -2
- package/lib/forms/controls/tickable.js +13 -5
- package/lib/forms/fields/boolean.js +14 -0
- package/lib/forms/fields/checkboxed-list.js +4 -0
- package/lib/forms/fields/collection-field.js +9 -0
- package/lib/forms/fields/color.js +10 -0
- package/lib/forms/fields/coordinates.js +49 -0
- package/lib/forms/fields/date.js +34 -0
- package/lib/forms/fields/datetime.js +46 -0
- package/lib/forms/fields/deep-reverse-single-reference-list.js +81 -0
- package/lib/forms/fields/deep-reverse-single-reference-table.js +122 -0
- package/lib/forms/fields/email.js +7 -0
- package/lib/forms/fields/enum-multiple-sealious.js +32 -0
- package/lib/forms/fields/field.js +32 -4
- package/lib/forms/fields/field.test.js +5 -5
- package/lib/forms/fields/fields.js +23 -8
- package/lib/forms/fields/file.js +33 -9
- package/lib/forms/fields/file.test.js +4 -16
- package/lib/forms/fields/float.js +10 -0
- package/lib/forms/fields/get-field-for-sealious.js +213 -0
- package/lib/forms/fields/html.js +14 -0
- package/lib/forms/fields/image.js +13 -0
- package/lib/forms/fields/int.js +23 -0
- package/lib/forms/fields/json.js +31 -0
- package/lib/forms/fields/markdown.js +14 -0
- package/lib/forms/fields/multiple-files.js +4 -0
- package/lib/forms/fields/number.js +6 -0
- package/lib/forms/fields/password.js +13 -0
- package/lib/forms/fields/pick-from-list-sealious.js +17 -0
- package/lib/forms/fields/pick-from-list.js +6 -2
- package/lib/forms/fields/proxy-field.js +3 -0
- package/lib/forms/fields/regexp.js +14 -0
- package/lib/forms/fields/simple-form-field.js +60 -2
- package/lib/forms/fields/single-reference.js +44 -0
- package/lib/forms/fields/structured-array.js +63 -12
- package/lib/forms/fields/table.js +28 -1
- package/lib/forms/fields/text.js +17 -0
- package/lib/forms/fields/url.js +17 -0
- package/lib/forms/form.js +30 -13
- package/lib/forms/form.test.js +3 -4
- package/lib/forms/multiform.js +4 -2
- package/lib/forms/multiform.test.js +3 -3
- package/lib/generate-stimulus.js +1 -0
- package/lib/index.js +1 -0
- package/lib/make-hidden-inputs.js +1 -1
- package/lib/mount.js +11 -0
- package/lib/notifier.js +0 -1
- package/lib/page/list.js +15 -8
- package/lib/page/mountable-with-fields.js +14 -6
- package/lib/page/mountable-with-fields.test.js +1 -1
- package/lib/templates/form.js +8 -9
- package/lib/templates/multiform.js +4 -4
- package/lib/templates/page.js +0 -2
- package/lib/templates/shared/collection-create-form.js +28 -40
- package/lib/templates/shared/collection-edit-form.js +40 -77
- package/lib/templates/shared/collection-list.js +12 -20
- package/lib/templates/shared/shared-crud-form-fields.js +27 -95
- package/lib/test_utils/test-on-real-app.js +3 -3
- package/lib/utils/extract-fields-from-collection.js +60 -20
- package/lib/utils/make-slug.js +1 -1
- package/lib/utils/wrap-attributes.js +20 -0
- package/package.json +4 -3
- package/src/add-crud.ts +86 -97
- package/src/add-list-route.test.ts +1 -1
- package/src/add-route.ts +0 -7
- package/src/build.ts +3 -1
- package/src/cli.ts +3 -5
- package/src/controllers/table-add-button.stimulus.ts +35 -0
- package/src/forms/controls/array.ts +23 -20
- package/src/forms/controls/autocomplete.ts +1 -1
- package/src/forms/controls/big-radio-group.ts +2 -2
- package/src/forms/controls/checkbox-group.ts +9 -9
- package/src/forms/controls/checkboxed-list-input.ts +27 -15
- package/src/forms/controls/controls.ts +2 -2
- package/src/forms/controls/derived-frame.ts +5 -1
- package/src/forms/controls/derived.ts +1 -1
- package/src/forms/controls/dropdown.ts +5 -2
- package/src/forms/controls/editable-collection-subset.ts +2 -2
- package/src/forms/controls/file.test.ts +4 -2
- package/src/forms/controls/file.ts +31 -5
- package/src/forms/controls/form-control.ts +7 -2
- package/src/forms/controls/hidden-input.ts +4 -1
- package/src/forms/controls/{photo.test.ts → image.test.ts} +5 -22
- package/src/forms/controls/{photo.ts → image.ts} +3 -5
- package/src/forms/controls/multiple-files.ts +18 -1
- package/src/forms/controls/{multiple-photos.ts → multiple-images.ts} +1 -1
- package/src/forms/controls/number.ts +1 -1
- package/src/forms/controls/simple-input.ts +18 -34
- package/src/forms/controls/single-reference.ts +10 -2
- package/src/forms/controls/table.ts +90 -31
- package/src/forms/controls/textarea.ts +6 -4
- package/src/forms/controls/tickable.ts +13 -5
- package/src/forms/fields/boolean.ts +23 -1
- package/src/forms/fields/checkboxed-list.ts +11 -2
- package/src/forms/fields/collection-field.ts +16 -1
- package/src/forms/fields/color.ts +9 -0
- package/src/forms/fields/coordinates.ts +66 -0
- package/src/forms/fields/date.ts +50 -0
- package/src/forms/fields/datetime.ts +66 -0
- package/src/forms/fields/deep-reverse-single-reference-list.ts +136 -0
- package/src/forms/fields/deep-reverse-single-reference-table.ts +213 -0
- package/src/forms/fields/email.ts +9 -0
- package/src/forms/fields/enum-multiple-sealious.ts +48 -0
- package/src/forms/fields/field.test.ts +5 -5
- package/src/forms/fields/field.ts +94 -8
- package/src/forms/fields/fields.ts +23 -8
- package/src/forms/fields/file.test.ts +4 -16
- package/src/forms/fields/file.ts +43 -15
- package/src/forms/fields/float.ts +9 -0
- package/src/forms/fields/get-field-for-sealious.ts +304 -0
- package/src/forms/fields/html.ts +15 -0
- package/src/forms/fields/image.ts +12 -0
- package/src/forms/fields/int.ts +25 -0
- package/src/forms/fields/json.ts +48 -0
- package/src/forms/fields/markdown.ts +15 -0
- package/src/forms/fields/multiple-files.ts +10 -1
- package/src/forms/fields/number.ts +8 -1
- package/src/forms/fields/password.ts +17 -0
- package/src/forms/fields/pick-from-list-sealious.ts +22 -0
- package/src/forms/fields/pick-from-list.ts +7 -3
- package/src/forms/fields/proxy-field.ts +6 -1
- package/src/forms/fields/regexp.ts +27 -1
- package/src/forms/fields/simple-form-field.ts +95 -7
- package/src/forms/fields/single-reference.ts +62 -0
- package/src/forms/fields/structured-array.ts +115 -18
- package/src/forms/fields/table.ts +32 -1
- package/src/forms/fields/text.ts +18 -0
- package/src/forms/fields/url.ts +20 -0
- package/src/forms/form-types.ts +2 -0
- package/src/forms/form.test.ts +3 -4
- package/src/forms/form.ts +37 -16
- package/src/forms/forms.css +0 -85
- package/src/forms/multiform.test.ts +3 -3
- package/src/forms/multiform.ts +2 -0
- package/src/generate-stimulus.ts +1 -0
- package/src/index.ts +2 -1
- package/src/make-hidden-inputs.ts +1 -1
- package/src/mount.ts +14 -0
- package/src/notifier.ts +0 -1
- package/src/page/list.ts +15 -8
- package/src/page/mountable-with-fields.test.ts +1 -1
- package/src/page/mountable-with-fields.ts +18 -9
- package/src/register-external.ts +1 -1
- package/src/templates/form.ts +8 -9
- package/src/templates/multiform.ts +4 -4
- package/src/templates/page.ts +0 -2
- package/src/templates/shared/collection-create-form.ts +30 -66
- package/src/templates/shared/collection-edit-form.ts +41 -102
- package/src/templates/shared/collection-list.ts +12 -20
- package/src/templates/shared/item-delete.ts +0 -1
- package/src/templates/shared/shared-crud-form-fields.ts +37 -171
- package/src/test_utils/test-on-real-app.ts +4 -3
- package/src/utils/extract-fields-from-collection.ts +76 -25
- package/src/utils/make-slug.ts +1 -1
- package/src/utils/wrap-attributes.ts +17 -0
- package/lib/add-verbose-crud.js +0 -119
- package/lib/crud-field-snippets.js +0 -52
- package/lib/find-css-includes.js +0 -3
- package/lib/forms/controls/reverse-single-reference.js +0 -1
- package/lib/forms/fields/enum-multiple.js +0 -47
- package/lib/forms/fields/enum-multiple.test.js +0 -27
- package/lib/forms/fields/enum.js +0 -41
- package/lib/forms/fields/enum.test.js +0 -21
- package/lib/forms/fields/reverse-single-reference.js +0 -17
- package/lib/templates/shared/handlers/boolean.js +0 -14
- package/lib/templates/shared/handlers/date.js +0 -8
- package/lib/templates/shared/handlers/deep-reverse-single-reference.js +0 -209
- package/lib/templates/shared/handlers/default.js +0 -49
- package/lib/templates/shared/handlers/enum.js +0 -19
- package/lib/templates/shared/handlers/file.js +0 -23
- package/lib/templates/shared/handlers/image.js +0 -32
- package/lib/templates/shared/handlers/int.js +0 -11
- package/lib/templates/shared/handlers/jdd.js +0 -10
- package/lib/templates/shared/handlers/single-reference.js +0 -12
- package/lib/templates/shared/handlers/structured-array.js +0 -33
- package/src/add-verbose-crud.ts +0 -138
- package/src/crud-field-snippets.ts +0 -57
- package/src/find-css-includes.ts +0 -3
- package/src/forms/controls/reverse-single-reference.ts +0 -50
- package/src/forms/fields/enum-multiple.test.ts +0 -31
- package/src/forms/fields/enum-multiple.ts +0 -62
- package/src/forms/fields/enum.test.ts +0 -25
- package/src/forms/fields/enum.ts +0 -56
- package/src/forms/fields/reverse-single-reference.ts +0 -20
- package/src/templates/shared/handlers/boolean.ts +0 -18
- package/src/templates/shared/handlers/date.ts +0 -12
- package/src/templates/shared/handlers/deep-reverse-single-reference.ts +0 -244
- package/src/templates/shared/handlers/default.ts +0 -64
- package/src/templates/shared/handlers/enum.ts +0 -23
- package/src/templates/shared/handlers/file.ts +0 -27
- package/src/templates/shared/handlers/image.ts +0 -45
- package/src/templates/shared/handlers/int.ts +0 -15
- package/src/templates/shared/handlers/jdd.ts +0 -14
- package/src/templates/shared/handlers/single-reference.ts +0 -16
- package/src/templates/shared/handlers/structured-array.ts +0 -42
|
@@ -22,9 +22,9 @@ export class EditableCollectionSubset extends FormFieldControl {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
25
|
-
const { parsed: values } = await this.field.
|
|
25
|
+
const { parsed: values } = await this.field.getParsedValue(
|
|
26
26
|
fctx.ctx,
|
|
27
|
-
fctx.data
|
|
27
|
+
fctx.data.raw_values
|
|
28
28
|
);
|
|
29
29
|
|
|
30
30
|
return tempstream/* HTML */ `<div>
|
|
@@ -12,6 +12,7 @@ import _locreq from "locreq";
|
|
|
12
12
|
import { module_dirname } from "../../utils/module-dirname.js";
|
|
13
13
|
import { FileManager, PathFilePointer } from "@sealcode/file-manager";
|
|
14
14
|
import assert from "node:assert";
|
|
15
|
+
|
|
15
16
|
const locreq = _locreq(module_dirname(import.meta.url));
|
|
16
17
|
|
|
17
18
|
describe("file-control", () => {
|
|
@@ -26,12 +27,12 @@ describe("file-control", () => {
|
|
|
26
27
|
|
|
27
28
|
it("doesn't require image input if it already has old-value", async () => {
|
|
28
29
|
const port = await getPort();
|
|
29
|
-
console.log(`Using port ${port} for
|
|
30
|
+
console.log(`Using port ${port} for image.test.ts`);
|
|
30
31
|
const app = new Koa();
|
|
31
32
|
const router = new Router();
|
|
32
33
|
|
|
33
34
|
const fields = {
|
|
34
|
-
file: new Fields.File(true
|
|
35
|
+
file: new Fields.File(true),
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
let submit_called = false;
|
|
@@ -63,6 +64,7 @@ describe("file-control", () => {
|
|
|
63
64
|
})(),
|
|
64
65
|
true
|
|
65
66
|
);
|
|
67
|
+
|
|
66
68
|
app.use(router.routes()).use(router.allowedMethods());
|
|
67
69
|
server = app.listen(port);
|
|
68
70
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
1
5
|
import { Context } from "koa";
|
|
2
|
-
import { FilePointer } from "@sealcode/file-manager";
|
|
6
|
+
import { FilePointer, PathFilePointer } from "@sealcode/file-manager";
|
|
3
7
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
4
|
-
import { FileContainer } from "../fields/file.js";
|
|
5
8
|
import { FormDataValue } from "../form-types.js";
|
|
6
9
|
import { FormControlContext } from "./form-control.js";
|
|
7
10
|
import { SimpleInput } from "./simple-input.js";
|
|
8
11
|
import { htmlEscape } from "escape-goat";
|
|
12
|
+
import { extname } from "node:path";
|
|
9
13
|
|
|
10
|
-
export class File extends SimpleInput
|
|
14
|
+
export class File extends SimpleInput {
|
|
11
15
|
getType() {
|
|
12
16
|
return "file";
|
|
13
17
|
}
|
|
@@ -21,6 +25,25 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
21
25
|
if (!file) {
|
|
22
26
|
return empty_container;
|
|
23
27
|
}
|
|
28
|
+
if (file instanceof PathFilePointer) {
|
|
29
|
+
const filename = await file.getOriginalFilename();
|
|
30
|
+
return tempstream/* HTML */ `<div class="${class_name}">
|
|
31
|
+
<div class="${class_name}__icon">
|
|
32
|
+
<picture>
|
|
33
|
+
<img
|
|
34
|
+
src="/dist/sealgen/file-icon.svg"
|
|
35
|
+
width="80"
|
|
36
|
+
height="80"
|
|
37
|
+
alt=""
|
|
38
|
+
/>
|
|
39
|
+
<span class="${class_name}__icon__extension"
|
|
40
|
+
>${extname(filename)}</span
|
|
41
|
+
>
|
|
42
|
+
</picture>
|
|
43
|
+
<a href="${file.getURL()}" download>${filename}</a>
|
|
44
|
+
</div>
|
|
45
|
+
</div>`;
|
|
46
|
+
}
|
|
24
47
|
return tempstream/* HTML */ `<div class="${class_name}">
|
|
25
48
|
${file.getOriginalFilename()}
|
|
26
49
|
</div>`;
|
|
@@ -30,7 +53,7 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
30
53
|
fctx: FormControlContext,
|
|
31
54
|
data: Record<string, FormDataValue>
|
|
32
55
|
) {
|
|
33
|
-
let { parsed } = await this.field.
|
|
56
|
+
let { parsed } = await this.field.getParsedValue(fctx.ctx, data);
|
|
34
57
|
if (parsed === null) {
|
|
35
58
|
parsed = { old: null, new: null };
|
|
36
59
|
}
|
|
@@ -52,7 +75,10 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
52
75
|
fctx: FormControlContext
|
|
53
76
|
): Promise<Record<string, string | boolean>> {
|
|
54
77
|
const original = await super.getInputAttributes(fctx);
|
|
55
|
-
const { parsed } = await this.field.
|
|
78
|
+
const { parsed } = await this.field.getParsedValue(
|
|
79
|
+
fctx.ctx,
|
|
80
|
+
fctx.data.raw_values
|
|
81
|
+
);
|
|
56
82
|
return {
|
|
57
83
|
...original,
|
|
58
84
|
name: this.field.name + "[new]",
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import Router from "@koa/router";
|
|
2
2
|
import { Context } from "koa";
|
|
3
3
|
import { FlatTemplatable } from "tempstream";
|
|
4
|
-
import {
|
|
4
|
+
import { FormMessage, FormData } from "../form-types.js";
|
|
5
5
|
import type { Form } from "../form.js";
|
|
6
6
|
|
|
7
|
+
export type FieldMessages<Fieldnames extends string = string> = Record<
|
|
8
|
+
Fieldnames,
|
|
9
|
+
{ type: "error" | "info"; message: string }
|
|
10
|
+
>;
|
|
11
|
+
|
|
7
12
|
export class FormControlContext {
|
|
8
13
|
constructor(
|
|
9
14
|
public ctx: Context,
|
|
10
|
-
public data:
|
|
15
|
+
public data: FormData,
|
|
11
16
|
public messages: FormMessage[],
|
|
12
17
|
public field_name_prefix: string,
|
|
13
18
|
public form_id: string,
|
|
@@ -10,7 +10,10 @@ export class HiddenInput extends FormFieldControl {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
13
|
-
const { raw } = await this.field.
|
|
13
|
+
const { raw } = await this.field.getParsedValue(
|
|
14
|
+
fctx.ctx,
|
|
15
|
+
fctx.data.raw_values
|
|
16
|
+
);
|
|
14
17
|
return tempstream`<input type="hidden" name="${
|
|
15
18
|
this.field.name
|
|
16
19
|
}" value="${attribute((raw || "").toString())}" form="${
|
|
@@ -7,8 +7,7 @@ import { mount } from "../../mount.js";
|
|
|
7
7
|
import { Form } from "../form.js";
|
|
8
8
|
import { getBrowser } from "../../utils/browser-creator.js";
|
|
9
9
|
import { Fields } from "../../index.js";
|
|
10
|
-
import {
|
|
11
|
-
import { KoaResponsiveImageRouter } from "koa-responsive-image-router";
|
|
10
|
+
import { Image } from "./image.js";
|
|
12
11
|
|
|
13
12
|
import _locreq from "locreq";
|
|
14
13
|
import { module_dirname } from "../../utils/module-dirname.js";
|
|
@@ -33,25 +32,17 @@ describe("photo-control", () => {
|
|
|
33
32
|
const router = new Router();
|
|
34
33
|
|
|
35
34
|
const fields = {
|
|
36
|
-
photo: new Fields.File(false
|
|
35
|
+
photo: new Fields.File(false),
|
|
37
36
|
};
|
|
38
37
|
|
|
39
38
|
let received_photo: unknown;
|
|
40
39
|
|
|
41
|
-
const imageRouter = new KoaResponsiveImageRouter({
|
|
42
|
-
staticPath: "/images",
|
|
43
|
-
thumbnailSize: 20,
|
|
44
|
-
cacheManagerResolutionThreshold: 50,
|
|
45
|
-
imageStoragePath: `/tmp/image-cache-${port}`,
|
|
46
|
-
smartCropStoragePath: `/tmp/smartcrop-storage-${port}`,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
40
|
mount(
|
|
50
41
|
router,
|
|
51
42
|
"/",
|
|
52
43
|
new (class extends Form<typeof fields, unknown> {
|
|
53
44
|
fields = fields;
|
|
54
|
-
controls = [new
|
|
45
|
+
controls = [new Image(fields.photo)];
|
|
55
46
|
|
|
56
47
|
async onSubmit(ctx: Context) {
|
|
57
48
|
const data = await this.getParsedValues(ctx);
|
|
@@ -92,19 +83,11 @@ describe("photo-control", () => {
|
|
|
92
83
|
const router = new Router();
|
|
93
84
|
|
|
94
85
|
const fields = {
|
|
95
|
-
photo: new Fields.File(true
|
|
86
|
+
photo: new Fields.File(true),
|
|
96
87
|
};
|
|
97
88
|
|
|
98
89
|
let received_photo: unknown;
|
|
99
90
|
|
|
100
|
-
const imageRouter = new KoaResponsiveImageRouter({
|
|
101
|
-
staticPath: "/images",
|
|
102
|
-
thumbnailSize: 20,
|
|
103
|
-
cacheManagerResolutionThreshold: 50,
|
|
104
|
-
imageStoragePath: `/tmp/image-cache-${port}`,
|
|
105
|
-
smartCropStoragePath: `/tmp/smartcrop-storage-${port}`,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
91
|
let submit_called = false;
|
|
109
92
|
|
|
110
93
|
mount(
|
|
@@ -112,7 +95,7 @@ describe("photo-control", () => {
|
|
|
112
95
|
"/",
|
|
113
96
|
new (class extends Form<typeof fields, unknown> {
|
|
114
97
|
fields = fields;
|
|
115
|
-
controls = [new
|
|
98
|
+
controls = [new Image(fields.photo)];
|
|
116
99
|
|
|
117
100
|
async onSubmit(ctx: Context) {
|
|
118
101
|
submit_called = true;
|
|
@@ -5,13 +5,11 @@ import { FormField } from "../fields/field.js";
|
|
|
5
5
|
import { SimpleInputOptions } from "./simple-input.js";
|
|
6
6
|
import { FormControlContext } from "./form-control.js";
|
|
7
7
|
import { FileContainer } from "../fields/file.js";
|
|
8
|
-
import { KoaResponsiveImageRouter } from "koa-responsive-image-router";
|
|
9
8
|
import { FilePointer } from "@sealcode/file-manager";
|
|
10
9
|
|
|
11
|
-
export class
|
|
10
|
+
export class Image extends File {
|
|
12
11
|
constructor(
|
|
13
12
|
public field: FormField<boolean, FileContainer>,
|
|
14
|
-
public imageRouter: KoaResponsiveImageRouter,
|
|
15
13
|
options?: SimpleInputOptions
|
|
16
14
|
) {
|
|
17
15
|
super(field, options);
|
|
@@ -22,7 +20,7 @@ export class Photo extends File {
|
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
async renderFilePreview(
|
|
25
|
-
|
|
23
|
+
ctx: Context,
|
|
26
24
|
file: FilePointer | null
|
|
27
25
|
): Promise<FlatTemplatable> {
|
|
28
26
|
const class_name = "file_preview";
|
|
@@ -31,7 +29,7 @@ export class Photo extends File {
|
|
|
31
29
|
return empty_container;
|
|
32
30
|
}
|
|
33
31
|
return tempstream/* HTML */ `<div class="${class_name}">
|
|
34
|
-
${
|
|
32
|
+
${ctx.$app.imageRouter.image(await file.getPath(), {
|
|
35
33
|
resolutions: [100, 200],
|
|
36
34
|
sizesAttr: "100px",
|
|
37
35
|
crop: { width: 100, height: 100 },
|
|
@@ -151,7 +151,7 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
151
151
|
if (!token) {
|
|
152
152
|
return null;
|
|
153
153
|
}
|
|
154
|
-
return await item.collection.app.
|
|
154
|
+
return await item.collection.app.fileManager.fromToken(token);
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
async renderFileItemPreview(
|
|
@@ -255,4 +255,21 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
255
255
|
`
|
|
256
256
|
);
|
|
257
257
|
}
|
|
258
|
+
|
|
259
|
+
setLabel(label: string) {
|
|
260
|
+
this.options.label = label;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
setUploadLabel(label: string) {
|
|
264
|
+
this.options.uploadLabel = label;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
setAdditionalFieldsGetter(
|
|
268
|
+
fn: (
|
|
269
|
+
ctx: Context,
|
|
270
|
+
file: FilePointer
|
|
271
|
+
) => Promise<Record<string, unknown>>
|
|
272
|
+
) {
|
|
273
|
+
this.options.getAdditionalFields = fn;
|
|
274
|
+
}
|
|
258
275
|
}
|
|
@@ -5,7 +5,7 @@ import { MultipleFiles, MultipleFilesOptions } from "./multiple-files.js";
|
|
|
5
5
|
import { MultipleFiles as MultipleFilesField } from "../fields/multiple-files.js";
|
|
6
6
|
import { KoaResponsiveImageRouter } from "koa-responsive-image-router";
|
|
7
7
|
|
|
8
|
-
export class
|
|
8
|
+
export class MultipleImages extends MultipleFiles {
|
|
9
9
|
constructor(
|
|
10
10
|
public field: MultipleFilesField,
|
|
11
11
|
public imageRouter: KoaResponsiveImageRouter,
|
|
@@ -4,7 +4,7 @@ import { SimpleInput, SimpleInputOptions } from "./simple-input.js";
|
|
|
4
4
|
|
|
5
5
|
export type NumberOptions = SimpleInputOptions & Partial<{ step: number }>;
|
|
6
6
|
|
|
7
|
-
export class Number extends SimpleInput
|
|
7
|
+
export class Number extends SimpleInput {
|
|
8
8
|
field: NumberField;
|
|
9
9
|
options: NumberOptions;
|
|
10
10
|
constructor(field: NumberField, options: NumberOptions) {
|
|
@@ -12,36 +12,20 @@ export type SimpleInputOptions = {
|
|
|
12
12
|
label?: string;
|
|
13
13
|
autocomplete?: boolean;
|
|
14
14
|
hide_errors?: boolean;
|
|
15
|
-
type?:
|
|
16
|
-
| "color"
|
|
17
|
-
| "date"
|
|
18
|
-
| "email"
|
|
19
|
-
| "file"
|
|
20
|
-
| "month"
|
|
21
|
-
| "number"
|
|
22
|
-
| "password"
|
|
23
|
-
| "search"
|
|
24
|
-
| "tel"
|
|
25
|
-
| "text"
|
|
26
|
-
| "time"
|
|
27
|
-
| "url"
|
|
28
|
-
| "week";
|
|
15
|
+
type?: string;
|
|
29
16
|
value?: string;
|
|
30
17
|
placeholder?: string;
|
|
31
18
|
readonly?: boolean;
|
|
32
19
|
step?: number;
|
|
33
20
|
suffix?: string;
|
|
21
|
+
pattern?: string;
|
|
34
22
|
};
|
|
35
23
|
|
|
36
24
|
export class SimpleInput<
|
|
37
|
-
ParsedValue,
|
|
38
25
|
Options extends SimpleInputOptions = SimpleInputOptions
|
|
39
26
|
> extends FormFieldControl {
|
|
40
27
|
options: SimpleInputOptions;
|
|
41
|
-
constructor(
|
|
42
|
-
public field: FormField<boolean, ParsedValue>,
|
|
43
|
-
options?: Options
|
|
44
|
-
) {
|
|
28
|
+
constructor(public field: FormField<boolean, any>, options?: Options) {
|
|
45
29
|
super([field]);
|
|
46
30
|
this.options = options || {};
|
|
47
31
|
}
|
|
@@ -78,29 +62,23 @@ export class SimpleInput<
|
|
|
78
62
|
): Promise<Record<string, string | boolean>> {
|
|
79
63
|
const readonly = this.options.readonly || false;
|
|
80
64
|
const required = this.field.required;
|
|
81
|
-
const {
|
|
65
|
+
const { raw, valid } = await this.field.getParsedValue(
|
|
82
66
|
fctx.ctx,
|
|
83
|
-
fctx.data,
|
|
67
|
+
fctx.data.raw_values,
|
|
84
68
|
true
|
|
85
69
|
);
|
|
86
70
|
return Object.fromEntries([
|
|
87
71
|
<const>["id", this.getID()],
|
|
88
72
|
<const>["type", this.getType()],
|
|
89
73
|
<const>["name", `${fctx.field_name_prefix}${this.field.name}`],
|
|
90
|
-
<const>[
|
|
91
|
-
"value",
|
|
92
|
-
!valid && raw
|
|
93
|
-
? raw.toString()
|
|
94
|
-
: parsed !== undefined && parsed !== null
|
|
95
|
-
? (parsed as string)?.toString() || ""
|
|
96
|
-
: "",
|
|
97
|
-
],
|
|
74
|
+
<const>["value", raw],
|
|
98
75
|
...(fctx.form_id ? [["form", fctx.form_id]] : []),
|
|
99
76
|
<const>["placeholder", this.getPlaceholder()],
|
|
100
77
|
...(readonly ? [["readonly", true]] : []),
|
|
101
78
|
...(required ? [["required", true]] : []),
|
|
102
79
|
...(!this.options.autocomplete ? [["autocomplete", "off"]] : []),
|
|
103
80
|
...(this.options.step ? [["step", this.options.step]] : []),
|
|
81
|
+
["aria-invalid", String(!valid)],
|
|
104
82
|
]) as Record<string, string>;
|
|
105
83
|
}
|
|
106
84
|
|
|
@@ -131,9 +109,9 @@ export class SimpleInput<
|
|
|
131
109
|
const id = this.getID();
|
|
132
110
|
const label = this.getLabel();
|
|
133
111
|
|
|
134
|
-
const { valid, message } = await this.field.
|
|
112
|
+
const { valid, message } = await this.field.getParsedValue(
|
|
135
113
|
fctx.ctx,
|
|
136
|
-
fctx.data,
|
|
114
|
+
fctx.data.raw_values,
|
|
137
115
|
true
|
|
138
116
|
);
|
|
139
117
|
return inputWrapper(
|
|
@@ -141,15 +119,21 @@ export class SimpleInput<
|
|
|
141
119
|
this.getWrapperModifiers(),
|
|
142
120
|
tempstream/* HTML */ `
|
|
143
121
|
${label ? `<label for="${id}">${label}</label>` : ""}
|
|
144
|
-
${await this.preInput(fctx, fctx.data)}
|
|
122
|
+
${await this.preInput(fctx, fctx.data.raw_values)}
|
|
145
123
|
${this.renderInput(
|
|
146
124
|
fctx.ctx,
|
|
147
125
|
renderAttributes(await this.getInputAttributes(fctx)),
|
|
148
|
-
fctx.data
|
|
126
|
+
fctx.data.raw_values
|
|
149
127
|
)}
|
|
150
128
|
${this.postInput(fctx.ctx)}
|
|
151
129
|
${~valid && !this.options.hide_errors && fctx.validate
|
|
152
|
-
? `<div class="input__error">${
|
|
130
|
+
? `<div class="input__error">${[
|
|
131
|
+
message,
|
|
132
|
+
fctx.data.field_messages?.[this.field.name]
|
|
133
|
+
?.message,
|
|
134
|
+
]
|
|
135
|
+
.filter((e) => !!e)
|
|
136
|
+
.join(" · ")}</div>`
|
|
153
137
|
: ""}
|
|
154
138
|
`
|
|
155
139
|
);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { FieldTypes as SealiousFieldTypes } from "sealious";
|
|
2
2
|
import { CollectionField } from "../fields/collection-field.js";
|
|
3
3
|
import { DropdownOptions, FreeformDropdown } from "./dropdown.js";
|
|
4
4
|
import { Collection, CollectionItem } from "sealious";
|
|
5
5
|
|
|
6
6
|
export class SingleReferenceDropdown<
|
|
7
|
-
|
|
7
|
+
TargetCollection extends Collection,
|
|
8
|
+
F extends SealiousFieldTypes.SingleReference,
|
|
8
9
|
Required extends boolean
|
|
9
10
|
> extends FreeformDropdown {
|
|
10
11
|
constructor(
|
|
@@ -38,4 +39,11 @@ export class SingleReferenceDropdown<
|
|
|
38
39
|
options
|
|
39
40
|
);
|
|
40
41
|
}
|
|
42
|
+
|
|
43
|
+
setOptionLabelGetter(
|
|
44
|
+
getter: (item: CollectionItem<TargetCollection>) => string
|
|
45
|
+
): this {
|
|
46
|
+
this.options.getLabel = getter;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
41
49
|
}
|
|
@@ -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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
${
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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>
|
|
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
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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="
|
|
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
|
|
7
|
+
export class Textarea extends SimpleInput {
|
|
8
8
|
constructor(
|
|
9
|
-
public field: FormField<boolean
|
|
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.
|
|
53
|
-
return /* HTML */ `<textarea ${attributes}
|
|
52
|
+
const { parsed: value } = await this.field.getParsedValue(ctx, data);
|
|
53
|
+
return /* HTML */ `<textarea ${attributes}>
|
|
54
|
+
${String(value) || ""}</textarea
|
|
55
|
+
>`;
|
|
54
56
|
}
|
|
55
57
|
}
|