formeo 2.2.2 → 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 +322 -60
  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.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.1";
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";
@@ -303,6 +502,7 @@ const scripts = {
303
502
  "build:icons": "node ./tools/generate-sprite",
304
503
  lint: "eslint ./src --ext .js || true",
305
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}",
306
506
  "test:updateSnapshots": "node --experimental-test-snapshots --test-update-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
307
507
  "test:ci": "npm test --coverage",
308
508
  start: "npm-run-all build:icons dev",
@@ -335,6 +535,7 @@ const devDependencies = {
335
535
  const dependencies = {
336
536
  "@draggable/formeo-languages": "^3.1.3",
337
537
  "@draggable/i18n": "^1.0.7",
538
+ "@draggable/tooltip": "^1.2.1",
338
539
  lodash: "^4.17.21",
339
540
  sortablejs: "^1.15.3"
340
541
  };
@@ -1502,11 +1703,17 @@ const uuid = (elem) => {
1502
1703
  }
1503
1704
  return id;
1504
1705
  };
1505
- const merge = (obj1, obj2, opts = /* @__PURE__ */ Object.create(null)) => {
1706
+ const merge = (obj1, obj2) => {
1506
1707
  const customizer = (objValue, srcValue) => {
1507
1708
  if (Array.isArray(objValue)) {
1508
- if (Array.isArray(srcValue)) {
1509
- 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));
1510
1717
  }
1511
1718
  return srcValue;
1512
1719
  }
@@ -1581,7 +1788,7 @@ function throttle$1(callback, limit = ANIMATION_SPEED_SLOW) {
1581
1788
  }
1582
1789
  };
1583
1790
  }
1584
- function debounce(fn, delay = ANIMATION_SPEED_SLOW) {
1791
+ function debounce(fn, delay = ANIMATION_SPEED_BASE) {
1585
1792
  let timeoutID;
1586
1793
  return function(...args) {
1587
1794
  if (timeoutID) {
@@ -1935,12 +2142,30 @@ const defaults$3 = {
1935
2142
  },
1936
2143
  onAdd: () => {
1937
2144
  },
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),
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
+ },
1944
2169
  onSave: (evt) => {
1945
2170
  },
1946
2171
  confirmClearAll: (evt) => {
@@ -1950,9 +2175,10 @@ const defaults$3 = {
1950
2175
  }
1951
2176
  };
1952
2177
  const defaultCustomEvent = ({ src, ...evtData }, type2 = EVENT_FORMEO_UPDATED) => {
2178
+ var _a, _b;
1953
2179
  const evt = new window.CustomEvent(type2, {
1954
2180
  detail: evtData,
1955
- 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)
1956
2182
  });
1957
2183
  evt.data = (src || document).dispatchEvent(evt);
1958
2184
  return evt;
@@ -2041,12 +2267,12 @@ let throttling;
2041
2267
  function onResizeWindow() {
2042
2268
  throttling = throttling || window.requestAnimationFrame(() => {
2043
2269
  throttling = false;
2044
- Object.values(Columns2.data).forEach((column) => {
2270
+ for (const column of Object.values(Columns2.data)) {
2045
2271
  column.dom.classList.add(NO_TRANSITION_CLASS_NAME);
2046
2272
  Controls2.dom.classList.add(NO_TRANSITION_CLASS_NAME);
2047
2273
  Controls2.panels.nav.refresh();
2048
2274
  column.refreshFieldPanels();
2049
- });
2275
+ }
2050
2276
  });
2051
2277
  }
2052
2278
  window.addEventListener("resize", onResizeWindow);
@@ -2781,11 +3007,11 @@ function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoS
2781
3007
  function isScrolledPast(el, elSide, parentSide) {
2782
3008
  var parent = getParentAutoScrollElement(el, true), elSideVal = getRect(el)[elSide];
2783
3009
  while (parent) {
2784
- var parentSideVal = getRect(parent)[parentSide], visible = void 0;
3010
+ var parentSideVal = getRect(parent)[parentSide], visible2 = void 0;
2785
3011
  {
2786
- visible = elSideVal >= parentSideVal;
3012
+ visible2 = elSideVal >= parentSideVal;
2787
3013
  }
2788
- if (!visible) return parent;
3014
+ if (!visible2) return parent;
2789
3015
  if (parent === getWindowScrollingElement()) break;
2790
3016
  parent = getParentAutoScrollElement(parent, false);
2791
3017
  }
@@ -5983,10 +6209,10 @@ class Component extends Data {
5983
6209
  tag: "span",
5984
6210
  className: ["component-tag", `${this.name}-tag`],
5985
6211
  children: [
5986
- (this.isColumn || this.isField) && dom.icon("component-corner", ["bottom-left"]),
6212
+ (this.isColumn || this.isField) && dom.icon("component-corner", { className: "bottom-left" }),
5987
6213
  dom.icon(`handle-${this.name}`),
5988
6214
  toTitleCase(this.name),
5989
- (this.isColumn || this.isRow) && dom.icon("component-corner", ["bottom-right"])
6215
+ (this.isColumn || this.isRow) && dom.icon("component-corner", { className: "bottom-right" })
5990
6216
  ].filter(Boolean)
5991
6217
  });
5992
6218
  });
@@ -6117,7 +6343,7 @@ class Component extends Data {
6117
6343
  this.config = components[`${this.name}s`].config;
6118
6344
  merge(this.config, data.config);
6119
6345
  this.dataPath = `${this.name}s.${this.id}.`;
6120
- this.observer = new MutationObserver(this.mutationHandler);
6346
+ this.observer = new window.MutationObserver(this.mutationHandler);
6121
6347
  this.render = render;
6122
6348
  }
6123
6349
  observe(container) {
@@ -6149,7 +6375,7 @@ class Component extends Data {
6149
6375
  return {
6150
6376
  className: [`${this.name}-actions`, "group-actions"],
6151
6377
  action: {
6152
- mouseenter: ({ target }) => {
6378
+ mouseenter: () => {
6153
6379
  components.stages.active.dom.classList.add(`active-hover-${this.name}`);
6154
6380
  this.dom.classList.add(...hoverClassnames);
6155
6381
  },
@@ -6744,11 +6970,20 @@ class Field extends Component {
6744
6970
  }
6745
6971
  },
6746
6972
  input: (evt) => {
6747
- if (["input", "meter", "progress", "button"].includes(this.data.tag)) {
6973
+ if (["input", "meter", "progress", "button"].includes(evt.target.tagName.toLowerCase())) {
6748
6974
  super.set("attrs.value", evt.target.value);
6749
- this.debouncedUpdateEditPanels();
6975
+ return this.debouncedUpdateEditPanels();
6750
6976
  }
6751
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
+ }
6752
6987
  super.set("content", evt.target.innerHTML);
6753
6988
  }
6754
6989
  }
@@ -7564,7 +7799,7 @@ let Controls$1 = class Controls {
7564
7799
  return controlConfig;
7565
7800
  }
7566
7801
  get(controlId) {
7567
- return this.data.get(controlId);
7802
+ return clone$1(this.data.get(controlId));
7568
7803
  }
7569
7804
  /**
7570
7805
  * Generate the DOM config for form actions like settings, save and clear
@@ -8013,13 +8248,25 @@ class Row extends Component {
8013
8248
  description: mi18n.get("row.makeInputGroupDesc")
8014
8249
  }
8015
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
+ };
8016
8258
  const legendInput = {
8017
8259
  tag: "input",
8018
8260
  attrs: {
8019
8261
  type: "text",
8020
8262
  ariaLabel: "Legend for fieldset",
8021
8263
  value: this.get("config.legend"),
8022
- placeholder: "Legend"
8264
+ placeholder: "Title"
8265
+ },
8266
+ config: {
8267
+ label: {
8268
+ children: ["Row Title", rowTitleTooltip]
8269
+ }
8023
8270
  },
8024
8271
  action: {
8025
8272
  input: ({ target: { value } }) => this.set("config.legend", value)
@@ -8345,7 +8592,6 @@ class Column extends Component {
8345
8592
  this.dom.style.width = width;
8346
8593
  return this.set("config.width", width);
8347
8594
  });
8348
- const _this = this;
8349
8595
  const children = this.createChildWrap();
8350
8596
  this.dom = dom.create({
8351
8597
  tag: "li",
@@ -8366,7 +8612,7 @@ class Column extends Component {
8366
8612
  events.columnResized = new window.CustomEvent("columnResized", {
8367
8613
  detail: {
8368
8614
  column: this.dom,
8369
- instance: _this
8615
+ instance: this
8370
8616
  }
8371
8617
  });
8372
8618
  Sortable.create(children, {
@@ -8624,11 +8870,12 @@ class DOM {
8624
8870
  if (!elemArg) {
8625
8871
  return;
8626
8872
  }
8627
- const { className, options, ...elem } = this.processTagName(elemArg);
8628
8873
  const _this = this;
8874
+ const processed = ["children", "content"];
8875
+ const { className, options, dataset, ...elem } = this.processTagName(elemArg);
8876
+ processed.push("tag");
8629
8877
  let childType;
8630
8878
  const { tag } = elem;
8631
- const processed = ["children", "content"];
8632
8879
  let i;
8633
8880
  const wrap = {
8634
8881
  attrs: {},
@@ -8664,9 +8911,8 @@ class DOM {
8664
8911
  undefined: () => null,
8665
8912
  boolean: () => null
8666
8913
  };
8667
- processed.push("tag");
8668
8914
  if (className) {
8669
- elem.attrs = { ...elem.attrs, className };
8915
+ elem.attrs = merge(elem.attrs, { className });
8670
8916
  }
8671
8917
  if (options) {
8672
8918
  const processedOptions = this.processOptions(options, elem, isPreview);
@@ -8693,7 +8939,10 @@ class DOM {
8693
8939
  if (elem.config.label && (elem.config.label && tag !== "button" || ["radio", "checkbox"].includes(helpers.get(elem, "attrs.type"))) && !isPreview) {
8694
8940
  const label = _this.label(elem);
8695
8941
  if (!elem.config.hideLabel) {
8696
- const wrapContent = [..._this.labelAfter(elem) ? [element, label] : [label, element]];
8942
+ const wrapContent = [label, element];
8943
+ if (_this.labelAfter(elem)) {
8944
+ wrapContent.reverse();
8945
+ }
8697
8946
  wrap.children.push(wrapContent);
8698
8947
  }
8699
8948
  }
@@ -8707,10 +8956,10 @@ class DOM {
8707
8956
  }
8708
8957
  appendChildren[childType].call(this, children);
8709
8958
  }
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];
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];
8714
8963
  }
8715
8964
  }
8716
8965
  processed.push("dataset");
@@ -8876,7 +9125,7 @@ class DOM {
8876
9125
  const createSvgIconConfig = (symbolId) => ({
8877
9126
  tag: "svg",
8878
9127
  attrs: {
8879
- className: `svg-icon ${symbolId}`
9128
+ className: ["svg-icon", symbolId]
8880
9129
  },
8881
9130
  children: [
8882
9131
  {
@@ -8890,9 +9139,10 @@ class DOM {
8890
9139
  });
8891
9140
  this.iconSymbols = Array.from(iconSymbolNodes).reduce((acc, symbol) => {
8892
9141
  const name2 = symbol.id.replace(iconPrefix, "");
8893
- acc[name2] = dom.create(createSvgIconConfig(symbol.id));
9142
+ acc[name2] = createSvgIconConfig(symbol.id);
8894
9143
  return acc;
8895
9144
  }, {});
9145
+ this.cachedIcons = {};
8896
9146
  return this.iconSymbols;
8897
9147
  }
8898
9148
  /**
@@ -8901,20 +9151,29 @@ class DOM {
8901
9151
  * - we don't need the perks of having icons be DOM objects at this stage
8902
9152
  * - it forces the icon to be appended using innerHTML which helps svg render
8903
9153
  * @param {String} name - icon name
9154
+ * @param {Function} config - dom element config object
8904
9155
  * @return {String} icon markup
8905
9156
  */
8906
- icon(name2 = null, classNames = []) {
8907
- var _a;
9157
+ icon(name2, config2) {
9158
+ var _a, _b;
8908
9159
  if (!name2) {
8909
9160
  return;
8910
9161
  }
8911
- const icon = this.icons[name2];
8912
- if (icon) {
8913
- const iconClone = icon.cloneNode(true);
8914
- iconClone.classList.add(...classNames);
8915
- 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];
8916
9165
  }
8917
- return ((_a = iconFontTemplates[dom.options.iconFont]) == null ? void 0 : _a.call(iconFontTemplates, name2)) || name2;
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];
9175
+ }
9176
+ return ((_b = iconFontTemplates[dom.options.iconFont]) == null ? void 0 : _b.call(iconFontTemplates, name2)) || name2;
8918
9177
  }
8919
9178
  /**
8920
9179
  * JS Object to DOM attributes
@@ -8925,27 +9184,29 @@ class DOM {
8925
9184
  */
8926
9185
  processAttrs(elem, element, isPreview) {
8927
9186
  const { attrs = {} } = elem;
8928
- if (!isPreview) {
8929
- if (!attrs.name && this.isInput(elem.tag)) {
8930
- element.setAttribute("name", uuid(elem));
8931
- }
9187
+ if (!isPreview && !attrs.name && this.isInput(elem.tag)) {
9188
+ element.setAttribute("name", uuid(elem));
8932
9189
  }
8933
9190
  for (const attr of Object.keys(attrs)) {
8934
9191
  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
- }
9192
+ const value = this.processAttrValue(attrs[attr]);
8944
9193
  if (value) {
8945
9194
  element.setAttribute(name2, value === true ? "" : value);
8946
9195
  }
8947
9196
  }
8948
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
+ }
8949
9210
  /**
8950
9211
  * Extend Array of option config objects
8951
9212
  * @param {Array} options
@@ -9340,6 +9601,7 @@ let FormeoEditor$1 = class FormeoEditor {
9340
9601
  this.dom = dom;
9341
9602
  events.init({ debug, ...events$1 });
9342
9603
  actions.init({ debug, sessionStorage: opts.sessionStorage, ...actions$1 });
9604
+ this.tooltip = new SmartTooltip();
9343
9605
  document.addEventListener("DOMContentLoaded", this.loadResources.bind(this));
9344
9606
  }
9345
9607
  get formData() {