@sequent-org/moodboard 1.4.49 → 1.4.52
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/bootstrap/CoreInitializer.js +3 -0
- package/src/core/commands/ApplyCropCommand.js +90 -0
- package/src/core/commands/UpdateFramePropertiesCommand.js +9 -2
- package/src/core/flows/ObjectLifecycleFlow.js +29 -8
- package/src/objects/FrameObject.js +242 -21
- package/src/objects/ImageObject.js +23 -7
- package/src/services/CropController.js +242 -0
- package/src/services/FrameService.js +87 -9
- package/src/services/ImageAttachmentService.js +260 -0
- package/src/tools/manager/ToolManagerLifecycle.js +4 -0
- package/src/tools/object-tools/DrawingTool.js +1 -0
- package/src/tools/object-tools/placement/GhostController.js +2 -2
- package/src/tools/object-tools/placement/PlacementPayloadFactory.js +9 -1
- package/src/tools/object-tools/selection/FrameTitleInlineEditorController.js +13 -4
- package/src/tools/object-tools/selection/InlineEditorDomFactory.js +15 -10
- package/src/tools/object-tools/selection/TransformInteractionController.js +50 -0
- package/src/ui/CropOverlay.js +654 -0
- package/src/ui/FramePropertiesPanel.js +1184 -405
- package/src/ui/HtmlHandlesLayer.js +2 -0
- package/src/ui/ImagePropertiesPanel.js +85 -41
- package/src/ui/connectors/ConnectionAnchorsLayer.js +4 -0
- package/src/ui/handles/HandlesDomRenderer.js +9 -2
- package/src/ui/handles/HandlesEventBridge.js +1 -0
- package/src/ui/styles/panels.css +402 -27
- package/src/ui/styles/workspace.css +20 -0
- package/src/utils/applyCrop.js +92 -0
|
@@ -43,7 +43,15 @@ export class PlacementPayloadFactory {
|
|
|
43
43
|
type: 'frame',
|
|
44
44
|
id: 'frame',
|
|
45
45
|
position: { x, y },
|
|
46
|
-
properties: {
|
|
46
|
+
properties: {
|
|
47
|
+
width: Math.round(w),
|
|
48
|
+
height: Math.round(h),
|
|
49
|
+
title: 'Произвольный',
|
|
50
|
+
lockedAspect: false,
|
|
51
|
+
isArbitrary: true,
|
|
52
|
+
bgMode: 'solid',
|
|
53
|
+
backgroundColor: 0xFFFFFF,
|
|
54
|
+
}
|
|
47
55
|
});
|
|
48
56
|
}
|
|
49
57
|
|
|
@@ -50,16 +50,25 @@ export function openFrameTitleEditor(object, _create = false) {
|
|
|
50
50
|
? toScreenWithContainerOffset(titleLayer, view, 0, 0)
|
|
51
51
|
: { x: 0, y: 0 };
|
|
52
52
|
|
|
53
|
-
//
|
|
53
|
+
// Габариты редактора = titleBg в экранных пикселях (с учётом зум-компенсации)
|
|
54
54
|
let inputWidth = 150;
|
|
55
|
+
let inputHeight = 22;
|
|
55
56
|
if (titleLayer && frameInstance.titleBg) {
|
|
56
57
|
const bgRight = toScreenWithContainerOffset(titleLayer, view, frameInstance.titleBg.width || 150, 0);
|
|
57
|
-
|
|
58
|
+
const bgBottom = toScreenWithContainerOffset(titleLayer, view, 0, frameInstance.titleBg.height || 22);
|
|
59
|
+
inputWidth = Math.max(1, Math.round(bgRight.x - screenPos.x));
|
|
60
|
+
inputHeight = Math.max(1, Math.round(bgBottom.y - screenPos.y));
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
const
|
|
61
|
-
|
|
63
|
+
const titleColors = typeof frameInstance.getTitleColors === 'function'
|
|
64
|
+
? frameInstance.getTitleColors()
|
|
65
|
+
: { bgCss: '#ffffff', textCss: '#333333' };
|
|
66
|
+
|
|
67
|
+
const wrapper = createFrameTitleEditorWrapper(titleColors.bgCss);
|
|
68
|
+
wrapper.id = `mb-frame-title-editor-${objectId}`;
|
|
69
|
+
const input = createFrameTitleEditorInput(currentTitle, titleColors.textCss);
|
|
62
70
|
wrapper.style.width = `${inputWidth}px`;
|
|
71
|
+
wrapper.style.height = `${inputHeight}px`;
|
|
63
72
|
|
|
64
73
|
wrapper.appendChild(input);
|
|
65
74
|
view.parentElement.appendChild(wrapper);
|
|
@@ -30,38 +30,43 @@ export function createFileNameEditorWrapper() {
|
|
|
30
30
|
return wrapper;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export function createFrameTitleEditorWrapper() {
|
|
33
|
+
export function createFrameTitleEditorWrapper(bgColor = '#ffffff') {
|
|
34
34
|
const wrapper = document.createElement('div');
|
|
35
35
|
wrapper.className = 'moodboard-frame-title-editor';
|
|
36
36
|
wrapper.style.cssText = `
|
|
37
37
|
position: absolute;
|
|
38
38
|
z-index: 1000;
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
background: ${bgColor};
|
|
43
|
+
border: none;
|
|
41
44
|
border-radius: 6px;
|
|
42
|
-
padding:
|
|
43
|
-
|
|
44
|
-
min-width: 100px;
|
|
45
|
-
max-width: 320px;
|
|
45
|
+
padding: 4px 8px;
|
|
46
|
+
overflow: hidden;
|
|
46
47
|
font-family: Inter, system-ui, -apple-system, Arial, sans-serif;
|
|
47
48
|
`;
|
|
48
49
|
return wrapper;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
export function createFrameTitleEditorInput(title) {
|
|
52
|
+
export function createFrameTitleEditorInput(title, textColor = '#333333') {
|
|
52
53
|
const input = document.createElement('input');
|
|
53
54
|
input.type = 'text';
|
|
54
55
|
input.value = title;
|
|
55
56
|
input.style.cssText = `
|
|
57
|
+
box-sizing: border-box;
|
|
56
58
|
border: none;
|
|
57
59
|
outline: none;
|
|
58
60
|
background: transparent;
|
|
59
61
|
font-family: Inter, system-ui, -apple-system, Arial, sans-serif;
|
|
60
62
|
font-size: 14px;
|
|
61
63
|
font-weight: 500;
|
|
64
|
+
line-height: 14px;
|
|
65
|
+
height: 14px;
|
|
62
66
|
width: 100%;
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
margin: 0;
|
|
68
|
+
padding: 0;
|
|
69
|
+
color: ${textColor};
|
|
65
70
|
`;
|
|
66
71
|
return input;
|
|
67
72
|
}
|
|
@@ -25,6 +25,12 @@ export function handleObjectSelect(objectId, event) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function startDrag(objectId, event) {
|
|
28
|
+
const req = { objectId, pixiObject: null };
|
|
29
|
+
this.emit('tool:get:object:pixi', req);
|
|
30
|
+
if (req.pixiObject?._mb?.properties?.locked) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
this.isDragging = true;
|
|
29
35
|
this.dragTarget = objectId;
|
|
30
36
|
// Сообщаем HtmlHandlesLayer о начале перетаскивания одиночного объекта
|
|
@@ -91,6 +97,23 @@ export function endDrag() {
|
|
|
91
97
|
}
|
|
92
98
|
|
|
93
99
|
export function startResize(handle, objectId) {
|
|
100
|
+
const isLocked = (() => {
|
|
101
|
+
if (objectId === this.groupId) {
|
|
102
|
+
return this.selection.toArray().some(id => {
|
|
103
|
+
const req = { objectId: id, pixiObject: null };
|
|
104
|
+
this.emit('tool:get:object:pixi', req);
|
|
105
|
+
return !!req.pixiObject?._mb?.properties?.locked;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const req = { objectId, pixiObject: null };
|
|
109
|
+
this.emit('tool:get:object:pixi', req);
|
|
110
|
+
return !!req.pixiObject?._mb?.properties?.locked;
|
|
111
|
+
})();
|
|
112
|
+
|
|
113
|
+
if (isLocked) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
94
117
|
// Групповой resize
|
|
95
118
|
if (objectId === this.groupId && this.selection.size() > 1) {
|
|
96
119
|
this.isGroupResizing = true;
|
|
@@ -169,6 +192,23 @@ export function endResize() {
|
|
|
169
192
|
}
|
|
170
193
|
|
|
171
194
|
export function startRotate(objectId) {
|
|
195
|
+
const isLocked = (() => {
|
|
196
|
+
if (objectId === this.groupId) {
|
|
197
|
+
return this.selection.toArray().some(id => {
|
|
198
|
+
const req = { objectId: id, pixiObject: null };
|
|
199
|
+
this.emit('tool:get:object:pixi', req);
|
|
200
|
+
return !!req.pixiObject?._mb?.properties?.locked;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const req = { objectId, pixiObject: null };
|
|
204
|
+
this.emit('tool:get:object:pixi', req);
|
|
205
|
+
return !!req.pixiObject?._mb?.properties?.locked;
|
|
206
|
+
})();
|
|
207
|
+
|
|
208
|
+
if (isLocked) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
172
212
|
// Групповой поворот
|
|
173
213
|
if (objectId === this.groupId && this.selection.size() > 1) {
|
|
174
214
|
this.isGroupRotating = true;
|
|
@@ -276,6 +316,16 @@ export function endBoxSelect() {
|
|
|
276
316
|
}
|
|
277
317
|
|
|
278
318
|
export function startGroupDrag(event) {
|
|
319
|
+
const isLocked = this.selection.toArray().some(id => {
|
|
320
|
+
const req = { objectId: id, pixiObject: null };
|
|
321
|
+
this.emit('tool:get:object:pixi', req);
|
|
322
|
+
return !!req.pixiObject?._mb?.properties?.locked;
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
if (isLocked) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
279
329
|
const gb = this.computeGroupBounds();
|
|
280
330
|
this.groupStartBounds = gb;
|
|
281
331
|
this.isGroupDragging = true;
|