@sequent-org/moodboard 1.2.33 → 1.2.36

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.33",
3
+ "version": "1.2.36",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
package/src/core/index.js CHANGED
@@ -1189,8 +1189,8 @@ export class CoreMoodBoard {
1189
1189
  // Принудительно сохраняем пропорции для фреймов (если lockedAspect=true)
1190
1190
  const objects = this.state.getObjects();
1191
1191
  const object = objects.find(obj => obj.id === data.object);
1192
- const objectType = object ? object.type : null;
1193
- if (objectType === 'frame' && !!(object?.properties && object.properties.lockedAspect === true)) {
1192
+ const objectType = object ? object : null;
1193
+ if (object && object.type === 'frame' && object.properties && object.properties.lockedAspect === true) {
1194
1194
  const start = this._activeResize?.startSize || { width: object.width, height: object.height };
1195
1195
  const aspect = (start.width > 0 && start.height > 0) ? (start.width / start.height) : (object.width / Math.max(1, object.height));
1196
1196
  let w = Math.max(1, data.newSize.width);
@@ -1198,7 +1198,7 @@ export class CoreMoodBoard {
1198
1198
  const dw = Math.abs(w - start.width);
1199
1199
  const dh = Math.abs(h - start.height);
1200
1200
  if (dw >= dh) { h = Math.round(w / aspect); } else { w = Math.round(h * aspect); }
1201
- // Минимальная площадь фрейма ~1800px²
1201
+ // Минимальная площадь фрейма ~х2 по сторонам
1202
1202
  const minArea = 1800;
1203
1203
  const area = Math.max(1, w * h);
1204
1204
  if (area < minArea) {
@@ -1208,7 +1208,7 @@ export class CoreMoodBoard {
1208
1208
  }
1209
1209
  data.newSize = { width: w, height: h };
1210
1210
  if (!data.newPosition && this._activeResize && this._activeResize.objectId === data.object) {
1211
- const hndl = (this._activeResize.handle || '').toLowerCase();
1211
+ const hndl = (this._activeResize?.full || this._activeResize?.handle || '').toLowerCase();
1212
1212
  const startPos = this._activeResize.startPosition;
1213
1213
  const sw = this._activeResize.startSize.width;
1214
1214
  const sh = this._activeResize.startSize.height;
@@ -1216,19 +1216,45 @@ export class CoreMoodBoard {
1216
1216
  let y = startPos.y;
1217
1217
  if (hndl.includes('w')) { x = startPos.x + (sw - w); }
1218
1218
  if (hndl.includes('n')) { y = startPos.y + (sh - h); }
1219
- const isEdge = ['n','s','e','w'].includes(hnl = hndl);
1219
+ const isEdge = ['n','s','e','w'].includes(hndl);
1220
1220
  if (isEdge) {
1221
- if (hnl === 'n' || hnl === 's') {
1222
- x = startPos.x + Math.round((sw - w) / 2);
1223
- } else if (hnl === 'e' || hnl === 'w') {
1224
- y = startPos.y + Math.round((sh - h) / 2);
1225
- }
1221
+ if (hndl === 'n' || hndl === 's') x = Math.round(startPos.x + (sw - w) / 2);
1222
+ if (hndl === 'e' || hndl === 'w') y = Math.round(startPos.y + (sh - h) / 2);
1226
1223
  }
1227
1224
  data.newPosition = { x: Math.round(x), y: Math.round(y) };
1228
1225
  }
1226
+ } else if (object && object.type === 'image') {
1227
+ // Для изображений всегда фиксируем исходное соотношение сторон
1228
+ const start = this._activeResize?.startSize || { width: object.width, height: object.height };
1229
+ const startW = Math.max(1, start.width);
1230
+ const startH = Math.max(1, start.height);
1231
+ const aspect = startW / startH;
1232
+ let w = Math.max(1, data.newSize.width);
1233
+ let h = Math.max(1, data.newSize.height);
1234
+ const dw = Math.abs(w - startW);
1235
+ const dh = Math.abs(h - startH);
1236
+ if (dw >= dh) { h = Math.round(w / aspect); } else { w = Math.round(h * aspect); }
1237
+ data.newSize = { width: w, height: h };
1238
+ if (!data.newPosition && this._activeResize && this._activeResize.objectId === data.object) {
1239
+ const hndl = (this.extent?.handle || this._activeResize?.handle || '').match ? (this._activeResize?.handle || '') : '';
1240
+ const handle = (this._activeResize?.handle || '').toString().toLowerCase();
1241
+ const startPos = this._activeResize.startPosition || { x: 0, y: 0 };
1242
+ const sw = this._activeResize.startSize?.width || startW;
1243
+ const sh = this._activeResize.startSize?.height || startH;
1244
+ let x = startPos.x;
1245
+ let y = startPos.y;
1246
+ if (handle.includes('w')) { x = startPos.x + (sw - w); }
1247
+ if (handle.includes('n')) { y = startPos.y + (sh - h); }
1248
+ const edge = ['n','s','e','w'].includes(handle);
1249
+ if (edge) {
1250
+ if (handle === 'n' || handle === 's') x = Math.round(startPos.x + (sw - w) / 2);
1251
+ if (handle === 'e' || handle === 'w') y = Math.round(startPos.y + (sh - h) / 2);
1252
+ }
1253
+ data.newPosition = { x: Math.floor(x), y: Math.floor(y) };
1254
+ }
1229
1255
  }
1230
1256
  // Для произвольных фреймов также обеспечим минимальную площадь
1231
- if (objectType === 'frame' && data.newSize && !(object?.properties && object.properties.lockedAspect === true)) {
1257
+ if (object && object.type === 'frame' && data.newSize && !(object.properties && object.properties === true)) {
1232
1258
  const minArea = 1800;
1233
1259
  const w0 = Math.max(1, data.newSize.width);
1234
1260
  const h0 = Math.max(1, data.newSize.height);
@@ -1239,22 +1265,20 @@ export class CoreMoodBoard {
1239
1265
  const h = Math.round(h0 * scale);
1240
1266
  data.newSize = { width: w, height: h };
1241
1267
  if (!data.newPosition && this._activeResize && this._activeResize.objectId === data.object) {
1242
- const hndl2 = (this._activeResize.handle || '').toLowerCase();
1243
- const startPos2 = this._activeResize.startPosition;
1268
+ const h2 = (this._activeResize?.handle || '').toLowerCase();
1269
+ const sPos2 = this._activeResize.startPosition;
1244
1270
  const sw2 = this._activeResize.startSize.width;
1245
1271
  const sh2 = this._activeResize.startSize.height;
1246
- let x2 = startPos2.x;
1247
- let y2 = startPos2.y;
1248
- if (hndl2.includes('w')) { x2 = startPos2.x + (sw2 - w); }
1249
- if (hndl2.includes('n')) { y2 = startPos2.y + (sh2 - h); }
1272
+ let x2 = sPos2.x;
1273
+ let y2 = sPos2.y;
1274
+ if (h2.includes('w')) { x2 = sPos2.x + (sw2 - w); }
1275
+ if (h2.includes('n')) { y2 = sPos2.y + (sh2 - h); }
1250
1276
  data.newPosition = { x: Math.round(x2), y: Math.round(y2) };
1251
1277
  }
1252
1278
  }
1253
1279
  }
1254
1280
  // Создаем команду только если размер действительно изменился
1255
- if (data.oldSize.width !== data.newSize.width ||
1256
- data.oldSize.height !== data.newSize.height) {
1257
-
1281
+ if (data.oldSize.width !== data.newSize.width || data.oldSize.height !== data.newSize.height) {
1258
1282
  console.log(`📝 Создаем ResizeObjectCommand:`, {
1259
1283
  object: data.object,
1260
1284
  oldSize: data.oldSize,
@@ -1262,14 +1286,13 @@ export class CoreMoodBoard {
1262
1286
  oldPosition: data.oldPosition,
1263
1287
  newPosition: data.newPosition
1264
1288
  });
1265
-
1266
1289
  // Гарантируем согласованность позиции: если UI не передал, вычислим
1267
1290
  let oldPos = data.oldPosition;
1268
1291
  let newPos = data.newPosition;
1269
1292
  if ((!oldPos || !newPos) && this._activeResize && this._activeResize.objectId === data.object) {
1270
- const h = (this._activeResize.handle || '').toLowerCase();
1293
+ const h = (this._activeResize?.handle || '').toLowerCase();
1271
1294
  const start = this._activeResize.startPosition;
1272
- const startSize = this._activeResize.startSize;
1295
+ const startSize = this.optimization?.startSize || this._activeResize.startSize;
1273
1296
  const dw = (data.newSize?.width || startSize.width) - startSize.width;
1274
1297
  const dh = (data.newSize?.height || startSize.height) - startSize.height;
1275
1298
  const calcNew = { x: start.x + (h.includes('w') ? dw : 0), y: start.y + (h.includes('n') ? dh : 0) };
@@ -1277,6 +1300,7 @@ export class CoreMoodBoard {
1277
1300
  if (!newPos) newPos = calcNew;
1278
1301
  }
1279
1302
  const command = new ResizeObjectCommand(
1303
+ this,
1280
1304
  this,
1281
1305
  data.object,
1282
1306
  data.oldSize,
@@ -48,11 +48,9 @@ export class PlacementTool extends BaseTool {
48
48
  this.app.view.style.cursor = (cur === 'default') ? '' : cur;
49
49
  }
50
50
 
51
- // Показываем призрак для текста, записки, эмоджи, фрейма или фигур, если они активны
51
+ // Показываем призрак для записки, эмоджи, фрейма или фигур, если они активны
52
52
  if (this.pending && this.app && this.world) {
53
- if (this.pending.type === 'text') {
54
- this.showTextGhost();
55
- } else if (this.pending.type === 'note') {
53
+ if (this.pending.type === 'note') {
56
54
  this.showNoteGhost();
57
55
  } else if (this.pending.type === 'emoji') {
58
56
  this.showEmojiGhost();
@@ -154,9 +152,7 @@ export class PlacementTool extends BaseTool {
154
152
  } else if (this.selectedImage) {
155
153
  this.showImageGhost();
156
154
  } else if (this.pending) {
157
- if (this.pending.type === 'text') {
158
- this.showTextGhost();
159
- } else if (this.pending.type === 'note') {
155
+ if (this.pending.type === 'note') {
160
156
  this.showNoteGhost();
161
157
  } else if (this.pending.type === 'emoji') {
162
158
  this.showEmojiGhost();
@@ -256,14 +252,10 @@ export class PlacementTool extends BaseTool {
256
252
  };
257
253
 
258
254
  if (isTextWithEditing) {
259
- // Для текста используем те же размеры, что и у "призрака",
260
- // чтобы позиция совпадала пиксель-в-пиксель
261
- const fontSize = props.fontSize || 18;
262
- const ghostWidth = 120;
263
- const ghostHeight = fontSize + 20;
255
+ // Для текста позиция должна совпадать с точкой клика без смещений
264
256
  position = {
265
- x: Math.round(worldPoint.x - ghostWidth / 2),
266
- y: Math.round(worldPoint.y - ghostHeight / 2)
257
+ x: Math.round(worldPoint.x),
258
+ y: Math.round(worldPoint.y)
267
259
  };
268
260
  // Слушаем событие создания объекта, чтобы получить его ID
269
261
  const handleObjectCreated = (objectData) => {