formeo 5.5.0 → 5.6.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.
package/dist/formeo.es.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 5.4.0
4
+ Version: 5.5.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -6060,7 +6060,7 @@ if (globalThis !== void 0) globalThis.SmartTooltip = SmartTooltip;
6060
6060
  var name$1, version$2, type, main, module$1, unpkg, exports$1, files, homepage, repository, author, contributors, bugs, description, keywords, ignore, config, scripts, devDependencies, dependencies, release, commitlint, package_default;
6061
6061
  var init_package = __esmMin((() => {
6062
6062
  name$1 = "formeo";
6063
- version$2 = "5.4.0";
6063
+ version$2 = "5.5.0";
6064
6064
  type = "module";
6065
6065
  main = "dist/formeo.cjs.js";
6066
6066
  module$1 = "dist/formeo.es.js";
@@ -11116,9 +11116,11 @@ var reachesDocument = (evt) => evt.target === document || Boolean(evt.bubbles &&
11116
11116
  */
11117
11117
  var Events = class {
11118
11118
  components = null;
11119
+ destroyed = false;
11119
11120
  constructor() {
11120
11121
  this.opts = this.defaults();
11121
11122
  this.formeoUpdatedThrottled = throttle$1(() => {
11123
+ if (this.destroyed) return;
11122
11124
  const eventData = {
11123
11125
  timeStamp: globalThis.performance.now(),
11124
11126
  type: EVENT_FORMEO_UPDATED,
@@ -11174,6 +11176,7 @@ var Events = class {
11174
11176
  return evt;
11175
11177
  }
11176
11178
  runCallbacks({ type, timeStamp, detail }) {
11179
+ if (this.destroyed) return;
11177
11180
  if (type === "formeoUpdated") return this.formeoUpdatedThrottled();
11178
11181
  if (type === "formeoSaved") return this.opts.onSave({
11179
11182
  timeStamp,
@@ -11201,6 +11204,7 @@ var Events = class {
11201
11204
  confirmClearAll = (detail) => {
11202
11205
  const evt = new globalThis.CustomEvent("confirmClearAll", { detail });
11203
11206
  document.dispatchEvent(evt);
11207
+ if (this.destroyed) return;
11204
11208
  this.opts.confirmClearAll({
11205
11209
  timeStamp: evt.timeStamp,
11206
11210
  type: evt.type,
@@ -11209,7 +11213,7 @@ var Events = class {
11209
11213
  };
11210
11214
  formeoLoaded = (formeo) => {
11211
11215
  document.dispatchEvent(new globalThis.CustomEvent("formeoLoaded", { detail: { formeo } }));
11212
- this.opts.formeoLoaded(formeo);
11216
+ if (!this.destroyed) this.opts.formeoLoaded(formeo);
11213
11217
  };
11214
11218
  columnResized = (detail) => document.dispatchEvent(new globalThis.CustomEvent("columnResized", { detail }));
11215
11219
  /**
@@ -11219,7 +11223,7 @@ var Events = class {
11219
11223
  */
11220
11224
  onResizeWindow = () => {
11221
11225
  const { columns, controls } = this.components || {};
11222
- if (!columns || !controls?.dom?.isConnected || this.resizeFrame) return;
11226
+ if (this.destroyed || !columns || !controls?.dom?.isConnected || this.resizeFrame) return;
11223
11227
  this.resizeFrame = window.requestAnimationFrame(() => {
11224
11228
  this.resizeFrame = null;
11225
11229
  for (const column of Object.values(columns.data)) {
@@ -11234,6 +11238,18 @@ var Events = class {
11234
11238
  }
11235
11239
  });
11236
11240
  };
11241
+ /**
11242
+ * Stop calling this editor's option callbacks, including a trailing onUpdate/onChange that is
11243
+ * already scheduled, and cancel a pending resize frame. FormeoEditor#destroy (#166) calls it.
11244
+ * DOM events are still dispatched, so page listeners are unaffected.
11245
+ */
11246
+ destroy() {
11247
+ this.destroyed = true;
11248
+ if (this.resizeFrame) {
11249
+ window.cancelAnimationFrame(this.resizeFrame);
11250
+ this.resizeFrame = null;
11251
+ }
11252
+ }
11237
11253
  };
11238
11254
  var events = new Events();
11239
11255
  //#endregion
@@ -13106,6 +13122,24 @@ var init_sortable_esm = __esmMin((() => {
13106
13122
  Sortable.mount(Remove, Revert);
13107
13123
  }));
13108
13124
  //#endregion
13125
+ //#region src/lib/js/common/sortable.js
13126
+ var destroySortables;
13127
+ var init_sortable = __esmMin((() => {
13128
+ init_sortable_esm();
13129
+ destroySortables = (root) => {
13130
+ if (!root) return 0;
13131
+ let count = 0;
13132
+ for (const el of [root, ...root.querySelectorAll("*")]) {
13133
+ const sortable = Sortable.get(el);
13134
+ if (sortable) {
13135
+ sortable.destroy();
13136
+ count++;
13137
+ }
13138
+ }
13139
+ return count;
13140
+ };
13141
+ }));
13142
+ //#endregion
13109
13143
  //#region src/lib/js/components/panels.js
13110
13144
  var defaults$1, getTransition, Panels;
13111
13145
  var init_panels = __esmMin((() => {
@@ -13135,18 +13169,25 @@ var init_panels = __esmMin((() => {
13135
13169
  const panelsWrap = this.createPanelsWrap();
13136
13170
  this.nav = this.navActions();
13137
13171
  this.nav.groupChange(this.activePanelIndex);
13138
- const resizeObserver = new window.ResizeObserver(([{ contentRect: { width } }]) => {
13172
+ this.resizeObserver = new window.ResizeObserver(([{ contentRect: { width } }]) => {
13139
13173
  if (this.currentWidth !== width) {
13140
13174
  this.toggleTabbedLayout();
13141
13175
  this.currentWidth = width;
13142
13176
  this.nav.setTranslateX(this.activePanelIndex, false);
13143
13177
  }
13144
13178
  });
13145
- const observeTimeout = window.setTimeout(() => {
13146
- resizeObserver.observe(panelsWrap);
13147
- window.clearTimeout(observeTimeout);
13179
+ this.observeTimeout = window.setTimeout(() => {
13180
+ this.resizeObserver?.observe(panelsWrap);
13148
13181
  }, ANIMATION_SPEED_SLOW);
13149
13182
  }
13183
+ /**
13184
+ * Stop watching the panels' size
13185
+ */
13186
+ destroy() {
13187
+ window.clearTimeout(this.observeTimeout);
13188
+ this.resizeObserver?.disconnect();
13189
+ this.resizeObserver = null;
13190
+ }
13150
13191
  getPanelDisplay() {
13151
13192
  const column = this.panelsWrap;
13152
13193
  const autoDisplayType = Number.parseInt(dom.getStyle(column, "width"), 10) > 390 ? "tabbed" : "slider";
@@ -13445,7 +13486,7 @@ var init_control = __esmMin((() => {
13445
13486
  }));
13446
13487
  //#endregion
13447
13488
  //#region src/lib/js/components/controls/options.js
13448
- init_sortable_esm();
13489
+ init_sortable();
13449
13490
  init_panels();
13450
13491
  init_control();
13451
13492
  var defaultOptions = Object.freeze({
@@ -14763,6 +14804,7 @@ var init_edit_panel_item = __esmMin((() => {
14763
14804
  var addAttributeActions, defaultConfigOptions, defaultConfigValues, EditPanel;
14764
14805
  var init_edit_panel = __esmMin((() => {
14765
14806
  init_i18n_es_min();
14807
+ init_sortable_esm();
14766
14808
  init_dom();
14767
14809
  init_helpers$2();
14768
14810
  init_string();
@@ -15088,6 +15130,7 @@ var init_edit_panel = __esmMin((() => {
15088
15130
  //#region src/lib/js/components/component.js
15089
15131
  var propertyOptions, Component;
15090
15132
  var init_component = __esmMin((() => {
15133
+ init_sortable_esm();
15091
15134
  init_animation();
15092
15135
  init_dom();
15093
15136
  init_helpers$2();
@@ -15242,6 +15285,8 @@ var init_component = __esmMin((() => {
15242
15285
  });
15243
15286
  forEach(children, (child) => child.remove());
15244
15287
  this.dom.remove();
15288
+ this.panels?.destroy();
15289
+ this.releaseSortables();
15245
15290
  remove(this.components.getAddress(siblingsPath), this.id);
15246
15291
  if (!parent.children.length) parent.emptyClass();
15247
15292
  if (parent.name === "row") parent.autoColumnWidths();
@@ -15590,6 +15635,20 @@ var init_component = __esmMin((() => {
15590
15635
  return this.saveChildOrder();
15591
15636
  };
15592
15637
  /**
15638
+ * Destroy the Sortables of this removed component and its descendants, so Sortable's page-wide
15639
+ * list stops holding them (and through them the editor). A column emptied by a drag is removed
15640
+ * from inside Sortable's drop handler; destroying that Sortable there would end the drop early,
15641
+ * so during a drag it is released once the drop has finished.
15642
+ */
15643
+ releaseSortables() {
15644
+ const { dom: removedDom } = this;
15645
+ if (Sortable.active) {
15646
+ queueMicrotask(() => destroySortables(removedDom));
15647
+ return;
15648
+ }
15649
+ destroySortables(removedDom);
15650
+ }
15651
+ /**
15593
15652
  * Handler for removing content from a sortable component
15594
15653
  * @param {Object} evt
15595
15654
  * @return {Array} updated child order
@@ -15815,6 +15874,7 @@ var init_component = __esmMin((() => {
15815
15874
  id: this.id,
15816
15875
  displayType: "auto"
15817
15876
  };
15877
+ this.panels?.destroy();
15818
15878
  this.panels = new Panels(panelsData);
15819
15879
  if (this.dom) {
15820
15880
  this.dom.querySelector(".panel-nav").replaceWith(this.panels.panelNav);
@@ -16593,6 +16653,7 @@ init_i18n_es_min();
16593
16653
  init_sortable_esm();
16594
16654
  init_dom();
16595
16655
  init_helpers$2();
16656
+ init_sortable();
16596
16657
  init_utils();
16597
16658
  init_object();
16598
16659
  init_constants();
@@ -16882,6 +16943,22 @@ var Controls = class {
16882
16943
  if (group === "layout") return this.layoutTypes[metaId.replace("layout-", "")]();
16883
16944
  return this.layoutTypes.field(elementData);
16884
16945
  };
16946
+ /**
16947
+ * Remove the controls from the page and release their Sortables and Panels. A control drag in
16948
+ * progress in these controls is ended: its ghost is removed and the page overflow it hid is
16949
+ * restored. Safe to call more than once, and before init().
16950
+ */
16951
+ destroy() {
16952
+ const element = this.dom;
16953
+ if (element && Sortable.active?.el && element.contains(Sortable.active.el)) Sortable.ghost?.remove();
16954
+ if (this.originalDocumentOverflow != null) {
16955
+ document.documentElement.style.overflow = this.originalDocumentOverflow;
16956
+ this.originalDocumentOverflow = null;
16957
+ }
16958
+ destroySortables(element);
16959
+ this.panels?.destroy();
16960
+ element?.remove();
16961
+ }
16885
16962
  applyOptions = async (controlOptions = {}) => {
16886
16963
  const { container, elements, groupOrder, ...options } = merge(defaultOptions, controlOptions);
16887
16964
  this.container = dom.resolveContainer(container);
@@ -17921,6 +17998,7 @@ var defaults = { get editor() {
17921
17998
  init_i18n_es_min();
17922
17999
  init_dom();
17923
18000
  init_loaders();
18001
+ init_sortable();
17924
18002
  init_utils();
17925
18003
  init_constants();
17926
18004
  /**
@@ -17931,9 +18009,11 @@ var INIT_STATES = {
17931
18009
  LOADING_RESOURCES: "loading",
17932
18010
  INITIALIZING: "initializing",
17933
18011
  READY: "ready",
17934
- ERROR: "error"
18012
+ ERROR: "error",
18013
+ DESTROYED: "destroyed"
17935
18014
  };
17936
18015
  var storageKeyHolders = /* @__PURE__ */ new Map();
18016
+ var pageTooltip = null;
17937
18017
  /**
17938
18018
  * Whether an editor is still on the page, or still on its way there. An editor whose container
17939
18019
  * left the page or no longer holds its DOM (a remount, a demo switch) no longer owns its key.
@@ -17941,7 +18021,7 @@ var storageKeyHolders = /* @__PURE__ */ new Map();
17941
18021
  * @return {Boolean}
17942
18022
  */
17943
18023
  var isLiveEditor = (editor) => {
17944
- if (editor.initState === INIT_STATES.ERROR) return false;
18024
+ if (editor.initState === INIT_STATES.ERROR || editor.initState === INIT_STATES.DESTROYED) return false;
17945
18025
  if (!editor.editor) return !editor.editorContainer || editor.editorContainer.isConnected;
17946
18026
  return Boolean(editor.editorContainer?.isConnected && editor.editorContainer.contains(editor.editor));
17947
18027
  };
@@ -17953,6 +18033,7 @@ var FormeoEditor$1 = class {
17953
18033
  #initPromise = null;
17954
18034
  #lockedFormData = null;
17955
18035
  #dataLoadedOnce = false;
18036
+ #onDOMContentLoaded = () => this.loadResources();
17956
18037
  /**
17957
18038
  * @param {Object} options formeo options
17958
18039
  * @param {String|Object} userFormData loaded formData
@@ -17988,7 +18069,7 @@ var FormeoEditor$1 = class {
17988
18069
  if (holder && isLiveEditor(holder)) console.warn(`formeo: another editor on this page already saves to sessionStorage key "${key}". Give each editor its own key, e.g. sessionStorage: 'orders-form'.`);
17989
18070
  storageKeyHolders.set(key, this);
17990
18071
  }
17991
- if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", this.loadResources.bind(this));
18072
+ if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", this.#onDOMContentLoaded, { once: true });
17992
18073
  else this.loadResources();
17993
18074
  }
17994
18075
  get formData() {
@@ -18011,6 +18092,7 @@ var FormeoEditor$1 = class {
18011
18092
  * @return {void}
18012
18093
  */
18013
18094
  clear() {
18095
+ if (this.isDestroyed) return;
18014
18096
  const defaultData = DEFAULT_FORMDATA();
18015
18097
  this.#lockedFormData = defaultData;
18016
18098
  this.userFormData = defaultData;
@@ -18022,7 +18104,8 @@ var FormeoEditor$1 = class {
18022
18104
  * @return {Promise} asynchronously loaded remote resources
18023
18105
  */
18024
18106
  async loadResources() {
18025
- document.removeEventListener("DOMContentLoaded", this.loadResources);
18107
+ document.removeEventListener("DOMContentLoaded", this.#onDOMContentLoaded);
18108
+ if (this.isDestroyed) return;
18026
18109
  this.#initState = INIT_STATES.LOADING_RESOURCES;
18027
18110
  const promises = [
18028
18111
  fetchIcons(this.opts.svgSprite),
@@ -18035,8 +18118,10 @@ var FormeoEditor$1 = class {
18035
18118
  ].filter(Boolean);
18036
18119
  try {
18037
18120
  await Promise.all(promises);
18121
+ if (this.isDestroyed) return;
18038
18122
  if (this.opts.allowEdit) this.init();
18039
18123
  } catch (error) {
18124
+ if (this.isDestroyed) return;
18040
18125
  this.#initState = INIT_STATES.ERROR;
18041
18126
  console.error("Failed to load resources:", error);
18042
18127
  throw error;
@@ -18048,10 +18133,15 @@ var FormeoEditor$1 = class {
18048
18133
  * dom elements, actions events and more.
18049
18134
  */
18050
18135
  init() {
18136
+ if (this.isDestroyed) return Promise.resolve(this);
18051
18137
  if (this.#initState === INIT_STATES.INITIALIZING) return this.#initPromise;
18052
18138
  if (this.#initState === INIT_STATES.READY) return this.#refreshUI();
18053
18139
  this.#initState = INIT_STATES.INITIALIZING;
18054
18140
  this.#initPromise = new Controls(this.Components).init(this.opts.controls, this.opts.stickyControls).then((controls) => {
18141
+ if (this.isDestroyed) {
18142
+ controls.destroy();
18143
+ return this;
18144
+ }
18055
18145
  this.controls = controls;
18056
18146
  this.Components.controls = controls;
18057
18147
  if (!this.#dataLoadedOnce) {
@@ -18061,13 +18151,17 @@ var FormeoEditor$1 = class {
18061
18151
  this.formId = this.Components.get("id");
18062
18152
  this.i18n = { setLang: this.#setLanguage.bind(this) };
18063
18153
  this.render();
18154
+ if (this.isDestroyed) return this;
18064
18155
  this.onResize = this.events.onResizeWindow;
18065
18156
  window.addEventListener("resize", this.onResize);
18066
18157
  this.#initState = INIT_STATES.READY;
18067
18158
  this.opts.onLoad?.(this);
18159
+ if (this.isDestroyed) return this;
18068
18160
  this.tooltipInstance = new SmartTooltip();
18161
+ pageTooltip = this.tooltipInstance;
18069
18162
  return this;
18070
18163
  }).catch((error) => {
18164
+ if (this.isDestroyed) return this;
18071
18165
  this.#initState = INIT_STATES.ERROR;
18072
18166
  console.error("Failed to initialize editor:", error);
18073
18167
  throw error;
@@ -18089,7 +18183,13 @@ var FormeoEditor$1 = class {
18089
18183
  * @return {Promise}
18090
18184
  */
18091
18185
  async #refreshUI() {
18092
- this.controls = await new Controls(this.Components).init(this.opts.controls, this.opts.stickyControls);
18186
+ if (this.isDestroyed) return this;
18187
+ const controls = await new Controls(this.Components).init(this.opts.controls, this.opts.stickyControls);
18188
+ if (this.isDestroyed) {
18189
+ controls.destroy();
18190
+ return this;
18191
+ }
18192
+ this.controls = controls;
18093
18193
  this.Components.controls = this.controls;
18094
18194
  this.render();
18095
18195
  return this;
@@ -18117,6 +18217,7 @@ var FormeoEditor$1 = class {
18117
18217
  return DEFAULT_FORMDATA();
18118
18218
  }
18119
18219
  load(formData = this.userFormData, opts = this.opts) {
18220
+ if (this.isDestroyed) return;
18120
18221
  this.Components.load(formData, opts);
18121
18222
  this.render();
18122
18223
  }
@@ -18135,16 +18236,28 @@ var FormeoEditor$1 = class {
18135
18236
  return this.#initState === INIT_STATES.READY;
18136
18237
  }
18137
18238
  /**
18239
+ * Check if destroy() was called
18240
+ * @return {boolean}
18241
+ */
18242
+ get isDestroyed() {
18243
+ return this.#initState === INIT_STATES.DESTROYED;
18244
+ }
18245
+ /**
18138
18246
  * Wait for the editor to be ready
18139
18247
  * @return {Promise} resolves when editor is ready
18140
18248
  */
18141
18249
  async whenReady() {
18142
18250
  if (this.#initState === INIT_STATES.READY) return this;
18251
+ if (this.isDestroyed) return Promise.reject(/* @__PURE__ */ new Error("Editor was destroyed"));
18143
18252
  if (this.#initState === INIT_STATES.ERROR) return Promise.reject(/* @__PURE__ */ new Error("Editor initialization failed"));
18144
- if (this.#initPromise) return this.#initPromise;
18253
+ if (this.#initPromise) return this.#initPromise.then((editor) => {
18254
+ if (this.isDestroyed) throw new Error("Editor was destroyed");
18255
+ return editor;
18256
+ });
18145
18257
  return new Promise((resolve, reject) => {
18146
18258
  const checkReady = () => {
18147
18259
  if (this.#initState === INIT_STATES.READY) resolve(this);
18260
+ else if (this.isDestroyed) reject(/* @__PURE__ */ new Error("Editor was destroyed"));
18148
18261
  else if (this.#initState === INIT_STATES.ERROR) reject(/* @__PURE__ */ new Error("Editor initialization failed"));
18149
18262
  else globalThis.requestAnimationFrame(checkReady);
18150
18263
  };
@@ -18156,6 +18269,7 @@ var FormeoEditor$1 = class {
18156
18269
  * @return {void}
18157
18270
  */
18158
18271
  render() {
18272
+ if (this.isDestroyed) return;
18159
18273
  if (!this.controls) return globalThis.requestAnimationFrame(() => this.render());
18160
18274
  this.stages = Object.values(this.Components.get("stages"));
18161
18275
  if (this.opts.controlOnLeft) for (const stage of this.stages) stage.dom.style.order = 1;
@@ -18186,6 +18300,46 @@ var FormeoEditor$1 = class {
18186
18300
  }
18187
18301
  this.events.formeoLoaded(this);
18188
18302
  }
18303
+ /**
18304
+ * Remove the editor from the page and release what it holds: its Sortable instances, resize
18305
+ * observers, window resize listener, pending callbacks and loaded components. Other editors on
18306
+ * the page keep working, and a new editor can mount in the same container.
18307
+ * Safe to call more than once, and before the editor is ready.
18308
+ * @return {void}
18309
+ */
18310
+ destroy() {
18311
+ if (this.isDestroyed) return;
18312
+ this.#initState = INIT_STATES.DESTROYED;
18313
+ document.removeEventListener("DOMContentLoaded", this.#onDOMContentLoaded);
18314
+ window.removeEventListener("resize", this.onResize);
18315
+ this.events.destroy();
18316
+ if (this.opts.sessionStorage) {
18317
+ const key = formDataStorageKey(this.opts.sessionStorage);
18318
+ if (storageKeyHolders.get(key) === this) storageKeyHolders.delete(key);
18319
+ }
18320
+ this.controls?.destroy();
18321
+ destroySortables(this.editor);
18322
+ for (const type of [
18323
+ "stages",
18324
+ "rows",
18325
+ "columns",
18326
+ "fields"
18327
+ ]) {
18328
+ for (const component of Object.values(this.Components[type]?.data || {})) component.panels?.destroy();
18329
+ this.Components[type]?.empty();
18330
+ }
18331
+ this.editor?.remove();
18332
+ this.Components.empty();
18333
+ if (pageTooltip && !document.querySelector(".formeo-editor")) {
18334
+ pageTooltip.destroy();
18335
+ pageTooltip = null;
18336
+ }
18337
+ this.tooltipInstance = null;
18338
+ this.editor = null;
18339
+ this.controls = null;
18340
+ this.Components.controls = null;
18341
+ this.stages = [];
18342
+ }
18189
18343
  };
18190
18344
  //#endregion
18191
18345
  //#region src/lib/js/renderer/helpers.js
@@ -18467,7 +18621,7 @@ var focusFirst = (page) => {
18467
18621
  * `progress` only affects the wizard, adding a clickable step list above the pages
18468
18622
  * @param {Array<Object>} stages stage data in render order, for page titles
18469
18623
  * @param {Function} [onChange] called with (page, previousPage) whenever the page changes
18470
- * @return {{show: Function, index: Number, count: Number}|null} null when there is only one page
18624
+ * @return {{show: Function, index: Number, count: Number, destroy: Function}|null} null when there is only one page
18471
18625
  */
18472
18626
  var paginate = (form, { type, progress, labels }, stages, onChange) => {
18473
18627
  const pages = Array.from(form.children).filter((elem) => elem.classList.contains(STAGE_CLASSNAME));
@@ -18660,14 +18814,16 @@ var paginate = (form, { type, progress, labels }, stages, onChange) => {
18660
18814
  }
18661
18815
  };
18662
18816
  const ownerDocument = form.ownerDocument;
18663
- ownerDocument.addEventListener("click", ({ target }) => {
18817
+ const onDocumentClick = ({ target }) => {
18664
18818
  const control = target.closest?.("button, input");
18665
18819
  if (control?.form !== form) return;
18666
18820
  if (control?.type === "submit" || control?.tagName === "INPUT" && control.type === "image") markReported();
18667
- }, true);
18668
- ownerDocument.addEventListener("keydown", ({ key, target }) => {
18821
+ };
18822
+ const onDocumentKeydown = ({ key, target }) => {
18669
18823
  if (key === "Enter" && target.tagName === "INPUT" && target.form === form) markReported();
18670
- }, true);
18824
+ };
18825
+ ownerDocument.addEventListener("click", onDocumentClick, true);
18826
+ ownerDocument.addEventListener("keydown", onDocumentKeydown, true);
18671
18827
  for (const method of ["requestSubmit", "reportValidity"]) {
18672
18828
  const native = HTMLFormElement.prototype[method];
18673
18829
  if (typeof native !== "function") continue;
@@ -18687,7 +18843,11 @@ var paginate = (form, { type, progress, labels }, stages, onChange) => {
18687
18843
  get index() {
18688
18844
  return current;
18689
18845
  },
18690
- count
18846
+ count,
18847
+ destroy() {
18848
+ ownerDocument.removeEventListener("click", onDocumentClick, true);
18849
+ ownerDocument.removeEventListener("keydown", onDocumentKeydown, true);
18850
+ }
18691
18851
  };
18692
18852
  };
18693
18853
  //#endregion
@@ -18814,8 +18974,21 @@ var FormeoRenderer$1 = class {
18814
18974
  formData: this.form
18815
18975
  });
18816
18976
  }
18977
+ /**
18978
+ * Remove the rendered form from the page and stop its pagination. render() can be called again afterwards.
18979
+ * @return {void}
18980
+ */
18981
+ destroy() {
18982
+ this.pager?.destroy();
18983
+ this.pager = null;
18984
+ this.renderedForm?.remove();
18985
+ this.renderedForm = null;
18986
+ this.components = Object.create(null);
18987
+ }
18817
18988
  getRenderedForm(formData = this.form) {
18818
18989
  this.form = cleanFormData(formData);
18990
+ this.pager?.destroy();
18991
+ this.pager = null;
18819
18992
  const renderCount = document.getElementsByClassName("formeo-render").length;
18820
18993
  const config = {
18821
18994
  ...this.config,