ngx-t-forms 2.0.31 → 2.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/fesm2022/{ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs → ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs} +2 -2
  2. package/fesm2022/{ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs.map → ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs.map} +1 -1
  3. package/fesm2022/{ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs → ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs} +3 -3
  4. package/fesm2022/{ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs.map → ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs.map} +1 -1
  5. package/fesm2022/{ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs → ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs} +4 -4
  6. package/fesm2022/{ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs.map → ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs.map} +1 -1
  7. package/fesm2022/{ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs → ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs} +4 -4
  8. package/fesm2022/{ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs.map → ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs.map} +1 -1
  9. package/fesm2022/{ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs → ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs} +2 -2
  10. package/fesm2022/{ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs.map → ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs.map} +1 -1
  11. package/fesm2022/{ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs → ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs} +6 -6
  12. package/fesm2022/{ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs.map → ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs.map} +1 -1
  13. package/fesm2022/{ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs → ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs} +2 -2
  14. package/fesm2022/{ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs.map → ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs.map} +1 -1
  15. package/fesm2022/{ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs → ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs} +2 -2
  16. package/fesm2022/{ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs.map → ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs.map} +1 -1
  17. package/fesm2022/{ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs → ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs} +3 -3
  18. package/fesm2022/{ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs.map → ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs.map} +1 -1
  19. package/fesm2022/{ngx-t-forms-document-picker.component-qObjcqhE.mjs → ngx-t-forms-document-picker.component-BThdRFec.mjs} +2 -2
  20. package/fesm2022/{ngx-t-forms-document-picker.component-qObjcqhE.mjs.map → ngx-t-forms-document-picker.component-BThdRFec.mjs.map} +1 -1
  21. package/fesm2022/{ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs → ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs} +3 -3
  22. package/fesm2022/{ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs.map → ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs.map} +1 -1
  23. package/fesm2022/{ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs → ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs} +2 -2
  24. package/fesm2022/{ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs.map → ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs.map} +1 -1
  25. package/fesm2022/{ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs → ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs} +2 -2
  26. package/fesm2022/{ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs.map → ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs.map} +1 -1
  27. package/fesm2022/{ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs → ngx-t-forms-form-input-selector.component-B42xP3jh.mjs} +2 -2
  28. package/fesm2022/{ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs.map → ngx-t-forms-form-input-selector.component-B42xP3jh.mjs.map} +1 -1
  29. package/fesm2022/{ngx-t-forms-form-json-view.component-856Hx1Bg.mjs → ngx-t-forms-form-json-view.component-DnnLXqR0.mjs} +2 -2
  30. package/fesm2022/{ngx-t-forms-form-json-view.component-856Hx1Bg.mjs.map → ngx-t-forms-form-json-view.component-DnnLXqR0.mjs.map} +1 -1
  31. package/fesm2022/{ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs → ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs} +4 -4
  32. package/fesm2022/{ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs.map → ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs.map} +1 -1
  33. package/fesm2022/{ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs → ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs} +4 -4
  34. package/fesm2022/{ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs.map → ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs.map} +1 -1
  35. package/fesm2022/{ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs → ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs} +5 -5
  36. package/fesm2022/{ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs.map → ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs.map} +1 -1
  37. package/fesm2022/{ngx-t-forms-geo-location.component-Bosp1UzR.mjs → ngx-t-forms-geo-location.component-Bmd84Gcb.mjs} +2 -2
  38. package/fesm2022/{ngx-t-forms-geo-location.component-Bosp1UzR.mjs.map → ngx-t-forms-geo-location.component-Bmd84Gcb.mjs.map} +1 -1
  39. package/fesm2022/{ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs → ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs} +2 -2
  40. package/fesm2022/{ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs.map → ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs.map} +1 -1
  41. package/fesm2022/ngx-t-forms-index-BcrQ01DQ.mjs +2 -0
  42. package/fesm2022/ngx-t-forms-index-BcrQ01DQ.mjs.map +1 -0
  43. package/fesm2022/{ngx-t-forms-input-custom.component-BkbHFAyR.mjs → ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs} +2 -2
  44. package/fesm2022/{ngx-t-forms-input-custom.component-BkbHFAyR.mjs.map → ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs.map} +1 -1
  45. package/fesm2022/{ngx-t-forms-input-editor.component-BPUOM9kQ.mjs → ngx-t-forms-input-editor.component-DLru1Ezu.mjs} +17 -5
  46. package/fesm2022/ngx-t-forms-input-editor.component-DLru1Ezu.mjs.map +1 -0
  47. package/fesm2022/{ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs → ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs} +2 -2
  48. package/fesm2022/{ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs.map → ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs.map} +1 -1
  49. package/fesm2022/{ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs → ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs} +4 -4
  50. package/fesm2022/{ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs.map → ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs.map} +1 -1
  51. package/fesm2022/{ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs → ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs} +2 -2
  52. package/fesm2022/{ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs.map → ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs.map} +1 -1
  53. package/fesm2022/{ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs → ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs} +2 -2
  54. package/fesm2022/{ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs.map → ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs.map} +1 -1
  55. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs +447 -0
  56. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs.map +1 -0
  57. package/fesm2022/{ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs → ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs} +16 -16
  58. package/fesm2022/{ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs.map → ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs.map} +1 -1
  59. package/fesm2022/{ngx-t-forms-ngx-t-forms-u_kigDid.mjs → ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs} +931 -82
  60. package/fesm2022/ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs.map +1 -0
  61. package/fesm2022/{ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs → ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs} +2 -2
  62. package/fesm2022/{ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs.map → ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs.map} +1 -1
  63. package/fesm2022/{ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs → ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs} +3 -3
  64. package/fesm2022/{ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs.map → ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs.map} +1 -1
  65. package/fesm2022/{ngx-t-forms-record-list-manager.component-CUMMvMch.mjs → ngx-t-forms-record-list-manager.component-CykBq_nW.mjs} +2 -2
  66. package/fesm2022/{ngx-t-forms-record-list-manager.component-CUMMvMch.mjs.map → ngx-t-forms-record-list-manager.component-CykBq_nW.mjs.map} +1 -1
  67. package/fesm2022/{ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs → ngx-t-forms-required-inputs.component-ONbhxVSH.mjs} +2 -2
  68. package/fesm2022/{ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs.map → ngx-t-forms-required-inputs.component-ONbhxVSH.mjs.map} +1 -1
  69. package/fesm2022/{ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs → ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs} +2 -2
  70. package/fesm2022/{ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs.map → ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs.map} +1 -1
  71. package/fesm2022/{ngx-t-forms-section-report.component-BxOhR6C0.mjs → ngx-t-forms-section-report.component-C1w16LYm.mjs} +4 -4
  72. package/fesm2022/{ngx-t-forms-section-report.component-BxOhR6C0.mjs.map → ngx-t-forms-section-report.component-C1w16LYm.mjs.map} +1 -1
  73. package/fesm2022/{ngx-t-forms-select-input-element.component-DbgZdNoe.mjs → ngx-t-forms-select-input-element.component-CWcywuS6.mjs} +8 -8
  74. package/fesm2022/{ngx-t-forms-select-input-element.component-DbgZdNoe.mjs.map → ngx-t-forms-select-input-element.component-CWcywuS6.mjs.map} +1 -1
  75. package/fesm2022/{ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs → ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs} +4 -4
  76. package/fesm2022/{ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs.map → ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs.map} +1 -1
  77. package/fesm2022/{ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs → ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs} +3 -3
  78. package/fesm2022/{ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs.map → ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs.map} +1 -1
  79. package/fesm2022/{ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs → ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs} +2 -2
  80. package/fesm2022/{ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs.map → ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs.map} +1 -1
  81. package/fesm2022/{ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs → ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs} +2 -2
  82. package/fesm2022/{ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs.map → ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs.map} +1 -1
  83. package/fesm2022/{ngx-t-forms-validators-config.component-oGjQVGE2.mjs → ngx-t-forms-validators-config.component-BknyAmV_.mjs} +8 -167
  84. package/fesm2022/ngx-t-forms-validators-config.component-BknyAmV_.mjs.map +1 -0
  85. package/fesm2022/{ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs → ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs} +3 -3
  86. package/fesm2022/{ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs.map → ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs.map} +1 -1
  87. package/fesm2022/ngx-t-forms.mjs +1 -1
  88. package/package.json +2 -2
  89. package/types/ngx-t-forms.d.ts +191 -4
  90. package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs +0 -2
  91. package/fesm2022/ngx-t-forms-index-dDSobs6A.mjs.map +0 -1
  92. package/fesm2022/ngx-t-forms-input-editor.component-BPUOM9kQ.mjs.map +0 -1
  93. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs +0 -336
  94. package/fesm2022/ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs.map +0 -1
  95. package/fesm2022/ngx-t-forms-ngx-t-forms-u_kigDid.mjs.map +0 -1
  96. package/fesm2022/ngx-t-forms-validators-config.component-oGjQVGE2.mjs.map +0 -1
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, computed, runInInjectionContext, effect, untracked, linkedSignal, resource, inject, Injector, ApplicationRef, signal, Inject, Directive, Injectable, DestroyRef, makeEnvironmentProviders, Pipe, PLATFORM_ID, ChangeDetectionStrategy, Component, input, viewChild, NgZone, output, model, Optional, ViewEncapsulation, NgModule, ChangeDetectorRef, Input, Self, ElementRef } from '@angular/core';
3
3
  import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { validateForm, getElementEditorConfig, ElementEditorTypes, AllFormInputPrimaryKeys, DefaultInputConfig, SpecialElementKeys, validateFormColumnInputsWithRequired, ElementTypes, validateFormSlide, FormListSection, DataSources, formColumnInputsSchema, CalculationFunctions, InputTypes, WorkflowFunctionTypes, validateCalculatedFieldRules, FormSubmissionStatus, InputDataTypes, AdjudicationSteps, InputPipeTypes, RichTextEditorType, OptionSelectTypes, MinInputTypes, FormStateErrors, BlurHandleTypes, FunctionTypes as FunctionTypes$2 } from 'ngx-t-forms-types';
5
- import { of, throwError, take, forkJoin, map as map$1, catchError as catchError$1, EMPTY, tap, switchMap, filter, firstValueFrom, from, concatMap, last, Subject, takeUntil, Subscription, timeout, Observable, BehaviorSubject, shareReplay, concat, finalize, distinctUntilChanged, isObservable, timer, debounceTime, combineLatest, merge, withLatestFrom } from 'rxjs';
5
+ import { of, throwError, take, forkJoin, map as map$1, catchError as catchError$1, EMPTY, tap, switchMap, filter, firstValueFrom, from, concatMap, last, Subject, takeUntil, Subscription, timeout, Observable, BehaviorSubject, shareReplay, concat, finalize, distinctUntilChanged, isObservable, timer, debounceTime, combineLatest, merge, withLatestFrom, startWith as startWith$1 } from 'rxjs';
6
6
  import { catchError, map, switchMap as switchMap$1, startWith, debounceTime as debounceTime$1, distinctUntilChanged as distinctUntilChanged$1, shareReplay as shareReplay$1, tap as tap$1, finalize as finalize$1 } from 'rxjs/operators';
7
7
  import * as i1$1 from '@angular/forms';
8
8
  import { Validators, FormControl, FormGroup, FormArray, FormsModule, ReactiveFormsModule, NgControl } from '@angular/forms';
@@ -70,9 +70,9 @@ import { CdkStepperModule } from '@angular/cdk/stepper';
70
70
  import { CdkTableModule } from '@angular/cdk/table';
71
71
  import { MatBadgeModule } from '@angular/material/badge';
72
72
  import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
73
- import * as i2$2 from '@angular/material/button-toggle';
73
+ import * as i3$5 from '@angular/material/button-toggle';
74
74
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
75
- import * as i1$6 from '@angular/material/chips';
75
+ import * as i4$3 from '@angular/material/chips';
76
76
  import { MatChipsModule } from '@angular/material/chips';
77
77
  import { MatDatepickerModule } from '@angular/material/datepicker';
78
78
  import { MatGridListModule } from '@angular/material/grid-list';
@@ -85,7 +85,7 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
85
85
  import * as i10 from '@angular/material/sort';
86
86
  import { MatSortModule, MatSort } from '@angular/material/sort';
87
87
  import { MatTabsModule } from '@angular/material/tabs';
88
- import * as i2$3 from '@angular/cdk/overlay';
88
+ import * as i2$2 from '@angular/cdk/overlay';
89
89
  import { OverlayModule } from '@angular/cdk/overlay';
90
90
  import { MatAutocompleteModule } from '@angular/material/autocomplete';
91
91
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
@@ -4816,13 +4816,18 @@ function _isEqual(prev, next) {
4816
4816
  const nRe = next;
4817
4817
  return pRe.source === nRe.source && pRe.flags === nRe.flags;
4818
4818
  }
4819
- const prevKeys = Object.keys(prevObj);
4820
- const nextKeys = Object.keys(nextObj);
4819
+ // A present-but-`undefined` key is treated as an absent key (mirrors
4820
+ // `getChangedProperties` above, JSON semantics, and every idempotency
4821
+ // guard in the store). Without this, an audit pass that adds `vat:
4822
+ // undefined` to a non-VAT segment would never compare equal to the same
4823
+ // value after it round-trips through the form (which drops the undefined
4824
+ // key), and the form ⇄ store ⇄ form graph oscillates — re-firing the
4825
+ // debounced MSCOA validation API forever on the same payload.
4826
+ const prevKeys = Object.keys(prevObj).filter((key) => prevObj[key] !== undefined);
4827
+ const nextKeys = Object.keys(nextObj).filter((key) => nextObj[key] !== undefined);
4821
4828
  if (prevKeys.length !== nextKeys.length)
4822
4829
  return false;
4823
4830
  for (const key of prevKeys) {
4824
- if (!Object.prototype.hasOwnProperty.call(nextObj, key))
4825
- return false;
4826
4831
  if (!_isEqual(prevObj[key], nextObj[key]))
4827
4832
  return false;
4828
4833
  }
@@ -6458,7 +6463,13 @@ function buildValuePostMethodApi(input, ctx) {
6458
6463
  catch {
6459
6464
  return undefined;
6460
6465
  }
6461
- }, ...(ngDevMode ? [{ debugName: "params" }] : /* istanbul ignore next */ []));
6466
+ }, { ...(ngDevMode ? { debugName: "params" } : /* istanbul ignore next */ {}),
6467
+ // `returnMappedData` allocates a fresh object on every recompute, and this
6468
+ // computed re-runs on ANY `#model` change (readDep reads the whole map).
6469
+ // Without structural equality the resource would treat every unrelated
6470
+ // value edit as a params change and reload the API. Emit only when the
6471
+ // mapped dependency values actually change.
6472
+ equal: _isEqual });
6462
6473
  return resource({
6463
6474
  params,
6464
6475
  loader: async ({ params: payload }) => {
@@ -6808,7 +6819,14 @@ function buildPostComputedOptionsResource(input, ctx) {
6808
6819
  }
6809
6820
  // Build the mapped POST body.
6810
6821
  return returnMappedData(snapshot, minInputs, fetchConfig.httpEndPoint);
6811
- }, ...(ngDevMode ? [{ debugName: "paramsSignal" }] : /* istanbul ignore next */ []));
6822
+ }, { ...(ngDevMode ? { debugName: "paramsSignal" } : /* istanbul ignore next */ {}),
6823
+ // `returnMappedData` allocates a fresh object on every recompute, and this
6824
+ // computed re-runs on ANY `#model` change (readDep reads the whole map).
6825
+ // Without structural equality the resource would treat every unrelated
6826
+ // value edit (e.g. selecting a row in THIS field) as a params change and
6827
+ // reload the API — a runaway refetch loop. Emit only when the mapped
6828
+ // dependency values actually change.
6829
+ equal: _isEqual });
6812
6830
  // Edge-tracker: a plain closure variable (NOT a signal — nothing reads it
6813
6831
  // reactively), so the resolved-edge effect below never writes a signal.
6814
6832
  let prevStatus = 'idle';
@@ -7392,6 +7410,16 @@ class FormTowerControllerService {
7392
7410
  * `(valueChange)` binding. Torn down on close / re-open / re-init.
7393
7411
  */
7394
7412
  this.#multipleInputRowSubs = new Map();
7413
+ /**
7414
+ * Live `valueChanges` bridge for mSCOA inner-input controls — the custom form
7415
+ * inputs configured inside an `MscoaSelection` column (e.g. `budgetValue`,
7416
+ * `department`) and rendered inline by the MSCOA chart through a
7417
+ * `ComponentPortal`. A single aggregate subscription: unlike MultipleInput
7418
+ * rows these inner inputs are static (created at form generation, never
7419
+ * toggled), so they are all bound once per init. See
7420
+ * {@link FormTowerControllerService.bindScoaInnerInputControls}.
7421
+ */
7422
+ this.#scoaInnerInputSub = undefined;
7395
7423
  // ──────────────────────────────────────────────────────────────────────────
7396
7424
  // Overridable-validation submission gate
7397
7425
  // ──────────────────────────────────────────────────────────────────────────
@@ -7661,6 +7689,11 @@ class FormTowerControllerService {
7661
7689
  // resource sits `idle` and never fires (and `refresh`/`.reload()` no-ops
7662
7690
  // on an idle resource) until the user manually edits the dependency.
7663
7691
  this.#seedModelFromDefinition();
7692
+ // 8. Bridge mSCOA inner-input (custom form input) controls into `#model` so
7693
+ // their user edits drive the signal graph. They render inline via the
7694
+ // MSCOA chart's ComponentPortal, which has no `(valueChange)` binding of
7695
+ // its own — mirrors step 5's MultipleInput sub-row bridge.
7696
+ this.bindScoaInnerInputControls();
7664
7697
  };
7665
7698
  /**
7666
7699
  * Marks the form's first slide as active. Called during
@@ -7790,8 +7823,11 @@ class FormTowerControllerService {
7790
7823
  continue;
7791
7824
  }
7792
7825
  if (isMultipleInput) {
7793
- // ── Phase 2 fence: MultipleInput array-remap branch — UNCHANGED. ──
7794
- const v = (value ?? []).map((item) => {
7826
+ // ── Phase 2 fence: MultipleInput array-remap branch. ──
7827
+ // `??` only guards null/undefined; a non-array value (e.g. an object or a
7828
+ // JSON-string row that pre-processing left unparsed) would reach `.map` and
7829
+ // throw "(value ?? []).map is not a function". Coerce any non-array to [].
7830
+ const v = (Array.isArray(value) ? value : []).map((item) => {
7795
7831
  return Object.entries(item).reduce((acc, [key, val]) => {
7796
7832
  const inp = allInputs.find((i) => i.formControlName === key);
7797
7833
  if (key === 'id') {
@@ -7868,6 +7904,13 @@ class FormTowerControllerService {
7868
7904
  catch { /* best-effort */ }
7869
7905
  }
7870
7906
  this.#multipleInputRowSubs.clear();
7907
+ // Drop the mSCOA inner-input valueChanges bridge (the takeUntil anchor below
7908
+ // also completes its inner subs; this clears the handle).
7909
+ try {
7910
+ this.#scoaInnerInputSub?.unsubscribe();
7911
+ }
7912
+ catch { /* best-effort */ }
7913
+ this.#scoaInnerInputSub = undefined;
7871
7914
  this.#definition.set(undefined);
7872
7915
  this._mainForm = undefined;
7873
7916
  this.#model.set({});
@@ -8027,6 +8070,54 @@ class FormTowerControllerService {
8027
8070
  existing.unsubscribe();
8028
8071
  this.#multipleInputRowSubs.delete(inputId);
8029
8072
  };
8073
+ /**
8074
+ * Bridges live edits of mSCOA inner inputs — the custom form inputs configured
8075
+ * inside an `MscoaSelection` column (e.g. `budgetValue`, `department`) and
8076
+ * rendered inline by the MSCOA chart via a `ComponentPortal` — into the signal
8077
+ * graph.
8078
+ *
8079
+ * Each inner input is a `${mscoaColId}.${innerId}` control sitting in the mSCOA
8080
+ * column's section group. The engine already lists it in `allFormInputs`, so
8081
+ * its derived calc / value-API / options graph is built at init (the OUTPUT
8082
+ * half). But a `ComponentPortal` forwards inputs only and never subscribes the
8083
+ * host's `valueChange` output, so the user's typed value never reached `#model`
8084
+ * — leaving dependent calculations / value-fetches / options blind to it. This
8085
+ * subscribes each such control's `valueChanges` → `updateValue(controlName, …)`,
8086
+ * restoring the INPUT half so an mSCOA custom input behaves exactly like a
8087
+ * primary-form input. Direct mirror of
8088
+ * {@link FormTowerControllerService.bindMultipleInputRowControls}.
8089
+ *
8090
+ * Idempotent (tears down the prior bridge first) and anchored to `_destroyed$`,
8091
+ * so the re-init `clearFormState` drops every inner subscription.
8092
+ */
8093
+ this.bindScoaInnerInputControls = () => {
8094
+ this.#scoaInnerInputSub?.unsubscribe();
8095
+ this.#scoaInnerInputSub = undefined;
8096
+ if (!this._mainForm)
8097
+ return;
8098
+ const mscoaColumnIds = (this.allFormInputs() ?? [])
8099
+ .filter(input => input.element === ElementTypes.MscoaSelection)
8100
+ .map(input => input.id);
8101
+ if (mscoaColumnIds.length === 0)
8102
+ return;
8103
+ const sub = new Subscription();
8104
+ for (const sectionGroup of Object.values(this._mainForm.controls)) {
8105
+ const group = sectionGroup;
8106
+ if (!group?.controls)
8107
+ continue;
8108
+ for (const [controlName, control] of Object.entries(group.controls)) {
8109
+ // An inner input is a `${mscoaColId}.${innerId}` sibling — never the
8110
+ // column control itself (no dotted suffix; the tower already bridges it
8111
+ // via the explicit `(valueChange)` binding on `<lib-t-form-input>`).
8112
+ if (!mscoaColumnIds.some(colId => controlName.startsWith(`${colId}.`)))
8113
+ continue;
8114
+ sub.add(control.valueChanges
8115
+ .pipe(takeUntil(this._destroyed$))
8116
+ .subscribe(value => this.updateValue(controlName, value)));
8117
+ }
8118
+ }
8119
+ this.#scoaInnerInputSub = sub;
8120
+ };
8030
8121
  // ──────────────────────────────────────────────────────────────────────────
8031
8122
  // W13 — Refresh / revert family (resource .reload() + #derived membership)
8032
8123
  // ──────────────────────────────────────────────────────────────────────────
@@ -8170,6 +8261,16 @@ class FormTowerControllerService {
8170
8261
  * `(valueChange)` binding. Torn down on close / re-open / re-init.
8171
8262
  */
8172
8263
  #multipleInputRowSubs;
8264
+ /**
8265
+ * Live `valueChanges` bridge for mSCOA inner-input controls — the custom form
8266
+ * inputs configured inside an `MscoaSelection` column (e.g. `budgetValue`,
8267
+ * `department`) and rendered inline by the MSCOA chart through a
8268
+ * `ComponentPortal`. A single aggregate subscription: unlike MultipleInput
8269
+ * rows these inner inputs are static (created at form generation, never
8270
+ * toggled), so they are all bound once per init. See
8271
+ * {@link FormTowerControllerService.bindScoaInnerInputControls}.
8272
+ */
8273
+ #scoaInnerInputSub;
8173
8274
  // ──────────────────────────────────────────────────────────────────────────
8174
8275
  // W7 — Getters / setters re-pointed onto the source signals
8175
8276
  // ──────────────────────────────────────────────────────────────────────────
@@ -8284,7 +8385,16 @@ class FormTowerControllerService {
8284
8385
  void debounceMs;
8285
8386
  // One-tick liveness lead-read: force-activate resources + flush effects.
8286
8387
  this.#forceLiveness();
8287
- return firstValueFrom(toObservable(this.settled, { injector: this.#injector }).pipe(filter((isSettled) => isSettled === true), take(1), timeout(timeoutMs), catchError$1(() => of(undefined)), tap(() => undefined))).then(() => undefined);
8388
+ return firstValueFrom(toObservable(this.settled, { injector: this.#injector }).pipe(filter((isSettled) => isSettled === true), take(1), timeout(timeoutMs), catchError$1(() => of(undefined)), tap(() => undefined))).then(() => {
8389
+ // Post-settle projection flush (headless-read guarantee). `settled === true`
8390
+ // only means every resource has resolved into `#value()`; the FormGroup is
8391
+ // patched by the async `#formProjection` effect, which may NOT have run yet —
8392
+ // notably for resources that resolve in a single microtask off a shared
8393
+ // `shareReplay` cache (import cache-hit rows). Headless consumers read
8394
+ // `mainForm.value` (getFormValueNames), so drain the projection effect here
8395
+ // before resolving, otherwise they capture the stale pre-fetch FormGroup.
8396
+ this.#forceLiveness();
8397
+ });
8288
8398
  }
8289
8399
  /**
8290
8400
  * Forces the signal graph live: reads `value()` and every resource `status()`
@@ -8796,12 +8906,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
8796
8906
  * ImportRowState { status, settledValue, isValid, validationErrors, colErrors }
8797
8907
  * ```
8798
8908
  *
8799
- * **Concurrency strategy:** every row processes in parallel via
8800
- * `Promise.all(...)`. To avoid 26 rows hammering the same endpoint 26 times,
8801
- * each tower's `httpGetDataFunction` / `httpPostDataFunction` is wrapped to
8802
- * route through {@link TFormImportController._cachedGet} /
8803
- * {@link TFormImportController._cachedPost}, which dedupe identical requests
8804
- * via `shareReplay(1)` for the lifetime of the session.
8909
+ * **Concurrency strategy:** rows are processed **sequentially** (one tower at a
8910
+ * time). Each tower's settle (`waitUntilSettled`) and FormGroup projection rely
8911
+ * on `ApplicationRef.tick()`-driven effect flushes over the application's single
8912
+ * shared `ApplicationRef`; running rows concurrently interleaves those ticks so
8913
+ * `waitUntilSettled` resolves on a spurious `settled === true` before a row's
8914
+ * value resources have drained + projected, leaving most rows with empty
8915
+ * API-derived fields. To still avoid N rows hammering the same endpoint N times,
8916
+ * each tower's `httpGetDataFunction` / `httpPostDataFunction` is wrapped to route
8917
+ * through {@link TFormImportController._cachedGet} /
8918
+ * {@link TFormImportController._cachedPost}, which dedupe identical requests via
8919
+ * `shareReplay(1)` for the lifetime of the session — so sequential rows reuse the
8920
+ * same in-flight/replayed network calls.
8805
8921
  *
8806
8922
  * **Settle model (Phase 1.5):** the signal-graph engine settles by construction —
8807
8923
  * `waitUntilSettled` resolves once every value/options resource and calculation
@@ -8909,9 +9025,23 @@ class TFormImportController {
8909
9025
  this._rows$.next(rows.map((originalData, rowIndex) => ({ rowIndex, originalData, status: 'pending' })));
8910
9026
  const hasPreProcessInputs = form.slides.some(slide => slide.columns.some(col => this._inputPreProcessors.has(col.element)));
8911
9027
  try {
8912
- console.error("Starting import with rows", rows);
8913
- await Promise.all(rows.map((row, i) => this._processRow(form, row, i, hasPreProcessInputs)));
8914
- console.error("Final settled values", this._rows$.value.map(r => r.settledValue));
9028
+ // Rows are processed SEQUENTIALLY, not concurrently. Each row spins up its
9029
+ // own tower whose settle (`waitUntilSettled`) and FormGroup projection rely
9030
+ // on `ApplicationRef.tick()`-driven effect flushes over the application's
9031
+ // single shared `ApplicationRef`. Running every row concurrently makes those
9032
+ // ticks interleave across towers, so `waitUntilSettled` resolves on a
9033
+ // spurious `settled === true` (value resources still `idle`, not yet
9034
+ // `loading`) before a row's derived values have drained and projected —
9035
+ // leaving most rows with empty API-derived fields (objectives/nKPA/etc.).
9036
+ // The per-session HTTP caches (`_getCache`/`_postCache`/`_financialCycles$`)
9037
+ // still dedupe identical requests across rows, so sequential processing
9038
+ // reuses the same network calls without the race.
9039
+ for (let i = 0; i < rows.length; i++) {
9040
+ const row = rows[i];
9041
+ if (!row)
9042
+ continue;
9043
+ await this._processRow(form, row, i, hasPreProcessInputs);
9044
+ }
8915
9045
  }
8916
9046
  finally {
8917
9047
  // Always release cached Observables — even if an unexpected error escapes
@@ -9054,6 +9184,22 @@ class TFormImportController {
9054
9184
  // Phase 3 makes validation reactive over observed fields).
9055
9185
  this._recomputeAllValidationErrors(tower.mainForm);
9056
9186
  const settledValue = tower.getFormValueNames();
9187
+ // Value-derived MultipleInputs (those carrying a value-API or calculation)
9188
+ // have their settled value produced by the tower resource, which overrides
9189
+ // the import rows in the tower's value graph. Per import semantics the tower
9190
+ // value is FAVORED, but the import rows must fill any gap it leaves — and a
9191
+ // tower value that resolves to an empty array falls back entirely to the
9192
+ // import rows. Deep-merge (tower favored) so neither the tower's computed
9193
+ // fields nor import-only fields (e.g. user selections) are lost.
9194
+ for (const col of this._valueDerivedMultipleInputs(form)) {
9195
+ const fcn = col.formControlName;
9196
+ if (!fcn)
9197
+ continue;
9198
+ const importVal = resolvedRowData[fcn];
9199
+ if (importVal === undefined)
9200
+ continue;
9201
+ settledValue[fcn] = this._deepMergePreferTower(importVal, settledValue[fcn]);
9202
+ }
9057
9203
  const validationErrors = this._collectValidationErrors(tower);
9058
9204
  const colErrors = { ...this._collectColErrors(tower), ...preColErrors };
9059
9205
  // Partition the settled errors so a row whose only remaining failures are
@@ -9232,8 +9378,16 @@ class TFormImportController {
9232
9378
  }
9233
9379
  const fcn = input.formControlName;
9234
9380
  const rawCandidate = row[fcn];
9235
- const rawItems = Array.isArray(rawCandidate)
9236
- ? rawCandidate
9381
+ // Spreadsheet imports deliver every cell as a primitive, so a MultipleInput
9382
+ // column arrives as a JSON-stringified array (e.g. '[{...},{...}]') — never a
9383
+ // parsed array. Mirror _processSelectInput's tolerance: parse a string
9384
+ // candidate into an array before deciding the field has no rows. A non-array
9385
+ // (empty cell '', plain text) normalizes to [] and is treated as no rows.
9386
+ const normalizedCandidate = typeof rawCandidate === 'string'
9387
+ ? this._tryParseJsonArray(rawCandidate)
9388
+ : rawCandidate;
9389
+ const rawItems = Array.isArray(normalizedCandidate)
9390
+ ? normalizedCandidate
9237
9391
  : [];
9238
9392
  if (rawItems.length === 0) {
9239
9393
  return { errors: [] };
@@ -9245,7 +9399,7 @@ class TFormImportController {
9245
9399
  sectionId: input.sectionId,
9246
9400
  label: '',
9247
9401
  columns: subFormInputs.map(col => ({
9248
- ...col,
9402
+ ...this._localizeSubInputDeps(col, input.id),
9249
9403
  multipleInputInEditId: undefined, // Prevent nested MultipleInputs from trying to edit the same item in the same shared mock form
9250
9404
  })),
9251
9405
  }],
@@ -9254,7 +9408,16 @@ class TFormImportController {
9254
9408
  const processedItems = new Array(rawItems.length);
9255
9409
  const errors = [];
9256
9410
  const overridableErrors = [];
9257
- await Promise.all(rawItems.map(async (item, index) => {
9411
+ // Sub-rows are processed SEQUENTIALLY for the same reason as the top-level
9412
+ // rows in `runImport` — each sub-row spins its own tower whose settle +
9413
+ // projection rely on `ApplicationRef.tick()` flushes over the shared
9414
+ // `ApplicationRef`; concurrent sub-towers interleave those ticks and resolve
9415
+ // `waitUntilSettled` before their derived values drain. The session HTTP
9416
+ // caches still dedupe identical requests across sub-rows.
9417
+ for (let index = 0; index < rawItems.length; index++) {
9418
+ const item = rawItems[index];
9419
+ if (!item)
9420
+ continue;
9258
9421
  // Step 1: resolve raw codes (MSCOA etc.) before the tower sees the data.
9259
9422
  // Pass _depth + 1 so nested MultipleInputs increment the depth guard correctly.
9260
9423
  const { row: resolvedItem, colErrors: preColErrors, overridableColErrors: preOverridable } = hasPreProcessableSubInputs
@@ -9296,13 +9459,75 @@ class TFormImportController {
9296
9459
  finally {
9297
9460
  tower.ngOnDestroy();
9298
9461
  }
9299
- }));
9462
+ }
9300
9463
  return {
9301
9464
  value: processedItems,
9302
9465
  errors,
9303
9466
  overridableErrors,
9304
9467
  };
9305
9468
  }
9469
+ /**
9470
+ * Rewrites a MultipleInput sub-input's cross-field dependency references from
9471
+ * the live form's COMPOUND id scheme back to the SIMPLE id the per-row mock
9472
+ * form uses.
9473
+ *
9474
+ * In the real form, {@link allFormInputs} flattens a MultipleInput's children
9475
+ * and rewrites each child's id to `${multipleInputId}.${childId}`. Every
9476
+ * dependent field's `mapTo.inputId` (value/options-API `minimumInputRequired`)
9477
+ * is authored against that compound id — so `readDep(compoundId)` resolves and
9478
+ * the dependent fetch fires. The mock form built in
9479
+ * {@link TFormImportController._processMultipleFormInput} hoists those children
9480
+ * to top-level columns, so they keep their SIMPLE ids; the baked-in compound
9481
+ * `mapTo.inputId` references then resolve to nothing, `validateMinInput` fails,
9482
+ * the value-API `params` stay `undefined`, and the resource never fetches —
9483
+ * leaving every derived sub-field null (and dropped by `getFormValueNames`).
9484
+ *
9485
+ * Deep-clones `node` (never mutates the shared form definition) and strips the
9486
+ * `${parentId}.` prefix from any `inputId` that targets a sibling in THIS
9487
+ * MultipleInput, so the sub-tower's signal graph resolves dependencies exactly
9488
+ * as the live form does.
9489
+ *
9490
+ * @param node - The sub-input config (or any nested fragment) to rewrite.
9491
+ * @param parentId - The owning MultipleInput's id (the compound prefix).
9492
+ */
9493
+ _localizeSubInputDeps(node, parentId) {
9494
+ const prefix = `${parentId}.`;
9495
+ const walk = (value) => {
9496
+ if (Array.isArray(value))
9497
+ return value.map(walk);
9498
+ if (value && typeof value === 'object') {
9499
+ const out = {};
9500
+ for (const [key, val] of Object.entries(value)) {
9501
+ out[key] = key === 'inputId' && typeof val === 'string' && val.startsWith(prefix)
9502
+ ? val.slice(prefix.length)
9503
+ : walk(val);
9504
+ }
9505
+ return out;
9506
+ }
9507
+ return value;
9508
+ };
9509
+ return walk(node);
9510
+ }
9511
+ /**
9512
+ * Parses a string MultipleInput cell into an array of row objects.
9513
+ *
9514
+ * Spreadsheet cells are primitives, so a MultipleInput column arrives as a
9515
+ * JSON-stringified array. Returns the parsed array on success; returns the
9516
+ * raw value unchanged on failure (empty string, plain text, malformed JSON,
9517
+ * or a non-array JSON value) so the caller's `Array.isArray` check treats it
9518
+ * as "no rows" rather than throwing.
9519
+ */
9520
+ _tryParseJsonArray(raw) {
9521
+ const trimmed = raw.trim();
9522
+ if (!trimmed.startsWith('['))
9523
+ return raw;
9524
+ try {
9525
+ return JSON.parse(trimmed);
9526
+ }
9527
+ catch {
9528
+ return raw;
9529
+ }
9530
+ }
9306
9531
  /**
9307
9532
  * Resolves a single account code to an IScoaAccount.
9308
9533
  * Routed through `_cachedGet` so identical codes across concurrent rows share
@@ -9483,6 +9708,71 @@ class TFormImportController {
9483
9708
  });
9484
9709
  return colErrors;
9485
9710
  }
9711
+ /**
9712
+ * Collects the MultipleInput columns whose value is tower-derived — i.e. they
9713
+ * carry a value-API fetch (`matOptions.fetch.value.source === 'api'`) or a
9714
+ * value-producing calculation. These are the columns whose import rows are
9715
+ * overridden by the tower's own value graph and therefore need the
9716
+ * tower-favored deep merge applied in {@link TFormImportController._processRow}.
9717
+ */
9718
+ _valueDerivedMultipleInputs(form) {
9719
+ return form.slides.flatMap(slide => slide.columns.filter(col => col.element === ElementTypes.MultipleInput && this._isValueDerivedColumn(col)));
9720
+ }
9721
+ /** True iff the column derives its value from a value-API fetch or a calculation. */
9722
+ _isValueDerivedColumn(col) {
9723
+ const valueFetch = col.matOptions?.fetch?.value;
9724
+ const hasApiValue = valueFetch?.source === 'api';
9725
+ let hasCalculation = false;
9726
+ try {
9727
+ hasCalculation = Boolean(validateCalculatedFieldRules(col.calculatedFieldRules)?.value);
9728
+ }
9729
+ catch {
9730
+ hasCalculation = false;
9731
+ }
9732
+ return hasApiValue || hasCalculation;
9733
+ }
9734
+ /**
9735
+ * Deep-merges two values with the **override** (tower-derived) value favored
9736
+ * and the **base** (import) value filling every gap it leaves.
9737
+ *
9738
+ * Rules (mirrors the import-merge contract):
9739
+ * - `override` wins for scalars and for any key it defines.
9740
+ * - Keys present only on `base` are preserved (import fills gaps).
9741
+ * - Arrays merge **element-wise by index** (each element deep-merged), so a
9742
+ * tower row that omits an import-only field keeps that field.
9743
+ * - An **empty** `override` array (or `null`/`undefined`) falls back entirely
9744
+ * to `base` — a tower value that resolves empty never erases the import rows.
9745
+ */
9746
+ _deepMergePreferTower(base, override) {
9747
+ if (override === undefined || override === null)
9748
+ return base;
9749
+ if (base === undefined || base === null)
9750
+ return override;
9751
+ if (Array.isArray(override) || Array.isArray(base)) {
9752
+ // Empty/absent override array → import covers the value.
9753
+ if (!Array.isArray(override) || override.length === 0)
9754
+ return base;
9755
+ if (!Array.isArray(base))
9756
+ return override;
9757
+ const length = Math.max(base.length, override.length);
9758
+ const out = [];
9759
+ for (let i = 0; i < length; i++) {
9760
+ out[i] = this._deepMergePreferTower(base[i], override[i]);
9761
+ }
9762
+ return out;
9763
+ }
9764
+ if (typeof override === 'object' && typeof base === 'object') {
9765
+ const b = base;
9766
+ const o = override;
9767
+ const out = { ...b };
9768
+ for (const key of Object.keys(o)) {
9769
+ out[key] = this._deepMergePreferTower(b[key], o[key]);
9770
+ }
9771
+ return out;
9772
+ }
9773
+ // Scalars / mismatched shapes: tower value is favored.
9774
+ return override;
9775
+ }
9486
9776
  /**
9487
9777
  * Immutable row update — clones the rows array and the targeted row before
9488
9778
  * pushing through `_rows$` so subscribers downstream of `progress$` always
@@ -10652,16 +10942,21 @@ const elementBlurFn = (form, inputId, event, element) => {
10652
10942
  }
10653
10943
  };
10654
10944
 
10655
- function addScoaExtensionInput(form, sectionId, scoaInputId) {
10945
+ function addScoaExtensionInput(form, sectionId, scoaInputId, linkedSegmentId, inputId) {
10656
10946
  try {
10657
10947
  if (!form || !sectionId || !scoaInputId) {
10658
10948
  throw new Error('Form, sectionId and scoaExtensionInputInEditId are required');
10659
10949
  }
10660
10950
  // ScoaInnerInput is the actual element type stored in `mscoaConfig.inputs`.
10661
10951
  // A stubbed extension entry carries only id + sectionId until the user fills it.
10952
+ // When `linkedSegmentId` is supplied the input is pre-attached to that segment
10953
+ // (its value projects into the segment's bag — see the mscoa chart projection).
10954
+ // `inputId` lets the caller pre-allocate the id so it can open the new input
10955
+ // in the editor right after adding it.
10662
10956
  const newInput = {
10663
- id: v4(),
10957
+ id: inputId ?? v4(),
10664
10958
  sectionId,
10959
+ ...(linkedSegmentId ? { linkedSegmentId } : {}),
10665
10960
  };
10666
10961
  return {
10667
10962
  ...form,
@@ -10852,8 +11147,58 @@ function formBuilderStoreActions(store) {
10852
11147
  const form = store.formInEditSnapshot();
10853
11148
  if (!form)
10854
11149
  return;
10855
- const newForm = addScoaExtensionInput(form.form, sectionId, scoaInputId);
11150
+ // A custom input is an account-level input (a peer of the SCOA segments). It
11151
+ // starts as an unconfigured stub, so open it in the editor right away for the
11152
+ // builder to set its type/label — otherwise it renders nothing in the chart.
11153
+ const newInputId = v4();
11154
+ const newForm = addScoaExtensionInput(form.form, sectionId, scoaInputId, undefined, newInputId);
10856
11155
  applyForm(newForm);
11156
+ store.actions.setInputInEditId({ inputInEdit: newInputId });
11157
+ };
11158
+ /**
11159
+ * Creates or updates a standalone SCOA custom input from the segment-config
11160
+ * quick editor. On create (or when the element type changes) the element
11161
+ * template is applied so the input has all required fields; then the editor
11162
+ * fields (label, control name, single-value-selection, read-only) are merged.
11163
+ */
11164
+ const saveScoaCustomInput = (sectionId, scoaInputId, config) => {
11165
+ const form = store.formInEditSnapshot();
11166
+ if (!form)
11167
+ return;
11168
+ const inputId = config.id ?? v4();
11169
+ const existing = config.id ? returnAnyFormInputFromForm(form.form, inputId) : undefined;
11170
+ let nextForm = form.form;
11171
+ if (!config.id) {
11172
+ nextForm = addScoaExtensionInput(nextForm, sectionId, scoaInputId, undefined, inputId);
11173
+ }
11174
+ if (!existing || existing.element !== config.element) {
11175
+ nextForm = selectInputTemplateFn(nextForm, inputId, config.element);
11176
+ }
11177
+ nextForm = {
11178
+ ...nextForm,
11179
+ slides: nextForm.slides.map((slide) => ({
11180
+ ...slide,
11181
+ columns: slide.columns.map((column) => {
11182
+ if (column.element !== ElementTypes.MscoaSelection)
11183
+ return column;
11184
+ return {
11185
+ ...column,
11186
+ mscoaConfig: {
11187
+ ...column.mscoaConfig,
11188
+ inputs: (column.mscoaConfig.inputs || []).map((input) => input.id === inputId
11189
+ ? deepMerge(input, {
11190
+ label: config.label,
11191
+ formControlName: config.formControlName,
11192
+ singleSelect: config.singleSelect,
11193
+ readonly: config.readonly,
11194
+ })
11195
+ : input),
11196
+ },
11197
+ };
11198
+ }),
11199
+ })),
11200
+ };
11201
+ applyForm(nextForm);
10857
11202
  };
10858
11203
  const applyFormTemplate = (form) => {
10859
11204
  if (!form)
@@ -11017,6 +11362,7 @@ function formBuilderStoreActions(store) {
11017
11362
  addMultipleFormInput,
11018
11363
  clearInputInEdit,
11019
11364
  addInputToScoaSelection,
11365
+ saveScoaCustomInput,
11020
11366
  };
11021
11367
  }
11022
11368
 
@@ -11416,10 +11762,17 @@ function setSegmentValues(state, segmentValues) {
11416
11762
  const accountTreeKeys = ((state.accountTreeKeys && state.accountTreeKeys.length > 0)
11417
11763
  ? state.accountTreeKeys
11418
11764
  : (state.segments?.map(s => s.segment) || []));
11765
+ // Standalone custom-input values live as peer keys in each basis bag (written
11766
+ // by `setCustomInputValue`, preserved by `auditStateValues`). They are NOT
11767
+ // segments, so `mapSegments` must carry them through unchanged — otherwise the
11768
+ // down-path strips a key the up-path keeps, the `_isEqual` guard below never
11769
+ // holds, and the form ⇄ store ⇄ form graph oscillates (re-firing the debounced
11770
+ // MSCOA validation API on every lap).
11771
+ const customInputKeys = new Set((state.inputs || []).filter((input) => !input.linkedSegmentId).map((input) => input.formControlName));
11419
11772
  const mapSegments = (source) => {
11420
11773
  if (!source || !accountTreeKeys)
11421
11774
  return {};
11422
- return accountTreeKeys.reduce((acc, key) => {
11775
+ const mapped = accountTreeKeys.reduce((acc, key) => {
11423
11776
  // Matches 'costing' -> 'COSTING' from your log
11424
11777
  const upperKey = key.toUpperCase();
11425
11778
  const v = source[upperKey] ?? source[key];
@@ -11427,6 +11780,13 @@ function setSegmentValues(state, segmentValues) {
11427
11780
  acc[key] = v;
11428
11781
  return acc;
11429
11782
  }, {});
11783
+ // Preserve standalone custom-input peer values (mirrors auditStateValues).
11784
+ for (const customKey of customInputKeys) {
11785
+ if (customKey && source[customKey] !== undefined) {
11786
+ mapped[customKey] = source[customKey];
11787
+ }
11788
+ }
11789
+ return mapped;
11430
11790
  };
11431
11791
  // 5. Generate Values
11432
11792
  const accrualValue = mapSegments(rawAccrual);
@@ -11498,11 +11858,80 @@ function setSegmentAccount(state, { segment, account, accountType, isCash }) {
11498
11858
  }
11499
11859
  };
11500
11860
  }
11861
+ /**
11862
+ * Writes one **segment-scoped** custom-input value into the segment bag as a
11863
+ * sibling of `debit`/`credit` (e.g. `REGIONAL.budgetValue`, `REGIONAL.DEPARTMENT`).
11864
+ *
11865
+ * The `value` is the custom input's `FormControl` value, projected here so it
11866
+ * lands *inside* the account value object (and thus flows into extracts, the
11867
+ * audit pass, and validation). v1 is segment-scoped: one value per segment, not
11868
+ * per leg. Keying matches {@link setSegmentAccount} (both upper-case the segment
11869
+ * key) so the custom value shares the SAME bag as the debit/credit accounts.
11870
+ */
11871
+ function setSegmentInput(state, { segmentKey, customKey, value, isCash }) {
11872
+ const basisKey = isCash ? 'cash' : 'accrual';
11873
+ const upperSegmentKey = segmentKey.toUpperCase();
11874
+ const currentBasisGroup = state.segmentValues?.[basisKey] || {};
11875
+ const oldSegmentData = currentBasisGroup[upperSegmentKey] || {
11876
+ debit: undefined,
11877
+ credit: undefined,
11878
+ };
11879
+ // Set the custom key, or omit it entirely when the input is cleared.
11880
+ const newSegmentData = { ...oldSegmentData };
11881
+ if (value === undefined) {
11882
+ delete newSegmentData[customKey];
11883
+ }
11884
+ else {
11885
+ newSegmentData[customKey] = value;
11886
+ }
11887
+ const newSegmentValues = {
11888
+ ...state.segmentValues,
11889
+ [basisKey]: {
11890
+ ...currentBasisGroup,
11891
+ [upperSegmentKey]: newSegmentData,
11892
+ },
11893
+ };
11894
+ // Idempotency guard (see setSegmentValues / setSegmentAccount): a no-op write
11895
+ // returns the SAME reference so the signal does not emit and the
11896
+ // form ⇄ store ⇄ form graph settles in a single pass instead of oscillating.
11897
+ if (_isEqual(newSegmentValues, state.segmentValues))
11898
+ return state;
11899
+ return { ...state, segmentValues: newSegmentValues };
11900
+ }
11901
+ /** Legs a custom-input value mirrors across under single-value selection. */
11902
+ const CUSTOM_INPUT_LEGS = ['debit', 'credit'];
11903
+ /**
11904
+ * Projects a **standalone (account-level) custom input's** value into the account
11905
+ * value object as a peer of the segments, keyed by its `formControlName`, mirrored
11906
+ * across debit/credit (single value selection). The scalar leg values are written
11907
+ * through the bag's string index signature so they stay type-legal without
11908
+ * weakening the account-bag type. Per-leg distinct entry is a later refinement.
11909
+ */
11910
+ function setCustomInputValue(state, { inputKey, value, isCash }) {
11911
+ if (!inputKey)
11912
+ return state;
11913
+ const basisKey = isCash ? 'cash' : 'accrual';
11914
+ const currentBasisGroup = state.segmentValues?.[basisKey] || {};
11915
+ const bag = {};
11916
+ for (const leg of CUSTOM_INPUT_LEGS) {
11917
+ bag[leg] = value;
11918
+ }
11919
+ const newSegmentValues = {
11920
+ ...state.segmentValues,
11921
+ [basisKey]: { ...currentBasisGroup, [inputKey]: bag },
11922
+ };
11923
+ if (_isEqual(newSegmentValues, state.segmentValues))
11924
+ return state;
11925
+ return { ...state, segmentValues: newSegmentValues };
11926
+ }
11501
11927
  /** Recomputes VAT + cash-from-accrual inheritance across all segment values. */
11502
11928
  function auditStateValues(state) {
11503
11929
  // 1. Safe access to state data
11504
11930
  const { cash = {}, accrual = {} } = state.segmentValues || {};
11505
11931
  const cashSegmentConfigs = state.cashSegments || [];
11932
+ // Standalone custom-input values live as peer keys in `segmentValues`; they are
11933
+ // NOT segments, so the VAT/inheritance passes below must leave them untouched.
11934
+ const customInputKeys = new Set((state.inputs || []).filter((input) => !input.linkedSegmentId).map((input) => input.formControlName));
11506
11935
  // 2. Pre-calculate "Has VAT Applicable" flags for both bases
11507
11936
  // (Checks if any segment in the group has a 'vatApplicableTo' flag set)
11508
11937
  const hasVatApplicableTo = (val) => val?.vatApplicableTo !== undefined;
@@ -11542,6 +11971,11 @@ function auditStateValues(state) {
11542
11971
  }, {});
11543
11972
  // 5. Process Accrual First (Source of Truth)
11544
11973
  const newAccrual = Object.entries(accrual).reduce((acc, [key, data]) => {
11974
+ // Custom-input peer values pass through untouched (not segments → no VAT).
11975
+ if (customInputKeys.has(key)) {
11976
+ acc[key] = data;
11977
+ return acc;
11978
+ }
11545
11979
  const record = data;
11546
11980
  acc[key] = {
11547
11981
  ...record,
@@ -11551,6 +11985,11 @@ function auditStateValues(state) {
11551
11985
  }, {});
11552
11986
  // 6. Process Cash (With Inheritance)
11553
11987
  const newCash = Object.entries(cash).reduce((acc, [key, data]) => {
11988
+ // Custom-input peer values pass through untouched (no VAT / inheritance).
11989
+ if (customInputKeys.has(key)) {
11990
+ acc[key] = data;
11991
+ return acc;
11992
+ }
11554
11993
  const record = data;
11555
11994
  const shouldInherit = inheritMap[key];
11556
11995
  // A. Determine the Source Data
@@ -11558,13 +11997,26 @@ function auditStateValues(state) {
11558
11997
  // Otherwise, use the existing Cash data.
11559
11998
  let workingData = record;
11560
11999
  if (shouldInherit && newAccrual[key]) {
11561
- workingData = {
12000
+ const accrualRecord = newAccrual[key];
12001
+ const inherited = {
11562
12002
  ...workingData, // Keep existing cash props (like ID, etc) if needed
11563
- debit: newAccrual[key].debit,
11564
- credit: newAccrual[key].credit,
12003
+ debit: accrualRecord.debit,
12004
+ credit: accrualRecord.credit,
11565
12005
  // Note: We do NOT inherit 'vatApplicableTo' or 'vat' blindly,
11566
12006
  // because Cash might have its own VAT context. We recalculate VAT below.
11567
12007
  };
12008
+ // Carry over the accrual segment's custom-input values (segment-scoped
12009
+ // siblings of debit/credit) so an inheriting cash segment mirrors them.
12010
+ // Reserved keys are recomputed for cash, so they are skipped here.
12011
+ for (const [customKey, customValue] of Object.entries(accrualRecord)) {
12012
+ if (customKey !== 'debit' &&
12013
+ customKey !== 'credit' &&
12014
+ customKey !== 'vat' &&
12015
+ customKey !== 'vatApplicableTo') {
12016
+ inherited[customKey] = customValue;
12017
+ }
12018
+ }
12019
+ workingData = inherited;
11568
12020
  }
11569
12021
  // B. Apply Cash-Specific VAT Logic
11570
12022
  acc[key] = {
@@ -11749,6 +12201,21 @@ class MscoaComponentStore {
11749
12201
  setSegmentAccount(payload) {
11750
12202
  this.#state.update((state) => setSegmentAccount(state, payload));
11751
12203
  }
12204
+ /**
12205
+ * Projects a segment-scoped custom-input value into the account value object
12206
+ * as a sibling of debit/credit. Called from the chart when a linked custom
12207
+ * input's `FormControl` value changes (see {@link reducers.setSegmentInput}).
12208
+ */
12209
+ setSegmentInput(payload) {
12210
+ this.#state.update((state) => setSegmentInput(state, payload));
12211
+ }
12212
+ /**
12213
+ * Projects a standalone (account-level) custom input's value into the account
12214
+ * value object as a peer of the segments (see {@link reducers.setCustomInputValue}).
12215
+ */
12216
+ setCustomInputValue(payload) {
12217
+ this.#state.update((state) => setCustomInputValue(state, payload));
12218
+ }
11752
12219
  /** Records the active segment. */
11753
12220
  setActiveSegment(activeSegment) {
11754
12221
  this.#state.update((state) => setActiveSegment(state, activeSegment));
@@ -12388,9 +12855,9 @@ class FormBuilderComponent {
12388
12855
  this.#store.actionsFormBuilder.setFormTitle(value);
12389
12856
  }
12390
12857
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: FormBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12391
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormBuilderComponent, isStandalone: true, selector: "lib-form-builder, app-form-builder", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [FormsStoreService], ngImport: i0, template: "<header style=\"position:fixed;width:100%;left:0px;top:0px\">\r\n <mat-toolbar color=\"primary\">\r\n @if (closeButton) {\r\n <button mat-icon-button [style.color]=\"closeButton.color\" (click)=\"closeButton.onClick()\">\r\n <mat-icon>{{closeButton.icon}}</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- Navigation group -->\r\n <div class=\"nav-group\">\r\n <button mat-button routerLink=\"/\">Forms</button>\r\n <mat-icon>navigate_next</mat-icon>\r\n </div>\r\n\r\n <!-- Title input with optimized binding -->\r\n @if (selectHasFormId()) {\r\n <input [ngModel]=\"titleValue()\" (ngModelChange)=\"setTitleValue($event)\" class=\"section-title-input\" placeholder=\"Enter Form Title\">\r\n }\r\n\r\n <span class=\"spacer\"></span>\r\n\r\n @defer (on viewport) {\r\n <lib-forms-builder-menu />\r\n } @placeholder {\r\n <div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"20\" />\r\n </div>\r\n\r\n }\r\n\r\n <span class=\"divider\">|</span>\r\n\r\n <!-- Persist to server: visible once local preview is in sync -->\r\n @if (!pendingExternalRefresh()) {\r\n <button mat-raised-button color=\"accent\" class=\"save-button\" [disabled]=\"!(canSaveForm())\" (click)=\"saveForm()\">\r\n <mat-icon style=\"width: 24px;\">cloud_upload</mat-icon>\r\n @if (selectFormBuilderIsBusy()) {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Creating form...' : 'Saving changes...'}}</span>\r\n </span>\r\n } @else {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Save New Form' : 'Save Changes'}}</span>\r\n @if (canSaveForm()) {\r\n <span class=\"save-sub\">Not saved to server yet</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Local sync: applies your changes to the builder preview \u00B7 does NOT save to server -->\r\n @if (pendingExternalRefresh()) {\r\n <button class=\"refresh-button\" matRipple matRippleColor=\"rgba(255,255,255,0.12)\" (click)=\"triggerRefreshNow()\">\r\n <span class=\"countdown-ring\">\r\n <mat-progress-spinner\r\n diameter=\"34\"\r\n mode=\"determinate\"\r\n [value]=\"refreshCountdown() * 20\">\r\n </mat-progress-spinner>\r\n <span class=\"countdown-number\">{{refreshCountdown()}}</span>\r\n </span>\r\n <span class=\"refresh-text\">\r\n <span class=\"refresh-label\">Apply Now</span>\r\n <span class=\"refresh-sub\">Preview updates in {{refreshCountdown()}}s</span>\r\n </span>\r\n <mat-icon class=\"refresh-chevron\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n\r\n </mat-toolbar>\r\n</header>\r\n\r\n<!-- Main content with optimized loading -->\r\n@defer (on viewport) {\r\n<div class=\"container\">\r\n <div class=\"middle\">\r\n <br>\r\n @if (selectLoadingForm()) {\r\n <div class=\"loading-container\">\r\n <mat-spinner />\r\n </div>\r\n } @else {\r\n <lib-form-section-stepper />\r\n }\r\n <br>\r\n @if ((hasMissingConfigs()) && !(selectLoadingForm())) {\r\n <lib-missing-form-configs />\r\n }\r\n <!-- Updated time info -->\r\n @if (!(isNewForm())) {\r\n <div class=\"updated-time\">\r\n <mat-icon>update</mat-icon>\r\n <span>Updated {{ selectFormUpdated() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (elementEditorOpen()) {\r\n <lib-input-editor style=\"max-width:480px;height:calc(100vh - 76px);\r\n position:sticky;\r\n top:76px;\r\n z-index:1\" cdkDrag cdkDragBoundary=\"container\" class=\"middle editor-container\" />\r\n }\r\n <!-- Missing fields section -->`\r\n\r\n\r\n</div>\r\n}@placeholder {\r\n<div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"50\" />\r\n</div>\r\n}", styles: [".container{display:flex;width:100%;height:calc(100% - 64px);padding-top:4em}.side{width:100px;background-color:var(--sem-error-surface)}.middle{flex-grow:1;height:calc(100vh - 68px);overflow:auto;background-color:none}.section-title-input{border:none;background-color:transparent;font-size:.8575em;font-weight:600;color:var(--lib-forms-on-primary);padding-top:12px;padding-bottom:12px;outline:none;width:100%;min-width:268px;transition:border-bottom-color .3s ease-in-out}.section-title-input:focus{border-bottom:1px solid var(--lib-forms-on-primary)}.missing-fields{position:fixed;bottom:0}.updated-time{display:flex;color:var(--mat-sidenav-content-text-color, var(--mat-sys-on-background));gap:8px;align-items:center;line-height:normal;font-size:.875em;bottom:0;position:absolute;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:8px;border-radius:4px}.nav-group{display:flex;align-items:center;gap:8px}.save-button{margin-left:8px;min-width:168px;height:44px}.save-button .save-text{display:flex;flex-direction:column;align-items:flex-start;gap:2px}.save-button .save-text .save-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap}.save-button .save-text .save-sub{font-size:10px;line-height:1;opacity:.78;white-space:nowrap}.refresh-button{margin-left:8px;background:var(--mat-fab-small-container-color, var(--mat-sys-tertiary-container));color:var(--mat-sys-on-tertiary-container);border:1.5px solid var(--mat-sys-outline-variant);border-radius:10px;padding:4px 14px 4px 6px;cursor:pointer;display:inline-flex;align-items:center;gap:12px;height:44px;width:fit-content;box-shadow:0 2px 12px color-mix(in srgb,var(--lib-forms-shadow-color) 18%,transparent);transition:box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);outline:none;overflow:hidden;position:relative}.refresh-button:hover{box-shadow:0 4px 20px color-mix(in srgb,var(--lib-forms-shadow-color) 28%,transparent);transform:translateY(-1px)}.refresh-button:active{transform:translateY(0);box-shadow:0 1px 6px color-mix(in srgb,var(--lib-forms-shadow-color) 12%,transparent)}.refresh-button .countdown-ring{position:relative;width:34px;height:34px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.refresh-button .countdown-ring mat-progress-spinner{position:absolute;inset:0;--mdc-circular-progress-active-indicator-color: var(--mat-sys-on-tertiary-container);--mdc-circular-progress-track-color: color-mix(in srgb, var(--mat-sys-on-tertiary-container) 18%, transparent)}.refresh-button .countdown-ring .countdown-number{font-size:11px;font-weight:600;line-height:1;z-index:1;letter-spacing:-.3px;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text{display:flex;flex-direction:column;align-items:flex-start;gap:3px}.refresh-button .refresh-text .refresh-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text .refresh-sub{font-size:10px;line-height:1;opacity:.68;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-chevron{font-size:18px;width:18px;height:18px;opacity:.65;flex-shrink:0;color:var(--mat-sys-on-tertiary-container)}.loading-container{display:flex;height:calc(100% - 150px);justify-content:center;align-items:center}.editor-container{max-width:500px}.divider{margin:0 8px;opacity:.5}app-missing-form-configs{position:absolute;bottom:0;right:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i5.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i7.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i7$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs').then(m => m.FormsBuilderMenuComponent)], () => [i3$1.MatIcon, i3$2.MatProgressSpinner, i1$3.CdkDrag, import('./ngx-t-forms-input-editor.component-BPUOM9kQ.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs').then(m => m.MissingFormConfigsComponent)]] }); }
12858
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: FormBuilderComponent, isStandalone: true, selector: "lib-form-builder, app-form-builder", inputs: { formId: { classPropertyName: "formId", publicName: "formId", isSignal: true, isRequired: false, transformFunction: null } }, providers: [FormsStoreService], ngImport: i0, template: "<header style=\"position:fixed;width:100%;left:0px;top:0px\">\r\n <mat-toolbar color=\"primary\">\r\n @if (closeButton) {\r\n <button mat-icon-button [style.color]=\"closeButton.color\" (click)=\"closeButton.onClick()\">\r\n <mat-icon>{{closeButton.icon}}</mat-icon>\r\n </button>\r\n }\r\n\r\n <!-- Navigation group -->\r\n <div class=\"nav-group\">\r\n <button mat-button routerLink=\"/\">Forms</button>\r\n <mat-icon>navigate_next</mat-icon>\r\n </div>\r\n\r\n <!-- Title input with optimized binding -->\r\n @if (selectHasFormId()) {\r\n <input [ngModel]=\"titleValue()\" (ngModelChange)=\"setTitleValue($event)\" class=\"section-title-input\" placeholder=\"Enter Form Title\">\r\n }\r\n\r\n <span class=\"spacer\"></span>\r\n\r\n @defer (on viewport) {\r\n <lib-forms-builder-menu />\r\n } @placeholder {\r\n <div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"20\" />\r\n </div>\r\n\r\n }\r\n\r\n <span class=\"divider\">|</span>\r\n\r\n <!-- Persist to server: visible once local preview is in sync -->\r\n @if (!pendingExternalRefresh()) {\r\n <button mat-raised-button color=\"accent\" class=\"save-button\" [disabled]=\"!(canSaveForm())\" (click)=\"saveForm()\">\r\n <mat-icon style=\"width: 24px;\">cloud_upload</mat-icon>\r\n @if (selectFormBuilderIsBusy()) {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Creating form...' : 'Saving changes...'}}</span>\r\n </span>\r\n } @else {\r\n <span class=\"save-text\">\r\n <span class=\"save-label\">{{(isNewForm()) ? 'Save New Form' : 'Save Changes'}}</span>\r\n @if (canSaveForm()) {\r\n <span class=\"save-sub\">Not saved to server yet</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Local sync: applies your changes to the builder preview \u00B7 does NOT save to server -->\r\n @if (pendingExternalRefresh()) {\r\n <button class=\"refresh-button\" matRipple matRippleColor=\"rgba(255,255,255,0.12)\" (click)=\"triggerRefreshNow()\">\r\n <span class=\"countdown-ring\">\r\n <mat-progress-spinner\r\n diameter=\"34\"\r\n mode=\"determinate\"\r\n [value]=\"refreshCountdown() * 20\">\r\n </mat-progress-spinner>\r\n <span class=\"countdown-number\">{{refreshCountdown()}}</span>\r\n </span>\r\n <span class=\"refresh-text\">\r\n <span class=\"refresh-label\">Apply Now</span>\r\n <span class=\"refresh-sub\">Preview updates in {{refreshCountdown()}}s</span>\r\n </span>\r\n <mat-icon class=\"refresh-chevron\">chevron_right</mat-icon>\r\n </button>\r\n }\r\n\r\n </mat-toolbar>\r\n</header>\r\n\r\n<!-- Main content with optimized loading -->\r\n@defer (on viewport) {\r\n<div class=\"container\">\r\n <div class=\"middle\">\r\n <br>\r\n @if (selectLoadingForm()) {\r\n <div class=\"loading-container\">\r\n <mat-spinner />\r\n </div>\r\n } @else {\r\n <lib-form-section-stepper />\r\n }\r\n <br>\r\n @if ((hasMissingConfigs()) && !(selectLoadingForm())) {\r\n <lib-missing-form-configs />\r\n }\r\n <!-- Updated time info -->\r\n @if (!(isNewForm())) {\r\n <div class=\"updated-time\">\r\n <mat-icon>update</mat-icon>\r\n <span>Updated {{ selectFormUpdated() }}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (elementEditorOpen()) {\r\n <lib-input-editor style=\"max-width:480px;height:calc(100vh - 76px);\r\n position:sticky;\r\n top:76px;\r\n z-index:1\" cdkDrag cdkDragBoundary=\"container\" class=\"middle editor-container\" />\r\n }\r\n <!-- Missing fields section -->`\r\n\r\n\r\n</div>\r\n}@placeholder {\r\n<div style=\"padding: 50px;display:flex;justify-content:center;align-items:center; text-align: center;\">\r\n <mat-spinner diameter=\"50\" />\r\n</div>\r\n}", styles: [".container{display:flex;width:100%;height:calc(100% - 64px);padding-top:4em}.side{width:100px;background-color:var(--sem-error-surface)}.middle{flex-grow:1;height:calc(100vh - 68px);overflow:auto;background-color:none}.section-title-input{border:none;background-color:transparent;font-size:.8575em;font-weight:600;color:var(--lib-forms-on-primary);padding-top:12px;padding-bottom:12px;outline:none;width:100%;min-width:268px;transition:border-bottom-color .3s ease-in-out}.section-title-input:focus{border-bottom:1px solid var(--lib-forms-on-primary)}.missing-fields{position:fixed;bottom:0}.updated-time{display:flex;color:var(--mat-sidenav-content-text-color, var(--mat-sys-on-background));gap:8px;align-items:center;line-height:normal;font-size:.875em;bottom:0;position:absolute;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);padding:8px;border-radius:4px}.nav-group{display:flex;align-items:center;gap:8px}.save-button{margin-left:8px;min-width:168px;height:44px}.save-button .save-text{display:flex;flex-direction:column;align-items:flex-start;gap:2px}.save-button .save-text .save-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap}.save-button .save-text .save-sub{font-size:10px;line-height:1;opacity:.78;white-space:nowrap}.refresh-button{margin-left:8px;background:var(--mat-fab-small-container-color, var(--mat-sys-tertiary-container));color:var(--mat-sys-on-tertiary-container);border:1.5px solid var(--mat-sys-outline-variant);border-radius:10px;padding:4px 14px 4px 6px;cursor:pointer;display:inline-flex;align-items:center;gap:12px;height:44px;width:fit-content;box-shadow:0 2px 12px color-mix(in srgb,var(--lib-forms-shadow-color) 18%,transparent);transition:box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);outline:none;overflow:hidden;position:relative}.refresh-button:hover{box-shadow:0 4px 20px color-mix(in srgb,var(--lib-forms-shadow-color) 28%,transparent);transform:translateY(-1px)}.refresh-button:active{transform:translateY(0);box-shadow:0 1px 6px color-mix(in srgb,var(--lib-forms-shadow-color) 12%,transparent)}.refresh-button .countdown-ring{position:relative;width:34px;height:34px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.refresh-button .countdown-ring mat-progress-spinner{position:absolute;inset:0;--mdc-circular-progress-active-indicator-color: var(--mat-sys-on-tertiary-container);--mdc-circular-progress-track-color: color-mix(in srgb, var(--mat-sys-on-tertiary-container) 18%, transparent)}.refresh-button .countdown-ring .countdown-number{font-size:11px;font-weight:600;line-height:1;z-index:1;letter-spacing:-.3px;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text{display:flex;flex-direction:column;align-items:flex-start;gap:3px}.refresh-button .refresh-text .refresh-label{font-size:13px;font-weight:600;line-height:1;letter-spacing:.01em;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-text .refresh-sub{font-size:10px;line-height:1;opacity:.68;white-space:nowrap;color:var(--mat-sys-on-tertiary-container)}.refresh-button .refresh-chevron{font-size:18px;width:18px;height:18px;opacity:.65;flex-shrink:0;color:var(--mat-sys-on-tertiary-container)}.loading-container{display:flex;height:calc(100% - 150px);justify-content:center;align-items:center}.editor-container{max-width:500px}.divider{margin:0 8px;opacity:.5}app-missing-form-configs{position:absolute;bottom:0;right:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i5.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i7.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i7$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs').then(m => m.FormsBuilderMenuComponent)], () => [i3$1.MatIcon, i3$2.MatProgressSpinner, i1$3.CdkDrag, import('./ngx-t-forms-input-editor.component-DLru1Ezu.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs').then(m => m.MissingFormConfigsComponent)]] }); }
12392
12859
  }
12393
- i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: FormBuilderComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-forms-builder-menu.component-qrhM0jGL.mjs').then(m => m.FormsBuilderMenuComponent), import('./ngx-t-forms-input-editor.component-BPUOM9kQ.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-Bs50-nEB.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DrnH8qdG.mjs').then(m => m.MissingFormConfigsComponent)], resolveMetadata: (FormsBuilderMenuComponent, InputEditorComponent, FormSectionStepperComponent, MissingFormConfigsComponent) => ({ decorators: [{
12860
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: FormBuilderComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-forms-builder-menu.component-Dv0Dfw79.mjs').then(m => m.FormsBuilderMenuComponent), import('./ngx-t-forms-input-editor.component-DLru1Ezu.mjs').then(m => m.InputEditorComponent), import('./ngx-t-forms-form-section-stepper.component-BPgPfZSy.mjs').then(m => m.FormSectionStepperComponent), import('./ngx-t-forms-missing-form-configs.component-DxdynZY6.mjs').then(m => m.MissingFormConfigsComponent)], resolveMetadata: (FormsBuilderMenuComponent, InputEditorComponent, FormSectionStepperComponent, MissingFormConfigsComponent) => ({ decorators: [{
12394
12861
  type: Component,
12395
12862
  args: [{ selector: 'lib-form-builder, app-form-builder', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
12396
12863
  CommonModule,
@@ -12926,6 +13393,16 @@ class TDynamicDataEditComponent {
12926
13393
  this.data = input(undefined, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
12927
13394
  /** Validation errors surfaced by the parent for display. */
12928
13395
  this.validationErrors = input(null, ...(ngDevMode ? [{ debugName: "validationErrors" }] : /* istanbul ignore next */ []));
13396
+ /**
13397
+ * Builder-only: creates or updates an account-level MSCOA custom input (a peer
13398
+ * of the segments) from the segment-config quick editor. Forwarded to that
13399
+ * editor; absent outside the form builder, which hides the related affordance.
13400
+ */
13401
+ this.mscoaSaveCustomInput = input(undefined, ...(ngDevMode ? [{ debugName: "mscoaSaveCustomInput" }] : /* istanbul ignore next */ []));
13402
+ /** Builder-only: opens an MSCOA custom input in the input editor for advanced configuration. */
13403
+ this.mscoaEditInput = input(undefined, ...(ngDevMode ? [{ debugName: "mscoaEditInput" }] : /* istanbul ignore next */ []));
13404
+ /** Builder-only: removes an MSCOA custom input from the config. */
13405
+ this.mscoaDeleteInput = input(undefined, ...(ngDevMode ? [{ debugName: "mscoaDeleteInput" }] : /* istanbul ignore next */ []));
12929
13406
  /** Fires when the edited value changes (debounced). */
12930
13407
  this.valueChange = output();
12931
13408
  /** Fires when an inner editor loses focus (used for expression-style editors). */
@@ -13183,9 +13660,9 @@ class TDynamicDataEditComponent {
13183
13660
  }
13184
13661
  }
13185
13662
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: TDynamicDataEditComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
13186
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TDynamicDataEditComponent, isStandalone: true, selector: "lib-t-dynamic-data-edit", inputs: { editorConfig: { classPropertyName: "editorConfig", publicName: "editorConfig", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, validationErrors: { classPropertyName: "validationErrors", publicName: "validationErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur" }, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], ngImport: i0, template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$3.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-oGjQVGE2.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs').then(m => m.MatChipListEditorComponent), i2.MatFormField, i2.MatLabel, i2.MatError, i2.MatSuffix, i8.MatSelect, i8.MatOption, i1$2.MatIconButton, i3$1.MatIcon, i5$1.MatTooltip, import('./ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CUMMvMch.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-BkbHFAyR.mjs').then(m => m.InputCustomComponent), i1$1.NgControlStatus, i1$1.RequiredValidator, i1$1.NgModel, import('./ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)]] }); }
13663
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: TDynamicDataEditComponent, isStandalone: true, selector: "lib-t-dynamic-data-edit", inputs: { editorConfig: { classPropertyName: "editorConfig", publicName: "editorConfig", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, validationErrors: { classPropertyName: "validationErrors", publicName: "validationErrors", isSignal: true, isRequired: false, transformFunction: null }, mscoaSaveCustomInput: { classPropertyName: "mscoaSaveCustomInput", publicName: "mscoaSaveCustomInput", isSignal: true, isRequired: false, transformFunction: null }, mscoaEditInput: { classPropertyName: "mscoaEditInput", publicName: "mscoaEditInput", isSignal: true, isRequired: false, transformFunction: null }, mscoaDeleteInput: { classPropertyName: "mscoaDeleteInput", publicName: "mscoaDeleteInput", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange", blur: "blur" }, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], ngImport: i0, template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [saveCustomInput]=\"mscoaSaveCustomInput()\"\n [editSegmentInput]=\"mscoaEditInput()\"\n [deleteSegmentInput]=\"mscoaDeleteInput()\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3$3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3$3.MatCardContent, selector: "mat-card-content" }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [import('./ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-B42xP3jh.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-ONbhxVSH.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-BknyAmV_.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs').then(m => m.MatChipListEditorComponent), i2.MatFormField, i2.MatLabel, i2.MatError, i2.MatSuffix, i8.MatSelect, i8.MatOption, i1$2.MatIconButton, i3$1.MatIcon, i5$1.MatTooltip, import('./ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CykBq_nW.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs').then(m => m.InputCustomComponent), i1$1.NgControlStatus, i1$1.RequiredValidator, i1$1.NgModel, import('./ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)]] }); }
13187
13664
  }
13188
- i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: TDynamicDataEditComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-selection-options-editor.component-Dhln81DL.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-C9u8zq9B.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-C_aFtdvW.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-Ch2yNcIS.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-DmNSc5aw.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-C5TPddVe.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-oGjQVGE2.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-CzisLSIP.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-C0qsMfsq.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-c7uZT1sr.mjs').then(m => m.MatChipListEditorComponent), import('./ngx-t-forms-chip-options-creator-editor.component-CICQaqz6.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Dzz_o6fJ.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CLUOXreG.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-leBokXvM.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-BQL0AH7H.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CUMMvMch.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-CDkTuX9S.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-BkbHFAyR.mjs').then(m => m.InputCustomComponent), import('./ngx-t-forms-map-mat-options-keys-B6hJ7Io5.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)], resolveMetadata: (SelectionOptionsEditorComponent, FormInputSelectorComponent, RestApiCallSetupComponent, ApiValueAccessRulesComponent, RequiredInputsComponent, PipelineGeneratorComponent, CalculatedFieldRulesComponent, ValidatorsConfigComponent, ConfigMscoaAdditionalInputsComponent, MatSliderEditorComponent, MscoaSegmentConfigComponent, MatSliderToggleEditorComponent, MatChipListEditorComponent, ChipOptionsCreatorEditorComponent, DataSourcePickerComponent, DocumentListLabelConfigEditorComponent, TWorkflowPickerComponent, EditorJsInputComponent, RecordListManagerComponent, FormPayloadProjectionComponent, InputCustomComponent, MapMatOptionsKeys, AsyncPipe) => ({ decorators: [{
13665
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: TDynamicDataEditComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-selection-options-editor.component-KjbZhc2u.mjs').then(m => m.SelectionOptionsEditorComponent), import('./ngx-t-forms-form-input-selector.component-B42xP3jh.mjs').then(m => m.FormInputSelectorComponent), import('./ngx-t-forms-rest-api-call-setup.component-WPUxtY7Q.mjs').then(m => m.RestApiCallSetupComponent), Promise.resolve().then(function () { return apiValueAccessRules_component; }).then(m => m.ApiValueAccessRulesComponent), import('./ngx-t-forms-required-inputs.component-ONbhxVSH.mjs').then(m => m.RequiredInputsComponent), import('./ngx-t-forms-pipeline-generator.component-CZ21sd77.mjs').then(m => m.PipelineGeneratorComponent), import('./ngx-t-forms-calculated-field-rules.component-BhxT6tRq.mjs').then(m => m.CalculatedFieldRulesComponent), import('./ngx-t-forms-validators-config.component-BknyAmV_.mjs').then(m => m.ValidatorsConfigComponent), import('./ngx-t-forms-config-mscoa-additional-inputs.component-Gn8exJ9a.mjs').then(m => m.ConfigMscoaAdditionalInputsComponent), import('./ngx-t-forms-mat-slider-editor.component-CTSBrM-j.mjs').then(m => m.MatSliderEditorComponent), import('./ngx-t-forms-mscoa-segment-config.component-Bo0aDEMy.mjs').then(m => m.MscoaSegmentConfigComponent), import('./ngx-t-forms-mat-slider-toggle-editor.component-CcYiwx-8.mjs').then(m => m.MatSliderToggleEditorComponent), import('./ngx-t-forms-mat-chip-list-editor.component-BWisS3Em.mjs').then(m => m.MatChipListEditorComponent), import('./ngx-t-forms-chip-options-creator-editor.component-d4QeVhsp.mjs').then(m => m.ChipOptionsCreatorEditorComponent), import('./ngx-t-forms-data-source-picker.component-Ebf_if9j.mjs').then(m => m.DataSourcePickerComponent), import('./ngx-t-forms-document-list-label-config-editor.component-CR6EvgJO.mjs').then(m => m.DocumentListLabelConfigEditorComponent), import('./ngx-t-forms-t-workflow-picker.component-CtavFAUq.mjs').then(m => m.TWorkflowPickerComponent), import('./ngx-t-forms-editor-js-input.component-5MD8wRj0.mjs').then(m => m.EditorJsInputComponent), import('./ngx-t-forms-record-list-manager.component-CykBq_nW.mjs').then(m => m.RecordListManagerComponent), import('./ngx-t-forms-form-payload-projection.component-Ip9ewB18.mjs').then(m => m.FormPayloadProjectionComponent), import('./ngx-t-forms-input-custom.component-Cn-KH0Lb.mjs').then(m => m.InputCustomComponent), import('./ngx-t-forms-map-mat-options-keys-CVlPdrCO.mjs').then(m => m.MapMatOptionsKeys), import('@angular/common').then(m => m.AsyncPipe)], resolveMetadata: (SelectionOptionsEditorComponent, FormInputSelectorComponent, RestApiCallSetupComponent, ApiValueAccessRulesComponent, RequiredInputsComponent, PipelineGeneratorComponent, CalculatedFieldRulesComponent, ValidatorsConfigComponent, ConfigMscoaAdditionalInputsComponent, MatSliderEditorComponent, MscoaSegmentConfigComponent, MatSliderToggleEditorComponent, MatChipListEditorComponent, ChipOptionsCreatorEditorComponent, DataSourcePickerComponent, DocumentListLabelConfigEditorComponent, TWorkflowPickerComponent, EditorJsInputComponent, RecordListManagerComponent, FormPayloadProjectionComponent, InputCustomComponent, MapMatOptionsKeys, AsyncPipe) => ({ decorators: [{
13189
13666
  type: Component,
13190
13667
  args: [{ selector: 'lib-t-dynamic-data-edit', imports: [
13191
13668
  AsyncPipe,
@@ -13218,8 +13695,8 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", n
13218
13695
  InputCustomComponent,
13219
13696
  FormsModule,
13220
13697
  MapMatOptionsKeys,
13221
- ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"] }]
13222
- }], ctorParameters: null, propDecorators: { editorConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "editorConfig", required: false }] }], formInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "formInputs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], validationErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationErrors", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], blur: [{ type: i0.Output, args: ["blur"] }] } }) });
13698
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: NESTED_EDITOR_COMPONENT, useValue: TDynamicDataEditComponent }], template: "@defer {\n@if (( vm$ |async); as vm) {\n\n @if (vm.isFormFieldControl) {\n <!-- Editor types that resolve to a MatFormFieldControl render inside the field. -->\n <mat-form-field appearance=\"outline\" [color]=\"((validationErrors())||[]).length>0 ? 'warn' : 'primary'\"\n [floatLabel]=\"'always'\" [subscriptSizing]=\"'dynamic'\" [hintLabel]=\"vm.editorConfigValue?.hint||''\">\n <mat-label> {{ (vm. editorConfigValue)?.label }} </mat-label>\n @switch ((vm. editorConfigValue)?.editType) {\n @default {\n <lib-input-custom\n [id]=\"((vm.editorConfigValue)?.id)\"\n [inputConfig]=\"$any(vm.inputConfig)\"\n [placeholder]=\"(vm. editorConfigValue)?.placeholder ||'Enter value'\"\n [required]=\"!!(vm. editorConfigValue)?.required\"\n [disabled]=\"!!(vm.disabled)\"\n [ngModel]=\"(vm.value)\"\n (blur)=\"elementBlur($event)\"\n (input)=\"inputChange($event)\" ></lib-input-custom>\n\n\n }\n @case ( elementEditorTypes.Toggle) {\n <lib-mat-slider-toggle-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [name]=\"((vm. editorConfigValue)?.name||'') \"\n [label]=\"((vm. editorConfigValue)?.label||'')\" [disabled]=\"(vm.disabled)||false\"\n (valueChange)=\"valueChanged(!!$event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n </lib-mat-slider-toggle-editor>\n\n }\n\n @case (elementEditorTypes.Range) {\n\n\n <lib-mat-slider-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [format]=\"( vm.editorConfigValue)?.format \" [formatLabel]=\" formatLabel\"\n [disabled]=\"(vm.disabled)||false\" [max]=\"( vm.editorConfigValue)?.max || 100\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [min]=\"( vm.editorConfigValue)?.min || 0\"\n (valueChange)=\"inputChange($event)\" [step]=\"( vm.editorConfigValue)?.step || 1\">\n\n\n </lib-mat-slider-editor>\n\n\n\n }\n\n @case (elementEditorTypes.OptionSelect) {\n\n <mat-select\n\n [value]=\"$any(vm.value)\" (selectionChange)=\"valueChanged($event.value)\"\n [disabled]=\"(vm.disabled)||false\">\n @for(option of ( vm.editorConfigValue)?.options || vm.dataOptions;track option.value){\n <mat-option [value]=\"option.value\">{{option.label}}</mat-option>\n }\n </mat-select>\n\n }\n\n @case (elementEditorTypes.RichTextEditor) {\n <lib-editor-js-input\n\n [id]=\"((vm.editorConfigValue)?.id)\"\n [value]=\"$any(vm.value)\" (valueChanged)=\"valueChanged($event)\"\n [disabled]=\"(vm.disabled)||false\" [inputConfig]=\"$any(data())\">\n </lib-editor-js-input>\n }\n\n @case (elementEditorTypes.MongoPipelineBuilder) {\n\n <lib-pipeline-generator [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\"></lib-pipeline-generator>\n\n }\n @case (elementEditorTypes.MapMatOptionsKeys) {\n <lib-map-mat-options-keys [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-map-mat-options-keys>\n\n }\n\n @case(elementEditorTypes.CalculatedFieldRules){\n\n <lib-calculated-field-rules [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\"\n [mapToData]=\"vm.dataOptions\"></lib-calculated-field-rules>\n }\n\n @case(elementEditorTypes.Validators){\n\n <lib-validators-config [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\"\n [mapToData]=\"vm.dataOptions\">\n </lib-validators-config>\n\n }\n @case(elementEditorTypes.ConfigMscoaAdditionalInputs){\n\n <lib-config-mscoa-additional-inputs [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-config-mscoa-additional-inputs>\n\n }\n @case (elementEditorTypes.DataSourcePicker) {\n <lib-data-source-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\" [formInputs]=\"formInputs() ||[]\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\">\n </lib-data-source-picker>\n }\n @case (elementEditorTypes.ListLabelConfigEditor) {\n <lib-document-list-label-config-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [formInputs]=\"formInputs() ||[]\"\n [disabled]=\"(vm.disabled)||false\"\n [editorConfig]=\"vm. editorConfigValue\"\n (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [mapToData]=\"vm.dataOptions\"\n [errors]=\"(validationErrors())||[]\">\n\n </lib-document-list-label-config-editor>\n }\n @case(\n elementEditorTypes.WorkflowPicker\n ){\n <lib-t-workflow-picker [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [getWorkflowOptions]=\"getWorkflowOptions$\"\n (valueChanged)=\"valueChanged($event)\" [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-t-workflow-picker>\n }\n @case (\n elementEditorTypes.RecordListManager\n ) {\n <lib-record-list-manager\n [id]=\"((vm.editorConfigValue)?.id)\"\n [editorConfig]=\"vm.editorConfigValue\" [disabled]=\"(vm.disabled)||false\"\n [formInputs]=\"formInputs() ||[]\" [mapToData]=\"vm.dataOptions\" (valueChange)=\"valueChanged($event)\"\n\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\"></lib-record-list-manager>\n }\n }\n\n @if (vm.inputHasBlurFunction) {\n <button [matTooltip]=\"blurFunctionTooltip((vm.editorConfigValue)?.blurHandle)\"\n [disabled]=\"(vm.disabled)\" [color]=\"blurOff?'':'primary'\" (click)=\"blurOff=!blurOff\" matSuffix\n mat-icon-button>\n <mat-icon>{{\n blurOff?'blur_off':'blur_on'\n }}\n\n\n </mat-icon>\n </button>\n }\n </mat-form-field>\n } @else {\n <!-- Editor types backed by plain (signal-based) components render outside\n the field, since they are not MatFormFieldControls. They are wrapped to\n mirror the outline mat-form-field appearance: the fieldset draws the\n outline, its legend is the notched floating label, and the hint renders\n as a subscript below the box. -->\n <div class=\"non-control-editor\">\n <fieldset class=\"non-control-editor__field\">\n @if ((vm. editorConfigValue)?.label) {\n <legend class=\"non-control-editor__label\">{{ (vm. editorConfigValue)?.label }}</legend>\n }\n @switch ((vm. editorConfigValue)?.editType) {\n\n @case (elementEditorTypes.ChipSelect) {\n\n <lib-mat-chip-list-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [multiple]=\"!!vm.editorConfigValue?.multipleSelection\"\n [disabled]=\"(vm.disabled)||false\"\n [options]=\"(vm.editorConfigValue)?.options || vm.dataOptions\"\n [required]=\"!!( vm.editorConfigValue)?.required\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n (valueChange)=\" valueChanged($event)\"></lib-mat-chip-list-editor>\n\n\n }\n\n @case (elementEditorTypes.SelectionOptions) {\n\n <lib-selection-options-editor\n [id]=\"((vm.editorConfigValue)?.id)\"\n [errors]=\"(validationErrors())||[]\" [disabled]=\"(vm.disabled)||false\"\n [options]=\"$any(vm.value) || []\" (valueChanged)=\"valueChanged($event)\"></lib-selection-options-editor>\n }\n\n @case (\n elementEditorTypes.ApiCall) {\n\n <lib-rest-api-call-setup\n [id]=\"((vm.editorConfigValue)?.id)\"\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\"\n [httpGetDataFunction]=\"(vm.editorConfigValue)?.httpGetDataFunction\" [disabled]=\"(vm.disabled)||false\"\n [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n\n </lib-rest-api-call-setup>\n\n }\n\n @case (elementEditorTypes.ApiValueAccessRules) {\n\n\n\n <lib-api-value-access-rules [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\"\n [formInputs]=\"formInputs() ||[]\"\n\n [postmanCollectionConfig]=\"(vm.editorConfigValue)?.postmanCollectionConfig\" [mapToData]=\"vm.dataOptions\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-api-value-access-rules>\n\n }\n\n @case (elementEditorTypes.FormInputSelector)\n {\n\n <lib-form-input-selector [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" [formInputs]=\"formInputs() ||[]\"\n [errors]=\"(validationErrors())||[]\" [value]=\"$any(vm.value) || []\" (change)=\"valueChanged($event)\">\n </lib-form-input-selector>\n }\n\n @case (\n elementEditorTypes.RequiredInputs\n ){\n\n <lib-required-inputs [formInputs]=\"formInputs() ||[]\" [disabled]=\"(vm.disabled)||false\"\n [id]=\"((vm.editorConfigValue)?.label||'')+((vm.editorConfigValue)?.editType||'')\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" (valueChanged)=\"valueChanged($event)\">\n </lib-required-inputs>\n }\n\n @case(elementEditorTypes.ConfigMscoaSegments){\n\n <lib-mscoa-segment-config [disabled]=\"(vm.disabled)||false\" [id]=\"((vm.editorConfigValue)?.id)\" [value]=\"$any(vm.value)\"\n [errors]=\"(validationErrors())||[]\" [getMscoaTree]=\"getMscoaTree$\" [dataValue]=\"$any(vm.dataValue)\"\n [isCashSegmentConfig]=\"vm.editorConfigValue?.deepBind?.at(-1) === 'cashSegments'\"\n [saveCustomInput]=\"mscoaSaveCustomInput()\"\n [editSegmentInput]=\"mscoaEditInput()\"\n [deleteSegmentInput]=\"mscoaDeleteInput()\"\n [showAllSegments]=\"vm.dataOptions\" (valueChanged)=\"valueChanged($event)\"></lib-mscoa-segment-config>\n }\n @case (elementEditorTypes.ChipOptionsCreator) {\n <lib-chip-options-creator-editor [id]=\"((vm.editorConfigValue)?.id)\" [disabled]=\"(vm.disabled)||false\" (valueChange)=\"valueChanged($event)\"\n [value]=\"$any(vm.value)\" [errors]=\"(validationErrors())||[]\">\n\n </lib-chip-options-creator-editor>\n\n }\n @case (elementEditorTypes.FormPayloadProjection) {\n <lib-form-payload-projection [disabled]=\"(vm.disabled)||false\" [value]=\"$any(vm.value)\"\n [formInputs]=\"formInputs() ||[]\" [errors]=\"(validationErrors())||[]\"\n (valueChanged)=\"valueChanged($event)\">\n </lib-form-payload-projection>\n\n }\n }\n </fieldset>\n\n @if ((vm. editorConfigValue)?.hint) {\n <small class=\"non-control-editor__hint\">{{ (vm. editorConfigValue)?.hint }}</small>\n }\n </div>\n }\n\n @if (!(vm.value) && (vm. editorConfigValue)?.required ) {\n <mat-error>\n {{ (vm. editorConfigValue)?.label }}'s is required\n </mat-error>}\n\n @for (error of (validationErrors())||[]; track error.key) {\n <mat-error style=\" font-size: 0.75em;\n margin-left: 14px;\n \">\n\n {{error.message}}</mat-error>\n }\n\n}\n\n}@error {\n<mat-card>\n <mat-card-content>\n\n <span>\n Failed to load form inputs\n </span>\n </mat-card-content>\n</mat-card>\n}\n\n\n\n<!-- -\n `TableConfigSetup`\n- `ConditionalInputConfig`\n- `MatrixTable`-->\n", styles: [".showItemValue{opacity:.6}.non-control-editor{display:flex;flex-direction:column;width:100%}.non-control-editor__field{margin:0;min-width:0;width:100%;box-sizing:border-box;display:flex;flex-direction:column;padding:.75rem;border:1px solid var(--mat-sys-outline-variant, var(--mat-app-outline));border-radius:var(--mdc-outlined-text-field-container-shape, 4px)}.non-control-editor__label{padding:0 .25rem;margin-left:.5rem;font-size:.75rem;font-weight:400;line-height:1;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}.non-control-editor__hint{margin-top:.5rem;padding:0 .875rem;font-size:.75rem;line-height:1.5;color:var(--mat-sys-on-surface-variant, var(--mat-app-on-surface-variant, var(--mat-app-outline)))}mat-form-field{width:100%}mat-slider{width:100%}.range{display:flex;align-items:center}.elementInfo{display:flex;align-items:center;justify-content:center;padding:0;height:24px;width:24px}.infoIcon{font-size:1em;height:16px;width:16px}.toggle-label{margin-left:5px;align-items:center;display:flex;font-weight:500;line-height:normal;justify-content:space-between;color:var(--mdc-filled-text-field-focus-label-text-color, var(--mat-app-primary))}\n"] }]
13699
+ }], ctorParameters: null, propDecorators: { editorConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "editorConfig", required: false }] }], formInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "formInputs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], validationErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationErrors", required: false }] }], mscoaSaveCustomInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mscoaSaveCustomInput", required: false }] }], mscoaEditInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mscoaEditInput", required: false }] }], mscoaDeleteInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "mscoaDeleteInput", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], blur: [{ type: i0.Output, args: ["blur"] }] } }) });
13223
13700
 
13224
13701
  const isEmptyPath = (path) => path.length === 0;
13225
13702
  const isEmptyTree = (tree) => tree.length === 0;
@@ -13732,41 +14209,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
13732
14209
  const ELEMENT_REGISTRY = {
13733
14210
  [ElementTypes.Location]: {
13734
14211
  builderAware: true,
13735
- load: () => import('./ngx-t-forms-geo-location.component-Bosp1UzR.mjs').then(m => m.GeoLocationComponent),
14212
+ load: () => import('./ngx-t-forms-geo-location.component-Bmd84Gcb.mjs').then(m => m.GeoLocationComponent),
13736
14213
  },
13737
14214
  [ElementTypes.AutoCompleteInput]: {
13738
- load: () => import('./ngx-t-forms-auto-complete-input-element.component-DCKuXHAW.mjs').then(m => m.AutoCompleteInputElementComponent),
14215
+ load: () => import('./ngx-t-forms-auto-complete-input-element.component-CaXs4561.mjs').then(m => m.AutoCompleteInputElementComponent),
13739
14216
  },
13740
14217
  [ElementTypes.Toggle]: {
13741
- load: () => import('./ngx-t-forms-toggle-input-element.component-DDErRUJd.mjs').then(m => m.ToggleInputElementComponent),
14218
+ load: () => import('./ngx-t-forms-toggle-input-element.component-Dr7MNli8.mjs').then(m => m.ToggleInputElementComponent),
13742
14219
  },
13743
14220
  [ElementTypes.Select]: {
13744
- load: () => import('./ngx-t-forms-select-input-element.component-DbgZdNoe.mjs').then(m => m.SelectInputElementComponent),
14221
+ load: () => import('./ngx-t-forms-select-input-element.component-CWcywuS6.mjs').then(m => m.SelectInputElementComponent),
13745
14222
  },
13746
14223
  [ElementTypes.Textarea]: {
13747
- load: () => import('./ngx-t-forms-textarea-input-element.component-BEbXJjFA.mjs').then(m => m.TextareaInputElementComponent),
14224
+ load: () => import('./ngx-t-forms-textarea-input-element.component-DkJkBQif.mjs').then(m => m.TextareaInputElementComponent),
13748
14225
  },
13749
14226
  [ElementTypes.DateRangePicker]: {
13750
- load: () => import('./ngx-t-forms-date-range-picker-input-element.component-CmoquQGV.mjs').then(m => m.DateRangePickerInputElementComponent),
14227
+ load: () => import('./ngx-t-forms-date-range-picker-input-element.component-4W6uvrDU.mjs').then(m => m.DateRangePickerInputElementComponent),
13751
14228
  },
13752
14229
  [ElementTypes.DatePicker]: {
13753
- load: () => import('./ngx-t-forms-date-picker-input-element.component-CYUbVyzP.mjs').then(m => m.DatePickerInputElementComponent),
14230
+ load: () => import('./ngx-t-forms-date-picker-input-element.component-kdinBGRA.mjs').then(m => m.DatePickerInputElementComponent),
13754
14231
  },
13755
14232
  [ElementTypes.FileUpload]: {
13756
- load: () => import('./ngx-t-forms-file-upload-input-element.component-C7mMeEjF.mjs').then(m => m.FileUploadInputElementComponent),
14233
+ load: () => import('./ngx-t-forms-file-upload-input-element.component-BAtuymMY.mjs').then(m => m.FileUploadInputElementComponent),
13757
14234
  },
13758
14235
  [ElementTypes.ImageCapture]: {
13759
- load: () => import('./ngx-t-forms-image-capture-input-element.component-C1g7Z0cK.mjs').then(m => m.ImageCaptureInputElementComponent),
14236
+ load: () => import('./ngx-t-forms-image-capture-input-element.component-CUd04Ghl.mjs').then(m => m.ImageCaptureInputElementComponent),
13760
14237
  },
13761
14238
  [ElementTypes.Editor]: {
13762
- load: () => import('./ngx-t-forms-editor-input-element.component-BLXlfb6F.mjs').then(m => m.EditorInputElementComponent),
14239
+ load: () => import('./ngx-t-forms-editor-input-element.component-1X6uAPeZ.mjs').then(m => m.EditorInputElementComponent),
13763
14240
  },
13764
14241
  [ElementTypes.Signature]: {
13765
14242
  load: () => Promise.resolve().then(function () { return signatureInputElement_component; }).then(m => m.SignatureInputElementComponent),
13766
14243
  },
13767
14244
  [ElementTypes.MultipleInput]: {
13768
14245
  builderAware: true,
13769
- load: () => import('./ngx-t-forms-multiple-input-input-element.component-C7y1OGPx.mjs').then(m => m.MultipleInputInputElementComponent),
14246
+ load: () => import('./ngx-t-forms-multiple-input-input-element.component-C8JP3D6r.mjs').then(m => m.MultipleInputInputElementComponent),
13770
14247
  },
13771
14248
  [ElementTypes.MscoaSelection]: {
13772
14249
  builderAware: true,
@@ -13774,14 +14251,14 @@ const ELEMENT_REGISTRY = {
13774
14251
  },
13775
14252
  [ElementTypes.WorkflowDocumentPicker]: {
13776
14253
  builderAware: true,
13777
- load: () => import('./ngx-t-forms-document-picker.component-qObjcqhE.mjs').then(m => m.DocumentPickerComponent),
14254
+ load: () => import('./ngx-t-forms-document-picker.component-BThdRFec.mjs').then(m => m.DocumentPickerComponent),
13778
14255
  },
13779
14256
  [ElementTypes.WorkflowAdjudication]: {
13780
14257
  builderAware: true,
13781
- load: () => import('./ngx-t-forms-workflow-adjudication.component-CtU8dECN.mjs').then(m => m.WorkflowAdjudicationComponent),
14258
+ load: () => import('./ngx-t-forms-workflow-adjudication.component-CPvwm7f4.mjs').then(m => m.WorkflowAdjudicationComponent),
13782
14259
  },
13783
14260
  [ElementTypes.PaginatedSelectionTable]: {
13784
- load: () => import('./ngx-t-forms-paginated-selection-table-AQZSMmhr.mjs').then(m => m.PaginatedSelectionTable),
14261
+ load: () => import('./ngx-t-forms-paginated-selection-table-0OI1ikWW.mjs').then(m => m.PaginatedSelectionTable),
13785
14262
  },
13786
14263
  };
13787
14264
  /**
@@ -13789,7 +14266,7 @@ const ELEMENT_REGISTRY = {
13789
14266
  * `@default` switch branch (a basic input).
13790
14267
  */
13791
14268
  const FALLBACK_ELEMENT = {
13792
- load: () => import('./ngx-t-forms-basic-input-input-element.component-Ce4ipSUc.mjs').then(m => m.BasicInputInputElementComponent),
14269
+ load: () => import('./ngx-t-forms-basic-input-input-element.component-Dotyd-Qs.mjs').then(m => m.BasicInputInputElementComponent),
13793
14270
  };
13794
14271
  /**
13795
14272
  * Resolves the renderer entry for a given element type, falling back to the
@@ -15590,6 +16067,9 @@ class MscoaChartComponent {
15590
16067
  // Form-builder functions, mirrored for dialog / portal use (read-only here).
15591
16068
  #formBuilderFunctions;
15592
16069
  #previousInputsHash;
16070
+ // Control keys already wired to the custom-input value projection (control → store),
16071
+ // guarding against duplicate subscriptions across input refreshes.
16072
+ #wiredInputProjections;
15593
16073
  #prevValidating;
15594
16074
  /**
15595
16075
  * Gets the success message for a specific accounting basis
@@ -15691,6 +16171,9 @@ class MscoaChartComponent {
15691
16171
  // Form-builder functions, mirrored for dialog / portal use (read-only here).
15692
16172
  this.#formBuilderFunctions = undefined;
15693
16173
  this.#previousInputsHash = '';
16174
+ // Control keys already wired to the custom-input value projection (control → store),
16175
+ // guarding against duplicate subscriptions across input refreshes.
16176
+ this.#wiredInputProjections = new Set();
15694
16177
  // Portal management — the portal component is loaded lazily via `import('../../../t-form-input/...')`
15695
16178
  // at runtime, so the eager `ComponentPortal<T>` generic cannot be tightened without breaking the
15696
16179
  // lazy module boundary. `ComponentPortal<T>` is invariant in T so `unknown` is not assignable from
@@ -15771,6 +16254,7 @@ class MscoaChartComponent {
15771
16254
  }))
15772
16255
  .subscribe(inputs => {
15773
16256
  this.setupPortals(inputs);
16257
+ this.#wireCustomInputProjections(inputs);
15774
16258
  this.#cdr.markForCheck();
15775
16259
  });
15776
16260
  // Show shield icon on validated cells when validation completes (true -> false)
@@ -15884,13 +16368,62 @@ class MscoaChartComponent {
15884
16368
  setupPortals(inputs) {
15885
16369
  this.#setupPortalsInternal(inputs);
15886
16370
  }
16371
+ /**
16372
+ * Wires each standalone (account-level) custom input's `FormControl` to the
16373
+ * store so its value is projected into the account value object as a peer of
16374
+ * the segments — single value selection mirrors the value across debit/credit.
16375
+ * Projects to the configured accounting basis (both for dual). `startWith`
16376
+ * seeds the store from the control on wire-up; `distinctUntilChanged` plus the
16377
+ * reducer's idempotency guard keep the form ⇄ store graph from oscillating.
16378
+ * Each control is wired at most once. (Per-leg distinct entry is a later step.)
16379
+ */
16380
+ #wireCustomInputProjections(inputs) {
16381
+ const formGroup = this.formGroup();
16382
+ const mscoaId = this.inputConfig()?.id;
16383
+ if (!formGroup || !mscoaId)
16384
+ return;
16385
+ const basis = this.config()?.accountingBasis;
16386
+ const cashFlags = basis === ACCOUNTING_BASIS.CASH ? [true]
16387
+ : basis === ACCOUNTING_BASIS.DUAL ? [false, true]
16388
+ : [false];
16389
+ for (const input of inputs) {
16390
+ if (input.linkedSegmentId || !input.formControlName)
16391
+ continue;
16392
+ const controlKey = `${mscoaId}.${input.id}`;
16393
+ const control = formGroup.controls[controlKey];
16394
+ if (!control)
16395
+ continue;
16396
+ if (this.#wiredInputProjections.has(controlKey))
16397
+ continue;
16398
+ this.#wiredInputProjections.add(controlKey);
16399
+ const inputKey = input.formControlName;
16400
+ control.valueChanges.pipe(startWith$1(control.value), distinctUntilChanged((a, b) => _isEqual(a, b)), takeUntilDestroyed(this.#destroyRef)).subscribe(value => {
16401
+ for (const isCash of cashFlags) {
16402
+ this.#store.setCustomInputValue({ inputKey, value, isCash });
16403
+ }
16404
+ });
16405
+ }
16406
+ }
15887
16407
  /**
15888
16408
  * Creates a hash of inputs array for comparison
15889
16409
  */
15890
16410
  getInputsHash(inputs) {
15891
16411
  if (!inputs || inputs.length === 0)
15892
16412
  return '';
15893
- return inputs.map(i => i.id).sort().join(',');
16413
+ // Hash the FULL config, not just id/element/formControlName. A custom input's
16414
+ // `type`, `validators`, `pattern`, `min`/`max`, calc/API rules etc. are all
16415
+ // edited through the advanced editor WITHOUT changing element/formControlName,
16416
+ // and each portal carries a STATIC `inputConfig` snapshot — so it must rebuild
16417
+ // whenever ANY of those change, or the live edit silently never reaches the
16418
+ // rendered input (it keeps behaving like a bare text field). Emissions here
16419
+ // are config-driven (not per-keystroke), so serializing is cheap.
16420
+ try {
16421
+ return JSON.stringify(inputs);
16422
+ }
16423
+ catch {
16424
+ // Non-serializable config (cycles): fall back to identity fields.
16425
+ return inputs.map(i => `${i.id}:${i.element ?? ''}:${i.formControlName ?? ''}`).sort().join(',');
16426
+ }
15894
16427
  }
15895
16428
  /**
15896
16429
  * Generates a consistent portal key for an input
@@ -16484,9 +17017,9 @@ class MscoaChartComponent {
16484
17017
  }
16485
17018
  }
16486
17019
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: MscoaChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
16487
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: MscoaChartComponent, isStandalone: true, selector: "lib-mscoa-chart", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null }, editorMode: { classPropertyName: "editorMode", publicName: "editorMode", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, formBuilderFunctions: { classPropertyName: "formBuilderFunctions", publicName: "formBuilderFunctions", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onContainerClick: "onContainerClick", interaction: "interaction" }, ngImport: i0, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id && formGroup() && inputPortals[getPortalKey(row.innerInput.id)]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[getPortalKey(row.innerInput.id)]\"></ng-template>\r\n </div>\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: PortalModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatIconModule }, { 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: "directive", type: i6.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: MscoaChartInputMenuComponent, selector: "lib-mscoa-chart-input-menu", inputs: ["innerInput", "countdownSeconds", "hoveredId"], outputs: ["edit", "delete", "cancelDelete", "hoverStart", "hoverEnd"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [i3.NgTemplateOutlet, i4$2.CdkPortalOutlet, i1$2.MatButton, i1$2.MatIconButton, i3$1.MatIcon, i6.MatMenuTrigger, i5$2.MatTable, i5$2.MatHeaderCellDef, i5$2.MatHeaderRowDef, i5$2.MatColumnDef, i5$2.MatCellDef, i5$2.MatRowDef, i5$2.MatHeaderCell, i5$2.MatCell, i5$2.MatHeaderRow, i5$2.MatRow, i5$1.MatTooltip, import('./ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), i3.AsyncPipe, i3.TitleCasePipe, Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)]] }); }
17020
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: MscoaChartComponent, isStandalone: true, selector: "lib-mscoa-chart", inputs: { inputConfig: { classPropertyName: "inputConfig", publicName: "inputConfig", isSignal: true, isRequired: true, transformFunction: null }, editorMode: { classPropertyName: "editorMode", publicName: "editorMode", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: false, transformFunction: null }, formBuilderFunctions: { classPropertyName: "formBuilderFunctions", publicName: "formBuilderFunctions", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onContainerClick: "onContainerClick", interaction: "interaction" }, ngImport: i0, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id) {\r\n <!-- Custom-input row (peer of the segments): the value is entered inline via the\r\n input portal on the primary (debit) leg; other legs mirror it and render no\r\n control. `innerInput.id` is already the namespaced portal key, so it is looked\r\n up directly \u2014 prepending it again (getPortalKey) double-namespaces and misses. -->\r\n @if (col === COLUMNS.DEBIT && formGroup() && inputPortals[row.innerInput.id]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[row.innerInput.id]\"></ng-template>\r\n </div>\r\n }\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: PortalModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatIconModule }, { 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: "directive", type: i6.MatMenuContent, selector: "ng-template[matMenuContent]" }, { kind: "ngmodule", type: MatTableModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: MscoaChartInputMenuComponent, selector: "lib-mscoa-chart-input-menu", inputs: ["innerInput", "countdownSeconds", "hoveredId"], outputs: ["edit", "delete", "cancelDelete", "hoverStart", "hoverEnd"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [i3.NgTemplateOutlet, i4$2.CdkPortalOutlet, i1$2.MatButton, i1$2.MatIconButton, i3$1.MatIcon, i6.MatMenuTrigger, i5$2.MatTable, i5$2.MatHeaderCellDef, i5$2.MatHeaderRowDef, i5$2.MatColumnDef, i5$2.MatCellDef, i5$2.MatRowDef, i5$2.MatHeaderCell, i5$2.MatCell, i5$2.MatHeaderRow, i5$2.MatRow, i5$1.MatTooltip, import('./ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), i3.AsyncPipe, i3.TitleCasePipe, Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)]] }); }
16488
17021
  }
16489
- i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: MscoaChartComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-mscoa-chart-toolbar.component-C_abEBQ5.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)], resolveMetadata: (MscoaChartToolbarComponent, MscoaErrorDisplayComponent, MscoaTemporaryHintComponent, ConvertCamelCasePipe) => ({ decorators: [{
17022
+ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", ngImport: i0, type: MscoaChartComponent, resolveDeferredDeps: () => [import('./ngx-t-forms-mscoa-chart-toolbar.component-D4Xa_Yi0.mjs').then(m => m.MscoaChartToolbarComponent), import('./ngx-t-forms-mscoa-error-display.component-99DpVSy7.mjs').then(m => m.MscoaErrorDisplayComponent), import('./ngx-t-forms-mscoa-temporary-hint.component-B1Z-IXSL.mjs').then(m => m.MscoaTemporaryHintComponent), Promise.resolve().then(function () { return daysAgo_pipe; }).then(m => m.ConvertCamelCasePipe)], resolveMetadata: (MscoaChartToolbarComponent, MscoaErrorDisplayComponent, MscoaTemporaryHintComponent, ConvertCamelCasePipe) => ({ decorators: [{
16490
17023
  type: Component,
16491
17024
  args: [{ selector: 'lib-mscoa-chart', imports: [
16492
17025
  CommonModule,
@@ -16503,7 +17036,7 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "21.2.12", n
16503
17036
  MscoaChartInputMenuComponent,
16504
17037
  MscoaErrorDisplayComponent,
16505
17038
  MscoaTemporaryHintComponent
16506
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id && formGroup() && inputPortals[getPortalKey(row.innerInput.id)]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[getPortalKey(row.innerInput.id)]\"></ng-template>\r\n </div>\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"] }]
17039
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if ((viewData$ | async); as viewData) {\r\n<section\r\n (click)=\"setAsTouched($event)\"\r\n class=\"mscoa-chart__container\"\r\n [class.mscoa-chart__container--touched]=\"touched()\"\r\n role=\"region\"\r\n [attr.aria-label]=\"'MSCOA Account Chart'\"\r\n [attr.aria-busy]=\"viewData.loading || viewData.validatingValue\">\r\n\r\n @if (viewData.loading) {\r\n <div class=\"mscoa-chart__loading-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-spinner [diameter]=\"40\"></mat-spinner>\r\n <span class=\"sr-only\">Loading account chart data...</span>\r\n </div>\r\n } @else {\r\n @defer () {\r\n @if (viewData.accountTreeKeys || viewData.cashAccountTreeKeys) {\r\n <div class=\"mscoa-chart__table-container\">\r\n @if (isDualAccountBasis) {\r\n <div class=\"dual-basis-container\" role=\"group\" aria-label=\"Dual accounting basis tables\">\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.ACCRUAL,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n\r\n <div class=\"dual-basis-container__item\">\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: ACCOUNTING_BASIS.CASH,\r\n canCollapse: true,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n </div>\r\n </div>\r\n } @else {\r\n <ng-container\r\n *ngTemplateOutlet=\"selectionTable;\r\n context: {\r\n accountingBasis: config()?.accountingBasis,\r\n canCollapse: false,\r\n viewData: viewData\r\n }\">\r\n </ng-container>\r\n }\r\n </div>\r\n }\r\n\r\n <ng-template\r\n #selectionTable\r\n let-accountingBasis=\"accountingBasis\"\r\n let-canCollapse=\"canCollapse\"\r\n let-viewData=\"viewData\">\r\n\r\n <div class=\"mscoa-chart-table\" role=\"group\" [attr.aria-label]=\"'Accounting basis: ' + (accountingBasis || 'Accrual')\">\r\n <!-- Toolbar -->\r\n <lib-mscoa-chart-toolbar\r\n [accountingBasis]=\"accountingBasis\"\r\n [canCollapse]=\"canCollapse\"\r\n [isExpanded]=\"getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n (toggleExpansion)=\"toggleDualBasisExpansion(accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\">\r\n </lib-mscoa-chart-toolbar>\r\n\r\n @if (shouldShowTable(isDualAccountBasis, getExpansionState(accountingBasis || ACCOUNTING_BASIS.ACCRUAL), accountingBasis)) {\r\n <div class=\"account-selection-table-wrapper\">\r\n <div\r\n class=\"account-selection-table-container\"\r\n [class.account-selection-table-container--accrual]=\"!accountingBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL\"\r\n [class.account-selection-table-container--cash]=\"accountingBasis === ACCOUNTING_BASIS.CASH\"\r\n role=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\">\r\n\r\n <table\r\n mat-table\r\n [dataSource]=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashTableData : viewData.tableData\"\r\n [trackBy]=\"trackByRow\"\r\n class=\"table\"\r\n [attr.aria-label]=\"'Account selection table for ' + (accountingBasis || 'Accrual') + ' basis'\"\r\n [attr.aria-describedby]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\"\r\n role=\"table\">\r\n <span [id]=\"'table-description-' + (accountingBasis || ACCOUNTING_BASIS.ACCRUAL)\" class=\"sr-only\">\r\n Use arrow keys to navigate between cells. Press Enter or Space to select an account.\r\n </span>\r\n\r\n @for (\r\n col of (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols);\r\n track trackByColumn($index, col);\r\n let i = $index\r\n ) {\r\n <ng-container [matColumnDef]=\"col\" [sticky]=\"i === 0\">\r\n <!-- Header Cell -->\r\n <th\r\n mat-header-cell\r\n *matHeaderCellDef\r\n [class.table__header-cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__header-cell--regular]=\"!isSegmentColumn(i)\"\r\n [style.width.%]=\"getColumnWidthPercent(isSegmentColumn(i), (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols).length)\"\r\n [style.min-width.px]=\"isSegmentColumn(i) ? 150 : 200\"\r\n [attr.aria-sort]=\"i === 0 ? 'none' : null\"\r\n [attr.scope]=\"'col'\"\r\n [attr.aria-label]=\"getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) + ' column'\">\r\n {{ getHeaderText(col, i, accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashHasMultiSelect : viewData.hasMultiSelect) | titlecase | unCamelCase }}\r\n </th>\r\n\r\n <!-- Data Cell -->\r\n <td\r\n mat-cell\r\n *matCellDef=\"let row\"\r\n [class.table__cell--segment]=\"isSegmentColumn(i)\"\r\n [class.table__cell--regular]=\"!isSegmentColumn(i)\"\r\n [class.table__cell--active]=\"editSelection?.segment === row['segment'] && activeColumn === col\"\r\n [class.table__cell--business-error]=\"!isSegmentColumn(i) && getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"'Cell for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-selected]=\"!!row[col]\"\r\n [attr.aria-invalid]=\"!isSegmentColumn(i) && !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.role]=\"'gridcell'\"\r\n [attr.tabindex]=\"isSegmentColumn(i) ? -1 : (row[col] ? 0 : -1)\">\r\n\r\n @if (isSegmentColumn(i)) {\r\n <!-- Segment Column -->\r\n <div class=\"segment-cell-content\">\r\n @if (editorMode() && row.innerInput?.id) {\r\n <button\r\n mat-icon-button\r\n [matMenuTriggerData]=\"{innerInput: row.innerInput}\"\r\n [matMenuTriggerFor]=\"inputMenu\"\r\n [matTooltip]=\"'Options for: ' + row.innerInput.label\"\r\n [attr.aria-label]=\"'Options menu for ' + row.innerInput.label\"\r\n (click)=\"$event.stopPropagation()\">\r\n <mat-icon>more_vert</mat-icon>\r\n </button>\r\n }\r\n <span class=\"segment-cell-content__label\">{{ row['label'] }}</span>\r\n </div>\r\n } @else {\r\n <!-- Regular Column -->\r\n @if (row.innerInput?.id) {\r\n <!-- Custom-input row (peer of the segments): the value is entered inline via the\r\n input portal on the primary (debit) leg; other legs mirror it and render no\r\n control. `innerInput.id` is already the namespaced portal key, so it is looked\r\n up directly \u2014 prepending it again (getPortalKey) double-namespaces and misses. -->\r\n @if (col === COLUMNS.DEBIT && formGroup() && inputPortals[row.innerInput.id]) {\r\n <div class=\"portal-container\">\r\n <ng-template [cdkPortalOutlet]=\"inputPortals[row.innerInput.id]\"></ng-template>\r\n </div>\r\n }\r\n } @else {\r\n @if (row[col]) {\r\n <!-- Account Selected -->\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment']); as cellError) {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"row['singleSelect'] === true && col === COLUMNS.CREDIT\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected cell-button--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Business error: ' + cellError.message\"\r\n [attr.aria-invalid]=\"true\"\r\n [attr.aria-pressed]=\"true\"\r\n [matTooltip]=\"cellError.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag selected-acount-label--business-error\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n </div>\r\n </button>\r\n </div>\r\n } @else {\r\n <div class=\"account-cell-wrapper\"\r\n [class.account-cell-wrapper--expandable]=\"isTextTruncated(row[col] | unCamelCase)\">\r\n <button\r\n [disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n (mousedown)=\"$event.preventDefault(); $event.stopPropagation(); selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n color=\"primary\"\r\n mat-button\r\n class=\"cell-button cell-button--selected\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase) + ' for ' + row['segment'] + ' segment, ' + col + ' column. Press Enter or Space to change'\"\r\n [attr.aria-invalid]=\"false\"\r\n [attr.aria-disabled]=\"(row['singleSelect'] === true && col === COLUMNS.CREDIT) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-pressed]=\"true\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label selected-acount-label--tag\"\r\n [attr.aria-label]=\"'Selected account: ' + (row[col] | unCamelCase)\">\r\n {{ row[col] | unCamelCase }}\r\n @if (shouldShowVatChip(row, col)) {\r\n <span\r\n class=\"vat-badge\"\r\n [attr.aria-label]=\"'VAT applicable to ' + col + ' column'\"\r\n [matTooltip]=\"'VAT is applicable to this ' + col + ' account selection'\">\r\n VAT\r\n </span>\r\n }\r\n </span>\r\n @if (showValidationSuccessIndicators) {\r\n <mat-icon class=\"validated-indicator\" aria-hidden=\"true\" [matTooltip]=\"'Validated'\">shield</mat-icon>\r\n } @else {\r\n <mat-icon class=\"success-indicator\" aria-hidden=\"true\">check_circle</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n </div>\r\n }\r\n } @else {\r\n <!-- No Account Selected -->\r\n <div class=\"cell-button-wrapper\">\r\n <button\r\n [disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [color]=\"\"\r\n (click)=\"selectAccount(row, col, accountingBasis === ACCOUNTING_BASIS.CASH); $event.stopPropagation(); setAsTouched($event)\"\r\n (keydown)=\"handleCellKeyDown($event, row, col, accountingBasis === ACCOUNTING_BASIS.CASH)\"\r\n mat-button\r\n class=\"cell-button\"\r\n [class.cell-button--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-label]=\"shouldShowAutoSelectedLabel(row, col) ? 'Auto selected for ' + row['segment'] + ' segment, ' + col + ' column' : 'Select account for ' + row['segment'] + ' segment, ' + col + ' column'\"\r\n [attr.aria-disabled]=\"selectionDisabled(row, col) || isCellDisabledByBusinessErrors(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-describedby]=\"getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ? 'hint-' + row['segment'] + '-' + col : null\"\r\n [attr.aria-invalid]=\"hasError(touched(), inputConfig().required || false, !!row[col]) || !!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\"\r\n [attr.aria-required]=\"inputConfig().required && !row[col]\"\r\n [matTooltip]=\"getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])?.message\">\r\n <div class=\"content\">\r\n <span\r\n class=\"selected-acount-label\"\r\n [class.selected-acount-label--error]=\"hasError(touched(), inputConfig().required || false, !!row[col])\"\r\n [class.selected-acount-label--business-error]=\"!!getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])\">\r\n {{ (shouldShowAutoSelectedLabel(row, col) ? 'auto selected' : 'Select account') | unCamelCase }}\r\n @if (inputConfig().required && !row[col]) {\r\n <span class=\"required-indicator\" aria-label=\"Required field\">*</span>\r\n }\r\n </span>\r\n @if (getCellBusinessError(viewData.validationErrors, accountingBasis || ACCOUNTING_BASIS.ACCRUAL, col, row['segment'])) {\r\n <mat-icon class=\"business-error-indicator\" aria-hidden=\"true\">error</mat-icon>\r\n } @else if (shouldShowDropdownIcon(row, col)) {\r\n <mat-icon aria-hidden=\"true\">arrow_drop_down</mat-icon>\r\n }\r\n </div>\r\n </button>\r\n @if (getValidationHint(row, col, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as hint) {\r\n <span\r\n class=\"inline-hint\"\r\n [id]=\"'hint-' + row['segment'] + '-' + col\"\r\n role=\"tooltip\"\r\n aria-live=\"polite\">\r\n {{ hint }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n }\r\n }\r\n </td>\r\n </ng-container>\r\n }\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: (accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashCols : viewData.cols)\"></tr>\r\n </table>\r\n </div>\r\n </div>\r\n\r\n <!-- Empty State -->\r\n @if ((accountingBasis === ACCOUNTING_BASIS.CASH ? viewData.cashAccountTreeKeys : viewData.accountTreeKeys).length === 0) {\r\n <section class=\"empty-state\" role=\"status\" aria-live=\"polite\">\r\n <mat-icon aria-hidden=\"true\">info</mat-icon>\r\n <span>\r\n No account segments are currently configured.\r\n Please configure account segments to proceed.\r\n </span>\r\n </section>\r\n }\r\n\r\n <!-- Success Messages (Temporary) -->\r\n @if ((successMessage$ | async); as successMessages) {\r\n @if (getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL); as msg) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"getSuccessMessage(successMessages, accountingBasis || ACCOUNTING_BASIS.ACCRUAL) ?? ''\"\r\n [type]=\"'info'\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n }\r\n\r\n <!-- Business Rule Errors (Temporary display, keeps error styling) -->\r\n @if ((viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []).length > 0) {\r\n <lib-mscoa-error-display\r\n [errors]=\"viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL] || []\"\r\n type=\"error\"\r\n [context]=\"{ accountingBasis: accountingBasis || ACCOUNTING_BASIS.ACCRUAL }\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-error-display>\r\n }\r\n\r\n <!-- Temporary Contextual Hints -->\r\n @if (temporaryHintMessage) {\r\n <lib-mscoa-temporary-hint\r\n [message]=\"temporaryHintMessage\"\r\n [type]=\"temporaryHintType\"\r\n [duration]=\"6000\"\r\n [showDismiss]=\"true\">\r\n </lib-mscoa-temporary-hint>\r\n }\r\n\r\n <!-- Validation Hints (Context-Aware) -->\r\n @if (!touched() && inputConfig().required && !viewData.busnessRuleErrors[accountingBasis || ACCOUNTING_BASIS.ACCRUAL]?.length && (!isDualAccountBasis || accountingBasis === ACCOUNTING_BASIS.ACCRUAL || !accountingBasis)) {\r\n <div class=\"validation-hints\" role=\"region\" aria-label=\"Validation guidance\">\r\n <p class=\"validation-hints__title\">Guidance:</p>\r\n <ul class=\"validation-hints__list\">\r\n <li>Account combinations are validated automatically. Select accounts that belong to compatible reporting categories.</li>\r\n <li>Required fields are marked with an asterisk (*). Complete all required selections to proceed.</li>\r\n <li>Some fields may be automatically populated based on your selections to ensure consistency.</li>\r\n </ul>\r\n </div>\r\n }\r\n }\r\n </div>\r\n </ng-template>\r\n } @placeholder {\r\n <div class=\"loading-placeholder\" role=\"status\" aria-live=\"polite\">\r\n <p>Loading data...</p>\r\n </div>\r\n } @loading (minimum 100ms) {\r\n <div class=\"loading-spinner-container\" role=\"status\" aria-live=\"polite\">\r\n <mat-progress-spinner mode=\"indeterminate\" [diameter]=\"40\"></mat-progress-spinner>\r\n <span class=\"sr-only\">Loading account chart...</span>\r\n </div>\r\n } @error {\r\n <div class=\"error-state\" role=\"alert\" aria-live=\"assertive\">\r\n <p>Error loading data. Please try again.</p>\r\n </div>\r\n }\r\n }\r\n</section>\r\n}\r\n\r\n<!-- Input Menu -->\r\n<mat-menu #inputMenu=\"matMenu\">\r\n <ng-template matMenuContent let-innerInput=\"innerInput\">\r\n <lib-mscoa-chart-input-menu\r\n [innerInput]=\"innerInput\"\r\n [countdownSeconds]=\"inputWillBeRemovedIn(innerInput.id)\"\r\n [hoveredId]=\"hoveredInputId\"\r\n (edit)=\"onInputMenuEdit($event)\"\r\n (delete)=\"onInputMenuDelete($event)\"\r\n (cancelDelete)=\"onInputMenuCancelDelete($event)\"\r\n (hoverStart)=\"onInputMenuHoverStart($event)\"\r\n (hoverEnd)=\"onInputMenuHoverEnd()\">\r\n </lib-mscoa-chart-input-menu>\r\n </ng-template>\r\n</mat-menu>\r\n", styles: ["@charset \"UTF-8\";:host{--mscoa-chart-spacing-xs: 4px;--mscoa-chart-spacing-sm: 8px;--mscoa-chart-spacing-md: 16px;--mscoa-chart-spacing-lg: 24px;--mscoa-chart-spacing-xl: 32px;--mscoa-chart-border-radius: 4px;--mscoa-chart-transition: var(--lib-forms-duration-hover) var(--lib-forms-easing);--mscoa-chart-font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;--mscoa-chart-font-size-base: 14px;--mscoa-chart-line-height: 1.5;display:block;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height)}.mscoa-chart__container{padding:0;transition:background-color var(--mscoa-chart-transition);width:100%;max-width:100%;overflow-x:hidden;box-sizing:border-box}.mscoa-chart__loading-container{padding:var(--mscoa-chart-spacing-lg);display:flex;align-items:center;justify-content:center}.mscoa-chart__table-container{position:relative;width:100%;max-width:100%;overflow-x:auto;overflow-y:visible;box-sizing:border-box}.dual-basis-container{display:flex;flex-direction:column;gap:var(--mscoa-chart-spacing-sm)}.dual-basis-container__item{flex:1}:host .single-base{gap:var(--mscoa-chart-spacing-sm);height:48px;font-size:.875em;font-weight:500;transition:background-color var(--mscoa-chart-transition)}:host .single-base--cash{background:var(--mat-sys-inverse-primary)}.account-selection-table-wrapper{position:relative;width:100%}.account-selection-table-container{border-radius:var(--mscoa-chart-border-radius);overflow-x:auto;overflow-y:visible;transition:border-color var(--mscoa-chart-transition);width:100%;max-width:100%;box-sizing:border-box;display:block}.account-selection-table-container--accrual{border:solid 1px var(--mat-sys-primary)}.account-selection-table-container--cash{border:solid 1px var(--mat-sys-inverse-primary)}.account-selection-table-container::-webkit-scrollbar{height:8px}.account-selection-table-container::-webkit-scrollbar-track{background:var(--lib-forms-surface-container-low);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb{background:var(--lib-forms-outline-variant);border-radius:4px}.account-selection-table-container::-webkit-scrollbar-thumb:hover{background:var(--lib-forms-outline)}.table{width:100%;table-layout:fixed;font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);border-collapse:separate;border-spacing:0;display:table;box-sizing:border-box;max-width:100%}.table__header-cell{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;box-sizing:border-box}.table__header-cell--segment{text-align:right;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px}.table__header-cell--regular{padding-left:var(--mscoa-chart-spacing-lg);min-width:200px;max-width:none}.table__cell{overflow:visible;box-sizing:border-box;position:relative;vertical-align:top}.table__cell--segment{background:var(--mat-list-active-indicator-color, var(--mat-sys-secondary-container));text-align:right;font-weight:500;padding-right:var(--mscoa-chart-spacing-md);min-width:150px;max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;vertical-align:middle}.table__cell--regular{padding:0;min-width:200px;max-width:none;word-wrap:break-word;vertical-align:top;overflow:visible}.table__cell--active{background-color:var(--mat-sys-primary-container);transition:background-color var(--mscoa-chart-transition)}mat-header-cell{background:var(--mat-sys-surface-container);font-weight:600;font-size:var(--mscoa-chart-font-size-base);padding:var(--mscoa-chart-spacing-md)}.mscoa-chart-table{display:flex;flex-direction:column}.portal-container{width:100%}.account-cell-wrapper{position:relative;width:100%;max-width:100%;overflow:visible;z-index:1;min-height:38px;display:flex;flex-direction:column;gap:4px}.cell-button-wrapper{position:relative;width:100%;max-width:100%;overflow:hidden}.cell-button{height:fit-content;min-height:38px;width:100%;max-width:100%;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);font-family:var(--mscoa-chart-font-family);font-size:var(--mscoa-chart-font-size-base);line-height:var(--mscoa-chart-line-height);position:relative;overflow:visible;padding:8px}.cell-button:hover:not(:disabled){background-color:var(--mat-sys-surface-container);transform:translateY(-1px);box-shadow:0 2px 4px #0000001a}.cell-button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;z-index:1}.cell-button:disabled{opacity:.6;cursor:not-allowed}.cell-button--selected{background-color:transparent}.cell-button--selected:hover:not(:disabled){background-color:var(--lib-forms-surface-container-low);border-color:var(--lib-forms-primary)}.cell-button.cell-button--selected{animation:fadeInSuccess var(--mscoa-chart-transition)}.cell-button.cell-button--business-error{border-color:var(--lib-forms-error)}.cell-button.cell-button--business-error .selected-acount-label--business-error{color:var(--mat-sys-error);border-color:var(--mat-sys-error)}.success-indicator{color:var(--sem-success);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);animation:scaleIn var(--mscoa-chart-transition);flex-shrink:0}.validated-indicator{color:var(--lib-forms-primary);font-size:18px;width:18px;height:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0;animation:validatedShieldIn .3s ease-out forwards}.business-error-indicator{color:var(--lib-forms-error);font-size:18px;width:18px;right:-8px;top:-4px;background:var(--lib-forms-surface);border-radius:16px;position:absolute;height:18px;margin-left:var(--mscoa-chart-spacing-xs);flex-shrink:0}.required-indicator{color:var(--lib-forms-error);font-weight:600;margin-left:2px}.inline-hint{display:block;font-size:12px;color:var(--lib-forms-on-surface-variant);margin-top:var(--mscoa-chart-spacing-xs);padding:var(--mscoa-chart-spacing-xs) var(--mscoa-chart-spacing-sm);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);line-height:1.4;max-width:100%;word-wrap:break-word}.content{padding:0;display:flex;gap:6px;width:100%;max-width:100%;overflow:visible;min-width:0;flex-wrap:wrap;align-items:center}.selected-acount-label{text-align:left;flex:1;font-weight:400;transition:color var(--mscoa-chart-transition)}.selected-acount-label--error,.selected-acount-label--business-error{color:var(--mat-sys-error);font-weight:500}.selected-acount-label--tag{display:inline-block;padding:4px 10px;background-color:var(--lib-forms-primary-container);color:var(--lib-forms-on-primary-container);border-radius:16px;font-size:13px;font-weight:500;line-height:1.5;border:1px solid var(--lib-forms-primary);box-shadow:0 1px 2px #0000001a;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing);width:100%;max-width:100%;overflow:visible;white-space:normal;word-wrap:break-word;word-break:break-word;cursor:pointer;box-sizing:border-box;position:relative}.selected-acount-label--tag:hover{background-color:var(--sem-info-surface);box-shadow:0 2px 4px #1976d226}.segment-cell-content{display:flex;align-items:center;justify-content:flex-end;font-weight:500}.vat-badge{display:inline-flex;align-items:center;justify-content:center;height:16px;padding:2px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;background-color:var(--sem-success-surface);color:var(--sem-warning);border:1px solid var(--lib-forms-outline-variant);box-shadow:none;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),border-color var(--lib-forms-duration-hover) var(--lib-forms-easing);flex-shrink:0;align-self:flex-start;margin-top:2px;line-height:1}.vat-badge:hover{background-color:var(--sem-warning-surface);border-color:var(--sem-warning)}.vat-chip-container{padding-left:var(--mscoa-chart-spacing-sm);padding-right:var(--mscoa-chart-spacing-sm);padding-bottom:var(--mscoa-chart-spacing-xs);margin-top:var(--mscoa-chart-spacing-xs)}.vat-chip{display:inline-flex;align-items:center;gap:4px;height:24px;padding:4px 8px;border-radius:12px;font-size:11px;font-weight:600;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),box-shadow var(--lib-forms-duration-hover) var(--lib-forms-easing),transform var(--lib-forms-duration-hover) var(--lib-forms-easing);box-shadow:0 1px 3px #0000001f}.vat-chip--applicable{background:linear-gradient(135deg,var(--sem-warning) 0%,var(--sem-warning) 100%);color:var(--lib-forms-on-primary);border:1px solid var(--sem-warning)}.vat-chip--applicable:hover{box-shadow:0 2px 6px #f57c004d;transform:translateY(-1px)}.vat-chip__icon{font-size:14px;width:14px;height:14px;opacity:.9}.vat-chip__text{font-size:11px;font-weight:600;letter-spacing:.3px}.info-box{display:flex;align-items:center;gap:var(--mscoa-chart-spacing-sm);padding:12px;background:var(--sem-info-surface);border-radius:var(--mscoa-chart-border-radius);margin-bottom:var(--mscoa-chart-spacing-md)}.info-icon{min-width:38px;margin:auto;margin-top:var(--mscoa-chart-spacing-sm)}.empty-state{padding:var(--mscoa-chart-spacing-md);text-align:center;display:flex;align-items:center;justify-content:center;gap:var(--mscoa-chart-spacing-sm);color:var(--mat-sys-on-surface-variant)}.validation-hints{margin-top:var(--mscoa-chart-spacing-md);padding:var(--mscoa-chart-spacing-md);background-color:var(--lib-forms-surface-container-low);border-radius:var(--mscoa-chart-border-radius);border-left:4px solid var(--lib-forms-primary);box-shadow:0 1px 3px #00000014}.validation-hints__title{font-weight:600;font-size:var(--mscoa-chart-font-size-base);margin:0 0 var(--mscoa-chart-spacing-sm) 0;color:var(--lib-forms-on-surface);display:flex;align-items:center;gap:var(--mscoa-chart-spacing-xs)}.validation-hints__title:before{content:\"\\1f4a1\";font-size:16px}.validation-hints__list{margin:0;padding-left:var(--mscoa-chart-spacing-md);color:var(--lib-forms-on-surface-variant);font-size:13px;line-height:1.6}.validation-hints__list li{margin-bottom:var(--mscoa-chart-spacing-sm);position:relative}.validation-hints__list li::marker{color:var(--lib-forms-primary)}.validation-hints__list li:last-child{margin-bottom:0}mat-error{font-size:.75em;margin-top:var(--mscoa-chart-spacing-xs)}mat-error ul{margin:0;padding-left:var(--mscoa-chart-spacing-md)}mat-error li{margin-bottom:var(--mscoa-chart-spacing-xs)}.loading-placeholder{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-on-surface-variant)}.loading-spinner-container{display:flex;justify-content:center;align-items:center;height:256px}.error-state{padding:var(--mscoa-chart-spacing-md);color:var(--mat-sys-error)}mat-panel-description{font-size:.875em;line-height:1.4}:host .main-expanse-content{background:var(--mat-sys-surface-container)}@media(max-width:768px){.dual-basis-container{gap:var(--mscoa-chart-spacing-md)}.cell-button{min-height:44px;font-size:15px;max-width:300px}.content{padding:var(--mscoa-chart-spacing-md)}.validation-hints{font-size:13px;padding:var(--mscoa-chart-spacing-sm)}.inline-hint{font-size:11px}}.cell-button:focus-visible,button:focus-visible{outline:3px solid var(--mat-sys-primary);outline-offset:2px;outline-style:solid}@media(prefers-contrast:high){.cell-button{border:2px solid currentColor}.cell-button:focus-visible{outline-width:4px}.selected-acount-label--error{font-weight:600}}@media(prefers-reduced-motion:reduce){.cell-button,.success-indicator,.fade-in,.validated-indicator{animation:none;transition:none}}.table__cell--active{background-color:var(--mat-sys-primary-container);color:var(--mat-sys-on-primary-container)}@media(prefers-contrast:high){.table__cell--active{background-color:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}}.table__cell--business-error{background-color:var(--lib-forms-error-container);border-left:3px solid var(--lib-forms-error)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInSuccess{0%{background-color:transparent}50%{background-color:var(--sem-success-surface)}to{background-color:var(--mat-sys-primary-container)}}@keyframes scaleIn{0%{transform:scale(0);opacity:0}to{transform:scale(1);opacity:1}}@keyframes validatedShieldIn{0%{opacity:0;transform:scale(.6)}70%{opacity:1;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.fade-in{animation:fadeIn var(--mscoa-chart-transition)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.skeleton-loader{background:linear-gradient(90deg,var(--mat-sys-surface-container) 25%,var(--mat-sys-surface-container-high) 50%,var(--mat-sys-surface-container) 75%);background-size:200% 100%;animation:loading 1.5s ease-in-out infinite;border-radius:var(--mscoa-chart-border-radius)}@keyframes loading{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-row{height:48px;margin-bottom:var(--mscoa-chart-spacing-xs)}.skeleton-cell{height:100%;margin-right:var(--mscoa-chart-spacing-md)}\n"] }]
16507
17040
  }], ctorParameters: () => [], propDecorators: { inputConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputConfig", required: true }] }], editorMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editorMode", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: false }] }], formBuilderFunctions: [{ type: i0.Input, args: [{ isSignal: true, alias: "formBuilderFunctions", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], onContainerClick: [{ type: i0.Output, args: ["onContainerClick"] }], interaction: [{ type: i0.Output, args: ["interaction"] }] } }) });
16508
17041
 
16509
17042
  /**
@@ -17799,9 +18332,9 @@ function builderKind(fn) {
17799
18332
  }
17800
18333
  }
17801
18334
  // --- helpers ----------------------------------------------------------------
17802
- const KEYWORD_OPS = ['includes', 'startsWith', 'endsWith', 'matches', 'in'];
17803
- const SYMBOLIC_OPS = ['===', '!==', '==', '!=', '>=', '<=', '>', '<'];
17804
- const unquote = (v) => {
18335
+ const KEYWORD_OPS$1 = ['includes', 'startsWith', 'endsWith', 'matches', 'in'];
18336
+ const SYMBOLIC_OPS$1 = ['===', '!==', '==', '!=', '>=', '<=', '>', '<'];
18337
+ const unquote$1 = (v) => {
17805
18338
  const t = v.trim();
17806
18339
  if (t.length >= 2) {
17807
18340
  const a = t[0];
@@ -17811,28 +18344,28 @@ const unquote = (v) => {
17811
18344
  }
17812
18345
  return t;
17813
18346
  };
17814
- const isBareLiteral = (v) => v === 'true' || v === 'false' || v === 'null' || (v.trim() !== '' && !Number.isNaN(Number(v)));
18347
+ const isBareLiteral$1 = (v) => v === 'true' || v === 'false' || v === 'null' || (v.trim() !== '' && !Number.isNaN(Number(v)));
17815
18348
  /** Formats a builder value for the expression string (bare for numbers/bools, else quoted). */
17816
- const formatValue = (v) => (isBareLiteral(v.trim()) ? v.trim() : `"${v}"`);
18349
+ const formatValue = (v) => (isBareLiteral$1(v.trim()) ? v.trim() : `"${v}"`);
17817
18350
  const toNum = (v, fallback = 0) => {
17818
18351
  const n = Number(v);
17819
18352
  return Number.isNaN(n) ? fallback : n;
17820
18353
  };
17821
18354
  // --- parse ------------------------------------------------------------------
17822
- function parseCondition(part) {
18355
+ function parseCondition$1(part) {
17823
18356
  const p = part.trim();
17824
- for (const kw of KEYWORD_OPS) {
18357
+ for (const kw of KEYWORD_OPS$1) {
17825
18358
  const m = p.match(new RegExp(`^(.+?)\\s+${kw}\\s+(.+)$`, 'i'));
17826
18359
  if (m && m[1] && m[2])
17827
- return { field: m[1].trim(), operator: kw, value: unquote(m[2]) };
18360
+ return { field: m[1].trim(), operator: kw, value: unquote$1(m[2]) };
17828
18361
  }
17829
- for (const op of SYMBOLIC_OPS) {
18362
+ for (const op of SYMBOLIC_OPS$1) {
17830
18363
  const idx = p.indexOf(op);
17831
18364
  if (idx > 0) {
17832
18365
  const field = p.slice(0, idx).trim();
17833
18366
  const value = p.slice(idx + op.length).trim();
17834
18367
  if (field && value)
17835
- return { field, operator: op, value: unquote(value) };
18368
+ return { field, operator: op, value: unquote$1(value) };
17836
18369
  }
17837
18370
  }
17838
18371
  return null;
@@ -17851,7 +18384,7 @@ function parsePredicate(expr) {
17851
18384
  const parts = hasOr ? e.split('||') : hasAnd ? e.split('&&') : [e];
17852
18385
  const conditions = [];
17853
18386
  for (const part of parts) {
17854
- const c = parseCondition(part);
18387
+ const c = parseCondition$1(part);
17855
18388
  if (!c)
17856
18389
  return null;
17857
18390
  conditions.push(c);
@@ -17884,7 +18417,7 @@ function parseProjection(expr) {
17884
18417
  items.push({ type: 'rename', alias: (segs[segs.length - 1] ?? '').trim(), path });
17885
18418
  }
17886
18419
  else if (!hasBrace && c !== -1) {
17887
- items.push({ type: 'literal', alias: t.slice(0, c).trim(), value: unquote(t.slice(c + 1)) });
18420
+ items.push({ type: 'literal', alias: t.slice(0, c).trim(), value: unquote$1(t.slice(c + 1)) });
17888
18421
  }
17889
18422
  else if (/^[\w.$-]+$/.test(t)) {
17890
18423
  items.push({ type: 'field', field: t });
@@ -18562,7 +19095,7 @@ class DataTreeComponent {
18562
19095
  setTimeout(() => textarea?.setSelectionRange(newCursorPosition, newCursorPosition), 0);
18563
19096
  }
18564
19097
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DataTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
18565
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DataTreeComponent, isStandalone: true, selector: "lib-data-tree", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pathChanged: "pathChanged" }, host: { classAttribute: "lib-data-tree" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-accordion multi class=\"surface\">\n <!-- 1 - Pick the data -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">dataset_linked</mat-icon>\n <span class=\"panel-title\">1 &middot; Pick your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">touch_app</mat-icon>\n <span>Tick a field to map it. Pick an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) to transform its items next.</span>\n </p>\n\n <mat-tree [dataSource]=\"treeClass.dataSource\" [treeControl]=\"treeClass.treeControl\" class=\"data-tree\">\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodePadding>\n <span class=\"node-spacer\" aria-hidden=\"true\"></span>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" class=\"node-checkbox\"\n [matTooltip]=\"'Map field: ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n <span class=\"node-value\" [style.color]=\"getNodeValueColor(node.value)\">{{ node.value }}</span>\n </mat-checkbox>\n </mat-tree-node>\n\n <mat-tree-node *matTreeNodeDef=\"let node; when: treeClass.hasChild\" matTreeNodePadding>\n <button class=\"node-toggle\" mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.key\">\n <mat-icon>{{ treeClass.treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" [matTooltip]=\"'Select ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n </mat-checkbox>\n </mat-tree-node>\n </mat-tree>\n </div>\n </mat-expansion-panel>\n\n <!-- 2 - Build the pipeline -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">account_tree</mat-icon>\n <span class=\"panel-title\">2 &middot; Transform your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (treeClass.activePath.length === 0) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">arrow_upward</mat-icon>\n <span>Select a field above to begin.</span>\n </p>\n } @else {\n <nav class=\"breadcrumb\" aria-label=\"Selected path\">\n @for (path of treeClass.activePath; track trackByPath($index, path); let isLast = $last) {\n <button type=\"button\" class=\"crumb\" [class.crumb-active]=\"path.inEdit\"\n [class.crumb-array]=\"path.keyIsArrayIndex\" [disabled]=\"!path.keyIsArrayIndex && !path.inEdit\"\n [matTooltip]=\"path.keyIsArrayIndex ? 'Transform this array' : path.key\" (click)=\"setupPath(path)\">\n <mat-icon>{{ path.keyIsArrayIndex ? 'data_array' : 'folder' }}</mat-icon>\n <span class=\"crumb-text\">{{ path.key }}</span>\n @if (path.functions.length > 0) { <span class=\"crumb-badge\">{{ path.functions.length }}</span> }\n </button>\n @if (!isLast) { <mat-icon class=\"crumb-sep\">chevron_right</mat-icon> }\n }\n </nav>\n\n @if (hasANodeInEdit()) {\n <div class=\"pipeline\" role=\"list\" aria-label=\"Transform pipeline\">\n <span class=\"stage stage-source\" role=\"listitem\">\n <mat-icon>database</mat-icon>\n <span class=\"stage-label\">Source</span>\n </span>\n\n @for (step of steps; track step.id; let i = $index) {\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-step\" role=\"listitem\" [class.stage-active]=\"step.inEdit\"\n [class.stage-empty]=\"!step.function\" (click)=\"editFunction(step.id)\"\n [matTooltip]=\"functionMeta(step.function)?.hint || 'Choose an operation'\">\n <mat-icon>{{ functionMeta(step.function)?.icon || 'help_outline' }}</mat-icon>\n <span class=\"stage-label\">{{ (step.function | titlecase) || 'Choose' }}</span>\n @if (stepRowCount(i); as n) {\n <span class=\"stage-count\">{{ n }} {{ n === 1 ? 'row' : 'rows' }}</span>\n }\n </button>\n }\n\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-add\" [matMenuTriggerFor]=\"addMenu\" matTooltip=\"Add a transform step\">\n <mat-icon>add</mat-icon>\n <span class=\"stage-label\">Add</span>\n </button>\n <mat-menu #addMenu=\"matMenu\">\n @for (option of functionOptions; track option.value) {\n <button mat-menu-item (click)=\"addStep(option.value)\">\n <mat-icon>{{ option.icon }}</mat-icon>\n <span>{{ option.label }}</span>\n <span class=\"menu-hint\">{{ option.hint }}</span>\n </button>\n }\n </mat-menu>\n </div>\n\n @if (getFunctionInEdit(); as fn) {\n <section class=\"editor\">\n <label class=\"f-field full\">\n <span class=\"f-label\">Operation</span>\n <select class=\"f-control\" [value]=\"fn.function\" (change)=\"functionChanged(inputValue($event))\">\n <option value=\"\" disabled>Choose what this step does</option>\n @for (option of functionOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n </label>\n @if (fn.function && activeFunctionMeta(); as meta) {\n <p class=\"sub-hint\">{{ meta.hint }}</p>\n }\n\n @if (!fn.function) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">info</mat-icon>\n <span>Choose an operation to configure this step.</span>\n </p>\n } @else {\n @if (rawMode()) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Expression</span>\n <textarea class=\"f-control f-textarea\" #textarea rows=\"2\" [value]=\"fn.expression\"\n (input)=\"onRawChange($event)\" (focus)=\"onFocus()\" placeholder=\"Type the raw expression\"></textarea>\n </label>\n <p class=\"sub-hint\">Type <code>$</code> to insert a field or operator.</p>\n\n @if (showSuggestions()) {\n <div class=\"suggestions\">\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Operators</span>\n <div class=\"chip-row\">\n @for (method of getMethods(); track method.value) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(method.value)\">\n {{ method.value }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Inputs</span>\n <div class=\"chip-row\">\n @for (input of getAllInputs(); track input.formControlName) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(input.formControlName)\">\n {{ input.label }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n } @else {\n @switch (activeKind()) {\n @case ('predicate') {\n @if (predicate(); as p) {\n @if (p.conditions.length > 1) {\n <div class=\"match-row\">\n <span class=\"field-label\">Match</span>\n <mat-button-toggle-group class=\"seg\" [value]=\"p.connector\" hideSingleSelectionIndicator\n (change)=\"setConnector($event.value)\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"muted\">of the conditions</span>\n </div>\n }\n @for (cond of p.conditions; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(cond.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <div class=\"q-pair q-pair-op\">\n <label class=\"f-field\">\n <span class=\"f-label\">Operator</span>\n <select class=\"f-control\" [value]=\"cond.operator\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) { <option [value]=\"op.value\">{{ op.label }}</option> }\n </select>\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Value</span>\n <input class=\"f-control\" [value]=\"cond.value\" placeholder=\"active, 18, Durban\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\">\n </label>\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeCondition($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add condition\n </button>\n }\n }\n\n @case ('project') {\n @if (projection(); as proj) {\n <span class=\"field-label\">Keep fields</span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"fieldPicked(f)\" (change)=\"toggleField(f)\">{{ f }}</mat-checkbox>\n }\n <mat-checkbox [checked]=\"hasSpread()\" (change)=\"toggleSpread()\"\n matTooltip=\"Include every field\">everything (*)</mat-checkbox>\n </div>\n\n <div class=\"section-head\">\n <span class=\"field-label\">Mapped fields</span>\n <span class=\"section-actions\">\n <button type=\"button\" class=\"link-btn\" (click)=\"addRename()\"><mat-icon>add</mat-icon> Field</button>\n <button type=\"button\" class=\"link-btn\" (click)=\"addLiteral()\"><mat-icon>add</mat-icon> Constant</button>\n </span>\n </div>\n\n @for (r of renameItems(); track r.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">New name</span>\n <input class=\"f-control\" [value]=\"r.item.alias\"\n (input)=\"updateItem(r.index, { alias: inputValue($event) })\">\n </label>\n <div class=\"f-field\">\n <span class=\"f-label\">From path</span>\n <button type=\"button\" class=\"f-control f-picker\" [matMenuTriggerFor]=\"pathMenu\">\n <span class=\"f-picker-text\" [class.f-placeholder]=\"!r.item.path\">{{ r.item.path || 'Select a path' }}</span>\n <mat-icon>account_tree</mat-icon>\n </button>\n <mat-menu #pathMenu=\"matMenu\" class=\"path-menu\">\n @for (p of availableDeepPaths(); track p.path) {\n <button mat-menu-item class=\"path-item\" [style.padding-left.px]=\"12 + p.depth * 14\"\n (click)=\"updateItem(r.index, { path: p.path })\">\n <mat-icon class=\"path-icon\">{{ p.leaf ? 'chevron_right' : 'folder_open' }}</mat-icon>\n <span>{{ p.name }}</span>\n </button>\n } @empty {\n <button mat-menu-item disabled>No paths detected</button>\n }\n </mat-menu>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(r.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n @for (l of literalItems(); track l.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field name</span>\n <input class=\"f-control\" [value]=\"l.item.alias\"\n (input)=\"updateItem(l.index, { alias: inputValue($event) })\">\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Constant</span>\n <input class=\"f-control\" [value]=\"l.item.value\" placeholder='\"api\", 1, true'\n (input)=\"updateItem(l.index, { value: inputValue($event) })\">\n </label>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(l.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n }\n }\n\n @case ('sort') {\n @if (sort(); as s) {\n @for (key of s.keys; track $index) {\n <div class=\"q-item\">\n <div class=\"q-pair q-pair-sort\">\n <label class=\"f-field\">\n <span class=\"f-label\">Sort by</span>\n <select class=\"f-control\" [value]=\"key.field\"\n (change)=\"updateSortKey($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(key.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <mat-button-toggle-group class=\"seg seg-dir\" [value]=\"key.dir\" hideSingleSelectionIndicator\n (change)=\"updateSortKey($index, { dir: $event.value })\">\n <mat-button-toggle value=\"asc\" matTooltip=\"Ascending\"><mat-icon>arrow_upward</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"desc\" matTooltip=\"Descending\"><mat-icon>arrow_downward</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeSortKey($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addSortKey()\">\n <mat-icon>add</mat-icon> Add sort key\n </button>\n }\n }\n\n @case ('slice') {\n @if (slice(); as sl) {\n <div class=\"field-grid\">\n <label class=\"f-field\">\n <span class=\"f-label\">Take</span>\n <select class=\"f-control\" [value]=\"sl.mode\" (change)=\"setSliceMode(inputValue($event))\">\n @for (mode of sliceModes; track mode.value) { <option [value]=\"mode.value\">{{ mode.label }}</option> }\n </select>\n </label>\n @switch (sl.mode) {\n @case ('range') {\n <label class=\"f-field\"><span class=\"f-label\">Start</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">End</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @case ('fromCount') {\n <label class=\"f-field\"><span class=\"f-label\">From index</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">Count</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @default {\n <label class=\"f-field\"><span class=\"f-label\">How many</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n }\n </div>\n }\n }\n\n @case ('keys') {\n @if (keysModel(); as k) {\n <span class=\"field-label\">\n @if (isUnique(fn.function)) { Unique by &mdash; none = whole row } @else { Group by }\n </span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"keyPicked(f)\" (change)=\"toggleKey(f)\">{{ f }}</mat-checkbox>\n }\n </div>\n @if (availableFields().length === 0) {\n <p class=\"hint-line\"><mat-icon class=\"info-icon\">info</mat-icon>\n <span>No fields detected &mdash; use Advanced to type a key path.</span></p>\n }\n }\n }\n\n @case ('flatten') {\n @if (flatten(); as fl) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Flatten</span>\n <select class=\"f-control\" [value]=\"fl.path\" (change)=\"setFlatten(inputValue($event))\">\n <option [value]=\"''\">nested arrays (one level)</option>\n @for (f of fieldOptionsWith(fl.path); track f) { <option [value]=\"f\">items in {{ f }}</option> }\n </select>\n </label>\n <p class=\"sub-hint\">Blank flattens one level; a field flat-maps that child array.</p>\n }\n }\n\n @case ('reduce') {\n @if (reduce(); as red) {\n @for (agg of red.aggs; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n @if (red.aggs.length > 1) {\n <label class=\"f-field\">\n <span class=\"f-label\">Output name</span>\n <input class=\"f-control\" [value]=\"agg.alias\"\n (input)=\"updateAgg($index, { alias: inputValue($event) })\">\n </label>\n }\n <div class=\"q-pair\">\n <label class=\"f-field\">\n <span class=\"f-label\">Aggregate</span>\n <select class=\"f-control\" [value]=\"agg.agg\"\n (change)=\"updateAgg($index, { agg: inputValue($event) })\">\n @for (a of aggregates; track a.value) { <option [value]=\"a.value\">{{ a.label }}</option> }\n </select>\n </label>\n @if (aggNeedsField(agg.agg)) {\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"agg.field\"\n (change)=\"updateAgg($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(agg.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n }\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeAgg($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addAgg()\">\n <mat-icon>add</mat-icon> Add aggregate\n </button>\n }\n }\n }\n }\n\n <div class=\"editor-foot\">\n <button type=\"button\" class=\"link-btn\" (click)=\"toggleRaw()\">\n @if (rawMode()) { <mat-icon>view_module</mat-icon> Guided }\n @else { <mat-icon>code</mat-icon> Advanced }\n </button>\n </div>\n }\n\n <div class=\"editor-actions\">\n <button mat-icon-button (click)=\"moveStep(fn.id, -1)\" matTooltip=\"Move earlier\"\n aria-label=\"Move step earlier\"><mat-icon>chevron_left</mat-icon></button>\n <button mat-icon-button (click)=\"moveStep(fn.id, 1)\" matTooltip=\"Move later\"\n aria-label=\"Move step later\"><mat-icon>chevron_right</mat-icon></button>\n <button mat-icon-button (click)=\"removeFunction(fn.id)\" matTooltip=\"Remove step\"\n aria-label=\"Remove step\"><mat-icon>delete_outline</mat-icon></button>\n <span class=\"spacer\"></span>\n <button mat-flat-button color=\"primary\" (click)=\"saveNodeInEdit()\">\n <mat-icon>check</mat-icon> Apply\n </button>\n </div>\n </section>\n }\n } @else {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">data_array</mat-icon>\n <span>Click an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) in the path above to add steps.</span>\n </p>\n }\n }\n </div>\n </mat-expansion-panel>\n\n <!-- 3 - Preview -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">preview</mat-icon>\n <span class=\"panel-title\">3 &middot; Result preview</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (resultRowCount(); as n) {\n <span class=\"result-count\"><mat-icon>check_circle</mat-icon> {{ n }} {{ n === 1 ? 'result' : 'results' }}</span>\n }\n <div class=\"mapped-value\">\n <pre>{{ mappedValue | json }}</pre>\n </div>\n </div>\n </mat-expansion-panel>\n</mat-accordion>\n", styles: ["@charset \"UTF-8\";:host{display:block}.surface mat-expansion-panel{background:var(--mat-sys-surface-container-low, var(--lib-forms-surface-container-low))}:host ::ng-deep .mat-expansion-panel-header{height:44px;padding:0 .875rem}:host ::ng-deep .mat-expansion-panel-body{padding:0 .875rem .75rem}button mat-icon{vertical-align:middle}.panel-title{font-size:.875rem;font-weight:500;letter-spacing:-.01em}.title-icon{margin-right:.625rem;vertical-align:middle;color:var(--lib-forms-on-surface-variant)}.content{display:flex;flex-direction:column;gap:.875rem;padding:.5rem 0 .25rem}.hint-line{display:flex;align-items:center;gap:.5rem;margin:0;font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.info-icon{color:var(--sem-info, var(--lib-forms-primary));flex:none}.inline-icon{font-size:1rem;width:1rem;height:1rem;vertical-align:text-bottom}.field-label{font-size:.625rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.muted{font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.data-tree{background:var(--lib-forms-surface-container-low);border-radius:var(--lib-forms-radius-md);padding:.5rem .75rem;min-width:fit-content}:host mat-tree-node{min-height:34px}.node-spacer{display:inline-block;width:36px}.node-toggle{color:var(--lib-forms-on-surface-variant)}.node-checkbox{width:100%}.node-key{font-weight:500;color:var(--lib-forms-on-surface);margin-right:.5rem}.node-value{font-family:var(--lib-forms-font-mono, monospace);padding:.0625rem .4375rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm);font-size:.8125rem;white-space:nowrap}.breadcrumb{display:flex;align-items:center;flex-wrap:wrap;gap:.125rem}.crumb{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;max-width:9rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-on-surface-variant);background:transparent;border:0;border-radius:var(--lib-forms-radius-pill);cursor:pointer;white-space:nowrap;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.crumb:hover:not(:disabled){background:var(--lib-forms-surface-container-high)}.crumb:disabled{cursor:default;opacity:.65}.crumb mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.crumb-text{overflow:hidden;text-overflow:ellipsis}.crumb-array{color:var(--lib-forms-primary)}.crumb-active,.crumb-active:hover:not(:disabled){background:var(--lib-forms-primary-container);color:var(--lib-forms-on-surface)}.crumb-badge{min-width:1.0625rem;padding:0 .3125rem;border-radius:var(--lib-forms-radius-pill);background:var(--lib-forms-primary);color:var(--mat-sys-on-primary, #fff);font-size:.625rem;line-height:1.0625rem;text-align:center}.crumb-sep{color:var(--lib-forms-outline);font-size:1rem;width:1rem;height:1rem}.pipeline{display:flex;align-items:stretch;flex-wrap:wrap;gap:.375rem}.stage{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:.0625rem;min-width:4rem;padding:.375rem .5rem;border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md);background:var(--lib-forms-surface-container-low);color:var(--lib-forms-on-surface);cursor:pointer;transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing),background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.stage mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.stage-source{cursor:default;color:var(--lib-forms-on-surface-variant);background:transparent;border-style:dashed}.stage-active{border-color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.stage-empty{border-style:dashed;color:var(--lib-forms-on-surface-variant)}.stage-add{border-style:dashed;color:var(--lib-forms-primary);min-width:3.75rem}.stage-label{font-size:.75rem;font-weight:500}.stage-count{font-size:.625rem;color:var(--lib-forms-on-surface-variant)}.flow-arrow{align-self:center;color:var(--lib-forms-outline);font-size:1.125rem;width:1rem;height:1.125rem}.menu-hint{display:block;font-size:.6875rem;color:var(--lib-forms-on-surface-variant)}.editor{display:flex;flex-direction:column;gap:.75rem;padding:1.125rem;border-radius:var(--lib-forms-radius-lg);background:var(--lib-forms-surface-container-low);box-shadow:var(--mat-sys-level1, 0 1px 3px rgba(0, 0, 0, .12))}.full{width:100%}.f-field{display:flex;flex-direction:column;gap:.1875rem;min-width:0}.f-label{font-size:.625rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.f-control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.25;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm);transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}select.f-control{cursor:pointer}.f-textarea{height:auto;min-height:3rem;line-height:1.4;resize:vertical}.f-control:hover{border-color:var(--lib-forms-outline)}.f-control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.sub-hint{margin:-.25rem 0 0;font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.section-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-top:.25rem}.section-actions{display:flex;gap:.25rem}.map-row{display:grid;grid-template-columns:1fr 1fr auto;align-items:end;gap:.5rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-item{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.25rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-stack{display:flex;flex-direction:column;gap:.5rem;min-width:0}.q-pair{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;min-width:0}.q-pair-op{grid-template-columns:8rem 1fr}.q-pair-sort{grid-template-columns:1fr auto;align-items:end}.q-remove{color:var(--lib-forms-on-surface-variant)}.field-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(6.5rem,1fr));gap:.5rem}.match-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.seg{--mat-standard-button-toggle-height: 34px;height:34px}.checklist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.125rem 1rem;padding:.25rem 0}.link-btn{display:inline-flex;align-items:center;align-self:flex-start;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm);cursor:pointer;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.link-btn:hover{background:var(--lib-forms-primary-container)}.link-btn mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.f-picker{display:flex;align-items:center;justify-content:space-between;gap:.25rem;text-align:left;cursor:pointer}.f-picker-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.f-placeholder{color:var(--lib-forms-on-surface-variant)}.f-picker mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem;color:var(--lib-forms-on-surface-variant)}.path-icon{margin-right:.25rem;font-size:1rem;width:1rem;height:1rem;color:var(--lib-forms-on-surface-variant)}.editor-foot{display:flex;justify-content:flex-end;margin-top:-.25rem}.editor-actions{display:flex;align-items:center;gap:.125rem;padding-top:.5rem}.spacer{flex:1}.suggestions{display:flex;gap:1rem;flex-wrap:wrap;padding:.75rem;border-radius:var(--lib-forms-radius-md);background:var(--sem-info-surface, var(--lib-forms-surface-container))}.suggestion-group{flex:1 1 10rem;display:flex;flex-direction:column;gap:.375rem}.chip-row{display:flex;flex-wrap:wrap;gap:.25rem}.ins-chip{font-size:.75rem}.result-count{display:inline-flex;align-items:center;gap:.375rem;font-size:.8125rem;font-weight:500;color:var(--sem-emerald, var(--lib-forms-method-get))}.result-count mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mapped-value{padding:1rem 1.25rem;background:var(--lib-forms-on-surface);color:var(--lib-forms-surface);border-radius:var(--lib-forms-radius-md);overflow:auto}.mapped-value pre{margin:0;font-family:var(--lib-forms-font-mono, monospace);font-size:.8125rem}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i2$2.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i2$2.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$3.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$3.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$3.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$3.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.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$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i1$4.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: i1$4.MatTreeNodePadding, selector: "[matTreeNodePadding]", inputs: ["matTreeNodePadding", "matTreeNodePaddingIndent"] }, { kind: "directive", type: i1$4.MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "component", type: i1$4.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i1$4.MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
19098
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: DataTreeComponent, isStandalone: true, selector: "lib-data-tree", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { pathChanged: "pathChanged" }, host: { classAttribute: "lib-data-tree" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-accordion multi class=\"surface\">\n <!-- 1 - Pick the data -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">dataset_linked</mat-icon>\n <span class=\"panel-title\">1 &middot; Pick your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">touch_app</mat-icon>\n <span>Tick a field to map it. Pick an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) to transform its items next.</span>\n </p>\n\n <mat-tree [dataSource]=\"treeClass.dataSource\" [treeControl]=\"treeClass.treeControl\" class=\"data-tree\">\n <mat-tree-node *matTreeNodeDef=\"let node\" matTreeNodePadding>\n <span class=\"node-spacer\" aria-hidden=\"true\"></span>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" class=\"node-checkbox\"\n [matTooltip]=\"'Map field: ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n <span class=\"node-value\" [style.color]=\"getNodeValueColor(node.value)\">{{ node.value }}</span>\n </mat-checkbox>\n </mat-tree-node>\n\n <mat-tree-node *matTreeNodeDef=\"let node; when: treeClass.hasChild\" matTreeNodePadding>\n <button class=\"node-toggle\" mat-icon-button matTreeNodeToggle [attr.aria-label]=\"'Toggle ' + node.key\">\n <mat-icon>{{ treeClass.treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n <mat-checkbox (change)=\"update(node)\" [checked]=\"nodeIsChecked(node)\" [matTooltip]=\"'Select ' + node.key\">\n <span class=\"node-key\">{{ node.key }}</span>\n </mat-checkbox>\n </mat-tree-node>\n </mat-tree>\n </div>\n </mat-expansion-panel>\n\n <!-- 2 - Build the pipeline -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">account_tree</mat-icon>\n <span class=\"panel-title\">2 &middot; Transform your data</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (treeClass.activePath.length === 0) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">arrow_upward</mat-icon>\n <span>Select a field above to begin.</span>\n </p>\n } @else {\n <nav class=\"breadcrumb\" aria-label=\"Selected path\">\n @for (path of treeClass.activePath; track trackByPath($index, path); let isLast = $last) {\n <button type=\"button\" class=\"crumb\" [class.crumb-active]=\"path.inEdit\"\n [class.crumb-array]=\"path.keyIsArrayIndex\" [disabled]=\"!path.keyIsArrayIndex && !path.inEdit\"\n [matTooltip]=\"path.keyIsArrayIndex ? 'Transform this array' : path.key\" (click)=\"setupPath(path)\">\n <mat-icon>{{ path.keyIsArrayIndex ? 'data_array' : 'folder' }}</mat-icon>\n <span class=\"crumb-text\">{{ path.key }}</span>\n @if (path.functions.length > 0) { <span class=\"crumb-badge\">{{ path.functions.length }}</span> }\n </button>\n @if (!isLast) { <mat-icon class=\"crumb-sep\">chevron_right</mat-icon> }\n }\n </nav>\n\n @if (hasANodeInEdit()) {\n <div class=\"pipeline\" role=\"list\" aria-label=\"Transform pipeline\">\n <span class=\"stage stage-source\" role=\"listitem\">\n <mat-icon>database</mat-icon>\n <span class=\"stage-label\">Source</span>\n </span>\n\n @for (step of steps; track step.id; let i = $index) {\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-step\" role=\"listitem\" [class.stage-active]=\"step.inEdit\"\n [class.stage-empty]=\"!step.function\" (click)=\"editFunction(step.id)\"\n [matTooltip]=\"functionMeta(step.function)?.hint || 'Choose an operation'\">\n <mat-icon>{{ functionMeta(step.function)?.icon || 'help_outline' }}</mat-icon>\n <span class=\"stage-label\">{{ (step.function | titlecase) || 'Choose' }}</span>\n @if (stepRowCount(i); as n) {\n <span class=\"stage-count\">{{ n }} {{ n === 1 ? 'row' : 'rows' }}</span>\n }\n </button>\n }\n\n <mat-icon class=\"flow-arrow\">chevron_right</mat-icon>\n <button class=\"stage stage-add\" [matMenuTriggerFor]=\"addMenu\" matTooltip=\"Add a transform step\">\n <mat-icon>add</mat-icon>\n <span class=\"stage-label\">Add</span>\n </button>\n <mat-menu #addMenu=\"matMenu\">\n @for (option of functionOptions; track option.value) {\n <button mat-menu-item (click)=\"addStep(option.value)\">\n <mat-icon>{{ option.icon }}</mat-icon>\n <span>{{ option.label }}</span>\n <span class=\"menu-hint\">{{ option.hint }}</span>\n </button>\n }\n </mat-menu>\n </div>\n\n @if (getFunctionInEdit(); as fn) {\n <section class=\"editor\">\n <label class=\"f-field full\">\n <span class=\"f-label\">Operation</span>\n <select class=\"f-control\" [value]=\"fn.function\" (change)=\"functionChanged(inputValue($event))\">\n <option value=\"\" disabled>Choose what this step does</option>\n @for (option of functionOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.label }}</option>\n }\n </select>\n </label>\n @if (fn.function && activeFunctionMeta(); as meta) {\n <p class=\"sub-hint\">{{ meta.hint }}</p>\n }\n\n @if (!fn.function) {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">info</mat-icon>\n <span>Choose an operation to configure this step.</span>\n </p>\n } @else {\n @if (rawMode()) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Expression</span>\n <textarea class=\"f-control f-textarea\" #textarea rows=\"2\" [value]=\"fn.expression\"\n (input)=\"onRawChange($event)\" (focus)=\"onFocus()\" placeholder=\"Type the raw expression\"></textarea>\n </label>\n <p class=\"sub-hint\">Type <code>$</code> to insert a field or operator.</p>\n\n @if (showSuggestions()) {\n <div class=\"suggestions\">\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Operators</span>\n <div class=\"chip-row\">\n @for (method of getMethods(); track method.value) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(method.value)\">\n {{ method.value }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-group\">\n <span class=\"field-label\">Inputs</span>\n <div class=\"chip-row\">\n @for (input of getAllInputs(); track input.formControlName) {\n <button mat-stroked-button class=\"ins-chip\" (click)=\"selectSuggestionInput(input.formControlName)\">\n {{ input.label }}\n </button>\n }\n </div>\n </div>\n </div>\n }\n } @else {\n @switch (activeKind()) {\n @case ('predicate') {\n @if (predicate(); as p) {\n @if (p.conditions.length > 1) {\n <div class=\"match-row\">\n <span class=\"field-label\">Match</span>\n <mat-button-toggle-group class=\"seg\" [value]=\"p.connector\" hideSingleSelectionIndicator\n (change)=\"setConnector($event.value)\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"muted\">of the conditions</span>\n </div>\n }\n @for (cond of p.conditions; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(cond.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <div class=\"q-pair q-pair-op\">\n <label class=\"f-field\">\n <span class=\"f-label\">Operator</span>\n <select class=\"f-control\" [value]=\"cond.operator\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) { <option [value]=\"op.value\">{{ op.label }}</option> }\n </select>\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Value</span>\n <input class=\"f-control\" [value]=\"cond.value\" placeholder=\"active, 18, Durban\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\">\n </label>\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeCondition($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add condition\n </button>\n }\n }\n\n @case ('project') {\n @if (projection(); as proj) {\n <span class=\"field-label\">Keep fields</span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"fieldPicked(f)\" (change)=\"toggleField(f)\">{{ f }}</mat-checkbox>\n }\n <mat-checkbox [checked]=\"hasSpread()\" (change)=\"toggleSpread()\"\n matTooltip=\"Include every field\">everything (*)</mat-checkbox>\n </div>\n\n <div class=\"section-head\">\n <span class=\"field-label\">Mapped fields</span>\n <span class=\"section-actions\">\n <button type=\"button\" class=\"link-btn\" (click)=\"addRename()\"><mat-icon>add</mat-icon> Field</button>\n <button type=\"button\" class=\"link-btn\" (click)=\"addLiteral()\"><mat-icon>add</mat-icon> Constant</button>\n </span>\n </div>\n\n @for (r of renameItems(); track r.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">New name</span>\n <input class=\"f-control\" [value]=\"r.item.alias\"\n (input)=\"updateItem(r.index, { alias: inputValue($event) })\">\n </label>\n <div class=\"f-field\">\n <span class=\"f-label\">From path</span>\n <button type=\"button\" class=\"f-control f-picker\" [matMenuTriggerFor]=\"pathMenu\">\n <span class=\"f-picker-text\" [class.f-placeholder]=\"!r.item.path\">{{ r.item.path || 'Select a path' }}</span>\n <mat-icon>account_tree</mat-icon>\n </button>\n <mat-menu #pathMenu=\"matMenu\" class=\"path-menu\">\n @for (p of availableDeepPaths(); track p.path) {\n <button mat-menu-item class=\"path-item\" [style.padding-left.px]=\"12 + p.depth * 14\"\n (click)=\"updateItem(r.index, { path: p.path })\">\n <mat-icon class=\"path-icon\">{{ p.leaf ? 'chevron_right' : 'folder_open' }}</mat-icon>\n <span>{{ p.name }}</span>\n </button>\n } @empty {\n <button mat-menu-item disabled>No paths detected</button>\n }\n </mat-menu>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(r.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n @for (l of literalItems(); track l.index) {\n <div class=\"map-row\">\n <label class=\"f-field\">\n <span class=\"f-label\">Field name</span>\n <input class=\"f-control\" [value]=\"l.item.alias\"\n (input)=\"updateItem(l.index, { alias: inputValue($event) })\">\n </label>\n <label class=\"f-field\">\n <span class=\"f-label\">Constant</span>\n <input class=\"f-control\" [value]=\"l.item.value\" placeholder='\"api\", 1, true'\n (input)=\"updateItem(l.index, { value: inputValue($event) })\">\n </label>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeItem(l.index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n }\n }\n\n @case ('sort') {\n @if (sort(); as s) {\n @for (key of s.keys; track $index) {\n <div class=\"q-item\">\n <div class=\"q-pair q-pair-sort\">\n <label class=\"f-field\">\n <span class=\"f-label\">Sort by</span>\n <select class=\"f-control\" [value]=\"key.field\"\n (change)=\"updateSortKey($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(key.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n <mat-button-toggle-group class=\"seg seg-dir\" [value]=\"key.dir\" hideSingleSelectionIndicator\n (change)=\"updateSortKey($index, { dir: $event.value })\">\n <mat-button-toggle value=\"asc\" matTooltip=\"Ascending\"><mat-icon>arrow_upward</mat-icon></mat-button-toggle>\n <mat-button-toggle value=\"desc\" matTooltip=\"Descending\"><mat-icon>arrow_downward</mat-icon></mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeSortKey($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addSortKey()\">\n <mat-icon>add</mat-icon> Add sort key\n </button>\n }\n }\n\n @case ('slice') {\n @if (slice(); as sl) {\n <div class=\"field-grid\">\n <label class=\"f-field\">\n <span class=\"f-label\">Take</span>\n <select class=\"f-control\" [value]=\"sl.mode\" (change)=\"setSliceMode(inputValue($event))\">\n @for (mode of sliceModes; track mode.value) { <option [value]=\"mode.value\">{{ mode.label }}</option> }\n </select>\n </label>\n @switch (sl.mode) {\n @case ('range') {\n <label class=\"f-field\"><span class=\"f-label\">Start</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">End</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @case ('fromCount') {\n <label class=\"f-field\"><span class=\"f-label\">From index</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.a\" (input)=\"setSliceA($event)\"></label>\n <label class=\"f-field\"><span class=\"f-label\">Count</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n @default {\n <label class=\"f-field\"><span class=\"f-label\">How many</span>\n <input class=\"f-control\" type=\"number\" [value]=\"sl.b\" (input)=\"setSliceB($event)\"></label>\n }\n }\n </div>\n }\n }\n\n @case ('keys') {\n @if (keysModel(); as k) {\n <span class=\"field-label\">\n @if (isUnique(fn.function)) { Unique by &mdash; none = whole row } @else { Group by }\n </span>\n <div class=\"checklist\">\n @for (f of availableFields(); track f) {\n <mat-checkbox [checked]=\"keyPicked(f)\" (change)=\"toggleKey(f)\">{{ f }}</mat-checkbox>\n }\n </div>\n @if (availableFields().length === 0) {\n <p class=\"hint-line\"><mat-icon class=\"info-icon\">info</mat-icon>\n <span>No fields detected &mdash; use Advanced to type a key path.</span></p>\n }\n }\n }\n\n @case ('flatten') {\n @if (flatten(); as fl) {\n <label class=\"f-field full\">\n <span class=\"f-label\">Flatten</span>\n <select class=\"f-control\" [value]=\"fl.path\" (change)=\"setFlatten(inputValue($event))\">\n <option [value]=\"''\">nested arrays (one level)</option>\n @for (f of fieldOptionsWith(fl.path); track f) { <option [value]=\"f\">items in {{ f }}</option> }\n </select>\n </label>\n <p class=\"sub-hint\">Blank flattens one level; a field flat-maps that child array.</p>\n }\n }\n\n @case ('reduce') {\n @if (reduce(); as red) {\n @for (agg of red.aggs; track $index) {\n <div class=\"q-item\">\n <div class=\"q-stack\">\n @if (red.aggs.length > 1) {\n <label class=\"f-field\">\n <span class=\"f-label\">Output name</span>\n <input class=\"f-control\" [value]=\"agg.alias\"\n (input)=\"updateAgg($index, { alias: inputValue($event) })\">\n </label>\n }\n <div class=\"q-pair\">\n <label class=\"f-field\">\n <span class=\"f-label\">Aggregate</span>\n <select class=\"f-control\" [value]=\"agg.agg\"\n (change)=\"updateAgg($index, { agg: inputValue($event) })\">\n @for (a of aggregates; track a.value) { <option [value]=\"a.value\">{{ a.label }}</option> }\n </select>\n </label>\n @if (aggNeedsField(agg.agg)) {\n <label class=\"f-field\">\n <span class=\"f-label\">Field</span>\n <select class=\"f-control\" [value]=\"agg.field\"\n (change)=\"updateAgg($index, { field: inputValue($event) })\">\n @for (f of fieldOptionsWith(agg.field); track f) { <option [value]=\"f\">{{ f }}</option> }\n </select>\n </label>\n }\n </div>\n </div>\n <button mat-icon-button class=\"q-remove\" (click)=\"removeAgg($index)\"\n matTooltip=\"Remove\"><mat-icon>close</mat-icon></button>\n </div>\n }\n <button type=\"button\" class=\"link-btn\" (click)=\"addAgg()\">\n <mat-icon>add</mat-icon> Add aggregate\n </button>\n }\n }\n }\n }\n\n <div class=\"editor-foot\">\n <button type=\"button\" class=\"link-btn\" (click)=\"toggleRaw()\">\n @if (rawMode()) { <mat-icon>view_module</mat-icon> Guided }\n @else { <mat-icon>code</mat-icon> Advanced }\n </button>\n </div>\n }\n\n <div class=\"editor-actions\">\n <button mat-icon-button (click)=\"moveStep(fn.id, -1)\" matTooltip=\"Move earlier\"\n aria-label=\"Move step earlier\"><mat-icon>chevron_left</mat-icon></button>\n <button mat-icon-button (click)=\"moveStep(fn.id, 1)\" matTooltip=\"Move later\"\n aria-label=\"Move step later\"><mat-icon>chevron_right</mat-icon></button>\n <button mat-icon-button (click)=\"removeFunction(fn.id)\" matTooltip=\"Remove step\"\n aria-label=\"Remove step\"><mat-icon>delete_outline</mat-icon></button>\n <span class=\"spacer\"></span>\n <button mat-flat-button color=\"primary\" (click)=\"saveNodeInEdit()\">\n <mat-icon>check</mat-icon> Apply\n </button>\n </div>\n </section>\n }\n } @else {\n <p class=\"hint-line\">\n <mat-icon class=\"info-icon\">data_array</mat-icon>\n <span>Click an array (<mat-icon class=\"inline-icon\">data_array</mat-icon>) in the path above to add steps.</span>\n </p>\n }\n }\n </div>\n </mat-expansion-panel>\n\n <!-- 3 - Preview -->\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header>\n <mat-panel-title>\n <mat-icon class=\"title-icon\">preview</mat-icon>\n <span class=\"panel-title\">3 &middot; Result preview</span>\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div class=\"content\">\n @if (resultRowCount(); as n) {\n <span class=\"result-count\"><mat-icon>check_circle</mat-icon> {{ n }} {{ n === 1 ? 'result' : 'results' }}</span>\n }\n <div class=\"mapped-value\">\n <pre>{{ mappedValue | json }}</pre>\n </div>\n </div>\n </mat-expansion-panel>\n</mat-accordion>\n", styles: ["@charset \"UTF-8\";:host{display:block}.surface mat-expansion-panel{background:var(--mat-sys-surface-container-low, var(--lib-forms-surface-container-low))}:host ::ng-deep .mat-expansion-panel-header{height:44px;padding:0 .875rem}:host ::ng-deep .mat-expansion-panel-body{padding:0 .875rem .75rem}button mat-icon{vertical-align:middle}.panel-title{font-size:.875rem;font-weight:500;letter-spacing:-.01em}.title-icon{margin-right:.625rem;vertical-align:middle;color:var(--lib-forms-on-surface-variant)}.content{display:flex;flex-direction:column;gap:.875rem;padding:.5rem 0 .25rem}.hint-line{display:flex;align-items:center;gap:.5rem;margin:0;font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.info-icon{color:var(--sem-info, var(--lib-forms-primary));flex:none}.inline-icon{font-size:1rem;width:1rem;height:1rem;vertical-align:text-bottom}.field-label{font-size:.625rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.muted{font-size:.8125rem;color:var(--lib-forms-on-surface-variant)}.data-tree{background:var(--lib-forms-surface-container-low);border-radius:var(--lib-forms-radius-md);padding:.5rem .75rem;min-width:fit-content}:host mat-tree-node{min-height:34px}.node-spacer{display:inline-block;width:36px}.node-toggle{color:var(--lib-forms-on-surface-variant)}.node-checkbox{width:100%}.node-key{font-weight:500;color:var(--lib-forms-on-surface);margin-right:.5rem}.node-value{font-family:var(--lib-forms-font-mono, monospace);padding:.0625rem .4375rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm);font-size:.8125rem;white-space:nowrap}.breadcrumb{display:flex;align-items:center;flex-wrap:wrap;gap:.125rem}.crumb{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;max-width:9rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-on-surface-variant);background:transparent;border:0;border-radius:var(--lib-forms-radius-pill);cursor:pointer;white-space:nowrap;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing),color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.crumb:hover:not(:disabled){background:var(--lib-forms-surface-container-high)}.crumb:disabled{cursor:default;opacity:.65}.crumb mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.crumb-text{overflow:hidden;text-overflow:ellipsis}.crumb-array{color:var(--lib-forms-primary)}.crumb-active,.crumb-active:hover:not(:disabled){background:var(--lib-forms-primary-container);color:var(--lib-forms-on-surface)}.crumb-badge{min-width:1.0625rem;padding:0 .3125rem;border-radius:var(--lib-forms-radius-pill);background:var(--lib-forms-primary);color:var(--mat-sys-on-primary, #fff);font-size:.625rem;line-height:1.0625rem;text-align:center}.crumb-sep{color:var(--lib-forms-outline);font-size:1rem;width:1rem;height:1rem}.pipeline{display:flex;align-items:stretch;flex-wrap:wrap;gap:.375rem}.stage{display:inline-flex;flex-direction:column;align-items:center;justify-content:center;gap:.0625rem;min-width:4rem;padding:.375rem .5rem;border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md);background:var(--lib-forms-surface-container-low);color:var(--lib-forms-on-surface);cursor:pointer;transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing),background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.stage mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.stage-source{cursor:default;color:var(--lib-forms-on-surface-variant);background:transparent;border-style:dashed}.stage-active{border-color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.stage-empty{border-style:dashed;color:var(--lib-forms-on-surface-variant)}.stage-add{border-style:dashed;color:var(--lib-forms-primary);min-width:3.75rem}.stage-label{font-size:.75rem;font-weight:500}.stage-count{font-size:.625rem;color:var(--lib-forms-on-surface-variant)}.flow-arrow{align-self:center;color:var(--lib-forms-outline);font-size:1.125rem;width:1rem;height:1.125rem}.menu-hint{display:block;font-size:.6875rem;color:var(--lib-forms-on-surface-variant)}.editor{display:flex;flex-direction:column;gap:.75rem;padding:1.125rem;border-radius:var(--lib-forms-radius-lg);background:var(--lib-forms-surface-container-low);box-shadow:var(--mat-sys-level1, 0 1px 3px rgba(0, 0, 0, .12))}.full{width:100%}.f-field{display:flex;flex-direction:column;gap:.1875rem;min-width:0}.f-label{font-size:.625rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.f-control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.25;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm);transition:border-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}select.f-control{cursor:pointer}.f-textarea{height:auto;min-height:3rem;line-height:1.4;resize:vertical}.f-control:hover{border-color:var(--lib-forms-outline)}.f-control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.sub-hint{margin:-.25rem 0 0;font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.section-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-top:.25rem}.section-actions{display:flex;gap:.25rem}.map-row{display:grid;grid-template-columns:1fr 1fr auto;align-items:end;gap:.5rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-item{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.25rem;padding:.5rem .5rem .5rem .625rem;background:var(--lib-forms-surface-container);border-radius:var(--lib-forms-radius-sm)}.q-stack{display:flex;flex-direction:column;gap:.5rem;min-width:0}.q-pair{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;min-width:0}.q-pair-op{grid-template-columns:8rem 1fr}.q-pair-sort{grid-template-columns:1fr auto;align-items:end}.q-remove{color:var(--lib-forms-on-surface-variant)}.field-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(6.5rem,1fr));gap:.5rem}.match-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.seg{--mat-standard-button-toggle-height: 34px;height:34px}.checklist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.125rem 1rem;padding:.25rem 0}.link-btn{display:inline-flex;align-items:center;align-self:flex-start;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm);cursor:pointer;transition:background-color var(--lib-forms-duration-hover) var(--lib-forms-easing)}.link-btn:hover{background:var(--lib-forms-primary-container)}.link-btn mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.f-picker{display:flex;align-items:center;justify-content:space-between;gap:.25rem;text-align:left;cursor:pointer}.f-picker-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.f-placeholder{color:var(--lib-forms-on-surface-variant)}.f-picker mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem;color:var(--lib-forms-on-surface-variant)}.path-icon{margin-right:.25rem;font-size:1rem;width:1rem;height:1rem;color:var(--lib-forms-on-surface-variant)}.editor-foot{display:flex;justify-content:flex-end;margin-top:-.25rem}.editor-actions{display:flex;align-items:center;gap:.125rem;padding-top:.5rem}.spacer{flex:1}.suggestions{display:flex;gap:1rem;flex-wrap:wrap;padding:.75rem;border-radius:var(--lib-forms-radius-md);background:var(--sem-info-surface, var(--lib-forms-surface-container))}.suggestion-group{flex:1 1 10rem;display:flex;flex-direction:column;gap:.375rem}.chip-row{display:flex;flex-wrap:wrap;gap:.25rem}.ins-chip{font-size:.75rem}.result-count{display:inline-flex;align-items:center;gap:.375rem;font-size:.8125rem;font-weight:500;color:var(--sem-emerald, var(--lib-forms-method-get))}.result-count mat-icon{font-size:1.125rem;width:1.125rem;height:1.125rem}.mapped-value{padding:1rem 1.25rem;background:var(--lib-forms-on-surface);color:var(--lib-forms-surface);border-radius:var(--lib-forms-radius-md);overflow:auto}.mapped-value pre{margin:0;font-family:var(--lib-forms-font-mono, monospace);font-size:.8125rem}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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$2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i3$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3$4.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5$3.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5$3.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5$3.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5$3.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.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$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i1$4.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "directive", type: i1$4.MatTreeNodePadding, selector: "[matTreeNodePadding]", inputs: ["matTreeNodePadding", "matTreeNodePaddingIndent"] }, { kind: "directive", type: i1$4.MatTreeNodeToggle, selector: "[matTreeNodeToggle]", inputs: ["matTreeNodeToggleRecursive"] }, { kind: "component", type: i1$4.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i1$4.MatTreeNode, selector: "mat-tree-node", inputs: ["tabIndex", "disabled"], outputs: ["activation", "expandedChange"], exportAs: ["matTreeNode"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
18566
19099
  }
18567
19100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: DataTreeComponent, decorators: [{
18568
19101
  type: Component,
@@ -19049,7 +19582,7 @@ class ApiValueAccessRulesComponent {
19049
19582
  }
19050
19583
  }
19051
19584
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ApiValueAccessRulesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19052
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ApiValueAccessRulesComponent, isStandalone: true, selector: "lib-api-value-access-rules", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multipleBind: { classPropertyName: "multipleBind", publicName: "multipleBind", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, mapToData: { classPropertyName: "mapToData", publicName: "mapToData", isSignal: true, isRequired: false, transformFunction: null }, postmanCollectionConfig: { classPropertyName: "postmanCollectionConfig", publicName: "postmanCollectionConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChanged: "valueChanged", reload: "reload" }, host: { classAttribute: "lib-api-value-access-rules" }, ngImport: i0, template: "@if (hasErrors()) {\n <lib-error-list [errors]=\"errors()\" />\n}\n\n<div class=\"mode-toggle\">\n <mat-button-toggle-group name=\"valueAccessMode\" aria-label=\"Value access mode\" [value]=\"viewMode()\">\n <mat-button-toggle (click)=\"setViewMode('map')\" [checked]=\"viewMode() === 'map'\" value=\"map\">\n Value Mapping\n </mat-button-toggle>\n <mat-button-toggle (click)=\"setViewMode('sync')\" [checked]=\"viewMode() === 'sync'\" value=\"sync\">\n Data Sync\n </mat-button-toggle>\n </mat-button-toggle-group>\n</div>\n\n@if (error(); as err) {\n <lib-empty-state icon=\"error_outline\"\n [message]=\"err.error || err.message || 'Failed to load the collection.'\" />\n}\n\n@switch (viewMode()) {\n @case ('sync') {\n @if (parsedRequestBody(); as body) {\n <lib-json-editor (valueChange)=\"requestBodyChanged($event)\" [value]=\"body\" />\n } @else {\n <lib-empty-state icon=\"data_object\"\n message=\"No request body found in the selected API request.\" />\n }\n\n <div class=\"run-bar\">\n <p class=\"run-bar__hint\">Run the API call with the body above to load a live response.</p>\n <span class=\"run-bar__spacer\"></span>\n <button mat-stroked-button type=\"button\" [disabled]=\"loading()\" (click)=\"runApiCall()\"\n [attr.aria-busy]=\"loading()\" aria-label=\"Run API call\">\n @if (loading()) {\n <mat-spinner diameter=\"16\" />\n } @else {\n <mat-icon>play_arrow</mat-icon>\n }\n <span>{{ loading() ? 'Running API\u2026' : 'Run API Call' }}</span>\n </button>\n </div>\n }\n\n @case ('map') {\n @if (multipleBind(); as controls) {\n @for (controlName of controls; track controlName) {\n <section class=\"mapping-section\">\n <label class=\"mapping-section__label\" [attr.for]=\"controlName\">\n Map <strong>{{ controlName }}</strong>\n </label>\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\"\n [value]=\"keyedValueFor(controlName)\"\n (pathChanged)=\"pathChanged($event, controlName)\" />\n </section>\n }\n } @else {\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\" [value]=\"singleValue()\"\n (pathChanged)=\"pathChanged($event)\" />\n }\n }\n}\n\n<!-- CDK overlay shown while disabled -->\n<ng-template cdkConnectedOverlay [cdkConnectedOverlayOpen]=\"disabled()\">\n <div class=\"disabled-overlay\" aria-hidden=\"true\"></div>\n</ng-template>\n", styles: [":host{display:block;position:relative}.mode-toggle{display:flex;justify-content:center;margin-bottom:1rem}.run-bar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;margin-top:1.5rem;padding:1rem 1.25rem;background:var(--lib-forms-surface);border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);box-shadow:var(--lib-forms-shadow-resting)}.run-bar__hint{margin:0;font-size:.8125rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.run-bar__spacer{flex:1 1 auto}.mapping-section{margin-bottom:1.5rem}.mapping-section__label{display:block;margin-bottom:.75rem;font-size:.875rem;color:var(--lib-forms-on-surface)}.disabled-overlay{position:absolute;inset:0;background:color-mix(in srgb,var(--lib-forms-on-surface) 30%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);z-index:10}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2$3.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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: MatButtonToggleModule }, { kind: "directive", type: i2$2.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i2$2.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: DataTreeComponent, selector: "lib-data-tree", inputs: ["data", "value", "formInputs"], outputs: ["pathChanged"] }, { kind: "component", type: JsonEditorComponent, selector: "lib-json-editor", inputs: ["value", "height", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: EmptyStateComponent, selector: "lib-empty-state", inputs: ["icon", "message"] }, { kind: "component", type: ErrorListComponent, selector: "lib-error-list", inputs: ["errors"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
19585
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ApiValueAccessRulesComponent, isStandalone: true, selector: "lib-api-value-access-rules", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multipleBind: { classPropertyName: "multipleBind", publicName: "multipleBind", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, mapToData: { classPropertyName: "mapToData", publicName: "mapToData", isSignal: true, isRequired: false, transformFunction: null }, postmanCollectionConfig: { classPropertyName: "postmanCollectionConfig", publicName: "postmanCollectionConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChanged: "valueChanged", reload: "reload" }, host: { classAttribute: "lib-api-value-access-rules" }, ngImport: i0, template: "@if (hasErrors()) {\n <lib-error-list [errors]=\"errors()\" />\n}\n\n<div class=\"mode-toggle\">\n <mat-button-toggle-group name=\"valueAccessMode\" aria-label=\"Value access mode\" [value]=\"viewMode()\">\n <mat-button-toggle (click)=\"setViewMode('map')\" [checked]=\"viewMode() === 'map'\" value=\"map\">\n Value Mapping\n </mat-button-toggle>\n <mat-button-toggle (click)=\"setViewMode('sync')\" [checked]=\"viewMode() === 'sync'\" value=\"sync\">\n Data Sync\n </mat-button-toggle>\n </mat-button-toggle-group>\n</div>\n\n@if (error(); as err) {\n <lib-empty-state icon=\"error_outline\"\n [message]=\"err.error || err.message || 'Failed to load the collection.'\" />\n}\n\n@switch (viewMode()) {\n @case ('sync') {\n @if (parsedRequestBody(); as body) {\n <lib-json-editor (valueChange)=\"requestBodyChanged($event)\" [value]=\"body\" />\n } @else {\n <lib-empty-state icon=\"data_object\"\n message=\"No request body found in the selected API request.\" />\n }\n\n <div class=\"run-bar\">\n <p class=\"run-bar__hint\">Run the API call with the body above to load a live response.</p>\n <span class=\"run-bar__spacer\"></span>\n <button mat-stroked-button type=\"button\" [disabled]=\"loading()\" (click)=\"runApiCall()\"\n [attr.aria-busy]=\"loading()\" aria-label=\"Run API call\">\n @if (loading()) {\n <mat-spinner diameter=\"16\" />\n } @else {\n <mat-icon>play_arrow</mat-icon>\n }\n <span>{{ loading() ? 'Running API\u2026' : 'Run API Call' }}</span>\n </button>\n </div>\n }\n\n @case ('map') {\n @if (multipleBind(); as controls) {\n @for (controlName of controls; track controlName) {\n <section class=\"mapping-section\">\n <label class=\"mapping-section__label\" [attr.for]=\"controlName\">\n Map <strong>{{ controlName }}</strong>\n </label>\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\"\n [value]=\"keyedValueFor(controlName)\"\n (pathChanged)=\"pathChanged($event, controlName)\" />\n </section>\n }\n } @else {\n <lib-data-tree [formInputs]=\"formInputs()\" [data]=\"treeData()\" [value]=\"singleValue()\"\n (pathChanged)=\"pathChanged($event)\" />\n }\n }\n}\n\n<!-- CDK overlay shown while disabled -->\n<ng-template cdkConnectedOverlay [cdkConnectedOverlayOpen]=\"disabled()\">\n <div class=\"disabled-overlay\" aria-hidden=\"true\"></div>\n</ng-template>\n", styles: [":host{display:block;position:relative}.mode-toggle{display:flex;justify-content:center;margin-bottom:1rem}.run-bar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;margin-top:1.5rem;padding:1rem 1.25rem;background:var(--lib-forms-surface);border:1px solid color-mix(in srgb,var(--lib-forms-outline) 15%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);box-shadow:var(--lib-forms-shadow-resting)}.run-bar__hint{margin:0;font-size:.8125rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.run-bar__spacer{flex:1 1 auto}.mapping-section{margin-bottom:1.5rem}.mapping-section__label{display:block;margin-bottom:.75rem;font-size:.875rem;color:var(--lib-forms-on-surface)}.disabled-overlay{position:absolute;inset:0;background:color-mix(in srgb,var(--lib-forms-on-surface) 30%,transparent);border-radius:var(--lib-forms-radius-lg, 12px);z-index:10}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i2$2.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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: MatButtonToggleModule }, { kind: "directive", type: i3$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i3$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: DataTreeComponent, selector: "lib-data-tree", inputs: ["data", "value", "formInputs"], outputs: ["pathChanged"] }, { kind: "component", type: JsonEditorComponent, selector: "lib-json-editor", inputs: ["value", "height", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: EmptyStateComponent, selector: "lib-empty-state", inputs: ["icon", "message"] }, { kind: "component", type: ErrorListComponent, selector: "lib-error-list", inputs: ["errors"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
19053
19586
  }
19054
19587
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ApiValueAccessRulesComponent, decorators: [{
19055
19588
  type: Component,
@@ -19071,6 +19604,165 @@ var apiValueAccessRules_component = /*#__PURE__*/Object.freeze({
19071
19604
  ApiValueAccessRulesComponent: ApiValueAccessRulesComponent
19072
19605
  });
19073
19606
 
19607
+ /** Canonical operator value keyed by its lower-cased spelling (for parse normalisation). */
19608
+ const OPERATOR_BY_KEY = new Map(PREDICATE_OPERATORS.map((op) => [op.value.toLowerCase(), op.value]));
19609
+ /** Symbolic operators, longest-match first so `===` wins over `==`. */
19610
+ const SYMBOLIC_OPS = ['===', '!==', '>=', '<=', '==', '!=', '>', '<'];
19611
+ /** Keyword operators (matched case-insensitively, surrounded by whitespace). */
19612
+ const KEYWORD_OPS = ['includes', 'startsWith', 'endsWith', 'matches', 'in'];
19613
+ /** An empty condition seeded with the given field and a sensible default operator. */
19614
+ function emptyCondition(field = '') {
19615
+ return { field, operator: '===', compareTo: 'value', value: '' };
19616
+ }
19617
+ const isBareLiteral = (v) => v === 'true' || v === 'false' || v === 'null' || (v.trim() !== '' && !Number.isNaN(Number(v)));
19618
+ const isQuoted = (v) => {
19619
+ const t = v.trim();
19620
+ if (t.length < 2)
19621
+ return false;
19622
+ const a = t[0];
19623
+ const b = t[t.length - 1];
19624
+ return (a === '"' && b === '"') || (a === "'" && b === "'");
19625
+ };
19626
+ const unquote = (v) => (isQuoted(v) ? v.trim().slice(1, -1) : v.trim());
19627
+ /** Formats a literal: bare for numbers/booleans/null, otherwise a quoted, escaped string. */
19628
+ function formatLiteral(value) {
19629
+ const t = value.trim();
19630
+ if (t === '')
19631
+ return '""';
19632
+ if (isBareLiteral(t))
19633
+ return t;
19634
+ return `"${t.replace(/"/g, '\\"')}"`;
19635
+ }
19636
+ /** The expression token for a condition's right operand. */
19637
+ function rightToken(condition) {
19638
+ return condition.compareTo === 'field' ? condition.value.trim() : formatLiteral(condition.value);
19639
+ }
19640
+ /** Whether a condition is complete enough to contribute to the expression. */
19641
+ function isComplete(condition) {
19642
+ if (condition.field.trim() === '')
19643
+ return false;
19644
+ if (condition.compareTo === 'field')
19645
+ return condition.value.trim() !== '';
19646
+ return true;
19647
+ }
19648
+ /**
19649
+ * Serialises a condition group into a predicate expression string. Incomplete
19650
+ * conditions are dropped, so an empty/half-built group yields `''` (which the
19651
+ * editor treats as "nothing to save yet").
19652
+ */
19653
+ function serializeConditions(group) {
19654
+ return group.conditions
19655
+ .filter(isComplete)
19656
+ .map((c) => `${c.field.trim()} ${c.operator} ${rightToken(c)}`)
19657
+ .join(` ${group.connector} `);
19658
+ }
19659
+ /** Resolves a raw operator spelling to its canonical {@link PREDICATE_OPERATORS} value, or `null`. */
19660
+ function canonicalOperator(raw) {
19661
+ return OPERATOR_BY_KEY.get(raw.toLowerCase()) ?? null;
19662
+ }
19663
+ /** Classifies a raw right-hand operand as a field reference or a literal value. */
19664
+ function classifyRight(raw, fieldNames) {
19665
+ const t = raw.trim();
19666
+ if (isQuoted(t))
19667
+ return { compareTo: 'value', value: unquote(t) };
19668
+ if (fieldNames.has(t))
19669
+ return { compareTo: 'field', value: t };
19670
+ return { compareTo: 'value', value: t };
19671
+ }
19672
+ /** Parses a single `left op right` comparison, or `null` if it is not representable. */
19673
+ function parseCondition(part, fieldNames) {
19674
+ const p = part.trim();
19675
+ for (const op of SYMBOLIC_OPS) {
19676
+ const idx = p.indexOf(op);
19677
+ if (idx > 0) {
19678
+ const operator = canonicalOperator(op);
19679
+ if (!operator)
19680
+ return null;
19681
+ const field = p.slice(0, idx).trim();
19682
+ const right = p.slice(idx + op.length).trim();
19683
+ if (field === '' || right === '')
19684
+ return null;
19685
+ return { field, operator, ...classifyRight(right, fieldNames) };
19686
+ }
19687
+ }
19688
+ for (const kw of KEYWORD_OPS) {
19689
+ const m = p.match(new RegExp(`^(.+?)\\s+${kw}\\s+(.+)$`, 'i'));
19690
+ if (m && m[1] && m[2]) {
19691
+ const operator = canonicalOperator(kw);
19692
+ if (!operator)
19693
+ return null;
19694
+ return { field: m[1].trim(), operator, ...classifyRight(m[2], fieldNames) };
19695
+ }
19696
+ }
19697
+ return null;
19698
+ }
19699
+ /**
19700
+ * Best-effort parse of an expression into a guided condition group. Returns
19701
+ * `null` (→ raw editor) for anything the builder cannot represent losslessly:
19702
+ * grouping `()`, mixed `&&`/`||`, unary `!`, or an unknown operator.
19703
+ */
19704
+ function parseConditions(expression, fieldNames) {
19705
+ const e = expression.trim();
19706
+ if (e === '')
19707
+ return { connector: '&&', conditions: [] };
19708
+ if (/[()]/.test(e))
19709
+ return null; // grouping → raw
19710
+ if (/!(?!=)/.test(e))
19711
+ return null; // unary negation (`!field`) → raw
19712
+ const hasAnd = e.includes('&&');
19713
+ const hasOr = e.includes('||');
19714
+ if (hasAnd && hasOr)
19715
+ return null; // mixed connectors → raw
19716
+ const connector = hasOr ? '||' : '&&';
19717
+ const parts = hasOr ? e.split('||') : hasAnd ? e.split('&&') : [e];
19718
+ const conditions = [];
19719
+ for (const part of parts) {
19720
+ const condition = parseCondition(part, fieldNames);
19721
+ if (!condition)
19722
+ return null;
19723
+ conditions.push(condition);
19724
+ }
19725
+ return { connector, conditions };
19726
+ }
19727
+ /** Returns the unique identifier tokens referenced in an expression. */
19728
+ function referencedTokens(expression) {
19729
+ return new Set(expression.match(/[A-Za-z_][A-Za-z0-9_]*/g) ?? []);
19730
+ }
19731
+ /**
19732
+ * Derives the `inputsObservedForChanges` dependency list from an expression by
19733
+ * matching identifier tokens against the editor's resolved {@link FieldBinding}s.
19734
+ * Works for both guided and raw expressions, so observed inputs always reflect
19735
+ * what the expression actually references — no manual add/remove, no orphans.
19736
+ *
19737
+ * When an aggregate has been chosen for a field (only possible for a
19738
+ * multiple-input column), the binding carries `parentInputId` + `function` so
19739
+ * the engine reduces its row array to a scalar. Otherwise it resolves directly
19740
+ * (a scalar primary input, or a per-row list value).
19741
+ */
19742
+ function deriveObservedInputs(expression, fields, functions) {
19743
+ const tokens = referencedTokens(expression);
19744
+ const observed = [];
19745
+ const seen = new Set();
19746
+ for (const field of fields) {
19747
+ if (!tokens.has(field.variable) || seen.has(field.variable))
19748
+ continue;
19749
+ seen.add(field.variable);
19750
+ const aggregate = functions[field.variable];
19751
+ if (aggregate && field.parentInputId) {
19752
+ observed.push({
19753
+ inputId: field.inputId,
19754
+ variable: field.variable,
19755
+ parentInputId: field.parentInputId,
19756
+ function: aggregate,
19757
+ });
19758
+ }
19759
+ else {
19760
+ observed.push({ inputId: field.inputId, variable: field.variable });
19761
+ }
19762
+ }
19763
+ return observed;
19764
+ }
19765
+
19074
19766
  /**
19075
19767
  * Builder-side editor for authoring a boolean expression (used for guarded
19076
19768
  * navigation, conditional validation, and API path-selection rules). Validates
@@ -19099,6 +19791,12 @@ var apiValueAccessRules_component = /*#__PURE__*/Object.freeze({
19099
19791
  */
19100
19792
  class ValidationExpressioCreatorComponent {
19101
19793
  #cursorPosition;
19794
+ /** Whether the expression is authored via the guided rows or the raw editor. */
19795
+ #mode;
19796
+ /** Guided builder model mirroring the current expression. */
19797
+ #group;
19798
+ /** Reactive mirror of the control value (the control itself is not a signal). */
19799
+ #expressionText;
19102
19800
  /** Local mutable mirror of incoming `valueAccessRules`. */
19103
19801
  #valueAccessRules;
19104
19802
  #destroyRef;
@@ -19118,7 +19816,9 @@ class ValidationExpressioCreatorComponent {
19118
19816
  this.valueAccessRules = input({}, ...(ngDevMode ? [{ debugName: "valueAccessRules" }] : /* istanbul ignore next */ []));
19119
19817
  /** Fires when either the expression text or its derived value-access tree changes. */
19120
19818
  this.expressionChange = output();
19121
- this.textareaElementRef = viewChild.required('textarea');
19819
+ // Optional: the raw textarea only exists in Advanced mode, so the guided
19820
+ // builder must not assume it is in the DOM.
19821
+ this.textareaElementRef = viewChild('textarea', ...(ngDevMode ? [{ debugName: "textareaElementRef" }] : /* istanbul ignore next */ []));
19122
19822
  this.expressionControl = new FormControl('', [
19123
19823
  Validators.required,
19124
19824
  expressionSyntaxValidator(),
@@ -19127,6 +19827,52 @@ class ValidationExpressioCreatorComponent {
19127
19827
  this.optionsSearch = signal(undefined, ...(ngDevMode ? [{ debugName: "optionsSearch" }] : /* istanbul ignore next */ []));
19128
19828
  this.variableInEdit = signal(null, ...(ngDevMode ? [{ debugName: "variableInEdit" }] : /* istanbul ignore next */ []));
19129
19829
  this.#cursorPosition = 0;
19830
+ /** Operator choices, shared with the validators builder for label parity. */
19831
+ this.operators = PREDICATE_OPERATORS;
19832
+ /** Whether the expression is authored via the guided rows or the raw editor. */
19833
+ this.#mode = signal('guided', ...(ngDevMode ? [{ debugName: "#mode" }] : /* istanbul ignore next */ []));
19834
+ this.mode = this.#mode.asReadonly();
19835
+ /** Guided builder model mirroring the current expression. */
19836
+ this.#group = signal({ connector: '&&', conditions: [] }, ...(ngDevMode ? [{ debugName: "#group" }] : /* istanbul ignore next */ []));
19837
+ this.group = this.#group.asReadonly();
19838
+ /** Reactive mirror of the control value (the control itself is not a signal). */
19839
+ this.#expressionText = signal('', ...(ngDevMode ? [{ debugName: "#expressionText" }] : /* istanbul ignore next */ []));
19840
+ this.expressionText = this.#expressionText.asReadonly();
19841
+ /** Fields the guided builder can reference, as friendly options. */
19842
+ this.fieldOptions = computed(() => this.allInputs().map((inp) => ({
19843
+ variable: inp.formControlName,
19844
+ label: inp.label || inp.formControlName,
19845
+ // `stepName` is attached at runtime by the form builder; it is not on the
19846
+ // static FormColumnInputs type, so read it defensively.
19847
+ stepName: inp.stepName ?? null,
19848
+ })), ...(ngDevMode ? [{ debugName: "fieldOptions" }] : /* istanbul ignore next */ []));
19849
+ /**
19850
+ * Field options grouped by their `stepName` for the dropdowns, preserving
19851
+ * first-seen order. Fields without a step collapse into a single ungrouped
19852
+ * bucket (rendered without an `<optgroup>`), so forms that don't carry step
19853
+ * names degrade to a plain flat list.
19854
+ */
19855
+ this.fieldOptionGroups = computed(() => {
19856
+ const buckets = new Map();
19857
+ const order = [];
19858
+ for (const option of this.fieldOptions()) {
19859
+ const key = option.stepName ?? '';
19860
+ const existing = buckets.get(key);
19861
+ if (existing) {
19862
+ existing.push(option);
19863
+ }
19864
+ else {
19865
+ buckets.set(key, [option]);
19866
+ order.push(key);
19867
+ }
19868
+ }
19869
+ return order.map((key) => ({
19870
+ label: key === '' ? null : key,
19871
+ options: buckets.get(key) ?? [],
19872
+ }));
19873
+ }, ...(ngDevMode ? [{ debugName: "fieldOptionGroups" }] : /* istanbul ignore next */ []));
19874
+ /** Whether the current expression can be represented by the guided builder. */
19875
+ this.canUseGuided = computed(() => parseConditions(this.expressionText(), this.#fieldNameSet()) !== null, ...(ngDevMode ? [{ debugName: "canUseGuided" }] : /* istanbul ignore next */ []));
19130
19876
  /** Local mutable mirror of incoming `valueAccessRules`. */
19131
19877
  this.#valueAccessRules = {};
19132
19878
  this.methods = [
@@ -19173,7 +19919,11 @@ class ValidationExpressioCreatorComponent {
19173
19919
  value: '<=',
19174
19920
  },
19175
19921
  ];
19176
- /** Bridge the `expression` input into the FormControl. */
19922
+ /**
19923
+ * Bridge the `expression` input into the FormControl and seed the guided
19924
+ * builder. Reparsing is `untracked` so this only re-runs when the `expression`
19925
+ * input changes — never when the user edits inside either mode.
19926
+ */
19177
19927
  this.expressionBridge = effect(() => {
19178
19928
  const value = this.expression();
19179
19929
  if (this.expressionControl.value !== value) {
@@ -19181,6 +19931,10 @@ class ValidationExpressioCreatorComponent {
19181
19931
  this.expressionControl.markAsPristine();
19182
19932
  this.expressionControl.markAsUntouched();
19183
19933
  }
19934
+ untracked(() => {
19935
+ this.#expressionText.set(value);
19936
+ this.#syncBuilderFromExpression(value);
19937
+ });
19184
19938
  }, ...(ngDevMode ? [{ debugName: "expressionBridge" }] : /* istanbul ignore next */ []));
19185
19939
  /** Mirror the `valueAccessRules` input into the local mutable copy. */
19186
19940
  this.valueAccessRulesBridge = effect(() => {
@@ -19191,6 +19945,7 @@ class ValidationExpressioCreatorComponent {
19191
19945
  this.#destroyRef = inject(DestroyRef);
19192
19946
  this.expressionControl.valueChanges
19193
19947
  .pipe(distinctUntilChanged((prev, curr) => prev === curr), tap((value) => {
19948
+ this.#expressionText.set(value || '');
19194
19949
  this.onTextChange(value || '').then(() => {
19195
19950
  this.expressionChange.emit({
19196
19951
  expression: this.expressionControl.value,
@@ -19220,7 +19975,14 @@ class ValidationExpressioCreatorComponent {
19220
19975
  return this.#valueAccessRules[key] ?? [];
19221
19976
  }
19222
19977
  async onTextChange(expression) {
19223
- const textarea = this.textareaElementRef().nativeElement;
19978
+ const textarea = this.textareaElementRef()?.nativeElement;
19979
+ // Guided mode has no textarea: skip the `$`-suggestion handling and just
19980
+ // keep the derived value-access rules in sync with the expression.
19981
+ if (!textarea) {
19982
+ this.showSuggestions.set(false);
19983
+ this.cleanValueAccessRules();
19984
+ return;
19985
+ }
19224
19986
  this.#cursorPosition = textarea.selectionStart || 0;
19225
19987
  // Define the operators that should prevent suggestions from showing
19226
19988
  const operators = this.methods.map((method) => method.value);
@@ -19280,7 +20042,9 @@ class ValidationExpressioCreatorComponent {
19280
20042
  this.expressionControl.setValue(newValue);
19281
20043
  this.expressionControl.markAsDirty();
19282
20044
  this.showSuggestions.set(false);
19283
- const textarea = this.textareaElementRef().nativeElement;
20045
+ const textarea = this.textareaElementRef()?.nativeElement;
20046
+ if (!textarea)
20047
+ return;
19284
20048
  textarea.focus();
19285
20049
  const newCursorPosition = (beforeDollar + suggestion + ' ').length;
19286
20050
  setTimeout(() => {
@@ -19304,9 +20068,65 @@ class ValidationExpressioCreatorComponent {
19304
20068
  }
19305
20069
  }
19306
20070
  onFocus() {
19307
- const textarea = this.textareaElementRef().nativeElement;
20071
+ const textarea = this.textareaElementRef()?.nativeElement;
20072
+ if (!textarea)
20073
+ return;
19308
20074
  this.#cursorPosition = textarea.selectionStart || 0;
19309
20075
  }
20076
+ // ---- guided condition builder ------------------------------------------
20077
+ /** Read the value-event target as a string. */
20078
+ inputValue(event) {
20079
+ return event.target.value;
20080
+ }
20081
+ /** Switch the All/Any connector joining the conditions. */
20082
+ setConnector(connector) {
20083
+ this.#applyGroup({ ...this.#group(), connector });
20084
+ }
20085
+ /** Append a fresh condition defaulting its field to the first available one. */
20086
+ addCondition() {
20087
+ const fallback = this.fieldOptions()[0]?.variable ?? '';
20088
+ const group = this.#group();
20089
+ this.#applyGroup({
20090
+ ...group,
20091
+ conditions: [...group.conditions, emptyCondition(fallback)],
20092
+ });
20093
+ }
20094
+ /** Apply a partial change to the condition at `index`. */
20095
+ updateCondition(index, patch) {
20096
+ const group = this.#group();
20097
+ const conditions = group.conditions.map((c, i) => (i === index ? { ...c, ...patch } : c));
20098
+ this.#applyGroup({ ...group, conditions });
20099
+ }
20100
+ /** Flip a condition between comparing to a typed value and another field. */
20101
+ toggleCompareTo(index) {
20102
+ const condition = this.#group().conditions[index];
20103
+ if (!condition)
20104
+ return;
20105
+ if (condition.compareTo === 'value') {
20106
+ const field = this.fieldOptions().find((f) => f.variable !== condition.field);
20107
+ this.updateCondition(index, { compareTo: 'field', value: field?.variable ?? '' });
20108
+ }
20109
+ else {
20110
+ this.updateCondition(index, { compareTo: 'value', value: '' });
20111
+ }
20112
+ }
20113
+ /** Remove the condition at `index`. */
20114
+ removeCondition(index) {
20115
+ const group = this.#group();
20116
+ this.#applyGroup({ ...group, conditions: group.conditions.filter((_, i) => i !== index) });
20117
+ }
20118
+ /** Switch to the raw expression editor (the escape hatch for power users). */
20119
+ useAdvanced() {
20120
+ this.#mode.set('advanced');
20121
+ }
20122
+ /** Switch back to the guided builder, reparsing the current expression. */
20123
+ useGuided() {
20124
+ const parsed = parseConditions(this.expressionText(), this.#fieldNameSet());
20125
+ if (!parsed)
20126
+ return;
20127
+ this.#group.set(parsed);
20128
+ this.#mode.set('guided');
20129
+ }
19310
20130
  toggleVariableInEdit(variable) {
19311
20131
  this.variableInEdit.update((current) => (current === variable ? null : variable));
19312
20132
  }
@@ -19319,8 +20139,35 @@ class ValidationExpressioCreatorComponent {
19319
20139
  },
19320
20140
  });
19321
20141
  }
20142
+ // ---- internal ----------------------------------------------------------
20143
+ /** Set of field variable names the builder recognises (for parsing). */
20144
+ #fieldNameSet() {
20145
+ return new Set(this.fieldOptions().map((f) => f.variable));
20146
+ }
20147
+ /**
20148
+ * Store a builder change: update the model, then serialise it into the
20149
+ * control. Writing the control drives the existing valueChanges pipeline
20150
+ * (value-access rule sync + `expressionChange` emit), so the guided and raw
20151
+ * paths share one source of truth.
20152
+ */
20153
+ #applyGroup(next) {
20154
+ this.#group.set(next);
20155
+ this.expressionControl.setValue(serializeConditions(next));
20156
+ this.expressionControl.markAsDirty();
20157
+ }
20158
+ /** Seed the builder from an expression: guided when parseable, else raw. */
20159
+ #syncBuilderFromExpression(expression) {
20160
+ const parsed = parseConditions(expression, this.#fieldNameSet());
20161
+ if (parsed) {
20162
+ this.#group.set(parsed);
20163
+ this.#mode.set('guided');
20164
+ }
20165
+ else {
20166
+ this.#mode.set('advanced');
20167
+ }
20168
+ }
19322
20169
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ValidationExpressioCreatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
19323
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ValidationExpressioCreatorComponent, isStandalone: true, selector: "lib-validation-expressio-creator", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, valueAccessRules: { classPropertyName: "valueAccessRules", publicName: "valueAccessRules", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, host: { classAttribute: "lib-validation-expressio-creator" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\" floatLabel=\"always\"\r\n id=\"validationExpressionCreator\">\r\n <mat-label>Condition expression</mat-label>\r\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\r\n placeholder=\"Enter a validation string for the function\"></textarea>\r\n\r\n\r\n <mat-hint\r\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\r\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\r\n {{ errorMessage }}\r\n } @else {\r\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\r\n @if (showSuggestions()) {\r\n <section class=\"showSuggestionContainer\">\r\n <mat-divider></mat-divider>\r\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\r\n <div class=\"suggestion-container\">\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Logical Operators\r\n </div>\r\n <div class=\"button-container\">\r\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\r\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\r\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\r\n {{ method.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Add Input as a Variable\r\n </div>\r\n <div class=\"button-container\">\r\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\r\n <button mat-button matTooltipPosition=\"right\"\r\n [matTooltip]=\"'Add Variable - ' + inp.label\"\r\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\r\n {{ inp.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n }\r\n }\r\n </mat-hint>\r\n</mat-form-field>\r\n\r\n@if (valueAccessOptions().length > 0) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\r\n floatLabel=\"always\" id=\"Value access options\">\r\n <mat-label>\r\n Form Fields for expression\r\n </mat-label>\r\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\r\n @for (variable of valueAccessOptions(); track variable) {\r\n <mat-chip-option\r\n [selected]=\"variableInEdit() === variable\"\r\n (click)=\"toggleVariableInEdit(variable)\"\r\n [aria-description]=\"'press enter to edit ' + variable\">\r\n {{ variable }}\r\n </mat-chip-option>\r\n }\r\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\r\n </mat-chip-grid>\r\n @if (variableInEdit(); as activeVariable) {\r\n <lib-api-value-access-rules\r\n [value]=\"getValueAccessRule(activeVariable)\"\r\n [errors]=\"[]\"\r\n [formInputs]=\"formInputs() || []\"\r\n [mapToData]=\"data()\"\r\n (valueChanged)=\"activeVariableChanged($event)\">\r\n </lib-api-value-access-rules>\r\n }\r\n <mat-hint>\r\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\r\n data within a complex object.\r\n </mat-hint>\r\n </mat-form-field>\r\n}\r\n", styles: [".suggestion-container{display:flex;width:100%;gap:8px}.suggestion-column{flex:1;min-width:0}.button-container{display:flex;flex-wrap:wrap}.suggestion-button{height:auto;text-align:left;font-size:10.5px;border-radius:4px;margin-bottom:4px;line-height:normal;padding:4px;white-space:nowrap;overflow:hidden;display:inline-block;text-overflow:ellipsis}.suggestion-heading{margin-bottom:8px;font-size:.6875em;font-weight:500}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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: MatChipsModule }, { kind: "component", type: i1$6.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i1$6.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: i1$6.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ApiValueAccessRulesComponent, selector: "lib-api-value-access-rules", inputs: ["disabled", "multipleBind", "errors", "value", "formInputs", "mapToData", "postmanCollectionConfig"], outputs: ["valueChanged", "reload"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: SearchListPipe, name: "searchList" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
20170
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.12", type: ValidationExpressioCreatorComponent, isStandalone: true, selector: "lib-validation-expressio-creator", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, formInputs: { classPropertyName: "formInputs", publicName: "formInputs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, valueAccessRules: { classPropertyName: "valueAccessRules", publicName: "valueAccessRules", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, host: { classAttribute: "lib-validation-expressio-creator" }, viewQueries: [{ propertyName: "textareaElementRef", first: true, predicate: ["textarea"], descendants: true, isSignal: true }], ngImport: i0, template: "<section class=\"lib-vec\">\n <div class=\"lib-vec__head\">\n <div class=\"lib-vec__heading\">\n <span class=\"lib-vec__f-label\">Condition expression</span>\n <p class=\"lib-vec__sub-hint\">{{ hint() }}</p>\n </div>\n\n @if (mode() === 'advanced') {\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"!canUseGuided()\"\n [matTooltip]=\"canUseGuided() ? 'Build this with guided rows' : 'This expression is too advanced for the guided builder'\"\n (click)=\"useGuided()\">\n <mat-icon>view_module</mat-icon> Guided\n </button>\n } @else {\n <button type=\"button\" class=\"lib-vec__link\" matTooltip=\"Type the expression yourself\"\n (click)=\"useAdvanced()\">\n <mat-icon>code</mat-icon> Advanced\n </button>\n }\n </div>\n\n @if (mode() === 'guided') {\n @if (fieldOptions().length === 0) {\n <p class=\"lib-vec__sub-hint\">\n No fields available yet \u2014 switch to Advanced to type an expression.\n </p>\n } @else if (group().conditions.length === 0) {\n <p class=\"lib-vec__sub-hint lib-vec__sub-hint--lead\">\n <mat-icon class=\"lib-vec__lead-icon\">lightbulb</mat-icon>\n <span>Add a check below \u2014 this passes when it\u2019s true.</span>\n </p>\n } @else if (group().conditions.length > 1) {\n <div class=\"lib-vec__match\">\n <span class=\"lib-vec__muted\">Match</span>\n <mat-button-toggle-group class=\"lib-vec__seg\" [value]=\"group().connector\"\n hideSingleSelectionIndicator (change)=\"setConnector($event.value)\"\n aria-label=\"Combine conditions\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"lib-vec__muted\">of the checks</span>\n </div>\n }\n\n @for (cond of group().conditions; track $index; let first = $first) {\n @if (!first) {\n <div class=\"lib-vec__connector\" aria-hidden=\"true\">\n <span>{{ group().connector === '&&' ? 'AND' : 'OR' }}</span>\n </div>\n }\n <div class=\"lib-vec__cond\" [class.lib-vec__cond--incomplete]=\"!cond.field || !cond.value\">\n <div class=\"lib-vec__cond-row\">\n <select class=\"lib-vec__control lib-vec__control--field\"\n [class.lib-vec__control--invalid]=\"!cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.field\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n (click)=\"removeCondition($index)\" matTooltip=\"Remove check\" aria-label=\"Remove check\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"lib-vec__cond-row lib-vec__cond-row--ops\">\n <select class=\"lib-vec__control\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) {\n <option [value]=\"op.value\" [selected]=\"op.value === cond.operator\">\n {{ op.label }}\n </option>\n }\n </select>\n\n @if (cond.compareTo === 'field') {\n <select class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n (change)=\"updateCondition($index, { value: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.value\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n } @else {\n <input class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n [value]=\"cond.value\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\"\n [placeholder]=\"'a value'\" />\n }\n\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n [class.lib-vec__icon-btn--on]=\"cond.compareTo === 'field'\"\n (click)=\"toggleCompareTo($index)\"\n [attr.aria-label]=\"cond.compareTo === 'field' ? 'Compare to a typed value' : 'Compare to another field'\"\n [matTooltip]=\"cond.compareTo === 'field' ? 'Comparing to a field \u2014 switch to a typed value' : 'Compare to another field instead'\">\n <mat-icon>{{ cond.compareTo === 'field' ? 'link' : 'link_off' }}</mat-icon>\n </button>\n </div>\n </div>\n }\n\n <div class=\"lib-vec__foot\">\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"fieldOptions().length === 0\"\n (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add check\n </button>\n\n @if (expressionText()) {\n <span class=\"lib-vec__valid\" matTooltip=\"Generated expression: {{ expressionText() }}\">\n <mat-icon>check_circle</mat-icon> Ready\n </span>\n }\n </div>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\"\n floatLabel=\"always\" id=\"validationExpressionCreator\">\n <mat-label>Expression</mat-label>\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\n class=\"lib-vec__mono\"\n placeholder=\"Enter a validation string for the function\"></textarea>\n\n <mat-hint\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\n {{ errorMessage }}\n } @else {\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\n @if (showSuggestions()) {\n <section class=\"showSuggestionContainer\">\n <mat-divider></mat-divider>\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\n <div class=\"suggestion-container\">\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Logical Operators\n </div>\n <div class=\"button-container\">\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\n {{ method.label | titlecase }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Add Input as a Variable\n </div>\n <div class=\"button-container\">\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\n <button mat-button matTooltipPosition=\"right\"\n [matTooltip]=\"'Add Variable - ' + inp.label\"\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\n {{ inp.label | titlecase }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n }\n }\n </mat-hint>\n </mat-form-field>\n }\n</section>\n\n@if (valueAccessOptions().length > 0) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\n floatLabel=\"always\" id=\"Value access options\">\n <mat-label>\n Form Fields for expression\n </mat-label>\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\n @for (variable of valueAccessOptions(); track variable) {\n <mat-chip-option\n [selected]=\"variableInEdit() === variable\"\n (click)=\"toggleVariableInEdit(variable)\"\n [aria-description]=\"'press enter to edit ' + variable\">\n {{ variable }}\n </mat-chip-option>\n }\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\n </mat-chip-grid>\n @if (variableInEdit(); as activeVariable) {\n <lib-api-value-access-rules\n [value]=\"getValueAccessRule(activeVariable)\"\n [errors]=\"[]\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"data()\"\n (valueChanged)=\"activeVariableChanged($event)\">\n </lib-api-value-access-rules>\n }\n <mat-hint>\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\n data within a complex object.\n </mat-hint>\n </mat-form-field>\n}\n", styles: [".lib-vec{display:flex;flex-direction:column;gap:.625rem}.lib-vec__head{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.lib-vec__heading{display:flex;flex-direction:column;gap:.125rem;min-width:0}.lib-vec__f-label{font-size:.625rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint{margin:0;font-size:.75rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint--lead{display:flex;align-items:center;gap:.375rem;padding:.4375rem .625rem;background:var(--lib-forms-surface-container-lowest);border:1px dashed var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px)}.lib-vec__lead-icon{flex:none;font-size:1rem;width:1rem;height:1rem;color:var(--sem-info, var(--lib-forms-primary))}.lib-vec__match{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.lib-vec__muted{font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.lib-vec__seg{--mat-standard-button-toggle-height: 28px;height:28px}.lib-vec__connector{display:flex;justify-content:center;margin:-.1875rem 0}.lib-vec__connector span{padding:.0625rem .5rem;font-size:.5625rem;font-weight:600;letter-spacing:.1em;color:var(--lib-forms-on-surface-variant);background:var(--lib-forms-surface-container-high);border-radius:var(--lib-forms-radius-pill, 999px)}.lib-vec__cond{display:flex;flex-direction:column;gap:.375rem;padding:.5rem .5rem .5625rem;background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md, 12px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__cond:hover{border-color:var(--lib-forms-outline)}.lib-vec__cond--incomplete{border-color:var(--sem-warning, var(--lib-forms-outline-variant))}.lib-vec__cond-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.375rem;min-width:0}.lib-vec__cond-row--ops{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto}.lib-vec__control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.2;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__control--field{font-weight:500}select.lib-vec__control{cursor:pointer}.lib-vec__control:hover{border-color:var(--lib-forms-outline)}.lib-vec__control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.lib-vec__control--invalid:not(:focus){border-color:var(--sem-warning, var(--lib-forms-outline));background:var(--sem-warning-surface, var(--lib-forms-surface-container-lowest))}.lib-vec__icon-btn{display:inline-flex;align-items:center;justify-content:center;flex:none;width:1.875rem;height:1.875rem;padding:0;color:var(--lib-forms-on-surface-variant);background:transparent;border:1px solid transparent;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__icon-btn:hover{color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.lib-vec__icon-btn--on{color:var(--lib-forms-primary);border-color:var(--lib-forms-primary)}.lib-vec__icon-btn mat-icon{font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__link{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__head .lib-vec__link{flex:none}.lib-vec__link:hover:not(:disabled){background:var(--lib-forms-primary-container)}.lib-vec__link:disabled{color:var(--lib-forms-on-surface-variant);cursor:default;opacity:.6}.lib-vec__link mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__foot{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.lib-vec__valid{display:inline-flex;align-items:center;gap:.25rem;font-size:.6875rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--sem-success, var(--lib-forms-primary));cursor:default}.lib-vec__valid mat-icon{font-size:.9375rem;width:.9375rem;height:.9375rem}.lib-vec__mono{font-family:var(--lib-forms-font-mono, monospace)}:host ::ng-deep .mat-mdc-form-field-hint-wrapper{min-width:0}:host ::ng-deep .mat-mdc-form-field-hint{min-width:0;width:100%}.showSuggestionContainer{display:block;box-sizing:border-box;width:100%;max-width:100%;overflow:hidden}.suggestion-container{display:flex;flex-wrap:wrap;box-sizing:border-box;width:100%;gap:24px;max-height:220px;overflow-x:hidden;overflow-y:auto}.suggestion-column{flex:1 1 150px;min-width:0}.suggestion-heading{margin-bottom:12px;font-size:.625rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;opacity:.7}.button-container{display:flex;flex-wrap:wrap;gap:4px}.suggestion-button{height:auto;min-width:0;max-width:100%;text-align:left;font-size:11px;line-height:normal;padding:4px 8px;border-radius:4px;overflow:hidden}.suggestion-button ::ng-deep .mdc-button__label{display:block;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$2.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: MatButtonToggleModule }, { kind: "directive", type: i3$5.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i3$5.MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled", "disabledInteractive"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i4$3.MatChipGrid, selector: "mat-chip-grid", inputs: ["disabled", "placeholder", "required", "value", "errorStateMatcher"], outputs: ["change", "valueChange"] }, { kind: "directive", type: i4$3.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled", "readonly", "matChipInputDisabledInteractive"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { kind: "component", type: i4$3.MatChipOption, selector: "mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]", inputs: ["selectable", "selected"], outputs: ["selectionChange"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i4.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i2$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ApiValueAccessRulesComponent, selector: "lib-api-value-access-rules", inputs: ["disabled", "multipleBind", "errors", "value", "formInputs", "mapToData", "postmanCollectionConfig"], outputs: ["valueChanged", "reload"] }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: SearchListPipe, name: "searchList" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
19324
20171
  }
19325
20172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImport: i0, type: ValidationExpressioCreatorComponent, decorators: [{
19326
20173
  type: Component,
@@ -19328,16 +20175,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.12", ngImpo
19328
20175
  TitleCasePipe,
19329
20176
  ReactiveFormsModule,
19330
20177
  MatButtonModule,
20178
+ MatButtonToggleModule,
19331
20179
  MatChipsModule,
19332
20180
  MatDividerModule,
19333
20181
  MatFormFieldModule,
20182
+ MatIconModule,
19334
20183
  MatInputModule,
19335
20184
  MatTooltipModule,
19336
20185
  SearchListPipe,
19337
20186
  ApiValueAccessRulesComponent,
19338
20187
  ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
19339
20188
  class: 'lib-validation-expressio-creator',
19340
- }, template: "<mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\" floatLabel=\"always\"\r\n id=\"validationExpressionCreator\">\r\n <mat-label>Condition expression</mat-label>\r\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\r\n placeholder=\"Enter a validation string for the function\"></textarea>\r\n\r\n\r\n <mat-hint\r\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\r\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\r\n {{ errorMessage }}\r\n } @else {\r\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\r\n @if (showSuggestions()) {\r\n <section class=\"showSuggestionContainer\">\r\n <mat-divider></mat-divider>\r\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\r\n <div class=\"suggestion-container\">\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Logical Operators\r\n </div>\r\n <div class=\"button-container\">\r\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\r\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\r\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\r\n {{ method.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"suggestion-column\">\r\n <div class=\"suggestion-heading\">\r\n Add Input as a Variable\r\n </div>\r\n <div class=\"button-container\">\r\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\r\n <button mat-button matTooltipPosition=\"right\"\r\n [matTooltip]=\"'Add Variable - ' + inp.label\"\r\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\r\n {{ inp.label | titlecase }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </section>\r\n }\r\n }\r\n </mat-hint>\r\n</mat-form-field>\r\n\r\n@if (valueAccessOptions().length > 0) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\r\n floatLabel=\"always\" id=\"Value access options\">\r\n <mat-label>\r\n Form Fields for expression\r\n </mat-label>\r\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\r\n @for (variable of valueAccessOptions(); track variable) {\r\n <mat-chip-option\r\n [selected]=\"variableInEdit() === variable\"\r\n (click)=\"toggleVariableInEdit(variable)\"\r\n [aria-description]=\"'press enter to edit ' + variable\">\r\n {{ variable }}\r\n </mat-chip-option>\r\n }\r\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\r\n </mat-chip-grid>\r\n @if (variableInEdit(); as activeVariable) {\r\n <lib-api-value-access-rules\r\n [value]=\"getValueAccessRule(activeVariable)\"\r\n [errors]=\"[]\"\r\n [formInputs]=\"formInputs() || []\"\r\n [mapToData]=\"data()\"\r\n (valueChanged)=\"activeVariableChanged($event)\">\r\n </lib-api-value-access-rules>\r\n }\r\n <mat-hint>\r\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\r\n data within a complex object.\r\n </mat-hint>\r\n </mat-form-field>\r\n}\r\n", styles: [".suggestion-container{display:flex;width:100%;gap:8px}.suggestion-column{flex:1;min-width:0}.button-container{display:flex;flex-wrap:wrap}.suggestion-button{height:auto;text-align:left;font-size:10.5px;border-radius:4px;margin-bottom:4px;line-height:normal;padding:4px;white-space:nowrap;overflow:hidden;display:inline-block;text-overflow:ellipsis}.suggestion-heading{margin-bottom:8px;font-size:.6875em;font-weight:500}\n"] }]
20189
+ }, template: "<section class=\"lib-vec\">\n <div class=\"lib-vec__head\">\n <div class=\"lib-vec__heading\">\n <span class=\"lib-vec__f-label\">Condition expression</span>\n <p class=\"lib-vec__sub-hint\">{{ hint() }}</p>\n </div>\n\n @if (mode() === 'advanced') {\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"!canUseGuided()\"\n [matTooltip]=\"canUseGuided() ? 'Build this with guided rows' : 'This expression is too advanced for the guided builder'\"\n (click)=\"useGuided()\">\n <mat-icon>view_module</mat-icon> Guided\n </button>\n } @else {\n <button type=\"button\" class=\"lib-vec__link\" matTooltip=\"Type the expression yourself\"\n (click)=\"useAdvanced()\">\n <mat-icon>code</mat-icon> Advanced\n </button>\n }\n </div>\n\n @if (mode() === 'guided') {\n @if (fieldOptions().length === 0) {\n <p class=\"lib-vec__sub-hint\">\n No fields available yet \u2014 switch to Advanced to type an expression.\n </p>\n } @else if (group().conditions.length === 0) {\n <p class=\"lib-vec__sub-hint lib-vec__sub-hint--lead\">\n <mat-icon class=\"lib-vec__lead-icon\">lightbulb</mat-icon>\n <span>Add a check below \u2014 this passes when it\u2019s true.</span>\n </p>\n } @else if (group().conditions.length > 1) {\n <div class=\"lib-vec__match\">\n <span class=\"lib-vec__muted\">Match</span>\n <mat-button-toggle-group class=\"lib-vec__seg\" [value]=\"group().connector\"\n hideSingleSelectionIndicator (change)=\"setConnector($event.value)\"\n aria-label=\"Combine conditions\">\n <mat-button-toggle value=\"&&\">All</mat-button-toggle>\n <mat-button-toggle value=\"||\">Any</mat-button-toggle>\n </mat-button-toggle-group>\n <span class=\"lib-vec__muted\">of the checks</span>\n </div>\n }\n\n @for (cond of group().conditions; track $index; let first = $first) {\n @if (!first) {\n <div class=\"lib-vec__connector\" aria-hidden=\"true\">\n <span>{{ group().connector === '&&' ? 'AND' : 'OR' }}</span>\n </div>\n }\n <div class=\"lib-vec__cond\" [class.lib-vec__cond--incomplete]=\"!cond.field || !cond.value\">\n <div class=\"lib-vec__cond-row\">\n <select class=\"lib-vec__control lib-vec__control--field\"\n [class.lib-vec__control--invalid]=\"!cond.field\"\n (change)=\"updateCondition($index, { field: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.field\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.field\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n (click)=\"removeCondition($index)\" matTooltip=\"Remove check\" aria-label=\"Remove check\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"lib-vec__cond-row lib-vec__cond-row--ops\">\n <select class=\"lib-vec__control\"\n (change)=\"updateCondition($index, { operator: inputValue($event) })\">\n @for (op of operators; track op.value) {\n <option [value]=\"op.value\" [selected]=\"op.value === cond.operator\">\n {{ op.label }}\n </option>\n }\n </select>\n\n @if (cond.compareTo === 'field') {\n <select class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n (change)=\"updateCondition($index, { value: inputValue($event) })\">\n <option value=\"\" disabled [selected]=\"!cond.value\">Choose a field</option>\n @for (group of fieldOptionGroups(); track $index) {\n @if (group.label) {\n <optgroup [label]=\"group.label\">\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n </optgroup>\n } @else {\n @for (f of group.options; track f.variable) {\n <option [value]=\"f.variable\" [selected]=\"f.variable === cond.value\">\n {{ f.label }}\n </option>\n }\n }\n }\n </select>\n } @else {\n <input class=\"lib-vec__control\"\n [class.lib-vec__control--invalid]=\"!cond.value\"\n [value]=\"cond.value\"\n (input)=\"updateCondition($index, { value: inputValue($event) })\"\n [placeholder]=\"'a value'\" />\n }\n\n <button type=\"button\" class=\"lib-vec__icon-btn\"\n [class.lib-vec__icon-btn--on]=\"cond.compareTo === 'field'\"\n (click)=\"toggleCompareTo($index)\"\n [attr.aria-label]=\"cond.compareTo === 'field' ? 'Compare to a typed value' : 'Compare to another field'\"\n [matTooltip]=\"cond.compareTo === 'field' ? 'Comparing to a field \u2014 switch to a typed value' : 'Compare to another field instead'\">\n <mat-icon>{{ cond.compareTo === 'field' ? 'link' : 'link_off' }}</mat-icon>\n </button>\n </div>\n </div>\n }\n\n <div class=\"lib-vec__foot\">\n <button type=\"button\" class=\"lib-vec__link\" [disabled]=\"fieldOptions().length === 0\"\n (click)=\"addCondition()\">\n <mat-icon>add</mat-icon> Add check\n </button>\n\n @if (expressionText()) {\n <span class=\"lib-vec__valid\" matTooltip=\"Generated expression: {{ expressionText() }}\">\n <mat-icon>check_circle</mat-icon> Ready\n </span>\n }\n </div>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;\"\n floatLabel=\"always\" id=\"validationExpressionCreator\">\n <mat-label>Expression</mat-label>\n <textarea [formControl]=\"expressionControl\" matInput #textarea (focus)=\"onFocus()\"\n class=\"lib-vec__mono\"\n placeholder=\"Enter a validation string for the function\"></textarea>\n\n <mat-hint\n [style.color]=\"expressionControl.invalid && !showSuggestions() ? 'var(--mat-form-field-error-text-color, var(--mat-sys-error))' : ''\">\n @if (expressionControl.invalid && errorMessage !== null && !showSuggestions()) {\n {{ errorMessage }}\n } @else {\n {{ showSuggestions() ? 'Click a suggestion to apply it' : 'Enter a filter condition. Type $ for options' }}\n @if (showSuggestions()) {\n <section class=\"showSuggestionContainer\">\n <mat-divider></mat-divider>\n <div style=\"padding: 0px;margin-top:8px\" class=\"\">\n <div class=\"suggestion-container\">\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Logical Operators\n </div>\n <div class=\"button-container\">\n @for (method of getMethods() | searchList:optionsSearch(); track method.value) {\n <button matTooltipPosition=\"left\" [matTooltip]=\"method.hint\" color=\"primary\" mat-button\n (click)=\"selectSuggestionInput(method.value)\" class=\"suggestion-button\">\n {{ method.label | titlecase }}\n </button>\n }\n </div>\n </div>\n <div class=\"suggestion-column\">\n <div class=\"suggestion-heading\">\n Add Input as a Variable\n </div>\n <div class=\"button-container\">\n @for (inp of allInputs() | searchList:optionsSearch(); track inp.formControlName) {\n <button mat-button matTooltipPosition=\"right\"\n [matTooltip]=\"'Add Variable - ' + inp.label\"\n (click)=\"selectSuggestionInput(inp.formControlName)\" class=\"suggestion-button\">\n {{ inp.label | titlecase }}\n </button>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n }\n }\n </mat-hint>\n </mat-form-field>\n }\n</section>\n\n@if (valueAccessOptions().length > 0) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" style=\"width: 100%;margin-top:12px\"\n floatLabel=\"always\" id=\"Value access options\">\n <mat-label>\n Form Fields for expression\n </mat-label>\n <mat-chip-grid #chipGrid aria-label=\"value access options\">\n @for (variable of valueAccessOptions(); track variable) {\n <mat-chip-option\n [selected]=\"variableInEdit() === variable\"\n (click)=\"toggleVariableInEdit(variable)\"\n [aria-description]=\"'press enter to edit ' + variable\">\n {{ variable }}\n </mat-chip-option>\n }\n <input placeholder=\"\" style=\"display: none;\" [matChipInputFor]=\"chipGrid\" />\n </mat-chip-grid>\n @if (variableInEdit(); as activeVariable) {\n <lib-api-value-access-rules\n [value]=\"getValueAccessRule(activeVariable)\"\n [errors]=\"[]\"\n [formInputs]=\"formInputs() || []\"\n [mapToData]=\"data()\"\n (valueChanged)=\"activeVariableChanged($event)\">\n </lib-api-value-access-rules>\n }\n <mat-hint>\n Click a field to define how to process its value. You can filter a list, count its items, or access specific\n data within a complex object.\n </mat-hint>\n </mat-form-field>\n}\n", styles: [".lib-vec{display:flex;flex-direction:column;gap:.625rem}.lib-vec__head{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.lib-vec__heading{display:flex;flex-direction:column;gap:.125rem;min-width:0}.lib-vec__f-label{font-size:.625rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint{margin:0;font-size:.75rem;line-height:1.4;color:var(--lib-forms-on-surface-variant)}.lib-vec__sub-hint--lead{display:flex;align-items:center;gap:.375rem;padding:.4375rem .625rem;background:var(--lib-forms-surface-container-lowest);border:1px dashed var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px)}.lib-vec__lead-icon{flex:none;font-size:1rem;width:1rem;height:1rem;color:var(--sem-info, var(--lib-forms-primary))}.lib-vec__match{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.lib-vec__muted{font-size:.75rem;color:var(--lib-forms-on-surface-variant)}.lib-vec__seg{--mat-standard-button-toggle-height: 28px;height:28px}.lib-vec__connector{display:flex;justify-content:center;margin:-.1875rem 0}.lib-vec__connector span{padding:.0625rem .5rem;font-size:.5625rem;font-weight:600;letter-spacing:.1em;color:var(--lib-forms-on-surface-variant);background:var(--lib-forms-surface-container-high);border-radius:var(--lib-forms-radius-pill, 999px)}.lib-vec__cond{display:flex;flex-direction:column;gap:.375rem;padding:.5rem .5rem .5625rem;background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-md, 12px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__cond:hover{border-color:var(--lib-forms-outline)}.lib-vec__cond--incomplete{border-color:var(--sem-warning, var(--lib-forms-outline-variant))}.lib-vec__cond-row{display:grid;grid-template-columns:1fr auto;align-items:center;gap:.375rem;min-width:0}.lib-vec__cond-row--ops{grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto}.lib-vec__control{box-sizing:border-box;width:100%;min-width:0;height:2rem;padding:.3125rem .5rem;font-family:inherit;font-size:.8125rem;line-height:1.2;color:var(--lib-forms-on-surface);background:var(--lib-forms-surface-container-lowest);border:1px solid var(--lib-forms-outline-variant);border-radius:var(--lib-forms-radius-sm, 8px);transition:border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__control--field{font-weight:500}select.lib-vec__control{cursor:pointer}.lib-vec__control:hover{border-color:var(--lib-forms-outline)}.lib-vec__control:focus{outline:none;border-color:var(--lib-forms-primary);box-shadow:0 0 0 1px var(--lib-forms-primary)}.lib-vec__control--invalid:not(:focus){border-color:var(--sem-warning, var(--lib-forms-outline));background:var(--sem-warning-surface, var(--lib-forms-surface-container-lowest))}.lib-vec__icon-btn{display:inline-flex;align-items:center;justify-content:center;flex:none;width:1.875rem;height:1.875rem;padding:0;color:var(--lib-forms-on-surface-variant);background:transparent;border:1px solid transparent;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1)),border-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__icon-btn:hover{color:var(--lib-forms-primary);background:var(--lib-forms-primary-container)}.lib-vec__icon-btn--on{color:var(--lib-forms-primary);border-color:var(--lib-forms-primary)}.lib-vec__icon-btn mat-icon{font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__link{display:inline-flex;align-items:center;gap:.25rem;height:1.75rem;padding:0 .5rem;font:inherit;font-size:.8125rem;font-weight:500;color:var(--lib-forms-primary);background:transparent;border:0;border-radius:var(--lib-forms-radius-sm, 8px);cursor:pointer;transition:background-color var(--lib-forms-duration-hover, .3s) var(--lib-forms-easing, cubic-bezier(.16, 1, .3, 1))}.lib-vec__head .lib-vec__link{flex:none}.lib-vec__link:hover:not(:disabled){background:var(--lib-forms-primary-container)}.lib-vec__link:disabled{color:var(--lib-forms-on-surface-variant);cursor:default;opacity:.6}.lib-vec__link mat-icon{flex:none;font-size:1.0625rem;width:1.0625rem;height:1.0625rem}.lib-vec__foot{display:flex;align-items:center;justify-content:space-between;gap:.5rem}.lib-vec__valid{display:inline-flex;align-items:center;gap:.25rem;font-size:.6875rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--sem-success, var(--lib-forms-primary));cursor:default}.lib-vec__valid mat-icon{font-size:.9375rem;width:.9375rem;height:.9375rem}.lib-vec__mono{font-family:var(--lib-forms-font-mono, monospace)}:host ::ng-deep .mat-mdc-form-field-hint-wrapper{min-width:0}:host ::ng-deep .mat-mdc-form-field-hint{min-width:0;width:100%}.showSuggestionContainer{display:block;box-sizing:border-box;width:100%;max-width:100%;overflow:hidden}.suggestion-container{display:flex;flex-wrap:wrap;box-sizing:border-box;width:100%;gap:24px;max-height:220px;overflow-x:hidden;overflow-y:auto}.suggestion-column{flex:1 1 150px;min-width:0}.suggestion-heading{margin-bottom:12px;font-size:.625rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;opacity:.7}.button-container{display:flex;flex-wrap:wrap;gap:4px}.suggestion-button{height:auto;min-width:0;max-width:100%;text-align:left;font-size:11px;line-height:normal;padding:4px 8px;border-radius:4px;overflow:hidden}.suggestion-button ::ng-deep .mdc-button__label{display:block;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n"] }]
19341
20190
  }], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], formInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "formInputs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], expression: [{ type: i0.Input, args: [{ isSignal: true, alias: "expression", required: false }] }], valueAccessRules: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueAccessRules", required: false }] }], expressionChange: [{ type: i0.Output, args: ["expressionChange"] }], textareaElementRef: [{ type: i0.ViewChild, args: ['textarea', { isSignal: true }] }] } });
19342
20191
 
19343
20192
  /**
@@ -19457,5 +20306,5 @@ const getSignatureImage = async (inputConfig, value, secret) => {
19457
20306
  * Generated bundle index. Do not edit.
19458
20307
  */
19459
20308
 
19460
- export { NgxTFormsComponent as $, ACCOUNTING_BASIS as A, BaseCustomInput as B, getToolbarBackground as C, DaysAgoPipe as D, EmptyStateComponent as E, FormsStoreService as F, getToolbarIconColor as G, FORM_ACTIONS_TOKEN as H, FORM_CONFIG_TOKEN as I, JsonEditorComponent as J, FORM_INPUTS_TOKEN as K, FORM_ROUTE_SOURCE as L, MscoaFormInputComponent as M, NGX_T_FORMS_CONFIG_TOKEN as N, FORM_SLIDES_TOKEN as O, PREDICATE_OPERATORS as P, FormTowerControllerService as Q, HttpPipelineRepository as R, SignatureInputElementComponent as S, TDynamicDataEditComponent as T, UserFormStepperComponent as U, ValidationExpressioCreatorComponent as V, IMPORT_TOWER_INSTANCE_ID as W, INPUT_SECRET_TOKEN as X, MSCOA_TREE_PROVIDER as Y, MULTIPLE_FORM_INPUT_TOKEN as Z, _isEqual as _, assignDeepPropertyToObject as a, NgxTFormsService as a0, PIPELINE_REPOSITORY as a1, PipelineRepository as a2, PropertyAccessError as a3, TFormImportController as a4, UTILS_OBJECT_TOKEN as a5, createFileFromBase64 as a6, formGenerator as a7, getPipedValueFromDataType as a8, getSampleValueForInput as a9, getSectionElements as aa, getUrl as ab, getValueFromValueAccessor as ac, initFormConfigToV2 as ad, provideNgxTForms as ae, returnDeepProperty as af, sheetConsolodation as ag, textIconsForUserHints as ah, validateExpressionSyntax as ai, validateObjectAgainstString as aj, withHttpPipeline as ak, withInputSecret as al, withRouterFormId as am, formatData_pipe as an, TDynamicDataViewComponent as b, TFormEngine as c, TourManagerService as d, getSubmissionStatusFn as e, evaluatePredicate as f, getAvatar as g, TreeComponent as h, convertPostmanFolderItemsToTree as i, ErrorListComponent as j, NESTED_EDITOR_COMPONENT as k, DataTreeComponent as l, getInputErrorMessage as m, TFormInputStatusComponent as n, DialogTemplateComponent as o, FormBuilderComponent as p, FormsComponent as q, TFormInputComponent as r, safeReturnDeepProperty as s, testAgainstItem as t, getSignatureImage as u, calculateListOveralFunctions as v, returnMappedPathValue as w, FormatDataPipe as x, fuzzySearch as y, getToolbarColor as z };
19461
- //# sourceMappingURL=ngx-t-forms-ngx-t-forms-u_kigDid.mjs.map
20309
+ export { HttpPipelineRepository as $, calculateListOveralFunctions as A, BaseCustomInput as B, returnMappedPathValue as C, DaysAgoPipe as D, EmptyStateComponent as E, FormsStoreService as F, FormatDataPipe as G, fuzzySearch as H, ACCOUNTING_BASIS as I, JsonEditorComponent as J, getToolbarColor as K, getToolbarBackground as L, MscoaFormInputComponent as M, NGX_T_FORMS_CONFIG_TOKEN as N, getToolbarIconColor as O, PREDICATE_OPERATORS as P, FORM_ACTIONS_TOKEN as Q, FORM_CONFIG_TOKEN as R, SignatureInputElementComponent as S, TDynamicDataEditComponent as T, UserFormStepperComponent as U, ValidationExpressioCreatorComponent as V, FORM_INPUTS_TOKEN as W, FORM_ROUTE_SOURCE as X, FORM_SLIDES_TOKEN as Y, FormTowerControllerService as Z, _isEqual as _, assignDeepPropertyToObject as a, IMPORT_TOWER_INSTANCE_ID as a0, INPUT_SECRET_TOKEN as a1, MSCOA_TREE_PROVIDER as a2, MULTIPLE_FORM_INPUT_TOKEN as a3, NgxTFormsComponent as a4, NgxTFormsService as a5, PIPELINE_REPOSITORY as a6, PipelineRepository as a7, PropertyAccessError as a8, TFormImportController as a9, UTILS_OBJECT_TOKEN as aa, createFileFromBase64 as ab, formGenerator as ac, getPipedValueFromDataType as ad, getSampleValueForInput as ae, getSectionElements as af, getUrl as ag, getValueFromValueAccessor as ah, initFormConfigToV2 as ai, provideNgxTForms as aj, returnDeepProperty as ak, sheetConsolodation as al, textIconsForUserHints as am, validateExpressionSyntax as an, validateObjectAgainstString as ao, withHttpPipeline as ap, withInputSecret as aq, withRouterFormId as ar, formatData_pipe as as, TDynamicDataViewComponent as b, TFormEngine as c, TourManagerService as d, getSubmissionStatusFn as e, evaluatePredicate as f, getAvatar as g, emptyCondition as h, deriveObservedInputs as i, TreeComponent as j, convertPostmanFolderItemsToTree as k, ErrorListComponent as l, NESTED_EDITOR_COMPONENT as m, safeReturnDeepProperty as n, DataTreeComponent as o, parseConditions as p, getInputErrorMessage as q, referencedTokens as r, serializeConditions as s, testAgainstItem as t, TFormInputStatusComponent as u, DialogTemplateComponent as v, FormBuilderComponent as w, FormsComponent as x, TFormInputComponent as y, getSignatureImage as z };
20310
+ //# sourceMappingURL=ngx-t-forms-ngx-t-forms-C2G8_WQk.mjs.map