@elle96/ng-json-schema-manager 0.2.0 → 0.3.0
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.
|
@@ -579,11 +579,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
579
579
|
}]
|
|
580
580
|
}] });
|
|
581
581
|
|
|
582
|
+
const DEFAULT_LABELS = {
|
|
583
|
+
formTitle: 'Form',
|
|
584
|
+
resolving: 'Resolving schema…',
|
|
585
|
+
schemaErrorsTitle: 'Schema errors',
|
|
586
|
+
schemaErrorsHint: 'The schema has structural issues. Fix them to get a valid form.',
|
|
587
|
+
addItem: 'Add item',
|
|
588
|
+
arrayItem: 'Item {n}',
|
|
589
|
+
remove: 'Remove',
|
|
590
|
+
add: 'Add',
|
|
591
|
+
addProperty: 'Add property',
|
|
592
|
+
propertyName: 'Property name',
|
|
593
|
+
noItems: 'No items yet — click "Add item" to start.',
|
|
594
|
+
mustContain: 'Must contain matching item(s)',
|
|
595
|
+
min: 'min {n}',
|
|
596
|
+
max: 'max {n}',
|
|
597
|
+
option: 'Option {n}',
|
|
598
|
+
section: 'Section {n}',
|
|
599
|
+
example: 'e.g.',
|
|
600
|
+
propertyNameRequired: 'Property name is required.',
|
|
601
|
+
propertyNameInvalid: 'Property name does not match schema constraints.',
|
|
602
|
+
propertyExists: 'Property already exists.',
|
|
603
|
+
propertyNotAllowed: 'This property is not allowed by the schema.',
|
|
604
|
+
errorRequired: 'This field is required',
|
|
605
|
+
errorMinLength: 'Minimum length is {n}',
|
|
606
|
+
errorMaxLength: 'Maximum length is {n}',
|
|
607
|
+
errorMin: 'Minimum value is {n}',
|
|
608
|
+
errorMax: 'Maximum value is {n}',
|
|
609
|
+
errorEmail: 'Invalid email address',
|
|
610
|
+
errorPattern: 'Value does not match the required pattern',
|
|
611
|
+
errorInteger: 'Value must be an integer',
|
|
612
|
+
errorExclusiveMin: 'Value must be greater than the minimum',
|
|
613
|
+
errorExclusiveMax: 'Value must be less than the maximum',
|
|
614
|
+
errorMultipleOf: 'Value must be a multiple of the required number',
|
|
615
|
+
errorMinItems: 'Minimum {n} items required',
|
|
616
|
+
errorMaxItems: 'Maximum {n} items allowed',
|
|
617
|
+
errorUniqueItems: 'Items must be unique',
|
|
618
|
+
};
|
|
619
|
+
/** Replaces `{key}` placeholders in a label template. */
|
|
620
|
+
function formatLabel(template, values = {}) {
|
|
621
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => (key in values ? String(values[key]) : match));
|
|
622
|
+
}
|
|
623
|
+
|
|
582
624
|
/**
|
|
583
625
|
* Options shared by every node of a form. Provided by `jsm-json-schema-form`, so each form instance has its own.
|
|
584
626
|
*/
|
|
585
627
|
class JsonSchemaFormOptions {
|
|
586
628
|
decimalSeparator = '.';
|
|
629
|
+
labels = DEFAULT_LABELS;
|
|
587
630
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormOptions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
588
631
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaFormOptions });
|
|
589
632
|
}
|
|
@@ -661,6 +704,10 @@ class NumericInputDirective {
|
|
|
661
704
|
}
|
|
662
705
|
writeValue(value) {
|
|
663
706
|
this._model = value ?? null;
|
|
707
|
+
// Keep the text being typed when it already means this number ("45," for 45): rewriting it would drop the separator.
|
|
708
|
+
if (typeof value === 'number' && parseNumericText(this._el.nativeElement.value) === value) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
664
711
|
this._show(formatNumeric(value, this.jsmDecimalSeparator));
|
|
665
712
|
}
|
|
666
713
|
registerOnChange(fn) {
|
|
@@ -717,6 +764,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
717
764
|
type: Input
|
|
718
765
|
}] } });
|
|
719
766
|
|
|
767
|
+
let nextNodeId = 0;
|
|
720
768
|
class JsonSchemaNodeComponent {
|
|
721
769
|
schemaService;
|
|
722
770
|
validation;
|
|
@@ -740,6 +788,8 @@ class JsonSchemaNodeComponent {
|
|
|
740
788
|
propertyError = '';
|
|
741
789
|
/** Tracks whether this primitive control has been touched (for OnPush CD). */
|
|
742
790
|
isTouched = false;
|
|
791
|
+
/** Unique DOM id base of this node: links labels, hints and errors to the control (WCAG 1.3.1, 4.1.2). */
|
|
792
|
+
nodeId = `jsm-n${++nextNodeId}`;
|
|
743
793
|
valueSub;
|
|
744
794
|
constructor(schemaService, validation, cdr, options) {
|
|
745
795
|
this.schemaService = schemaService;
|
|
@@ -800,6 +850,74 @@ class JsonSchemaNodeComponent {
|
|
|
800
850
|
get decimalSeparator() {
|
|
801
851
|
return this.options?.decimalSeparator ?? '.';
|
|
802
852
|
}
|
|
853
|
+
/** Texts shown by the form (see `labels` of `jsm-json-schema-form`). */
|
|
854
|
+
get l() {
|
|
855
|
+
return this.options?.labels ?? DEFAULT_LABELS;
|
|
856
|
+
}
|
|
857
|
+
fmt(template, values = {}) {
|
|
858
|
+
return formatLabel(template, values);
|
|
859
|
+
}
|
|
860
|
+
localize(message) {
|
|
861
|
+
return localizeNumbers(message, this.decimalSeparator);
|
|
862
|
+
}
|
|
863
|
+
optionLabel(index) {
|
|
864
|
+
return this.fmt(this.l.option, { n: index + 1 });
|
|
865
|
+
}
|
|
866
|
+
sectionLabel(index) {
|
|
867
|
+
return this.fmt(this.l.section, { n: index + 1 });
|
|
868
|
+
}
|
|
869
|
+
/** DOM id of a dynamic key label (keys may contain characters that are not valid in ids). */
|
|
870
|
+
keyId(key) {
|
|
871
|
+
return `${this.nodeId}-key-${key.replace(/[^A-Za-z0-9_-]/g, (c) => `_${c.charCodeAt(0).toString(16)}`)}`;
|
|
872
|
+
}
|
|
873
|
+
/** True when the error list of this primitive is shown (same gate as the error styling). */
|
|
874
|
+
get visibleError() {
|
|
875
|
+
return this.allErrors.length > 0 && (this.control.dirty || this.isTouched || this.showErrors);
|
|
876
|
+
}
|
|
877
|
+
/** Ids of the hint, example, media type and error texts that describe this control. */
|
|
878
|
+
get describedBy() {
|
|
879
|
+
const ids = [];
|
|
880
|
+
if (this.schema.description)
|
|
881
|
+
ids.push(`${this.nodeId}-hint`);
|
|
882
|
+
if (this.effectiveSchema.examples?.length)
|
|
883
|
+
ids.push(`${this.nodeId}-example`);
|
|
884
|
+
if (this.effectiveSchema.contentMediaType)
|
|
885
|
+
ids.push(`${this.nodeId}-media`);
|
|
886
|
+
if (this.visibleError)
|
|
887
|
+
ids.push(`${this.nodeId}-error`);
|
|
888
|
+
return ids.length ? ids.join(' ') : null;
|
|
889
|
+
}
|
|
890
|
+
selectOneOf(index) {
|
|
891
|
+
this.selectedOneOf = index;
|
|
892
|
+
this.onOneOfChange();
|
|
893
|
+
}
|
|
894
|
+
/** WAI-ARIA tabs keyboard support: arrows, Home and End move between the oneOf options. */
|
|
895
|
+
onOneOfKeydown(event) {
|
|
896
|
+
const count = this.schema.oneOf?.length ?? 0;
|
|
897
|
+
if (!count)
|
|
898
|
+
return;
|
|
899
|
+
let next = this.selectedOneOf;
|
|
900
|
+
switch (event.key) {
|
|
901
|
+
case 'ArrowRight':
|
|
902
|
+
case 'ArrowDown':
|
|
903
|
+
next = (next + 1) % count;
|
|
904
|
+
break;
|
|
905
|
+
case 'ArrowLeft':
|
|
906
|
+
case 'ArrowUp':
|
|
907
|
+
next = (next - 1 + count) % count;
|
|
908
|
+
break;
|
|
909
|
+
case 'Home':
|
|
910
|
+
next = 0;
|
|
911
|
+
break;
|
|
912
|
+
case 'End':
|
|
913
|
+
next = count - 1;
|
|
914
|
+
break;
|
|
915
|
+
default: return;
|
|
916
|
+
}
|
|
917
|
+
event.preventDefault();
|
|
918
|
+
this.selectOneOf(next);
|
|
919
|
+
setTimeout(() => document.getElementById(`${this.nodeId}-tab-${next}`)?.focus());
|
|
920
|
+
}
|
|
803
921
|
/** `multipleOf` of this node's own schema, exposed as step metadata. */
|
|
804
922
|
get numericStep() {
|
|
805
923
|
return this.effectiveSchema.multipleOf ? String(this.effectiveSchema.multipleOf) : 'any';
|
|
@@ -851,34 +969,35 @@ class JsonSchemaNodeComponent {
|
|
|
851
969
|
return ajvErrors;
|
|
852
970
|
const angularErrors = [];
|
|
853
971
|
const errs = ctrl.errors;
|
|
972
|
+
const l = this.l;
|
|
854
973
|
if (errs['required'])
|
|
855
|
-
angularErrors.push(
|
|
974
|
+
angularErrors.push(l.errorRequired);
|
|
856
975
|
if (errs['minlength'])
|
|
857
|
-
angularErrors.push(
|
|
976
|
+
angularErrors.push(this.fmt(l.errorMinLength, { n: errs['minlength'].requiredLength }));
|
|
858
977
|
if (errs['maxlength'])
|
|
859
|
-
angularErrors.push(
|
|
978
|
+
angularErrors.push(this.fmt(l.errorMaxLength, { n: errs['maxlength'].requiredLength }));
|
|
860
979
|
if (errs['min'])
|
|
861
|
-
angularErrors.push(
|
|
980
|
+
angularErrors.push(this.fmt(l.errorMin, { n: errs['min'].min }));
|
|
862
981
|
if (errs['max'])
|
|
863
|
-
angularErrors.push(
|
|
982
|
+
angularErrors.push(this.fmt(l.errorMax, { n: errs['max'].max }));
|
|
864
983
|
if (errs['email'])
|
|
865
|
-
angularErrors.push(
|
|
984
|
+
angularErrors.push(l.errorEmail);
|
|
866
985
|
if (errs['pattern'])
|
|
867
|
-
angularErrors.push(
|
|
986
|
+
angularErrors.push(l.errorPattern);
|
|
868
987
|
if (errs['integer'])
|
|
869
|
-
angularErrors.push(
|
|
988
|
+
angularErrors.push(l.errorInteger);
|
|
870
989
|
if (errs['exclusiveMinimum'])
|
|
871
|
-
angularErrors.push(
|
|
990
|
+
angularErrors.push(l.errorExclusiveMin);
|
|
872
991
|
if (errs['exclusiveMaximum'])
|
|
873
|
-
angularErrors.push(
|
|
992
|
+
angularErrors.push(l.errorExclusiveMax);
|
|
874
993
|
if (errs['multipleOf'])
|
|
875
|
-
angularErrors.push(
|
|
994
|
+
angularErrors.push(l.errorMultipleOf);
|
|
876
995
|
if (errs['minItems'])
|
|
877
|
-
angularErrors.push(
|
|
996
|
+
angularErrors.push(this.fmt(l.errorMinItems, { n: errs['minItems'].requiredLength ?? '' }));
|
|
878
997
|
if (errs['maxItems'])
|
|
879
|
-
angularErrors.push(
|
|
998
|
+
angularErrors.push(this.fmt(l.errorMaxItems, { n: errs['maxItems'].requiredLength ?? '' }));
|
|
880
999
|
if (errs['uniqueItems'])
|
|
881
|
-
angularErrors.push(
|
|
1000
|
+
angularErrors.push(l.errorUniqueItems);
|
|
882
1001
|
// Merge: prefer Ajv messages, fall back to Angular messages for errors not covered by Ajv
|
|
883
1002
|
const messages = ajvErrors.length > 0 ? ajvErrors : angularErrors;
|
|
884
1003
|
return messages.map((message) => localizeNumbers(message, this.decimalSeparator));
|
|
@@ -908,8 +1027,16 @@ class JsonSchemaNodeComponent {
|
|
|
908
1027
|
return this.mergeSchemas([this.schema, ...this.schema.allOf]);
|
|
909
1028
|
return this.effectiveSchema;
|
|
910
1029
|
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Sections rendered for an allOf: the schema's own keywords (without the allOf itself, which would render
|
|
1032
|
+
* this node again forever) when it declares any, followed by every allOf entry.
|
|
1033
|
+
*/
|
|
911
1034
|
get mergedAllOf() {
|
|
912
|
-
|
|
1035
|
+
const { allOf, ...own } = this.schema;
|
|
1036
|
+
if (!allOf?.length)
|
|
1037
|
+
return [this.schema];
|
|
1038
|
+
const declaresOwn = Object.keys(own).some((key) => !['title', 'description', '$id', '$schema', '$comment'].includes(key));
|
|
1039
|
+
return declaresOwn ? [own, ...allOf] : [...allOf];
|
|
913
1040
|
}
|
|
914
1041
|
isRequired(key) { return this.effectiveSchema.required?.includes(key) ?? false; }
|
|
915
1042
|
schemaForKey(key) {
|
|
@@ -923,22 +1050,22 @@ class JsonSchemaNodeComponent {
|
|
|
923
1050
|
this.propertyError = '';
|
|
924
1051
|
const key = this.newPropertyKey.trim();
|
|
925
1052
|
if (!key) {
|
|
926
|
-
this.propertyError =
|
|
1053
|
+
this.propertyError = this.l.propertyNameRequired;
|
|
927
1054
|
return;
|
|
928
1055
|
}
|
|
929
1056
|
if (this.effectiveSchema.propertyNames) {
|
|
930
1057
|
if (this.validation.validate(this.effectiveSchema.propertyNames, key).length) {
|
|
931
|
-
this.propertyError =
|
|
1058
|
+
this.propertyError = this.l.propertyNameInvalid;
|
|
932
1059
|
return;
|
|
933
1060
|
}
|
|
934
1061
|
}
|
|
935
1062
|
if (this.controlAsGroup.contains(key)) {
|
|
936
|
-
this.propertyError =
|
|
1063
|
+
this.propertyError = this.l.propertyExists;
|
|
937
1064
|
return;
|
|
938
1065
|
}
|
|
939
1066
|
const s = this.schemaService.resolveDynamicSchema(this.effectiveSchema, key);
|
|
940
1067
|
if (!s) {
|
|
941
|
-
this.propertyError =
|
|
1068
|
+
this.propertyError = this.l.propertyNotAllowed;
|
|
942
1069
|
return;
|
|
943
1070
|
}
|
|
944
1071
|
this.controlAsGroup.addControl(key, this.schemaService.buildControl(s, undefined, false));
|
|
@@ -1073,14 +1200,17 @@ class JsonSchemaNodeComponent {
|
|
|
1073
1200
|
</div>
|
|
1074
1201
|
<span class="jsm-combinator-badge jsm-badge--oneof">oneOf</span>
|
|
1075
1202
|
</div>
|
|
1076
|
-
<div class="jsm-oneof-tabs">
|
|
1077
|
-
<button *ngFor="let option of schema.oneOf; let i = index" type="button"
|
|
1203
|
+
<div class="jsm-oneof-tabs" role="tablist" [attr.aria-label]="schema.title || label || null" (keydown)="onOneOfKeydown($event)">
|
|
1204
|
+
<button *ngFor="let option of schema.oneOf; let i = index" type="button" role="tab"
|
|
1078
1205
|
class="jsm-tab" [class.jsm-tab--active]="selectedOneOf === i"
|
|
1079
|
-
|
|
1080
|
-
|
|
1206
|
+
[id]="nodeId + '-tab-' + i" [attr.aria-selected]="selectedOneOf === i"
|
|
1207
|
+
[attr.aria-controls]="nodeId + '-panel'" [attr.tabindex]="selectedOneOf === i ? 0 : -1"
|
|
1208
|
+
(click)="selectOneOf(i)">
|
|
1209
|
+
{{ option.title || optionLabel(i) }}
|
|
1081
1210
|
</button>
|
|
1082
1211
|
</div>
|
|
1083
|
-
<div class="jsm-combinator-body" *ngIf="activeVariant"
|
|
1212
|
+
<div class="jsm-combinator-body" *ngIf="activeVariant" role="tabpanel" [id]="nodeId + '-panel'"
|
|
1213
|
+
[attr.aria-labelledby]="nodeId + '-tab-' + selectedOneOf">
|
|
1084
1214
|
<jsm-schema-node [schema]="activeVariant" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1085
1215
|
[path]="path" [errorsMap]="errorsMap" [label]="label" [required]="required"
|
|
1086
1216
|
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
@@ -1097,11 +1227,11 @@ class JsonSchemaNodeComponent {
|
|
|
1097
1227
|
</div>
|
|
1098
1228
|
<span class="jsm-combinator-badge jsm-badge--anyof">anyOf</span>
|
|
1099
1229
|
</div>
|
|
1100
|
-
<div class="jsm-anyof-options">
|
|
1230
|
+
<div class="jsm-anyof-options" role="group" [attr.aria-label]="schema.title || label || null">
|
|
1101
1231
|
<label *ngFor="let option of schema.anyOf; let i = index"
|
|
1102
1232
|
class="jsm-anyof-option" [class.jsm-anyof-option--active]="selectedAnyOf.has(i)">
|
|
1103
1233
|
<input type="checkbox" class="sr-only" [checked]="selectedAnyOf.has(i)" (change)="toggleAnyOf(i)" />
|
|
1104
|
-
{{ option.title || (
|
|
1234
|
+
{{ option.title || optionLabel(i) }}
|
|
1105
1235
|
</label>
|
|
1106
1236
|
</div>
|
|
1107
1237
|
<div class="jsm-combinator-body" *ngIf="activeVariant">
|
|
@@ -1124,7 +1254,7 @@ class JsonSchemaNodeComponent {
|
|
|
1124
1254
|
<div class="jsm-combinator-body">
|
|
1125
1255
|
<div *ngFor="let subSchema of mergedAllOf; let i = index" class="jsm-allof-section">
|
|
1126
1256
|
<jsm-schema-node [schema]="subSchema" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1127
|
-
[path]="path" [errorsMap]="errorsMap" [label]="subSchema.title || (
|
|
1257
|
+
[path]="path" [errorsMap]="errorsMap" [label]="subSchema.title || sectionLabel(i)" [required]="required"
|
|
1128
1258
|
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1129
1259
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1130
1260
|
</div>
|
|
@@ -1144,8 +1274,9 @@ class JsonSchemaNodeComponent {
|
|
|
1144
1274
|
<ng-container *ngFor="let key of simpleKeys">
|
|
1145
1275
|
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1146
1276
|
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1147
|
-
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1148
|
-
<button type="button" class="jsm-btn-danger"
|
|
1277
|
+
<span class="jsm-dynamic-key-label" [id]="keyId(key)">{{ key }}</span>
|
|
1278
|
+
<button type="button" class="jsm-btn-danger" [id]="keyId(key) + '-remove'"
|
|
1279
|
+
[attr.aria-labelledby]="keyId(key) + '-remove ' + keyId(key)" (click)="removeDynamicKey(key)">{{ l.remove }}</button>
|
|
1149
1280
|
</div>
|
|
1150
1281
|
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1151
1282
|
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
@@ -1159,8 +1290,9 @@ class JsonSchemaNodeComponent {
|
|
|
1159
1290
|
<ng-container *ngFor="let key of complexKeys">
|
|
1160
1291
|
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1161
1292
|
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1162
|
-
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1163
|
-
<button type="button" class="jsm-btn-danger"
|
|
1293
|
+
<span class="jsm-dynamic-key-label" [id]="keyId(key)">{{ key }}</span>
|
|
1294
|
+
<button type="button" class="jsm-btn-danger" [id]="keyId(key) + '-remove'"
|
|
1295
|
+
[attr.aria-labelledby]="keyId(key) + '-remove ' + keyId(key)" (click)="removeDynamicKey(key)">{{ l.remove }}</button>
|
|
1164
1296
|
</div>
|
|
1165
1297
|
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1166
1298
|
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
@@ -1170,45 +1302,48 @@ class JsonSchemaNodeComponent {
|
|
|
1170
1302
|
</ng-container>
|
|
1171
1303
|
</div>
|
|
1172
1304
|
|
|
1173
|
-
<div *ngIf="canAddProperty" class="jsm-add-prop">
|
|
1174
|
-
<p class="jsm-add-prop-label">
|
|
1305
|
+
<div *ngIf="canAddProperty" class="jsm-add-prop" role="group" [attr.aria-labelledby]="nodeId + '-addprop'">
|
|
1306
|
+
<p class="jsm-add-prop-label" [id]="nodeId + '-addprop'">{{ l.addProperty }}</p>
|
|
1175
1307
|
<div class="jsm-add-prop-row">
|
|
1176
|
-
<input class="jsm-input jsm-input--sm" style="flex:1;" [(ngModel)]="newPropertyKey"
|
|
1177
|
-
|
|
1308
|
+
<input class="jsm-input jsm-input--sm" style="flex:1;" [(ngModel)]="newPropertyKey" [ngModelOptions]="{standalone: true}"
|
|
1309
|
+
[attr.aria-label]="l.propertyName" [attr.placeholder]="l.propertyName"
|
|
1310
|
+
[attr.aria-invalid]="propertyError ? 'true' : null" [attr.aria-describedby]="propertyError ? nodeId + '-prop-error' : null" />
|
|
1311
|
+
<button type="button" class="jsm-btn-primary" (click)="addDynamicProperty()">{{ l.add }}</button>
|
|
1178
1312
|
</div>
|
|
1179
|
-
<p *ngIf="propertyError" class="jsm-error-msg">
|
|
1180
|
-
<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>
|
|
1313
|
+
<p *ngIf="propertyError" class="jsm-error-msg" role="alert" [id]="nodeId + '-prop-error'">
|
|
1314
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
|
|
1181
1315
|
{{ propertyError }}
|
|
1182
1316
|
</p>
|
|
1183
1317
|
</div>
|
|
1184
1318
|
|
|
1185
|
-
<div *ngIf="errorsForPath.length" class="jsm-error-list" style="margin-top:.75rem;">
|
|
1319
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list" role="alert" style="margin-top:.75rem;">
|
|
1186
1320
|
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1187
|
-
<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>
|
|
1188
|
-
{{ error }}
|
|
1321
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
|
|
1322
|
+
{{ localize(error) }}
|
|
1189
1323
|
</p>
|
|
1190
1324
|
</div>
|
|
1191
1325
|
</fieldset>
|
|
1192
1326
|
|
|
1193
1327
|
<!-- ═══ array ═══ -->
|
|
1194
|
-
<div *ngSwitchCase="'array'" class="jsm-array-block">
|
|
1328
|
+
<div *ngSwitchCase="'array'" class="jsm-array-block" role="group" [attr.aria-labelledby]="nodeId + '-title'">
|
|
1195
1329
|
<div class="jsm-array-header">
|
|
1196
1330
|
<div>
|
|
1197
|
-
<p class="jsm-array-title">
|
|
1198
|
-
{{ schema.title || label }}<span *ngIf="required"
|
|
1331
|
+
<p class="jsm-array-title" [id]="nodeId + '-title'">
|
|
1332
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required" aria-hidden="true">*</span>
|
|
1199
1333
|
</p>
|
|
1200
1334
|
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1201
1335
|
</div>
|
|
1202
|
-
<button type="button" class="jsm-btn-primary"
|
|
1203
|
-
|
|
1204
|
-
|
|
1336
|
+
<button type="button" class="jsm-btn-primary" [id]="nodeId + '-add'"
|
|
1337
|
+
[attr.aria-labelledby]="nodeId + '-add ' + nodeId + '-title'" (click)="addArrayItem()" [disabled]="!canAddArrayItem">
|
|
1338
|
+
<svg style="width:.875rem;height:.875rem;flex-shrink:0;" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1339
|
+
{{ l.addItem }}
|
|
1205
1340
|
</button>
|
|
1206
1341
|
</div>
|
|
1207
1342
|
|
|
1208
1343
|
<div *ngIf="effectiveSchema.contains" class="jsm-contains-hint">
|
|
1209
|
-
|
|
1210
|
-
<span *ngIf="effectiveSchema.minContains"> · min {
|
|
1211
|
-
<span *ngIf="effectiveSchema.maxContains"> · max {
|
|
1344
|
+
{{ l.mustContain }}
|
|
1345
|
+
<span *ngIf="effectiveSchema.minContains"> · {{ fmt(l.min, { n: effectiveSchema.minContains }) }}</span>
|
|
1346
|
+
<span *ngIf="effectiveSchema.maxContains"> · {{ fmt(l.max, { n: effectiveSchema.maxContains }) }}</span>
|
|
1212
1347
|
</div>
|
|
1213
1348
|
|
|
1214
1349
|
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
@@ -1216,10 +1351,12 @@ class JsonSchemaNodeComponent {
|
|
|
1216
1351
|
</div>
|
|
1217
1352
|
|
|
1218
1353
|
<div class="jsm-array-items" *ngIf="arrayControls.length > 0; else emptyArray">
|
|
1219
|
-
<div *ngFor="let item of arrayControls; let i = index" class="jsm-array-item">
|
|
1354
|
+
<div *ngFor="let item of arrayControls; let i = index" class="jsm-array-item" role="group" [attr.aria-labelledby]="nodeId + '-item-' + i">
|
|
1220
1355
|
<div class="jsm-array-item-header">
|
|
1221
|
-
<span class="jsm-array-index">{{ i + 1 }}</span>
|
|
1222
|
-
<
|
|
1356
|
+
<span class="jsm-array-index" aria-hidden="true">{{ i + 1 }}</span>
|
|
1357
|
+
<span class="sr-only" [id]="nodeId + '-item-' + i">{{ fmt(l.arrayItem, { n: i + 1 }) }}</span>
|
|
1358
|
+
<button type="button" class="jsm-btn-danger" [id]="nodeId + '-remove-' + i"
|
|
1359
|
+
[attr.aria-labelledby]="nodeId + '-remove-' + i + ' ' + nodeId + '-item-' + i" (click)="removeArrayItem(i)">{{ l.remove }}</button>
|
|
1223
1360
|
</div>
|
|
1224
1361
|
<jsm-schema-node [schema]="schemaForIndex(i)" [control]="item" [parent]="controlAsArray"
|
|
1225
1362
|
[controlKey]="i" [path]="pathForChild(i)" [errorsMap]="errorsMap" [label]="label + ' item'"
|
|
@@ -1229,13 +1366,13 @@ class JsonSchemaNodeComponent {
|
|
|
1229
1366
|
</div>
|
|
1230
1367
|
|
|
1231
1368
|
<ng-template #emptyArray>
|
|
1232
|
-
<div class="jsm-empty-array">
|
|
1369
|
+
<div class="jsm-empty-array">{{ l.noItems }}</div>
|
|
1233
1370
|
</ng-template>
|
|
1234
1371
|
|
|
1235
|
-
<div *ngIf="errorsForPath.length" class="jsm-error-list">
|
|
1372
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list" role="alert">
|
|
1236
1373
|
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1237
|
-
<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>
|
|
1238
|
-
{{ error }}
|
|
1374
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
|
|
1375
|
+
{{ localize(error) }}
|
|
1239
1376
|
</p>
|
|
1240
1377
|
</div>
|
|
1241
1378
|
</div>
|
|
@@ -1243,10 +1380,10 @@ class JsonSchemaNodeComponent {
|
|
|
1243
1380
|
<!-- ═══ primitive ═══ -->
|
|
1244
1381
|
<div *ngSwitchDefault class="jsm-field">
|
|
1245
1382
|
<ng-container *ngIf="inputKind !== 'checkbox'">
|
|
1246
|
-
<label class="jsm-field-label">
|
|
1247
|
-
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1383
|
+
<label class="jsm-field-label" [attr.for]="nodeId">
|
|
1384
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required" aria-hidden="true">*</span>
|
|
1248
1385
|
</label>
|
|
1249
|
-
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1386
|
+
<p *ngIf="schema.description" class="jsm-field-hint" [id]="nodeId + '-hint'">{{ schema.description }}</p>
|
|
1250
1387
|
</ng-container>
|
|
1251
1388
|
|
|
1252
1389
|
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
@@ -1254,57 +1391,65 @@ class JsonSchemaNodeComponent {
|
|
|
1254
1391
|
</div>
|
|
1255
1392
|
|
|
1256
1393
|
<ng-container>
|
|
1257
|
-
<input *ngIf="inputKind === 'number'" jsmNumeric type="text" inputmode="decimal" class="jsm-input"
|
|
1394
|
+
<input *ngIf="inputKind === 'number'" jsmNumeric type="text" inputmode="decimal" class="jsm-input" [id]="nodeId"
|
|
1258
1395
|
[class.jsm-input--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1259
1396
|
[jsmDecimalSeparator]="decimalSeparator" [attr.data-step]="numericStep"
|
|
1260
|
-
[attr.
|
|
1397
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1398
|
+
[attr.aria-describedby]="describedBy"
|
|
1261
1399
|
[formControl]="controlAsFormControl"
|
|
1262
1400
|
(blur)="onBlur()" />
|
|
1263
1401
|
|
|
1264
|
-
<input *ngIf="inputKind === 'text'" class="jsm-input"
|
|
1402
|
+
<input *ngIf="inputKind === 'text'" class="jsm-input" [id]="nodeId"
|
|
1265
1403
|
[class.jsm-input--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1266
|
-
[attr.type]="inputType"
|
|
1404
|
+
[attr.type]="inputType"
|
|
1405
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1406
|
+
[attr.aria-describedby]="describedBy"
|
|
1267
1407
|
[formControl]="controlAsFormControl"
|
|
1268
1408
|
(blur)="onBlur()" />
|
|
1269
1409
|
|
|
1270
|
-
<textarea *ngIf="inputKind === 'textarea'" rows="4" class="jsm-textarea"
|
|
1410
|
+
<textarea *ngIf="inputKind === 'textarea'" rows="4" class="jsm-textarea" [id]="nodeId"
|
|
1271
1411
|
[class.jsm-textarea--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1272
|
-
[attr.
|
|
1412
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1413
|
+
[attr.aria-describedby]="describedBy"
|
|
1273
1414
|
[formControl]="controlAsFormControl"
|
|
1274
1415
|
(blur)="onBlur()"></textarea>
|
|
1275
1416
|
|
|
1276
1417
|
<div *ngIf="inputKind === 'select'" class="jsm-select-wrap">
|
|
1277
|
-
<select class="jsm-select"
|
|
1418
|
+
<select class="jsm-select" [id]="nodeId"
|
|
1278
1419
|
[class.jsm-select--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1420
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1421
|
+
[attr.aria-describedby]="describedBy"
|
|
1279
1422
|
[formControl]="controlAsFormControl"
|
|
1280
1423
|
(blur)="onBlur()">
|
|
1281
1424
|
<option *ngFor="let option of effectiveSchema.enum" [ngValue]="option">{{ option }}</option>
|
|
1282
1425
|
</select>
|
|
1283
|
-
<svg class="jsm-select-chevron" viewBox="0 0 16 16" fill="none">
|
|
1426
|
+
<svg class="jsm-select-chevron" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1284
1427
|
<path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1285
1428
|
</svg>
|
|
1286
1429
|
</div>
|
|
1287
1430
|
|
|
1288
1431
|
<label *ngIf="inputKind === 'checkbox'" class="jsm-toggle-label">
|
|
1289
1432
|
<span class="jsm-toggle-track" [class.jsm-on]="controlAsFormControl.value">
|
|
1290
|
-
<input type="checkbox" class="sr-only" [formControl]="controlAsFormControl"
|
|
1433
|
+
<input type="checkbox" class="sr-only" [id]="nodeId" [formControl]="controlAsFormControl"
|
|
1434
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1435
|
+
[attr.aria-describedby]="describedBy" (blur)="onBlur()" />
|
|
1291
1436
|
<span class="jsm-toggle-thumb"></span>
|
|
1292
1437
|
</span>
|
|
1293
1438
|
<span class="jsm-toggle-text">
|
|
1294
|
-
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1439
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required" aria-hidden="true">*</span>
|
|
1295
1440
|
</span>
|
|
1296
1441
|
</label>
|
|
1297
1442
|
</ng-container>
|
|
1298
1443
|
|
|
1299
|
-
<p *ngIf="inputKind === 'checkbox' && schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1300
|
-
<p *ngIf="effectiveSchema.examples?.length" class="jsm-example">
|
|
1301
|
-
<p *ngIf="effectiveSchema.contentMediaType" class="jsm-example">
|
|
1444
|
+
<p *ngIf="inputKind === 'checkbox' && schema.description" class="jsm-field-hint" [id]="nodeId + '-hint'">{{ schema.description }}</p>
|
|
1445
|
+
<p *ngIf="effectiveSchema.examples?.length" class="jsm-example" [id]="nodeId + '-example'">{{ l.example }} {{ effectiveSchema.examples?.[0] }}</p>
|
|
1446
|
+
<p *ngIf="effectiveSchema.contentMediaType" class="jsm-example" [id]="nodeId + '-media'">
|
|
1302
1447
|
{{ effectiveSchema.contentMediaType }}<span *ngIf="effectiveSchema.contentEncoding"> ({{ effectiveSchema.contentEncoding }})</span>
|
|
1303
1448
|
</p>
|
|
1304
1449
|
|
|
1305
|
-
<div *ngIf="
|
|
1450
|
+
<div *ngIf="visibleError" class="jsm-error-list" role="alert" [id]="nodeId + '-error'">
|
|
1306
1451
|
<p *ngFor="let error of allErrors" class="jsm-error-msg">
|
|
1307
|
-
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none">
|
|
1452
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1308
1453
|
<circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/>
|
|
1309
1454
|
<path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
1310
1455
|
</svg>
|
|
@@ -1314,7 +1459,7 @@ class JsonSchemaNodeComponent {
|
|
|
1314
1459
|
</div>
|
|
1315
1460
|
|
|
1316
1461
|
</ng-container>
|
|
1317
|
-
`, 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: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i4.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.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: i5.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i5.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i5.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: NumericInputDirective, selector: "input[jsmNumeric]", inputs: ["jsmDecimalSeparator"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1462
|
+
`, 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:#dc2626;margin-left:.125rem}.jsm-example{font-size:.6875rem;color:#6b7280;margin:0}.jsm-input,.jsm-textarea,.jsm-select{width:100%;border-radius:.5rem;border:1.5px solid #6b7280;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:#4b5563}.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:#dc2626!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:#6b7280;pointer-events:none}.jsm-toggle-label{display:inline-flex;align-items:center;gap:.625rem;cursor:pointer;-webkit-user-select:none;user-select:none;min-height:1.5rem}.jsm-toggle-track{position:relative;display:inline-flex;align-items:center;width:2.25rem;height:1.25rem;border-radius:9999px;flex-shrink:0;background:#6b7280;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:#b91c1c;min-height:1.5rem;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:#4b5563}.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:#6b7280;font-size:.8125rem;text-align:center}.jsm-contains-hint{display:flex;align-items:center;gap:.375rem;font-size:.75rem;color:#4f46e5;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 #6b7280;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}.jsm-input:focus-visible,.jsm-textarea:focus-visible,.jsm-select:focus-visible,.jsm-btn-primary:focus-visible,.jsm-btn-danger:focus-visible,.jsm-tab:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}.jsm-toggle-label:has(input:focus-visible) .jsm-toggle-track,.jsm-anyof-option:has(input:focus-visible){outline:2px solid #4f46e5;outline-offset:2px}.dark .jsm-field-label{color:#d1d5db}.dark .jsm-required{color:#f87171}.dark .jsm-example{color:#9ca3af}.dark .jsm-input:focus-visible,.dark .jsm-textarea:focus-visible,.dark .jsm-select:focus-visible,.dark .jsm-btn-primary:focus-visible,.dark .jsm-btn-danger:focus-visible,.dark .jsm-tab:focus-visible,.dark .jsm-toggle-label:has(input:focus-visible) .jsm-toggle-track,.dark .jsm-anyof-option:has(input:focus-visible){outline-color:#818cf8}.dark .jsm-btn-danger{color:#f87171;border-color:#f87171}.dark .jsm-btn-danger:hover{background:#f8717126}.dark .jsm-field-hint{color:#9ca3af}.dark .jsm-toggle-track{background:#64748b}.dark .jsm-toggle-track.jsm-on{background:#6366f1}.dark .jsm-toggle-text{color:#d1d5db}.dark .jsm-input,.dark .jsm-textarea,.dark .jsm-select{border-color:#64748b;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:#64748b;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:#94a3b8}.dark .jsm-contains-hint{background:#6366f126;color:#818cf8}.dark .jsm-add-prop{background:#1e293b66;border-color:#475569}.dark .jsm-add-prop-label{color:#94a3b8}.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:#94a3b8}\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: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i4.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i5.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: i5.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i5.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i5.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: NumericInputDirective, selector: "input[jsmNumeric]", inputs: ["jsmDecimalSeparator"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
1318
1463
|
}
|
|
1319
1464
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: JsonSchemaNodeComponent, decorators: [{
|
|
1320
1465
|
type: Component,
|
|
@@ -1330,14 +1475,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1330
1475
|
</div>
|
|
1331
1476
|
<span class="jsm-combinator-badge jsm-badge--oneof">oneOf</span>
|
|
1332
1477
|
</div>
|
|
1333
|
-
<div class="jsm-oneof-tabs">
|
|
1334
|
-
<button *ngFor="let option of schema.oneOf; let i = index" type="button"
|
|
1478
|
+
<div class="jsm-oneof-tabs" role="tablist" [attr.aria-label]="schema.title || label || null" (keydown)="onOneOfKeydown($event)">
|
|
1479
|
+
<button *ngFor="let option of schema.oneOf; let i = index" type="button" role="tab"
|
|
1335
1480
|
class="jsm-tab" [class.jsm-tab--active]="selectedOneOf === i"
|
|
1336
|
-
|
|
1337
|
-
|
|
1481
|
+
[id]="nodeId + '-tab-' + i" [attr.aria-selected]="selectedOneOf === i"
|
|
1482
|
+
[attr.aria-controls]="nodeId + '-panel'" [attr.tabindex]="selectedOneOf === i ? 0 : -1"
|
|
1483
|
+
(click)="selectOneOf(i)">
|
|
1484
|
+
{{ option.title || optionLabel(i) }}
|
|
1338
1485
|
</button>
|
|
1339
1486
|
</div>
|
|
1340
|
-
<div class="jsm-combinator-body" *ngIf="activeVariant"
|
|
1487
|
+
<div class="jsm-combinator-body" *ngIf="activeVariant" role="tabpanel" [id]="nodeId + '-panel'"
|
|
1488
|
+
[attr.aria-labelledby]="nodeId + '-tab-' + selectedOneOf">
|
|
1341
1489
|
<jsm-schema-node [schema]="activeVariant" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1342
1490
|
[path]="path" [errorsMap]="errorsMap" [label]="label" [required]="required"
|
|
1343
1491
|
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
@@ -1354,11 +1502,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1354
1502
|
</div>
|
|
1355
1503
|
<span class="jsm-combinator-badge jsm-badge--anyof">anyOf</span>
|
|
1356
1504
|
</div>
|
|
1357
|
-
<div class="jsm-anyof-options">
|
|
1505
|
+
<div class="jsm-anyof-options" role="group" [attr.aria-label]="schema.title || label || null">
|
|
1358
1506
|
<label *ngFor="let option of schema.anyOf; let i = index"
|
|
1359
1507
|
class="jsm-anyof-option" [class.jsm-anyof-option--active]="selectedAnyOf.has(i)">
|
|
1360
1508
|
<input type="checkbox" class="sr-only" [checked]="selectedAnyOf.has(i)" (change)="toggleAnyOf(i)" />
|
|
1361
|
-
{{ option.title || (
|
|
1509
|
+
{{ option.title || optionLabel(i) }}
|
|
1362
1510
|
</label>
|
|
1363
1511
|
</div>
|
|
1364
1512
|
<div class="jsm-combinator-body" *ngIf="activeVariant">
|
|
@@ -1381,7 +1529,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1381
1529
|
<div class="jsm-combinator-body">
|
|
1382
1530
|
<div *ngFor="let subSchema of mergedAllOf; let i = index" class="jsm-allof-section">
|
|
1383
1531
|
<jsm-schema-node [schema]="subSchema" [control]="control" [parent]="parent" [controlKey]="controlKey"
|
|
1384
|
-
[path]="path" [errorsMap]="errorsMap" [label]="subSchema.title || (
|
|
1532
|
+
[path]="path" [errorsMap]="errorsMap" [label]="subSchema.title || sectionLabel(i)" [required]="required"
|
|
1385
1533
|
[allowAdditionalProperties]="allowAdditionalProperties" [showErrors]="showErrors"
|
|
1386
1534
|
(controlReplaced)="controlReplaced.emit($event)"></jsm-schema-node>
|
|
1387
1535
|
</div>
|
|
@@ -1401,8 +1549,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1401
1549
|
<ng-container *ngFor="let key of simpleKeys">
|
|
1402
1550
|
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1403
1551
|
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1404
|
-
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1405
|
-
<button type="button" class="jsm-btn-danger"
|
|
1552
|
+
<span class="jsm-dynamic-key-label" [id]="keyId(key)">{{ key }}</span>
|
|
1553
|
+
<button type="button" class="jsm-btn-danger" [id]="keyId(key) + '-remove'"
|
|
1554
|
+
[attr.aria-labelledby]="keyId(key) + '-remove ' + keyId(key)" (click)="removeDynamicKey(key)">{{ l.remove }}</button>
|
|
1406
1555
|
</div>
|
|
1407
1556
|
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1408
1557
|
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
@@ -1416,8 +1565,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1416
1565
|
<ng-container *ngFor="let key of complexKeys">
|
|
1417
1566
|
<div style="display:flex;flex-direction:column;gap:.25rem;">
|
|
1418
1567
|
<div *ngIf="isDynamicKey(key)" class="jsm-dynamic-key-header">
|
|
1419
|
-
<span class="jsm-dynamic-key-label">{{ key }}</span>
|
|
1420
|
-
<button type="button" class="jsm-btn-danger"
|
|
1568
|
+
<span class="jsm-dynamic-key-label" [id]="keyId(key)">{{ key }}</span>
|
|
1569
|
+
<button type="button" class="jsm-btn-danger" [id]="keyId(key) + '-remove'"
|
|
1570
|
+
[attr.aria-labelledby]="keyId(key) + '-remove ' + keyId(key)" (click)="removeDynamicKey(key)">{{ l.remove }}</button>
|
|
1421
1571
|
</div>
|
|
1422
1572
|
<jsm-schema-node [schema]="schemaForKey(key)" [control]="childControl(key)" [parent]="controlAsGroup"
|
|
1423
1573
|
[controlKey]="key" [path]="pathForChild(key)" [errorsMap]="errorsMap" [label]="key"
|
|
@@ -1427,45 +1577,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1427
1577
|
</ng-container>
|
|
1428
1578
|
</div>
|
|
1429
1579
|
|
|
1430
|
-
<div *ngIf="canAddProperty" class="jsm-add-prop">
|
|
1431
|
-
<p class="jsm-add-prop-label">
|
|
1580
|
+
<div *ngIf="canAddProperty" class="jsm-add-prop" role="group" [attr.aria-labelledby]="nodeId + '-addprop'">
|
|
1581
|
+
<p class="jsm-add-prop-label" [id]="nodeId + '-addprop'">{{ l.addProperty }}</p>
|
|
1432
1582
|
<div class="jsm-add-prop-row">
|
|
1433
|
-
<input class="jsm-input jsm-input--sm" style="flex:1;" [(ngModel)]="newPropertyKey"
|
|
1434
|
-
|
|
1583
|
+
<input class="jsm-input jsm-input--sm" style="flex:1;" [(ngModel)]="newPropertyKey" [ngModelOptions]="{standalone: true}"
|
|
1584
|
+
[attr.aria-label]="l.propertyName" [attr.placeholder]="l.propertyName"
|
|
1585
|
+
[attr.aria-invalid]="propertyError ? 'true' : null" [attr.aria-describedby]="propertyError ? nodeId + '-prop-error' : null" />
|
|
1586
|
+
<button type="button" class="jsm-btn-primary" (click)="addDynamicProperty()">{{ l.add }}</button>
|
|
1435
1587
|
</div>
|
|
1436
|
-
<p *ngIf="propertyError" class="jsm-error-msg">
|
|
1437
|
-
<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>
|
|
1588
|
+
<p *ngIf="propertyError" class="jsm-error-msg" role="alert" [id]="nodeId + '-prop-error'">
|
|
1589
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
|
|
1438
1590
|
{{ propertyError }}
|
|
1439
1591
|
</p>
|
|
1440
1592
|
</div>
|
|
1441
1593
|
|
|
1442
|
-
<div *ngIf="errorsForPath.length" class="jsm-error-list" style="margin-top:.75rem;">
|
|
1594
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list" role="alert" style="margin-top:.75rem;">
|
|
1443
1595
|
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1444
|
-
<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>
|
|
1445
|
-
{{ error }}
|
|
1596
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
|
|
1597
|
+
{{ localize(error) }}
|
|
1446
1598
|
</p>
|
|
1447
1599
|
</div>
|
|
1448
1600
|
</fieldset>
|
|
1449
1601
|
|
|
1450
1602
|
<!-- ═══ array ═══ -->
|
|
1451
|
-
<div *ngSwitchCase="'array'" class="jsm-array-block">
|
|
1603
|
+
<div *ngSwitchCase="'array'" class="jsm-array-block" role="group" [attr.aria-labelledby]="nodeId + '-title'">
|
|
1452
1604
|
<div class="jsm-array-header">
|
|
1453
1605
|
<div>
|
|
1454
|
-
<p class="jsm-array-title">
|
|
1455
|
-
{{ schema.title || label }}<span *ngIf="required"
|
|
1606
|
+
<p class="jsm-array-title" [id]="nodeId + '-title'">
|
|
1607
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required" aria-hidden="true">*</span>
|
|
1456
1608
|
</p>
|
|
1457
1609
|
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1458
1610
|
</div>
|
|
1459
|
-
<button type="button" class="jsm-btn-primary"
|
|
1460
|
-
|
|
1461
|
-
|
|
1611
|
+
<button type="button" class="jsm-btn-primary" [id]="nodeId + '-add'"
|
|
1612
|
+
[attr.aria-labelledby]="nodeId + '-add ' + nodeId + '-title'" (click)="addArrayItem()" [disabled]="!canAddArrayItem">
|
|
1613
|
+
<svg style="width:.875rem;height:.875rem;flex-shrink:0;" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
1614
|
+
{{ l.addItem }}
|
|
1462
1615
|
</button>
|
|
1463
1616
|
</div>
|
|
1464
1617
|
|
|
1465
1618
|
<div *ngIf="effectiveSchema.contains" class="jsm-contains-hint">
|
|
1466
|
-
|
|
1467
|
-
<span *ngIf="effectiveSchema.minContains"> · min {
|
|
1468
|
-
<span *ngIf="effectiveSchema.maxContains"> · max {
|
|
1619
|
+
{{ l.mustContain }}
|
|
1620
|
+
<span *ngIf="effectiveSchema.minContains"> · {{ fmt(l.min, { n: effectiveSchema.minContains }) }}</span>
|
|
1621
|
+
<span *ngIf="effectiveSchema.maxContains"> · {{ fmt(l.max, { n: effectiveSchema.maxContains }) }}</span>
|
|
1469
1622
|
</div>
|
|
1470
1623
|
|
|
1471
1624
|
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
@@ -1473,10 +1626,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1473
1626
|
</div>
|
|
1474
1627
|
|
|
1475
1628
|
<div class="jsm-array-items" *ngIf="arrayControls.length > 0; else emptyArray">
|
|
1476
|
-
<div *ngFor="let item of arrayControls; let i = index" class="jsm-array-item">
|
|
1629
|
+
<div *ngFor="let item of arrayControls; let i = index" class="jsm-array-item" role="group" [attr.aria-labelledby]="nodeId + '-item-' + i">
|
|
1477
1630
|
<div class="jsm-array-item-header">
|
|
1478
|
-
<span class="jsm-array-index">{{ i + 1 }}</span>
|
|
1479
|
-
<
|
|
1631
|
+
<span class="jsm-array-index" aria-hidden="true">{{ i + 1 }}</span>
|
|
1632
|
+
<span class="sr-only" [id]="nodeId + '-item-' + i">{{ fmt(l.arrayItem, { n: i + 1 }) }}</span>
|
|
1633
|
+
<button type="button" class="jsm-btn-danger" [id]="nodeId + '-remove-' + i"
|
|
1634
|
+
[attr.aria-labelledby]="nodeId + '-remove-' + i + ' ' + nodeId + '-item-' + i" (click)="removeArrayItem(i)">{{ l.remove }}</button>
|
|
1480
1635
|
</div>
|
|
1481
1636
|
<jsm-schema-node [schema]="schemaForIndex(i)" [control]="item" [parent]="controlAsArray"
|
|
1482
1637
|
[controlKey]="i" [path]="pathForChild(i)" [errorsMap]="errorsMap" [label]="label + ' item'"
|
|
@@ -1486,13 +1641,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1486
1641
|
</div>
|
|
1487
1642
|
|
|
1488
1643
|
<ng-template #emptyArray>
|
|
1489
|
-
<div class="jsm-empty-array">
|
|
1644
|
+
<div class="jsm-empty-array">{{ l.noItems }}</div>
|
|
1490
1645
|
</ng-template>
|
|
1491
1646
|
|
|
1492
|
-
<div *ngIf="errorsForPath.length" class="jsm-error-list">
|
|
1647
|
+
<div *ngIf="errorsForPath.length" class="jsm-error-list" role="alert">
|
|
1493
1648
|
<p *ngFor="let error of errorsForPath" class="jsm-error-msg">
|
|
1494
|
-
<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>
|
|
1495
|
-
{{ error }}
|
|
1649
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true"><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>
|
|
1650
|
+
{{ localize(error) }}
|
|
1496
1651
|
</p>
|
|
1497
1652
|
</div>
|
|
1498
1653
|
</div>
|
|
@@ -1500,10 +1655,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1500
1655
|
<!-- ═══ primitive ═══ -->
|
|
1501
1656
|
<div *ngSwitchDefault class="jsm-field">
|
|
1502
1657
|
<ng-container *ngIf="inputKind !== 'checkbox'">
|
|
1503
|
-
<label class="jsm-field-label">
|
|
1504
|
-
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1658
|
+
<label class="jsm-field-label" [attr.for]="nodeId">
|
|
1659
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required" aria-hidden="true">*</span>
|
|
1505
1660
|
</label>
|
|
1506
|
-
<p *ngIf="schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1661
|
+
<p *ngIf="schema.description" class="jsm-field-hint" [id]="nodeId + '-hint'">{{ schema.description }}</p>
|
|
1507
1662
|
</ng-container>
|
|
1508
1663
|
|
|
1509
1664
|
<div *ngIf="metaBadges.length" class="jsm-badge-row">
|
|
@@ -1511,57 +1666,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1511
1666
|
</div>
|
|
1512
1667
|
|
|
1513
1668
|
<ng-container>
|
|
1514
|
-
<input *ngIf="inputKind === 'number'" jsmNumeric type="text" inputmode="decimal" class="jsm-input"
|
|
1669
|
+
<input *ngIf="inputKind === 'number'" jsmNumeric type="text" inputmode="decimal" class="jsm-input" [id]="nodeId"
|
|
1515
1670
|
[class.jsm-input--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1516
1671
|
[jsmDecimalSeparator]="decimalSeparator" [attr.data-step]="numericStep"
|
|
1517
|
-
[attr.
|
|
1672
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1673
|
+
[attr.aria-describedby]="describedBy"
|
|
1518
1674
|
[formControl]="controlAsFormControl"
|
|
1519
1675
|
(blur)="onBlur()" />
|
|
1520
1676
|
|
|
1521
|
-
<input *ngIf="inputKind === 'text'" class="jsm-input"
|
|
1677
|
+
<input *ngIf="inputKind === 'text'" class="jsm-input" [id]="nodeId"
|
|
1522
1678
|
[class.jsm-input--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1523
|
-
[attr.type]="inputType"
|
|
1679
|
+
[attr.type]="inputType"
|
|
1680
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1681
|
+
[attr.aria-describedby]="describedBy"
|
|
1524
1682
|
[formControl]="controlAsFormControl"
|
|
1525
1683
|
(blur)="onBlur()" />
|
|
1526
1684
|
|
|
1527
|
-
<textarea *ngIf="inputKind === 'textarea'" rows="4" class="jsm-textarea"
|
|
1685
|
+
<textarea *ngIf="inputKind === 'textarea'" rows="4" class="jsm-textarea" [id]="nodeId"
|
|
1528
1686
|
[class.jsm-textarea--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1529
|
-
[attr.
|
|
1687
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1688
|
+
[attr.aria-describedby]="describedBy"
|
|
1530
1689
|
[formControl]="controlAsFormControl"
|
|
1531
1690
|
(blur)="onBlur()"></textarea>
|
|
1532
1691
|
|
|
1533
1692
|
<div *ngIf="inputKind === 'select'" class="jsm-select-wrap">
|
|
1534
|
-
<select class="jsm-select"
|
|
1693
|
+
<select class="jsm-select" [id]="nodeId"
|
|
1535
1694
|
[class.jsm-select--error]="controlAsFormControl.invalid && (controlAsFormControl.dirty || isTouched || showErrors)"
|
|
1695
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1696
|
+
[attr.aria-describedby]="describedBy"
|
|
1536
1697
|
[formControl]="controlAsFormControl"
|
|
1537
1698
|
(blur)="onBlur()">
|
|
1538
1699
|
<option *ngFor="let option of effectiveSchema.enum" [ngValue]="option">{{ option }}</option>
|
|
1539
1700
|
</select>
|
|
1540
|
-
<svg class="jsm-select-chevron" viewBox="0 0 16 16" fill="none">
|
|
1701
|
+
<svg class="jsm-select-chevron" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1541
1702
|
<path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
1542
1703
|
</svg>
|
|
1543
1704
|
</div>
|
|
1544
1705
|
|
|
1545
1706
|
<label *ngIf="inputKind === 'checkbox'" class="jsm-toggle-label">
|
|
1546
1707
|
<span class="jsm-toggle-track" [class.jsm-on]="controlAsFormControl.value">
|
|
1547
|
-
<input type="checkbox" class="sr-only" [formControl]="controlAsFormControl"
|
|
1708
|
+
<input type="checkbox" class="sr-only" [id]="nodeId" [formControl]="controlAsFormControl"
|
|
1709
|
+
[attr.aria-required]="required ? 'true' : null" [attr.aria-invalid]="visibleError ? 'true' : null"
|
|
1710
|
+
[attr.aria-describedby]="describedBy" (blur)="onBlur()" />
|
|
1548
1711
|
<span class="jsm-toggle-thumb"></span>
|
|
1549
1712
|
</span>
|
|
1550
1713
|
<span class="jsm-toggle-text">
|
|
1551
|
-
{{ schema.title || label }}<span *ngIf="required" class="jsm-required">*</span>
|
|
1714
|
+
{{ schema.title || label }}<span *ngIf="required" class="jsm-required" aria-hidden="true">*</span>
|
|
1552
1715
|
</span>
|
|
1553
1716
|
</label>
|
|
1554
1717
|
</ng-container>
|
|
1555
1718
|
|
|
1556
|
-
<p *ngIf="inputKind === 'checkbox' && schema.description" class="jsm-field-hint">{{ schema.description }}</p>
|
|
1557
|
-
<p *ngIf="effectiveSchema.examples?.length" class="jsm-example">
|
|
1558
|
-
<p *ngIf="effectiveSchema.contentMediaType" class="jsm-example">
|
|
1719
|
+
<p *ngIf="inputKind === 'checkbox' && schema.description" class="jsm-field-hint" [id]="nodeId + '-hint'">{{ schema.description }}</p>
|
|
1720
|
+
<p *ngIf="effectiveSchema.examples?.length" class="jsm-example" [id]="nodeId + '-example'">{{ l.example }} {{ effectiveSchema.examples?.[0] }}</p>
|
|
1721
|
+
<p *ngIf="effectiveSchema.contentMediaType" class="jsm-example" [id]="nodeId + '-media'">
|
|
1559
1722
|
{{ effectiveSchema.contentMediaType }}<span *ngIf="effectiveSchema.contentEncoding"> ({{ effectiveSchema.contentEncoding }})</span>
|
|
1560
1723
|
</p>
|
|
1561
1724
|
|
|
1562
|
-
<div *ngIf="
|
|
1725
|
+
<div *ngIf="visibleError" class="jsm-error-list" role="alert" [id]="nodeId + '-error'">
|
|
1563
1726
|
<p *ngFor="let error of allErrors" class="jsm-error-msg">
|
|
1564
|
-
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none">
|
|
1727
|
+
<svg class="jsm-error-icon" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1565
1728
|
<circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.5"/>
|
|
1566
1729
|
<path d="M8 5v3.5M8 11v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
1567
1730
|
</svg>
|
|
@@ -1571,7 +1734,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1571
1734
|
</div>
|
|
1572
1735
|
|
|
1573
1736
|
</ng-container>
|
|
1574
|
-
`, 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"] }]
|
|
1737
|
+
`, 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:#dc2626;margin-left:.125rem}.jsm-example{font-size:.6875rem;color:#6b7280;margin:0}.jsm-input,.jsm-textarea,.jsm-select{width:100%;border-radius:.5rem;border:1.5px solid #6b7280;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:#4b5563}.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:#dc2626!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:#6b7280;pointer-events:none}.jsm-toggle-label{display:inline-flex;align-items:center;gap:.625rem;cursor:pointer;-webkit-user-select:none;user-select:none;min-height:1.5rem}.jsm-toggle-track{position:relative;display:inline-flex;align-items:center;width:2.25rem;height:1.25rem;border-radius:9999px;flex-shrink:0;background:#6b7280;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:#b91c1c;min-height:1.5rem;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:#4b5563}.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:#6b7280;font-size:.8125rem;text-align:center}.jsm-contains-hint{display:flex;align-items:center;gap:.375rem;font-size:.75rem;color:#4f46e5;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 #6b7280;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}.jsm-input:focus-visible,.jsm-textarea:focus-visible,.jsm-select:focus-visible,.jsm-btn-primary:focus-visible,.jsm-btn-danger:focus-visible,.jsm-tab:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}.jsm-toggle-label:has(input:focus-visible) .jsm-toggle-track,.jsm-anyof-option:has(input:focus-visible){outline:2px solid #4f46e5;outline-offset:2px}.dark .jsm-field-label{color:#d1d5db}.dark .jsm-required{color:#f87171}.dark .jsm-example{color:#9ca3af}.dark .jsm-input:focus-visible,.dark .jsm-textarea:focus-visible,.dark .jsm-select:focus-visible,.dark .jsm-btn-primary:focus-visible,.dark .jsm-btn-danger:focus-visible,.dark .jsm-tab:focus-visible,.dark .jsm-toggle-label:has(input:focus-visible) .jsm-toggle-track,.dark .jsm-anyof-option:has(input:focus-visible){outline-color:#818cf8}.dark .jsm-btn-danger{color:#f87171;border-color:#f87171}.dark .jsm-btn-danger:hover{background:#f8717126}.dark .jsm-field-hint{color:#9ca3af}.dark .jsm-toggle-track{background:#64748b}.dark .jsm-toggle-track.jsm-on{background:#6366f1}.dark .jsm-toggle-text{color:#d1d5db}.dark .jsm-input,.dark .jsm-textarea,.dark .jsm-select{border-color:#64748b;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:#64748b;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:#94a3b8}.dark .jsm-contains-hint{background:#6366f126;color:#818cf8}.dark .jsm-add-prop{background:#1e293b66;border-color:#475569}.dark .jsm-add-prop-label{color:#94a3b8}.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:#94a3b8}\n"] }]
|
|
1575
1738
|
}], ctorParameters: () => [{ type: JsonSchemaFormService }, { type: JsonSchemaValidationService }, { type: i0.ChangeDetectorRef }, { type: JsonSchemaFormOptions, decorators: [{
|
|
1576
1739
|
type: Optional
|
|
1577
1740
|
}] }], propDecorators: { schema: [{
|
|
@@ -1784,6 +1947,8 @@ class JsonSchemaFormComponent {
|
|
|
1784
1947
|
* either way); the emitted value is always a JSON number.
|
|
1785
1948
|
*/
|
|
1786
1949
|
decimalSeparator = '.';
|
|
1950
|
+
/** Texts shown by the form (translate them here); omitted keys keep the English default. */
|
|
1951
|
+
labels = {};
|
|
1787
1952
|
formReady = new EventEmitter();
|
|
1788
1953
|
valueChange = new EventEmitter();
|
|
1789
1954
|
schemaReady = new EventEmitter();
|
|
@@ -1797,6 +1962,8 @@ class JsonSchemaFormComponent {
|
|
|
1797
1962
|
/** When true, all field errors are shown regardless of touched/dirty state. */
|
|
1798
1963
|
showErrors = false;
|
|
1799
1964
|
valueSub;
|
|
1965
|
+
/** Last value emitted through valueChange (same reference the parent gets back through `data`/`value`). */
|
|
1966
|
+
lastEmitted;
|
|
1800
1967
|
constructor(schemaService, resolver, validation, cdr, options, stylesService) {
|
|
1801
1968
|
this.schemaService = schemaService;
|
|
1802
1969
|
this.resolver = resolver;
|
|
@@ -1809,6 +1976,9 @@ class JsonSchemaFormComponent {
|
|
|
1809
1976
|
if (changes['decimalSeparator']) {
|
|
1810
1977
|
this.options.decimalSeparator = this.decimalSeparator;
|
|
1811
1978
|
}
|
|
1979
|
+
if (changes['labels']) {
|
|
1980
|
+
this.options.labels = { ...DEFAULT_LABELS, ...this.labels };
|
|
1981
|
+
}
|
|
1812
1982
|
if (changes['schema']) {
|
|
1813
1983
|
// Schema changed — full rebuild required
|
|
1814
1984
|
void this.buildForm();
|
|
@@ -1816,7 +1986,11 @@ class JsonSchemaFormComponent {
|
|
|
1816
1986
|
else if ((changes['value'] || changes['data']) && this.form) {
|
|
1817
1987
|
// Only data changed and form already exists — patch values without rebuilding
|
|
1818
1988
|
const newData = this.value !== undefined ? this.value : this.data;
|
|
1819
|
-
|
|
1989
|
+
// The parent usually feeds back what valueChange just emitted: patching it would overwrite the text being
|
|
1990
|
+
// typed (e.g. "45," would become "45"), so a round trip of the emitted value is ignored.
|
|
1991
|
+
if (newData !== this.lastEmitted) {
|
|
1992
|
+
this.form.patchValue(newData, { emitEvent: false });
|
|
1993
|
+
}
|
|
1820
1994
|
}
|
|
1821
1995
|
else if (changes['value'] || changes['data']) {
|
|
1822
1996
|
// Form not built yet — build it
|
|
@@ -1898,24 +2072,25 @@ class JsonSchemaFormComponent {
|
|
|
1898
2072
|
this.updateErrors();
|
|
1899
2073
|
this.valueSub = this.form.valueChanges.subscribe(() => {
|
|
1900
2074
|
this.updateErrors();
|
|
1901
|
-
this.
|
|
2075
|
+
this.lastEmitted = this.resolvedSchema ? normalizeValue(this.resolvedSchema, this.rootControl.value) : this.rootControl.value;
|
|
2076
|
+
this.valueChange.emit(this.lastEmitted);
|
|
1902
2077
|
});
|
|
1903
2078
|
}
|
|
1904
2079
|
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: JsonSchemaFormOptions }, { token: JsonSchemaStylesService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1905
|
-
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", decimalSeparator: "decimalSeparator" }, outputs: { formReady: "formReady", valueChange: "valueChange", schemaReady: "schemaReady", schemaErrors: "schemaErrors" }, providers: [JsonSchemaFormOptions], usesOnChanges: true, ngImport: i0, template: `
|
|
2080
|
+
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", decimalSeparator: "decimalSeparator", labels: "labels" }, outputs: { formReady: "formReady", valueChange: "valueChange", schemaReady: "schemaReady", schemaErrors: "schemaErrors" }, providers: [JsonSchemaFormOptions], usesOnChanges: true, ngImport: i0, template: `
|
|
1906
2081
|
<div class="jsm-root">
|
|
1907
2082
|
<form class="w-full space-y-5">
|
|
1908
2083
|
<div *ngIf="resolvedSchema?.title || resolvedSchema?.description" class="space-y-0.5">
|
|
1909
|
-
<h2 class="text-lg font-bold tracking-tight text-slate-900 dark:text-white">{{ resolvedSchema?.title ||
|
|
2084
|
+
<h2 class="text-lg font-bold tracking-tight text-slate-900 dark:text-white">{{ resolvedSchema?.title || options.labels.formTitle }}</h2>
|
|
1910
2085
|
<p *ngIf="resolvedSchema?.description" class="text-sm text-slate-500 dark:text-slate-400">{{ resolvedSchema?.description }}</p>
|
|
1911
2086
|
</div>
|
|
1912
2087
|
|
|
1913
|
-
<div *ngIf="loading" class="flex items-center gap-2 py-6 text-sm text-slate-500 dark:text-slate-400"
|
|
1914
|
-
<svg class="h-4 w-4 animate-spin text-indigo-500 dark:text-indigo-400" viewBox="0 0 24 24" fill="none">
|
|
2088
|
+
<div *ngIf="loading" class="flex items-center gap-2 py-6 text-sm text-slate-500 dark:text-slate-400" role="status">
|
|
2089
|
+
<svg class="h-4 w-4 animate-spin text-indigo-500 dark:text-indigo-400" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
1915
2090
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
|
1916
2091
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"/>
|
|
1917
2092
|
</svg>
|
|
1918
|
-
|
|
2093
|
+
{{ options.labels.resolving }}
|
|
1919
2094
|
</div>
|
|
1920
2095
|
|
|
1921
2096
|
<!-- schema structural errors panel -->
|
|
@@ -1923,16 +2098,16 @@ class JsonSchemaFormComponent {
|
|
|
1923
2098
|
class="rounded-xl border border-amber-300 dark:border-amber-700 bg-amber-50 dark:bg-amber-900/20 p-4 space-y-3"
|
|
1924
2099
|
role="alert">
|
|
1925
2100
|
<div class="flex items-center gap-2">
|
|
1926
|
-
<svg class="w-4 h-4 shrink-0 text-amber-600 dark:text-amber-400" viewBox="0 0 16 16" fill="none">
|
|
2101
|
+
<svg class="w-4 h-4 shrink-0 text-amber-600 dark:text-amber-400" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1927
2102
|
<path d="M8 2L1.5 13.5h13L8 2z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
|
1928
2103
|
<path d="M8 6v3.5M8 11.5v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
1929
2104
|
</svg>
|
|
1930
2105
|
<span class="text-sm font-semibold text-amber-800 dark:text-amber-300">
|
|
1931
|
-
|
|
2106
|
+
{{ options.labels.schemaErrorsTitle }} ({{ schemaErrorList.length }})
|
|
1932
2107
|
</span>
|
|
1933
2108
|
</div>
|
|
1934
2109
|
<p class="text-xs text-amber-700 dark:text-amber-400">
|
|
1935
|
-
|
|
2110
|
+
{{ options.labels.schemaErrorsHint }}
|
|
1936
2111
|
</p>
|
|
1937
2112
|
<div class="space-y-2">
|
|
1938
2113
|
<div *ngFor="let err of schemaErrorList"
|
|
@@ -1966,16 +2141,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1966
2141
|
<div class="jsm-root">
|
|
1967
2142
|
<form class="w-full space-y-5">
|
|
1968
2143
|
<div *ngIf="resolvedSchema?.title || resolvedSchema?.description" class="space-y-0.5">
|
|
1969
|
-
<h2 class="text-lg font-bold tracking-tight text-slate-900 dark:text-white">{{ resolvedSchema?.title ||
|
|
2144
|
+
<h2 class="text-lg font-bold tracking-tight text-slate-900 dark:text-white">{{ resolvedSchema?.title || options.labels.formTitle }}</h2>
|
|
1970
2145
|
<p *ngIf="resolvedSchema?.description" class="text-sm text-slate-500 dark:text-slate-400">{{ resolvedSchema?.description }}</p>
|
|
1971
2146
|
</div>
|
|
1972
2147
|
|
|
1973
|
-
<div *ngIf="loading" class="flex items-center gap-2 py-6 text-sm text-slate-500 dark:text-slate-400"
|
|
1974
|
-
<svg class="h-4 w-4 animate-spin text-indigo-500 dark:text-indigo-400" viewBox="0 0 24 24" fill="none">
|
|
2148
|
+
<div *ngIf="loading" class="flex items-center gap-2 py-6 text-sm text-slate-500 dark:text-slate-400" role="status">
|
|
2149
|
+
<svg class="h-4 w-4 animate-spin text-indigo-500 dark:text-indigo-400" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
|
1975
2150
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
|
1976
2151
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"/>
|
|
1977
2152
|
</svg>
|
|
1978
|
-
|
|
2153
|
+
{{ options.labels.resolving }}
|
|
1979
2154
|
</div>
|
|
1980
2155
|
|
|
1981
2156
|
<!-- schema structural errors panel -->
|
|
@@ -1983,16 +2158,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1983
2158
|
class="rounded-xl border border-amber-300 dark:border-amber-700 bg-amber-50 dark:bg-amber-900/20 p-4 space-y-3"
|
|
1984
2159
|
role="alert">
|
|
1985
2160
|
<div class="flex items-center gap-2">
|
|
1986
|
-
<svg class="w-4 h-4 shrink-0 text-amber-600 dark:text-amber-400" viewBox="0 0 16 16" fill="none">
|
|
2161
|
+
<svg class="w-4 h-4 shrink-0 text-amber-600 dark:text-amber-400" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
1987
2162
|
<path d="M8 2L1.5 13.5h13L8 2z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
|
1988
2163
|
<path d="M8 6v3.5M8 11.5v.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
1989
2164
|
</svg>
|
|
1990
2165
|
<span class="text-sm font-semibold text-amber-800 dark:text-amber-300">
|
|
1991
|
-
|
|
2166
|
+
{{ options.labels.schemaErrorsTitle }} ({{ schemaErrorList.length }})
|
|
1992
2167
|
</span>
|
|
1993
2168
|
</div>
|
|
1994
2169
|
<p class="text-xs text-amber-700 dark:text-amber-400">
|
|
1995
|
-
|
|
2170
|
+
{{ options.labels.schemaErrorsHint }}
|
|
1996
2171
|
</p>
|
|
1997
2172
|
<div class="space-y-2">
|
|
1998
2173
|
<div *ngFor="let err of schemaErrorList"
|
|
@@ -2030,6 +2205,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
2030
2205
|
type: Input
|
|
2031
2206
|
}], decimalSeparator: [{
|
|
2032
2207
|
type: Input
|
|
2208
|
+
}], labels: [{
|
|
2209
|
+
type: Input
|
|
2033
2210
|
}], formReady: [{
|
|
2034
2211
|
type: Output
|
|
2035
2212
|
}], valueChange: [{
|
|
@@ -2057,5 +2234,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
2057
2234
|
* Generated bundle index. Do not edit.
|
|
2058
2235
|
*/
|
|
2059
2236
|
|
|
2060
|
-
export { JsonSchemaFormComponent, JsonSchemaFormModule, JsonSchemaFormOptions, JsonSchemaFormService, JsonSchemaNodeComponent, JsonSchemaResolverService, JsonSchemaStylesService, JsonSchemaValidationService, NumericInputDirective, formatNumeric, localizeNumbers, normalizeValue, parseNumericText, sanitizeNumericText };
|
|
2237
|
+
export { DEFAULT_LABELS, JsonSchemaFormComponent, JsonSchemaFormModule, JsonSchemaFormOptions, JsonSchemaFormService, JsonSchemaNodeComponent, JsonSchemaResolverService, JsonSchemaStylesService, JsonSchemaValidationService, NumericInputDirective, formatLabel, formatNumeric, localizeNumbers, normalizeValue, parseNumericText, sanitizeNumericText };
|
|
2061
2238
|
//# sourceMappingURL=elle96-ng-json-schema-manager.mjs.map
|