formeo 5.0.0 → 5.0.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.
Binary file
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 4.2.5
4
+ Version: 5.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -434,7 +434,7 @@ if (window !== void 0) {
434
434
  window.SmartTooltip = SmartTooltip;
435
435
  }
436
436
  const name$1 = "formeo";
437
- const version$2 = "4.2.5";
437
+ const version$2 = "5.0.0";
438
438
  const pkg = {
439
439
  name: name$1,
440
440
  version: version$2
@@ -10716,11 +10716,25 @@ const Columns2 = columns;
10716
10716
  const Fields2 = fields;
10717
10717
  const Controls2 = Controls$2;
10718
10718
  const getFormData = (formData, useSessionStorage = false) => {
10719
- if (formData) {
10720
- return clone$1(parseData(formData));
10719
+ if (formData !== void 0 && formData !== null) {
10720
+ const parsed = parseData(formData);
10721
+ if (parsed && typeof parsed === "object") {
10722
+ const cloned = clone$1(parsed);
10723
+ return {
10724
+ id: cloned.id || DEFAULT_FORMDATA().id,
10725
+ stages: cloned.stages || DEFAULT_FORMDATA().stages,
10726
+ rows: cloned.rows || {},
10727
+ columns: cloned.columns || {},
10728
+ fields: cloned.fields || {}
10729
+ };
10730
+ }
10731
+ console.warn("Formeo: Invalid formData provided, using default");
10721
10732
  }
10722
10733
  if (useSessionStorage) {
10723
- return sessionStorage.get(SESSION_FORMDATA_KEY) || DEFAULT_FORMDATA();
10734
+ const sessionData = sessionStorage.get(SESSION_FORMDATA_KEY);
10735
+ if (sessionData) {
10736
+ return sessionData;
10737
+ }
10724
10738
  }
10725
10739
  return DEFAULT_FORMDATA();
10726
10740
  };
@@ -11124,7 +11138,18 @@ const defaults = {
11124
11138
  };
11125
11139
  }
11126
11140
  };
11141
+ const INIT_STATES = {
11142
+ CREATED: "created",
11143
+ LOADING_RESOURCES: "loading",
11144
+ INITIALIZING: "initializing",
11145
+ READY: "ready",
11146
+ ERROR: "error"
11147
+ };
11127
11148
  let FormeoEditor$1 = class FormeoEditor {
11149
+ #initState = INIT_STATES.CREATED;
11150
+ #initPromise = null;
11151
+ #lockedFormData = null;
11152
+ #dataLoadedOnce = false;
11128
11153
  /**
11129
11154
  * @param {Object} options formeo options
11130
11155
  * @param {String|Object} userFormData loaded formData
@@ -11139,7 +11164,9 @@ let FormeoEditor$1 = class FormeoEditor {
11139
11164
  this.opts = opts;
11140
11165
  dom.setOptions = opts;
11141
11166
  components.config = config;
11142
- this.userFormData = userFormData || formData;
11167
+ const providedData = userFormData || formData;
11168
+ this.#lockedFormData = providedData ? cleanFormData(providedData) : null;
11169
+ this.userFormData = this.#lockedFormData;
11143
11170
  this.Components = components;
11144
11171
  this.dom = dom;
11145
11172
  events.init({ debug, ...events$1 });
@@ -11154,7 +11181,9 @@ let FormeoEditor$1 = class FormeoEditor {
11154
11181
  return this.Components.formData;
11155
11182
  }
11156
11183
  set formData(data = {}) {
11157
- this.userFormData = cleanFormData(data);
11184
+ const cleaned = cleanFormData(data);
11185
+ this.#lockedFormData = cleaned;
11186
+ this.userFormData = cleaned;
11158
11187
  this.load(this.userFormData, this.opts);
11159
11188
  }
11160
11189
  loadData(data = {}) {
@@ -11168,7 +11197,9 @@ let FormeoEditor$1 = class FormeoEditor {
11168
11197
  * @return {void}
11169
11198
  */
11170
11199
  clear() {
11171
- this.userFormData = DEFAULT_FORMDATA();
11200
+ const defaultData = DEFAULT_FORMDATA();
11201
+ this.#lockedFormData = defaultData;
11202
+ this.userFormData = defaultData;
11172
11203
  this.Components.load(this.userFormData, this.opts);
11173
11204
  this.render();
11174
11205
  }
@@ -11178,6 +11209,7 @@ let FormeoEditor$1 = class FormeoEditor {
11178
11209
  */
11179
11210
  async loadResources() {
11180
11211
  document.removeEventListener("DOMContentLoaded", this.loadResources);
11212
+ this.#initState = INIT_STATES.LOADING_RESOURCES;
11181
11213
  const promises = [
11182
11214
  fetchIcons(this.opts.svgSprite),
11183
11215
  fetchFormeoStyle(this.opts.style),
@@ -11187,38 +11219,142 @@ let FormeoEditor$1 = class FormeoEditor {
11187
11219
  locale: globalThis.sessionStorage?.getItem(SESSION_LOCALE_KEY)
11188
11220
  })
11189
11221
  ].filter(Boolean);
11190
- await Promise.all(promises);
11191
- if (this.opts.allowEdit) {
11192
- this.init();
11222
+ try {
11223
+ await Promise.all(promises);
11224
+ if (this.opts.allowEdit) {
11225
+ this.init();
11226
+ }
11227
+ } catch (error) {
11228
+ this.#initState = INIT_STATES.ERROR;
11229
+ console.error("Failed to load resources:", error);
11230
+ throw error;
11193
11231
  }
11194
11232
  }
11195
11233
  /**
11196
11234
  * Formeo initializer
11197
- * @return {Object} References to formeo instance,
11235
+ * @return {Promise} References to formeo instance,
11198
11236
  * dom elements, actions events and more.
11199
11237
  */
11200
11238
  init() {
11201
- return Controls$2.init(this.opts.controls, this.opts.stickyControls).then((controls) => {
11239
+ if (this.#initState === INIT_STATES.INITIALIZING) {
11240
+ return this.#initPromise;
11241
+ }
11242
+ if (this.#initState === INIT_STATES.READY) {
11243
+ return this.#refreshUI();
11244
+ }
11245
+ this.#initState = INIT_STATES.INITIALIZING;
11246
+ this.#initPromise = Controls$2.init(this.opts.controls, this.opts.stickyControls).then((controls) => {
11202
11247
  this.controls = controls;
11203
- this.load(this.userFormData, this.opts);
11248
+ if (!this.#dataLoadedOnce) {
11249
+ this.#loadInitialData();
11250
+ this.#dataLoadedOnce = true;
11251
+ }
11204
11252
  this.formId = components.get("id");
11205
11253
  this.i18n = {
11206
- setLang: (formeoLocale) => {
11207
- globalThis.sessionStorage?.setItem(SESSION_LOCALE_KEY, formeoLocale);
11208
- const loadLang = mi18n.setCurrent(formeoLocale);
11209
- loadLang.then(() => {
11210
- this.init();
11211
- }, console.error);
11212
- }
11254
+ setLang: this.#setLanguage.bind(this)
11213
11255
  };
11256
+ this.render();
11257
+ this.#initState = INIT_STATES.READY;
11214
11258
  this.opts.onLoad?.(this);
11215
11259
  this.tooltipInstance = new SmartTooltip();
11260
+ return this;
11261
+ }).catch((error) => {
11262
+ this.#initState = INIT_STATES.ERROR;
11263
+ console.error("Failed to initialize editor:", error);
11264
+ throw error;
11216
11265
  });
11266
+ return this.#initPromise;
11267
+ }
11268
+ /**
11269
+ * Set language without reloading form data (fixes race condition)
11270
+ * @param {string} formeoLocale - locale code
11271
+ * @return {Promise}
11272
+ */
11273
+ async #setLanguage(formeoLocale) {
11274
+ globalThis.sessionStorage?.setItem(SESSION_LOCALE_KEY, formeoLocale);
11275
+ await mi18n.setCurrent(formeoLocale);
11276
+ await this.#refreshUI();
11277
+ }
11278
+ /**
11279
+ * Refresh UI without reloading data (used for language changes)
11280
+ * @return {Promise}
11281
+ */
11282
+ async #refreshUI() {
11283
+ this.controls = await Controls$2.init(this.opts.controls, this.opts.stickyControls);
11284
+ this.render();
11285
+ return this;
11286
+ }
11287
+ /**
11288
+ * Load initial data with proper priority
11289
+ */
11290
+ #loadInitialData() {
11291
+ const dataToLoad = this.#getDataWithPriority();
11292
+ this.Components.load(dataToLoad, this.opts);
11293
+ }
11294
+ /**
11295
+ * Get form data with proper priority:
11296
+ * 1. User-provided data (locked at construction)
11297
+ * 2. SessionStorage (if enabled)
11298
+ * 3. Default empty form
11299
+ * @return {Object} form data to load
11300
+ */
11301
+ #getDataWithPriority() {
11302
+ if (this.#lockedFormData) {
11303
+ return clone$1(this.#lockedFormData);
11304
+ }
11305
+ if (this.opts.sessionStorage) {
11306
+ const sessionData = sessionStorage.get(SESSION_FORMDATA_KEY);
11307
+ if (sessionData) {
11308
+ return sessionData;
11309
+ }
11310
+ }
11311
+ return DEFAULT_FORMDATA();
11217
11312
  }
11218
11313
  load(formData = this.userFormData, opts = this.opts) {
11219
11314
  this.Components.load(formData, opts);
11220
11315
  this.render();
11221
11316
  }
11317
+ /**
11318
+ * Get current initialization state
11319
+ * @return {string} current state
11320
+ */
11321
+ get initState() {
11322
+ return this.#initState;
11323
+ }
11324
+ /**
11325
+ * Check if the editor is ready
11326
+ * @return {boolean}
11327
+ */
11328
+ get isReady() {
11329
+ return this.#initState === INIT_STATES.READY;
11330
+ }
11331
+ /**
11332
+ * Wait for the editor to be ready
11333
+ * @return {Promise} resolves when editor is ready
11334
+ */
11335
+ async whenReady() {
11336
+ if (this.#initState === INIT_STATES.READY) {
11337
+ return this;
11338
+ }
11339
+ if (this.#initState === INIT_STATES.ERROR) {
11340
+ return Promise.reject(new Error("Editor initialization failed"));
11341
+ }
11342
+ if (this.#initPromise) {
11343
+ return this.#initPromise;
11344
+ }
11345
+ return new Promise((resolve, reject) => {
11346
+ const checkReady = () => {
11347
+ if (this.#initState === INIT_STATES.READY) {
11348
+ resolve(this);
11349
+ } else if (this.#initState === INIT_STATES.ERROR) {
11350
+ reject(new Error("Editor initialization failed"));
11351
+ } else {
11352
+ globalThis.requestAnimationFrame(checkReady);
11353
+ }
11354
+ };
11355
+ checkReady();
11356
+ });
11357
+ }
11222
11358
  /**
11223
11359
  * Render the formeo sections
11224
11360
  * @return {void}
@@ -1,7 +1,7 @@
1
1
 
2
2
  /**
3
3
  formeo - https://formeo.io
4
- Version: 4.2.5
4
+ Version: 5.0.0
5
5
  Author: Draggable https://draggable.io
6
6
  */
7
7
 
@@ -432,7 +432,7 @@ if (window !== void 0) {
432
432
  window.SmartTooltip = SmartTooltip;
433
433
  }
434
434
  const name$1 = "formeo";
435
- const version$2 = "4.2.5";
435
+ const version$2 = "5.0.0";
436
436
  const pkg = {
437
437
  name: name$1,
438
438
  version: version$2
@@ -10714,11 +10714,25 @@ const Columns2 = columns;
10714
10714
  const Fields2 = fields;
10715
10715
  const Controls2 = Controls$2;
10716
10716
  const getFormData = (formData, useSessionStorage = false) => {
10717
- if (formData) {
10718
- return clone$1(parseData(formData));
10717
+ if (formData !== void 0 && formData !== null) {
10718
+ const parsed = parseData(formData);
10719
+ if (parsed && typeof parsed === "object") {
10720
+ const cloned = clone$1(parsed);
10721
+ return {
10722
+ id: cloned.id || DEFAULT_FORMDATA().id,
10723
+ stages: cloned.stages || DEFAULT_FORMDATA().stages,
10724
+ rows: cloned.rows || {},
10725
+ columns: cloned.columns || {},
10726
+ fields: cloned.fields || {}
10727
+ };
10728
+ }
10729
+ console.warn("Formeo: Invalid formData provided, using default");
10719
10730
  }
10720
10731
  if (useSessionStorage) {
10721
- return sessionStorage.get(SESSION_FORMDATA_KEY) || DEFAULT_FORMDATA();
10732
+ const sessionData = sessionStorage.get(SESSION_FORMDATA_KEY);
10733
+ if (sessionData) {
10734
+ return sessionData;
10735
+ }
10722
10736
  }
10723
10737
  return DEFAULT_FORMDATA();
10724
10738
  };
@@ -11122,7 +11136,18 @@ const defaults = {
11122
11136
  };
11123
11137
  }
11124
11138
  };
11139
+ const INIT_STATES = {
11140
+ CREATED: "created",
11141
+ LOADING_RESOURCES: "loading",
11142
+ INITIALIZING: "initializing",
11143
+ READY: "ready",
11144
+ ERROR: "error"
11145
+ };
11125
11146
  let FormeoEditor$1 = class FormeoEditor {
11147
+ #initState = INIT_STATES.CREATED;
11148
+ #initPromise = null;
11149
+ #lockedFormData = null;
11150
+ #dataLoadedOnce = false;
11126
11151
  /**
11127
11152
  * @param {Object} options formeo options
11128
11153
  * @param {String|Object} userFormData loaded formData
@@ -11137,7 +11162,9 @@ let FormeoEditor$1 = class FormeoEditor {
11137
11162
  this.opts = opts;
11138
11163
  dom.setOptions = opts;
11139
11164
  components.config = config;
11140
- this.userFormData = userFormData || formData;
11165
+ const providedData = userFormData || formData;
11166
+ this.#lockedFormData = providedData ? cleanFormData(providedData) : null;
11167
+ this.userFormData = this.#lockedFormData;
11141
11168
  this.Components = components;
11142
11169
  this.dom = dom;
11143
11170
  events.init({ debug, ...events$1 });
@@ -11152,7 +11179,9 @@ let FormeoEditor$1 = class FormeoEditor {
11152
11179
  return this.Components.formData;
11153
11180
  }
11154
11181
  set formData(data = {}) {
11155
- this.userFormData = cleanFormData(data);
11182
+ const cleaned = cleanFormData(data);
11183
+ this.#lockedFormData = cleaned;
11184
+ this.userFormData = cleaned;
11156
11185
  this.load(this.userFormData, this.opts);
11157
11186
  }
11158
11187
  loadData(data = {}) {
@@ -11166,7 +11195,9 @@ let FormeoEditor$1 = class FormeoEditor {
11166
11195
  * @return {void}
11167
11196
  */
11168
11197
  clear() {
11169
- this.userFormData = DEFAULT_FORMDATA();
11198
+ const defaultData = DEFAULT_FORMDATA();
11199
+ this.#lockedFormData = defaultData;
11200
+ this.userFormData = defaultData;
11170
11201
  this.Components.load(this.userFormData, this.opts);
11171
11202
  this.render();
11172
11203
  }
@@ -11176,6 +11207,7 @@ let FormeoEditor$1 = class FormeoEditor {
11176
11207
  */
11177
11208
  async loadResources() {
11178
11209
  document.removeEventListener("DOMContentLoaded", this.loadResources);
11210
+ this.#initState = INIT_STATES.LOADING_RESOURCES;
11179
11211
  const promises = [
11180
11212
  fetchIcons(this.opts.svgSprite),
11181
11213
  fetchFormeoStyle(this.opts.style),
@@ -11185,38 +11217,142 @@ let FormeoEditor$1 = class FormeoEditor {
11185
11217
  locale: globalThis.sessionStorage?.getItem(SESSION_LOCALE_KEY)
11186
11218
  })
11187
11219
  ].filter(Boolean);
11188
- await Promise.all(promises);
11189
- if (this.opts.allowEdit) {
11190
- this.init();
11220
+ try {
11221
+ await Promise.all(promises);
11222
+ if (this.opts.allowEdit) {
11223
+ this.init();
11224
+ }
11225
+ } catch (error) {
11226
+ this.#initState = INIT_STATES.ERROR;
11227
+ console.error("Failed to load resources:", error);
11228
+ throw error;
11191
11229
  }
11192
11230
  }
11193
11231
  /**
11194
11232
  * Formeo initializer
11195
- * @return {Object} References to formeo instance,
11233
+ * @return {Promise} References to formeo instance,
11196
11234
  * dom elements, actions events and more.
11197
11235
  */
11198
11236
  init() {
11199
- return Controls$2.init(this.opts.controls, this.opts.stickyControls).then((controls) => {
11237
+ if (this.#initState === INIT_STATES.INITIALIZING) {
11238
+ return this.#initPromise;
11239
+ }
11240
+ if (this.#initState === INIT_STATES.READY) {
11241
+ return this.#refreshUI();
11242
+ }
11243
+ this.#initState = INIT_STATES.INITIALIZING;
11244
+ this.#initPromise = Controls$2.init(this.opts.controls, this.opts.stickyControls).then((controls) => {
11200
11245
  this.controls = controls;
11201
- this.load(this.userFormData, this.opts);
11246
+ if (!this.#dataLoadedOnce) {
11247
+ this.#loadInitialData();
11248
+ this.#dataLoadedOnce = true;
11249
+ }
11202
11250
  this.formId = components.get("id");
11203
11251
  this.i18n = {
11204
- setLang: (formeoLocale) => {
11205
- globalThis.sessionStorage?.setItem(SESSION_LOCALE_KEY, formeoLocale);
11206
- const loadLang = mi18n.setCurrent(formeoLocale);
11207
- loadLang.then(() => {
11208
- this.init();
11209
- }, console.error);
11210
- }
11252
+ setLang: this.#setLanguage.bind(this)
11211
11253
  };
11254
+ this.render();
11255
+ this.#initState = INIT_STATES.READY;
11212
11256
  this.opts.onLoad?.(this);
11213
11257
  this.tooltipInstance = new SmartTooltip();
11258
+ return this;
11259
+ }).catch((error) => {
11260
+ this.#initState = INIT_STATES.ERROR;
11261
+ console.error("Failed to initialize editor:", error);
11262
+ throw error;
11214
11263
  });
11264
+ return this.#initPromise;
11265
+ }
11266
+ /**
11267
+ * Set language without reloading form data (fixes race condition)
11268
+ * @param {string} formeoLocale - locale code
11269
+ * @return {Promise}
11270
+ */
11271
+ async #setLanguage(formeoLocale) {
11272
+ globalThis.sessionStorage?.setItem(SESSION_LOCALE_KEY, formeoLocale);
11273
+ await mi18n.setCurrent(formeoLocale);
11274
+ await this.#refreshUI();
11275
+ }
11276
+ /**
11277
+ * Refresh UI without reloading data (used for language changes)
11278
+ * @return {Promise}
11279
+ */
11280
+ async #refreshUI() {
11281
+ this.controls = await Controls$2.init(this.opts.controls, this.opts.stickyControls);
11282
+ this.render();
11283
+ return this;
11284
+ }
11285
+ /**
11286
+ * Load initial data with proper priority
11287
+ */
11288
+ #loadInitialData() {
11289
+ const dataToLoad = this.#getDataWithPriority();
11290
+ this.Components.load(dataToLoad, this.opts);
11291
+ }
11292
+ /**
11293
+ * Get form data with proper priority:
11294
+ * 1. User-provided data (locked at construction)
11295
+ * 2. SessionStorage (if enabled)
11296
+ * 3. Default empty form
11297
+ * @return {Object} form data to load
11298
+ */
11299
+ #getDataWithPriority() {
11300
+ if (this.#lockedFormData) {
11301
+ return clone$1(this.#lockedFormData);
11302
+ }
11303
+ if (this.opts.sessionStorage) {
11304
+ const sessionData = sessionStorage.get(SESSION_FORMDATA_KEY);
11305
+ if (sessionData) {
11306
+ return sessionData;
11307
+ }
11308
+ }
11309
+ return DEFAULT_FORMDATA();
11215
11310
  }
11216
11311
  load(formData = this.userFormData, opts = this.opts) {
11217
11312
  this.Components.load(formData, opts);
11218
11313
  this.render();
11219
11314
  }
11315
+ /**
11316
+ * Get current initialization state
11317
+ * @return {string} current state
11318
+ */
11319
+ get initState() {
11320
+ return this.#initState;
11321
+ }
11322
+ /**
11323
+ * Check if the editor is ready
11324
+ * @return {boolean}
11325
+ */
11326
+ get isReady() {
11327
+ return this.#initState === INIT_STATES.READY;
11328
+ }
11329
+ /**
11330
+ * Wait for the editor to be ready
11331
+ * @return {Promise} resolves when editor is ready
11332
+ */
11333
+ async whenReady() {
11334
+ if (this.#initState === INIT_STATES.READY) {
11335
+ return this;
11336
+ }
11337
+ if (this.#initState === INIT_STATES.ERROR) {
11338
+ return Promise.reject(new Error("Editor initialization failed"));
11339
+ }
11340
+ if (this.#initPromise) {
11341
+ return this.#initPromise;
11342
+ }
11343
+ return new Promise((resolve, reject) => {
11344
+ const checkReady = () => {
11345
+ if (this.#initState === INIT_STATES.READY) {
11346
+ resolve(this);
11347
+ } else if (this.#initState === INIT_STATES.ERROR) {
11348
+ reject(new Error("Editor initialization failed"));
11349
+ } else {
11350
+ globalThis.requestAnimationFrame(checkReady);
11351
+ }
11352
+ };
11353
+ checkReady();
11354
+ });
11355
+ }
11220
11356
  /**
11221
11357
  * Render the formeo sections
11222
11358
  * @return {void}