formeo 4.0.0 → 4.1.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.
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -438,7 +438,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
438
438
  window.SmartTooltip = SmartTooltip;
439
439
  }
440
440
  const name$1 = "formeo";
441
- const version$2 = "3.1.4";
441
+ const version$2 = "4.0.0";
442
442
  const type = "module";
443
443
  const main = "dist/formeo.cjs.js";
444
444
  const module2 = "dist/formeo.es.js";
@@ -569,7 +569,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
569
569
  sortablejs: "^1.15.3"
570
570
  };
571
571
  const release = {
572
- branch: "master",
572
+ branch: "main",
573
573
  verifyConditions: [
574
574
  "@semantic-release/changelog",
575
575
  "@semantic-release/npm",
@@ -5003,7 +5003,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
5003
5003
  }
5004
5004
  const _this = this;
5005
5005
  const processed = ["children", "content"];
5006
- const { className, options, dataset, conditions, ...elem } = this.processElemArg(elemArg);
5006
+ const { className, options, dataset, ...elem } = this.processElemArg(elemArg);
5007
5007
  processed.push("tag");
5008
5008
  let childType;
5009
5009
  const { tag } = elem;
@@ -7035,7 +7035,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7035
7035
  }
7036
7036
  getPanelDisplay() {
7037
7037
  const column = this.panelsWrap;
7038
- const width = Number.parseInt(dom.getStyle(column, "width"));
7038
+ const width = Number.parseInt(dom.getStyle(column, "width"), 10);
7039
7039
  const autoDisplayType = width > 390 ? "tabbed" : "slider";
7040
7040
  const isAuto = this.opts.displayType === "auto";
7041
7041
  this.panelDisplay = isAuto ? autoDisplayType : this.opts.displayType || defaults$2.displayType;
@@ -7291,6 +7291,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7291
7291
  }
7292
7292
  const parent = this.parent;
7293
7293
  const children = this.children;
7294
+ this.dispatchComponentEvent("onRemove", {
7295
+ path,
7296
+ parent,
7297
+ children: [...children]
7298
+ // copy array since children will be modified
7299
+ });
7294
7300
  forEach(children, (child) => child.remove());
7295
7301
  this.dom.parentElement.removeChild(this.dom);
7296
7302
  remove(components.getAddress(`${parent.name}s.${parent.id}.children`), this.id);
@@ -7432,6 +7438,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7432
7438
  if (this.name !== "field") {
7433
7439
  this.cloneChildren(newClone);
7434
7440
  }
7441
+ this.dispatchComponentEvent("onClone", {
7442
+ original: this,
7443
+ clone: newClone,
7444
+ parent
7445
+ });
7435
7446
  return newClone;
7436
7447
  });
7437
7448
  __publicField(this, "createChildWrap", (children) => dom.create({
@@ -7503,11 +7514,91 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7503
7514
  this.address = `${this.name}s.${this.id}`;
7504
7515
  this.dataPath = `${this.address}.`;
7505
7516
  this.editPanels = /* @__PURE__ */ new Map();
7517
+ this.eventListeners = /* @__PURE__ */ new Map();
7518
+ this.initEventHandlers();
7519
+ }
7520
+ /**
7521
+ * Initialize event handlers based on config
7522
+ */
7523
+ initEventHandlers() {
7524
+ if (!this.config.events) {
7525
+ return;
7526
+ }
7527
+ Object.entries(this.config.events).forEach(([eventName, handler]) => {
7528
+ this.addEventListener(eventName, handler);
7529
+ });
7530
+ }
7531
+ /**
7532
+ * Add an event listener to this component
7533
+ * @param {string} eventName - Name of the event
7534
+ * @param {function} handler - Event handler function
7535
+ */
7536
+ addEventListener(eventName, handler) {
7537
+ if (!this.eventListeners.has(eventName)) {
7538
+ this.eventListeners.set(eventName, []);
7539
+ }
7540
+ this.eventListeners.get(eventName).push(handler);
7541
+ }
7542
+ /**
7543
+ * Remove an event listener from this component
7544
+ * @param {string} eventName - Name of the event
7545
+ * @param {function} handler - Event handler function to remove
7546
+ */
7547
+ removeEventListener(eventName, handler) {
7548
+ var _a;
7549
+ if (!((_a = this.eventListeners) == null ? void 0 : _a.has(eventName))) {
7550
+ return;
7551
+ }
7552
+ const handlers = this.eventListeners.get(eventName);
7553
+ const index2 = handlers.indexOf(handler);
7554
+ if (index2 > -1) {
7555
+ handlers.splice(index2, 1);
7556
+ }
7557
+ }
7558
+ /**
7559
+ * Dispatch a component event to all registered listeners
7560
+ * @param {string} eventName - Name of the event to dispatch
7561
+ * @param {object} eventData - Data to pass to event handlers
7562
+ */
7563
+ dispatchComponentEvent(eventName, eventData = {}) {
7564
+ var _a;
7565
+ const fullEventData = {
7566
+ component: this,
7567
+ type: eventName,
7568
+ timestamp: Date.now(),
7569
+ ...eventData
7570
+ };
7571
+ if ((_a = this.eventListeners) == null ? void 0 : _a.has(eventName)) {
7572
+ this.eventListeners.get(eventName).forEach((handler) => {
7573
+ try {
7574
+ if (typeof handler === "function") {
7575
+ handler(fullEventData);
7576
+ }
7577
+ } catch (error) {
7578
+ console.error(`Error in ${eventName} event handler for ${this.name} ${this.id}:`, error);
7579
+ }
7580
+ });
7581
+ }
7582
+ return fullEventData;
7583
+ }
7584
+ /**
7585
+ * Override Data.set to dispatch component update events
7586
+ */
7587
+ set(path, newVal) {
7588
+ const oldVal = this.get(path);
7589
+ const result = super.set(path, newVal);
7590
+ if (oldVal !== newVal && this.dom) {
7591
+ this.dispatchComponentEvent("onUpdate", {
7592
+ path,
7593
+ oldValue: oldVal,
7594
+ newValue: newVal
7595
+ });
7596
+ }
7597
+ return result;
7506
7598
  }
7507
7599
  // mutationHandler = mutations =>
7508
7600
  // mutations.map(mutation => {
7509
- // @todo pull handler form config
7510
- // see dom.create.onRender for implementation pattern
7601
+ // @todo pull handler form config see dom.create.onRender for implementation pattern
7511
7602
  // })
7512
7603
  // observe(container) {
7513
7604
  // this.observer.disconnect()
@@ -7710,7 +7801,24 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7710
7801
  }
7711
7802
  const childComponentType = `${childGroup}s`;
7712
7803
  const child = components.getAddress(`${childComponentType}.${childId}`) || components[childComponentType].add(childId, data);
7713
- childWrap.insertBefore(child.dom, childWrap.children[index2]);
7804
+ if (index2 >= childWrap.children.length) {
7805
+ childWrap.appendChild(child.dom);
7806
+ } else {
7807
+ childWrap.children[index2].before(child.dom);
7808
+ }
7809
+ this.dispatchComponentEvent("onAddChild", {
7810
+ parent: this,
7811
+ target: child,
7812
+ child,
7813
+ index: index2
7814
+ });
7815
+ child.dispatchComponentEvent("onAdd", {
7816
+ parent: this,
7817
+ target: child,
7818
+ index: index2,
7819
+ addedVia: "addChild"
7820
+ // indicate how the component was added
7821
+ });
7714
7822
  (_b = (_a = this.config.events) == null ? void 0 : _a.onAddChild) == null ? void 0 : _b.call(_a, { parent: this, child });
7715
7823
  const grandChildren = child.get("children");
7716
7824
  if (grandChildren == null ? void 0 : grandChildren.length) {
@@ -7819,6 +7927,17 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7819
7927
  }
7820
7928
  };
7821
7929
  const component = (_a = onAddConditions[fromType]) == null ? void 0 : _a.call(onAddConditions, item, newIndex2);
7930
+ this.dispatchComponentEvent("onAdd", {
7931
+ from,
7932
+ to,
7933
+ item,
7934
+ newIndex: newIndex2,
7935
+ fromType,
7936
+ toType,
7937
+ addedComponent: component,
7938
+ addedVia: "dragDrop"
7939
+ // indicate how the component was added
7940
+ });
7822
7941
  defaultOnAdd();
7823
7942
  return component;
7824
7943
  }
@@ -7841,6 +7960,9 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
7841
7960
  * Callback for onRender, executes any defined onRender for component
7842
7961
  */
7843
7962
  onRender() {
7963
+ this.dispatchComponentEvent("onRender", {
7964
+ dom: this.dom
7965
+ });
7844
7966
  const { events: events2 } = this.config;
7845
7967
  if (!events2) {
7846
7968
  return null;
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -1 +1 @@
1
- <!doctype html><html lang="en" xml:lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="chrome=1"><meta name="viewport" content="user-scalable=no,width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name="description" content="Vanilla Javascript form building module"><meta name="theme-color" content="#232323"><title>Formeo | Drag &amp; Drop Form Creation</title><script type="module" crossorigin src="/formeo/assets/js/demo.min.js"></script><link rel="stylesheet" crossorigin href="/formeo/assets/css/demo.min.css"></head><body><div class="site-wrap"><header id="demo-header"><nav aria-label="Footer navigation"><ul><li><label for="locale">Language</label> <select name="locale" id="locale" class="form-control"><option value="af-ZA" dir="ltr">Afrikaans (Suid-Afrika)</option><option value="ar-TN" dir="rtl">العربية (تونس)</option><option value="cs-CZ" dir="ltr">čeština (Česko)</option><option value="de-DE" dir="ltr">Deutsch (Deutschland)</option><option value="en-US" dir="ltr">English</option><option value="es-ES" dir="ltr">español de España</option><option value="fa-IR" dir="rtl">فارسی (ایران)</option><option value="fi-FI" dir="ltr">suomi (Suomi)</option><option value="fr-FR" dir="ltr">français (France)</option><option value="he-IL" dir="rtl">עברית (ישראל)</option><option value="hi-IN" dir="ltr">हिन्दी (भारत)</option><option value="hu-HU" dir="ltr">magyar (Magyarország)</option><option value="it-IT" dir="ltr">italiano (Italia)</option><option value="ja-JP" dir="ltr">日本語 (日本)</option><option value="nb-NO" dir="ltr">norsk bokmål (Norge)</option><option value="pl-PL" dir="ltr">polski (Polska)</option><option value="pt-BR" dir="ltr">português (Brasil)</option><option value="pt-PT" dir="ltr">português europeu</option><option value="ro-RO" dir="ltr">română (România)</option><option value="ru-RU" dir="ltr">русский (Россия)</option><option value="th-TH" dir="ltr">ไทย (ไทย)</option><option value="tr-TR" dir="ltr">Türkçe (Türkiye)</option><option value="zh-CN" dir="ltr">中文(中国)</option><option value="zh-HK" dir="ltr">中文(中國香港特別行政區)</option></select> <label for="control-filter">Control Filter:</label> <input id="control-filter" placeholder="ex. text" class="form-control"></li><li style="float:right">v3.1.4</li></ul></nav><span id="formeo-logo-wrap"></span></header><section id="main_content" class="inner"><form class="build-form"></form><div class="render-form"></div></section><div class="container render-btn-wrap" id="editor-action-buttons"></div><div id="formData-popover" popover><div class="popover-header"><h3>Test formData</h3><div><button type="button" id="format-json">Format</button> <button type="button" id="collapse-json">Collapse</button> <button type="button" id="copy-json">Copy to Clipboard</button></div></div><pre id="formData-editor"></pre><div class="formData-actions"><button popovertarget="formData-popover" popovertargetaction="hide" type="button">Cancel</button> <button id="submit-formData" type="button">Submit</button></div></div><footer id="demo-footer"><nav aria-label="Footer navigation"><ul><li><a href="https://github.com/Draggable/formeo" target="_blank" title="View project on GitHub"><img src="/formeo/assets/img/github.png" width="77" alt="GitHub"></a></li></ul></nav></footer></div></body></html>
1
+ <!doctype html><html lang="en" xml:lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="chrome=1"><meta name="viewport" content="user-scalable=no,width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1"><meta name="description" content="Vanilla Javascript form building module"><meta name="theme-color" content="#232323"><title>Formeo | Drag &amp; Drop Form Creation</title><script type="module" crossorigin src="/formeo/assets/js/demo.min.js"></script><link rel="stylesheet" crossorigin href="/formeo/assets/css/demo.min.css"></head><body><div class="site-wrap"><header id="demo-header"><nav aria-label="Footer navigation"><ul><li><label for="locale">Language</label> <select name="locale" id="locale" class="form-control"><option value="af-ZA" dir="ltr">Afrikaans (Suid-Afrika)</option><option value="ar-TN" dir="rtl">العربية (تونس)</option><option value="cs-CZ" dir="ltr">čeština (Česko)</option><option value="de-DE" dir="ltr">Deutsch (Deutschland)</option><option value="en-US" dir="ltr">English</option><option value="es-ES" dir="ltr">español de España</option><option value="fa-IR" dir="rtl">فارسی (ایران)</option><option value="fi-FI" dir="ltr">suomi (Suomi)</option><option value="fr-FR" dir="ltr">français (France)</option><option value="he-IL" dir="rtl">עברית (ישראל)</option><option value="hi-IN" dir="ltr">हिन्दी (भारत)</option><option value="hu-HU" dir="ltr">magyar (Magyarország)</option><option value="it-IT" dir="ltr">italiano (Italia)</option><option value="ja-JP" dir="ltr">日本語 (日本)</option><option value="nb-NO" dir="ltr">norsk bokmål (Norge)</option><option value="pl-PL" dir="ltr">polski (Polska)</option><option value="pt-BR" dir="ltr">português (Brasil)</option><option value="pt-PT" dir="ltr">português europeu</option><option value="ro-RO" dir="ltr">română (România)</option><option value="ru-RU" dir="ltr">русский (Россия)</option><option value="th-TH" dir="ltr">ไทย (ไทย)</option><option value="tr-TR" dir="ltr">Türkçe (Türkiye)</option><option value="zh-CN" dir="ltr">中文(中国)</option><option value="zh-HK" dir="ltr">中文(中國香港特別行政區)</option></select> <label for="control-filter">Control Filter:</label> <input id="control-filter" placeholder="ex. text" class="form-control"></li><li style="float:right">v4.0.0</li></ul></nav><span id="formeo-logo-wrap"></span></header><section id="main_content" class="inner"><form class="build-form"></form><div class="render-form"></div></section><div class="container render-btn-wrap" id="editor-action-buttons"></div><div id="formData-popover" popover><div class="popover-header"><h3>Test formData</h3><div><button type="button" id="format-json">Format</button> <button type="button" id="collapse-json">Collapse</button> <button type="button" id="copy-json">Copy to Clipboard</button></div></div><pre id="formData-editor"></pre><div class="formData-actions"><button popovertarget="formData-popover" popovertargetaction="hide" type="button">Cancel</button> <button id="submit-formData" type="button">Submit</button></div></div><footer id="demo-footer"><nav aria-label="Footer navigation"><ul><li><a href="https://github.com/Draggable/formeo" target="_blank" title="View project on GitHub"><img src="/formeo/assets/img/github.png" width="77" alt="GitHub"></a></li></ul></nav></footer></div></body></html>
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -436,7 +436,7 @@ if (window !== void 0) {
436
436
  window.SmartTooltip = SmartTooltip;
437
437
  }
438
438
  const name$1 = "formeo";
439
- const version$2 = "3.1.4";
439
+ const version$2 = "4.0.0";
440
440
  const type = "module";
441
441
  const main = "dist/formeo.cjs.js";
442
442
  const module$1 = "dist/formeo.es.js";
@@ -567,7 +567,7 @@ const dependencies = {
567
567
  sortablejs: "^1.15.3"
568
568
  };
569
569
  const release = {
570
- branch: "master",
570
+ branch: "main",
571
571
  verifyConditions: [
572
572
  "@semantic-release/changelog",
573
573
  "@semantic-release/npm",
@@ -5001,7 +5001,7 @@ class DOM {
5001
5001
  }
5002
5002
  const _this = this;
5003
5003
  const processed = ["children", "content"];
5004
- const { className, options, dataset, conditions, ...elem } = this.processElemArg(elemArg);
5004
+ const { className, options, dataset, ...elem } = this.processElemArg(elemArg);
5005
5005
  processed.push("tag");
5006
5006
  let childType;
5007
5007
  const { tag } = elem;
@@ -7033,7 +7033,7 @@ class Panels {
7033
7033
  }
7034
7034
  getPanelDisplay() {
7035
7035
  const column = this.panelsWrap;
7036
- const width = Number.parseInt(dom.getStyle(column, "width"));
7036
+ const width = Number.parseInt(dom.getStyle(column, "width"), 10);
7037
7037
  const autoDisplayType = width > 390 ? "tabbed" : "slider";
7038
7038
  const isAuto = this.opts.displayType === "auto";
7039
7039
  this.panelDisplay = isAuto ? autoDisplayType : this.opts.displayType || defaults$2.displayType;
@@ -7289,6 +7289,12 @@ class Component extends Data {
7289
7289
  }
7290
7290
  const parent = this.parent;
7291
7291
  const children = this.children;
7292
+ this.dispatchComponentEvent("onRemove", {
7293
+ path,
7294
+ parent,
7295
+ children: [...children]
7296
+ // copy array since children will be modified
7297
+ });
7292
7298
  forEach(children, (child) => child.remove());
7293
7299
  this.dom.parentElement.removeChild(this.dom);
7294
7300
  remove(components.getAddress(`${parent.name}s.${parent.id}.children`), this.id);
@@ -7430,6 +7436,11 @@ class Component extends Data {
7430
7436
  if (this.name !== "field") {
7431
7437
  this.cloneChildren(newClone);
7432
7438
  }
7439
+ this.dispatchComponentEvent("onClone", {
7440
+ original: this,
7441
+ clone: newClone,
7442
+ parent
7443
+ });
7433
7444
  return newClone;
7434
7445
  });
7435
7446
  __publicField(this, "createChildWrap", (children) => dom.create({
@@ -7501,11 +7512,91 @@ class Component extends Data {
7501
7512
  this.address = `${this.name}s.${this.id}`;
7502
7513
  this.dataPath = `${this.address}.`;
7503
7514
  this.editPanels = /* @__PURE__ */ new Map();
7515
+ this.eventListeners = /* @__PURE__ */ new Map();
7516
+ this.initEventHandlers();
7517
+ }
7518
+ /**
7519
+ * Initialize event handlers based on config
7520
+ */
7521
+ initEventHandlers() {
7522
+ if (!this.config.events) {
7523
+ return;
7524
+ }
7525
+ Object.entries(this.config.events).forEach(([eventName, handler]) => {
7526
+ this.addEventListener(eventName, handler);
7527
+ });
7528
+ }
7529
+ /**
7530
+ * Add an event listener to this component
7531
+ * @param {string} eventName - Name of the event
7532
+ * @param {function} handler - Event handler function
7533
+ */
7534
+ addEventListener(eventName, handler) {
7535
+ if (!this.eventListeners.has(eventName)) {
7536
+ this.eventListeners.set(eventName, []);
7537
+ }
7538
+ this.eventListeners.get(eventName).push(handler);
7539
+ }
7540
+ /**
7541
+ * Remove an event listener from this component
7542
+ * @param {string} eventName - Name of the event
7543
+ * @param {function} handler - Event handler function to remove
7544
+ */
7545
+ removeEventListener(eventName, handler) {
7546
+ var _a;
7547
+ if (!((_a = this.eventListeners) == null ? void 0 : _a.has(eventName))) {
7548
+ return;
7549
+ }
7550
+ const handlers = this.eventListeners.get(eventName);
7551
+ const index2 = handlers.indexOf(handler);
7552
+ if (index2 > -1) {
7553
+ handlers.splice(index2, 1);
7554
+ }
7555
+ }
7556
+ /**
7557
+ * Dispatch a component event to all registered listeners
7558
+ * @param {string} eventName - Name of the event to dispatch
7559
+ * @param {object} eventData - Data to pass to event handlers
7560
+ */
7561
+ dispatchComponentEvent(eventName, eventData = {}) {
7562
+ var _a;
7563
+ const fullEventData = {
7564
+ component: this,
7565
+ type: eventName,
7566
+ timestamp: Date.now(),
7567
+ ...eventData
7568
+ };
7569
+ if ((_a = this.eventListeners) == null ? void 0 : _a.has(eventName)) {
7570
+ this.eventListeners.get(eventName).forEach((handler) => {
7571
+ try {
7572
+ if (typeof handler === "function") {
7573
+ handler(fullEventData);
7574
+ }
7575
+ } catch (error) {
7576
+ console.error(`Error in ${eventName} event handler for ${this.name} ${this.id}:`, error);
7577
+ }
7578
+ });
7579
+ }
7580
+ return fullEventData;
7581
+ }
7582
+ /**
7583
+ * Override Data.set to dispatch component update events
7584
+ */
7585
+ set(path, newVal) {
7586
+ const oldVal = this.get(path);
7587
+ const result = super.set(path, newVal);
7588
+ if (oldVal !== newVal && this.dom) {
7589
+ this.dispatchComponentEvent("onUpdate", {
7590
+ path,
7591
+ oldValue: oldVal,
7592
+ newValue: newVal
7593
+ });
7594
+ }
7595
+ return result;
7504
7596
  }
7505
7597
  // mutationHandler = mutations =>
7506
7598
  // mutations.map(mutation => {
7507
- // @todo pull handler form config
7508
- // see dom.create.onRender for implementation pattern
7599
+ // @todo pull handler form config see dom.create.onRender for implementation pattern
7509
7600
  // })
7510
7601
  // observe(container) {
7511
7602
  // this.observer.disconnect()
@@ -7708,7 +7799,24 @@ class Component extends Data {
7708
7799
  }
7709
7800
  const childComponentType = `${childGroup}s`;
7710
7801
  const child = components.getAddress(`${childComponentType}.${childId}`) || components[childComponentType].add(childId, data);
7711
- childWrap.insertBefore(child.dom, childWrap.children[index2]);
7802
+ if (index2 >= childWrap.children.length) {
7803
+ childWrap.appendChild(child.dom);
7804
+ } else {
7805
+ childWrap.children[index2].before(child.dom);
7806
+ }
7807
+ this.dispatchComponentEvent("onAddChild", {
7808
+ parent: this,
7809
+ target: child,
7810
+ child,
7811
+ index: index2
7812
+ });
7813
+ child.dispatchComponentEvent("onAdd", {
7814
+ parent: this,
7815
+ target: child,
7816
+ index: index2,
7817
+ addedVia: "addChild"
7818
+ // indicate how the component was added
7819
+ });
7712
7820
  (_b = (_a = this.config.events) == null ? void 0 : _a.onAddChild) == null ? void 0 : _b.call(_a, { parent: this, child });
7713
7821
  const grandChildren = child.get("children");
7714
7822
  if (grandChildren == null ? void 0 : grandChildren.length) {
@@ -7817,6 +7925,17 @@ class Component extends Data {
7817
7925
  }
7818
7926
  };
7819
7927
  const component = (_a = onAddConditions[fromType]) == null ? void 0 : _a.call(onAddConditions, item, newIndex2);
7928
+ this.dispatchComponentEvent("onAdd", {
7929
+ from,
7930
+ to,
7931
+ item,
7932
+ newIndex: newIndex2,
7933
+ fromType,
7934
+ toType,
7935
+ addedComponent: component,
7936
+ addedVia: "dragDrop"
7937
+ // indicate how the component was added
7938
+ });
7820
7939
  defaultOnAdd();
7821
7940
  return component;
7822
7941
  }
@@ -7839,6 +7958,9 @@ class Component extends Data {
7839
7958
  * Callback for onRender, executes any defined onRender for component
7840
7959
  */
7841
7960
  onRender() {
7961
+ this.dispatchComponentEvent("onRender", {
7962
+ dom: this.dom
7963
+ });
7842
7964
  const { events: events2 } = this.config;
7843
7965
  if (!events2) {
7844
7966
  return null;
package/dist/formeo.css CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 3.1.4
4
+ Version: 4.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7