jedison 1.5.0 → 1.6.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.
@@ -32,7 +32,7 @@ function replaceAll(str, find, replace) {
32
32
  return str.replace(new RegExp(escapeRegExp(find), "g"), replace);
33
33
  }
34
34
  function pathToAttribute(path) {
35
- return replaceAll(replaceAll(path, "#", "root"), "/", "-");
35
+ return replaceAll(replaceAll(path, "#", "root"), "/", "-").replace(/[^a-zA-Z0-9_-]/g, "");
36
36
  }
37
37
  function hasOwn(obj, prop) {
38
38
  return Object.prototype.hasOwnProperty.call(obj, prop);
@@ -220,6 +220,19 @@ function removeDuplicatesFromArray(arr) {
220
220
  }
221
221
  return uniqueObjects;
222
222
  }
223
+ function resolveInstancePath(currentPath, sourcePath) {
224
+ if (sourcePath.startsWith("#")) return sourcePath;
225
+ const parts = currentPath.split("/");
226
+ parts.pop();
227
+ for (const part of sourcePath.split("/")) {
228
+ if (part === "..") {
229
+ if (parts.length > 1) parts.pop();
230
+ } else if (part !== "." && part !== "") {
231
+ parts.push(part);
232
+ }
233
+ }
234
+ return parts.join("/");
235
+ }
223
236
  function generateRandomID(maxLength2) {
224
237
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
225
238
  let randomID = "";
@@ -510,14 +523,33 @@ function allOf(context) {
510
523
  let errors = [];
511
524
  const allOf2 = getSchemaAllOf(context.schema);
512
525
  if (isSet(allOf2)) {
513
- allOf2.forEach((schema) => {
514
- const subSchemaErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
515
- subSchemaErrors.forEach((error) => {
516
- error.path = context.path;
526
+ const enableSubErrors = getSchemaXOption(context.schema, "subErrors") ?? context.validator.subErrors;
527
+ if (enableSubErrors) {
528
+ const schemaResults = [];
529
+ allOf2.forEach((schema, index2) => {
530
+ const subSchemaErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
531
+ if (subSchemaErrors.length > 0) {
532
+ schemaResults.push({ schemaIndex: index2, errors: subSchemaErrors });
533
+ }
517
534
  });
518
- errors.push(...subSchemaErrors);
519
- });
520
- errors = removeDuplicatesFromArray(errors);
535
+ if (schemaResults.length > 0) {
536
+ errors.push({
537
+ type: "error",
538
+ path: context.path,
539
+ constraint: "allOf",
540
+ subErrors: schemaResults
541
+ });
542
+ }
543
+ } else {
544
+ allOf2.forEach((schema) => {
545
+ const subSchemaErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
546
+ subSchemaErrors.forEach((error) => {
547
+ error.path = context.path;
548
+ });
549
+ errors.push(...subSchemaErrors);
550
+ });
551
+ errors = removeDuplicatesFromArray(errors);
552
+ }
521
553
  }
522
554
  return errors;
523
555
  }
@@ -546,23 +578,46 @@ function anyOf(context) {
546
578
  const errors = [];
547
579
  const anyOf2 = getSchemaAnyOf(context.schema);
548
580
  if (isSet(anyOf2)) {
581
+ const enableSubErrors = getSchemaXOption(context.schema, "subErrors") ?? context.validator.subErrors;
549
582
  let valid = false;
550
- for (const schema of anyOf2) {
551
- const anyOfErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
552
- if (anyOfErrors.length === 0) {
553
- valid = true;
554
- break;
555
- }
556
- }
557
- if (!valid) {
558
- errors.push({
559
- type: "error",
560
- path: context.path,
561
- constraint: "anyOf",
562
- messages: [
563
- context.translator.translate("errorAnyOf")
564
- ]
583
+ if (enableSubErrors) {
584
+ const schemaResults = [];
585
+ anyOf2.forEach((schema, index2) => {
586
+ const anyOfErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
587
+ if (anyOfErrors.length === 0) {
588
+ valid = true;
589
+ }
590
+ schemaResults.push({ schemaIndex: index2, errors: anyOfErrors });
565
591
  });
592
+ if (!valid) {
593
+ errors.push({
594
+ type: "error",
595
+ path: context.path,
596
+ constraint: "anyOf",
597
+ messages: [
598
+ context.translator.translate("errorAnyOf")
599
+ ],
600
+ subErrors: schemaResults.filter((r) => r.errors.length > 0)
601
+ });
602
+ }
603
+ } else {
604
+ for (const schema of anyOf2) {
605
+ const anyOfErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
606
+ if (anyOfErrors.length === 0) {
607
+ valid = true;
608
+ break;
609
+ }
610
+ }
611
+ if (!valid) {
612
+ errors.push({
613
+ type: "error",
614
+ path: context.path,
615
+ constraint: "anyOf",
616
+ messages: [
617
+ context.translator.translate("errorAnyOf")
618
+ ]
619
+ });
620
+ }
566
621
  }
567
622
  }
568
623
  return errors;
@@ -630,10 +685,8 @@ function exclusiveMinimum(context) {
630
685
  function format(context) {
631
686
  const errors = [];
632
687
  const format2 = getSchemaFormat(context.schema);
633
- let assertFormat = context.validator.assertFormat;
634
- if (getSchemaXOption(context.schema, "assertFormat")) {
635
- assertFormat = context.schema.options.assertFormat;
636
- }
688
+ const xAssertFormat = getSchemaXOption(context.schema, "assertFormat");
689
+ const assertFormat = xAssertFormat !== void 0 ? xAssertFormat : context.validator.assertFormat;
637
690
  if (isSet(format2) && isString(context.value) && assertFormat) {
638
691
  let regexp;
639
692
  if (format2 === "email") {
@@ -673,18 +726,23 @@ function items(context) {
673
726
  messages: [context.translator.translate("errorItems")]
674
727
  });
675
728
  } else if (isObject(items2)) {
729
+ const enableSubErrors = getSchemaXOption(context.schema, "subErrors") ?? context.validator.subErrors;
676
730
  context.value.slice(prefixItemsSchemasCount).forEach((itemValue, i) => {
677
731
  const index2 = prefixItemsSchemasCount + i;
678
732
  const tmpErrors = context.validator.getErrors(itemValue, items2, index2, context.path + "/" + index2);
679
733
  if (tmpErrors.length > 0) {
680
- errors.push({
734
+ const error = {
681
735
  type: "error",
682
736
  path: context.path,
683
737
  constraint: "items",
684
738
  messages: [
685
739
  compileTemplate(context.translator.translate("errorItems"), { index: index2 })
686
740
  ]
687
- });
741
+ };
742
+ if (enableSubErrors) {
743
+ error.subErrors = tmpErrors;
744
+ }
745
+ errors.push(error);
688
746
  }
689
747
  });
690
748
  }
@@ -862,23 +920,64 @@ function oneOf(context) {
862
920
  const oneOf2 = getSchemaOneOf(context.schema);
863
921
  if (isSet(oneOf2)) {
864
922
  let counter = 0;
865
- oneOf2.forEach((schema) => {
866
- const oneOfErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
867
- if (oneOfErrors.length === 0) {
868
- counter++;
923
+ const enableSubErrors = getSchemaXOption(context.schema, "subErrors") ?? context.validator.subErrors;
924
+ if (enableSubErrors) {
925
+ const schemaResults = [];
926
+ oneOf2.forEach((schema, index2) => {
927
+ const oneOfErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
928
+ if (oneOfErrors.length === 0) {
929
+ counter++;
930
+ schemaResults.push({ schemaIndex: index2, matched: true, errors: [] });
931
+ } else {
932
+ schemaResults.push({ schemaIndex: index2, matched: false, errors: oneOfErrors });
933
+ }
934
+ });
935
+ if (counter !== 1) {
936
+ const error = {
937
+ type: "error",
938
+ path: context.path,
939
+ constraint: "oneOf",
940
+ messages: [
941
+ compileTemplate(context.translator.translate("errorOneOf"), {
942
+ counter
943
+ })
944
+ ]
945
+ };
946
+ if (counter === 0) {
947
+ error.subErrors = schemaResults.filter((r) => !r.matched).map((r) => ({
948
+ schemaIndex: r.schemaIndex,
949
+ errors: r.errors
950
+ }));
951
+ } else {
952
+ error.matchingSchemas = schemaResults.filter((r) => r.matched).map((r) => r.schemaIndex);
953
+ }
954
+ errors.push(error);
869
955
  }
870
- });
871
- if (counter !== 1) {
872
- errors.push({
873
- type: "error",
874
- path: context.path,
875
- constraint: "oneOf",
876
- messages: [
877
- compileTemplate(context.translator.translate("errorOneOf"), {
878
- counter
879
- })
880
- ]
956
+ } else {
957
+ const matchingSchemas = [];
958
+ oneOf2.forEach((schema, index2) => {
959
+ const oneOfErrors = context.validator.getErrors(context.value, schema, context.key, context.path);
960
+ if (oneOfErrors.length === 0) {
961
+ counter++;
962
+ matchingSchemas.push(index2);
963
+ }
881
964
  });
965
+ if (counter !== 1) {
966
+ const error = {
967
+ type: "error",
968
+ path: context.path,
969
+ constraint: "oneOf",
970
+ messages: [
971
+ compileTemplate(context.translator.translate("errorOneOf"), {
972
+ counter
973
+ })
974
+ ]
975
+ };
976
+ if (counter > 0) {
977
+ error.matchingSchemas = matchingSchemas;
978
+ }
979
+ errors.push(error);
980
+ }
882
981
  }
883
982
  }
884
983
  return errors;
@@ -931,6 +1030,8 @@ function patternProperties(context) {
931
1030
  function properties(context) {
932
1031
  const schemaProperties = getSchemaProperties(context.schema);
933
1032
  const invalidProperties = [];
1033
+ const enableSubErrors = getSchemaXOption(context.schema, "subErrors") ?? context.validator.subErrors;
1034
+ const propertySubErrors = [];
934
1035
  if (isObject(context.value) && isSet(schemaProperties)) {
935
1036
  Object.keys(schemaProperties).forEach((propertyName) => {
936
1037
  if (hasOwn(context.value, propertyName)) {
@@ -943,19 +1044,26 @@ function properties(context) {
943
1044
  );
944
1045
  if (propertyErrors.length > 0) {
945
1046
  invalidProperties.push(propertyName);
1047
+ if (enableSubErrors) {
1048
+ propertySubErrors.push({ property: propertyName, errors: propertyErrors });
1049
+ }
946
1050
  }
947
1051
  }
948
1052
  });
949
1053
  }
950
1054
  if (invalidProperties.length > 0) {
951
- return [{
1055
+ const error = {
952
1056
  type: "error",
953
1057
  path: context.path,
954
1058
  constraint: "properties",
955
1059
  messages: [
956
1060
  compileTemplate(context.translator.translate("errorProperties"), { properties: invalidProperties.join(", ") })
957
1061
  ]
958
- }];
1062
+ };
1063
+ if (enableSubErrors) {
1064
+ error.subErrors = propertySubErrors;
1065
+ }
1066
+ return [error];
959
1067
  }
960
1068
  return [];
961
1069
  }
@@ -1232,9 +1340,11 @@ function dependentRequired(context) {
1232
1340
  Object.keys(dependentRequired2).forEach((key) => {
1233
1341
  if (isSet(context.value[key])) {
1234
1342
  const requiredProperties = dependentRequired2[key];
1235
- missingProperties = requiredProperties.filter((property) => {
1236
- return !hasOwn(context.value, property);
1237
- });
1343
+ if (isArray(requiredProperties)) {
1344
+ missingProperties = requiredProperties.filter((property) => {
1345
+ return !hasOwn(context.value, property);
1346
+ });
1347
+ }
1238
1348
  }
1239
1349
  });
1240
1350
  const invalid = missingProperties.length > 0;
@@ -1293,12 +1403,13 @@ function prefixItems(context) {
1293
1403
  const errors = [];
1294
1404
  const prefixItems2 = getSchemaPrefixItems(context.schema);
1295
1405
  if (isArray(context.value) && isSet(prefixItems2)) {
1406
+ const enableSubErrors = getSchemaXOption(context.schema, "subErrors") ?? context.validator.subErrors;
1296
1407
  prefixItems2.forEach((itemSchema, index2) => {
1297
1408
  const itemValue = context.value[index2];
1298
1409
  if (isSet(itemValue)) {
1299
1410
  const tmpErrors = context.validator.getErrors(itemValue, itemSchema, index2, context.path + "/" + index2);
1300
1411
  if (tmpErrors.length > 0) {
1301
- errors.push({
1412
+ const error = {
1302
1413
  type: "error",
1303
1414
  path: context.path,
1304
1415
  constraint: "prefixItems",
@@ -1307,7 +1418,11 @@ function prefixItems(context) {
1307
1418
  index: index2
1308
1419
  })
1309
1420
  ]
1310
- });
1421
+ };
1422
+ if (enableSubErrors) {
1423
+ error.subErrors = tmpErrors;
1424
+ }
1425
+ errors.push(error);
1311
1426
  }
1312
1427
  }
1313
1428
  });
@@ -1538,6 +1653,7 @@ class Validator {
1538
1653
  this.constraints = config.constraints ?? {};
1539
1654
  this.assertFormat = config.assertFormat ? config.assertFormat : false;
1540
1655
  this.translator = config.translator ? config.translator : false;
1656
+ this.subErrors = config.subErrors ?? false;
1541
1657
  this.draft = draft202012;
1542
1658
  this.jsonSchemaDrafts = {
1543
1659
  "http://json-schema.org/draft-04/schema#": draft04,
@@ -2123,11 +2239,13 @@ class Editor {
2123
2239
  });
2124
2240
  this.control.messages.innerHTML = "";
2125
2241
  this.showingValidationErrors = false;
2242
+ this.setAriaInvalid(false);
2126
2243
  const neverShowErrors = this.instance.jedison.options.showErrors === "never" || getSchemaXOption(this.instance.schema, "showErrors") === "never";
2127
2244
  if (neverShowErrors && !force || errors.length === 0) {
2128
2245
  return;
2129
2246
  }
2130
2247
  const muteValidationMessages = getSchemaXOption(this.instance.schema, "muteValidationMessages") ?? this.instance.jedison.options.muteValidationMessages ?? [];
2248
+ let hasErrors = false;
2131
2249
  errors.forEach((error) => {
2132
2250
  if (muteValidationMessages.includes(error.constraint)) {
2133
2251
  return;
@@ -2135,6 +2253,7 @@ class Editor {
2135
2253
  error.messages.forEach((message) => {
2136
2254
  let invalidFeedback;
2137
2255
  if (error.type === "error") {
2256
+ hasErrors = true;
2138
2257
  invalidFeedback = this.getErrorFeedback({
2139
2258
  message
2140
2259
  });
@@ -2146,8 +2265,20 @@ class Editor {
2146
2265
  this.control.messages.appendChild(invalidFeedback);
2147
2266
  });
2148
2267
  });
2268
+ if (hasErrors) {
2269
+ this.setAriaInvalid(true);
2270
+ }
2149
2271
  this.showingValidationErrors = true;
2150
2272
  }
2273
+ setAriaInvalid(invalid) {
2274
+ if (this.control.input) {
2275
+ if (invalid) {
2276
+ this.control.input.setAttribute("aria-invalid", "true");
2277
+ } else {
2278
+ this.control.input.removeAttribute("aria-invalid");
2279
+ }
2280
+ }
2281
+ }
2151
2282
  /**
2152
2283
  * Get an error message container
2153
2284
  */
@@ -2234,6 +2365,8 @@ class Editor {
2234
2365
  }
2235
2366
  return schemaInfo;
2236
2367
  }
2368
+ refreshLegendWarning() {
2369
+ }
2237
2370
  /**
2238
2371
  * Updates control UI when its state changes
2239
2372
  */
@@ -2635,6 +2768,21 @@ class InstanceMultiple extends Instance {
2635
2768
  * Returns the index of the instance that has less validation errors
2636
2769
  */
2637
2770
  getFittestIndex(value) {
2771
+ const discriminator = getSchemaXOption(this.schema, "discriminator");
2772
+ if (isSet(discriminator) && isObject(value)) {
2773
+ const propName = isString(discriminator) ? discriminator : discriminator.propertyName;
2774
+ const discriminatorValue = value[propName];
2775
+ if (isSet(discriminatorValue)) {
2776
+ for (let index2 = 0; index2 < this.schemas.length; index2++) {
2777
+ const schema = this.schemas[index2];
2778
+ const propSchema = schema.properties && schema.properties[propName];
2779
+ if (propSchema) {
2780
+ const propErrors = this.jedison.validator.getErrors(discriminatorValue, propSchema, propName, this.path);
2781
+ if (propErrors.length === 0) return index2;
2782
+ }
2783
+ }
2784
+ }
2785
+ }
2638
2786
  let fittestIndex;
2639
2787
  let championErrors;
2640
2788
  for (let index2 = 0; index2 < this.instances.length; index2++) {
@@ -2761,9 +2909,11 @@ class InstanceObject extends Instance {
2761
2909
  Object.keys(dependentRequired2).forEach((key) => {
2762
2910
  if (isSet(this.value[key])) {
2763
2911
  const requiredProperties = dependentRequired2[key];
2764
- missingProperties = requiredProperties.filter((property2) => {
2765
- return !hasOwn(this.value, property2);
2766
- });
2912
+ if (isArray(requiredProperties)) {
2913
+ missingProperties = requiredProperties.filter((property2) => {
2914
+ return !hasOwn(this.value, property2);
2915
+ });
2916
+ }
2767
2917
  }
2768
2918
  });
2769
2919
  return missingProperties.includes(property);
@@ -3149,6 +3299,15 @@ class EditorRadios extends EditorBoolean {
3149
3299
  radio.checked = radioValue === this.instance.getValue();
3150
3300
  });
3151
3301
  }
3302
+ setAriaInvalid(invalid) {
3303
+ this.control.radios.forEach((radio) => {
3304
+ if (invalid) {
3305
+ radio.setAttribute("aria-invalid", "true");
3306
+ } else {
3307
+ radio.removeAttribute("aria-invalid");
3308
+ }
3309
+ });
3310
+ }
3152
3311
  }
3153
3312
  class EditorBooleanSelect extends EditorBoolean {
3154
3313
  static resolves(schema) {
@@ -3218,18 +3377,86 @@ class EditorStringRadios extends EditorString {
3218
3377
  static resolves(schema) {
3219
3378
  return getSchemaType(schema) === "string" && (getSchemaXOption(schema, "format") === "radios" || getSchemaXOption(schema, "format") === "radios-inline");
3220
3379
  }
3380
+ init() {
3381
+ super.init();
3382
+ this.setupEnumSource();
3383
+ }
3384
+ setupEnumSource() {
3385
+ const enumSourceRaw = getSchemaXOption(this.instance.schema, "enumSource");
3386
+ if (!isSet(enumSourceRaw)) return;
3387
+ const enumSource = resolveInstancePath(this.instance.path, enumSourceRaw);
3388
+ const src = this.instance.jedison.getInstance(enumSource);
3389
+ if (src) this.enumSourceValues = src.getValue();
3390
+ this.instance.jedison.watch(enumSource, () => {
3391
+ if (!this.control) return;
3392
+ const s = this.instance.jedison.getInstance(enumSource);
3393
+ if (s) {
3394
+ this.enumSourceValues = s.getValue();
3395
+ this.refreshOptions();
3396
+ }
3397
+ });
3398
+ }
3399
+ getEnumSourceValues() {
3400
+ if (this.enumSourceValues !== void 0) {
3401
+ if (isArray(this.enumSourceValues)) return this.enumSourceValues;
3402
+ if (isObject(this.enumSourceValues)) return Object.keys(this.enumSourceValues);
3403
+ return [];
3404
+ }
3405
+ return getSchemaEnum(this.instance.schema) || [];
3406
+ }
3221
3407
  build() {
3408
+ const values = this.getEnumSourceValues();
3222
3409
  this.control = this.theme.getRadiosControl({
3223
3410
  title: this.getTitle(),
3224
3411
  description: this.getDescription(),
3225
- values: getSchemaEnum(this.instance.schema),
3226
- titles: getSchemaXOption(this.instance.schema, "enumTitles") || getSchemaEnum(this.instance.schema),
3412
+ values,
3413
+ titles: getSchemaXOption(this.instance.schema, "enumTitles") || values,
3227
3414
  id: this.getIdFromPath(this.instance.path),
3228
3415
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
3229
3416
  inline: getSchemaXOption(this.instance.schema, "format") === "radios-inline",
3230
3417
  info: this.getInfo()
3231
3418
  });
3232
3419
  }
3420
+ refreshOptions() {
3421
+ const values = this.getEnumSourceValues();
3422
+ const titles = getSchemaXOption(this.instance.schema, "enumTitles") || values;
3423
+ const id = this.getIdFromPath(this.instance.path);
3424
+ const messagesId = id + "-messages";
3425
+ const descriptionId = id + "-description";
3426
+ const describedBy = messagesId + " " + descriptionId;
3427
+ this.control.radioControls.forEach((rc) => {
3428
+ if (rc.parentNode) rc.parentNode.removeChild(rc);
3429
+ });
3430
+ this.control.radios = [];
3431
+ this.control.labels = [];
3432
+ this.control.radioControls = [];
3433
+ this.control.labelTexts = [];
3434
+ values.forEach((value, index2) => {
3435
+ const radioControl = document.createElement("div");
3436
+ const radio = document.createElement("input");
3437
+ const label = document.createElement("label");
3438
+ const labelText = document.createElement("span");
3439
+ radio.setAttribute("type", "radio");
3440
+ radio.setAttribute("id", id + "-" + index2);
3441
+ radio.setAttribute("name", id);
3442
+ radio.setAttribute("value", value);
3443
+ radio.setAttribute("aria-describedby", describedBy);
3444
+ label.setAttribute("for", id + "-" + index2);
3445
+ label.classList.add("jedi-title");
3446
+ label.classList.add("jedi-label");
3447
+ labelText.textContent = titles && titles[index2] !== void 0 ? titles[index2] : value;
3448
+ radioControl.appendChild(radio);
3449
+ radioControl.appendChild(label);
3450
+ label.appendChild(labelText);
3451
+ this.control.radios.push(radio);
3452
+ this.control.labels.push(label);
3453
+ this.control.labelTexts.push(labelText);
3454
+ this.control.radioControls.push(radioControl);
3455
+ this.control.fieldset.insertBefore(radioControl, this.control.description);
3456
+ });
3457
+ this.addEventListeners();
3458
+ this.refreshUI();
3459
+ }
3233
3460
  adaptForTable() {
3234
3461
  this.theme.adaptForTableRadiosControl(this.control);
3235
3462
  }
@@ -3246,23 +3473,73 @@ class EditorStringRadios extends EditorString {
3246
3473
  radio.checked = radio.value === this.instance.getValue();
3247
3474
  });
3248
3475
  }
3476
+ setAriaInvalid(invalid) {
3477
+ this.control.radios.forEach((radio) => {
3478
+ if (invalid) {
3479
+ radio.setAttribute("aria-invalid", "true");
3480
+ } else {
3481
+ radio.removeAttribute("aria-invalid");
3482
+ }
3483
+ });
3484
+ }
3249
3485
  }
3250
3486
  class EditorStringSelect extends EditorString {
3251
3487
  static resolves(schema) {
3252
- return getSchemaType(schema) === "string" && isSet(getSchemaEnum(schema));
3488
+ return getSchemaType(schema) === "string" && (isSet(getSchemaEnum(schema)) || isSet(getSchemaXOption(schema, "enumSource")));
3489
+ }
3490
+ init() {
3491
+ super.init();
3492
+ this.setupEnumSource();
3493
+ }
3494
+ setupEnumSource() {
3495
+ const enumSourceRaw = getSchemaXOption(this.instance.schema, "enumSource");
3496
+ if (!isSet(enumSourceRaw)) return;
3497
+ const enumSource = resolveInstancePath(this.instance.path, enumSourceRaw);
3498
+ const src = this.instance.jedison.getInstance(enumSource);
3499
+ if (src) this.enumSourceValues = src.getValue();
3500
+ this.instance.jedison.watch(enumSource, () => {
3501
+ if (!this.control) return;
3502
+ const s = this.instance.jedison.getInstance(enumSource);
3503
+ if (s) {
3504
+ this.enumSourceValues = s.getValue();
3505
+ this.refreshOptions();
3506
+ }
3507
+ });
3508
+ }
3509
+ getEnumSourceValues() {
3510
+ if (this.enumSourceValues !== void 0) {
3511
+ if (isArray(this.enumSourceValues)) return this.enumSourceValues;
3512
+ if (isObject(this.enumSourceValues)) return Object.keys(this.enumSourceValues);
3513
+ return [];
3514
+ }
3515
+ return getSchemaEnum(this.instance.schema) || [];
3253
3516
  }
3254
3517
  build() {
3518
+ const values = this.getEnumSourceValues();
3255
3519
  this.control = this.theme.getSelectControl({
3256
3520
  title: this.getTitle(),
3257
3521
  description: this.getDescription(),
3258
- values: getSchemaEnum(this.instance.schema),
3259
- titles: getSchemaXOption(this.instance.schema, "enumTitles") || getSchemaEnum(this.instance.schema),
3522
+ values,
3523
+ titles: getSchemaXOption(this.instance.schema, "enumTitles") || values,
3260
3524
  id: this.getIdFromPath(this.instance.path),
3261
3525
  titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass"),
3262
3526
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
3263
3527
  info: this.getInfo()
3264
3528
  });
3265
3529
  }
3530
+ refreshOptions() {
3531
+ const values = this.getEnumSourceValues();
3532
+ const titles = getSchemaXOption(this.instance.schema, "enumTitles") || values;
3533
+ const select = this.control.input;
3534
+ select.innerHTML = "";
3535
+ values.forEach((value, i) => {
3536
+ const option = document.createElement("option");
3537
+ option.setAttribute("value", value);
3538
+ option.textContent = titles && titles[i] !== void 0 ? titles[i] : value;
3539
+ select.appendChild(option);
3540
+ });
3541
+ this.refreshUI();
3542
+ }
3266
3543
  adaptForTable() {
3267
3544
  this.theme.adaptForTableSelectControl(this.control);
3268
3545
  }
@@ -3504,25 +3781,75 @@ class EditorNumberRadios extends EditorNumber {
3504
3781
  radio.checked = Number(radio.value) === Number(this.instance.getValue());
3505
3782
  });
3506
3783
  }
3784
+ setAriaInvalid(invalid) {
3785
+ this.control.radios.forEach((radio) => {
3786
+ if (invalid) {
3787
+ radio.setAttribute("aria-invalid", "true");
3788
+ } else {
3789
+ radio.removeAttribute("aria-invalid");
3790
+ }
3791
+ });
3792
+ }
3507
3793
  }
3508
3794
  class EditorNumberSelect extends EditorNumber {
3509
3795
  static resolves(schema) {
3510
3796
  const schemaType = getSchemaType(schema);
3511
3797
  const typeIsNumeric = schemaType === "number" || schemaType === "integer";
3512
- return typeIsNumeric && isSet(getSchemaEnum(schema));
3798
+ return typeIsNumeric && (isSet(getSchemaEnum(schema)) || isSet(getSchemaXOption(schema, "enumSource")));
3799
+ }
3800
+ init() {
3801
+ super.init();
3802
+ this.setupEnumSource();
3803
+ }
3804
+ setupEnumSource() {
3805
+ const enumSourceRaw = getSchemaXOption(this.instance.schema, "enumSource");
3806
+ if (!isSet(enumSourceRaw)) return;
3807
+ const enumSource = resolveInstancePath(this.instance.path, enumSourceRaw);
3808
+ const src = this.instance.jedison.getInstance(enumSource);
3809
+ if (src) this.enumSourceValues = src.getValue();
3810
+ this.instance.jedison.watch(enumSource, () => {
3811
+ if (!this.control) return;
3812
+ const s = this.instance.jedison.getInstance(enumSource);
3813
+ if (s) {
3814
+ this.enumSourceValues = s.getValue();
3815
+ this.refreshOptions();
3816
+ }
3817
+ });
3818
+ }
3819
+ getEnumSourceValues() {
3820
+ if (this.enumSourceValues !== void 0) {
3821
+ if (isArray(this.enumSourceValues)) return this.enumSourceValues;
3822
+ if (isObject(this.enumSourceValues)) return Object.keys(this.enumSourceValues);
3823
+ return [];
3824
+ }
3825
+ return getSchemaEnum(this.instance.schema) || [];
3513
3826
  }
3514
3827
  build() {
3828
+ const values = this.getEnumSourceValues();
3515
3829
  this.control = this.theme.getSelectControl({
3516
3830
  title: this.getTitle(),
3517
3831
  description: this.getDescription(),
3518
- values: getSchemaEnum(this.instance.schema),
3519
- titles: getSchemaXOption(this.instance.schema, "enumTitles") || getSchemaEnum(this.instance.schema),
3832
+ values,
3833
+ titles: getSchemaXOption(this.instance.schema, "enumTitles") || values,
3520
3834
  id: this.getIdFromPath(this.instance.path),
3521
3835
  titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass"),
3522
3836
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
3523
3837
  info: this.getInfo()
3524
3838
  });
3525
3839
  }
3840
+ refreshOptions() {
3841
+ const values = this.getEnumSourceValues();
3842
+ const titles = getSchemaXOption(this.instance.schema, "enumTitles") || values;
3843
+ const select = this.control.input;
3844
+ select.innerHTML = "";
3845
+ values.forEach((value, i) => {
3846
+ const option = document.createElement("option");
3847
+ option.setAttribute("value", value);
3848
+ option.textContent = titles && titles[i] !== void 0 ? titles[i] : value;
3849
+ select.appendChild(option);
3850
+ });
3851
+ this.refreshUI();
3852
+ }
3526
3853
  adaptForTable() {
3527
3854
  this.theme.adaptForTableSelectControl(this.control);
3528
3855
  }
@@ -3645,6 +3972,10 @@ class EditorObject extends Editor {
3645
3972
  if (isSet(additionalProperties2) && additionalProperties2 === false) {
3646
3973
  addProperty = false;
3647
3974
  }
3975
+ const objectAdd = getSchemaXOption(this.instance.schema, "objectAdd") ?? this.instance.jedison.options.objectAdd;
3976
+ if (isSet(objectAdd) && objectAdd === false) {
3977
+ addProperty = false;
3978
+ }
3648
3979
  let enablePropertiesToggle = false;
3649
3980
  if (isSet(this.instance.jedison.options.enablePropertiesToggle)) {
3650
3981
  enablePropertiesToggle = this.instance.jedison.options.enablePropertiesToggle;
@@ -3671,30 +4002,30 @@ class EditorObject extends Editor {
3671
4002
  });
3672
4003
  this.control.jsonData.input.value = JSON.stringify(this.instance.getValue(), null, 2);
3673
4004
  }
4005
+ announcePropertyAdded(propertyName, child) {
4006
+ const schemaTitle = getSchemaTitle(child.schema);
4007
+ const label = isSet(schemaTitle) ? schemaTitle : propertyName;
4008
+ const ariaLiveMessage = this.theme.getAriaLiveMessage();
4009
+ ariaLiveMessage.textContent = label + " " + this.instance.jedison.translator.translate("objectPropertyAdded");
4010
+ this.control.ariaLive.appendChild(ariaLiveMessage);
4011
+ }
4012
+ addProperty(input, postAction) {
4013
+ const propertyName = input.value.split(" ").join("");
4014
+ if (propertyName.length === 0) return;
4015
+ if (isSet(this.instance.value[propertyName])) return;
4016
+ const schema = this.instance.getPropertySchema(propertyName);
4017
+ const child = this.instance.createChild(schema, propertyName);
4018
+ child.activate();
4019
+ this.instance.setValue(this.instance.value, true, "user");
4020
+ input.value = "";
4021
+ this.announcePropertyAdded(propertyName, child);
4022
+ postAction();
4023
+ }
3674
4024
  addEventListeners() {
3675
- this.control.addPropertyBtn.addEventListener("click", () => {
3676
- const propertyName = this.control.addPropertyControl.input.value.split(" ").join("");
3677
- const propertyNameEmpty = propertyName.length === 0;
3678
- if (propertyNameEmpty) {
3679
- return;
3680
- }
3681
- const propertyExist = isSet(this.instance.value[propertyName]);
3682
- if (propertyExist) {
3683
- return;
3684
- }
3685
- const schema = this.instance.getPropertySchema(propertyName);
3686
- const child = this.instance.createChild(schema, propertyName);
3687
- child.activate();
3688
- this.instance.setValue(this.instance.value, true, "user");
3689
- this.control.addPropertyControl.input.value = "";
3690
- const ariaLive = this.control.ariaLive;
3691
- const schemaTitle = getSchemaTitle(child.schema);
3692
- const label = isSet(schemaTitle) ? schemaTitle : propertyName;
3693
- const ariaLiveMessage = this.theme.getAriaLiveMessage();
3694
- ariaLiveMessage.textContent = label + " " + this.instance.jedison.translator.translate("objectPropertyAdded");
3695
- ariaLive.appendChild(ariaLiveMessage);
3696
- this.control.propertiesContainer.close();
3697
- this.control.propertiesContainer.showModal();
4025
+ this.control.quickAddPropertyBtn.addEventListener("click", () => {
4026
+ this.addProperty(this.control.quickAddPropertyControl.input, () => {
4027
+ this.control.quickAddPropertyContainer.close();
4028
+ });
3698
4029
  });
3699
4030
  this.control.jsonData.saveBtn.addEventListener("click", () => {
3700
4031
  try {
@@ -3724,9 +4055,7 @@ class EditorObject extends Editor {
3724
4055
  const declaredProperties = Object.keys(this.instance.properties);
3725
4056
  const instanceProperties = this.instance.children.map((child) => child.getKey());
3726
4057
  const properties2 = [.../* @__PURE__ */ new Set([...declaredProperties, ...instanceProperties])];
3727
- while (this.control.propertiesActivators.firstChild) {
3728
- this.control.propertiesActivators.removeChild(this.control.propertiesActivators.firstChild);
3729
- }
4058
+ this.control.propertiesActivators.replaceChildren();
3730
4059
  const {
3731
4060
  container: defaultGroupContainer,
3732
4061
  group: defaultGroup
@@ -3783,12 +4112,28 @@ class EditorObject extends Editor {
3783
4112
  checkbox.disabled = this.disabled || isRequired;
3784
4113
  checkbox.checked = hasOwn(currentValue, property);
3785
4114
  });
4115
+ const propGroupOrder = getSchemaXOption(this.instance.schema, "propGroupOrder");
4116
+ if (isSet(propGroupOrder) && Array.isArray(propGroupOrder)) {
4117
+ const orderedContainers = [defaultGroupContainer];
4118
+ propGroupOrder.forEach((groupName) => {
4119
+ if (isSet(propertiesGroups[groupName])) {
4120
+ orderedContainers.push(propertiesGroups[groupName].container);
4121
+ }
4122
+ });
4123
+ Object.keys(propertiesGroups).forEach((groupName) => {
4124
+ if (!propGroupOrder.includes(groupName)) {
4125
+ orderedContainers.push(propertiesGroups[groupName].container);
4126
+ }
4127
+ });
4128
+ this.control.propertiesActivators.replaceChildren();
4129
+ orderedContainers.forEach((container) => {
4130
+ this.control.propertiesActivators.appendChild(container);
4131
+ });
4132
+ }
3786
4133
  }
3787
4134
  }
3788
4135
  refreshEditors() {
3789
- while (this.control.childrenSlot.firstChild) {
3790
- this.control.childrenSlot.removeChild(this.control.childrenSlot.firstChild);
3791
- }
4136
+ this.control.childrenSlot.replaceChildren();
3792
4137
  this.instance.children.forEach((child) => {
3793
4138
  const optIn = this.theme.getCheckboxControl({
3794
4139
  id: child.path + "-opt-in",
@@ -3822,11 +4167,32 @@ class EditorObject extends Editor {
3822
4167
  }
3823
4168
  });
3824
4169
  }
4170
+ refreshLegendWarning() {
4171
+ if (!this.control.legendText) return;
4172
+ const navWarning = getSchemaXOption(this.instance.schema, "navWarning") ?? true;
4173
+ const hasErrors = navWarning && this.instance.hasNestedValidationErrors();
4174
+ const existing = this.control.legendText.querySelector(".jedi-legend-warning");
4175
+ if (existing) existing.parentNode.removeChild(existing);
4176
+ if (hasErrors) {
4177
+ const warning = document.createElement("span");
4178
+ warning.classList.add("jedi-legend-warning");
4179
+ warning.textContent = "⚠";
4180
+ const navWarningMessage = getSchemaXOption(this.instance.schema, "navWarningMessage");
4181
+ if (navWarningMessage) warning.setAttribute("title", navWarningMessage);
4182
+ this.theme.styleLegendWarning(warning);
4183
+ this.control.legendText.appendChild(warning);
4184
+ }
4185
+ }
4186
+ showValidationErrors(errors, force = false) {
4187
+ super.showValidationErrors(errors, force);
4188
+ this.refreshLegendWarning();
4189
+ }
3825
4190
  refreshUI() {
3826
4191
  super.refreshUI();
3827
4192
  this.refreshPropertiesSlot();
3828
4193
  this.refreshEditors();
3829
4194
  this.refreshJsonData();
4195
+ this.refreshLegendWarning();
3830
4196
  }
3831
4197
  }
3832
4198
  class EditorObjectGrid extends EditorObject {
@@ -3904,6 +4270,8 @@ class EditorObjectCategories extends EditorObject {
3904
4270
  const categoriesMap = /* @__PURE__ */ new Map();
3905
4271
  this.instance.children.forEach((child) => {
3906
4272
  if (!child.isActive) return;
4273
+ const hidden = getSchemaXOption(child.schema, "hidden");
4274
+ if (isSet(hidden) && hidden === true) return;
3907
4275
  const childSchemaType = getSchemaType(child.schema);
3908
4276
  const xCategory = getSchemaXOption(child.schema, "category");
3909
4277
  let categoryName;
@@ -3963,6 +4331,22 @@ class EditorObjectNav extends EditorObject {
3963
4331
  super.init();
3964
4332
  this.activeTabIndex = 0;
3965
4333
  }
4334
+ isChildVisible(child) {
4335
+ if (!child.isActive) return false;
4336
+ const hidden = getSchemaXOption(child.schema, "hidden");
4337
+ return !(isSet(hidden) && hidden === true);
4338
+ }
4339
+ getVisibleChildIndices() {
4340
+ return this.instance.children.reduce((indices, child, index2) => {
4341
+ if (this.isChildVisible(child)) indices.push(index2);
4342
+ return indices;
4343
+ }, []);
4344
+ }
4345
+ ensureActiveTabIsVisible(visibleIndices) {
4346
+ if (!visibleIndices.includes(this.activeTabIndex)) {
4347
+ this.activeTabIndex = visibleIndices[0] ?? 0;
4348
+ }
4349
+ }
3966
4350
  refreshEditors() {
3967
4351
  while (this.control.childrenSlot.firstChild) {
3968
4352
  this.control.childrenSlot.removeChild(this.control.childrenSlot.lastChild);
@@ -3984,31 +4368,32 @@ class EditorObjectNav extends EditorObject {
3984
4368
  row.appendChild(tabContentCol);
3985
4369
  tabListCol.appendChild(tabList);
3986
4370
  tabContentCol.appendChild(tabContent);
4371
+ const visibleIndices = this.getVisibleChildIndices();
4372
+ this.ensureActiveTabIsVisible(visibleIndices);
3987
4373
  this.instance.children.forEach((child, index2) => {
3988
- if (child.isActive) {
3989
- const active = index2 === this.activeTabIndex;
3990
- const id = pathToAttribute(child.path);
3991
- const schemaTitle = getSchemaTitle(child.schema);
3992
- const navWarning = getSchemaXOption(this.instance.schema, "navWarning") ?? true;
3993
- const navWarningMessage = getSchemaXOption(this.instance.schema, "navWarningMessage");
3994
- const tab = this.theme.getTab({
3995
- hasErrors: navWarning && child.hasNestedValidationErrors(),
3996
- navWarningMessage,
3997
- title: isSet(schemaTitle) ? schemaTitle : child.getKey(),
3998
- id,
3999
- active
4000
- });
4001
- tab.list.addEventListener("click", () => {
4002
- this.activeTabIndex = index2;
4003
- });
4004
- this.theme.setTabPaneAttributes(child.ui.control.container, active, id);
4005
- tabList.appendChild(tab.list);
4006
- tabContent.appendChild(child.ui.control.container);
4007
- if (this.disabled || this.instance.isReadOnly()) {
4008
- child.ui.disable();
4009
- } else {
4010
- child.ui.enable();
4011
- }
4374
+ if (!this.isChildVisible(child)) return;
4375
+ const active = index2 === this.activeTabIndex;
4376
+ const id = pathToAttribute(child.path);
4377
+ const schemaTitle = getSchemaTitle(child.schema);
4378
+ const navWarning = getSchemaXOption(this.instance.schema, "navWarning") ?? true;
4379
+ const navWarningMessage = getSchemaXOption(this.instance.schema, "navWarningMessage");
4380
+ const tab = this.theme.getTab({
4381
+ hasErrors: navWarning && child.hasNestedValidationErrors(),
4382
+ navWarningMessage,
4383
+ title: isSet(schemaTitle) ? schemaTitle : child.getKey(),
4384
+ id,
4385
+ active
4386
+ });
4387
+ tab.list.addEventListener("click", () => {
4388
+ this.activeTabIndex = index2;
4389
+ });
4390
+ this.theme.setTabPaneAttributes(child.ui.control.container, active, id);
4391
+ tabList.appendChild(tab.list);
4392
+ tabContent.appendChild(child.ui.control.container);
4393
+ if (this.disabled || this.instance.isReadOnly()) {
4394
+ child.ui.disable();
4395
+ } else {
4396
+ child.ui.enable();
4012
4397
  }
4013
4398
  });
4014
4399
  }
@@ -4086,10 +4471,19 @@ class EditorArray extends Editor {
4086
4471
  });
4087
4472
  const btnGroup = this.theme.getBtnGroup();
4088
4473
  deleteBtn.addEventListener("click", () => {
4089
- const confirmDeletion = window.confirm(this.instance.jedison.translator.translate("arrayConfirmDelete"));
4090
- if (confirmDeletion) {
4474
+ const schemaConfirm = getSchemaXOption(this.instance.schema, "arrayDeleteConfirm");
4475
+ const globalConfirm = this.instance.jedison.options.arrayDeleteConfirm;
4476
+ const shouldConfirm = isSet(schemaConfirm) ? schemaConfirm : globalConfirm;
4477
+ const doDelete = () => {
4091
4478
  this.activeItemIndex = clamp(index2 - 1, 0, this.instance.value.length - 1);
4092
4479
  this.instance.deleteItem(index2, "user");
4480
+ };
4481
+ if (shouldConfirm) {
4482
+ if (window.confirm(this.instance.jedison.translator.translate("arrayConfirmDelete"))) {
4483
+ doDelete();
4484
+ }
4485
+ } else {
4486
+ doDelete();
4093
4487
  }
4094
4488
  });
4095
4489
  moveUpBtn.addEventListener("click", () => {
@@ -4182,6 +4576,27 @@ class EditorArray extends Editor {
4182
4576
  });
4183
4577
  this.refreshAddBtn();
4184
4578
  this.refreshJsonData();
4579
+ this.refreshLegendWarning();
4580
+ }
4581
+ refreshLegendWarning() {
4582
+ if (!this.control.legendText) return;
4583
+ const navWarning = getSchemaXOption(this.instance.schema, "navWarning") ?? true;
4584
+ const hasErrors = navWarning && this.instance.hasNestedValidationErrors();
4585
+ const existing = this.control.legendText.querySelector(".jedi-legend-warning");
4586
+ if (existing) existing.parentNode.removeChild(existing);
4587
+ if (hasErrors) {
4588
+ const warning = document.createElement("span");
4589
+ warning.classList.add("jedi-legend-warning");
4590
+ warning.textContent = "⚠";
4591
+ const navWarningMessage = getSchemaXOption(this.instance.schema, "navWarningMessage");
4592
+ if (navWarningMessage) warning.setAttribute("title", navWarningMessage);
4593
+ this.theme.styleLegendWarning(warning);
4594
+ this.control.legendText.appendChild(warning);
4595
+ }
4596
+ }
4597
+ showValidationErrors(errors, force = false) {
4598
+ super.showValidationErrors(errors, force);
4599
+ this.refreshLegendWarning();
4185
4600
  }
4186
4601
  }
4187
4602
  class EditorArrayTuple extends EditorArray {
@@ -4256,20 +4671,22 @@ class EditorArrayTable extends EditorArray {
4256
4671
  if (this.instance.children.length) {
4257
4672
  const schemaItems = getSchemaItems(this.instance.schema);
4258
4673
  const thTitle = this.theme.getTableHeader();
4259
- if (schemaItems.title) {
4260
- const fakeLabel = this.theme.getFakeLabel({
4261
- content: schemaItems.title
4262
- });
4263
- thTitle.appendChild(fakeLabel.label);
4264
- }
4265
- const schemaXInfo = getSchemaXOption(schemaItems, "info");
4266
- if (isSet(schemaXInfo)) {
4267
- const infoContent = this.getInfo(schemaItems);
4268
- const info = this.theme.getInfo(infoContent);
4269
- if (schemaXInfo.variant === "modal") {
4270
- this.theme.infoAsModal(info, this.getIdFromPath(this.instance.path), infoContent);
4674
+ if (schemaItems) {
4675
+ if (schemaItems.title) {
4676
+ const fakeLabel = this.theme.getFakeLabel({
4677
+ content: schemaItems.title
4678
+ });
4679
+ thTitle.appendChild(fakeLabel.label);
4680
+ }
4681
+ const schemaXInfo = getSchemaXOption(schemaItems, "info");
4682
+ if (isSet(schemaXInfo)) {
4683
+ const infoContent = this.getInfo(schemaItems);
4684
+ const info = this.theme.getInfo(infoContent);
4685
+ if (schemaXInfo.variant === "modal") {
4686
+ this.theme.infoAsModal(info, this.getIdFromPath(this.instance.path), infoContent);
4687
+ }
4688
+ thTitle.appendChild(info.container);
4271
4689
  }
4272
- thTitle.appendChild(info.container);
4273
4690
  }
4274
4691
  table.thead.appendChild(thTitle);
4275
4692
  }
@@ -4489,6 +4906,45 @@ class EditorArrayChoices extends Editor {
4489
4906
  const hasValidItemType = isSet(schemaItems) && isSet(schemaItemsType) && (validTypes.includes(schemaItemsType) || isArray(schemaItemsType) && schemaItemsType.some((type2) => validTypes.includes(type2)));
4490
4907
  return hasChoicesFormat && choicesInstalled && isArrayType && isUniqueItems && hasTypes && hasValidItemType;
4491
4908
  }
4909
+ init() {
4910
+ super.init();
4911
+ this.setupEnumSource();
4912
+ }
4913
+ setupEnumSource() {
4914
+ const enumSourceRaw = getSchemaXOption(this.instance.schema, "enumSource");
4915
+ if (!isSet(enumSourceRaw)) return;
4916
+ const enumSource = resolveInstancePath(this.instance.path, enumSourceRaw);
4917
+ const src = this.instance.jedison.getInstance(enumSource);
4918
+ if (src) this.enumSourceValues = src.getValue();
4919
+ this.instance.jedison.watch(enumSource, () => {
4920
+ if (!this.control) return;
4921
+ const s = this.instance.jedison.getInstance(enumSource);
4922
+ if (s) {
4923
+ this.enumSourceValues = s.getValue();
4924
+ this.refreshOptions();
4925
+ }
4926
+ });
4927
+ }
4928
+ getEnumSourceValues() {
4929
+ if (this.enumSourceValues !== void 0) {
4930
+ if (isArray(this.enumSourceValues)) return this.enumSourceValues;
4931
+ if (isObject(this.enumSourceValues)) return Object.keys(this.enumSourceValues);
4932
+ return [];
4933
+ }
4934
+ return this.instance.schema.items && this.instance.schema.items.enum || [];
4935
+ }
4936
+ refreshOptions() {
4937
+ if (!this.choicesInstance) return;
4938
+ const values = this.getEnumSourceValues();
4939
+ const currentValue = this.instance.getValue();
4940
+ const itemEnumTitles = getSchemaXOption(this.instance.schema.items || {}, "enumTitles") || [];
4941
+ const choices = values.map((item, index2) => ({
4942
+ value: item,
4943
+ label: itemEnumTitles[index2] || item,
4944
+ selected: isArray(currentValue) && currentValue.includes(item)
4945
+ }));
4946
+ this.choicesInstance.setChoices(choices, "value", "label", true);
4947
+ }
4492
4948
  build() {
4493
4949
  this.control = this.theme.getSelectControl({
4494
4950
  title: this.getTitle(),
@@ -4503,8 +4959,8 @@ class EditorArrayChoices extends Editor {
4503
4959
  this.control.input.setAttribute("multiple", "");
4504
4960
  try {
4505
4961
  const value = this.instance.getValue();
4506
- const itemEnum = this.instance.schema.items.enum ?? [];
4507
- const itemEnumTitles = getSchemaXOption(this.instance.schema.items, "enumTitles") ?? this.instance.getValue();
4962
+ const itemEnum = this.getEnumSourceValues();
4963
+ const itemEnumTitles = getSchemaXOption(this.instance.schema.items || {}, "enumTitles") || [];
4508
4964
  const choicesOptions = getSchemaXOption(this.instance.schema, "choicesOptions") ?? {};
4509
4965
  if (this.choicesInstance) {
4510
4966
  this.choicesInstance.destroy();
@@ -4659,6 +5115,7 @@ class EditorMultiple extends Editor {
4659
5115
  }
4660
5116
  build() {
4661
5117
  this.switcherInput = getSchemaXOption(this.instance.schema, "switcherInput") ?? this.instance.jedison.options.switcherInput;
5118
+ this.embedSwitcher = getSchemaXOption(this.instance.schema, "embedSwitcher") ?? this.instance.jedison.options.embedSwitcher;
4662
5119
  this.control = this.theme.getMultipleControl({
4663
5120
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
4664
5121
  id: this.getIdFromPath(this.instance.path),
@@ -4667,6 +5124,9 @@ class EditorMultiple extends Editor {
4667
5124
  switcher: this.switcherInput,
4668
5125
  readOnly: this.instance.isReadOnly()
4669
5126
  });
5127
+ if (this.embedSwitcher) {
5128
+ this.control.header.style.display = "none";
5129
+ }
4670
5130
  }
4671
5131
  adaptForTable(td) {
4672
5132
  this.theme.adaptForTableMultipleControl(this.control, td);
@@ -4691,6 +5151,17 @@ class EditorMultiple extends Editor {
4691
5151
  this.refreshDisabledState();
4692
5152
  this.control.childrenSlot.innerHTML = "";
4693
5153
  this.control.childrenSlot.appendChild(this.instance.activeInstance.ui.control.container);
5154
+ if (this.embedSwitcher) {
5155
+ const slot = this.instance.activeInstance.ui.control.switcherSlot;
5156
+ if (slot) {
5157
+ slot.innerHTML = "";
5158
+ slot.appendChild(this.control.switcher.container);
5159
+ this.control.header.style.display = "none";
5160
+ } else {
5161
+ this.control.header.style.display = "";
5162
+ this.control.header.appendChild(this.control.switcher.container);
5163
+ }
5164
+ }
4694
5165
  if (this.switcherInput === "select") {
4695
5166
  this.control.switcher.input.value = this.instance.index;
4696
5167
  }
@@ -5060,6 +5531,38 @@ class EditorNumberRaty extends EditorNumber {
5060
5531
  this.raty.score(this.instance.getValue());
5061
5532
  }
5062
5533
  }
5534
+ class EditorAnyJson extends Editor {
5535
+ static resolves(schema) {
5536
+ return getSchemaXOption(schema, "format") === "json";
5537
+ }
5538
+ build() {
5539
+ this.control = this.theme.getTextareaControl({
5540
+ title: this.getTitle(),
5541
+ description: this.getDescription(),
5542
+ id: this.getIdFromPath(this.instance.path),
5543
+ titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass"),
5544
+ titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
5545
+ info: this.getInfo()
5546
+ });
5547
+ this.jsonErrorEl = document.createElement("div");
5548
+ this.jsonErrorEl.style.color = "red";
5549
+ this.control.container.appendChild(this.jsonErrorEl);
5550
+ }
5551
+ addEventListeners() {
5552
+ this.control.input.addEventListener("change", () => {
5553
+ try {
5554
+ const parsed = JSON.parse(this.control.input.value);
5555
+ this.jsonErrorEl.textContent = "";
5556
+ this.instance.setValue(parsed, true, "user");
5557
+ } catch (e) {
5558
+ this.jsonErrorEl.textContent = e.message;
5559
+ }
5560
+ });
5561
+ }
5562
+ refreshUI() {
5563
+ this.control.input.value = JSON.stringify(this.instance.getValue(), null, 2);
5564
+ }
5565
+ }
5063
5566
  class EditorArrayCheckboxes extends Editor {
5064
5567
  static resolves(schema) {
5065
5568
  const schemaType = getSchemaType(schema);
@@ -5069,22 +5572,93 @@ class EditorArrayCheckboxes extends Editor {
5069
5572
  const isUniqueItems = getSchemaUniqueItems(schema) === true;
5070
5573
  const hasEnum = isSet(schemaItems) && isSet(getSchemaEnum(schema.items));
5071
5574
  const hasTypes = isSet(schemaItems) && isSet(schemaItemsType);
5575
+ const hasEnumSource = isSet(getSchemaXOption(schema, "enumSource"));
5072
5576
  const validTypes = ["string", "number", "integer"];
5073
5577
  const hasValidItemType = isSet(schemaItems) && isSet(schemaItemsType) && (validTypes.includes(schemaItemsType) || isArray(schemaItemsType) && schemaItemsType.some((type2) => validTypes.includes(type2)));
5074
- return isArrayType && isUniqueItems && hasEnum && hasTypes && hasValidItemType;
5578
+ return isArrayType && isUniqueItems && (hasEnumSource || hasEnum && hasTypes && hasValidItemType);
5579
+ }
5580
+ init() {
5581
+ super.init();
5582
+ this.setupEnumSource();
5583
+ }
5584
+ setupEnumSource() {
5585
+ const enumSourceRaw = getSchemaXOption(this.instance.schema, "enumSource");
5586
+ if (!isSet(enumSourceRaw)) return;
5587
+ const enumSource = resolveInstancePath(this.instance.path, enumSourceRaw);
5588
+ const src = this.instance.jedison.getInstance(enumSource);
5589
+ if (src) this.enumSourceValues = src.getValue();
5590
+ this.instance.jedison.watch(enumSource, () => {
5591
+ if (!this.control) return;
5592
+ const s = this.instance.jedison.getInstance(enumSource);
5593
+ if (s) {
5594
+ this.enumSourceValues = s.getValue();
5595
+ this.refreshOptions();
5596
+ }
5597
+ });
5598
+ }
5599
+ getEnumSourceValues() {
5600
+ if (this.enumSourceValues !== void 0) {
5601
+ if (isArray(this.enumSourceValues)) return this.enumSourceValues;
5602
+ if (isObject(this.enumSourceValues)) return Object.keys(this.enumSourceValues);
5603
+ return [];
5604
+ }
5605
+ return getSchemaEnum(this.instance.schema.items) || [];
5075
5606
  }
5076
5607
  build() {
5608
+ const values = this.getEnumSourceValues();
5609
+ const schemaItems = this.instance.schema.items || {};
5610
+ const titles = getSchemaXOption(schemaItems, "enumTitles") || values;
5077
5611
  this.control = this.theme.getCheckboxesControl({
5078
5612
  title: this.getTitle(),
5079
5613
  description: this.getDescription(),
5080
- values: getSchemaEnum(this.instance.schema.items),
5081
- titles: getSchemaXOption(this.instance.schema.items, "enumTitles") || getSchemaEnum(this.instance.schema.items),
5614
+ values,
5615
+ titles,
5082
5616
  id: this.getIdFromPath(this.instance.path),
5083
5617
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
5084
5618
  inline: getSchemaXOption(this.instance.schema, "format") === "checkboxes-inline",
5085
5619
  info: this.getInfo()
5086
5620
  });
5087
5621
  }
5622
+ refreshOptions() {
5623
+ const values = this.getEnumSourceValues();
5624
+ const schemaItems = this.instance.schema.items || {};
5625
+ const titles = getSchemaXOption(schemaItems, "enumTitles") || values;
5626
+ const id = this.getIdFromPath(this.instance.path);
5627
+ const messagesId = id + "-messages";
5628
+ const descriptionId = id + "-description";
5629
+ const describedBy = messagesId + " " + descriptionId;
5630
+ this.control.checkboxControls.forEach((cc) => {
5631
+ if (cc.parentNode) cc.parentNode.removeChild(cc);
5632
+ });
5633
+ this.control.checkboxes = [];
5634
+ this.control.labels = [];
5635
+ this.control.checkboxControls = [];
5636
+ this.control.labelTexts = [];
5637
+ values.forEach((value, index2) => {
5638
+ const checkboxId = id + "-" + index2;
5639
+ const checkboxControl = document.createElement("div");
5640
+ const checkbox = document.createElement("input");
5641
+ const label = document.createElement("label");
5642
+ const labelText = document.createElement("span");
5643
+ checkbox.setAttribute("type", "checkbox");
5644
+ checkbox.setAttribute("id", checkboxId);
5645
+ checkbox.setAttribute("name", id);
5646
+ checkbox.setAttribute("value", value);
5647
+ checkbox.setAttribute("aria-describedby", describedBy);
5648
+ label.setAttribute("for", checkboxId);
5649
+ labelText.textContent = titles && titles[index2] !== void 0 ? titles[index2] : value;
5650
+ checkboxControl.appendChild(checkbox);
5651
+ checkboxControl.appendChild(label);
5652
+ label.appendChild(labelText);
5653
+ this.control.checkboxes.push(checkbox);
5654
+ this.control.labels.push(label);
5655
+ this.control.labelTexts.push(labelText);
5656
+ this.control.checkboxControls.push(checkboxControl);
5657
+ this.control.fieldset.insertBefore(checkboxControl, this.control.description);
5658
+ });
5659
+ this.addEventListeners();
5660
+ this.refreshUI();
5661
+ }
5088
5662
  adaptForTable(td) {
5089
5663
  this.theme.adaptForTableCheckboxesControl(this.control, td);
5090
5664
  }
@@ -5117,6 +5691,15 @@ class EditorArrayCheckboxes extends Editor {
5117
5691
  checkbox.checked = value.includes(checkbox.value);
5118
5692
  });
5119
5693
  }
5694
+ setAriaInvalid(invalid) {
5695
+ this.control.checkboxes.forEach((checkbox) => {
5696
+ if (invalid) {
5697
+ checkbox.setAttribute("aria-invalid", "true");
5698
+ } else {
5699
+ checkbox.removeAttribute("aria-invalid");
5700
+ }
5701
+ });
5702
+ }
5120
5703
  }
5121
5704
  class EditorNumberRange extends EditorNumber {
5122
5705
  static resolves(schema) {
@@ -5291,6 +5874,7 @@ class UiResolver {
5291
5874
  EditorNumberInputNullable,
5292
5875
  EditorMultiple,
5293
5876
  EditorIfThenElse,
5877
+ EditorAnyJson,
5294
5878
  EditorRadios,
5295
5879
  EditorBooleanCheckbox,
5296
5880
  EditorBooleanSelect,
@@ -5629,14 +6213,17 @@ class Jedison extends EventEmitter {
5629
6213
  btnContents: true,
5630
6214
  btnIcons: true,
5631
6215
  arrayDelete: true,
6216
+ arrayDeleteConfirm: true,
5632
6217
  arrayMove: true,
5633
6218
  arrayAdd: true,
6219
+ objectAdd: true,
5634
6220
  arrayButtonsPosition: "left",
5635
6221
  startCollapsed: false,
5636
6222
  deactivateNonRequired: false,
5637
6223
  schema: {},
5638
6224
  showErrors: "change",
5639
6225
  switcherInput: "select",
6226
+ embedSwitcher: false,
5640
6227
  data: void 0,
5641
6228
  assertFormat: false,
5642
6229
  customEditors: [],
@@ -5661,6 +6248,7 @@ class Jedison extends EventEmitter {
5661
6248
  enforceMinItems: true,
5662
6249
  enforceMaxItems: true,
5663
6250
  enforceEnum: true,
6251
+ subErrors: false,
5664
6252
  debug: false
5665
6253
  }, options);
5666
6254
  this.rootName = "#";
@@ -5728,7 +6316,8 @@ class Jedison extends EventEmitter {
5728
6316
  refParser: this.refParser,
5729
6317
  assertFormat: this.options.assertFormat,
5730
6318
  translator: this.translator,
5731
- constraints: this.options.constraints
6319
+ constraints: this.options.constraints,
6320
+ subErrors: this.options.subErrors
5732
6321
  });
5733
6322
  this.root = this.createInstance({
5734
6323
  jedison: this,
@@ -6280,6 +6869,8 @@ class Theme {
6280
6869
  const dummyInputId = "legend-dummy-input-" + config.id;
6281
6870
  left.classList.add("jedi-editor-legend-left");
6282
6871
  right.classList.add("jedi-editor-legend-right");
6872
+ right.style.display = "flex";
6873
+ right.style.alignItems = "center";
6283
6874
  legend.classList.add("jedi-editor-legend");
6284
6875
  legend.style.fontSize = "inherit";
6285
6876
  legend.setAttribute("aria-labelledby", legendLabelId);
@@ -6495,6 +7086,18 @@ class Theme {
6495
7086
  });
6496
7087
  return toggle;
6497
7088
  }
7089
+ getQuickAddPropertyToggle(config) {
7090
+ const toggle = this.getButton(config);
7091
+ toggle.classList.add("jedi-quick-add-property-toggle");
7092
+ toggle.addEventListener("click", () => {
7093
+ if (config.propertiesContainer.open) {
7094
+ config.propertiesContainer.close();
7095
+ } else {
7096
+ config.propertiesContainer.showModal();
7097
+ }
7098
+ });
7099
+ return toggle;
7100
+ }
6498
7101
  /**
6499
7102
  * Container that will collapse and expand to show and hide it contents
6500
7103
  */
@@ -6557,6 +7160,17 @@ class Theme {
6557
7160
  });
6558
7161
  return html;
6559
7162
  }
7163
+ getQuickAddPropertySlot(config) {
7164
+ const html = document.createElement("dialog");
7165
+ html.classList.add("jedi-quick-add-property-slot");
7166
+ html.setAttribute("id", config.id);
7167
+ window.addEventListener("click", (event) => {
7168
+ if (event.target === html) {
7169
+ html.close();
7170
+ }
7171
+ });
7172
+ return html;
7173
+ }
6560
7174
  /**
6561
7175
  * Container for properties editing elements like property activators
6562
7176
  */
@@ -6909,17 +7523,25 @@ class Theme {
6909
7523
  collapse,
6910
7524
  startCollapsed: config.startCollapsed
6911
7525
  });
6912
- const addPropertyControl = this.getInputControl({
7526
+ const quickAddPropertyContainer = this.getQuickAddPropertySlot({
7527
+ id: "quick-add-property-slot-" + config.id
7528
+ });
7529
+ const quickAddPropertyControl = this.getInputControl({
6913
7530
  type: "text",
6914
- id: "jedi-add-property-input-" + config.id,
7531
+ id: "jedi-quick-add-property-input-" + config.id,
6915
7532
  title: config.addPropertyContent
6916
7533
  });
6917
- const addPropertyBtn = this.getAddPropertyButton({
7534
+ const quickAddPropertyBtn = this.getAddPropertyButton({
6918
7535
  content: config.addPropertyContent,
6919
7536
  icon: "add"
6920
7537
  });
7538
+ const quickAddPropertyToggle = this.getQuickAddPropertyToggle({
7539
+ content: config.addPropertyContent,
7540
+ icon: "add",
7541
+ propertiesContainer: quickAddPropertyContainer
7542
+ });
6921
7543
  const fieldset = this.getFieldset();
6922
- const { legend, infoContainer, legendText } = this.getLegend({
7544
+ const { legend, infoContainer, legendText, right } = this.getLegend({
6923
7545
  content: config.title,
6924
7546
  id: config.id,
6925
7547
  titleHidden: config.titleHidden
@@ -6927,9 +7549,13 @@ class Theme {
6927
7549
  if (((_a = config == null ? void 0 : config.info) == null ? void 0 : _a.variant) === "modal") {
6928
7550
  this.infoAsModal(info, config.id, config.info);
6929
7551
  }
6930
- addPropertyBtn.classList.add("jedi-object-add");
6931
7552
  container.appendChild(fieldset);
6932
7553
  container.appendChild(propertiesContainer);
7554
+ container.appendChild(quickAddPropertyContainer);
7555
+ if (config.addProperty) {
7556
+ quickAddPropertyContainer.appendChild(quickAddPropertyControl.container);
7557
+ quickAddPropertyContainer.appendChild(quickAddPropertyBtn);
7558
+ }
6933
7559
  if (config.editJsonData) {
6934
7560
  container.appendChild(jsonData.dialog);
6935
7561
  }
@@ -6943,18 +7569,19 @@ class Theme {
6943
7569
  body.appendChild(description);
6944
7570
  }
6945
7571
  body.appendChild(messages);
7572
+ const switcherSlot = document.createElement("div");
7573
+ switcherSlot.classList.add("jedi-switcher-slot");
6946
7574
  if (config.readOnly === false) {
6947
- legend.appendChild(actions);
7575
+ right.appendChild(switcherSlot);
7576
+ right.appendChild(actions);
6948
7577
  }
6949
7578
  body.appendChild(childrenSlot);
6950
- if (config.addProperty) {
6951
- propertiesContainer.appendChild(addPropertyControl.container);
6952
- propertiesContainer.appendChild(addPropertyBtn);
6953
- propertiesContainer.appendChild(document.createElement("hr"));
6954
- }
6955
7579
  if (config.editJsonData) {
6956
7580
  actions.appendChild(jsonData.toggle);
6957
7581
  }
7582
+ if (config.addProperty) {
7583
+ actions.appendChild(quickAddPropertyToggle);
7584
+ }
6958
7585
  if (config.enablePropertiesToggle) {
6959
7586
  actions.appendChild(propertiesToggle);
6960
7587
  propertiesContainer.appendChild(ariaLive);
@@ -6975,13 +7602,17 @@ class Theme {
6975
7602
  propertiesToggle,
6976
7603
  jsonData,
6977
7604
  propertiesContainer,
6978
- addPropertyControl,
6979
- addPropertyBtn,
7605
+ quickAddPropertyContainer,
7606
+ quickAddPropertyControl,
7607
+ quickAddPropertyBtn,
7608
+ quickAddPropertyToggle,
6980
7609
  ariaLive,
6981
7610
  propertiesActivators,
6982
7611
  legend,
6983
7612
  legendText,
6984
- infoContainer
7613
+ infoContainer,
7614
+ right,
7615
+ switcherSlot
6985
7616
  };
6986
7617
  }
6987
7618
  /**
@@ -7002,7 +7633,7 @@ class Theme {
7002
7633
  });
7003
7634
  const fieldset = this.getFieldset();
7004
7635
  const info = this.getInfo(config.info);
7005
- const { legend, legendText, infoContainer } = this.getLegend({
7636
+ const { legend, legendText, infoContainer, right } = this.getLegend({
7006
7637
  content: config.title,
7007
7638
  id: config.id,
7008
7639
  titleHidden: config.titleHidden
@@ -7042,7 +7673,12 @@ class Theme {
7042
7673
  body.appendChild(description);
7043
7674
  }
7044
7675
  body.appendChild(messages);
7045
- legend.appendChild(actions);
7676
+ const switcherSlot = document.createElement("div");
7677
+ switcherSlot.classList.add("jedi-switcher-slot");
7678
+ if (config.readOnly === false) {
7679
+ right.appendChild(switcherSlot);
7680
+ right.appendChild(actions);
7681
+ }
7046
7682
  actions.appendChild(btnGroup);
7047
7683
  if (config.editJsonData) {
7048
7684
  btnGroup.appendChild(jsonData.toggle);
@@ -7066,7 +7702,8 @@ class Theme {
7066
7702
  addBtn,
7067
7703
  jsonData,
7068
7704
  legend,
7069
- legendText
7705
+ legendText,
7706
+ switcherSlot
7070
7707
  };
7071
7708
  }
7072
7709
  getArrayItem(config = {}) {
@@ -7102,8 +7739,10 @@ class Theme {
7102
7739
  const messages = this.getMessagesSlot();
7103
7740
  const childrenSlot = this.getChildrenSlot();
7104
7741
  const randomId = generateRandomID(5);
7742
+ const knownSwitchers = ["select", "radios", "radios-inline"];
7743
+ const switcherType = knownSwitchers.includes(config.switcher) ? config.switcher : "select";
7105
7744
  let switcher;
7106
- if (config.switcher === "select") {
7745
+ if (switcherType === "select") {
7107
7746
  switcher = this.getSwitcherSelect({
7108
7747
  values: config.switcherOptionValues,
7109
7748
  titles: config.switcherOptionsLabels,
@@ -7111,10 +7750,11 @@ class Theme {
7111
7750
  id: config.id + "-switcher-" + randomId,
7112
7751
  label: config.id + "-switcher-" + randomId,
7113
7752
  titleHidden: true,
7114
- readOnly: config.readOnly
7753
+ readOnly: config.readOnly,
7754
+ noSpacing: true
7115
7755
  });
7116
7756
  }
7117
- if (config.switcher === "radios" || config.switcher === "radios-inline") {
7757
+ if (switcherType === "radios" || switcherType === "radios-inline") {
7118
7758
  switcher = this.getSwitcherRadios({
7119
7759
  values: config.switcherOptionValues,
7120
7760
  titles: config.switcherOptionsLabels,
@@ -7123,7 +7763,8 @@ class Theme {
7123
7763
  label: config.id + "-switcher-" + randomId,
7124
7764
  titleHidden: true,
7125
7765
  readOnly: config.readOnly,
7126
- inline: config.switcher === "radios-inline"
7766
+ inline: switcherType === "radios-inline",
7767
+ noSpacing: true
7127
7768
  });
7128
7769
  }
7129
7770
  switcher.container.classList.add("jedi-switcher");
@@ -7661,6 +8302,8 @@ class Theme {
7661
8302
  tabList.classList.add("jedi-nav-list");
7662
8303
  return tabList;
7663
8304
  }
8305
+ styleLegendWarning(span) {
8306
+ }
7664
8307
  /**
7665
8308
  * A Tab is a wrapper for content
7666
8309
  */
@@ -7972,7 +8615,9 @@ class ThemeBootstrap3 extends Theme {
7972
8615
  getSelectControl(config) {
7973
8616
  const control = super.getSelectControl(config);
7974
8617
  const { container, input, label } = control;
7975
- container.classList.add("form-group");
8618
+ if (!config.noSpacing) {
8619
+ container.classList.add("form-group");
8620
+ }
7976
8621
  input.classList.add("form-control");
7977
8622
  if (config.titleHidden) {
7978
8623
  this.visuallyHidden(label);
@@ -8272,7 +8917,9 @@ class ThemeBootstrap4 extends Theme {
8272
8917
  getRadiosControl(config) {
8273
8918
  const control = super.getRadiosControl(config);
8274
8919
  const { container, fieldset, radios, labels, labelTexts, radioControls, description, messages } = control;
8275
- container.classList.add("form-group");
8920
+ if (!config.noSpacing) {
8921
+ container.classList.add("form-group");
8922
+ }
8276
8923
  radioControls.forEach((radioControl, index2) => {
8277
8924
  radioControl.classList.add("form-check");
8278
8925
  radios[index2].classList.add("form-check-input");
@@ -8344,7 +8991,9 @@ class ThemeBootstrap4 extends Theme {
8344
8991
  getSelectControl(config) {
8345
8992
  const control = super.getSelectControl(config);
8346
8993
  const { container, input } = control;
8347
- container.classList.add("form-group");
8994
+ if (!config.noSpacing) {
8995
+ container.classList.add("form-group");
8996
+ }
8348
8997
  input.classList.add("form-control");
8349
8998
  return control;
8350
8999
  }
@@ -8553,6 +9202,9 @@ class ThemeBootstrap5 extends Theme {
8553
9202
  legend.classList.add("py-2");
8554
9203
  return superLegend;
8555
9204
  }
9205
+ styleLegendWarning(span) {
9206
+ span.classList.add("ms-1");
9207
+ }
8556
9208
  getLabel(config) {
8557
9209
  const labelObj = super.getLabel(config);
8558
9210
  if (labelObj.icon.classList) {
@@ -8651,7 +9303,9 @@ class ThemeBootstrap5 extends Theme {
8651
9303
  getRadiosControl(config) {
8652
9304
  const control = super.getRadiosControl(config);
8653
9305
  const { container, fieldset, radios, labels, labelTexts, radioControls, description, messages } = control;
8654
- container.classList.add("mb-3");
9306
+ if (!config.noSpacing) {
9307
+ container.classList.add("mb-3");
9308
+ }
8655
9309
  radioControls.forEach((radioControl, index2) => {
8656
9310
  radioControl.classList.add("form-check");
8657
9311
  radios[index2].classList.add("form-check-input");
@@ -8716,7 +9370,9 @@ class ThemeBootstrap5 extends Theme {
8716
9370
  getSelectControl(config) {
8717
9371
  const control = super.getSelectControl(config);
8718
9372
  const { container, input } = control;
8719
- container.classList.add("mb-3");
9373
+ if (!config.noSpacing) {
9374
+ container.classList.add("mb-3");
9375
+ }
8720
9376
  input.classList.add("form-select");
8721
9377
  return control;
8722
9378
  }