ngx-t-forms 2.0.29 → 2.0.31
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-DCKuXHAW.mjs +104 -0
- package/fesm2022/ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs +85 -0
- package/fesm2022/ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs +643 -0
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs +97 -0
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs +195 -0
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs +261 -0
- package/fesm2022/ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs +85 -0
- package/fesm2022/ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs +156 -0
- package/fesm2022/ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs +368 -0
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-document-picker.component-qObjcqhE.mjs +704 -0
- package/fesm2022/ngx-t-forms-document-picker.component-qObjcqhE.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs +294 -0
- package/fesm2022/ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs +240 -0
- package/fesm2022/ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs +205 -0
- package/fesm2022/ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs +86 -0
- package/fesm2022/ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-json-view.component-856Hx1Bg.mjs +22 -0
- package/fesm2022/ngx-t-forms-form-json-view.component-856Hx1Bg.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs +179 -0
- package/fesm2022/ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs +319 -0
- package/fesm2022/ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs +379 -0
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-geo-location.component-Bosp1UzR.mjs +124 -0
- package/fesm2022/ngx-t-forms-geo-location.component-Bosp1UzR.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-C1g7Z0cK.mjs +180 -0
- package/fesm2022/ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs +2 -0
- package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-input-custom.component-BkbHFAyR.mjs +105 -0
- package/fesm2022/ngx-t-forms-input-custom.component-BkbHFAyR.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-input-editor.component-BPUOM9kQ.mjs +181 -0
- package/fesm2022/ngx-t-forms-input-editor.component-BPUOM9kQ.mjs.map +1 -0
- package/fesm2022/{ngx-t-forms-map-mat-options-keys-CbdW82su.mjs → ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs} +12 -14
- package/fesm2022/ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs +66 -0
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.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-DrnH8qdG.mjs +38 -0
- package/fesm2022/ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs +38 -0
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.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-C0qsMfsq.mjs +336 -0
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.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-C7y1OGPx.mjs +905 -0
- package/fesm2022/ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-ngx-t-forms-u_kigDid.mjs +19461 -0
- package/fesm2022/ngx-t-forms-ngx-t-forms-u_kigDid.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs +555 -0
- package/fesm2022/ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs +748 -0
- package/fesm2022/ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-record-list-manager.component-CUMMvMch.mjs +358 -0
- package/fesm2022/ngx-t-forms-record-list-manager.component-CUMMvMch.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs +272 -0
- package/fesm2022/ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs +398 -0
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.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-BxOhR6C0.mjs +98 -0
- package/fesm2022/ngx-t-forms-section-report.component-BxOhR6C0.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-select-input-element.component-DbgZdNoe.mjs +150 -0
- package/fesm2022/ngx-t-forms-select-input-element.component-DbgZdNoe.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs +169 -0
- package/fesm2022/ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs +204 -0
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs +95 -0
- package/fesm2022/ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs +82 -0
- package/fesm2022/ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-validators-config.component-oGjQVGE2.mjs +733 -0
- package/fesm2022/ngx-t-forms-validators-config.component-oGjQVGE2.mjs.map +1 -0
- package/fesm2022/ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs +1303 -0
- package/fesm2022/ngx-t-forms-workflow-adjudication.component-CtU8dECN.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 +1767 -621
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-D-SBMdYg.mjs +0 -313
- package/fesm2022/ngx-t-forms-calculated-field-rules.component-D-SBMdYg.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-1cpszpPN.mjs +0 -191
- package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-1cpszpPN.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-DFdAVWTg.mjs +0 -207
- package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-DFdAVWTg.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-data-source-picker.component-DxORinAD.mjs +0 -204
- package/fesm2022/ngx-t-forms-data-source-picker.component-DxORinAD.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-DcWS1txl.mjs +0 -289
- package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-DcWS1txl.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-form-input-selector.component-B2QEnvkq.mjs +0 -134
- package/fesm2022/ngx-t-forms-form-input-selector.component-B2QEnvkq.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-form-json-view.component-DePf44w6.mjs +0 -22
- package/fesm2022/ngx-t-forms-form-json-view.component-DePf44w6.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-form-section-stepper.component-BTkcSjg7.mjs +0 -270
- package/fesm2022/ngx-t-forms-form-section-stepper.component-BTkcSjg7.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-Wamzf_sq.mjs +0 -345
- package/fesm2022/ngx-t-forms-forms-builder-menu.component-Wamzf_sq.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-input-editor.component-D4xHO76K.mjs +0 -147
- package/fesm2022/ngx-t-forms-input-editor.component-D4xHO76K.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-map-mat-options-keys-CbdW82su.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-DmTyO9Wi.mjs +0 -105
- package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-DmTyO9Wi.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mat-slider-editor.component-DZ4TenrI.mjs +0 -109
- package/fesm2022/ngx-t-forms-mat-slider-editor.component-DZ4TenrI.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-DPyBYE4p.mjs +0 -155
- package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-DPyBYE4p.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-missing-form-configs.component-BRmnwAK6.mjs +0 -28
- package/fesm2022/ngx-t-forms-missing-form-configs.component-BRmnwAK6.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-D_umeAPL.mjs +0 -43
- package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-D_umeAPL.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-error-display.component-CSX2NCNU.mjs +0 -116
- package/fesm2022/ngx-t-forms-mscoa-error-display.component-CSX2NCNU.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-B6IF8kGg.mjs +0 -296
- package/fesm2022/ngx-t-forms-mscoa-segment-config.component-B6IF8kGg.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-BPkjsRmH.mjs +0 -83
- package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-BPkjsRmH.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-ngx-t-forms-D9qmig6g.mjs +0 -16844
- package/fesm2022/ngx-t-forms-ngx-t-forms-D9qmig6g.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-pipeline-generator.component-DBJEyCbd.mjs +0 -613
- package/fesm2022/ngx-t-forms-pipeline-generator.component-DBJEyCbd.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-record-list-manager.component-Dgs9lNSr.mjs +0 -269
- package/fesm2022/ngx-t-forms-record-list-manager.component-Dgs9lNSr.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-required-inputs.component-CSIJvSHq.mjs +0 -190
- package/fesm2022/ngx-t-forms-required-inputs.component-CSIJvSHq.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-CY-JSkGs.mjs +0 -291
- package/fesm2022/ngx-t-forms-rest-api-call-setup.component-CY-JSkGs.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-section-report.component-12-KdKT6.mjs +0 -156
- package/fesm2022/ngx-t-forms-section-report.component-12-KdKT6.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-selection-options-editor.component-Be3QAG_L.mjs +0 -186
- package/fesm2022/ngx-t-forms-selection-options-editor.component-Be3QAG_L.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-a4f1r8gH.mjs +0 -187
- package/fesm2022/ngx-t-forms-t-workflow-picker.component-a4f1r8gH.mjs.map +0 -1
- package/fesm2022/ngx-t-forms-validators-config.component-B3j9Dmgu.mjs +0 -215
- package/fesm2022/ngx-t-forms-validators-config.component-B3j9Dmgu.mjs.map +0 -1
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, ChangeDetectionStrategy, Component, computed, signal, DestroyRef } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import * as i1$3 from '@angular/material/badge';
|
|
5
|
+
import { MatBadgeModule } from '@angular/material/badge';
|
|
6
|
+
import * as i1 from '@angular/material/button';
|
|
7
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
8
|
+
import * as i3 from '@angular/material/icon';
|
|
9
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
10
|
+
import * as i6 from '@angular/material/menu';
|
|
11
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
12
|
+
import * as i5 from '@angular/material/tooltip';
|
|
13
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
14
|
+
import * as i3$2 from '@angular/material/card';
|
|
15
|
+
import { MatCardModule } from '@angular/material/card';
|
|
16
|
+
import * as i5$2 from '@angular/material/toolbar';
|
|
17
|
+
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
18
|
+
import { MatDividerModule } from '@angular/material/divider';
|
|
19
|
+
import * as i3$1 from '@angular/material/progress-spinner';
|
|
20
|
+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
21
|
+
import * as i2 from '@angular/material/form-field';
|
|
22
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
23
|
+
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
24
|
+
import * as i1$2 from '@angular/material/dialog';
|
|
25
|
+
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
|
|
26
|
+
import * as i1$1 from '@angular/cdk/clipboard';
|
|
27
|
+
import { ClipboardModule } from '@angular/cdk/clipboard';
|
|
28
|
+
import { AsyncPipe, TitleCasePipe } from '@angular/common';
|
|
29
|
+
import { F as FormsStoreService, g as getAvatar, D as DaysAgoPipe, N as NGX_T_FORMS_CONFIG_TOKEN, t as testAgainstItem, a as assignDeepPropertyToObject, T as TDynamicDataEditComponent } from './ngx-t-forms-ngx-t-forms-u_kigDid.mjs';
|
|
30
|
+
import * as i5$1 from '@angular/material/expansion';
|
|
31
|
+
import { MatExpansionModule } from '@angular/material/expansion';
|
|
32
|
+
import { ElementEditorTypes, SpecialElementKeys, validateApiDataFetchingConfiguration } from 'ngx-t-forms-types';
|
|
33
|
+
import * as i4 from '@angular/material/list';
|
|
34
|
+
import { take } from 'rxjs';
|
|
35
|
+
|
|
36
|
+
class SelectFormTemplateComponent {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.#store = inject(FormsStoreService);
|
|
39
|
+
this.#dialogRef = inject((MatDialogRef));
|
|
40
|
+
// TODO(phase-3): MAT_DIALOG_DATA payload shape is not typed by callers; keep `unknown` here.
|
|
41
|
+
this.data = inject(MAT_DIALOG_DATA);
|
|
42
|
+
this.selectForms$ = this.#store.selectors.selectForms$;
|
|
43
|
+
this.selectLoadingForms$ = this.#store.selectors.selectLoadingForms$;
|
|
44
|
+
}
|
|
45
|
+
#store;
|
|
46
|
+
#dialogRef;
|
|
47
|
+
ngOnInit() {
|
|
48
|
+
this.#store.effects.loadForms$();
|
|
49
|
+
}
|
|
50
|
+
close() {
|
|
51
|
+
this.#dialogRef.close();
|
|
52
|
+
}
|
|
53
|
+
selectForm(form) {
|
|
54
|
+
this.#store.actionsFormBuilder.applyFormTemplate(form);
|
|
55
|
+
this.#dialogRef.close(form);
|
|
56
|
+
}
|
|
57
|
+
getFormAvatar(formTitle) {
|
|
58
|
+
return getAvatar(formTitle);
|
|
59
|
+
}
|
|
60
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: SelectFormTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
61
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: SelectFormTemplateComponent, isStandalone: true, selector: "lib-select-form-template", ngImport: i0, template: "<div class=\"template-select-dialog\">\r\n <!-- Header: icon + title + subtitle per design rule \u00A74 -->\r\n <header class=\"dialog-header\">\r\n <div class=\"header-icon\" aria-hidden=\"true\">\r\n <mat-icon>description</mat-icon>\r\n </div>\r\n <div class=\"header-text\">\r\n <h1 class=\"header-title\">Choose a Form Template</h1>\r\n <p class=\"header-subtitle\">\r\n Select a pre-built form template to start with. You can customize and save it as your own form after copying it to the editor.\r\n </p>\r\n </div>\r\n </header>\r\n\r\n <section class=\"dialog-content\">\r\n @if (selectLoadingForms$ | async) {\r\n <div class=\"loading-state\">\r\n <mat-spinner diameter=\"40\" aria-label=\"Loading form templates\"></mat-spinner>\r\n <span class=\"loading-text\">Loading form templates...</span>\r\n </div>\r\n } @else {\r\n <ul class=\"form-template-list\" aria-label=\"Available form templates\">\r\n @for (form of selectForms$ | async; track form._id) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"form-list-item\"\r\n (click)=\"selectForm(form)\"\r\n [matTooltip]=\"'Click to select this template'\"\r\n [attr.aria-label]=\"'Select template: ' + form.formTitle\">\r\n <img\r\n class=\"form-avatar\"\r\n [class.form-avatar--error]=\"form.errors.length > 0\"\r\n [src]=\"getFormAvatar(form.formTitle)\"\r\n [alt]=\"''\"\r\n aria-hidden=\"true\">\r\n <div class=\"form-item-content\">\r\n <span class=\"form-title\">{{ form.formTitle | titlecase }}</span>\r\n <div class=\"form-metadata\">\r\n @if (form.errors.length > 0) {\r\n <span class=\"metadata-item\">\r\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\r\n <small>{{ form.errors.length }}</small>\r\n </span>\r\n <span class=\"metadata-divider\" aria-hidden=\"true\">\u2022</span>\r\n }\r\n <span class=\"metadata-item\">\r\n <mat-icon aria-hidden=\"true\">add_circle_outline</mat-icon>\r\n <small>{{ form.createdAt | daysAgo }}</small>\r\n </span>\r\n <span class=\"metadata-divider\" aria-hidden=\"true\">\u2022</span>\r\n <span class=\"metadata-item\">\r\n <mat-icon aria-hidden=\"true\">update</mat-icon>\r\n <small>{{ form.updatedAt | daysAgo }}</small>\r\n </span>\r\n </div>\r\n </div>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n\r\n @if ((selectForms$ | async)?.length === 0) {\r\n <div class=\"empty-state\">\r\n <mat-icon class=\"empty-state-icon\" aria-hidden=\"true\">folder_off</mat-icon>\r\n <p>No form templates available.</p>\r\n </div>\r\n }\r\n }\r\n </section>\r\n\r\n <footer class=\"dialog-actions\">\r\n <button mat-button (click)=\"close()\" aria-label=\"Close dialog\">\r\n Close\r\n </button>\r\n </footer>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.template-select-dialog{display:flex;flex-direction:column;min-width:28rem;max-width:36rem;max-height:calc(100vh - 24px);background:var(--mat-sys-surface, var(--mat-app-surface));overflow:hidden}.dialog-header{display:flex;align-items:flex-start;gap:1rem;padding:1.5rem 1.5rem 0;flex-shrink:0}.header-icon{width:2.75rem;height:2.75rem;border-radius:8px;background:color-mix(in srgb,var(--lib-forms-primary) 12%,transparent);display:flex;align-items:center;justify-content:center;flex-shrink:0}.header-icon mat-icon{font-size:1.5rem;width:1.5rem;height:1.5rem;color:var(--lib-forms-primary)}.header-text{flex:1;min-width:0}.header-title{font-size:1.25rem;font-weight:600;letter-spacing:-.01em;color:var(--lib-forms-on-surface);margin:0;line-height:1.3}.header-subtitle{font-size:.875rem;color:var(--lib-forms-on-surface-variant);line-height:1.4;margin-top:.25rem;margin-bottom:0}.dialog-content{padding:1rem 1.5rem 1.5rem;overflow-y:auto;max-height:70vh;flex:1;min-height:0}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;gap:1rem;min-height:12rem}.loading-text{font-size:.875rem;color:var(--lib-forms-on-surface-variant)}.form-template-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}.form-list-item{display:flex;align-items:flex-start;gap:1rem;width:100%;padding:.5rem 1.25rem;min-height:2.25rem;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);border-radius:8px;background:var(--mat-sys-surface-container, var(--mat-app-surface-container-low));color:var(--lib-forms-on-surface);font-size:.875rem;text-align:left;cursor:pointer;transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),background-color var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 2px 8px #00000014}.form-list-item:hover{border-color:var(--lib-forms-primary);background:color-mix(in srgb,var(--lib-forms-primary) 6%,transparent)}.form-list-item:focus-visible{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--lib-forms-primary) 25%,transparent)}.form-list-item:active{background:color-mix(in srgb,var(--lib-forms-primary) 12%,transparent)}@media(prefers-color-scheme:dark){.form-list-item{box-shadow:0 1px 3px #0000004d}}.form-avatar{width:2.5rem;height:2.5rem;border-radius:6px;object-fit:cover;flex-shrink:0;display:block}.form-avatar.form-avatar--error{outline:2px solid var(--sem-error);outline-offset:2px}.form-item-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:.25rem}.form-title{font-weight:600;font-size:.9375rem}.form-metadata{display:flex;align-items:center;flex-wrap:wrap;gap:.25rem;font-size:.75rem;color:var(--lib-forms-on-surface-variant);line-height:1.35}.form-metadata .metadata-divider{margin:0 .25rem;opacity:.7}.form-metadata .metadata-item{display:inline-flex;align-items:center;gap:.25rem}.form-metadata .metadata-item mat-icon{font-size:.875rem;width:.875rem;height:.875rem}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1.5rem;background:var(--mat-sys-surface-container, var(--mat-app-surface-container-low));border-radius:8px;text-align:center}.empty-state p{font-size:.875rem;color:var(--lib-forms-on-surface-variant);margin:0}.empty-state-icon{font-size:2rem;width:2rem;height:2rem;color:var(--lib-forms-on-surface-variant);opacity:.7}.dialog-actions{display:flex;justify-content:flex-end;align-items:center;gap:.75rem;padding:1rem 1.5rem 1.25rem;flex-shrink:0;border-top:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: DaysAgoPipe, name: "daysAgo" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
62
|
+
}
|
|
63
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: SelectFormTemplateComponent, decorators: [{
|
|
64
|
+
type: Component,
|
|
65
|
+
args: [{ selector: 'lib-select-form-template', imports: [
|
|
66
|
+
AsyncPipe,
|
|
67
|
+
TitleCasePipe,
|
|
68
|
+
MatButtonModule,
|
|
69
|
+
MatIconModule,
|
|
70
|
+
MatProgressSpinnerModule,
|
|
71
|
+
MatTooltipModule,
|
|
72
|
+
DaysAgoPipe,
|
|
73
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"template-select-dialog\">\r\n <!-- Header: icon + title + subtitle per design rule \u00A74 -->\r\n <header class=\"dialog-header\">\r\n <div class=\"header-icon\" aria-hidden=\"true\">\r\n <mat-icon>description</mat-icon>\r\n </div>\r\n <div class=\"header-text\">\r\n <h1 class=\"header-title\">Choose a Form Template</h1>\r\n <p class=\"header-subtitle\">\r\n Select a pre-built form template to start with. You can customize and save it as your own form after copying it to the editor.\r\n </p>\r\n </div>\r\n </header>\r\n\r\n <section class=\"dialog-content\">\r\n @if (selectLoadingForms$ | async) {\r\n <div class=\"loading-state\">\r\n <mat-spinner diameter=\"40\" aria-label=\"Loading form templates\"></mat-spinner>\r\n <span class=\"loading-text\">Loading form templates...</span>\r\n </div>\r\n } @else {\r\n <ul class=\"form-template-list\" aria-label=\"Available form templates\">\r\n @for (form of selectForms$ | async; track form._id) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"form-list-item\"\r\n (click)=\"selectForm(form)\"\r\n [matTooltip]=\"'Click to select this template'\"\r\n [attr.aria-label]=\"'Select template: ' + form.formTitle\">\r\n <img\r\n class=\"form-avatar\"\r\n [class.form-avatar--error]=\"form.errors.length > 0\"\r\n [src]=\"getFormAvatar(form.formTitle)\"\r\n [alt]=\"''\"\r\n aria-hidden=\"true\">\r\n <div class=\"form-item-content\">\r\n <span class=\"form-title\">{{ form.formTitle | titlecase }}</span>\r\n <div class=\"form-metadata\">\r\n @if (form.errors.length > 0) {\r\n <span class=\"metadata-item\">\r\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\r\n <small>{{ form.errors.length }}</small>\r\n </span>\r\n <span class=\"metadata-divider\" aria-hidden=\"true\">\u2022</span>\r\n }\r\n <span class=\"metadata-item\">\r\n <mat-icon aria-hidden=\"true\">add_circle_outline</mat-icon>\r\n <small>{{ form.createdAt | daysAgo }}</small>\r\n </span>\r\n <span class=\"metadata-divider\" aria-hidden=\"true\">\u2022</span>\r\n <span class=\"metadata-item\">\r\n <mat-icon aria-hidden=\"true\">update</mat-icon>\r\n <small>{{ form.updatedAt | daysAgo }}</small>\r\n </span>\r\n </div>\r\n </div>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n\r\n @if ((selectForms$ | async)?.length === 0) {\r\n <div class=\"empty-state\">\r\n <mat-icon class=\"empty-state-icon\" aria-hidden=\"true\">folder_off</mat-icon>\r\n <p>No form templates available.</p>\r\n </div>\r\n }\r\n }\r\n </section>\r\n\r\n <footer class=\"dialog-actions\">\r\n <button mat-button (click)=\"close()\" aria-label=\"Close dialog\">\r\n Close\r\n </button>\r\n </footer>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.template-select-dialog{display:flex;flex-direction:column;min-width:28rem;max-width:36rem;max-height:calc(100vh - 24px);background:var(--mat-sys-surface, var(--mat-app-surface));overflow:hidden}.dialog-header{display:flex;align-items:flex-start;gap:1rem;padding:1.5rem 1.5rem 0;flex-shrink:0}.header-icon{width:2.75rem;height:2.75rem;border-radius:8px;background:color-mix(in srgb,var(--lib-forms-primary) 12%,transparent);display:flex;align-items:center;justify-content:center;flex-shrink:0}.header-icon mat-icon{font-size:1.5rem;width:1.5rem;height:1.5rem;color:var(--lib-forms-primary)}.header-text{flex:1;min-width:0}.header-title{font-size:1.25rem;font-weight:600;letter-spacing:-.01em;color:var(--lib-forms-on-surface);margin:0;line-height:1.3}.header-subtitle{font-size:.875rem;color:var(--lib-forms-on-surface-variant);line-height:1.4;margin-top:.25rem;margin-bottom:0}.dialog-content{padding:1rem 1.5rem 1.5rem;overflow-y:auto;max-height:70vh;flex:1;min-height:0}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:1.5rem;gap:1rem;min-height:12rem}.loading-text{font-size:.875rem;color:var(--lib-forms-on-surface-variant)}.form-template-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}.form-list-item{display:flex;align-items:flex-start;gap:1rem;width:100%;padding:.5rem 1.25rem;min-height:2.25rem;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);border-radius:8px;background:var(--mat-sys-surface-container, var(--mat-app-surface-container-low));color:var(--lib-forms-on-surface);font-size:.875rem;text-align:left;cursor:pointer;transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),background-color var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 2px 8px #00000014}.form-list-item:hover{border-color:var(--lib-forms-primary);background:color-mix(in srgb,var(--lib-forms-primary) 6%,transparent)}.form-list-item:focus-visible{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--lib-forms-primary) 25%,transparent)}.form-list-item:active{background:color-mix(in srgb,var(--lib-forms-primary) 12%,transparent)}@media(prefers-color-scheme:dark){.form-list-item{box-shadow:0 1px 3px #0000004d}}.form-avatar{width:2.5rem;height:2.5rem;border-radius:6px;object-fit:cover;flex-shrink:0;display:block}.form-avatar.form-avatar--error{outline:2px solid var(--sem-error);outline-offset:2px}.form-item-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:.25rem}.form-title{font-weight:600;font-size:.9375rem}.form-metadata{display:flex;align-items:center;flex-wrap:wrap;gap:.25rem;font-size:.75rem;color:var(--lib-forms-on-surface-variant);line-height:1.35}.form-metadata .metadata-divider{margin:0 .25rem;opacity:.7}.form-metadata .metadata-item{display:inline-flex;align-items:center;gap:.25rem}.form-metadata .metadata-item mat-icon{font-size:.875rem;width:.875rem;height:.875rem}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.5rem;padding:1.5rem;background:var(--mat-sys-surface-container, var(--mat-app-surface-container-low));border-radius:8px;text-align:center}.empty-state p{font-size:.875rem;color:var(--lib-forms-on-surface-variant);margin:0}.empty-state-icon{font-size:2rem;width:2rem;height:2rem;color:var(--lib-forms-on-surface-variant);opacity:.7}.dialog-actions{display:flex;justify-content:flex-end;align-items:center;gap:.75rem;padding:1rem 1.5rem 1.25rem;flex-shrink:0;border-top:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent)}\n"] }]
|
|
74
|
+
}] });
|
|
75
|
+
|
|
76
|
+
function SubmissionAPIListItemConfig(environment) {
|
|
77
|
+
return [
|
|
78
|
+
{
|
|
79
|
+
id: '16140923-0542-4d5d-9b63-186c1e91b1a7',
|
|
80
|
+
name: SpecialElementKeys.MatOptionsApiCall,
|
|
81
|
+
editType: ElementEditorTypes.ApiCall,
|
|
82
|
+
required: true,
|
|
83
|
+
postmanCollectionConfig: {
|
|
84
|
+
collectionUrl: environment['POSTMAN_COLLECTION_URL'],
|
|
85
|
+
collectionKey: environment['POSTMAN_COLLECTION_KEY']
|
|
86
|
+
},
|
|
87
|
+
hint: `APIs are loaded from Postman collection. Configure required headers, payload format, and response mapping before use. Ensure API is documented in Postman.`,
|
|
88
|
+
deepBind: ['data'],
|
|
89
|
+
label: 'Select form submission api',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: SpecialElementKeys.Default,
|
|
93
|
+
deepBind: [
|
|
94
|
+
'data',
|
|
95
|
+
'backEndConfig',
|
|
96
|
+
'minimumInputRequired',
|
|
97
|
+
],
|
|
98
|
+
additionalTest: [
|
|
99
|
+
{
|
|
100
|
+
testType: 'exists',
|
|
101
|
+
deepBind: [
|
|
102
|
+
'data',
|
|
103
|
+
'backEndConfig',
|
|
104
|
+
'minimumInputRequired',
|
|
105
|
+
],
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
hint: `These are payload fields that are required to be filled in order to fetch data from the selected source`,
|
|
109
|
+
editType: ElementEditorTypes.RequiredInputs,
|
|
110
|
+
label: 'Set up required inputs',
|
|
111
|
+
id: "2d0f1e18-897b-4c28-97bc-3078be09f8ee"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: SpecialElementKeys.Default,
|
|
115
|
+
deepBind: ['data', 'projectFormData'],
|
|
116
|
+
editType: ElementEditorTypes.FormPayloadProjection,
|
|
117
|
+
label: 'Project form data',
|
|
118
|
+
defaultValue: `data:{$formValue}`,
|
|
119
|
+
hint: 'Choose how the submitted form is shaped before it is sent — sent flat, or wrapped under one or more keys.',
|
|
120
|
+
id: "$2d0f1e18-897b-4c28-97bc-3078be09f8ee"
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
const SubmissionAPIOtherConfig = [
|
|
125
|
+
{
|
|
126
|
+
id: "7acaa5d1-fb37-4dc0-9f1a-53b6f36534e0",
|
|
127
|
+
name: SpecialElementKeys.Default,
|
|
128
|
+
deepBind: ['submissionHandle', 'submissionMessage'],
|
|
129
|
+
editType: ElementEditorTypes.Input,
|
|
130
|
+
label: "Submission Message",
|
|
131
|
+
hint: "Message shown to the user after successful form submission.",
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "5636c16c-be58-48d9-b701-81fe05573a39",
|
|
135
|
+
name: SpecialElementKeys.Default,
|
|
136
|
+
deepBind: ['submissionHandle', 'innerComponentShowSubmitButton'],
|
|
137
|
+
editType: ElementEditorTypes.Toggle,
|
|
138
|
+
label: "Show submit button in inner component form",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "c9103faa-eeba-4cf3-b3d0-f25fd05ccb3c",
|
|
142
|
+
name: SpecialElementKeys.Default,
|
|
143
|
+
deepBind: ['systemDefault'],
|
|
144
|
+
editType: ElementEditorTypes.Toggle,
|
|
145
|
+
label: "Is system default",
|
|
146
|
+
}
|
|
147
|
+
];
|
|
148
|
+
const SubmissionDialogConfig = [
|
|
149
|
+
{
|
|
150
|
+
titleIcon: 'send',
|
|
151
|
+
id: '44023662-7343-4c93-999d-fc03c54438c3',
|
|
152
|
+
title: 'Form Submission Endpoint',
|
|
153
|
+
description: `Choose where to send your form data after submission. Connect to your database, data pipeline, or
|
|
154
|
+
third-party service.`,
|
|
155
|
+
primaryKey: 'submissionAPI',
|
|
156
|
+
sectionLabel: 'Submission Endpoints',
|
|
157
|
+
emptyMessage: 'No submission endpoints configured. Add one to send form data.',
|
|
158
|
+
elements: SubmissionAPIOtherConfig
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
titleIcon: 'rule',
|
|
162
|
+
title: 'Data Validation Rules',
|
|
163
|
+
description: `Define validation rules to ensure data quality before form submission.
|
|
164
|
+
<br>
|
|
165
|
+
<strong>Note:</strong> All validation endpoints must return a boolean value -
|
|
166
|
+
<code>true</code> indicates valid data that will be submitted.`,
|
|
167
|
+
primaryKey: 'canSubmitAPI',
|
|
168
|
+
sectionLabel: 'Validation Endpoints',
|
|
169
|
+
emptyMessage: 'No validation endpoints configured. Add one to validate data before submission.',
|
|
170
|
+
id: 'acac6045-5b13-4c8d-a7ee-da194ebbad41',
|
|
171
|
+
}
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
class FormSubmissionsConfigComponent {
|
|
175
|
+
constructor() {
|
|
176
|
+
// TODO: NGX_T_FORMS_CONFIG should be #private; kept accessible due to template/getter usage.
|
|
177
|
+
this.NGX_T_FORMS_CONFIG = inject(NGX_T_FORMS_CONFIG_TOKEN);
|
|
178
|
+
this.#data = inject(MAT_DIALOG_DATA);
|
|
179
|
+
this.store = this.#data.store;
|
|
180
|
+
this.#matDialog = inject(MatDialog);
|
|
181
|
+
this.form = computed(() => this.store.signalSelectors.selectFormInEdit()?.form, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
182
|
+
this.formInputs = this.store.formBuilderSignalSelectors.getAllFormInputs;
|
|
183
|
+
this.formValidationError = this.store.formBuilderSignalSelectors.formErrors;
|
|
184
|
+
/** The endpoint currently open in the inline editor (one panel at a time). */
|
|
185
|
+
this.keyInEdit = signal(undefined, ...(ngDevMode ? [{ debugName: "keyInEdit" }] : /* istanbul ignore next */ []));
|
|
186
|
+
/** Draft endpoint being added or edited; `undefined` when the editor is closed. */
|
|
187
|
+
this.dataPlaceholder = signal(undefined, ...(ngDevMode ? [{ debugName: "dataPlaceholder" }] : /* istanbul ignore next */ []));
|
|
188
|
+
/** True when the inline editor is updating an existing endpoint rather than adding one. */
|
|
189
|
+
this.isEditingExisting = computed(() => this.dataPlaceholder()?.data?._id != null, ...(ngDevMode ? [{ debugName: "isEditingExisting" }] : /* istanbul ignore next */ []));
|
|
190
|
+
/**
|
|
191
|
+
* Panels enriched with their live endpoint list and required-state error.
|
|
192
|
+
* Driven entirely from {@link SubmissionDialogConfig}, so adding a panel is a
|
|
193
|
+
* config-only change — no template branching on `primaryKey`.
|
|
194
|
+
*/
|
|
195
|
+
this.panels = computed(() => {
|
|
196
|
+
const form = this.form();
|
|
197
|
+
return SubmissionDialogConfig.map((panel) => {
|
|
198
|
+
const apis = form?.submissionHandle?.[panel.primaryKey] ?? [];
|
|
199
|
+
const error = panel.primaryKey === 'submissionAPI' && apis.length === 0
|
|
200
|
+
? 'At least one submission API is required'
|
|
201
|
+
: undefined;
|
|
202
|
+
return { ...panel, apis, error };
|
|
203
|
+
});
|
|
204
|
+
}, ...(ngDevMode ? [{ debugName: "panels" }] : /* istanbul ignore next */ []));
|
|
205
|
+
/** Editor elements for the inline endpoint form, gated by their `additionalTest`. */
|
|
206
|
+
this.submissionApiElements = computed(() => {
|
|
207
|
+
const placeholder = this.dataPlaceholder() ?? { data: {} };
|
|
208
|
+
return SubmissionAPIListItemConfig(this.NGX_T_FORMS_CONFIG).filter((el) => !el.additionalTest ||
|
|
209
|
+
el.additionalTest.every((test) => testAgainstItem(test, placeholder)));
|
|
210
|
+
}, ...(ngDevMode ? [{ debugName: "submissionApiElements" }] : /* istanbul ignore next */ []));
|
|
211
|
+
/** Validation errors for the draft endpoint, computed once per change. */
|
|
212
|
+
this.#placeholderErrors = computed(() => validateApiDataFetchingConfiguration(this.dataPlaceholder() ?? {}).map((error) => ({
|
|
213
|
+
message: error.message,
|
|
214
|
+
key: 'data.' + error.key,
|
|
215
|
+
})), ...(ngDevMode ? [{ debugName: "#placeholderErrors" }] : /* istanbul ignore next */ []));
|
|
216
|
+
}
|
|
217
|
+
#data;
|
|
218
|
+
#matDialog;
|
|
219
|
+
/** Validation errors for the draft endpoint, computed once per change. */
|
|
220
|
+
#placeholderErrors;
|
|
221
|
+
/** Store-level validation errors bound to a given panel element. */
|
|
222
|
+
errorsFor(element) {
|
|
223
|
+
const bind = element.deepBind?.join('.');
|
|
224
|
+
return this.formValidationError()?.filter((error) => error.key === bind) ?? [];
|
|
225
|
+
}
|
|
226
|
+
/** Draft-endpoint validation errors bound to a given inline-editor element. */
|
|
227
|
+
validationErrors(element) {
|
|
228
|
+
const bind = element.deepBind?.join('.');
|
|
229
|
+
return this.#placeholderErrors().filter((error) => error.key === bind);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Event payload types from `lib-t-dynamic-data-edit` are heterogeneous (per
|
|
233
|
+
* element kind). Until that emission contract is narrowed via a discriminated
|
|
234
|
+
* union, accept `unknown` and forward through; element-level handlers narrow.
|
|
235
|
+
*/
|
|
236
|
+
elementBlur(_event, _element) {
|
|
237
|
+
// intentional no-op
|
|
238
|
+
}
|
|
239
|
+
formInputChange(value, ele) {
|
|
240
|
+
this.store.actionsFormBuilder.formInputChange(ele, value);
|
|
241
|
+
}
|
|
242
|
+
elementConfigurationChanged(value, ele) {
|
|
243
|
+
const applyTo = { ...this.dataPlaceholder() };
|
|
244
|
+
if (ele.clearOnChange) {
|
|
245
|
+
ele.clearOnChange.forEach((clear) => {
|
|
246
|
+
assignDeepPropertyToObject(applyTo, clear, undefined);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (ele.deepBind) {
|
|
250
|
+
assignDeepPropertyToObject(applyTo, ele.deepBind, value);
|
|
251
|
+
}
|
|
252
|
+
// Placeholder shape is dynamic — `applyTo` is built from a partial spread plus
|
|
253
|
+
// deep-bind assignments. The data field is known to be the API configuration
|
|
254
|
+
// type by contract with the element editor.
|
|
255
|
+
this.dataPlaceholder.set({ ...applyTo });
|
|
256
|
+
}
|
|
257
|
+
addNewSubmitApi(key) {
|
|
258
|
+
this.dataPlaceholder.set({ data: {} });
|
|
259
|
+
this.keyInEdit.set(key);
|
|
260
|
+
}
|
|
261
|
+
editSubmitApi(api, key) {
|
|
262
|
+
this.dataPlaceholder.set({ data: { ...api } });
|
|
263
|
+
this.keyInEdit.set(key);
|
|
264
|
+
}
|
|
265
|
+
saveSubmitApi() {
|
|
266
|
+
this.store.actionsFormBuilder.saveSubmitApi(this.dataPlaceholder(), this.keyInEdit());
|
|
267
|
+
this.#closeEditor();
|
|
268
|
+
}
|
|
269
|
+
removeSubmissionApi(api, key) {
|
|
270
|
+
this.store.actionsFormBuilder.removeSubmissionApi(api, key);
|
|
271
|
+
this.#closeEditor();
|
|
272
|
+
}
|
|
273
|
+
cancelSubmitApi() {
|
|
274
|
+
this.#closeEditor();
|
|
275
|
+
}
|
|
276
|
+
close() {
|
|
277
|
+
this.#matDialog.closeAll();
|
|
278
|
+
}
|
|
279
|
+
#closeEditor() {
|
|
280
|
+
this.dataPlaceholder.set(undefined);
|
|
281
|
+
this.keyInEdit.set(undefined);
|
|
282
|
+
}
|
|
283
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormSubmissionsConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
284
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormSubmissionsConfigComponent, isStandalone: true, selector: "lib-form-submissions-config", ngImport: i0, template: "<div class=\"submissions-dialog\">\r\n <!-- Header: icon + title + subtitle per design rule \u00A74 -->\r\n <header class=\"dialog-header\">\r\n <div class=\"header-icon\" aria-hidden=\"true\">\r\n <mat-icon>settings</mat-icon>\r\n </div>\r\n <div class=\"header-text\">\r\n <h1 class=\"header-title\">Form Submission Configuration</h1>\r\n <p class=\"header-subtitle\">Configure how your form is submitted and validated before submission.</p>\r\n </div>\r\n <button mat-icon-button mat-dialog-close [attr.aria-label]=\"'Close dialog'\" class=\"header-close\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </header>\r\n\r\n <section class=\"dialog-content\">\r\n <mat-accordion multi>\r\n @for (panel of panels(); track panel.id) {\r\n <mat-expansion-panel [expanded]=\"true\" class=\"config-panel\">\r\n <mat-expansion-panel-header class=\"panel-header\">\r\n <mat-panel-title class=\"panel-title\">\r\n <mat-icon class=\"panel-icon\" [color]=\"'primary'\">{{ panel.titleIcon }}</mat-icon>\r\n {{ panel.title }}\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n\r\n <div class=\"panel-content\">\r\n <p class=\"panel-description\" [innerHTML]=\"panel.description\"></p>\r\n\r\n <!-- Dynamic form elements (submission message, toggles, etc.) -->\r\n @if ((panel?.elements || []).length > 0) {\r\n <div class=\"edit-section\">\r\n @for (edit of (panel?.elements || []); track edit.id) {\r\n <div class=\"edit-field\">\r\n <lib-t-dynamic-data-edit\r\n [editorConfig]=\"edit\"\r\n [data]=\"form()\"\r\n [validationErrors]=\"errorsFor(edit)\"\r\n (valueChange)=\"formInputChange($event, edit)\"\r\n [formInputs]=\"(formInputs()) || []\"\r\n (blur)=\"elementBlur($event, edit)\">\r\n </lib-t-dynamic-data-edit>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- API endpoints list -->\r\n <div class=\"api-section\">\r\n <h3 class=\"api-section-header\" [class.api-section-header--error]=\"panel.error\">\r\n {{ panel.sectionLabel }}\r\n </h3>\r\n\r\n @if (panel.apis.length === 0) {\r\n <div class=\"empty-state\" [class.empty-state--error]=\"panel.error\">\r\n <mat-icon class=\"empty-state-icon\">add_link</mat-icon>\r\n <p>{{ panel.emptyMessage }}</p>\r\n </div>\r\n }\r\n\r\n @for (api of panel.apis; track api._id) {\r\n <div\r\n class=\"api-list-item\"\r\n [class.api-list-item--active]=\"keyInEdit() === panel.primaryKey && dataPlaceholder()?.data?._id === api._id\">\r\n <span class=\"api-method-tag\" [class.api-method-tag--post]=\"api.httpMethod === 'POST'\">\r\n {{ api.httpMethod }}\r\n </span>\r\n <div class=\"api-details\">\r\n <span class=\"api-name\">{{ api.name }}</span>\r\n <span class=\"api-endpoint\" [matTooltip]=\"api.httpEndPoint\" matTooltipPosition=\"above\">\r\n {{ api.httpEndPoint }}\r\n </span>\r\n </div>\r\n <div class=\"api-item-actions\">\r\n <button\r\n (click)=\"editSubmitApi(api, panel.primaryKey)\"\r\n mat-icon-button\r\n matTooltip=\"Edit endpoint\"\r\n [attr.aria-label]=\"'Edit endpoint ' + api.name\"\r\n class=\"api-edit-btn\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n [cdkCopyToClipboard]=\"api.httpEndPoint || ''\"\r\n mat-icon-button\r\n matTooltip=\"Copy URL\"\r\n [attr.aria-label]=\"'Copy endpoint URL'\"\r\n class=\"api-copy-btn\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <button\r\n (click)=\"removeSubmissionApi(api, panel.primaryKey)\"\r\n mat-icon-button\r\n matTooltip=\"Remove endpoint\"\r\n [attr.aria-label]=\"'Remove endpoint ' + api.name\"\r\n class=\"api-remove-btn\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n <mat-divider></mat-divider>\r\n }\r\n\r\n @if (keyInEdit() !== panel.primaryKey) {\r\n <div class=\"api-actions\">\r\n <button\r\n (click)=\"addNewSubmitApi(panel.primaryKey)\"\r\n mat-stroked-button\r\n color=\"primary\"\r\n class=\"add-endpoint-btn\">\r\n <mat-icon>add</mat-icon>\r\n Add new endpoint\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (panel.error) {\r\n <mat-error class=\"panel-error\">{{ panel.error }}</mat-error>\r\n }\r\n </div>\r\n\r\n <!-- Inline edit form for new/editing endpoint -->\r\n @if (keyInEdit() === panel.primaryKey) {\r\n <div class=\"edit-section edit-section--inline\">\r\n <h4 class=\"inline-edit-title\">\r\n {{ isEditingExisting() ? 'Edit endpoint' : 'New endpoint' }}\r\n </h4>\r\n @for (element of submissionApiElements(); track element.id) {\r\n <div class=\"edit-field\">\r\n <lib-t-dynamic-data-edit\r\n [editorConfig]=\"element\"\r\n [data]=\"dataPlaceholder()\"\r\n [validationErrors]=\"validationErrors(element)\"\r\n (valueChange)=\"elementConfigurationChanged($event, element)\"\r\n [formInputs]=\"(formInputs()) || []\"\r\n (blur)=\"elementBlur($event, element)\">\r\n </lib-t-dynamic-data-edit>\r\n </div>\r\n }\r\n <mat-divider></mat-divider>\r\n <div class=\"inline-edit-actions\">\r\n <button mat-flat-button (click)=\"saveSubmitApi()\" color=\"primary\">\r\n {{ isEditingExisting() ? 'Update' : 'Save' }}\r\n </button>\r\n <button mat-button (click)=\"cancelSubmitApi()\" color=\"warn\">Cancel</button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mat-expansion-panel>\r\n }\r\n </mat-accordion>\r\n </section>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.submissions-dialog{display:flex;flex-direction:column;min-width:28rem;max-width:36rem;max-height:calc(100vh - 24px);background:var(--mat-sys-surface, var(--mat-app-surface));border:1px solid var(--mat-sys-outline-variant, var(--mat-divider-color));overflow:hidden}.dialog-header{display:flex;align-items:flex-start;gap:1rem;padding:1.5rem 1.5rem 0;flex-shrink:0}.header-icon{width:2.75rem;height:2.75rem;border-radius:8px;background:color-mix(in srgb,var(--lib-forms-primary) 12%,transparent);display:flex;align-items:center;justify-content:center;flex-shrink:0}.header-icon mat-icon{font-size:1.5rem;width:1.5rem;height:1.5rem;color:var(--lib-forms-primary)}.header-text{flex:1;min-width:0}.header-title{font-size:1.25rem;font-weight:600;letter-spacing:-.01em;color:var(--lib-forms-on-surface);margin:0;line-height:1.3}.header-subtitle{font-size:.875rem;color:var(--lib-forms-on-surface-variant);line-height:1.4;margin-top:.25rem;margin-bottom:0}.header-close{margin-top:-.5rem;margin-right:-.5rem}.dialog-content{padding:1rem 1.5rem 1.5rem;overflow-y:auto;max-height:70vh;flex:1;min-height:0}.config-panel{border-radius:12px;box-shadow:0 2px 8px #00000014;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);overflow:hidden;margin-bottom:1rem}.config-panel:last-child{margin-bottom:0}.panel-header{background:color-mix(in srgb,var(--lib-forms-primary) 4%,transparent);border-bottom:1px solid color-mix(in srgb,var(--lib-forms-outline) 10%,transparent)}.panel-title{display:flex;align-items:center;gap:.75rem;font-weight:600}.panel-icon{margin-right:0;font-size:1.25rem;width:1.25rem;height:1.25rem}.panel-content{padding:1.25rem;display:flex;flex-direction:column;gap:1rem;background:var(--mat-sys-surface-container, var(--mat-sys-surface))}.panel-description{font-size:.8125rem;color:var(--lib-forms-on-surface-variant);line-height:1.35;margin:0 0 1rem}.edit-section{background:var(--mat-sys-surface-container-high, var(--mat-sys-surface-container));border-radius:8px;padding:1rem;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 10%,transparent)}.edit-section--inline{margin-top:.5rem}.inline-edit-title{font-size:.625rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant);margin:0 0 1rem}.edit-field{margin-bottom:1rem}.edit-field:last-child{margin-bottom:0}.api-section{background:var(--mat-sys-surface-container-high, var(--mat-sys-surface-container));border-radius:8px;padding:1rem;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 10%,transparent)}.api-section-header{font-size:.75rem;font-weight:500;letter-spacing:.04em;color:var(--lib-forms-on-surface-variant);margin:0 0 1rem;padding-left:.25rem}.api-section-header--error{color:var(--lib-forms-error)}.empty-state{display:flex;align-items:center;gap:.5rem;padding:1rem;background:var(--lib-forms-surface-container-highest);border-radius:8px;font-size:.875rem;color:var(--lib-forms-on-surface-variant);margin:0 0 1rem}.empty-state p{margin:0;flex:1}.empty-state--error{color:var(--lib-forms-error)}.empty-state-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;opacity:.8}.api-list-item{display:flex;align-items:center;gap:1rem;padding:.5rem;min-height:2.75rem;border-radius:8px;transition:background .3s cubic-bezier(.16,1,.3,1)}.api-list-item--active{background:color-mix(in srgb,var(--lib-forms-primary) 8%,transparent)}.api-method-tag{flex-shrink:0;padding:.25rem .5rem;font-size:.75rem;font-weight:600;border-radius:6px;text-align:center;min-width:3rem;background:color-mix(in srgb,var(--lib-forms-primary) 10%,transparent);color:var(--lib-forms-primary)}.api-method-tag--post{background:color-mix(in srgb,var(--sem-success) 12%,transparent);color:var(--sem-success)}.api-details{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem}.api-name{font-size:.875rem;font-weight:600;color:var(--lib-forms-on-surface);line-height:1.3}.api-endpoint{font-size:.75rem;color:var(--lib-forms-on-surface-variant);opacity:.85;line-height:1.3;max-width:18rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:help}.api-item-actions{display:flex;align-items:center;gap:.25rem;flex-shrink:0}.api-edit-btn:hover mat-icon,.api-copy-btn:hover mat-icon,.api-remove-btn:hover mat-icon{color:var(--lib-forms-primary)}.api-remove-btn:hover mat-icon{color:var(--lib-forms-error)}.api-actions{margin-top:1rem}.add-endpoint-btn{width:100%;border-style:dashed;padding:.5rem .875rem;font-size:.8125rem}.add-endpoint-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;margin-right:.5rem}.panel-error{margin-top:.5rem;font-size:.75rem}.inline-edit-actions{display:flex;justify-content:flex-end;gap:.75rem;padding-top:1rem;margin-top:.5rem}@media(prefers-color-scheme:dark){.config-panel{box-shadow:0 1px 3px #0000004d}}\n"], dependencies: [{ kind: "ngmodule", type: ClipboardModule }, { kind: "directive", type: i1$1.CdkCopyToClipboard, selector: "[cdkCopyToClipboard]", inputs: ["cdkCopyToClipboard", "cdkCopyToClipboardAttempts"], outputs: ["cdkCopyToClipboardCopied"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$2.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$1.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: TDynamicDataEditComponent, selector: "lib-t-dynamic-data-edit", inputs: ["editorConfig", "formInputs", "data", "validationErrors"], outputs: ["valueChange", "blur"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
285
|
+
}
|
|
286
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormSubmissionsConfigComponent, decorators: [{
|
|
287
|
+
type: Component,
|
|
288
|
+
args: [{ selector: 'lib-form-submissions-config', imports: [
|
|
289
|
+
ClipboardModule,
|
|
290
|
+
MatButtonModule,
|
|
291
|
+
MatDialogModule,
|
|
292
|
+
MatDividerModule,
|
|
293
|
+
MatExpansionModule,
|
|
294
|
+
MatFormFieldModule,
|
|
295
|
+
MatIconModule,
|
|
296
|
+
MatTooltipModule,
|
|
297
|
+
TDynamicDataEditComponent,
|
|
298
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"submissions-dialog\">\r\n <!-- Header: icon + title + subtitle per design rule \u00A74 -->\r\n <header class=\"dialog-header\">\r\n <div class=\"header-icon\" aria-hidden=\"true\">\r\n <mat-icon>settings</mat-icon>\r\n </div>\r\n <div class=\"header-text\">\r\n <h1 class=\"header-title\">Form Submission Configuration</h1>\r\n <p class=\"header-subtitle\">Configure how your form is submitted and validated before submission.</p>\r\n </div>\r\n <button mat-icon-button mat-dialog-close [attr.aria-label]=\"'Close dialog'\" class=\"header-close\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </header>\r\n\r\n <section class=\"dialog-content\">\r\n <mat-accordion multi>\r\n @for (panel of panels(); track panel.id) {\r\n <mat-expansion-panel [expanded]=\"true\" class=\"config-panel\">\r\n <mat-expansion-panel-header class=\"panel-header\">\r\n <mat-panel-title class=\"panel-title\">\r\n <mat-icon class=\"panel-icon\" [color]=\"'primary'\">{{ panel.titleIcon }}</mat-icon>\r\n {{ panel.title }}\r\n </mat-panel-title>\r\n </mat-expansion-panel-header>\r\n\r\n <div class=\"panel-content\">\r\n <p class=\"panel-description\" [innerHTML]=\"panel.description\"></p>\r\n\r\n <!-- Dynamic form elements (submission message, toggles, etc.) -->\r\n @if ((panel?.elements || []).length > 0) {\r\n <div class=\"edit-section\">\r\n @for (edit of (panel?.elements || []); track edit.id) {\r\n <div class=\"edit-field\">\r\n <lib-t-dynamic-data-edit\r\n [editorConfig]=\"edit\"\r\n [data]=\"form()\"\r\n [validationErrors]=\"errorsFor(edit)\"\r\n (valueChange)=\"formInputChange($event, edit)\"\r\n [formInputs]=\"(formInputs()) || []\"\r\n (blur)=\"elementBlur($event, edit)\">\r\n </lib-t-dynamic-data-edit>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- API endpoints list -->\r\n <div class=\"api-section\">\r\n <h3 class=\"api-section-header\" [class.api-section-header--error]=\"panel.error\">\r\n {{ panel.sectionLabel }}\r\n </h3>\r\n\r\n @if (panel.apis.length === 0) {\r\n <div class=\"empty-state\" [class.empty-state--error]=\"panel.error\">\r\n <mat-icon class=\"empty-state-icon\">add_link</mat-icon>\r\n <p>{{ panel.emptyMessage }}</p>\r\n </div>\r\n }\r\n\r\n @for (api of panel.apis; track api._id) {\r\n <div\r\n class=\"api-list-item\"\r\n [class.api-list-item--active]=\"keyInEdit() === panel.primaryKey && dataPlaceholder()?.data?._id === api._id\">\r\n <span class=\"api-method-tag\" [class.api-method-tag--post]=\"api.httpMethod === 'POST'\">\r\n {{ api.httpMethod }}\r\n </span>\r\n <div class=\"api-details\">\r\n <span class=\"api-name\">{{ api.name }}</span>\r\n <span class=\"api-endpoint\" [matTooltip]=\"api.httpEndPoint\" matTooltipPosition=\"above\">\r\n {{ api.httpEndPoint }}\r\n </span>\r\n </div>\r\n <div class=\"api-item-actions\">\r\n <button\r\n (click)=\"editSubmitApi(api, panel.primaryKey)\"\r\n mat-icon-button\r\n matTooltip=\"Edit endpoint\"\r\n [attr.aria-label]=\"'Edit endpoint ' + api.name\"\r\n class=\"api-edit-btn\">\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n [cdkCopyToClipboard]=\"api.httpEndPoint || ''\"\r\n mat-icon-button\r\n matTooltip=\"Copy URL\"\r\n [attr.aria-label]=\"'Copy endpoint URL'\"\r\n class=\"api-copy-btn\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>content_copy</mat-icon>\r\n </button>\r\n <button\r\n (click)=\"removeSubmissionApi(api, panel.primaryKey)\"\r\n mat-icon-button\r\n matTooltip=\"Remove endpoint\"\r\n [attr.aria-label]=\"'Remove endpoint ' + api.name\"\r\n class=\"api-remove-btn\">\r\n <mat-icon>delete</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n <mat-divider></mat-divider>\r\n }\r\n\r\n @if (keyInEdit() !== panel.primaryKey) {\r\n <div class=\"api-actions\">\r\n <button\r\n (click)=\"addNewSubmitApi(panel.primaryKey)\"\r\n mat-stroked-button\r\n color=\"primary\"\r\n class=\"add-endpoint-btn\">\r\n <mat-icon>add</mat-icon>\r\n Add new endpoint\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (panel.error) {\r\n <mat-error class=\"panel-error\">{{ panel.error }}</mat-error>\r\n }\r\n </div>\r\n\r\n <!-- Inline edit form for new/editing endpoint -->\r\n @if (keyInEdit() === panel.primaryKey) {\r\n <div class=\"edit-section edit-section--inline\">\r\n <h4 class=\"inline-edit-title\">\r\n {{ isEditingExisting() ? 'Edit endpoint' : 'New endpoint' }}\r\n </h4>\r\n @for (element of submissionApiElements(); track element.id) {\r\n <div class=\"edit-field\">\r\n <lib-t-dynamic-data-edit\r\n [editorConfig]=\"element\"\r\n [data]=\"dataPlaceholder()\"\r\n [validationErrors]=\"validationErrors(element)\"\r\n (valueChange)=\"elementConfigurationChanged($event, element)\"\r\n [formInputs]=\"(formInputs()) || []\"\r\n (blur)=\"elementBlur($event, element)\">\r\n </lib-t-dynamic-data-edit>\r\n </div>\r\n }\r\n <mat-divider></mat-divider>\r\n <div class=\"inline-edit-actions\">\r\n <button mat-flat-button (click)=\"saveSubmitApi()\" color=\"primary\">\r\n {{ isEditingExisting() ? 'Update' : 'Save' }}\r\n </button>\r\n <button mat-button (click)=\"cancelSubmitApi()\" color=\"warn\">Cancel</button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </mat-expansion-panel>\r\n }\r\n </mat-accordion>\r\n </section>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";.submissions-dialog{display:flex;flex-direction:column;min-width:28rem;max-width:36rem;max-height:calc(100vh - 24px);background:var(--mat-sys-surface, var(--mat-app-surface));border:1px solid var(--mat-sys-outline-variant, var(--mat-divider-color));overflow:hidden}.dialog-header{display:flex;align-items:flex-start;gap:1rem;padding:1.5rem 1.5rem 0;flex-shrink:0}.header-icon{width:2.75rem;height:2.75rem;border-radius:8px;background:color-mix(in srgb,var(--lib-forms-primary) 12%,transparent);display:flex;align-items:center;justify-content:center;flex-shrink:0}.header-icon mat-icon{font-size:1.5rem;width:1.5rem;height:1.5rem;color:var(--lib-forms-primary)}.header-text{flex:1;min-width:0}.header-title{font-size:1.25rem;font-weight:600;letter-spacing:-.01em;color:var(--lib-forms-on-surface);margin:0;line-height:1.3}.header-subtitle{font-size:.875rem;color:var(--lib-forms-on-surface-variant);line-height:1.4;margin-top:.25rem;margin-bottom:0}.header-close{margin-top:-.5rem;margin-right:-.5rem}.dialog-content{padding:1rem 1.5rem 1.5rem;overflow-y:auto;max-height:70vh;flex:1;min-height:0}.config-panel{border-radius:12px;box-shadow:0 2px 8px #00000014;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);overflow:hidden;margin-bottom:1rem}.config-panel:last-child{margin-bottom:0}.panel-header{background:color-mix(in srgb,var(--lib-forms-primary) 4%,transparent);border-bottom:1px solid color-mix(in srgb,var(--lib-forms-outline) 10%,transparent)}.panel-title{display:flex;align-items:center;gap:.75rem;font-weight:600}.panel-icon{margin-right:0;font-size:1.25rem;width:1.25rem;height:1.25rem}.panel-content{padding:1.25rem;display:flex;flex-direction:column;gap:1rem;background:var(--mat-sys-surface-container, var(--mat-sys-surface))}.panel-description{font-size:.8125rem;color:var(--lib-forms-on-surface-variant);line-height:1.35;margin:0 0 1rem}.edit-section{background:var(--mat-sys-surface-container-high, var(--mat-sys-surface-container));border-radius:8px;padding:1rem;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 10%,transparent)}.edit-section--inline{margin-top:.5rem}.inline-edit-title{font-size:.625rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant);margin:0 0 1rem}.edit-field{margin-bottom:1rem}.edit-field:last-child{margin-bottom:0}.api-section{background:var(--mat-sys-surface-container-high, var(--mat-sys-surface-container));border-radius:8px;padding:1rem;border:1px solid color-mix(in srgb,var(--lib-forms-outline) 10%,transparent)}.api-section-header{font-size:.75rem;font-weight:500;letter-spacing:.04em;color:var(--lib-forms-on-surface-variant);margin:0 0 1rem;padding-left:.25rem}.api-section-header--error{color:var(--lib-forms-error)}.empty-state{display:flex;align-items:center;gap:.5rem;padding:1rem;background:var(--lib-forms-surface-container-highest);border-radius:8px;font-size:.875rem;color:var(--lib-forms-on-surface-variant);margin:0 0 1rem}.empty-state p{margin:0;flex:1}.empty-state--error{color:var(--lib-forms-error)}.empty-state-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;opacity:.8}.api-list-item{display:flex;align-items:center;gap:1rem;padding:.5rem;min-height:2.75rem;border-radius:8px;transition:background .3s cubic-bezier(.16,1,.3,1)}.api-list-item--active{background:color-mix(in srgb,var(--lib-forms-primary) 8%,transparent)}.api-method-tag{flex-shrink:0;padding:.25rem .5rem;font-size:.75rem;font-weight:600;border-radius:6px;text-align:center;min-width:3rem;background:color-mix(in srgb,var(--lib-forms-primary) 10%,transparent);color:var(--lib-forms-primary)}.api-method-tag--post{background:color-mix(in srgb,var(--sem-success) 12%,transparent);color:var(--sem-success)}.api-details{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem}.api-name{font-size:.875rem;font-weight:600;color:var(--lib-forms-on-surface);line-height:1.3}.api-endpoint{font-size:.75rem;color:var(--lib-forms-on-surface-variant);opacity:.85;line-height:1.3;max-width:18rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:help}.api-item-actions{display:flex;align-items:center;gap:.25rem;flex-shrink:0}.api-edit-btn:hover mat-icon,.api-copy-btn:hover mat-icon,.api-remove-btn:hover mat-icon{color:var(--lib-forms-primary)}.api-remove-btn:hover mat-icon{color:var(--lib-forms-error)}.api-actions{margin-top:1rem}.add-endpoint-btn{width:100%;border-style:dashed;padding:.5rem .875rem;font-size:.8125rem}.add-endpoint-btn mat-icon{font-size:1.25rem;width:1.25rem;height:1.25rem;margin-right:.5rem}.panel-error{margin-top:.5rem;font-size:.75rem}.inline-edit-actions{display:flex;justify-content:flex-end;gap:.75rem;padding-top:1rem;margin-top:.5rem}@media(prefers-color-scheme:dark){.config-panel{box-shadow:0 1px 3px #0000004d}}\n"] }]
|
|
299
|
+
}] });
|
|
300
|
+
|
|
301
|
+
class FormsBuilderMenuComponent {
|
|
302
|
+
constructor() {
|
|
303
|
+
this.#store = inject(FormsStoreService);
|
|
304
|
+
this.#destroyRef = inject(DestroyRef);
|
|
305
|
+
this.snackBar = inject(MatSnackBar);
|
|
306
|
+
this.dialog = inject(MatDialog);
|
|
307
|
+
this.showJson = false;
|
|
308
|
+
this.form = computed(() => this.#store.signalSelectors.selectFormInEdit()?.form, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
309
|
+
this.formCopy = computed(() => JSON.stringify(this.form() || {}), ...(ngDevMode ? [{ debugName: "formCopy" }] : /* istanbul ignore next */ []));
|
|
310
|
+
this.errors = this.#store.formBuilderSignalSelectors.formErrors;
|
|
311
|
+
this.configHasErrors = computed(() => this.errors().some((error) => error.key.split('.')?.[0] === 'submissionHandle'), ...(ngDevMode ? [{ debugName: "configHasErrors" }] : /* istanbul ignore next */ []));
|
|
312
|
+
this.items = computed(() => [
|
|
313
|
+
{
|
|
314
|
+
label: 'Templates',
|
|
315
|
+
icon: 'content_copy',
|
|
316
|
+
hint: 'Select a form to apply as a template',
|
|
317
|
+
action: () => this.openDialog(),
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
label: 'Submission Config',
|
|
321
|
+
hint: 'Setup form submission api and other configurations',
|
|
322
|
+
icon: 'api',
|
|
323
|
+
errors: this.configHasErrors(),
|
|
324
|
+
action: () => this.openFormSubmissionDialog(),
|
|
325
|
+
},
|
|
326
|
+
], ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
327
|
+
this.applyFormTemplate = (form) => this.#store.actionsFormBuilder.applyFormTemplate(form);
|
|
328
|
+
}
|
|
329
|
+
#store;
|
|
330
|
+
#destroyRef;
|
|
331
|
+
openDialog() {
|
|
332
|
+
const dialogRef = this.dialog.open(SelectFormTemplateComponent);
|
|
333
|
+
dialogRef
|
|
334
|
+
.afterClosed()
|
|
335
|
+
.pipe(take(1), takeUntilDestroyed(this.#destroyRef))
|
|
336
|
+
.subscribe((form) => {
|
|
337
|
+
if (form) {
|
|
338
|
+
this.applyFormTemplate(form);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
openFormSubmissionDialog() {
|
|
343
|
+
const dialogRef = this.dialog.open(FormSubmissionsConfigComponent, {
|
|
344
|
+
data: { store: this.#store },
|
|
345
|
+
});
|
|
346
|
+
dialogRef
|
|
347
|
+
.afterClosed()
|
|
348
|
+
.pipe(take(1), takeUntilDestroyed(this.#destroyRef))
|
|
349
|
+
.subscribe(() => {
|
|
350
|
+
// no-op
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
toggleJson() {
|
|
354
|
+
this.showJson = !this.showJson;
|
|
355
|
+
}
|
|
356
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormsBuilderMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
357
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormsBuilderMenuComponent, isStandalone: true, selector: "lib-forms-builder-menu", ngImport: i0, template: "<button [matBadge]=\"'!'\" matBadgeColor=\"warn\" [matTooltip]=\"configHasErrors() === false?'\nClick to view form configuration\n':'Click to fix or add missing form configurations'\" [matBadgeHidden]=\"!!(configHasErrors()) === false\"\n [matMenuTriggerFor]=\"configMenu\" mat-flat-button>\n Config\n <mat-icon>\n settings_suggest\n </mat-icon>\n</button>\n\n<mat-menu #configMenu=\"matMenu\">\n\n\n <div mat-subheader style=\"padding-left: 16px;\">Form edit options</div>\n @for (item of items(); track item.label) {\n <button [matTooltip]=\"item.hint\" matTooltipPosition=\"right\" style=\"padding-top:4px;padding-bottom:4px\"\n (click)=\"item?.action()\" mat-menu-item>\n <mat-icon>{{item.icon}}</mat-icon>\n\n <span>\n @if (item.errors) {\n <div style=\"line-height: normal;\">\n {{item.label}}\n </div>\n <div style=\"line-height: normal;\">\n\n <mat-error>\n <small>\n Invalid configurations\n </small>\n\n </mat-error>\n </div>\n }@else {\n\n {{item.label}}\n\n }\n\n\n </span>\n\n </button>\n <mat-divider></mat-divider>\n }\n <button [matTooltip]=\"showJson?'Hide json':'Show json'\" (click)=\"toggleJson()\" mat-menu-item>\n <mat-icon>data_object</mat-icon>\n\n <span>\n <div>\n Show json\n </div>\n\n\n\n </span>\n </button>\n\n</mat-menu>\n\n@if (showJson) {\n<div class=\"DragBoundary\">\n @defer (on viewport) {\n <mat-card cdkDragBoundary=\"DragBoundary\" cdkDrag class=\"menuCard\">\n <mat-toolbar\n style=\"background: var(--mat-sidenav-content-background-color);color:var(--mdc-filled-button-label-text-color, var(--mat-app-on-primary))\">\n <span>\n Json Form Value\n </span>\n <span class=\"spacer\"></span>\n\n <mat-icon cdkDragHandle style=\"\n margin:8px;\n color:var(--mat-divider-color, var(--mat-app-outline))\">\n drag_indicator\n </mat-icon>\n </mat-toolbar>\n <mat-divider style=\"margin-bottom: 12px;\"></mat-divider>\n\n\n <mat-card-content style=\" overflow-y: auto;\n max-height: calc(100vh - 150px);\">\n <lib-form-json-view></lib-form-json-view>\n </mat-card-content>\n <mat-card-actions>\n <span class=\"spacer\"></span>\n <button (click)=\"toggleJson()\" mat-flat-button>\n Close\n </button>\n <button color=\"primary\" [cdkCopyToClipboard]=\"(formCopy())||''\" matTooltip=\"Copy json to clipboard\"\n mat-flat-button>\n Copy\n </button>\n\n </mat-card-actions>\n\n\n </mat-card>\n }@placeholder {\n <div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\n <mat-spinner diameter=\"20\" />\n </div>\n\n }\n</div>\n}\n", styles: [".menuCard{width:fit-content;margin:0;resize:horizontal;z-index:2}.DragBoundary{position:absolute;left:0;top:74px;width:100%;height:calc(100% - 74px)}\n"], dependencies: [{ kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i1$3.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i6.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i6.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i6.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "directive", type: i2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: ClipboardModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [i1.MatButton, i3.MatIcon, i5.MatTooltip, i3$2.MatCard, i3$2.MatCardActions, i3$2.MatCardContent, i5$2.MatToolbar, i4.MatDivider, import('@angular/cdk/drag-drop').then(m => m.CdkDrag), i1$1.CdkCopyToClipboard, import('./ngx-t-forms-form-json-view.component-856Hx1Bg.mjs').then(m => m.FormJsonViewComponent)]] }); }
|
|
358
|
+
}
|
|
359
|
+
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: FormsBuilderMenuComponent, resolveDeferredDeps: () => [import('@angular/cdk/drag-drop').then(m => m.CdkDrag), import('./ngx-t-forms-form-json-view.component-856Hx1Bg.mjs').then(m => m.FormJsonViewComponent)], resolveMetadata: (CdkDrag, FormJsonViewComponent) => ({ decorators: [{
|
|
360
|
+
type: Component,
|
|
361
|
+
args: [{ selector: 'lib-forms-builder-menu', imports: [
|
|
362
|
+
MatBadgeModule,
|
|
363
|
+
MatButtonModule,
|
|
364
|
+
MatIconModule,
|
|
365
|
+
MatMenuModule,
|
|
366
|
+
MatTooltipModule,
|
|
367
|
+
MatCardModule,
|
|
368
|
+
MatToolbarModule,
|
|
369
|
+
MatDividerModule,
|
|
370
|
+
MatProgressSpinnerModule,
|
|
371
|
+
MatFormFieldModule,
|
|
372
|
+
CdkDrag,
|
|
373
|
+
ClipboardModule,
|
|
374
|
+
FormJsonViewComponent,
|
|
375
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<button [matBadge]=\"'!'\" matBadgeColor=\"warn\" [matTooltip]=\"configHasErrors() === false?'\nClick to view form configuration\n':'Click to fix or add missing form configurations'\" [matBadgeHidden]=\"!!(configHasErrors()) === false\"\n [matMenuTriggerFor]=\"configMenu\" mat-flat-button>\n Config\n <mat-icon>\n settings_suggest\n </mat-icon>\n</button>\n\n<mat-menu #configMenu=\"matMenu\">\n\n\n <div mat-subheader style=\"padding-left: 16px;\">Form edit options</div>\n @for (item of items(); track item.label) {\n <button [matTooltip]=\"item.hint\" matTooltipPosition=\"right\" style=\"padding-top:4px;padding-bottom:4px\"\n (click)=\"item?.action()\" mat-menu-item>\n <mat-icon>{{item.icon}}</mat-icon>\n\n <span>\n @if (item.errors) {\n <div style=\"line-height: normal;\">\n {{item.label}}\n </div>\n <div style=\"line-height: normal;\">\n\n <mat-error>\n <small>\n Invalid configurations\n </small>\n\n </mat-error>\n </div>\n }@else {\n\n {{item.label}}\n\n }\n\n\n </span>\n\n </button>\n <mat-divider></mat-divider>\n }\n <button [matTooltip]=\"showJson?'Hide json':'Show json'\" (click)=\"toggleJson()\" mat-menu-item>\n <mat-icon>data_object</mat-icon>\n\n <span>\n <div>\n Show json\n </div>\n\n\n\n </span>\n </button>\n\n</mat-menu>\n\n@if (showJson) {\n<div class=\"DragBoundary\">\n @defer (on viewport) {\n <mat-card cdkDragBoundary=\"DragBoundary\" cdkDrag class=\"menuCard\">\n <mat-toolbar\n style=\"background: var(--mat-sidenav-content-background-color);color:var(--mdc-filled-button-label-text-color, var(--mat-app-on-primary))\">\n <span>\n Json Form Value\n </span>\n <span class=\"spacer\"></span>\n\n <mat-icon cdkDragHandle style=\"\n margin:8px;\n color:var(--mat-divider-color, var(--mat-app-outline))\">\n drag_indicator\n </mat-icon>\n </mat-toolbar>\n <mat-divider style=\"margin-bottom: 12px;\"></mat-divider>\n\n\n <mat-card-content style=\" overflow-y: auto;\n max-height: calc(100vh - 150px);\">\n <lib-form-json-view></lib-form-json-view>\n </mat-card-content>\n <mat-card-actions>\n <span class=\"spacer\"></span>\n <button (click)=\"toggleJson()\" mat-flat-button>\n Close\n </button>\n <button color=\"primary\" [cdkCopyToClipboard]=\"(formCopy())||''\" matTooltip=\"Copy json to clipboard\"\n mat-flat-button>\n Copy\n </button>\n\n </mat-card-actions>\n\n\n </mat-card>\n }@placeholder {\n <div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\n <mat-spinner diameter=\"20\" />\n </div>\n\n }\n</div>\n}\n", styles: [".menuCard{width:fit-content;margin:0;resize:horizontal;z-index:2}.DragBoundary{position:absolute;left:0;top:74px;width:100%;height:calc(100% - 74px)}\n"] }]
|
|
376
|
+
}], ctorParameters: null, propDecorators: null }) });
|
|
377
|
+
|
|
378
|
+
export { FormsBuilderMenuComponent };
|
|
379
|
+
//# sourceMappingURL=ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs.map
|