@sequent-org/moodboard 1.2.20 → 1.2.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sequent-org/moodboard",
3
- "version": "1.2.20",
3
+ "version": "1.2.21",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
package/src/core/index.js CHANGED
@@ -2062,6 +2062,17 @@ export class CoreMoodBoard {
2062
2062
  * Создание объекта из полных данных (для загрузки с сервера)
2063
2063
  */
2064
2064
  createObjectFromData(objectData) {
2065
+ // Защита от двойной загрузки одного и того же объекта (дубликаты при повторном вызове loadData)
2066
+ try {
2067
+ const id = objectData && objectData.id;
2068
+ const alreadyInPixi = !!(id && this.pixi && this.pixi.objects && this.pixi.objects.has(id));
2069
+ const alreadyInState = !!(id && Array.isArray(this.state?.state?.objects) && this.state.state.objects.some(o => o && o.id === id));
2070
+ if (alreadyInPixi || alreadyInState) {
2071
+ // Объект уже создан ранее в этой сессии — не добавляем повторно ни в state, ни в PIXI
2072
+ return objectData;
2073
+ }
2074
+ } catch (_) { /* no-op */ }
2075
+
2065
2076
  // Инициализируем флаг компенсации пивота для загруженных объектов.
2066
2077
  // В state координаты хранятся как левый-верх. PIXI позиционирует по центру (anchor/pivot по центру),
2067
2078
  // поэтому при создании нужно ДОБАВИТЬ половину ширины/высоты (т.е. pivotCompensated должен быть false),
@@ -73,9 +73,22 @@ export class DataManager {
73
73
  clearBoard() {
74
74
  if (!this.coreMoodboard) return;
75
75
 
76
+ // 1) Удаляем все объекты, известные состоянию
76
77
  const objects = this.coreMoodboard.objects || [];
77
78
  objects.forEach(obj => this.coreMoodboard.deleteObject(obj.id));
78
-
79
+
80
+ // 2) Страховка: удаляем «висячие» PIXI-объекты, которые не попали в state
81
+ try {
82
+ const pixi = this.coreMoodboard.pixi;
83
+ const stateIds = new Set((this.coreMoodboard.state?.state?.objects || []).map(o => o && o.id));
84
+ if (pixi && pixi.objects && pixi.objects.size > 0) {
85
+ for (const [objectId] of pixi.objects) {
86
+ if (!stateIds.has(objectId)) {
87
+ pixi.removeObject(objectId);
88
+ }
89
+ }
90
+ }
91
+ } catch (_) { /* no-op */ }
79
92
 
80
93
  return objects.length;
81
94
  }