@sequent-org/moodboard 1.0.0

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.
Files changed (123) hide show
  1. package/package.json +44 -0
  2. package/src/assets/icons/README.md +105 -0
  3. package/src/assets/icons/attachments.svg +3 -0
  4. package/src/assets/icons/clear.svg +5 -0
  5. package/src/assets/icons/comments.svg +3 -0
  6. package/src/assets/icons/emoji.svg +6 -0
  7. package/src/assets/icons/frame.svg +3 -0
  8. package/src/assets/icons/image.svg +3 -0
  9. package/src/assets/icons/note.svg +3 -0
  10. package/src/assets/icons/pan.svg +3 -0
  11. package/src/assets/icons/pencil.svg +3 -0
  12. package/src/assets/icons/redo.svg +3 -0
  13. package/src/assets/icons/select.svg +9 -0
  14. package/src/assets/icons/shapes.svg +3 -0
  15. package/src/assets/icons/text-add.svg +3 -0
  16. package/src/assets/icons/topbar/README.md +39 -0
  17. package/src/assets/icons/topbar/grid-cross.svg +6 -0
  18. package/src/assets/icons/topbar/grid-dot.svg +3 -0
  19. package/src/assets/icons/topbar/grid-line.svg +3 -0
  20. package/src/assets/icons/topbar/grid-off.svg +3 -0
  21. package/src/assets/icons/topbar/paint.svg +3 -0
  22. package/src/assets/icons/undo.svg +3 -0
  23. package/src/core/ApiClient.js +309 -0
  24. package/src/core/EventBus.js +42 -0
  25. package/src/core/HistoryManager.js +261 -0
  26. package/src/core/KeyboardManager.js +710 -0
  27. package/src/core/PixiEngine.js +439 -0
  28. package/src/core/SaveManager.js +381 -0
  29. package/src/core/StateManager.js +64 -0
  30. package/src/core/commands/BaseCommand.js +68 -0
  31. package/src/core/commands/CopyObjectCommand.js +44 -0
  32. package/src/core/commands/CreateObjectCommand.js +46 -0
  33. package/src/core/commands/DeleteObjectCommand.js +146 -0
  34. package/src/core/commands/EditFileNameCommand.js +107 -0
  35. package/src/core/commands/GroupMoveCommand.js +47 -0
  36. package/src/core/commands/GroupReorderZCommand.js +74 -0
  37. package/src/core/commands/GroupResizeCommand.js +37 -0
  38. package/src/core/commands/GroupRotateCommand.js +41 -0
  39. package/src/core/commands/MoveObjectCommand.js +89 -0
  40. package/src/core/commands/PasteObjectCommand.js +103 -0
  41. package/src/core/commands/ReorderZCommand.js +45 -0
  42. package/src/core/commands/ResizeObjectCommand.js +135 -0
  43. package/src/core/commands/RotateObjectCommand.js +70 -0
  44. package/src/core/commands/index.js +14 -0
  45. package/src/core/events/Events.js +147 -0
  46. package/src/core/index.js +1632 -0
  47. package/src/core/rendering/GeometryUtils.js +89 -0
  48. package/src/core/rendering/HitTestManager.js +186 -0
  49. package/src/core/rendering/LayerManager.js +137 -0
  50. package/src/core/rendering/ObjectRenderer.js +363 -0
  51. package/src/core/rendering/PixiRenderer.js +140 -0
  52. package/src/core/rendering/index.js +9 -0
  53. package/src/grid/BaseGrid.js +164 -0
  54. package/src/grid/CrossGrid.js +75 -0
  55. package/src/grid/DotGrid.js +148 -0
  56. package/src/grid/GridFactory.js +173 -0
  57. package/src/grid/LineGrid.js +115 -0
  58. package/src/index.js +2 -0
  59. package/src/moodboard/ActionHandler.js +114 -0
  60. package/src/moodboard/DataManager.js +114 -0
  61. package/src/moodboard/MoodBoard.js +359 -0
  62. package/src/moodboard/WorkspaceManager.js +103 -0
  63. package/src/objects/BaseObject.js +1 -0
  64. package/src/objects/CommentObject.js +115 -0
  65. package/src/objects/DrawingObject.js +114 -0
  66. package/src/objects/EmojiObject.js +98 -0
  67. package/src/objects/FileObject.js +318 -0
  68. package/src/objects/FrameObject.js +127 -0
  69. package/src/objects/ImageObject.js +72 -0
  70. package/src/objects/NoteObject.js +227 -0
  71. package/src/objects/ObjectFactory.js +61 -0
  72. package/src/objects/ShapeObject.js +134 -0
  73. package/src/objects/StampObject.js +0 -0
  74. package/src/objects/StickerObject.js +0 -0
  75. package/src/objects/TextObject.js +123 -0
  76. package/src/services/BoardService.js +85 -0
  77. package/src/services/FileUploadService.js +398 -0
  78. package/src/services/FrameService.js +138 -0
  79. package/src/services/ImageUploadService.js +246 -0
  80. package/src/services/ZOrderManager.js +50 -0
  81. package/src/services/ZoomPanController.js +78 -0
  82. package/src/src.7z +0 -0
  83. package/src/src.zip +0 -0
  84. package/src/src2.zip +0 -0
  85. package/src/tools/AlignmentGuides.js +326 -0
  86. package/src/tools/BaseTool.js +257 -0
  87. package/src/tools/ResizeHandles.js +381 -0
  88. package/src/tools/ToolManager.js +580 -0
  89. package/src/tools/board-tools/PanTool.js +43 -0
  90. package/src/tools/board-tools/ZoomTool.js +393 -0
  91. package/src/tools/object-tools/DrawingTool.js +404 -0
  92. package/src/tools/object-tools/PlacementTool.js +1005 -0
  93. package/src/tools/object-tools/SelectTool.js +2183 -0
  94. package/src/tools/object-tools/TextTool.js +416 -0
  95. package/src/tools/object-tools/selection/BoxSelectController.js +105 -0
  96. package/src/tools/object-tools/selection/GeometryUtils.js +101 -0
  97. package/src/tools/object-tools/selection/GroupDragController.js +61 -0
  98. package/src/tools/object-tools/selection/GroupResizeController.js +90 -0
  99. package/src/tools/object-tools/selection/GroupRotateController.js +61 -0
  100. package/src/tools/object-tools/selection/HandlesSync.js +96 -0
  101. package/src/tools/object-tools/selection/ResizeController.js +68 -0
  102. package/src/tools/object-tools/selection/RotateController.js +58 -0
  103. package/src/tools/object-tools/selection/SelectionModel.js +42 -0
  104. package/src/tools/object-tools/selection/SimpleDragController.js +45 -0
  105. package/src/ui/CommentPopover.js +187 -0
  106. package/src/ui/ContextMenu.js +340 -0
  107. package/src/ui/FilePropertiesPanel.js +298 -0
  108. package/src/ui/FramePropertiesPanel.js +462 -0
  109. package/src/ui/HtmlHandlesLayer.js +778 -0
  110. package/src/ui/HtmlTextLayer.js +279 -0
  111. package/src/ui/MapPanel.js +290 -0
  112. package/src/ui/NotePropertiesPanel.js +502 -0
  113. package/src/ui/SaveStatus.js +250 -0
  114. package/src/ui/TextPropertiesPanel.js +911 -0
  115. package/src/ui/Toolbar.js +1118 -0
  116. package/src/ui/Topbar.js +220 -0
  117. package/src/ui/ZoomPanel.js +116 -0
  118. package/src/ui/styles/workspace.css +854 -0
  119. package/src/utils/colors.js +0 -0
  120. package/src/utils/geometry.js +0 -0
  121. package/src/utils/iconLoader.js +270 -0
  122. package/src/utils/objectIdGenerator.js +17 -0
  123. package/src/utils/topbarIconLoader.js +114 -0
@@ -0,0 +1,393 @@
1
+ import { BaseTool } from '../BaseTool.js';
2
+
3
+ /**
4
+ * Инструмент масштабирования доски
5
+ */
6
+ export class ZoomTool extends BaseTool {
7
+ constructor(eventBus) {
8
+ super('zoom', eventBus);
9
+ this.cursor = 'zoom-in';
10
+ this.hotkey = 'z';
11
+
12
+ // Настройки масштабирования
13
+ this.minZoom = 0.1;
14
+ this.maxZoom = 10.0;
15
+ this.currentZoom = 1.0;
16
+ this.zoomStep = 0.1;
17
+ this.wheelZoomSpeed = 0.1;
18
+
19
+ // Режимы зума
20
+ this.zoomMode = 'in'; // 'in' | 'out' | 'fit'
21
+
22
+ // Состояние drag-to-zoom
23
+ this.isDragZooming = false;
24
+ this.zoomRect = null;
25
+ }
26
+
27
+ /**
28
+ * Клик для зума в точку
29
+ */
30
+ onMouseDown(event) {
31
+ super.onMouseDown(event);
32
+
33
+ if (event.button === 0) { // Левая кнопка
34
+ if (event.originalEvent.shiftKey) {
35
+ // Shift + клик = zoom out
36
+ this.zoomOut(event.x, event.y);
37
+ } else if (event.originalEvent.altKey) {
38
+ // Alt + drag = zoom to rectangle
39
+ this.startDragZoom(event);
40
+ } else {
41
+ // Обычный клик = zoom in
42
+ this.zoomIn(event.x, event.y);
43
+ }
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Обновление drag-to-zoom
49
+ */
50
+ onMouseMove(event) {
51
+ super.onMouseMove(event);
52
+
53
+ if (this.isDragZooming) {
54
+ this.updateDragZoom(event);
55
+ } else {
56
+ // Обновляем курсор в зависимости от модификаторов
57
+ this.updateCursor(event);
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Завершение drag-to-zoom
63
+ */
64
+ onMouseUp(event) {
65
+ if (this.isDragZooming) {
66
+ this.endDragZoom(event);
67
+ }
68
+
69
+ super.onMouseUp(event);
70
+ }
71
+
72
+ /**
73
+ * Масштабирование колесиком мыши
74
+ */
75
+ onMouseWheel(event) {
76
+ if (event.ctrlKey || event.metaKey) {
77
+ // Ctrl/Cmd + колесико = зум
78
+ const zoomDelta = -event.delta * this.wheelZoomSpeed;
79
+ this.zoomByDelta(zoomDelta, event.x, event.y);
80
+ event.originalEvent.preventDefault();
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Горячие клавиши для зума
86
+ */
87
+ onKeyDown(event) {
88
+ switch (event.key) {
89
+ case '=':
90
+ case '+':
91
+ this.zoomIn();
92
+ event.originalEvent.preventDefault();
93
+ break;
94
+
95
+ case '-':
96
+ case '_':
97
+ this.zoomOut();
98
+ event.originalEvent.preventDefault();
99
+ break;
100
+
101
+ case '0':
102
+ this.resetZoom();
103
+ event.originalEvent.preventDefault();
104
+ break;
105
+
106
+ case '1':
107
+ this.zoomToFit();
108
+ event.originalEvent.preventDefault();
109
+ break;
110
+
111
+ case '2':
112
+ this.zoomToSelection();
113
+ event.originalEvent.preventDefault();
114
+ break;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Увеличение масштаба
120
+ */
121
+ zoomIn(centerX = null, centerY = null) {
122
+ const newZoom = Math.min(this.maxZoom, this.currentZoom + this.zoomStep);
123
+ this.setZoom(newZoom, centerX, centerY);
124
+ }
125
+
126
+ /**
127
+ * Уменьшение масштаба
128
+ */
129
+ zoomOut(centerX = null, centerY = null) {
130
+ const newZoom = Math.max(this.minZoom, this.currentZoom - this.zoomStep);
131
+ this.setZoom(newZoom, centerX, centerY);
132
+ }
133
+
134
+ /**
135
+ * Масштабирование на указанную дельту
136
+ */
137
+ zoomByDelta(delta, centerX = null, centerY = null) {
138
+ const newZoom = Math.max(this.minZoom,
139
+ Math.min(this.maxZoom, this.currentZoom + delta));
140
+ this.setZoom(newZoom, centerX, centerY);
141
+ }
142
+
143
+ /**
144
+ * Установка конкретного масштаба
145
+ */
146
+ setZoom(zoom, centerX = null, centerY = null, animated = false) {
147
+ const clampedZoom = Math.max(this.minZoom, Math.min(this.maxZoom, zoom));
148
+
149
+ if (clampedZoom === this.currentZoom) return;
150
+
151
+ const oldZoom = this.currentZoom;
152
+ this.currentZoom = clampedZoom;
153
+
154
+ this.emit('zoom:change', {
155
+ zoom: this.currentZoom,
156
+ oldZoom,
157
+ centerX,
158
+ centerY,
159
+ animated
160
+ });
161
+
162
+ this.updateZoomPercentage();
163
+ }
164
+
165
+ /**
166
+ * Сброс масштаба к 100%
167
+ */
168
+ resetZoom(animated = true) {
169
+ this.setZoom(1.0, null, null, animated);
170
+ }
171
+
172
+ /**
173
+ * Подгонка под размер экрана
174
+ */
175
+ zoomToFit(animated = true) {
176
+ this.emit('zoom:fit', { animated });
177
+ }
178
+
179
+ /**
180
+ * Масштабирование к выделенным объектам
181
+ */
182
+ zoomToSelection(animated = true) {
183
+ this.emit('zoom:selection', { animated });
184
+ }
185
+
186
+ /**
187
+ * Масштабирование к области
188
+ */
189
+ zoomToRect(x, y, width, height, animated = true) {
190
+ this.emit('zoom:rect', {
191
+ bounds: { x, y, width, height },
192
+ animated
193
+ });
194
+ }
195
+
196
+ /**
197
+ * Начало drag-to-zoom
198
+ */
199
+ startDragZoom(event) {
200
+ this.isDragZooming = true;
201
+ this.zoomRect = {
202
+ startX: event.x,
203
+ startY: event.y,
204
+ endX: event.x,
205
+ endY: event.y
206
+ };
207
+
208
+ this.cursor = 'crosshair';
209
+ this.setCursor();
210
+
211
+ this.emit('zoom:drag:start', {
212
+ startPoint: { x: event.x, y: event.y }
213
+ });
214
+ }
215
+
216
+ /**
217
+ * Обновление drag-to-zoom
218
+ */
219
+ updateDragZoom(event) {
220
+ if (!this.zoomRect) return;
221
+
222
+ this.zoomRect.endX = event.x;
223
+ this.zoomRect.endY = event.y;
224
+
225
+ // Вычисляем размеры прямоугольника
226
+ const rect = this.normalizeRect(this.zoomRect);
227
+
228
+ this.emit('zoom:drag:update', {
229
+ rect: { ...rect }
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Завершение drag-to-zoom
235
+ */
236
+ endDragZoom(event) {
237
+ if (!this.zoomRect) return;
238
+
239
+ const rect = this.normalizeRect(this.zoomRect);
240
+
241
+ // Зумим только если прямоугольник достаточно большой
242
+ const minSize = 20;
243
+ if (rect.width > minSize && rect.height > minSize) {
244
+ this.zoomToRect(rect.x, rect.y, rect.width, rect.height);
245
+ }
246
+
247
+ this.emit('zoom:drag:end', {
248
+ rect: { ...rect }
249
+ });
250
+
251
+ this.isDragZooming = false;
252
+ this.zoomRect = null;
253
+ this.updateCursor();
254
+ }
255
+
256
+ /**
257
+ * Нормализация прямоугольника (чтобы width и height были положительными)
258
+ */
259
+ normalizeRect(rect) {
260
+ const x = Math.min(rect.startX, rect.endX);
261
+ const y = Math.min(rect.startY, rect.endY);
262
+ const width = Math.abs(rect.endX - rect.startX);
263
+ const height = Math.abs(rect.endY - rect.startY);
264
+
265
+ return { x, y, width, height };
266
+ }
267
+
268
+ /**
269
+ * Обновление курсора в зависимости от модификаторов
270
+ */
271
+ updateCursor(event = null) {
272
+ if (this.isDragZooming) {
273
+ this.cursor = 'crosshair';
274
+ } else if (event && event.originalEvent) {
275
+ if (event.originalEvent.shiftKey) {
276
+ this.cursor = 'zoom-out';
277
+ } else if (event.originalEvent.altKey) {
278
+ this.cursor = 'crosshair';
279
+ } else {
280
+ this.cursor = 'zoom-in';
281
+ }
282
+ } else {
283
+ this.cursor = this.zoomMode === 'out' ? 'zoom-out' : 'zoom-in';
284
+ }
285
+
286
+ this.setCursor();
287
+ }
288
+
289
+ /**
290
+ * Переключение режима зума
291
+ */
292
+ setZoomMode(mode) {
293
+ this.zoomMode = mode;
294
+ this.updateCursor();
295
+ }
296
+
297
+ /**
298
+ * Обновление отображения процента зума
299
+ */
300
+ updateZoomPercentage() {
301
+ const percentage = Math.round(this.currentZoom * 100);
302
+
303
+ this.emit('zoom:percentage', {
304
+ zoom: this.currentZoom,
305
+ percentage
306
+ });
307
+ }
308
+
309
+ /**
310
+ * Получение текущего масштаба
311
+ */
312
+ getCurrentZoom() {
313
+ return this.currentZoom;
314
+ }
315
+
316
+ /**
317
+ * Получение процента масштаба
318
+ */
319
+ getZoomPercentage() {
320
+ return Math.round(this.currentZoom * 100);
321
+ }
322
+
323
+ /**
324
+ * Проверка возможности увеличения
325
+ */
326
+ canZoomIn() {
327
+ return this.currentZoom < this.maxZoom;
328
+ }
329
+
330
+ /**
331
+ * Проверка возможности уменьшения
332
+ */
333
+ canZoomOut() {
334
+ return this.currentZoom > this.minZoom;
335
+ }
336
+
337
+ /**
338
+ * Установка ограничений масштаба
339
+ */
340
+ setZoomLimits(minZoom, maxZoom) {
341
+ this.minZoom = Math.max(0.01, minZoom);
342
+ this.maxZoom = Math.min(100, maxZoom);
343
+
344
+ // Ограничиваем текущий зум новыми пределами
345
+ if (this.currentZoom < this.minZoom || this.currentZoom > this.maxZoom) {
346
+ this.setZoom(Math.max(this.minZoom, Math.min(this.maxZoom, this.currentZoom)));
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Установка шага зума
352
+ */
353
+ setZoomStep(step) {
354
+ this.zoomStep = Math.max(0.01, Math.min(1.0, step));
355
+ }
356
+
357
+ /**
358
+ * Получение настроек инструмента
359
+ */
360
+ getSettings() {
361
+ return {
362
+ ...super.getSettings(),
363
+ currentZoom: this.currentZoom,
364
+ minZoom: this.minZoom,
365
+ maxZoom: this.maxZoom,
366
+ zoomStep: this.zoomStep,
367
+ zoomMode: this.zoomMode
368
+ };
369
+ }
370
+
371
+ /**
372
+ * Активация инструмента
373
+ */
374
+ onActivate() {
375
+ super.onActivate();
376
+
377
+ this.emit('tool:hint', {
378
+ message: 'Click to zoom in • Shift+Click to zoom out • Alt+Drag to zoom to area • Ctrl+Wheel to zoom'
379
+ });
380
+ }
381
+
382
+ /**
383
+ * Деактивация инструмента
384
+ */
385
+ onDeactivate() {
386
+ if (this.isDragZooming) {
387
+ this.isDragZooming = false;
388
+ this.zoomRect = null;
389
+ }
390
+
391
+ super.onDeactivate();
392
+ }
393
+ }