ngx-t-forms 2.0.30 → 2.0.32
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/fesm2022/ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs +104 -0
- package/fesm2022/ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs +85 -0
- package/fesm2022/ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs +643 -0
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs +97 -0
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs +195 -0
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs +261 -0
- package/fesm2022/ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs +85 -0
- package/fesm2022/ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs +156 -0
- package/fesm2022/ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs +368 -0
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-document-picker.component-BThdRFec.mjs +704 -0
- package/fesm2022/ngx-t-forms-document-picker.component-BThdRFec.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs +294 -0
- package/fesm2022/ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs +240 -0
- package/fesm2022/ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs +205 -0
- package/fesm2022/ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-input-selector.component-B42xP3jh.mjs +86 -0
- package/fesm2022/ngx-t-forms-form-input-selector.component-B42xP3jh.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-json-view.component-DnnLXqR0.mjs +22 -0
- package/fesm2022/ngx-t-forms-form-json-view.component-DnnLXqR0.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs +179 -0
- package/fesm2022/ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs +319 -0
- package/fesm2022/ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs +379 -0
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-geo-location.component-Bmd84Gcb.mjs +124 -0
- package/fesm2022/ngx-t-forms-geo-location.component-Bmd84Gcb.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-getInputIcon-B4ADgevZ.mjs +31 -0
- package/fesm2022/ngx-t-forms-getInputIcon-B4ADgevZ.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs +180 -0
- package/fesm2022/ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-index-BcrQ01DQ.mjs +2 -0
- package/fesm2022/ngx-t-forms-index-BcrQ01DQ.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs +105 -0
- package/fesm2022/ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-input-editor.component-DLru1Ezu.mjs +193 -0
- package/fesm2022/ngx-t-forms-input-editor.component-DLru1Ezu.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-map-mat-options-keys-SM5XM9uy.mjs → ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs} +12 -14
- package/fesm2022/ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs +66 -0
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs +211 -0
- package/fesm2022/ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs +165 -0
- package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs +38 -0
- package/fesm2022/ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs +38 -0
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs +126 -0
- package/fesm2022/ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs +447 -0
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs +74 -0
- package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs +905 -0
- package/fesm2022/ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs +20310 -0
- package/fesm2022/ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs +555 -0
- package/fesm2022/ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs +748 -0
- package/fesm2022/ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-record-list-manager.component-CykBq_nW.mjs +358 -0
- package/fesm2022/ngx-t-forms-record-list-manager.component-CykBq_nW.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-required-inputs.component-ONbhxVSH.mjs +272 -0
- package/fesm2022/ngx-t-forms-required-inputs.component-ONbhxVSH.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs +398 -0
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-search-field.component-B2ZO7lqO.mjs +38 -0
- package/fesm2022/ngx-t-forms-search-field.component-B2ZO7lqO.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-section-report.component-C1w16LYm.mjs +98 -0
- package/fesm2022/ngx-t-forms-section-report.component-C1w16LYm.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-select-input-element.component-CWcywuS6.mjs +150 -0
- package/fesm2022/ngx-t-forms-select-input-element.component-CWcywuS6.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs +169 -0
- package/fesm2022/ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs +204 -0
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs +95 -0
- package/fesm2022/ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs +82 -0
- package/fesm2022/ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-validators-config.component-BknyAmV_.mjs +574 -0
- package/fesm2022/ngx-t-forms-validators-config.component-BknyAmV_.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs +1303 -0
- package/fesm2022/ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs.map +1 -0
- package/fesm2022/ngx-t-forms.mjs +2 -1
- package/fesm2022/ngx-t-forms.mjs.map +1 -1
- package/package.json +20 -18
- package/styles/_editor-mixins.scss +62 -0
- package/styles/_json-editor-syntax.scss +26 -0
- package/styles/_signature-pad.scss +26 -0
- package/styles/_tokens.scss +148 -0
- package/types/ngx-t-forms.d.ts +1921 -733
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-Ct6_c_Lj.mjs +0 -313
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-Ct6_c_Lj.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-yuM1KHho.mjs +0 -191
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-yuM1KHho.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-BptpYSe-.mjs +0 -207
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-BptpYSe-.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-data-source-picker.component-Badna1Rl.mjs +0 -204
- package/fesm2022/ngx-t-forms-data-source-picker.component-Badna1Rl.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-2_8XzUgD.mjs +0 -289
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-2_8XzUgD.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-form-input-selector.component-DV4Sts9F.mjs +0 -134
- package/fesm2022/ngx-t-forms-form-input-selector.component-DV4Sts9F.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-form-json-view.component-B8seYzMQ.mjs +0 -22
- package/fesm2022/ngx-t-forms-form-json-view.component-B8seYzMQ.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-form-section-stepper.component-x_83iAWA.mjs +0 -281
- package/fesm2022/ngx-t-forms-form-section-stepper.component-x_83iAWA.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-UWo_dyVt.mjs +0 -345
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-UWo_dyVt.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-input-editor.component-B_kkOoEO.mjs +0 -147
- package/fesm2022/ngx-t-forms-input-editor.component-B_kkOoEO.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-map-mat-options-keys-SM5XM9uy.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-C41AL9Et.mjs +0 -105
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-C41AL9Et.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mat-slider-editor.component-BWe8U-sI.mjs +0 -109
- package/fesm2022/ngx-t-forms-mat-slider-editor.component-BWe8U-sI.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-B_XlkHuK.mjs +0 -155
- package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-B_XlkHuK.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-missing-form-configs.component-DPNNyKkt.mjs +0 -28
- package/fesm2022/ngx-t-forms-missing-form-configs.component-DPNNyKkt.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-DY1QnG08.mjs +0 -43
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-DY1QnG08.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-error-display.component-CRc_4l3l.mjs +0 -116
- package/fesm2022/ngx-t-forms-mscoa-error-display.component-CRc_4l3l.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Ckr_nuZF.mjs +0 -296
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Ckr_nuZF.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-GYxT-56Y.mjs +0 -83
- package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-GYxT-56Y.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-ngx-t-forms-DP2koSL5.mjs +0 -17401
- package/fesm2022/ngx-t-forms-ngx-t-forms-DP2koSL5.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-pipeline-generator.component-BxHetD_Q.mjs +0 -613
- package/fesm2022/ngx-t-forms-pipeline-generator.component-BxHetD_Q.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-record-list-manager.component-BQuMkoXo.mjs +0 -269
- package/fesm2022/ngx-t-forms-record-list-manager.component-BQuMkoXo.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-required-inputs.component-CLyq9dIR.mjs +0 -190
- package/fesm2022/ngx-t-forms-required-inputs.component-CLyq9dIR.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-CWeIUKLz.mjs +0 -291
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-CWeIUKLz.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-section-report.component-BtaF39WD.mjs +0 -156
- package/fesm2022/ngx-t-forms-section-report.component-BtaF39WD.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-selection-options-editor.component-B4cEGWrK.mjs +0 -186
- package/fesm2022/ngx-t-forms-selection-options-editor.component-B4cEGWrK.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-BkVN4Wdk.mjs +0 -187
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-BkVN4Wdk.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-validators-config.component-Cq07Er-G.mjs +0 -215
- package/fesm2022/ngx-t-forms-validators-config.component-Cq07Er-G.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs","sources":["../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/core/quill-input/quill.config.ts","../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/core/quill-input/quill-input.component.ts","../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/core/quill-input/quill-input.component.html","../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/editor-input-element.component.ts","../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/editor-input-element.component.html"],"sourcesContent":["import type Quill from 'quill';\nimport type { Op, QuillOptions } from 'quill';\n\n/**\n * Serialized Quill document — the Delta op-list persisted as the control value.\n *\n * Stored as a plain object (NOT a live `Delta` instance) so it round-trips through\n * reactive-form state and the library's structural `_isEqual` check cleanly. `_isEqual`\n * rejects values whose constructors differ, so a `Delta` instance would never compare\n * equal to the plain object rehydrated from saved form data.\n */\nexport interface QuillContent {\n ops: Op[];\n}\n\n/** Inputs the host component feeds into the Quill setup. */\nexport interface QuillEditorPayload {\n /** Render the editor in non-editable mode. */\n readOnly: boolean;\n /** Placeholder shown while the document is empty. */\n placeholder?: string;\n}\n\n/**\n * Narrow surface of Quill's built-in table module (`getModule('table')`), typed so the\n * host component can drive table operations without leaking `any`.\n */\nexport interface QuillTableModule {\n insertTable(rows: number, columns: number): void;\n insertRowBelow(): void;\n insertColumnRight(): void;\n deleteRow(): void;\n deleteColumn(): void;\n deleteTable(): void;\n}\n\n/** A custom toolbar control wired to a native Quill table operation. */\nexport interface QuillTableControl {\n /** Toolbar format key — Quill renders it as a `button.ql-<format>`. */\n format: string;\n /** Tooltip surfaced via the button's `title` attribute. */\n title: string;\n /** Inline SVG markup. Paths use `ql-stroke` so they inherit the themed icon colour. */\n icon: string;\n /** Operation run against the native table module when the button is pressed. */\n run: (table: QuillTableModule) => void;\n}\n\nconst svg = (body: string): string => `<svg viewBox=\"0 0 18 18\">${body}</svg>`;\n\n/**\n * Word-like table toolkit backed by Quill's native table module. Each control degrades to a\n * no-op when the caret is outside a table, so the buttons are always safe to press.\n */\nexport const QUILL_TABLE_CONTROLS: readonly QuillTableControl[] = [\n {\n format: 'table-insert',\n title: 'Insert table (3×3)',\n icon: svg('<rect class=\"ql-stroke\" fill=\"none\" x=\"3\" y=\"4\" width=\"12\" height=\"10\" rx=\"1\"></rect><line class=\"ql-stroke\" x1=\"3\" y1=\"7.3\" x2=\"15\" y2=\"7.3\"></line><line class=\"ql-stroke\" x1=\"3\" y1=\"10.6\" x2=\"15\" y2=\"10.6\"></line><line class=\"ql-stroke\" x1=\"7\" y1=\"4\" x2=\"7\" y2=\"14\"></line><line class=\"ql-stroke\" x1=\"11\" y1=\"4\" x2=\"11\" y2=\"14\"></line>'),\n run: table => table.insertTable(3, 3),\n },\n {\n format: 'table-row',\n title: 'Insert row below',\n icon: svg('<rect class=\"ql-stroke\" fill=\"none\" x=\"3\" y=\"3\" width=\"12\" height=\"6\" rx=\"1\"></rect><line class=\"ql-stroke\" x1=\"9\" y1=\"11\" x2=\"9\" y2=\"15\"></line><line class=\"ql-stroke\" x1=\"7\" y1=\"13\" x2=\"11\" y2=\"13\"></line>'),\n run: table => table.insertRowBelow(),\n },\n {\n format: 'table-column',\n title: 'Insert column right',\n icon: svg('<rect class=\"ql-stroke\" fill=\"none\" x=\"3\" y=\"3\" width=\"6\" height=\"12\" rx=\"1\"></rect><line class=\"ql-stroke\" x1=\"13\" y1=\"6\" x2=\"13\" y2=\"12\"></line><line class=\"ql-stroke\" x1=\"11\" y1=\"9\" x2=\"15\" y2=\"9\"></line>'),\n run: table => table.insertColumnRight(),\n },\n {\n format: 'table-delete-row',\n title: 'Delete row',\n icon: svg('<rect class=\"ql-stroke\" fill=\"none\" x=\"3\" y=\"3\" width=\"12\" height=\"6\" rx=\"1\"></rect><line class=\"ql-stroke\" x1=\"7\" y1=\"13\" x2=\"11\" y2=\"13\"></line>'),\n run: table => table.deleteRow(),\n },\n {\n format: 'table-delete-column',\n title: 'Delete column',\n icon: svg('<rect class=\"ql-stroke\" fill=\"none\" x=\"3\" y=\"3\" width=\"6\" height=\"12\" rx=\"1\"></rect><line class=\"ql-stroke\" x1=\"11\" y1=\"9\" x2=\"15\" y2=\"9\"></line>'),\n run: table => table.deleteColumn(),\n },\n {\n format: 'table-delete',\n title: 'Delete table',\n icon: svg('<rect class=\"ql-stroke\" fill=\"none\" x=\"3\" y=\"3\" width=\"12\" height=\"12\" rx=\"1\"></rect><line class=\"ql-stroke\" x1=\"5.5\" y1=\"5.5\" x2=\"12.5\" y2=\"12.5\"></line><line class=\"ql-stroke\" x1=\"12.5\" y1=\"5.5\" x2=\"5.5\" y2=\"12.5\"></line>'),\n run: table => table.deleteTable(),\n },\n];\n\n/**\n * Human-readable tooltips for the built-in controls, keyed by the button's CSS selector.\n * Quill ships no titles of its own, so these make the toolbar self-explanatory.\n */\nexport const QUILL_BUILTIN_TITLES: Readonly<Record<string, string>> = {\n '.ql-bold': 'Bold',\n '.ql-italic': 'Italic',\n '.ql-underline': 'Underline',\n '.ql-strike': 'Strikethrough',\n '.ql-blockquote': 'Quote',\n '.ql-code-block': 'Code block',\n '.ql-link': 'Insert link',\n '.ql-image': 'Insert image',\n '.ql-video': 'Embed video',\n '.ql-clean': 'Clear formatting',\n '.ql-list[value=\"ordered\"]': 'Numbered list',\n '.ql-list[value=\"bullet\"]': 'Bulleted list',\n '.ql-list[value=\"check\"]': 'Checklist',\n '.ql-script[value=\"sub\"]': 'Subscript',\n '.ql-script[value=\"super\"]': 'Superscript',\n '.ql-indent[value=\"-1\"]': 'Decrease indent',\n '.ql-indent[value=\"+1\"]': 'Increase indent',\n '.ql-direction[value=\"rtl\"]': 'Right-to-left',\n '.ql-color': 'Text colour',\n '.ql-background': 'Highlight colour',\n '.ql-align': 'Alignment',\n '.ql-header': 'Heading',\n '.ql-font': 'Font',\n '.ql-size': 'Font size',\n};\n\n/**\n * Comprehensive, logically grouped \"snow\" toolbar — headings/fonts, inline styling, colour,\n * scripts, lists, indentation/alignment, blocks, media and a native table toolkit.\n */\nconst TOOLBAR_CONTAINER: readonly unknown[] = [\n [{ header: [1, 2, 3, 4, 5, 6, false] }, { font: [] }, { size: ['small', false, 'large', 'huge'] }],\n ['bold', 'italic', 'underline', 'strike'],\n [{ color: [] }, { background: [] }],\n [{ script: 'sub' }, { script: 'super' }],\n [{ list: 'ordered' }, { list: 'bullet' }, { list: 'check' }],\n [{ indent: '-1' }, { indent: '+1' }, { align: [] }, { direction: 'rtl' }],\n ['blockquote', 'code-block'],\n ['link', 'image', 'video'],\n QUILL_TABLE_CONTROLS.map(control => control.format),\n ['clean']\n];\n\n/** The `this` context Quill binds when it invokes a toolbar handler. */\ninterface ToolbarHandlerContext {\n quill: Quill;\n}\n\n/**\n * Builds the toolbar handler map for the custom table buttons.\n *\n * These MUST be supplied in the toolbar config (not added later via `addHandler`): Quill's\n * toolbar skips attaching a click listener to any button whose format is neither a registered\n * blot nor already present in `handlers` at construction time. A late `addHandler` sets the\n * handler but never re-attaches the listener, so the button stays inert.\n */\nconst buildTableHandlers = (): Record<string, (this: ToolbarHandlerContext) => void> => {\n const handlers: Record<string, (this: ToolbarHandlerContext) => void> = {};\n for (const control of QUILL_TABLE_CONTROLS) {\n handlers[control.format] = function tableHandler(this: ToolbarHandlerContext): void {\n const table = this.quill.getModule('table') as QuillTableModule;\n // Native table ops bail when there is no selection; force focus + a range first.\n this.quill.getSelection(true);\n control.run(table);\n };\n }\n return handlers;\n};\n\n/**\n * Builds a ready-to-use `QuillOptions` for a \"snow\" editor with the native table module\n * enabled and the custom table-button handlers wired into the toolbar config.\n *\n * Browser-only by construction: callers MUST instantiate Quill behind an\n * `isPlatformBrowser(...)` guard because Quill touches `document` at construction time.\n */\nexport const buildQuillOptions = (payload: QuillEditorPayload): QuillOptions => ({\n theme: 'snow',\n readOnly: payload.readOnly,\n placeholder: payload.placeholder ?? \"Let's write something amazing...\",\n modules: {\n toolbar: {\n container: TOOLBAR_CONTAINER,\n handlers: buildTableHandlers()\n },\n table: true,\n history: { delay: 1000, maxStack: 100, userOnly: true },\n clipboard: { matchVisual: false }\n }\n});\n\n/**\n * Quill's empty document is a single trailing newline op. Treat that — and a literally\n * empty op-list — as \"no value\" so `required` validation behaves intuitively.\n */\nexport const isEmptyQuillDocument = (ops: Op[]): boolean =>\n ops.length === 0 || (ops.length === 1 && ops[0]?.insert === '\\n');\n","/// <reference path=\"../../../../../../../types/quill.d.ts\" />\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n Input,\n OnDestroy,\n PLATFORM_ID,\n inject,\n input,\n output,\n viewChild\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { NgControl } from '@angular/forms';\n\nimport { ITowerStepColumn } from 'ngx-t-forms-types';\n// Mirrors the EditorJS sibling (Trap 16): `quill` is a browser-only bundle that touches\n// `document` at construction time and crashes under bare-Node SSR. The top-level import is\n// type-only (zero runtime emission); the real load happens inside the SSR-gated\n// `ngAfterViewInit` via dynamic `import()`.\nimport type QuillType from 'quill';\nimport { MatFormFieldControl } from '@angular/material/form-field';\n\nimport { BaseCustomInput, BaseCustomInputConfig } from '../../../../../../services/core/t-input-controller/functions/baseCustomInput';\nimport {\n buildQuillOptions,\n isEmptyQuillDocument,\n QUILL_BUILTIN_TITLES,\n QUILL_TABLE_CONTROLS,\n QuillContent\n} from './quill.config';\nimport { _isEqual } from '../../../../../../shared/functions/isEqual';\n\nconst customInputConfig: BaseCustomInputConfig = {\n controlType: 'lib-quill-input',\n nextId: 0\n};\n\n/**\n * Quill (\"snow\" theme) rich-text editor wired into Angular Material's form-field as a\n * custom `MatFormFieldControl`. The full Quill setup — toolbar, formats, history — lives in\n * `quill.config.ts`; this component owns lifecycle, SSR gating and value round-tripping.\n */\n@Component({\n selector: 'lib-quill-input',\n templateUrl: './quill-input.component.html',\n styleUrl: './quill-input.component.css',\n imports: [],\n host: {\n '[class.floating]': 'shouldLabelFloat',\n '[id]': 'id'\n },\n providers: [{ provide: MatFormFieldControl, useExisting: QuillInputComponent }],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class QuillInputComponent\n extends BaseCustomInput<QuillContent | undefined>\n implements AfterViewInit, OnDestroy {\n\n readonly inputConfig = input.required<ITowerStepColumn>();\n\n readonly valueChanged = output<QuillContent | undefined>();\n\n protected editor: QuillType | undefined;\n\n private readonly editorHost = viewChild.required<ElementRef<HTMLElement>>('editorHost');\n\n readonly #platformId = inject(PLATFORM_ID);\n\n #changeHandler: (() => void) | undefined;\n\n constructor() {\n super(\n inject(NgControl, { optional: true, self: true }) as NgControl,\n inject<ElementRef<HTMLElement>>(ElementRef),\n customInputConfig\n );\n }\n\n override get empty(): boolean {\n const n = this.value;\n return n === null || n === undefined;\n }\n\n override get shouldLabelFloat(): boolean {\n return true;\n }\n\n override _value: QuillContent | undefined = undefined;\n\n @Input() override set value(value: QuillContent | undefined) {\n if (!_isEqual(this._value, value)) {\n this._value = value;\n this.onChange(value);\n this.stateChanges.next();\n }\n }\n\n override get value(): QuillContent | undefined {\n return this._value;\n }\n\n async ngAfterViewInit(): Promise<void> {\n if (!isPlatformBrowser(this.#platformId)) return;\n\n // Browser-only dynamic load — see the Trap 16 comment at the top of this file. The\n // CSS import injects Quill's global theme styles (Quill's runtime DOM is not view-scoped).\n const [{ default: Quill, Delta }] = await Promise.all([\n import('quill'),\n import('quill/dist/quill.snow.css')\n ]);\n\n const config = this.inputConfig();\n this.editor = new Quill(this.editorHost().nativeElement, buildQuillOptions({\n readOnly: config.readonly || false,\n placeholder: config.placeholder\n }));\n\n const initial = this.value;\n if (initial?.ops?.length) {\n this.editor.setContents(new Delta(initial.ops), 'silent');\n }\n\n this.#decorateToolbar();\n\n this.#changeHandler = () => this.contentChangedSaveValue();\n this.editor.on('text-change', this.#changeHandler);\n }\n\n /**\n * Quill ships no icons for custom buttons and no tooltips for any button. Inject themeable\n * SVG icons (their `ql-stroke` paths inherit the toolbar colour) and `title` tooltips so the\n * toolbar reads clearly in both light and dark mode.\n */\n #decorateToolbar(): void {\n const root = this._elementRef.nativeElement;\n for (const control of QUILL_TABLE_CONTROLS) {\n const button = root.querySelector<HTMLElement>(`.ql-${control.format}`);\n if (!button) continue;\n button.innerHTML = control.icon;\n button.setAttribute('title', control.title);\n }\n for (const [selector, title] of Object.entries(QUILL_BUILTIN_TITLES)) {\n root.querySelectorAll<HTMLElement>(selector).forEach(el => el.setAttribute('title', title));\n }\n }\n\n contentChangedSaveValue(): void {\n if (!this.editor) return;\n const ops = this.editor.getContents().ops;\n const value: QuillContent | undefined = isEmptyQuillDocument(ops) ? undefined : { ops };\n this.value = value;\n this.onChange(value);\n console.error('Quill content changed, new value:', value);\n this.valueChanged.emit(value);\n }\n\n override ngOnDestroy(): void {\n this.stateChanges.complete();\n if (this.editor && this.#changeHandler) {\n this.editor.off('text-change', this.#changeHandler);\n }\n this.editor = undefined;\n }\n}\n","\n<div class=\"quill-host\">\n <div #editorHost></div>\n</div>\n","import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\r\nimport { FormGroup, ReactiveFormsModule } from '@angular/forms';\r\nimport { MatFormFieldModule } from '@angular/material/form-field';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatTooltipModule } from '@angular/material/tooltip';\r\nimport type { ITowerStepColumn } from 'ngx-t-forms-types';\r\nimport { RichTextEditorType } from 'ngx-t-forms-types';\r\nimport { TFormInputStatusComponent } from '../../../t-form-input-status/t-form-input-status.component';\r\nimport { EditorJsInputComponent } from './core/editor-js-input/editor-js-input.component';\r\nimport { QuillInputComponent } from './core/quill-input/quill-input.component';\r\nimport { getInputErrorMessage } from '../../../../services/core/t-input-controller/functions/inputErrorMessage';\r\n\r\n/**\r\n * Wraps a configurable rich-text editor inside a `mat-form-field`, selecting the concrete\r\n * editor (EditorJS or Quill) from the column's `richTextEditorLibrary`, with shared\r\n * label / hint / error / suffix / prefix metadata from the column.\r\n */\r\n@Component({\r\n selector: 'lib-editor-input-element',\r\n templateUrl: './editor-input-element.component.html',\r\n styleUrl: './editor-input-element.component.css',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n imports: [\r\n ReactiveFormsModule,\r\n MatFormFieldModule,\r\n MatIconModule,\r\n MatButtonModule,\r\n MatTooltipModule,\r\n TFormInputStatusComponent,\r\n EditorJsInputComponent,\r\n QuillInputComponent,\r\n ],\r\n})\r\nexport class EditorInputElementComponent {\r\n readonly inputConfig = input.required<ITowerStepColumn>();\r\n readonly formGroup = input.required<FormGroup>();\r\n readonly reload = output<void>();\r\n\r\n /** Editor-library enum exposed for `@switch` in the template. */\r\n protected readonly editorType = RichTextEditorType;\r\n\r\n protected readonly errorMessage = computed(() =>\r\n getInputErrorMessage(this.inputConfig(), this.formGroup()),\r\n );\r\n}\r\n","<form [formGroup]=\"formGroup()\">\n @if (inputConfig(); as inputConfig) {\n <mat-form-field [appearance]=\"inputConfig.appearance || 'fill'\" subscriptSizing=\"dynamic\">\n <mat-label>\n {{ inputConfig.label }}\n <lib-t-form-input-status [inputConfig]=\"inputConfig\"></lib-t-form-input-status>\n </mat-label>\n\n @switch (inputConfig.richTextEditorLibrary) {\n @case (editorType.Quill) {\n <lib-quill-input\n [inputConfig]=\"inputConfig\"\n [formControlName]=\"inputConfig.id\"\n [required]=\"inputConfig.required\"\n ></lib-quill-input>\n }\n @case (editorType.EditorJS) {\n <lib-editor-js-input\n [inputConfig]=\"inputConfig\"\n [formControlName]=\"inputConfig.id\"\n [required]=\"inputConfig.required\"\n ></lib-editor-js-input>\n }\n }\n\n @if (inputConfig.hintLabel || inputConfig.temporaryHint) {\n <mat-hint class=\"inputHint\">\n {{ inputConfig.temporaryHint || inputConfig.hintLabel }}\n </mat-hint>\n }\n\n @if (!!errorMessage()) {\n <mat-error class=\"oneLineTextEllipsis\" matTooltipClass=\"errorToolTip\">{{ errorMessage() }}</mat-error>\n }\n\n @if (inputConfig.prefixIcon) {\n <mat-icon matPrefix>{{ inputConfig.prefixIcon }}</mat-icon>\n }\n\n @if (inputConfig.canReload?.canReload) {\n <button\n mat-icon-button\n style=\"margin-right: 4px;\"\n matTooltip=\"Click to refresh this field.\"\n class=\"input-sync-button\"\n (click)=\"inputConfig.canReload.emit()\"\n matSuffix\n >\n <mat-icon style=\"color: var(--mat-sys-primary)\">sync</mat-icon>\n </button>\n }\n\n @if (inputConfig.suffixIcon && inputConfig.id !== 'password') {\n <mat-icon matSuffix>{{ inputConfig.suffixIcon }}</mat-icon>\n }\n\n @if (inputConfig.prefixText) {\n <span matPrefix style=\"top: 0\">{{ inputConfig.prefixText }}</span>\n }\n @if (inputConfig.suffixText) {\n <span matSuffix style=\"padding-left: 5px\">{{ inputConfig.suffixText }}</span>\n }\n\n @if (inputConfig.maxLength && formGroup()) {\n <mat-hint align=\"end\">\n {{ (formGroup().controls[inputConfig.id]?.value?.length || 0) + '/' + inputConfig.maxLength }}\n </mat-hint>\n }\n </mat-form-field>\n }\n</form>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, input, output, PLATFORM_ID, Input, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
4
|
+
import { NgControl } from '@angular/forms';
|
|
5
|
+
import { MatFormFieldControl } from '@angular/material/form-field';
|
|
6
|
+
import { B as BaseCustomInput, _ as _isEqual } from './ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs';
|
|
7
|
+
|
|
8
|
+
// Third-party Editor.js tool packages ship without typings that line up with
|
|
9
|
+
// the host editor's `ToolConstructable`. We narrow at the registration boundary
|
|
10
|
+
// via `unknown` rather than leaking `any` through this module.
|
|
11
|
+
const asToolConstructable = (tool) => tool;
|
|
12
|
+
/**
|
|
13
|
+
* Dynamically loads every Editor.js plugin bundle and returns a ready-to-use `EditorConfig`.
|
|
14
|
+
*
|
|
15
|
+
* Browser-only: callers MUST gate this behind `isPlatformBrowser(...)` because each plugin
|
|
16
|
+
* package touches `self` / `document` at module-eval time and crashes under bare-Node SSR.
|
|
17
|
+
*/
|
|
18
|
+
const loadEditorConfig = async (payload) => {
|
|
19
|
+
const [{ default: Header }, { default: List }, { default: Paragraph }, { default: Quote }, { default: Table }, { default: ImageTool }, { default: Delimiter }, { default: CodeTool }, { default: Embed },] = await Promise.all([
|
|
20
|
+
import('@editorjs/header'),
|
|
21
|
+
import('@editorjs/list'),
|
|
22
|
+
import('@editorjs/paragraph'),
|
|
23
|
+
import('@editorjs/quote'),
|
|
24
|
+
import('@editorjs/table'),
|
|
25
|
+
import('@editorjs/image'),
|
|
26
|
+
import('@editorjs/delimiter'),
|
|
27
|
+
import('@editorjs/code'),
|
|
28
|
+
import('@editorjs/embed'),
|
|
29
|
+
]);
|
|
30
|
+
return ({
|
|
31
|
+
holder: payload.holderId,
|
|
32
|
+
autofocus: true,
|
|
33
|
+
placeholder: 'Let\'s write something amazing...',
|
|
34
|
+
inlineToolbar: true,
|
|
35
|
+
tools: {
|
|
36
|
+
header: {
|
|
37
|
+
class: asToolConstructable(Header),
|
|
38
|
+
config: {
|
|
39
|
+
levels: [1, 2, 3, 4, 5, 6],
|
|
40
|
+
defaultLevel: 1,
|
|
41
|
+
placeholder: 'Type your heading here...'
|
|
42
|
+
},
|
|
43
|
+
inlineToolbar: ['link', 'bold', 'italic', 'marker']
|
|
44
|
+
},
|
|
45
|
+
list: {
|
|
46
|
+
class: asToolConstructable(List),
|
|
47
|
+
inlineToolbar: true,
|
|
48
|
+
config: {
|
|
49
|
+
defaultStyle: 'unordered',
|
|
50
|
+
placeholder: 'Enter a list item here...'
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
paragraph: {
|
|
54
|
+
class: asToolConstructable(Paragraph),
|
|
55
|
+
inlineToolbar: true,
|
|
56
|
+
config: {
|
|
57
|
+
preserveBlank: true,
|
|
58
|
+
placeholder: 'Type your paragraph here...'
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
quote: {
|
|
62
|
+
class: asToolConstructable(Quote),
|
|
63
|
+
inlineToolbar: true,
|
|
64
|
+
shortcut: 'CMD+SHIFT+Q',
|
|
65
|
+
config: {
|
|
66
|
+
quotePlaceholder: 'Enter a quote',
|
|
67
|
+
captionPlaceholder: 'Quote\'s author',
|
|
68
|
+
alignmentEnabled: true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
delimiter: {
|
|
72
|
+
class: asToolConstructable(Delimiter)
|
|
73
|
+
},
|
|
74
|
+
image: {
|
|
75
|
+
class: asToolConstructable(ImageTool),
|
|
76
|
+
config: {
|
|
77
|
+
endpoints: {
|
|
78
|
+
byFile: payload.imageUploadEndpoint,
|
|
79
|
+
byUrl: payload.imageFetchEndpoint
|
|
80
|
+
},
|
|
81
|
+
uploader: {
|
|
82
|
+
uploadByFile(file) {
|
|
83
|
+
// Custom upload logic
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
table: {
|
|
89
|
+
class: asToolConstructable(Table),
|
|
90
|
+
inlineToolbar: true,
|
|
91
|
+
config: {
|
|
92
|
+
rows: 2,
|
|
93
|
+
cols: 3
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
code: {
|
|
97
|
+
class: asToolConstructable(CodeTool),
|
|
98
|
+
config: {
|
|
99
|
+
placeholder: 'Enter code here...'
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
embed: {
|
|
103
|
+
class: asToolConstructable(Embed),
|
|
104
|
+
config: {
|
|
105
|
+
services: {
|
|
106
|
+
youtube: true,
|
|
107
|
+
codesandbox: true,
|
|
108
|
+
codepen: true
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
defaultBlock: 'paragraph',
|
|
114
|
+
hideToolbar: false,
|
|
115
|
+
data: payload.data,
|
|
116
|
+
readOnly: payload.readOnly,
|
|
117
|
+
logLevel: 'ERROR',
|
|
118
|
+
minHeight: 300,
|
|
119
|
+
onChange: (api, event) => {
|
|
120
|
+
payload.onChangeFn();
|
|
121
|
+
},
|
|
122
|
+
onReady: () => { },
|
|
123
|
+
sanitizer: {
|
|
124
|
+
p: true,
|
|
125
|
+
b: true,
|
|
126
|
+
a: {
|
|
127
|
+
href: true,
|
|
128
|
+
target: '_blank',
|
|
129
|
+
rel: 'nofollow'
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
i18n: {
|
|
133
|
+
messages: {
|
|
134
|
+
ui: {
|
|
135
|
+
blockTunes: {
|
|
136
|
+
toggler: {
|
|
137
|
+
'Click to tune': 'Click to tune',
|
|
138
|
+
'or drag to move': 'or drag to move'
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const customInputConfig = {
|
|
148
|
+
controlType: 'lib-editor-js-input',
|
|
149
|
+
nextId: 0
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Rich-text input backed by the Editor.js block editor, wired into Angular
|
|
153
|
+
* Material's form-field via {@link MatFormFieldControl}.
|
|
154
|
+
*
|
|
155
|
+
* The Editor.js bundle is browser-only, so it is dynamically imported and
|
|
156
|
+
* instantiated inside `ngAfterViewInit` behind an `isPlatformBrowser` guard
|
|
157
|
+
* to stay SSR-safe. The editor instance is destroyed on `ngOnDestroy`.
|
|
158
|
+
*
|
|
159
|
+
* @deprecated Scheduled for removal. Do not use in new code; migrate existing
|
|
160
|
+
* usages to the supported rich-text input element. Retained only for backward
|
|
161
|
+
* compatibility with forms that still reference `lib-editor-js-input`.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* <lib-editor-js-input [inputConfig]="column()" (valueChanged)="onChange($event)" />
|
|
165
|
+
*/
|
|
166
|
+
class EditorJsInputComponent extends BaseCustomInput {
|
|
167
|
+
#platformId;
|
|
168
|
+
constructor() {
|
|
169
|
+
super(inject(NgControl, { optional: true, self: true }), inject(ElementRef), customInputConfig);
|
|
170
|
+
/** Column definition describing the field's id, read-only state and metadata. */
|
|
171
|
+
this.inputConfig = input.required(...(ngDevMode ? [{ debugName: "inputConfig" }] : /* istanbul ignore next */ []));
|
|
172
|
+
/** Emits the editor's saved {@link OutputData} whenever its content changes. */
|
|
173
|
+
this.valueChanged = output();
|
|
174
|
+
this.#platformId = inject(PLATFORM_ID);
|
|
175
|
+
this._value = undefined;
|
|
176
|
+
}
|
|
177
|
+
get empty() {
|
|
178
|
+
const n = this.value;
|
|
179
|
+
// Check for null, undefined, or empty string, but allow 0
|
|
180
|
+
return n === null || n === undefined || n === '';
|
|
181
|
+
}
|
|
182
|
+
get shouldLabelFloat() {
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
set value(value) {
|
|
186
|
+
if (!_isEqual(this._value, value)) {
|
|
187
|
+
this._value = value;
|
|
188
|
+
this.onChange(value);
|
|
189
|
+
this.stateChanges.next();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
get value() {
|
|
193
|
+
return this._value;
|
|
194
|
+
}
|
|
195
|
+
async ngAfterViewInit() {
|
|
196
|
+
if (!isPlatformBrowser(this.#platformId))
|
|
197
|
+
return;
|
|
198
|
+
if (this.editor) {
|
|
199
|
+
this.editor.destroy();
|
|
200
|
+
}
|
|
201
|
+
const payload = {
|
|
202
|
+
holderId: this.inputConfig().id,
|
|
203
|
+
imageFetchEndpoint: '',
|
|
204
|
+
imageUploadEndpoint: '',
|
|
205
|
+
readOnly: this.inputConfig().readonly || false,
|
|
206
|
+
data: this.value || undefined,
|
|
207
|
+
onChangeFn: this.contentChangedSaveValue.bind(this)
|
|
208
|
+
};
|
|
209
|
+
// Browser-only dynamic load — see Trap 16 comment at the top of this file and in config.ts.
|
|
210
|
+
const [{ default: EditorJS }, config] = await Promise.all([
|
|
211
|
+
import('@editorjs/editorjs'),
|
|
212
|
+
loadEditorConfig(payload),
|
|
213
|
+
]);
|
|
214
|
+
this.editor = new EditorJS(config);
|
|
215
|
+
}
|
|
216
|
+
async contentChangedSaveValue() {
|
|
217
|
+
const value = await this.editor?.save();
|
|
218
|
+
this.value = value;
|
|
219
|
+
this.onChange(value);
|
|
220
|
+
this.valueChanged.emit(value);
|
|
221
|
+
}
|
|
222
|
+
ngOnDestroy() {
|
|
223
|
+
this.stateChanges.complete();
|
|
224
|
+
this.editor?.destroy();
|
|
225
|
+
}
|
|
226
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EditorJsInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
227
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.12", type: EditorJsInputComponent, isStandalone: true, selector: "lib-editor-js-input", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { valueChanged: "valueChanged" }, host: { properties: { "class.floating": "shouldLabelFloat", "id": "id" } }, providers: [{ provide: MatFormFieldControl, useExisting: EditorJsInputComponent }], usesInheritance: true, ngImport: i0, template: "\r\n<div class=\" editor-container\" style=\"padding: 16px;\">\r\n <div #editorJs [id]=\"inputConfig().id\"></div>\r\n</div>\r\n", styles: [".editor-container{border:solid 1px var(--mat-divider-color, var(--mat-app-outline));padding:16px;background:var(--mdc-elevated-card-container-color, var(--mat-app-surface-container-low))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
228
|
+
}
|
|
229
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: EditorJsInputComponent, decorators: [{
|
|
230
|
+
type: Component,
|
|
231
|
+
args: [{ selector: 'lib-editor-js-input', imports: [], host: {
|
|
232
|
+
'[class.floating]': 'shouldLabelFloat',
|
|
233
|
+
'[id]': 'id'
|
|
234
|
+
}, providers: [{ provide: MatFormFieldControl, useExisting: EditorJsInputComponent }], changeDetection: ChangeDetectionStrategy.OnPush, template: "\r\n<div class=\" editor-container\" style=\"padding: 16px;\">\r\n <div #editorJs [id]=\"inputConfig().id\"></div>\r\n</div>\r\n", styles: [".editor-container{border:solid 1px var(--mat-divider-color, var(--mat-app-outline));padding:16px;background:var(--mdc-elevated-card-container-color, var(--mat-app-surface-container-low))}\n"] }]
|
|
235
|
+
}], ctorParameters: () => [], propDecorators: { inputConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputConfig", required: true }] }], valueChanged: [{ type: i0.Output, args: ["valueChanged"] }], value: [{
|
|
236
|
+
type: Input
|
|
237
|
+
}] } });
|
|
238
|
+
|
|
239
|
+
export { EditorJsInputComponent };
|
|
240
|
+
//# sourceMappingURL=ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs","sources":["../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/core/form-input-rich-text-editor/config.ts","../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/core/editor-js-input/editor-js-input.component.ts","../../../projects/ngx-t-forms/src/lib/components/t-form-input/elements/editor-input-element/core/editor-js-input/editor-js-input.component.html"],"sourcesContent":["/// <reference path=\"../../../../../../../types/editorjs.d.ts\" />\r\nimport type { EditorConfig, LogLevels, OutputData, ToolConstructable } from \"@editorjs/editorjs\";\r\n// `@editorjs/editorjs` is CJS — runtime named imports fail under Node ESM (SSR / smoke harness).\r\n// `LogLevels` is a runtime enum with string values; use the string literal cast at the single use site below.\r\n//\r\n// Wave 2 / Trap 16: every Editor.js plugin package below is a browser-only UMD bundle that crashes\r\n// under bare Node SSR (`self`/`document` not defined at module-eval). They are now loaded via\r\n// dynamic `import()` inside `loadEditorConfig()`, which is only invoked from an SSR-gated\r\n// `ngAfterViewInit` (see `editor-js-input.component.ts`). Static top-level imports here are\r\n// type-only and emit zero runtime code.\r\n\r\nexport interface EditorJsPayload {\r\n holderId: string,\r\n imageFetchEndpoint:string,\r\n imageUploadEndpoint: string,\r\n readOnly:boolean,\r\n onChangeFn: () => void,\r\n data:OutputData|undefined\r\n}\r\n\r\n// Third-party Editor.js tool packages ship without typings that line up with\r\n// the host editor's `ToolConstructable`. We narrow at the registration boundary\r\n// via `unknown` rather than leaking `any` through this module.\r\nconst asToolConstructable = (tool: unknown): ToolConstructable =>\r\n tool as ToolConstructable;\r\n\r\n/**\r\n * Dynamically loads every Editor.js plugin bundle and returns a ready-to-use `EditorConfig`.\r\n *\r\n * Browser-only: callers MUST gate this behind `isPlatformBrowser(...)` because each plugin\r\n * package touches `self` / `document` at module-eval time and crashes under bare-Node SSR.\r\n */\r\nexport const loadEditorConfig = async (\r\n payload: EditorJsPayload\r\n): Promise<EditorConfig> => {\r\n const [\r\n { default: Header },\r\n { default: List },\r\n { default: Paragraph },\r\n { default: Quote },\r\n { default: Table },\r\n { default: ImageTool },\r\n { default: Delimiter },\r\n { default: CodeTool },\r\n { default: Embed },\r\n ] = await Promise.all([\r\n import('@editorjs/header'),\r\n import('@editorjs/list'),\r\n import('@editorjs/paragraph'),\r\n import('@editorjs/quote'),\r\n import('@editorjs/table'),\r\n import('@editorjs/image'),\r\n import('@editorjs/delimiter'),\r\n import('@editorjs/code'),\r\n import('@editorjs/embed'),\r\n ]);\r\n\r\n return ({\r\n holder: payload.holderId,\r\n autofocus: true,\r\n placeholder: 'Let\\'s write something amazing...',\r\n inlineToolbar: true,\r\n tools: {\r\n header: {\r\n class: asToolConstructable(Header),\r\n config: {\r\n levels: [1, 2, 3, 4, 5, 6],\r\n defaultLevel: 1,\r\n placeholder: 'Type your heading here...'\r\n },\r\n inlineToolbar: ['link', 'bold', 'italic', 'marker']\r\n },\r\n list: {\r\n class: asToolConstructable(List),\r\n inlineToolbar: true,\r\n config: {\r\n defaultStyle: 'unordered',\r\n placeholder: 'Enter a list item here...'\r\n }\r\n },\r\n paragraph: {\r\n class: asToolConstructable(Paragraph),\r\n inlineToolbar: true,\r\n config: {\r\n preserveBlank: true,\r\n placeholder: 'Type your paragraph here...'\r\n }\r\n },\r\n quote: {\r\n class: asToolConstructable(Quote),\r\n inlineToolbar: true,\r\n shortcut: 'CMD+SHIFT+Q',\r\n config: {\r\n quotePlaceholder: 'Enter a quote',\r\n captionPlaceholder: 'Quote\\'s author',\r\n alignmentEnabled: true\r\n }\r\n },\r\n delimiter: {\r\n class: asToolConstructable(Delimiter)\r\n },\r\n image: {\r\n class: asToolConstructable(ImageTool),\r\n config: {\r\n endpoints: {\r\n byFile: payload.imageUploadEndpoint,\r\n byUrl: payload.imageFetchEndpoint\r\n },\r\n uploader: {\r\n uploadByFile(file: File) {\r\n // Custom upload logic\r\n }\r\n }\r\n }\r\n },\r\n table: {\r\n class: asToolConstructable(Table),\r\n inlineToolbar: true,\r\n config: {\r\n rows: 2,\r\n cols: 3\r\n }\r\n },\r\n code: {\r\n class: asToolConstructable(CodeTool),\r\n config: {\r\n placeholder: 'Enter code here...'\r\n }\r\n },\r\n\r\n embed: {\r\n class: asToolConstructable(Embed),\r\n config: {\r\n services: {\r\n youtube: true,\r\n codesandbox: true,\r\n codepen: true\r\n }\r\n }\r\n },\r\n\r\n },\r\n defaultBlock: 'paragraph',\r\n hideToolbar: false,\r\n data: payload.data,\r\n readOnly:payload.readOnly,\r\n logLevel: 'ERROR' as LogLevels,\r\n minHeight: 300,\r\n onChange: (api, event) => {\r\n payload.onChangeFn()\r\n },\r\n onReady: () => {},\r\n sanitizer: {\r\n p: true,\r\n b: true,\r\n a: {\r\n href: true,\r\n target: '_blank',\r\n rel: 'nofollow'\r\n }\r\n },\r\n i18n: {\r\n messages: {\r\n ui: {\r\n blockTunes: {\r\n toggler: {\r\n 'Click to tune': 'Click to tune',\r\n 'or drag to move': 'or drag to move'\r\n }\r\n }\r\n }\r\n }\r\n }\r\n });\r\n}\r\n\r\n\r\n","import {\r\n AfterViewInit,\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n Input,\r\n OnDestroy,\r\n PLATFORM_ID,\r\n inject,\r\n input,\r\n output\r\n} from '@angular/core';\r\nimport { isPlatformBrowser } from '@angular/common';\r\nimport { NgControl } from '@angular/forms';\r\n\r\nimport { ITowerStepColumn } from 'ngx-t-forms-types';\r\n// Wave 2 / Trap 16: `@editorjs/editorjs` is a browser-only UMD bundle that crashes under\r\n// bare-Node SSR at module-eval time. Type-only import at the top keeps the surface intact\r\n// with zero runtime emission; the runtime load happens inside the SSR-gated `ngAfterViewInit`.\r\nimport type EditorJSType from '@editorjs/editorjs';\r\nimport type { OutputData } from '@editorjs/editorjs';\r\nimport { MatFormFieldControl } from '@angular/material/form-field';\r\n\r\nimport { BaseCustomInput, BaseCustomInputConfig } from '../../../../../../services/core/t-input-controller/functions/baseCustomInput';\r\nimport { loadEditorConfig, EditorJsPayload } from '../form-input-rich-text-editor/config';\r\nimport { _isEqual } from '../../../../../../shared/functions/isEqual';\r\n\r\nconst customInputConfig: BaseCustomInputConfig = {\r\n controlType: 'lib-editor-js-input',\r\n nextId: 0\r\n};\r\n\r\n/**\r\n * Rich-text input backed by the Editor.js block editor, wired into Angular\r\n * Material's form-field via {@link MatFormFieldControl}.\r\n *\r\n * The Editor.js bundle is browser-only, so it is dynamically imported and\r\n * instantiated inside `ngAfterViewInit` behind an `isPlatformBrowser` guard\r\n * to stay SSR-safe. The editor instance is destroyed on `ngOnDestroy`.\r\n *\r\n * @deprecated Scheduled for removal. Do not use in new code; migrate existing\r\n * usages to the supported rich-text input element. Retained only for backward\r\n * compatibility with forms that still reference `lib-editor-js-input`.\r\n *\r\n * @example\r\n * <lib-editor-js-input [inputConfig]=\"column()\" (valueChanged)=\"onChange($event)\" />\r\n */\r\n@Component({\r\n selector: 'lib-editor-js-input',\r\n templateUrl: './editor-js-input.component.html',\r\n styleUrl: './editor-js-input.component.css',\r\n imports: [],\r\n host: {\r\n '[class.floating]': 'shouldLabelFloat',\r\n '[id]': 'id'\r\n },\r\n providers: [{ provide: MatFormFieldControl, useExisting: EditorJsInputComponent }],\r\n changeDetection: ChangeDetectionStrategy.OnPush\r\n})\r\nexport class EditorJsInputComponent\r\n extends BaseCustomInput<OutputData | undefined>\r\n implements AfterViewInit, OnDestroy {\r\n\r\n /** Column definition describing the field's id, read-only state and metadata. */\r\n readonly inputConfig = input.required<ITowerStepColumn>();\r\n\r\n /** Emits the editor's saved {@link OutputData} whenever its content changes. */\r\n readonly valueChanged = output<OutputData | undefined>();\r\n\r\n /** Live Editor.js instance; `undefined` until initialised (or on the server). */\r\n protected editor: EditorJSType | undefined;\r\n\r\n readonly #platformId = inject(PLATFORM_ID);\r\n\r\n constructor() {\r\n super(\r\n inject(NgControl, { optional: true, self: true }) as NgControl,\r\n inject<ElementRef<HTMLElement>>(ElementRef),\r\n customInputConfig\r\n );\r\n }\r\n\r\n override get empty(): boolean {\r\n const n = this.value;\r\n // Check for null, undefined, or empty string, but allow 0\r\n return n === null || n === undefined || (n as unknown) === '';\r\n }\r\n\r\n override get shouldLabelFloat(): boolean {\r\n return true;\r\n }\r\n\r\n override _value: OutputData | undefined = undefined;\r\n\r\n @Input() override set value(value: OutputData | undefined) {\r\n if (!_isEqual(this._value, value)) {\r\n this._value = value;\r\n this.onChange(value);\r\n this.stateChanges.next();\r\n }\r\n }\r\n\r\n override get value(): OutputData | undefined {\r\n return this._value;\r\n }\r\n\r\n async ngAfterViewInit(): Promise<void> {\r\n if (!isPlatformBrowser(this.#platformId)) return;\r\n\r\n if (this.editor) {\r\n this.editor.destroy();\r\n }\r\n\r\n const payload: EditorJsPayload = {\r\n holderId: this.inputConfig().id,\r\n imageFetchEndpoint: '',\r\n imageUploadEndpoint: '',\r\n readOnly: this.inputConfig().readonly || false,\r\n data: this.value || undefined,\r\n onChangeFn: this.contentChangedSaveValue.bind(this)\r\n };\r\n\r\n // Browser-only dynamic load — see Trap 16 comment at the top of this file and in config.ts.\r\n const [{ default: EditorJS }, config] = await Promise.all([\r\n import('@editorjs/editorjs'),\r\n loadEditorConfig(payload),\r\n ]);\r\n this.editor = new EditorJS(config);\r\n }\r\n\r\n async contentChangedSaveValue(): Promise<void> {\r\n const value: OutputData | undefined = await this.editor?.save();\r\n this.value = value;\r\n this.onChange(value);\r\n this.valueChanged.emit(value);\r\n }\r\n\r\n override ngOnDestroy(): void {\r\n this.stateChanges.complete();\r\n this.editor?.destroy();\r\n }\r\n}\r\n","\r\n<div class=\" editor-container\" style=\"padding: 16px;\">\r\n <div #editorJs [id]=\"inputConfig().id\"></div>\r\n</div>\r\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, input, viewChild, computed, PLATFORM_ID, ChangeDetectionStrategy, Component, output } from '@angular/core';
|
|
3
|
+
import * as i1$2 from '@angular/forms';
|
|
4
|
+
import { NgControl, ReactiveFormsModule } from '@angular/forms';
|
|
5
|
+
import * as i2 from '@angular/material/form-field';
|
|
6
|
+
import { MatFormFieldControl, MatFormFieldModule } from '@angular/material/form-field';
|
|
7
|
+
import * as i3 from '@angular/material/icon';
|
|
8
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
9
|
+
import * as i1$1 from '@angular/material/button';
|
|
10
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
11
|
+
import * as i5$1 from '@angular/material/tooltip';
|
|
12
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
13
|
+
import { B as BaseCustomInput, q as getInputErrorMessage, u as TFormInputStatusComponent } from './ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs';
|
|
14
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
15
|
+
import * as i1 from '@angular/material/progress-bar';
|
|
16
|
+
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
17
|
+
import * as i5 from '@angular/material/toolbar';
|
|
18
|
+
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
19
|
+
import { InputFileType, UploadTypes, AllDocumentFileExtensions, AllImageFileExtensions } from 'ngx-t-forms-types';
|
|
20
|
+
|
|
21
|
+
const customInputConfig = {
|
|
22
|
+
controlType: 'app-file-uploader',
|
|
23
|
+
nextId: 0,
|
|
24
|
+
};
|
|
25
|
+
class FileUploaderComponent extends BaseCustomInput {
|
|
26
|
+
#platformId;
|
|
27
|
+
constructor() {
|
|
28
|
+
super(inject(NgControl, { optional: true, self: true }), inject(ElementRef), customInputConfig);
|
|
29
|
+
this.inputConfig = input.required(...(ngDevMode ? [{ debugName: "inputConfig" }] : /* istanbul ignore next */ []));
|
|
30
|
+
this.uploader = viewChild.required('uploader');
|
|
31
|
+
this.uploadAccept = computed(() => {
|
|
32
|
+
const cfg = this.inputConfig();
|
|
33
|
+
const fileType = cfg?.fileType;
|
|
34
|
+
if (!fileType) {
|
|
35
|
+
return InputFileType.file;
|
|
36
|
+
}
|
|
37
|
+
return UploadTypes[String(fileType)] ?? InputFileType.file;
|
|
38
|
+
}, ...(ngDevMode ? [{ debugName: "uploadAccept" }] : /* istanbul ignore next */ []));
|
|
39
|
+
this.previewSrc = computed(() => {
|
|
40
|
+
const cfg = this.inputConfig();
|
|
41
|
+
const fileType = cfg?.fileType;
|
|
42
|
+
switch (fileType) {
|
|
43
|
+
case InputFileType.file:
|
|
44
|
+
return 'https://res.cloudinary.com/afrob/image/upload/v1676973154/Flows/Icons/iPhone_14_-_1_tx1scw.png';
|
|
45
|
+
default:
|
|
46
|
+
return this.value?.base64 ?? undefined;
|
|
47
|
+
}
|
|
48
|
+
}, ...(ngDevMode ? [{ debugName: "previewSrc" }] : /* istanbul ignore next */ []));
|
|
49
|
+
this.fileName = null;
|
|
50
|
+
this.loading = null;
|
|
51
|
+
this.dragOver = false;
|
|
52
|
+
this.#platformId = inject(PLATFORM_ID);
|
|
53
|
+
}
|
|
54
|
+
get value() {
|
|
55
|
+
return this._value;
|
|
56
|
+
}
|
|
57
|
+
set value(file) {
|
|
58
|
+
const fileType = this.inputConfig()?.fileType;
|
|
59
|
+
if (!file || typeof file !== 'object') {
|
|
60
|
+
this._value = file;
|
|
61
|
+
this.stateChanges.next();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const { base64, fileExtension } = file;
|
|
65
|
+
if (!base64) {
|
|
66
|
+
this._value = file;
|
|
67
|
+
this.stateChanges.next();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const allDocExtensions = Object.values(AllDocumentFileExtensions);
|
|
71
|
+
const allImageExtensions = Object.values(AllImageFileExtensions);
|
|
72
|
+
const isFile = allDocExtensions.includes(fileExtension);
|
|
73
|
+
const isImage = allImageExtensions.includes(fileExtension);
|
|
74
|
+
if ((fileType === InputFileType.file && !isFile) ||
|
|
75
|
+
((fileType === InputFileType.Image || fileType === InputFileType.CaptureImage) && !isImage)) {
|
|
76
|
+
this._value = null;
|
|
77
|
+
this.temporaryError(`Invalid file type. Expected ${fileType} file`);
|
|
78
|
+
this.stateChanges.next();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this._value = file;
|
|
83
|
+
this.stateChanges.next();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
get empty() {
|
|
88
|
+
return !this.value;
|
|
89
|
+
}
|
|
90
|
+
get shouldLabelFloat() {
|
|
91
|
+
return this.focused || !this.empty;
|
|
92
|
+
}
|
|
93
|
+
onContainerClick(event) {
|
|
94
|
+
this.uploader().nativeElement.click();
|
|
95
|
+
if (event.target !== this._elementRef.nativeElement) {
|
|
96
|
+
this.markAsTouched();
|
|
97
|
+
this.stateChanges.next();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
triggerUploader() {
|
|
101
|
+
this.uploader().nativeElement.click();
|
|
102
|
+
}
|
|
103
|
+
onFileSelected(event) {
|
|
104
|
+
const files = event.target.files;
|
|
105
|
+
if (files && files.length > 0) {
|
|
106
|
+
const file = files[0];
|
|
107
|
+
if (!file)
|
|
108
|
+
return;
|
|
109
|
+
this.assignFile(file);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
assignFile(file) {
|
|
113
|
+
// FileReader is a browser-only API; gate by isPlatformBrowser to keep SSR-safe.
|
|
114
|
+
if (!isPlatformBrowser(this.#platformId)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const reader = new FileReader();
|
|
118
|
+
reader.onload = () => {
|
|
119
|
+
this.fileName = file.name;
|
|
120
|
+
const nameSplit = file.name.split('.');
|
|
121
|
+
const fileExtension = nameSplit[nameSplit.length - 1];
|
|
122
|
+
this.value = {
|
|
123
|
+
fileName: file.name,
|
|
124
|
+
base64: reader.result,
|
|
125
|
+
type: this.inputConfig()?.fileType,
|
|
126
|
+
blob: file,
|
|
127
|
+
fileExtension,
|
|
128
|
+
};
|
|
129
|
+
this.onChange(this.value);
|
|
130
|
+
};
|
|
131
|
+
reader.readAsDataURL(file);
|
|
132
|
+
}
|
|
133
|
+
onDragOver(event) {
|
|
134
|
+
this.dragOver = true;
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
event.stopPropagation();
|
|
137
|
+
}
|
|
138
|
+
onDrop(event) {
|
|
139
|
+
this.dragOver = false;
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
event.stopPropagation();
|
|
142
|
+
const files = event.dataTransfer?.files;
|
|
143
|
+
if (files && files.length > 0) {
|
|
144
|
+
const file = files[0];
|
|
145
|
+
if (!file)
|
|
146
|
+
return;
|
|
147
|
+
this.assignFile(file);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
onDragLeave(event) {
|
|
151
|
+
this.dragOver = false;
|
|
152
|
+
event.preventDefault();
|
|
153
|
+
event.stopPropagation();
|
|
154
|
+
}
|
|
155
|
+
clearFile(event) {
|
|
156
|
+
event.preventDefault();
|
|
157
|
+
event.stopPropagation();
|
|
158
|
+
this.value = null;
|
|
159
|
+
this.stateChanges.next();
|
|
160
|
+
}
|
|
161
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FileUploaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
162
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FileUploaderComponent, isStandalone: true, selector: "lib-file-uploader", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class.floating": "shouldLabelFloat", "id": "id" } }, providers: [{ provide: MatFormFieldControl, useExisting: FileUploaderComponent }], viewQueries: [{ propertyName: "uploader", first: true, predicate: ["uploader"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "@if (loading) {\r\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\r\n}\r\n\r\n@if (!shouldLabelFloat) {\r\n <section>\r\n <br>\r\n <div\r\n [style.border-color]=\"dragOver ? ' var(--mat-stepper-header-selected-state-icon-background-color)' : '#ccc;'\"\r\n (dragover)=\"onDragOver($event)\"\r\n (drop)=\"onDrop($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n class=\"drop-zone\">\r\n <div>\r\n <mat-icon>\r\n cloud_upload\r\n </mat-icon>\r\n </div>\r\n <div>\r\n @if (!!errorMessage) {\r\n <span class=\"mat-mdc-form-field-error\">\r\n {{ errorMessage }}\r\n </span>\r\n } @else {\r\n Drag and drop files or click to upload\r\n }\r\n </div>\r\n </div>\r\n </section>\r\n}\r\n\r\n<input\r\n style=\"display: none\"\r\n hidden\r\n [readonly]=\"!!inputConfig().readonly\"\r\n [type]=\"inputConfig().type || 'file'\"\r\n [accept]=\"uploadAccept()\"\r\n (change)=\"onFileSelected($event)\"\r\n #uploader\r\n/>\r\n\r\n@if (!!shouldLabelFloat) {\r\n <div\r\n [style.border-color]=\"dragOver ? 'var(--mat-stepper-header-selected-state-icon-background-color)' : '#ccc;'\"\r\n class=\"drop-zone\"\r\n (dragover)=\"onDragOver($event)\"\r\n (drop)=\"onDrop($event)\"\r\n (dragleave)=\"onDragLeave($event)\">\r\n <img style=\"width: 100%;\" [src]=\"previewSrc()\" alt=\"\">\r\n <mat-toolbar style=\" height: min-content !important;\">\r\n <mat-icon\r\n [style.color]=\"dragOver ? 'var(--mat-stepper-header-selected-state-icon-background-color)' : ''\">\r\n cloud_upload\r\n </mat-icon>\r\n <span class=\"spacer\"></span>\r\n <div style=\"padding: 8px;\">\r\n @if (!!fileName) {\r\n <div style=\"\r\n line-height: normal;width: 100%;\r\n white-space:normal;overflow: hidden;text-overflow: ellipsis;\r\n font-size: 0.75em;color:var(--mat-stepper-header-selected-state-icon-background-color);\">\r\n {{ fileName }}\r\n </div>\r\n }\r\n <div style=\"font-size: 0.875em;\">\r\n Drag and drop files or click to upload\r\n </div>\r\n </div>\r\n\r\n <span class=\"spacer\"></span>\r\n <button (click)=\"clearFile($event)\" mat-icon-button>\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </mat-toolbar>\r\n </div>\r\n}\r\n", styles: [".fileUploader{opacity:0;display:none;transition:opacity .2s;height:50px}:host.floating .fileUploader{opacity:1}.drop-zone{border:2px dashed #ccc;padding:20px;text-align:center;cursor:pointer}.drop-zone:hover{border-color:var(--mat-stepper-header-selected-state-icon-background-color)}\n"], dependencies: [{ kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i5.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
163
|
+
}
|
|
164
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FileUploaderComponent, decorators: [{
|
|
165
|
+
type: Component,
|
|
166
|
+
args: [{ selector: 'lib-file-uploader', imports: [
|
|
167
|
+
MatProgressBarModule,
|
|
168
|
+
MatIconModule,
|
|
169
|
+
MatToolbarModule,
|
|
170
|
+
MatButtonModule,
|
|
171
|
+
], host: {
|
|
172
|
+
'[class.floating]': 'shouldLabelFloat',
|
|
173
|
+
'[id]': 'id',
|
|
174
|
+
}, providers: [{ provide: MatFormFieldControl, useExisting: FileUploaderComponent }], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (loading) {\r\n <mat-progress-bar mode=\"indeterminate\"></mat-progress-bar>\r\n}\r\n\r\n@if (!shouldLabelFloat) {\r\n <section>\r\n <br>\r\n <div\r\n [style.border-color]=\"dragOver ? ' var(--mat-stepper-header-selected-state-icon-background-color)' : '#ccc;'\"\r\n (dragover)=\"onDragOver($event)\"\r\n (drop)=\"onDrop($event)\"\r\n (dragleave)=\"onDragLeave($event)\"\r\n class=\"drop-zone\">\r\n <div>\r\n <mat-icon>\r\n cloud_upload\r\n </mat-icon>\r\n </div>\r\n <div>\r\n @if (!!errorMessage) {\r\n <span class=\"mat-mdc-form-field-error\">\r\n {{ errorMessage }}\r\n </span>\r\n } @else {\r\n Drag and drop files or click to upload\r\n }\r\n </div>\r\n </div>\r\n </section>\r\n}\r\n\r\n<input\r\n style=\"display: none\"\r\n hidden\r\n [readonly]=\"!!inputConfig().readonly\"\r\n [type]=\"inputConfig().type || 'file'\"\r\n [accept]=\"uploadAccept()\"\r\n (change)=\"onFileSelected($event)\"\r\n #uploader\r\n/>\r\n\r\n@if (!!shouldLabelFloat) {\r\n <div\r\n [style.border-color]=\"dragOver ? 'var(--mat-stepper-header-selected-state-icon-background-color)' : '#ccc;'\"\r\n class=\"drop-zone\"\r\n (dragover)=\"onDragOver($event)\"\r\n (drop)=\"onDrop($event)\"\r\n (dragleave)=\"onDragLeave($event)\">\r\n <img style=\"width: 100%;\" [src]=\"previewSrc()\" alt=\"\">\r\n <mat-toolbar style=\" height: min-content !important;\">\r\n <mat-icon\r\n [style.color]=\"dragOver ? 'var(--mat-stepper-header-selected-state-icon-background-color)' : ''\">\r\n cloud_upload\r\n </mat-icon>\r\n <span class=\"spacer\"></span>\r\n <div style=\"padding: 8px;\">\r\n @if (!!fileName) {\r\n <div style=\"\r\n line-height: normal;width: 100%;\r\n white-space:normal;overflow: hidden;text-overflow: ellipsis;\r\n font-size: 0.75em;color:var(--mat-stepper-header-selected-state-icon-background-color);\">\r\n {{ fileName }}\r\n </div>\r\n }\r\n <div style=\"font-size: 0.875em;\">\r\n Drag and drop files or click to upload\r\n </div>\r\n </div>\r\n\r\n <span class=\"spacer\"></span>\r\n <button (click)=\"clearFile($event)\" mat-icon-button>\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </mat-toolbar>\r\n </div>\r\n}\r\n", styles: [".fileUploader{opacity:0;display:none;transition:opacity .2s;height:50px}:host.floating .fileUploader{opacity:1}.drop-zone{border:2px dashed #ccc;padding:20px;text-align:center;cursor:pointer}.drop-zone:hover{border-color:var(--mat-stepper-header-selected-state-icon-background-color)}\n"] }]
|
|
175
|
+
}], ctorParameters: () => [], propDecorators: { inputConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputConfig", required: true }] }], uploader: [{ type: i0.ViewChild, args: ['uploader', { isSignal: true }] }] } });
|
|
176
|
+
|
|
177
|
+
/** Wraps a reactive file-uploader control inside a `mat-form-field`. */
|
|
178
|
+
class FileUploadInputElementComponent {
|
|
179
|
+
constructor() {
|
|
180
|
+
this.inputConfig = input.required(...(ngDevMode ? [{ debugName: "inputConfig" }] : /* istanbul ignore next */ []));
|
|
181
|
+
this.formGroup = input.required(...(ngDevMode ? [{ debugName: "formGroup" }] : /* istanbul ignore next */ []));
|
|
182
|
+
this.reload = output();
|
|
183
|
+
this.errorMessage = computed(() => getInputErrorMessage(this.inputConfig(), this.formGroup()), ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
|
|
184
|
+
}
|
|
185
|
+
getErrors() {
|
|
186
|
+
return this.formGroup().controls[this.inputConfig().id]?.errors;
|
|
187
|
+
}
|
|
188
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FileUploadInputElementComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
189
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FileUploadInputElementComponent, isStandalone: true, selector: "lib-file-upload-input-element", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { reload: "reload" }, ngImport: i0, template: "<form [formGroup]=\"formGroup()\">\r\n @if (inputConfig(); as inputConfig) {\r\n <mat-form-field [appearance]=\"inputConfig.appearance || 'fill'\" subscriptSizing=\"dynamic\">\r\n <mat-label>\r\n {{ inputConfig.label }}\r\n <lib-t-form-input-status [inputConfig]=\"inputConfig\"></lib-t-form-input-status>\r\n </mat-label>\r\n\r\n <lib-file-uploader\r\n [inputConfig]=\"inputConfig\"\r\n [formControlName]=\"inputConfig.id\"\r\n [required]=\"inputConfig.required\"\r\n ></lib-file-uploader>\r\n\r\n @if (inputConfig.hintLabel || inputConfig.temporaryHint) {\r\n <mat-hint class=\"inputHint\">\r\n {{ inputConfig.temporaryHint || inputConfig.hintLabel }}\r\n </mat-hint>\r\n }\r\n\r\n @if (!!errorMessage()) {\r\n <mat-error class=\"oneLineTextEllipsis\" matTooltipClass=\"errorToolTip\">{{ errorMessage() }}</mat-error>\r\n }\r\n\r\n @if (inputConfig.prefixIcon) {\r\n <mat-icon matPrefix>{{ inputConfig.prefixIcon }}</mat-icon>\r\n }\r\n\r\n @if (inputConfig.canReload?.canReload) {\r\n <button\r\n mat-icon-button\r\n style=\"margin-right: 4px;\"\r\n matTooltip=\"Click to refresh this field.\"\r\n class=\"input-sync-button\"\r\n (click)=\"inputConfig.canReload.emit()\"\r\n matSuffix\r\n >\r\n <mat-icon style=\"color: var(--mat-sys-primary)\">sync</mat-icon>\r\n </button>\r\n }\r\n\r\n @if (inputConfig.suffixIcon && inputConfig.id !== 'password') {\r\n <mat-icon matSuffix>{{ inputConfig.suffixIcon }}</mat-icon>\r\n }\r\n\r\n @if (inputConfig.prefixText) {\r\n <span matPrefix style=\"top: 0\">{{ inputConfig.prefixText }}</span>\r\n }\r\n @if (inputConfig.suffixText) {\r\n <span matSuffix style=\"padding-left: 5px\">{{ inputConfig.suffixText }}</span>\r\n }\r\n\r\n @if (inputConfig.maxLength && formGroup()) {\r\n <mat-hint align=\"end\">\r\n {{ (formGroup().controls[inputConfig.id]?.value?.length || 0) + '/' + inputConfig.maxLength }}\r\n </mat-hint>\r\n }\r\n </mat-form-field>\r\n }\r\n</form>\r\n", styles: ["mat-form-field{width:100%!important}mat-form-field .input-sync-button{display:none}mat-form-field:hover .input-sync-button{display:inline-block}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FileUploaderComponent, selector: "lib-file-uploader", inputs: ["inputConfig"] }, { kind: "component", type: TFormInputStatusComponent, selector: "lib-t-form-input-status", inputs: ["inputConfig"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
190
|
+
}
|
|
191
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FileUploadInputElementComponent, decorators: [{
|
|
192
|
+
type: Component,
|
|
193
|
+
args: [{ selector: 'lib-file-upload-input-element', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
194
|
+
ReactiveFormsModule,
|
|
195
|
+
MatFormFieldModule,
|
|
196
|
+
MatIconModule,
|
|
197
|
+
MatButtonModule,
|
|
198
|
+
MatTooltipModule,
|
|
199
|
+
FileUploaderComponent,
|
|
200
|
+
TFormInputStatusComponent,
|
|
201
|
+
], template: "<form [formGroup]=\"formGroup()\">\r\n @if (inputConfig(); as inputConfig) {\r\n <mat-form-field [appearance]=\"inputConfig.appearance || 'fill'\" subscriptSizing=\"dynamic\">\r\n <mat-label>\r\n {{ inputConfig.label }}\r\n <lib-t-form-input-status [inputConfig]=\"inputConfig\"></lib-t-form-input-status>\r\n </mat-label>\r\n\r\n <lib-file-uploader\r\n [inputConfig]=\"inputConfig\"\r\n [formControlName]=\"inputConfig.id\"\r\n [required]=\"inputConfig.required\"\r\n ></lib-file-uploader>\r\n\r\n @if (inputConfig.hintLabel || inputConfig.temporaryHint) {\r\n <mat-hint class=\"inputHint\">\r\n {{ inputConfig.temporaryHint || inputConfig.hintLabel }}\r\n </mat-hint>\r\n }\r\n\r\n @if (!!errorMessage()) {\r\n <mat-error class=\"oneLineTextEllipsis\" matTooltipClass=\"errorToolTip\">{{ errorMessage() }}</mat-error>\r\n }\r\n\r\n @if (inputConfig.prefixIcon) {\r\n <mat-icon matPrefix>{{ inputConfig.prefixIcon }}</mat-icon>\r\n }\r\n\r\n @if (inputConfig.canReload?.canReload) {\r\n <button\r\n mat-icon-button\r\n style=\"margin-right: 4px;\"\r\n matTooltip=\"Click to refresh this field.\"\r\n class=\"input-sync-button\"\r\n (click)=\"inputConfig.canReload.emit()\"\r\n matSuffix\r\n >\r\n <mat-icon style=\"color: var(--mat-sys-primary)\">sync</mat-icon>\r\n </button>\r\n }\r\n\r\n @if (inputConfig.suffixIcon && inputConfig.id !== 'password') {\r\n <mat-icon matSuffix>{{ inputConfig.suffixIcon }}</mat-icon>\r\n }\r\n\r\n @if (inputConfig.prefixText) {\r\n <span matPrefix style=\"top: 0\">{{ inputConfig.prefixText }}</span>\r\n }\r\n @if (inputConfig.suffixText) {\r\n <span matSuffix style=\"padding-left: 5px\">{{ inputConfig.suffixText }}</span>\r\n }\r\n\r\n @if (inputConfig.maxLength && formGroup()) {\r\n <mat-hint align=\"end\">\r\n {{ (formGroup().controls[inputConfig.id]?.value?.length || 0) + '/' + inputConfig.maxLength }}\r\n </mat-hint>\r\n }\r\n </mat-form-field>\r\n }\r\n</form>\r\n", styles: ["mat-form-field{width:100%!important}mat-form-field .input-sync-button{display:none}mat-form-field:hover .input-sync-button{display:inline-block}\n"] }]
|
|
202
|
+
}], propDecorators: { inputConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputConfig", required: true }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: true }] }], reload: [{ type: i0.Output, args: ["reload"] }] } });
|
|
203
|
+
|
|
204
|
+
export { FileUploadInputElementComponent };
|
|
205
|
+
//# sourceMappingURL=ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs.map
|