formeo 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/demo/assets/css/demo.min.css +2 -2
  2. package/dist/demo/assets/css/demo.min.css.gz +0 -0
  3. package/dist/demo/assets/css/formeo.min.css +2 -2
  4. package/dist/demo/assets/css/formeo.min.css.gz +0 -0
  5. package/dist/demo/assets/js/demo.min.js +2 -2
  6. package/dist/demo/assets/js/demo.min.js.gz +0 -0
  7. package/dist/demo/assets/js/formeo.min.js +3 -3
  8. package/dist/demo/assets/js/formeo.min.js.gz +0 -0
  9. package/dist/demo/assets/lang/af-ZA.json +1 -1
  10. package/dist/demo/assets/lang/af-ZA.lang +73 -30
  11. package/dist/demo/assets/lang/ar-TN.json +1 -1
  12. package/dist/demo/assets/lang/ar-TN.lang +161 -30
  13. package/dist/demo/assets/lang/cs-CZ.json +1 -1
  14. package/dist/demo/assets/lang/cs-CZ.lang +73 -30
  15. package/dist/demo/assets/lang/de-DE.json +1 -1
  16. package/dist/demo/assets/lang/de-DE.lang +72 -30
  17. package/dist/demo/assets/lang/en-US.json +1 -1
  18. package/dist/demo/assets/lang/en-US.lang +72 -28
  19. package/dist/demo/assets/lang/es-ES.json +1 -1
  20. package/dist/demo/assets/lang/es-ES.lang +73 -30
  21. package/dist/demo/assets/lang/fa-IR.json +1 -1
  22. package/dist/demo/assets/lang/fa-IR.lang +73 -30
  23. package/dist/demo/assets/lang/fi-FI.json +1 -1
  24. package/dist/demo/assets/lang/fi-FI.lang +73 -30
  25. package/dist/demo/assets/lang/fr-FR.json +1 -1
  26. package/dist/demo/assets/lang/fr-FR.lang +74 -30
  27. package/dist/demo/assets/lang/he-IL.json +1 -0
  28. package/dist/demo/assets/lang/he-IL.lang +231 -0
  29. package/dist/demo/assets/lang/hi-IN.json +1 -0
  30. package/dist/demo/assets/lang/hi-IN.json.gz +0 -0
  31. package/dist/demo/assets/lang/hi-IN.lang +229 -0
  32. package/dist/demo/assets/lang/hu-HU.json +1 -1
  33. package/dist/demo/assets/lang/hu-HU.lang +73 -30
  34. package/dist/demo/assets/lang/it-IT.json +1 -1
  35. package/dist/demo/assets/lang/it-IT.lang +72 -30
  36. package/dist/demo/assets/lang/ja-JP.json +1 -1
  37. package/dist/demo/assets/lang/ja-JP.lang +73 -31
  38. package/dist/demo/assets/lang/nb-NO.json +1 -1
  39. package/dist/demo/assets/lang/nb-NO.lang +72 -30
  40. package/dist/demo/assets/lang/pl-PL.json +1 -1
  41. package/dist/demo/assets/lang/pl-PL.lang +72 -30
  42. package/dist/demo/assets/lang/pt-BR.json +1 -1
  43. package/dist/demo/assets/lang/pt-BR.lang +73 -30
  44. package/dist/demo/assets/lang/pt-PT.json +1 -1
  45. package/dist/demo/assets/lang/pt-PT.lang +74 -30
  46. package/dist/demo/assets/lang/ro-RO.json +1 -1
  47. package/dist/demo/assets/lang/ro-RO.lang +72 -30
  48. package/dist/demo/assets/lang/ru-RU.json +1 -1
  49. package/dist/demo/assets/lang/ru-RU.lang +72 -30
  50. package/dist/demo/assets/lang/th-TH.json +1 -1
  51. package/dist/demo/assets/lang/th-TH.json.gz +0 -0
  52. package/dist/demo/assets/lang/th-TH.lang +74 -30
  53. package/dist/demo/assets/lang/tr-TR.json +1 -1
  54. package/dist/demo/assets/lang/tr-TR.lang +72 -30
  55. package/dist/demo/assets/lang/zh-CN.json +1 -1
  56. package/dist/demo/assets/lang/zh-CN.lang +72 -30
  57. package/dist/demo/assets/lang/zh-HK.json +1 -1
  58. package/dist/demo/assets/lang/zh-HK.lang +74 -30
  59. package/dist/demo/index.html +1 -1
  60. package/dist/formeo.cjs.js +3 -3
  61. package/dist/formeo.es.js +486 -219
  62. package/dist/formeo.min.css +2 -2
  63. package/dist/formeo.min.js +3 -3
  64. package/dist/formeo.umd.js +3 -3
  65. package/package.json +9 -6
package/dist/formeo.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 2.2.0
4
+ Version: 2.2.2
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -230,8 +230,207 @@ class I18N {
230
230
  }
231
231
  }
232
232
  const mi18n = new I18N();
233
+ !function() {
234
+ try {
235
+ if ("undefined" != typeof document) {
236
+ var o = document.createElement("style");
237
+ o.appendChild(document.createTextNode('._3x4ZIcu-{position:absolute;background:#1f2937;color:#fff;padding:.75rem;border-radius:.375rem;max-width:200px;z-index:50;visibility:hidden;opacity:0;transition:opacity .2s;pointer-events:none;left:0;top:0}._3x4ZIcu-.JIt36hCJ{visibility:visible;opacity:1;pointer-events:all}._3x4ZIcu-:before{content:"";position:absolute;width:0;height:0;border:6px solid transparent}._3x4ZIcu-[data-position=top]:before{border-top-color:#1f2937;bottom:-12px;left:50%;transform:translate(-50%)}._3x4ZIcu-[data-position=bottom]:before{border-bottom-color:#1f2937;top:-12px;left:50%;transform:translate(-50%)}._3x4ZIcu-[data-position=left]:before{border-left-color:#1f2937;right:-12px;top:50%;transform:translateY(-50%)}._3x4ZIcu-[data-position=right]:before{border-right-color:#1f2937;left:-12px;top:50%;transform:translateY(-50%)}._3x4ZIcu-[data-position=top-left]:before{border-top-color:#1f2937;bottom:-12px;left:12px;transform:none}._3x4ZIcu-[data-position=top-right]:before{border-top-color:#1f2937;bottom:-12px;right:12px;left:auto;transform:none}._3x4ZIcu-[data-position=bottom-left]:before{border-bottom-color:#1f2937;top:-12px;left:12px;transform:none}._3x4ZIcu-[data-position=bottom-right]:before{border-bottom-color:#1f2937;top:-12px;right:12px;left:auto;transform:none}')), document.head.appendChild(o);
238
+ }
239
+ } catch (t) {
240
+ console.error("vite-plugin-css-injected-by-js", t);
241
+ }
242
+ }();
243
+ var __defProp2 = Object.defineProperty;
244
+ var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
245
+ var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
246
+ const tooltip = "_3x4ZIcu-";
247
+ const visible = "JIt36hCJ";
248
+ const styles = {
249
+ tooltip,
250
+ visible
251
+ };
252
+ const defaultOptions$1 = {
253
+ triggerName: "tooltip"
254
+ };
255
+ class SmartTooltip {
256
+ constructor(options = defaultOptions$1) {
257
+ __publicField2(this, "triggerName");
258
+ __publicField2(this, "tooltip");
259
+ __publicField2(this, "activeTriggerType", null);
260
+ __publicField2(this, "spacing", 12);
261
+ __publicField2(this, "handleClick", (e) => {
262
+ const triggerName = this.triggerName;
263
+ const trigger = e.target.closest(`[${triggerName}][${triggerName}-type="click"]`);
264
+ if (trigger) {
265
+ if (this.isVisible()) {
266
+ this.hide();
267
+ } else {
268
+ const content = trigger.getAttribute(`${triggerName}`);
269
+ this.show(trigger, content);
270
+ this.activeTriggerType = "click";
271
+ }
272
+ } else {
273
+ this.hide();
274
+ }
275
+ });
276
+ __publicField2(this, "handleMouseOver", (e) => {
277
+ const triggerName = this.triggerName;
278
+ const trigger = e.target.closest(`[${triggerName}]`);
279
+ if (this.activeTriggerType !== "click" && (trigger == null ? void 0 : trigger.getAttribute(`${triggerName}-type`)) !== "click") {
280
+ const content = trigger == null ? void 0 : trigger.getAttribute(`${triggerName}`);
281
+ if (content) {
282
+ this.show(trigger, content);
283
+ this.activeTriggerType = "hover";
284
+ }
285
+ }
286
+ });
287
+ __publicField2(this, "handleMouseOut", (e) => {
288
+ const triggerName = this.triggerName;
289
+ const trigger = e.target.closest(`[${triggerName}]`);
290
+ if (this.activeTriggerType !== "click" && (trigger == null ? void 0 : trigger.getAttribute(`${triggerName}-type`)) !== "click") {
291
+ this.hide();
292
+ }
293
+ });
294
+ __publicField2(this, "handleResize", () => {
295
+ if (this.isVisible()) {
296
+ this.hide();
297
+ }
298
+ });
299
+ __publicField2(this, "handleScroll", () => {
300
+ if (this.isVisible()) {
301
+ this.hide();
302
+ }
303
+ });
304
+ this.triggerName = `data-${options.triggerName}`;
305
+ this.tooltip = document.createElement("div");
306
+ this.tooltip.className = `d-tooltip ${styles.tooltip}`;
307
+ document.body.appendChild(this.tooltip);
308
+ this.setupEventListeners();
309
+ }
310
+ setupEventListeners() {
311
+ document.addEventListener("mouseover", this.handleMouseOver);
312
+ document.addEventListener("mouseout", this.handleMouseOut);
313
+ document.addEventListener("click", this.handleClick);
314
+ window.addEventListener("resize", this.handleResize);
315
+ window.addEventListener("scroll", this.handleScroll, true);
316
+ }
317
+ isVisible() {
318
+ return this.tooltip.classList.contains(styles.visible);
319
+ }
320
+ /**
321
+ * Calculates the optimal position for the tooltip relative to the trigger element.
322
+ * It tries to find a position where the tooltip fits within the viewport.
323
+ * If no position fits, it defaults to the first position in the list.
324
+ *
325
+ * @param {HTMLElement} trigger - The HTML element that triggers the tooltip.
326
+ * @returns {Position} The calculated position for the tooltip.
327
+ */
328
+ calculatePosition(trigger) {
329
+ const triggerRect = trigger.getBoundingClientRect();
330
+ const tooltipRect = this.tooltip.getBoundingClientRect();
331
+ const positions = [
332
+ {
333
+ name: "top",
334
+ x: triggerRect.left + (triggerRect.width - tooltipRect.width) / 2,
335
+ y: triggerRect.top - tooltipRect.height - this.spacing
336
+ },
337
+ {
338
+ name: "bottom",
339
+ x: triggerRect.left + (triggerRect.width - tooltipRect.width) / 2,
340
+ y: triggerRect.bottom + this.spacing
341
+ },
342
+ {
343
+ name: "left",
344
+ x: triggerRect.left - tooltipRect.width - this.spacing,
345
+ y: triggerRect.top + (triggerRect.height - tooltipRect.height) / 2
346
+ },
347
+ {
348
+ name: "right",
349
+ x: triggerRect.right + this.spacing,
350
+ y: triggerRect.top + (triggerRect.height - tooltipRect.height) / 2
351
+ },
352
+ // Corner positions
353
+ {
354
+ name: "top-left",
355
+ x: triggerRect.left,
356
+ y: triggerRect.top - tooltipRect.height - this.spacing
357
+ },
358
+ {
359
+ name: "top-right",
360
+ x: triggerRect.right - tooltipRect.width,
361
+ y: triggerRect.top - tooltipRect.height - this.spacing
362
+ },
363
+ {
364
+ name: "bottom-left",
365
+ x: triggerRect.left,
366
+ y: triggerRect.bottom + this.spacing
367
+ },
368
+ {
369
+ name: "bottom-right",
370
+ x: triggerRect.right - tooltipRect.width,
371
+ y: triggerRect.bottom + this.spacing
372
+ }
373
+ ];
374
+ return positions.find((pos) => this.fitsInViewport(pos, tooltipRect)) || positions[0];
375
+ }
376
+ /**
377
+ * Checks if the tooltip fits within the viewport and is not obstructed by other elements.
378
+ *
379
+ * @param pos - The position of the tooltip.
380
+ * @param tooltipRect - The bounding rectangle of the tooltip.
381
+ * @returns `true` if the tooltip fits within the viewport and is not obstructed, otherwise `false`.
382
+ */
383
+ fitsInViewport(pos, tooltipRect) {
384
+ const inViewport = pos.x >= 0 && pos.y >= 0 && pos.x + tooltipRect.width <= window.innerWidth && pos.y + tooltipRect.height <= window.innerHeight;
385
+ if (!inViewport) return false;
386
+ const points = [
387
+ [pos.x, pos.y],
388
+ // Top-left
389
+ [pos.x + tooltipRect.width, pos.y],
390
+ // Top-right
391
+ [pos.x, pos.y + tooltipRect.height],
392
+ // Bottom-left
393
+ [pos.x + tooltipRect.width, pos.y + tooltipRect.height],
394
+ // Bottom-right
395
+ [pos.x + tooltipRect.width / 2, pos.y + tooltipRect.height / 2]
396
+ // Center
397
+ ];
398
+ const elementsAtPoints = points.flatMap(([x, y]) => Array.from(document.elementsFromPoint(x, y)));
399
+ const obstructingElements = elementsAtPoints.filter((element) => {
400
+ if (this.tooltip.contains(element) || // Exclude tooltip and its children
401
+ element === this.tooltip || element.classList.contains(styles.tooltip) || // Ignore other tooltips
402
+ getComputedStyle(element).pointerEvents === "none") {
403
+ return false;
404
+ }
405
+ });
406
+ return obstructingElements.length === 0;
407
+ }
408
+ show(trigger, content) {
409
+ this.tooltip.innerHTML = content ?? "";
410
+ this.tooltip.classList.add(styles.visible);
411
+ const position = this.calculatePosition(trigger);
412
+ this.tooltip.style.left = `${position.x}px`;
413
+ this.tooltip.style.top = `${position.y}px`;
414
+ this.tooltip.dataset.position = position.name;
415
+ }
416
+ hide() {
417
+ this.tooltip.classList.remove(styles.visible);
418
+ this.activeTriggerType = null;
419
+ }
420
+ destroy() {
421
+ document.removeEventListener("mouseover", this.handleMouseOver);
422
+ document.removeEventListener("mouseout", this.handleMouseOut);
423
+ document.removeEventListener("click", this.handleClick);
424
+ window.removeEventListener("resize", this.handleResize);
425
+ window.removeEventListener("scroll", this.handleScroll, true);
426
+ this.tooltip.remove();
427
+ }
428
+ }
429
+ if (window !== void 0) {
430
+ window.SmartTooltip = SmartTooltip;
431
+ }
233
432
  const name$1 = "formeo";
234
- const version$2 = "2.2.0";
433
+ const version$2 = "2.2.2";
235
434
  const type = "module";
236
435
  const main = "dist/formeo.cjs.js";
237
436
  const module = "dist/formeo.es.js";
@@ -302,15 +501,17 @@ const scripts = {
302
501
  "build:demo:watch": "vite build --mode demo --watch",
303
502
  "build:icons": "node ./tools/generate-sprite",
304
503
  lint: "eslint ./src --ext .js || true",
305
- test: "node --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.js",
306
- "test:updateSnapshots": "node --experimental-test-snapshots --test-update-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.js",
307
- "test:ci": "yarn test --coverage",
504
+ test: "node --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
505
+ "test:watch": "node --watch --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
506
+ "test:updateSnapshots": "node --experimental-test-snapshots --test-update-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
507
+ "test:ci": "npm test --coverage",
308
508
  start: "npm-run-all build:icons dev",
309
509
  "semantic-release": "semantic-release --ci --debug",
310
510
  "copy:lang": "node ./tools/copy-directory.mjs ./node_modules/formeo-i18n/dist/lang ./src/demo/assets/lang",
311
511
  "travis-deploy-once": "travis-deploy-once --pro",
312
- prepush: "yarn test",
313
- defaults: "webpack-defaults"
512
+ prepush: "npm test",
513
+ prepare: "lefthook install",
514
+ postmerge: "lefthook install"
314
515
  };
315
516
  const devDependencies = {
316
517
  "@biomejs/biome": "^1.9.3",
@@ -334,6 +535,7 @@ const devDependencies = {
334
535
  const dependencies = {
335
536
  "@draggable/formeo-languages": "^3.1.3",
336
537
  "@draggable/i18n": "^1.0.7",
538
+ "@draggable/tooltip": "^1.2.1",
337
539
  lodash: "^4.17.21",
338
540
  sortablejs: "^1.15.3"
339
541
  };
@@ -1501,11 +1703,17 @@ const uuid = (elem) => {
1501
1703
  }
1502
1704
  return id;
1503
1705
  };
1504
- const merge = (obj1, obj2, opts = /* @__PURE__ */ Object.create(null)) => {
1706
+ const merge = (obj1, obj2) => {
1505
1707
  const customizer = (objValue, srcValue) => {
1506
1708
  if (Array.isArray(objValue)) {
1507
- if (Array.isArray(srcValue)) {
1508
- return unique(opts.mergeArray ? objValue.concat(srcValue) : srcValue);
1709
+ if (srcValue !== void 0 && srcValue !== null) {
1710
+ return unique(objValue.concat(srcValue));
1711
+ }
1712
+ return srcValue;
1713
+ }
1714
+ if (Array.isArray(srcValue)) {
1715
+ if (objValue !== void 0 && objValue !== null) {
1716
+ return unique(srcValue.concat(objValue));
1509
1717
  }
1510
1718
  return srcValue;
1511
1719
  }
@@ -1570,17 +1778,23 @@ const sessionStorage = Object.create(null, {
1570
1778
  const isAddress = (str) => COMPONENT_INDEX_TYPES.some((indexType) => new RegExp(`^${indexType}.`).test(str));
1571
1779
  const isExternalAddress = (str) => str.startsWith("external");
1572
1780
  const isBoolKey = (key) => /^is|^has/.test(key);
1573
- function throttle$1(callback, limit) {
1574
- let wait = false;
1575
- return function() {
1576
- if (!wait) {
1577
- callback(...arguments);
1578
- wait = true;
1579
- const timeout = setTimeout(() => {
1580
- wait = false;
1581
- clearTimeout(timeout);
1582
- }, limit);
1781
+ function throttle$1(callback, limit = ANIMATION_SPEED_SLOW) {
1782
+ let lastCall = 0;
1783
+ return function(...args) {
1784
+ const now = Date.now();
1785
+ if (now - lastCall >= limit) {
1786
+ lastCall = now;
1787
+ callback.apply(this, args);
1788
+ }
1789
+ };
1790
+ }
1791
+ function debounce(fn, delay = ANIMATION_SPEED_BASE) {
1792
+ let timeoutID;
1793
+ return function(...args) {
1794
+ if (timeoutID) {
1795
+ clearTimeout(timeoutID);
1583
1796
  }
1797
+ timeoutID = setTimeout(() => fn.apply(this, args), delay);
1584
1798
  };
1585
1799
  }
1586
1800
  function identity(value) {
@@ -1803,7 +2017,7 @@ const safeAttrName = (name2) => {
1803
2017
  return sanitizedAttributeNames[name2];
1804
2018
  }
1805
2019
  const attributeName = attributeMap[name2] || name2;
1806
- const sanitizedAttributeName = attributeName.replace(/^\d/, "").replace(/[^a-zA-Z0-9-:]/g, "");
2020
+ const sanitizedAttributeName = attributeName.replace(/^\d+/, "").replace(/[^a-zA-Z0-9-:]/g, "");
1807
2021
  sanitizedAttributeNames[name2] = sanitizedAttributeName;
1808
2022
  return sanitizedAttributeName;
1809
2023
  };
@@ -1928,12 +2142,30 @@ const defaults$3 = {
1928
2142
  },
1929
2143
  onAdd: () => {
1930
2144
  },
1931
- onUpdate: (evt) => events.opts.debug && console.log(evt),
1932
- onUpdateStage: (evt) => events.opts.debug && console.log(evt),
1933
- onUpdateRow: (evt) => events.opts.debug && console.log(evt),
1934
- onUpdateColumn: (evt) => events.opts.debug && console.log(evt),
1935
- onUpdateField: (evt) => events.opts.debug && console.log(evt),
1936
- onRender: (evt) => events.opts.debug && console.log(evt),
2145
+ onUpdate: (evt) => {
2146
+ var _a;
2147
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2148
+ },
2149
+ onUpdateStage: (evt) => {
2150
+ var _a;
2151
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2152
+ },
2153
+ onUpdateRow: (evt) => {
2154
+ var _a;
2155
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2156
+ },
2157
+ onUpdateColumn: (evt) => {
2158
+ var _a;
2159
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2160
+ },
2161
+ onUpdateField: (evt) => {
2162
+ var _a;
2163
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2164
+ },
2165
+ onRender: (evt) => {
2166
+ var _a;
2167
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2168
+ },
1937
2169
  onSave: (evt) => {
1938
2170
  },
1939
2171
  confirmClearAll: (evt) => {
@@ -1943,9 +2175,10 @@ const defaults$3 = {
1943
2175
  }
1944
2176
  };
1945
2177
  const defaultCustomEvent = ({ src, ...evtData }, type2 = EVENT_FORMEO_UPDATED) => {
2178
+ var _a, _b;
1946
2179
  const evt = new window.CustomEvent(type2, {
1947
2180
  detail: evtData,
1948
- bubbles: events.opts.debug || events.opts.bubbles
2181
+ bubbles: ((_a = events.opts) == null ? void 0 : _a.debug) || ((_b = events.opts) == null ? void 0 : _b.bubbles)
1949
2182
  });
1950
2183
  evt.data = (src || document).dispatchEvent(evt);
1951
2184
  return evt;
@@ -2034,12 +2267,12 @@ let throttling;
2034
2267
  function onResizeWindow() {
2035
2268
  throttling = throttling || window.requestAnimationFrame(() => {
2036
2269
  throttling = false;
2037
- Object.values(Columns2.data).forEach((column) => {
2270
+ for (const column of Object.values(Columns2.data)) {
2038
2271
  column.dom.classList.add(NO_TRANSITION_CLASS_NAME);
2039
2272
  Controls2.dom.classList.add(NO_TRANSITION_CLASS_NAME);
2040
2273
  Controls2.panels.nav.refresh();
2041
2274
  column.refreshFieldPanels();
2042
- });
2275
+ }
2043
2276
  });
2044
2277
  }
2045
2278
  window.addEventListener("resize", onResizeWindow);
@@ -2774,11 +3007,11 @@ function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoS
2774
3007
  function isScrolledPast(el, elSide, parentSide) {
2775
3008
  var parent = getParentAutoScrollElement(el, true), elSideVal = getRect(el)[elSide];
2776
3009
  while (parent) {
2777
- var parentSideVal = getRect(parent)[parentSide], visible = void 0;
3010
+ var parentSideVal = getRect(parent)[parentSide], visible2 = void 0;
2778
3011
  {
2779
- visible = elSideVal >= parentSideVal;
3012
+ visible2 = elSideVal >= parentSideVal;
2780
3013
  }
2781
- if (!visible) return parent;
3014
+ if (!visible2) return parent;
2782
3015
  if (parent === getWindowScrollingElement()) break;
2783
3016
  parent = getParentAutoScrollElement(parent, false);
2784
3017
  }
@@ -5018,7 +5251,10 @@ const BASE_NAME = "f-autocomplete";
5018
5251
  const HIGHLIGHT_CLASS_NAME = "highlight-component";
5019
5252
  let lastCache = Date.now();
5020
5253
  let optionsCache;
5021
- const labelCount = (arr, label) => arr.reduce((n, x) => n + (x === label), 0);
5254
+ const labelCount = (arr, label) => {
5255
+ const count = arr.reduce((n, x) => n + (x === label), 0);
5256
+ return count > 1 ? `(${count})` : "";
5257
+ };
5022
5258
  const getComponentLabel = ({ name: name2, id, ...component }) => {
5023
5259
  const labelPaths = ["config.label", "attrs.id", "meta.id"];
5024
5260
  const label = labelPaths.reduce((acc, cur) => {
@@ -5030,13 +5266,24 @@ const getComponentLabel = ({ name: name2, id, ...component }) => {
5030
5266
  const externalLabel = (...externalAddress) => mi18n.get(externalAddress.join(".")) || toTitleCase(externalAddress.join(" "));
5031
5267
  return label || name2 === "external" && externalLabel(name2, id);
5032
5268
  };
5033
- const componentOptions = (selected) => {
5269
+ const makeOption = ({ id, textLabel, htmlLabel, selectedId }) => {
5270
+ const option2 = {
5271
+ value: id,
5272
+ textLabel,
5273
+ htmlLabel
5274
+ };
5275
+ if (id === selectedId) {
5276
+ option2.selected = true;
5277
+ }
5278
+ return option2;
5279
+ };
5280
+ const componentOptions = (selectedId) => {
5034
5281
  const labels = [];
5035
5282
  const flatList = components.flatList();
5036
5283
  const options = Object.entries(flatList).map(([id, component]) => {
5037
5284
  const label = getComponentLabel(component);
5038
5285
  if (label) {
5039
- const type2 = {
5286
+ const typeConfig = {
5040
5287
  tag: "span",
5041
5288
  content: ` ${toTitleCase(component.name)}`,
5042
5289
  className: "component-type"
@@ -5046,10 +5293,12 @@ const componentOptions = (selected) => {
5046
5293
  const count = labelCount(labels, labelKey);
5047
5294
  const countConfig = {
5048
5295
  tag: "span",
5049
- content: count > 1 && `(${count})`,
5296
+ content: count,
5050
5297
  className: "component-label-count"
5051
5298
  };
5052
- return dom.makeOption([id, [`${label} `, countConfig, type2]], selected);
5299
+ const htmlLabel = [`${label} `, countConfig, typeConfig];
5300
+ const textLabel = [label, count].join(" ").trim();
5301
+ return makeOption({ id, textLabel, htmlLabel, selectedId });
5053
5302
  }
5054
5303
  });
5055
5304
  return options.filter(Boolean);
@@ -5147,9 +5396,9 @@ class Autocomplete {
5147
5396
  const activeOption = this.getActiveOption() || filteredOptions[0];
5148
5397
  this.showList(activeOption);
5149
5398
  }
5150
- this.hiddenField.value = evt.target.value;
5151
- this.value = evt.target.value;
5152
- this.runEvent("onChange", { target: this.hiddenField });
5399
+ const value = evt.target.value.trim();
5400
+ this.hiddenField.value = value;
5401
+ this.value = value;
5153
5402
  }
5154
5403
  };
5155
5404
  this.displayField = dom.create({
@@ -5195,7 +5444,9 @@ class Autocomplete {
5195
5444
  lastCache = now;
5196
5445
  }
5197
5446
  const options = optionsCache || this.generateOptions();
5198
- options.forEach((option2) => this.list.appendChild(option2));
5447
+ for (const option2 of options) {
5448
+ this.list.appendChild(option2);
5449
+ }
5199
5450
  }
5200
5451
  generateOptions() {
5201
5452
  const options = componentOptions();
@@ -5207,15 +5458,13 @@ class Autocomplete {
5207
5458
  return target;
5208
5459
  };
5209
5460
  optionsCache = options.map((optionData) => {
5210
- const value = optionData.value;
5211
- let [label] = optionData.label;
5212
- label = label.trim();
5461
+ const { value, textLabel, htmlLabel } = optionData;
5213
5462
  const optionConfig = {
5214
5463
  tag: "li",
5215
- children: optionData.label,
5464
+ children: htmlLabel,
5216
5465
  dataset: {
5217
5466
  value,
5218
- label
5467
+ label: textLabel
5219
5468
  },
5220
5469
  className: `${BASE_NAME}-list-item`,
5221
5470
  action: {
@@ -5296,15 +5545,16 @@ class Autocomplete {
5296
5545
  * @param {Object} selectedOption - option - 'li' element - to be selected in autocomplete list
5297
5546
  */
5298
5547
  selectOption(selectedOption, list = this.list) {
5548
+ var _a;
5299
5549
  const options = list.querySelectorAll("li");
5300
- for (let i = 0; i < options.length; i++) {
5550
+ for (const option2 of options) {
5301
5551
  const {
5302
5552
  dataset: { value }
5303
- } = options[i];
5304
- options[i].classList.remove("active-option");
5553
+ } = option2;
5554
+ option2.classList.remove("active-option");
5305
5555
  if (value) {
5306
5556
  const component = components.getAddress(value);
5307
- component.dom && component.dom.classList.remove(HIGHLIGHT_CLASS_NAME);
5557
+ (_a = component.dom) == null ? void 0 : _a.classList.remove(HIGHLIGHT_CLASS_NAME);
5308
5558
  }
5309
5559
  }
5310
5560
  if (selectedOption) {
@@ -5317,20 +5567,21 @@ class Autocomplete {
5317
5567
  */
5318
5568
  removeHighlight() {
5319
5569
  const highlightedComponents = document.getElementsByClassName(HIGHLIGHT_CLASS_NAME);
5320
- for (let i = 0; i < highlightedComponents.length; i++) {
5321
- highlightedComponents[i].classList.remove(HIGHLIGHT_CLASS_NAME);
5570
+ for (const component of highlightedComponents) {
5571
+ component.classList.remove(HIGHLIGHT_CLASS_NAME);
5322
5572
  }
5323
5573
  }
5324
5574
  /**
5325
5575
  * Highlight a component that maps to the option
5326
5576
  */
5327
5577
  highlightComponent(option2) {
5578
+ var _a;
5328
5579
  const {
5329
5580
  dataset: { value }
5330
5581
  } = option2;
5331
5582
  if (value) {
5332
5583
  const component = components.getAddress(value);
5333
- component.dom && component.dom.classList.add(HIGHLIGHT_CLASS_NAME);
5584
+ (_a = component.dom) == null ? void 0 : _a.classList.add(HIGHLIGHT_CLASS_NAME);
5334
5585
  }
5335
5586
  }
5336
5587
  /**
@@ -5359,11 +5610,11 @@ class Autocomplete {
5359
5610
  this.events.push([key, event]);
5360
5611
  }
5361
5612
  runEvent(eventName, evt) {
5362
- this.events.forEach(([key, event]) => {
5613
+ for (const [key, event] of this.events) {
5363
5614
  if (key === eventName) {
5364
5615
  event(evt);
5365
5616
  }
5366
- });
5617
+ }
5367
5618
  }
5368
5619
  }
5369
5620
  const getOptionData = (key) => {
@@ -5400,7 +5651,9 @@ const createOptions = (fieldVal, selected) => {
5400
5651
  };
5401
5652
  const addOptions = (select, options) => {
5402
5653
  dom.empty(select);
5403
- options.forEach((option2) => select.add(option2));
5654
+ for (const option2 of options) {
5655
+ select.add(option2);
5656
+ }
5404
5657
  };
5405
5658
  const inputConfigBase = ({ key, value, type: type2 = "text", checked }) => {
5406
5659
  const config2 = {
@@ -5446,7 +5699,6 @@ const ITEM_INPUT_TYPE_MAP = {
5446
5699
  },
5447
5700
  object: (val) => {
5448
5701
  return Object.entries(val).map(([key, val2]) => {
5449
- console.log(dom.childType(val2));
5450
5702
  return ITEM_INPUT_TYPE_MAP[dom.childType(val2)](key, val2);
5451
5703
  });
5452
5704
  }
@@ -5463,7 +5715,6 @@ const INPUT_TYPE_ACTION = {
5463
5715
  );
5464
5716
  }
5465
5717
  field.set(dataKey, checked);
5466
- field.updatePreview();
5467
5718
  }
5468
5719
  }),
5469
5720
  string: (dataKey, field) => ({
@@ -5474,13 +5725,11 @@ const INPUT_TYPE_ACTION = {
5474
5725
  number: (dataKey, field) => ({
5475
5726
  input: ({ target: { value } }) => {
5476
5727
  field.set(dataKey, Number(value));
5477
- field.updatePreview();
5478
5728
  }
5479
5729
  }),
5480
5730
  array: (dataKey, field) => ({
5481
5731
  change: ({ target: { value } }) => {
5482
5732
  field.set(dataKey, value);
5483
- field.updatePreview();
5484
5733
  }
5485
5734
  }),
5486
5735
  object: () => ({})
@@ -5590,12 +5839,12 @@ class EditPanelItem {
5590
5839
  }
5591
5840
  ]
5592
5841
  ]);
5593
- fields2.forEach((field) => {
5842
+ for (const field of fields2) {
5594
5843
  const action = actions2.get(field.className);
5595
5844
  if (action) {
5596
5845
  action(field);
5597
5846
  }
5598
- });
5847
+ }
5599
5848
  });
5600
5849
  __publicField(this, "conditionInput", (key, val, conditionType, i) => {
5601
5850
  const field = this.field;
@@ -5604,7 +5853,7 @@ class EditPanelItem {
5604
5853
  const dataPath = `${field.name}s.${conditionAddress}.${key}`;
5605
5854
  const createConditionSelect = (key2, propertyValue, i18nKey) => {
5606
5855
  const options = createOptions(i18nKey || key2, propertyValue);
5607
- const propertyFieldConfig = ITEM_INPUT_TYPE_MAP["array"](`condition.${key2}`);
5856
+ const propertyFieldConfig = ITEM_INPUT_TYPE_MAP.array(`condition.${key2}`);
5608
5857
  propertyFieldConfig.action = {
5609
5858
  change: conditionChangeAction,
5610
5859
  onRender: (elem) => conditionChangeAction({ target: elem })
@@ -5633,7 +5882,7 @@ class EditPanelItem {
5633
5882
  comparison: (value) => createConditionSelect("comparison", value),
5634
5883
  logical: (value) => createConditionSelect("logical", value),
5635
5884
  source: (value, type2 = "source") => {
5636
- const componentInput = ITEM_INPUT_TYPE_MAP["autocomplete"](`condition.${type2}`, value, conditionType);
5885
+ const componentInput = ITEM_INPUT_TYPE_MAP.autocomplete(`condition.${type2}`, value, conditionType);
5637
5886
  components.setConditionMap(value, field);
5638
5887
  componentInput.addEvent("onChange", (evt) => {
5639
5888
  components.removeConditionMap(components.getAddress(dataPath));
@@ -5646,7 +5895,7 @@ class EditPanelItem {
5646
5895
  targetProperty: (value) => createConditionSelect("targetProperty", value, "field.property"),
5647
5896
  target: (value) => segmentTypes.source(value, "target"),
5648
5897
  value: (value) => {
5649
- const valueField = ITEM_INPUT_TYPE_MAP["string"]("condition.value", value);
5898
+ const valueField = ITEM_INPUT_TYPE_MAP.string("condition.value", value);
5650
5899
  valueField.action = {
5651
5900
  input: conditionChangeAction
5652
5901
  };
@@ -5727,14 +5976,14 @@ class EditPanelItem {
5727
5976
  const valType = dom.childType(val) || "string";
5728
5977
  const inputTypeConfig = { ...{ config: {}, attrs: {} }, ...ITEM_INPUT_TYPE_MAP[valType](key, val) };
5729
5978
  const dataKey = this.itemKey.replace(/.\d+$/, (index2) => `${index2}.${key}`);
5730
- const labelKey = dataKey.split(".").filter(Number.isNaN).join(".");
5979
+ const labelKey = dataKey.split(".").filter(Number.isNaN).join(".") || key;
5731
5980
  const [id, name2] = [[...this.itemKey.split("."), key], [key]].map(
5732
5981
  (attrVars) => [this.field.id, ...attrVars].filter(Boolean).join("-")
5733
5982
  );
5734
5983
  inputTypeConfig.config = {
5735
5984
  ...inputTypeConfig.config,
5736
5985
  ...{
5737
- label: this.panelName !== "options" && labelHelper(labelKey),
5986
+ label: this.panelName !== "options" && (labelHelper(labelKey) || toTitleCase(labelKey)),
5738
5987
  labelAfter: false
5739
5988
  }
5740
5989
  };
@@ -5960,10 +6209,10 @@ class Component extends Data {
5960
6209
  tag: "span",
5961
6210
  className: ["component-tag", `${this.name}-tag`],
5962
6211
  children: [
5963
- (this.isColumn || this.isField) && dom.icon("component-corner", ["bottom-left"]),
6212
+ (this.isColumn || this.isField) && dom.icon("component-corner", { className: "bottom-left" }),
5964
6213
  dom.icon(`handle-${this.name}`),
5965
6214
  toTitleCase(this.name),
5966
- (this.isColumn || this.isRow) && dom.icon("component-corner", ["bottom-right"])
6215
+ (this.isColumn || this.isRow) && dom.icon("component-corner", { className: "bottom-right" })
5967
6216
  ].filter(Boolean)
5968
6217
  });
5969
6218
  });
@@ -6094,7 +6343,7 @@ class Component extends Data {
6094
6343
  this.config = components[`${this.name}s`].config;
6095
6344
  merge(this.config, data.config);
6096
6345
  this.dataPath = `${this.name}s.${this.id}.`;
6097
- this.observer = new MutationObserver(this.mutationHandler);
6346
+ this.observer = new window.MutationObserver(this.mutationHandler);
6098
6347
  this.render = render;
6099
6348
  }
6100
6349
  observe(container) {
@@ -6126,7 +6375,7 @@ class Component extends Data {
6126
6375
  return {
6127
6376
  className: [`${this.name}-actions`, "group-actions"],
6128
6377
  action: {
6129
- mouseenter: ({ target }) => {
6378
+ mouseenter: () => {
6130
6379
  components.stages.active.dom.classList.add(`active-hover-${this.name}`);
6131
6380
  this.dom.classList.add(...hoverClassnames);
6132
6381
  },
@@ -6473,23 +6722,20 @@ class Field extends Component {
6473
6722
  /**
6474
6723
  * Updates the conditions panel when linked field data changes
6475
6724
  */
6476
- __publicField(this, "updateConditionsPanel", () => {
6477
- const updateConditionsTimeout = setTimeout(() => {
6478
- const newConditionsPanel = this.editPanels.find(({ name: name2 }) => name2 === "conditions");
6479
- if (!newConditionsPanel) {
6480
- return null;
6481
- }
6482
- const newProps = newConditionsPanel.createProps();
6483
- const currentConditionsProps = this.dom.querySelector(".field-edit-conditions");
6484
- currentConditionsProps.parentElement.replaceChild(newProps, currentConditionsProps);
6485
- clearTimeout(updateConditionsTimeout);
6486
- }, ANIMATION_SPEED_BASE);
6487
- });
6725
+ __publicField(this, "updateConditionsPanel", throttle$1(() => {
6726
+ const newConditionsPanel = this.editPanels.find(({ name: name2 }) => name2 === "conditions");
6727
+ if (!newConditionsPanel) {
6728
+ return null;
6729
+ }
6730
+ const newProps = newConditionsPanel.createProps();
6731
+ const currentConditionsProps = this.dom.querySelector(".field-edit-conditions");
6732
+ currentConditionsProps.parentElement.replaceChild(newProps, currentConditionsProps);
6733
+ }, ANIMATION_SPEED_BASE));
6488
6734
  /**
6489
6735
  * Updates a field's preview
6490
6736
  * @return {Object} fresh preview
6491
6737
  */
6492
- __publicField(this, "updatePreview", throttle$1(() => {
6738
+ __publicField(this, "updatePreview", () => {
6493
6739
  if (!this.preview.parentElement) {
6494
6740
  return null;
6495
6741
  }
@@ -6497,7 +6743,44 @@ class Field extends Component {
6497
6743
  const newPreview = dom.create(this.fieldPreview(), true);
6498
6744
  this.preview.parentElement.replaceChild(newPreview, this.preview);
6499
6745
  this.preview = newPreview;
6500
- }, ANIMATION_SPEED_BASE));
6746
+ });
6747
+ __publicField(this, "updateEditPanels", () => {
6748
+ this.editPanels = [];
6749
+ const editable = ["object", "array"];
6750
+ const panelOrder = unique([...this.config.panels.order, ...Object.keys(this.data)]);
6751
+ const noPanels = ["config", "meta", "action", "events", ...this.config.panels.disabled];
6752
+ const allowedPanels = panelOrder.filter((panelName) => !noPanels.includes(panelName));
6753
+ for (const panelName of allowedPanels) {
6754
+ const panelData = this.get(panelName);
6755
+ const propType = dom.childType(panelData);
6756
+ if (editable.includes(propType)) {
6757
+ const editPanel = new EditPanel(panelData, panelName, this);
6758
+ this.editPanels.push(editPanel);
6759
+ }
6760
+ }
6761
+ const panelsData = {
6762
+ panels: this.editPanels.map(({ panelConfig }) => panelConfig),
6763
+ id: this.id,
6764
+ displayType: "auto"
6765
+ };
6766
+ this.panels = new Panels(panelsData);
6767
+ if (this.dom) {
6768
+ this.dom.querySelector(".panel-nav").replaceWith(this.panels.panelNav);
6769
+ this.dom.querySelector(".panels").replaceWith(this.panels.panelsWrap);
6770
+ }
6771
+ });
6772
+ __publicField(this, "toggleCheckedOptions", (optionIndex, type2) => {
6773
+ const updatedOptionData = this.get("options").map((option2, index2) => {
6774
+ const isCurrentIndex = index2 === optionIndex;
6775
+ if (type2 === "radio") {
6776
+ option2.selected = isCurrentIndex;
6777
+ } else {
6778
+ option2.checked = isCurrentIndex ? !option2.checked : option2.checked;
6779
+ }
6780
+ return option2;
6781
+ });
6782
+ this.set("options", updatedOptionData);
6783
+ });
6501
6784
  /**
6502
6785
  * Checks if attribute is allowed to be edited
6503
6786
  * @param {String} propName
@@ -6524,6 +6807,7 @@ class Field extends Component {
6524
6807
  const lockedAttrs = propKind.locked.concat(this.get(`config.locked${toTitleCase(kind)}`));
6525
6808
  return lockedAttrs.includes(propName);
6526
6809
  });
6810
+ this.debouncedUpdateEditPanels = debounce(this.updateEditPanels);
6527
6811
  this.label = dom.create(this.labelConfig);
6528
6812
  this.preview = dom.create({});
6529
6813
  this.editPanels = [];
@@ -6642,65 +6926,42 @@ class Field extends Component {
6642
6926
  * @return {Object} fieldEdit element config
6643
6927
  */
6644
6928
  get fieldEdit() {
6645
- this.editPanels = [];
6646
- const editable = ["object", "array"];
6647
- const noPanels = ["config", "meta", "action", "events", ...this.config.panels.disabled];
6648
- const panelOrder = unique([...this.config.panels.order, ...Object.keys(this.data)]);
6649
- const allowedPanels = panelOrder.filter((panelName) => !noPanels.includes(panelName));
6650
6929
  const fieldEdit = {
6651
6930
  className: ["field-edit", "slide-toggle", "formeo-panels-wrap"]
6652
6931
  };
6653
- for (const panelName of allowedPanels) {
6654
- const panelData = this.get(panelName);
6655
- const propType = dom.childType(panelData);
6656
- if (editable.includes(propType)) {
6657
- const editPanel = new EditPanel(panelData, panelName, this);
6658
- this.editPanels.push(editPanel);
6659
- }
6660
- }
6661
- const panelsData = {
6662
- panels: this.editPanels.map(({ panelConfig }) => panelConfig),
6663
- id: this.id,
6664
- displayType: "auto"
6665
- };
6932
+ this.updateEditPanels();
6666
6933
  const editPanelLength = this.editPanels.length;
6667
6934
  if (editPanelLength) {
6668
- this.panels = new Panels(panelsData);
6669
6935
  fieldEdit.className.push(`panel-count-${editPanelLength}`);
6670
6936
  fieldEdit.content = [this.panels.panelNav, this.panels.panelsWrap];
6671
6937
  this.panelNav = this.panels.nav;
6672
6938
  this.resizePanelWrap = this.panels.nav.refresh;
6673
- fieldEdit.action = {
6674
- onRender: () => {
6939
+ }
6940
+ fieldEdit.action = {
6941
+ onRender: () => {
6942
+ if (editPanelLength === 0) {
6943
+ const field = this.dom;
6944
+ const editToggle = field.querySelector(".item-edit-toggle");
6945
+ const fieldActions = field.querySelector(".field-actions");
6946
+ const actionButtons = fieldActions.getElementsByTagName("button");
6947
+ fieldActions.style.maxWidth = `${actionButtons.length * actionButtons[0].clientWidth}px`;
6948
+ dom.remove(editToggle);
6949
+ } else {
6675
6950
  this.resizePanelWrap();
6676
- if (!editPanelLength) {
6677
- const field = this.dom;
6678
- const editToggle = field.querySelector(".item-edit-toggle");
6679
- const fieldActions = field.querySelector(".field-actions");
6680
- const actionButtons = fieldActions.getElementsByTagName("button");
6681
- fieldActions.style.maxWidth = `${actionButtons.length * actionButtons[0].clientWidth}px`;
6682
- dom.remove(editToggle);
6683
- }
6684
6951
  }
6685
- };
6686
- }
6687
- return fieldEdit;
6952
+ }
6953
+ };
6954
+ return dom.create(fieldEdit);
6688
6955
  }
6689
6956
  get defaultPreviewActions() {
6690
6957
  return {
6691
6958
  change: (evt) => {
6692
6959
  const { target } = evt;
6693
- const { checked, type: type2 } = target;
6960
+ const { type: type2 } = target;
6694
6961
  if (["checkbox", "radio"].includes(type2)) {
6695
6962
  const optionIndex = +target.id.split("-").pop();
6696
- if (type2 === "radio") {
6697
- this.set(
6698
- "options",
6699
- this.get("options").map((option2) => ({ ...option2, selected: false }))
6700
- );
6701
- }
6702
- const checkType = type2 === "checkbox" ? "checked" : "selected";
6703
- this.set(`options.${optionIndex}.${checkType}`, checked);
6963
+ this.toggleCheckedOptions(optionIndex, type2);
6964
+ this.debouncedUpdateEditPanels();
6704
6965
  }
6705
6966
  },
6706
6967
  click: (evt) => {
@@ -6709,10 +6970,20 @@ class Field extends Component {
6709
6970
  }
6710
6971
  },
6711
6972
  input: (evt) => {
6712
- if (["input", "meter", "progress", "button"].includes(this.data.tag)) {
6973
+ if (["input", "meter", "progress", "button"].includes(evt.target.tagName.toLowerCase())) {
6713
6974
  super.set("attrs.value", evt.target.value);
6975
+ return this.debouncedUpdateEditPanels();
6714
6976
  }
6715
6977
  if (evt.target.contentEditable) {
6978
+ const parentClassList = evt.target.parentElement.classList;
6979
+ const isOption = parentClassList.contains("f-checkbox") || parentClassList.contains("f-radio");
6980
+ if (isOption) {
6981
+ const option2 = evt.target.parentElement;
6982
+ const optionWrap = option2.parentElement;
6983
+ const optionIndex = indexOfNode(option2, optionWrap);
6984
+ super.set(`options[${optionIndex}].label`, evt.target.innerHTML);
6985
+ return this.debouncedUpdateEditPanels();
6986
+ }
6716
6987
  super.set("content", evt.target.innerHTML);
6717
6988
  }
6718
6989
  }
@@ -7528,7 +7799,7 @@ let Controls$1 = class Controls {
7528
7799
  return controlConfig;
7529
7800
  }
7530
7801
  get(controlId) {
7531
- return this.data.get(controlId);
7802
+ return clone$1(this.data.get(controlId));
7532
7803
  }
7533
7804
  /**
7534
7805
  * Generate the DOM config for form actions like settings, save and clear
@@ -7977,13 +8248,25 @@ class Row extends Component {
7977
8248
  description: mi18n.get("row.makeInputGroupDesc")
7978
8249
  }
7979
8250
  };
8251
+ const rowTitleTooltip = {
8252
+ tag: "span",
8253
+ content: " ⓘ",
8254
+ dataset: {
8255
+ tooltip: "Row title will be used as the legend for the fieldset"
8256
+ }
8257
+ };
7980
8258
  const legendInput = {
7981
8259
  tag: "input",
7982
8260
  attrs: {
7983
8261
  type: "text",
7984
8262
  ariaLabel: "Legend for fieldset",
7985
8263
  value: this.get("config.legend"),
7986
- placeholder: "Legend"
8264
+ placeholder: "Title"
8265
+ },
8266
+ config: {
8267
+ label: {
8268
+ children: ["Row Title", rowTitleTooltip]
8269
+ }
7987
8270
  },
7988
8271
  action: {
7989
8272
  input: ({ target: { value } }) => this.set("config.legend", value)
@@ -8309,7 +8592,6 @@ class Column extends Component {
8309
8592
  this.dom.style.width = width;
8310
8593
  return this.set("config.width", width);
8311
8594
  });
8312
- const _this = this;
8313
8595
  const children = this.createChildWrap();
8314
8596
  this.dom = dom.create({
8315
8597
  tag: "li",
@@ -8330,7 +8612,7 @@ class Column extends Component {
8330
8612
  events.columnResized = new window.CustomEvent("columnResized", {
8331
8613
  detail: {
8332
8614
  column: this.dom,
8333
- instance: _this
8615
+ instance: this
8334
8616
  }
8335
8617
  });
8336
8618
  Sortable.create(children, {
@@ -8563,12 +8845,13 @@ const iconFontTemplates = {
8563
8845
  },
8564
8846
  fontello: (icon) => `<i class="${iconPrefix}${icon}">${icon}</i>`
8565
8847
  };
8848
+ const inputTags = /* @__PURE__ */ new Set(["input", "textarea", "select"]);
8566
8849
  class DOM {
8567
8850
  /**
8568
8851
  * Set defaults, store references to key elements
8569
8852
  * like stages, rows, columns etc
8570
8853
  */
8571
- constructor() {
8854
+ constructor(options = /* @__PURE__ */ Object.create(null)) {
8572
8855
  /**
8573
8856
  * Wraps dom.create to modify data
8574
8857
  * Used when rendering components in form- not editor
@@ -8584,15 +8867,15 @@ class DOM {
8584
8867
  * @return {Object} DOM Object
8585
8868
  */
8586
8869
  __publicField(this, "create", (elemArg, isPreview = false) => {
8587
- let elem = elemArg;
8588
- if (!elem) {
8870
+ if (!elemArg) {
8589
8871
  return;
8590
8872
  }
8591
- elem = this.processTagName(elem);
8592
8873
  const _this = this;
8874
+ const processed = ["children", "content"];
8875
+ const { className, options, dataset, ...elem } = this.processTagName(elemArg);
8876
+ processed.push("tag");
8593
8877
  let childType;
8594
8878
  const { tag } = elem;
8595
- const processed = ["children", "content"];
8596
8879
  let i;
8597
8880
  const wrap = {
8598
8881
  attrs: {},
@@ -8628,36 +8911,26 @@ class DOM {
8628
8911
  undefined: () => null,
8629
8912
  boolean: () => null
8630
8913
  };
8631
- processed.push("tag");
8632
- if (elem.className) {
8633
- const { className } = elem;
8634
- elem.attrs = Object.assign({}, elem.attrs, { className });
8635
- delete elem.className;
8636
- }
8637
- if (elem.options) {
8638
- let { options } = elem;
8639
- options = this.processOptions(options, elem, isPreview);
8914
+ if (className) {
8915
+ elem.attrs = merge(elem.attrs, { className });
8916
+ }
8917
+ if (options) {
8918
+ const processedOptions = this.processOptions(options, elem, isPreview);
8640
8919
  if (this.holdsContent(element) && tag !== "button") {
8641
- appendChildren.array.call(this, options);
8642
- delete elem.content;
8920
+ appendChildren.array.call(this, processedOptions);
8921
+ elem.content = void 0;
8643
8922
  } else {
8644
- helpers.forEach(options, (option2) => {
8923
+ helpers.forEach(processedOptions, (option2) => {
8645
8924
  wrap.children.push(_this.create(option2, isPreview));
8646
8925
  });
8647
8926
  if (elem.attrs.className) {
8648
8927
  wrap.className = elem.attrs.className;
8649
8928
  }
8650
- wrap.config = Object.assign({}, elem.config);
8929
+ wrap.config = { ...elem.config };
8651
8930
  return this.create(wrap, isPreview);
8652
8931
  }
8653
8932
  processed.push("options");
8654
8933
  }
8655
- if (element.tagName === "OPTION") {
8656
- const timeout = setTimeout(() => {
8657
- element.selected = false;
8658
- clearTimeout(timeout);
8659
- }, 0);
8660
- }
8661
8934
  if (elem.attrs) {
8662
8935
  _this.processAttrs(elem, element, isPreview);
8663
8936
  processed.push("attrs");
@@ -8666,7 +8939,10 @@ class DOM {
8666
8939
  if (elem.config.label && (elem.config.label && tag !== "button" || ["radio", "checkbox"].includes(helpers.get(elem, "attrs.type"))) && !isPreview) {
8667
8940
  const label = _this.label(elem);
8668
8941
  if (!elem.config.hideLabel) {
8669
- const wrapContent = [..._this.labelAfter(elem) ? [element, label] : [label, element]];
8942
+ const wrapContent = [label, element];
8943
+ if (_this.labelAfter(elem)) {
8944
+ wrapContent.reverse();
8945
+ }
8670
8946
  wrap.children.push(wrapContent);
8671
8947
  }
8672
8948
  }
@@ -8680,10 +8956,10 @@ class DOM {
8680
8956
  }
8681
8957
  appendChildren[childType].call(this, children);
8682
8958
  }
8683
- if (elem.dataset) {
8684
- for (const data in elem.dataset) {
8685
- if (Object.hasOwn(elem.dataset, data)) {
8686
- element.dataset[data] = typeof elem.dataset[data] === "function" ? elem.dataset[data]() : elem.dataset[data];
8959
+ if (dataset) {
8960
+ for (const data in dataset) {
8961
+ if (Object.hasOwn(dataset, data)) {
8962
+ element.dataset[data] = typeof dataset[data] === "function" ? dataset[data]() : dataset[data];
8687
8963
  }
8688
8964
  }
8689
8965
  processed.push("dataset");
@@ -8754,16 +9030,6 @@ class DOM {
8754
9030
  }
8755
9031
  };
8756
9032
  });
8757
- __publicField(this, "makeOption", ([value, label], selected, i18nKey) => {
8758
- const option2 = {
8759
- value,
8760
- label: mi18n.get(`${i18nKey}.${label}`) || label
8761
- };
8762
- if (value === selected) {
8763
- option2.selected = true;
8764
- }
8765
- return option2;
8766
- });
8767
9033
  __publicField(this, "requiredMark", () => ({
8768
9034
  tag: "span",
8769
9035
  className: "text-error",
@@ -8782,9 +9048,8 @@ class DOM {
8782
9048
  if (!children.length) {
8783
9049
  if (!this.isStage(parent)) {
8784
9050
  return this.removeEmpty(parent);
8785
- } else {
8786
- this.emptyClass(parent);
8787
9051
  }
9052
+ return this.emptyClass(parent);
8788
9053
  }
8789
9054
  });
8790
9055
  __publicField(this, "btnTemplate", ({ title = "", ...rest }) => ({
@@ -8801,29 +9066,23 @@ class DOM {
8801
9066
  __publicField(this, "isColumn", (node) => componentType(node) === COLUMN_CLASSNAME);
8802
9067
  __publicField(this, "isField", (node) => componentType(node) === FIELD_CLASSNAME);
8803
9068
  __publicField(this, "asComponent", (elem) => components[`${componentType(elem)}s`].get(elem.id));
8804
- this.options = /* @__PURE__ */ Object.create(null);
8805
- this.styleSheet = (() => {
8806
- const style = document.createElement("style");
8807
- style.setAttribute("media", "screen");
8808
- style.setAttribute("type", "text/css");
8809
- style.appendChild(document.createTextNode(""));
8810
- document.head.appendChild(style);
8811
- return style.sheet;
8812
- })();
9069
+ this.options = options;
8813
9070
  }
8814
9071
  set setOptions(options) {
8815
- this.options = merge(Object.assign({}, this.options, options));
9072
+ this.options = merge(this.options, options);
8816
9073
  }
8817
9074
  /**
8818
9075
  * Ensure elements have proper tagName
8819
9076
  * @param {Object|String} elem
8820
9077
  * @return {Object} valid element object
8821
9078
  */
8822
- processTagName(elem) {
9079
+ processTagName(elemArg) {
9080
+ let elem = elemArg;
8823
9081
  let tagName;
8824
9082
  if (typeof elem === "string") {
8825
9083
  tagName = elem;
8826
9084
  elem = { tag: tagName };
9085
+ return elem;
8827
9086
  }
8828
9087
  if (elem.attrs) {
8829
9088
  const { tag, ...restAttrs } = elem.attrs;
@@ -8866,7 +9125,7 @@ class DOM {
8866
9125
  const createSvgIconConfig = (symbolId) => ({
8867
9126
  tag: "svg",
8868
9127
  attrs: {
8869
- className: `svg-icon ${symbolId}`
9128
+ className: ["svg-icon", symbolId]
8870
9129
  },
8871
9130
  children: [
8872
9131
  {
@@ -8880,9 +9139,10 @@ class DOM {
8880
9139
  });
8881
9140
  this.iconSymbols = Array.from(iconSymbolNodes).reduce((acc, symbol) => {
8882
9141
  const name2 = symbol.id.replace(iconPrefix, "");
8883
- acc[name2] = dom.create(createSvgIconConfig(symbol.id));
9142
+ acc[name2] = createSvgIconConfig(symbol.id);
8884
9143
  return acc;
8885
9144
  }, {});
9145
+ this.cachedIcons = {};
8886
9146
  return this.iconSymbols;
8887
9147
  }
8888
9148
  /**
@@ -8891,20 +9151,29 @@ class DOM {
8891
9151
  * - we don't need the perks of having icons be DOM objects at this stage
8892
9152
  * - it forces the icon to be appended using innerHTML which helps svg render
8893
9153
  * @param {String} name - icon name
9154
+ * @param {Function} config - dom element config object
8894
9155
  * @return {String} icon markup
8895
9156
  */
8896
- icon(name2 = null, classNames = []) {
8897
- var _a;
9157
+ icon(name2, config2) {
9158
+ var _a, _b;
8898
9159
  if (!name2) {
8899
9160
  return;
8900
9161
  }
8901
- const icon = this.icons[name2];
8902
- if (icon) {
8903
- const iconClone = icon.cloneNode(true);
8904
- iconClone.classList.add(...classNames);
8905
- return iconClone.outerHTML;
9162
+ const cacheKey = `${name2}?${new URLSearchParams(config2).toString()}`;
9163
+ if ((_a = this.cachedIcons) == null ? void 0 : _a[cacheKey]) {
9164
+ return this.cachedIcons[cacheKey];
9165
+ }
9166
+ const iconConfig = this.icons[name2];
9167
+ if (iconConfig) {
9168
+ if (config2) {
9169
+ const mergedConfig = merge(iconConfig, config2);
9170
+ this.cachedIcons[cacheKey] = dom.create(mergedConfig).outerHTML;
9171
+ return this.cachedIcons[cacheKey];
9172
+ }
9173
+ this.cachedIcons[cacheKey] = dom.create(iconConfig).outerHTML;
9174
+ return this.cachedIcons[cacheKey];
8906
9175
  }
8907
- return ((_a = iconFontTemplates[dom.options.iconFont]) == null ? void 0 : _a.call(iconFontTemplates, name2)) || name2;
9176
+ return ((_b = iconFontTemplates[dom.options.iconFont]) == null ? void 0 : _b.call(iconFontTemplates, name2)) || name2;
8908
9177
  }
8909
9178
  /**
8910
9179
  * JS Object to DOM attributes
@@ -8915,34 +9184,29 @@ class DOM {
8915
9184
  */
8916
9185
  processAttrs(elem, element, isPreview) {
8917
9186
  const { attrs = {} } = elem;
8918
- if (!isPreview) {
8919
- if (!attrs.name && this.isInput(elem.tag)) {
8920
- element.setAttribute("name", uuid(elem));
8921
- }
9187
+ if (!isPreview && !attrs.name && this.isInput(elem.tag)) {
9188
+ element.setAttribute("name", uuid(elem));
8922
9189
  }
8923
9190
  for (const attr of Object.keys(attrs)) {
8924
9191
  const name2 = helpers.safeAttrName(attr);
8925
- let value = attrs[attr] || "";
8926
- if (Array.isArray(value)) {
8927
- if (typeof value[0] === "object") {
8928
- const selected = value.filter((t) => t.selected === true);
8929
- value = selected.length ? selected[0].value : value[0].value;
8930
- } else {
8931
- value = value.join(" ");
8932
- }
8933
- }
9192
+ const value = this.processAttrValue(attrs[attr]);
8934
9193
  if (value) {
8935
- if (element.tagName === "OPTION" && name2 === "selected") {
8936
- const timeout = setTimeout(() => {
8937
- element.setAttribute(name2, value);
8938
- clearTimeout(timeout);
8939
- }, 0);
8940
- } else {
8941
- element.setAttribute(name2, value);
8942
- }
9194
+ element.setAttribute(name2, value === true ? "" : value);
8943
9195
  }
8944
9196
  }
8945
9197
  }
9198
+ processAttrValue(valueArg) {
9199
+ let value = valueArg || "";
9200
+ if (Array.isArray(value)) {
9201
+ if (typeof value[0] === "object") {
9202
+ const selected = value.filter((t) => t.selected === true);
9203
+ value = selected.length ? selected[0].value : value[0].value;
9204
+ } else {
9205
+ value = value.join(" ");
9206
+ }
9207
+ }
9208
+ return value;
9209
+ }
8946
9210
  /**
8947
9211
  * Extend Array of option config objects
8948
9212
  * @param {Array} options
@@ -9049,11 +9313,12 @@ class DOM {
9049
9313
  * @param {String|Object} tag tagName or DOM element
9050
9314
  * @return {Boolean} isInput
9051
9315
  */
9052
- isInput(tag) {
9316
+ isInput(tagArg) {
9317
+ let tag = tagArg;
9053
9318
  if (typeof tag !== "string") {
9054
9319
  tag = tag.tagName;
9055
9320
  }
9056
- return ["input", "textarea", "select"].indexOf(tag) !== -1;
9321
+ return inputTags.has(tag);
9057
9322
  }
9058
9323
  /**
9059
9324
  * Converts escaped HTML into usable HTML
@@ -9101,7 +9366,7 @@ class DOM {
9101
9366
  action: {}
9102
9367
  };
9103
9368
  if (fMap) {
9104
- delete fieldLabel.attrs.for;
9369
+ fieldLabel.attrs.for = void 0;
9105
9370
  fieldLabel.attrs.contenteditable = true;
9106
9371
  fieldLabel.fMap = fMap;
9107
9372
  }
@@ -9257,7 +9522,8 @@ class DOM {
9257
9522
  * @param {Object} elem DOM element
9258
9523
  * @param {Boolean} state
9259
9524
  */
9260
- toggleSortable(elem, state) {
9525
+ toggleSortable(elem, stateArg) {
9526
+ let state = stateArg;
9261
9527
  const fType = componentType(elem);
9262
9528
  if (!fType) {
9263
9529
  return;
@@ -9335,6 +9601,7 @@ let FormeoEditor$1 = class FormeoEditor {
9335
9601
  this.dom = dom;
9336
9602
  events.init({ debug, ...events$1 });
9337
9603
  actions.init({ debug, sessionStorage: opts.sessionStorage, ...actions$1 });
9604
+ this.tooltip = new SmartTooltip();
9338
9605
  document.addEventListener("DOMContentLoaded", this.loadResources.bind(this));
9339
9606
  }
9340
9607
  get formData() {