@sequent-org/moodboard 1.2.114 → 1.2.115

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.114",
3
+ "version": "1.2.115",
4
4
  "type": "module",
5
5
  "description": "Interactive moodboard",
6
6
  "main": "./src/index.js",
@@ -34,6 +34,7 @@ export class ToolManager {
34
34
  // Последняя позиция курсора относительно контейнера (CSS-пиксели)
35
35
  this.lastMousePos = null;
36
36
  this.isMouseOverContainer = false;
37
+ this._originalPixiCursorStyles = null;
37
38
 
38
39
  // Устанавливаем курсор по умолчанию на контейнер, если инструмент ещё не активирован
39
40
  if (this.container) {
@@ -77,6 +78,7 @@ export class ToolManager {
77
78
  if (typeof this.activeTool.activate === 'function') {
78
79
  this.activeTool.activate(this.pixiApp);
79
80
  }
81
+ this.syncActiveToolCursor();
80
82
 
81
83
  return true;
82
84
  }
@@ -148,7 +150,9 @@ export class ToolManager {
148
150
  this.isMouseOverContainer = true;
149
151
  if (!this.activeTool) {
150
152
  this.container.style.cursor = DEFAULT_CURSOR;
153
+ return;
151
154
  }
155
+ this.syncActiveToolCursor();
152
156
  });
153
157
  this.container.addEventListener('mouseleave', () => { this.isMouseOverContainer = false; });
154
158
  // Убираем отдельные слушатели aux-pan на контейнере, чтобы не дублировать mousedown/mouseup
@@ -305,9 +309,55 @@ export class ToolManager {
305
309
  // Если временно активирован pan, проксируем движение именно ему
306
310
  if (this.temporaryTool === 'pan' && this.activeTool?.name === 'pan') {
307
311
  this.activeTool.onMouseMove(event);
312
+ this.syncActiveToolCursor();
308
313
  return;
309
314
  }
310
315
  this.activeTool.onMouseMove(event);
316
+ this.syncActiveToolCursor();
317
+ }
318
+
319
+ isCursorLockedToActiveTool() {
320
+ return !!this.activeTool && this.activeTool.name !== 'select';
321
+ }
322
+
323
+ getPixiCursorStyles() {
324
+ const renderer = this.pixiApp && this.pixiApp.renderer;
325
+ if (!renderer) return null;
326
+ const events = renderer.events || (renderer.plugins && renderer.plugins.interaction);
327
+ return events && events.cursorStyles ? events.cursorStyles : null;
328
+ }
329
+
330
+ getActiveToolCursor() {
331
+ const cursor = this.activeTool && this.activeTool.cursor;
332
+ if (typeof cursor === 'string' && cursor.length > 0) return cursor;
333
+ return DEFAULT_CURSOR;
334
+ }
335
+
336
+ syncActiveToolCursor() {
337
+ const cursorStyles = this.getPixiCursorStyles();
338
+ const lockCursor = this.isCursorLockedToActiveTool();
339
+ const activeCursor = this.getActiveToolCursor();
340
+
341
+ if (cursorStyles && !this._originalPixiCursorStyles) {
342
+ this._originalPixiCursorStyles = {
343
+ pointer: cursorStyles.pointer,
344
+ default: cursorStyles.default
345
+ };
346
+ }
347
+
348
+ if (cursorStyles) {
349
+ if (lockCursor) {
350
+ cursorStyles.pointer = activeCursor;
351
+ cursorStyles.default = activeCursor;
352
+ } else if (this._originalPixiCursorStyles) {
353
+ cursorStyles.pointer = this._originalPixiCursorStyles.pointer;
354
+ cursorStyles.default = this._originalPixiCursorStyles.default;
355
+ }
356
+ }
357
+
358
+ if (lockCursor && this.pixiApp && this.pixiApp.view) {
359
+ this.pixiApp.view.style.cursor = activeCursor;
360
+ }
311
361
  }
312
362
 
313
363
  handleMouseUp(e) {
@@ -329,6 +379,7 @@ export class ToolManager {
329
379
  return;
330
380
  }
331
381
  this.activeTool.onMouseUp(event);
382
+ this.syncActiveToolCursor();
332
383
  }
333
384
 
334
385
  handleDoubleClick(e) {
@@ -614,5 +665,12 @@ export class ToolManager {
614
665
  try { window.removeEventListener('wheel', this._onWindowWheel); } catch (_) {}
615
666
  this._onWindowWheel = null;
616
667
  }
668
+
669
+ const cursorStyles = this.getPixiCursorStyles();
670
+ if (cursorStyles && this._originalPixiCursorStyles) {
671
+ cursorStyles.pointer = this._originalPixiCursorStyles.pointer;
672
+ cursorStyles.default = this._originalPixiCursorStyles.default;
673
+ }
674
+ this._originalPixiCursorStyles = null;
617
675
  }
618
676
  }
@@ -8,8 +8,9 @@ import * as PIXI from 'pixi.js';
8
8
  export class DrawingTool extends BaseTool {
9
9
  constructor(eventBus) {
10
10
  super('draw', eventBus);
11
- this.cursor = 'crosshair';
12
11
  this.hotkey = 'd';
12
+ const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><path d='M4 20 L20 4 L28 12 L12 28 L4 28 Z' fill='black'/></svg>`;
13
+ this.cursor = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}") 4 28, crosshair`;
13
14
 
14
15
  // Состояние рисования
15
16
  this.isDrawing = false;
@@ -50,12 +51,7 @@ export class DrawingTool extends BaseTool {
50
51
  super.activate();
51
52
  this.app = app;
52
53
  this.world = this._getWorldLayer();
53
- // Кастомный курсор-карандаш (SVG)
54
- const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'><path d='M4 20 L20 4 L28 12 L12 28 L4 28 Z' fill='black'/></svg>`;
55
- // Горячая точка ставим в реальный нижний левый угол фигуры (x=4, y=28),
56
- // чтобы линия выходила прямо из карандаша без зазора.
57
- const url = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}") 4 28, crosshair`;
58
- if (this.app && this.app.view) this.app.view.style.cursor = url;
54
+ this.setCursor();
59
55
  }
60
56
 
61
57
  deactivate() {
@@ -70,6 +66,12 @@ export class DrawingTool extends BaseTool {
70
66
  this.world = null;
71
67
  }
72
68
 
69
+ setCursor() {
70
+ if (this.app && this.app.view) {
71
+ this.app.view.style.cursor = this.cursor;
72
+ }
73
+ }
74
+
73
75
  onMouseDown(event) {
74
76
  super.onMouseDown(event);
75
77
  if (!this.world) this.world = this._getWorldLayer();
@@ -47,6 +47,7 @@ export class PlacementTool extends BaseTool {
47
47
  // Обновляем курсор в зависимости от pending
48
48
  if (this.app && this.app.view) {
49
49
  const cur = this._getPendingCursor();
50
+ this.cursor = cur;
50
51
  this.app.view.style.cursor = (cur === 'default') ? '' : cur;
51
52
  }
52
53
  // При выборе текста заставляем pointer вести себя как текстовый курсор
@@ -147,7 +148,8 @@ export class PlacementTool extends BaseTool {
147
148
  this.world = this._getWorldLayer();
148
149
  // Курсор в зависимости от типа размещаемого объекта
149
150
  if (this.app && this.app.view) {
150
- this.app.view.style.cursor = this._getPendingCursor();
151
+ this.cursor = this._getPendingCursor();
152
+ this.app.view.style.cursor = this.cursor;
151
153
  // Добавляем обработчик движения мыши для "призрака"
152
154
  this.app.view.addEventListener('mousemove', this._onMouseMove.bind(this));
153
155
  }
@@ -492,7 +494,8 @@ export class PlacementTool extends BaseTool {
492
494
 
493
495
  startFrameDrawMode() {
494
496
  // Курсор при рисовании фрейма
495
- if (this.app && this.app.view) this.app.view.style.cursor = 'crosshair';
497
+ this.cursor = 'crosshair';
498
+ if (this.app && this.app.view) this.app.view.style.cursor = this.cursor;
496
499
  }
497
500
 
498
501
  _onFrameDrawMove(event) {
@@ -941,13 +944,15 @@ export class PlacementTool extends BaseTool {
941
944
  const cursorSize = 24;
942
945
  const url = encodeURI(src);
943
946
  // Используем CSS cursor с изображением, если поддерживается
944
- this.app.view.style.cursor = `url(${url}) ${Math.floor(cursorSize/2)} ${Math.floor(cursorSize/2)}, default`;
947
+ this.cursor = `url(${url}) ${Math.floor(cursorSize/2)} ${Math.floor(cursorSize/2)}, default`;
948
+ this.app.view.style.cursor = this.cursor;
945
949
  }
946
950
  } catch (_) {}
947
951
  } else {
948
952
  // Для эмоджи используем стандартный курсор
949
953
  if (this.app && this.app.view) {
950
- this.app.view.style.cursor = 'crosshair';
954
+ this.cursor = 'crosshair';
955
+ this.app.view.style.cursor = this.cursor;
951
956
  }
952
957
  }
953
958
  }