@sequent-org/moodboard 1.4.52 → 1.4.54
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 +1 -1
- package/src/core/index.js +3 -3
- package/src/grid/BaseGrid.js +12 -0
- package/src/grid/CrossGrid.js +1 -1
- package/src/grid/DotGrid.js +1 -1
- package/src/grid/LineGrid.js +25 -4
- package/src/initNoBundler.js +1 -1
- package/src/moodboard/integration/MoodBoardLoadApi.js +1 -1
- package/src/services/BoardService.js +17 -0
- package/src/services/SettingsApplier.js +22 -0
- package/src/ui/ConnectorPropertiesPanel.js +11 -7
- package/src/ui/Topbar.js +24 -10
- package/src/ui/boardPalette.js +1 -1
- package/src/ui/connector-properties/ConnectorPropertiesPanelMapper.js +39 -0
- package/src/ui/styles/workspace.css +1 -1
package/package.json
CHANGED
package/src/core/index.js
CHANGED
|
@@ -39,7 +39,7 @@ export class CoreMoodBoard {
|
|
|
39
39
|
autoSave: false,
|
|
40
40
|
width: this.container.clientWidth || 800,
|
|
41
41
|
height: this.container.clientHeight || 600,
|
|
42
|
-
backgroundColor:
|
|
42
|
+
backgroundColor: 0xFFFFFF,
|
|
43
43
|
...options
|
|
44
44
|
};
|
|
45
45
|
|
|
@@ -624,7 +624,7 @@ export class CoreMoodBoard {
|
|
|
624
624
|
const app = this.pixi?.app;
|
|
625
625
|
const rendererBg = app?.renderer?.background?.color ?? app?.renderer?.backgroundColor;
|
|
626
626
|
const toHex = (num) => {
|
|
627
|
-
try { return '#' + Number(num >>> 0).toString(16).padStart(6, '0'); } catch (_) { return '#
|
|
627
|
+
try { return '#' + Number(num >>> 0).toString(16).padStart(6, '0'); } catch (_) { return '#FFFFFF'; }
|
|
628
628
|
};
|
|
629
629
|
const world = this.pixi?.worldLayer || app?.stage;
|
|
630
630
|
const currentZoom = Math.max(0.02, Math.min(5, world?.scale?.x || 1));
|
|
@@ -653,7 +653,7 @@ export class CoreMoodBoard {
|
|
|
653
653
|
})();
|
|
654
654
|
|
|
655
655
|
const settings = {
|
|
656
|
-
backgroundColor: toHex(rendererBg ??
|
|
656
|
+
backgroundColor: toHex(rendererBg ?? 0xFFFFFF),
|
|
657
657
|
grid: gridSettings || undefined,
|
|
658
658
|
zoom: { min: 0.1, max: 5.0, default: 1.0, current: currentZoom },
|
|
659
659
|
pan: currentPan,
|
package/src/grid/BaseGrid.js
CHANGED
|
@@ -20,6 +20,9 @@ export class BaseGrid {
|
|
|
20
20
|
this.color = options.color;
|
|
21
21
|
this.opacity = options.opacity;
|
|
22
22
|
this.lineWidth = options.lineWidth;
|
|
23
|
+
// Эфемерный override цвета сетки (производный от фона доски, не сериализуется).
|
|
24
|
+
// null — используется штатный цвет/бэнды типа сетки.
|
|
25
|
+
this.colorOverride = null;
|
|
23
26
|
|
|
24
27
|
// Размеры области отрисовки
|
|
25
28
|
this.width = options.width || 1920;
|
|
@@ -169,6 +172,15 @@ export class BaseGrid {
|
|
|
169
172
|
this.color = color;
|
|
170
173
|
this.updateVisual();
|
|
171
174
|
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Устанавливает override-цвет сетки (производный от фона доски).
|
|
178
|
+
* @param {number|null} color — int-цвет либо null для сброса к штатному.
|
|
179
|
+
*/
|
|
180
|
+
setColorOverride(color) {
|
|
181
|
+
this.colorOverride = (typeof color === 'number' && Number.isFinite(color)) ? color : null;
|
|
182
|
+
this.updateVisual();
|
|
183
|
+
}
|
|
172
184
|
|
|
173
185
|
/**
|
|
174
186
|
* Устанавливает прозрачность
|
package/src/grid/CrossGrid.js
CHANGED
|
@@ -38,7 +38,7 @@ export class CrossGrid extends BaseGrid {
|
|
|
38
38
|
const g = this.graphics;
|
|
39
39
|
// Строго без прозрачности.
|
|
40
40
|
g.alpha = 1;
|
|
41
|
-
const lineColor = getCrossColor(this._zoom, this.color);
|
|
41
|
+
const lineColor = this.colorOverride != null ? this.colorOverride : getCrossColor(this._zoom, this.color);
|
|
42
42
|
g.beginFill(lineColor, 1);
|
|
43
43
|
|
|
44
44
|
const checkpoint = getCrossCheckpointForZoom(this._zoom);
|
package/src/grid/DotGrid.js
CHANGED
|
@@ -105,7 +105,7 @@ export class DotGrid extends BaseGrid {
|
|
|
105
105
|
const zoomPct = checkpoint?.zoomPercent ?? 100;
|
|
106
106
|
const use1px = DOT_1PX_CHECKPOINTS.has(zoomPct);
|
|
107
107
|
const dotSize = use1px ? 0.4 : rawDotSize;
|
|
108
|
-
const dotColor = getDotColor(this._zoom, this.color);
|
|
108
|
+
const dotColor = this.colorOverride != null ? this.colorOverride : getDotColor(this._zoom, this.color);
|
|
109
109
|
|
|
110
110
|
this.graphics.beginFill(dotColor, alpha);
|
|
111
111
|
for (let x = startX; x <= endX; x += stepPx) {
|
package/src/grid/LineGrid.js
CHANGED
|
@@ -44,15 +44,21 @@ export class LineGrid extends BaseGrid {
|
|
|
44
44
|
this.graphics.alpha = this.opacity;
|
|
45
45
|
}
|
|
46
46
|
const state = this.getScreenGridState();
|
|
47
|
+
// Miro-профиль: по умолчанию нативная пара цветов. Если из палитры пришёл colorOverride
|
|
48
|
+
// (например светлый фон #f0f6fc с gridColor #d4d4d4), используем его — иначе мелкая сетка
|
|
49
|
+
// сливается с фоном.
|
|
50
|
+
const mainColor = (typeof this.colorOverride === 'number' && Number.isFinite(this.colorOverride))
|
|
51
|
+
? this._deriveMinorColor(this.colorOverride)
|
|
52
|
+
: this.color;
|
|
47
53
|
try {
|
|
48
54
|
this.graphics.lineStyle({
|
|
49
55
|
width: Math.max(1, Math.round(this.lineWidth || 1)),
|
|
50
|
-
color:
|
|
56
|
+
color: mainColor,
|
|
51
57
|
alpha: 1,
|
|
52
58
|
alignment: 0
|
|
53
59
|
});
|
|
54
60
|
} catch (_) {
|
|
55
|
-
this.graphics.lineStyle(Math.max(1, Math.round(this.lineWidth || 1)),
|
|
61
|
+
this.graphics.lineStyle(Math.max(1, Math.round(this.lineWidth || 1)), mainColor, 1);
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
// Основные линии сетки
|
|
@@ -160,15 +166,18 @@ export class LineGrid extends BaseGrid {
|
|
|
160
166
|
const { secondGridStep } = this.getScreenGridState();
|
|
161
167
|
const step = Math.max(1, Math.round(secondGridStep || 0));
|
|
162
168
|
if (step <= 0) return;
|
|
169
|
+
const bigColor = (typeof this.colorOverride === 'number' && Number.isFinite(this.colorOverride))
|
|
170
|
+
? this.colorOverride
|
|
171
|
+
: this.bigGridColor;
|
|
163
172
|
try {
|
|
164
173
|
this.graphics.lineStyle({
|
|
165
174
|
width: 1,
|
|
166
|
-
color:
|
|
175
|
+
color: bigColor,
|
|
167
176
|
alpha: this.bigGridOpacity,
|
|
168
177
|
alignment: 0
|
|
169
178
|
});
|
|
170
179
|
} catch (_) {
|
|
171
|
-
this.graphics.lineStyle(1,
|
|
180
|
+
this.graphics.lineStyle(1, bigColor, this.bigGridOpacity);
|
|
172
181
|
}
|
|
173
182
|
const b = this.getDrawBounds();
|
|
174
183
|
const worldX = this.viewportTransform?.worldX || 0;
|
|
@@ -198,6 +207,18 @@ export class LineGrid extends BaseGrid {
|
|
|
198
207
|
}
|
|
199
208
|
}
|
|
200
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Цвет мелкой сетки из цвета крупной: на 20 светлее на канал, чтобы крупная (override)
|
|
212
|
+
* читалась как заметный якорь, а мелкая была тоньше/бледнее. Для #d4d4d4 даёт #e8e8e8.
|
|
213
|
+
*/
|
|
214
|
+
_deriveMinorColor(bigColor) {
|
|
215
|
+
const delta = 0x14;
|
|
216
|
+
const r = Math.min(0xFF, ((bigColor >> 16) & 0xFF) + delta);
|
|
217
|
+
const g = Math.min(0xFF, ((bigColor >> 8) & 0xFF) + delta);
|
|
218
|
+
const b = Math.min(0xFF, (bigColor & 0xFF) + delta);
|
|
219
|
+
return (r << 16) | (g << 8) | b;
|
|
220
|
+
}
|
|
221
|
+
|
|
201
222
|
_normalizeAnchor(anchor, stepPx) {
|
|
202
223
|
const step = Math.max(1, Math.round(stepPx));
|
|
203
224
|
return ((Math.round(anchor) % step) + step) % step;
|
package/src/initNoBundler.js
CHANGED
|
@@ -16,6 +16,20 @@ export class BoardService {
|
|
|
16
16
|
this._destroyed = false;
|
|
17
17
|
this._lastZoomCursor = null;
|
|
18
18
|
this._consumeZoomCursorAnchor = false;
|
|
19
|
+
// Override цвета сетки, производный от фона доски (null — штатный цвет типа сетки).
|
|
20
|
+
this._gridColorOverride = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Устанавливает override цвета сетки от фона доски и применяет к текущей сетке.
|
|
25
|
+
* Сохраняется, чтобы переехать на новую сетку при смене её типа.
|
|
26
|
+
* @param {number|null} color
|
|
27
|
+
*/
|
|
28
|
+
setGridColorOverride(color) {
|
|
29
|
+
this._gridColorOverride = (typeof color === 'number' && Number.isFinite(color)) ? color : null;
|
|
30
|
+
if (this.grid && typeof this.grid.setColorOverride === 'function') {
|
|
31
|
+
this.grid.setColorOverride(this._gridColorOverride);
|
|
32
|
+
}
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
async init(getCanvasSize) {
|
|
@@ -57,6 +71,9 @@ export class BoardService {
|
|
|
57
71
|
};
|
|
58
72
|
try {
|
|
59
73
|
this.grid = GridFactory.createGrid(type, gridOptions);
|
|
74
|
+
if (this._gridColorOverride != null && typeof this.grid.setColorOverride === 'function') {
|
|
75
|
+
this.grid.setColorOverride(this._gridColorOverride);
|
|
76
|
+
}
|
|
60
77
|
this.pixi.setGrid(this.grid);
|
|
61
78
|
this.refreshGridViewport();
|
|
62
79
|
this.eventBus.emit(Events.UI.GridCurrent, { type });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Events } from '../core/events/Events.js';
|
|
2
|
+
import { BOARD_PALETTE } from '../ui/boardPalette.js';
|
|
2
3
|
|
|
3
4
|
export class SettingsApplier {
|
|
4
5
|
constructor(eventBus, pixi, boardService = null, uiRefs = {}) {
|
|
@@ -43,6 +44,12 @@ export class SettingsApplier {
|
|
|
43
44
|
this.ui.topbar.setPaintButtonHex(this.ui.topbar.mapBoardToBtnHex(boardHex));
|
|
44
45
|
} catch (_) {}
|
|
45
46
|
}
|
|
47
|
+
// Цвет сетки производный от фона: для палитры с заданным gridColor — override, иначе сброс.
|
|
48
|
+
try {
|
|
49
|
+
if (this.boardService && typeof this.boardService.setGridColorOverride === 'function') {
|
|
50
|
+
this.boardService.setGridColorOverride(this._resolveGridColorOverride(bgInt));
|
|
51
|
+
}
|
|
52
|
+
} catch (_) {}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
// 2) Сетка — применяем только если grid пришёл в partial
|
|
@@ -114,6 +121,21 @@ export class SettingsApplier {
|
|
|
114
121
|
_toHex(intColor) {
|
|
115
122
|
try { return `#${(intColor >>> 0).toString(16).padStart(6, '0')}`.toLowerCase(); } catch (_) { return '#f5f5f5'; }
|
|
116
123
|
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Возвращает int-цвет сетки для фона из палитры (если задан gridColor), иначе null.
|
|
127
|
+
* @param {number|null} bgInt
|
|
128
|
+
* @returns {number|null}
|
|
129
|
+
*/
|
|
130
|
+
_resolveGridColorOverride(bgInt) {
|
|
131
|
+
if (bgInt == null) return null;
|
|
132
|
+
const hex = this._toHex(bgInt);
|
|
133
|
+
const entry = BOARD_PALETTE.find((p) => String(p.board).toLowerCase() === hex);
|
|
134
|
+
if (entry && entry.gridColor) {
|
|
135
|
+
return this._toIntColor(entry.gridColor);
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
117
139
|
}
|
|
118
140
|
|
|
119
141
|
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getSelectedConnectorId,
|
|
11
11
|
getConnectorData,
|
|
12
12
|
getConnectorMidpointScreen,
|
|
13
|
+
getConnectorTopScreen,
|
|
13
14
|
getConnectorStyle,
|
|
14
15
|
buildStyleUpdate,
|
|
15
16
|
} from './connector-properties/ConnectorPropertiesPanelMapper.js';
|
|
@@ -62,18 +63,21 @@ export class ConnectorPropertiesPanel {
|
|
|
62
63
|
const stillSelected = getSelectedConnectorId(this.core) === this.currentId;
|
|
63
64
|
if (!stillSelected) { this.hide(); return; }
|
|
64
65
|
|
|
65
|
-
const
|
|
66
|
-
if (!
|
|
66
|
+
const top = getConnectorTopScreen(this.core, this.currentId);
|
|
67
|
+
if (!top) return;
|
|
67
68
|
|
|
68
69
|
const panelW = this.panel.offsetWidth || 480;
|
|
69
70
|
const panelH = this.panel.offsetHeight || 40;
|
|
70
|
-
const GAP =
|
|
71
|
+
const GAP = 20;
|
|
71
72
|
|
|
72
|
-
let px =
|
|
73
|
-
let py =
|
|
73
|
+
let px = top.x - Math.round(panelW / 2);
|
|
74
|
+
let py = top.topY - panelH - GAP;
|
|
74
75
|
|
|
75
|
-
// Если уходит вверх за контейнер — переносим ниже
|
|
76
|
-
if (py < 0)
|
|
76
|
+
// Если уходит вверх за контейнер — переносим ниже наивысшей точки
|
|
77
|
+
if (py < 0) {
|
|
78
|
+
const mid = getConnectorMidpointScreen(this.core, this.currentId);
|
|
79
|
+
py = (mid?.y ?? top.topY) + GAP;
|
|
80
|
+
}
|
|
77
81
|
|
|
78
82
|
// Clamp по ширине контейнера
|
|
79
83
|
const cw = this.container.offsetWidth || window.innerWidth;
|
package/src/ui/Topbar.js
CHANGED
|
@@ -176,10 +176,18 @@ export class Topbar {
|
|
|
176
176
|
_getCurrentBoardBackgroundHex() {
|
|
177
177
|
try {
|
|
178
178
|
const app = window?.moodboard?.coreMoodboard?.pixi?.app || window?.moodboard?.core?.pixi?.app;
|
|
179
|
-
const
|
|
179
|
+
const renderer = app?.renderer;
|
|
180
|
+
if (!renderer) return null;
|
|
181
|
+
const bg = renderer.background;
|
|
182
|
+
// PIXI v7+: bg.color — экземпляр Color с методом toHex()
|
|
183
|
+
if (bg?.color && typeof bg.color.toHex === 'function') {
|
|
184
|
+
return String(bg.color.toHex()).toLowerCase();
|
|
185
|
+
}
|
|
186
|
+
const colorInt = (typeof bg?.color === 'number')
|
|
187
|
+
? bg.color
|
|
188
|
+
: (typeof renderer.backgroundColor === 'number' ? renderer.backgroundColor : null);
|
|
180
189
|
if (typeof colorInt !== 'number') return null;
|
|
181
|
-
|
|
182
|
-
return hex.toLowerCase();
|
|
190
|
+
return `#${colorInt.toString(16).padStart(6, '0')}`.toLowerCase();
|
|
183
191
|
} catch (_) { return null; }
|
|
184
192
|
}
|
|
185
193
|
|
|
@@ -288,14 +296,20 @@ export class Topbar {
|
|
|
288
296
|
// Выделяем активный цвет галочкой по фактическому boardHex
|
|
289
297
|
try {
|
|
290
298
|
const ap = window?.moodboard?.coreMoodboard?.settingsApplier;
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
this.
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
299
|
+
const raw = (ap && ap.get && ap.get().backgroundColor)
|
|
300
|
+
|| this._currentBoardHex
|
|
301
|
+
|| this._getCurrentBoardBackgroundHex()
|
|
302
|
+
|| '';
|
|
303
|
+
let boardHex = '';
|
|
304
|
+
if (typeof raw === 'number') {
|
|
305
|
+
boardHex = `#${raw.toString(16).padStart(6, '0')}`;
|
|
306
|
+
} else if (typeof raw === 'string') {
|
|
307
|
+
boardHex = raw;
|
|
308
|
+
}
|
|
309
|
+
boardHex = boardHex.toLowerCase();
|
|
297
310
|
const match = boardHex ? grid.querySelector(`[data-board="${boardHex}"]`) : null;
|
|
298
|
-
|
|
311
|
+
const toActivate = match || grid.querySelector('[data-board="#ffffff"]');
|
|
312
|
+
if (toActivate) toActivate.classList.add('is-active');
|
|
299
313
|
} catch (_) {}
|
|
300
314
|
|
|
301
315
|
// позиционируем поповер
|
package/src/ui/boardPalette.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* btnHex — цвет кнопки в Topbar; board — реальный цвет фона canvas.
|
|
5
5
|
*/
|
|
6
6
|
export const BOARD_PALETTE = [
|
|
7
|
-
{ id: 1, name: 'default-light', btnHex: '#d6e8f7', board: '#f0f6fc' },
|
|
7
|
+
{ id: 1, name: 'default-light', btnHex: '#d6e8f7', board: '#f0f6fc', gridColor: '#d4d4d4' },
|
|
8
8
|
{ id: 2, name: 'mint-light', btnHex: '#E8F5E9', board: '#f8fff7' },
|
|
9
9
|
{ id: 3, name: 'peach-light', btnHex: '#FFF3E0', board: '#fffcf7' },
|
|
10
10
|
{ id: 4, name: 'gray-light', btnHex: '#f5f5f5', board: '#f5f5f5' },
|
|
@@ -119,6 +119,45 @@ export function getConnectorMidpointScreen(core, connectorId) {
|
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Возвращает наивысшую экранную точку коннектора (минимальный y) и горизонтальный центр.
|
|
124
|
+
* Координаты — целые числа (screen-space integer contract).
|
|
125
|
+
* @returns {{ x: number, topY: number } | null}
|
|
126
|
+
*/
|
|
127
|
+
export function getConnectorTopScreen(core, connectorId) {
|
|
128
|
+
const segments = core?.connectorLayer?._lastSegments;
|
|
129
|
+
if (!segments) return null;
|
|
130
|
+
const seg = segments.find(s => s.id === connectorId);
|
|
131
|
+
if (!seg) return null;
|
|
132
|
+
|
|
133
|
+
const worldLayer = core?.pixi?.worldLayer;
|
|
134
|
+
const scale = worldLayer?.scale?.x ?? 1;
|
|
135
|
+
const worldX = worldLayer?.x ?? 0;
|
|
136
|
+
const worldY = worldLayer?.y ?? 0;
|
|
137
|
+
|
|
138
|
+
let pts;
|
|
139
|
+
if (seg.points && seg.points.length >= 2) {
|
|
140
|
+
pts = seg.points;
|
|
141
|
+
} else if (seg.start && seg.end) {
|
|
142
|
+
pts = [seg.start, seg.end];
|
|
143
|
+
} else {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let minWorldY = Infinity;
|
|
148
|
+
let sumWorldX = 0;
|
|
149
|
+
for (const p of pts) {
|
|
150
|
+
if (p.y < minWorldY) minWorldY = p.y;
|
|
151
|
+
sumWorldX += p.x;
|
|
152
|
+
}
|
|
153
|
+
const avgWorldX = sumWorldX / pts.length;
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
x: Math.round(avgWorldX * scale + worldX),
|
|
157
|
+
topY: Math.round(minWorldY * scale + worldY),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
122
161
|
/**
|
|
123
162
|
* Формирует updates.properties.style для StateChanged-эмита.
|
|
124
163
|
*/
|