jedison 1.11.2 → 1.12.1

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.
@@ -3270,7 +3270,8 @@ const glyphicons = {
3270
3270
  close: "glyphicon glyphicon-remove",
3271
3271
  edit: "glyphicon glyphicon-pencil",
3272
3272
  save: "glyphicon glyphicon-floppy-disk",
3273
- copy: "glyphicon glyphicon-copy"
3273
+ copy: "glyphicon glyphicon-copy",
3274
+ switcher: "glyphicon glyphicon-chevron-down"
3274
3275
  };
3275
3276
  const bootstrapIcons = {
3276
3277
  properties: "bi bi-card-list",
@@ -3285,7 +3286,8 @@ const bootstrapIcons = {
3285
3286
  close: "bi bi-x",
3286
3287
  edit: "bi bi-pencil",
3287
3288
  save: "bi bi-floppy",
3288
- copy: "bi bi-clipboard"
3289
+ copy: "bi bi-clipboard",
3290
+ switcher: "bi bi-chevron-down"
3289
3291
  };
3290
3292
  const fontAwesome3 = {
3291
3293
  properties: "icon-list",
@@ -3300,7 +3302,8 @@ const fontAwesome3 = {
3300
3302
  close: "icon-remove",
3301
3303
  edit: "icon-pencil",
3302
3304
  save: "icon-save",
3303
- copy: "icon-copy"
3305
+ copy: "icon-copy",
3306
+ switcher: "icon-chevron-down"
3304
3307
  };
3305
3308
  const fontAwesome4 = {
3306
3309
  properties: "fa fa-list",
@@ -3315,7 +3318,8 @@ const fontAwesome4 = {
3315
3318
  close: "fa fa-times",
3316
3319
  edit: "fa fa-pencil",
3317
3320
  save: "fa fa-floppy-o",
3318
- copy: "fa fa-clipboard"
3321
+ copy: "fa fa-clipboard",
3322
+ switcher: "fa fa-chevron-down"
3319
3323
  };
3320
3324
  const fontAwesome5 = {
3321
3325
  properties: "fas fa-list",
@@ -3330,7 +3334,8 @@ const fontAwesome5 = {
3330
3334
  close: "fas fa-times",
3331
3335
  edit: "fas fa-pencil-alt",
3332
3336
  save: "fas fa-save",
3333
- copy: "fas fa-clipboard"
3337
+ copy: "fas fa-clipboard",
3338
+ switcher: "fas fa-chevron-down"
3334
3339
  };
3335
3340
  const fontAwesome6 = {
3336
3341
  properties: "fa-solid fa-list",
@@ -3345,7 +3350,8 @@ const fontAwesome6 = {
3345
3350
  close: "fa-solid fa-xmark",
3346
3351
  edit: "fa-solid fa-pencil",
3347
3352
  save: "fa-solid fa-floppy-disk",
3348
- copy: "fa-solid fa-clipboard"
3353
+ copy: "fa-solid fa-clipboard",
3354
+ switcher: "fa-solid fa-chevron-down"
3349
3355
  };
3350
3356
  class EditorBoolean extends Editor {
3351
3357
  sanitize(value) {
@@ -3364,6 +3370,7 @@ class EditorRadios extends EditorBoolean {
3364
3370
  titles: getSchemaXOption(this.instance.schema, "enumTitles") || ["false", "true"],
3365
3371
  id: this.getIdFromPath(this.instance.path),
3366
3372
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
3373
+ titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass"),
3367
3374
  inline: getSchemaXOption(this.instance.schema, "format") === "radios-inline",
3368
3375
  info: this.getInfo()
3369
3376
  });
@@ -3436,6 +3443,7 @@ class EditorBooleanCheckbox extends EditorBoolean {
3436
3443
  description: this.getDescription(),
3437
3444
  id: this.getIdFromPath(this.instance.path),
3438
3445
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
3446
+ titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass"),
3439
3447
  info: this.getInfo()
3440
3448
  });
3441
3449
  }
@@ -4052,8 +4060,7 @@ class EditorObject extends Editor {
4052
4060
  static resolves(schema) {
4053
4061
  return getSchemaType(schema) === "object";
4054
4062
  }
4055
- build() {
4056
- this.propertyActivators = {};
4063
+ getObjectControlConfig() {
4057
4064
  let addProperty = true;
4058
4065
  const additionalProperties2 = getSchemaAdditionalProperties(this.instance.schema);
4059
4066
  if (isSet(additionalProperties2) && additionalProperties2 === false) {
@@ -4071,7 +4078,7 @@ class EditorObject extends Editor {
4071
4078
  if (isSet(schemaEnablePropertiesToggle)) {
4072
4079
  enablePropertiesToggle = schemaEnablePropertiesToggle;
4073
4080
  }
4074
- this.control = this.theme.getObjectControl({
4081
+ return {
4075
4082
  title: this.getTitle(),
4076
4083
  description: this.getDescription(),
4077
4084
  titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
@@ -4085,8 +4092,14 @@ class EditorObject extends Editor {
4085
4092
  editJsonData: getSchemaXOption(this.instance.schema, "editJsonData") ?? this.instance.jedison.getOption("editJsonData"),
4086
4093
  propertiesToggleContent: getSchemaXOption(this.instance.schema, "propertiesToggleContent") ?? this.instance.jedison.translator.translate("propertiesToggle"),
4087
4094
  collapseToggleContent: getSchemaXOption(this.instance.schema, "collapseToggleContent") ?? this.instance.jedison.translator.translate("collapseToggle"),
4088
- addPropertyContent: getSchemaXOption(this.instance.schema, "addPropertyContent") ?? this.instance.jedison.translator.translate("objectAddProperty")
4089
- });
4095
+ addPropertyContent: getSchemaXOption(this.instance.schema, "addPropertyContent") ?? this.instance.jedison.translator.translate("objectAddProperty"),
4096
+ isAccordion: false,
4097
+ titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass")
4098
+ };
4099
+ }
4100
+ build() {
4101
+ this.propertyActivators = {};
4102
+ this.control = this.theme.getObjectControl(this.getObjectControlConfig());
4090
4103
  this.control.jsonData.input.value = JSON.stringify(this.instance.getValue(), null, 2);
4091
4104
  }
4092
4105
  announcePropertyAdded(propertyName, child) {
@@ -4531,6 +4544,32 @@ class EditorObjectNav extends EditorObject {
4531
4544
  });
4532
4545
  }
4533
4546
  }
4547
+ class EditorObjectAccordion extends EditorObject {
4548
+ static resolves(schema) {
4549
+ return getSchemaType(schema) === "object" && getSchemaXOption(schema, "format") === "accordion";
4550
+ }
4551
+ getObjectControlConfig() {
4552
+ return { ...super.getObjectControlConfig(), isAccordionProperties: true };
4553
+ }
4554
+ refreshEditors() {
4555
+ this.control.childrenSlot.replaceChildren();
4556
+ const accordionId = this.control.childrenSlot.id;
4557
+ this.instance.children.forEach((child) => {
4558
+ if (!child.isActive) return;
4559
+ const schemaTitle = getSchemaTitle(child.schema);
4560
+ const title = isSet(schemaTitle) ? schemaTitle : child.getKey();
4561
+ const id = this.getIdFromPath(child.path);
4562
+ const accordionItem = this.theme.getAccordionItem({ title, id, accordionId });
4563
+ accordionItem.body.appendChild(child.ui.control.container);
4564
+ this.control.childrenSlot.appendChild(accordionItem.container);
4565
+ if (this.disabled || this.instance.isReadOnly()) {
4566
+ child.ui.disable();
4567
+ } else {
4568
+ child.ui.enable();
4569
+ }
4570
+ });
4571
+ }
4572
+ }
4534
4573
  class EditorArray extends Editor {
4535
4574
  static resolves(schema) {
4536
4575
  return getSchemaType(schema) === "array";
@@ -4559,7 +4598,8 @@ class EditorArray extends Editor {
4559
4598
  arrayDeleteAllContent: getSchemaXOption(this.instance.schema, "arrayDeleteAllContent") ?? this.instance.jedison.translator.translate("arrayDeleteAll"),
4560
4599
  arrayFooterDeleteAll: getSchemaXOption(this.instance.schema, "arrayFooterDeleteAll") ?? this.instance.jedison.getOption("arrayFooterDeleteAll"),
4561
4600
  arrayFooterDeleteAllContent: getSchemaXOption(this.instance.schema, "arrayFooterDeleteAllContent") ?? this.instance.jedison.translator.translate("arrayDeleteAll"),
4562
- collapseToggleContent: getSchemaXOption(this.instance.schema, "collapseToggleContent") ?? this.instance.jedison.translator.translate("collapseToggle")
4601
+ collapseToggleContent: getSchemaXOption(this.instance.schema, "collapseToggleContent") ?? this.instance.jedison.translator.translate("collapseToggle"),
4602
+ titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass")
4563
4603
  });
4564
4604
  this.control.jsonData.input.value = JSON.stringify(this.instance.getValue(), null, 2);
4565
4605
  }
@@ -5470,8 +5510,18 @@ class EditorMultiple extends Editor {
5470
5510
  });
5471
5511
  });
5472
5512
  }
5513
+ if (this.switcherInput === "modal") {
5514
+ this.control.switcher.optionButtons.forEach((btn) => {
5515
+ btn.addEventListener("click", () => {
5516
+ const index2 = Number(btn.dataset.switcherValue);
5517
+ this.control.switcher.dialog.close();
5518
+ this.instance.switchInstance(index2, void 0, "user");
5519
+ });
5520
+ });
5521
+ }
5473
5522
  }
5474
5523
  refreshUI() {
5524
+ var _a;
5475
5525
  this.refreshDisabledState();
5476
5526
  this.control.childrenSlot.innerHTML = "";
5477
5527
  this.control.childrenSlot.appendChild(this.instance.activeInstance.ui.control.container);
@@ -5486,6 +5536,20 @@ class EditorMultiple extends Editor {
5486
5536
  this.control.header.appendChild(this.control.switcher.container);
5487
5537
  }
5488
5538
  }
5539
+ if (this.switcherInput === "modal") {
5540
+ const childControl = this.instance.activeInstance.ui.control;
5541
+ const infoContainer = childControl.infoContainer;
5542
+ const titleEl = childControl.legendText || childControl.label;
5543
+ if (infoContainer) {
5544
+ infoContainer.after(this.control.switcher.container);
5545
+ this.control.header.style.display = "none";
5546
+ } else if (titleEl) {
5547
+ const infoEl = (_a = childControl.info) == null ? void 0 : _a.container;
5548
+ const anchor = infoEl && infoEl.parentNode ? infoEl : titleEl;
5549
+ anchor.after(this.control.switcher.container);
5550
+ this.control.header.style.display = "none";
5551
+ }
5552
+ }
5489
5553
  if (this.switcherInput === "select") {
5490
5554
  this.control.switcher.input.value = this.instance.index;
5491
5555
  }
@@ -5495,6 +5559,12 @@ class EditorMultiple extends Editor {
5495
5559
  radio.checked = radioIndex === this.instance.index;
5496
5560
  });
5497
5561
  }
5562
+ if (this.switcherInput === "modal") {
5563
+ this.control.switcher.triggerText.textContent = this.instance.switcherOptionsLabels[this.instance.index];
5564
+ this.control.switcher.optionButtons.forEach((btn, index2) => {
5565
+ this.theme.setSwitcherOptionActive(btn, index2 === this.instance.index);
5566
+ });
5567
+ }
5498
5568
  if (this.disabled || this.instance.isReadOnly()) {
5499
5569
  this.instance.activeInstance.ui.disable();
5500
5570
  } else {
@@ -5995,6 +6065,48 @@ class EditorArrayCheckboxes extends Editor {
5995
6065
  }
5996
6066
  return getSchemaEnum(this.instance.schema.items) || [];
5997
6067
  }
6068
+ isSortable() {
6069
+ return window.Sortable && isSet(getSchemaXOption(this.instance.schema, "sortable"));
6070
+ }
6071
+ addDragHandles() {
6072
+ if (!this.isSortable()) return;
6073
+ this.control.checkboxControls.forEach((checkboxControl, index2) => {
6074
+ if (checkboxControl.classList.contains("jedi-checkbox-control")) return;
6075
+ const wrapper = document.createElement("div");
6076
+ wrapper.classList.add("jedi-checkbox-control");
6077
+ wrapper.style.display = "flex";
6078
+ wrapper.style.alignItems = "baseline";
6079
+ const dragBtn = this.theme.getDragItemBtn({
6080
+ content: this.instance.jedison.translator.translate("arrayDrag")
6081
+ });
6082
+ checkboxControl.parentNode.insertBefore(wrapper, checkboxControl);
6083
+ wrapper.appendChild(dragBtn);
6084
+ wrapper.appendChild(checkboxControl);
6085
+ this.control.checkboxControls[index2] = wrapper;
6086
+ });
6087
+ }
6088
+ refreshSortable() {
6089
+ if (this.isSortable()) {
6090
+ if (this.sortable) {
6091
+ this.sortable.destroy();
6092
+ }
6093
+ this.sortable = window.Sortable.create(this.control.fieldset, {
6094
+ animation: 150,
6095
+ handle: ".jedi-array-drag",
6096
+ draggable: ".jedi-checkbox-control",
6097
+ disabled: this.disabled || this.readOnly,
6098
+ onEnd: () => {
6099
+ const sorted = Array.from(this.control.fieldset.querySelectorAll(".jedi-checkbox-control"));
6100
+ this.control.checkboxControls = sorted;
6101
+ this.control.checkboxes = sorted.map((cc) => cc.querySelector('input[type="checkbox"]'));
6102
+ this.control.labels = sorted.map((cc) => cc.querySelector("label"));
6103
+ this.control.labelTexts = sorted.map((cc) => cc.querySelector("label span"));
6104
+ const newValue = this.control.checkboxes.filter((cb) => cb.checked).map((cb) => cb.value);
6105
+ this.instance.setValue(newValue, true, "user");
6106
+ }
6107
+ });
6108
+ }
6109
+ }
5998
6110
  build() {
5999
6111
  const values = this.getEnumSourceValues();
6000
6112
  const schemaItems = this.instance.schema.items || {};
@@ -6009,6 +6121,7 @@ class EditorArrayCheckboxes extends Editor {
6009
6121
  inline: getSchemaXOption(this.instance.schema, "format") === "checkboxes-inline",
6010
6122
  info: this.getInfo()
6011
6123
  });
6124
+ this.addDragHandles();
6012
6125
  }
6013
6126
  refreshOptions() {
6014
6127
  const values = this.getEnumSourceValues();
@@ -6047,6 +6160,7 @@ class EditorArrayCheckboxes extends Editor {
6047
6160
  this.control.checkboxControls.push(checkboxControl);
6048
6161
  this.control.fieldset.insertBefore(checkboxControl, this.control.description);
6049
6162
  });
6163
+ this.addDragHandles();
6050
6164
  this.addEventListeners();
6051
6165
  this.refreshUI();
6052
6166
  }
@@ -6081,6 +6195,7 @@ class EditorArrayCheckboxes extends Editor {
6081
6195
  this.control.checkboxes.forEach((checkbox) => {
6082
6196
  checkbox.checked = value.includes(checkbox.value);
6083
6197
  });
6198
+ this.refreshSortable();
6084
6199
  }
6085
6200
  setAriaInvalid(invalid) {
6086
6201
  this.control.checkboxes.forEach((checkbox) => {
@@ -6257,6 +6372,69 @@ class EditorStringAce extends EditorString {
6257
6372
  }
6258
6373
  }
6259
6374
  }
6375
+ class EditorStringFilepond extends EditorString {
6376
+ static resolves(schema) {
6377
+ const format2 = getSchemaXOption(schema, "format");
6378
+ return isSet(format2) && format2 === "filepond" && window.FilePond && getSchemaType(schema) === "string";
6379
+ }
6380
+ build() {
6381
+ this.control = this.theme.getInputControl({
6382
+ title: this.getTitle(),
6383
+ description: this.getDescription(),
6384
+ type: "file",
6385
+ id: this.getIdFromPath(this.instance.path),
6386
+ titleIconClass: getSchemaXOption(this.instance.schema, "titleIconClass"),
6387
+ titleHidden: getSchemaXOption(this.instance.schema, "titleHidden"),
6388
+ info: this.getInfo()
6389
+ });
6390
+ try {
6391
+ const schemaFilepond = getSchemaXOption(this.instance.schema, "filepond") ?? {};
6392
+ const settingsKey = schemaFilepond["x-settings"];
6393
+ const settings = settingsKey && this.instance.jedison.getOption("settings")[settingsKey] ? this.instance.jedison.getOption("settings")[settingsKey] : {};
6394
+ const filepondOptions = { ...schemaFilepond, ...settings };
6395
+ this.hasServer = !!filepondOptions.server;
6396
+ this.filepond = window.FilePond.create(this.control.input, filepondOptions);
6397
+ this.filepond.on("processfile", (error, file) => {
6398
+ if (error) return;
6399
+ const serverIds = this.filepond.getFiles().filter((f) => f.serverId).map((f) => f.serverId);
6400
+ this.instance.setValue(serverIds.join(", "), true, "user");
6401
+ });
6402
+ this.filepond.on("addfile", (error) => {
6403
+ if (error || this.hasServer) return;
6404
+ const names = this.filepond.getFiles().map((f) => f.filename).join(", ");
6405
+ this.instance.setValue(names, true, "user");
6406
+ });
6407
+ this.filepond.on("processfilerevert", () => {
6408
+ const serverIds = this.filepond.getFiles().filter((f) => f.serverId).map((f) => f.serverId);
6409
+ this.instance.setValue(serverIds.join(", "), true, "user");
6410
+ });
6411
+ this.filepond.on("removefile", () => {
6412
+ const remaining = this.filepond.getFiles();
6413
+ if (this.hasServer) {
6414
+ const serverIds = remaining.filter((f) => f.serverId).map((f) => f.serverId);
6415
+ this.instance.setValue(serverIds.join(", "), true, "user");
6416
+ } else {
6417
+ this.instance.setValue(remaining.map((f) => f.filename).join(", "), true, "user");
6418
+ }
6419
+ });
6420
+ } catch (e) {
6421
+ console.error("FilePond is not available or not loaded correctly.", e);
6422
+ }
6423
+ }
6424
+ addEventListeners() {
6425
+ }
6426
+ refreshUI() {
6427
+ if (!this.filepond) return;
6428
+ this.refreshTemplates();
6429
+ this.filepond.setOptions({ disabled: this.disabled || this.readOnly });
6430
+ }
6431
+ destroy() {
6432
+ if (this.filepond) {
6433
+ this.filepond.destroy();
6434
+ }
6435
+ super.destroy();
6436
+ }
6437
+ }
6260
6438
  class UiResolver {
6261
6439
  constructor(options) {
6262
6440
  this.customEditors = options.customEditors ?? [];
@@ -6281,6 +6459,7 @@ class UiResolver {
6281
6459
  EditorStringFlatpickr,
6282
6460
  EditorStringIMask,
6283
6461
  EditorStringAce,
6462
+ EditorStringFilepond,
6284
6463
  EditorStringInput,
6285
6464
  EditorNumberIMask,
6286
6465
  EditorNumberRaty,
@@ -6291,6 +6470,7 @@ class UiResolver {
6291
6470
  EditorObjectGrid,
6292
6471
  EditorObjectCategories,
6293
6472
  EditorObjectNav,
6473
+ EditorObjectAccordion,
6294
6474
  EditorObject,
6295
6475
  EditorArrayChoices,
6296
6476
  EditorArrayCheckboxes,
@@ -7297,6 +7477,7 @@ class Theme {
7297
7477
  const right = document.createElement("div");
7298
7478
  const legend = document.createElement("legend");
7299
7479
  const legendText = document.createElement("label");
7480
+ const icon = document.createElement("i");
7300
7481
  const infoContainer = document.createElement("span");
7301
7482
  const dummyInput = document.createElement("input");
7302
7483
  const legendLabelId = "legend-label-" + config.id;
@@ -7312,6 +7493,11 @@ class Theme {
7312
7493
  legendText.classList.add("jedi-legend");
7313
7494
  legendText.setAttribute("id", legendLabelId);
7314
7495
  legendText.innerHTML = config.content;
7496
+ if (config.titleIconClass) {
7497
+ this.addIconClass(icon, config.titleIconClass);
7498
+ icon.style.marginRight = "4px";
7499
+ }
7500
+ legendText.style.marginRight = "4px";
7315
7501
  infoContainer.classList.add("jedi-editor-info-container");
7316
7502
  infoContainer.setAttribute("for", dummyInputId);
7317
7503
  dummyInput.setAttribute("aria-hidden", "true");
@@ -7323,6 +7509,9 @@ class Theme {
7323
7509
  }
7324
7510
  legend.appendChild(left);
7325
7511
  legend.appendChild(right);
7512
+ if (config.titleIconClass) {
7513
+ left.appendChild(icon);
7514
+ }
7326
7515
  left.appendChild(legendText);
7327
7516
  left.appendChild(infoContainer);
7328
7517
  legendText.appendChild(dummyInput);
@@ -7346,6 +7535,7 @@ class Theme {
7346
7535
  const legendLabelId = "legend-label-" + config.id;
7347
7536
  const legend = document.createElement("legend");
7348
7537
  const legendText = document.createElement("label");
7538
+ const icon = document.createElement("i");
7349
7539
  const dummyInput = document.createElement("input");
7350
7540
  legend.classList.add("jedi-editor-legend");
7351
7541
  legend.style.fontSize = "inherit";
@@ -7354,13 +7544,19 @@ class Theme {
7354
7544
  legendText.classList.add("jedi-label");
7355
7545
  legendText.innerHTML = config.content;
7356
7546
  legendText.setAttribute("id", legendLabelId);
7547
+ legendText.style.marginRight = "4px";
7357
7548
  dummyInput.setAttribute("aria-hidden", "true");
7358
7549
  dummyInput.setAttribute("type", "hidden");
7359
7550
  dummyInput.setAttribute("disabled", "");
7360
7551
  this.visuallyHidden(dummyInput);
7552
+ if (config.titleIconClass) {
7553
+ this.addIconClass(icon, config.titleIconClass);
7554
+ icon.style.marginRight = "4px";
7555
+ legend.appendChild(icon);
7556
+ }
7361
7557
  legend.appendChild(legendText);
7362
7558
  legendText.appendChild(dummyInput);
7363
- return { legend, legendText };
7559
+ return { legend, legendText, icon };
7364
7560
  }
7365
7561
  /**
7366
7562
  * Represents a caption for the content of its parent fieldset
@@ -7378,10 +7574,12 @@ class Theme {
7378
7574
  }
7379
7575
  if (config.titleIconClass) {
7380
7576
  this.addIconClass(icon, config.titleIconClass);
7577
+ icon.style.marginRight = "4px";
7381
7578
  }
7382
7579
  if (config.titleIconClass) {
7383
7580
  label.appendChild(icon);
7384
7581
  }
7582
+ labelText.style.marginRight = "4px";
7385
7583
  label.appendChild(labelText);
7386
7584
  return { label, labelText, icon };
7387
7585
  }
@@ -7399,13 +7597,17 @@ class Theme {
7399
7597
  labelText.innerHTML = config.content;
7400
7598
  if (config.titleIconClass) {
7401
7599
  this.addIconClass(icon, config.titleIconClass);
7600
+ icon.style.marginRight = "4px";
7402
7601
  }
7403
7602
  dummyInput.setAttribute("aria-hidden", "true");
7404
7603
  dummyInput.setAttribute("type", "hidden");
7405
7604
  dummyInput.setAttribute("disabled", "");
7406
7605
  dummyInput.setAttribute("id", config.for);
7407
7606
  this.visuallyHidden(dummyInput);
7408
- label.appendChild(icon);
7607
+ if (config.titleIconClass) {
7608
+ label.appendChild(icon);
7609
+ }
7610
+ labelText.style.marginRight = "4px";
7409
7611
  label.appendChild(labelText);
7410
7612
  label.appendChild(dummyInput);
7411
7613
  return { label, labelText, icon, dummyInput };
@@ -7570,31 +7772,27 @@ class Theme {
7570
7772
  }
7571
7773
  });
7572
7774
  }
7573
- let collapsed = config.startCollapsed;
7574
- if (collapsed) {
7575
- toggle.setAttribute("aria-expanded", "false");
7576
- } else {
7577
- toggle.setAttribute("aria-expanded", "true");
7578
- }
7579
7775
  toggle.style.transition = "transform 0.1s ease";
7580
- if (collapsed) {
7581
- toggle.style.transform = "rotate(90deg)";
7776
+ if (config.startCollapsed) {
7777
+ toggle.classList.add("collapsed");
7582
7778
  }
7583
- toggle.addEventListener("click", () => {
7584
- if (collapsed) {
7585
- toggle.style.transform = "rotate(0deg)";
7586
- } else {
7587
- toggle.style.transform = "rotate(90deg)";
7588
- }
7589
- collapsed = !collapsed;
7590
- });
7779
+ const syncState = () => {
7780
+ const collapsed = toggle.classList.contains("collapsed");
7781
+ toggle.setAttribute("aria-expanded", collapsed ? "false" : "true");
7782
+ toggle.style.transform = collapsed ? "rotate(90deg)" : "rotate(0deg)";
7783
+ };
7784
+ syncState();
7785
+ if (this.useToggleEvents) {
7786
+ toggle.addEventListener("click", () => toggle.classList.toggle("collapsed"));
7787
+ }
7788
+ new MutationObserver(syncState).observe(toggle, { attributes: true, attributeFilter: ["class"] });
7591
7789
  return toggle;
7592
7790
  }
7593
7791
  /**
7594
7792
  * Container for properties editing elements like property activators
7595
7793
  */
7596
7794
  getPropertiesSlot(config) {
7597
- const html = document.createElement("dialog");
7795
+ const html = this.getDialog();
7598
7796
  html.classList.add("jedi-properties-slot");
7599
7797
  html.setAttribute("id", config.id);
7600
7798
  html.addEventListener("click", (event) => {
@@ -7605,7 +7803,7 @@ class Theme {
7605
7803
  return html;
7606
7804
  }
7607
7805
  getQuickAddPropertySlot(config) {
7608
- const html = document.createElement("dialog");
7806
+ const html = this.getDialog();
7609
7807
  html.classList.add("jedi-quick-add-property-slot");
7610
7808
  html.setAttribute("id", config.id);
7611
7809
  html.addEventListener("click", (event) => {
@@ -7619,7 +7817,7 @@ class Theme {
7619
7817
  * Container for properties editing elements like property activators
7620
7818
  */
7621
7819
  getJsonData(config) {
7622
- const dialog = document.createElement("dialog");
7820
+ const dialog = this.getDialog();
7623
7821
  dialog.classList.add("jedi-json-data");
7624
7822
  dialog.setAttribute("id", config.id);
7625
7823
  dialog.addEventListener("click", (event) => {
@@ -7862,7 +8060,6 @@ class Theme {
7862
8060
  container.style.display = "inline-block";
7863
8061
  info.setAttribute("href", "#");
7864
8062
  info.classList.add("jedi-info-button");
7865
- info.style.marginLeft = "4px";
7866
8063
  if (isObject(config.attributes)) {
7867
8064
  for (const [key, value] of Object.entries(config.attributes)) {
7868
8065
  info.setAttribute(key, value);
@@ -7881,18 +8078,28 @@ class Theme {
7881
8078
  container.appendChild(info);
7882
8079
  return { container, info };
7883
8080
  }
8081
+ /**
8082
+ * Creates a base native <dialog> element with shared styling
8083
+ */
8084
+ getDialog() {
8085
+ const dialog = document.createElement("dialog");
8086
+ dialog.classList.add("jedi-modal-dialog");
8087
+ dialog.style.border = "1px solid #6c757d";
8088
+ dialog.style.borderRadius = "4px";
8089
+ dialog.style.minWidth = "200px";
8090
+ return dialog;
8091
+ }
7884
8092
  /**
7885
8093
  * Dialog or modal that contains extra information about the control
7886
8094
  */
7887
8095
  infoAsModal(info, id, config = {}) {
7888
- const dialog = document.createElement("dialog");
8096
+ const dialog = this.getDialog();
7889
8097
  const title = document.createElement("div");
7890
8098
  const content = document.createElement("div");
7891
8099
  const closeBtn = this.getButton({
7892
8100
  content: "Close",
7893
8101
  icon: "close"
7894
8102
  });
7895
- dialog.classList.add("jedi-modal-dialog");
7896
8103
  dialog.setAttribute("id", id + "-modal");
7897
8104
  title.classList.add("jedi-modal-title");
7898
8105
  if (isString(config.title)) {
@@ -7946,13 +8153,13 @@ class Theme {
7946
8153
  }
7947
8154
  container.appendChild(label);
7948
8155
  if (isObject(config.info)) {
7949
- label.appendChild(info.container);
8156
+ container.appendChild(info.container);
7950
8157
  }
7951
8158
  container.appendChild(placeholder);
7952
8159
  container.appendChild(description);
7953
8160
  container.appendChild(messages);
7954
8161
  container.appendChild(actions);
7955
- return { container, placeholder, label, labelText, description, messages, actions };
8162
+ return { container, placeholder, label, info, labelText, description, messages, actions };
7956
8163
  }
7957
8164
  /**
7958
8165
  * Object control is a card containing multiple editors.
@@ -7968,6 +8175,9 @@ class Theme {
7968
8175
  const ariaLive = this.getPropertiesAriaLive();
7969
8176
  const messages = this.getMessagesSlot();
7970
8177
  const childrenSlot = this.getChildrenSlot();
8178
+ if (config.isAccordion || config.isAccordionProperties) {
8179
+ childrenSlot.id = "accordion-" + config.id;
8180
+ }
7971
8181
  const propertiesActivators = this.getPropertiesActivators();
7972
8182
  const info = this.getInfo(config.info);
7973
8183
  const description = this.getDescription({
@@ -8018,7 +8228,8 @@ class Theme {
8018
8228
  const { legend, infoContainer, legendText, right } = this.getLegend({
8019
8229
  content: config.title,
8020
8230
  id: config.id,
8021
- titleHidden: config.titleHidden
8231
+ titleHidden: config.titleHidden,
8232
+ titleIconClass: config.titleIconClass
8022
8233
  });
8023
8234
  if (((_a = config == null ? void 0 : config.info) == null ? void 0 : _a.variant) === "modal") {
8024
8235
  this.infoAsModal(info, config.id, config.info);
@@ -8035,7 +8246,9 @@ class Theme {
8035
8246
  }
8036
8247
  fieldset.appendChild(legend);
8037
8248
  if (isObject(config.info)) {
8038
- infoContainer.appendChild(info.container);
8249
+ while (info.container.firstChild) {
8250
+ infoContainer.appendChild(info.container.firstChild);
8251
+ }
8039
8252
  }
8040
8253
  fieldset.appendChild(collapse);
8041
8254
  collapse.appendChild(body);
@@ -8089,6 +8302,57 @@ class Theme {
8089
8302
  switcherSlot
8090
8303
  };
8091
8304
  }
8305
+ /**
8306
+ * Returns an accordion item wrapping a child editor.
8307
+ * Used by EditorObjectAccordionProperties to wrap each property.
8308
+ */
8309
+ getAccordionItem(config) {
8310
+ const container = document.createElement("div");
8311
+ container.classList.add("jedi-accordion-item");
8312
+ const header = document.createElement("div");
8313
+ header.classList.add("jedi-accordion-header");
8314
+ const toggle = document.createElement("button");
8315
+ toggle.type = "button";
8316
+ toggle.classList.add("jedi-accordion-toggle", "collapsed");
8317
+ const chevron = document.createElement("i");
8318
+ chevron.classList.add("jedi-accordion-chevron");
8319
+ if (this.icons && this.icons["collapse"]) {
8320
+ this.addIconClass(chevron, this.icons["collapse"]);
8321
+ } else {
8322
+ chevron.textContent = "▾";
8323
+ }
8324
+ chevron.style.display = "inline-block";
8325
+ chevron.style.transition = "transform 0.1s ease";
8326
+ chevron.style.marginRight = "0.5em";
8327
+ toggle.appendChild(chevron);
8328
+ toggle.appendChild(document.createTextNode(config.title));
8329
+ const collapse = document.createElement("div");
8330
+ collapse.classList.add("jedi-accordion-collapse");
8331
+ collapse.style.display = "none";
8332
+ const body = document.createElement("div");
8333
+ body.classList.add("jedi-accordion-body");
8334
+ const syncState = () => {
8335
+ const collapsed = toggle.classList.contains("collapsed");
8336
+ chevron.style.transform = collapsed ? "rotate(0deg)" : "rotate(-180deg)";
8337
+ };
8338
+ syncState();
8339
+ if (this.useToggleEvents) {
8340
+ toggle.addEventListener("click", () => {
8341
+ if (collapse.style.display === "none") {
8342
+ collapse.style.display = "block";
8343
+ } else {
8344
+ collapse.style.display = "none";
8345
+ }
8346
+ toggle.classList.toggle("collapsed");
8347
+ });
8348
+ }
8349
+ new MutationObserver(syncState).observe(toggle, { attributes: true, attributeFilter: ["class"] });
8350
+ header.appendChild(toggle);
8351
+ collapse.appendChild(body);
8352
+ container.appendChild(header);
8353
+ container.appendChild(collapse);
8354
+ return { container, header, toggle, collapse, body };
8355
+ }
8092
8356
  /**
8093
8357
  * Array control is a card containing multiple editors.
8094
8358
  * Items can bve added, deleted or moved up or down.
@@ -8117,7 +8381,8 @@ class Theme {
8117
8381
  const { legend, legendText, infoContainer, right } = this.getLegend({
8118
8382
  content: config.title,
8119
8383
  id: config.id,
8120
- titleHidden: config.titleHidden
8384
+ titleHidden: config.titleHidden,
8385
+ titleIconClass: config.titleIconClass
8121
8386
  });
8122
8387
  const description = this.getDescription({
8123
8388
  content: config.description
@@ -8146,7 +8411,9 @@ class Theme {
8146
8411
  }
8147
8412
  fieldset.appendChild(legend);
8148
8413
  if (isObject(config.info)) {
8149
- infoContainer.appendChild(info.container);
8414
+ while (info.container.firstChild) {
8415
+ infoContainer.appendChild(info.container.firstChild);
8416
+ }
8150
8417
  }
8151
8418
  fieldset.appendChild(collapse);
8152
8419
  collapse.appendChild(body);
@@ -8201,6 +8468,7 @@ class Theme {
8201
8468
  jsonData,
8202
8469
  legend,
8203
8470
  legendText,
8471
+ infoContainer,
8204
8472
  switcherSlot,
8205
8473
  footerAddBtn,
8206
8474
  deleteAllBtn,
@@ -8240,7 +8508,7 @@ class Theme {
8240
8508
  const messages = this.getMessagesSlot();
8241
8509
  const childrenSlot = this.getChildrenSlot();
8242
8510
  const randomId = generateRandomID(5);
8243
- const knownSwitchers = ["select", "radios", "radios-inline"];
8511
+ const knownSwitchers = ["select", "radios", "radios-inline", "modal"];
8244
8512
  const switcherType = knownSwitchers.includes(config.switcher) ? config.switcher : "select";
8245
8513
  let switcher;
8246
8514
  if (switcherType === "select") {
@@ -8268,6 +8536,14 @@ class Theme {
8268
8536
  noSpacing: true
8269
8537
  });
8270
8538
  }
8539
+ if (switcherType === "modal") {
8540
+ switcher = this.getSwitcherModal({
8541
+ values: config.switcherOptionValues,
8542
+ titles: config.switcherOptionsLabels,
8543
+ id: config.id + "-switcher-" + randomId,
8544
+ readOnly: config.readOnly
8545
+ });
8546
+ }
8271
8547
  switcher.container.classList.add("jedi-switcher");
8272
8548
  container.appendChild(header);
8273
8549
  container.appendChild(body);
@@ -8338,13 +8614,13 @@ class Theme {
8338
8614
  }
8339
8615
  container.appendChild(label);
8340
8616
  if (isObject(config.info)) {
8341
- label.appendChild(info.container);
8617
+ container.appendChild(info.container);
8342
8618
  }
8343
8619
  container.appendChild(br);
8344
8620
  container.appendChild(description);
8345
8621
  container.appendChild(messages);
8346
8622
  container.appendChild(actions);
8347
- return { container, label, labelText, description, messages, actions };
8623
+ return { container, label, info, labelText, description, messages, actions };
8348
8624
  }
8349
8625
  /**
8350
8626
  * A Textarea
@@ -8361,7 +8637,8 @@ class Theme {
8361
8637
  const { label, labelText } = this.getLabel({
8362
8638
  for: config.id,
8363
8639
  text: config.title,
8364
- visuallyHidden: config.titleHidden
8640
+ visuallyHidden: config.titleHidden,
8641
+ titleIconClass: config.titleIconClass
8365
8642
  });
8366
8643
  const description = this.getDescription({
8367
8644
  content: config.description,
@@ -8379,13 +8656,13 @@ class Theme {
8379
8656
  }
8380
8657
  container.appendChild(label);
8381
8658
  if (isObject(config.info)) {
8382
- label.appendChild(info.container);
8659
+ container.appendChild(info.container);
8383
8660
  }
8384
8661
  container.appendChild(input);
8385
8662
  container.appendChild(description);
8386
8663
  container.appendChild(messages);
8387
8664
  container.appendChild(actions);
8388
- return { container, input, label, labelText, description, messages, actions };
8665
+ return { container, input, label, info, labelText, description, messages, actions };
8389
8666
  }
8390
8667
  adaptForTableTextareaControl(control) {
8391
8668
  this.visuallyHidden(control.label);
@@ -8427,7 +8704,7 @@ class Theme {
8427
8704
  this.infoAsModal(info, config.id, config.info);
8428
8705
  }
8429
8706
  if (isObject(config.info)) {
8430
- label.appendChild(info.container);
8707
+ container.appendChild(info.container);
8431
8708
  }
8432
8709
  container.appendChild(input);
8433
8710
  container.appendChild(description);
@@ -8461,7 +8738,8 @@ class Theme {
8461
8738
  const { legend, legendText } = this.getRadioLegend({
8462
8739
  content: config.title,
8463
8740
  id: config.id,
8464
- for: config.id
8741
+ for: config.id,
8742
+ titleIconClass: config.titleIconClass
8465
8743
  });
8466
8744
  const messages = this.getMessagesSlot({
8467
8745
  id: messagesId
@@ -8505,7 +8783,7 @@ class Theme {
8505
8783
  container.appendChild(fieldset);
8506
8784
  fieldset.appendChild(legend);
8507
8785
  if (isObject(config.info)) {
8508
- legendText.appendChild(info.container);
8786
+ legendText.after(info.container);
8509
8787
  }
8510
8788
  radioControls.forEach((radioControl, index2) => {
8511
8789
  fieldset.appendChild(radioControls[index2]);
@@ -8549,7 +8827,8 @@ class Theme {
8549
8827
  const { label, labelText } = this.getLabel({
8550
8828
  for: config.id,
8551
8829
  text: config.title,
8552
- visuallyHidden: config.titleHidden
8830
+ visuallyHidden: config.titleHidden,
8831
+ titleIconClass: config.titleIconClass
8553
8832
  });
8554
8833
  const description = this.getDescription({
8555
8834
  content: config.description,
@@ -8570,7 +8849,7 @@ class Theme {
8570
8849
  formGroup.appendChild(input);
8571
8850
  formGroup.appendChild(label);
8572
8851
  if (isObject(config.info)) {
8573
- label.appendChild(info.container);
8852
+ formGroup.appendChild(info.container);
8574
8853
  }
8575
8854
  formGroup.appendChild(description);
8576
8855
  formGroup.appendChild(messages);
@@ -8590,7 +8869,8 @@ class Theme {
8590
8869
  const { legend, legendText } = this.getRadioLegend({
8591
8870
  content: config.title,
8592
8871
  id: config.id,
8593
- for: config.id
8872
+ for: config.id,
8873
+ titleIconClass: config.titleIconClass
8594
8874
  });
8595
8875
  const messages = this.getMessagesSlot({
8596
8876
  id: messagesId
@@ -8633,7 +8913,7 @@ class Theme {
8633
8913
  container.appendChild(fieldset);
8634
8914
  fieldset.appendChild(legend);
8635
8915
  if (isObject(config.info)) {
8636
- legendText.appendChild(info.container);
8916
+ legendText.after(info.container);
8637
8917
  }
8638
8918
  checkboxControls.forEach((checkboxControl, index2) => {
8639
8919
  fieldset.appendChild(checkboxControls[index2]);
@@ -8675,7 +8955,8 @@ class Theme {
8675
8955
  const { label, labelText } = this.getLabel({
8676
8956
  for: config.id,
8677
8957
  text: config.title,
8678
- visuallyHidden: config.titleHidden
8958
+ visuallyHidden: config.titleHidden,
8959
+ titleIconClass: config.titleIconClass
8679
8960
  });
8680
8961
  const messages = this.getMessagesSlot({
8681
8962
  id: messagesId
@@ -8700,7 +8981,7 @@ class Theme {
8700
8981
  }
8701
8982
  container.appendChild(label);
8702
8983
  if (isObject(config.info)) {
8703
- label.appendChild(info.container);
8984
+ container.appendChild(info.container);
8704
8985
  }
8705
8986
  container.appendChild(input);
8706
8987
  container.appendChild(description);
@@ -8724,6 +9005,62 @@ class Theme {
8724
9005
  getSwitcherRadios(config) {
8725
9006
  return this.getRadiosControl(config);
8726
9007
  }
9008
+ /**
9009
+ * Compact badge-button trigger that opens a modal to switch between multiple editors options
9010
+ */
9011
+ getSwitcherModal(config) {
9012
+ const container = document.createElement("span");
9013
+ const trigger = document.createElement("span");
9014
+ const dialog = this.getDialog();
9015
+ const dialogBody = document.createElement("div");
9016
+ const optionButtons = [];
9017
+ const triggerText = document.createElement("span");
9018
+ const triggerIcon = document.createElement("i");
9019
+ container.classList.add("jedi-switcher-modal");
9020
+ trigger.classList.add("jedi-switcher-modal-trigger");
9021
+ trigger.setAttribute("role", "button");
9022
+ trigger.setAttribute("tabindex", "0");
9023
+ trigger.setAttribute("aria-haspopup", "dialog");
9024
+ trigger.setAttribute("aria-label", "Switch type");
9025
+ trigger.appendChild(triggerText);
9026
+ if (this.icons && this.icons.switcher) {
9027
+ this.addIconClass(triggerIcon, this.icons.switcher);
9028
+ trigger.appendChild(document.createTextNode(" "));
9029
+ trigger.appendChild(triggerIcon);
9030
+ }
9031
+ dialogBody.classList.add("jedi-modal-content");
9032
+ config.values.forEach((value, index2) => {
9033
+ const btn = document.createElement("button");
9034
+ btn.setAttribute("type", "button");
9035
+ btn.setAttribute("aria-label", `Select: ${config.titles[index2]}`);
9036
+ btn.textContent = config.titles[index2];
9037
+ btn.dataset.switcherValue = value;
9038
+ btn.classList.add("jedi-switcher-option-btn");
9039
+ optionButtons.push(btn);
9040
+ dialogBody.appendChild(btn);
9041
+ });
9042
+ trigger.addEventListener("click", () => {
9043
+ dialog.showModal();
9044
+ });
9045
+ trigger.addEventListener("keydown", (event) => {
9046
+ if (event.key === "Enter" || event.key === " ") {
9047
+ event.preventDefault();
9048
+ dialog.showModal();
9049
+ }
9050
+ });
9051
+ dialog.addEventListener("click", (event) => {
9052
+ if (event.target === dialog) {
9053
+ dialog.close();
9054
+ }
9055
+ });
9056
+ container.appendChild(trigger);
9057
+ container.appendChild(dialog);
9058
+ dialog.appendChild(dialogBody);
9059
+ return { container, trigger, triggerText, dialog, dialogBody, optionButtons };
9060
+ }
9061
+ setSwitcherOptionActive(btn, active) {
9062
+ btn.classList.toggle("jedi-switcher-option-active", active);
9063
+ }
8727
9064
  /**
8728
9065
  * Another type of error message container used for more complex editors like
8729
9066
  * object, array and multiple editors
@@ -8935,6 +9272,74 @@ class ThemeBootstrap3 extends Theme {
8935
9272
  }
8936
9273
  return collapse;
8937
9274
  }
9275
+ getObjectControl(config) {
9276
+ const control = super.getObjectControl(config);
9277
+ if (config.isAccordion) {
9278
+ const { childrenSlot } = control;
9279
+ childrenSlot.classList.add("panel-group");
9280
+ const accordionId = childrenSlot.id;
9281
+ const originalAppendChild = childrenSlot.appendChild.bind(childrenSlot);
9282
+ childrenSlot.appendChild = (child) => {
9283
+ const collapse = child.querySelector(".collapse");
9284
+ if (collapse) {
9285
+ collapse.classList.remove("in");
9286
+ collapse.classList.add("panel-collapse");
9287
+ }
9288
+ const collapseToggle = child.querySelector(".jedi-collapse-toggle");
9289
+ if (collapseToggle) {
9290
+ collapseToggle.setAttribute("data-parent", "#" + accordionId);
9291
+ }
9292
+ return originalAppendChild(child);
9293
+ };
9294
+ }
9295
+ if (config.isAccordionProperties) {
9296
+ control.childrenSlot.classList.add("panel-group");
9297
+ }
9298
+ return control;
9299
+ }
9300
+ getAccordionItem(config) {
9301
+ const collapseId = config.id + "-acc-collapse";
9302
+ const container = document.createElement("div");
9303
+ container.classList.add("panel", "panel-default");
9304
+ const header = document.createElement("div");
9305
+ header.classList.add("panel-heading", "collapsed");
9306
+ header.setAttribute("data-toggle", "collapse");
9307
+ header.setAttribute("data-parent", "#" + config.accordionId);
9308
+ header.setAttribute("href", "#" + collapseId);
9309
+ header.style.cursor = "pointer";
9310
+ const title = document.createElement("h4");
9311
+ title.classList.add("panel-title");
9312
+ const toggle = document.createElement("a");
9313
+ const chevron = document.createElement("i");
9314
+ chevron.classList.add("jedi-accordion-chevron");
9315
+ if (this.icons && this.icons["collapse"]) {
9316
+ this.addIconClass(chevron, this.icons["collapse"]);
9317
+ } else {
9318
+ chevron.textContent = "▾";
9319
+ }
9320
+ chevron.style.display = "inline-block";
9321
+ chevron.style.transition = "transform 0.1s ease";
9322
+ chevron.style.marginRight = "0.5em";
9323
+ toggle.appendChild(chevron);
9324
+ toggle.appendChild(document.createTextNode(config.title));
9325
+ const collapse = document.createElement("div");
9326
+ collapse.id = collapseId;
9327
+ collapse.classList.add("panel-collapse", "collapse");
9328
+ const syncState = () => {
9329
+ const collapsed = header.classList.contains("collapsed");
9330
+ chevron.style.transform = collapsed ? "rotate(-90deg)" : "rotate(0deg)";
9331
+ };
9332
+ syncState();
9333
+ new MutationObserver(syncState).observe(header, { attributes: true, attributeFilter: ["class"] });
9334
+ const body = document.createElement("div");
9335
+ body.classList.add("panel-body", "p-0");
9336
+ title.appendChild(toggle);
9337
+ header.appendChild(title);
9338
+ collapse.appendChild(body);
9339
+ container.appendChild(header);
9340
+ container.appendChild(collapse);
9341
+ return { container, header, toggle, collapse, body };
9342
+ }
8938
9343
  getJsonData(config) {
8939
9344
  const jsonData = super.getJsonData(config);
8940
9345
  jsonData.control.classList.add("form-group");
@@ -8954,13 +9359,14 @@ class ThemeBootstrap3 extends Theme {
8954
9359
  }
8955
9360
  getLegend(config) {
8956
9361
  const superLegend = super.getLegend(config);
8957
- const { legend } = superLegend;
9362
+ const { legend, infoContainer } = superLegend;
8958
9363
  legend.classList.add("panel-heading");
8959
9364
  legend.classList.add("pull-left");
8960
9365
  legend.style.margin = "0";
8961
9366
  legend.style.display = "flex";
8962
9367
  legend.style.justifyContent = "space-between";
8963
9368
  legend.style.alignItems = "center";
9369
+ infoContainer.style.marginRight = "4px";
8964
9370
  return superLegend;
8965
9371
  }
8966
9372
  getRadioLegend(config) {
@@ -8972,11 +9378,12 @@ class ThemeBootstrap3 extends Theme {
8972
9378
  return superRadioLegend;
8973
9379
  }
8974
9380
  getLabel(config) {
8975
- const labelObj = super.getLabel(config);
8976
- if (labelObj.icon.classList) {
8977
- labelObj.icon.style.marginRight = "5px";
8978
- }
8979
- return labelObj;
9381
+ return super.getLabel(config);
9382
+ }
9383
+ getInfo(config = {}) {
9384
+ const info = super.getInfo(config);
9385
+ info.container.style.marginRight = "4px";
9386
+ return info;
8980
9387
  }
8981
9388
  getCard() {
8982
9389
  const card = super.getCard();
@@ -9136,6 +9543,26 @@ class ThemeBootstrap3 extends Theme {
9136
9543
  super.adaptForTableSelectControl(control, td);
9137
9544
  control.container.classList.remove("form-group");
9138
9545
  }
9546
+ getSwitcherSelect(config) {
9547
+ const control = super.getSwitcherSelect(config);
9548
+ control.input.classList.add("input-sm");
9549
+ return control;
9550
+ }
9551
+ getSwitcherModal(config) {
9552
+ const control = super.getSwitcherModal(config);
9553
+ control.trigger.classList.add("label", "label-primary");
9554
+ control.dialogBody.classList.add("btn-group-vertical");
9555
+ control.dialogBody.style.width = "100%";
9556
+ control.optionButtons.forEach((btn) => {
9557
+ btn.classList.add("btn", "btn-default", "btn-block");
9558
+ });
9559
+ return control;
9560
+ }
9561
+ setSwitcherOptionActive(btn, active) {
9562
+ super.setSwitcherOptionActive(btn, active);
9563
+ btn.classList.toggle("btn-primary", active);
9564
+ btn.classList.toggle("btn-default", !active);
9565
+ }
9139
9566
  adaptForTableMultipleControl(control, td) {
9140
9567
  super.adaptForTableMultipleControl(control, td);
9141
9568
  }
@@ -9188,7 +9615,7 @@ class ThemeBootstrap3 extends Theme {
9188
9615
  tab.link.style.display = "flex";
9189
9616
  tab.link.style.alignItems = "center";
9190
9617
  tab.arrayActions.style.flexShrink = "0";
9191
- tab.arrayActions.style.whiteSpace = "nowrap";
9618
+ tab.arrayActions.classList.add("text-nowrap");
9192
9619
  tab.text.style.flex = "1";
9193
9620
  tab.text.style.marginLeft = "5px";
9194
9621
  tab.text.style.marginRight = "5px";
@@ -9197,7 +9624,7 @@ class ThemeBootstrap3 extends Theme {
9197
9624
  if (warning) {
9198
9625
  tab.text.removeChild(warning);
9199
9626
  warning.style.flexShrink = "0";
9200
- warning.style.whiteSpace = "nowrap";
9627
+ warning.classList.add("text-nowrap");
9201
9628
  tab.link.appendChild(warning);
9202
9629
  }
9203
9630
  }
@@ -9302,6 +9729,68 @@ class ThemeBootstrap4 extends Theme {
9302
9729
  }
9303
9730
  return collapse;
9304
9731
  }
9732
+ getObjectControl(config) {
9733
+ const control = super.getObjectControl(config);
9734
+ if (config.isAccordion) {
9735
+ const { childrenSlot } = control;
9736
+ const accordionId = childrenSlot.id;
9737
+ const originalAppendChild = childrenSlot.appendChild.bind(childrenSlot);
9738
+ childrenSlot.appendChild = (child) => {
9739
+ const collapse = child.querySelector(".collapse");
9740
+ if (collapse) {
9741
+ collapse.classList.remove("show");
9742
+ collapse.setAttribute("data-parent", "#" + accordionId);
9743
+ }
9744
+ return originalAppendChild(child);
9745
+ };
9746
+ }
9747
+ if (config.isAccordionProperties) {
9748
+ control.childrenSlot.classList.add("accordion", "pb-3");
9749
+ }
9750
+ return control;
9751
+ }
9752
+ getAccordionItem(config) {
9753
+ const collapseId = config.id + "-acc-collapse";
9754
+ const container = document.createElement("div");
9755
+ container.classList.add("card", "mb-0");
9756
+ const header = document.createElement("div");
9757
+ header.classList.add("card-header", "p-0");
9758
+ const toggle = document.createElement("button");
9759
+ toggle.type = "button";
9760
+ toggle.classList.add("btn", "btn-link", "w-100", "text-left");
9761
+ toggle.setAttribute("data-toggle", "collapse");
9762
+ toggle.setAttribute("data-target", "#" + collapseId);
9763
+ toggle.setAttribute("data-parent", "#" + config.accordionId);
9764
+ toggle.classList.add("collapsed");
9765
+ const chevron = document.createElement("i");
9766
+ chevron.classList.add("jedi-accordion-chevron");
9767
+ if (this.icons && this.icons["collapse"]) {
9768
+ this.addIconClass(chevron, this.icons["collapse"]);
9769
+ } else {
9770
+ chevron.textContent = "▾";
9771
+ }
9772
+ chevron.classList.add("d-inline-block", "mr-2");
9773
+ chevron.style.transition = "transform 0.1s ease";
9774
+ toggle.appendChild(chevron);
9775
+ toggle.appendChild(document.createTextNode(config.title));
9776
+ const collapse = document.createElement("div");
9777
+ collapse.id = collapseId;
9778
+ collapse.classList.add("collapse");
9779
+ collapse.setAttribute("data-parent", "#" + config.accordionId);
9780
+ const syncState = () => {
9781
+ const collapsed = toggle.classList.contains("collapsed");
9782
+ chevron.style.transform = collapsed ? "rotate(-90deg)" : "rotate(0deg)";
9783
+ };
9784
+ syncState();
9785
+ new MutationObserver(syncState).observe(toggle, { attributes: true, attributeFilter: ["class"] });
9786
+ const body = document.createElement("div");
9787
+ body.classList.add("card-body", "pb-0");
9788
+ header.appendChild(toggle);
9789
+ collapse.appendChild(body);
9790
+ container.appendChild(header);
9791
+ container.appendChild(collapse);
9792
+ return { container, header, toggle, collapse, body };
9793
+ }
9305
9794
  getJsonData(config) {
9306
9795
  const jsonData = super.getJsonData(config);
9307
9796
  jsonData.control.classList.add("form-group");
@@ -9321,21 +9810,23 @@ class ThemeBootstrap4 extends Theme {
9321
9810
  }
9322
9811
  getLegend(config) {
9323
9812
  const superLegend = super.getLegend(config);
9324
- const { legend } = superLegend;
9813
+ const { legend, infoContainer } = superLegend;
9325
9814
  legend.classList.add("card-header");
9326
9815
  legend.classList.add("d-flex");
9327
9816
  legend.classList.add("justify-content-between");
9328
9817
  legend.classList.add("align-items-center");
9329
9818
  legend.classList.add("float-left");
9330
9819
  legend.classList.add("py-2");
9820
+ infoContainer.classList.add("mr-1");
9331
9821
  return superLegend;
9332
9822
  }
9333
9823
  getLabel(config) {
9334
- const labelObj = super.getLabel(config);
9335
- if (labelObj.icon.classList) {
9336
- labelObj.icon.classList.add("mr-1");
9337
- }
9338
- return labelObj;
9824
+ return super.getLabel(config);
9825
+ }
9826
+ getInfo(config = {}) {
9827
+ const info = super.getInfo(config);
9828
+ info.container.classList.add("mr-1");
9829
+ return info;
9339
9830
  }
9340
9831
  getCard() {
9341
9832
  const card = super.getCard();
@@ -9453,7 +9944,7 @@ class ThemeBootstrap4 extends Theme {
9453
9944
  super.adaptForTableRadiosControl(control, td);
9454
9945
  control.container.classList.remove("form-group");
9455
9946
  control.fieldset.classList.remove("card");
9456
- control.fieldset.style.marginBottom = "0";
9947
+ control.fieldset.classList.add("mb-0");
9457
9948
  }
9458
9949
  getCheckboxesControl(config) {
9459
9950
  const control = super.getCheckboxesControl(config);
@@ -9514,6 +10005,25 @@ class ThemeBootstrap4 extends Theme {
9514
10005
  super.adaptForTableSelectControl(control, td);
9515
10006
  control.container.classList.remove("form-group");
9516
10007
  }
10008
+ getSwitcherSelect(config) {
10009
+ const control = super.getSwitcherSelect(config);
10010
+ control.input.classList.add("form-control-sm");
10011
+ return control;
10012
+ }
10013
+ getSwitcherModal(config) {
10014
+ const control = super.getSwitcherModal(config);
10015
+ control.trigger.classList.add("badge", "badge-primary");
10016
+ control.dialogBody.classList.add("btn-group", "btn-group-vertical", "w-100");
10017
+ control.optionButtons.forEach((btn) => {
10018
+ btn.classList.add("btn", "btn-light");
10019
+ });
10020
+ return control;
10021
+ }
10022
+ setSwitcherOptionActive(btn, active) {
10023
+ super.setSwitcherOptionActive(btn, active);
10024
+ btn.classList.toggle("btn-primary", active);
10025
+ btn.classList.toggle("btn-light", !active);
10026
+ }
9517
10027
  adaptForTableMultipleControl(control, td) {
9518
10028
  super.adaptForTableMultipleControl(control, td);
9519
10029
  control.container.classList.remove("mb-3");
@@ -9632,7 +10142,6 @@ class ThemeBootstrap4 extends Theme {
9632
10142
  closeBtn.setAttribute("always-enabled", "");
9633
10143
  info.info.setAttribute("data-toggle", "modal");
9634
10144
  info.info.setAttribute("data-target", "#" + modalId);
9635
- info.container.classList.add("ml-1");
9636
10145
  modal.classList.add("modal");
9637
10146
  modal.classList.add("fade");
9638
10147
  modalDialog.classList.add("modal-dialog");
@@ -9688,6 +10197,74 @@ class ThemeBootstrap5 extends Theme {
9688
10197
  }
9689
10198
  return collapse;
9690
10199
  }
10200
+ getObjectControl(config) {
10201
+ const control = super.getObjectControl(config);
10202
+ if (config.isAccordion) {
10203
+ const { childrenSlot } = control;
10204
+ const accordionId = childrenSlot.id;
10205
+ const originalAppendChild = childrenSlot.appendChild.bind(childrenSlot);
10206
+ childrenSlot.appendChild = (child) => {
10207
+ const collapse = child.querySelector(".collapse");
10208
+ if (collapse) {
10209
+ collapse.classList.remove("show");
10210
+ collapse.setAttribute("data-bs-parent", "#" + accordionId);
10211
+ }
10212
+ return originalAppendChild(child);
10213
+ };
10214
+ }
10215
+ if (config.isAccordionProperties) {
10216
+ control.childrenSlot.classList.add("accordion", "pb-3");
10217
+ }
10218
+ return control;
10219
+ }
10220
+ getAccordionItem(config) {
10221
+ const collapseId = config.id + "-acc-collapse";
10222
+ const container = document.createElement("div");
10223
+ container.classList.add("accordion-item");
10224
+ const header = document.createElement("h2");
10225
+ header.classList.add("accordion-header");
10226
+ const toggle = document.createElement("button");
10227
+ toggle.type = "button";
10228
+ toggle.classList.add("accordion-button", "collapsed");
10229
+ toggle.setAttribute("data-bs-toggle", "collapse");
10230
+ toggle.setAttribute("data-bs-target", "#" + collapseId);
10231
+ toggle.setAttribute("data-bs-parent", "#" + config.accordionId);
10232
+ toggle.classList.add("jedi-accordion-button");
10233
+ if (!document.getElementById("jedi-accordion-button-style")) {
10234
+ const style = document.createElement("style");
10235
+ style.id = "jedi-accordion-button-style";
10236
+ style.textContent = ".jedi-accordion-button::after { display: none !important; }";
10237
+ document.head.appendChild(style);
10238
+ }
10239
+ const chevron = document.createElement("i");
10240
+ chevron.classList.add("jedi-accordion-chevron");
10241
+ if (this.icons && this.icons["collapse"]) {
10242
+ this.addIconClass(chevron, this.icons["collapse"]);
10243
+ } else {
10244
+ chevron.textContent = "▾";
10245
+ }
10246
+ chevron.classList.add("d-inline-block", "me-2");
10247
+ chevron.style.transition = "transform 0.1s ease";
10248
+ toggle.appendChild(chevron);
10249
+ toggle.appendChild(document.createTextNode(config.title));
10250
+ const collapse = document.createElement("div");
10251
+ collapse.id = collapseId;
10252
+ collapse.classList.add("accordion-collapse", "collapse");
10253
+ collapse.setAttribute("data-bs-parent", "#" + config.accordionId);
10254
+ const syncState = () => {
10255
+ const collapsed = toggle.classList.contains("collapsed");
10256
+ chevron.style.transform = collapsed ? "rotate(-90deg)" : "rotate(0deg)";
10257
+ };
10258
+ syncState();
10259
+ new MutationObserver(syncState).observe(toggle, { attributes: true, attributeFilter: ["class"] });
10260
+ const body = document.createElement("div");
10261
+ body.classList.add("accordion-body", "pb-3");
10262
+ header.appendChild(toggle);
10263
+ collapse.appendChild(body);
10264
+ container.appendChild(header);
10265
+ container.appendChild(collapse);
10266
+ return { container, header, toggle, collapse, body };
10267
+ }
9691
10268
  getJsonData(config) {
9692
10269
  const jsonData = super.getJsonData(config);
9693
10270
  jsonData.control.classList.add("mb-3");
@@ -9707,24 +10284,28 @@ class ThemeBootstrap5 extends Theme {
9707
10284
  }
9708
10285
  getLegend(config) {
9709
10286
  const superLegend = super.getLegend(config);
9710
- const { legend } = superLegend;
10287
+ const { legend, infoContainer } = superLegend;
9711
10288
  legend.classList.add("card-header");
9712
10289
  legend.classList.add("d-flex");
9713
10290
  legend.classList.add("justify-content-between");
9714
10291
  legend.classList.add("align-items-center");
9715
10292
  legend.classList.add("py-2");
10293
+ infoContainer.classList.add("me-1");
9716
10294
  return superLegend;
9717
10295
  }
9718
10296
  styleLegendWarning(span) {
9719
- span.classList.add("ms-1");
10297
+ span.classList.add("me-1");
9720
10298
  }
9721
10299
  getLabel(config) {
9722
10300
  const labelObj = super.getLabel(config);
9723
- if (labelObj.icon.classList) {
9724
- labelObj.icon.classList.add("me-1");
9725
- }
10301
+ labelObj.label.classList.add("mb-1");
9726
10302
  return labelObj;
9727
10303
  }
10304
+ getInfo(config = {}) {
10305
+ const info = super.getInfo(config);
10306
+ info.container.classList.add("me-1");
10307
+ return info;
10308
+ }
9728
10309
  getCard() {
9729
10310
  const card = super.getCard();
9730
10311
  card.classList.add("card");
@@ -9844,7 +10425,7 @@ class ThemeBootstrap5 extends Theme {
9844
10425
  super.adaptForTableRadiosControl(control, td);
9845
10426
  control.container.classList.remove("mb-3");
9846
10427
  control.fieldset.classList.remove("card");
9847
- control.fieldset.style.marginBottom = "0";
10428
+ control.fieldset.classList.add("mb-0");
9848
10429
  }
9849
10430
  getCheckboxesControl(config) {
9850
10431
  const control = super.getCheckboxesControl(config);
@@ -9898,6 +10479,25 @@ class ThemeBootstrap5 extends Theme {
9898
10479
  super.adaptForTableSelectControl(control, td);
9899
10480
  control.container.classList.remove("mb-3");
9900
10481
  }
10482
+ getSwitcherSelect(config) {
10483
+ const control = super.getSwitcherSelect(config);
10484
+ control.input.classList.add("form-select-sm");
10485
+ return control;
10486
+ }
10487
+ getSwitcherModal(config) {
10488
+ const control = super.getSwitcherModal(config);
10489
+ control.trigger.classList.add("badge", "bg-primary");
10490
+ control.dialogBody.classList.add("btn-group", "btn-group-vertical", "w-100");
10491
+ control.optionButtons.forEach((btn) => {
10492
+ btn.classList.add("btn", "btn-light");
10493
+ });
10494
+ return control;
10495
+ }
10496
+ setSwitcherOptionActive(btn, active) {
10497
+ super.setSwitcherOptionActive(btn, active);
10498
+ btn.classList.toggle("btn-primary", active);
10499
+ btn.classList.toggle("btn-light", !active);
10500
+ }
9901
10501
  adaptForTableMultipleControl(control, td) {
9902
10502
  super.adaptForTableMultipleControl(control, td);
9903
10503
  control.container.classList.remove("mb-3");
@@ -10013,7 +10613,6 @@ class ThemeBootstrap5 extends Theme {
10013
10613
  closeBtn.setAttribute("always-enabled", "");
10014
10614
  info.info.setAttribute("data-bs-toggle", "modal");
10015
10615
  info.info.setAttribute("data-bs-target", "#" + modalId);
10016
- info.container.classList.add("ms-1");
10017
10616
  modal.classList.add("modal");
10018
10617
  modal.classList.add("fade");
10019
10618
  modalDialog.classList.add("modal-dialog");
@@ -10066,6 +10665,7 @@ const index = {
10066
10665
  EditorObjectGrid,
10067
10666
  EditorObjectCategories,
10068
10667
  EditorObjectNav,
10668
+ EditorObjectAccordion,
10069
10669
  EditorObject,
10070
10670
  EditorArrayChoices,
10071
10671
  EditorArrayNav,