@expeed/ngx-data-mapper 1.3.0 → 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.
@@ -2938,6 +2938,7 @@ class FieldItemComponent {
2938
2938
  fieldChange = new EventEmitter();
2939
2939
  delete = new EventEmitter();
2940
2940
  duplicate = new EventEmitter();
2941
+ outdent = new EventEmitter();
2941
2942
  fieldTypes = [
2942
2943
  { value: 'string', label: 'String', icon: 'text_fields' },
2943
2944
  { value: 'number', label: 'Number', icon: 'pin' },
@@ -3123,8 +3124,7 @@ class FieldItemComponent {
3123
3124
  this.duplicate.emit(this.field);
3124
3125
  }
3125
3126
  onChildFieldChange() {
3126
- console.log('onChildFieldChange called on parent');
3127
- this.cdr.detectChanges();
3127
+ // Just propagate the change up - don't force detectChanges as it can reset expanded state
3128
3128
  this.fieldChange.emit();
3129
3129
  }
3130
3130
  onChildDelete(child) {
@@ -3163,7 +3163,8 @@ class FieldItemComponent {
3163
3163
  onFieldDrop(event) {
3164
3164
  if (event.previousIndex !== event.currentIndex && this.field.children) {
3165
3165
  moveItemInArray(this.field.children, event.previousIndex, event.currentIndex);
3166
- this.fieldChange.emit();
3166
+ // Don't emit fieldChange for reorder - array is mutated in place
3167
+ // and emitting causes parent re-render which resets expanded state
3167
3168
  }
3168
3169
  }
3169
3170
  canIndent() {
@@ -3185,7 +3186,28 @@ class FieldItemComponent {
3185
3186
  prevSibling.children = [];
3186
3187
  prevSibling.children.push(this.field);
3187
3188
  prevSibling.expanded = true;
3188
- this.fieldChange.emit();
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
3189
3211
  }
3190
3212
  toggleValuesEditor() {
3191
3213
  this.field.isEditingValues = !this.field.isEditingValues;
@@ -3323,7 +3345,7 @@ class FieldItemComponent {
3323
3345
  return (this.field.type === 'object' || this.field.type === 'array') && this.localExpanded();
3324
3346
  }
3325
3347
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3326
- 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" }, 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 <!-- Expand/Collapse - outside field-left to avoid drag interference -->\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 <!-- 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 <!-- 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 >\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-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}.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: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}.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: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}.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}.validators-editor{margin:4px 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:4px;margin-bottom:8px;padding-left:32px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-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}.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"] }, { 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"] }] });
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"] }] });
3327
3349
  }
3328
3350
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: FieldItemComponent, decorators: [{
3329
3351
  type: Component,
@@ -3338,7 +3360,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3338
3360
  MatMenuModule,
3339
3361
  DragDropModule,
3340
3362
  FieldItemComponent,
3341
- ], template: "<div class=\"field-wrapper\">\n <div\n class=\"field-item\"\n [class.is-complex]=\"field.type === 'object' || field.type === 'array'\"\n >\n <!-- Expand/Collapse - outside field-left to avoid drag interference -->\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 <!-- 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 <!-- 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 >\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-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}.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: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}.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: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}.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}.validators-editor{margin:4px 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:4px;margin-bottom:8px;padding-left:32px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-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}.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"] }]
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"] }]
3342
3364
  }], propDecorators: { field: [{
3343
3365
  type: Input
3344
3366
  }], parentList: [{
@@ -3353,6 +3375,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3353
3375
  type: Output
3354
3376
  }], duplicate: [{
3355
3377
  type: Output
3378
+ }], outdent: [{
3379
+ type: Output
3356
3380
  }] } });
3357
3381
 
3358
3382
  class SchemaEditorComponent {
@@ -3480,14 +3504,8 @@ class SchemaEditorComponent {
3480
3504
  }
3481
3505
  // Handle field change from FieldItemComponent
3482
3506
  onFieldChange() {
3483
- console.log('schema-editor onFieldChange called');
3484
- this.fields().forEach(f => {
3485
- if (f.type === 'object' || f.type === 'array') {
3486
- console.log(` field "${f.name}" expanded:${f.expanded} children:${f.children?.length}`);
3487
- }
3488
- });
3489
- this.fields.update(fields => [...fields]);
3490
- this.appRef.tick();
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
3491
3509
  this.emitChange();
3492
3510
  }
3493
3511
  // Handle field delete from FieldItemComponent
@@ -4171,7 +4189,7 @@ class SchemaEditorComponent {
4171
4189
  });
4172
4190
  }
4173
4191
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4174
- 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}::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}.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: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:4px;margin-bottom:8px;padding-left:32px}.nested-fields .field-wrapper{margin-bottom:4px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-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}.field-actions .has-validators{color:#3b82f6!important}.validators-editor{margin:4px 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: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: "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"] }] });
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"] }] });
4175
4193
  }
4176
4194
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SchemaEditorComponent, decorators: [{
4177
4195
  type: Component,
@@ -4188,7 +4206,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4188
4206
  MatButtonToggleModule,
4189
4207
  DragDropModule,
4190
4208
  FieldItemComponent,
4191
- ], 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}::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}.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: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:4px;margin-bottom:8px;padding-left:32px}.nested-fields .field-wrapper{margin-bottom:4px}.nested-fields .allowed-values-editor,.nested-fields .default-value-editor,.nested-fields .validators-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}.field-actions .has-validators{color:#3b82f6!important}.validators-editor{margin:4px 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: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"] }]
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"] }]
4192
4210
  }], propDecorators: { schema: [{
4193
4211
  type: Input
4194
4212
  }], showJsonToggle: [{