@sealcode/sealgen 0.18.10 → 0.19.2
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/.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 +20 -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 +5 -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/register-external.d.ts +2 -2
- package/@types/templates/form.d.ts +1 -3
- package/@types/templates/jdd-component.d.ts +1 -1
- package/@types/templates/page.d.ts +1 -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 +1 -68
- package/@types/templates/templates.d.ts +1 -21
- 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/eslint.config.mjs +56 -0
- package/lib/add-crud.js +77 -89
- package/lib/add-jdd-component.js +3 -3
- package/lib/add-list-route.test.js +1 -1
- package/lib/add-route.js +2 -9
- package/lib/build.js +6 -4
- package/lib/builders/backend-ts-builder.js +0 -1
- package/lib/builders/colors-builder.js +11 -8
- package/lib/builders/fonts-builder.js +0 -1
- package/lib/builders/frontend-ts-builder.js +0 -1
- package/lib/cli.js +4 -7
- package/lib/components/tabs.js +36 -36
- package/lib/controllers/table-add-button.stimulus.js +35 -0
- package/lib/esbuild-plugins/rewrite-asset-imports.js +7 -10
- package/lib/forms/controls/array.js +25 -22
- 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 +7 -1
- package/lib/forms/controls/checkboxed-list-input.test.js +6 -6
- package/lib/forms/controls/controls.js +2 -2
- package/lib/forms/controls/derived-frame.js +8 -4
- package/lib/forms/controls/derived.js +1 -1
- package/lib/forms/controls/dropdown.js +5 -3
- 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/form-control.js +1 -1
- 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} +8 -23
- 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/single-reference.test.js +1 -1
- package/lib/forms/controls/table.js +62 -25
- package/lib/forms/controls/textarea.js +5 -3
- 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 +8 -8
- package/lib/forms/fields/fields.js +23 -8
- package/lib/forms/fields/file.js +33 -9
- package/lib/forms/fields/file.test.js +5 -17
- 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 +61 -2
- package/lib/forms/fields/single-reference.js +44 -0
- package/lib/forms/fields/structured-array.js +61 -12
- package/lib/forms/fields/table.js +29 -2
- package/lib/forms/fields/text.js +17 -0
- package/lib/forms/fields/url.js +17 -0
- package/lib/forms/form.js +30 -14
- package/lib/forms/form.test.js +5 -7
- package/lib/forms/multiform.js +10 -9
- package/lib/forms/multiform.test.js +5 -5
- package/lib/generate-collections.js +2 -3
- package/lib/generate-components.js +2 -3
- package/lib/generate-routes.js +3 -5
- package/lib/generate-routes.test.js +7 -16
- package/lib/generate-stimulus.js +4 -4
- package/lib/get-fonts.js +29 -27
- package/lib/index.js +1 -0
- package/lib/make-env.js +1 -1
- package/lib/make-hidden-inputs.js +4 -4
- package/lib/mount.js +11 -1
- package/lib/notifier.js +3 -4
- package/lib/page/list.js +20 -15
- package/lib/page/mountable-with-fields.js +14 -6
- package/lib/page/mountable-with-fields.test.js +1 -1
- package/lib/page/mountable.js +0 -1
- package/lib/page/page.js +0 -1
- package/lib/register-external.js +4 -4
- package/lib/templates/form.js +9 -10
- package/lib/templates/jdd-component.js +1 -1
- package/lib/templates/jdd-editor.js +1 -1
- package/lib/templates/multiform.js +4 -4
- package/lib/templates/page.js +1 -3
- package/lib/templates/shared/collection-create-form.js +31 -44
- package/lib/templates/shared/collection-edit-form.js +43 -81
- package/lib/templates/shared/collection-list.js +13 -21
- package/lib/templates/shared/shared-crud-form-fields.js +28 -98
- package/lib/test_utils/exec_async.js +3 -3
- package/lib/test_utils/test-on-real-app.js +12 -14
- 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/lib/utils/write-file.js +1 -1
- package/package.json +11 -9
- package/src/add-collection.ts +1 -3
- package/src/add-crud.ts +84 -100
- package/src/add-jdd-component.ts +4 -5
- package/src/add-list-route.test.ts +1 -1
- package/src/add-route.ts +3 -13
- package/src/build.ts +6 -4
- package/src/builders/backend-ts-builder.ts +0 -1
- package/src/builders/builder.ts +4 -1
- package/src/builders/colors-builder.ts +11 -9
- package/src/builders/css-builder.ts +4 -1
- package/src/builders/fonts-builder.ts +0 -1
- package/src/builders/frontend-ts-builder.ts +0 -1
- package/src/cli.ts +5 -7
- package/src/components/tabs.ts +38 -37
- package/src/components/toggle-modal.ts +1 -1
- package/src/controllers/table-add-button.stimulus.ts +35 -0
- package/src/esbuild-plugins/rewrite-asset-imports.ts +7 -10
- package/src/forms/controls/array.ts +35 -36
- package/src/forms/controls/autocomplete.ts +2 -2
- package/src/forms/controls/big-radio-group.ts +4 -4
- package/src/forms/controls/checkbox-group.ts +10 -10
- package/src/forms/controls/checkboxed-list-input.test.ts +6 -6
- package/src/forms/controls/checkboxed-list-input.ts +16 -8
- package/src/forms/controls/controls.ts +2 -2
- package/src/forms/controls/derived-frame.ts +16 -11
- package/src/forms/controls/derived.ts +7 -6
- package/src/forms/controls/dropdown.ts +13 -13
- package/src/forms/controls/editable-collection-subset.ts +4 -3
- package/src/forms/controls/field-group.ts +1 -1
- package/src/forms/controls/file.test.ts +4 -2
- package/src/forms/controls/file.ts +30 -7
- package/src/forms/controls/form-control.ts +8 -3
- package/src/forms/controls/hidden-input.ts +5 -1
- package/src/forms/controls/html.ts +1 -0
- package/src/forms/controls/{photo.test.ts → image.test.ts} +7 -24
- package/src/forms/controls/{photo.ts → image.ts} +4 -6
- package/src/forms/controls/multiple-files.ts +23 -8
- package/src/forms/controls/{multiple-photos.ts → multiple-images.ts} +2 -2
- package/src/forms/controls/number.ts +1 -1
- package/src/forms/controls/simple-input.ts +21 -33
- package/src/forms/controls/single-reference.test.ts +1 -1
- package/src/forms/controls/single-reference.ts +11 -3
- package/src/forms/controls/table.ts +87 -33
- package/src/forms/controls/textarea.ts +7 -5
- package/src/forms/controls/tickable.ts +13 -7
- package/src/forms/fields/boolean.ts +27 -2
- package/src/forms/fields/checkboxed-list.ts +11 -2
- package/src/forms/fields/collection-field.ts +21 -3
- 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 +130 -0
- package/src/forms/fields/deep-reverse-single-reference-table.ts +213 -0
- package/src/forms/fields/email.ts +10 -1
- package/src/forms/fields/enum-multiple-sealious.ts +48 -0
- package/src/forms/fields/existing-sealious-value.ts +1 -1
- package/src/forms/fields/field.test.ts +8 -8
- package/src/forms/fields/field.ts +98 -11
- package/src/forms/fields/fields.ts +23 -8
- package/src/forms/fields/file.test.ts +5 -17
- package/src/forms/fields/file.ts +44 -16
- package/src/forms/fields/float.ts +9 -0
- package/src/forms/fields/get-field-for-sealious.ts +337 -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 +10 -3
- package/src/forms/fields/password.ts +13 -0
- package/src/forms/fields/pick-from-list-sealious.ts +22 -0
- package/src/forms/fields/pick-from-list.ts +8 -4
- package/src/forms/fields/proxy-field.ts +7 -1
- package/src/forms/fields/regexp.ts +27 -1
- package/src/forms/fields/simple-form-field.ts +103 -7
- package/src/forms/fields/single-reference.ts +62 -0
- package/src/forms/fields/structured-array.ts +111 -18
- package/src/forms/fields/table.ts +39 -16
- package/src/forms/fields/text.ts +18 -0
- package/src/forms/fields/url.ts +20 -0
- package/src/forms/form-types.ts +5 -4
- package/src/forms/form.test.ts +5 -7
- package/src/forms/form.ts +42 -23
- package/src/forms/forms.css +0 -85
- package/src/forms/multiform.test.ts +9 -9
- package/src/forms/multiform.ts +12 -10
- package/src/generate-collections.ts +2 -3
- package/src/generate-components.ts +2 -3
- package/src/generate-routes.test.ts +7 -16
- package/src/generate-routes.ts +6 -10
- package/src/generate-stimulus.ts +4 -5
- package/src/get-fonts.ts +32 -30
- package/src/index.ts +2 -1
- package/src/make-env.ts +1 -1
- package/src/make-hidden-inputs.ts +8 -7
- package/src/mount.ts +16 -7
- package/src/notifier.ts +4 -7
- package/src/page/default-list-filters.ts +1 -0
- package/src/page/list.ts +33 -28
- package/src/page/mountable-with-fields.test.ts +1 -1
- package/src/page/mountable-with-fields.ts +21 -12
- package/src/page/mountable.ts +0 -1
- package/src/page/page.ts +2 -3
- package/src/page/props-parser.ts +1 -1
- package/src/page/sealious-list.ts +1 -1
- package/src/page/stateful-page.ts +6 -10
- package/src/register-external.ts +5 -5
- package/src/templates/form.ts +9 -11
- package/src/templates/jdd-component.ts +1 -1
- package/src/templates/jdd-editor.ts +2 -4
- package/src/templates/list.ts +0 -1
- package/src/templates/multiform.ts +4 -4
- package/src/templates/page.ts +1 -6
- package/src/templates/shared/collection-create-form.ts +34 -71
- package/src/templates/shared/collection-edit-form.ts +46 -108
- package/src/templates/shared/collection-list.ts +13 -21
- package/src/templates/shared/item-delete.ts +0 -1
- package/src/templates/shared/shared-crud-form-fields.ts +38 -177
- package/src/templates/templates.ts +5 -1
- package/src/test_utils/exec_async.ts +3 -4
- package/src/test_utils/test-on-real-app.ts +13 -14
- package/src/utils/browser-creator.js +0 -1
- package/src/utils/exec.ts +0 -1
- package/src/utils/extract-fields-from-collection.ts +76 -25
- package/src/utils/input-wrapper.ts +1 -1
- package/src/utils/make-slug.ts +1 -1
- package/src/utils/wrap-attributes.ts +17 -0
- package/src/utils/write-file.ts +1 -1
- package/.eslintrc.cjs +0 -39
- 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
|
@@ -25,15 +25,16 @@ export class DerivedFrame extends Derived<{
|
|
|
25
25
|
) {
|
|
26
26
|
super(
|
|
27
27
|
fields,
|
|
28
|
-
async (values, consts) =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
async (values, consts) =>
|
|
29
|
+
/* HTML */ `<turbo-frame
|
|
30
|
+
id="${consts.frame_id}"
|
|
31
|
+
src="./${consts.frame_id}?${Object.entries({
|
|
32
|
+
...consts,
|
|
33
|
+
...(values || {}),
|
|
34
|
+
})
|
|
35
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
36
|
+
.join("&")}"
|
|
37
|
+
></turbo-frame>`,
|
|
37
38
|
async (fctx) => ({
|
|
38
39
|
form_id: fctx.form_id,
|
|
39
40
|
field_name_prefix: fctx.field_name_prefix,
|
|
@@ -44,7 +45,7 @@ export class DerivedFrame extends Derived<{
|
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
renderBackendResponseFrame(_ctx: Context, content: FlatTemplatable) {
|
|
47
|
-
return tempstream/* HTML */ `<turbo-frame
|
|
48
|
+
return tempstream /* HTML */ `<turbo-frame
|
|
48
49
|
id="${this.frame_id}"
|
|
49
50
|
target="_top"
|
|
50
51
|
>
|
|
@@ -76,7 +77,11 @@ export class DerivedFrame extends Derived<{
|
|
|
76
77
|
await this.generateFrameContent(
|
|
77
78
|
new FormControlContext(
|
|
78
79
|
ctx,
|
|
79
|
-
|
|
80
|
+
{
|
|
81
|
+
messages: [],
|
|
82
|
+
field_messages: {},
|
|
83
|
+
raw_values: ctx.query,
|
|
84
|
+
},
|
|
80
85
|
[],
|
|
81
86
|
query.field_name_prefix,
|
|
82
87
|
query.form_id,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint @typescript-eslint/no-redundant-type-constituents: off */
|
|
1
2
|
import { randomUUID } from "crypto";
|
|
2
3
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
3
4
|
import { FormField } from "../fields/field.js";
|
|
@@ -5,7 +6,7 @@ import { FormDataValue } from "../form-types.js";
|
|
|
5
6
|
import { FormControl, FormControlContext } from "./form-control.js";
|
|
6
7
|
|
|
7
8
|
export class Derived<
|
|
8
|
-
Consts extends Record<string, unknown | undefined
|
|
9
|
+
Consts extends Record<string, unknown | undefined>,
|
|
9
10
|
> extends FormControl {
|
|
10
11
|
role = <const>"decoration";
|
|
11
12
|
|
|
@@ -17,7 +18,7 @@ export class Derived<
|
|
|
17
18
|
) => Promise<FlatTemplatable>,
|
|
18
19
|
public getConsts: (
|
|
19
20
|
fctx: FormControlContext
|
|
20
|
-
) => Promise<Consts> = async () => ({} as Consts
|
|
21
|
+
) => Promise<Consts> = async () => ({}) as Consts
|
|
21
22
|
) {
|
|
22
23
|
super();
|
|
23
24
|
}
|
|
@@ -27,7 +28,7 @@ export class Derived<
|
|
|
27
28
|
): Promise<Record<string, FormDataValue>> {
|
|
28
29
|
const fieldnames = this.fields.map((f) => f.name);
|
|
29
30
|
const result = Object.fromEntries(
|
|
30
|
-
Object.entries(fctx.data).filter(([key]) =>
|
|
31
|
+
Object.entries(fctx.data.raw_values).filter(([key]) =>
|
|
31
32
|
fieldnames.includes(key)
|
|
32
33
|
)
|
|
33
34
|
);
|
|
@@ -44,7 +45,7 @@ export class Derived<
|
|
|
44
45
|
`render(${values_code}, consts)
|
|
45
46
|
.then(result=>document.querySelector("#${id}").innerHTML=result)`;
|
|
46
47
|
|
|
47
|
-
return tempstream/* HTML */ `<div>
|
|
48
|
+
return tempstream /* HTML */ `<div>
|
|
48
49
|
<script>
|
|
49
50
|
(function () {
|
|
50
51
|
const consts = ${"{" +
|
|
@@ -54,8 +55,8 @@ export class Derived<
|
|
|
54
55
|
typeof value === "object"
|
|
55
56
|
? JSON.stringify(value)
|
|
56
57
|
: typeof value == "string"
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
? '"' + value.toString() + '"'
|
|
59
|
+
: (value as string).toString()
|
|
59
60
|
}`;
|
|
60
61
|
})
|
|
61
62
|
.join(",") +
|
|
@@ -15,7 +15,7 @@ export type DropdownOptions = {
|
|
|
15
15
|
|
|
16
16
|
export type DropdownOption = { value: string; label: string };
|
|
17
17
|
|
|
18
|
-
export class FreeformDropdown extends SimpleInput
|
|
18
|
+
export class FreeformDropdown extends SimpleInput {
|
|
19
19
|
constructor(
|
|
20
20
|
public field: FormField<boolean, string | null>,
|
|
21
21
|
public _generateOptions: (ctx: Context) => Promise<DropdownOption[]>,
|
|
@@ -46,7 +46,7 @@ export class FreeformDropdown extends SimpleInput<string | null> {
|
|
|
46
46
|
((original.onchange as string | undefined) ||
|
|
47
47
|
"") + ";this.form.submit();",
|
|
48
48
|
],
|
|
49
|
-
|
|
49
|
+
]
|
|
50
50
|
: []),
|
|
51
51
|
]),
|
|
52
52
|
} as Record<string, string>;
|
|
@@ -57,19 +57,19 @@ export class FreeformDropdown extends SimpleInput<string | null> {
|
|
|
57
57
|
attributes_str: string,
|
|
58
58
|
data: Record<string, FormDataValue>
|
|
59
59
|
): Promise<FlatTemplatable> {
|
|
60
|
-
const { parsed: picked_value } = await this.field.
|
|
60
|
+
const { parsed: picked_value } = await this.field.getParsedValue(
|
|
61
|
+
ctx,
|
|
62
|
+
data
|
|
63
|
+
);
|
|
61
64
|
return /* HTML */ tempstream`<select ${attributes_str}>
|
|
62
|
-
${
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
(value || "") == picked_value ? "selected" : ""
|
|
69
|
-
}>${label}</option>`
|
|
70
|
-
)
|
|
65
|
+
${Promise.resolve(this.generateOptions(ctx)).then((options) =>
|
|
66
|
+
options.map(
|
|
67
|
+
({ value, label }) =>
|
|
68
|
+
`<option value="${attribute(value)}" ${
|
|
69
|
+
(value || "") == picked_value ? "selected" : ""
|
|
70
|
+
}>${label}</option>`
|
|
71
71
|
)
|
|
72
|
-
}
|
|
72
|
+
)}
|
|
73
73
|
</select>`;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint @typescript-eslint/no-base-to-string: off */
|
|
1
2
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
2
3
|
import { attribute } from "../../sanitize.js";
|
|
3
4
|
import { PickFromListField } from "../fields/pick-from-list.js";
|
|
@@ -22,12 +23,12 @@ export class EditableCollectionSubset extends FormFieldControl {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
25
|
-
const { parsed: values } = await this.field.
|
|
26
|
+
const { parsed: values } = await this.field.getParsedValue(
|
|
26
27
|
fctx.ctx,
|
|
27
|
-
fctx.data
|
|
28
|
+
fctx.data.raw_values
|
|
28
29
|
);
|
|
29
30
|
|
|
30
|
-
return tempstream/* HTML */ `<div>
|
|
31
|
+
return tempstream /* HTML */ `<div>
|
|
31
32
|
<ul>
|
|
32
33
|
${Promise.resolve(this.field.generateOptions(fctx.ctx)).then(
|
|
33
34
|
(options) =>
|
|
@@ -41,7 +41,7 @@ export class FieldGroup extends FormFieldControl {
|
|
|
41
41
|
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
42
42
|
const { label, classes } = this.options;
|
|
43
43
|
|
|
44
|
-
return tempstream/* HTML */ `
|
|
44
|
+
return tempstream /* HTML */ `
|
|
45
45
|
<div
|
|
46
46
|
class="field-group ${(classes || []).join(" ")}"
|
|
47
47
|
${this.options.containerID
|
|
@@ -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.
|
|
30
|
+
console.info(`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,14 @@
|
|
|
1
|
+
/* eslint @typescript-eslint/no-unsafe-assignment: off, @typescript-eslint/no-unsafe-argument: off, @typescript-eslint/no-unsafe-member-access: off, @typescript-eslint/no-unsafe-call: off */
|
|
1
2
|
import { Context } from "koa";
|
|
2
|
-
import { FilePointer } from "@sealcode/file-manager";
|
|
3
|
+
import { FilePointer, PathFilePointer } from "@sealcode/file-manager";
|
|
3
4
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
4
|
-
import { FileContainer } from "../fields/file.js";
|
|
5
5
|
import { FormDataValue } from "../form-types.js";
|
|
6
6
|
import { FormControlContext } from "./form-control.js";
|
|
7
7
|
import { SimpleInput } from "./simple-input.js";
|
|
8
8
|
import { htmlEscape } from "escape-goat";
|
|
9
|
+
import { extname } from "node:path";
|
|
9
10
|
|
|
10
|
-
export class File extends SimpleInput
|
|
11
|
+
export class File extends SimpleInput {
|
|
11
12
|
getType() {
|
|
12
13
|
return "file";
|
|
13
14
|
}
|
|
@@ -21,7 +22,26 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
21
22
|
if (!file) {
|
|
22
23
|
return empty_container;
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
+
if (file instanceof PathFilePointer) {
|
|
26
|
+
const filename = await file.getOriginalFilename();
|
|
27
|
+
return tempstream /* HTML */ `<div class="${class_name}">
|
|
28
|
+
<div class="${class_name}__icon">
|
|
29
|
+
<picture>
|
|
30
|
+
<img
|
|
31
|
+
src="/dist/sealgen/file-icon.svg"
|
|
32
|
+
width="80"
|
|
33
|
+
height="80"
|
|
34
|
+
alt=""
|
|
35
|
+
/>
|
|
36
|
+
<span class="${class_name}__icon__extension"
|
|
37
|
+
>${extname(filename)}</span
|
|
38
|
+
>
|
|
39
|
+
</picture>
|
|
40
|
+
<a href="${file.getURL()}" download>${filename}</a>
|
|
41
|
+
</div>
|
|
42
|
+
</div>`;
|
|
43
|
+
}
|
|
44
|
+
return tempstream /* HTML */ `<div class="${class_name}">
|
|
25
45
|
${file.getOriginalFilename()}
|
|
26
46
|
</div>`;
|
|
27
47
|
}
|
|
@@ -30,11 +50,11 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
30
50
|
fctx: FormControlContext,
|
|
31
51
|
data: Record<string, FormDataValue>
|
|
32
52
|
) {
|
|
33
|
-
let { parsed } = await this.field.
|
|
53
|
+
let { parsed } = await this.field.getParsedValue(fctx.ctx, data);
|
|
34
54
|
if (parsed === null) {
|
|
35
55
|
parsed = { old: null, new: null };
|
|
36
56
|
}
|
|
37
|
-
return tempstream/* HTML */ `${this.renderFilePreview(
|
|
57
|
+
return tempstream /* HTML */ `${this.renderFilePreview(
|
|
38
58
|
fctx.ctx,
|
|
39
59
|
parsed.old
|
|
40
60
|
)}
|
|
@@ -52,7 +72,10 @@ export class File extends SimpleInput<FileContainer> {
|
|
|
52
72
|
fctx: FormControlContext
|
|
53
73
|
): Promise<Record<string, string | boolean>> {
|
|
54
74
|
const original = await super.getInputAttributes(fctx);
|
|
55
|
-
const { parsed } = await this.field.
|
|
75
|
+
const { parsed } = await this.field.getParsedValue(
|
|
76
|
+
fctx.ctx,
|
|
77
|
+
fctx.data.raw_values
|
|
78
|
+
);
|
|
56
79
|
return {
|
|
57
80
|
...original,
|
|
58
81
|
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,
|
|
@@ -21,6 +26,6 @@ export abstract class FormControl {
|
|
|
21
26
|
): FlatTemplatable | Promise<FlatTemplatable>;
|
|
22
27
|
abstract role: "input" | "decoration" | "messages" | "submit";
|
|
23
28
|
|
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
30
|
mount(_router: Router, _form: Form<any, any>) {}
|
|
26
31
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint @typescript-eslint/no-base-to-string: off */
|
|
1
2
|
import { FlatTemplatable, tempstream } from "tempstream";
|
|
2
3
|
import { attribute } from "../../sanitize.js";
|
|
3
4
|
import { FormField } from "../fields/field.js";
|
|
@@ -10,7 +11,10 @@ export class HiddenInput extends FormFieldControl {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
async render(fctx: FormControlContext): Promise<FlatTemplatable> {
|
|
13
|
-
const { raw } = await this.field.
|
|
14
|
+
const { raw } = await this.field.getParsedValue(
|
|
15
|
+
fctx.ctx,
|
|
16
|
+
fctx.data.raw_values
|
|
17
|
+
);
|
|
14
18
|
return tempstream`<input type="hidden" name="${
|
|
15
19
|
this.field.name
|
|
16
20
|
}" value="${attribute((raw || "").toString())}" form="${
|
|
@@ -12,6 +12,7 @@ export class HTML extends FormControl {
|
|
|
12
12
|
constructor(role: "decoration" | "submit", renderer: Renderer);
|
|
13
13
|
constructor(renderer: Renderer);
|
|
14
14
|
constructor(
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
|
15
16
|
role_or_renderer: "decoration" | "submit" | Renderer,
|
|
16
17
|
renderer_or_undefined?: Renderer | FlatTemplatable
|
|
17
18
|
) {
|
|
@@ -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";
|
|
@@ -28,30 +27,22 @@ describe("photo-control", () => {
|
|
|
28
27
|
|
|
29
28
|
it("sends the old photo if it wasn't changed and it has an initial value", async () => {
|
|
30
29
|
const port = await getPort();
|
|
31
|
-
console.
|
|
30
|
+
console.info(`Using port ${port} for photo.test.ts`);
|
|
32
31
|
const app = new Koa();
|
|
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);
|
|
@@ -87,24 +78,16 @@ describe("photo-control", () => {
|
|
|
87
78
|
|
|
88
79
|
it("doesn't require image input if it already has old-value", async () => {
|
|
89
80
|
const port = await getPort();
|
|
90
|
-
console.
|
|
81
|
+
console.info(`Using port ${port} for photo.test.ts`);
|
|
91
82
|
const app = new Koa();
|
|
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";
|
|
@@ -30,8 +28,8 @@ export class Photo extends File {
|
|
|
30
28
|
if (!file) {
|
|
31
29
|
return empty_container;
|
|
32
30
|
}
|
|
33
|
-
return tempstream/* HTML */ `<div class="${class_name}">
|
|
34
|
-
${
|
|
31
|
+
return tempstream /* HTML */ `<div class="${class_name}">
|
|
32
|
+
${ctx.$app.imageRouter.image(await file.getPath(), {
|
|
35
33
|
resolutions: [100, 200],
|
|
36
34
|
sizesAttr: "100px",
|
|
37
35
|
crop: { width: 100, height: 100 },
|
|
@@ -105,7 +105,7 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
renderFrame(_ctx: Context, content?: FlatTemplatable) {
|
|
108
|
-
return tempstream/* HTML */ `<turbo-frame
|
|
108
|
+
return tempstream /* HTML */ `<turbo-frame
|
|
109
109
|
${content ? "" : `src="./${this.getFrameRelativeURL()}"`}
|
|
110
110
|
id="${this.getFrameID()}"
|
|
111
111
|
target="_top"
|
|
@@ -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(
|
|
@@ -168,7 +168,7 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
168
168
|
if (!(file instanceof PathFilePointer)) {
|
|
169
169
|
return "";
|
|
170
170
|
}
|
|
171
|
-
return tempstream/* HTML */ `<li class="file-list-item">
|
|
171
|
+
return tempstream /* HTML */ `<li class="file-list-item">
|
|
172
172
|
<a
|
|
173
173
|
class="file-list-item__preview"
|
|
174
174
|
href="${file.getURL()}"
|
|
@@ -215,9 +215,7 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
215
215
|
async renderFrameContent(ctx: Context): Promise<FlatTemplatable> {
|
|
216
216
|
const files = (
|
|
217
217
|
await Promise.all(
|
|
218
|
-
(
|
|
219
|
-
await this.getFileItems(ctx)
|
|
220
|
-
)
|
|
218
|
+
(await this.getFileItems(ctx))
|
|
221
219
|
.filter((item) => item) // filter out undefineds
|
|
222
220
|
.map(async (item: CollectionItem<Collection>) => [
|
|
223
221
|
item,
|
|
@@ -226,13 +224,13 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
226
224
|
)
|
|
227
225
|
).filter(([_, f]) => f !== null) as [
|
|
228
226
|
CollectionItem<Collection>,
|
|
229
|
-
FilePointer
|
|
227
|
+
FilePointer,
|
|
230
228
|
][];
|
|
231
229
|
|
|
232
230
|
return inputWrapper(
|
|
233
231
|
"multiple-files",
|
|
234
232
|
["multiple-files", this.field.name, ...this.getClassModifiers()],
|
|
235
|
-
tempstream/* HTML */ `
|
|
233
|
+
tempstream /* HTML */ `
|
|
236
234
|
<label>${this.options.label || this.field.name}</label>
|
|
237
235
|
<ul class="multiple-files__list">
|
|
238
236
|
${files.map(([item, file]) =>
|
|
@@ -255,4 +253,21 @@ export class MultipleFiles extends FormFieldControl {
|
|
|
255
253
|
`
|
|
256
254
|
);
|
|
257
255
|
}
|
|
256
|
+
|
|
257
|
+
setLabel(label: string) {
|
|
258
|
+
this.options.label = label;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
setUploadLabel(label: string) {
|
|
262
|
+
this.options.uploadLabel = label;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
setAdditionalFieldsGetter(
|
|
266
|
+
fn: (
|
|
267
|
+
ctx: Context,
|
|
268
|
+
file: FilePointer
|
|
269
|
+
) => Promise<Record<string, unknown>>
|
|
270
|
+
) {
|
|
271
|
+
this.options.getAdditionalFields = fn;
|
|
272
|
+
}
|
|
258
273
|
}
|
|
@@ -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,
|
|
@@ -33,7 +33,7 @@ export class MultiplePhotos extends MultipleFiles {
|
|
|
33
33
|
if (!path) {
|
|
34
34
|
return "missing file";
|
|
35
35
|
}
|
|
36
|
-
return tempstream/* HTML */ `<li>
|
|
36
|
+
return tempstream /* HTML */ `<li>
|
|
37
37
|
<a href="${file.getURL()}" data-turbo="false">
|
|
38
38
|
${this.imageRouter.image(path, {
|
|
39
39
|
resolutions: [150, 300],
|
|
@@ -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,34 +12,22 @@ 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
|
-
|
|
38
|
-
Options extends SimpleInputOptions = SimpleInputOptions
|
|
25
|
+
Options extends SimpleInputOptions = SimpleInputOptions,
|
|
39
26
|
> extends FormFieldControl {
|
|
40
27
|
options: SimpleInputOptions;
|
|
41
28
|
constructor(
|
|
42
|
-
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
public field: FormField<boolean, any>,
|
|
43
31
|
options?: Options
|
|
44
32
|
) {
|
|
45
33
|
super([field]);
|
|
@@ -78,29 +66,23 @@ export class SimpleInput<
|
|
|
78
66
|
): Promise<Record<string, string | boolean>> {
|
|
79
67
|
const readonly = this.options.readonly || false;
|
|
80
68
|
const required = this.field.required;
|
|
81
|
-
const {
|
|
69
|
+
const { raw, valid } = await this.field.getParsedValue(
|
|
82
70
|
fctx.ctx,
|
|
83
|
-
fctx.data,
|
|
71
|
+
fctx.data.raw_values,
|
|
84
72
|
true
|
|
85
73
|
);
|
|
86
74
|
return Object.fromEntries([
|
|
87
75
|
<const>["id", this.getID()],
|
|
88
76
|
<const>["type", this.getType()],
|
|
89
77
|
<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
|
-
],
|
|
78
|
+
<const>["value", raw],
|
|
98
79
|
...(fctx.form_id ? [["form", fctx.form_id]] : []),
|
|
99
80
|
<const>["placeholder", this.getPlaceholder()],
|
|
100
81
|
...(readonly ? [["readonly", true]] : []),
|
|
101
82
|
...(required ? [["required", true]] : []),
|
|
102
83
|
...(!this.options.autocomplete ? [["autocomplete", "off"]] : []),
|
|
103
84
|
...(this.options.step ? [["step", this.options.step]] : []),
|
|
85
|
+
["aria-invalid", String(!valid)],
|
|
104
86
|
]) as Record<string, string>;
|
|
105
87
|
}
|
|
106
88
|
|
|
@@ -131,25 +113,31 @@ export class SimpleInput<
|
|
|
131
113
|
const id = this.getID();
|
|
132
114
|
const label = this.getLabel();
|
|
133
115
|
|
|
134
|
-
const { valid, message } = await this.field.
|
|
116
|
+
const { valid, message } = await this.field.getParsedValue(
|
|
135
117
|
fctx.ctx,
|
|
136
|
-
fctx.data,
|
|
118
|
+
fctx.data.raw_values,
|
|
137
119
|
true
|
|
138
120
|
);
|
|
139
121
|
return inputWrapper(
|
|
140
122
|
"simple-input",
|
|
141
123
|
this.getWrapperModifiers(),
|
|
142
|
-
tempstream/* HTML */ `
|
|
124
|
+
tempstream /* HTML */ `
|
|
143
125
|
${label ? `<label for="${id}">${label}</label>` : ""}
|
|
144
|
-
${await this.preInput(fctx, fctx.data)}
|
|
126
|
+
${await this.preInput(fctx, fctx.data.raw_values)}
|
|
145
127
|
${this.renderInput(
|
|
146
128
|
fctx.ctx,
|
|
147
129
|
renderAttributes(await this.getInputAttributes(fctx)),
|
|
148
|
-
fctx.data
|
|
130
|
+
fctx.data.raw_values
|
|
149
131
|
)}
|
|
150
132
|
${this.postInput(fctx.ctx)}
|
|
151
133
|
${~valid && !this.options.hide_errors && fctx.validate
|
|
152
|
-
? `<div class="input__error">${
|
|
134
|
+
? `<div class="input__error">${[
|
|
135
|
+
message,
|
|
136
|
+
fctx.data.field_messages?.[this.field.name]
|
|
137
|
+
?.message,
|
|
138
|
+
]
|
|
139
|
+
.filter((e) => !!e)
|
|
140
|
+
.join(" · ")}</div>`
|
|
153
141
|
: ""}
|
|
154
142
|
`
|
|
155
143
|
);
|