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.
Files changed (161) hide show
  1. package/fesm2022/ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs +104 -0
  2. package/fesm2022/ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs.map +1 -0
  3. package/fesm2022/ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs +85 -0
  4. package/fesm2022/ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs.map +1 -0
  5. package/fesm2022/ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs +643 -0
  6. package/fesm2022/ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs.map +1 -0
  7. package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs +97 -0
  8. package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs.map +1 -0
  9. package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs +195 -0
  10. package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs.map +1 -0
  11. package/fesm2022/ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs +261 -0
  12. package/fesm2022/ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs.map +1 -0
  13. package/fesm2022/ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs +85 -0
  14. package/fesm2022/ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs.map +1 -0
  15. package/fesm2022/ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs +156 -0
  16. package/fesm2022/ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs.map +1 -0
  17. package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs +368 -0
  18. package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs.map +1 -0
  19. package/fesm2022/ngx-t-forms-document-picker.component-qObjcqhE.mjs +704 -0
  20. package/fesm2022/ngx-t-forms-document-picker.component-qObjcqhE.mjs.map +1 -0
  21. package/fesm2022/ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs +294 -0
  22. package/fesm2022/ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs.map +1 -0
  23. package/fesm2022/ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs +240 -0
  24. package/fesm2022/ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs.map +1 -0
  25. package/fesm2022/ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs +205 -0
  26. package/fesm2022/ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs.map +1 -0
  27. package/fesm2022/ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs +86 -0
  28. package/fesm2022/ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs.map +1 -0
  29. package/fesm2022/ngx-t-forms-form-json-view.component-856Hx1Bg.mjs +22 -0
  30. package/fesm2022/ngx-t-forms-form-json-view.component-856Hx1Bg.mjs.map +1 -0
  31. package/fesm2022/ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs +179 -0
  32. package/fesm2022/ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs.map +1 -0
  33. package/fesm2022/ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs +319 -0
  34. package/fesm2022/ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs.map +1 -0
  35. package/fesm2022/ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs +379 -0
  36. package/fesm2022/ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs.map +1 -0
  37. package/fesm2022/ngx-t-forms-geo-location.component-Bosp1UzR.mjs +124 -0
  38. package/fesm2022/ngx-t-forms-geo-location.component-Bosp1UzR.mjs.map +1 -0
  39. package/fesm2022/ngx-t-forms-getInputIcon-B4ADgevZ.mjs +31 -0
  40. package/fesm2022/ngx-t-forms-getInputIcon-B4ADgevZ.mjs.map +1 -0
  41. package/fesm2022/ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs +180 -0
  42. package/fesm2022/ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs.map +1 -0
  43. package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs +2 -0
  44. package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs.map +1 -0
  45. package/fesm2022/ngx-t-forms-input-custom.component-BkbHFAyR.mjs +105 -0
  46. package/fesm2022/ngx-t-forms-input-custom.component-BkbHFAyR.mjs.map +1 -0
  47. package/fesm2022/ngx-t-forms-input-editor.component-BPUOM9kQ.mjs +181 -0
  48. package/fesm2022/ngx-t-forms-input-editor.component-BPUOM9kQ.mjs.map +1 -0
  49. package/fesm2022/{ngx-t-forms-map-mat-options-keys-CbdW82su.mjs → ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs} +12 -14
  50. package/fesm2022/ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs.map +1 -0
  51. package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs +66 -0
  52. package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs.map +1 -0
  53. package/fesm2022/ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs +211 -0
  54. package/fesm2022/ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs.map +1 -0
  55. package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs +165 -0
  56. package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs.map +1 -0
  57. package/fesm2022/ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs +38 -0
  58. package/fesm2022/ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs.map +1 -0
  59. package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs +38 -0
  60. package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs.map +1 -0
  61. package/fesm2022/ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs +126 -0
  62. package/fesm2022/ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs.map +1 -0
  63. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs +336 -0
  64. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs.map +1 -0
  65. package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs +74 -0
  66. package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs.map +1 -0
  67. package/fesm2022/ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs +905 -0
  68. package/fesm2022/ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs.map +1 -0
  69. package/fesm2022/ngx-t-forms-ngx-t-forms-u_kigDid.mjs +19461 -0
  70. package/fesm2022/ngx-t-forms-ngx-t-forms-u_kigDid.mjs.map +1 -0
  71. package/fesm2022/ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs +555 -0
  72. package/fesm2022/ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs.map +1 -0
  73. package/fesm2022/ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs +748 -0
  74. package/fesm2022/ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs.map +1 -0
  75. package/fesm2022/ngx-t-forms-record-list-manager.component-CUMMvMch.mjs +358 -0
  76. package/fesm2022/ngx-t-forms-record-list-manager.component-CUMMvMch.mjs.map +1 -0
  77. package/fesm2022/ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs +272 -0
  78. package/fesm2022/ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs.map +1 -0
  79. package/fesm2022/ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs +398 -0
  80. package/fesm2022/ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs.map +1 -0
  81. package/fesm2022/ngx-t-forms-search-field.component-B2ZO7lqO.mjs +38 -0
  82. package/fesm2022/ngx-t-forms-search-field.component-B2ZO7lqO.mjs.map +1 -0
  83. package/fesm2022/ngx-t-forms-section-report.component-BxOhR6C0.mjs +98 -0
  84. package/fesm2022/ngx-t-forms-section-report.component-BxOhR6C0.mjs.map +1 -0
  85. package/fesm2022/ngx-t-forms-select-input-element.component-DbgZdNoe.mjs +150 -0
  86. package/fesm2022/ngx-t-forms-select-input-element.component-DbgZdNoe.mjs.map +1 -0
  87. package/fesm2022/ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs +169 -0
  88. package/fesm2022/ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs.map +1 -0
  89. package/fesm2022/ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs +204 -0
  90. package/fesm2022/ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs.map +1 -0
  91. package/fesm2022/ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs +95 -0
  92. package/fesm2022/ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs.map +1 -0
  93. package/fesm2022/ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs +82 -0
  94. package/fesm2022/ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs.map +1 -0
  95. package/fesm2022/ngx-t-forms-validators-config.component-oGjQVGE2.mjs +733 -0
  96. package/fesm2022/ngx-t-forms-validators-config.component-oGjQVGE2.mjs.map +1 -0
  97. package/fesm2022/ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs +1303 -0
  98. package/fesm2022/ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs.map +1 -0
  99. package/fesm2022/ngx-t-forms.mjs +2 -1
  100. package/fesm2022/ngx-t-forms.mjs.map +1 -1
  101. package/package.json +20 -18
  102. package/styles/_editor-mixins.scss +62 -0
  103. package/styles/_json-editor-syntax.scss +26 -0
  104. package/styles/_signature-pad.scss +26 -0
  105. package/styles/_tokens.scss +148 -0
  106. package/types/ngx-t-forms.d.ts +1767 -621
  107. package/fesm2022/ngx-t-forms-calculated-field-rules.component-D-SBMdYg.mjs +0 -313
  108. package/fesm2022/ngx-t-forms-calculated-field-rules.component-D-SBMdYg.mjs.map +0 -1
  109. package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-1cpszpPN.mjs +0 -191
  110. package/fesm2022/ngx-t-forms-chip-options-creator-editor.component-1cpszpPN.mjs.map +0 -1
  111. package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-DFdAVWTg.mjs +0 -207
  112. package/fesm2022/ngx-t-forms-config-mscoa-additional-inputs.component-DFdAVWTg.mjs.map +0 -1
  113. package/fesm2022/ngx-t-forms-data-source-picker.component-DxORinAD.mjs +0 -204
  114. package/fesm2022/ngx-t-forms-data-source-picker.component-DxORinAD.mjs.map +0 -1
  115. package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-DcWS1txl.mjs +0 -289
  116. package/fesm2022/ngx-t-forms-document-list-label-config-editor.component-DcWS1txl.mjs.map +0 -1
  117. package/fesm2022/ngx-t-forms-form-input-selector.component-B2QEnvkq.mjs +0 -134
  118. package/fesm2022/ngx-t-forms-form-input-selector.component-B2QEnvkq.mjs.map +0 -1
  119. package/fesm2022/ngx-t-forms-form-json-view.component-DePf44w6.mjs +0 -22
  120. package/fesm2022/ngx-t-forms-form-json-view.component-DePf44w6.mjs.map +0 -1
  121. package/fesm2022/ngx-t-forms-form-section-stepper.component-BTkcSjg7.mjs +0 -270
  122. package/fesm2022/ngx-t-forms-form-section-stepper.component-BTkcSjg7.mjs.map +0 -1
  123. package/fesm2022/ngx-t-forms-forms-builder-menu.component-Wamzf_sq.mjs +0 -345
  124. package/fesm2022/ngx-t-forms-forms-builder-menu.component-Wamzf_sq.mjs.map +0 -1
  125. package/fesm2022/ngx-t-forms-input-editor.component-D4xHO76K.mjs +0 -147
  126. package/fesm2022/ngx-t-forms-input-editor.component-D4xHO76K.mjs.map +0 -1
  127. package/fesm2022/ngx-t-forms-map-mat-options-keys-CbdW82su.mjs.map +0 -1
  128. package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-DmTyO9Wi.mjs +0 -105
  129. package/fesm2022/ngx-t-forms-mat-chip-list-editor.component-DmTyO9Wi.mjs.map +0 -1
  130. package/fesm2022/ngx-t-forms-mat-slider-editor.component-DZ4TenrI.mjs +0 -109
  131. package/fesm2022/ngx-t-forms-mat-slider-editor.component-DZ4TenrI.mjs.map +0 -1
  132. package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-DPyBYE4p.mjs +0 -155
  133. package/fesm2022/ngx-t-forms-mat-slider-toggle-editor.component-DPyBYE4p.mjs.map +0 -1
  134. package/fesm2022/ngx-t-forms-missing-form-configs.component-BRmnwAK6.mjs +0 -28
  135. package/fesm2022/ngx-t-forms-missing-form-configs.component-BRmnwAK6.mjs.map +0 -1
  136. package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-D_umeAPL.mjs +0 -43
  137. package/fesm2022/ngx-t-forms-mscoa-chart-toolbar.component-D_umeAPL.mjs.map +0 -1
  138. package/fesm2022/ngx-t-forms-mscoa-error-display.component-CSX2NCNU.mjs +0 -116
  139. package/fesm2022/ngx-t-forms-mscoa-error-display.component-CSX2NCNU.mjs.map +0 -1
  140. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-B6IF8kGg.mjs +0 -296
  141. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-B6IF8kGg.mjs.map +0 -1
  142. package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-BPkjsRmH.mjs +0 -83
  143. package/fesm2022/ngx-t-forms-mscoa-temporary-hint.component-BPkjsRmH.mjs.map +0 -1
  144. package/fesm2022/ngx-t-forms-ngx-t-forms-D9qmig6g.mjs +0 -16844
  145. package/fesm2022/ngx-t-forms-ngx-t-forms-D9qmig6g.mjs.map +0 -1
  146. package/fesm2022/ngx-t-forms-pipeline-generator.component-DBJEyCbd.mjs +0 -613
  147. package/fesm2022/ngx-t-forms-pipeline-generator.component-DBJEyCbd.mjs.map +0 -1
  148. package/fesm2022/ngx-t-forms-record-list-manager.component-Dgs9lNSr.mjs +0 -269
  149. package/fesm2022/ngx-t-forms-record-list-manager.component-Dgs9lNSr.mjs.map +0 -1
  150. package/fesm2022/ngx-t-forms-required-inputs.component-CSIJvSHq.mjs +0 -190
  151. package/fesm2022/ngx-t-forms-required-inputs.component-CSIJvSHq.mjs.map +0 -1
  152. package/fesm2022/ngx-t-forms-rest-api-call-setup.component-CY-JSkGs.mjs +0 -291
  153. package/fesm2022/ngx-t-forms-rest-api-call-setup.component-CY-JSkGs.mjs.map +0 -1
  154. package/fesm2022/ngx-t-forms-section-report.component-12-KdKT6.mjs +0 -156
  155. package/fesm2022/ngx-t-forms-section-report.component-12-KdKT6.mjs.map +0 -1
  156. package/fesm2022/ngx-t-forms-selection-options-editor.component-Be3QAG_L.mjs +0 -186
  157. package/fesm2022/ngx-t-forms-selection-options-editor.component-Be3QAG_L.mjs.map +0 -1
  158. package/fesm2022/ngx-t-forms-t-workflow-picker.component-a4f1r8gH.mjs +0 -187
  159. package/fesm2022/ngx-t-forms-t-workflow-picker.component-a4f1r8gH.mjs.map +0 -1
  160. package/fesm2022/ngx-t-forms-validators-config.component-B3j9Dmgu.mjs +0 -215
  161. 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