formeo 2.2.2 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +350 -96
  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 +3 -1
package/dist/formeo.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 2.2.1
4
+ Version: 2.3.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -230,8 +230,211 @@ 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("touchstart", this.handleMouseOver);
314
+ document.addEventListener("touchend", this.handleMouseOut);
315
+ document.addEventListener("click", this.handleClick);
316
+ window.addEventListener("resize", this.handleResize);
317
+ window.addEventListener("scroll", this.handleScroll, true);
318
+ }
319
+ isVisible() {
320
+ return this.tooltip.classList.contains(styles.visible);
321
+ }
322
+ /**
323
+ * Calculates the optimal position for the tooltip relative to the trigger element.
324
+ * It tries to find a position where the tooltip fits within the viewport.
325
+ * If no position fits, it defaults to the first position in the list.
326
+ *
327
+ * @param {HTMLElement} trigger - The HTML element that triggers the tooltip.
328
+ * @returns {Position} The calculated position for the tooltip.
329
+ */
330
+ calculatePosition(trigger) {
331
+ const triggerRect = trigger.getBoundingClientRect();
332
+ const tooltipRect = this.tooltip.getBoundingClientRect();
333
+ const positions = [
334
+ {
335
+ name: "top",
336
+ x: triggerRect.left + (triggerRect.width - tooltipRect.width) / 2,
337
+ y: triggerRect.top - tooltipRect.height - this.spacing
338
+ },
339
+ {
340
+ name: "bottom",
341
+ x: triggerRect.left + (triggerRect.width - tooltipRect.width) / 2,
342
+ y: triggerRect.bottom + this.spacing
343
+ },
344
+ {
345
+ name: "left",
346
+ x: triggerRect.left - tooltipRect.width - this.spacing,
347
+ y: triggerRect.top + (triggerRect.height - tooltipRect.height) / 2
348
+ },
349
+ {
350
+ name: "right",
351
+ x: triggerRect.right + this.spacing,
352
+ y: triggerRect.top + (triggerRect.height - tooltipRect.height) / 2
353
+ },
354
+ // Corner positions
355
+ {
356
+ name: "top-left",
357
+ x: triggerRect.left,
358
+ y: triggerRect.top - tooltipRect.height - this.spacing
359
+ },
360
+ {
361
+ name: "top-right",
362
+ x: triggerRect.right - tooltipRect.width,
363
+ y: triggerRect.top - tooltipRect.height - this.spacing
364
+ },
365
+ {
366
+ name: "bottom-left",
367
+ x: triggerRect.left,
368
+ y: triggerRect.bottom + this.spacing
369
+ },
370
+ {
371
+ name: "bottom-right",
372
+ x: triggerRect.right - tooltipRect.width,
373
+ y: triggerRect.bottom + this.spacing
374
+ }
375
+ ];
376
+ return positions.find((pos) => this.fitsInViewport(pos, tooltipRect)) || positions[0];
377
+ }
378
+ /**
379
+ * Checks if the tooltip fits within the viewport and is not obstructed by other elements.
380
+ *
381
+ * @param pos - The position of the tooltip.
382
+ * @param tooltipRect - The bounding rectangle of the tooltip.
383
+ * @returns `true` if the tooltip fits within the viewport and is not obstructed, otherwise `false`.
384
+ */
385
+ fitsInViewport(pos, tooltipRect) {
386
+ const inViewport = pos.x >= 0 && pos.y >= 0 && pos.x + tooltipRect.width <= window.innerWidth && pos.y + tooltipRect.height <= window.innerHeight;
387
+ if (!inViewport) return false;
388
+ const points = [
389
+ [pos.x, pos.y],
390
+ // Top-left
391
+ [pos.x + tooltipRect.width, pos.y],
392
+ // Top-right
393
+ [pos.x, pos.y + tooltipRect.height],
394
+ // Bottom-left
395
+ [pos.x + tooltipRect.width, pos.y + tooltipRect.height],
396
+ // Bottom-right
397
+ [pos.x + tooltipRect.width / 2, pos.y + tooltipRect.height / 2]
398
+ // Center
399
+ ];
400
+ const elementsAtPoints = points.flatMap(([x, y]) => Array.from(document.elementsFromPoint(x, y)));
401
+ const obstructingElements = elementsAtPoints.filter((element) => {
402
+ if (this.tooltip.contains(element) || // Exclude tooltip and its children
403
+ element === this.tooltip || element.classList.contains(styles.tooltip) || // Ignore other tooltips
404
+ getComputedStyle(element).pointerEvents === "none") {
405
+ return false;
406
+ }
407
+ });
408
+ return obstructingElements.length === 0;
409
+ }
410
+ show(trigger, content) {
411
+ this.tooltip.innerHTML = content ?? "";
412
+ this.tooltip.classList.add(styles.visible);
413
+ const position = this.calculatePosition(trigger);
414
+ this.tooltip.style.left = `${position.x}px`;
415
+ this.tooltip.style.top = `${position.y}px`;
416
+ this.tooltip.dataset.position = position.name;
417
+ }
418
+ hide() {
419
+ this.tooltip.classList.remove(styles.visible);
420
+ this.activeTriggerType = null;
421
+ }
422
+ destroy() {
423
+ document.removeEventListener("mouseover", this.handleMouseOver);
424
+ document.removeEventListener("mouseout", this.handleMouseOut);
425
+ document.removeEventListener("touchstart", this.handleMouseOver);
426
+ document.removeEventListener("touchend", this.handleMouseOut);
427
+ document.removeEventListener("click", this.handleClick);
428
+ window.removeEventListener("resize", this.handleResize);
429
+ window.removeEventListener("scroll", this.handleScroll, true);
430
+ this.tooltip.remove();
431
+ }
432
+ }
433
+ if (window !== void 0) {
434
+ window.SmartTooltip = SmartTooltip;
435
+ }
233
436
  const name$1 = "formeo";
234
- const version$2 = "2.2.1";
437
+ const version$2 = "2.3.0";
235
438
  const type = "module";
236
439
  const main = "dist/formeo.cjs.js";
237
440
  const module = "dist/formeo.es.js";
@@ -303,6 +506,7 @@ const scripts = {
303
506
  "build:icons": "node ./tools/generate-sprite",
304
507
  lint: "eslint ./src --ext .js || true",
305
508
  test: "node --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
509
+ "test:watch": "node --watch --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
306
510
  "test:updateSnapshots": "node --experimental-test-snapshots --test-update-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
307
511
  "test:ci": "npm test --coverage",
308
512
  start: "npm-run-all build:icons dev",
@@ -335,6 +539,7 @@ const devDependencies = {
335
539
  const dependencies = {
336
540
  "@draggable/formeo-languages": "^3.1.3",
337
541
  "@draggable/i18n": "^1.0.7",
542
+ "@draggable/tooltip": "^1.2.2",
338
543
  lodash: "^4.17.21",
339
544
  sortablejs: "^1.15.3"
340
545
  };
@@ -1502,11 +1707,17 @@ const uuid = (elem) => {
1502
1707
  }
1503
1708
  return id;
1504
1709
  };
1505
- const merge = (obj1, obj2, opts = /* @__PURE__ */ Object.create(null)) => {
1710
+ const merge = (obj1, obj2) => {
1506
1711
  const customizer = (objValue, srcValue) => {
1507
1712
  if (Array.isArray(objValue)) {
1508
- if (Array.isArray(srcValue)) {
1509
- return unique(opts.mergeArray ? objValue.concat(srcValue) : srcValue);
1713
+ if (srcValue !== void 0 && srcValue !== null) {
1714
+ return unique(objValue.concat(srcValue));
1715
+ }
1716
+ return srcValue;
1717
+ }
1718
+ if (Array.isArray(srcValue)) {
1719
+ if (objValue !== void 0 && objValue !== null) {
1720
+ return unique(srcValue.concat(objValue));
1510
1721
  }
1511
1722
  return srcValue;
1512
1723
  }
@@ -1581,7 +1792,7 @@ function throttle$1(callback, limit = ANIMATION_SPEED_SLOW) {
1581
1792
  }
1582
1793
  };
1583
1794
  }
1584
- function debounce(fn, delay = ANIMATION_SPEED_SLOW) {
1795
+ function debounce(fn, delay = ANIMATION_SPEED_BASE) {
1585
1796
  let timeoutID;
1586
1797
  return function(...args) {
1587
1798
  if (timeoutID) {
@@ -1759,21 +1970,6 @@ var get_1 = get$1;
1759
1970
  const lodashGet = /* @__PURE__ */ getDefaultExportFromCjs(get_1);
1760
1971
  const get = lodashGet;
1761
1972
  const set = lodashSet;
1762
- const cleanObj = (obj) => {
1763
- const fresh = { ...obj };
1764
- const typeMap = {
1765
- string: () => "",
1766
- boolean: () => false,
1767
- object: (val) => cleanObj(val)
1768
- };
1769
- for (const key of Object.keys(obj)) {
1770
- const valType = typeof obj[key];
1771
- if (typeMap[valType]) {
1772
- fresh[key] = typeMap[valType](obj[key]);
1773
- }
1774
- }
1775
- return fresh;
1776
- };
1777
1973
  const isInt = (n) => Number.isInteger(Number(n));
1778
1974
  const indexOfNode = (node, parent) => {
1779
1975
  const parentElement = parent || node.parentElement;
@@ -1935,12 +2131,30 @@ const defaults$3 = {
1935
2131
  },
1936
2132
  onAdd: () => {
1937
2133
  },
1938
- onUpdate: (evt) => events.opts.debug && console.log(evt),
1939
- onUpdateStage: (evt) => events.opts.debug && console.log(evt),
1940
- onUpdateRow: (evt) => events.opts.debug && console.log(evt),
1941
- onUpdateColumn: (evt) => events.opts.debug && console.log(evt),
1942
- onUpdateField: (evt) => events.opts.debug && console.log(evt),
1943
- onRender: (evt) => events.opts.debug && console.log(evt),
2134
+ onUpdate: (evt) => {
2135
+ var _a;
2136
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2137
+ },
2138
+ onUpdateStage: (evt) => {
2139
+ var _a;
2140
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2141
+ },
2142
+ onUpdateRow: (evt) => {
2143
+ var _a;
2144
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2145
+ },
2146
+ onUpdateColumn: (evt) => {
2147
+ var _a;
2148
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2149
+ },
2150
+ onUpdateField: (evt) => {
2151
+ var _a;
2152
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2153
+ },
2154
+ onRender: (evt) => {
2155
+ var _a;
2156
+ return ((_a = events.opts) == null ? void 0 : _a.debug) && console.log(evt);
2157
+ },
1944
2158
  onSave: (evt) => {
1945
2159
  },
1946
2160
  confirmClearAll: (evt) => {
@@ -1950,9 +2164,10 @@ const defaults$3 = {
1950
2164
  }
1951
2165
  };
1952
2166
  const defaultCustomEvent = ({ src, ...evtData }, type2 = EVENT_FORMEO_UPDATED) => {
2167
+ var _a, _b;
1953
2168
  const evt = new window.CustomEvent(type2, {
1954
2169
  detail: evtData,
1955
- bubbles: events.opts.debug || events.opts.bubbles
2170
+ bubbles: ((_a = events.opts) == null ? void 0 : _a.debug) || ((_b = events.opts) == null ? void 0 : _b.bubbles)
1956
2171
  });
1957
2172
  evt.data = (src || document).dispatchEvent(evt);
1958
2173
  return evt;
@@ -2041,12 +2256,12 @@ let throttling;
2041
2256
  function onResizeWindow() {
2042
2257
  throttling = throttling || window.requestAnimationFrame(() => {
2043
2258
  throttling = false;
2044
- Object.values(Columns2.data).forEach((column) => {
2259
+ for (const column of Object.values(Columns2.data)) {
2045
2260
  column.dom.classList.add(NO_TRANSITION_CLASS_NAME);
2046
2261
  Controls2.dom.classList.add(NO_TRANSITION_CLASS_NAME);
2047
2262
  Controls2.panels.nav.refresh();
2048
2263
  column.refreshFieldPanels();
2049
- });
2264
+ }
2050
2265
  });
2051
2266
  }
2052
2267
  window.addEventListener("resize", onResizeWindow);
@@ -2781,11 +2996,11 @@ function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoS
2781
2996
  function isScrolledPast(el, elSide, parentSide) {
2782
2997
  var parent = getParentAutoScrollElement(el, true), elSideVal = getRect(el)[elSide];
2783
2998
  while (parent) {
2784
- var parentSideVal = getRect(parent)[parentSide], visible = void 0;
2999
+ var parentSideVal = getRect(parent)[parentSide], visible2 = void 0;
2785
3000
  {
2786
- visible = elSideVal >= parentSideVal;
3001
+ visible2 = elSideVal >= parentSideVal;
2787
3002
  }
2788
- if (!visible) return parent;
3003
+ if (!visible2) return parent;
2789
3004
  if (parent === getWindowScrollingElement()) break;
2790
3005
  parent = getParentAutoScrollElement(parent, false);
2791
3006
  }
@@ -4828,11 +5043,8 @@ class Panels {
4828
5043
  action: {
4829
5044
  click: (evt) => {
4830
5045
  const index2 = indexOfNode(evt.target, evt.target.parentElement);
4831
- this.currentPanel = this.panels[index2];
4832
- const labels2 = evt.target.parentElement.childNodes;
4833
- this.nav.refresh(index2);
4834
- dom.removeClasses(labels2, "active-tab");
4835
- evt.target.classList.add("active-tab");
5046
+ this.nav.setTranslateX(index2, false);
5047
+ this.nav.groupChange(index2);
4836
5048
  }
4837
5049
  },
4838
5050
  content: panel.config.label
@@ -4905,17 +5117,18 @@ class Panels {
4905
5117
  const action = {};
4906
5118
  const groupParent = this.currentPanel.parentElement;
4907
5119
  const labelWrap = this.labels.firstChild;
5120
+ const panelTabs = labelWrap.children;
4908
5121
  const siblingGroups = this.currentPanel.parentElement.childNodes;
4909
5122
  this.activePanelIndex = indexOfNode(this.currentPanel, groupParent);
4910
5123
  let offset = { nav: 0, panel: 0 };
4911
5124
  let lastOffset = { ...offset };
4912
5125
  action.groupChange = (newIndex2) => {
4913
- const labels = labelWrap.children;
4914
- dom.removeClasses(siblingGroups, "active-panel");
4915
- dom.removeClasses(labels, "active-tab");
5126
+ this.activePanelIndex = newIndex2;
4916
5127
  this.currentPanel = siblingGroups[newIndex2];
5128
+ dom.removeClasses(siblingGroups, "active-panel");
5129
+ dom.removeClasses(panelTabs, "active-tab");
4917
5130
  this.currentPanel.classList.add("active-panel");
4918
- labels[newIndex2].classList.add("active-tab");
5131
+ panelTabs[newIndex2].classList.add("active-tab");
4919
5132
  return this.currentPanel;
4920
5133
  };
4921
5134
  const getOffset = (index2) => {
@@ -4955,22 +5168,21 @@ class Panels {
4955
5168
  };
4956
5169
  action.refresh = (newIndex2 = this.activePanelIndex) => {
4957
5170
  if (this.activePanelIndex !== newIndex2) {
4958
- this.activePanelIndex = newIndex2;
4959
5171
  action.groupChange(newIndex2);
4960
5172
  }
4961
- action.setTranslateX(this.activePanelIndex);
5173
+ action.setTranslateX(this.activePanelIndex, false);
4962
5174
  this.resizePanels();
4963
5175
  };
4964
5176
  action.nextGroup = () => {
4965
5177
  const newIndex2 = this.activePanelIndex + 1;
4966
5178
  if (newIndex2 !== siblingGroups.length) {
4967
- const curPanel = action.groupChange(newIndex2);
5179
+ const nextPanel = siblingGroups[newIndex2];
4968
5180
  offset = {
4969
5181
  nav: -labelWrap.offsetWidth * newIndex2,
4970
- panel: -curPanel.offsetLeft
5182
+ panel: -nextPanel.offsetLeft
4971
5183
  };
4972
5184
  translateX({ offset });
4973
- this.activePanelIndex++;
5185
+ action.groupChange(newIndex2);
4974
5186
  } else {
4975
5187
  offset = {
4976
5188
  nav: lastOffset.nav - 8,
@@ -4983,13 +5195,13 @@ class Panels {
4983
5195
  action.prevGroup = () => {
4984
5196
  if (this.activePanelIndex !== 0) {
4985
5197
  const newIndex2 = this.activePanelIndex - 1;
4986
- const curPanel = action.groupChange(newIndex2);
5198
+ const prevPanel = siblingGroups[newIndex2];
4987
5199
  offset = {
4988
5200
  nav: -labelWrap.offsetWidth * newIndex2,
4989
- panel: -curPanel.offsetLeft
5201
+ panel: -prevPanel.offsetLeft
4990
5202
  };
4991
5203
  translateX({ offset });
4992
- this.activePanelIndex--;
5204
+ action.groupChange(newIndex2);
4993
5205
  } else {
4994
5206
  offset = {
4995
5207
  nav: 8,
@@ -5816,10 +6028,14 @@ class EditPanel {
5816
6028
  const metaId = this.field.data.meta.id;
5817
6029
  const fieldOptionData = this.field.get("options");
5818
6030
  const type2 = metaId === "select" ? "option" : metaId;
5819
- const newOptionLabel = mi18n.get(`newOptionLabel`, { type: type2 }) || "New Option";
6031
+ const newOptionLabel = mi18n.get("newOptionLabel", { type: type2 }) || "New Option";
5820
6032
  const itemKey = `options.${this.data.length}`;
5821
- const optionTemplate = fieldOptionData.length ? cleanObj(fieldOptionData[fieldOptionData.length - 1]) : {};
5822
- const itemData = { ...optionTemplate, label: newOptionLabel, value: slugify(newOptionLabel) };
6033
+ const lastOptionData = fieldOptionData[fieldOptionData.length - 1];
6034
+ const optionTemplate = fieldOptionData.length ? lastOptionData : {};
6035
+ const itemData = { ...optionTemplate, label: newOptionLabel };
6036
+ if (metaId !== "button") {
6037
+ itemData.value = slugify(newOptionLabel);
6038
+ }
5823
6039
  const newOption = new EditPanelItem({
5824
6040
  key: itemKey,
5825
6041
  data: itemData,
@@ -5983,10 +6199,10 @@ class Component extends Data {
5983
6199
  tag: "span",
5984
6200
  className: ["component-tag", `${this.name}-tag`],
5985
6201
  children: [
5986
- (this.isColumn || this.isField) && dom.icon("component-corner", ["bottom-left"]),
6202
+ (this.isColumn || this.isField) && dom.icon("component-corner", { className: "bottom-left" }),
5987
6203
  dom.icon(`handle-${this.name}`),
5988
6204
  toTitleCase(this.name),
5989
- (this.isColumn || this.isRow) && dom.icon("component-corner", ["bottom-right"])
6205
+ (this.isColumn || this.isRow) && dom.icon("component-corner", { className: "bottom-right" })
5990
6206
  ].filter(Boolean)
5991
6207
  });
5992
6208
  });
@@ -6117,7 +6333,7 @@ class Component extends Data {
6117
6333
  this.config = components[`${this.name}s`].config;
6118
6334
  merge(this.config, data.config);
6119
6335
  this.dataPath = `${this.name}s.${this.id}.`;
6120
- this.observer = new MutationObserver(this.mutationHandler);
6336
+ this.observer = new window.MutationObserver(this.mutationHandler);
6121
6337
  this.render = render;
6122
6338
  }
6123
6339
  observe(container) {
@@ -6149,7 +6365,7 @@ class Component extends Data {
6149
6365
  return {
6150
6366
  className: [`${this.name}-actions`, "group-actions"],
6151
6367
  action: {
6152
- mouseenter: ({ target }) => {
6368
+ mouseenter: () => {
6153
6369
  components.stages.active.dom.classList.add(`active-hover-${this.name}`);
6154
6370
  this.dom.classList.add(...hoverClassnames);
6155
6371
  },
@@ -6744,11 +6960,20 @@ class Field extends Component {
6744
6960
  }
6745
6961
  },
6746
6962
  input: (evt) => {
6747
- if (["input", "meter", "progress", "button"].includes(this.data.tag)) {
6963
+ if (["input", "meter", "progress", "button"].includes(evt.target.tagName.toLowerCase())) {
6748
6964
  super.set("attrs.value", evt.target.value);
6749
- this.debouncedUpdateEditPanels();
6965
+ return this.debouncedUpdateEditPanels();
6750
6966
  }
6751
6967
  if (evt.target.contentEditable) {
6968
+ const parentClassList = evt.target.parentElement.classList;
6969
+ const isOption = parentClassList.contains("f-checkbox") || parentClassList.contains("f-radio");
6970
+ if (isOption) {
6971
+ const option2 = evt.target.parentElement;
6972
+ const optionWrap = option2.parentElement;
6973
+ const optionIndex = indexOfNode(option2, optionWrap);
6974
+ super.set(`options[${optionIndex}].label`, evt.target.innerHTML);
6975
+ return this.debouncedUpdateEditPanels();
6976
+ }
6752
6977
  super.set("content", evt.target.innerHTML);
6753
6978
  }
6754
6979
  }
@@ -7564,7 +7789,7 @@ let Controls$1 = class Controls {
7564
7789
  return controlConfig;
7565
7790
  }
7566
7791
  get(controlId) {
7567
- return this.data.get(controlId);
7792
+ return clone$1(this.data.get(controlId));
7568
7793
  }
7569
7794
  /**
7570
7795
  * Generate the DOM config for form actions like settings, save and clear
@@ -8013,13 +8238,25 @@ class Row extends Component {
8013
8238
  description: mi18n.get("row.makeInputGroupDesc")
8014
8239
  }
8015
8240
  };
8241
+ const rowTitleTooltip = {
8242
+ tag: "span",
8243
+ content: " ⓘ",
8244
+ dataset: {
8245
+ tooltip: "Row title will be used as the legend for the fieldset"
8246
+ }
8247
+ };
8016
8248
  const legendInput = {
8017
8249
  tag: "input",
8018
8250
  attrs: {
8019
8251
  type: "text",
8020
8252
  ariaLabel: "Legend for fieldset",
8021
8253
  value: this.get("config.legend"),
8022
- placeholder: "Legend"
8254
+ placeholder: "Title"
8255
+ },
8256
+ config: {
8257
+ label: {
8258
+ children: ["Row Title", rowTitleTooltip]
8259
+ }
8023
8260
  },
8024
8261
  action: {
8025
8262
  input: ({ target: { value } }) => this.set("config.legend", value)
@@ -8334,7 +8571,9 @@ class Column extends Component {
8334
8571
  super("column", { ...DEFAULT_DATA$1(), ...columnData });
8335
8572
  // loops through children and refresh their edit panels
8336
8573
  __publicField(this, "refreshFieldPanels", () => {
8337
- this.children.forEach((field) => field.panels.nav.refresh());
8574
+ for (const field of this.children) {
8575
+ field.panels.nav.refresh();
8576
+ }
8338
8577
  });
8339
8578
  /**
8340
8579
  * Sets a columns width
@@ -8345,7 +8584,6 @@ class Column extends Component {
8345
8584
  this.dom.style.width = width;
8346
8585
  return this.set("config.width", width);
8347
8586
  });
8348
- const _this = this;
8349
8587
  const children = this.createChildWrap();
8350
8588
  this.dom = dom.create({
8351
8589
  tag: "li",
@@ -8366,7 +8604,7 @@ class Column extends Component {
8366
8604
  events.columnResized = new window.CustomEvent("columnResized", {
8367
8605
  detail: {
8368
8606
  column: this.dom,
8369
- instance: _this
8607
+ instance: this
8370
8608
  }
8371
8609
  });
8372
8610
  Sortable.create(children, {
@@ -8624,11 +8862,12 @@ class DOM {
8624
8862
  if (!elemArg) {
8625
8863
  return;
8626
8864
  }
8627
- const { className, options, ...elem } = this.processTagName(elemArg);
8628
8865
  const _this = this;
8866
+ const processed = ["children", "content"];
8867
+ const { className, options, dataset, ...elem } = this.processTagName(elemArg);
8868
+ processed.push("tag");
8629
8869
  let childType;
8630
8870
  const { tag } = elem;
8631
- const processed = ["children", "content"];
8632
8871
  let i;
8633
8872
  const wrap = {
8634
8873
  attrs: {},
@@ -8664,9 +8903,8 @@ class DOM {
8664
8903
  undefined: () => null,
8665
8904
  boolean: () => null
8666
8905
  };
8667
- processed.push("tag");
8668
8906
  if (className) {
8669
- elem.attrs = { ...elem.attrs, className };
8907
+ elem.attrs = merge(elem.attrs, { className });
8670
8908
  }
8671
8909
  if (options) {
8672
8910
  const processedOptions = this.processOptions(options, elem, isPreview);
@@ -8693,7 +8931,10 @@ class DOM {
8693
8931
  if (elem.config.label && (elem.config.label && tag !== "button" || ["radio", "checkbox"].includes(helpers.get(elem, "attrs.type"))) && !isPreview) {
8694
8932
  const label = _this.label(elem);
8695
8933
  if (!elem.config.hideLabel) {
8696
- const wrapContent = [..._this.labelAfter(elem) ? [element, label] : [label, element]];
8934
+ const wrapContent = [label, element];
8935
+ if (_this.labelAfter(elem)) {
8936
+ wrapContent.reverse();
8937
+ }
8697
8938
  wrap.children.push(wrapContent);
8698
8939
  }
8699
8940
  }
@@ -8707,10 +8948,10 @@ class DOM {
8707
8948
  }
8708
8949
  appendChildren[childType].call(this, children);
8709
8950
  }
8710
- if (elem.dataset) {
8711
- for (const data in elem.dataset) {
8712
- if (Object.hasOwn(elem.dataset, data)) {
8713
- element.dataset[data] = typeof elem.dataset[data] === "function" ? elem.dataset[data]() : elem.dataset[data];
8951
+ if (dataset) {
8952
+ for (const data in dataset) {
8953
+ if (Object.hasOwn(dataset, data)) {
8954
+ element.dataset[data] = typeof dataset[data] === "function" ? dataset[data]() : dataset[data];
8714
8955
  }
8715
8956
  }
8716
8957
  processed.push("dataset");
@@ -8876,7 +9117,7 @@ class DOM {
8876
9117
  const createSvgIconConfig = (symbolId) => ({
8877
9118
  tag: "svg",
8878
9119
  attrs: {
8879
- className: `svg-icon ${symbolId}`
9120
+ className: ["svg-icon", symbolId]
8880
9121
  },
8881
9122
  children: [
8882
9123
  {
@@ -8890,9 +9131,10 @@ class DOM {
8890
9131
  });
8891
9132
  this.iconSymbols = Array.from(iconSymbolNodes).reduce((acc, symbol) => {
8892
9133
  const name2 = symbol.id.replace(iconPrefix, "");
8893
- acc[name2] = dom.create(createSvgIconConfig(symbol.id));
9134
+ acc[name2] = createSvgIconConfig(symbol.id);
8894
9135
  return acc;
8895
9136
  }, {});
9137
+ this.cachedIcons = {};
8896
9138
  return this.iconSymbols;
8897
9139
  }
8898
9140
  /**
@@ -8901,20 +9143,29 @@ class DOM {
8901
9143
  * - we don't need the perks of having icons be DOM objects at this stage
8902
9144
  * - it forces the icon to be appended using innerHTML which helps svg render
8903
9145
  * @param {String} name - icon name
9146
+ * @param {Function} config - dom element config object
8904
9147
  * @return {String} icon markup
8905
9148
  */
8906
- icon(name2 = null, classNames = []) {
8907
- var _a;
9149
+ icon(name2, config2) {
9150
+ var _a, _b;
8908
9151
  if (!name2) {
8909
9152
  return;
8910
9153
  }
8911
- const icon = this.icons[name2];
8912
- if (icon) {
8913
- const iconClone = icon.cloneNode(true);
8914
- iconClone.classList.add(...classNames);
8915
- return iconClone.outerHTML;
9154
+ const cacheKey = `${name2}?${new URLSearchParams(config2).toString()}`;
9155
+ if ((_a = this.cachedIcons) == null ? void 0 : _a[cacheKey]) {
9156
+ return this.cachedIcons[cacheKey];
9157
+ }
9158
+ const iconConfig = this.icons[name2];
9159
+ if (iconConfig) {
9160
+ if (config2) {
9161
+ const mergedConfig = merge(iconConfig, config2);
9162
+ this.cachedIcons[cacheKey] = dom.create(mergedConfig).outerHTML;
9163
+ return this.cachedIcons[cacheKey];
9164
+ }
9165
+ this.cachedIcons[cacheKey] = dom.create(iconConfig).outerHTML;
9166
+ return this.cachedIcons[cacheKey];
8916
9167
  }
8917
- return ((_a = iconFontTemplates[dom.options.iconFont]) == null ? void 0 : _a.call(iconFontTemplates, name2)) || name2;
9168
+ return ((_b = iconFontTemplates[dom.options.iconFont]) == null ? void 0 : _b.call(iconFontTemplates, name2)) || name2;
8918
9169
  }
8919
9170
  /**
8920
9171
  * JS Object to DOM attributes
@@ -8925,27 +9176,29 @@ class DOM {
8925
9176
  */
8926
9177
  processAttrs(elem, element, isPreview) {
8927
9178
  const { attrs = {} } = elem;
8928
- if (!isPreview) {
8929
- if (!attrs.name && this.isInput(elem.tag)) {
8930
- element.setAttribute("name", uuid(elem));
8931
- }
9179
+ if (!isPreview && !attrs.name && this.isInput(elem.tag)) {
9180
+ element.setAttribute("name", uuid(elem));
8932
9181
  }
8933
9182
  for (const attr of Object.keys(attrs)) {
8934
9183
  const name2 = helpers.safeAttrName(attr);
8935
- let value = attrs[attr] || "";
8936
- if (Array.isArray(value)) {
8937
- if (typeof value[0] === "object") {
8938
- const selected = value.filter((t) => t.selected === true);
8939
- value = selected.length ? selected[0].value : value[0].value;
8940
- } else {
8941
- value = value.join(" ");
8942
- }
8943
- }
9184
+ const value = this.processAttrValue(attrs[attr]);
8944
9185
  if (value) {
8945
9186
  element.setAttribute(name2, value === true ? "" : value);
8946
9187
  }
8947
9188
  }
8948
9189
  }
9190
+ processAttrValue(valueArg) {
9191
+ let value = valueArg || "";
9192
+ if (Array.isArray(value)) {
9193
+ if (typeof value[0] === "object") {
9194
+ const selected = value.filter((t) => t.selected === true);
9195
+ value = selected.length ? selected[0].value : value[0].value;
9196
+ } else {
9197
+ value = value.join(" ");
9198
+ }
9199
+ }
9200
+ return value;
9201
+ }
8949
9202
  /**
8950
9203
  * Extend Array of option config objects
8951
9204
  * @param {Array} options
@@ -9340,6 +9593,7 @@ let FormeoEditor$1 = class FormeoEditor {
9340
9593
  this.dom = dom;
9341
9594
  events.init({ debug, ...events$1 });
9342
9595
  actions.init({ debug, sessionStorage: opts.sessionStorage, ...actions$1 });
9596
+ this.tooltip = new SmartTooltip();
9343
9597
  document.addEventListener("DOMContentLoaded", this.loadResources.bind(this));
9344
9598
  }
9345
9599
  get formData() {