@sequent-org/moodboard 1.2.49 → 1.2.51

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.49",
3
+ "version": "1.2.51",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -42,8 +42,12 @@ export class ApiClient {
42
42
 
43
43
  async saveBoard(boardId, boardData) {
44
44
  try {
45
+ // Поддержка нового формата: { boardData: {...}, settings: {...} }
46
+ let payloadBoardData = boardData && boardData.boardData ? boardData.boardData : boardData;
47
+ let payloadSettings = boardData && boardData.settings ? boardData.settings : undefined;
48
+
45
49
  // Фильтруем объекты изображений и файлов - убираем избыточные данные
46
- const cleanedData = this._cleanObjectData(boardData);
50
+ const cleanedData = this._cleanObjectData(payloadBoardData);
47
51
 
48
52
  const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
49
53
 
@@ -58,7 +62,8 @@ export class ApiClient {
58
62
  credentials: 'same-origin',
59
63
  body: JSON.stringify({
60
64
  boardId: boardId,
61
- boardData: cleanedData
65
+ boardData: cleanedData,
66
+ settings: payloadSettings
62
67
  })
63
68
  });
64
69
 
@@ -132,6 +132,13 @@ export class SaveManager {
132
132
  try {
133
133
  // Получаем данные для сохранения
134
134
  const saveData = data || await this.getBoardData();
135
+
136
+ // Защита: если данные не получены (например, при уничтожении/отписке обработчиков) — выходим без ошибки
137
+ if (!saveData || typeof saveData !== 'object') {
138
+ console.warn('SaveManager: нет данных для сохранения (saveData is null) — пропускаем сохранение');
139
+ this.updateSaveStatus('idle');
140
+ return;
141
+ }
135
142
 
136
143
  // Проверяем, изменились ли данные с последнего сохранения
137
144
  if (this.lastSavedData && JSON.stringify(saveData) === JSON.stringify(this.lastSavedData)) {
package/src/core/index.js CHANGED
@@ -2151,7 +2151,52 @@ export class CoreMoodBoard {
2151
2151
  * Получение данных доски для сохранения
2152
2152
  */
2153
2153
  getBoardData() {
2154
- return this.state.serialize();
2154
+ // Базовые данные доски (объекты и метаданные из state)
2155
+ const s = this.state.serialize();
2156
+ const boardData = {
2157
+ objects: Array.isArray(s.objects) ? s.objects : [],
2158
+ name: s.name || s.title || 'Untitled Board',
2159
+ description: s.description || null
2160
+ };
2161
+
2162
+ // Настройки (settings): фон, сетка, зум, размеры канваса
2163
+ const app = this.pixi?.app;
2164
+ const rendererBg = app?.renderer?.background?.color ?? app?.renderer?.backgroundColor;
2165
+ const toHex = (num) => {
2166
+ try { return '#' + Number(num >>> 0).toString(16).padStart(6, '0'); } catch (_) { return '#F5F5F5'; }
2167
+ };
2168
+ const world = this.pixi?.worldLayer || app?.stage;
2169
+ const currentZoom = Math.max(0.1, Math.min(5, world?.scale?.x || 1));
2170
+ const canvasW = app?.view?.clientWidth || app?.view?.width || 0;
2171
+ const canvasH = app?.view?.clientHeight || app?.view?.height || 0;
2172
+
2173
+ // Сетка: берём то, что накапливается в state.board.grid через BoardService
2174
+ const gridState = (this.state?.state?.board && this.state.state.board.grid) ? this.state.state.board.grid : null;
2175
+ const gridSettings = (() => {
2176
+ if (gridState && gridState.type) {
2177
+ // Если храним полные options от serialize(), извлекаем ключевые
2178
+ const opts = gridState.options || {};
2179
+ // Унификация ключей под формат из задачи
2180
+ return {
2181
+ type: gridState.type,
2182
+ size: opts.size || 20,
2183
+ visible: opts.enabled !== false,
2184
+ color: toHex(opts.color ?? 0xE0E0E0)
2185
+ };
2186
+ }
2187
+ return null;
2188
+ })();
2189
+
2190
+ const settings = {
2191
+ backgroundColor: toHex(rendererBg ?? 0xF5F5F5),
2192
+ grid: gridSettings || undefined,
2193
+ zoom: { min: 0.1, max: 5.0, default: 1.0, current: currentZoom },
2194
+ canvas: { width: canvasW, height: canvasH }
2195
+ };
2196
+
2197
+ const boardId = (this.state?.state?.board && this.state.state.board.id) || this.options?.boardId || null;
2198
+
2199
+ return { id: boardId, boardData, settings };
2155
2200
  }
2156
2201
 
2157
2202
  /**
@@ -19,7 +19,7 @@ export class DataManager {
19
19
 
20
20
  // Восстанавливаем тип сетки и её параметры до загрузки объектов
21
21
  try {
22
- const grid = data.grid || (data.board && data.board.grid);
22
+ const grid = (data.settings && data.settings.grid) || data.grid || (data.board && data.board.grid);
23
23
  if (grid && grid.type) {
24
24
  const payload = { type: grid.type };
25
25
  const opts = grid.options || null;
@@ -29,6 +29,36 @@ export class DataManager {
29
29
  this.coreMoodboard.eventBus.emit(this.coreMoodboard.Events?.UI?.GridChange || 'ui:grid:change', payload);
30
30
  }
31
31
  } catch (_) {}
32
+
33
+ // Восстановим фон и зум из settings, если есть
34
+ try {
35
+ const settings = data.settings || {};
36
+ // Фон
37
+ const bg = settings.backgroundColor;
38
+ if (bg && this.coreMoodboard?.pixi?.app?.renderer) {
39
+ const parseHex = (v) => {
40
+ if (typeof v === 'number') return v;
41
+ if (typeof v === 'string') {
42
+ const s = v.startsWith('#') ? v.slice(1) : v;
43
+ const n = parseInt(s, 16);
44
+ if (Number.isFinite(n)) return n;
45
+ }
46
+ return null;
47
+ };
48
+ const bgInt = parseHex(bg);
49
+ if (bgInt != null) this.coreMoodboard.pixi.app.renderer.backgroundColor = bgInt;
50
+ }
51
+ // Зум
52
+ const z = settings.zoom && (settings.zoom.current || settings.zoom.default);
53
+ const world = this.coreMoodboard?.pixi?.worldLayer || this.coreMoodboard?.pixi?.app?.stage;
54
+ if (world && Number.isFinite(z) && z > 0) {
55
+ world.scale.set(z);
56
+ const percent = Math.round(z * 100);
57
+ try {
58
+ this.coreMoodboard.eventBus.emit('ui:zoom:percent', { percentage: percent });
59
+ } catch (_) {}
60
+ }
61
+ } catch (_) {}
32
62
 
33
63
  // Загружаем объекты
34
64
  if (data.objects && Array.isArray(data.objects)) {