@sequent-org/moodboard 1.2.104 → 1.2.106

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.104",
3
+ "version": "1.2.106",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -38,6 +38,8 @@ export class PlacementTool extends BaseTool {
38
38
  // Состояние выбранного изображения
39
39
  this.selectedImage = null; // { file, fileName, fileSize, mimeType, properties }
40
40
  this.ghostContainer = null; // Контейнер для "призрака" файла, изображения, текста, записки, эмоджи, фрейма или фигур
41
+ // Оригинальные стили курсора PIXI, чтобы можно было временно переопределить pointer для текстового инструмента
42
+ this._origCursorStyles = null;
41
43
 
42
44
  if (this.eventBus) {
43
45
  this.eventBus.on(Events.Place.Set, (cfg) => {
@@ -47,6 +49,8 @@ export class PlacementTool extends BaseTool {
47
49
  const cur = this._getPendingCursor();
48
50
  this.app.view.style.cursor = (cur === 'default') ? '' : cur;
49
51
  }
52
+ // При выборе текста заставляем pointer вести себя как текстовый курсор
53
+ this._updateCursorOverride();
50
54
 
51
55
  // Показываем призрак для записки, эмоджи, фрейма или фигур, если они активны
52
56
  if (this.pending && this.app && this.world) {
@@ -96,6 +100,8 @@ export class PlacementTool extends BaseTool {
96
100
  this.selectedFile = null;
97
101
  this.selectedImage = null;
98
102
  this.hideGhost();
103
+ // Возвращаем стандартное поведение курсора, когда уходим с PlacementTool
104
+ this._updateCursorOverride();
99
105
  }
100
106
  });
101
107
 
@@ -145,6 +151,8 @@ export class PlacementTool extends BaseTool {
145
151
  // Добавляем обработчик движения мыши для "призрака"
146
152
  this.app.view.addEventListener('mousemove', this._onMouseMove.bind(this));
147
153
  }
154
+ // При активации синхронизируем переопределение курсора pointer для текста
155
+ this._updateCursorOverride();
148
156
 
149
157
  // Если есть выбранный файл или изображение, показываем призрак
150
158
  if (this.selectedFile) {
@@ -171,6 +179,8 @@ export class PlacementTool extends BaseTool {
171
179
  // Убираем обработчик движения мыши
172
180
  this.app.view.removeEventListener('mousemove', this._onMouseMove.bind(this));
173
181
  }
182
+ // Восстанавливаем стандартные стили курсора при выходе из инструмента
183
+ this._updateCursorOverride(true);
174
184
  this.hideGhost();
175
185
  this.app = null;
176
186
  this.world = null;
@@ -252,17 +262,35 @@ export class PlacementTool extends BaseTool {
252
262
  };
253
263
 
254
264
  if (isTextWithEditing) {
255
- // Для текста позиция должна совпадать с точкой клика без смещений
256
- // Диагностика: логируем позицию курсора и мировые координаты в момент клика
265
+ // Для текста позиция должна совпадать с точкой клика без смещений.
266
+ // Используем ту же систему координат, что HtmlTextLayer/HtmlHandlesLayer:
267
+ // CSS ←→ world через toGlobal/toLocal БЕЗ дополнительных поправок на resolution.
268
+ let worldForText = worldPoint;
257
269
  try {
270
+ const app = this.app;
271
+ const view = app?.view;
272
+ const worldLayer = this.world || this._getWorldLayer();
273
+ if (view && view.parentElement && worldLayer && worldLayer.toLocal) {
274
+ const containerRect = view.parentElement.getBoundingClientRect();
275
+ const viewRect = view.getBoundingClientRect();
276
+ const offsetLeft = viewRect.left - containerRect.left;
277
+ const offsetTop = viewRect.top - containerRect.top;
278
+ // event.x / event.y заданы в координатах контейнера ToolManager,
279
+ // поэтому приводим их к экранным координатам относительно view
280
+ const screenX = event.x - offsetLeft;
281
+ const screenY = event.y - offsetTop;
282
+ const globalPoint = new PIXI.Point(screenX, screenY);
283
+ const local = worldLayer.toLocal(globalPoint);
284
+ worldForText = { x: local.x, y: local.y };
285
+ }
258
286
  console.log('🧭 Text click', {
259
287
  cursor: { x: event.x, y: event.y },
260
- world: { x: Math.round(worldPoint.x), y: Math.round(worldPoint.y) }
288
+ world: { x: Math.round(worldForText.x), y: Math.round(worldForText.y) }
261
289
  });
262
290
  } catch (_) {}
263
291
  position = {
264
- x: Math.round(worldPoint.x),
265
- y: Math.round(worldPoint.y)
292
+ x: Math.round(worldForText.x),
293
+ y: Math.round(worldForText.y)
266
294
  };
267
295
  // Слушаем событие создания объекта, чтобы получить его ID
268
296
  const handleObjectCreated = (objectData) => {
@@ -546,6 +574,41 @@ export class PlacementTool extends BaseTool {
546
574
  }
547
575
  }
548
576
 
577
+ /**
578
+ * Включает/выключает временное переопределение cursorStyles.pointer в PIXI,
579
+ * чтобы во время работы с текстом курсор оставался текстовым даже при наведении на объекты.
580
+ * @param {boolean} forceReset - если true, всегда восстанавливает оригинальные стили
581
+ */
582
+ _updateCursorOverride(forceReset = false) {
583
+ try {
584
+ const renderer = this.app && this.app.renderer;
585
+ if (!renderer) return;
586
+ const events = renderer.events || (renderer.plugins && renderer.plugins.interaction);
587
+ const cursorStyles = events && events.cursorStyles;
588
+ if (!cursorStyles) return;
589
+
590
+ const needTextOverride = !forceReset && this.pending && this.pending.type === 'text';
591
+
592
+ if (needTextOverride) {
593
+ // Сохраняем оригинальные стили только один раз
594
+ if (!this._origCursorStyles) {
595
+ this._origCursorStyles = {
596
+ pointer: cursorStyles.pointer
597
+ };
598
+ }
599
+ cursorStyles.pointer = TEXT_CURSOR;
600
+ } else if (this._origCursorStyles) {
601
+ // Восстанавливаем оригинальный pointer
602
+ if (Object.prototype.hasOwnProperty.call(this._origCursorStyles, 'pointer')) {
603
+ cursorStyles.pointer = this._origCursorStyles.pointer;
604
+ }
605
+ this._origCursorStyles = null;
606
+ }
607
+ } catch (_) {
608
+ // Если что-то пошло не так, не ломаем остальной функционал
609
+ }
610
+ }
611
+
549
612
  /**
550
613
  * Показать "призрак" файла
551
614
  */