@expeed/ngx-data-mapper 1.2.6 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, Injectable, EventEmitter, inject, ViewChildren, ViewChild, Output, Input, Component, HostListener } from '@angular/core';
2
+ import { signal, computed, Injectable, EventEmitter, inject, ViewChildren, ViewChild, Output, Input, Component, HostListener, ChangeDetectorRef, ApplicationRef } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i3 from '@angular/material/icon';
@@ -8,7 +8,7 @@ import * as i2 from '@angular/material/button';
8
8
  import { MatButtonModule } from '@angular/material/button';
9
9
  import * as i7 from '@angular/material/tooltip';
10
10
  import { MatTooltipModule } from '@angular/material/tooltip';
11
- import * as i2$1 from '@angular/forms';
11
+ import * as i1$1 from '@angular/forms';
12
12
  import { FormsModule } from '@angular/forms';
13
13
  import * as i4 from '@angular/material/select';
14
14
  import { MatSelectModule } from '@angular/material/select';
@@ -17,7 +17,7 @@ import { MatInputModule } from '@angular/material/input';
17
17
  import { MatFormFieldModule } from '@angular/material/form-field';
18
18
  import * as i8 from '@angular/material/checkbox';
19
19
  import { MatCheckboxModule } from '@angular/material/checkbox';
20
- import * as i10 from '@angular/cdk/drag-drop';
20
+ import * as i7$2 from '@angular/cdk/drag-drop';
21
21
  import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
22
22
  import * as i6 from '@angular/material/radio';
23
23
  import { MatRadioModule } from '@angular/material/radio';
@@ -28,9 +28,9 @@ import { MatDividerModule } from '@angular/material/divider';
28
28
  import * as i6$1 from '@angular/material/datepicker';
29
29
  import { MatDatepickerModule } from '@angular/material/datepicker';
30
30
  import { MatNativeDateModule } from '@angular/material/core';
31
- import * as i8$1 from '@angular/material/menu';
31
+ import * as i6$2 from '@angular/material/menu';
32
32
  import { MatMenuModule } from '@angular/material/menu';
33
- import * as i9$1 from '@angular/material/button-toggle';
33
+ import * as i6$3 from '@angular/material/button-toggle';
34
34
  import { MatButtonToggleModule } from '@angular/material/button-toggle';
35
35
 
36
36
  /**
@@ -1887,7 +1887,7 @@ class TransformationPopoverComponent {
1887
1887
  return labels[operator] || operator;
1888
1888
  }
1889
1889
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TransformationPopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1890
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TransformationPopoverComponent, isStandalone: true, selector: "transformation-popover", inputs: { mapping: "mapping", position: "position", sampleData: "sampleData" }, outputs: { save: "save", delete: "delete", close: "close" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"transformation-popover\" [ngStyle]=\"getPopoverStyle()\">\r\n <div class=\"popover-arrow\"></div>\r\n\r\n <div class=\"popover-header\">\r\n <span class=\"popover-title\">Transformation</span>\r\n <button mat-icon-button class=\"close-btn\" (click)=\"onClose()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"popover-content\">\r\n <!-- Source/Target Info -->\r\n <div class=\"mapping-info\">\r\n <div class=\"info-row\">\r\n <span class=\"info-label\">Source:</span>\r\n <span class=\"info-value\">{{ getSourceFieldNames() }}</span>\r\n </div>\r\n <div class=\"info-row\">\r\n <span class=\"info-label\">Target:</span>\r\n <span class=\"info-value\">{{ mapping.targetField.name }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Single Step Mode (default, clean UI) -->\r\n @if (!isMultiStep) {\r\n <ng-container *ngTemplateOutlet=\"stepConfig; context: { step: steps[0], index: 0, showHeader: false }\"></ng-container>\r\n\r\n <!-- Preview Section -->\r\n <div class=\"preview-section\">\r\n <span class=\"preview-label\">Preview:</span>\r\n <div class=\"preview-value\">{{ stepPreviews[0] || '(empty)' }}</div>\r\n </div>\r\n }\r\n\r\n <!-- Multi-Step Mode -->\r\n @if (isMultiStep) {\r\n <div class=\"steps-container\" cdkDropList (cdkDropListDropped)=\"onStepDrop($event)\">\r\n @for (step of steps; track $index; let i = $index) {\r\n <div class=\"step-card\" [class.expanded]=\"isStepExpanded(i)\" cdkDrag>\r\n <!-- Collapsed View -->\r\n @if (!isStepExpanded(i)) {\r\n <div class=\"step-collapsed\" (click)=\"toggleStep(i)\">\r\n <mat-icon class=\"drag-handle\" cdkDragHandle (click)=\"$event.stopPropagation()\">drag_indicator</mat-icon>\r\n <div class=\"step-collapsed-header\">\r\n <div class=\"step-title-row\">\r\n <span class=\"step-number\">Step {{ i + 1 }}: {{ getStepTypeLabel(step.type) }}</span>\r\n @if (hasCondition(step)) {\r\n <span class=\"condition-badge\" matTooltip=\"{{ getConditionSummary(step) }}\">\r\n <mat-icon>filter_alt</mat-icon>\r\n if\r\n </span>\r\n }\r\n </div>\r\n <div class=\"step-collapsed-actions\">\r\n <button\r\n mat-icon-button\r\n class=\"expand-btn\"\r\n (click)=\"toggleStep(i); $event.stopPropagation()\"\r\n matTooltip=\"Edit step\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n class=\"remove-step-btn\"\r\n (click)=\"removeStep(i); $event.stopPropagation()\"\r\n matTooltip=\"Remove step\"\r\n >\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"step-collapsed-preview\">\r\n <span class=\"step-input\">\"{{ (stepInputs[i] || '') | slice:0:20 }}{{ (stepInputs[i] || '').length > 20 ? '...' : '' }}\"</span>\r\n <mat-icon class=\"arrow-icon\">arrow_forward</mat-icon>\r\n <span class=\"step-output\">\"{{ (stepPreviews[i] || '') | slice:0:20 }}{{ (stepPreviews[i] || '').length > 20 ? '...' : '' }}\"</span>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Expanded View -->\r\n @if (isStepExpanded(i)) {\r\n <div class=\"step-expanded\">\r\n <mat-icon class=\"drag-handle\" cdkDragHandle>drag_indicator</mat-icon>\r\n <div class=\"step-header\">\r\n <span class=\"step-number\">Step {{ i + 1 }}</span>\r\n <div class=\"step-header-actions\">\r\n <button\r\n mat-icon-button\r\n class=\"collapse-btn\"\r\n (click)=\"toggleStep(i)\"\r\n matTooltip=\"Collapse\"\r\n >\r\n <mat-icon>expand_less</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n class=\"remove-step-btn\"\r\n (click)=\"removeStep(i)\"\r\n matTooltip=\"Remove step\"\r\n >\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"step-content\">\r\n <ng-container *ngTemplateOutlet=\"stepConfig; context: { step: step, index: i, showHeader: false }\"></ng-container>\r\n </div>\r\n\r\n <!-- Step Preview -->\r\n <div class=\"step-preview\">\r\n <mat-icon class=\"preview-arrow\">arrow_downward</mat-icon>\r\n <span class=\"step-preview-value\">{{ stepPreviews[i] || '(empty)' }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Final Preview -->\r\n <div class=\"preview-section final-preview\">\r\n <span class=\"preview-label\">Final Result:</span>\r\n <div class=\"preview-value\">{{ finalPreview || '(empty)' }}</div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Add Step Button - Always visible -->\r\n <div class=\"add-step-section\">\r\n <button mat-stroked-button class=\"add-step-btn\" (click)=\"addStep()\">\r\n <mat-icon>add</mat-icon>\r\n @if (isMultiStep) {\r\n Add Step\r\n } @else {\r\n Add Transformation Step\r\n }\r\n </button>\r\n </div>\r\n\r\n <div class=\"popover-actions\">\r\n <button mat-button color=\"warn\" (click)=\"onDelete()\" matTooltip=\"Remove this mapping\">\r\n <mat-icon>delete</mat-icon>\r\n Delete\r\n </button>\r\n <div class=\"action-spacer\"></div>\r\n <button mat-button (click)=\"onClose()\">Cancel</button>\r\n <button mat-flat-button color=\"primary\" (click)=\"onSave()\">Apply</button>\r\n </div>\r\n</div>\r\n\r\n<!-- Backdrop -->\r\n<div class=\"popover-backdrop\" (click)=\"onClose()\"></div>\r\n\r\n<!-- Step Configuration Template -->\r\n<ng-template #stepConfig let-step=\"step\" let-index=\"index\" let-showHeader=\"showHeader\">\r\n <!-- Transformation Type -->\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Transformation Type</mat-label>\r\n <mat-select [(ngModel)]=\"step.type\" (selectionChange)=\"onStepTypeChange(index)\">\r\n @for (t of availableTransformations; track t.type) {\r\n <mat-option [value]=\"t.type\">{{ t.label }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- Type-specific options -->\r\n @switch (step.type) {\r\n @case ('concat') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Separator</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.separator\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\" \"\r\n />\r\n <mat-hint>Join values with this (default: space)</mat-hint>\r\n </mat-form-field>\r\n <div class=\"or-divider\">or use template for custom format</div>\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Template</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.template\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n [placeholder]=\"'{0} - {1}'\"\r\n />\r\n <mat-hint>Overrides separator if set</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('substring') {\r\n <div class=\"config-section config-row\">\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>Start Index</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [(ngModel)]=\"step.startIndex\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n min=\"0\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>End Index</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [(ngModel)]=\"step.endIndex\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('replace') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Search For</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.searchValue\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Replace With</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.replaceValue\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('dateFormat') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Output Format</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.outputFormat\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\"YYYY-MM-DD\"\r\n />\r\n <mat-hint>YYYY, MM, DD, HH, mm, ss</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('numberFormat') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Decimal Places</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [(ngModel)]=\"step.decimalPlaces\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n min=\"0\"\r\n />\r\n </mat-form-field>\r\n <div class=\"config-row\">\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>Prefix</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.prefix\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\"$\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>Suffix</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.suffix\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('mask') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Pattern</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.pattern\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\"(###) ###-####\"\r\n />\r\n <mat-hint># = character from input</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('template') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Template Expression</mat-label>\r\n <textarea\r\n matInput\r\n [(ngModel)]=\"step.template\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n rows=\"3\"\r\n [placeholder]=\"'Hello {0}, your ID is {1}'\"\r\n ></textarea>\r\n @if (index === 0) {\r\n <mat-hint>Use {{ '{' }}0{{ '}' }}, {{ '{' }}1{{ '}' }}, etc. for source fields</mat-hint>\r\n } @else {\r\n <mat-hint>Use {{ '{' }}0{{ '}' }} for the value from previous step</mat-hint>\r\n }\r\n </mat-form-field>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Condition Section -->\r\n <div class=\"condition-section\">\r\n <mat-checkbox\r\n [checked]=\"hasCondition(step)\"\r\n (change)=\"toggleCondition(step, $event.checked)\"\r\n class=\"condition-checkbox\"\r\n >\r\n Apply conditionally\r\n </mat-checkbox>\r\n\r\n @if (hasCondition(step)) {\r\n <div class=\"condition-content\">\r\n <condition-builder\r\n [condition]=\"step.condition?.root || null\"\r\n [compact]=\"true\"\r\n (conditionChange)=\"onConditionChange(step, $event)\"\r\n ></condition-builder>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";.popover-backdrop{position:fixed;inset:0;background:#0000004d;z-index:999}.transformation-popover{position:fixed;z-index:1000;width:420px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #0003;transform:translate(-50%,-50%);animation:popoverIn .2s ease-out}@keyframes popoverIn{0%{opacity:0;transform:translate(-50%,-50%) scale(.95)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}.popover-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #e2e8f0;background:#f8fafc;border-radius:12px 12px 0 0}.popover-title{font-size:16px;font-weight:600;color:#1e293b}.close-btn{width:32px;height:32px;line-height:32px}.close-btn mat-icon{font-size:20px;width:20px;height:20px}.popover-content{padding:20px;max-height:500px;overflow-y:auto}.mapping-info{background:#f1f5f9;border-radius:8px;padding:12px 16px;margin-bottom:16px}.info-row{display:flex;align-items:center;gap:8px}.info-row+.info-row{margin-top:8px}.info-label{font-size:12px;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px;width:60px}.info-value{font-size:14px;color:#1e293b;font-weight:500}.full-width{width:100%}.config-section{margin-top:12px}.or-divider{text-align:center;font-size:11px;color:#94a3b8;margin:8px 0}.condition-section{margin-top:16px;padding-top:12px;border-top:1px dashed #e2e8f0}.condition-checkbox{font-size:13px;color:#64748b}.condition-content{margin-top:12px}.config-row{display:flex;gap:12px}.config-row mat-form-field{flex:1}.preview-section{margin-top:16px;padding:12px 16px;background:linear-gradient(135deg,#eff6ff,#f0fdf4);border-radius:8px;border:1px solid #e0e7ff}.preview-label{font-size:11px;font-weight:600;color:#6366f1;text-transform:uppercase;letter-spacing:.5px;display:block;margin-bottom:6px}.preview-value{font-size:14px;color:#1e293b;font-family:Monaco,Menlo,monospace;word-break:break-all;min-height:20px}.steps-container{display:flex;flex-direction:column;gap:12px}.step-card{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;overflow:hidden;transition:all .2s ease}.step-card.expanded{border-color:#6366f1;border-width:2px;background:#fff}.step-collapsed{display:grid;grid-template-columns:auto 1fr;gap:0 12px;padding:12px;cursor:pointer;transition:background .15s ease}.step-collapsed:hover{background:#f1f5f9}.step-collapsed .drag-handle{grid-row:span 2;align-self:center}.step-collapsed-header{display:flex;align-items:center;flex-wrap:wrap;gap:4px}.step-collapsed-header .step-title-row{display:flex;align-items:center;gap:8px;flex:1}.step-collapsed-header .step-number{flex-shrink:0}.condition-badge{display:inline-flex;align-items:center;gap:2px;padding:2px 6px;background:#fef3c7;border:1px solid #f59e0b;border-radius:4px;font-size:10px;font-weight:600;color:#b45309;cursor:help}.condition-badge mat-icon{font-size:12px;width:12px;height:12px}.step-collapsed-actions{display:flex;align-items:center;gap:4px}.step-collapsed-preview{display:flex;align-items:center;gap:8px;margin-top:8px;font-size:12px;font-family:Monaco,Menlo,monospace}.step-input{color:#64748b;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.arrow-icon{font-size:14px;width:14px;height:14px;color:#6366f1}.step-output{color:#059669;font-weight:500;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.step-expanded{display:grid;grid-template-columns:auto 1fr;gap:0 12px;padding:12px}.step-expanded .drag-handle{grid-row:1;align-self:center}.step-expanded .step-header,.step-expanded .step-content,.step-expanded .step-preview{grid-column:2}.step-header{display:flex;align-items:center;margin-bottom:12px}.step-header .step-number{flex:1}.step-header-actions{display:flex;align-items:center;gap:4px}.step-number{font-size:12px;font-weight:600;color:#6366f1;text-transform:uppercase;letter-spacing:.5px}.expand-btn,.collapse-btn{width:28px;height:28px;line-height:28px}.expand-btn mat-icon,.collapse-btn mat-icon{font-size:18px;width:18px;height:18px;color:#64748b}.expand-btn:hover mat-icon,.collapse-btn:hover mat-icon{color:#6366f1}.remove-step-btn{width:28px;height:28px;line-height:28px}.remove-step-btn mat-icon{font-size:18px;width:18px;height:18px;color:#94a3b8}.remove-step-btn:hover mat-icon{color:#ef4444}.step-preview{display:flex;align-items:center;gap:8px;margin-top:12px;padding:8px 12px;background:#f1f5f9;border-radius:6px}.preview-arrow{font-size:16px;width:16px;height:16px;color:#6366f1}.step-preview-value{font-size:13px;color:#475569;font-family:Monaco,Menlo,monospace;word-break:break-all;flex:1}.add-step-section{padding:12px 20px;border-top:1px solid #e2e8f0;background:#fafafa}.add-step-btn{width:100%;border-style:dashed;color:#64748b}.add-step-btn mat-icon{font-size:18px;width:18px;height:18px;margin-right:4px}.add-step-btn:hover{border-color:#6366f1;color:#6366f1;background:#f5f3ff}.final-preview{margin-top:16px;background:linear-gradient(135deg,#ecfdf5,#d1fae5);border:2px solid #10b981;border-radius:8px;position:relative}.final-preview .preview-label{color:#059669;font-size:12px;font-weight:700}.final-preview .preview-value{color:#065f46;font-weight:600}.final-preview:before{content:\"\\2713\";position:absolute;right:12px;top:10px;color:#10b981;font-size:16px;font-weight:700}.popover-actions{display:flex;align-items:center;gap:8px;padding:16px 20px;border-top:1px solid #e2e8f0;background:#f8fafc;border-radius:0 0 12px 12px}.action-spacer{flex:1}::ng-deep .transformation-popover .mat-mdc-form-field{font-size:14px}::ng-deep .transformation-popover .mat-mdc-text-field-wrapper{background:#fff}::ng-deep .transformation-popover .mat-mdc-form-field-subscript-wrapper{font-size:11px}.drag-handle{cursor:grab;color:#94a3b8;font-size:20px;width:20px;height:20px;flex-shrink:0}.drag-handle:hover{color:#6366f1}.drag-handle:active{cursor:grabbing}.step-card.cdk-drag-preview{box-shadow:0 5px 20px #00000040;border-radius:8px;background:#fff}.step-card.cdk-drag-placeholder{opacity:.4;background:#e2e8f0;border:2px dashed #94a3b8}.step-card.cdk-drag-animating{transition:transform .2s ease}.steps-container.cdk-drop-list-dragging .step-card:not(.cdk-drag-placeholder){transition:transform .2s ease}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$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: i2$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatFormFieldModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i8.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: DragDropModule }, { kind: "directive", type: i10.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i10.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i10.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: ConditionBuilderComponent, selector: "condition-builder", inputs: ["fields", "condition", "compact"], outputs: ["conditionChange"] }, { kind: "pipe", type: i1.SlicePipe, name: "slice" }] });
1890
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: TransformationPopoverComponent, isStandalone: true, selector: "transformation-popover", inputs: { mapping: "mapping", position: "position", sampleData: "sampleData" }, outputs: { save: "save", delete: "delete", close: "close" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"transformation-popover\" [ngStyle]=\"getPopoverStyle()\">\r\n <div class=\"popover-arrow\"></div>\r\n\r\n <div class=\"popover-header\">\r\n <span class=\"popover-title\">Transformation</span>\r\n <button mat-icon-button class=\"close-btn\" (click)=\"onClose()\">\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n\r\n <div class=\"popover-content\">\r\n <!-- Source/Target Info -->\r\n <div class=\"mapping-info\">\r\n <div class=\"info-row\">\r\n <span class=\"info-label\">Source:</span>\r\n <span class=\"info-value\">{{ getSourceFieldNames() }}</span>\r\n </div>\r\n <div class=\"info-row\">\r\n <span class=\"info-label\">Target:</span>\r\n <span class=\"info-value\">{{ mapping.targetField.name }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- Single Step Mode (default, clean UI) -->\r\n @if (!isMultiStep) {\r\n <ng-container *ngTemplateOutlet=\"stepConfig; context: { step: steps[0], index: 0, showHeader: false }\"></ng-container>\r\n\r\n <!-- Preview Section -->\r\n <div class=\"preview-section\">\r\n <span class=\"preview-label\">Preview:</span>\r\n <div class=\"preview-value\">{{ stepPreviews[0] || '(empty)' }}</div>\r\n </div>\r\n }\r\n\r\n <!-- Multi-Step Mode -->\r\n @if (isMultiStep) {\r\n <div class=\"steps-container\" cdkDropList (cdkDropListDropped)=\"onStepDrop($event)\">\r\n @for (step of steps; track $index; let i = $index) {\r\n <div class=\"step-card\" [class.expanded]=\"isStepExpanded(i)\" cdkDrag>\r\n <!-- Collapsed View -->\r\n @if (!isStepExpanded(i)) {\r\n <div class=\"step-collapsed\" (click)=\"toggleStep(i)\">\r\n <mat-icon class=\"drag-handle\" cdkDragHandle (click)=\"$event.stopPropagation()\">drag_indicator</mat-icon>\r\n <div class=\"step-collapsed-header\">\r\n <div class=\"step-title-row\">\r\n <span class=\"step-number\">Step {{ i + 1 }}: {{ getStepTypeLabel(step.type) }}</span>\r\n @if (hasCondition(step)) {\r\n <span class=\"condition-badge\" matTooltip=\"{{ getConditionSummary(step) }}\">\r\n <mat-icon>filter_alt</mat-icon>\r\n if\r\n </span>\r\n }\r\n </div>\r\n <div class=\"step-collapsed-actions\">\r\n <button\r\n mat-icon-button\r\n class=\"expand-btn\"\r\n (click)=\"toggleStep(i); $event.stopPropagation()\"\r\n matTooltip=\"Edit step\"\r\n >\r\n <mat-icon>edit</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n class=\"remove-step-btn\"\r\n (click)=\"removeStep(i); $event.stopPropagation()\"\r\n matTooltip=\"Remove step\"\r\n >\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n <div class=\"step-collapsed-preview\">\r\n <span class=\"step-input\">\"{{ (stepInputs[i] || '') | slice:0:20 }}{{ (stepInputs[i] || '').length > 20 ? '...' : '' }}\"</span>\r\n <mat-icon class=\"arrow-icon\">arrow_forward</mat-icon>\r\n <span class=\"step-output\">\"{{ (stepPreviews[i] || '') | slice:0:20 }}{{ (stepPreviews[i] || '').length > 20 ? '...' : '' }}\"</span>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Expanded View -->\r\n @if (isStepExpanded(i)) {\r\n <div class=\"step-expanded\">\r\n <mat-icon class=\"drag-handle\" cdkDragHandle>drag_indicator</mat-icon>\r\n <div class=\"step-header\">\r\n <span class=\"step-number\">Step {{ i + 1 }}</span>\r\n <div class=\"step-header-actions\">\r\n <button\r\n mat-icon-button\r\n class=\"collapse-btn\"\r\n (click)=\"toggleStep(i)\"\r\n matTooltip=\"Collapse\"\r\n >\r\n <mat-icon>expand_less</mat-icon>\r\n </button>\r\n <button\r\n mat-icon-button\r\n class=\"remove-step-btn\"\r\n (click)=\"removeStep(i)\"\r\n matTooltip=\"Remove step\"\r\n >\r\n <mat-icon>close</mat-icon>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <div class=\"step-content\">\r\n <ng-container *ngTemplateOutlet=\"stepConfig; context: { step: step, index: i, showHeader: false }\"></ng-container>\r\n </div>\r\n\r\n <!-- Step Preview -->\r\n <div class=\"step-preview\">\r\n <mat-icon class=\"preview-arrow\">arrow_downward</mat-icon>\r\n <span class=\"step-preview-value\">{{ stepPreviews[i] || '(empty)' }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Final Preview -->\r\n <div class=\"preview-section final-preview\">\r\n <span class=\"preview-label\">Final Result:</span>\r\n <div class=\"preview-value\">{{ finalPreview || '(empty)' }}</div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Add Step Button - Always visible -->\r\n <div class=\"add-step-section\">\r\n <button mat-stroked-button class=\"add-step-btn\" (click)=\"addStep()\">\r\n <mat-icon>add</mat-icon>\r\n @if (isMultiStep) {\r\n Add Step\r\n } @else {\r\n Add Transformation Step\r\n }\r\n </button>\r\n </div>\r\n\r\n <div class=\"popover-actions\">\r\n <button mat-button color=\"warn\" (click)=\"onDelete()\" matTooltip=\"Remove this mapping\">\r\n <mat-icon>delete</mat-icon>\r\n Delete\r\n </button>\r\n <div class=\"action-spacer\"></div>\r\n <button mat-button (click)=\"onClose()\">Cancel</button>\r\n <button mat-flat-button color=\"primary\" (click)=\"onSave()\">Apply</button>\r\n </div>\r\n</div>\r\n\r\n<!-- Backdrop -->\r\n<div class=\"popover-backdrop\" (click)=\"onClose()\"></div>\r\n\r\n<!-- Step Configuration Template -->\r\n<ng-template #stepConfig let-step=\"step\" let-index=\"index\" let-showHeader=\"showHeader\">\r\n <!-- Transformation Type -->\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Transformation Type</mat-label>\r\n <mat-select [(ngModel)]=\"step.type\" (selectionChange)=\"onStepTypeChange(index)\">\r\n @for (t of availableTransformations; track t.type) {\r\n <mat-option [value]=\"t.type\">{{ t.label }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n\r\n <!-- Type-specific options -->\r\n @switch (step.type) {\r\n @case ('concat') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Separator</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.separator\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\" \"\r\n />\r\n <mat-hint>Join values with this (default: space)</mat-hint>\r\n </mat-form-field>\r\n <div class=\"or-divider\">or use template for custom format</div>\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Template</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.template\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n [placeholder]=\"'{0} - {1}'\"\r\n />\r\n <mat-hint>Overrides separator if set</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('substring') {\r\n <div class=\"config-section config-row\">\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>Start Index</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [(ngModel)]=\"step.startIndex\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n min=\"0\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>End Index</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [(ngModel)]=\"step.endIndex\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('replace') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Search For</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.searchValue\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Replace With</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.replaceValue\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('dateFormat') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Output Format</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.outputFormat\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\"YYYY-MM-DD\"\r\n />\r\n <mat-hint>YYYY, MM, DD, HH, mm, ss</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('numberFormat') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Decimal Places</mat-label>\r\n <input\r\n matInput\r\n type=\"number\"\r\n [(ngModel)]=\"step.decimalPlaces\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n min=\"0\"\r\n />\r\n </mat-form-field>\r\n <div class=\"config-row\">\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>Prefix</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.prefix\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\"$\"\r\n />\r\n </mat-form-field>\r\n <mat-form-field appearance=\"outline\">\r\n <mat-label>Suffix</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.suffix\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n />\r\n </mat-form-field>\r\n </div>\r\n </div>\r\n }\r\n\r\n @case ('mask') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Pattern</mat-label>\r\n <input\r\n matInput\r\n [(ngModel)]=\"step.pattern\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n placeholder=\"(###) ###-####\"\r\n />\r\n <mat-hint># = character from input</mat-hint>\r\n </mat-form-field>\r\n </div>\r\n }\r\n\r\n @case ('template') {\r\n <div class=\"config-section\">\r\n <mat-form-field appearance=\"outline\" class=\"full-width\">\r\n <mat-label>Template Expression</mat-label>\r\n <textarea\r\n matInput\r\n [(ngModel)]=\"step.template\"\r\n (ngModelChange)=\"onConfigChange()\"\r\n rows=\"3\"\r\n [placeholder]=\"'Hello {0}, your ID is {1}'\"\r\n ></textarea>\r\n @if (index === 0) {\r\n <mat-hint>Use {{ '{' }}0{{ '}' }}, {{ '{' }}1{{ '}' }}, etc. for source fields</mat-hint>\r\n } @else {\r\n <mat-hint>Use {{ '{' }}0{{ '}' }} for the value from previous step</mat-hint>\r\n }\r\n </mat-form-field>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Condition Section -->\r\n <div class=\"condition-section\">\r\n <mat-checkbox\r\n [checked]=\"hasCondition(step)\"\r\n (change)=\"toggleCondition(step, $event.checked)\"\r\n class=\"condition-checkbox\"\r\n >\r\n Apply conditionally\r\n </mat-checkbox>\r\n\r\n @if (hasCondition(step)) {\r\n <div class=\"condition-content\">\r\n <condition-builder\r\n [condition]=\"step.condition?.root || null\"\r\n [compact]=\"true\"\r\n (conditionChange)=\"onConditionChange(step, $event)\"\r\n ></condition-builder>\r\n </div>\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: ["@charset \"UTF-8\";.popover-backdrop{position:fixed;inset:0;background:#0000004d;z-index:999}.transformation-popover{position:fixed;z-index:1000;width:420px;background:#fff;border-radius:12px;box-shadow:0 10px 40px #0003;transform:translate(-50%,-50%);animation:popoverIn .2s ease-out}@keyframes popoverIn{0%{opacity:0;transform:translate(-50%,-50%) scale(.95)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}.popover-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #e2e8f0;background:#f8fafc;border-radius:12px 12px 0 0}.popover-title{font-size:16px;font-weight:600;color:#1e293b}.close-btn{width:32px;height:32px;line-height:32px}.close-btn mat-icon{font-size:20px;width:20px;height:20px}.popover-content{padding:20px;max-height:500px;overflow-y:auto}.mapping-info{background:#f1f5f9;border-radius:8px;padding:12px 16px;margin-bottom:16px}.info-row{display:flex;align-items:center;gap:8px}.info-row+.info-row{margin-top:8px}.info-label{font-size:12px;font-weight:600;color:#64748b;text-transform:uppercase;letter-spacing:.5px;width:60px}.info-value{font-size:14px;color:#1e293b;font-weight:500}.full-width{width:100%}.config-section{margin-top:12px}.or-divider{text-align:center;font-size:11px;color:#94a3b8;margin:8px 0}.condition-section{margin-top:16px;padding-top:12px;border-top:1px dashed #e2e8f0}.condition-checkbox{font-size:13px;color:#64748b}.condition-content{margin-top:12px}.config-row{display:flex;gap:12px}.config-row mat-form-field{flex:1}.preview-section{margin-top:16px;padding:12px 16px;background:linear-gradient(135deg,#eff6ff,#f0fdf4);border-radius:8px;border:1px solid #e0e7ff}.preview-label{font-size:11px;font-weight:600;color:#6366f1;text-transform:uppercase;letter-spacing:.5px;display:block;margin-bottom:6px}.preview-value{font-size:14px;color:#1e293b;font-family:Monaco,Menlo,monospace;word-break:break-all;min-height:20px}.steps-container{display:flex;flex-direction:column;gap:12px}.step-card{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;overflow:hidden;transition:all .2s ease}.step-card.expanded{border-color:#6366f1;border-width:2px;background:#fff}.step-collapsed{display:grid;grid-template-columns:auto 1fr;gap:0 12px;padding:12px;cursor:pointer;transition:background .15s ease}.step-collapsed:hover{background:#f1f5f9}.step-collapsed .drag-handle{grid-row:span 2;align-self:center}.step-collapsed-header{display:flex;align-items:center;flex-wrap:wrap;gap:4px}.step-collapsed-header .step-title-row{display:flex;align-items:center;gap:8px;flex:1}.step-collapsed-header .step-number{flex-shrink:0}.condition-badge{display:inline-flex;align-items:center;gap:2px;padding:2px 6px;background:#fef3c7;border:1px solid #f59e0b;border-radius:4px;font-size:10px;font-weight:600;color:#b45309;cursor:help}.condition-badge mat-icon{font-size:12px;width:12px;height:12px}.step-collapsed-actions{display:flex;align-items:center;gap:4px}.step-collapsed-preview{display:flex;align-items:center;gap:8px;margin-top:8px;font-size:12px;font-family:Monaco,Menlo,monospace}.step-input{color:#64748b;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.arrow-icon{font-size:14px;width:14px;height:14px;color:#6366f1}.step-output{color:#059669;font-weight:500;max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.step-expanded{display:grid;grid-template-columns:auto 1fr;gap:0 12px;padding:12px}.step-expanded .drag-handle{grid-row:1;align-self:center}.step-expanded .step-header,.step-expanded .step-content,.step-expanded .step-preview{grid-column:2}.step-header{display:flex;align-items:center;margin-bottom:12px}.step-header .step-number{flex:1}.step-header-actions{display:flex;align-items:center;gap:4px}.step-number{font-size:12px;font-weight:600;color:#6366f1;text-transform:uppercase;letter-spacing:.5px}.expand-btn,.collapse-btn{width:28px;height:28px;line-height:28px}.expand-btn mat-icon,.collapse-btn mat-icon{font-size:18px;width:18px;height:18px;color:#64748b}.expand-btn:hover mat-icon,.collapse-btn:hover mat-icon{color:#6366f1}.remove-step-btn{width:28px;height:28px;line-height:28px}.remove-step-btn mat-icon{font-size:18px;width:18px;height:18px;color:#94a3b8}.remove-step-btn:hover mat-icon{color:#ef4444}.step-preview{display:flex;align-items:center;gap:8px;margin-top:12px;padding:8px 12px;background:#f1f5f9;border-radius:6px}.preview-arrow{font-size:16px;width:16px;height:16px;color:#6366f1}.step-preview-value{font-size:13px;color:#475569;font-family:Monaco,Menlo,monospace;word-break:break-all;flex:1}.add-step-section{padding:12px 20px;border-top:1px solid #e2e8f0;background:#fafafa}.add-step-btn{width:100%;border-style:dashed;color:#64748b}.add-step-btn mat-icon{font-size:18px;width:18px;height:18px;margin-right:4px}.add-step-btn:hover{border-color:#6366f1;color:#6366f1;background:#f5f3ff}.final-preview{margin-top:16px;background:linear-gradient(135deg,#ecfdf5,#d1fae5);border:2px solid #10b981;border-radius:8px;position:relative}.final-preview .preview-label{color:#059669;font-size:12px;font-weight:700}.final-preview .preview-value{color:#065f46;font-weight:600}.final-preview:before{content:\"\\2713\";position:absolute;right:12px;top:10px;color:#10b981;font-size:16px;font-weight:700}.popover-actions{display:flex;align-items:center;gap:8px;padding:16px 20px;border-top:1px solid #e2e8f0;background:#f8fafc;border-radius:0 0 12px 12px}.action-spacer{flex:1}::ng-deep .transformation-popover .mat-mdc-form-field{font-size:14px}::ng-deep .transformation-popover .mat-mdc-text-field-wrapper{background:#fff}::ng-deep .transformation-popover .mat-mdc-form-field-subscript-wrapper{font-size:11px}.drag-handle{cursor:grab;color:#94a3b8;font-size:20px;width:20px;height:20px;flex-shrink:0}.drag-handle:hover{color:#6366f1}.drag-handle:active{cursor:grabbing}.step-card.cdk-drag-preview{box-shadow:0 5px 20px #00000040;border-radius:8px;background:#fff}.step-card.cdk-drag-placeholder{opacity:.4;background:#e2e8f0;border:2px dashed #94a3b8}.step-card.cdk-drag-animating{transition:transform .2s ease}.steps-container.cdk-drop-list-dragging .step-card:not(.cdk-drag-placeholder){transition:transform .2s ease}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: MatFormFieldModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i8.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: DragDropModule }, { kind: "directive", type: i7$2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i7$2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i7$2.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: ConditionBuilderComponent, selector: "condition-builder", inputs: ["fields", "condition", "compact"], outputs: ["conditionChange"] }, { kind: "pipe", type: i1.SlicePipe, name: "slice" }] });
1891
1891
  }
1892
1892
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: TransformationPopoverComponent, decorators: [{
1893
1893
  type: Component,
@@ -2411,7 +2411,7 @@ class DefaultValuePopoverComponent {
2411
2411
  }
2412
2412
  }
2413
2413
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DefaultValuePopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2414
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: DefaultValuePopoverComponent, isStandalone: true, selector: "default-value-popover", inputs: { field: "field", existingValue: "existingValue", position: "position" }, outputs: { save: "save", delete: "delete", close: "close" }, ngImport: i0, template: "<div class=\"popover-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"popover-container\">\n <div class=\"popover-header\">\n <div class=\"header-title\">\n <mat-icon>edit</mat-icon>\n <span>Default Value</span>\n </div>\n <button mat-icon-button (click)=\"onClose()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"popover-content\">\n <div class=\"field-info\">\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-type\">{{ fieldType }}</span>\n </div>\n\n <!-- String input -->\n @if (fieldType === 'string') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Default Value</mat-label>\n <input matInput [(ngModel)]=\"stringValue\" placeholder=\"Enter default value\">\n </mat-form-field>\n }\n\n <!-- Number input -->\n @if (fieldType === 'number') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Default Value</mat-label>\n <input matInput type=\"number\" [(ngModel)]=\"numberValue\" placeholder=\"Enter number\">\n </mat-form-field>\n }\n\n <!-- Boolean input -->\n @if (fieldType === 'boolean') {\n <div class=\"boolean-input\">\n <mat-slide-toggle [(ngModel)]=\"booleanValue\">\n {{ booleanValue ? 'True' : 'False' }}\n </mat-slide-toggle>\n </div>\n }\n\n <!-- Date input -->\n @if (fieldType === 'date') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Default Date</mat-label>\n <input matInput [matDatepicker]=\"picker\" [(ngModel)]=\"dateValue\">\n <mat-datepicker-toggle matIconSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n </mat-form-field>\n }\n </div>\n\n <div class=\"popover-actions\">\n @if (existingValue) {\n <button mat-button color=\"warn\" (click)=\"onDelete()\">\n <mat-icon>delete</mat-icon>\n Remove\n </button>\n }\n <span class=\"spacer\"></span>\n <button mat-button (click)=\"onClose()\">Cancel</button>\n <button mat-flat-button color=\"primary\" (click)=\"onSave()\">Save</button>\n </div>\n </div>\n</div>\n", styles: [".popover-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:#0000004d;z-index:1000;display:flex;align-items:center;justify-content:center}.popover-container{background:#fff;border-radius:12px;box-shadow:0 8px 32px #0003;min-width:320px;max-width:400px;overflow:hidden}.popover-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:linear-gradient(135deg,#10b981,#059669);color:#fff}.popover-header .header-title{display:flex;align-items:center;gap:8px;font-size:16px;font-weight:600}.popover-header .header-title mat-icon{font-size:20px;width:20px;height:20px}.popover-header button{color:#fff}.popover-content{padding:20px}.field-info{display:flex;align-items:center;gap:8px;margin-bottom:16px;padding:10px 12px;background:#f8fafc;border-radius:8px}.field-info .field-name{font-weight:600;color:#1e293b}.field-info .field-type{font-size:12px;color:#64748b;background:#e2e8f0;padding:2px 8px;border-radius:4px;text-transform:uppercase}.full-width{width:100%}.boolean-input{padding:12px 0}.popover-actions{display:flex;align-items:center;gap:8px;padding:16px 20px;background:#f8fafc;border-top:1px solid #e2e8f0}.popover-actions .spacer{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$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: i2$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.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.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i6$1.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i6$1.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i6$1.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
2414
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: DefaultValuePopoverComponent, isStandalone: true, selector: "default-value-popover", inputs: { field: "field", existingValue: "existingValue", position: "position" }, outputs: { save: "save", delete: "delete", close: "close" }, ngImport: i0, template: "<div class=\"popover-backdrop\" (click)=\"onBackdropClick($event)\">\n <div class=\"popover-container\">\n <div class=\"popover-header\">\n <div class=\"header-title\">\n <mat-icon>edit</mat-icon>\n <span>Default Value</span>\n </div>\n <button mat-icon-button (click)=\"onClose()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"popover-content\">\n <div class=\"field-info\">\n <span class=\"field-name\">{{ field.name }}</span>\n <span class=\"field-type\">{{ fieldType }}</span>\n </div>\n\n <!-- String input -->\n @if (fieldType === 'string') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Default Value</mat-label>\n <input matInput [(ngModel)]=\"stringValue\" placeholder=\"Enter default value\">\n </mat-form-field>\n }\n\n <!-- Number input -->\n @if (fieldType === 'number') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Default Value</mat-label>\n <input matInput type=\"number\" [(ngModel)]=\"numberValue\" placeholder=\"Enter number\">\n </mat-form-field>\n }\n\n <!-- Boolean input -->\n @if (fieldType === 'boolean') {\n <div class=\"boolean-input\">\n <mat-slide-toggle [(ngModel)]=\"booleanValue\">\n {{ booleanValue ? 'True' : 'False' }}\n </mat-slide-toggle>\n </div>\n }\n\n <!-- Date input -->\n @if (fieldType === 'date') {\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Default Date</mat-label>\n <input matInput [matDatepicker]=\"picker\" [(ngModel)]=\"dateValue\">\n <mat-datepicker-toggle matIconSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker #picker></mat-datepicker>\n </mat-form-field>\n }\n </div>\n\n <div class=\"popover-actions\">\n @if (existingValue) {\n <button mat-button color=\"warn\" (click)=\"onDelete()\">\n <mat-icon>delete</mat-icon>\n Remove\n </button>\n }\n <span class=\"spacer\"></span>\n <button mat-button (click)=\"onClose()\">Cancel</button>\n <button mat-flat-button color=\"primary\" (click)=\"onSave()\">Save</button>\n </div>\n </div>\n</div>\n", styles: [".popover-backdrop{position:fixed;top:0;left:0;width:100%;height:100%;background:#0000004d;z-index:1000;display:flex;align-items:center;justify-content:center}.popover-container{background:#fff;border-radius:12px;box-shadow:0 8px 32px #0003;min-width:320px;max-width:400px;overflow:hidden}.popover-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;background:linear-gradient(135deg,#10b981,#059669);color:#fff}.popover-header .header-title{display:flex;align-items:center;gap:8px;font-size:16px;font-weight:600}.popover-header .header-title mat-icon{font-size:20px;width:20px;height:20px}.popover-header button{color:#fff}.popover-content{padding:20px}.field-info{display:flex;align-items:center;gap:8px;margin-bottom:16px;padding:10px 12px;background:#f8fafc;border-radius:8px}.field-info .field-name{font-weight:600;color:#1e293b}.field-info .field-type{font-size:12px;color:#64748b;background:#e2e8f0;padding:2px 8px;border-radius:4px;text-transform:uppercase}.full-width{width:100%}.boolean-input{padding:12px 0}.popover-actions{display:flex;align-items:center;gap:8px;padding:16px 20px;background:#f8fafc;border-top:1px solid #e2e8f0}.popover-actions .spacer{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { 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.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { 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: MatButtonModule }, { kind: "component", type: i2.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: i2.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.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatDatepickerModule }, { kind: "component", type: i6$1.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: i6$1.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: i6$1.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "ngmodule", type: MatNativeDateModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i7$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
2415
2415
  }
2416
2416
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: DefaultValuePopoverComponent, decorators: [{
2417
2417
  type: Component,
@@ -2926,11 +2926,465 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
2926
2926
  args: ['document:mouseup', ['$event']]
2927
2927
  }] } });
2928
2928
 
2929
+ class FieldItemComponent {
2930
+ cdr = inject(ChangeDetectorRef);
2931
+ appRef = inject(ApplicationRef);
2932
+ // Local expanded state to bypass change detection issues - using signal for better reactivity
2933
+ localExpanded = signal(false, ...(ngDevMode ? [{ debugName: "localExpanded" }] : []));
2934
+ field;
2935
+ parentList;
2936
+ level = 0;
2937
+ showDisplayType = false;
2938
+ fieldChange = new EventEmitter();
2939
+ delete = new EventEmitter();
2940
+ duplicate = new EventEmitter();
2941
+ outdent = new EventEmitter();
2942
+ fieldTypes = [
2943
+ { value: 'string', label: 'String', icon: 'text_fields' },
2944
+ { value: 'number', label: 'Number', icon: 'pin' },
2945
+ { value: 'boolean', label: 'Boolean', icon: 'toggle_on' },
2946
+ { value: 'date', label: 'Date', icon: 'calendar_today' },
2947
+ { value: 'time', label: 'Time', icon: 'schedule' },
2948
+ { value: 'object', label: 'Object', icon: 'data_object' },
2949
+ { value: 'array', label: 'Array', icon: 'data_array' },
2950
+ ];
2951
+ stringDisplayTypes = [
2952
+ { value: 'textbox', label: 'Textbox', icon: 'edit' },
2953
+ { value: 'dropdown', label: 'Dropdown', icon: 'arrow_drop_down_circle' },
2954
+ { value: 'textarea', label: 'Textarea', icon: 'notes' },
2955
+ { value: 'richtext', label: 'Rich Text', icon: 'format_color_text' },
2956
+ ];
2957
+ dateDisplayTypes = [
2958
+ { value: 'datepicker', label: 'Date Picker', icon: 'calendar_today' },
2959
+ { value: 'datetimepicker', label: 'DateTime Picker', icon: 'schedule' },
2960
+ { value: 'textbox', label: 'Textbox', icon: 'edit' },
2961
+ ];
2962
+ timeDisplayTypes = [
2963
+ { value: 'timepicker', label: 'Time Picker', icon: 'schedule' },
2964
+ { value: 'textbox', label: 'Textbox', icon: 'edit' },
2965
+ ];
2966
+ numberDisplayTypes = [
2967
+ { value: 'textbox', label: 'Textbox', icon: 'edit' },
2968
+ { value: 'stepper', label: 'Stepper', icon: 'unfold_more' },
2969
+ ];
2970
+ booleanDisplayTypes = [
2971
+ { value: 'checkbox', label: 'Checkbox', icon: 'check_box' },
2972
+ { value: 'toggle', label: 'Toggle', icon: 'toggle_on' },
2973
+ ];
2974
+ stringFormats = [
2975
+ { value: '', label: '(none)' },
2976
+ { value: 'email', label: 'Email' },
2977
+ { value: 'uri', label: 'URI (URL)' },
2978
+ { value: 'uuid', label: 'UUID' },
2979
+ ];
2980
+ getDisplayTypes(fieldType) {
2981
+ if (fieldType === 'date')
2982
+ return this.dateDisplayTypes;
2983
+ if (fieldType === 'time')
2984
+ return this.timeDisplayTypes;
2985
+ if (fieldType === 'number')
2986
+ return this.numberDisplayTypes;
2987
+ if (fieldType === 'boolean')
2988
+ return this.booleanDisplayTypes;
2989
+ return this.stringDisplayTypes;
2990
+ }
2991
+ getTypeIcon(type) {
2992
+ return this.fieldTypes.find(t => t.value === type)?.icon || 'help_outline';
2993
+ }
2994
+ ngOnInit() {
2995
+ // Initialize localExpanded from field.expanded if it exists
2996
+ if (this.field?.expanded !== undefined) {
2997
+ this.localExpanded.set(this.field.expanded);
2998
+ }
2999
+ // Initialize children array for object/array types if needed
3000
+ if ((this.field?.type === 'object' || this.field?.type === 'array') && !this.field.children) {
3001
+ this.field.children = [];
3002
+ }
3003
+ }
3004
+ ngOnChanges(changes) {
3005
+ // When field input changes, sync localExpanded with field.expanded
3006
+ // But PRESERVE localExpanded if field.expanded is false/undefined and we have a true value
3007
+ if (changes['field']) {
3008
+ if (this.field) {
3009
+ // If field.expanded is explicitly true, use it (we just set it)
3010
+ if (this.field.expanded === true) {
3011
+ this.localExpanded.set(true);
3012
+ }
3013
+ // If field.expanded is explicitly false, use it (user collapsed)
3014
+ else if (this.field.expanded === false) {
3015
+ this.localExpanded.set(false);
3016
+ }
3017
+ // If field.expanded is undefined, preserve current localExpanded state
3018
+ // This happens when parent updates and field object is new but doesn't have expanded set yet
3019
+ else {
3020
+ // Preserve current localExpanded, and sync field.expanded to match
3021
+ if (this.field.expanded !== this.localExpanded()) {
3022
+ this.field.expanded = this.localExpanded();
3023
+ }
3024
+ }
3025
+ // Initialize children array for object/array types if needed
3026
+ if ((this.field.type === 'object' || this.field.type === 'array') && !this.field.children) {
3027
+ this.field.children = [];
3028
+ }
3029
+ }
3030
+ }
3031
+ }
3032
+ generateId() {
3033
+ return `field-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
3034
+ }
3035
+ toggleExpand() {
3036
+ this.handleExpandClick();
3037
+ }
3038
+ handleExpandClick(event) {
3039
+ if (event) {
3040
+ event.stopPropagation();
3041
+ }
3042
+ // Ensure children array exists
3043
+ if (!this.field.children) {
3044
+ this.field.children = [];
3045
+ }
3046
+ // Toggle local expanded state (using signal)
3047
+ const newExpandedState = !this.localExpanded();
3048
+ this.localExpanded.set(newExpandedState);
3049
+ // Sync to field.expanded (mutation persists because field object reference stays the same)
3050
+ this.field.expanded = newExpandedState;
3051
+ // Force immediate change detection - this should trigger template re-render
3052
+ this.cdr.markForCheck();
3053
+ this.cdr.detectChanges();
3054
+ // Don't emit fieldChange - expand/collapse is local UI state only
3055
+ // We only emit when actual field data changes (name, type, children, etc.)
3056
+ }
3057
+ onFieldNameChange(event) {
3058
+ const input = event.target;
3059
+ const sanitized = input.value.replace(/[^a-zA-Z0-9_$]/g, '');
3060
+ this.field.name = sanitized;
3061
+ if (input.value !== sanitized) {
3062
+ input.value = sanitized;
3063
+ }
3064
+ }
3065
+ onFieldNameBlur() {
3066
+ if (!this.field.name.trim()) {
3067
+ this.field.name = 'unnamed';
3068
+ }
3069
+ this.fieldChange.emit();
3070
+ }
3071
+ onFieldTypeChange(type) {
3072
+ this.field.type = type;
3073
+ if ((type === 'object' || type === 'array') && !this.field.children) {
3074
+ this.field.children = [];
3075
+ }
3076
+ if (type === 'string')
3077
+ this.field.displayType = 'textbox';
3078
+ else if (type === 'number')
3079
+ this.field.displayType = 'textbox';
3080
+ else if (type === 'boolean')
3081
+ this.field.displayType = 'checkbox';
3082
+ else if (type === 'date')
3083
+ this.field.displayType = 'datepicker';
3084
+ else if (type === 'time')
3085
+ this.field.displayType = 'timepicker';
3086
+ else
3087
+ this.field.displayType = undefined;
3088
+ this.fieldChange.emit();
3089
+ }
3090
+ onDisplayTypeChange(displayType) {
3091
+ this.field.displayType = displayType;
3092
+ this.fieldChange.emit();
3093
+ }
3094
+ toggleRequired() {
3095
+ this.field.required = !this.field.required;
3096
+ this.fieldChange.emit();
3097
+ }
3098
+ onLabelChange(label) {
3099
+ this.field.label = label;
3100
+ }
3101
+ onLabelBlur() {
3102
+ this.fieldChange.emit();
3103
+ }
3104
+ addChildField() {
3105
+ if (!this.field.children) {
3106
+ this.field.children = [];
3107
+ }
3108
+ const newField = {
3109
+ id: this.generateId(),
3110
+ name: '',
3111
+ type: 'string',
3112
+ displayType: 'textbox',
3113
+ };
3114
+ this.field.children.push(newField);
3115
+ this.localExpanded.set(true);
3116
+ this.field.expanded = true;
3117
+ this.cdr.detectChanges();
3118
+ this.fieldChange.emit();
3119
+ }
3120
+ deleteField() {
3121
+ this.delete.emit(this.field);
3122
+ }
3123
+ duplicateField() {
3124
+ this.duplicate.emit(this.field);
3125
+ }
3126
+ onChildFieldChange() {
3127
+ // Just propagate the change up - don't force detectChanges as it can reset expanded state
3128
+ this.fieldChange.emit();
3129
+ }
3130
+ onChildDelete(child) {
3131
+ if (this.field.children) {
3132
+ const index = this.field.children.indexOf(child);
3133
+ if (index > -1) {
3134
+ this.field.children.splice(index, 1);
3135
+ this.cdr.detectChanges();
3136
+ this.fieldChange.emit();
3137
+ }
3138
+ }
3139
+ }
3140
+ onChildDuplicate(child) {
3141
+ if (this.field.children) {
3142
+ const index = this.field.children.indexOf(child);
3143
+ if (index > -1) {
3144
+ const clone = {
3145
+ ...child,
3146
+ id: this.generateId(),
3147
+ name: child.name + '_copy',
3148
+ children: child.children ? this.cloneFields(child.children) : undefined,
3149
+ };
3150
+ this.field.children.splice(index + 1, 0, clone);
3151
+ this.cdr.detectChanges();
3152
+ this.fieldChange.emit();
3153
+ }
3154
+ }
3155
+ }
3156
+ cloneFields(fields) {
3157
+ return fields.map(f => ({
3158
+ ...f,
3159
+ id: this.generateId(),
3160
+ children: f.children ? this.cloneFields(f.children) : undefined,
3161
+ }));
3162
+ }
3163
+ onFieldDrop(event) {
3164
+ if (event.previousIndex !== event.currentIndex && this.field.children) {
3165
+ moveItemInArray(this.field.children, event.previousIndex, event.currentIndex);
3166
+ // Don't emit fieldChange for reorder - array is mutated in place
3167
+ // and emitting causes parent re-render which resets expanded state
3168
+ }
3169
+ }
3170
+ canIndent() {
3171
+ const index = this.parentList.indexOf(this.field);
3172
+ if (index <= 0)
3173
+ return false;
3174
+ const prevSibling = this.parentList[index - 1];
3175
+ return prevSibling.type === 'object' || prevSibling.type === 'array';
3176
+ }
3177
+ indentField() {
3178
+ const index = this.parentList.indexOf(this.field);
3179
+ if (index <= 0)
3180
+ return;
3181
+ const prevSibling = this.parentList[index - 1];
3182
+ if (prevSibling.type !== 'object' && prevSibling.type !== 'array')
3183
+ return;
3184
+ this.parentList.splice(index, 1);
3185
+ if (!prevSibling.children)
3186
+ prevSibling.children = [];
3187
+ prevSibling.children.push(this.field);
3188
+ prevSibling.expanded = true;
3189
+ // Don't emit fieldChange - arrays are mutated in place
3190
+ }
3191
+ canOutdent() {
3192
+ return this.level > 0;
3193
+ }
3194
+ outdentField() {
3195
+ if (this.level <= 0)
3196
+ return;
3197
+ this.outdent.emit(this.field);
3198
+ }
3199
+ onChildOutdent(child) {
3200
+ if (!this.field.children)
3201
+ return;
3202
+ const childIndex = this.field.children.indexOf(child);
3203
+ if (childIndex === -1)
3204
+ return;
3205
+ // Remove child from this field's children
3206
+ this.field.children.splice(childIndex, 1);
3207
+ // Add to parent list after this field
3208
+ const myIndex = this.parentList.indexOf(this.field);
3209
+ this.parentList.splice(myIndex + 1, 0, child);
3210
+ // Don't emit fieldChange - arrays are mutated in place
3211
+ }
3212
+ toggleValuesEditor() {
3213
+ this.field.isEditingValues = !this.field.isEditingValues;
3214
+ if (this.field.isEditingValues) {
3215
+ this.field.isEditingDefault = false;
3216
+ this.field.isEditingValidators = false;
3217
+ if (!this.field.allowedValues)
3218
+ this.field.allowedValues = [];
3219
+ }
3220
+ this.fieldChange.emit();
3221
+ }
3222
+ addAllowedValue(input) {
3223
+ let inputEl = null;
3224
+ if (input instanceof HTMLInputElement) {
3225
+ inputEl = input;
3226
+ }
3227
+ else {
3228
+ const target = input.target;
3229
+ const header = target.closest('.values-header');
3230
+ inputEl = header?.querySelector('.value-input');
3231
+ }
3232
+ if (!inputEl)
3233
+ return;
3234
+ const value = inputEl.value.trim();
3235
+ if (value && !this.field.allowedValues?.includes(value)) {
3236
+ if (!this.field.allowedValues)
3237
+ this.field.allowedValues = [];
3238
+ this.field.allowedValues.push(value);
3239
+ inputEl.value = '';
3240
+ this.fieldChange.emit();
3241
+ }
3242
+ }
3243
+ removeAllowedValue(index) {
3244
+ if (this.field.allowedValues) {
3245
+ this.field.allowedValues.splice(index, 1);
3246
+ if (this.field.allowedValues.length === 0)
3247
+ this.field.allowedValues = undefined;
3248
+ this.fieldChange.emit();
3249
+ }
3250
+ }
3251
+ onAllowedValueKeydown(event, input) {
3252
+ if (event.key === 'Enter') {
3253
+ event.preventDefault();
3254
+ this.addAllowedValue(input);
3255
+ }
3256
+ }
3257
+ toggleDefaultEditor() {
3258
+ this.field.isEditingDefault = !this.field.isEditingDefault;
3259
+ if (this.field.isEditingDefault) {
3260
+ this.field.isEditingValues = false;
3261
+ this.field.isEditingValidators = false;
3262
+ }
3263
+ this.fieldChange.emit();
3264
+ }
3265
+ onDefaultValueChange(value) {
3266
+ if (value === '') {
3267
+ this.field.defaultValue = undefined;
3268
+ }
3269
+ else if (this.field.type === 'number') {
3270
+ const num = parseFloat(value);
3271
+ this.field.defaultValue = isNaN(num) ? undefined : num;
3272
+ }
3273
+ else if (this.field.type === 'boolean') {
3274
+ this.field.defaultValue = value === 'true';
3275
+ }
3276
+ else {
3277
+ this.field.defaultValue = value;
3278
+ }
3279
+ this.fieldChange.emit();
3280
+ }
3281
+ clearDefaultValue() {
3282
+ this.field.defaultValue = undefined;
3283
+ this.field.isEditingDefault = false;
3284
+ this.fieldChange.emit();
3285
+ }
3286
+ onDefaultValueKeydown(event) {
3287
+ if (event.key === 'Enter' || event.key === 'Escape') {
3288
+ this.field.isEditingDefault = false;
3289
+ this.fieldChange.emit();
3290
+ }
3291
+ }
3292
+ toggleValidatorsEditor() {
3293
+ this.field.isEditingValidators = !this.field.isEditingValidators;
3294
+ if (this.field.isEditingValidators) {
3295
+ this.field.isEditingValues = false;
3296
+ this.field.isEditingDefault = false;
3297
+ }
3298
+ this.fieldChange.emit();
3299
+ }
3300
+ hasValidators() {
3301
+ if (this.field.type === 'string') {
3302
+ return !!(this.field.minLength || this.field.maxLength || this.field.pattern || this.field.format);
3303
+ }
3304
+ if (this.field.type === 'number') {
3305
+ return this.field.minimum !== undefined || this.field.maximum !== undefined;
3306
+ }
3307
+ return false;
3308
+ }
3309
+ onFormatChange(format) {
3310
+ this.field.format = format || undefined;
3311
+ if (format)
3312
+ this.field.pattern = undefined;
3313
+ this.fieldChange.emit();
3314
+ }
3315
+ onMinLengthChange(value) {
3316
+ this.field.minLength = value ? parseInt(value, 10) : undefined;
3317
+ this.fieldChange.emit();
3318
+ }
3319
+ onMaxLengthChange(value) {
3320
+ this.field.maxLength = value ? parseInt(value, 10) : undefined;
3321
+ this.fieldChange.emit();
3322
+ }
3323
+ onPatternChange(value) {
3324
+ this.field.pattern = value || undefined;
3325
+ this.fieldChange.emit();
3326
+ }
3327
+ onMinimumChange(value) {
3328
+ this.field.minimum = value ? parseFloat(value) : undefined;
3329
+ this.fieldChange.emit();
3330
+ }
3331
+ onMaximumChange(value) {
3332
+ this.field.maximum = value ? parseFloat(value) : undefined;
3333
+ this.fieldChange.emit();
3334
+ }
3335
+ canAddChildToArray() {
3336
+ return this.field.type === 'array' && (!this.field.children || this.field.children.length === 0);
3337
+ }
3338
+ getEmptyMessage() {
3339
+ return this.field.type === 'array' ? 'No item schema defined' : 'No child fields';
3340
+ }
3341
+ getAddButtonLabel() {
3342
+ return this.field.type === 'array' ? 'Define item schema' : 'Add field';
3343
+ }
3344
+ shouldShowNestedFields() {
3345
+ return (this.field.type === 'object' || this.field.type === 'array') && this.localExpanded();
3346
+ }
3347
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3348
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: FieldItemComponent, isStandalone: true, selector: "field-item", inputs: { field: "field", parentList: "parentList", level: "level", showDisplayType: "showDisplayType" }, outputs: { fieldChange: "fieldChange", delete: "delete", duplicate: "duplicate", outdent: "outdent" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"field-wrapper\">\n <div\n class=\"field-item\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Left section: field controls -->\n <div class=\"field-left\">\n <!-- Drag Handle (leftmost) -->\n <div class=\"drag-handle\" cdkDragHandle matTooltip=\"Drag to reorder\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n\n <!-- Indent/Outdent Button (show one or the other) -->\n <div class=\"indent-buttons\">\n @if (level > 0) {\n <button\n class=\"indent-btn\"\n (click)=\"outdentField()\"\n matTooltip=\"Outdent (move to parent level)\"\n >\n <mat-icon>format_indent_decrease</mat-icon>\n </button>\n } @else {\n <button\n class=\"indent-btn\"\n [disabled]=\"!canIndent()\"\n (click)=\"indentField()\"\n matTooltip=\"Indent (make child of previous sibling)\"\n >\n <mat-icon>format_indent_increase</mat-icon>\n </button>\n }\n </div>\n\n <!-- Expand/Collapse -->\n @if (field.type === 'object' || field.type === 'array') {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-btn\"\n (click)=\"handleExpandClick()\"\n [matTooltip]=\"localExpanded() ? 'Collapse' : 'Expand'\"\n >\n <mat-icon>{{ localExpanded() ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <!-- Type Icon -->\n <mat-icon class=\"type-icon\" [matTooltip]=\"field.type\">{{ getTypeIcon(field.type) }}</mat-icon>\n\n <!-- Field Name -->\n <input\n class=\"field-name-input\"\n [value]=\"field.name\"\n (input)=\"onFieldNameChange($event)\"\n (blur)=\"onFieldNameBlur()\"\n placeholder=\"Field name\"\n matTooltip=\"Property name in JSON Schema\"\n />\n @if (field.type === 'array') {\n <span class=\"array-indicator\">[]</span>\n }\n\n <!-- Required Toggle -->\n <button\n class=\"required-btn\"\n [class.is-required]=\"field.required\"\n (click)=\"toggleRequired()\"\n [matTooltip]=\"field.required ? 'Required (click to make optional)' : 'Optional (click to make required)'\"\n >\n <mat-icon>{{ field.required ? 'star' : 'star_border' }}</mat-icon>\n </button>\n </div>\n\n <!-- Middle section: label (flexible) -->\n <input\n class=\"label-input\"\n [value]=\"field.label || ''\"\n (input)=\"onLabelChange($any($event.target).value)\"\n (blur)=\"onLabelBlur()\"\n placeholder=\"Label...\"\n matTooltip=\"Display label (stored as title)\"\n />\n\n <!-- Right section: type and actions -->\n <div class=\"field-right\">\n <!-- Type Selector -->\n <mat-form-field appearance=\"outline\" class=\"type-selector\" matTooltip=\"Data type\">\n <mat-select [value]=\"field.type\" (selectionChange)=\"onFieldTypeChange($event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (type of fieldTypes; track type.value) {\n <mat-option [value]=\"type.value\">\n <mat-icon>{{ type.icon }}</mat-icon>\n {{ type.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Display Type Selector -->\n @if (showDisplayType) {\n @if (field.type === 'string' || field.type === 'number' || field.type === 'boolean' || field.type === 'date' || field.type === 'time') {\n <mat-form-field appearance=\"outline\" class=\"display-type-selector\" matTooltip=\"Display Type\">\n <mat-select [value]=\"field.displayType\" (selectionChange)=\"onDisplayTypeChange($event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (dt of getDisplayTypes(field.type); track dt.value) {\n <mat-option [value]=\"dt.value\">\n <mat-icon>{{ dt.icon }}</mat-icon>\n {{ dt.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <div class=\"display-type-placeholder\"></div>\n }\n }\n\n <!-- Actions -->\n <div class=\"field-actions\">\n @if (field.type === 'object' || canAddChildToArray()) {\n <button\n mat-icon-button\n (click)=\"addChildField()\"\n [matTooltip]=\"field.type === 'array' ? 'Define item schema' : 'Add child field'\"\n >\n <mat-icon>add_circle_outline</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValuesEditor()\"\n [matTooltip]=\"field.allowedValues?.length ? 'Edit allowed values (' + field.allowedValues!.length + ')' : 'Add allowed values'\"\n [class.has-values]=\"field.allowedValues?.length\"\n >\n <mat-icon>list</mat-icon>\n </button>\n }\n @if (field.type !== 'object' && field.type !== 'array') {\n <button\n mat-icon-button\n (click)=\"toggleDefaultEditor()\"\n [matTooltip]=\"field.defaultValue !== undefined ? 'Default: ' + field.defaultValue : 'Set default value'\"\n [class.has-default]=\"field.defaultValue !== undefined\"\n >\n <mat-icon>{{ field.defaultValue !== undefined ? 'label' : 'label_outline' }}</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValidatorsEditor()\"\n [matTooltip]=\"hasValidators() ? 'Edit validators' : 'Add validators'\"\n [class.has-validators]=\"hasValidators()\"\n >\n <mat-icon>rule</mat-icon>\n </button>\n }\n <button mat-icon-button [matMenuTriggerFor]=\"fieldMenu\" matTooltip=\"More options\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #fieldMenu=\"matMenu\">\n <button mat-menu-item (click)=\"duplicateField()\">\n <mat-icon>content_copy</mat-icon>\n <span>Duplicate</span>\n </button>\n <button mat-menu-item (click)=\"deleteField()\" class=\"delete-action\">\n <mat-icon>delete</mat-icon>\n <span>Delete</span>\n </button>\n </mat-menu>\n </div>\n </div>\n </div>\n\n <!-- Allowed Values Editor -->\n @if (field.isEditingValues && (field.type === 'string' || field.type === 'number')) {\n <div class=\"allowed-values-editor\">\n <div class=\"values-header\">\n <span class=\"values-label\">Allowed values:</span>\n <input\n #valueInput\n class=\"value-input\"\n type=\"text\"\n placeholder=\"Type value and press Enter\"\n (keydown)=\"onAllowedValueKeydown($event, valueInput)\"\n />\n <button class=\"add-value-btn\" (click)=\"addAllowedValue($event)\" matTooltip=\"Add value\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n @if (field.allowedValues && field.allowedValues.length > 0) {\n <div class=\"values-list\">\n @for (value of field.allowedValues; track value; let vi = $index) {\n <span class=\"value-chip\">\n {{ value }}\n <button class=\"remove-value-btn\" (click)=\"removeAllowedValue(vi)\" matTooltip=\"Remove\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n }\n </div>\n } @else {\n <div class=\"no-values\">No values defined yet</div>\n }\n </div>\n }\n\n <!-- Default Value Editor -->\n @if (field.isEditingDefault && field.type !== 'object' && field.type !== 'array') {\n <div class=\"default-value-editor\">\n <div class=\"default-header\">\n <span class=\"default-label\">Default value:</span>\n @if (field.type === 'boolean') {\n <select\n class=\"default-select\"\n [value]=\"field.defaultValue?.toString() || ''\"\n (change)=\"onDefaultValueChange($any($event.target).value)\"\n >\n <option value=\"\">No default</option>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </select>\n } @else {\n <input\n class=\"default-input\"\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [value]=\"field.defaultValue ?? ''\"\n (input)=\"onDefaultValueChange($any($event.target).value)\"\n (keydown)=\"onDefaultValueKeydown($event)\"\n placeholder=\"Enter default value\"\n />\n }\n @if (field.defaultValue !== undefined) {\n <button class=\"clear-default-btn\" (click)=\"clearDefaultValue()\" matTooltip=\"Clear default\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Validators Editor -->\n @if (field.isEditingValidators && (field.type === 'string' || field.type === 'number')) {\n <div class=\"validators-editor\">\n <div class=\"validators-header\">\n <span class=\"validators-label\">Validators:</span>\n </div>\n @if (field.type === 'string') {\n <div class=\"validators-row\">\n <div class=\"validator-field\">\n <label>Format</label>\n <select\n class=\"validator-select\"\n [value]=\"field.format || ''\"\n (change)=\"onFormatChange($any($event.target).value)\"\n >\n @for (fmt of stringFormats; track fmt.value) {\n <option [value]=\"fmt.value\">{{ fmt.label }}</option>\n }\n </select>\n </div>\n </div>\n <div class=\"validators-row\">\n <div class=\"validator-field\">\n <label>Min Length</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.minLength ?? ''\"\n (input)=\"onMinLengthChange($any($event.target).value)\"\n placeholder=\"0\"\n min=\"0\"\n />\n </div>\n <div class=\"validator-field\">\n <label>Max Length</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.maxLength ?? ''\"\n (input)=\"onMaxLengthChange($any($event.target).value)\"\n placeholder=\"\u221E\"\n min=\"0\"\n />\n </div>\n @if (!field.format) {\n <div class=\"validator-field pattern-field\">\n <label>Pattern (regex)</label>\n <input\n type=\"text\"\n class=\"validator-input\"\n [value]=\"field.pattern ?? ''\"\n (input)=\"onPatternChange($any($event.target).value)\"\n placeholder=\"^[a-z]+$\"\n />\n </div>\n }\n </div>\n }\n @if (field.type === 'number') {\n <div class=\"validators-row\">\n <div class=\"validator-field\">\n <label>Minimum</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.minimum ?? ''\"\n (input)=\"onMinimumChange($any($event.target).value)\"\n placeholder=\"-\u221E\"\n />\n </div>\n <div class=\"validator-field\">\n <label>Maximum</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.maximum ?? ''\"\n (input)=\"onMaximumChange($any($event.target).value)\"\n placeholder=\"\u221E\"\n />\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Nested Children -->\n @if ((field.type === 'object' || field.type === 'array') && (localExpanded() || field.expanded)) {\n <div\n class=\"nested-fields\"\n cdkDropList\n [cdkDropListData]=\"field.children || []\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @if (field.children && field.children.length > 0) {\n @for (child of field.children; track child.id) {\n <field-item\n cdkDrag\n [field]=\"child\"\n [parentList]=\"field.children\"\n [level]=\"level + 1\"\n [showDisplayType]=\"showDisplayType\"\n (fieldChange)=\"onChildFieldChange()\"\n (delete)=\"onChildDelete($event)\"\n (duplicate)=\"onChildDuplicate($event)\"\n (outdent)=\"onChildOutdent($event)\"\n >\n <!-- Drag Placeholder -->\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <!-- Drag Preview -->\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(child.type) }}</mat-icon>\n {{ child.name || 'unnamed' }}\n </div>\n </field-item>\n }\n } @else {\n <div class=\"empty-nested\">\n <span>{{ getEmptyMessage() }}</span>\n <button mat-button (click)=\"addChildField()\" color=\"primary\">\n <mat-icon>add</mat-icon>\n {{ getAddButtonLabel() }}\n </button>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".field-wrapper{display:block;width:100%;max-width:100%;box-sizing:border-box;overflow:hidden;margin-bottom:4px}.field-wrapper ::ng-deep .mat-mdc-icon-button{width:32px!important;height:32px!important;padding:4px!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;flex-shrink:0!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-touch-target{width:32px!important;height:32px!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-persistent-ripple{border-radius:50%}.field-wrapper ::ng-deep .mat-mdc-icon-button mat-icon,.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-icon{font-size:20px!important;width:20px!important;height:20px!important;line-height:20px!important;overflow:hidden!important}.field-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#f8fafc;border-radius:8px;border:1px solid transparent;transition:all .15s ease;box-sizing:border-box}.field-item:hover{background:#f1f5f9;border-color:#e2e8f0}.field-item:focus-within{background:#eff6ff;border-color:#3b82f6}.field-item.is-complex{background:#fefce8}.field-item.is-complex:hover{background:#fef9c3}.field-item.is-complex:focus-within{background:#fef3c7;border-color:#3b82f6}.field-left{display:flex;align-items:center;gap:8px;flex-shrink:0}.field-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}.drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:#94a3b8;padding:4px;border-radius:4px;transition:all .15s ease}.drag-handle:hover{background:#e2e8f0;color:#64748b}.drag-handle:active{cursor:grabbing}.drag-handle mat-icon{font-size:20px;width:20px;height:20px}.indent-buttons{display:flex;flex-direction:row;gap:2px}.indent-buttons .indent-btn{background:none;border:none;padding:2px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;transition:all .15s ease}.indent-buttons .indent-btn:hover:not(:disabled){background:#dbeafe;color:#2563eb}.indent-buttons .indent-btn:disabled{opacity:.3;cursor:default}.indent-buttons .indent-btn mat-icon{font-size:16px;width:16px;height:16px}.expand-btn{background:none;border:none;padding:4px;cursor:pointer;color:#64748b;border-radius:4px;display:flex;align-items:center;transition:background-color .15s ease,color .15s ease}.expand-btn:hover{background:#e2e8f0;color:#1e293b}.expand-btn mat-icon{font-size:20px;width:20px;height:20px;transition:transform .15s ease}.expand-placeholder{width:28px;flex-shrink:0}.type-icon{font-size:18px;width:18px;height:18px;color:#64748b;flex-shrink:0}.array-indicator{color:#f59e0b;font-weight:600;font-size:14px;margin-left:2px}.field-name-input{flex:0 0 auto;width:120px;font-size:14px;font-weight:500;color:#1e293b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;transition:all .15s ease}.field-name-input:focus{border-color:#3b82f6;background:#fff}.field-name-input::placeholder{color:#94a3b8;font-weight:400}.required-btn{background:none;border:none;padding:4px;cursor:pointer;color:#cbd5e1;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease;flex-shrink:0}.required-btn:hover{color:#f59e0b;background:#fef3c7}.required-btn.is-required{color:#f59e0b}.required-btn mat-icon{font-size:18px;width:18px;height:18px}.label-input{flex:1;font-size:13px;color:#64748b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;min-width:80px;transition:all .15s ease}.label-input:focus{border-color:#3b82f6;background:#fff}.label-input::placeholder{color:#94a3b8;font-style:italic}.type-selector,.display-type-selector{width:130px;flex-shrink:0;margin-right:4px}.type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper,.display-type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.type-selector ::ng-deep .mdc-text-field--outlined,.display-type-selector ::ng-deep .mdc-text-field--outlined{height:32px!important}.type-selector ::ng-deep .mat-mdc-text-field-wrapper,.display-type-selector ::ng-deep .mat-mdc-text-field-wrapper{padding:0 8px!important;height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-flex,.display-type-selector ::ng-deep .mat-mdc-form-field-flex{height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-infix,.display-type-selector ::ng-deep .mat-mdc-form-field-infix{padding-top:4px!important;padding-bottom:4px!important;min-height:28px!important;height:28px!important}.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#e2e8f0!important}.type-selector ::ng-deep .mat-mdc-select,.display-type-selector ::ng-deep .mat-mdc-select{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-value-text,.display-type-selector ::ng-deep .mat-mdc-select-value-text{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-arrow-wrapper,.display-type-selector ::ng-deep .mat-mdc-select-arrow-wrapper{transform:scale(.8)}.display-type-selector{width:120px}.display-type-placeholder{width:120px;flex-shrink:0;margin-right:4px}::ng-deep .schema-editor-select-panel .mat-mdc-option{font-size:12px!important;min-height:36px!important;padding:0 12px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:12px!important;display:flex!important;align-items:center!important;gap:8px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option mat-icon{font-size:16px!important;width:16px!important;height:16px!important;margin-right:0!important;color:#64748b}.field-actions{display:flex;align-items:center;justify-content:flex-end;gap:2px;width:168px;flex-shrink:0;margin-left:4px;opacity:0;transition:opacity .15s ease}.field-item:hover .field-actions,.field-right:hover .field-actions{opacity:1}.field-actions button[mat-icon-button]{width:32px;height:32px;padding:4px;line-height:1;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.field-actions button[mat-icon-button] mat-icon{font-size:20px;width:20px;height:20px;line-height:20px}.field-actions button{color:#64748b}.field-actions button:hover{color:#1e293b}.field-actions .has-values,.field-actions .has-default,.field-actions .has-validators{color:#22c55e!important}.delete-action{color:#ef4444!important}.delete-action mat-icon{color:#ef4444}.allowed-values-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;box-sizing:border-box}.allowed-values-editor .values-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.allowed-values-editor .values-label{font-size:12px;font-weight:500;color:#166534}.allowed-values-editor .value-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #86efac;border-radius:4px;outline:none;background:#fff}.allowed-values-editor .value-input:focus{border-color:#22c55e}.allowed-values-editor .value-input::placeholder{color:#94a3b8}.allowed-values-editor .add-value-btn{background:#22c55e;border:none;color:#fff;width:28px;height:28px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}.allowed-values-editor .add-value-btn:hover{background:#16a34a}.allowed-values-editor .add-value-btn mat-icon{font-size:18px;width:18px;height:18px}.allowed-values-editor .values-list{display:flex;flex-wrap:wrap;gap:6px}.allowed-values-editor .value-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#fff;border:1px solid #86efac;border-radius:4px;font-size:12px;color:#166534}.allowed-values-editor .value-chip .remove-value-btn{background:none;border:none;padding:0;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.allowed-values-editor .value-chip .remove-value-btn:hover{color:#ef4444}.allowed-values-editor .value-chip .remove-value-btn mat-icon{font-size:14px;width:14px;height:14px}.allowed-values-editor .no-values{font-size:12px;color:#94a3b8;font-style:italic}.default-value-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f5f3ff;border:1px solid #c4b5fd;border-radius:8px;box-sizing:border-box}.default-value-editor .default-header{display:flex;align-items:center;gap:8px}.default-value-editor .default-label{font-size:12px;font-weight:500;color:#6d28d9}.default-value-editor .default-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;max-width:200px}.default-value-editor .default-input:focus{border-color:#8b5cf6}.default-value-editor .default-input::placeholder{color:#94a3b8}.default-value-editor .default-select{padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;cursor:pointer}.default-value-editor .default-select:focus{border-color:#8b5cf6}.default-value-editor .clear-default-btn{background:none;border:none;padding:4px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.default-value-editor .clear-default-btn:hover{color:#ef4444}.default-value-editor .clear-default-btn mat-icon{font-size:16px;width:16px;height:16px}.validators-editor{margin:12px 12px 8px 48px;padding:12px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;box-sizing:border-box;overflow:hidden}.validators-editor .validators-header{display:flex;align-items:center;gap:8px;margin-bottom:10px}.validators-editor .validators-label{font-size:12px;font-weight:500;color:#1d4ed8}.validators-editor .validators-row{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:8px;overflow:hidden;width:100%;box-sizing:border-box}.validators-editor .validators-row:last-child{margin-bottom:0}.validators-editor .validator-field{display:flex;flex-direction:column;gap:4px;flex-shrink:0;box-sizing:border-box}.validators-editor .validator-field label{font-size:11px;font-weight:500;color:#3b82f6}.validators-editor .validator-field.pattern-field{flex:1 1 auto;min-width:80px;overflow:hidden}.validators-editor .validator-input,.validators-editor .validator-select{padding:6px 10px;font-size:13px;border:1px solid #93c5fd;border-radius:4px;outline:none;background:#fff;width:100px;box-sizing:border-box!important}.validators-editor .validator-input:focus,.validators-editor .validator-select:focus{border-color:#3b82f6}.validators-editor .validator-input::placeholder,.validators-editor .validator-select::placeholder{color:#94a3b8}.validators-editor .validator-select{cursor:pointer;width:120px}.validators-editor .pattern-field .validator-input{width:100%;box-sizing:border-box!important}.nested-fields{display:block;min-height:30px;margin-top:8px;margin-bottom:8px;padding-left:32px;box-sizing:border-box}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-editor{margin-left:16px;margin-top:8px}.empty-nested{display:flex;align-items:center;gap:12px;padding:12px 16px;color:#94a3b8;font-size:13px;font-style:italic;background:#f8fafc;border-radius:6px;border:1px dashed #e2e8f0}.drag-placeholder{background:#e2e8f0;border:2px dashed #3b82f6;border-radius:8px;min-height:48px;margin-bottom:4px}::ng-deep .drag-preview{display:flex!important;align-items:center!important;gap:8px!important;padding:12px 16px!important;background:#fff!important;border:2px solid #3b82f6!important;border-radius:8px!important;box-shadow:0 8px 24px #0003!important;font-size:14px!important;font-weight:500!important;color:#1e293b!important;overflow:hidden!important;white-space:nowrap!important;box-sizing:border-box!important}::ng-deep .drag-preview mat-icon{color:#3b82f6!important;font-size:20px!important;width:20px!important;height:20px!important;flex-shrink:0!important;overflow:hidden!important}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .field-wrapper:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "component", type: FieldItemComponent, selector: "field-item", inputs: ["field", "parentList", "level", "showDisplayType"], outputs: ["fieldChange", "delete", "duplicate", "outdent"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.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.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i6$2.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$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i6$2.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: DragDropModule }, { kind: "directive", type: i7$2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i7$2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i7$2.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i7$2.CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "directive", type: i7$2.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }] });
3349
+ }
3350
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldItemComponent, decorators: [{
3351
+ type: Component,
3352
+ args: [{ selector: 'field-item', standalone: true, imports: [
3353
+ CommonModule,
3354
+ FormsModule,
3355
+ MatButtonModule,
3356
+ MatIconModule,
3357
+ MatFormFieldModule,
3358
+ MatSelectModule,
3359
+ MatTooltipModule,
3360
+ MatMenuModule,
3361
+ DragDropModule,
3362
+ FieldItemComponent,
3363
+ ], template: "<div class=\"field-wrapper\">\n <div\n class=\"field-item\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Left section: field controls -->\n <div class=\"field-left\">\n <!-- Drag Handle (leftmost) -->\n <div class=\"drag-handle\" cdkDragHandle matTooltip=\"Drag to reorder\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n\n <!-- Indent/Outdent Button (show one or the other) -->\n <div class=\"indent-buttons\">\n @if (level > 0) {\n <button\n class=\"indent-btn\"\n (click)=\"outdentField()\"\n matTooltip=\"Outdent (move to parent level)\"\n >\n <mat-icon>format_indent_decrease</mat-icon>\n </button>\n } @else {\n <button\n class=\"indent-btn\"\n [disabled]=\"!canIndent()\"\n (click)=\"indentField()\"\n matTooltip=\"Indent (make child of previous sibling)\"\n >\n <mat-icon>format_indent_increase</mat-icon>\n </button>\n }\n </div>\n\n <!-- Expand/Collapse -->\n @if (field.type === 'object' || field.type === 'array') {\n <button\n mat-icon-button\n type=\"button\"\n class=\"expand-btn\"\n (click)=\"handleExpandClick()\"\n [matTooltip]=\"localExpanded() ? 'Collapse' : 'Expand'\"\n >\n <mat-icon>{{ localExpanded() ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <!-- Type Icon -->\n <mat-icon class=\"type-icon\" [matTooltip]=\"field.type\">{{ getTypeIcon(field.type) }}</mat-icon>\n\n <!-- Field Name -->\n <input\n class=\"field-name-input\"\n [value]=\"field.name\"\n (input)=\"onFieldNameChange($event)\"\n (blur)=\"onFieldNameBlur()\"\n placeholder=\"Field name\"\n matTooltip=\"Property name in JSON Schema\"\n />\n @if (field.type === 'array') {\n <span class=\"array-indicator\">[]</span>\n }\n\n <!-- Required Toggle -->\n <button\n class=\"required-btn\"\n [class.is-required]=\"field.required\"\n (click)=\"toggleRequired()\"\n [matTooltip]=\"field.required ? 'Required (click to make optional)' : 'Optional (click to make required)'\"\n >\n <mat-icon>{{ field.required ? 'star' : 'star_border' }}</mat-icon>\n </button>\n </div>\n\n <!-- Middle section: label (flexible) -->\n <input\n class=\"label-input\"\n [value]=\"field.label || ''\"\n (input)=\"onLabelChange($any($event.target).value)\"\n (blur)=\"onLabelBlur()\"\n placeholder=\"Label...\"\n matTooltip=\"Display label (stored as title)\"\n />\n\n <!-- Right section: type and actions -->\n <div class=\"field-right\">\n <!-- Type Selector -->\n <mat-form-field appearance=\"outline\" class=\"type-selector\" matTooltip=\"Data type\">\n <mat-select [value]=\"field.type\" (selectionChange)=\"onFieldTypeChange($event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (type of fieldTypes; track type.value) {\n <mat-option [value]=\"type.value\">\n <mat-icon>{{ type.icon }}</mat-icon>\n {{ type.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Display Type Selector -->\n @if (showDisplayType) {\n @if (field.type === 'string' || field.type === 'number' || field.type === 'boolean' || field.type === 'date' || field.type === 'time') {\n <mat-form-field appearance=\"outline\" class=\"display-type-selector\" matTooltip=\"Display Type\">\n <mat-select [value]=\"field.displayType\" (selectionChange)=\"onDisplayTypeChange($event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (dt of getDisplayTypes(field.type); track dt.value) {\n <mat-option [value]=\"dt.value\">\n <mat-icon>{{ dt.icon }}</mat-icon>\n {{ dt.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <div class=\"display-type-placeholder\"></div>\n }\n }\n\n <!-- Actions -->\n <div class=\"field-actions\">\n @if (field.type === 'object' || canAddChildToArray()) {\n <button\n mat-icon-button\n (click)=\"addChildField()\"\n [matTooltip]=\"field.type === 'array' ? 'Define item schema' : 'Add child field'\"\n >\n <mat-icon>add_circle_outline</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValuesEditor()\"\n [matTooltip]=\"field.allowedValues?.length ? 'Edit allowed values (' + field.allowedValues!.length + ')' : 'Add allowed values'\"\n [class.has-values]=\"field.allowedValues?.length\"\n >\n <mat-icon>list</mat-icon>\n </button>\n }\n @if (field.type !== 'object' && field.type !== 'array') {\n <button\n mat-icon-button\n (click)=\"toggleDefaultEditor()\"\n [matTooltip]=\"field.defaultValue !== undefined ? 'Default: ' + field.defaultValue : 'Set default value'\"\n [class.has-default]=\"field.defaultValue !== undefined\"\n >\n <mat-icon>{{ field.defaultValue !== undefined ? 'label' : 'label_outline' }}</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValidatorsEditor()\"\n [matTooltip]=\"hasValidators() ? 'Edit validators' : 'Add validators'\"\n [class.has-validators]=\"hasValidators()\"\n >\n <mat-icon>rule</mat-icon>\n </button>\n }\n <button mat-icon-button [matMenuTriggerFor]=\"fieldMenu\" matTooltip=\"More options\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #fieldMenu=\"matMenu\">\n <button mat-menu-item (click)=\"duplicateField()\">\n <mat-icon>content_copy</mat-icon>\n <span>Duplicate</span>\n </button>\n <button mat-menu-item (click)=\"deleteField()\" class=\"delete-action\">\n <mat-icon>delete</mat-icon>\n <span>Delete</span>\n </button>\n </mat-menu>\n </div>\n </div>\n </div>\n\n <!-- Allowed Values Editor -->\n @if (field.isEditingValues && (field.type === 'string' || field.type === 'number')) {\n <div class=\"allowed-values-editor\">\n <div class=\"values-header\">\n <span class=\"values-label\">Allowed values:</span>\n <input\n #valueInput\n class=\"value-input\"\n type=\"text\"\n placeholder=\"Type value and press Enter\"\n (keydown)=\"onAllowedValueKeydown($event, valueInput)\"\n />\n <button class=\"add-value-btn\" (click)=\"addAllowedValue($event)\" matTooltip=\"Add value\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n @if (field.allowedValues && field.allowedValues.length > 0) {\n <div class=\"values-list\">\n @for (value of field.allowedValues; track value; let vi = $index) {\n <span class=\"value-chip\">\n {{ value }}\n <button class=\"remove-value-btn\" (click)=\"removeAllowedValue(vi)\" matTooltip=\"Remove\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n }\n </div>\n } @else {\n <div class=\"no-values\">No values defined yet</div>\n }\n </div>\n }\n\n <!-- Default Value Editor -->\n @if (field.isEditingDefault && field.type !== 'object' && field.type !== 'array') {\n <div class=\"default-value-editor\">\n <div class=\"default-header\">\n <span class=\"default-label\">Default value:</span>\n @if (field.type === 'boolean') {\n <select\n class=\"default-select\"\n [value]=\"field.defaultValue?.toString() || ''\"\n (change)=\"onDefaultValueChange($any($event.target).value)\"\n >\n <option value=\"\">No default</option>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </select>\n } @else {\n <input\n class=\"default-input\"\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [value]=\"field.defaultValue ?? ''\"\n (input)=\"onDefaultValueChange($any($event.target).value)\"\n (keydown)=\"onDefaultValueKeydown($event)\"\n placeholder=\"Enter default value\"\n />\n }\n @if (field.defaultValue !== undefined) {\n <button class=\"clear-default-btn\" (click)=\"clearDefaultValue()\" matTooltip=\"Clear default\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Validators Editor -->\n @if (field.isEditingValidators && (field.type === 'string' || field.type === 'number')) {\n <div class=\"validators-editor\">\n <div class=\"validators-header\">\n <span class=\"validators-label\">Validators:</span>\n </div>\n @if (field.type === 'string') {\n <div class=\"validators-row\">\n <div class=\"validator-field\">\n <label>Format</label>\n <select\n class=\"validator-select\"\n [value]=\"field.format || ''\"\n (change)=\"onFormatChange($any($event.target).value)\"\n >\n @for (fmt of stringFormats; track fmt.value) {\n <option [value]=\"fmt.value\">{{ fmt.label }}</option>\n }\n </select>\n </div>\n </div>\n <div class=\"validators-row\">\n <div class=\"validator-field\">\n <label>Min Length</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.minLength ?? ''\"\n (input)=\"onMinLengthChange($any($event.target).value)\"\n placeholder=\"0\"\n min=\"0\"\n />\n </div>\n <div class=\"validator-field\">\n <label>Max Length</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.maxLength ?? ''\"\n (input)=\"onMaxLengthChange($any($event.target).value)\"\n placeholder=\"\u221E\"\n min=\"0\"\n />\n </div>\n @if (!field.format) {\n <div class=\"validator-field pattern-field\">\n <label>Pattern (regex)</label>\n <input\n type=\"text\"\n class=\"validator-input\"\n [value]=\"field.pattern ?? ''\"\n (input)=\"onPatternChange($any($event.target).value)\"\n placeholder=\"^[a-z]+$\"\n />\n </div>\n }\n </div>\n }\n @if (field.type === 'number') {\n <div class=\"validators-row\">\n <div class=\"validator-field\">\n <label>Minimum</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.minimum ?? ''\"\n (input)=\"onMinimumChange($any($event.target).value)\"\n placeholder=\"-\u221E\"\n />\n </div>\n <div class=\"validator-field\">\n <label>Maximum</label>\n <input\n type=\"number\"\n class=\"validator-input\"\n [value]=\"field.maximum ?? ''\"\n (input)=\"onMaximumChange($any($event.target).value)\"\n placeholder=\"\u221E\"\n />\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Nested Children -->\n @if ((field.type === 'object' || field.type === 'array') && (localExpanded() || field.expanded)) {\n <div\n class=\"nested-fields\"\n cdkDropList\n [cdkDropListData]=\"field.children || []\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @if (field.children && field.children.length > 0) {\n @for (child of field.children; track child.id) {\n <field-item\n cdkDrag\n [field]=\"child\"\n [parentList]=\"field.children\"\n [level]=\"level + 1\"\n [showDisplayType]=\"showDisplayType\"\n (fieldChange)=\"onChildFieldChange()\"\n (delete)=\"onChildDelete($event)\"\n (duplicate)=\"onChildDuplicate($event)\"\n (outdent)=\"onChildOutdent($event)\"\n >\n <!-- Drag Placeholder -->\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <!-- Drag Preview -->\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(child.type) }}</mat-icon>\n {{ child.name || 'unnamed' }}\n </div>\n </field-item>\n }\n } @else {\n <div class=\"empty-nested\">\n <span>{{ getEmptyMessage() }}</span>\n <button mat-button (click)=\"addChildField()\" color=\"primary\">\n <mat-icon>add</mat-icon>\n {{ getAddButtonLabel() }}\n </button>\n </div>\n }\n </div>\n }\n</div>\n", styles: [".field-wrapper{display:block;width:100%;max-width:100%;box-sizing:border-box;overflow:hidden;margin-bottom:4px}.field-wrapper ::ng-deep .mat-mdc-icon-button{width:32px!important;height:32px!important;padding:4px!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;flex-shrink:0!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-touch-target{width:32px!important;height:32px!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-persistent-ripple{border-radius:50%}.field-wrapper ::ng-deep .mat-mdc-icon-button mat-icon,.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-icon{font-size:20px!important;width:20px!important;height:20px!important;line-height:20px!important;overflow:hidden!important}.field-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:#f8fafc;border-radius:8px;border:1px solid transparent;transition:all .15s ease;box-sizing:border-box}.field-item:hover{background:#f1f5f9;border-color:#e2e8f0}.field-item:focus-within{background:#eff6ff;border-color:#3b82f6}.field-item.is-complex{background:#fefce8}.field-item.is-complex:hover{background:#fef9c3}.field-item.is-complex:focus-within{background:#fef3c7;border-color:#3b82f6}.field-left{display:flex;align-items:center;gap:8px;flex-shrink:0}.field-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}.drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:#94a3b8;padding:4px;border-radius:4px;transition:all .15s ease}.drag-handle:hover{background:#e2e8f0;color:#64748b}.drag-handle:active{cursor:grabbing}.drag-handle mat-icon{font-size:20px;width:20px;height:20px}.indent-buttons{display:flex;flex-direction:row;gap:2px}.indent-buttons .indent-btn{background:none;border:none;padding:2px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;transition:all .15s ease}.indent-buttons .indent-btn:hover:not(:disabled){background:#dbeafe;color:#2563eb}.indent-buttons .indent-btn:disabled{opacity:.3;cursor:default}.indent-buttons .indent-btn mat-icon{font-size:16px;width:16px;height:16px}.expand-btn{background:none;border:none;padding:4px;cursor:pointer;color:#64748b;border-radius:4px;display:flex;align-items:center;transition:background-color .15s ease,color .15s ease}.expand-btn:hover{background:#e2e8f0;color:#1e293b}.expand-btn mat-icon{font-size:20px;width:20px;height:20px;transition:transform .15s ease}.expand-placeholder{width:28px;flex-shrink:0}.type-icon{font-size:18px;width:18px;height:18px;color:#64748b;flex-shrink:0}.array-indicator{color:#f59e0b;font-weight:600;font-size:14px;margin-left:2px}.field-name-input{flex:0 0 auto;width:120px;font-size:14px;font-weight:500;color:#1e293b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;transition:all .15s ease}.field-name-input:focus{border-color:#3b82f6;background:#fff}.field-name-input::placeholder{color:#94a3b8;font-weight:400}.required-btn{background:none;border:none;padding:4px;cursor:pointer;color:#cbd5e1;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease;flex-shrink:0}.required-btn:hover{color:#f59e0b;background:#fef3c7}.required-btn.is-required{color:#f59e0b}.required-btn mat-icon{font-size:18px;width:18px;height:18px}.label-input{flex:1;font-size:13px;color:#64748b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;min-width:80px;transition:all .15s ease}.label-input:focus{border-color:#3b82f6;background:#fff}.label-input::placeholder{color:#94a3b8;font-style:italic}.type-selector,.display-type-selector{width:130px;flex-shrink:0;margin-right:4px}.type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper,.display-type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.type-selector ::ng-deep .mdc-text-field--outlined,.display-type-selector ::ng-deep .mdc-text-field--outlined{height:32px!important}.type-selector ::ng-deep .mat-mdc-text-field-wrapper,.display-type-selector ::ng-deep .mat-mdc-text-field-wrapper{padding:0 8px!important;height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-flex,.display-type-selector ::ng-deep .mat-mdc-form-field-flex{height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-infix,.display-type-selector ::ng-deep .mat-mdc-form-field-infix{padding-top:4px!important;padding-bottom:4px!important;min-height:28px!important;height:28px!important}.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#e2e8f0!important}.type-selector ::ng-deep .mat-mdc-select,.display-type-selector ::ng-deep .mat-mdc-select{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-value-text,.display-type-selector ::ng-deep .mat-mdc-select-value-text{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-arrow-wrapper,.display-type-selector ::ng-deep .mat-mdc-select-arrow-wrapper{transform:scale(.8)}.display-type-selector{width:120px}.display-type-placeholder{width:120px;flex-shrink:0;margin-right:4px}::ng-deep .schema-editor-select-panel .mat-mdc-option{font-size:12px!important;min-height:36px!important;padding:0 12px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:12px!important;display:flex!important;align-items:center!important;gap:8px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option mat-icon{font-size:16px!important;width:16px!important;height:16px!important;margin-right:0!important;color:#64748b}.field-actions{display:flex;align-items:center;justify-content:flex-end;gap:2px;width:168px;flex-shrink:0;margin-left:4px;opacity:0;transition:opacity .15s ease}.field-item:hover .field-actions,.field-right:hover .field-actions{opacity:1}.field-actions button[mat-icon-button]{width:32px;height:32px;padding:4px;line-height:1;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.field-actions button[mat-icon-button] mat-icon{font-size:20px;width:20px;height:20px;line-height:20px}.field-actions button{color:#64748b}.field-actions button:hover{color:#1e293b}.field-actions .has-values,.field-actions .has-default,.field-actions .has-validators{color:#22c55e!important}.delete-action{color:#ef4444!important}.delete-action mat-icon{color:#ef4444}.allowed-values-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;box-sizing:border-box}.allowed-values-editor .values-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.allowed-values-editor .values-label{font-size:12px;font-weight:500;color:#166534}.allowed-values-editor .value-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #86efac;border-radius:4px;outline:none;background:#fff}.allowed-values-editor .value-input:focus{border-color:#22c55e}.allowed-values-editor .value-input::placeholder{color:#94a3b8}.allowed-values-editor .add-value-btn{background:#22c55e;border:none;color:#fff;width:28px;height:28px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}.allowed-values-editor .add-value-btn:hover{background:#16a34a}.allowed-values-editor .add-value-btn mat-icon{font-size:18px;width:18px;height:18px}.allowed-values-editor .values-list{display:flex;flex-wrap:wrap;gap:6px}.allowed-values-editor .value-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#fff;border:1px solid #86efac;border-radius:4px;font-size:12px;color:#166534}.allowed-values-editor .value-chip .remove-value-btn{background:none;border:none;padding:0;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.allowed-values-editor .value-chip .remove-value-btn:hover{color:#ef4444}.allowed-values-editor .value-chip .remove-value-btn mat-icon{font-size:14px;width:14px;height:14px}.allowed-values-editor .no-values{font-size:12px;color:#94a3b8;font-style:italic}.default-value-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f5f3ff;border:1px solid #c4b5fd;border-radius:8px;box-sizing:border-box}.default-value-editor .default-header{display:flex;align-items:center;gap:8px}.default-value-editor .default-label{font-size:12px;font-weight:500;color:#6d28d9}.default-value-editor .default-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;max-width:200px}.default-value-editor .default-input:focus{border-color:#8b5cf6}.default-value-editor .default-input::placeholder{color:#94a3b8}.default-value-editor .default-select{padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;cursor:pointer}.default-value-editor .default-select:focus{border-color:#8b5cf6}.default-value-editor .clear-default-btn{background:none;border:none;padding:4px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.default-value-editor .clear-default-btn:hover{color:#ef4444}.default-value-editor .clear-default-btn mat-icon{font-size:16px;width:16px;height:16px}.validators-editor{margin:12px 12px 8px 48px;padding:12px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;box-sizing:border-box;overflow:hidden}.validators-editor .validators-header{display:flex;align-items:center;gap:8px;margin-bottom:10px}.validators-editor .validators-label{font-size:12px;font-weight:500;color:#1d4ed8}.validators-editor .validators-row{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:8px;overflow:hidden;width:100%;box-sizing:border-box}.validators-editor .validators-row:last-child{margin-bottom:0}.validators-editor .validator-field{display:flex;flex-direction:column;gap:4px;flex-shrink:0;box-sizing:border-box}.validators-editor .validator-field label{font-size:11px;font-weight:500;color:#3b82f6}.validators-editor .validator-field.pattern-field{flex:1 1 auto;min-width:80px;overflow:hidden}.validators-editor .validator-input,.validators-editor .validator-select{padding:6px 10px;font-size:13px;border:1px solid #93c5fd;border-radius:4px;outline:none;background:#fff;width:100px;box-sizing:border-box!important}.validators-editor .validator-input:focus,.validators-editor .validator-select:focus{border-color:#3b82f6}.validators-editor .validator-input::placeholder,.validators-editor .validator-select::placeholder{color:#94a3b8}.validators-editor .validator-select{cursor:pointer;width:120px}.validators-editor .pattern-field .validator-input{width:100%;box-sizing:border-box!important}.nested-fields{display:block;min-height:30px;margin-top:8px;margin-bottom:8px;padding-left:32px;box-sizing:border-box}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-editor{margin-left:16px;margin-top:8px}.empty-nested{display:flex;align-items:center;gap:12px;padding:12px 16px;color:#94a3b8;font-size:13px;font-style:italic;background:#f8fafc;border-radius:6px;border:1px dashed #e2e8f0}.drag-placeholder{background:#e2e8f0;border:2px dashed #3b82f6;border-radius:8px;min-height:48px;margin-bottom:4px}::ng-deep .drag-preview{display:flex!important;align-items:center!important;gap:8px!important;padding:12px 16px!important;background:#fff!important;border:2px solid #3b82f6!important;border-radius:8px!important;box-shadow:0 8px 24px #0003!important;font-size:14px!important;font-weight:500!important;color:#1e293b!important;overflow:hidden!important;white-space:nowrap!important;box-sizing:border-box!important}::ng-deep .drag-preview mat-icon{color:#3b82f6!important;font-size:20px!important;width:20px!important;height:20px!important;flex-shrink:0!important;overflow:hidden!important}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .field-wrapper:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}\n"] }]
3364
+ }], propDecorators: { field: [{
3365
+ type: Input
3366
+ }], parentList: [{
3367
+ type: Input
3368
+ }], level: [{
3369
+ type: Input
3370
+ }], showDisplayType: [{
3371
+ type: Input
3372
+ }], fieldChange: [{
3373
+ type: Output
3374
+ }], delete: [{
3375
+ type: Output
3376
+ }], duplicate: [{
3377
+ type: Output
3378
+ }], outdent: [{
3379
+ type: Output
3380
+ }] } });
3381
+
2929
3382
  class SchemaEditorComponent {
3383
+ appRef = inject(ApplicationRef);
2930
3384
  set schema(value) {
2931
3385
  if (value) {
2932
- // Don't overwrite fields if we have uncommitted changes (fields being edited or with empty names)
2933
- const hasUncommittedChanges = this.fields().some(f => f.isEditing || f.isEditingDefault || f.isEditingValues || !f.name) || this.hasUncommittedChildFields(this.fields());
3386
+ // Don't overwrite fields if we have uncommitted changes (fields with editors open or empty names)
3387
+ const hasUncommittedChanges = this.fields().some(f => f.isEditingDefault || f.isEditingValues || f.isEditingValidators || !f.name) || this.hasUncommittedChildFields(this.fields());
2934
3388
  this.schemaName.set(value.title || 'New Schema');
2935
3389
  if (!hasUncommittedChanges) {
2936
3390
  this.fields.set(this.jsonSchemaToEditorFields(value));
@@ -2940,7 +3394,7 @@ class SchemaEditorComponent {
2940
3394
  hasUncommittedChildFields(fields) {
2941
3395
  for (const field of fields) {
2942
3396
  if (field.children) {
2943
- if (field.children.some(c => c.isEditing || c.isEditingDefault || c.isEditingValues || !c.name)) {
3397
+ if (field.children.some(c => c.isEditingDefault || c.isEditingValues || c.isEditingValidators || !c.name)) {
2944
3398
  return true;
2945
3399
  }
2946
3400
  if (this.hasUncommittedChildFields(field.children)) {
@@ -2993,6 +3447,12 @@ class SchemaEditorComponent {
2993
3447
  { value: 'checkbox', label: 'Checkbox', icon: 'check_box' },
2994
3448
  { value: 'toggle', label: 'Toggle', icon: 'toggle_on' },
2995
3449
  ];
3450
+ stringFormats = [
3451
+ { value: '', label: '(none)' },
3452
+ { value: 'email', label: 'Email' },
3453
+ { value: 'uri', label: 'URI (URL)' },
3454
+ { value: 'uuid', label: 'UUID' },
3455
+ ];
2996
3456
  getDisplayTypes(fieldType) {
2997
3457
  if (fieldType === 'date')
2998
3458
  return this.dateDisplayTypes;
@@ -3023,12 +3483,9 @@ class SchemaEditorComponent {
3023
3483
  name: '',
3024
3484
  type: 'string',
3025
3485
  displayType: 'textbox',
3026
- isEditing: true,
3027
3486
  expanded: false,
3028
3487
  };
3029
3488
  this.fields.update(fields => [...fields, newField]);
3030
- // Don't emit change here - field has empty name and would be filtered out
3031
- // Change will be emitted in stopEdit() when user provides a name
3032
3489
  }
3033
3490
  // Add a child field to an object or array
3034
3491
  addChildField(parent) {
@@ -3040,13 +3497,46 @@ class SchemaEditorComponent {
3040
3497
  name: '',
3041
3498
  type: 'string',
3042
3499
  displayType: 'textbox',
3043
- isEditing: true,
3044
3500
  };
3045
3501
  parent.children.push(newField);
3046
3502
  parent.expanded = true;
3047
3503
  this.fields.update(fields => [...fields]);
3048
- // Don't emit change here - field has empty name and would be filtered out
3049
- // Change will be emitted in stopEdit() when user provides a name
3504
+ }
3505
+ // Handle field change from FieldItemComponent
3506
+ onFieldChange() {
3507
+ // Just emit the change - field objects are mutated in place
3508
+ // Don't recreate array or force tick as it causes expanded state to reset
3509
+ this.emitChange();
3510
+ }
3511
+ // Handle field delete from FieldItemComponent
3512
+ onFieldDelete(field) {
3513
+ const index = this.fields().indexOf(field);
3514
+ if (index > -1) {
3515
+ this.fields.update(fields => {
3516
+ const newFields = [...fields];
3517
+ newFields.splice(index, 1);
3518
+ return newFields;
3519
+ });
3520
+ this.emitChange();
3521
+ }
3522
+ }
3523
+ // Handle field duplicate from FieldItemComponent
3524
+ onFieldDuplicate(field) {
3525
+ const index = this.fields().indexOf(field);
3526
+ if (index > -1) {
3527
+ const clone = {
3528
+ ...field,
3529
+ id: this.generateId(),
3530
+ name: field.name + '_copy',
3531
+ children: field.children ? this.cloneFields(field.children) : undefined,
3532
+ };
3533
+ this.fields.update(fields => {
3534
+ const newFields = [...fields];
3535
+ newFields.splice(index + 1, 0, clone);
3536
+ return newFields;
3537
+ });
3538
+ this.emitChange();
3539
+ }
3050
3540
  }
3051
3541
  // Delete a field
3052
3542
  deleteField(field, parentList) {
@@ -3066,7 +3556,6 @@ class SchemaEditorComponent {
3066
3556
  id: this.generateId(),
3067
3557
  name: field.name + '_copy',
3068
3558
  children: field.children ? this.cloneFields(field.children) : undefined,
3069
- isEditing: false,
3070
3559
  };
3071
3560
  parentList.splice(index + 1, 0, clone);
3072
3561
  this.fields.update(fields => [...fields]);
@@ -3078,20 +3567,6 @@ class SchemaEditorComponent {
3078
3567
  field.expanded = !field.expanded;
3079
3568
  this.fields.update(fields => [...fields]);
3080
3569
  }
3081
- // Start editing a field
3082
- startEdit(field) {
3083
- field.isEditing = true;
3084
- this.fields.update(fields => [...fields]);
3085
- }
3086
- // Stop editing a field
3087
- stopEdit(field) {
3088
- field.isEditing = false;
3089
- if (!field.name.trim()) {
3090
- field.name = 'unnamed';
3091
- }
3092
- this.fields.update(fields => [...fields]);
3093
- this.emitChange();
3094
- }
3095
3570
  // Handle field name input - only allow valid property name characters
3096
3571
  onFieldNameChange(field, event) {
3097
3572
  const input = event.target;
@@ -3104,6 +3579,14 @@ class SchemaEditorComponent {
3104
3579
  input.value = sanitized;
3105
3580
  }
3106
3581
  }
3582
+ // Handle field name blur - ensure name is valid and emit change
3583
+ onFieldNameBlur(field) {
3584
+ if (!field.name.trim()) {
3585
+ field.name = 'unnamed';
3586
+ }
3587
+ this.fields.update(fields => [...fields]);
3588
+ this.emitChange();
3589
+ }
3107
3590
  // Handle field type change
3108
3591
  onFieldTypeChange(field, type) {
3109
3592
  field.type = type;
@@ -3145,30 +3628,26 @@ class SchemaEditorComponent {
3145
3628
  this.fields.update(fields => [...fields]);
3146
3629
  this.emitChange();
3147
3630
  }
3148
- // Update field description (only update the field, don't trigger re-render)
3149
- onDescriptionChange(field, description) {
3150
- field.description = description;
3631
+ // Update field label (only update the field, don't trigger re-render)
3632
+ onLabelChange(field, label) {
3633
+ field.label = label;
3151
3634
  }
3152
- // Emit change when description input loses focus
3153
- onDescriptionBlur() {
3635
+ // Emit change when label input loses focus
3636
+ onLabelBlur() {
3154
3637
  this.emitChange();
3155
3638
  }
3156
3639
  // Toggle allowed values editor
3157
3640
  toggleValuesEditor(field) {
3158
- const wasEditingDefault = field.isEditingDefault;
3159
3641
  field.isEditingValues = !field.isEditingValues;
3160
3642
  if (field.isEditingValues) {
3161
- // Close default editor when opening values editor
3643
+ // Close other editors
3162
3644
  field.isEditingDefault = false;
3645
+ field.isEditingValidators = false;
3163
3646
  if (!field.allowedValues) {
3164
3647
  field.allowedValues = [];
3165
3648
  }
3166
3649
  }
3167
3650
  this.fields.update(fields => [...fields]);
3168
- // Emit change if we closed the default editor (to save any default value)
3169
- if (wasEditingDefault) {
3170
- this.emitChange();
3171
- }
3172
3651
  }
3173
3652
  // Add allowed value
3174
3653
  addAllowedValue(field, input) {
@@ -3216,17 +3695,13 @@ class SchemaEditorComponent {
3216
3695
  }
3217
3696
  // Toggle default value editor
3218
3697
  toggleDefaultEditor(field) {
3219
- const wasEditingValues = field.isEditingValues;
3220
3698
  field.isEditingDefault = !field.isEditingDefault;
3221
3699
  if (field.isEditingDefault) {
3222
- // Close values editor when opening default editor
3700
+ // Close other editors
3223
3701
  field.isEditingValues = false;
3702
+ field.isEditingValidators = false;
3224
3703
  }
3225
3704
  this.fields.update(fields => [...fields]);
3226
- // Emit change if we closed the values editor (to save any allowed values)
3227
- if (wasEditingValues) {
3228
- this.emitChange();
3229
- }
3230
3705
  }
3231
3706
  // Update default value
3232
3707
  onDefaultValueChange(field, value) {
@@ -3260,15 +3735,65 @@ class SchemaEditorComponent {
3260
3735
  this.fields.update(fields => [...fields]);
3261
3736
  }
3262
3737
  }
3263
- // Handle keyboard events in field name input
3264
- onFieldNameKeydown(event, field) {
3265
- if (event.key === 'Enter') {
3266
- this.stopEdit(field);
3738
+ // Toggle validators editor
3739
+ toggleValidatorsEditor(field) {
3740
+ field.isEditingValidators = !field.isEditingValidators;
3741
+ if (field.isEditingValidators) {
3742
+ // Close other editors
3743
+ field.isEditingValues = false;
3744
+ field.isEditingDefault = false;
3267
3745
  }
3268
- else if (event.key === 'Escape') {
3269
- field.isEditing = false;
3270
- this.fields.update(fields => [...fields]);
3746
+ this.fields.update(fields => [...fields]);
3747
+ }
3748
+ // Check if field has any validators set
3749
+ hasValidators(field) {
3750
+ if (field.type === 'string') {
3751
+ return !!(field.minLength || field.maxLength || field.pattern || field.format);
3752
+ }
3753
+ if (field.type === 'number') {
3754
+ return field.minimum !== undefined || field.maximum !== undefined;
3271
3755
  }
3756
+ return false;
3757
+ }
3758
+ // Update string format
3759
+ onFormatChange(field, format) {
3760
+ field.format = format || undefined;
3761
+ // Clear pattern when format is set (they're mutually exclusive)
3762
+ if (format) {
3763
+ field.pattern = undefined;
3764
+ }
3765
+ this.fields.update(fields => [...fields]);
3766
+ this.emitChange();
3767
+ }
3768
+ // Update minLength
3769
+ onMinLengthChange(field, value) {
3770
+ field.minLength = value ? parseInt(value, 10) : undefined;
3771
+ this.fields.update(fields => [...fields]);
3772
+ this.emitChange();
3773
+ }
3774
+ // Update maxLength
3775
+ onMaxLengthChange(field, value) {
3776
+ field.maxLength = value ? parseInt(value, 10) : undefined;
3777
+ this.fields.update(fields => [...fields]);
3778
+ this.emitChange();
3779
+ }
3780
+ // Update pattern
3781
+ onPatternChange(field, value) {
3782
+ field.pattern = value || undefined;
3783
+ this.fields.update(fields => [...fields]);
3784
+ this.emitChange();
3785
+ }
3786
+ // Update minimum
3787
+ onMinimumChange(field, value) {
3788
+ field.minimum = value ? parseFloat(value) : undefined;
3789
+ this.fields.update(fields => [...fields]);
3790
+ this.emitChange();
3791
+ }
3792
+ // Update maximum
3793
+ onMaximumChange(field, value) {
3794
+ field.maximum = value ? parseFloat(value) : undefined;
3795
+ this.fields.update(fields => [...fields]);
3796
+ this.emitChange();
3272
3797
  }
3273
3798
  // Move field up in list
3274
3799
  moveFieldUp(field, parentList) {
@@ -3423,21 +3948,30 @@ class SchemaEditorComponent {
3423
3948
  else if (fieldType === 'time') {
3424
3949
  displayType = schema['x-display-type'] || 'timepicker';
3425
3950
  }
3426
- // Preserve format for string types (not date/time which have dedicated field types)
3951
+ // Preserve format for string types and date types
3427
3952
  let format;
3428
3953
  if (fieldType === 'string' && schema.format) {
3429
3954
  format = schema.format;
3430
3955
  }
3956
+ else if (fieldType === 'date' && schema.format) {
3957
+ format = schema.format; // Preserve 'date' vs 'date-time'
3958
+ }
3431
3959
  const field = {
3432
3960
  id: this.generateId(),
3433
3961
  name,
3434
3962
  type: fieldType,
3435
3963
  format,
3436
3964
  displayType,
3437
- description: schema.description,
3965
+ label: schema.title,
3438
3966
  required: isRequired,
3439
3967
  allowedValues: schema.enum,
3440
3968
  defaultValue: schema.default,
3969
+ // Validators
3970
+ minLength: schema.minLength,
3971
+ maxLength: schema.maxLength,
3972
+ pattern: schema.pattern,
3973
+ minimum: schema.minimum,
3974
+ maximum: schema.maximum,
3441
3975
  expanded: false,
3442
3976
  };
3443
3977
  if (schema.type === 'object' && schema.properties) {
@@ -3503,7 +4037,7 @@ class SchemaEditorComponent {
3503
4037
  // Map type
3504
4038
  if (field.type === 'date') {
3505
4039
  schema['type'] = 'string';
3506
- schema['format'] = 'date-time';
4040
+ schema['format'] = field.format || 'date-time'; // Use preserved format or default
3507
4041
  }
3508
4042
  else if (field.type === 'time') {
3509
4043
  schema['type'] = 'string';
@@ -3559,9 +4093,9 @@ class SchemaEditorComponent {
3559
4093
  schema['format'] = field.format;
3560
4094
  }
3561
4095
  }
3562
- // Add description
3563
- if (field.description) {
3564
- schema['description'] = field.description;
4096
+ // Add label as title
4097
+ if (field.label) {
4098
+ schema['title'] = field.label;
3565
4099
  }
3566
4100
  // Add enum for allowed values
3567
4101
  if (field.allowedValues && field.allowedValues.length > 0) {
@@ -3571,6 +4105,22 @@ class SchemaEditorComponent {
3571
4105
  if (field.defaultValue !== undefined) {
3572
4106
  schema['default'] = field.defaultValue;
3573
4107
  }
4108
+ // Add validators
4109
+ if (field.minLength !== undefined) {
4110
+ schema['minLength'] = field.minLength;
4111
+ }
4112
+ if (field.maxLength !== undefined) {
4113
+ schema['maxLength'] = field.maxLength;
4114
+ }
4115
+ if (field.pattern) {
4116
+ schema['pattern'] = field.pattern;
4117
+ }
4118
+ if (field.minimum !== undefined) {
4119
+ schema['minimum'] = field.minimum;
4120
+ }
4121
+ if (field.maximum !== undefined) {
4122
+ schema['maximum'] = field.maximum;
4123
+ }
3574
4124
  // Add display type (custom extension)
3575
4125
  if (field.displayType) {
3576
4126
  schema['x-display-type'] = field.displayType;
@@ -3579,7 +4129,7 @@ class SchemaEditorComponent {
3579
4129
  }
3580
4130
  stripEditingState(fields) {
3581
4131
  return fields.map(f => {
3582
- const { isEditing, isEditingValues, isEditingDefault, ...rest } = f;
4132
+ const { isEditingValues, isEditingDefault, isEditingValidators, ...rest } = f;
3583
4133
  return {
3584
4134
  ...rest,
3585
4135
  children: f.children ? this.stripEditingState(f.children) : undefined,
@@ -3639,7 +4189,7 @@ class SchemaEditorComponent {
3639
4189
  });
3640
4190
  }
3641
4191
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3642
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: SchemaEditorComponent, isStandalone: true, selector: "schema-editor", inputs: { schema: "schema", showJsonToggle: "showJsonToggle", showSchemaName: "showSchemaName", showDisplayType: "showDisplayType" }, outputs: { schemaChange: "schemaChange", save: "save" }, ngImport: i0, template: "<div class=\"schema-editor\">\n <!-- Schema Header -->\n <div class=\"editor-header\">\n @if (showSchemaName) {\n <div class=\"schema-name-section\">\n <mat-form-field appearance=\"outline\" class=\"schema-name-field\">\n <mat-label>Schema Name</mat-label>\n <input\n #schemaNameInput\n matInput\n [value]=\"schemaName()\"\n (input)=\"onSchemaNameChange($any($event.target).value, schemaNameInput)\"\n placeholder=\"Enter schema name\"\n />\n </mat-form-field>\n </div>\n }\n\n @if (showJsonToggle) {\n <mat-button-toggle-group [value]=\"viewMode()\" (change)=\"setViewMode($event.value)\" class=\"view-toggle\">\n <mat-button-toggle value=\"visual\">Visual</mat-button-toggle>\n <mat-button-toggle value=\"json\">JSON</mat-button-toggle>\n </mat-button-toggle-group>\n }\n\n <div class=\"header-actions\">\n @if (viewMode() === 'visual') {\n <button mat-flat-button color=\"primary\" (click)=\"addField()\">\n <mat-icon>add</mat-icon>\n Add Field\n </button>\n } @else {\n <button mat-stroked-button (click)=\"copyJson()\" matTooltip=\"Copy JSON to clipboard\">\n <mat-icon>content_copy</mat-icon>\n Copy\n </button>\n <button mat-stroked-button (click)=\"formatJson()\">\n <mat-icon>auto_fix_high</mat-icon>\n Format\n </button>\n <button mat-flat-button color=\"primary\" (click)=\"applyJsonChanges()\" [disabled]=\"jsonError()\">\n <mat-icon>check</mat-icon>\n Apply\n </button>\n }\n </div>\n </div>\n\n <!-- JSON View -->\n @if (viewMode() === 'json') {\n <div class=\"json-view\">\n @if (jsonError()) {\n <div class=\"json-error\">\n <mat-icon>error</mat-icon>\n {{ jsonError() }}\n </div>\n }\n <textarea\n class=\"json-textarea\"\n [value]=\"jsonText()\"\n (input)=\"onJsonTextChange($any($event.target).value)\"\n spellcheck=\"false\"\n ></textarea>\n </div>\n }\n\n <!-- Fields List (Visual View) -->\n <div class=\"fields-container\" [class.hidden]=\"viewMode() === 'json'\">\n @if (fields().length === 0) {\n <div class=\"empty-state\">\n <mat-icon>schema</mat-icon>\n <p>No fields yet. Click \"Add Field\" to get started.</p>\n </div>\n } @else {\n <div\n class=\"fields-list\"\n cdkDropList\n [cdkDropListData]=\"fields()\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @for (field of fields(); track field.id) {\n <div class=\"field-wrapper\" cdkDrag [attr.data-field-name]=\"field.name\" [attr.data-field-type]=\"field.type\">\n <!-- Drag Placeholder -->\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n\n <!-- Drag Preview -->\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(field.type) }}</mat-icon>\n {{ field.name || 'unnamed' }}\n </div>\n\n <div\n class=\"field-item\"\n [class.is-editing]=\"field.isEditing\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Left section: field controls -->\n <div class=\"field-left\">\n <!-- Drag Handle -->\n <div class=\"drag-handle\" cdkDragHandle matTooltip=\"Drag to reorder\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n\n <!-- Indent/Outdent Buttons -->\n <div class=\"indent-buttons\">\n <button\n class=\"indent-btn\"\n [disabled]=\"!canIndent(field, fields())\"\n (click)=\"indentField(field, fields())\"\n matTooltip=\"Move into previous object/array\"\n >\n <mat-icon>chevron_right</mat-icon>\n </button>\n <button\n class=\"indent-btn\"\n disabled\n matTooltip=\"Move out of parent\"\n >\n <mat-icon>chevron_left</mat-icon>\n </button>\n </div>\n\n <!-- Expand/Collapse -->\n @if (field.type === 'object' || field.type === 'array') {\n <button\n class=\"expand-btn\"\n (click)=\"toggleExpand(field)\"\n [matTooltip]=\"field.expanded ? 'Collapse' : 'Expand'\"\n >\n <mat-icon>{{ field.expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <!-- Type Icon -->\n <mat-icon class=\"type-icon\" [matTooltip]=\"field.type\">{{ getTypeIcon(field.type) }}</mat-icon>\n\n <!-- Field Name -->\n @if (field.isEditing) {\n <input\n class=\"field-name-input\"\n [value]=\"field.name\"\n (input)=\"onFieldNameChange(field, $event)\"\n (blur)=\"stopEdit(field)\"\n (keydown)=\"onFieldNameKeydown($event, field)\"\n placeholder=\"Field name\"\n autofocus\n />\n } @else {\n <span class=\"field-name\" (dblclick)=\"startEdit(field)\">\n {{ field.name || 'unnamed' }}\n @if (field.type === 'array') {\n <span class=\"array-indicator\">[]</span>\n }\n </span>\n }\n\n <!-- Required Toggle -->\n <button\n class=\"required-btn\"\n [class.is-required]=\"field.required\"\n (click)=\"toggleRequired(field)\"\n [matTooltip]=\"field.required ? 'Required (click to make optional)' : 'Optional (click to make required)'\"\n >\n <mat-icon>{{ field.required ? 'star' : 'star_border' }}</mat-icon>\n </button>\n </div>\n\n <!-- Middle section: description (flexible) -->\n <input\n class=\"description-input\"\n [value]=\"field.description || ''\"\n (input)=\"onDescriptionChange(field, $any($event.target).value)\"\n (blur)=\"onDescriptionBlur()\"\n placeholder=\"Description...\"\n />\n\n <!-- Right section: type and actions (fixed position) -->\n <div class=\"field-right\">\n <!-- Type Selector -->\n <mat-form-field appearance=\"outline\" class=\"type-selector\">\n <mat-select [value]=\"field.type\" (selectionChange)=\"onFieldTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (type of fieldTypes; track type.value) {\n <mat-option [value]=\"type.value\">\n <mat-icon>{{ type.icon }}</mat-icon>\n {{ type.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Display Type Selector (for string, number, boolean, date, time types) -->\n @if (showDisplayType) {\n @if (field.type === 'string' || field.type === 'number' || field.type === 'boolean' || field.type === 'date' || field.type === 'time') {\n <mat-form-field appearance=\"outline\" class=\"display-type-selector\" matTooltip=\"Display Type\">\n <mat-select [value]=\"field.displayType\" (selectionChange)=\"onDisplayTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (dt of getDisplayTypes(field.type); track dt.value) {\n <mat-option [value]=\"dt.value\">\n <mat-icon>{{ dt.icon }}</mat-icon>\n {{ dt.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <div class=\"display-type-placeholder\"></div>\n }\n }\n\n <!-- Actions -->\n <div class=\"field-actions\">\n @if (field.type === 'object' || field.type === 'array') {\n <button\n mat-icon-button\n (click)=\"addChildField(field)\"\n matTooltip=\"Add child field\"\n >\n <mat-icon>add_circle_outline</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValuesEditor(field)\"\n [matTooltip]=\"field.allowedValues?.length ? 'Edit allowed values (' + field.allowedValues!.length + ')' : 'Add allowed values'\"\n [class.has-values]=\"field.allowedValues?.length\"\n >\n <mat-icon>list</mat-icon>\n </button>\n }\n @if (field.type !== 'object' && field.type !== 'array') {\n <button\n mat-icon-button\n (click)=\"toggleDefaultEditor(field)\"\n [matTooltip]=\"field.defaultValue !== undefined ? 'Default: ' + field.defaultValue : 'Set default value'\"\n [class.has-default]=\"field.defaultValue !== undefined\"\n >\n <mat-icon>{{ field.defaultValue !== undefined ? 'label' : 'label_outline' }}</mat-icon>\n </button>\n }\n <button mat-icon-button [matMenuTriggerFor]=\"fieldMenu\" matTooltip=\"More options\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #fieldMenu=\"matMenu\">\n <button mat-menu-item (click)=\"startEdit(field)\">\n <mat-icon>edit</mat-icon>\n <span>Rename</span>\n </button>\n <button mat-menu-item (click)=\"duplicateField(field, fields())\">\n <mat-icon>content_copy</mat-icon>\n <span>Duplicate</span>\n </button>\n <button mat-menu-item (click)=\"deleteField(field, fields())\" class=\"delete-action\">\n <mat-icon>delete</mat-icon>\n <span>Delete</span>\n </button>\n </mat-menu>\n </div>\n </div>\n </div>\n\n <!-- Allowed Values Editor -->\n @if (field.isEditingValues && (field.type === 'string' || field.type === 'number')) {\n <div class=\"allowed-values-editor\">\n <div class=\"values-header\">\n <span class=\"values-label\">Allowed values:</span>\n <input\n #valueInput\n class=\"value-input\"\n type=\"text\"\n placeholder=\"Type value and press Enter\"\n (keydown)=\"onAllowedValueKeydown($event, field, valueInput)\"\n />\n <button class=\"add-value-btn\" (click)=\"addAllowedValue(field, $event)\" matTooltip=\"Add value\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n @if (field.allowedValues && field.allowedValues.length > 0) {\n <div class=\"values-list\">\n @for (value of field.allowedValues; track value; let vi = $index) {\n <span class=\"value-chip\">\n {{ value }}\n <button class=\"remove-value-btn\" (click)=\"removeAllowedValue(field, vi)\" matTooltip=\"Remove\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n }\n </div>\n } @else {\n <div class=\"no-values\">No values defined yet</div>\n }\n </div>\n }\n\n <!-- Default Value Editor -->\n @if (field.isEditingDefault && field.type !== 'object' && field.type !== 'array') {\n <div class=\"default-value-editor\">\n <div class=\"default-header\">\n <span class=\"default-label\">Default value:</span>\n @if (field.type === 'boolean') {\n <select\n class=\"default-select\"\n [value]=\"field.defaultValue?.toString() || ''\"\n (change)=\"onDefaultValueChange(field, $any($event.target).value)\"\n >\n <option value=\"\">No default</option>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </select>\n } @else {\n <input\n class=\"default-input\"\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [value]=\"field.defaultValue ?? ''\"\n (input)=\"onDefaultValueChange(field, $any($event.target).value)\"\n (keydown)=\"onDefaultValueKeydown($event, field)\"\n placeholder=\"Enter default value\"\n />\n }\n @if (field.defaultValue !== undefined) {\n <button class=\"clear-default-btn\" (click)=\"clearDefaultValue(field)\" matTooltip=\"Clear default\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Nested Children -->\n @if ((field.type === 'object' || field.type === 'array') && field.expanded && field.children) {\n <div\n class=\"nested-fields\"\n cdkDropList\n [cdkDropListData]=\"field.children\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @if (field.children.length > 0) {\n @for (child of field.children; track child.id) {\n <div class=\"field-wrapper\" cdkDrag [attr.data-field-name]=\"child.name\" [attr.data-field-type]=\"child.type\" [attr.data-parent]=\"field.name\">\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(child.type) }}</mat-icon>\n {{ child.name || 'unnamed' }}\n </div>\n <ng-container *ngTemplateOutlet=\"fieldItemTemplate; context: { field: child, parentList: field.children, level: 1 }\"></ng-container>\n\n <!-- Allowed Values Editor for nested field -->\n @if (child.isEditingValues && (child.type === 'string' || child.type === 'number')) {\n <div class=\"allowed-values-editor\">\n <div class=\"values-header\">\n <span class=\"values-label\">Allowed values:</span>\n <input\n #childValueInput\n class=\"value-input\"\n type=\"text\"\n placeholder=\"Type value and press Enter\"\n (keydown)=\"onAllowedValueKeydown($event, child, childValueInput)\"\n />\n <button class=\"add-value-btn\" (click)=\"addAllowedValue(child, $event)\" matTooltip=\"Add value\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n @if (child.allowedValues && child.allowedValues.length > 0) {\n <div class=\"values-list\">\n @for (value of child.allowedValues; track value; let vi = $index) {\n <span class=\"value-chip\">\n {{ value }}\n <button class=\"remove-value-btn\" (click)=\"removeAllowedValue(child, vi)\" matTooltip=\"Remove\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n }\n </div>\n } @else {\n <div class=\"no-values\">No values defined yet</div>\n }\n </div>\n }\n\n <!-- Default Value Editor for nested field -->\n @if (child.isEditingDefault && child.type !== 'object' && child.type !== 'array') {\n <div class=\"default-value-editor\">\n <div class=\"default-header\">\n <span class=\"default-label\">Default value:</span>\n @if (child.type === 'boolean') {\n <select\n class=\"default-select\"\n [value]=\"child.defaultValue?.toString() || ''\"\n (change)=\"onDefaultValueChange(child, $any($event.target).value)\"\n >\n <option value=\"\">No default</option>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </select>\n } @else {\n <input\n class=\"default-input\"\n [type]=\"child.type === 'number' ? 'number' : 'text'\"\n [value]=\"child.defaultValue ?? ''\"\n (input)=\"onDefaultValueChange(child, $any($event.target).value)\"\n (keydown)=\"onDefaultValueKeydown($event, child)\"\n placeholder=\"Enter default value\"\n />\n }\n @if (child.defaultValue !== undefined) {\n <button class=\"clear-default-btn\" (click)=\"clearDefaultValue(child)\" matTooltip=\"Clear default\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <div class=\"empty-nested\">\n <span>No child fields</span>\n <button mat-button (click)=\"addChildField(field)\" color=\"primary\">\n <mat-icon>add</mat-icon>\n Add field\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Field Item Template (for nested fields) -->\n<ng-template #fieldItemTemplate let-field=\"field\" let-parentList=\"parentList\" let-level=\"level\">\n <div\n class=\"field-item\"\n [class.is-editing]=\"field.isEditing\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Left section: field controls -->\n <div class=\"field-left\">\n <div class=\"drag-handle\" cdkDragHandle matTooltip=\"Drag to reorder\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n\n <div class=\"indent-buttons\">\n <button\n class=\"indent-btn\"\n [disabled]=\"!canIndent(field, parentList)\"\n (click)=\"indentField(field, parentList)\"\n matTooltip=\"Move into previous object/array\"\n >\n <mat-icon>chevron_right</mat-icon>\n </button>\n <button\n class=\"indent-btn\"\n (click)=\"outdentField(field, parentList, level)\"\n matTooltip=\"Move out of parent\"\n >\n <mat-icon>chevron_left</mat-icon>\n </button>\n </div>\n\n @if (field.type === 'object' || field.type === 'array') {\n <button class=\"expand-btn\" (click)=\"toggleExpand(field)\" [matTooltip]=\"field.expanded ? 'Collapse' : 'Expand'\">\n <mat-icon>{{ field.expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <mat-icon class=\"type-icon\" [matTooltip]=\"field.type\">{{ getTypeIcon(field.type) }}</mat-icon>\n\n @if (field.isEditing) {\n <input\n class=\"field-name-input\"\n [value]=\"field.name\"\n (input)=\"onFieldNameChange(field, $event)\"\n (blur)=\"stopEdit(field)\"\n (keydown)=\"onFieldNameKeydown($event, field)\"\n placeholder=\"Field name\"\n autofocus\n />\n } @else {\n <span class=\"field-name\" (dblclick)=\"startEdit(field)\">\n {{ field.name || 'unnamed' }}\n @if (field.type === 'array') {\n <span class=\"array-indicator\">[]</span>\n }\n </span>\n }\n\n <button\n class=\"required-btn\"\n [class.is-required]=\"field.required\"\n (click)=\"toggleRequired(field)\"\n [matTooltip]=\"field.required ? 'Required' : 'Optional'\"\n >\n <mat-icon>{{ field.required ? 'star' : 'star_border' }}</mat-icon>\n </button>\n </div>\n\n <!-- Middle section: description (flexible) -->\n <input\n class=\"description-input\"\n [value]=\"field.description || ''\"\n (input)=\"onDescriptionChange(field, $any($event.target).value)\"\n (blur)=\"onDescriptionBlur()\"\n placeholder=\"Description...\"\n />\n\n <!-- Right section: type and actions (fixed position) -->\n <div class=\"field-right\">\n <mat-form-field appearance=\"outline\" class=\"type-selector\">\n <mat-select [value]=\"field.type\" (selectionChange)=\"onFieldTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (type of fieldTypes; track type.value) {\n <mat-option [value]=\"type.value\">\n <mat-icon>{{ type.icon }}</mat-icon>\n {{ type.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Display Type Selector (for string, number, boolean, date, time types) -->\n @if (showDisplayType) {\n @if (field.type === 'string' || field.type === 'number' || field.type === 'boolean' || field.type === 'date' || field.type === 'time') {\n <mat-form-field appearance=\"outline\" class=\"display-type-selector\" matTooltip=\"Display Type\">\n <mat-select [value]=\"field.displayType\" (selectionChange)=\"onDisplayTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (dt of getDisplayTypes(field.type); track dt.value) {\n <mat-option [value]=\"dt.value\">\n <mat-icon>{{ dt.icon }}</mat-icon>\n {{ dt.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <div class=\"display-type-placeholder\"></div>\n }\n }\n\n <div class=\"field-actions\">\n @if (field.type === 'object' || field.type === 'array') {\n <button mat-icon-button (click)=\"addChildField(field)\" matTooltip=\"Add child field\">\n <mat-icon>add_circle_outline</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValuesEditor(field)\"\n [matTooltip]=\"field.allowedValues?.length ? 'Edit allowed values' : 'Add allowed values'\"\n [class.has-values]=\"field.allowedValues?.length\"\n >\n <mat-icon>list</mat-icon>\n </button>\n }\n @if (field.type !== 'object' && field.type !== 'array') {\n <button\n mat-icon-button\n (click)=\"toggleDefaultEditor(field)\"\n [matTooltip]=\"field.defaultValue !== undefined ? 'Default: ' + field.defaultValue : 'Set default value'\"\n [class.has-default]=\"field.defaultValue !== undefined\"\n >\n <mat-icon>{{ field.defaultValue !== undefined ? 'label' : 'label_outline' }}</mat-icon>\n </button>\n }\n <button mat-icon-button [matMenuTriggerFor]=\"nestedMenu\" matTooltip=\"More options\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #nestedMenu=\"matMenu\">\n <button mat-menu-item (click)=\"startEdit(field)\">\n <mat-icon>edit</mat-icon>\n <span>Rename</span>\n </button>\n <button mat-menu-item (click)=\"duplicateField(field, parentList)\">\n <mat-icon>content_copy</mat-icon>\n <span>Duplicate</span>\n </button>\n <button mat-menu-item (click)=\"deleteField(field, parentList)\" class=\"delete-action\">\n <mat-icon>delete</mat-icon>\n <span>Delete</span>\n </button>\n </mat-menu>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{--schema-editor-bg: white;--schema-editor-border-radius: 12px;--schema-editor-shadow: 0 4px 20px rgba(0, 0, 0, .08);--schema-editor-border-color: #e2e8f0;--schema-editor-header-bg: white;--schema-editor-header-border: #e2e8f0;--schema-editor-field-bg: #f8fafc;--schema-editor-field-bg-hover: #f1f5f9;--schema-editor-field-bg-editing: #eff6ff;--schema-editor-field-bg-complex: #fefce8;--schema-editor-field-border-radius: 8px;--schema-editor-text-primary: #1e293b;--schema-editor-text-secondary: #64748b;--schema-editor-text-muted: #94a3b8;--schema-editor-accent-primary: #3b82f6;--schema-editor-accent-success: #22c55e;--schema-editor-accent-warning: #f59e0b;--schema-editor-accent-danger: #ef4444;--schema-editor-spacing-sm: 8px;--schema-editor-spacing-md: 16px;--schema-editor-spacing-lg: 24px;--schema-editor-font-size-sm: 12px;--schema-editor-font-size-md: 14px;--schema-editor-font-size-lg: 16px}.schema-editor{background:var(--schema-editor-bg);border-radius:var(--schema-editor-border-radius);box-shadow:var(--schema-editor-shadow);height:100%;display:flex;flex-direction:column;overflow:hidden}.editor-header{display:flex;align-items:center;justify-content:space-between;padding:var(--schema-editor-spacing-md) var(--schema-editor-spacing-lg);border-bottom:1px solid var(--schema-editor-border-color);gap:var(--schema-editor-spacing-md);flex-shrink:0;background:var(--schema-editor-bg)}.editor-header .schema-name-section{flex:1;max-width:400px}.editor-header .schema-name-field{width:100%}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.editor-header .schema-name-field ::ng-deep .mat-mdc-text-field-wrapper{padding:0 12px}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-infix{padding-top:8px;padding-bottom:8px;min-height:36px}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__leading,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__trailing{border-color:var(--schema-editor-border-color)!important}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch{border-right:none}.editor-header .schema-name-field ::ng-deep input.mat-mdc-input-element{font-size:14px}.editor-header .schema-name-field ::ng-deep .mat-mdc-floating-label{font-size:13px}.editor-header .header-actions{display:flex;gap:12px}.editor-header .header-actions button{display:flex;align-items:center;gap:6px}.editor-header .view-toggle{border:1px solid var(--schema-editor-border-color);border-radius:8px;overflow:hidden}.editor-header .view-toggle ::ng-deep .mat-button-toggle{background:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle.mat-button-toggle-checked{background:var(--schema-editor-accent-primary);color:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle .mat-button-toggle-label-content{padding:0 16px;font-size:13px;font-weight:500;line-height:32px}.json-view{flex:1;display:flex;flex-direction:column;min-height:0;overflow:hidden}.json-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#fef2f2;border-bottom:1px solid #fecaca;color:#dc2626;font-size:12px;flex-shrink:0}.json-error mat-icon{font-size:16px;width:16px;height:16px}.json-textarea{flex:1;width:100%;padding:16px;border:none;outline:none;resize:none;font-family:SF Mono,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:13px;line-height:1.6;color:var(--schema-editor-text-primary);background:var(--schema-editor-bg);tab-size:2;box-sizing:border-box}.json-textarea:focus{outline:none}.hidden{display:none!important}.fields-container{flex:1;overflow-y:auto;padding:16px;min-height:0}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px;color:#94a3b8;text-align:center}.empty-state mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px;opacity:.5}.empty-state p{font-size:16px;margin:0}.fields-list{display:block;width:100%;min-height:50px}.fields-list .field-wrapper{margin-bottom:4px}.field-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--schema-editor-field-bg);border-radius:var(--schema-editor-field-border-radius);border:1px solid transparent;transition:all .15s ease;box-sizing:border-box}.field-item:hover{background:var(--schema-editor-field-bg-hover);border-color:var(--schema-editor-border-color)}.field-item.is-editing{background:var(--schema-editor-field-bg-editing);border-color:var(--schema-editor-accent-primary)}.field-item.is-complex{background:var(--schema-editor-field-bg-complex)}.field-item.is-complex:hover{background:#fef9c3}.field-left{display:flex;align-items:center;gap:8px;flex-shrink:0}.field-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}.drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:#94a3b8;padding:4px;border-radius:4px;transition:all .15s ease}.drag-handle:hover{background:#e2e8f0;color:#64748b}.drag-handle:active{cursor:grabbing}.drag-handle mat-icon{font-size:20px;width:20px;height:20px}.field-wrapper{display:block;width:100%;box-sizing:border-box}::ng-deep .drag-preview{display:flex!important;align-items:center!important;gap:8px!important;padding:12px 16px!important;background:#fff!important;border:2px solid #3b82f6!important;border-radius:8px!important;box-shadow:0 8px 24px #0003!important;font-size:14px!important;font-weight:500!important;color:#1e293b!important;overflow:hidden!important;white-space:nowrap!important;box-sizing:border-box!important}::ng-deep .drag-preview mat-icon{color:#3b82f6!important;font-size:20px!important;width:20px!important;height:20px!important;flex-shrink:0!important;overflow:hidden!important}.drag-placeholder{background:#e2e8f0;border:2px dashed var(--schema-editor-accent-primary);border-radius:var(--schema-editor-field-border-radius);min-height:48px;margin-bottom:4px}.drag-placeholder .placeholder-content{height:100%;min-height:48px}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .field-wrapper:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.indent-buttons{display:flex;flex-direction:row;gap:2px}.indent-buttons .indent-btn{background:none;border:none;padding:2px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;transition:all .15s ease}.indent-buttons .indent-btn:hover:not(:disabled){background:#dbeafe;color:#2563eb}.indent-buttons .indent-btn:disabled{opacity:.3;cursor:default}.indent-buttons .indent-btn mat-icon{font-size:16px;width:16px;height:16px}.expand-btn{background:none;border:none;padding:4px;cursor:pointer;color:#64748b;border-radius:4px;display:flex;align-items:center;transition:all .15s ease}.expand-btn:hover{background:#e2e8f0;color:#1e293b}.expand-btn mat-icon{font-size:20px;width:20px;height:20px}.expand-placeholder{width:28px;flex-shrink:0}.type-icon{font-size:18px;width:18px;height:18px;color:#64748b;flex-shrink:0}.field-name{flex:0 0 auto;width:150px;font-size:14px;font-weight:500;color:#1e293b;cursor:pointer;padding:4px 8px;border-radius:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.field-name:hover{background:#e2e8f0}.field-name .array-indicator{color:#f59e0b;font-weight:600;margin-left:2px}.field-name-input{flex:0 0 auto;width:150px;font-size:14px;font-weight:500;color:#1e293b;padding:6px 10px;border:2px solid #3b82f6;border-radius:6px;outline:none;background:#fff}.field-name-input::placeholder{color:#94a3b8;font-weight:400}.required-btn{background:none;border:none;padding:4px;cursor:pointer;color:#cbd5e1;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease;flex-shrink:0}.required-btn:hover{color:#f59e0b;background:#fef3c7}.required-btn.is-required{color:#f59e0b}.required-btn mat-icon{font-size:18px;width:18px;height:18px}.description-input{flex:1;font-size:13px;color:#64748b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;min-width:80px;max-width:100%;transition:all .15s ease}.description-input:focus{border-color:#3b82f6;background:#fff}.description-input::placeholder{color:#94a3b8;font-style:italic}.type-selector,.display-type-selector{width:140px;flex-shrink:0;margin-right:8px}.type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper,.display-type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.type-selector ::ng-deep .mat-mdc-text-field-wrapper,.display-type-selector ::ng-deep .mat-mdc-text-field-wrapper{padding:0 8px!important}.type-selector ::ng-deep .mat-mdc-form-field-infix,.display-type-selector ::ng-deep .mat-mdc-form-field-infix{padding-top:4px!important;padding-bottom:4px!important;min-height:28px!important}.type-selector ::ng-deep .mat-mdc-select,.display-type-selector ::ng-deep .mat-mdc-select{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-value-text,.display-type-selector ::ng-deep .mat-mdc-select-value-text{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-arrow-wrapper,.display-type-selector ::ng-deep .mat-mdc-select-arrow-wrapper{transform:scale(.8)}.display-type-selector{width:130px}.display-type-placeholder{width:130px;flex-shrink:0;margin-right:8px}::ng-deep .schema-editor-select-panel .mat-mdc-option{font-size:12px!important;min-height:36px!important;padding:0 12px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:12px!important;display:flex!important;align-items:center!important;gap:8px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option mat-icon{font-size:16px!important;width:16px!important;height:16px!important;margin-right:0!important;color:#64748b}.field-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;width:128px;flex-shrink:0;margin-left:8px;opacity:0;transition:opacity .15s ease}.field-item:hover .field-actions,.field-right:hover .field-actions{opacity:1}.field-actions button{color:#64748b}.field-actions button:hover{color:#1e293b}.delete-action{color:#ef4444!important}.delete-action mat-icon{color:#ef4444}.nested-fields{display:block;min-height:30px;margin-top:4px;margin-bottom:8px;padding-left:32px}.nested-fields .field-wrapper{margin-bottom:4px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor{margin-left:16px}.empty-nested{display:flex;align-items:center;gap:12px;padding:12px 16px;color:#94a3b8;font-size:13px;font-style:italic;background:#f8fafc;border-radius:6px;border:1px dashed #e2e8f0}.allowed-values-editor{margin-left:48px;margin-top:4px;margin-bottom:8px;padding:12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px}.allowed-values-editor .values-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.allowed-values-editor .values-label{font-size:12px;font-weight:500;color:#166534}.allowed-values-editor .value-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #86efac;border-radius:4px;outline:none;background:#fff}.allowed-values-editor .value-input:focus{border-color:#22c55e}.allowed-values-editor .value-input::placeholder{color:#94a3b8}.allowed-values-editor .add-value-btn{background:#22c55e;border:none;color:#fff;width:28px;height:28px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}.allowed-values-editor .add-value-btn:hover{background:#16a34a}.allowed-values-editor .add-value-btn mat-icon{font-size:18px;width:18px;height:18px}.allowed-values-editor .values-list{display:flex;flex-wrap:wrap;gap:6px}.allowed-values-editor .value-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#fff;border:1px solid #86efac;border-radius:4px;font-size:12px;color:#166534}.allowed-values-editor .value-chip .remove-value-btn{background:none;border:none;padding:0;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.allowed-values-editor .value-chip .remove-value-btn:hover{color:#ef4444}.allowed-values-editor .value-chip .remove-value-btn mat-icon{font-size:14px;width:14px;height:14px}.allowed-values-editor .no-values{font-size:12px;color:#94a3b8;font-style:italic}.field-actions .has-values{color:#22c55e!important}.field-actions .has-default{color:#8b5cf6!important}.default-value-editor{margin-left:48px;margin-top:4px;margin-bottom:8px;padding:12px;background:#f5f3ff;border:1px solid #c4b5fd;border-radius:8px}.default-value-editor .default-header{display:flex;align-items:center;gap:8px}.default-value-editor .default-label{font-size:12px;font-weight:500;color:#6d28d9}.default-value-editor .default-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;max-width:200px}.default-value-editor .default-input:focus{border-color:#8b5cf6}.default-value-editor .default-input::placeholder{color:#94a3b8}.default-value-editor .default-select{padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;cursor:pointer}.default-value-editor .default-select:focus{border-color:#8b5cf6}.default-value-editor .clear-default-btn{background:none;border:none;padding:4px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.default-value-editor .clear-default-btn:hover{color:#ef4444}.default-value-editor .clear-default-btn mat-icon{font-size:16px;width:16px;height:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.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: i2.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.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i4.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i8$1.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: i8$1.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i8$1.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: MatButtonToggleModule }, { kind: "directive", type: i9$1.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i9$1.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: DragDropModule }, { kind: "directive", type: i10.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i10.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i10.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i10.CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "directive", type: i10.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }] });
4192
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: SchemaEditorComponent, isStandalone: true, selector: "schema-editor", inputs: { schema: "schema", showJsonToggle: "showJsonToggle", showSchemaName: "showSchemaName", showDisplayType: "showDisplayType" }, outputs: { schemaChange: "schemaChange", save: "save" }, ngImport: i0, template: "<div class=\"schema-editor\">\n <!-- Schema Header -->\n <div class=\"editor-header\">\n @if (showSchemaName) {\n <div class=\"schema-name-section\">\n <mat-form-field appearance=\"outline\" class=\"schema-name-field\">\n <mat-label>Schema Name</mat-label>\n <input\n #schemaNameInput\n matInput\n [value]=\"schemaName()\"\n (input)=\"onSchemaNameChange($any($event.target).value, schemaNameInput)\"\n placeholder=\"Enter schema name\"\n />\n </mat-form-field>\n </div>\n }\n\n @if (showJsonToggle) {\n <mat-button-toggle-group [value]=\"viewMode()\" (change)=\"setViewMode($event.value)\" class=\"view-toggle\">\n <mat-button-toggle value=\"visual\">Visual</mat-button-toggle>\n <mat-button-toggle value=\"json\">JSON</mat-button-toggle>\n </mat-button-toggle-group>\n }\n\n <div class=\"header-actions\">\n @if (viewMode() === 'visual') {\n <button mat-flat-button color=\"primary\" (click)=\"addField()\">\n <mat-icon>add</mat-icon>\n Add Field\n </button>\n } @else {\n <button mat-stroked-button (click)=\"copyJson()\" matTooltip=\"Copy JSON to clipboard\">\n <mat-icon>content_copy</mat-icon>\n Copy\n </button>\n <button mat-stroked-button (click)=\"formatJson()\">\n <mat-icon>auto_fix_high</mat-icon>\n Format\n </button>\n <button mat-flat-button color=\"primary\" (click)=\"applyJsonChanges()\" [disabled]=\"jsonError()\">\n <mat-icon>check</mat-icon>\n Apply\n </button>\n }\n </div>\n </div>\n\n <!-- JSON View -->\n @if (viewMode() === 'json') {\n <div class=\"json-view\">\n @if (jsonError()) {\n <div class=\"json-error\">\n <mat-icon>error</mat-icon>\n {{ jsonError() }}\n </div>\n }\n <textarea\n class=\"json-textarea\"\n [value]=\"jsonText()\"\n (input)=\"onJsonTextChange($any($event.target).value)\"\n spellcheck=\"false\"\n ></textarea>\n </div>\n }\n\n <!-- Fields List (Visual View) -->\n <div class=\"fields-container\" [class.hidden]=\"viewMode() === 'json'\">\n @if (fields().length === 0) {\n <div class=\"empty-state\">\n <mat-icon>schema</mat-icon>\n <p>No fields yet. Click \"Add Field\" to get started.</p>\n </div>\n } @else {\n <div\n class=\"fields-list\"\n cdkDropList\n [cdkDropListData]=\"fields()\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @for (field of fields(); track field.id) {\n <field-item\n cdkDrag\n [field]=\"field\"\n [parentList]=\"fields()\"\n [level]=\"0\"\n [showDisplayType]=\"showDisplayType\"\n (fieldChange)=\"onFieldChange()\"\n (delete)=\"onFieldDelete($event)\"\n (duplicate)=\"onFieldDuplicate($event)\"\n >\n <!-- Drag Placeholder -->\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <!-- Drag Preview -->\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(field.type) }}</mat-icon>\n {{ field.name || 'unnamed' }}\n </div>\n </field-item>\n }\n </div>\n }\n </div>\n</div>\n", styles: [":host{--schema-editor-bg: white;--schema-editor-border-radius: 12px;--schema-editor-shadow: 0 4px 20px rgba(0, 0, 0, .08);--schema-editor-border-color: #e2e8f0;--schema-editor-header-bg: white;--schema-editor-header-border: #e2e8f0;--schema-editor-field-bg: #f8fafc;--schema-editor-field-bg-hover: #f1f5f9;--schema-editor-field-bg-editing: #eff6ff;--schema-editor-field-bg-complex: #fefce8;--schema-editor-field-border-radius: 8px;--schema-editor-text-primary: #1e293b;--schema-editor-text-secondary: #64748b;--schema-editor-text-muted: #94a3b8;--schema-editor-accent-primary: #3b82f6;--schema-editor-accent-success: #22c55e;--schema-editor-accent-warning: #f59e0b;--schema-editor-accent-danger: #ef4444;--schema-editor-spacing-sm: 8px;--schema-editor-spacing-md: 16px;--schema-editor-spacing-lg: 24px;--schema-editor-font-size-sm: 12px;--schema-editor-font-size-md: 14px;--schema-editor-font-size-lg: 16px}.schema-editor{background:var(--schema-editor-bg);border-radius:var(--schema-editor-border-radius);box-shadow:var(--schema-editor-shadow);height:100%;display:flex;flex-direction:column;overflow:hidden}.editor-header{display:flex;align-items:center;justify-content:space-between;padding:var(--schema-editor-spacing-md) var(--schema-editor-spacing-lg);border-bottom:1px solid var(--schema-editor-border-color);gap:var(--schema-editor-spacing-md);flex-shrink:0;background:var(--schema-editor-bg)}.editor-header .schema-name-section{flex:1;max-width:400px}.editor-header .schema-name-field{width:100%}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.editor-header .schema-name-field ::ng-deep .mat-mdc-text-field-wrapper{padding:0 12px}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-infix{padding-top:8px;padding-bottom:8px;min-height:36px}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__leading,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__trailing{border-color:var(--schema-editor-border-color)!important}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch{border-right:none}.editor-header .schema-name-field ::ng-deep input.mat-mdc-input-element{font-size:14px}.editor-header .schema-name-field ::ng-deep .mat-mdc-floating-label{font-size:13px}.editor-header .header-actions{display:flex;gap:12px}.editor-header .header-actions button{display:flex;align-items:center;gap:6px}.editor-header .view-toggle{border:1px solid var(--schema-editor-border-color);border-radius:8px;overflow:hidden}.editor-header .view-toggle ::ng-deep .mat-button-toggle{background:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle.mat-button-toggle-checked{background:var(--schema-editor-accent-primary);color:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle .mat-button-toggle-label-content{padding:0 16px;font-size:13px;font-weight:500;line-height:32px}.json-view{flex:1;display:flex;flex-direction:column;min-height:0;overflow:hidden}.json-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#fef2f2;border-bottom:1px solid #fecaca;color:#dc2626;font-size:12px;flex-shrink:0}.json-error mat-icon{font-size:16px;width:16px;height:16px}.json-textarea{flex:1;width:100%;padding:16px;border:none;outline:none;resize:none;font-family:SF Mono,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:13px;line-height:1.6;color:var(--schema-editor-text-primary);background:var(--schema-editor-bg);tab-size:2;box-sizing:border-box}.json-textarea:focus{outline:none}.hidden{display:none!important}.fields-container{flex:1;overflow-y:auto;padding:16px;min-height:0}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px;color:#94a3b8;text-align:center}.empty-state mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px;opacity:.5}.empty-state p{font-size:16px;margin:0}.fields-list{display:block;width:100%;min-height:50px}.fields-list .field-wrapper{margin-bottom:4px}.field-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--schema-editor-field-bg);border-radius:var(--schema-editor-field-border-radius);border:1px solid transparent;transition:all .15s ease;box-sizing:border-box}.field-item:hover{background:var(--schema-editor-field-bg-hover);border-color:var(--schema-editor-border-color)}.field-item:focus-within{background:var(--schema-editor-field-bg-editing);border-color:var(--schema-editor-accent-primary)}.field-item.is-complex{background:var(--schema-editor-field-bg-complex)}.field-item.is-complex:hover{background:#fef9c3}.field-item.is-complex:focus-within{background:#fef3c7;border-color:var(--schema-editor-accent-primary)}.field-left{display:flex;align-items:center;gap:8px;flex-shrink:0}.field-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}.drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:#94a3b8;padding:4px;border-radius:4px;transition:all .15s ease}.drag-handle:hover{background:#e2e8f0;color:#64748b}.drag-handle:active{cursor:grabbing}.drag-handle mat-icon{font-size:20px;width:20px;height:20px}.field-wrapper{display:block;width:100%;max-width:100%;box-sizing:border-box;overflow:hidden}.field-wrapper ::ng-deep .mat-mdc-icon-button{width:32px!important;height:32px!important;padding:4px!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;flex-shrink:0!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-touch-target{width:32px!important;height:32px!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-persistent-ripple{border-radius:50%}.field-wrapper ::ng-deep .mat-mdc-icon-button mat-icon,.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-icon{font-size:20px!important;width:20px!important;height:20px!important;line-height:20px!important;overflow:hidden!important}::ng-deep .drag-preview{display:flex!important;align-items:center!important;gap:8px!important;padding:12px 16px!important;background:#fff!important;border:2px solid #3b82f6!important;border-radius:8px!important;box-shadow:0 8px 24px #0003!important;font-size:14px!important;font-weight:500!important;color:#1e293b!important;overflow:hidden!important;white-space:nowrap!important;box-sizing:border-box!important}::ng-deep .drag-preview mat-icon{color:#3b82f6!important;font-size:20px!important;width:20px!important;height:20px!important;flex-shrink:0!important;overflow:hidden!important}.drag-placeholder{background:#e2e8f0;border:2px dashed var(--schema-editor-accent-primary);border-radius:var(--schema-editor-field-border-radius);min-height:48px;margin-bottom:4px}.drag-placeholder .placeholder-content{height:100%;min-height:48px}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .field-wrapper:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.indent-buttons{display:flex;flex-direction:row;gap:2px}.indent-buttons .indent-btn{background:none;border:none;padding:2px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;transition:all .15s ease}.indent-buttons .indent-btn:hover:not(:disabled){background:#dbeafe;color:#2563eb}.indent-buttons .indent-btn:disabled{opacity:.3;cursor:default}.indent-buttons .indent-btn mat-icon{font-size:16px;width:16px;height:16px}.expand-btn{background:none;border:none;padding:4px;cursor:pointer;color:#64748b;border-radius:4px;display:flex;align-items:center;transition:all .15s ease}.expand-btn:hover{background:#e2e8f0;color:#1e293b}.expand-btn mat-icon{font-size:20px;width:20px;height:20px}.expand-placeholder{width:28px;flex-shrink:0}.type-icon{font-size:18px;width:18px;height:18px;color:#64748b;flex-shrink:0}.array-indicator{color:#f59e0b;font-weight:600;font-size:14px;margin-left:2px}.field-name-input{flex:0 0 auto;width:120px;font-size:14px;font-weight:500;color:#1e293b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;transition:all .15s ease}.field-name-input:focus{border-color:#3b82f6;background:#fff}.field-name-input::placeholder{color:#94a3b8;font-weight:400}.required-btn{background:none;border:none;padding:4px;cursor:pointer;color:#cbd5e1;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease;flex-shrink:0}.required-btn:hover{color:#f59e0b;background:#fef3c7}.required-btn.is-required{color:#f59e0b}.required-btn mat-icon{font-size:18px;width:18px;height:18px}.label-input{flex:1;font-size:13px;color:#64748b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;min-width:80px;transition:all .15s ease}.label-input:focus{border-color:#3b82f6;background:#fff}.label-input::placeholder{color:#94a3b8;font-style:italic}.type-selector,.display-type-selector{width:130px;flex-shrink:0;margin-right:4px}.type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper,.display-type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.type-selector ::ng-deep .mdc-text-field--outlined,.display-type-selector ::ng-deep .mdc-text-field--outlined{height:32px!important}.type-selector ::ng-deep .mat-mdc-text-field-wrapper,.display-type-selector ::ng-deep .mat-mdc-text-field-wrapper{padding:0 8px!important;height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-flex,.display-type-selector ::ng-deep .mat-mdc-form-field-flex{height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-infix,.display-type-selector ::ng-deep .mat-mdc-form-field-infix{padding-top:4px!important;padding-bottom:4px!important;min-height:28px!important;height:28px!important}.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#e2e8f0!important}.type-selector ::ng-deep .mat-mdc-select,.display-type-selector ::ng-deep .mat-mdc-select{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-value-text,.display-type-selector ::ng-deep .mat-mdc-select-value-text{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-arrow-wrapper,.display-type-selector ::ng-deep .mat-mdc-select-arrow-wrapper{transform:scale(.8)}.display-type-selector{width:120px}.display-type-placeholder{width:120px;flex-shrink:0;margin-right:4px}::ng-deep .schema-editor-select-panel .mat-mdc-option{font-size:12px!important;min-height:36px!important;padding:0 12px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:12px!important;display:flex!important;align-items:center!important;gap:8px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option mat-icon{font-size:16px!important;width:16px!important;height:16px!important;margin-right:0!important;color:#64748b}.field-actions{display:flex;align-items:center;justify-content:flex-end;gap:2px;width:168px;flex-shrink:0;margin-left:4px;opacity:0;transition:opacity .15s ease}.field-item:hover .field-actions,.field-right:hover .field-actions{opacity:1}.field-actions button{color:#64748b}.field-actions button:hover{color:#1e293b}.delete-action{color:#ef4444!important}.delete-action mat-icon{color:#ef4444}.nested-fields{display:block;min-height:30px;margin-top:8px;margin-bottom:8px;padding-left:32px;box-sizing:border-box}.nested-fields .field-wrapper{margin-bottom:4px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-editor{margin-left:16px;margin-top:8px}.empty-nested{display:flex;align-items:center;gap:12px;padding:12px 16px;color:#94a3b8;font-size:13px;font-style:italic;background:#f8fafc;border-radius:6px;border:1px dashed #e2e8f0}.allowed-values-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;box-sizing:border-box}.allowed-values-editor .values-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.allowed-values-editor .values-label{font-size:12px;font-weight:500;color:#166534}.allowed-values-editor .value-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #86efac;border-radius:4px;outline:none;background:#fff}.allowed-values-editor .value-input:focus{border-color:#22c55e}.allowed-values-editor .value-input::placeholder{color:#94a3b8}.allowed-values-editor .add-value-btn{background:#22c55e;border:none;color:#fff;width:28px;height:28px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}.allowed-values-editor .add-value-btn:hover{background:#16a34a}.allowed-values-editor .add-value-btn mat-icon{font-size:18px;width:18px;height:18px}.allowed-values-editor .values-list{display:flex;flex-wrap:wrap;gap:6px}.allowed-values-editor .value-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#fff;border:1px solid #86efac;border-radius:4px;font-size:12px;color:#166534}.allowed-values-editor .value-chip .remove-value-btn{background:none;border:none;padding:0;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.allowed-values-editor .value-chip .remove-value-btn:hover{color:#ef4444}.allowed-values-editor .value-chip .remove-value-btn mat-icon{font-size:14px;width:14px;height:14px}.allowed-values-editor .no-values{font-size:12px;color:#94a3b8;font-style:italic}.field-actions .has-values{color:#22c55e!important}.field-actions .has-default{color:#8b5cf6!important}.field-actions .has-validators{color:#3b82f6!important}.validators-editor{margin:12px 12px 8px 48px;padding:12px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;box-sizing:border-box;overflow:hidden;width:calc(100% - 60px)}.validators-editor .validators-header{display:flex;align-items:center;gap:8px;margin-bottom:10px}.validators-editor .validators-label{font-size:12px;font-weight:500;color:#1d4ed8}.validators-editor .validators-row{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:8px;overflow:hidden;width:100%;box-sizing:border-box}.validators-editor .validators-row:last-child{margin-bottom:0}.validators-editor .validator-field{display:flex;flex-direction:column;gap:4px;flex-shrink:0;box-sizing:border-box}.validators-editor .validator-field label{font-size:11px;font-weight:500;color:#3b82f6}.validators-editor .validator-field.pattern-field{flex:1 1 auto;min-width:80px;overflow:hidden}.validators-editor .validator-input,.validators-editor .validator-select{padding:6px 10px;font-size:13px;border:1px solid #93c5fd;border-radius:4px;outline:none;background:#fff;width:100px;box-sizing:border-box!important}.validators-editor .validator-input:focus,.validators-editor .validator-select:focus{border-color:#3b82f6}.validators-editor .validator-input::placeholder,.validators-editor .validator-select::placeholder{color:#94a3b8}.validators-editor .validator-select{cursor:pointer;width:120px}.validators-editor .pattern-field .validator-input{width:100%;box-sizing:border-box!important}.default-value-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f5f3ff;border:1px solid #c4b5fd;border-radius:8px;box-sizing:border-box}.default-value-editor .default-header{display:flex;align-items:center;gap:8px}.default-value-editor .default-label{font-size:12px;font-weight:500;color:#6d28d9}.default-value-editor .default-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;max-width:200px}.default-value-editor .default-input:focus{border-color:#8b5cf6}.default-value-editor .default-input::placeholder{color:#94a3b8}.default-value-editor .default-select{padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;cursor:pointer}.default-value-editor .default-select:focus{border-color:#8b5cf6}.default-value-editor .clear-default-btn{background:none;border:none;padding:4px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.default-value-editor .clear-default-btn:hover{color:#ef4444}.default-value-editor .clear-default-btn mat-icon{font-size:16px;width:16px;height:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i5.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: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "ngmodule", type: MatButtonToggleModule }, { kind: "directive", type: i6$3.MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "disabledInteractive", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "component", type: i6$3.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: DragDropModule }, { kind: "directive", type: i7$2.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i7$2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i7$2.CdkDragPreview, selector: "ng-template[cdkDragPreview]", inputs: ["data", "matchSize"] }, { kind: "directive", type: i7$2.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: FieldItemComponent, selector: "field-item", inputs: ["field", "parentList", "level", "showDisplayType"], outputs: ["fieldChange", "delete", "duplicate", "outdent"] }] });
3643
4193
  }
3644
4194
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaEditorComponent, decorators: [{
3645
4195
  type: Component,
@@ -3655,7 +4205,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3655
4205
  MatMenuModule,
3656
4206
  MatButtonToggleModule,
3657
4207
  DragDropModule,
3658
- ], template: "<div class=\"schema-editor\">\n <!-- Schema Header -->\n <div class=\"editor-header\">\n @if (showSchemaName) {\n <div class=\"schema-name-section\">\n <mat-form-field appearance=\"outline\" class=\"schema-name-field\">\n <mat-label>Schema Name</mat-label>\n <input\n #schemaNameInput\n matInput\n [value]=\"schemaName()\"\n (input)=\"onSchemaNameChange($any($event.target).value, schemaNameInput)\"\n placeholder=\"Enter schema name\"\n />\n </mat-form-field>\n </div>\n }\n\n @if (showJsonToggle) {\n <mat-button-toggle-group [value]=\"viewMode()\" (change)=\"setViewMode($event.value)\" class=\"view-toggle\">\n <mat-button-toggle value=\"visual\">Visual</mat-button-toggle>\n <mat-button-toggle value=\"json\">JSON</mat-button-toggle>\n </mat-button-toggle-group>\n }\n\n <div class=\"header-actions\">\n @if (viewMode() === 'visual') {\n <button mat-flat-button color=\"primary\" (click)=\"addField()\">\n <mat-icon>add</mat-icon>\n Add Field\n </button>\n } @else {\n <button mat-stroked-button (click)=\"copyJson()\" matTooltip=\"Copy JSON to clipboard\">\n <mat-icon>content_copy</mat-icon>\n Copy\n </button>\n <button mat-stroked-button (click)=\"formatJson()\">\n <mat-icon>auto_fix_high</mat-icon>\n Format\n </button>\n <button mat-flat-button color=\"primary\" (click)=\"applyJsonChanges()\" [disabled]=\"jsonError()\">\n <mat-icon>check</mat-icon>\n Apply\n </button>\n }\n </div>\n </div>\n\n <!-- JSON View -->\n @if (viewMode() === 'json') {\n <div class=\"json-view\">\n @if (jsonError()) {\n <div class=\"json-error\">\n <mat-icon>error</mat-icon>\n {{ jsonError() }}\n </div>\n }\n <textarea\n class=\"json-textarea\"\n [value]=\"jsonText()\"\n (input)=\"onJsonTextChange($any($event.target).value)\"\n spellcheck=\"false\"\n ></textarea>\n </div>\n }\n\n <!-- Fields List (Visual View) -->\n <div class=\"fields-container\" [class.hidden]=\"viewMode() === 'json'\">\n @if (fields().length === 0) {\n <div class=\"empty-state\">\n <mat-icon>schema</mat-icon>\n <p>No fields yet. Click \"Add Field\" to get started.</p>\n </div>\n } @else {\n <div\n class=\"fields-list\"\n cdkDropList\n [cdkDropListData]=\"fields()\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @for (field of fields(); track field.id) {\n <div class=\"field-wrapper\" cdkDrag [attr.data-field-name]=\"field.name\" [attr.data-field-type]=\"field.type\">\n <!-- Drag Placeholder -->\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n\n <!-- Drag Preview -->\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(field.type) }}</mat-icon>\n {{ field.name || 'unnamed' }}\n </div>\n\n <div\n class=\"field-item\"\n [class.is-editing]=\"field.isEditing\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Left section: field controls -->\n <div class=\"field-left\">\n <!-- Drag Handle -->\n <div class=\"drag-handle\" cdkDragHandle matTooltip=\"Drag to reorder\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n\n <!-- Indent/Outdent Buttons -->\n <div class=\"indent-buttons\">\n <button\n class=\"indent-btn\"\n [disabled]=\"!canIndent(field, fields())\"\n (click)=\"indentField(field, fields())\"\n matTooltip=\"Move into previous object/array\"\n >\n <mat-icon>chevron_right</mat-icon>\n </button>\n <button\n class=\"indent-btn\"\n disabled\n matTooltip=\"Move out of parent\"\n >\n <mat-icon>chevron_left</mat-icon>\n </button>\n </div>\n\n <!-- Expand/Collapse -->\n @if (field.type === 'object' || field.type === 'array') {\n <button\n class=\"expand-btn\"\n (click)=\"toggleExpand(field)\"\n [matTooltip]=\"field.expanded ? 'Collapse' : 'Expand'\"\n >\n <mat-icon>{{ field.expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <!-- Type Icon -->\n <mat-icon class=\"type-icon\" [matTooltip]=\"field.type\">{{ getTypeIcon(field.type) }}</mat-icon>\n\n <!-- Field Name -->\n @if (field.isEditing) {\n <input\n class=\"field-name-input\"\n [value]=\"field.name\"\n (input)=\"onFieldNameChange(field, $event)\"\n (blur)=\"stopEdit(field)\"\n (keydown)=\"onFieldNameKeydown($event, field)\"\n placeholder=\"Field name\"\n autofocus\n />\n } @else {\n <span class=\"field-name\" (dblclick)=\"startEdit(field)\">\n {{ field.name || 'unnamed' }}\n @if (field.type === 'array') {\n <span class=\"array-indicator\">[]</span>\n }\n </span>\n }\n\n <!-- Required Toggle -->\n <button\n class=\"required-btn\"\n [class.is-required]=\"field.required\"\n (click)=\"toggleRequired(field)\"\n [matTooltip]=\"field.required ? 'Required (click to make optional)' : 'Optional (click to make required)'\"\n >\n <mat-icon>{{ field.required ? 'star' : 'star_border' }}</mat-icon>\n </button>\n </div>\n\n <!-- Middle section: description (flexible) -->\n <input\n class=\"description-input\"\n [value]=\"field.description || ''\"\n (input)=\"onDescriptionChange(field, $any($event.target).value)\"\n (blur)=\"onDescriptionBlur()\"\n placeholder=\"Description...\"\n />\n\n <!-- Right section: type and actions (fixed position) -->\n <div class=\"field-right\">\n <!-- Type Selector -->\n <mat-form-field appearance=\"outline\" class=\"type-selector\">\n <mat-select [value]=\"field.type\" (selectionChange)=\"onFieldTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (type of fieldTypes; track type.value) {\n <mat-option [value]=\"type.value\">\n <mat-icon>{{ type.icon }}</mat-icon>\n {{ type.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Display Type Selector (for string, number, boolean, date, time types) -->\n @if (showDisplayType) {\n @if (field.type === 'string' || field.type === 'number' || field.type === 'boolean' || field.type === 'date' || field.type === 'time') {\n <mat-form-field appearance=\"outline\" class=\"display-type-selector\" matTooltip=\"Display Type\">\n <mat-select [value]=\"field.displayType\" (selectionChange)=\"onDisplayTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (dt of getDisplayTypes(field.type); track dt.value) {\n <mat-option [value]=\"dt.value\">\n <mat-icon>{{ dt.icon }}</mat-icon>\n {{ dt.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <div class=\"display-type-placeholder\"></div>\n }\n }\n\n <!-- Actions -->\n <div class=\"field-actions\">\n @if (field.type === 'object' || field.type === 'array') {\n <button\n mat-icon-button\n (click)=\"addChildField(field)\"\n matTooltip=\"Add child field\"\n >\n <mat-icon>add_circle_outline</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValuesEditor(field)\"\n [matTooltip]=\"field.allowedValues?.length ? 'Edit allowed values (' + field.allowedValues!.length + ')' : 'Add allowed values'\"\n [class.has-values]=\"field.allowedValues?.length\"\n >\n <mat-icon>list</mat-icon>\n </button>\n }\n @if (field.type !== 'object' && field.type !== 'array') {\n <button\n mat-icon-button\n (click)=\"toggleDefaultEditor(field)\"\n [matTooltip]=\"field.defaultValue !== undefined ? 'Default: ' + field.defaultValue : 'Set default value'\"\n [class.has-default]=\"field.defaultValue !== undefined\"\n >\n <mat-icon>{{ field.defaultValue !== undefined ? 'label' : 'label_outline' }}</mat-icon>\n </button>\n }\n <button mat-icon-button [matMenuTriggerFor]=\"fieldMenu\" matTooltip=\"More options\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #fieldMenu=\"matMenu\">\n <button mat-menu-item (click)=\"startEdit(field)\">\n <mat-icon>edit</mat-icon>\n <span>Rename</span>\n </button>\n <button mat-menu-item (click)=\"duplicateField(field, fields())\">\n <mat-icon>content_copy</mat-icon>\n <span>Duplicate</span>\n </button>\n <button mat-menu-item (click)=\"deleteField(field, fields())\" class=\"delete-action\">\n <mat-icon>delete</mat-icon>\n <span>Delete</span>\n </button>\n </mat-menu>\n </div>\n </div>\n </div>\n\n <!-- Allowed Values Editor -->\n @if (field.isEditingValues && (field.type === 'string' || field.type === 'number')) {\n <div class=\"allowed-values-editor\">\n <div class=\"values-header\">\n <span class=\"values-label\">Allowed values:</span>\n <input\n #valueInput\n class=\"value-input\"\n type=\"text\"\n placeholder=\"Type value and press Enter\"\n (keydown)=\"onAllowedValueKeydown($event, field, valueInput)\"\n />\n <button class=\"add-value-btn\" (click)=\"addAllowedValue(field, $event)\" matTooltip=\"Add value\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n @if (field.allowedValues && field.allowedValues.length > 0) {\n <div class=\"values-list\">\n @for (value of field.allowedValues; track value; let vi = $index) {\n <span class=\"value-chip\">\n {{ value }}\n <button class=\"remove-value-btn\" (click)=\"removeAllowedValue(field, vi)\" matTooltip=\"Remove\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n }\n </div>\n } @else {\n <div class=\"no-values\">No values defined yet</div>\n }\n </div>\n }\n\n <!-- Default Value Editor -->\n @if (field.isEditingDefault && field.type !== 'object' && field.type !== 'array') {\n <div class=\"default-value-editor\">\n <div class=\"default-header\">\n <span class=\"default-label\">Default value:</span>\n @if (field.type === 'boolean') {\n <select\n class=\"default-select\"\n [value]=\"field.defaultValue?.toString() || ''\"\n (change)=\"onDefaultValueChange(field, $any($event.target).value)\"\n >\n <option value=\"\">No default</option>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </select>\n } @else {\n <input\n class=\"default-input\"\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [value]=\"field.defaultValue ?? ''\"\n (input)=\"onDefaultValueChange(field, $any($event.target).value)\"\n (keydown)=\"onDefaultValueKeydown($event, field)\"\n placeholder=\"Enter default value\"\n />\n }\n @if (field.defaultValue !== undefined) {\n <button class=\"clear-default-btn\" (click)=\"clearDefaultValue(field)\" matTooltip=\"Clear default\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Nested Children -->\n @if ((field.type === 'object' || field.type === 'array') && field.expanded && field.children) {\n <div\n class=\"nested-fields\"\n cdkDropList\n [cdkDropListData]=\"field.children\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @if (field.children.length > 0) {\n @for (child of field.children; track child.id) {\n <div class=\"field-wrapper\" cdkDrag [attr.data-field-name]=\"child.name\" [attr.data-field-type]=\"child.type\" [attr.data-parent]=\"field.name\">\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(child.type) }}</mat-icon>\n {{ child.name || 'unnamed' }}\n </div>\n <ng-container *ngTemplateOutlet=\"fieldItemTemplate; context: { field: child, parentList: field.children, level: 1 }\"></ng-container>\n\n <!-- Allowed Values Editor for nested field -->\n @if (child.isEditingValues && (child.type === 'string' || child.type === 'number')) {\n <div class=\"allowed-values-editor\">\n <div class=\"values-header\">\n <span class=\"values-label\">Allowed values:</span>\n <input\n #childValueInput\n class=\"value-input\"\n type=\"text\"\n placeholder=\"Type value and press Enter\"\n (keydown)=\"onAllowedValueKeydown($event, child, childValueInput)\"\n />\n <button class=\"add-value-btn\" (click)=\"addAllowedValue(child, $event)\" matTooltip=\"Add value\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n @if (child.allowedValues && child.allowedValues.length > 0) {\n <div class=\"values-list\">\n @for (value of child.allowedValues; track value; let vi = $index) {\n <span class=\"value-chip\">\n {{ value }}\n <button class=\"remove-value-btn\" (click)=\"removeAllowedValue(child, vi)\" matTooltip=\"Remove\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n }\n </div>\n } @else {\n <div class=\"no-values\">No values defined yet</div>\n }\n </div>\n }\n\n <!-- Default Value Editor for nested field -->\n @if (child.isEditingDefault && child.type !== 'object' && child.type !== 'array') {\n <div class=\"default-value-editor\">\n <div class=\"default-header\">\n <span class=\"default-label\">Default value:</span>\n @if (child.type === 'boolean') {\n <select\n class=\"default-select\"\n [value]=\"child.defaultValue?.toString() || ''\"\n (change)=\"onDefaultValueChange(child, $any($event.target).value)\"\n >\n <option value=\"\">No default</option>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </select>\n } @else {\n <input\n class=\"default-input\"\n [type]=\"child.type === 'number' ? 'number' : 'text'\"\n [value]=\"child.defaultValue ?? ''\"\n (input)=\"onDefaultValueChange(child, $any($event.target).value)\"\n (keydown)=\"onDefaultValueKeydown($event, child)\"\n placeholder=\"Enter default value\"\n />\n }\n @if (child.defaultValue !== undefined) {\n <button class=\"clear-default-btn\" (click)=\"clearDefaultValue(child)\" matTooltip=\"Clear default\">\n <mat-icon>close</mat-icon>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n } @else {\n <div class=\"empty-nested\">\n <span>No child fields</span>\n <button mat-button (click)=\"addChildField(field)\" color=\"primary\">\n <mat-icon>add</mat-icon>\n Add field\n </button>\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n</div>\n\n<!-- Field Item Template (for nested fields) -->\n<ng-template #fieldItemTemplate let-field=\"field\" let-parentList=\"parentList\" let-level=\"level\">\n <div\n class=\"field-item\"\n [class.is-editing]=\"field.isEditing\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Left section: field controls -->\n <div class=\"field-left\">\n <div class=\"drag-handle\" cdkDragHandle matTooltip=\"Drag to reorder\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n\n <div class=\"indent-buttons\">\n <button\n class=\"indent-btn\"\n [disabled]=\"!canIndent(field, parentList)\"\n (click)=\"indentField(field, parentList)\"\n matTooltip=\"Move into previous object/array\"\n >\n <mat-icon>chevron_right</mat-icon>\n </button>\n <button\n class=\"indent-btn\"\n (click)=\"outdentField(field, parentList, level)\"\n matTooltip=\"Move out of parent\"\n >\n <mat-icon>chevron_left</mat-icon>\n </button>\n </div>\n\n @if (field.type === 'object' || field.type === 'array') {\n <button class=\"expand-btn\" (click)=\"toggleExpand(field)\" [matTooltip]=\"field.expanded ? 'Collapse' : 'Expand'\">\n <mat-icon>{{ field.expanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n } @else {\n <span class=\"expand-placeholder\"></span>\n }\n\n <mat-icon class=\"type-icon\" [matTooltip]=\"field.type\">{{ getTypeIcon(field.type) }}</mat-icon>\n\n @if (field.isEditing) {\n <input\n class=\"field-name-input\"\n [value]=\"field.name\"\n (input)=\"onFieldNameChange(field, $event)\"\n (blur)=\"stopEdit(field)\"\n (keydown)=\"onFieldNameKeydown($event, field)\"\n placeholder=\"Field name\"\n autofocus\n />\n } @else {\n <span class=\"field-name\" (dblclick)=\"startEdit(field)\">\n {{ field.name || 'unnamed' }}\n @if (field.type === 'array') {\n <span class=\"array-indicator\">[]</span>\n }\n </span>\n }\n\n <button\n class=\"required-btn\"\n [class.is-required]=\"field.required\"\n (click)=\"toggleRequired(field)\"\n [matTooltip]=\"field.required ? 'Required' : 'Optional'\"\n >\n <mat-icon>{{ field.required ? 'star' : 'star_border' }}</mat-icon>\n </button>\n </div>\n\n <!-- Middle section: description (flexible) -->\n <input\n class=\"description-input\"\n [value]=\"field.description || ''\"\n (input)=\"onDescriptionChange(field, $any($event.target).value)\"\n (blur)=\"onDescriptionBlur()\"\n placeholder=\"Description...\"\n />\n\n <!-- Right section: type and actions (fixed position) -->\n <div class=\"field-right\">\n <mat-form-field appearance=\"outline\" class=\"type-selector\">\n <mat-select [value]=\"field.type\" (selectionChange)=\"onFieldTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (type of fieldTypes; track type.value) {\n <mat-option [value]=\"type.value\">\n <mat-icon>{{ type.icon }}</mat-icon>\n {{ type.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n\n <!-- Display Type Selector (for string, number, boolean, date, time types) -->\n @if (showDisplayType) {\n @if (field.type === 'string' || field.type === 'number' || field.type === 'boolean' || field.type === 'date' || field.type === 'time') {\n <mat-form-field appearance=\"outline\" class=\"display-type-selector\" matTooltip=\"Display Type\">\n <mat-select [value]=\"field.displayType\" (selectionChange)=\"onDisplayTypeChange(field, $event.value)\" panelClass=\"schema-editor-select-panel\">\n @for (dt of getDisplayTypes(field.type); track dt.value) {\n <mat-option [value]=\"dt.value\">\n <mat-icon>{{ dt.icon }}</mat-icon>\n {{ dt.label }}\n </mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <div class=\"display-type-placeholder\"></div>\n }\n }\n\n <div class=\"field-actions\">\n @if (field.type === 'object' || field.type === 'array') {\n <button mat-icon-button (click)=\"addChildField(field)\" matTooltip=\"Add child field\">\n <mat-icon>add_circle_outline</mat-icon>\n </button>\n }\n @if (field.type === 'string' || field.type === 'number') {\n <button\n mat-icon-button\n (click)=\"toggleValuesEditor(field)\"\n [matTooltip]=\"field.allowedValues?.length ? 'Edit allowed values' : 'Add allowed values'\"\n [class.has-values]=\"field.allowedValues?.length\"\n >\n <mat-icon>list</mat-icon>\n </button>\n }\n @if (field.type !== 'object' && field.type !== 'array') {\n <button\n mat-icon-button\n (click)=\"toggleDefaultEditor(field)\"\n [matTooltip]=\"field.defaultValue !== undefined ? 'Default: ' + field.defaultValue : 'Set default value'\"\n [class.has-default]=\"field.defaultValue !== undefined\"\n >\n <mat-icon>{{ field.defaultValue !== undefined ? 'label' : 'label_outline' }}</mat-icon>\n </button>\n }\n <button mat-icon-button [matMenuTriggerFor]=\"nestedMenu\" matTooltip=\"More options\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #nestedMenu=\"matMenu\">\n <button mat-menu-item (click)=\"startEdit(field)\">\n <mat-icon>edit</mat-icon>\n <span>Rename</span>\n </button>\n <button mat-menu-item (click)=\"duplicateField(field, parentList)\">\n <mat-icon>content_copy</mat-icon>\n <span>Duplicate</span>\n </button>\n <button mat-menu-item (click)=\"deleteField(field, parentList)\" class=\"delete-action\">\n <mat-icon>delete</mat-icon>\n <span>Delete</span>\n </button>\n </mat-menu>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [":host{--schema-editor-bg: white;--schema-editor-border-radius: 12px;--schema-editor-shadow: 0 4px 20px rgba(0, 0, 0, .08);--schema-editor-border-color: #e2e8f0;--schema-editor-header-bg: white;--schema-editor-header-border: #e2e8f0;--schema-editor-field-bg: #f8fafc;--schema-editor-field-bg-hover: #f1f5f9;--schema-editor-field-bg-editing: #eff6ff;--schema-editor-field-bg-complex: #fefce8;--schema-editor-field-border-radius: 8px;--schema-editor-text-primary: #1e293b;--schema-editor-text-secondary: #64748b;--schema-editor-text-muted: #94a3b8;--schema-editor-accent-primary: #3b82f6;--schema-editor-accent-success: #22c55e;--schema-editor-accent-warning: #f59e0b;--schema-editor-accent-danger: #ef4444;--schema-editor-spacing-sm: 8px;--schema-editor-spacing-md: 16px;--schema-editor-spacing-lg: 24px;--schema-editor-font-size-sm: 12px;--schema-editor-font-size-md: 14px;--schema-editor-font-size-lg: 16px}.schema-editor{background:var(--schema-editor-bg);border-radius:var(--schema-editor-border-radius);box-shadow:var(--schema-editor-shadow);height:100%;display:flex;flex-direction:column;overflow:hidden}.editor-header{display:flex;align-items:center;justify-content:space-between;padding:var(--schema-editor-spacing-md) var(--schema-editor-spacing-lg);border-bottom:1px solid var(--schema-editor-border-color);gap:var(--schema-editor-spacing-md);flex-shrink:0;background:var(--schema-editor-bg)}.editor-header .schema-name-section{flex:1;max-width:400px}.editor-header .schema-name-field{width:100%}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.editor-header .schema-name-field ::ng-deep .mat-mdc-text-field-wrapper{padding:0 12px}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-infix{padding-top:8px;padding-bottom:8px;min-height:36px}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__leading,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__trailing{border-color:var(--schema-editor-border-color)!important}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch{border-right:none}.editor-header .schema-name-field ::ng-deep input.mat-mdc-input-element{font-size:14px}.editor-header .schema-name-field ::ng-deep .mat-mdc-floating-label{font-size:13px}.editor-header .header-actions{display:flex;gap:12px}.editor-header .header-actions button{display:flex;align-items:center;gap:6px}.editor-header .view-toggle{border:1px solid var(--schema-editor-border-color);border-radius:8px;overflow:hidden}.editor-header .view-toggle ::ng-deep .mat-button-toggle{background:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle.mat-button-toggle-checked{background:var(--schema-editor-accent-primary);color:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle .mat-button-toggle-label-content{padding:0 16px;font-size:13px;font-weight:500;line-height:32px}.json-view{flex:1;display:flex;flex-direction:column;min-height:0;overflow:hidden}.json-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#fef2f2;border-bottom:1px solid #fecaca;color:#dc2626;font-size:12px;flex-shrink:0}.json-error mat-icon{font-size:16px;width:16px;height:16px}.json-textarea{flex:1;width:100%;padding:16px;border:none;outline:none;resize:none;font-family:SF Mono,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:13px;line-height:1.6;color:var(--schema-editor-text-primary);background:var(--schema-editor-bg);tab-size:2;box-sizing:border-box}.json-textarea:focus{outline:none}.hidden{display:none!important}.fields-container{flex:1;overflow-y:auto;padding:16px;min-height:0}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px;color:#94a3b8;text-align:center}.empty-state mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px;opacity:.5}.empty-state p{font-size:16px;margin:0}.fields-list{display:block;width:100%;min-height:50px}.fields-list .field-wrapper{margin-bottom:4px}.field-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--schema-editor-field-bg);border-radius:var(--schema-editor-field-border-radius);border:1px solid transparent;transition:all .15s ease;box-sizing:border-box}.field-item:hover{background:var(--schema-editor-field-bg-hover);border-color:var(--schema-editor-border-color)}.field-item.is-editing{background:var(--schema-editor-field-bg-editing);border-color:var(--schema-editor-accent-primary)}.field-item.is-complex{background:var(--schema-editor-field-bg-complex)}.field-item.is-complex:hover{background:#fef9c3}.field-left{display:flex;align-items:center;gap:8px;flex-shrink:0}.field-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}.drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:#94a3b8;padding:4px;border-radius:4px;transition:all .15s ease}.drag-handle:hover{background:#e2e8f0;color:#64748b}.drag-handle:active{cursor:grabbing}.drag-handle mat-icon{font-size:20px;width:20px;height:20px}.field-wrapper{display:block;width:100%;box-sizing:border-box}::ng-deep .drag-preview{display:flex!important;align-items:center!important;gap:8px!important;padding:12px 16px!important;background:#fff!important;border:2px solid #3b82f6!important;border-radius:8px!important;box-shadow:0 8px 24px #0003!important;font-size:14px!important;font-weight:500!important;color:#1e293b!important;overflow:hidden!important;white-space:nowrap!important;box-sizing:border-box!important}::ng-deep .drag-preview mat-icon{color:#3b82f6!important;font-size:20px!important;width:20px!important;height:20px!important;flex-shrink:0!important;overflow:hidden!important}.drag-placeholder{background:#e2e8f0;border:2px dashed var(--schema-editor-accent-primary);border-radius:var(--schema-editor-field-border-radius);min-height:48px;margin-bottom:4px}.drag-placeholder .placeholder-content{height:100%;min-height:48px}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .field-wrapper:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.indent-buttons{display:flex;flex-direction:row;gap:2px}.indent-buttons .indent-btn{background:none;border:none;padding:2px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;transition:all .15s ease}.indent-buttons .indent-btn:hover:not(:disabled){background:#dbeafe;color:#2563eb}.indent-buttons .indent-btn:disabled{opacity:.3;cursor:default}.indent-buttons .indent-btn mat-icon{font-size:16px;width:16px;height:16px}.expand-btn{background:none;border:none;padding:4px;cursor:pointer;color:#64748b;border-radius:4px;display:flex;align-items:center;transition:all .15s ease}.expand-btn:hover{background:#e2e8f0;color:#1e293b}.expand-btn mat-icon{font-size:20px;width:20px;height:20px}.expand-placeholder{width:28px;flex-shrink:0}.type-icon{font-size:18px;width:18px;height:18px;color:#64748b;flex-shrink:0}.field-name{flex:0 0 auto;width:150px;font-size:14px;font-weight:500;color:#1e293b;cursor:pointer;padding:4px 8px;border-radius:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.field-name:hover{background:#e2e8f0}.field-name .array-indicator{color:#f59e0b;font-weight:600;margin-left:2px}.field-name-input{flex:0 0 auto;width:150px;font-size:14px;font-weight:500;color:#1e293b;padding:6px 10px;border:2px solid #3b82f6;border-radius:6px;outline:none;background:#fff}.field-name-input::placeholder{color:#94a3b8;font-weight:400}.required-btn{background:none;border:none;padding:4px;cursor:pointer;color:#cbd5e1;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease;flex-shrink:0}.required-btn:hover{color:#f59e0b;background:#fef3c7}.required-btn.is-required{color:#f59e0b}.required-btn mat-icon{font-size:18px;width:18px;height:18px}.description-input{flex:1;font-size:13px;color:#64748b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;min-width:80px;max-width:100%;transition:all .15s ease}.description-input:focus{border-color:#3b82f6;background:#fff}.description-input::placeholder{color:#94a3b8;font-style:italic}.type-selector,.display-type-selector{width:140px;flex-shrink:0;margin-right:8px}.type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper,.display-type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.type-selector ::ng-deep .mat-mdc-text-field-wrapper,.display-type-selector ::ng-deep .mat-mdc-text-field-wrapper{padding:0 8px!important}.type-selector ::ng-deep .mat-mdc-form-field-infix,.display-type-selector ::ng-deep .mat-mdc-form-field-infix{padding-top:4px!important;padding-bottom:4px!important;min-height:28px!important}.type-selector ::ng-deep .mat-mdc-select,.display-type-selector ::ng-deep .mat-mdc-select{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-value-text,.display-type-selector ::ng-deep .mat-mdc-select-value-text{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-arrow-wrapper,.display-type-selector ::ng-deep .mat-mdc-select-arrow-wrapper{transform:scale(.8)}.display-type-selector{width:130px}.display-type-placeholder{width:130px;flex-shrink:0;margin-right:8px}::ng-deep .schema-editor-select-panel .mat-mdc-option{font-size:12px!important;min-height:36px!important;padding:0 12px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:12px!important;display:flex!important;align-items:center!important;gap:8px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option mat-icon{font-size:16px!important;width:16px!important;height:16px!important;margin-right:0!important;color:#64748b}.field-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px;width:128px;flex-shrink:0;margin-left:8px;opacity:0;transition:opacity .15s ease}.field-item:hover .field-actions,.field-right:hover .field-actions{opacity:1}.field-actions button{color:#64748b}.field-actions button:hover{color:#1e293b}.delete-action{color:#ef4444!important}.delete-action mat-icon{color:#ef4444}.nested-fields{display:block;min-height:30px;margin-top:4px;margin-bottom:8px;padding-left:32px}.nested-fields .field-wrapper{margin-bottom:4px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor{margin-left:16px}.empty-nested{display:flex;align-items:center;gap:12px;padding:12px 16px;color:#94a3b8;font-size:13px;font-style:italic;background:#f8fafc;border-radius:6px;border:1px dashed #e2e8f0}.allowed-values-editor{margin-left:48px;margin-top:4px;margin-bottom:8px;padding:12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px}.allowed-values-editor .values-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.allowed-values-editor .values-label{font-size:12px;font-weight:500;color:#166534}.allowed-values-editor .value-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #86efac;border-radius:4px;outline:none;background:#fff}.allowed-values-editor .value-input:focus{border-color:#22c55e}.allowed-values-editor .value-input::placeholder{color:#94a3b8}.allowed-values-editor .add-value-btn{background:#22c55e;border:none;color:#fff;width:28px;height:28px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}.allowed-values-editor .add-value-btn:hover{background:#16a34a}.allowed-values-editor .add-value-btn mat-icon{font-size:18px;width:18px;height:18px}.allowed-values-editor .values-list{display:flex;flex-wrap:wrap;gap:6px}.allowed-values-editor .value-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#fff;border:1px solid #86efac;border-radius:4px;font-size:12px;color:#166534}.allowed-values-editor .value-chip .remove-value-btn{background:none;border:none;padding:0;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.allowed-values-editor .value-chip .remove-value-btn:hover{color:#ef4444}.allowed-values-editor .value-chip .remove-value-btn mat-icon{font-size:14px;width:14px;height:14px}.allowed-values-editor .no-values{font-size:12px;color:#94a3b8;font-style:italic}.field-actions .has-values{color:#22c55e!important}.field-actions .has-default{color:#8b5cf6!important}.default-value-editor{margin-left:48px;margin-top:4px;margin-bottom:8px;padding:12px;background:#f5f3ff;border:1px solid #c4b5fd;border-radius:8px}.default-value-editor .default-header{display:flex;align-items:center;gap:8px}.default-value-editor .default-label{font-size:12px;font-weight:500;color:#6d28d9}.default-value-editor .default-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;max-width:200px}.default-value-editor .default-input:focus{border-color:#8b5cf6}.default-value-editor .default-input::placeholder{color:#94a3b8}.default-value-editor .default-select{padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;cursor:pointer}.default-value-editor .default-select:focus{border-color:#8b5cf6}.default-value-editor .clear-default-btn{background:none;border:none;padding:4px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.default-value-editor .clear-default-btn:hover{color:#ef4444}.default-value-editor .clear-default-btn mat-icon{font-size:16px;width:16px;height:16px}\n"] }]
4208
+ FieldItemComponent,
4209
+ ], template: "<div class=\"schema-editor\">\n <!-- Schema Header -->\n <div class=\"editor-header\">\n @if (showSchemaName) {\n <div class=\"schema-name-section\">\n <mat-form-field appearance=\"outline\" class=\"schema-name-field\">\n <mat-label>Schema Name</mat-label>\n <input\n #schemaNameInput\n matInput\n [value]=\"schemaName()\"\n (input)=\"onSchemaNameChange($any($event.target).value, schemaNameInput)\"\n placeholder=\"Enter schema name\"\n />\n </mat-form-field>\n </div>\n }\n\n @if (showJsonToggle) {\n <mat-button-toggle-group [value]=\"viewMode()\" (change)=\"setViewMode($event.value)\" class=\"view-toggle\">\n <mat-button-toggle value=\"visual\">Visual</mat-button-toggle>\n <mat-button-toggle value=\"json\">JSON</mat-button-toggle>\n </mat-button-toggle-group>\n }\n\n <div class=\"header-actions\">\n @if (viewMode() === 'visual') {\n <button mat-flat-button color=\"primary\" (click)=\"addField()\">\n <mat-icon>add</mat-icon>\n Add Field\n </button>\n } @else {\n <button mat-stroked-button (click)=\"copyJson()\" matTooltip=\"Copy JSON to clipboard\">\n <mat-icon>content_copy</mat-icon>\n Copy\n </button>\n <button mat-stroked-button (click)=\"formatJson()\">\n <mat-icon>auto_fix_high</mat-icon>\n Format\n </button>\n <button mat-flat-button color=\"primary\" (click)=\"applyJsonChanges()\" [disabled]=\"jsonError()\">\n <mat-icon>check</mat-icon>\n Apply\n </button>\n }\n </div>\n </div>\n\n <!-- JSON View -->\n @if (viewMode() === 'json') {\n <div class=\"json-view\">\n @if (jsonError()) {\n <div class=\"json-error\">\n <mat-icon>error</mat-icon>\n {{ jsonError() }}\n </div>\n }\n <textarea\n class=\"json-textarea\"\n [value]=\"jsonText()\"\n (input)=\"onJsonTextChange($any($event.target).value)\"\n spellcheck=\"false\"\n ></textarea>\n </div>\n }\n\n <!-- Fields List (Visual View) -->\n <div class=\"fields-container\" [class.hidden]=\"viewMode() === 'json'\">\n @if (fields().length === 0) {\n <div class=\"empty-state\">\n <mat-icon>schema</mat-icon>\n <p>No fields yet. Click \"Add Field\" to get started.</p>\n </div>\n } @else {\n <div\n class=\"fields-list\"\n cdkDropList\n [cdkDropListData]=\"fields()\"\n (cdkDropListDropped)=\"onFieldDrop($event)\"\n >\n @for (field of fields(); track field.id) {\n <field-item\n cdkDrag\n [field]=\"field\"\n [parentList]=\"fields()\"\n [level]=\"0\"\n [showDisplayType]=\"showDisplayType\"\n (fieldChange)=\"onFieldChange()\"\n (delete)=\"onFieldDelete($event)\"\n (duplicate)=\"onFieldDuplicate($event)\"\n >\n <!-- Drag Placeholder -->\n <div class=\"drag-placeholder\" *cdkDragPlaceholder></div>\n <!-- Drag Preview -->\n <div *cdkDragPreview class=\"drag-preview\">\n <mat-icon>{{ getTypeIcon(field.type) }}</mat-icon>\n {{ field.name || 'unnamed' }}\n </div>\n </field-item>\n }\n </div>\n }\n </div>\n</div>\n", styles: [":host{--schema-editor-bg: white;--schema-editor-border-radius: 12px;--schema-editor-shadow: 0 4px 20px rgba(0, 0, 0, .08);--schema-editor-border-color: #e2e8f0;--schema-editor-header-bg: white;--schema-editor-header-border: #e2e8f0;--schema-editor-field-bg: #f8fafc;--schema-editor-field-bg-hover: #f1f5f9;--schema-editor-field-bg-editing: #eff6ff;--schema-editor-field-bg-complex: #fefce8;--schema-editor-field-border-radius: 8px;--schema-editor-text-primary: #1e293b;--schema-editor-text-secondary: #64748b;--schema-editor-text-muted: #94a3b8;--schema-editor-accent-primary: #3b82f6;--schema-editor-accent-success: #22c55e;--schema-editor-accent-warning: #f59e0b;--schema-editor-accent-danger: #ef4444;--schema-editor-spacing-sm: 8px;--schema-editor-spacing-md: 16px;--schema-editor-spacing-lg: 24px;--schema-editor-font-size-sm: 12px;--schema-editor-font-size-md: 14px;--schema-editor-font-size-lg: 16px}.schema-editor{background:var(--schema-editor-bg);border-radius:var(--schema-editor-border-radius);box-shadow:var(--schema-editor-shadow);height:100%;display:flex;flex-direction:column;overflow:hidden}.editor-header{display:flex;align-items:center;justify-content:space-between;padding:var(--schema-editor-spacing-md) var(--schema-editor-spacing-lg);border-bottom:1px solid var(--schema-editor-border-color);gap:var(--schema-editor-spacing-md);flex-shrink:0;background:var(--schema-editor-bg)}.editor-header .schema-name-section{flex:1;max-width:400px}.editor-header .schema-name-field{width:100%}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}.editor-header .schema-name-field ::ng-deep .mat-mdc-text-field-wrapper{padding:0 12px}.editor-header .schema-name-field ::ng-deep .mat-mdc-form-field-infix{padding-top:8px;padding-bottom:8px;min-height:36px}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__leading,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch,.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__trailing{border-color:var(--schema-editor-border-color)!important}.editor-header .schema-name-field ::ng-deep .mdc-notched-outline__notch{border-right:none}.editor-header .schema-name-field ::ng-deep input.mat-mdc-input-element{font-size:14px}.editor-header .schema-name-field ::ng-deep .mat-mdc-floating-label{font-size:13px}.editor-header .header-actions{display:flex;gap:12px}.editor-header .header-actions button{display:flex;align-items:center;gap:6px}.editor-header .view-toggle{border:1px solid var(--schema-editor-border-color);border-radius:8px;overflow:hidden}.editor-header .view-toggle ::ng-deep .mat-button-toggle{background:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle.mat-button-toggle-checked{background:var(--schema-editor-accent-primary);color:#fff}.editor-header .view-toggle ::ng-deep .mat-button-toggle .mat-button-toggle-label-content{padding:0 16px;font-size:13px;font-weight:500;line-height:32px}.json-view{flex:1;display:flex;flex-direction:column;min-height:0;overflow:hidden}.json-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#fef2f2;border-bottom:1px solid #fecaca;color:#dc2626;font-size:12px;flex-shrink:0}.json-error mat-icon{font-size:16px;width:16px;height:16px}.json-textarea{flex:1;width:100%;padding:16px;border:none;outline:none;resize:none;font-family:SF Mono,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:13px;line-height:1.6;color:var(--schema-editor-text-primary);background:var(--schema-editor-bg);tab-size:2;box-sizing:border-box}.json-textarea:focus{outline:none}.hidden{display:none!important}.fields-container{flex:1;overflow-y:auto;padding:16px;min-height:0}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:60px 24px;color:#94a3b8;text-align:center}.empty-state mat-icon{font-size:64px;width:64px;height:64px;margin-bottom:16px;opacity:.5}.empty-state p{font-size:16px;margin:0}.fields-list{display:block;width:100%;min-height:50px}.fields-list .field-wrapper{margin-bottom:4px}.field-item{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--schema-editor-field-bg);border-radius:var(--schema-editor-field-border-radius);border:1px solid transparent;transition:all .15s ease;box-sizing:border-box}.field-item:hover{background:var(--schema-editor-field-bg-hover);border-color:var(--schema-editor-border-color)}.field-item:focus-within{background:var(--schema-editor-field-bg-editing);border-color:var(--schema-editor-accent-primary)}.field-item.is-complex{background:var(--schema-editor-field-bg-complex)}.field-item.is-complex:hover{background:#fef9c3}.field-item.is-complex:focus-within{background:#fef3c7;border-color:var(--schema-editor-accent-primary)}.field-left{display:flex;align-items:center;gap:8px;flex-shrink:0}.field-right{display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto}.drag-handle{display:flex;align-items:center;justify-content:center;cursor:grab;color:#94a3b8;padding:4px;border-radius:4px;transition:all .15s ease}.drag-handle:hover{background:#e2e8f0;color:#64748b}.drag-handle:active{cursor:grabbing}.drag-handle mat-icon{font-size:20px;width:20px;height:20px}.field-wrapper{display:block;width:100%;max-width:100%;box-sizing:border-box;overflow:hidden}.field-wrapper ::ng-deep .mat-mdc-icon-button{width:32px!important;height:32px!important;padding:4px!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;flex-shrink:0!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-touch-target{width:32px!important;height:32px!important}.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-mdc-button-persistent-ripple{border-radius:50%}.field-wrapper ::ng-deep .mat-mdc-icon-button mat-icon,.field-wrapper ::ng-deep .mat-mdc-icon-button .mat-icon{font-size:20px!important;width:20px!important;height:20px!important;line-height:20px!important;overflow:hidden!important}::ng-deep .drag-preview{display:flex!important;align-items:center!important;gap:8px!important;padding:12px 16px!important;background:#fff!important;border:2px solid #3b82f6!important;border-radius:8px!important;box-shadow:0 8px 24px #0003!important;font-size:14px!important;font-weight:500!important;color:#1e293b!important;overflow:hidden!important;white-space:nowrap!important;box-sizing:border-box!important}::ng-deep .drag-preview mat-icon{color:#3b82f6!important;font-size:20px!important;width:20px!important;height:20px!important;flex-shrink:0!important;overflow:hidden!important}.drag-placeholder{background:#e2e8f0;border:2px dashed var(--schema-editor-accent-primary);border-radius:var(--schema-editor-field-border-radius);min-height:48px;margin-bottom:4px}.drag-placeholder .placeholder-content{height:100%;min-height:48px}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging .field-wrapper:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.indent-buttons{display:flex;flex-direction:row;gap:2px}.indent-buttons .indent-btn{background:none;border:none;padding:2px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:3px;transition:all .15s ease}.indent-buttons .indent-btn:hover:not(:disabled){background:#dbeafe;color:#2563eb}.indent-buttons .indent-btn:disabled{opacity:.3;cursor:default}.indent-buttons .indent-btn mat-icon{font-size:16px;width:16px;height:16px}.expand-btn{background:none;border:none;padding:4px;cursor:pointer;color:#64748b;border-radius:4px;display:flex;align-items:center;transition:all .15s ease}.expand-btn:hover{background:#e2e8f0;color:#1e293b}.expand-btn mat-icon{font-size:20px;width:20px;height:20px}.expand-placeholder{width:28px;flex-shrink:0}.type-icon{font-size:18px;width:18px;height:18px;color:#64748b;flex-shrink:0}.array-indicator{color:#f59e0b;font-weight:600;font-size:14px;margin-left:2px}.field-name-input{flex:0 0 auto;width:120px;font-size:14px;font-weight:500;color:#1e293b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;transition:all .15s ease}.field-name-input:focus{border-color:#3b82f6;background:#fff}.field-name-input::placeholder{color:#94a3b8;font-weight:400}.required-btn{background:none;border:none;padding:4px;cursor:pointer;color:#cbd5e1;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all .15s ease;flex-shrink:0}.required-btn:hover{color:#f59e0b;background:#fef3c7}.required-btn.is-required{color:#f59e0b}.required-btn mat-icon{font-size:18px;width:18px;height:18px}.label-input{flex:1;font-size:13px;color:#64748b;padding:6px 10px;border:1px solid #e2e8f0;border-radius:6px;outline:none;background:#f8fafc;min-width:80px;transition:all .15s ease}.label-input:focus{border-color:#3b82f6;background:#fff}.label-input::placeholder{color:#94a3b8;font-style:italic}.type-selector,.display-type-selector{width:130px;flex-shrink:0;margin-right:4px}.type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper,.display-type-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none!important}.type-selector ::ng-deep .mdc-text-field--outlined,.display-type-selector ::ng-deep .mdc-text-field--outlined{height:32px!important}.type-selector ::ng-deep .mat-mdc-text-field-wrapper,.display-type-selector ::ng-deep .mat-mdc-text-field-wrapper{padding:0 8px!important;height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-flex,.display-type-selector ::ng-deep .mat-mdc-form-field-flex{height:32px!important}.type-selector ::ng-deep .mat-mdc-form-field-infix,.display-type-selector ::ng-deep .mat-mdc-form-field-infix{padding-top:4px!important;padding-bottom:4px!important;min-height:28px!important;height:28px!important}.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.display-type-selector ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:#e2e8f0!important}.type-selector ::ng-deep .mat-mdc-select,.display-type-selector ::ng-deep .mat-mdc-select{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-value-text,.display-type-selector ::ng-deep .mat-mdc-select-value-text{font-size:12px!important}.type-selector ::ng-deep .mat-mdc-select-arrow-wrapper,.display-type-selector ::ng-deep .mat-mdc-select-arrow-wrapper{transform:scale(.8)}.display-type-selector{width:120px}.display-type-placeholder{width:120px;flex-shrink:0;margin-right:4px}::ng-deep .schema-editor-select-panel .mat-mdc-option{font-size:12px!important;min-height:36px!important;padding:0 12px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:12px!important;display:flex!important;align-items:center!important;gap:8px!important}::ng-deep .schema-editor-select-panel .mat-mdc-option mat-icon{font-size:16px!important;width:16px!important;height:16px!important;margin-right:0!important;color:#64748b}.field-actions{display:flex;align-items:center;justify-content:flex-end;gap:2px;width:168px;flex-shrink:0;margin-left:4px;opacity:0;transition:opacity .15s ease}.field-item:hover .field-actions,.field-right:hover .field-actions{opacity:1}.field-actions button{color:#64748b}.field-actions button:hover{color:#1e293b}.delete-action{color:#ef4444!important}.delete-action mat-icon{color:#ef4444}.nested-fields{display:block;min-height:30px;margin-top:8px;margin-bottom:8px;padding-left:32px;box-sizing:border-box}.nested-fields .field-wrapper{margin-bottom:4px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-editor{margin-left:16px;margin-top:8px}.empty-nested{display:flex;align-items:center;gap:12px;padding:12px 16px;color:#94a3b8;font-size:13px;font-style:italic;background:#f8fafc;border-radius:6px;border:1px dashed #e2e8f0}.allowed-values-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;box-sizing:border-box}.allowed-values-editor .values-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.allowed-values-editor .values-label{font-size:12px;font-weight:500;color:#166534}.allowed-values-editor .value-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #86efac;border-radius:4px;outline:none;background:#fff}.allowed-values-editor .value-input:focus{border-color:#22c55e}.allowed-values-editor .value-input::placeholder{color:#94a3b8}.allowed-values-editor .add-value-btn{background:#22c55e;border:none;color:#fff;width:28px;height:28px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s ease}.allowed-values-editor .add-value-btn:hover{background:#16a34a}.allowed-values-editor .add-value-btn mat-icon{font-size:18px;width:18px;height:18px}.allowed-values-editor .values-list{display:flex;flex-wrap:wrap;gap:6px}.allowed-values-editor .value-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 8px;background:#fff;border:1px solid #86efac;border-radius:4px;font-size:12px;color:#166534}.allowed-values-editor .value-chip .remove-value-btn{background:none;border:none;padding:0;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.allowed-values-editor .value-chip .remove-value-btn:hover{color:#ef4444}.allowed-values-editor .value-chip .remove-value-btn mat-icon{font-size:14px;width:14px;height:14px}.allowed-values-editor .no-values{font-size:12px;color:#94a3b8;font-style:italic}.field-actions .has-values{color:#22c55e!important}.field-actions .has-default{color:#8b5cf6!important}.field-actions .has-validators{color:#3b82f6!important}.validators-editor{margin:12px 12px 8px 48px;padding:12px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;box-sizing:border-box;overflow:hidden;width:calc(100% - 60px)}.validators-editor .validators-header{display:flex;align-items:center;gap:8px;margin-bottom:10px}.validators-editor .validators-label{font-size:12px;font-weight:500;color:#1d4ed8}.validators-editor .validators-row{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:8px;overflow:hidden;width:100%;box-sizing:border-box}.validators-editor .validators-row:last-child{margin-bottom:0}.validators-editor .validator-field{display:flex;flex-direction:column;gap:4px;flex-shrink:0;box-sizing:border-box}.validators-editor .validator-field label{font-size:11px;font-weight:500;color:#3b82f6}.validators-editor .validator-field.pattern-field{flex:1 1 auto;min-width:80px;overflow:hidden}.validators-editor .validator-input,.validators-editor .validator-select{padding:6px 10px;font-size:13px;border:1px solid #93c5fd;border-radius:4px;outline:none;background:#fff;width:100px;box-sizing:border-box!important}.validators-editor .validator-input:focus,.validators-editor .validator-select:focus{border-color:#3b82f6}.validators-editor .validator-input::placeholder,.validators-editor .validator-select::placeholder{color:#94a3b8}.validators-editor .validator-select{cursor:pointer;width:120px}.validators-editor .pattern-field .validator-input{width:100%;box-sizing:border-box!important}.default-value-editor{margin-left:48px;margin-top:12px;margin-bottom:8px;padding:12px;background:#f5f3ff;border:1px solid #c4b5fd;border-radius:8px;box-sizing:border-box}.default-value-editor .default-header{display:flex;align-items:center;gap:8px}.default-value-editor .default-label{font-size:12px;font-weight:500;color:#6d28d9}.default-value-editor .default-input{flex:1;padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;max-width:200px}.default-value-editor .default-input:focus{border-color:#8b5cf6}.default-value-editor .default-input::placeholder{color:#94a3b8}.default-value-editor .default-select{padding:6px 10px;font-size:13px;border:1px solid #a78bfa;border-radius:4px;outline:none;background:#fff;cursor:pointer}.default-value-editor .default-select:focus{border-color:#8b5cf6}.default-value-editor .clear-default-btn{background:none;border:none;padding:4px;cursor:pointer;color:#94a3b8;display:flex;align-items:center;transition:color .15s ease}.default-value-editor .clear-default-btn:hover{color:#ef4444}.default-value-editor .clear-default-btn mat-icon{font-size:16px;width:16px;height:16px}\n"] }]
3659
4210
  }], propDecorators: { schema: [{
3660
4211
  type: Input
3661
4212
  }], showJsonToggle: [{