formeo 3.1.0 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/formeo.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.0.8
4
+ Version: 3.1.1
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -434,7 +434,7 @@ if (window !== void 0) {
434
434
  window.SmartTooltip = SmartTooltip;
435
435
  }
436
436
  const name$1 = "formeo";
437
- const version$2 = "3.0.8";
437
+ const version$2 = "3.1.1";
438
438
  const type = "module";
439
439
  const main = "dist/formeo.cjs.js";
440
440
  const module = "dist/formeo.es.js";
@@ -3050,7 +3050,7 @@ function lastChild(el, selector) {
3050
3050
  }
3051
3051
  return last || null;
3052
3052
  }
3053
- function index(el, selector) {
3053
+ function index$6(el, selector) {
3054
3054
  var index2 = 0;
3055
3055
  if (!el || !el.parentNode) {
3056
3056
  return -1;
@@ -3661,8 +3661,8 @@ Sortable.prototype = /** @lends Sortable.prototype */
3661
3661
  if (lastDownEl === target) {
3662
3662
  return;
3663
3663
  }
3664
- oldIndex = index(target);
3665
- oldDraggableIndex = index(target, options.draggable);
3664
+ oldIndex = index$6(target);
3665
+ oldDraggableIndex = index$6(target, options.draggable);
3666
3666
  if (typeof filter === "function") {
3667
3667
  if (filter.call(this, evt, target, this)) {
3668
3668
  _dispatchEvent({
@@ -4082,8 +4082,8 @@ Sortable.prototype = /** @lends Sortable.prototype */
4082
4082
  return completedFired = true;
4083
4083
  }
4084
4084
  function changed() {
4085
- newIndex = index(dragEl);
4086
- newDraggableIndex = index(dragEl, options.draggable);
4085
+ newIndex = index$6(dragEl);
4086
+ newDraggableIndex = index$6(dragEl, options.draggable);
4087
4087
  _dispatchEvent({
4088
4088
  sortable: _this,
4089
4089
  name: "change",
@@ -4169,7 +4169,7 @@ Sortable.prototype = /** @lends Sortable.prototype */
4169
4169
  direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
4170
4170
  var sibling;
4171
4171
  if (direction !== 0) {
4172
- var dragIndex = index(dragEl);
4172
+ var dragIndex = index$6(dragEl);
4173
4173
  do {
4174
4174
  dragIndex -= direction;
4175
4175
  sibling = parentEl.children[dragIndex];
@@ -4231,14 +4231,14 @@ Sortable.prototype = /** @lends Sortable.prototype */
4231
4231
  },
4232
4232
  _onDrop: function _onDrop(evt) {
4233
4233
  var el = this.el, options = this.options;
4234
- newIndex = index(dragEl);
4235
- newDraggableIndex = index(dragEl, options.draggable);
4234
+ newIndex = index$6(dragEl);
4235
+ newDraggableIndex = index$6(dragEl, options.draggable);
4236
4236
  pluginEvent2("drop", this, {
4237
4237
  evt
4238
4238
  });
4239
4239
  parentEl = dragEl && dragEl.parentNode;
4240
- newIndex = index(dragEl);
4241
- newDraggableIndex = index(dragEl, options.draggable);
4240
+ newIndex = index$6(dragEl);
4241
+ newDraggableIndex = index$6(dragEl, options.draggable);
4242
4242
  if (Sortable.eventCanceled) {
4243
4243
  this._nulling();
4244
4244
  return;
@@ -4585,7 +4585,7 @@ function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, inv
4585
4585
  return 0;
4586
4586
  }
4587
4587
  function _getInsertDirection(target) {
4588
- if (index(dragEl) < index(target)) {
4588
+ if (index$6(dragEl) < index$6(target)) {
4589
4589
  return 1;
4590
4590
  } else {
4591
4591
  return -1;
@@ -4633,7 +4633,7 @@ Sortable.utils = {
4633
4633
  closest,
4634
4634
  toggleClass,
4635
4635
  clone,
4636
- index,
4636
+ index: index$6,
4637
4637
  nextTick: _nextTick,
4638
4638
  cancelNextTick: _cancelNextTick,
4639
4639
  detectDirection: _detectDirection,
@@ -6777,6 +6777,9 @@ class Field extends Component {
6777
6777
  */
6778
6778
  constructor(fieldData = /* @__PURE__ */ Object.create(null)) {
6779
6779
  super("field", { ...DEFAULT_DATA$3(), ...fieldData });
6780
+ __publicField(this, "setData", (path, value) => {
6781
+ return super.set(path, value);
6782
+ });
6780
6783
  /**
6781
6784
  * Updates the conditions panel when linked field data changes
6782
6785
  */
@@ -6962,9 +6965,8 @@ class Field extends Component {
6962
6965
  /**
6963
6966
  * wrapper for Data.set
6964
6967
  */
6965
- set(...args) {
6966
- const [path, value] = args;
6967
- const data = super.set(path, value);
6968
+ set(path, value) {
6969
+ const data = this.setData(path, value);
6968
6970
  this.updatePreview();
6969
6971
  return data;
6970
6972
  }
@@ -7033,16 +7035,17 @@ class Field extends Component {
7033
7035
  return this.debouncedUpdateEditPanels();
7034
7036
  }
7035
7037
  if (evt.target.contentEditable) {
7036
- const parentClassList = evt.target.parentElement.classList;
7038
+ const target = evt.target;
7039
+ const parentClassList = target.parentElement.classList;
7037
7040
  const isOption = parentClassList.contains("f-checkbox") || parentClassList.contains("f-radio");
7038
7041
  if (isOption) {
7039
- const option2 = evt.target.parentElement;
7042
+ const option2 = target.parentElement;
7040
7043
  const optionWrap = option2.parentElement;
7041
7044
  const optionIndex = indexOfNode(option2, optionWrap);
7042
- super.set(`options[${optionIndex}].label`, evt.target.innerHTML);
7045
+ this.setData(`options[${optionIndex}].label`, target.innerHTML);
7043
7046
  return this.debouncedUpdateEditPanels();
7044
7047
  }
7045
- super.set("content", evt.target.innerHTML);
7048
+ this.setData("content", target.innerHTML || target.value);
7046
7049
  }
7047
7050
  }
7048
7051
  };
@@ -7056,7 +7059,10 @@ class Field extends Component {
7056
7059
  const prevData = clone$1(this.data);
7057
7060
  const { action = {} } = Controls$2.get(prevData.config.controlId);
7058
7061
  prevData.id = `prev-${this.id}`;
7059
- prevData.action = action;
7062
+ prevData.action = Object.entries(action).reduce((acc, [key, value]) => {
7063
+ acc[key] = value.bind(this);
7064
+ return acc;
7065
+ }, {});
7060
7066
  if ((_a = this.data) == null ? void 0 : _a.config.editableContent) {
7061
7067
  prevData.attrs = { ...prevData.attrs, contenteditable: true };
7062
7068
  }
@@ -7268,1008 +7274,578 @@ class Control {
7268
7274
  return (((_b = localeTranslations[lookup]) == null ? void 0 : _b.call(localeTranslations)) ?? localeTranslations[lookup]) || mi18n.get(lookup, args);
7269
7275
  }
7270
7276
  }
7271
- const rowControl = {
7272
- config: {
7273
- label: "row"
7274
- },
7275
- meta: {
7276
- group: "layout",
7277
- icon: "rows",
7278
- id: "layout-row"
7279
- }
7280
- };
7281
- const columnControl = {
7282
- config: {
7283
- label: "column"
7277
+ const defaultOptions = Object.freeze({
7278
+ sortable: true,
7279
+ elementOrder: {},
7280
+ groupOrder: [],
7281
+ groups: [
7282
+ {
7283
+ id: "layout",
7284
+ label: "controls.groups.layout",
7285
+ elementOrder: ["row", "column"]
7286
+ },
7287
+ {
7288
+ id: "common",
7289
+ label: "controls.groups.form",
7290
+ elementOrder: ["button", "checkbox"]
7291
+ },
7292
+ {
7293
+ id: "html",
7294
+ label: "controls.groups.html",
7295
+ elementOrder: ["header", "block-text"]
7296
+ }
7297
+ ],
7298
+ disable: {
7299
+ groups: [],
7300
+ elements: [],
7301
+ formActions: []
7284
7302
  },
7285
- meta: {
7286
- group: "layout",
7287
- icon: "columns",
7288
- id: "layout-column"
7289
- }
7290
- };
7291
- const layoutControls = [rowControl, columnControl];
7292
- class HiddenControl extends Control {
7303
+ elements: [],
7304
+ container: null,
7305
+ panels: { displayType: "slider" }
7306
+ });
7307
+ let Controls$1 = class Controls {
7293
7308
  constructor() {
7294
- const hiddenInput = {
7295
- tag: "input",
7296
- attrs: {
7297
- type: "hidden",
7298
- value: ""
7299
- },
7300
- config: {
7301
- label: mi18n.get("hidden"),
7302
- hideLabel: true
7303
- },
7304
- meta: {
7305
- group: "common",
7306
- icon: "hidden",
7307
- id: "hidden"
7309
+ __publicField(this, "groupLabel", (key) => mi18n.get(key) || key || "");
7310
+ __publicField(this, "layoutTypes", {
7311
+ row: () => Stages2.active.addChild(),
7312
+ column: () => this.layoutTypes.row().addChild(),
7313
+ field: (controlData) => this.layoutTypes.column().addChild(controlData)
7314
+ });
7315
+ /**
7316
+ * Append an element to the stage
7317
+ * @param {String} id of elements
7318
+ */
7319
+ __publicField(this, "addElement", (id) => {
7320
+ const {
7321
+ meta: { group, id: metaId },
7322
+ ...elementData
7323
+ } = get(this.get(id), "controlData");
7324
+ set(elementData, "config.controlId", metaId);
7325
+ if (group === "layout") {
7326
+ return this.layoutTypes[metaId.replace("layout-", "")]();
7308
7327
  }
7309
- };
7310
- super(hiddenInput);
7311
- }
7312
- }
7313
- class NumberControl extends Control {
7314
- constructor() {
7315
- const numberInput = {
7316
- tag: "input",
7317
- attrs: {
7318
- type: "number",
7319
- required: false,
7320
- className: ""
7321
- },
7322
- config: {
7323
- label: mi18n.get("number")
7328
+ return this.layoutTypes.field(elementData);
7329
+ });
7330
+ __publicField(this, "applyOptions", async (controlOptions = {}) => {
7331
+ const { container, elements, groupOrder, ...options } = merge(defaultOptions, controlOptions);
7332
+ this.container = container;
7333
+ this.groupOrder = unique(groupOrder.concat(["common", "html", "layout"]));
7334
+ this.options = options;
7335
+ const [layoutControls, formControls, htmlControls] = await Promise.all([
7336
+ Promise.resolve().then(() => index$5),
7337
+ Promise.resolve().then(() => index$3),
7338
+ Promise.resolve().then(() => index$1)
7339
+ ]);
7340
+ const allControls = [layoutControls.default, formControls.default, htmlControls.default].flat();
7341
+ return Promise.all(this.registerControls([...allControls, ...elements]));
7342
+ });
7343
+ this.data = /* @__PURE__ */ new Map();
7344
+ this.buttonActions = {
7345
+ // this is used for keyboard navigation. when tabbing through controls it
7346
+ // will auto navigated between the groups
7347
+ focus: ({ target }) => {
7348
+ const group = target.closest(`.${CONTROL_GROUP_CLASSNAME}`);
7349
+ return group && this.panels.nav.refresh(indexOfNode(group));
7324
7350
  },
7325
- meta: {
7326
- group: "common",
7327
- icon: "hash",
7328
- id: "number"
7351
+ click: ({ target }) => {
7352
+ this.addElement(target.parentElement.id);
7329
7353
  }
7330
7354
  };
7331
- super(numberInput);
7332
7355
  }
7333
- }
7334
- class TextAreaControl extends Control {
7335
- constructor() {
7336
- const textAreaConfig = {
7337
- tag: "textarea",
7338
- config: {
7339
- label: mi18n.get("controls.form.textarea")
7340
- },
7341
- // This is the beginning of actions being supported for render
7342
- // editor field actions should be in config.action
7343
- // action: {
7344
- // mousedown: function(evt) {
7345
- // let {target} = evt;
7346
- // let startHeight = target.style.height;
7347
- // const onMouseup = evt => {
7348
- // let {target} = evt;
7349
- // let endHeight = target.style.height;
7350
- // if (startHeight !== endHeight) {
7351
- // //eslint-disable-next-line
7352
- // let fieldId = closest(target, '.stage-field').id;
7353
- // const field = d.fields.get(fieldId).instance;
7354
- // field.addAttribute('style', `height: ${endHeight}`);
7355
- // }
7356
- // target.removeEventListener('mouseup', onMouseup);
7357
- // };
7358
- // target.addEventListener('mouseup', onMouseup);
7359
- // }
7360
- // },
7361
- meta: {
7362
- group: "common",
7363
- icon: "textarea",
7364
- id: "textarea"
7365
- },
7366
- attrs: {
7367
- required: false
7368
- }
7369
- };
7370
- super(textAreaConfig);
7356
+ /**
7357
+ * Methods to be called on initialization
7358
+ * @param {Object} controlOptions
7359
+ */
7360
+ async init(controlOptions, sticky = false) {
7361
+ await this.applyOptions(controlOptions);
7362
+ this.buildDOM(sticky);
7363
+ return this;
7371
7364
  }
7372
- }
7373
- class TextControl extends Control {
7374
- constructor() {
7375
- const textInput = {
7376
- tag: "input",
7377
- attrs: {
7378
- required: false,
7379
- type: "text",
7380
- className: ""
7381
- },
7382
- config: {
7383
- label: mi18n.get("controls.form.input.text")
7384
- },
7385
- meta: {
7386
- group: "common",
7387
- icon: "text-input",
7388
- id: "text-input"
7365
+ /**
7366
+ * Generate control config for UI and bind actions
7367
+ * @return {Array} elementControls
7368
+ */
7369
+ registerControls(elements) {
7370
+ this.controls = [];
7371
+ return elements.map(async (Element) => {
7372
+ const isControl = typeof Element === "function";
7373
+ let control;
7374
+ if (isControl) {
7375
+ control = new Element();
7376
+ } else {
7377
+ control = new Control(Element);
7389
7378
  }
7390
- };
7391
- super(textInput);
7379
+ this.add(control);
7380
+ this.controls.push(control.dom);
7381
+ return control.promise();
7382
+ });
7392
7383
  }
7393
- }
7394
- class FileControl extends Control {
7395
- constructor() {
7396
- const fileInput = {
7397
- tag: "input",
7398
- attrs: {
7399
- type: "file",
7400
- required: false
7401
- },
7402
- config: {
7403
- label: mi18n.get("fileUpload")
7404
- },
7405
- meta: {
7406
- group: "common",
7407
- icon: "upload",
7408
- id: "upload"
7384
+ /**
7385
+ * Group elements into their respective control group
7386
+ * @return {Array} allGroups
7387
+ */
7388
+ groupElements() {
7389
+ let groups = this.options.groups.slice();
7390
+ let elements = this.controls.slice();
7391
+ let allGroups = [];
7392
+ const usedElementIds = [];
7393
+ groups = orderObjectsBy(groups, this.groupOrder, "id");
7394
+ groups = groups.filter((group) => match(group.id, this.options.disable.groups));
7395
+ allGroups = groups.map((group) => {
7396
+ const groupConfig = {
7397
+ tag: "ul",
7398
+ attrs: {
7399
+ className: CONTROL_GROUP_CLASSNAME,
7400
+ id: `${group.id}-${CONTROL_GROUP_CLASSNAME}`
7401
+ },
7402
+ config: {
7403
+ label: this.groupLabel(group.label)
7404
+ }
7405
+ };
7406
+ if (this.options.elementOrder[group.id]) {
7407
+ const userOrder = this.options.elementOrder[group.id];
7408
+ const newOrder = unique(userOrder.concat(group.elementOrder));
7409
+ group.elementOrder = newOrder;
7409
7410
  }
7410
- };
7411
- super(fileInput);
7411
+ elements = orderObjectsBy(elements, group.elementOrder, "meta.id");
7412
+ groupConfig.content = elements.filter((control) => {
7413
+ const { controlData: field } = this.get(control.id);
7414
+ const controlId = field.meta.id || "";
7415
+ const filters = [
7416
+ match(controlId, this.options.disable.elements),
7417
+ field.meta.group === group.id,
7418
+ !usedElementIds.includes(controlId)
7419
+ ];
7420
+ let shouldFilter = true;
7421
+ shouldFilter = filters.every((val) => val === true);
7422
+ if (shouldFilter) {
7423
+ usedElementIds.push(controlId);
7424
+ }
7425
+ return shouldFilter;
7426
+ });
7427
+ return groupConfig;
7428
+ });
7429
+ return allGroups;
7412
7430
  }
7413
- }
7414
- const generateOptionConfig = (type2, count = 3) => Array.from({ length: count }, (v, k) => k + 1).map((i) => {
7415
- const selectedKey = type2 === "checkbox" ? "checked" : "selected";
7416
- return {
7417
- label: mi18n.get("labelCount", {
7418
- label: toTitleCase(type2),
7419
- count: i
7420
- }),
7421
- value: `${type2}-${i}`,
7422
- [selectedKey]: !i
7423
- };
7424
- });
7425
- class SelectControl extends Control {
7426
- constructor() {
7427
- const selectConfig = {
7428
- tag: "select",
7429
- config: {
7430
- label: mi18n.get("controls.form.select")
7431
- },
7432
- attrs: {
7433
- required: false,
7434
- className: ""
7435
- },
7436
- meta: {
7437
- group: "common",
7438
- icon: "select",
7439
- id: "select"
7440
- },
7441
- options: generateOptionConfig("option")
7442
- };
7443
- super(selectConfig);
7444
- }
7445
- }
7446
- class CheckboxGroupControl extends Control {
7447
- constructor() {
7448
- const checkboxGroup = {
7449
- tag: "input",
7450
- attrs: {
7451
- type: "checkbox",
7452
- required: false
7453
- },
7454
- config: {
7455
- label: mi18n.get("controls.form.checkbox-group"),
7456
- disabledAttrs: ["type"]
7457
- },
7458
- meta: {
7459
- group: "common",
7460
- icon: "checkbox",
7461
- id: "checkbox"
7462
- },
7463
- options: generateOptionConfig("checkbox", 1)
7464
- };
7465
- super(checkboxGroup);
7431
+ add(control = /* @__PURE__ */ Object.create(null)) {
7432
+ const controlConfig = clone$1(control);
7433
+ this.data.set(controlConfig.id, controlConfig);
7434
+ if (controlConfig.controlData.meta.id) {
7435
+ this.data.set(controlConfig.controlData.meta.id, controlConfig.controlData);
7436
+ }
7437
+ return controlConfig;
7466
7438
  }
7467
- }
7468
- class RadioGroupControl extends Control {
7469
- constructor() {
7470
- const radioGroup = {
7471
- tag: "input",
7472
- attrs: {
7473
- type: "radio",
7474
- required: false
7475
- },
7476
- config: {
7477
- label: mi18n.get("controls.form.radio-group"),
7478
- disabledAttrs: ["type"]
7479
- },
7480
- meta: {
7481
- group: "common",
7482
- icon: "radio-group",
7483
- id: "radio"
7484
- },
7485
- options: generateOptionConfig("radio")
7486
- };
7487
- super(radioGroup);
7439
+ get(controlId) {
7440
+ return clone$1(this.data.get(controlId));
7488
7441
  }
7489
- }
7490
- class ButtonControl extends Control {
7491
- constructor() {
7492
- const buttonConfig = {
7493
- tag: "button",
7494
- attrs: {
7495
- className: [{ label: "grouped", value: "f-btn-group" }, { label: "ungrouped", value: "f-field-group" }]
7496
- },
7497
- config: {
7498
- label: mi18n.get("controls.form.button"),
7499
- hideLabel: true
7500
- },
7501
- meta: {
7502
- group: "common",
7503
- icon: "button",
7504
- id: "button"
7505
- },
7506
- options: [
7507
- {
7508
- label: mi18n.get("button"),
7509
- type: ["button", "submit", "reset"].map((buttonType) => ({
7510
- label: buttonType,
7511
- type: buttonType
7512
- })),
7513
- className: [
7514
- {
7515
- label: "default",
7516
- value: "",
7517
- selected: true
7518
- },
7519
- {
7520
- label: "primary",
7521
- value: "primary"
7522
- },
7523
- {
7524
- label: "danger",
7525
- value: "error"
7526
- },
7527
- {
7528
- label: "success",
7529
- value: "success"
7530
- },
7531
- {
7532
- label: "warning",
7533
- value: "warning"
7534
- }
7535
- ]
7442
+ /**
7443
+ * Generate the DOM config for form actions like settings, save and clear
7444
+ * @return {Object} form action buttons config
7445
+ */
7446
+ formActions() {
7447
+ if (this.options.disable.formActions === true) {
7448
+ return null;
7449
+ }
7450
+ const clearBtn = {
7451
+ ...dom.btnTemplate({ content: [dom.icon("bin"), mi18n.get("clear")], title: mi18n.get("clearAll") }),
7452
+ className: ["clear-form"],
7453
+ action: {
7454
+ click: (evt) => {
7455
+ if (Rows2.size) {
7456
+ events.confirmClearAll = new window.CustomEvent("confirmClearAll", {
7457
+ detail: {
7458
+ confirmationMessage: mi18n.get("confirmClearAll"),
7459
+ clearAllAction: () => {
7460
+ Stages2.clearAll().then(() => {
7461
+ const evtData = {
7462
+ src: evt.target
7463
+ };
7464
+ events.formeoCleared(evtData);
7465
+ });
7466
+ },
7467
+ btnCoords: dom.coords(evt.target)
7468
+ }
7469
+ });
7470
+ document.dispatchEvent(events.confirmClearAll);
7471
+ } else {
7472
+ window.alert(mi18n.get("cannotClearFields"));
7473
+ }
7536
7474
  }
7537
- ]
7538
- };
7539
- super(buttonConfig);
7540
- }
7541
- }
7542
- class DateControl extends Control {
7543
- constructor() {
7544
- const dateInput = {
7545
- tag: "input",
7546
- attrs: {
7547
- type: "date",
7548
- required: false,
7549
- className: ""
7550
- },
7551
- config: {
7552
- label: mi18n.get("controls.form.input.date")
7553
- },
7554
- meta: {
7555
- group: "common",
7556
- icon: "calendar",
7557
- id: "date-input"
7558
7475
  }
7559
7476
  };
7560
- super(dateInput);
7561
- }
7562
- }
7563
- const formControls = [
7564
- ButtonControl,
7565
- DateControl,
7566
- HiddenControl,
7567
- NumberControl,
7568
- TextAreaControl,
7569
- TextControl,
7570
- FileControl,
7571
- SelectControl,
7572
- CheckboxGroupControl,
7573
- RadioGroupControl
7574
- ];
7575
- const headerTags = Array.from(Array(5).keys()).slice(1).map((key) => `h${key}`);
7576
- const headerKey = "controls.html.header";
7577
- class HeaderControl extends Control {
7578
- constructor() {
7579
- const header = {
7580
- tag: headerTags[0],
7581
- attrs: {
7582
- tag: headerTags.map((tag, index2) => ({
7583
- label: tag.toUpperCase(),
7584
- value: tag,
7585
- selected: !index2
7586
- })),
7587
- className: ""
7588
- },
7589
- config: {
7590
- label: mi18n.get(headerKey),
7591
- hideLabel: true,
7592
- editableContent: true
7593
- },
7594
- meta: {
7595
- group: "html",
7596
- icon: "header",
7597
- id: "html.header"
7598
- },
7599
- content: mi18n.get(headerKey),
7477
+ const saveBtn = {
7478
+ ...dom.btnTemplate({ content: [dom.icon("floppy-disk"), mi18n.get("save")], title: mi18n.get("save") }),
7479
+ className: ["save-form"],
7600
7480
  action: {
7601
- // onRender: evt => {},
7602
- // click: evt => {},
7481
+ click: ({ target }) => {
7482
+ const { formData } = components;
7483
+ const saveEvt = {
7484
+ action: () => {
7485
+ },
7486
+ coords: dom.coords(target),
7487
+ message: "",
7488
+ button: target
7489
+ };
7490
+ actions.click.btn(saveEvt);
7491
+ return actions.save.form(formData);
7492
+ }
7603
7493
  }
7604
7494
  };
7605
- super(header);
7606
- }
7607
- /**
7608
- * class configuration
7609
- */
7610
- static get definition() {
7611
- return {
7612
- // i18n custom mappings (defaults to camelCase type)
7613
- i18n: {
7614
- "en-US": {
7615
- header: "Custom English Header"
7495
+ const formActions = {
7496
+ className: "form-actions f-btn-group",
7497
+ content: Object.entries({ clearBtn, saveBtn }).reduce((acc, [key, value]) => {
7498
+ if (!this.options.disable.formActions.includes(key)) {
7499
+ acc.push(value);
7616
7500
  }
7617
- }
7501
+ return acc;
7502
+ }, [])
7618
7503
  };
7504
+ return formActions;
7619
7505
  }
7620
- get content() {
7621
- return super.i18n(headerKey);
7622
- }
7623
- }
7624
- class ParagraphControl extends Control {
7625
- constructor() {
7626
- const paragraphConfig = {
7627
- tag: "p",
7628
- attrs: {
7629
- className: ""
7630
- },
7631
- config: {
7632
- label: mi18n.get("controls.html.paragraph"),
7633
- hideLabel: true,
7634
- editableContent: true
7635
- },
7636
- meta: {
7637
- group: "html",
7638
- icon: "paragraph",
7639
- id: "paragraph"
7506
+ /**
7507
+ * Returns the markup for the form controls/fields
7508
+ * @return {DOM}
7509
+ */
7510
+ buildDOM(sticky) {
7511
+ const groupedFields = this.groupElements();
7512
+ const formActions = this.formActions();
7513
+ const { displayType } = this.options.panels;
7514
+ this.panels = new Panels({ panels: groupedFields, type: "controls", displayType });
7515
+ const groupsWrapClasses = ["control-groups", "formeo-panels-wrap", `panel-count-${groupedFields.length}`];
7516
+ const groupsWrap = dom.create({
7517
+ className: groupsWrapClasses,
7518
+ content: [this.panels.panelNav, this.panels.panelsWrap]
7519
+ });
7520
+ const controlClasses = ["formeo-controls"];
7521
+ if (sticky) {
7522
+ controlClasses.push("formeo-sticky");
7523
+ }
7524
+ const element = dom.create({
7525
+ className: controlClasses,
7526
+ content: [groupsWrap, formActions]
7527
+ });
7528
+ const groups = element.getElementsByClassName("control-group");
7529
+ this.dom = element;
7530
+ this.groups = groups;
7531
+ const [firstGroup] = groups;
7532
+ this.currentGroup = firstGroup;
7533
+ this.actions = {
7534
+ filter: (term) => {
7535
+ const filtering = term !== "";
7536
+ const fields2 = this.controls;
7537
+ let filteredTerm = groupsWrap.querySelector(".filtered-term");
7538
+ dom.toggleElementsByStr(fields2, term);
7539
+ if (filtering) {
7540
+ const filteredStr = mi18n.get("controls.filteringTerm", term);
7541
+ element.classList.add("filtered");
7542
+ if (filteredTerm) {
7543
+ filteredTerm.textContent = filteredStr;
7544
+ } else {
7545
+ filteredTerm = dom.create({
7546
+ tag: "h5",
7547
+ className: "filtered-term",
7548
+ content: filteredStr
7549
+ });
7550
+ groupsWrap.insertBefore(filteredTerm, groupsWrap.firstChild);
7551
+ }
7552
+ } else if (filteredTerm) {
7553
+ element.classList.remove("filtered");
7554
+ filteredTerm.remove();
7555
+ }
7640
7556
  },
7641
- // eslint-disable-next-line
7642
- content: "Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment."
7557
+ addElement: this.addElement,
7558
+ // @todo finish the addGroup method
7559
+ addGroup: (group) => console.log(group)
7643
7560
  };
7644
- super(paragraphConfig);
7645
- }
7646
- }
7647
- class HRControl extends Control {
7648
- constructor() {
7649
- const hrConfig = {
7650
- tag: "hr",
7651
- config: {
7652
- label: mi18n.get("controls.html.divider"),
7653
- hideLabel: true
7654
- },
7655
- meta: {
7656
- group: "html",
7657
- icon: "divider",
7658
- id: "divider"
7561
+ for (let i = groups.length - 1; i >= 0; i--) {
7562
+ const storeID = `formeo-controls-${groups[i]}`;
7563
+ if (!this.options.sortable) {
7564
+ window.localStorage.removeItem(storeID);
7659
7565
  }
7660
- };
7661
- super(hrConfig);
7662
- }
7663
- }
7664
- class TinyMCEControl extends Control {
7665
- constructor(options) {
7666
- const textAreaConfig = {
7667
- tag: "textarea",
7668
- config: {
7669
- label: "WYSIWYG",
7670
- editableContent: true
7671
- },
7672
- meta: {
7673
- group: "html",
7674
- icon: "rich-text",
7675
- id: "tinymce"
7676
- },
7677
- attrs: {
7678
- required: false
7679
- },
7680
- dependencies: { js: "https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.9.11/tinymce.min.js" },
7681
- // this action is passed to the rendered control/element
7682
- // useful for actions and events on the control preview
7683
- action: {
7684
- onRender: (elem) => {
7685
- const selector = `#${elem.id}`;
7686
- window.tinymce.remove(selector);
7687
- window.tinymce.init({
7688
- selector
7689
- });
7690
- }
7691
- },
7692
- controlAction: {
7693
- // callback when control is clicked
7694
- click: () => {
7566
+ Sortable.create(groups[i], {
7567
+ animation: 150,
7568
+ forceFallback: true,
7569
+ fallbackClass: "control-moving",
7570
+ fallbackOnBody: true,
7571
+ group: {
7572
+ name: "controls",
7573
+ pull: "clone",
7574
+ put: false
7695
7575
  },
7696
- // callback for when control is rendered
7697
- onRender: () => {
7576
+ onStart: ({ item }) => {
7577
+ const { controlData } = this.get(item.id);
7578
+ if (this.options.ghostPreview) {
7579
+ item.innerHTML = "";
7580
+ item.appendChild(new Field(controlData).preview);
7581
+ }
7582
+ },
7583
+ onEnd: ({ from, item, clone: clone2 }) => {
7584
+ if (from.contains(clone2)) {
7585
+ from.replaceChild(item, clone2);
7586
+ }
7587
+ },
7588
+ sort: this.options.sortable,
7589
+ store: {
7590
+ /**
7591
+ * Get the order of elements.
7592
+ * @param {Sortable} sortable
7593
+ * @return {Array}
7594
+ */
7595
+ get: () => {
7596
+ const order = window.localStorage.getItem(storeID);
7597
+ return order ? order.split("|") : [];
7598
+ },
7599
+ /**
7600
+ * Save the order of elements.
7601
+ * @param {Sortable} sortable
7602
+ */
7603
+ set: (sortable) => {
7604
+ const order = sortable.toArray();
7605
+ window.localStorage.setItem(storeID, order.join("|"));
7606
+ }
7698
7607
  }
7699
- }
7700
- };
7701
- const mergedOptions = merge(textAreaConfig, options);
7702
- super(mergedOptions);
7703
- }
7704
- }
7705
- const htmlControls = [HeaderControl, ParagraphControl, HRControl, TinyMCEControl];
7706
- const defaultOptions = Object.freeze({
7707
- sortable: true,
7708
- elementOrder: {},
7709
- groupOrder: [],
7710
- groups: [
7711
- {
7712
- id: "layout",
7713
- label: "controls.groups.layout",
7714
- elementOrder: ["row", "column"]
7715
- },
7716
- {
7717
- id: "common",
7718
- label: "controls.groups.form",
7719
- elementOrder: ["button", "checkbox"]
7720
- },
7721
- {
7722
- id: "html",
7723
- label: "controls.groups.html",
7724
- elementOrder: ["header", "block-text"]
7608
+ });
7725
7609
  }
7726
- ],
7727
- disable: {
7728
- groups: [],
7729
- elements: [],
7730
- formActions: []
7731
- },
7732
- elements: [],
7733
- container: null,
7734
- panels: { displayType: "slider" }
7735
- });
7736
- const defaultElements = [...formControls, ...htmlControls, ...layoutControls];
7737
- let Controls$1 = class Controls {
7610
+ return element;
7611
+ }
7612
+ };
7613
+ const Controls$2 = new Controls$1();
7614
+ class ComponentData extends Data {
7738
7615
  constructor() {
7739
- __publicField(this, "groupLabel", (key) => mi18n.get(key) || key || "");
7740
- __publicField(this, "layoutTypes", {
7741
- row: () => Stages2.active.addChild(),
7742
- column: () => this.layoutTypes.row().addChild(),
7743
- field: (controlData) => this.layoutTypes.column().addChild(controlData)
7616
+ super(...arguments);
7617
+ __publicField(this, "load", (dataArg) => {
7618
+ const data = parseData(dataArg);
7619
+ this.empty();
7620
+ for (const [key, val] of Object.entries(data)) {
7621
+ this.add(key, val);
7622
+ }
7623
+ return this.data;
7744
7624
  });
7745
7625
  /**
7746
- * Append an element to the stage
7747
- * @param {String} id of elements
7626
+ * Retrieves data from the specified path or adds new data if no path is provided.
7627
+ *
7628
+ * @param {string} [path] - The path to retrieve data from. If not provided, new data will be added.
7629
+ * @returns {*} The data retrieved from the specified path or the result of adding new data.
7748
7630
  */
7749
- __publicField(this, "addElement", (id) => {
7750
- const {
7751
- meta: { group, id: metaId },
7752
- ...elementData
7753
- } = get(this.get(id), "controlData");
7754
- set(elementData, "config.controlId", metaId);
7755
- if (group === "layout") {
7756
- return this.layoutTypes[metaId.replace("layout-", "")]();
7757
- }
7758
- return this.layoutTypes.field(elementData);
7631
+ __publicField(this, "get", (path) => path ? get(this.data, path) : this.add());
7632
+ /**
7633
+ * Adds a new component with the given id and data.
7634
+ *
7635
+ * @param {string} id - The unique identifier for the component. If not provided, a new UUID will be generated.
7636
+ * @param {Object} [data=Object.create(null)] - The data to initialize the component with.
7637
+ * @returns {Object} The newly created component.
7638
+ */
7639
+ __publicField(this, "add", (id, data = /* @__PURE__ */ Object.create(null)) => {
7640
+ const elemId = id || uuid();
7641
+ const component = this.Component({ ...data, id: elemId });
7642
+ this.set(elemId, component);
7643
+ this.active = component;
7644
+ return component;
7759
7645
  });
7760
- __publicField(this, "applyOptions", async (controlOptions = {}) => {
7761
- const { container, elements, groupOrder, ...options } = merge(defaultOptions, controlOptions);
7762
- this.container = container;
7763
- this.groupOrder = unique(groupOrder.concat(["common", "html", "layout"]));
7764
- this.options = options;
7765
- return Promise.all(this.registerControls([...defaultElements, ...elements]));
7766
- });
7767
- this.data = /* @__PURE__ */ new Map();
7768
- this.buttonActions = {
7769
- // this is used for keyboard navigation. when tabbing through controls it
7770
- // will auto navigated between the groups
7771
- focus: ({ target }) => {
7772
- const group = target.closest(`.${CONTROL_GROUP_CLASSNAME}`);
7773
- return group && this.panels.nav.refresh(indexOfNode(group));
7774
- },
7775
- click: ({ target }) => {
7776
- this.addElement(target.parentElement.id);
7646
+ /**
7647
+ * removes a component form the index
7648
+ * @param {String|Array} componentId
7649
+ */
7650
+ __publicField(this, "remove", (componentId) => {
7651
+ if (Array.isArray(componentId)) {
7652
+ for (const id of componentId) {
7653
+ this.get(id).remove();
7654
+ }
7655
+ } else {
7656
+ this.get(componentId).remove();
7777
7657
  }
7778
- };
7658
+ return this.data;
7659
+ });
7660
+ /**
7661
+ * Deletes a component from the data object.
7662
+ *
7663
+ * @param {string} componentId - The ID of the component to delete.
7664
+ * @returns {string} The ID of the deleted component.
7665
+ */
7666
+ __publicField(this, "delete", (componentId) => {
7667
+ delete this.data[componentId];
7668
+ return componentId;
7669
+ });
7670
+ /**
7671
+ * Clears all instances from the store
7672
+ * @param {Object} evt
7673
+ */
7674
+ __publicField(this, "clearAll", (isAnimated = true) => {
7675
+ const promises = Object.values(this.data).map((component) => component.empty(isAnimated));
7676
+ return Promise.all(promises);
7677
+ });
7678
+ __publicField(this, "conditionMap", /* @__PURE__ */ new Map());
7779
7679
  }
7780
7680
  /**
7781
- * Methods to be called on initialization
7782
- * @param {Object} controlOptions
7681
+ * Extends the configVal for a component type,
7682
+ * eventually read by Component
7683
+ * @return {Object} configVal
7783
7684
  */
7784
- async init(controlOptions, sticky = false) {
7785
- await this.applyOptions(controlOptions);
7786
- this.buildDOM(sticky);
7787
- return this;
7685
+ set config(config2) {
7686
+ this.configVal = merge(this.configVal, clone$1(config2));
7788
7687
  }
7789
7688
  /**
7790
- * Generate control config for UI and bind actions
7791
- * @return {Array} elementControls
7689
+ * Reads configVal for a component type
7690
+ * @return {Object} configVal
7792
7691
  */
7793
- registerControls(elements) {
7794
- this.controls = [];
7795
- return elements.map(async (Element) => {
7796
- const isControl = typeof Element === "function";
7797
- let control;
7798
- if (isControl) {
7799
- control = new Element();
7800
- } else {
7801
- control = new Control(Element);
7802
- }
7803
- this.add(control);
7804
- this.controls.push(control.dom);
7805
- return control.promise();
7806
- });
7692
+ get config() {
7693
+ return this.configVal;
7807
7694
  }
7695
+ }
7696
+ const DEFAULT_DATA$2 = () => Object.freeze({ children: [] });
7697
+ class Stage extends Component {
7808
7698
  /**
7809
- * Group elements into their respective control group
7810
- * @return {Array} allGroups
7699
+ * Process options and load existing fields from data to the stage
7700
+ * @param {Object} formeoOptions
7701
+ * @param {String} stageData uuid
7702
+ * @return {Object} DOM element
7811
7703
  */
7812
- groupElements() {
7813
- let groups = this.options.groups.slice();
7814
- let elements = this.controls.slice();
7815
- let allGroups = [];
7816
- const usedElementIds = [];
7817
- groups = orderObjectsBy(groups, this.groupOrder, "id");
7818
- groups = groups.filter((group) => match(group.id, this.options.disable.groups));
7819
- allGroups = groups.map((group) => {
7820
- const groupConfig = {
7821
- tag: "ul",
7822
- attrs: {
7823
- className: CONTROL_GROUP_CLASSNAME,
7824
- id: `${group.id}-${CONTROL_GROUP_CLASSNAME}`
7825
- },
7826
- config: {
7827
- label: this.groupLabel(group.label)
7828
- }
7829
- };
7830
- if (this.options.elementOrder[group.id]) {
7831
- const userOrder = this.options.elementOrder[group.id];
7832
- const newOrder = unique(userOrder.concat(group.elementOrder));
7833
- group.elementOrder = newOrder;
7704
+ constructor(stageData, render) {
7705
+ super("stage", { ...DEFAULT_DATA$2(), ...stageData }, render);
7706
+ const children = this.createChildWrap();
7707
+ this.dom = dom.create({
7708
+ attrs: {
7709
+ className: [STAGE_CLASSNAME, "empty"],
7710
+ id: this.id
7711
+ },
7712
+ children
7713
+ });
7714
+ Sortable.create(children, {
7715
+ animation: 150,
7716
+ fallbackClass: "row-moving",
7717
+ forceFallback: true,
7718
+ group: {
7719
+ name: "stage",
7720
+ pull: true,
7721
+ put: ["row", "column", "controls"]
7722
+ },
7723
+ sort: true,
7724
+ disabled: false,
7725
+ onAdd: this.onAdd.bind(this),
7726
+ onRemove: this.onRemove.bind(this),
7727
+ onStart: () => {
7728
+ stages.active = this;
7729
+ },
7730
+ onSort: this.onSort.bind(this),
7731
+ draggable: `.${ROW_CLASSNAME}`,
7732
+ handle: ".item-move"
7733
+ });
7734
+ }
7735
+ empty(isAnimated = true) {
7736
+ return new Promise((resolve) => {
7737
+ if (isAnimated) {
7738
+ this.dom.classList.add("removing-all-fields");
7739
+ animate.slideUp(this.dom, ANIMATION_SPEED_BASE, () => {
7740
+ resolve(super.empty(isAnimated));
7741
+ this.dom.classList.remove("removing-all-fields");
7742
+ animate.slideDown(this.dom, ANIMATION_SPEED_BASE);
7743
+ });
7744
+ } else {
7745
+ resolve(super.empty());
7834
7746
  }
7835
- elements = orderObjectsBy(elements, group.elementOrder, "meta.id");
7836
- groupConfig.content = elements.filter((control) => {
7837
- const { controlData: field } = this.get(control.id);
7838
- const controlId = field.meta.id || "";
7839
- const filters = [
7840
- match(controlId, this.options.disable.elements),
7841
- field.meta.group === group.id,
7842
- !usedElementIds.includes(controlId)
7843
- ];
7844
- let shouldFilter = true;
7845
- shouldFilter = filters.every((val) => val === true);
7846
- if (shouldFilter) {
7847
- usedElementIds.push(controlId);
7848
- }
7849
- return shouldFilter;
7850
- });
7851
- return groupConfig;
7852
7747
  });
7853
- return allGroups;
7854
7748
  }
7855
- add(control = /* @__PURE__ */ Object.create(null)) {
7856
- const controlConfig = clone$1(control);
7857
- this.data.set(controlConfig.id, controlConfig);
7858
- if (controlConfig.controlData.meta.id) {
7859
- this.data.set(controlConfig.controlData.meta.id, controlConfig.controlData);
7749
+ onAdd(...args) {
7750
+ const component = super.onAdd(...args);
7751
+ if (component && component.name === "column") {
7752
+ component.parent.autoColumnWidths();
7860
7753
  }
7861
- return controlConfig;
7862
7754
  }
7863
- get(controlId) {
7864
- return clone$1(this.data.get(controlId));
7755
+ }
7756
+ let Stages$1 = class Stages extends ComponentData {
7757
+ constructor(stageData) {
7758
+ super("stages", stageData);
7759
+ }
7760
+ Component(data) {
7761
+ return new Stage(data);
7865
7762
  }
7763
+ };
7764
+ const stages = new Stages$1();
7765
+ const DEFAULT_DATA$1 = () => Object.freeze({
7766
+ config: {
7767
+ fieldset: false,
7768
+ // wrap contents of row in fieldset
7769
+ legend: "",
7770
+ // Legend for fieldset
7771
+ inputGroup: false
7772
+ // is repeatable input-group?
7773
+ },
7774
+ children: [],
7775
+ className: [ROW_CLASSNAME]
7776
+ });
7777
+ class Row extends Component {
7866
7778
  /**
7867
- * Generate the DOM config for form actions like settings, save and clear
7868
- * @return {Object} form action buttons config
7779
+ * Set default and generate dom for row in editor
7780
+ * @param {String} dataID
7781
+ * @return {Object}
7869
7782
  */
7870
- formActions() {
7871
- if (this.options.disable.formActions === true) {
7872
- return null;
7873
- }
7874
- const clearBtn = {
7875
- ...dom.btnTemplate({ content: [dom.icon("bin"), mi18n.get("clear")], title: mi18n.get("clearAll") }),
7876
- className: ["clear-form"],
7877
- action: {
7878
- click: (evt) => {
7879
- if (Rows2.size) {
7880
- events.confirmClearAll = new window.CustomEvent("confirmClearAll", {
7881
- detail: {
7882
- confirmationMessage: mi18n.get("confirmClearAll"),
7883
- clearAllAction: () => {
7884
- Stages2.clearAll().then(() => {
7885
- const evtData = {
7886
- src: evt.target
7887
- };
7888
- events.formeoCleared(evtData);
7889
- });
7890
- },
7891
- btnCoords: dom.coords(evt.target)
7892
- }
7893
- });
7894
- document.dispatchEvent(events.confirmClearAll);
7895
- } else {
7896
- window.alert(mi18n.get("cannotClearFields"));
7897
- }
7898
- }
7783
+ constructor(rowData) {
7784
+ super("row", { ...DEFAULT_DATA$1(), ...rowData });
7785
+ /**
7786
+ * Read columns and generate bootstrap cols
7787
+ * @param {Object} row DOM element
7788
+ */
7789
+ __publicField(this, "autoColumnWidths", () => {
7790
+ const columns2 = this.children;
7791
+ if (!columns2.length) {
7792
+ return;
7899
7793
  }
7900
- };
7901
- const saveBtn = {
7902
- ...dom.btnTemplate({ content: [dom.icon("floppy-disk"), mi18n.get("save")], title: mi18n.get("save") }),
7903
- className: ["save-form"],
7904
- action: {
7905
- click: ({ target }) => {
7906
- const { formData } = components;
7907
- const saveEvt = {
7908
- action: () => {
7909
- },
7910
- coords: dom.coords(target),
7911
- message: "",
7912
- button: target
7913
- };
7914
- actions.click.btn(saveEvt);
7915
- return actions.save.form(formData);
7916
- }
7917
- }
7918
- };
7919
- const formActions = {
7920
- className: "form-actions f-btn-group",
7921
- content: Object.entries({ clearBtn, saveBtn }).reduce((acc, [key, value]) => {
7922
- if (!this.options.disable.formActions.includes(key)) {
7923
- acc.push(value);
7924
- }
7925
- return acc;
7926
- }, [])
7927
- };
7928
- return formActions;
7929
- }
7930
- /**
7931
- * Returns the markup for the form controls/fields
7932
- * @return {DOM}
7933
- */
7934
- buildDOM(sticky) {
7935
- const groupedFields = this.groupElements();
7936
- const formActions = this.formActions();
7937
- const { displayType } = this.options.panels;
7938
- this.panels = new Panels({ panels: groupedFields, type: "controls", displayType });
7939
- const groupsWrapClasses = ["control-groups", "formeo-panels-wrap", `panel-count-${groupedFields.length}`];
7940
- const groupsWrap = dom.create({
7941
- className: groupsWrapClasses,
7942
- content: [this.panels.panelNav, this.panels.panelsWrap]
7943
- });
7944
- const controlClasses = ["formeo-controls"];
7945
- if (sticky) {
7946
- controlClasses.push("formeo-sticky");
7947
- }
7948
- const element = dom.create({
7949
- className: controlClasses,
7950
- content: [groupsWrap, formActions]
7951
- });
7952
- const groups = element.getElementsByClassName("control-group");
7953
- this.dom = element;
7954
- this.groups = groups;
7955
- const [firstGroup] = groups;
7956
- this.currentGroup = firstGroup;
7957
- this.actions = {
7958
- filter: (term) => {
7959
- const filtering = term !== "";
7960
- const fields2 = this.controls;
7961
- let filteredTerm = groupsWrap.querySelector(".filtered-term");
7962
- dom.toggleElementsByStr(fields2, term);
7963
- if (filtering) {
7964
- const filteredStr = mi18n.get("controls.filteringTerm", term);
7965
- element.classList.add("filtered");
7966
- if (filteredTerm) {
7967
- filteredTerm.textContent = filteredStr;
7968
- } else {
7969
- filteredTerm = dom.create({
7970
- tag: "h5",
7971
- className: "filtered-term",
7972
- content: filteredStr
7973
- });
7974
- groupsWrap.insertBefore(filteredTerm, groupsWrap.firstChild);
7975
- }
7976
- } else if (filteredTerm) {
7977
- element.classList.remove("filtered");
7978
- filteredTerm.remove();
7979
- }
7980
- },
7981
- addElement: this.addElement,
7982
- // @todo finish the addGroup method
7983
- addGroup: (group) => console.log(group)
7984
- };
7985
- for (let i = groups.length - 1; i >= 0; i--) {
7986
- const storeID = `formeo-controls-${groups[i]}`;
7987
- if (!this.options.sortable) {
7988
- window.localStorage.removeItem(storeID);
7989
- }
7990
- Sortable.create(groups[i], {
7991
- animation: 150,
7992
- forceFallback: true,
7993
- fallbackClass: "control-moving",
7994
- fallbackOnBody: true,
7995
- group: {
7996
- name: "controls",
7997
- pull: "clone",
7998
- put: false
7999
- },
8000
- onStart: ({ item }) => {
8001
- const { controlData } = this.get(item.id);
8002
- if (this.options.ghostPreview) {
8003
- item.innerHTML = "";
8004
- item.appendChild(new Field(controlData).preview);
8005
- }
8006
- },
8007
- onEnd: ({ from, item, clone: clone2 }) => {
8008
- if (from.contains(clone2)) {
8009
- from.replaceChild(item, clone2);
8010
- }
8011
- },
8012
- sort: this.options.sortable,
8013
- store: {
8014
- /**
8015
- * Get the order of elements.
8016
- * @param {Sortable} sortable
8017
- * @return {Array}
8018
- */
8019
- get: () => {
8020
- const order = window.localStorage.getItem(storeID);
8021
- return order ? order.split("|") : [];
8022
- },
8023
- /**
8024
- * Save the order of elements.
8025
- * @param {Sortable} sortable
8026
- */
8027
- set: (sortable) => {
8028
- const order = sortable.toArray();
8029
- window.localStorage.setItem(storeID, order.join("|"));
8030
- }
8031
- }
8032
- });
8033
- }
8034
- return element;
8035
- }
8036
- };
8037
- const Controls$2 = new Controls$1();
8038
- class ComponentData extends Data {
8039
- constructor() {
8040
- super(...arguments);
8041
- __publicField(this, "load", (dataArg) => {
8042
- const data = parseData(dataArg);
8043
- this.empty();
8044
- for (const [key, val] of Object.entries(data)) {
8045
- this.add(key, val);
7794
+ const width = Number.parseFloat((100 / columns2.length).toFixed(1)) / 1;
7795
+ for (const column of columns2) {
7796
+ column.removeClasses(bsColRegExp);
7797
+ const colDom = column.dom;
7798
+ const newColWidth = numToPercent(width);
7799
+ column.set("config.width", newColWidth);
7800
+ colDom.style.width = newColWidth;
7801
+ colDom.dataset.colWidth = newColWidth;
7802
+ const refreshTimeout = setTimeout(() => {
7803
+ clearTimeout(refreshTimeout);
7804
+ column.refreshFieldPanels();
7805
+ }, ANIMATION_SPEED_FAST);
7806
+ document.dispatchEvent(events.columnResized);
8046
7807
  }
8047
- return this.data;
7808
+ this.updateColumnPreset();
8048
7809
  });
8049
7810
  /**
8050
- * Retrieves data from the specified path or adds new data if no path is provided.
8051
- *
8052
- * @param {string} [path] - The path to retrieve data from. If not provided, new data will be added.
8053
- * @returns {*} The data retrieved from the specified path or the result of adding new data.
8054
- */
8055
- __publicField(this, "get", (path) => path ? get(this.data, path) : this.add());
8056
- /**
8057
- * Adds a new component with the given id and data.
8058
- *
8059
- * @param {string} id - The unique identifier for the component. If not provided, a new UUID will be generated.
8060
- * @param {Object} [data=Object.create(null)] - The data to initialize the component with.
8061
- * @returns {Object} The newly created component.
7811
+ * Updates the column preset <select>
7812
+ * @return {Object} columnPresetConfig
8062
7813
  */
8063
- __publicField(this, "add", (id, data = /* @__PURE__ */ Object.create(null)) => {
8064
- const elemId = id || uuid();
8065
- const component = this.Component({ ...data, id: elemId });
8066
- this.set(elemId, component);
8067
- this.active = component;
8068
- return component;
7814
+ __publicField(this, "updateColumnPreset", () => {
7815
+ this.columnPresetControl.innerHTML = "";
7816
+ const presetOptions = this.getColumnPresetOptions.map(
7817
+ ({ label, ...attrs }) => dom.create({
7818
+ tag: "option",
7819
+ content: label,
7820
+ attrs
7821
+ })
7822
+ );
7823
+ this.columnPresetControl.append(...presetOptions);
8069
7824
  });
8070
7825
  /**
8071
- * removes a component form the index
8072
- * @param {String|Array} componentId
7826
+ * Set the widths of columns in a row
7827
+ * @param {Object} row DOM element
7828
+ * @param {String} widths
8073
7829
  */
8074
- __publicField(this, "remove", (componentId) => {
8075
- if (Array.isArray(componentId)) {
8076
- for (const id of componentId) {
8077
- this.get(id).remove();
8078
- }
8079
- } else {
8080
- this.get(componentId).remove();
7830
+ __publicField(this, "setColumnWidths", (widths) => {
7831
+ if (typeof widths === "string") {
7832
+ widths = widths.split(",");
8081
7833
  }
8082
- return this.data;
8083
- });
8084
- /**
8085
- * Deletes a component from the data object.
8086
- *
8087
- * @param {string} componentId - The ID of the component to delete.
8088
- * @returns {string} The ID of the deleted component.
8089
- */
8090
- __publicField(this, "delete", (componentId) => {
8091
- delete this.data[componentId];
8092
- return componentId;
8093
- });
8094
- /**
8095
- * Clears all instances from the store
8096
- * @param {Object} evt
8097
- */
8098
- __publicField(this, "clearAll", (isAnimated = true) => {
8099
- const promises = Object.values(this.data).map((component) => component.empty(isAnimated));
8100
- return Promise.all(promises);
7834
+ this.children.forEach((column, i) => {
7835
+ column.setWidth(`${widths[i]}%`);
7836
+ column.refreshFieldPanels();
7837
+ });
8101
7838
  });
8102
- __publicField(this, "conditionMap", /* @__PURE__ */ new Map());
8103
- }
8104
- /**
8105
- * Extends the configVal for a component type,
8106
- * eventually read by Component
8107
- * @return {Object} configVal
8108
- */
8109
- set config(config2) {
8110
- this.configVal = merge(this.configVal, clone$1(config2));
8111
- }
8112
- /**
8113
- * Reads configVal for a component type
8114
- * @return {Object} configVal
8115
- */
8116
- get config() {
8117
- return this.configVal;
8118
- }
8119
- }
8120
- const DEFAULT_DATA$2 = () => Object.freeze({ children: [] });
8121
- class Stage extends Component {
8122
- /**
8123
- * Process options and load existing fields from data to the stage
8124
- * @param {Object} formeoOptions
8125
- * @param {String} stageData uuid
8126
- * @return {Object} DOM element
8127
- */
8128
- constructor(stageData, render) {
8129
- super("stage", { ...DEFAULT_DATA$2(), ...stageData }, render);
8130
7839
  const children = this.createChildWrap();
8131
7840
  this.dom = dom.create({
8132
- attrs: {
8133
- className: [STAGE_CLASSNAME, "empty"],
8134
- id: this.id
7841
+ tag: "li",
7842
+ className: [ROW_CLASSNAME, "empty"],
7843
+ dataset: {
7844
+ hoverTag: mi18n.get("row"),
7845
+ editingHoverTag: mi18n.get("editing.row")
8135
7846
  },
8136
- children
8137
- });
8138
- Sortable.create(children, {
8139
- animation: 150,
8140
- fallbackClass: "row-moving",
8141
- forceFallback: true,
8142
- group: {
8143
- name: "stage",
8144
- pull: true,
8145
- put: ["row", "column", "controls"]
8146
- },
8147
- sort: true,
8148
- disabled: false,
8149
- onAdd: this.onAdd.bind(this),
8150
- onRemove: this.onRemove.bind(this),
8151
- onStart: () => {
8152
- stages.active = this;
8153
- },
8154
- onSort: this.onSort.bind(this),
8155
- draggable: `.${ROW_CLASSNAME}`,
8156
- handle: ".item-move"
8157
- });
8158
- }
8159
- empty(isAnimated = true) {
8160
- return new Promise((resolve) => {
8161
- if (isAnimated) {
8162
- this.dom.classList.add("removing-all-fields");
8163
- animate.slideUp(this.dom, ANIMATION_SPEED_BASE, () => {
8164
- resolve(super.empty(isAnimated));
8165
- this.dom.classList.remove("removing-all-fields");
8166
- animate.slideDown(this.dom, ANIMATION_SPEED_BASE);
8167
- });
8168
- } else {
8169
- resolve(super.empty());
8170
- }
8171
- });
8172
- }
8173
- onAdd(...args) {
8174
- const component = super.onAdd(...args);
8175
- if (component && component.name === "column") {
8176
- component.parent.autoColumnWidths();
8177
- }
8178
- }
8179
- }
8180
- let Stages$1 = class Stages extends ComponentData {
8181
- constructor(stageData) {
8182
- super("stages", stageData);
8183
- }
8184
- Component(data) {
8185
- return new Stage(data);
8186
- }
8187
- };
8188
- const stages = new Stages$1();
8189
- const DEFAULT_DATA$1 = () => Object.freeze({
8190
- config: {
8191
- fieldset: false,
8192
- // wrap contents of row in fieldset
8193
- legend: "",
8194
- // Legend for fieldset
8195
- inputGroup: false
8196
- // is repeatable input-group?
8197
- },
8198
- children: [],
8199
- className: [ROW_CLASSNAME]
8200
- });
8201
- class Row extends Component {
8202
- /**
8203
- * Set default and generate dom for row in editor
8204
- * @param {String} dataID
8205
- * @return {Object}
8206
- */
8207
- constructor(rowData) {
8208
- super("row", { ...DEFAULT_DATA$1(), ...rowData });
8209
- /**
8210
- * Read columns and generate bootstrap cols
8211
- * @param {Object} row DOM element
8212
- */
8213
- __publicField(this, "autoColumnWidths", () => {
8214
- const columns2 = this.children;
8215
- if (!columns2.length) {
8216
- return;
8217
- }
8218
- const width = Number.parseFloat((100 / columns2.length).toFixed(1)) / 1;
8219
- for (const column of columns2) {
8220
- column.removeClasses(bsColRegExp);
8221
- const colDom = column.dom;
8222
- const newColWidth = numToPercent(width);
8223
- column.set("config.width", newColWidth);
8224
- colDom.style.width = newColWidth;
8225
- colDom.dataset.colWidth = newColWidth;
8226
- const refreshTimeout = setTimeout(() => {
8227
- clearTimeout(refreshTimeout);
8228
- column.refreshFieldPanels();
8229
- }, ANIMATION_SPEED_FAST);
8230
- document.dispatchEvent(events.columnResized);
8231
- }
8232
- this.updateColumnPreset();
8233
- });
8234
- /**
8235
- * Updates the column preset <select>
8236
- * @return {Object} columnPresetConfig
8237
- */
8238
- __publicField(this, "updateColumnPreset", () => {
8239
- this.columnPresetControl.innerHTML = "";
8240
- const presetOptions = this.getColumnPresetOptions.map(
8241
- ({ label, ...attrs }) => dom.create({
8242
- tag: "option",
8243
- content: label,
8244
- attrs
8245
- })
8246
- );
8247
- this.columnPresetControl.append(...presetOptions);
8248
- });
8249
- /**
8250
- * Set the widths of columns in a row
8251
- * @param {Object} row DOM element
8252
- * @param {String} widths
8253
- */
8254
- __publicField(this, "setColumnWidths", (widths) => {
8255
- if (typeof widths === "string") {
8256
- widths = widths.split(",");
8257
- }
8258
- this.children.forEach((column, i) => {
8259
- column.setWidth(`${widths[i]}%`);
8260
- column.refreshFieldPanels();
8261
- });
8262
- });
8263
- const children = this.createChildWrap();
8264
- this.dom = dom.create({
8265
- tag: "li",
8266
- className: [ROW_CLASSNAME, "empty"],
8267
- dataset: {
8268
- hoverTag: mi18n.get("row"),
8269
- editingHoverTag: mi18n.get("editing.row")
8270
- },
8271
- id: this.id,
8272
- content: [this.getComponentTag(), this.getActionButtons(), this.editWindow, children]
7847
+ id: this.id,
7848
+ content: [this.getComponentTag(), this.getActionButtons(), this.editWindow, children]
8273
7849
  });
8274
7850
  Sortable.create(children, {
8275
7851
  animation: 150,
@@ -9945,164 +9521,591 @@ let FormeoRenderer$1 = class FormeoRenderer {
9945
9521
  className: "add-input-group btn pull-right",
9946
9522
  type: "button"
9947
9523
  },
9948
- children: "Add +",
9524
+ children: "Add +",
9525
+ action: {
9526
+ click: (e) => {
9527
+ const fInputGroup = e.target.parentElement;
9528
+ const elem = dom.render(this.cloneComponentData(id));
9529
+ fInputGroup.insertBefore(elem, fInputGroup.lastChild);
9530
+ elem.appendChild(createRemoveButton());
9531
+ }
9532
+ }
9533
+ }));
9534
+ __publicField(this, "processColumns", (rowId) => {
9535
+ return this.orderChildren("columns", this.form.rows[rowId].children).map(
9536
+ (column) => this.cacheComponent(this.processColumn(column))
9537
+ );
9538
+ });
9539
+ __publicField(this, "processFields", (fieldIds) => this.orderChildren("fields", fieldIds).map(({ id, ...field }) => {
9540
+ var _a, _b;
9541
+ const controlId = ((_a = field.config) == null ? void 0 : _a.controlId) || ((_b = field.meta) == null ? void 0 : _b.id);
9542
+ const { action = {}, dependencies: dependencies2 = {} } = this.elements[controlId] || {};
9543
+ if (dependencies2) {
9544
+ fetchDependencies(dependencies2);
9545
+ }
9546
+ const mergedFieldData = merge({ action }, field);
9547
+ return this.cacheComponent({ ...mergedFieldData, id: this.prefixId(id) });
9548
+ }));
9549
+ /**
9550
+ * Evaulate and execute conditions for fields by creating listeners for input and changes
9551
+ * @return {Array} flattened array of conditions
9552
+ */
9553
+ __publicField(this, "handleComponentCondition", (component, ifRest, thenConditions) => {
9554
+ const listenerEvent = LISTEN_TYPE_MAP(component);
9555
+ if (listenerEvent) {
9556
+ component.addEventListener(
9557
+ listenerEvent,
9558
+ (evt) => {
9559
+ if (this.evaluateCondition(ifRest, evt)) {
9560
+ for (const thenCondition of thenConditions) {
9561
+ this.execResult(thenCondition, evt);
9562
+ }
9563
+ }
9564
+ },
9565
+ false
9566
+ );
9567
+ }
9568
+ const fakeEvt = { target: component };
9569
+ if (this.evaluateCondition(ifRest, fakeEvt)) {
9570
+ for (const thenCondition of thenConditions) {
9571
+ this.execResult(thenCondition, fakeEvt);
9572
+ }
9573
+ }
9574
+ });
9575
+ __publicField(this, "applyConditions", () => {
9576
+ for (const { conditions } of Object.values(this.components)) {
9577
+ if (conditions) {
9578
+ for (const condition of conditions) {
9579
+ const { if: ifConditions, then: thenConditions } = condition;
9580
+ for (const ifCondition of ifConditions) {
9581
+ const { source, ...ifRest } = ifCondition;
9582
+ if (isAddress(source)) {
9583
+ const components2 = this.getComponents(source);
9584
+ for (const component of components2) {
9585
+ this.handleComponentCondition(component, ifRest, thenConditions);
9586
+ }
9587
+ }
9588
+ }
9589
+ }
9590
+ }
9591
+ }
9592
+ });
9593
+ /**
9594
+ * Evaulate conditions
9595
+ */
9596
+ __publicField(this, "evaluateCondition", ({ sourceProperty, targetProperty, comparison, target }, evt) => {
9597
+ var _a;
9598
+ const comparisonMap = {
9599
+ equals: isEqual$1,
9600
+ notEquals: (source, target2) => !isEqual$1(source, target2),
9601
+ contains: (source, target2) => source.includes(target2),
9602
+ notContains: (source, target2) => !source.includes(target2)
9603
+ };
9604
+ const sourceValue = String(evt.target[sourceProperty]);
9605
+ const targetValue = String(isAddress(target) ? this.getComponent(target)[targetProperty] : target);
9606
+ return (_a = comparisonMap[comparison]) == null ? void 0 : _a.call(comparisonMap, sourceValue, targetValue);
9607
+ });
9608
+ __publicField(this, "execResult", ({ assignment, target, targetProperty, value }) => {
9609
+ var _a;
9610
+ const assignMap = {
9611
+ equals: (elem) => {
9612
+ var _a2;
9613
+ const propMap = {
9614
+ value: () => {
9615
+ elem[targetProperty] = value;
9616
+ },
9617
+ isNotVisible: () => {
9618
+ elem.parentElement.setAttribute("hidden", true);
9619
+ elem.required = false;
9620
+ },
9621
+ isVisible: () => {
9622
+ elem.parentElement.removeAttribute("hidden");
9623
+ elem.required = elem._required;
9624
+ }
9625
+ };
9626
+ (_a2 = propMap[targetProperty]) == null ? void 0 : _a2.call(propMap);
9627
+ }
9628
+ };
9629
+ if (isAddress(target)) {
9630
+ const elem = this.getComponent(target);
9631
+ if (elem && elem._required === void 0) {
9632
+ elem._required = elem.required;
9633
+ }
9634
+ (_a = assignMap[assignment]) == null ? void 0 : _a.call(assignMap, elem);
9635
+ }
9636
+ });
9637
+ __publicField(this, "getComponent", (address) => {
9638
+ const componentId = address.slice(address.indexOf(".") + 1);
9639
+ const component = isExternalAddress(address) ? this.external[componentId] : this.renderedForm.querySelector(`#f-${componentId}`);
9640
+ return component;
9641
+ });
9642
+ __publicField(this, "getComponents", (address) => {
9643
+ const components2 = [];
9644
+ const componentId = address.slice(address.indexOf(".") + 1);
9645
+ if (isExternalAddress(address)) {
9646
+ components2.push(this.external[componentId]);
9647
+ } else {
9648
+ components2.push(...this.renderedForm.querySelectorAll(`[name=f-${componentId}]`));
9649
+ }
9650
+ return components2;
9651
+ });
9652
+ const { renderContainer, external, elements, formData } = processOptions(opts);
9653
+ this.container = renderContainer;
9654
+ this.form = cleanFormData(formDataArg || formData);
9655
+ this.external = external;
9656
+ this.dom = dom;
9657
+ this.components = /* @__PURE__ */ Object.create(null);
9658
+ this.elements = elements;
9659
+ }
9660
+ get processedData() {
9661
+ return Object.values(this.form.stages).map((stage) => {
9662
+ stage.children = this.processRows(stage.id);
9663
+ stage.className = STAGE_CLASSNAME;
9664
+ return dom.render(stage);
9665
+ });
9666
+ }
9667
+ };
9668
+ const LISTEN_TYPE_MAP = (component) => {
9669
+ const typesMap = [
9670
+ ["input", (c) => ["textarea", "text"].includes(c.type)],
9671
+ ["change", (c) => ["select"].includes(c.tagName.toLowerCase()) || ["checkbox", "radio"].includes(c.type)]
9672
+ ];
9673
+ const [listenerEvent] = typesMap.find((typeMap) => typeMap[1](component)) || [false];
9674
+ return listenerEvent;
9675
+ };
9676
+ if (window !== void 0) {
9677
+ window.FormeoEditor = FormeoEditor$1;
9678
+ window.FormeoRenderer = FormeoRenderer$1;
9679
+ }
9680
+ const FormeoEditor2 = FormeoEditor$1;
9681
+ const FormeoRenderer2 = FormeoRenderer$1;
9682
+ const rowControl = {
9683
+ config: {
9684
+ label: "row"
9685
+ },
9686
+ meta: {
9687
+ group: "layout",
9688
+ icon: "rows",
9689
+ id: "layout-row"
9690
+ }
9691
+ };
9692
+ const columnControl = {
9693
+ config: {
9694
+ label: "column"
9695
+ },
9696
+ meta: {
9697
+ group: "layout",
9698
+ icon: "columns",
9699
+ id: "layout-column"
9700
+ }
9701
+ };
9702
+ const index$4 = [rowControl, columnControl];
9703
+ const index$5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
9704
+ __proto__: null,
9705
+ default: index$4
9706
+ }, Symbol.toStringTag, { value: "Module" }));
9707
+ class HiddenControl extends Control {
9708
+ constructor() {
9709
+ const hiddenInput = {
9710
+ tag: "input",
9711
+ attrs: {
9712
+ type: "hidden",
9713
+ value: ""
9714
+ },
9715
+ config: {
9716
+ label: mi18n.get("hidden"),
9717
+ hideLabel: true
9718
+ },
9719
+ meta: {
9720
+ group: "common",
9721
+ icon: "hidden",
9722
+ id: "hidden"
9723
+ }
9724
+ };
9725
+ super(hiddenInput);
9726
+ }
9727
+ }
9728
+ class NumberControl extends Control {
9729
+ constructor() {
9730
+ const numberInput = {
9731
+ tag: "input",
9732
+ attrs: {
9733
+ type: "number",
9734
+ required: false,
9735
+ className: ""
9736
+ },
9737
+ config: {
9738
+ label: mi18n.get("number")
9739
+ },
9740
+ meta: {
9741
+ group: "common",
9742
+ icon: "hash",
9743
+ id: "number"
9744
+ }
9745
+ };
9746
+ super(numberInput);
9747
+ }
9748
+ }
9749
+ class TextAreaControl extends Control {
9750
+ constructor() {
9751
+ const textAreaConfig = {
9752
+ tag: "textarea",
9753
+ config: {
9754
+ label: mi18n.get("controls.form.textarea")
9755
+ },
9756
+ meta: {
9757
+ group: "common",
9758
+ icon: "textarea",
9759
+ id: "textarea"
9760
+ },
9761
+ attrs: {
9762
+ required: false
9763
+ }
9764
+ };
9765
+ super(textAreaConfig);
9766
+ }
9767
+ }
9768
+ class TextControl extends Control {
9769
+ constructor() {
9770
+ const textInput = {
9771
+ tag: "input",
9772
+ attrs: {
9773
+ required: false,
9774
+ type: "text",
9775
+ className: ""
9776
+ },
9777
+ config: {
9778
+ label: mi18n.get("controls.form.input.text")
9779
+ },
9780
+ meta: {
9781
+ group: "common",
9782
+ icon: "text-input",
9783
+ id: "text-input"
9784
+ }
9785
+ };
9786
+ super(textInput);
9787
+ }
9788
+ }
9789
+ class FileControl extends Control {
9790
+ constructor() {
9791
+ const fileInput = {
9792
+ tag: "input",
9793
+ attrs: {
9794
+ type: "file",
9795
+ required: false
9796
+ },
9797
+ config: {
9798
+ label: mi18n.get("fileUpload")
9799
+ },
9800
+ meta: {
9801
+ group: "common",
9802
+ icon: "upload",
9803
+ id: "upload"
9804
+ }
9805
+ };
9806
+ super(fileInput);
9807
+ }
9808
+ }
9809
+ const generateOptionConfig = (type2, count = 3) => Array.from({ length: count }, (v, k) => k + 1).map((i) => {
9810
+ const selectedKey = type2 === "checkbox" ? "checked" : "selected";
9811
+ return {
9812
+ label: mi18n.get("labelCount", {
9813
+ label: toTitleCase(type2),
9814
+ count: i
9815
+ }),
9816
+ value: `${type2}-${i}`,
9817
+ [selectedKey]: !i
9818
+ };
9819
+ });
9820
+ class SelectControl extends Control {
9821
+ constructor() {
9822
+ const selectConfig = {
9823
+ tag: "select",
9824
+ config: {
9825
+ label: mi18n.get("controls.form.select")
9826
+ },
9827
+ attrs: {
9828
+ required: false,
9829
+ className: ""
9830
+ },
9831
+ meta: {
9832
+ group: "common",
9833
+ icon: "select",
9834
+ id: "select"
9835
+ },
9836
+ options: generateOptionConfig("option")
9837
+ };
9838
+ super(selectConfig);
9839
+ }
9840
+ }
9841
+ class CheckboxGroupControl extends Control {
9842
+ constructor() {
9843
+ const checkboxGroup = {
9844
+ tag: "input",
9845
+ attrs: {
9846
+ type: "checkbox",
9847
+ required: false
9848
+ },
9849
+ config: {
9850
+ label: mi18n.get("controls.form.checkbox-group"),
9851
+ disabledAttrs: ["type"]
9852
+ },
9853
+ meta: {
9854
+ group: "common",
9855
+ icon: "checkbox",
9856
+ id: "checkbox"
9857
+ },
9858
+ options: generateOptionConfig("checkbox", 1)
9859
+ };
9860
+ super(checkboxGroup);
9861
+ }
9862
+ }
9863
+ class RadioGroupControl extends Control {
9864
+ constructor() {
9865
+ const radioGroup = {
9866
+ tag: "input",
9867
+ attrs: {
9868
+ type: "radio",
9869
+ required: false
9870
+ },
9871
+ config: {
9872
+ label: mi18n.get("controls.form.radio-group"),
9873
+ disabledAttrs: ["type"]
9874
+ },
9875
+ meta: {
9876
+ group: "common",
9877
+ icon: "radio-group",
9878
+ id: "radio"
9879
+ },
9880
+ options: generateOptionConfig("radio")
9881
+ };
9882
+ super(radioGroup);
9883
+ }
9884
+ }
9885
+ class ButtonControl extends Control {
9886
+ constructor() {
9887
+ const buttonConfig = {
9888
+ tag: "button",
9889
+ attrs: {
9890
+ className: [{ label: "grouped", value: "f-btn-group" }, { label: "ungrouped", value: "f-field-group" }]
9891
+ },
9892
+ config: {
9893
+ label: mi18n.get("controls.form.button"),
9894
+ hideLabel: true
9895
+ },
9896
+ meta: {
9897
+ group: "common",
9898
+ icon: "button",
9899
+ id: "button"
9900
+ },
9901
+ options: [
9902
+ {
9903
+ label: mi18n.get("button"),
9904
+ type: ["button", "submit", "reset"].map((buttonType) => ({
9905
+ label: buttonType,
9906
+ type: buttonType
9907
+ })),
9908
+ className: [
9909
+ {
9910
+ label: "default",
9911
+ value: "",
9912
+ selected: true
9913
+ },
9914
+ {
9915
+ label: "primary",
9916
+ value: "primary"
9917
+ },
9918
+ {
9919
+ label: "danger",
9920
+ value: "error"
9921
+ },
9922
+ {
9923
+ label: "success",
9924
+ value: "success"
9925
+ },
9926
+ {
9927
+ label: "warning",
9928
+ value: "warning"
9929
+ }
9930
+ ]
9931
+ }
9932
+ ]
9933
+ };
9934
+ super(buttonConfig);
9935
+ }
9936
+ }
9937
+ class DateControl extends Control {
9938
+ constructor() {
9939
+ const dateInput = {
9940
+ tag: "input",
9941
+ attrs: {
9942
+ type: "date",
9943
+ required: false,
9944
+ className: ""
9945
+ },
9946
+ config: {
9947
+ label: mi18n.get("controls.form.input.date")
9948
+ },
9949
+ meta: {
9950
+ group: "common",
9951
+ icon: "calendar",
9952
+ id: "date-input"
9953
+ }
9954
+ };
9955
+ super(dateInput);
9956
+ }
9957
+ }
9958
+ const index$2 = [
9959
+ ButtonControl,
9960
+ DateControl,
9961
+ HiddenControl,
9962
+ NumberControl,
9963
+ TextAreaControl,
9964
+ TextControl,
9965
+ FileControl,
9966
+ SelectControl,
9967
+ CheckboxGroupControl,
9968
+ RadioGroupControl
9969
+ ];
9970
+ const index$3 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
9971
+ __proto__: null,
9972
+ default: index$2
9973
+ }, Symbol.toStringTag, { value: "Module" }));
9974
+ const headerTags = Array.from(Array(5).keys()).slice(1).map((key) => `h${key}`);
9975
+ const headerKey = "controls.html.header";
9976
+ class HeaderControl extends Control {
9977
+ constructor() {
9978
+ const header = {
9979
+ tag: headerTags[0],
9980
+ attrs: {
9981
+ tag: headerTags.map((tag, index2) => ({
9982
+ label: tag.toUpperCase(),
9983
+ value: tag,
9984
+ selected: !index2
9985
+ })),
9986
+ className: ""
9987
+ },
9988
+ config: {
9989
+ label: mi18n.get(headerKey),
9990
+ hideLabel: true,
9991
+ editableContent: true
9992
+ },
9993
+ meta: {
9994
+ group: "html",
9995
+ icon: "header",
9996
+ id: "html.header"
9997
+ },
9998
+ content: mi18n.get(headerKey),
9949
9999
  action: {
9950
- click: (e) => {
9951
- const fInputGroup = e.target.parentElement;
9952
- const elem = dom.render(this.cloneComponentData(id));
9953
- fInputGroup.insertBefore(elem, fInputGroup.lastChild);
9954
- elem.appendChild(createRemoveButton());
9955
- }
9956
- }
9957
- }));
9958
- __publicField(this, "processColumns", (rowId) => {
9959
- return this.orderChildren("columns", this.form.rows[rowId].children).map(
9960
- (column) => this.cacheComponent(this.processColumn(column))
9961
- );
9962
- });
9963
- __publicField(this, "processFields", (fieldIds) => this.orderChildren("fields", fieldIds).map(({ id, ...field }) => {
9964
- var _a, _b;
9965
- const controlId = ((_a = field.config) == null ? void 0 : _a.controlId) || ((_b = field.meta) == null ? void 0 : _b.id);
9966
- const { action = {}, dependencies: dependencies2 = {} } = this.elements[controlId] || {};
9967
- if (dependencies2) {
9968
- fetchDependencies(dependencies2);
9969
- }
9970
- const mergedFieldData = merge({ action }, field);
9971
- return this.cacheComponent({ ...mergedFieldData, id: this.prefixId(id) });
9972
- }));
9973
- /**
9974
- * Evaulate and execute conditions for fields by creating listeners for input and changes
9975
- * @return {Array} flattened array of conditions
9976
- */
9977
- __publicField(this, "handleComponentCondition", (component, ifRest, thenConditions) => {
9978
- const listenerEvent = LISTEN_TYPE_MAP(component);
9979
- if (listenerEvent) {
9980
- component.addEventListener(
9981
- listenerEvent,
9982
- (evt) => {
9983
- if (this.evaluateCondition(ifRest, evt)) {
9984
- for (const thenCondition of thenConditions) {
9985
- this.execResult(thenCondition, evt);
9986
- }
9987
- }
9988
- },
9989
- false
9990
- );
10000
+ // onRender: evt => {},
10001
+ // click: evt => {},
9991
10002
  }
9992
- const fakeEvt = { target: component };
9993
- if (this.evaluateCondition(ifRest, fakeEvt)) {
9994
- for (const thenCondition of thenConditions) {
9995
- this.execResult(thenCondition, fakeEvt);
10003
+ };
10004
+ super(header);
10005
+ }
10006
+ /**
10007
+ * class configuration
10008
+ */
10009
+ static get definition() {
10010
+ return {
10011
+ // i18n custom mappings (defaults to camelCase type)
10012
+ i18n: {
10013
+ "en-US": {
10014
+ header: "Custom English Header"
9996
10015
  }
9997
10016
  }
9998
- });
9999
- __publicField(this, "applyConditions", () => {
10000
- for (const { conditions } of Object.values(this.components)) {
10001
- if (conditions) {
10002
- for (const condition of conditions) {
10003
- const { if: ifConditions, then: thenConditions } = condition;
10004
- for (const ifCondition of ifConditions) {
10005
- const { source, ...ifRest } = ifCondition;
10006
- if (isAddress(source)) {
10007
- const components2 = this.getComponents(source);
10008
- for (const component of components2) {
10009
- this.handleComponentCondition(component, ifRest, thenConditions);
10010
- }
10011
- }
10012
- }
10013
- }
10014
- }
10017
+ };
10018
+ }
10019
+ get content() {
10020
+ return super.i18n(headerKey);
10021
+ }
10022
+ }
10023
+ class ParagraphControl extends Control {
10024
+ constructor() {
10025
+ const paragraphConfig = {
10026
+ tag: "p",
10027
+ attrs: {
10028
+ className: ""
10029
+ },
10030
+ config: {
10031
+ label: mi18n.get("controls.html.paragraph"),
10032
+ hideLabel: true,
10033
+ editableContent: true
10034
+ },
10035
+ meta: {
10036
+ group: "html",
10037
+ icon: "paragraph",
10038
+ id: "paragraph"
10039
+ },
10040
+ // eslint-disable-next-line
10041
+ content: "Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment."
10042
+ };
10043
+ super(paragraphConfig);
10044
+ }
10045
+ }
10046
+ class HRControl extends Control {
10047
+ constructor() {
10048
+ const hrConfig = {
10049
+ tag: "hr",
10050
+ config: {
10051
+ label: mi18n.get("controls.html.divider"),
10052
+ hideLabel: true
10053
+ },
10054
+ meta: {
10055
+ group: "html",
10056
+ icon: "divider",
10057
+ id: "divider"
10015
10058
  }
10016
- });
10017
- /**
10018
- * Evaulate conditions
10019
- */
10020
- __publicField(this, "evaluateCondition", ({ sourceProperty, targetProperty, comparison, target }, evt) => {
10021
- var _a;
10022
- const comparisonMap = {
10023
- equals: isEqual$1,
10024
- notEquals: (source, target2) => !isEqual$1(source, target2),
10025
- contains: (source, target2) => source.includes(target2),
10026
- notContains: (source, target2) => !source.includes(target2)
10027
- };
10028
- const sourceValue = String(evt.target[sourceProperty]);
10029
- const targetValue = String(isAddress(target) ? this.getComponent(target)[targetProperty] : target);
10030
- return (_a = comparisonMap[comparison]) == null ? void 0 : _a.call(comparisonMap, sourceValue, targetValue);
10031
- });
10032
- __publicField(this, "execResult", ({ assignment, target, targetProperty, value }) => {
10033
- var _a;
10034
- const assignMap = {
10035
- equals: (elem) => {
10036
- var _a2;
10037
- const propMap = {
10038
- value: () => {
10039
- elem[targetProperty] = value;
10040
- },
10041
- isNotVisible: () => {
10042
- elem.parentElement.setAttribute("hidden", true);
10043
- elem.required = false;
10044
- },
10045
- isVisible: () => {
10046
- elem.parentElement.removeAttribute("hidden");
10047
- elem.required = elem._required;
10048
- }
10049
- };
10050
- (_a2 = propMap[targetProperty]) == null ? void 0 : _a2.call(propMap);
10059
+ };
10060
+ super(hrConfig);
10061
+ }
10062
+ }
10063
+ class TinyMCEControl extends Control {
10064
+ constructor(options) {
10065
+ const textAreaConfig = {
10066
+ tag: "textarea",
10067
+ config: {
10068
+ label: "WYSIWYG",
10069
+ editableContent: true
10070
+ },
10071
+ meta: {
10072
+ group: "html",
10073
+ icon: "rich-text",
10074
+ id: "tinymce"
10075
+ },
10076
+ attrs: {
10077
+ required: false
10078
+ },
10079
+ dependencies: { js: "https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.9.11/tinymce.min.js" },
10080
+ // this action is passed to the rendered control/element
10081
+ // useful for actions and events on the control preview
10082
+ action: {
10083
+ onRender: (elem) => {
10084
+ const selector = `#${elem.id}`;
10085
+ window.tinymce.remove(selector);
10086
+ window.tinymce.init({
10087
+ selector
10088
+ });
10051
10089
  }
10052
- };
10053
- if (isAddress(target)) {
10054
- const elem = this.getComponent(target);
10055
- if (elem && elem._required === void 0) {
10056
- elem._required = elem.required;
10090
+ },
10091
+ controlAction: {
10092
+ // callback when control is clicked
10093
+ click: () => {
10094
+ },
10095
+ // callback for when control is rendered
10096
+ onRender: () => {
10057
10097
  }
10058
- (_a = assignMap[assignment]) == null ? void 0 : _a.call(assignMap, elem);
10059
- }
10060
- });
10061
- __publicField(this, "getComponent", (address) => {
10062
- const componentId = address.slice(address.indexOf(".") + 1);
10063
- const component = isExternalAddress(address) ? this.external[componentId] : this.renderedForm.querySelector(`#f-${componentId}`);
10064
- return component;
10065
- });
10066
- __publicField(this, "getComponents", (address) => {
10067
- const components2 = [];
10068
- const componentId = address.slice(address.indexOf(".") + 1);
10069
- if (isExternalAddress(address)) {
10070
- components2.push(this.external[componentId]);
10071
- } else {
10072
- components2.push(...this.renderedForm.querySelectorAll(`[name=f-${componentId}]`));
10073
10098
  }
10074
- return components2;
10075
- });
10076
- const { renderContainer, external, elements, formData } = processOptions(opts);
10077
- this.container = renderContainer;
10078
- this.form = cleanFormData(formDataArg || formData);
10079
- this.external = external;
10080
- this.dom = dom;
10081
- this.components = /* @__PURE__ */ Object.create(null);
10082
- this.elements = elements;
10083
- }
10084
- get processedData() {
10085
- return Object.values(this.form.stages).map((stage) => {
10086
- stage.children = this.processRows(stage.id);
10087
- stage.className = STAGE_CLASSNAME;
10088
- return dom.render(stage);
10089
- });
10099
+ };
10100
+ const mergedOptions = merge(textAreaConfig, options);
10101
+ super(mergedOptions);
10090
10102
  }
10091
- };
10092
- const LISTEN_TYPE_MAP = (component) => {
10093
- const typesMap = [
10094
- ["input", (c) => ["textarea", "text"].includes(c.type)],
10095
- ["change", (c) => ["select"].includes(c.tagName.toLowerCase()) || ["checkbox", "radio"].includes(c.type)]
10096
- ];
10097
- const [listenerEvent] = typesMap.find((typeMap) => typeMap[1](component)) || [false];
10098
- return listenerEvent;
10099
- };
10100
- if (window !== void 0) {
10101
- window.FormeoEditor = FormeoEditor$1;
10102
- window.FormeoRenderer = FormeoRenderer$1;
10103
10103
  }
10104
- const FormeoEditor2 = FormeoEditor$1;
10105
- const FormeoRenderer2 = FormeoRenderer$1;
10104
+ const index = [HeaderControl, ParagraphControl, HRControl, TinyMCEControl];
10105
+ const index$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
10106
+ __proto__: null,
10107
+ default: index
10108
+ }, Symbol.toStringTag, { value: "Module" }));
10106
10109
  export {
10107
10110
  FormeoEditor2 as FormeoEditor,
10108
10111
  FormeoRenderer2 as FormeoRenderer