@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,502 @@
1
+ import { Events } from '../core/events/Events.js';
2
+
3
+ /**
4
+ * Панель свойств записки
5
+ * Отображается над выделенной запиской
6
+ */
7
+ export class NotePropertiesPanel {
8
+ constructor(eventBus, container, core = null) {
9
+ this.eventBus = eventBus;
10
+ this.container = container;
11
+ this.core = core;
12
+ this.panel = null;
13
+ this.currentId = null;
14
+
15
+ this._attachEvents();
16
+ this._createPanel();
17
+ }
18
+
19
+ _attachEvents() {
20
+ // Показываем панель при изменении выделения
21
+ this.eventBus.on(Events.Tool.SelectionAdd, () => this.updateFromSelection());
22
+ this.eventBus.on(Events.Tool.SelectionRemove, () => this.updateFromSelection());
23
+ this.eventBus.on(Events.Tool.SelectionClear, () => this.hide());
24
+
25
+ // Скрываем панель при удалении объекта
26
+ this.eventBus.on(Events.Object.Deleted, (objectId) => {
27
+ if (this.currentId && objectId === this.currentId) this.hide();
28
+ });
29
+
30
+ // Обновляем позицию при любых изменениях
31
+ this.eventBus.on(Events.Tool.DragUpdate, () => this.reposition());
32
+ this.eventBus.on(Events.Tool.GroupDragUpdate, () => this.reposition());
33
+ this.eventBus.on(Events.Tool.ResizeUpdate, () => this.reposition());
34
+ this.eventBus.on(Events.Tool.RotateUpdate, () => this.reposition());
35
+
36
+ // Обновляем позицию при зуме/пане
37
+ this.eventBus.on(Events.UI.ZoomPercent, () => {
38
+ if (this.currentId) this.reposition();
39
+ });
40
+
41
+ this.eventBus.on(Events.Tool.PanUpdate, () => {
42
+ if (this.currentId) this.reposition();
43
+ });
44
+
45
+ // Скрываем панель при активации других инструментов
46
+ this.eventBus.on(Events.Tool.Activated, ({ tool }) => {
47
+ if (tool !== 'select') {
48
+ this.hide();
49
+ }
50
+ });
51
+ }
52
+
53
+ updateFromSelection() {
54
+ // Показываем только для одиночного выделения записки
55
+ const ids = this.core?.selectTool ? Array.from(this.core.selectTool.selectedObjects || []) : [];
56
+
57
+ if (!ids || ids.length !== 1) {
58
+ this.hide();
59
+ return;
60
+ }
61
+
62
+ const id = ids[0];
63
+
64
+ // Избегаем дублирования - если уже показываем панель для этого объекта
65
+ if (this.currentId === id && this.panel && this.panel.style.display !== 'none') {
66
+ return;
67
+ }
68
+
69
+ const pixi = this.core?.pixi?.objects?.get ? this.core.pixi.objects.get(id) : null;
70
+ const isNote = !!(pixi && pixi._mb && pixi._mb.type === 'note');
71
+
72
+ console.log('📝 NotePropertiesPanel: updateFromSelection - id=', id, 'isNote=', isNote);
73
+
74
+ if (isNote) {
75
+ this.showFor(id);
76
+ } else {
77
+ this.hide();
78
+ }
79
+ }
80
+
81
+ showFor(objectId) {
82
+ console.log('📝 NotePropertiesPanel: Showing panel for objectId:', objectId);
83
+ this.currentId = objectId;
84
+ if (this.panel) {
85
+ this.panel.style.display = 'flex';
86
+ this.reposition();
87
+ }
88
+
89
+ // Обновляем контролы в соответствии с текущими свойствами объекта
90
+ this._updateControlsFromObject();
91
+ }
92
+
93
+ hide() {
94
+ this.currentId = null;
95
+ if (this.panel) {
96
+ this.panel.style.display = 'none';
97
+ }
98
+ // Скрываем все палитры цветов
99
+ if (this.backgroundColorPalette) this.backgroundColorPalette.style.display = 'none';
100
+ if (this.borderColorPalette) this.borderColorPalette.style.display = 'none';
101
+ if (this.textColorPalette) this.textColorPalette.style.display = 'none';
102
+ }
103
+
104
+ _createPanel() {
105
+ const panel = document.createElement('div');
106
+ panel.className = 'note-properties-panel';
107
+ Object.assign(panel.style, {
108
+ position: 'absolute',
109
+ display: 'none',
110
+ flexDirection: 'row',
111
+ alignItems: 'center',
112
+ gap: '8px',
113
+ padding: '8px 12px',
114
+ backgroundColor: 'white',
115
+ border: '1px solid #e0e0e0',
116
+ borderRadius: '8px',
117
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
118
+ fontSize: '12px',
119
+ fontFamily: 'Arial, sans-serif',
120
+ minWidth: '320px',
121
+ height: '40px',
122
+ zIndex: '10000'
123
+ });
124
+
125
+ // Создаем контролы для записки
126
+ this._createNoteControls(panel);
127
+
128
+ // Добавляем ID для удобной настройки через DevTools
129
+ panel.id = 'note-properties-panel';
130
+
131
+ this.panel = panel;
132
+ this.container.appendChild(panel);
133
+ }
134
+
135
+ reposition() {
136
+ if (!this.panel || !this.currentId || this.panel.style.display === 'none') {
137
+ return;
138
+ }
139
+
140
+ // Проверяем, что наш объект все еще выделен
141
+ const ids = this.core?.selectTool ? Array.from(this.core.selectTool.selectedObjects || []) : [];
142
+ if (!ids.includes(this.currentId)) {
143
+ this.hide();
144
+ return;
145
+ }
146
+
147
+ // Получаем позицию и размеры объекта
148
+ const posData = { objectId: this.currentId, position: null };
149
+ this.eventBus.emit(Events.Tool.GetObjectPosition, posData);
150
+
151
+ const sizeData = { objectId: this.currentId, size: null };
152
+ this.eventBus.emit(Events.Tool.GetObjectSize, sizeData);
153
+
154
+ if (!posData.position || !sizeData.size) {
155
+ return;
156
+ }
157
+
158
+ const { x, y } = posData.position;
159
+ const { width, height } = sizeData.size;
160
+
161
+ // Позиционируем панель справа от записки
162
+ const panelX = x + width + 10;
163
+ const panelY = y;
164
+
165
+ console.log('📝 NotePropertiesPanel: Positioning next to note:', {
166
+ noteX: x, noteY: y, noteWidth: width, noteHeight: height,
167
+ panelX, panelY
168
+ });
169
+
170
+ this.panel.style.left = `${panelX}px`;
171
+ this.panel.style.top = `${panelY}px`;
172
+ }
173
+
174
+ _createNoteControls(panel) {
175
+ // Контейнер для цвета фона
176
+ const backgroundContainer = this._createColorControl(
177
+ 'Фон:',
178
+ 'backgroundColorButton',
179
+ 'backgroundColorPalette',
180
+ [
181
+ { name: 'Желтый', hex: '#FFF9C4', pixi: 0xFFF9C4 },
182
+ { name: 'Розовый', hex: '#FCE4EC', pixi: 0xFCE4EC },
183
+ { name: 'Голубой', hex: '#E3F2FD', pixi: 0xE3F2FD },
184
+ { name: 'Зеленый', hex: '#E8F5E8', pixi: 0xE8F5E8 },
185
+ { name: 'Оранжевый', hex: '#FFF3E0', pixi: 0xFFF3E0 },
186
+ { name: 'Сиреневый', hex: '#F3E5F5', pixi: 0xF3E5F5 }
187
+ ],
188
+ 'backgroundColor'
189
+ );
190
+
191
+ // Контейнер для цвета границы
192
+ const borderContainer = this._createColorControl(
193
+ 'Граница:',
194
+ 'borderColorButton',
195
+ 'borderColorPalette',
196
+ [
197
+ { name: 'Золотой', hex: '#F9A825', pixi: 0xF9A825 },
198
+ { name: 'Розовый', hex: '#E91E63', pixi: 0xE91E63 },
199
+ { name: 'Синий', hex: '#2196F3', pixi: 0x2196F3 },
200
+ { name: 'Зеленый', hex: '#4CAF50', pixi: 0x4CAF50 },
201
+ { name: 'Оранжевый', hex: '#FF9800', pixi: 0xFF9800 },
202
+ { name: 'Фиолетовый', hex: '#9C27B0', pixi: 0x9C27B0 }
203
+ ],
204
+ 'borderColor'
205
+ );
206
+
207
+ // Контейнер для цвета текста
208
+ const textContainer = this._createColorControl(
209
+ 'Текст:',
210
+ 'textColorButton',
211
+ 'textColorPalette',
212
+ [
213
+ { name: 'Черный', hex: '#1A1A1A', pixi: 0x1A1A1A },
214
+ { name: 'Серый', hex: '#666666', pixi: 0x666666 },
215
+ { name: 'Синий', hex: '#1976D2', pixi: 0x1976D2 },
216
+ { name: 'Зеленый', hex: '#388E3C', pixi: 0x388E3C },
217
+ { name: 'Красный', hex: '#D32F2F', pixi: 0xD32F2F },
218
+ { name: 'Фиолетовый', hex: '#7B1FA2', pixi: 0x7B1FA2 }
219
+ ],
220
+ 'textColor'
221
+ );
222
+
223
+ // Контейнер для размера шрифта
224
+ const fontSizeContainer = document.createElement('div');
225
+ Object.assign(fontSizeContainer.style, {
226
+ display: 'flex',
227
+ alignItems: 'center',
228
+ gap: '4px'
229
+ });
230
+
231
+ const fontSizeLabel = document.createElement('span');
232
+ fontSizeLabel.textContent = 'Размер:';
233
+ Object.assign(fontSizeLabel.style, {
234
+ fontSize: '11px',
235
+ color: '#666',
236
+ minWidth: '32px'
237
+ });
238
+
239
+ const fontSizeInput = document.createElement('input');
240
+ fontSizeInput.type = 'number';
241
+ fontSizeInput.min = '8';
242
+ fontSizeInput.max = '32';
243
+ fontSizeInput.value = '16';
244
+ Object.assign(fontSizeInput.style, {
245
+ width: '40px',
246
+ height: '20px',
247
+ padding: '1px 4px',
248
+ border: '1px solid #ccc',
249
+ borderRadius: '4px',
250
+ fontSize: '11px',
251
+ textAlign: 'center'
252
+ });
253
+
254
+ fontSizeInput.addEventListener('change', () => {
255
+ const fontSize = parseInt(fontSizeInput.value);
256
+ if (fontSize >= 8 && fontSize <= 32) {
257
+ this._changeFontSize(fontSize);
258
+ }
259
+ });
260
+
261
+ this.fontSizeInput = fontSizeInput;
262
+
263
+ fontSizeContainer.appendChild(fontSizeLabel);
264
+ fontSizeContainer.appendChild(fontSizeInput);
265
+
266
+ panel.appendChild(backgroundContainer);
267
+ panel.appendChild(borderContainer);
268
+ panel.appendChild(textContainer);
269
+ panel.appendChild(fontSizeContainer);
270
+ }
271
+
272
+ _createColorControl(labelText, buttonProperty, paletteProperty, colors, propertyName) {
273
+ const container = document.createElement('div');
274
+ Object.assign(container.style, {
275
+ display: 'flex',
276
+ alignItems: 'center',
277
+ gap: '4px',
278
+ position: 'relative'
279
+ });
280
+
281
+ const label = document.createElement('span');
282
+ label.textContent = labelText;
283
+ Object.assign(label.style, {
284
+ fontSize: '11px',
285
+ color: '#666',
286
+ minWidth: '32px'
287
+ });
288
+
289
+ const button = document.createElement('button');
290
+ Object.assign(button.style, {
291
+ width: '32px',
292
+ height: '20px',
293
+ border: '1px solid #ccc',
294
+ borderRadius: '4px',
295
+ cursor: 'pointer',
296
+ backgroundColor: colors[0].hex
297
+ });
298
+
299
+ button.addEventListener('click', (e) => {
300
+ e.stopPropagation();
301
+ this._toggleColorPalette(button, paletteProperty);
302
+ });
303
+
304
+ this[buttonProperty] = button;
305
+
306
+ // Создаем палитру
307
+ const palette = this._createColorPalette(colors, propertyName);
308
+ this[paletteProperty] = palette;
309
+
310
+ container.appendChild(label);
311
+ container.appendChild(button);
312
+ container.appendChild(palette);
313
+
314
+ return container;
315
+ }
316
+
317
+ _createColorPalette(colors, propertyName) {
318
+ const palette = document.createElement('div');
319
+ Object.assign(palette.style, {
320
+ position: 'absolute',
321
+ top: '100%',
322
+ left: '0',
323
+ display: 'none',
324
+ flexWrap: 'wrap',
325
+ gap: '4px',
326
+ padding: '8px',
327
+ backgroundColor: 'white',
328
+ border: '1px solid #e0e0e0',
329
+ borderRadius: '8px',
330
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
331
+ zIndex: '10001',
332
+ width: '120px'
333
+ });
334
+
335
+ colors.forEach(color => {
336
+ const colorSwatch = document.createElement('div');
337
+ Object.assign(colorSwatch.style, {
338
+ width: '20px',
339
+ height: '20px',
340
+ backgroundColor: color.hex,
341
+ border: '1px solid #ccc',
342
+ borderRadius: '4px',
343
+ cursor: 'pointer',
344
+ transition: 'transform 0.1s'
345
+ });
346
+
347
+ colorSwatch.title = color.name;
348
+
349
+ colorSwatch.addEventListener('click', () => {
350
+ this._selectColor(color, propertyName);
351
+ this._hideAllColorPalettes();
352
+ });
353
+
354
+ colorSwatch.addEventListener('mouseenter', () => {
355
+ colorSwatch.style.transform = 'scale(1.1)';
356
+ });
357
+
358
+ colorSwatch.addEventListener('mouseleave', () => {
359
+ colorSwatch.style.transform = 'scale(1)';
360
+ });
361
+
362
+ palette.appendChild(colorSwatch);
363
+ });
364
+
365
+ return palette;
366
+ }
367
+
368
+ _toggleColorPalette(button, paletteProperty) {
369
+ // Скрываем все другие палитры
370
+ this._hideAllColorPalettes();
371
+
372
+ const palette = this[paletteProperty];
373
+ if (!palette) return;
374
+
375
+ const isVisible = palette.style.display !== 'none';
376
+
377
+ if (isVisible) {
378
+ palette.style.display = 'none';
379
+ } else {
380
+ palette.style.display = 'flex';
381
+ // Добавляем обработчик клика по документу для закрытия палитры
382
+ setTimeout(() => {
383
+ document.addEventListener('click', this._documentClickHandler.bind(this));
384
+ }, 0);
385
+ }
386
+ }
387
+
388
+ _hideAllColorPalettes() {
389
+ if (this.backgroundColorPalette) this.backgroundColorPalette.style.display = 'none';
390
+ if (this.borderColorPalette) this.borderColorPalette.style.display = 'none';
391
+ if (this.textColorPalette) this.textColorPalette.style.display = 'none';
392
+ document.removeEventListener('click', this._documentClickHandler.bind(this));
393
+ }
394
+
395
+ _documentClickHandler(e) {
396
+ const palettes = [this.backgroundColorPalette, this.borderColorPalette, this.textColorPalette];
397
+ const buttons = [this.backgroundColorButton, this.borderColorButton, this.textColorButton];
398
+
399
+ let shouldClose = true;
400
+
401
+ for (let palette of palettes) {
402
+ if (palette && palette.contains(e.target)) {
403
+ shouldClose = false;
404
+ break;
405
+ }
406
+ }
407
+
408
+ for (let button of buttons) {
409
+ if (button && button.contains(e.target)) {
410
+ shouldClose = false;
411
+ break;
412
+ }
413
+ }
414
+
415
+ if (shouldClose) {
416
+ this._hideAllColorPalettes();
417
+ }
418
+ }
419
+
420
+ _selectColor(color, propertyName) {
421
+ if (!this.currentId) return;
422
+
423
+ console.log(`📝 NotePropertiesPanel: Selecting ${propertyName}:`, color);
424
+
425
+ // Обновляем соответствующую кнопку
426
+ if (propertyName === 'backgroundColor' && this.backgroundColorButton) {
427
+ this.backgroundColorButton.style.backgroundColor = color.hex;
428
+ this.backgroundColorButton.title = `Цвет фона: ${color.name}`;
429
+ } else if (propertyName === 'borderColor' && this.borderColorButton) {
430
+ this.borderColorButton.style.backgroundColor = color.hex;
431
+ this.borderColorButton.title = `Цвет границы: ${color.name}`;
432
+ } else if (propertyName === 'textColor' && this.textColorButton) {
433
+ this.textColorButton.style.backgroundColor = color.hex;
434
+ this.textColorButton.title = `Цвет текста: ${color.name}`;
435
+ }
436
+
437
+ // Отправляем событие изменения свойства
438
+ const updates = { properties: {} };
439
+ updates.properties[propertyName] = color.pixi;
440
+
441
+ this.eventBus.emit(Events.Object.StateChanged, {
442
+ objectId: this.currentId,
443
+ updates: updates
444
+ });
445
+ }
446
+
447
+ _changeFontSize(fontSize) {
448
+ if (!this.currentId) return;
449
+
450
+ console.log('📝 NotePropertiesPanel: Changing font size to:', fontSize);
451
+
452
+ // Отправляем событие изменения размера шрифта
453
+ this.eventBus.emit(Events.Object.StateChanged, {
454
+ objectId: this.currentId,
455
+ updates: { properties: { fontSize: fontSize } }
456
+ });
457
+ }
458
+
459
+ _updateControlsFromObject() {
460
+ if (!this.currentId) return;
461
+
462
+ const objectData = this.core.getObjectData(this.currentId);
463
+ if (objectData && objectData.properties) {
464
+ const props = objectData.properties;
465
+
466
+ // Обновляем кнопки цветов
467
+ if (this.backgroundColorButton && props.backgroundColor !== undefined) {
468
+ this._updateColorButton(this.backgroundColorButton, props.backgroundColor);
469
+ }
470
+ if (this.borderColorButton && props.borderColor !== undefined) {
471
+ this._updateColorButton(this.borderColorButton, props.borderColor);
472
+ }
473
+ if (this.textColorButton && props.textColor !== undefined) {
474
+ this._updateColorButton(this.textColorButton, props.textColor);
475
+ }
476
+
477
+ // Обновляем размер шрифта
478
+ if (this.fontSizeInput && props.fontSize !== undefined) {
479
+ this.fontSizeInput.value = props.fontSize.toString();
480
+ }
481
+ }
482
+ }
483
+
484
+ _updateColorButton(button, pixiColor) {
485
+ if (!button) return;
486
+
487
+ // Конвертируем PIXI цвет в hex строку
488
+ const hexColor = `#${pixiColor.toString(16).padStart(6, '0').toUpperCase()}`;
489
+ button.style.backgroundColor = hexColor;
490
+ }
491
+
492
+ destroy() {
493
+ // Удаляем обработчик клика по документу
494
+ document.removeEventListener('click', this._documentClickHandler.bind(this));
495
+
496
+ if (this.panel && this.panel.parentNode) {
497
+ this.panel.parentNode.removeChild(this.panel);
498
+ }
499
+ this.panel = null;
500
+ this.currentId = null;
501
+ }
502
+ }