@elixpo/lixsketch 5.4.1 → 5.4.2
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
|
@@ -8,7 +8,7 @@ import { handleMouseDownCircle, handleMouseMoveCircle, handleMouseUpCircle } fro
|
|
|
8
8
|
import { handleMouseUpImage, handleMouseDownImage, handleMouseMoveImage } from '../tools/imageTool.js';
|
|
9
9
|
import { handleMouseDownLine, handleMouseMoveLine, handleMouseUpLine } from '../tools/lineTool.js';
|
|
10
10
|
import { handleFreehandMouseDown, handleFreehandMouseMove, handleFreehandMouseUp } from '../tools/freehandTool.js';
|
|
11
|
-
import { handleTextMouseDown, handleTextMouseMove, handleTextMouseUp } from '../tools/textTool.js';
|
|
11
|
+
import { handleTextMouseDown, handleTextMouseMove, handleTextMouseUp, enterEditMode } from '../tools/textTool.js';
|
|
12
12
|
import { handleMouseDownFrame, handleMouseMoveFrame, handleMouseUpFrame } from '../tools/frameTool.js';
|
|
13
13
|
import { handleMultiSelectionMouseDown, handleMultiSelectionMouseMove, handleMultiSelectionMouseUp, removeMultiSelectionRect, multiSelection, isMultiSelecting} from './Selection.js';
|
|
14
14
|
import { handleMouseDownIcon, handleMouseMoveIcon, handleMouseUpIcon } from '../tools/iconTool.js';
|
|
@@ -464,6 +464,15 @@ function _onMouseEnter(e) {
|
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
+
const handleMainDblClick = (e) => {
|
|
468
|
+
// Double-click on a text group from any tool: enter text edit mode
|
|
469
|
+
const targetTextGroup = e.target.closest('g[data-type="text-group"]');
|
|
470
|
+
if (targetTextGroup) {
|
|
471
|
+
e.stopPropagation();
|
|
472
|
+
enterEditMode(targetTextGroup);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
|
|
467
476
|
function initEventDispatcher(svgEl) {
|
|
468
477
|
if (_boundSvg) cleanupEventDispatcher();
|
|
469
478
|
const target = svgEl || svg;
|
|
@@ -472,6 +481,7 @@ function initEventDispatcher(svgEl) {
|
|
|
472
481
|
target.addEventListener('mouseup', handleMainMouseUp);
|
|
473
482
|
target.addEventListener('mouseleave', handleMainMouseLeave);
|
|
474
483
|
target.addEventListener('mouseenter', _onMouseEnter);
|
|
484
|
+
target.addEventListener('dblclick', handleMainDblClick);
|
|
475
485
|
_boundSvg = target;
|
|
476
486
|
}
|
|
477
487
|
|
|
@@ -488,6 +498,7 @@ function cleanupEventDispatcher() {
|
|
|
488
498
|
_boundSvg.removeEventListener('mouseup', handleMainMouseUp);
|
|
489
499
|
_boundSvg.removeEventListener('mouseleave', handleMainMouseLeave);
|
|
490
500
|
_boundSvg.removeEventListener('mouseenter', _onMouseEnter);
|
|
501
|
+
_boundSvg.removeEventListener('dblclick', handleMainDblClick);
|
|
491
502
|
_boundSvg = null;
|
|
492
503
|
}
|
|
493
504
|
}
|
package/src/core/Selection.js
CHANGED
|
@@ -80,9 +80,10 @@ function highlightShapesInSelectionRect(currentX, currentY) {
|
|
|
80
80
|
shapes.forEach(shape => {
|
|
81
81
|
if (isShapeInSelectionRect(shape, selBounds)) {
|
|
82
82
|
// Add a semi-transparent overlay to the shape's group
|
|
83
|
-
if (shape.group) {
|
|
83
|
+
if (shape.group && typeof shape.group.getBBox === 'function') {
|
|
84
|
+
let bbox;
|
|
85
|
+
try { bbox = shape.group.getBBox(); } catch { return; }
|
|
84
86
|
const overlay = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
85
|
-
const bbox = shape.group.getBBox();
|
|
86
87
|
overlay.setAttribute('x', bbox.x - 2);
|
|
87
88
|
overlay.setAttribute('y', bbox.y - 2);
|
|
88
89
|
overlay.setAttribute('width', bbox.width + 4);
|
package/src/shapes/CodeShape.js
CHANGED
|
@@ -202,11 +202,12 @@ class CodeShape {
|
|
|
202
202
|
|
|
203
203
|
contains(x, y) {
|
|
204
204
|
const codeElement = this.group.querySelector('text');
|
|
205
|
-
if (!codeElement) return false;
|
|
206
|
-
|
|
207
|
-
|
|
205
|
+
if (!codeElement || typeof codeElement.getBBox !== 'function') return false;
|
|
206
|
+
|
|
207
|
+
let bbox;
|
|
208
|
+
try { bbox = codeElement.getBBox(); } catch { return false; }
|
|
208
209
|
const padding = 8; // Selection padding
|
|
209
|
-
|
|
210
|
+
|
|
210
211
|
const CTM = this.group.getCTM();
|
|
211
212
|
if (!CTM) return false;
|
|
212
213
|
|
package/src/shapes/TextShape.js
CHANGED
|
@@ -182,11 +182,12 @@ class TextShape {
|
|
|
182
182
|
|
|
183
183
|
contains(x, y) {
|
|
184
184
|
const textElement = this.group.querySelector('text');
|
|
185
|
-
if (!textElement) return false;
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
if (!textElement || typeof textElement.getBBox !== 'function') return false;
|
|
186
|
+
|
|
187
|
+
let bbox;
|
|
188
|
+
try { bbox = textElement.getBBox(); } catch { return false; }
|
|
188
189
|
const padding = 8; // Selection padding
|
|
189
|
-
|
|
190
|
+
|
|
190
191
|
const CTM = this.group.getCTM();
|
|
191
192
|
if (!CTM) return false;
|
|
192
193
|
|
package/src/tools/textTool.js
CHANGED
|
@@ -51,6 +51,7 @@ let rotationStartTransform = null;
|
|
|
51
51
|
let initialHandlePosRelGroup = null;
|
|
52
52
|
let initialGroupTx = 0;
|
|
53
53
|
let initialGroupTy = 0;
|
|
54
|
+
let initialInverseScreenCTM = null;
|
|
54
55
|
|
|
55
56
|
// Frame attachment variables
|
|
56
57
|
let draggedShapeInitialFrameText = null;
|
|
@@ -753,6 +754,10 @@ function startResize(event, anchor) {
|
|
|
753
754
|
|
|
754
755
|
startPoint = getSVGCoordinates(event, selectedElement);
|
|
755
756
|
|
|
757
|
+
// Freeze the group's screen CTM at resize start so mouse→local mapping stays stable
|
|
758
|
+
const groupScreenCTM = selectedElement.getScreenCTM();
|
|
759
|
+
initialInverseScreenCTM = groupScreenCTM ? groupScreenCTM.inverse() : null;
|
|
760
|
+
|
|
756
761
|
const currentTransform = selectedElement.transform.baseVal.consolidate();
|
|
757
762
|
initialGroupTx = currentTransform ? currentTransform.matrix.e : 0;
|
|
758
763
|
initialGroupTy = currentTransform ? currentTransform.matrix.f : 0;
|
|
@@ -828,7 +833,16 @@ const handleMouseMove = (event) => {
|
|
|
828
833
|
const textElement = selectedElement.querySelector('text');
|
|
829
834
|
if (!textElement || !startBBox || startFontSize === null || !startPoint || !initialHandlePosRelGroup) return;
|
|
830
835
|
|
|
831
|
-
|
|
836
|
+
// Use the frozen initial CTM so the mapping doesn't shift as we change the group transform
|
|
837
|
+
let currentPoint;
|
|
838
|
+
if (initialInverseScreenCTM) {
|
|
839
|
+
const pt = svg.createSVGPoint();
|
|
840
|
+
pt.x = event.clientX;
|
|
841
|
+
pt.y = event.clientY;
|
|
842
|
+
currentPoint = pt.matrixTransform(initialInverseScreenCTM);
|
|
843
|
+
} else {
|
|
844
|
+
currentPoint = getSVGCoordinates(event, selectedElement);
|
|
845
|
+
}
|
|
832
846
|
|
|
833
847
|
const startX = startBBox.x;
|
|
834
848
|
const startY = startBBox.y;
|
|
@@ -1820,4 +1834,4 @@ window.__setCodeLanguage = function(lang) {
|
|
|
1820
1834
|
}
|
|
1821
1835
|
};
|
|
1822
1836
|
|
|
1823
|
-
export { handleTextMouseDown, handleTextMouseMove, handleTextMouseUp, updateCodeToggleForShape, deselectElement as deselectTextElement };
|
|
1837
|
+
export { handleTextMouseDown, handleTextMouseMove, handleTextMouseUp, updateCodeToggleForShape, deselectElement as deselectTextElement, enterEditMode };
|