@elle96/ng-json-schema-manager 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, ViewEncapsulation, Component, NgModule } from '@angular/core';
|
|
2
|
+
import { Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, ViewEncapsulation, Component, PLATFORM_ID, Inject, NgModule } from '@angular/core';
|
|
3
3
|
import * as i4 from '@angular/forms';
|
|
4
4
|
import { FormGroup, FormArray, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
5
5
|
import Ajv from 'ajv';
|
|
@@ -8,7 +8,7 @@ import Ajv2020 from 'ajv/dist/2020';
|
|
|
8
8
|
import addFormats from 'ajv-formats';
|
|
9
9
|
import AjvDraft04 from 'ajv-draft-04';
|
|
10
10
|
import * as i3 from '@angular/common';
|
|
11
|
-
import { CommonModule } from '@angular/common';
|
|
11
|
+
import { CommonModule, isPlatformBrowser } from '@angular/common';
|
|
12
12
|
|
|
13
13
|
class JsonSchemaFormService {
|
|
14
14
|
buildControl(schema, value, required = false) {
|
|
@@ -274,10 +274,10 @@ class JsonSchemaFormService {
|
|
|
274
274
|
return merged;
|
|
275
275
|
}, {});
|
|
276
276
|
}
|
|
277
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
278
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
277
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
278
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormService, providedIn: 'root' });
|
|
279
279
|
}
|
|
280
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
280
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormService, decorators: [{
|
|
281
281
|
type: Injectable,
|
|
282
282
|
args: [{
|
|
283
283
|
providedIn: 'root',
|
|
@@ -449,10 +449,10 @@ class JsonSchemaResolverService {
|
|
|
449
449
|
}
|
|
450
450
|
return current;
|
|
451
451
|
}
|
|
452
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
453
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
452
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaResolverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
453
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaResolverService, providedIn: 'root' });
|
|
454
454
|
}
|
|
455
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
455
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaResolverService, decorators: [{
|
|
456
456
|
type: Injectable,
|
|
457
457
|
args: [{
|
|
458
458
|
providedIn: 'root',
|
|
@@ -569,10 +569,10 @@ class JsonSchemaValidationService {
|
|
|
569
569
|
this.ajvCache.set(draft, ajv);
|
|
570
570
|
return ajv;
|
|
571
571
|
}
|
|
572
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
573
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.
|
|
572
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaValidationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
573
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaValidationService, providedIn: 'root' });
|
|
574
574
|
}
|
|
575
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
575
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaValidationService, decorators: [{
|
|
576
576
|
type: Injectable,
|
|
577
577
|
args: [{
|
|
578
578
|
providedIn: 'root',
|
|
@@ -582,6 +582,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
582
582
|
class JsonSchemaNodeComponent {
|
|
583
583
|
schemaService;
|
|
584
584
|
validation;
|
|
585
|
+
cdr;
|
|
585
586
|
schema;
|
|
586
587
|
control;
|
|
587
588
|
label = '';
|
|
@@ -591,39 +592,53 @@ class JsonSchemaNodeComponent {
|
|
|
591
592
|
parent;
|
|
592
593
|
controlKey;
|
|
593
594
|
allowAdditionalProperties = false;
|
|
595
|
+
/** When true, errors are shown regardless of touched/dirty state (e.g. triggered by an external save button). */
|
|
596
|
+
showErrors = false;
|
|
594
597
|
controlReplaced = new EventEmitter();
|
|
595
598
|
selectedOneOf = 0;
|
|
596
599
|
selectedAnyOf = new Set();
|
|
597
600
|
newPropertyKey = '';
|
|
598
601
|
propertyError = '';
|
|
599
|
-
|
|
602
|
+
/** Tracks whether this primitive control has been touched (for OnPush CD). */
|
|
603
|
+
isTouched = false;
|
|
604
|
+
valueSub;
|
|
605
|
+
constructor(schemaService, validation, cdr) {
|
|
600
606
|
this.schemaService = schemaService;
|
|
601
607
|
this.validation = validation;
|
|
608
|
+
this.cdr = cdr;
|
|
602
609
|
}
|
|
603
610
|
ngOnInit() {
|
|
604
|
-
if (this.schema.anyOf?.length)
|
|
611
|
+
if (this.schema.anyOf?.length)
|
|
605
612
|
this.selectedAnyOf.add(0);
|
|
606
|
-
|
|
613
|
+
// markForCheck is enough for value changes — Angular will re-render in the next CD cycle
|
|
614
|
+
// without recreating DOM nodes, so the focused input keeps its focus.
|
|
615
|
+
this.valueSub = this.control.valueChanges.subscribe(() => this.cdr.markForCheck());
|
|
616
|
+
}
|
|
617
|
+
ngOnDestroy() {
|
|
618
|
+
this.valueSub?.unsubscribe();
|
|
619
|
+
}
|
|
620
|
+
/** Called on blur of primitive inputs to trigger CD after Angular marks the control as touched. */
|
|
621
|
+
onBlur() {
|
|
622
|
+
this.isTouched = true;
|
|
623
|
+
this.cdr.markForCheck();
|
|
607
624
|
}
|
|
608
|
-
/**
|
|
609
|
-
* Determina se un figlio di un object è "semplice" (primitive/enum/bool),
|
|
610
|
-
* quindi può stare in griglia 2-col, oppure "complesso" (object/array/combinator)
|
|
611
|
-
* che deve occupare la larghezza piena.
|
|
612
|
-
*/
|
|
613
625
|
isSimpleChild(key) {
|
|
614
|
-
const
|
|
615
|
-
if (
|
|
626
|
+
const s = this.schemaForKey(key);
|
|
627
|
+
if (s.oneOf?.length || s.anyOf?.length || s.allOf?.length)
|
|
616
628
|
return false;
|
|
617
|
-
const t = this.schemaService.resolveType(
|
|
629
|
+
const t = this.schemaService.resolveType(s);
|
|
618
630
|
return t !== 'object' && t !== 'array';
|
|
619
631
|
}
|
|
620
632
|
badgeClass(badge) {
|
|
621
|
-
|
|
622
|
-
'
|
|
623
|
-
|
|
624
|
-
'
|
|
625
|
-
|
|
626
|
-
|
|
633
|
+
if (badge === 'Deprecated')
|
|
634
|
+
return 'jsm-badge--deprecated';
|
|
635
|
+
if (badge === 'Read-only' || badge === 'Nullable')
|
|
636
|
+
return 'jsm-badge--readonly';
|
|
637
|
+
if (badge === 'Write-only')
|
|
638
|
+
return 'jsm-badge--writeonly';
|
|
639
|
+
if (badge === 'Not constraint')
|
|
640
|
+
return 'jsm-badge--not';
|
|
641
|
+
return 'jsm-badge--nullable';
|
|
627
642
|
}
|
|
628
643
|
get nodeKind() {
|
|
629
644
|
if (this.schema.oneOf?.length)
|
|
@@ -632,10 +647,10 @@ class JsonSchemaNodeComponent {
|
|
|
632
647
|
return 'anyOf';
|
|
633
648
|
if (this.schema.allOf?.length)
|
|
634
649
|
return 'allOf';
|
|
635
|
-
const
|
|
636
|
-
if (
|
|
650
|
+
const r = this.resolvedType;
|
|
651
|
+
if (r === 'object')
|
|
637
652
|
return 'object';
|
|
638
|
-
if (
|
|
653
|
+
if (r === 'array')
|
|
639
654
|
return 'array';
|
|
640
655
|
return 'primitive';
|
|
641
656
|
}
|
|
@@ -671,38 +686,73 @@ class JsonSchemaNodeComponent {
|
|
|
671
686
|
get controlAsArray() { return this.control; }
|
|
672
687
|
get arrayControls() { return this.controlAsArray.controls; }
|
|
673
688
|
get objectKeys() { return Object.keys(this.controlAsGroup.controls); }
|
|
674
|
-
get simpleKeys() {
|
|
675
|
-
|
|
676
|
-
}
|
|
677
|
-
get complexKeys() {
|
|
678
|
-
return this.objectKeys.filter(k => !this.isSimpleChild(k));
|
|
679
|
-
}
|
|
689
|
+
get simpleKeys() { return this.objectKeys.filter(k => this.isSimpleChild(k)); }
|
|
690
|
+
get complexKeys() { return this.objectKeys.filter(k => !this.isSimpleChild(k)); }
|
|
680
691
|
get canAddProperty() {
|
|
681
692
|
if (!this.allowAdditionalProperties)
|
|
682
693
|
return false;
|
|
683
694
|
return this.effectiveSchema.additionalProperties !== false || !!this.effectiveSchema.patternProperties;
|
|
684
695
|
}
|
|
685
696
|
get errorsForPath() { return this.errorsMap.get(this.path) ?? []; }
|
|
697
|
+
/** Combined errors: Ajv errors from errorsMap + Angular validator errors on the control. */
|
|
698
|
+
get allErrors() {
|
|
699
|
+
const ajvErrors = this.errorsForPath;
|
|
700
|
+
const ctrl = this.control;
|
|
701
|
+
if (!ctrl.errors)
|
|
702
|
+
return ajvErrors;
|
|
703
|
+
const angularErrors = [];
|
|
704
|
+
const errs = ctrl.errors;
|
|
705
|
+
if (errs['required'])
|
|
706
|
+
angularErrors.push('This field is required');
|
|
707
|
+
if (errs['minlength'])
|
|
708
|
+
angularErrors.push(`Minimum length is ${errs['minlength'].requiredLength}`);
|
|
709
|
+
if (errs['maxlength'])
|
|
710
|
+
angularErrors.push(`Maximum length is ${errs['maxlength'].requiredLength}`);
|
|
711
|
+
if (errs['min'])
|
|
712
|
+
angularErrors.push(`Minimum value is ${errs['min'].min}`);
|
|
713
|
+
if (errs['max'])
|
|
714
|
+
angularErrors.push(`Maximum value is ${errs['max'].max}`);
|
|
715
|
+
if (errs['email'])
|
|
716
|
+
angularErrors.push('Invalid email address');
|
|
717
|
+
if (errs['pattern'])
|
|
718
|
+
angularErrors.push('Value does not match the required pattern');
|
|
719
|
+
if (errs['integer'])
|
|
720
|
+
angularErrors.push('Value must be an integer');
|
|
721
|
+
if (errs['exclusiveMinimum'])
|
|
722
|
+
angularErrors.push('Value must be greater than the minimum');
|
|
723
|
+
if (errs['exclusiveMaximum'])
|
|
724
|
+
angularErrors.push('Value must be less than the maximum');
|
|
725
|
+
if (errs['multipleOf'])
|
|
726
|
+
angularErrors.push('Value must be a multiple of the required number');
|
|
727
|
+
if (errs['minItems'])
|
|
728
|
+
angularErrors.push(`Minimum ${errs['minItems'].requiredLength ?? ''} items required`);
|
|
729
|
+
if (errs['maxItems'])
|
|
730
|
+
angularErrors.push(`Maximum ${errs['maxItems'].requiredLength ?? ''} items allowed`);
|
|
731
|
+
if (errs['uniqueItems'])
|
|
732
|
+
angularErrors.push('Items must be unique');
|
|
733
|
+
// Merge: prefer Ajv messages, fall back to Angular messages for errors not covered by Ajv
|
|
734
|
+
return ajvErrors.length > 0 ? ajvErrors : angularErrors;
|
|
735
|
+
}
|
|
686
736
|
get metaBadges() {
|
|
687
|
-
const
|
|
737
|
+
const b = [];
|
|
688
738
|
if (this.effectiveSchema.deprecated)
|
|
689
|
-
|
|
739
|
+
b.push('Deprecated');
|
|
690
740
|
if (this.effectiveSchema.readOnly)
|
|
691
|
-
|
|
741
|
+
b.push('Read-only');
|
|
692
742
|
if (this.effectiveSchema.writeOnly)
|
|
693
|
-
|
|
743
|
+
b.push('Write-only');
|
|
694
744
|
if (this.effectiveSchema.nullable)
|
|
695
|
-
|
|
745
|
+
b.push('Nullable');
|
|
696
746
|
if (this.effectiveSchema.not)
|
|
697
|
-
|
|
698
|
-
return
|
|
747
|
+
b.push('Not constraint');
|
|
748
|
+
return b;
|
|
699
749
|
}
|
|
700
750
|
get activeVariant() {
|
|
701
751
|
if (this.schema.oneOf?.length)
|
|
702
752
|
return this.schema.oneOf[this.selectedOneOf] ?? null;
|
|
703
753
|
if (this.schema.anyOf?.length) {
|
|
704
|
-
const
|
|
705
|
-
return
|
|
754
|
+
const sel = Array.from(this.selectedAnyOf).map(i => this.schema.anyOf[i]);
|
|
755
|
+
return sel.length ? this.mergeSchemas(sel) : this.schema.anyOf[0] ?? null;
|
|
706
756
|
}
|
|
707
757
|
if (this.schema.allOf?.length)
|
|
708
758
|
return this.mergeSchemas([this.schema, ...this.schema.allOf]);
|
|
@@ -713,9 +763,7 @@ class JsonSchemaNodeComponent {
|
|
|
713
763
|
}
|
|
714
764
|
isRequired(key) { return this.effectiveSchema.required?.includes(key) ?? false; }
|
|
715
765
|
schemaForKey(key) {
|
|
716
|
-
return
|
|
717
|
-
this.schemaService.resolveDynamicSchema(this.effectiveSchema, key) ??
|
|
718
|
-
{});
|
|
766
|
+
return this.effectiveSchema.properties?.[key] ?? this.schemaService.resolveDynamicSchema(this.effectiveSchema, key) ?? {};
|
|
719
767
|
}
|
|
720
768
|
isDynamicKey(key) { return !this.effectiveSchema.properties?.[key]; }
|
|
721
769
|
pathForChild(key) {
|
|
@@ -729,8 +777,7 @@ class JsonSchemaNodeComponent {
|
|
|
729
777
|
return;
|
|
730
778
|
}
|
|
731
779
|
if (this.effectiveSchema.propertyNames) {
|
|
732
|
-
|
|
733
|
-
if (nameErrors.length) {
|
|
780
|
+
if (this.validation.validate(this.effectiveSchema.propertyNames, key).length) {
|
|
734
781
|
this.propertyError = 'Property name does not match schema constraints.';
|
|
735
782
|
return;
|
|
736
783
|
}
|
|
@@ -739,20 +786,19 @@ class JsonSchemaNodeComponent {
|
|
|
739
786
|
this.propertyError = 'Property already exists.';
|
|
740
787
|
return;
|
|
741
788
|
}
|
|
742
|
-
const
|
|
743
|
-
if (!
|
|
789
|
+
const s = this.schemaService.resolveDynamicSchema(this.effectiveSchema, key);
|
|
790
|
+
if (!s) {
|
|
744
791
|
this.propertyError = 'This property is not allowed by the schema.';
|
|
745
792
|
return;
|
|
746
793
|
}
|
|
747
|
-
|
|
748
|
-
this.controlAsGroup.addControl(key, control);
|
|
794
|
+
this.controlAsGroup.addControl(key, this.schemaService.buildControl(s, undefined, false));
|
|
749
795
|
this.newPropertyKey = '';
|
|
750
796
|
}
|
|
751
797
|
removeDynamicKey(key) { this.controlAsGroup.removeControl(key); }
|
|
752
798
|
schemaForIndex(index) {
|
|
753
|
-
const
|
|
754
|
-
if (
|
|
755
|
-
return
|
|
799
|
+
const p = this.effectiveSchema.prefixItems ?? [];
|
|
800
|
+
if (p[index])
|
|
801
|
+
return p[index];
|
|
756
802
|
if (this.effectiveSchema.items && this.effectiveSchema.items !== true)
|
|
757
803
|
return this.effectiveSchema.items;
|
|
758
804
|
if (this.effectiveSchema.additionalItems && this.effectiveSchema.additionalItems !== true)
|
|
@@ -762,17 +808,14 @@ class JsonSchemaNodeComponent {
|
|
|
762
808
|
return {};
|
|
763
809
|
}
|
|
764
810
|
get canAddArrayItem() {
|
|
765
|
-
return !(this.effectiveSchema.items === false ||
|
|
766
|
-
this.effectiveSchema.additionalItems === false ||
|
|
767
|
-
this.effectiveSchema.unevaluatedItems === false);
|
|
811
|
+
return !(this.effectiveSchema.items === false || this.effectiveSchema.additionalItems === false || this.effectiveSchema.unevaluatedItems === false);
|
|
768
812
|
}
|
|
769
813
|
addArrayItem() {
|
|
770
814
|
if (!this.canAddArrayItem)
|
|
771
815
|
return;
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
formArray.markAsDirty();
|
|
816
|
+
const fa = this.controlAsArray;
|
|
817
|
+
fa.push(this.schemaService.buildControl(this.schemaForIndex(fa.length), undefined, false));
|
|
818
|
+
fa.markAsDirty();
|
|
776
819
|
}
|
|
777
820
|
removeArrayItem(index) {
|
|
778
821
|
this.controlAsArray.removeAt(index);
|
|
@@ -788,9 +831,9 @@ class JsonSchemaNodeComponent {
|
|
|
788
831
|
this.selectedAnyOf.delete(index);
|
|
789
832
|
else
|
|
790
833
|
this.selectedAnyOf.add(index);
|
|
791
|
-
const
|
|
792
|
-
if (
|
|
793
|
-
this.replaceControl(this.schemaService.buildControl(
|
|
834
|
+
const v = this.activeVariant;
|
|
835
|
+
if (v)
|
|
836
|
+
this.replaceControl(this.schemaService.buildControl(v, this.control.value, this.required));
|
|
794
837
|
}
|
|
795
838
|
replaceControl(control) {
|
|
796
839
|
if (this.parent) {
|
|
@@ -806,12 +849,12 @@ class JsonSchemaNodeComponent {
|
|
|
806
849
|
}
|
|
807
850
|
childControl(key) { return this.controlAsGroup.get(key); }
|
|
808
851
|
get effectiveSchema() {
|
|
809
|
-
let
|
|
810
|
-
if (
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
return
|
|
852
|
+
let s = this.schema;
|
|
853
|
+
if (s.allOf?.length)
|
|
854
|
+
s = this.mergeSchemas([s, ...s.allOf]);
|
|
855
|
+
s = this.applyConditional(s);
|
|
856
|
+
s = this.applyDependencies(s);
|
|
857
|
+
return s;
|
|
815
858
|
}
|
|
816
859
|
applyConditional(schema) {
|
|
817
860
|
if (!schema.if)
|
|
@@ -827,406 +870,284 @@ class JsonSchemaNodeComponent {
|
|
|
827
870
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
828
871
|
return schema;
|
|
829
872
|
let merged = { ...schema };
|
|
830
|
-
const
|
|
873
|
+
const keys = Object.keys(value);
|
|
831
874
|
if (schema.dependentRequired) {
|
|
832
|
-
for (const
|
|
833
|
-
const
|
|
834
|
-
if (
|
|
835
|
-
merged = this.mergeSchemas([merged, { required }]);
|
|
875
|
+
for (const k of keys) {
|
|
876
|
+
const r = schema.dependentRequired[k];
|
|
877
|
+
if (r?.length)
|
|
878
|
+
merged = this.mergeSchemas([merged, { required: r }]);
|
|
836
879
|
}
|
|
837
880
|
}
|
|
838
881
|
if (schema.dependentSchemas) {
|
|
839
|
-
for (const
|
|
840
|
-
const
|
|
841
|
-
if (
|
|
842
|
-
merged = this.mergeSchemas([merged,
|
|
882
|
+
for (const k of keys) {
|
|
883
|
+
const d = schema.dependentSchemas[k];
|
|
884
|
+
if (d)
|
|
885
|
+
merged = this.mergeSchemas([merged, d]);
|
|
843
886
|
}
|
|
844
887
|
}
|
|
845
888
|
if (schema.dependencies) {
|
|
846
|
-
for (const
|
|
847
|
-
const
|
|
848
|
-
if (Array.isArray(
|
|
849
|
-
merged = this.mergeSchemas([merged, { required:
|
|
850
|
-
else if (
|
|
851
|
-
merged = this.mergeSchemas([merged,
|
|
889
|
+
for (const k of keys) {
|
|
890
|
+
const d = schema.dependencies[k];
|
|
891
|
+
if (Array.isArray(d))
|
|
892
|
+
merged = this.mergeSchemas([merged, { required: d }]);
|
|
893
|
+
else if (d)
|
|
894
|
+
merged = this.mergeSchemas([merged, d]);
|
|
852
895
|
}
|
|
853
896
|
}
|
|
854
897
|
return merged;
|
|
855
898
|
}
|
|
856
899
|
mergeSchemas(schemas) {
|
|
857
|
-
return schemas.reduce((acc,
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
870
|
-
return merged;
|
|
871
|
-
}, {});
|
|
900
|
+
return schemas.reduce((acc, s) => ({
|
|
901
|
+
...acc, ...s,
|
|
902
|
+
properties: { ...(acc.properties ?? {}), ...(s.properties ?? {}) },
|
|
903
|
+
patternProperties: { ...(acc.patternProperties ?? {}), ...(s.patternProperties ?? {}) },
|
|
904
|
+
required: Array.from(new Set([...(acc.required ?? []), ...(s.required ?? [])])),
|
|
905
|
+
...(acc.type && s.type ? {
|
|
906
|
+
type: Array.from(new Set([
|
|
907
|
+
...(Array.isArray(acc.type) ? acc.type : [acc.type]),
|
|
908
|
+
...(Array.isArray(s.type) ? s.type : [s.type]),
|
|
909
|
+
]))
|
|
910
|
+
} : {}),
|
|
911
|
+
}), {});
|
|
872
912
|
}
|
|
873
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
874
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.
|
|
913
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaNodeComponent, deps: [{ token: JsonSchemaFormService }, { token: JsonSchemaValidationService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
914
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: JsonSchemaNodeComponent, isStandalone: true, selector: "jsm-schema-node", inputs: { schema: "schema", control: "control", label: "label", required: "required", path: "path", errorsMap: "errorsMap", parent: "parent", controlKey: "controlKey", allowAdditionalProperties: "allowAdditionalProperties", showErrors: "showErrors" }, outputs: { controlReplaced: "controlReplaced" }, ngImport: i0, template: `
|
|
875
915
|
<ng-container [ngSwitch]="nodeKind">
|
|
876
916
|
|
|
877
|
-
<!--
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
<div *ngSwitchCase="'oneOf'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm overflow-hidden">
|
|
881
|
-
<div class="flex items-start justify-between px-4 py-3 bg-slate-50 dark:bg-slate-800/60 border-b border-slate-200 dark:border-slate-700">
|
|
917
|
+
<!-- ═══ oneOf ═══ -->
|
|
918
|
+
<div *ngSwitchCase="'oneOf'" class="jsm-combinator">
|
|
919
|
+
<div class="jsm-combinator-header">
|
|
882
920
|
<div>
|
|
883
|
-
<p class="
|
|
884
|
-
<p *ngIf="schema.description" class="
|
|
921
|
+
<p class="jsm-combinator-title">{{ schema.title || label }}</p>
|
|
922
|
+
<p *ngIf="schema.description" class="jsm-combinator-hint">{{ schema.description }}</p>
|
|
885
923
|
</div>
|
|
886
|
-
<span class="
|
|
924
|
+
<span class="jsm-combinator-badge jsm-badge--oneof">oneOf</span>
|
|
887
925
|
</div>
|
|
888
|
-
<div class="
|
|
889
|
-
<button
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
[class.text-indigo-600]="selectedOneOf === i"
|
|
895
|
-
[class.dark:text-indigo-400]="selectedOneOf === i"
|
|
896
|
-
[class.font-semibold]="selectedOneOf === i"
|
|
897
|
-
[class.border-transparent]="selectedOneOf !== i"
|
|
898
|
-
[class.text-slate-500]="selectedOneOf !== i"
|
|
899
|
-
[class.dark:text-slate-400]="selectedOneOf !== i"
|
|
900
|
-
(click)="selectedOneOf = i; onOneOfChange()"
|
|
901
|
-
>{{ option.title || ('Option ' + (i + 1)) }}</button>
|
|
926
|
+
<div class="jsm-oneof-tabs">
|
|
927
|
+
<button *ngFor="let option of schema.oneOf; let i = index" type="button"
|
|
928
|
+
class="jsm-tab" [class.jsm-tab--active]="selectedOneOf === i"
|
|
929
|
+
(click)="selectedOneOf = i; onOneOfChange()">
|
|
930
|
+
{{ option.title || ('Option ' + (i + 1)) }}
|
|
931
|
+
</button>
|
|
902
932
|
</div>
|
|
903
|
-
<div class="
|
|
933
|
+
<div class="jsm-combinator-body" *ngIf="activeVariant">
|
|
904
934
|
<jsm-schema-node [schema]="activeVariant" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
905
935
|
[path]="path" [errorsMap]="errorsMap" [label]="label" [required]="required"
|
|
906
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
936
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
907
937
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
908
938
|
</div>
|
|
909
939
|
</div>
|
|
910
940
|
|
|
911
|
-
<!--
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
<div *ngSwitchCase="'anyOf'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm overflow-hidden">
|
|
915
|
-
<div class="flex items-start justify-between px-4 py-3 bg-slate-50 dark:bg-slate-800/60 border-b border-slate-200 dark:border-slate-700">
|
|
941
|
+
<!-- ═══ anyOf ═══ -->
|
|
942
|
+
<div *ngSwitchCase="'anyOf'" class="jsm-combinator">
|
|
943
|
+
<div class="jsm-combinator-header">
|
|
916
944
|
<div>
|
|
917
|
-
<p class="
|
|
918
|
-
<p *ngIf="schema.description" class="
|
|
945
|
+
<p class="jsm-combinator-title">{{ schema.title || label }}</p>
|
|
946
|
+
<p *ngIf="schema.description" class="jsm-combinator-hint">{{ schema.description }}</p>
|
|
919
947
|
</div>
|
|
920
|
-
<span class="
|
|
948
|
+
<span class="jsm-combinator-badge jsm-badge--anyof">anyOf</span>
|
|
921
949
|
</div>
|
|
922
|
-
<div class="
|
|
923
|
-
<label
|
|
924
|
-
|
|
925
|
-
class="
|
|
926
|
-
[class.border-indigo-400]="selectedAnyOf.has(i)"
|
|
927
|
-
[class.bg-indigo-50]="selectedAnyOf.has(i)"
|
|
928
|
-
[class.dark:bg-indigo-900/30]="selectedAnyOf.has(i)"
|
|
929
|
-
[class.text-indigo-700]="selectedAnyOf.has(i)"
|
|
930
|
-
[class.dark:text-indigo-400]="selectedAnyOf.has(i)"
|
|
931
|
-
[class.border-slate-200]="!selectedAnyOf.has(i)"
|
|
932
|
-
[class.dark:border-slate-600]="!selectedAnyOf.has(i)"
|
|
933
|
-
[class.text-slate-600]="!selectedAnyOf.has(i)"
|
|
934
|
-
[class.dark:text-slate-400]="!selectedAnyOf.has(i)"
|
|
935
|
-
>
|
|
936
|
-
<input type="checkbox" class="h-3.5 w-3.5 accent-indigo-600" [checked]="selectedAnyOf.has(i)" (change)="toggleAnyOf(i)" />
|
|
950
|
+
<div class="jsm-anyof-options">
|
|
951
|
+
<label *ngFor="let option of schema.anyOf; let i = index"
|
|
952
|
+
class="jsm-anyof-option" [class.jsm-anyof-option--active]="selectedAnyOf.has(i)">
|
|
953
|
+
<input type="checkbox" class="sr-only" [checked]="selectedAnyOf.has(i)" (change)="toggleAnyOf(i)" />
|
|
937
954
|
{{ option.title || ('Option ' + (i + 1)) }}
|
|
938
955
|
</label>
|
|
939
956
|
</div>
|
|
940
|
-
<div class="
|
|
957
|
+
<div class="jsm-combinator-body" *ngIf="activeVariant">
|
|
941
958
|
<jsm-schema-node [schema]="activeVariant" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
942
959
|
[path]="path" [errorsMap]="errorsMap" [label]="label" [required]="required"
|
|
943
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
960
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
944
961
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
945
962
|
</div>
|
|
946
963
|
</div>
|
|
947
964
|
|
|
948
|
-
<!--
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
<div *ngSwitchCase="'allOf'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm overflow-hidden">
|
|
952
|
-
<div class="flex items-start justify-between px-4 py-3 bg-slate-50 dark:bg-slate-800/60 border-b border-slate-200 dark:border-slate-700">
|
|
965
|
+
<!-- ═══ allOf ═══ -->
|
|
966
|
+
<div *ngSwitchCase="'allOf'" class="jsm-combinator">
|
|
967
|
+
<div class="jsm-combinator-header">
|
|
953
968
|
<div>
|
|
954
|
-
<p class="
|
|
955
|
-
<p *ngIf="schema.description" class="
|
|
969
|
+
<p class="jsm-combinator-title">{{ schema.title || label }}</p>
|
|
970
|
+
<p *ngIf="schema.description" class="jsm-combinator-hint">{{ schema.description }}</p>
|
|
956
971
|
</div>
|
|
957
|
-
<span class="
|
|
972
|
+
<span class="jsm-combinator-badge jsm-badge--allof">allOf</span>
|
|
958
973
|
</div>
|
|
959
|
-
<div class="
|
|
960
|
-
<div *ngFor="let subSchema of mergedAllOf; let i = index" class="
|
|
974
|
+
<div class="jsm-combinator-body">
|
|
975
|
+
<div *ngFor="let subSchema of mergedAllOf; let i = index" class="jsm-allof-section">
|
|
961
976
|
<jsm-schema-node [schema]="subSchema" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
962
977
|
[path]="path" [errorsMap]="errorsMap" [label]="subSchema.title || ('Section ' + (i + 1))" [required]="required"
|
|
963
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
978
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
964
979
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
965
980
|
</div>
|
|
966
981
|
</div>
|
|
967
982
|
</div>
|
|
968
983
|
|
|
969
|
-
<!--
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
o "complessi" (object/array/oneOf/anyOf/allOf).
|
|
974
|
-
- I semplici vanno in griglia 2 colonne (sm:grid-cols-2).
|
|
975
|
-
- I complessi vanno sempre in colonna piena (col-span-2).
|
|
976
|
-
═══════════════════════════════════════════════════════════ -->
|
|
977
|
-
<fieldset *ngSwitchCase="'object'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm p-4 transition-shadow focus-within:border-indigo-300 dark:focus-within:border-indigo-600 focus-within:ring-2 focus-within:ring-indigo-100 dark:focus-within:ring-indigo-900/40">
|
|
978
|
-
<legend class="px-2 text-sm font-bold text-slate-800 dark:text-slate-200">{{ schema.title || label }}</legend>
|
|
979
|
-
|
|
980
|
-
<p *ngIf="schema.description" class="text-xs text-slate-500 dark:text-slate-400 mb-3 mt-1">{{ schema.description }}</p>
|
|
984
|
+
<!-- ═══ object ═══ -->
|
|
985
|
+
<fieldset *ngSwitchCase="'object'" class="jsm-fieldset">
|
|
986
|
+
<legend class="jsm-legend">{{ schema.title || label }}</legend>
|
|
987
|
+
<p *ngIf="schema.description" class="jsm-field-hint" style="margin-bottom:.75rem;margin-top:.25rem;">{{ schema.description }}</p>
|
|
981
988
|
|
|
982
|
-
<div *ngIf="metaBadges.length" class="
|
|
983
|
-
<span *ngFor="let badge of metaBadges"
|
|
984
|
-
class="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
985
|
-
[ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
989
|
+
<div *ngIf="metaBadges.length" class="jsm-badge-row" style="margin-bottom:.75rem;">
|
|
990
|
+
<span *ngFor="let badge of metaBadges" class="jsm-badge" [ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
986
991
|
</div>
|
|
987
992
|
|
|
988
|
-
|
|
989
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4" [formGroup]="controlAsGroup">
|
|
993
|
+
<div class="jsm-obj-grid" [formGroup]="controlAsGroup">
|
|
990
994
|
<ng-container *ngFor="let key of simpleKeys">
|
|
991
|
-
<div
|
|
992
|
-
<div *ngIf="isDynamicKey(key)"
|
|
993
|
-
class="
|
|
994
|
-
<
|
|
995
|
-
<button type="button"
|
|
996
|
-
class="rounded px-1.5 py-0.5 text-xs font-semibold text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
997
|
-
(click)="removeDynamicKey(key)">Remove</button>
|
|
995
|
+
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
996
|
+
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
997
|
+
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
998
|
+
<button type="button" class="jsm-btn-danger" (click)="removeDynamicKey(key)">Remove</button>
|
|
998
999
|
</div>
|
|
999
|
-
<jsm-schema-node
|
|
1000
|
-
[
|
|
1001
|
-
[
|
|
1002
|
-
|
|
1003
|
-
[controlKey]="key"
|
|
1004
|
-
[path]="pathForChild(key)"
|
|
1005
|
-
[errorsMap]="errorsMap"
|
|
1006
|
-
[label]="key"
|
|
1007
|
-
[required]="isRequired(key)"
|
|
1008
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1009
|
-
(controlReplaced)="controlReplaced.emit($event)">
|
|
1010
|
-
</jsm-schema-node>
|
|
1000
|
+
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1001
|
+
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
1002
|
+
[required]="isRequired(key)" [allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1003
|
+
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1011
1004
|
</div>
|
|
1012
1005
|
</ng-container>
|
|
1013
1006
|
</div>
|
|
1014
1007
|
|
|
1015
|
-
|
|
1016
|
-
<div class="space-y-4 mt-4" *ngIf="complexKeys.length > 0" [formGroup]="controlAsGroup">
|
|
1008
|
+
<div class="jsm-obj-complex" *ngIf="complexKeys.length > 0" [formGroup]="controlAsGroup">
|
|
1017
1009
|
<ng-container *ngFor="let key of complexKeys">
|
|
1018
|
-
<div
|
|
1019
|
-
<div *ngIf="isDynamicKey(key)"
|
|
1020
|
-
class="
|
|
1021
|
-
<
|
|
1022
|
-
<button type="button"
|
|
1023
|
-
class="rounded px-1.5 py-0.5 text-xs font-semibold text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
1024
|
-
(click)="removeDynamicKey(key)">Remove</button>
|
|
1010
|
+
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1011
|
+
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1012
|
+
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1013
|
+
<button type="button" class="jsm-btn-danger" (click)="removeDynamicKey(key)">Remove</button>
|
|
1025
1014
|
</div>
|
|
1026
|
-
<jsm-schema-node
|
|
1027
|
-
[
|
|
1028
|
-
[
|
|
1029
|
-
|
|
1030
|
-
[controlKey]="key"
|
|
1031
|
-
[path]="pathForChild(key)"
|
|
1032
|
-
[errorsMap]="errorsMap"
|
|
1033
|
-
[label]="key"
|
|
1034
|
-
[required]="isRequired(key)"
|
|
1035
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1036
|
-
(controlReplaced)="controlReplaced.emit($event)">
|
|
1037
|
-
</jsm-schema-node>
|
|
1015
|
+
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1016
|
+
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
1017
|
+
[required]="isRequired(key)" [allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1018
|
+
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1038
1019
|
</div>
|
|
1039
1020
|
</ng-container>
|
|
1040
1021
|
</div>
|
|
1041
1022
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
<
|
|
1045
|
-
|
|
1046
|
-
<
|
|
1047
|
-
class="flex-1 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 placeholder:text-slate-400 dark:placeholder:text-slate-500 px-3 py-1.5 text-sm shadow-sm outline-none transition hover:border-slate-400 dark:hover:border-slate-500 focus:border-indigo-400 focus:ring-2 focus:ring-indigo-100 dark:focus:ring-indigo-900/40"
|
|
1048
|
-
[(ngModel)]="newPropertyKey" placeholder="propertyName" />
|
|
1049
|
-
<button type="button"
|
|
1050
|
-
class="rounded-lg bg-indigo-600 px-3 py-1.5 text-sm font-semibold text-white shadow-sm transition hover:bg-indigo-700 active:scale-95"
|
|
1051
|
-
(click)="addDynamicProperty()">Add</button>
|
|
1023
|
+
<div *ngIf="canAddProperty" class="jsm-add-prop">
|
|
1024
|
+
<p class="jsm-add-prop-label">Add property</p>
|
|
1025
|
+
<div class="jsm-add-prop-row">
|
|
1026
|
+
<input class="jsm-input jsm-input--sm" style="flex:1;" [(ngModel)]="newPropertyKey" placeholder="propertyName" />
|
|
1027
|
+
<button type="button" class="jsm-btn-primary" (click)="addDynamicProperty()">Add</button>
|
|
1052
1028
|
</div>
|
|
1053
|
-
<p *ngIf="propertyError" class="
|
|
1054
|
-
|
|
1055
|
-
<svg class="w-3.5 h-3.5 shrink-0" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1029
|
+
<p *ngIf="propertyError" class="jsm-error-msg">
|
|
1030
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1056
1031
|
{{ propertyError }}
|
|
1057
1032
|
</p>
|
|
1058
1033
|
</div>
|
|
1059
1034
|
|
|
1060
|
-
<div *ngIf="errorsForPath.length" class="
|
|
1061
|
-
<p *ngFor="let error of errorsForPath" class="
|
|
1062
|
-
<svg class="
|
|
1035
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list" style="margin-top:.75rem;">
|
|
1036
|
+
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1037
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1063
1038
|
{{ error }}
|
|
1064
1039
|
</p>
|
|
1065
1040
|
</div>
|
|
1066
1041
|
</fieldset>
|
|
1067
1042
|
|
|
1068
|
-
<!--
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
<div *ngSwitchCase="'array'" class="space-y-3">
|
|
1072
|
-
<div class="flex items-start justify-between gap-2">
|
|
1043
|
+
<!-- ═══ array ═══ -->
|
|
1044
|
+
<div *ngSwitchCase="'array'" class="jsm-array-block">
|
|
1045
|
+
<div class="jsm-array-header">
|
|
1073
1046
|
<div>
|
|
1074
|
-
<p class="
|
|
1075
|
-
{{ schema.title || label }}<span *ngIf="required"
|
|
1047
|
+
<p class="jsm-array-title">
|
|
1048
|
+
{{ schema.title || label }}<span *ngIf="required" style="color:#ef4444;margin-left:.125rem;">*</span>
|
|
1076
1049
|
</p>
|
|
1077
|
-
<p *ngIf="schema.description" class="
|
|
1050
|
+
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1078
1051
|
</div>
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
class="shrink-0 flex items-center gap-1 rounded-lg bg-indigo-600 px-3 py-1.5 text-xs font-semibold text-white shadow-sm transition hover:bg-indigo-700 active:scale-95 disabled:opacity-40 disabled:cursor-not-allowed"
|
|
1082
|
-
(click)="addArrayItem()" [disabled]="!canAddArrayItem">
|
|
1083
|
-
<svg class="w-3.5 h-3.5" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1052
|
+
<button type="button" class="jsm-btn-primary" (click)="addArrayItem()" [disabled]="!canAddArrayItem">
|
|
1053
|
+
<svg style="width:.875rem;height:.875rem;flex-shrink:0;" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1084
1054
|
Add item
|
|
1085
1055
|
</button>
|
|
1086
1056
|
</div>
|
|
1087
1057
|
|
|
1088
|
-
<div *ngIf="effectiveSchema.contains" class="
|
|
1058
|
+
<div *ngIf="effectiveSchema.contains" class="jsm-contains-hint">
|
|
1089
1059
|
Must contain matching item(s)
|
|
1090
1060
|
<span *ngIf="effectiveSchema.minContains"> · min {{ effectiveSchema.minContains }}</span>
|
|
1091
1061
|
<span *ngIf="effectiveSchema.maxContains"> · max {{ effectiveSchema.maxContains }}</span>
|
|
1092
1062
|
</div>
|
|
1093
1063
|
|
|
1094
|
-
<div *ngIf="metaBadges.length" class="
|
|
1095
|
-
<span *ngFor="let badge of metaBadges"
|
|
1096
|
-
class="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
1097
|
-
[ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1064
|
+
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
1065
|
+
<span *ngFor="let badge of metaBadges" class="jsm-badge" [ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1098
1066
|
</div>
|
|
1099
1067
|
|
|
1100
|
-
<div class="
|
|
1101
|
-
<div *ngFor="let item of arrayControls; let i = index"
|
|
1102
|
-
class="
|
|
1103
|
-
|
|
1104
|
-
<
|
|
1105
|
-
<button type="button"
|
|
1106
|
-
class="rounded-md border border-red-200 dark:border-red-800 px-2 py-0.5 text-xs font-semibold text-red-600 dark:text-red-400 transition hover:bg-red-50 dark:hover:bg-red-900/20"
|
|
1107
|
-
(click)="removeArrayItem(i)">Remove</button>
|
|
1068
|
+
<div class="jsm-array-items" *ngIf="arrayControls.length > 0; else emptyArray">
|
|
1069
|
+
<div *ngFor="let item of arrayControls; let i = index" class="jsm-array-item">
|
|
1070
|
+
<div class="jsm-array-item-header">
|
|
1071
|
+
<span class="jsm-array-index">{{ i + 1 }}</span>
|
|
1072
|
+
<button type="button" class="jsm-btn-danger" (click)="removeArrayItem(i)">Remove</button>
|
|
1108
1073
|
</div>
|
|
1109
1074
|
<jsm-schema-node [schema]="schemaForIndex(i)" [control]="item" [parent]="controlAsArray"
|
|
1110
1075
|
[controlKey]="i" [path]="pathForChild(i)" [errorsMap]="errorsMap" [label]="label + ' item'"
|
|
1111
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1076
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1112
1077
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1113
1078
|
</div>
|
|
1114
1079
|
</div>
|
|
1115
1080
|
|
|
1116
1081
|
<ng-template #emptyArray>
|
|
1117
|
-
<div class="
|
|
1118
|
-
No items yet — click "Add item" to start.
|
|
1119
|
-
</div>
|
|
1082
|
+
<div class="jsm-empty-array">No items yet — click "Add item" to start.</div>
|
|
1120
1083
|
</ng-template>
|
|
1121
1084
|
|
|
1122
|
-
<div *ngIf="errorsForPath.length" class="
|
|
1123
|
-
<p *ngFor="let error of errorsForPath" class="
|
|
1124
|
-
<svg class="
|
|
1085
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list">
|
|
1086
|
+
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1087
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1125
1088
|
{{ error }}
|
|
1126
1089
|
</p>
|
|
1127
1090
|
</div>
|
|
1128
1091
|
</div>
|
|
1129
1092
|
|
|
1130
|
-
<!--
|
|
1131
|
-
|
|
1132
|
-
Icona errore solo nei messaggi di validazione.
|
|
1133
|
-
Icona chevron nel select: funzionale (indica dropdown).
|
|
1134
|
-
═══════════════════════════════════════════════════════════ -->
|
|
1135
|
-
<div *ngSwitchDefault class="space-y-1.5">
|
|
1093
|
+
<!-- ═══ primitive ═══ -->
|
|
1094
|
+
<div *ngSwitchDefault class="jsm-field">
|
|
1136
1095
|
<ng-container *ngIf="inputKind !== 'checkbox'">
|
|
1137
|
-
<label class="
|
|
1138
|
-
{{ schema.title || label }}<span *ngIf="required" class="
|
|
1096
|
+
<label class="jsm-field-label">
|
|
1097
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1139
1098
|
</label>
|
|
1140
|
-
<p *ngIf="schema.description" class="
|
|
1099
|
+
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1141
1100
|
</ng-container>
|
|
1142
1101
|
|
|
1143
|
-
<div *ngIf="metaBadges.length" class="
|
|
1144
|
-
<span *ngFor="let badge of metaBadges"
|
|
1145
|
-
class="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
1146
|
-
[ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1102
|
+
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
1103
|
+
<span *ngFor="let badge of metaBadges" class="jsm-badge" [ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1147
1104
|
</div>
|
|
1148
1105
|
|
|
1149
|
-
<ng-container
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
[class.border-slate-300]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1154
|
-
[class.dark:border-slate-600]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1155
|
-
[class.focus:border-indigo-400]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1156
|
-
[class.focus:ring-indigo-100]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1157
|
-
[class.dark:focus:ring-indigo-900/40]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1158
|
-
[class.border-red-300]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1159
|
-
[class.dark:border-red-700]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1160
|
-
[class.bg-red-50]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1161
|
-
[class.dark:bg-red-900/20]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1162
|
-
[class.focus:border-red-400]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1163
|
-
[class.focus:ring-red-100]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1164
|
-
[attr.type]="inputType"
|
|
1165
|
-
[attr.placeholder]="schema.title || label"
|
|
1106
|
+
<ng-container>
|
|
1107
|
+
<input *ngIf="inputKind === 'text'" class="jsm-input"
|
|
1108
|
+
[class.jsm-input--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1109
|
+
[attr.type]="inputType" [attr.placeholder]="schema.title || label"
|
|
1166
1110
|
[formControl]="controlAsFormControl"
|
|
1167
|
-
|
|
1111
|
+
(blur)="onBlur()" />
|
|
1168
1112
|
|
|
1169
|
-
<textarea *
|
|
1170
|
-
class="
|
|
1171
|
-
[class.border-slate-300]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1172
|
-
[class.dark:border-slate-600]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1173
|
-
[class.focus:border-indigo-400]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1174
|
-
[class.focus:ring-indigo-100]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1175
|
-
[class.dark:focus:ring-indigo-900/40]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1176
|
-
[class.border-red-300]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1177
|
-
[class.dark:border-red-700]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1178
|
-
[class.bg-red-50]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1179
|
-
[class.dark:bg-red-900/20]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1180
|
-
[class.focus:border-red-400]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1181
|
-
[class.focus:ring-red-100]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1113
|
+
<textarea *ngIf="inputKind === 'textarea'" rows="4" class="jsm-textarea"
|
|
1114
|
+
[class.jsm-textarea--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1182
1115
|
[attr.placeholder]="schema.title || label"
|
|
1183
1116
|
[formControl]="controlAsFormControl"
|
|
1184
|
-
|
|
1117
|
+
(blur)="onBlur()"></textarea>
|
|
1185
1118
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
[class.dark:border-red-700]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1192
|
-
[class.bg-red-50]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1193
|
-
[class.dark:bg-red-900/20]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1194
|
-
[formControl]="controlAsFormControl">
|
|
1119
|
+
<div *ngIf="inputKind === 'select'" class="jsm-select-wrap">
|
|
1120
|
+
<select class="jsm-select"
|
|
1121
|
+
[class.jsm-select--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1122
|
+
[formControl]="controlAsFormControl"
|
|
1123
|
+
(blur)="onBlur()">
|
|
1195
1124
|
<option *ngFor="let option of effectiveSchema.enum" [ngValue]="option">{{ option }}</option>
|
|
1196
1125
|
</select>
|
|
1197
|
-
<svg class="
|
|
1198
|
-
viewBox="0 0 16 16" fill="none">
|
|
1126
|
+
<svg class="jsm-select-chevron" viewBox="0 0 16 16" fill="none">
|
|
1199
1127
|
<path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1200
1128
|
</svg>
|
|
1201
1129
|
</div>
|
|
1202
1130
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
<span class="jsm-toggle-track" [class.jsm-toggle-on]="controlAsFormControl.value">
|
|
1131
|
+
<label *ngIf="inputKind === 'checkbox'" class="jsm-toggle-label">
|
|
1132
|
+
<span class="jsm-toggle-track" [class.jsm-on]="controlAsFormControl.value">
|
|
1206
1133
|
<input type="checkbox" class="sr-only" [formControl]="controlAsFormControl" />
|
|
1207
1134
|
<span class="jsm-toggle-thumb"></span>
|
|
1208
1135
|
</span>
|
|
1209
|
-
<span class="
|
|
1210
|
-
{{ schema.title || label }}<span *ngIf="required" class="
|
|
1136
|
+
<span class="jsm-toggle-text">
|
|
1137
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1211
1138
|
</span>
|
|
1212
1139
|
</label>
|
|
1213
|
-
|
|
1214
1140
|
</ng-container>
|
|
1215
1141
|
|
|
1216
|
-
<p *ngIf="inputKind === 'checkbox' && schema.description" class="
|
|
1217
|
-
|
|
1218
|
-
<p *ngIf="effectiveSchema.
|
|
1219
|
-
e.g. {{ effectiveSchema.examples?.[0] }}
|
|
1220
|
-
</p>
|
|
1221
|
-
|
|
1222
|
-
<p *ngIf="effectiveSchema.contentMediaType" class="text-[11px] text-slate-400 dark:text-slate-500">
|
|
1142
|
+
<p *ngIf="inputKind === 'checkbox' && schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1143
|
+
<p *ngIf="effectiveSchema.examples?.length" class="jsm-example">e.g. {{ effectiveSchema.examples?.[0] }}</p>
|
|
1144
|
+
<p *ngIf="effectiveSchema.contentMediaType" class="jsm-example">
|
|
1223
1145
|
{{ effectiveSchema.contentMediaType }}<span *ngIf="effectiveSchema.contentEncoding"> ({{ effectiveSchema.contentEncoding }})</span>
|
|
1224
1146
|
</p>
|
|
1225
1147
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
<svg class="w-3.5 h-3.5 shrink-0" viewBox="0 0 16 16" fill="none">
|
|
1148
|
+
<div *ngIf="allErrors.length && (controlAsFormControl.dirty || isTouched || showErrors)" class="jsm-error-list">
|
|
1149
|
+
<p *ngFor="let error of allErrors" class="jsm-error-msg">
|
|
1150
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none">
|
|
1230
1151
|
<circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/>
|
|
1231
1152
|
<path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
1232
1153
|
</svg>
|
|
@@ -1236,366 +1157,247 @@ class JsonSchemaNodeComponent {
|
|
|
1236
1157
|
</div>
|
|
1237
1158
|
|
|
1238
1159
|
</ng-container>
|
|
1239
|
-
`, isInline: true, styles: [".jsm-toggle-track{position:relative;display:inline-flex;align-items:center;width:2.25rem;height:1.25rem;border-radius:9999px;flex-shrink:0;transition:background-color .2s;background-color:#cbd5e1}.jsm-toggle-track.jsm-toggle-on{background-color:#4f46e5}.dark .jsm-toggle-track:not(.jsm-toggle-on){background-color:#475569}.jsm-toggle-thumb{display:inline-block;width:1rem;height:1rem;border-radius:9999px;background:#fff;box-shadow:0 1px 3px #0003;transform:translate(.125rem);transition:transform .2s}.jsm-toggle-track.jsm-toggle-on .jsm-toggle-thumb{transform:translate(1.125rem)}\n"], dependencies: [{ kind: "component", type: JsonSchemaNodeComponent, selector: "jsm-schema-node", inputs: ["schema", "control", "label", "required", "path", "errorsMap", "parent", "controlKey", "allowAdditionalProperties"], outputs: ["controlReplaced"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i3.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1160
|
+
`, isInline: true, styles: [".jsm-field{display:flex;flex-direction:column;gap:.375rem}.jsm-field-label{display:block;font-size:.8125rem;font-weight:600;color:#374151}.jsm-field-hint{font-size:.75rem;color:#6b7280;margin:0;line-height:1.4}.jsm-required{color:#ef4444;margin-left:.125rem}.jsm-example{font-size:.6875rem;color:#9ca3af}.jsm-input,.jsm-textarea,.jsm-select{width:100%;border-radius:.5rem;border:1.5px solid #d1d5db;background:Canvas;padding:.5rem .75rem;font-size:.875rem;color:CanvasText;outline:none;box-shadow:0 1px 2px #0000000a;transition:border-color .15s,box-shadow .15s;font-family:inherit;box-sizing:border-box}.jsm-input:hover,.jsm-textarea:hover,.jsm-select:hover{border-color:#9ca3af}.jsm-input:focus,.jsm-textarea:focus,.jsm-select:focus{border-color:#6366f1;box-shadow:0 0 0 3px #6366f126}.jsm-input--error,.jsm-textarea--error,.jsm-select--error{border-color:#f87171!important;background:#fff5f5}.jsm-input--error:focus,.jsm-textarea--error:focus,.jsm-select--error:focus{box-shadow:0 0 0 3px #f8717133!important}.jsm-textarea{resize:vertical;min-height:6rem}.jsm-select-wrap{position:relative}.jsm-select{appearance:none;padding-right:2.25rem;cursor:pointer}.jsm-select-chevron{position:absolute;right:.625rem;top:50%;transform:translateY(-50%);width:1rem;height:1rem;color:#9ca3af;pointer-events:none}.jsm-toggle-label{display:inline-flex;align-items:center;gap:.625rem;cursor:pointer;-webkit-user-select:none;user-select:none}.jsm-toggle-track{position:relative;display:inline-flex;align-items:center;width:2.25rem;height:1.25rem;border-radius:9999px;flex-shrink:0;background:#d1d5db;transition:background .2s}.jsm-toggle-track.jsm-on{background:#4f46e5}.jsm-toggle-thumb{display:inline-block;width:1rem;height:1rem;border-radius:9999px;background:#fff;box-shadow:0 1px 3px #0003;transform:translate(.125rem);transition:transform .2s}.jsm-toggle-track.jsm-on .jsm-toggle-thumb{transform:translate(1.125rem)}.jsm-toggle-text{font-size:.875rem;font-weight:500;color:#374151}.jsm-btn-primary{display:inline-flex;align-items:center;gap:.25rem;padding:.375rem .75rem;border-radius:.5rem;font-size:.8125rem;font-weight:600;background:#4f46e5;color:#fff;border:none;cursor:pointer;box-shadow:0 1px 2px #4f46e54d;transition:background .15s,transform .1s,box-shadow .15s;white-space:nowrap;font-family:inherit}.jsm-btn-primary:hover{background:#4338ca;transform:translateY(-1px);box-shadow:0 3px 8px #4f46e54d}.jsm-btn-primary:active{transform:translateY(0)}.jsm-btn-primary:disabled{opacity:.45;cursor:not-allowed;transform:none}.jsm-btn-danger{display:inline-flex;align-items:center;gap:.25rem;padding:.25rem .5rem;border-radius:.375rem;font-size:.75rem;font-weight:600;background:transparent;color:#dc2626;border:1.5px solid #fca5a5;cursor:pointer;transition:background .15s,border-color .15s;font-family:inherit}.jsm-btn-danger:hover{background:#fee2e2;border-color:#f87171}.jsm-error-list{display:flex;flex-direction:column;gap:.25rem;margin-top:.25rem}.jsm-error-msg{display:flex;align-items:center;gap:.375rem;font-size:.75rem;color:#dc2626;font-weight:500}.jsm-error-icon{width:.875rem;height:.875rem;flex-shrink:0}.jsm-badge-row{display:flex;flex-wrap:wrap;gap:.375rem}.jsm-badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .5rem;font-size:.6875rem;font-weight:600;letter-spacing:.02em;text-transform:uppercase}.jsm-badge--deprecated{background:#fef3c7;color:#92400e}.jsm-badge--readonly{background:#f1f5f9;color:#475569}.jsm-badge--writeonly{background:#dbeafe;color:#1e40af}.jsm-badge--not{background:#fee2e2;color:#991b1b}.jsm-badge--nullable{background:#f3f4f6;color:#6b7280}.jsm-fieldset{border:1.5px solid #e5e7eb;border-radius:.875rem;padding:1.25rem;background:transparent;box-shadow:0 1px 3px #0000000f;transition:box-shadow .2s;box-sizing:border-box}.jsm-fieldset:focus-within{border-color:#c7d2fe;box-shadow:0 0 0 3px #6366f114,0 1px 3px #0000000f}.jsm-legend{display:inline-flex;align-items:center;gap:.375rem;padding:0 .5rem;font-size:.875rem;font-weight:700;color:#1f2937}.jsm-obj-grid{display:grid;grid-template-columns:1fr;gap:1rem}@media (min-width:640px){.jsm-obj-grid{grid-template-columns:repeat(2,1fr)}}.jsm-obj-complex{display:flex;flex-direction:column;gap:1rem;margin-top:1rem}.jsm-dynamic-key-header{display:flex;align-items:center;justify-content:space-between;padding:.25rem .5rem;background:#f9fafb;border-radius:.375rem;border:1px dashed #d1d5db;margin-bottom:.25rem}.jsm-dynamic-key-label{font-size:.75rem;font-weight:600;color:#6b7280;font-family:monospace}.jsm-add-prop{margin-top:1rem;padding:.875rem;background:#f9fafb;border-radius:.625rem;border:1.5px dashed #d1d5db;display:flex;flex-direction:column;gap:.5rem}.jsm-add-prop-label{font-size:.75rem;font-weight:600;color:#6b7280;text-transform:uppercase;letter-spacing:.04em}.jsm-add-prop-row{display:flex;gap:.5rem;align-items:center}.jsm-input--sm{padding:.375rem .625rem;font-size:.8125rem}.jsm-array-block{display:flex;flex-direction:column;gap:.75rem}.jsm-array-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem}.jsm-array-title{font-size:.875rem;font-weight:700;color:#1f2937;display:flex;align-items:center;gap:.375rem}.jsm-array-items{display:flex;flex-direction:column;gap:.75rem}.jsm-array-item{border:1.5px solid #e5e7eb;border-radius:.75rem;padding:.875rem;background:transparent;box-shadow:0 1px 2px #0000000a;transition:border-color .15s,box-shadow .15s}.jsm-array-item:focus-within{border-color:#c7d2fe;box-shadow:0 0 0 3px #6366f114}.jsm-array-item-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:.75rem}.jsm-array-index{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:9999px;background:#eef2ff;color:#4f46e5;font-size:.6875rem;font-weight:700}.jsm-empty-array{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding:2rem 1rem;border:1.5px dashed #e5e7eb;border-radius:.75rem;color:#9ca3af;font-size:.8125rem;text-align:center}.jsm-contains-hint{display:flex;align-items:center;gap:.375rem;font-size:.75rem;color:#6366f1;background:#eef2ff;border-radius:.375rem;padding:.375rem .625rem}.jsm-combinator{border:1.5px solid #e5e7eb;border-radius:.875rem;overflow:hidden;background:transparent;box-shadow:0 1px 3px #0000000f}.jsm-combinator-header{display:flex;align-items:flex-start;justify-content:space-between;padding:.875rem 1rem;background:#00000008;border-bottom:1.5px solid #e5e7eb}.jsm-combinator-title{font-size:.875rem;font-weight:700;color:#1f2937}.jsm-combinator-body{padding:1rem}.jsm-combinator-hint{font-size:.75rem;color:#6b7280;margin:.25rem 0 0}.jsm-oneof-tabs{display:flex;overflow-x:auto;border-bottom:1.5px solid #e5e7eb}.jsm-tab{padding:.5rem 1rem;font-size:.8125rem;font-weight:500;color:#6b7280;border:none;background:transparent;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1.5px;transition:color .15s,border-color .15s;white-space:nowrap;font-family:inherit}.jsm-tab:hover{color:#4f46e5}.jsm-tab--active{color:#4f46e5;border-bottom-color:#4f46e5;font-weight:600}.jsm-anyof-options{display:flex;flex-wrap:wrap;gap:.5rem;padding:.75rem 1rem;border-bottom:1.5px solid #e5e7eb}.jsm-anyof-option{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border-radius:9999px;border:1.5px solid #e5e7eb;font-size:.8125rem;font-weight:500;color:#6b7280;cursor:pointer;transition:all .15s;background:transparent}.jsm-anyof-option:hover{border-color:#a5b4fc;color:#4f46e5}.jsm-anyof-option--active{border-color:#6366f1;background:#eef2ff;color:#4f46e5}.jsm-allof-section{border-left:3px solid #e0e7ff;padding-left:1rem}.jsm-combinator-badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .5rem;font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;flex-shrink:0;margin-left:.75rem}.jsm-badge--oneof{background:#dbeafe;color:#1e40af}.jsm-badge--anyof{background:#ede9fe;color:#5b21b6}.jsm-badge--allof{background:#ccfbf1;color:#065f46}.dark .jsm-field-label{color:#d1d5db}.dark .jsm-field-hint{color:#9ca3af}.dark .jsm-toggle-track{background:#475569}.dark .jsm-toggle-track.jsm-on{background:#4f46e5}.dark .jsm-toggle-text{color:#d1d5db}.dark .jsm-input,.dark .jsm-textarea,.dark .jsm-select{border-color:#475569;color:#f1f5f9}.dark .jsm-input:focus,.dark .jsm-textarea:focus,.dark .jsm-select:focus{border-color:#6366f1;box-shadow:0 0 0 3px #6366f133}.dark .jsm-input--error,.dark .jsm-textarea--error,.dark .jsm-select--error{border-color:#f87171!important;background:#f871711a}.dark .jsm-fieldset{border-color:#334155}.dark .jsm-fieldset:focus-within{border-color:#6366f1}.dark .jsm-legend{color:#f1f5f9}.dark .jsm-combinator{border-color:#334155}.dark .jsm-combinator-header{background:#ffffff0a;border-color:#334155}.dark .jsm-combinator-title{color:#f1f5f9}.dark .jsm-oneof-tabs{border-color:#334155}.dark .jsm-tab{color:#94a3b8}.dark .jsm-tab--active{color:#818cf8;border-bottom-color:#818cf8}.dark .jsm-anyof-options{border-color:#334155}.dark .jsm-anyof-option{border-color:#334155;color:#94a3b8;background:#0f172a}.dark .jsm-anyof-option--active{border-color:#6366f1;background:#6366f126;color:#818cf8}.dark .jsm-allof-section{border-left-color:#3730a3}.dark .jsm-array-item{border-color:#334155}.dark .jsm-array-item:focus-within{border-color:#6366f1}.dark .jsm-array-index{background:#6366f133;color:#818cf8}.dark .jsm-empty-array{border-color:#334155;color:#64748b}.dark .jsm-contains-hint{background:#6366f126;color:#818cf8}.dark .jsm-add-prop{background:#1e293b66;border-color:#475569}.dark .jsm-add-prop-label{color:#64748b}.dark .jsm-dynamic-key-header{background:#1e293b80;border-color:#475569}.dark .jsm-dynamic-key-label{color:#94a3b8}.dark .jsm-error-msg{color:#f87171}.dark .jsm-array-title{color:#f1f5f9}.dark .jsm-badge--deprecated{background:#d9770633;color:#fbbf24}.dark .jsm-badge--readonly{background:#1e293b;color:#94a3b8}.dark .jsm-badge--writeonly{background:#2563eb33;color:#60a5fa}.dark .jsm-badge--not{background:#dc262633;color:#f87171}.dark .jsm-badge--nullable{background:#1e293b;color:#94a3b8}.dark .jsm-select-chevron{color:#64748b}\n"], dependencies: [{ kind: "component", type: JsonSchemaNodeComponent, selector: "jsm-schema-node", inputs: ["schema", "control", "label", "required", "path", "errorsMap", "parent", "controlKey", "allowAdditionalProperties", "showErrors"], outputs: ["controlReplaced"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i3.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1240
1161
|
}
|
|
1241
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1162
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaNodeComponent, decorators: [{
|
|
1242
1163
|
type: Component,
|
|
1243
1164
|
args: [{ selector: 'jsm-schema-node', standalone: true, imports: [CommonModule, FormsModule, ReactiveFormsModule], encapsulation: ViewEncapsulation.None, template: `
|
|
1244
1165
|
<ng-container [ngSwitch]="nodeKind">
|
|
1245
1166
|
|
|
1246
|
-
<!--
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
<div *ngSwitchCase="'oneOf'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm overflow-hidden">
|
|
1250
|
-
<div class="flex items-start justify-between px-4 py-3 bg-slate-50 dark:bg-slate-800/60 border-b border-slate-200 dark:border-slate-700">
|
|
1167
|
+
<!-- ═══ oneOf ═══ -->
|
|
1168
|
+
<div *ngSwitchCase="'oneOf'" class="jsm-combinator">
|
|
1169
|
+
<div class="jsm-combinator-header">
|
|
1251
1170
|
<div>
|
|
1252
|
-
<p class="
|
|
1253
|
-
<p *ngIf="schema.description" class="
|
|
1171
|
+
<p class="jsm-combinator-title">{{ schema.title || label }}</p>
|
|
1172
|
+
<p *ngIf="schema.description" class="jsm-combinator-hint">{{ schema.description }}</p>
|
|
1254
1173
|
</div>
|
|
1255
|
-
<span class="
|
|
1174
|
+
<span class="jsm-combinator-badge jsm-badge--oneof">oneOf</span>
|
|
1256
1175
|
</div>
|
|
1257
|
-
<div class="
|
|
1258
|
-
<button
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
[class.text-indigo-600]="selectedOneOf === i"
|
|
1264
|
-
[class.dark:text-indigo-400]="selectedOneOf === i"
|
|
1265
|
-
[class.font-semibold]="selectedOneOf === i"
|
|
1266
|
-
[class.border-transparent]="selectedOneOf !== i"
|
|
1267
|
-
[class.text-slate-500]="selectedOneOf !== i"
|
|
1268
|
-
[class.dark:text-slate-400]="selectedOneOf !== i"
|
|
1269
|
-
(click)="selectedOneOf = i; onOneOfChange()"
|
|
1270
|
-
>{{ option.title || ('Option ' + (i + 1)) }}</button>
|
|
1176
|
+
<div class="jsm-oneof-tabs">
|
|
1177
|
+
<button *ngFor="let option of schema.oneOf; let i = index" type="button"
|
|
1178
|
+
class="jsm-tab" [class.jsm-tab--active]="selectedOneOf === i"
|
|
1179
|
+
(click)="selectedOneOf = i; onOneOfChange()">
|
|
1180
|
+
{{ option.title || ('Option ' + (i + 1)) }}
|
|
1181
|
+
</button>
|
|
1271
1182
|
</div>
|
|
1272
|
-
<div class="
|
|
1183
|
+
<div class="jsm-combinator-body" *ngIf="activeVariant">
|
|
1273
1184
|
<jsm-schema-node [schema]="activeVariant" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1274
1185
|
[path]="path" [errorsMap]="errorsMap" [label]="label" [required]="required"
|
|
1275
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1186
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1276
1187
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1277
1188
|
</div>
|
|
1278
1189
|
</div>
|
|
1279
1190
|
|
|
1280
|
-
<!--
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
<div *ngSwitchCase="'anyOf'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm overflow-hidden">
|
|
1284
|
-
<div class="flex items-start justify-between px-4 py-3 bg-slate-50 dark:bg-slate-800/60 border-b border-slate-200 dark:border-slate-700">
|
|
1191
|
+
<!-- ═══ anyOf ═══ -->
|
|
1192
|
+
<div *ngSwitchCase="'anyOf'" class="jsm-combinator">
|
|
1193
|
+
<div class="jsm-combinator-header">
|
|
1285
1194
|
<div>
|
|
1286
|
-
<p class="
|
|
1287
|
-
<p *ngIf="schema.description" class="
|
|
1195
|
+
<p class="jsm-combinator-title">{{ schema.title || label }}</p>
|
|
1196
|
+
<p *ngIf="schema.description" class="jsm-combinator-hint">{{ schema.description }}</p>
|
|
1288
1197
|
</div>
|
|
1289
|
-
<span class="
|
|
1198
|
+
<span class="jsm-combinator-badge jsm-badge--anyof">anyOf</span>
|
|
1290
1199
|
</div>
|
|
1291
|
-
<div class="
|
|
1292
|
-
<label
|
|
1293
|
-
|
|
1294
|
-
class="
|
|
1295
|
-
[class.border-indigo-400]="selectedAnyOf.has(i)"
|
|
1296
|
-
[class.bg-indigo-50]="selectedAnyOf.has(i)"
|
|
1297
|
-
[class.dark:bg-indigo-900/30]="selectedAnyOf.has(i)"
|
|
1298
|
-
[class.text-indigo-700]="selectedAnyOf.has(i)"
|
|
1299
|
-
[class.dark:text-indigo-400]="selectedAnyOf.has(i)"
|
|
1300
|
-
[class.border-slate-200]="!selectedAnyOf.has(i)"
|
|
1301
|
-
[class.dark:border-slate-600]="!selectedAnyOf.has(i)"
|
|
1302
|
-
[class.text-slate-600]="!selectedAnyOf.has(i)"
|
|
1303
|
-
[class.dark:text-slate-400]="!selectedAnyOf.has(i)"
|
|
1304
|
-
>
|
|
1305
|
-
<input type="checkbox" class="h-3.5 w-3.5 accent-indigo-600" [checked]="selectedAnyOf.has(i)" (change)="toggleAnyOf(i)" />
|
|
1200
|
+
<div class="jsm-anyof-options">
|
|
1201
|
+
<label *ngFor="let option of schema.anyOf; let i = index"
|
|
1202
|
+
class="jsm-anyof-option" [class.jsm-anyof-option--active]="selectedAnyOf.has(i)">
|
|
1203
|
+
<input type="checkbox" class="sr-only" [checked]="selectedAnyOf.has(i)" (change)="toggleAnyOf(i)" />
|
|
1306
1204
|
{{ option.title || ('Option ' + (i + 1)) }}
|
|
1307
1205
|
</label>
|
|
1308
1206
|
</div>
|
|
1309
|
-
<div class="
|
|
1207
|
+
<div class="jsm-combinator-body" *ngIf="activeVariant">
|
|
1310
1208
|
<jsm-schema-node [schema]="activeVariant" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1311
1209
|
[path]="path" [errorsMap]="errorsMap" [label]="label" [required]="required"
|
|
1312
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1210
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1313
1211
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1314
1212
|
</div>
|
|
1315
1213
|
</div>
|
|
1316
1214
|
|
|
1317
|
-
<!--
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
<div *ngSwitchCase="'allOf'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm overflow-hidden">
|
|
1321
|
-
<div class="flex items-start justify-between px-4 py-3 bg-slate-50 dark:bg-slate-800/60 border-b border-slate-200 dark:border-slate-700">
|
|
1215
|
+
<!-- ═══ allOf ═══ -->
|
|
1216
|
+
<div *ngSwitchCase="'allOf'" class="jsm-combinator">
|
|
1217
|
+
<div class="jsm-combinator-header">
|
|
1322
1218
|
<div>
|
|
1323
|
-
<p class="
|
|
1324
|
-
<p *ngIf="schema.description" class="
|
|
1219
|
+
<p class="jsm-combinator-title">{{ schema.title || label }}</p>
|
|
1220
|
+
<p *ngIf="schema.description" class="jsm-combinator-hint">{{ schema.description }}</p>
|
|
1325
1221
|
</div>
|
|
1326
|
-
<span class="
|
|
1222
|
+
<span class="jsm-combinator-badge jsm-badge--allof">allOf</span>
|
|
1327
1223
|
</div>
|
|
1328
|
-
<div class="
|
|
1329
|
-
<div *ngFor="let subSchema of mergedAllOf; let i = index" class="
|
|
1224
|
+
<div class="jsm-combinator-body">
|
|
1225
|
+
<div *ngFor="let subSchema of mergedAllOf; let i = index" class="jsm-allof-section">
|
|
1330
1226
|
<jsm-schema-node [schema]="subSchema" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1331
1227
|
[path]="path" [errorsMap]="errorsMap" [label]="subSchema.title || ('Section ' + (i + 1))" [required]="required"
|
|
1332
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1228
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1333
1229
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1334
1230
|
</div>
|
|
1335
1231
|
</div>
|
|
1336
1232
|
</div>
|
|
1337
1233
|
|
|
1338
|
-
<!--
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
o "complessi" (object/array/oneOf/anyOf/allOf).
|
|
1343
|
-
- I semplici vanno in griglia 2 colonne (sm:grid-cols-2).
|
|
1344
|
-
- I complessi vanno sempre in colonna piena (col-span-2).
|
|
1345
|
-
═══════════════════════════════════════════════════════════ -->
|
|
1346
|
-
<fieldset *ngSwitchCase="'object'" class="rounded-xl border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 shadow-sm p-4 transition-shadow focus-within:border-indigo-300 dark:focus-within:border-indigo-600 focus-within:ring-2 focus-within:ring-indigo-100 dark:focus-within:ring-indigo-900/40">
|
|
1347
|
-
<legend class="px-2 text-sm font-bold text-slate-800 dark:text-slate-200">{{ schema.title || label }}</legend>
|
|
1234
|
+
<!-- ═══ object ═══ -->
|
|
1235
|
+
<fieldset *ngSwitchCase="'object'" class="jsm-fieldset">
|
|
1236
|
+
<legend class="jsm-legend">{{ schema.title || label }}</legend>
|
|
1237
|
+
<p *ngIf="schema.description" class="jsm-field-hint" style="margin-bottom:.75rem;margin-top:.25rem;">{{ schema.description }}</p>
|
|
1348
1238
|
|
|
1349
|
-
<
|
|
1350
|
-
|
|
1351
|
-
<div *ngIf="metaBadges.length" class="flex flex-wrap gap-1.5 mb-3">
|
|
1352
|
-
<span *ngFor="let badge of metaBadges"
|
|
1353
|
-
class="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
1354
|
-
[ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1239
|
+
<div *ngIf="metaBadges.length" class="jsm-badge-row" style="margin-bottom:.75rem;">
|
|
1240
|
+
<span *ngFor="let badge of metaBadges" class="jsm-badge" [ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1355
1241
|
</div>
|
|
1356
1242
|
|
|
1357
|
-
|
|
1358
|
-
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4" [formGroup]="controlAsGroup">
|
|
1243
|
+
<div class="jsm-obj-grid" [formGroup]="controlAsGroup">
|
|
1359
1244
|
<ng-container *ngFor="let key of simpleKeys">
|
|
1360
|
-
<div
|
|
1361
|
-
<div *ngIf="isDynamicKey(key)"
|
|
1362
|
-
class="
|
|
1363
|
-
<
|
|
1364
|
-
<button type="button"
|
|
1365
|
-
class="rounded px-1.5 py-0.5 text-xs font-semibold text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
1366
|
-
(click)="removeDynamicKey(key)">Remove</button>
|
|
1245
|
+
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1246
|
+
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1247
|
+
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1248
|
+
<button type="button" class="jsm-btn-danger" (click)="removeDynamicKey(key)">Remove</button>
|
|
1367
1249
|
</div>
|
|
1368
|
-
<jsm-schema-node
|
|
1369
|
-
[
|
|
1370
|
-
[
|
|
1371
|
-
|
|
1372
|
-
[controlKey]="key"
|
|
1373
|
-
[path]="pathForChild(key)"
|
|
1374
|
-
[errorsMap]="errorsMap"
|
|
1375
|
-
[label]="key"
|
|
1376
|
-
[required]="isRequired(key)"
|
|
1377
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1378
|
-
(controlReplaced)="controlReplaced.emit($event)">
|
|
1379
|
-
</jsm-schema-node>
|
|
1250
|
+
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1251
|
+
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
1252
|
+
[required]="isRequired(key)" [allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1253
|
+
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1380
1254
|
</div>
|
|
1381
1255
|
</ng-container>
|
|
1382
1256
|
</div>
|
|
1383
1257
|
|
|
1384
|
-
|
|
1385
|
-
<div class="space-y-4 mt-4" *ngIf="complexKeys.length > 0" [formGroup]="controlAsGroup">
|
|
1258
|
+
<div class="jsm-obj-complex" *ngIf="complexKeys.length > 0" [formGroup]="controlAsGroup">
|
|
1386
1259
|
<ng-container *ngFor="let key of complexKeys">
|
|
1387
|
-
<div
|
|
1388
|
-
<div *ngIf="isDynamicKey(key)"
|
|
1389
|
-
class="
|
|
1390
|
-
<
|
|
1391
|
-
<button type="button"
|
|
1392
|
-
class="rounded px-1.5 py-0.5 text-xs font-semibold text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
|
|
1393
|
-
(click)="removeDynamicKey(key)">Remove</button>
|
|
1260
|
+
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1261
|
+
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1262
|
+
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1263
|
+
<button type="button" class="jsm-btn-danger" (click)="removeDynamicKey(key)">Remove</button>
|
|
1394
1264
|
</div>
|
|
1395
|
-
<jsm-schema-node
|
|
1396
|
-
[
|
|
1397
|
-
[
|
|
1398
|
-
|
|
1399
|
-
[controlKey]="key"
|
|
1400
|
-
[path]="pathForChild(key)"
|
|
1401
|
-
[errorsMap]="errorsMap"
|
|
1402
|
-
[label]="key"
|
|
1403
|
-
[required]="isRequired(key)"
|
|
1404
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1405
|
-
(controlReplaced)="controlReplaced.emit($event)">
|
|
1406
|
-
</jsm-schema-node>
|
|
1265
|
+
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1266
|
+
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
1267
|
+
[required]="isRequired(key)" [allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1268
|
+
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1407
1269
|
</div>
|
|
1408
1270
|
</ng-container>
|
|
1409
1271
|
</div>
|
|
1410
1272
|
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
<
|
|
1414
|
-
|
|
1415
|
-
<
|
|
1416
|
-
class="flex-1 rounded-lg border border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-800 text-slate-900 dark:text-slate-100 placeholder:text-slate-400 dark:placeholder:text-slate-500 px-3 py-1.5 text-sm shadow-sm outline-none transition hover:border-slate-400 dark:hover:border-slate-500 focus:border-indigo-400 focus:ring-2 focus:ring-indigo-100 dark:focus:ring-indigo-900/40"
|
|
1417
|
-
[(ngModel)]="newPropertyKey" placeholder="propertyName" />
|
|
1418
|
-
<button type="button"
|
|
1419
|
-
class="rounded-lg bg-indigo-600 px-3 py-1.5 text-sm font-semibold text-white shadow-sm transition hover:bg-indigo-700 active:scale-95"
|
|
1420
|
-
(click)="addDynamicProperty()">Add</button>
|
|
1273
|
+
<div *ngIf="canAddProperty" class="jsm-add-prop">
|
|
1274
|
+
<p class="jsm-add-prop-label">Add property</p>
|
|
1275
|
+
<div class="jsm-add-prop-row">
|
|
1276
|
+
<input class="jsm-input jsm-input--sm" style="flex:1;" [(ngModel)]="newPropertyKey" placeholder="propertyName" />
|
|
1277
|
+
<button type="button" class="jsm-btn-primary" (click)="addDynamicProperty()">Add</button>
|
|
1421
1278
|
</div>
|
|
1422
|
-
<p *ngIf="propertyError" class="
|
|
1423
|
-
|
|
1424
|
-
<svg class="w-3.5 h-3.5 shrink-0" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1279
|
+
<p *ngIf="propertyError" class="jsm-error-msg">
|
|
1280
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1425
1281
|
{{ propertyError }}
|
|
1426
1282
|
</p>
|
|
1427
1283
|
</div>
|
|
1428
1284
|
|
|
1429
|
-
<div *ngIf="errorsForPath.length" class="
|
|
1430
|
-
<p *ngFor="let error of errorsForPath" class="
|
|
1431
|
-
<svg class="
|
|
1285
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list" style="margin-top:.75rem;">
|
|
1286
|
+
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1287
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1432
1288
|
{{ error }}
|
|
1433
1289
|
</p>
|
|
1434
1290
|
</div>
|
|
1435
1291
|
</fieldset>
|
|
1436
1292
|
|
|
1437
|
-
<!--
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
<div *ngSwitchCase="'array'" class="space-y-3">
|
|
1441
|
-
<div class="flex items-start justify-between gap-2">
|
|
1293
|
+
<!-- ═══ array ═══ -->
|
|
1294
|
+
<div *ngSwitchCase="'array'" class="jsm-array-block">
|
|
1295
|
+
<div class="jsm-array-header">
|
|
1442
1296
|
<div>
|
|
1443
|
-
<p class="
|
|
1444
|
-
{{ schema.title || label }}<span *ngIf="required"
|
|
1297
|
+
<p class="jsm-array-title">
|
|
1298
|
+
{{ schema.title || label }}<span *ngIf="required" style="color:#ef4444;margin-left:.125rem;">*</span>
|
|
1445
1299
|
</p>
|
|
1446
|
-
<p *ngIf="schema.description" class="
|
|
1300
|
+
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1447
1301
|
</div>
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
class="shrink-0 flex items-center gap-1 rounded-lg bg-indigo-600 px-3 py-1.5 text-xs font-semibold text-white shadow-sm transition hover:bg-indigo-700 active:scale-95 disabled:opacity-40 disabled:cursor-not-allowed"
|
|
1451
|
-
(click)="addArrayItem()" [disabled]="!canAddArrayItem">
|
|
1452
|
-
<svg class="w-3.5 h-3.5" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1302
|
+
<button type="button" class="jsm-btn-primary" (click)="addArrayItem()" [disabled]="!canAddArrayItem">
|
|
1303
|
+
<svg style="width:.875rem;height:.875rem;flex-shrink:0;" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1453
1304
|
Add item
|
|
1454
1305
|
</button>
|
|
1455
1306
|
</div>
|
|
1456
1307
|
|
|
1457
|
-
<div *ngIf="effectiveSchema.contains" class="
|
|
1308
|
+
<div *ngIf="effectiveSchema.contains" class="jsm-contains-hint">
|
|
1458
1309
|
Must contain matching item(s)
|
|
1459
1310
|
<span *ngIf="effectiveSchema.minContains"> · min {{ effectiveSchema.minContains }}</span>
|
|
1460
1311
|
<span *ngIf="effectiveSchema.maxContains"> · max {{ effectiveSchema.maxContains }}</span>
|
|
1461
1312
|
</div>
|
|
1462
1313
|
|
|
1463
|
-
<div *ngIf="metaBadges.length" class="
|
|
1464
|
-
<span *ngFor="let badge of metaBadges"
|
|
1465
|
-
class="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
1466
|
-
[ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1314
|
+
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
1315
|
+
<span *ngFor="let badge of metaBadges" class="jsm-badge" [ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1467
1316
|
</div>
|
|
1468
1317
|
|
|
1469
|
-
<div class="
|
|
1470
|
-
<div *ngFor="let item of arrayControls; let i = index"
|
|
1471
|
-
class="
|
|
1472
|
-
|
|
1473
|
-
<
|
|
1474
|
-
<button type="button"
|
|
1475
|
-
class="rounded-md border border-red-200 dark:border-red-800 px-2 py-0.5 text-xs font-semibold text-red-600 dark:text-red-400 transition hover:bg-red-50 dark:hover:bg-red-900/20"
|
|
1476
|
-
(click)="removeArrayItem(i)">Remove</button>
|
|
1318
|
+
<div class="jsm-array-items" *ngIf="arrayControls.length > 0; else emptyArray">
|
|
1319
|
+
<div *ngFor="let item of arrayControls; let i = index" class="jsm-array-item">
|
|
1320
|
+
<div class="jsm-array-item-header">
|
|
1321
|
+
<span class="jsm-array-index">{{ i + 1 }}</span>
|
|
1322
|
+
<button type="button" class="jsm-btn-danger" (click)="removeArrayItem(i)">Remove</button>
|
|
1477
1323
|
</div>
|
|
1478
1324
|
<jsm-schema-node [schema]="schemaForIndex(i)" [control]="item" [parent]="controlAsArray"
|
|
1479
1325
|
[controlKey]="i" [path]="pathForChild(i)" [errorsMap]="errorsMap" [label]="label + ' item'"
|
|
1480
|
-
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1326
|
+
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1481
1327
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1482
1328
|
</div>
|
|
1483
1329
|
</div>
|
|
1484
1330
|
|
|
1485
1331
|
<ng-template #emptyArray>
|
|
1486
|
-
<div class="
|
|
1487
|
-
No items yet — click "Add item" to start.
|
|
1488
|
-
</div>
|
|
1332
|
+
<div class="jsm-empty-array">No items yet — click "Add item" to start.</div>
|
|
1489
1333
|
</ng-template>
|
|
1490
1334
|
|
|
1491
|
-
<div *ngIf="errorsForPath.length" class="
|
|
1492
|
-
<p *ngFor="let error of errorsForPath" class="
|
|
1493
|
-
<svg class="
|
|
1335
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list">
|
|
1336
|
+
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1337
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/><path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1494
1338
|
{{ error }}
|
|
1495
1339
|
</p>
|
|
1496
1340
|
</div>
|
|
1497
1341
|
</div>
|
|
1498
1342
|
|
|
1499
|
-
<!--
|
|
1500
|
-
|
|
1501
|
-
Icona errore solo nei messaggi di validazione.
|
|
1502
|
-
Icona chevron nel select: funzionale (indica dropdown).
|
|
1503
|
-
═══════════════════════════════════════════════════════════ -->
|
|
1504
|
-
<div *ngSwitchDefault class="space-y-1.5">
|
|
1343
|
+
<!-- ═══ primitive ═══ -->
|
|
1344
|
+
<div *ngSwitchDefault class="jsm-field">
|
|
1505
1345
|
<ng-container *ngIf="inputKind !== 'checkbox'">
|
|
1506
|
-
<label class="
|
|
1507
|
-
{{ schema.title || label }}<span *ngIf="required" class="
|
|
1346
|
+
<label class="jsm-field-label">
|
|
1347
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1508
1348
|
</label>
|
|
1509
|
-
<p *ngIf="schema.description" class="
|
|
1349
|
+
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1510
1350
|
</ng-container>
|
|
1511
1351
|
|
|
1512
|
-
<div *ngIf="metaBadges.length" class="
|
|
1513
|
-
<span *ngFor="let badge of metaBadges"
|
|
1514
|
-
class="rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide"
|
|
1515
|
-
[ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1352
|
+
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
1353
|
+
<span *ngFor="let badge of metaBadges" class="jsm-badge" [ngClass]="badgeClass(badge)">{{ badge }}</span>
|
|
1516
1354
|
</div>
|
|
1517
1355
|
|
|
1518
|
-
<ng-container
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
[class.border-slate-300]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1523
|
-
[class.dark:border-slate-600]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1524
|
-
[class.focus:border-indigo-400]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1525
|
-
[class.focus:ring-indigo-100]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1526
|
-
[class.dark:focus:ring-indigo-900/40]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1527
|
-
[class.border-red-300]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1528
|
-
[class.dark:border-red-700]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1529
|
-
[class.bg-red-50]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1530
|
-
[class.dark:bg-red-900/20]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1531
|
-
[class.focus:border-red-400]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1532
|
-
[class.focus:ring-red-100]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1533
|
-
[attr.type]="inputType"
|
|
1534
|
-
[attr.placeholder]="schema.title || label"
|
|
1356
|
+
<ng-container>
|
|
1357
|
+
<input *ngIf="inputKind === 'text'" class="jsm-input"
|
|
1358
|
+
[class.jsm-input--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1359
|
+
[attr.type]="inputType" [attr.placeholder]="schema.title || label"
|
|
1535
1360
|
[formControl]="controlAsFormControl"
|
|
1536
|
-
|
|
1361
|
+
(blur)="onBlur()" />
|
|
1537
1362
|
|
|
1538
|
-
<textarea *
|
|
1539
|
-
class="
|
|
1540
|
-
[class.border-slate-300]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1541
|
-
[class.dark:border-slate-600]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1542
|
-
[class.focus:border-indigo-400]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1543
|
-
[class.focus:ring-indigo-100]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1544
|
-
[class.dark:focus:ring-indigo-900/40]="!(errorsForPath.length && controlAsFormControl.dirty)"
|
|
1545
|
-
[class.border-red-300]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1546
|
-
[class.dark:border-red-700]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1547
|
-
[class.bg-red-50]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1548
|
-
[class.dark:bg-red-900/20]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1549
|
-
[class.focus:border-red-400]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1550
|
-
[class.focus:ring-red-100]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1363
|
+
<textarea *ngIf="inputKind === 'textarea'" rows="4" class="jsm-textarea"
|
|
1364
|
+
[class.jsm-textarea--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1551
1365
|
[attr.placeholder]="schema.title || label"
|
|
1552
1366
|
[formControl]="controlAsFormControl"
|
|
1553
|
-
|
|
1367
|
+
(blur)="onBlur()"></textarea>
|
|
1554
1368
|
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
[class.dark:border-red-700]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1561
|
-
[class.bg-red-50]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1562
|
-
[class.dark:bg-red-900/20]="errorsForPath.length && controlAsFormControl.dirty"
|
|
1563
|
-
[formControl]="controlAsFormControl">
|
|
1369
|
+
<div *ngIf="inputKind === 'select'" class="jsm-select-wrap">
|
|
1370
|
+
<select class="jsm-select"
|
|
1371
|
+
[class.jsm-select--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1372
|
+
[formControl]="controlAsFormControl"
|
|
1373
|
+
(blur)="onBlur()">
|
|
1564
1374
|
<option *ngFor="let option of effectiveSchema.enum" [ngValue]="option">{{ option }}</option>
|
|
1565
1375
|
</select>
|
|
1566
|
-
<svg class="
|
|
1567
|
-
viewBox="0 0 16 16" fill="none">
|
|
1376
|
+
<svg class="jsm-select-chevron" viewBox="0 0 16 16" fill="none">
|
|
1568
1377
|
<path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1569
1378
|
</svg>
|
|
1570
1379
|
</div>
|
|
1571
1380
|
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
<span class="jsm-toggle-track" [class.jsm-toggle-on]="controlAsFormControl.value">
|
|
1381
|
+
<label *ngIf="inputKind === 'checkbox'" class="jsm-toggle-label">
|
|
1382
|
+
<span class="jsm-toggle-track" [class.jsm-on]="controlAsFormControl.value">
|
|
1575
1383
|
<input type="checkbox" class="sr-only" [formControl]="controlAsFormControl" />
|
|
1576
1384
|
<span class="jsm-toggle-thumb"></span>
|
|
1577
1385
|
</span>
|
|
1578
|
-
<span class="
|
|
1579
|
-
{{ schema.title || label }}<span *ngIf="required" class="
|
|
1386
|
+
<span class="jsm-toggle-text">
|
|
1387
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1580
1388
|
</span>
|
|
1581
1389
|
</label>
|
|
1582
|
-
|
|
1583
1390
|
</ng-container>
|
|
1584
1391
|
|
|
1585
|
-
<p *ngIf="inputKind === 'checkbox' && schema.description" class="
|
|
1586
|
-
|
|
1587
|
-
<p *ngIf="effectiveSchema.
|
|
1588
|
-
e.g. {{ effectiveSchema.examples?.[0] }}
|
|
1589
|
-
</p>
|
|
1590
|
-
|
|
1591
|
-
<p *ngIf="effectiveSchema.contentMediaType" class="text-[11px] text-slate-400 dark:text-slate-500">
|
|
1392
|
+
<p *ngIf="inputKind === 'checkbox' && schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1393
|
+
<p *ngIf="effectiveSchema.examples?.length" class="jsm-example">e.g. {{ effectiveSchema.examples?.[0] }}</p>
|
|
1394
|
+
<p *ngIf="effectiveSchema.contentMediaType" class="jsm-example">
|
|
1592
1395
|
{{ effectiveSchema.contentMediaType }}<span *ngIf="effectiveSchema.contentEncoding"> ({{ effectiveSchema.contentEncoding }})</span>
|
|
1593
1396
|
</p>
|
|
1594
1397
|
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
<svg class="w-3.5 h-3.5 shrink-0" viewBox="0 0 16 16" fill="none">
|
|
1398
|
+
<div *ngIf="allErrors.length && (controlAsFormControl.dirty || isTouched || showErrors)" class="jsm-error-list">
|
|
1399
|
+
<p *ngFor="let error of allErrors" class="jsm-error-msg">
|
|
1400
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none">
|
|
1599
1401
|
<circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/>
|
|
1600
1402
|
<path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
1601
1403
|
</svg>
|
|
@@ -1605,8 +1407,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1605
1407
|
</div>
|
|
1606
1408
|
|
|
1607
1409
|
</ng-container>
|
|
1608
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".jsm-toggle-track{position:relative;display:inline-flex;align-items:center;width:2.25rem;height:1.25rem;border-radius:9999px;flex-shrink:0;transition:background-color .2s;background-color:#cbd5e1}.jsm-toggle-track.jsm-toggle-on{background-color:#4f46e5}.dark .jsm-toggle-track:not(.jsm-toggle-on){background-color:#475569}.jsm-toggle-thumb{display:inline-block;width:1rem;height:1rem;border-radius:9999px;background:#fff;box-shadow:0 1px 3px #0003;transform:translate(.125rem);transition:transform .2s}.jsm-toggle-track.jsm-toggle-on .jsm-toggle-thumb{transform:translate(1.125rem)}\n"] }]
|
|
1609
|
-
}], ctorParameters: () => [{ type: JsonSchemaFormService }, { type: JsonSchemaValidationService }], propDecorators: { schema: [{
|
|
1410
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".jsm-field{display:flex;flex-direction:column;gap:.375rem}.jsm-field-label{display:block;font-size:.8125rem;font-weight:600;color:#374151}.jsm-field-hint{font-size:.75rem;color:#6b7280;margin:0;line-height:1.4}.jsm-required{color:#ef4444;margin-left:.125rem}.jsm-example{font-size:.6875rem;color:#9ca3af}.jsm-input,.jsm-textarea,.jsm-select{width:100%;border-radius:.5rem;border:1.5px solid #d1d5db;background:Canvas;padding:.5rem .75rem;font-size:.875rem;color:CanvasText;outline:none;box-shadow:0 1px 2px #0000000a;transition:border-color .15s,box-shadow .15s;font-family:inherit;box-sizing:border-box}.jsm-input:hover,.jsm-textarea:hover,.jsm-select:hover{border-color:#9ca3af}.jsm-input:focus,.jsm-textarea:focus,.jsm-select:focus{border-color:#6366f1;box-shadow:0 0 0 3px #6366f126}.jsm-input--error,.jsm-textarea--error,.jsm-select--error{border-color:#f87171!important;background:#fff5f5}.jsm-input--error:focus,.jsm-textarea--error:focus,.jsm-select--error:focus{box-shadow:0 0 0 3px #f8717133!important}.jsm-textarea{resize:vertical;min-height:6rem}.jsm-select-wrap{position:relative}.jsm-select{appearance:none;padding-right:2.25rem;cursor:pointer}.jsm-select-chevron{position:absolute;right:.625rem;top:50%;transform:translateY(-50%);width:1rem;height:1rem;color:#9ca3af;pointer-events:none}.jsm-toggle-label{display:inline-flex;align-items:center;gap:.625rem;cursor:pointer;-webkit-user-select:none;user-select:none}.jsm-toggle-track{position:relative;display:inline-flex;align-items:center;width:2.25rem;height:1.25rem;border-radius:9999px;flex-shrink:0;background:#d1d5db;transition:background .2s}.jsm-toggle-track.jsm-on{background:#4f46e5}.jsm-toggle-thumb{display:inline-block;width:1rem;height:1rem;border-radius:9999px;background:#fff;box-shadow:0 1px 3px #0003;transform:translate(.125rem);transition:transform .2s}.jsm-toggle-track.jsm-on .jsm-toggle-thumb{transform:translate(1.125rem)}.jsm-toggle-text{font-size:.875rem;font-weight:500;color:#374151}.jsm-btn-primary{display:inline-flex;align-items:center;gap:.25rem;padding:.375rem .75rem;border-radius:.5rem;font-size:.8125rem;font-weight:600;background:#4f46e5;color:#fff;border:none;cursor:pointer;box-shadow:0 1px 2px #4f46e54d;transition:background .15s,transform .1s,box-shadow .15s;white-space:nowrap;font-family:inherit}.jsm-btn-primary:hover{background:#4338ca;transform:translateY(-1px);box-shadow:0 3px 8px #4f46e54d}.jsm-btn-primary:active{transform:translateY(0)}.jsm-btn-primary:disabled{opacity:.45;cursor:not-allowed;transform:none}.jsm-btn-danger{display:inline-flex;align-items:center;gap:.25rem;padding:.25rem .5rem;border-radius:.375rem;font-size:.75rem;font-weight:600;background:transparent;color:#dc2626;border:1.5px solid #fca5a5;cursor:pointer;transition:background .15s,border-color .15s;font-family:inherit}.jsm-btn-danger:hover{background:#fee2e2;border-color:#f87171}.jsm-error-list{display:flex;flex-direction:column;gap:.25rem;margin-top:.25rem}.jsm-error-msg{display:flex;align-items:center;gap:.375rem;font-size:.75rem;color:#dc2626;font-weight:500}.jsm-error-icon{width:.875rem;height:.875rem;flex-shrink:0}.jsm-badge-row{display:flex;flex-wrap:wrap;gap:.375rem}.jsm-badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .5rem;font-size:.6875rem;font-weight:600;letter-spacing:.02em;text-transform:uppercase}.jsm-badge--deprecated{background:#fef3c7;color:#92400e}.jsm-badge--readonly{background:#f1f5f9;color:#475569}.jsm-badge--writeonly{background:#dbeafe;color:#1e40af}.jsm-badge--not{background:#fee2e2;color:#991b1b}.jsm-badge--nullable{background:#f3f4f6;color:#6b7280}.jsm-fieldset{border:1.5px solid #e5e7eb;border-radius:.875rem;padding:1.25rem;background:transparent;box-shadow:0 1px 3px #0000000f;transition:box-shadow .2s;box-sizing:border-box}.jsm-fieldset:focus-within{border-color:#c7d2fe;box-shadow:0 0 0 3px #6366f114,0 1px 3px #0000000f}.jsm-legend{display:inline-flex;align-items:center;gap:.375rem;padding:0 .5rem;font-size:.875rem;font-weight:700;color:#1f2937}.jsm-obj-grid{display:grid;grid-template-columns:1fr;gap:1rem}@media (min-width:640px){.jsm-obj-grid{grid-template-columns:repeat(2,1fr)}}.jsm-obj-complex{display:flex;flex-direction:column;gap:1rem;margin-top:1rem}.jsm-dynamic-key-header{display:flex;align-items:center;justify-content:space-between;padding:.25rem .5rem;background:#f9fafb;border-radius:.375rem;border:1px dashed #d1d5db;margin-bottom:.25rem}.jsm-dynamic-key-label{font-size:.75rem;font-weight:600;color:#6b7280;font-family:monospace}.jsm-add-prop{margin-top:1rem;padding:.875rem;background:#f9fafb;border-radius:.625rem;border:1.5px dashed #d1d5db;display:flex;flex-direction:column;gap:.5rem}.jsm-add-prop-label{font-size:.75rem;font-weight:600;color:#6b7280;text-transform:uppercase;letter-spacing:.04em}.jsm-add-prop-row{display:flex;gap:.5rem;align-items:center}.jsm-input--sm{padding:.375rem .625rem;font-size:.8125rem}.jsm-array-block{display:flex;flex-direction:column;gap:.75rem}.jsm-array-header{display:flex;align-items:flex-start;justify-content:space-between;gap:.5rem}.jsm-array-title{font-size:.875rem;font-weight:700;color:#1f2937;display:flex;align-items:center;gap:.375rem}.jsm-array-items{display:flex;flex-direction:column;gap:.75rem}.jsm-array-item{border:1.5px solid #e5e7eb;border-radius:.75rem;padding:.875rem;background:transparent;box-shadow:0 1px 2px #0000000a;transition:border-color .15s,box-shadow .15s}.jsm-array-item:focus-within{border-color:#c7d2fe;box-shadow:0 0 0 3px #6366f114}.jsm-array-item-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:.75rem}.jsm-array-index{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:9999px;background:#eef2ff;color:#4f46e5;font-size:.6875rem;font-weight:700}.jsm-empty-array{display:flex;flex-direction:column;align-items:center;gap:.5rem;padding:2rem 1rem;border:1.5px dashed #e5e7eb;border-radius:.75rem;color:#9ca3af;font-size:.8125rem;text-align:center}.jsm-contains-hint{display:flex;align-items:center;gap:.375rem;font-size:.75rem;color:#6366f1;background:#eef2ff;border-radius:.375rem;padding:.375rem .625rem}.jsm-combinator{border:1.5px solid #e5e7eb;border-radius:.875rem;overflow:hidden;background:transparent;box-shadow:0 1px 3px #0000000f}.jsm-combinator-header{display:flex;align-items:flex-start;justify-content:space-between;padding:.875rem 1rem;background:#00000008;border-bottom:1.5px solid #e5e7eb}.jsm-combinator-title{font-size:.875rem;font-weight:700;color:#1f2937}.jsm-combinator-body{padding:1rem}.jsm-combinator-hint{font-size:.75rem;color:#6b7280;margin:.25rem 0 0}.jsm-oneof-tabs{display:flex;overflow-x:auto;border-bottom:1.5px solid #e5e7eb}.jsm-tab{padding:.5rem 1rem;font-size:.8125rem;font-weight:500;color:#6b7280;border:none;background:transparent;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1.5px;transition:color .15s,border-color .15s;white-space:nowrap;font-family:inherit}.jsm-tab:hover{color:#4f46e5}.jsm-tab--active{color:#4f46e5;border-bottom-color:#4f46e5;font-weight:600}.jsm-anyof-options{display:flex;flex-wrap:wrap;gap:.5rem;padding:.75rem 1rem;border-bottom:1.5px solid #e5e7eb}.jsm-anyof-option{display:inline-flex;align-items:center;gap:.375rem;padding:.375rem .75rem;border-radius:9999px;border:1.5px solid #e5e7eb;font-size:.8125rem;font-weight:500;color:#6b7280;cursor:pointer;transition:all .15s;background:transparent}.jsm-anyof-option:hover{border-color:#a5b4fc;color:#4f46e5}.jsm-anyof-option--active{border-color:#6366f1;background:#eef2ff;color:#4f46e5}.jsm-allof-section{border-left:3px solid #e0e7ff;padding-left:1rem}.jsm-combinator-badge{display:inline-flex;align-items:center;border-radius:9999px;padding:.125rem .5rem;font-size:.6875rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;flex-shrink:0;margin-left:.75rem}.jsm-badge--oneof{background:#dbeafe;color:#1e40af}.jsm-badge--anyof{background:#ede9fe;color:#5b21b6}.jsm-badge--allof{background:#ccfbf1;color:#065f46}.dark .jsm-field-label{color:#d1d5db}.dark .jsm-field-hint{color:#9ca3af}.dark .jsm-toggle-track{background:#475569}.dark .jsm-toggle-track.jsm-on{background:#4f46e5}.dark .jsm-toggle-text{color:#d1d5db}.dark .jsm-input,.dark .jsm-textarea,.dark .jsm-select{border-color:#475569;color:#f1f5f9}.dark .jsm-input:focus,.dark .jsm-textarea:focus,.dark .jsm-select:focus{border-color:#6366f1;box-shadow:0 0 0 3px #6366f133}.dark .jsm-input--error,.dark .jsm-textarea--error,.dark .jsm-select--error{border-color:#f87171!important;background:#f871711a}.dark .jsm-fieldset{border-color:#334155}.dark .jsm-fieldset:focus-within{border-color:#6366f1}.dark .jsm-legend{color:#f1f5f9}.dark .jsm-combinator{border-color:#334155}.dark .jsm-combinator-header{background:#ffffff0a;border-color:#334155}.dark .jsm-combinator-title{color:#f1f5f9}.dark .jsm-oneof-tabs{border-color:#334155}.dark .jsm-tab{color:#94a3b8}.dark .jsm-tab--active{color:#818cf8;border-bottom-color:#818cf8}.dark .jsm-anyof-options{border-color:#334155}.dark .jsm-anyof-option{border-color:#334155;color:#94a3b8;background:#0f172a}.dark .jsm-anyof-option--active{border-color:#6366f1;background:#6366f126;color:#818cf8}.dark .jsm-allof-section{border-left-color:#3730a3}.dark .jsm-array-item{border-color:#334155}.dark .jsm-array-item:focus-within{border-color:#6366f1}.dark .jsm-array-index{background:#6366f133;color:#818cf8}.dark .jsm-empty-array{border-color:#334155;color:#64748b}.dark .jsm-contains-hint{background:#6366f126;color:#818cf8}.dark .jsm-add-prop{background:#1e293b66;border-color:#475569}.dark .jsm-add-prop-label{color:#64748b}.dark .jsm-dynamic-key-header{background:#1e293b80;border-color:#475569}.dark .jsm-dynamic-key-label{color:#94a3b8}.dark .jsm-error-msg{color:#f87171}.dark .jsm-array-title{color:#f1f5f9}.dark .jsm-badge--deprecated{background:#d9770633;color:#fbbf24}.dark .jsm-badge--readonly{background:#1e293b;color:#94a3b8}.dark .jsm-badge--writeonly{background:#2563eb33;color:#60a5fa}.dark .jsm-badge--not{background:#dc262633;color:#f87171}.dark .jsm-badge--nullable{background:#1e293b;color:#94a3b8}.dark .jsm-select-chevron{color:#64748b}\n"] }]
|
|
1411
|
+
}], ctorParameters: () => [{ type: JsonSchemaFormService }, { type: JsonSchemaValidationService }, { type: i0.ChangeDetectorRef }], propDecorators: { schema: [{
|
|
1610
1412
|
type: Input,
|
|
1611
1413
|
args: [{ required: true }]
|
|
1612
1414
|
}], control: [{
|
|
@@ -1626,14 +1428,53 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1626
1428
|
type: Input
|
|
1627
1429
|
}], allowAdditionalProperties: [{
|
|
1628
1430
|
type: Input
|
|
1431
|
+
}], showErrors: [{
|
|
1432
|
+
type: Input
|
|
1629
1433
|
}], controlReplaced: [{
|
|
1630
1434
|
type: Output
|
|
1631
1435
|
}] } });
|
|
1632
1436
|
|
|
1437
|
+
// AUTO-GENERATED — do not edit manually. Run: node scripts/generate-lib-styles.mjs
|
|
1438
|
+
const JSM_CSS = "/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root, :host {\n --font-sans: ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\",\n \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\",\n \"Courier New\", monospace;\n --color-red-50: oklch(97.1% 0.013 17.38);\n --color-red-300: oklch(80.8% 0.114 19.571);\n --color-red-700: oklch(50.5% 0.213 27.518);\n --color-red-900: oklch(39.6% 0.141 25.723);\n --color-amber-50: oklch(98.7% 0.022 95.277);\n --color-amber-200: oklch(92.4% 0.12 95.746);\n --color-amber-300: oklch(87.9% 0.169 91.605);\n --color-amber-400: oklch(82.8% 0.189 84.429);\n --color-amber-600: oklch(66.6% 0.179 58.318);\n --color-amber-700: oklch(55.5% 0.163 48.998);\n --color-amber-800: oklch(47.3% 0.137 46.201);\n --color-amber-900: oklch(41.4% 0.112 45.904);\n --color-emerald-50: oklch(97.9% 0.021 166.113);\n --color-emerald-400: oklch(76.5% 0.177 163.223);\n --color-emerald-700: oklch(50.8% 0.118 165.612);\n --color-emerald-900: oklch(37.8% 0.077 168.94);\n --color-indigo-50: oklch(96.2% 0.018 272.314);\n --color-indigo-100: oklch(93% 0.034 272.788);\n --color-indigo-200: oklch(87% 0.065 274.039);\n --color-indigo-300: oklch(78.5% 0.115 274.713);\n --color-indigo-400: oklch(67.3% 0.182 276.935);\n --color-indigo-500: oklch(58.5% 0.233 277.117);\n --color-indigo-600: oklch(51.1% 0.262 276.966);\n --color-indigo-700: oklch(45.7% 0.24 277.023);\n --color-indigo-900: oklch(35.9% 0.144 278.697);\n --color-rose-50: oklch(96.9% 0.015 12.422);\n --color-rose-400: oklch(71.2% 0.194 13.428);\n --color-rose-500: oklch(64.5% 0.246 16.439);\n --color-rose-600: oklch(58.6% 0.253 17.585);\n --color-rose-700: oklch(51.4% 0.222 16.935);\n --color-rose-900: oklch(41% 0.159 10.272);\n --color-slate-50: oklch(98.4% 0.003 247.858);\n --color-slate-100: oklch(96.8% 0.007 247.896);\n --color-slate-200: oklch(92.9% 0.013 255.508);\n --color-slate-300: oklch(86.9% 0.022 252.894);\n --color-slate-400: oklch(70.4% 0.04 256.788);\n --color-slate-500: oklch(55.4% 0.046 257.417);\n --color-slate-600: oklch(44.6% 0.043 257.281);\n --color-slate-700: oklch(37.2% 0.044 257.287);\n --color-slate-800: oklch(27.9% 0.041 260.031);\n --color-slate-900: oklch(20.8% 0.042 265.755);\n --color-slate-950: oklch(12.9% 0.042 264.695);\n --color-white: #fff;\n --spacing: 0.25rem;\n --container-2xl: 42rem;\n --container-3xl: 48rem;\n --container-6xl: 72rem;\n --text-xs: 0.75rem;\n --text-xs--line-height: calc(1 / 0.75);\n --text-sm: 0.875rem;\n --text-sm--line-height: calc(1.25 / 0.875);\n --text-lg: 1.125rem;\n --text-lg--line-height: calc(1.75 / 1.125);\n --text-xl: 1.25rem;\n --text-xl--line-height: calc(1.75 / 1.25);\n --text-3xl: 1.875rem;\n --text-3xl--line-height: calc(2.25 / 1.875);\n --text-4xl: 2.25rem;\n --text-4xl--line-height: calc(2.5 / 2.25);\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --font-weight-bold: 700;\n --tracking-tight: -0.025em;\n --tracking-wide: 0.025em;\n --radius-lg: 0.5rem;\n --radius-xl: 0.75rem;\n --radius-2xl: 1rem;\n --animate-spin: spin 1s linear infinite;\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: var(--font-sans);\n --default-mono-font-family: var(--font-mono);\n }\n}\n@layer base {\n *, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b, strong {\n font-weight: bolder;\n }\n code, kbd, samp, pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol, ul, menu {\n list-style: none;\n }\n img, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n }\n img, video {\n max-width: 100%;\n height: auto;\n }\n button, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button, input:where([type=\"button\"], [type=\"reset\"], [type=\"submit\"]), ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden=\"until-found\"])) {\n display: none !important;\n }\n}\n@layer utilities {\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border-width: 0;\n }\n .relative {\n position: relative;\n }\n .start {\n inset-inline-start: var(--spacing);\n }\n .col-span-2 {\n grid-column: span 2 / span 2;\n }\n .mx-auto {\n margin-inline: auto;\n }\n .mb-2 {\n margin-bottom: calc(var(--spacing) * 2);\n }\n .mb-4 {\n margin-bottom: calc(var(--spacing) * 4);\n }\n .contents {\n display: contents;\n }\n .flex {\n display: flex;\n }\n .grid {\n display: grid;\n }\n .inline {\n display: inline;\n }\n .inline-block {\n display: inline-block;\n }\n .inline-flex {\n display: inline-flex;\n }\n .table {\n display: table;\n }\n .h-3 {\n height: calc(var(--spacing) * 3);\n }\n .h-3\\.5 {\n height: calc(var(--spacing) * 3.5);\n }\n .h-4 {\n height: calc(var(--spacing) * 4);\n }\n .h-5 {\n height: calc(var(--spacing) * 5);\n }\n .h-40 {\n height: calc(var(--spacing) * 40);\n }\n .h-56 {\n height: calc(var(--spacing) * 56);\n }\n .min-h-screen {\n min-height: 100vh;\n }\n .w-3 {\n width: calc(var(--spacing) * 3);\n }\n .w-3\\.5 {\n width: calc(var(--spacing) * 3.5);\n }\n .w-4 {\n width: calc(var(--spacing) * 4);\n }\n .w-9 {\n width: calc(var(--spacing) * 9);\n }\n .w-full {\n width: 100%;\n }\n .max-w-2xl {\n max-width: var(--container-2xl);\n }\n .max-w-3xl {\n max-width: var(--container-3xl);\n }\n .max-w-6xl {\n max-width: var(--container-6xl);\n }\n .flex-shrink {\n flex-shrink: 1;\n }\n .shrink-0 {\n flex-shrink: 0;\n }\n .border-collapse {\n border-collapse: collapse;\n }\n .translate-x-0 {\n --tw-translate-x: calc(var(--spacing) * 0);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .translate-x-0\\.5 {\n --tw-translate-x: calc(var(--spacing) * 0.5);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .translate-x-4 {\n --tw-translate-x: calc(var(--spacing) * 4);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .transform {\n transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);\n }\n .animate-spin {\n animation: var(--animate-spin);\n }\n .cursor-pointer {\n cursor: pointer;\n }\n .resize {\n resize: both;\n }\n .grid-cols-1 {\n grid-template-columns: repeat(1, minmax(0, 1fr));\n }\n .flex-col {\n flex-direction: column;\n }\n .items-center {\n align-items: center;\n }\n .justify-between {\n justify-content: space-between;\n }\n .justify-center {\n justify-content: center;\n }\n .gap-2 {\n gap: calc(var(--spacing) * 2);\n }\n .gap-3 {\n gap: calc(var(--spacing) * 3);\n }\n .gap-4 {\n gap: calc(var(--spacing) * 4);\n }\n .gap-6 {\n gap: calc(var(--spacing) * 6);\n }\n .space-y-0 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 0) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 0) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-0\\.5 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 0.5) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 0.5) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-1 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-2 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-3 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-4 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-5 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-6 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .space-y-10 {\n :where(& > :not(:last-child)) {\n --tw-space-y-reverse: 0;\n margin-block-start: calc(calc(var(--spacing) * 10) * var(--tw-space-y-reverse));\n margin-block-end: calc(calc(var(--spacing) * 10) * calc(1 - var(--tw-space-y-reverse)));\n }\n }\n .rounded {\n border-radius: 0.25rem;\n }\n .rounded-2xl {\n border-radius: var(--radius-2xl);\n }\n .rounded-full {\n border-radius: calc(infinity * 1px);\n }\n .rounded-lg {\n border-radius: var(--radius-lg);\n }\n .rounded-xl {\n border-radius: var(--radius-xl);\n }\n .border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n .border-2 {\n border-style: var(--tw-border-style);\n border-width: 2px;\n }\n .border-amber-200 {\n border-color: var(--color-amber-200);\n }\n .border-amber-300 {\n border-color: var(--color-amber-300);\n }\n .border-indigo-200 {\n border-color: var(--color-indigo-200);\n }\n .border-red-300 {\n border-color: var(--color-red-300);\n }\n .border-red-700 {\n border-color: var(--color-red-700);\n }\n .border-slate-100 {\n border-color: var(--color-slate-100);\n }\n .border-slate-200 {\n border-color: var(--color-slate-200);\n }\n .border-slate-300 {\n border-color: var(--color-slate-300);\n }\n .border-t-slate-900 {\n border-top-color: var(--color-slate-900);\n }\n .bg-amber-50 {\n background-color: var(--color-amber-50);\n }\n .bg-emerald-50 {\n background-color: var(--color-emerald-50);\n }\n .bg-indigo-50 {\n background-color: var(--color-indigo-50);\n }\n .bg-indigo-600 {\n background-color: var(--color-indigo-600);\n }\n .bg-red-50 {\n background-color: var(--color-red-50);\n }\n .bg-red-900 {\n background-color: var(--color-red-900);\n }\n .bg-red-900\\/20 {\n background-color: color-mix(in srgb, oklch(39.6% 0.141 25.723) 20%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-red-900) 20%, transparent);\n }\n }\n .bg-rose-50 {\n background-color: var(--color-rose-50);\n }\n .bg-slate-50 {\n background-color: var(--color-slate-50);\n }\n .bg-slate-300 {\n background-color: var(--color-slate-300);\n }\n .bg-slate-900 {\n background-color: var(--color-slate-900);\n }\n .bg-white {\n background-color: var(--color-white);\n }\n .bg-white\\/70 {\n background-color: color-mix(in srgb, #fff 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-white) 70%, transparent);\n }\n }\n .bg-white\\/90 {\n background-color: color-mix(in srgb, #fff 90%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-white) 90%, transparent);\n }\n }\n .p-3 {\n padding: calc(var(--spacing) * 3);\n }\n .p-4 {\n padding: calc(var(--spacing) * 4);\n }\n .p-5 {\n padding: calc(var(--spacing) * 5);\n }\n .p-6 {\n padding: calc(var(--spacing) * 6);\n }\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n .px-3 {\n padding-inline: calc(var(--spacing) * 3);\n }\n .px-6 {\n padding-inline: calc(var(--spacing) * 6);\n }\n .py-1 {\n padding-block: calc(var(--spacing) * 1);\n }\n .py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n }\n .py-2 {\n padding-block: calc(var(--spacing) * 2);\n }\n .py-2\\.5 {\n padding-block: calc(var(--spacing) * 2.5);\n }\n .py-6 {\n padding-block: calc(var(--spacing) * 6);\n }\n .py-8 {\n padding-block: calc(var(--spacing) * 8);\n }\n .py-10 {\n padding-block: calc(var(--spacing) * 10);\n }\n .font-mono {\n font-family: var(--font-mono);\n }\n .text-3xl {\n font-size: var(--text-3xl);\n line-height: var(--tw-leading, var(--text-3xl--line-height));\n }\n .text-lg {\n font-size: var(--text-lg);\n line-height: var(--tw-leading, var(--text-lg--line-height));\n }\n .text-sm {\n font-size: var(--text-sm);\n line-height: var(--tw-leading, var(--text-sm--line-height));\n }\n .text-xl {\n font-size: var(--text-xl);\n line-height: var(--tw-leading, var(--text-xl--line-height));\n }\n .text-xs {\n font-size: var(--text-xs);\n line-height: var(--tw-leading, var(--text-xs--line-height));\n }\n .text-\\[10px\\] {\n font-size: 10px;\n }\n .text-\\[11px\\] {\n font-size: 11px;\n }\n .font-bold {\n --tw-font-weight: var(--font-weight-bold);\n font-weight: var(--font-weight-bold);\n }\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n .tracking-\\[0\\.2em\\] {\n --tw-tracking: 0.2em;\n letter-spacing: 0.2em;\n }\n .tracking-tight {\n --tw-tracking: var(--tracking-tight);\n letter-spacing: var(--tracking-tight);\n }\n .tracking-wide {\n --tw-tracking: var(--tracking-wide);\n letter-spacing: var(--tracking-wide);\n }\n .whitespace-pre-wrap {\n white-space: pre-wrap;\n }\n .text-amber-600 {\n color: var(--color-amber-600);\n }\n .text-amber-700 {\n color: var(--color-amber-700);\n }\n .text-amber-800 {\n color: var(--color-amber-800);\n }\n .text-emerald-700 {\n color: var(--color-emerald-700);\n }\n .text-indigo-500 {\n color: var(--color-indigo-500);\n }\n .text-indigo-700 {\n color: var(--color-indigo-700);\n }\n .text-rose-500 {\n color: var(--color-rose-500);\n }\n .text-rose-600 {\n color: var(--color-rose-600);\n }\n .text-rose-700 {\n color: var(--color-rose-700);\n }\n .text-slate-400 {\n color: var(--color-slate-400);\n }\n .text-slate-500 {\n color: var(--color-slate-500);\n }\n .text-slate-600 {\n color: var(--color-slate-600);\n }\n .text-slate-700 {\n color: var(--color-slate-700);\n }\n .text-slate-800 {\n color: var(--color-slate-800);\n }\n .text-slate-900 {\n color: var(--color-slate-900);\n }\n .text-white {\n color: var(--color-white);\n }\n .uppercase {\n text-transform: uppercase;\n }\n .italic {\n font-style: italic;\n }\n .underline {\n text-decoration-line: underline;\n }\n .opacity-25 {\n opacity: 25%;\n }\n .opacity-75 {\n opacity: 75%;\n }\n .shadow {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .shadow-sm {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .outline {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n .blur {\n --tw-blur: blur(8px);\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n }\n .filter {\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n }\n .backdrop-blur {\n --tw-backdrop-blur: blur(8px);\n -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n }\n .backdrop-filter {\n -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n }\n .transition {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-all {\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-colors {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-transform {\n transition-property: transform, translate, scale, rotate;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .duration-200 {\n --tw-duration: 200ms;\n transition-duration: 200ms;\n }\n .focus-within\\:border-indigo-300 {\n &:focus-within {\n border-color: var(--color-indigo-300);\n }\n }\n .focus-within\\:ring-2 {\n &:focus-within {\n --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n }\n .hover\\:-translate-y-0\\.5 {\n &:hover {\n @media (hover: hover) {\n --tw-translate-y: calc(var(--spacing) * -0.5);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n }\n }\n .hover\\:border-slate-300 {\n &:hover {\n @media (hover: hover) {\n border-color: var(--color-slate-300);\n }\n }\n }\n .hover\\:border-slate-400 {\n &:hover {\n @media (hover: hover) {\n border-color: var(--color-slate-400);\n }\n }\n }\n .hover\\:bg-indigo-100 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--color-indigo-100);\n }\n }\n }\n .hover\\:bg-slate-50 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--color-slate-50);\n }\n }\n }\n .hover\\:bg-slate-800 {\n &:hover {\n @media (hover: hover) {\n background-color: var(--color-slate-800);\n }\n }\n }\n .hover\\:text-rose-700 {\n &:hover {\n @media (hover: hover) {\n color: var(--color-rose-700);\n }\n }\n }\n .hover\\:shadow {\n &:hover {\n @media (hover: hover) {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n }\n }\n .hover\\:shadow-lg {\n &:hover {\n @media (hover: hover) {\n --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n }\n }\n .hover\\:shadow-md {\n &:hover {\n @media (hover: hover) {\n --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n }\n }\n .focus\\:border-indigo-400 {\n &:focus {\n border-color: var(--color-indigo-400);\n }\n }\n .focus\\:ring-2 {\n &:focus {\n --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n }\n .focus\\:ring-indigo-100 {\n &:focus {\n --tw-ring-color: var(--color-indigo-100);\n }\n }\n .focus\\:ring-indigo-500 {\n &:focus {\n --tw-ring-color: var(--color-indigo-500);\n }\n }\n .focus\\:ring-slate-900 {\n &:focus {\n --tw-ring-color: var(--color-slate-900);\n }\n }\n .focus\\:outline-none {\n &:focus {\n --tw-outline-style: none;\n outline-style: none;\n }\n }\n .sm\\:grid-cols-2 {\n @media (width >= 40rem) {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n }\n .md\\:grid-cols-2 {\n @media (width >= 48rem) {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n }\n .md\\:flex-row {\n @media (width >= 48rem) {\n flex-direction: row;\n }\n }\n .md\\:items-center {\n @media (width >= 48rem) {\n align-items: center;\n }\n }\n .md\\:justify-between {\n @media (width >= 48rem) {\n justify-content: space-between;\n }\n }\n .md\\:p-6 {\n @media (width >= 48rem) {\n padding: calc(var(--spacing) * 6);\n }\n }\n .md\\:text-4xl {\n @media (width >= 48rem) {\n font-size: var(--text-4xl);\n line-height: var(--tw-leading, var(--text-4xl--line-height));\n }\n }\n .lg\\:grid-cols-\\[360px\\,1fr\\] {\n @media (width >= 64rem) {\n grid-template-columns: 360px,1fr;\n }\n }\n .dark\\:border-amber-700 {\n &:where(.dark, .dark *) {\n border-color: var(--color-amber-700);\n }\n }\n .dark\\:border-amber-800 {\n &:where(.dark, .dark *) {\n border-color: var(--color-amber-800);\n }\n }\n .dark\\:border-indigo-700 {\n &:where(.dark, .dark *) {\n border-color: var(--color-indigo-700);\n }\n }\n .dark\\:border-slate-600 {\n &:where(.dark, .dark *) {\n border-color: var(--color-slate-600);\n }\n }\n .dark\\:border-slate-700 {\n &:where(.dark, .dark *) {\n border-color: var(--color-slate-700);\n }\n }\n .dark\\:border-t-indigo-400 {\n &:where(.dark, .dark *) {\n border-top-color: var(--color-indigo-400);\n }\n }\n .dark\\:bg-amber-900\\/20 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(41.4% 0.112 45.904) 20%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-amber-900) 20%, transparent);\n }\n }\n }\n .dark\\:bg-emerald-900\\/30 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(37.8% 0.077 168.94) 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-emerald-900) 30%, transparent);\n }\n }\n }\n .dark\\:bg-indigo-600 {\n &:where(.dark, .dark *) {\n background-color: var(--color-indigo-600);\n }\n }\n .dark\\:bg-indigo-900\\/30 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(35.9% 0.144 278.697) 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-indigo-900) 30%, transparent);\n }\n }\n }\n .dark\\:bg-rose-900\\/30 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(41% 0.159 10.272) 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-rose-900) 30%, transparent);\n }\n }\n }\n .dark\\:bg-slate-600 {\n &:where(.dark, .dark *) {\n background-color: var(--color-slate-600);\n }\n }\n .dark\\:bg-slate-700 {\n &:where(.dark, .dark *) {\n background-color: var(--color-slate-700);\n }\n }\n .dark\\:bg-slate-800 {\n &:where(.dark, .dark *) {\n background-color: var(--color-slate-800);\n }\n }\n .dark\\:bg-slate-800\\/50 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(27.9% 0.041 260.031) 50%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-slate-800) 50%, transparent);\n }\n }\n }\n .dark\\:bg-slate-800\\/60 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(27.9% 0.041 260.031) 60%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-slate-800) 60%, transparent);\n }\n }\n }\n .dark\\:bg-slate-900 {\n &:where(.dark, .dark *) {\n background-color: var(--color-slate-900);\n }\n }\n .dark\\:bg-slate-900\\/90 {\n &:where(.dark, .dark *) {\n background-color: color-mix(in srgb, oklch(20.8% 0.042 265.755) 90%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-slate-900) 90%, transparent);\n }\n }\n }\n .dark\\:bg-slate-950 {\n &:where(.dark, .dark *) {\n background-color: var(--color-slate-950);\n }\n }\n .dark\\:text-amber-300 {\n &:where(.dark, .dark *) {\n color: var(--color-amber-300);\n }\n }\n .dark\\:text-amber-400 {\n &:where(.dark, .dark *) {\n color: var(--color-amber-400);\n }\n }\n .dark\\:text-emerald-400 {\n &:where(.dark, .dark *) {\n color: var(--color-emerald-400);\n }\n }\n .dark\\:text-indigo-300 {\n &:where(.dark, .dark *) {\n color: var(--color-indigo-300);\n }\n }\n .dark\\:text-indigo-400 {\n &:where(.dark, .dark *) {\n color: var(--color-indigo-400);\n }\n }\n .dark\\:text-rose-400 {\n &:where(.dark, .dark *) {\n color: var(--color-rose-400);\n }\n }\n .dark\\:text-slate-100 {\n &:where(.dark, .dark *) {\n color: var(--color-slate-100);\n }\n }\n .dark\\:text-slate-200 {\n &:where(.dark, .dark *) {\n color: var(--color-slate-200);\n }\n }\n .dark\\:text-slate-300 {\n &:where(.dark, .dark *) {\n color: var(--color-slate-300);\n }\n }\n .dark\\:text-slate-400 {\n &:where(.dark, .dark *) {\n color: var(--color-slate-400);\n }\n }\n .dark\\:text-slate-500 {\n &:where(.dark, .dark *) {\n color: var(--color-slate-500);\n }\n }\n .dark\\:text-white {\n &:where(.dark, .dark *) {\n color: var(--color-white);\n }\n }\n .dark\\:hover\\:border-slate-500 {\n &:where(.dark, .dark *) {\n &:hover {\n @media (hover: hover) {\n border-color: var(--color-slate-500);\n }\n }\n }\n }\n .dark\\:hover\\:bg-indigo-700 {\n &:where(.dark, .dark *) {\n &:hover {\n @media (hover: hover) {\n background-color: var(--color-indigo-700);\n }\n }\n }\n }\n .dark\\:hover\\:bg-indigo-900\\/50 {\n &:where(.dark, .dark *) {\n &:hover {\n @media (hover: hover) {\n background-color: color-mix(in srgb, oklch(35.9% 0.144 278.697) 50%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-indigo-900) 50%, transparent);\n }\n }\n }\n }\n }\n .dark\\:hover\\:bg-slate-700 {\n &:where(.dark, .dark *) {\n &:hover {\n @media (hover: hover) {\n background-color: var(--color-slate-700);\n }\n }\n }\n }\n .dark\\:focus\\:ring-indigo-900\\/40 {\n &:where(.dark, .dark *) {\n &:focus {\n --tw-ring-color: color-mix(in srgb, oklch(35.9% 0.144 278.697) 40%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n --tw-ring-color: color-mix(in oklab, var(--color-indigo-900) 40%, transparent);\n }\n }\n }\n }\n}\n@property --tw-translate-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-rotate-x {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-rotate-y {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-rotate-z {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-skew-x {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-skew-y {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-space-y-reverse {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-border-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-font-weight {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-tracking {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-inset-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-inset-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-ring-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ring-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-ring-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-inset-ring-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-ring-inset {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ring-offset-width {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --tw-ring-offset-color {\n syntax: \"*\";\n inherits: false;\n initial-value: #fff;\n}\n@property --tw-ring-offset-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-outline-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-blur {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-brightness {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contrast {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-grayscale {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-hue-rotate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-invert {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-opacity {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-saturate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-sepia {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-drop-shadow-size {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-blur {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-brightness {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-contrast {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-grayscale {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-hue-rotate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-invert {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-opacity {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-saturate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-sepia {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-duration {\n syntax: \"*\";\n inherits: false;\n}\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-rotate-x: initial;\n --tw-rotate-y: initial;\n --tw-rotate-z: initial;\n --tw-skew-x: initial;\n --tw-skew-y: initial;\n --tw-space-y-reverse: 0;\n --tw-border-style: solid;\n --tw-font-weight: initial;\n --tw-tracking: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-outline-style: solid;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-backdrop-blur: initial;\n --tw-backdrop-brightness: initial;\n --tw-backdrop-contrast: initial;\n --tw-backdrop-grayscale: initial;\n --tw-backdrop-hue-rotate: initial;\n --tw-backdrop-invert: initial;\n --tw-backdrop-opacity: initial;\n --tw-backdrop-saturate: initial;\n --tw-backdrop-sepia: initial;\n --tw-duration: initial;\n }\n }\n}\n";
|
|
1439
|
+
|
|
1440
|
+
const STYLE_ID = 'jsm-tailwind-styles';
|
|
1441
|
+
class JsonSchemaStylesService {
|
|
1442
|
+
platformId;
|
|
1443
|
+
injected = false;
|
|
1444
|
+
constructor(platformId) {
|
|
1445
|
+
this.platformId = platformId;
|
|
1446
|
+
}
|
|
1447
|
+
inject() {
|
|
1448
|
+
if (this.injected || !isPlatformBrowser(this.platformId))
|
|
1449
|
+
return;
|
|
1450
|
+
if (typeof document === 'undefined')
|
|
1451
|
+
return;
|
|
1452
|
+
if (document.getElementById(STYLE_ID)) {
|
|
1453
|
+
this.injected = true;
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
const style = document.createElement('style');
|
|
1457
|
+
style.id = STYLE_ID;
|
|
1458
|
+
style.textContent = JSM_CSS;
|
|
1459
|
+
document.head.appendChild(style);
|
|
1460
|
+
this.injected = true;
|
|
1461
|
+
}
|
|
1462
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaStylesService, deps: [{ token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1463
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaStylesService, providedIn: 'root' });
|
|
1464
|
+
}
|
|
1465
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaStylesService, decorators: [{
|
|
1466
|
+
type: Injectable,
|
|
1467
|
+
args: [{ providedIn: 'root' }]
|
|
1468
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1469
|
+
type: Inject,
|
|
1470
|
+
args: [PLATFORM_ID]
|
|
1471
|
+
}] }] });
|
|
1472
|
+
|
|
1633
1473
|
class JsonSchemaFormComponent {
|
|
1634
1474
|
schemaService;
|
|
1635
1475
|
resolver;
|
|
1636
1476
|
validation;
|
|
1477
|
+
cdr;
|
|
1637
1478
|
schema;
|
|
1638
1479
|
value;
|
|
1639
1480
|
data;
|
|
@@ -1648,20 +1489,48 @@ class JsonSchemaFormComponent {
|
|
|
1648
1489
|
errorsMap = new Map();
|
|
1649
1490
|
schemaErrorList = [];
|
|
1650
1491
|
loading = false;
|
|
1492
|
+
/** When true, all field errors are shown regardless of touched/dirty state. */
|
|
1493
|
+
showErrors = false;
|
|
1651
1494
|
valueSub;
|
|
1652
|
-
constructor(schemaService, resolver, validation) {
|
|
1495
|
+
constructor(schemaService, resolver, validation, cdr, stylesService) {
|
|
1653
1496
|
this.schemaService = schemaService;
|
|
1654
1497
|
this.resolver = resolver;
|
|
1655
1498
|
this.validation = validation;
|
|
1499
|
+
this.cdr = cdr;
|
|
1500
|
+
stylesService.inject();
|
|
1656
1501
|
}
|
|
1657
1502
|
ngOnChanges(changes) {
|
|
1658
|
-
if (changes['schema']
|
|
1503
|
+
if (changes['schema']) {
|
|
1504
|
+
// Schema changed — full rebuild required
|
|
1505
|
+
void this.buildForm();
|
|
1506
|
+
}
|
|
1507
|
+
else if ((changes['value'] || changes['data']) && this.form) {
|
|
1508
|
+
// Only data changed and form already exists — patch values without rebuilding
|
|
1509
|
+
const newData = this.value !== undefined ? this.value : this.data;
|
|
1510
|
+
this.form.patchValue(newData, { emitEvent: false });
|
|
1511
|
+
}
|
|
1512
|
+
else if (changes['value'] || changes['data']) {
|
|
1513
|
+
// Form not built yet — build it
|
|
1659
1514
|
void this.buildForm();
|
|
1660
1515
|
}
|
|
1661
1516
|
}
|
|
1662
1517
|
ngOnDestroy() {
|
|
1663
1518
|
this.valueSub?.unsubscribe();
|
|
1664
1519
|
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Marks all fields as touched and forces error display across the entire form.
|
|
1522
|
+
* Call this from an external "Save" or "Submit" button to show all validation errors at once.
|
|
1523
|
+
* Returns true if the form is valid, false otherwise.
|
|
1524
|
+
*/
|
|
1525
|
+
validate() {
|
|
1526
|
+
if (!this.form)
|
|
1527
|
+
return false;
|
|
1528
|
+
this.form.markAllAsTouched();
|
|
1529
|
+
this.showErrors = true;
|
|
1530
|
+
this.updateErrors();
|
|
1531
|
+
this.cdr.detectChanges();
|
|
1532
|
+
return this.form.valid;
|
|
1533
|
+
}
|
|
1665
1534
|
async buildForm() {
|
|
1666
1535
|
this.valueSub?.unsubscribe();
|
|
1667
1536
|
this.loading = true;
|
|
@@ -1689,7 +1558,8 @@ class JsonSchemaFormComponent {
|
|
|
1689
1558
|
this.errorsMap = new Map();
|
|
1690
1559
|
return;
|
|
1691
1560
|
}
|
|
1692
|
-
const
|
|
1561
|
+
const normalized = this.normalizeValue(this.resolvedSchema, this.rootControl.value);
|
|
1562
|
+
const errors = this.validation.validate(this.resolvedSchema, normalized);
|
|
1693
1563
|
const map = new Map();
|
|
1694
1564
|
for (const error of errors) {
|
|
1695
1565
|
const path = error.instancePath ?? '';
|
|
@@ -1699,6 +1569,37 @@ class JsonSchemaFormComponent {
|
|
|
1699
1569
|
}
|
|
1700
1570
|
this.errorsMap = map;
|
|
1701
1571
|
}
|
|
1572
|
+
/**
|
|
1573
|
+
* Recursively coerces string values to numbers/booleans where the schema declares
|
|
1574
|
+
* type "number" or "integer". This is needed because <input type="number"> always
|
|
1575
|
+
* returns a string to Angular's FormControl, but Ajv validates against the JSON type.
|
|
1576
|
+
*/
|
|
1577
|
+
normalizeValue(schema, value) {
|
|
1578
|
+
if (value === null || value === undefined)
|
|
1579
|
+
return value;
|
|
1580
|
+
const type = Array.isArray(schema.type)
|
|
1581
|
+
? schema.type.find((t) => t !== 'null') ?? schema.type[0]
|
|
1582
|
+
: schema.type;
|
|
1583
|
+
if ((type === 'number' || type === 'integer') && typeof value === 'string') {
|
|
1584
|
+
const n = Number(value);
|
|
1585
|
+
return isNaN(n) ? value : n;
|
|
1586
|
+
}
|
|
1587
|
+
if (type === 'object' && schema.properties && typeof value === 'object' && !Array.isArray(value)) {
|
|
1588
|
+
const obj = value;
|
|
1589
|
+
const result = { ...obj };
|
|
1590
|
+
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
1591
|
+
if (key in result) {
|
|
1592
|
+
result[key] = this.normalizeValue(propSchema, result[key]);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
return result;
|
|
1596
|
+
}
|
|
1597
|
+
if (type === 'array' && Array.isArray(value)) {
|
|
1598
|
+
const itemSchema = schema.items ?? {};
|
|
1599
|
+
return value.map((item) => this.normalizeValue(itemSchema, item));
|
|
1600
|
+
}
|
|
1601
|
+
return value;
|
|
1602
|
+
}
|
|
1702
1603
|
onRootReplaced(control) {
|
|
1703
1604
|
this.rootControl = control;
|
|
1704
1605
|
if (control instanceof FormGroup) {
|
|
@@ -1722,8 +1623,8 @@ class JsonSchemaFormComponent {
|
|
|
1722
1623
|
this.valueChange.emit(this.rootControl.value);
|
|
1723
1624
|
});
|
|
1724
1625
|
}
|
|
1725
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1726
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.
|
|
1626
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormComponent, deps: [{ token: JsonSchemaFormService }, { token: JsonSchemaResolverService }, { token: JsonSchemaValidationService }, { token: i0.ChangeDetectorRef }, { token: JsonSchemaStylesService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1627
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: JsonSchemaFormComponent, isStandalone: true, selector: "jsm-json-schema-form", inputs: { schema: "schema", value: "value", data: "data", allowAdditionalProperties: "allowAdditionalProperties" }, outputs: { formReady: "formReady", valueChange: "valueChange", schemaReady: "schemaReady", schemaErrors: "schemaErrors" }, usesOnChanges: true, ngImport: i0, template: `
|
|
1727
1628
|
<div class="jsm-root">
|
|
1728
1629
|
<form class="w-full space-y-5">
|
|
1729
1630
|
<div *ngIf="resolvedSchema?.title || resolvedSchema?.description" class="space-y-0.5">
|
|
@@ -1772,15 +1673,16 @@ class JsonSchemaFormComponent {
|
|
|
1772
1673
|
[path]="''"
|
|
1773
1674
|
[errorsMap]="errorsMap"
|
|
1774
1675
|
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1676
|
+
[showErrors]="showErrors"
|
|
1775
1677
|
label="Root"
|
|
1776
1678
|
(controlReplaced)="onRootReplaced($event)"
|
|
1777
1679
|
></jsm-schema-node>
|
|
1778
1680
|
</div>
|
|
1779
1681
|
</form>
|
|
1780
1682
|
</div>
|
|
1781
|
-
`, isInline: true, styles: [".jsm-root *,.jsm-root *:before,.jsm-root *:after{box-sizing:border-box}.jsm-root input,.jsm-root textarea,.jsm-root select,.jsm-root button{font-family:inherit;font-size:inherit;line-height:inherit}.jsm-root input[type=number]::-webkit-inner-spin-button,.jsm-root input[type=number]::-webkit-outer-spin-button{opacity:1}.jsm-root input:not([type=checkbox]):not([type=radio]):not(.sr-only),.jsm-root textarea,.jsm-root select{border-width:1.5px!important;border-style:solid!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: JsonSchemaNodeComponent, selector: "jsm-schema-node", inputs: ["schema", "control", "label", "required", "path", "errorsMap", "parent", "controlKey", "allowAdditionalProperties"], outputs: ["controlReplaced"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1683
|
+
`, isInline: true, styles: [".jsm-root *,.jsm-root *:before,.jsm-root *:after{box-sizing:border-box}.jsm-root input,.jsm-root textarea,.jsm-root select,.jsm-root button{font-family:inherit;font-size:inherit;line-height:inherit}.jsm-root input[type=number]::-webkit-inner-spin-button,.jsm-root input[type=number]::-webkit-outer-spin-button{opacity:1}.jsm-root input:not([type=checkbox]):not([type=radio]):not(.sr-only),.jsm-root textarea,.jsm-root select{border-width:1.5px!important;border-style:solid!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: JsonSchemaNodeComponent, selector: "jsm-schema-node", inputs: ["schema", "control", "label", "required", "path", "errorsMap", "parent", "controlKey", "allowAdditionalProperties", "showErrors"], outputs: ["controlReplaced"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1782
1684
|
}
|
|
1783
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormComponent, decorators: [{
|
|
1784
1686
|
type: Component,
|
|
1785
1687
|
args: [{ selector: 'jsm-json-schema-form', standalone: true, imports: [CommonModule, ReactiveFormsModule, JsonSchemaNodeComponent], encapsulation: ViewEncapsulation.None, template: `
|
|
1786
1688
|
<div class="jsm-root">
|
|
@@ -1831,6 +1733,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1831
1733
|
[path]="''"
|
|
1832
1734
|
[errorsMap]="errorsMap"
|
|
1833
1735
|
[allowAdditionalProperties]="allowAdditionalProperties"
|
|
1736
|
+
[showErrors]="showErrors"
|
|
1834
1737
|
label="Root"
|
|
1835
1738
|
(controlReplaced)="onRootReplaced($event)"
|
|
1836
1739
|
></jsm-schema-node>
|
|
@@ -1838,7 +1741,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1838
1741
|
</form>
|
|
1839
1742
|
</div>
|
|
1840
1743
|
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".jsm-root *,.jsm-root *:before,.jsm-root *:after{box-sizing:border-box}.jsm-root input,.jsm-root textarea,.jsm-root select,.jsm-root button{font-family:inherit;font-size:inherit;line-height:inherit}.jsm-root input[type=number]::-webkit-inner-spin-button,.jsm-root input[type=number]::-webkit-outer-spin-button{opacity:1}.jsm-root input:not([type=checkbox]):not([type=radio]):not(.sr-only),.jsm-root textarea,.jsm-root select{border-width:1.5px!important;border-style:solid!important}\n"] }]
|
|
1841
|
-
}], ctorParameters: () => [{ type: JsonSchemaFormService }, { type: JsonSchemaResolverService }, { type: JsonSchemaValidationService }], propDecorators: { schema: [{
|
|
1744
|
+
}], ctorParameters: () => [{ type: JsonSchemaFormService }, { type: JsonSchemaResolverService }, { type: JsonSchemaValidationService }, { type: i0.ChangeDetectorRef }, { type: JsonSchemaStylesService }], propDecorators: { schema: [{
|
|
1842
1745
|
type: Input,
|
|
1843
1746
|
args: [{ required: true }]
|
|
1844
1747
|
}], value: [{
|
|
@@ -1858,11 +1761,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1858
1761
|
}] } });
|
|
1859
1762
|
|
|
1860
1763
|
class JsonSchemaFormModule {
|
|
1861
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.
|
|
1862
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.
|
|
1863
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.
|
|
1764
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1765
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormModule, imports: [JsonSchemaFormComponent, JsonSchemaNodeComponent], exports: [JsonSchemaFormComponent, JsonSchemaNodeComponent] });
|
|
1766
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormModule, imports: [JsonSchemaFormComponent, JsonSchemaNodeComponent] });
|
|
1864
1767
|
}
|
|
1865
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.
|
|
1768
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormModule, decorators: [{
|
|
1866
1769
|
type: NgModule,
|
|
1867
1770
|
args: [{
|
|
1868
1771
|
imports: [JsonSchemaFormComponent, JsonSchemaNodeComponent],
|
|
@@ -1874,5 +1777,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
|
|
|
1874
1777
|
* Generated bundle index. Do not edit.
|
|
1875
1778
|
*/
|
|
1876
1779
|
|
|
1877
|
-
export { JsonSchemaFormComponent, JsonSchemaFormModule, JsonSchemaFormService, JsonSchemaNodeComponent, JsonSchemaResolverService, JsonSchemaValidationService };
|
|
1780
|
+
export { JsonSchemaFormComponent, JsonSchemaFormModule, JsonSchemaFormService, JsonSchemaNodeComponent, JsonSchemaResolverService, JsonSchemaStylesService, JsonSchemaValidationService };
|
|
1878
1781
|
//# sourceMappingURL=elle96-ng-json-schema-manager.mjs.map
|