Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 80 additions & 15 deletions web/libs/editor/src/components/KonvaVector/KonvaVector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
pointStroke = DEFAULT_POINT_STROKE,
pointStrokeSelected = DEFAULT_POINT_STROKE_SELECTED,
pointStrokeWidth = DEFAULT_POINT_STROKE_WIDTH,
// Optional: marks this vector as the active one for interactions and ghost line
isActive = true,
} = props;

// Normalize input points to BezierPoint format
Expand Down Expand Up @@ -1763,6 +1765,27 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
pointCreationManager,
});

// Attach Stage-level listeners for cursor tracking (always active when not disabled)
// This allows drawing over other regions while maintaining ghost line functionality
useEffect(() => {
if (disabled) return;
const group = stageRef.current as unknown as Konva.Node | null;
const stage = group?.getStage();
if (!stage) return;

const ns = `.${instanceId}`;
const onMouseMove = (e: any) => {
// Only handle mousemove for cursor tracking - let other regions handle their own events
eventHandlers.handleLayerMouseMove?.(e);
};

stage.on(`mousemove${ns}`, onMouseMove);

return () => {
stage.off(`mousemove${ns}`);
};
}, [disabled, eventHandlers, instanceId]);

return (
<Group
ref={stageRef}
Expand All @@ -1784,6 +1807,24 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
return;
}

// Check if the click target is a Path (shape) - if so, let it propagate to parent handlers
// This allows region selection to work when clicking on the shape itself
const target = e.target;
const targetName = target?.name?.() || "";
const isPathClick = target?.getType?.() === "Path" || targetName.includes("path-");

// If clicking on the shape (not a point), let the onClick prop handle it directly
// This ensures region selection works properly
if (isPathClick) {
// Reset the flag and let the event propagate
pointSelectionHandled.current = false;
// Call the onClick prop directly if provided (for region selection)
if (onClick) {
onClick(e);
}
return;
}

// For the first point in drawing mode, we need to ensure the click handler works
// The issue is that the flag logic is interfering with first point creation
// Let's try calling the drawing mode click handler directly for the first point
Expand Down Expand Up @@ -1840,17 +1881,7 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
}
}
>
{/* Invisible rectangle - always render to capture mouse events for cursor position updates */}
{!disabled && (
<Shape
sceneFunc={(ctx, shape) => {
ctx.beginPath();
ctx.rect(0, 0, width, height);
ctx.fillShape(shape);
}}
fill={INVISIBLE_SHAPE_OPACITY}
/>
)}
{/* Invisible rectangle removed - cursor tracking now handled by stage-level listeners */}

{/* Conditionally wrap content with _transformable group for ImageTransformer */}
{isMultiRegionSelected ? (
Expand Down Expand Up @@ -1973,8 +2004,16 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
}
}

// Use debouncing for click/double-click detection
handleClickWithDebouncing(e, onClick, onDblClick);
// For region selection, call onClick prop directly without debouncing
// This ensures clicks on the shape itself trigger region selection immediately
if (onClick) {
onClick(e);
}

// Use debouncing for double-click detection only
if (onDblClick) {
handleClickWithDebouncing(e, undefined, onDblClick);
}
}}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
Expand Down Expand Up @@ -2214,8 +2253,16 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
}
}

// Use debouncing for click/double-click detection
handleClickWithDebouncing(e, onClick, onDblClick);
// For region selection, call onClick prop directly without debouncing
// This ensures clicks on the shape itself trigger region selection immediately
if (onClick) {
onClick(e);
}

// Use debouncing for double-click detection only
if (onDblClick) {
handleClickWithDebouncing(e, undefined, onDblClick);
}
}}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
Expand Down Expand Up @@ -2275,6 +2322,22 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
onPointClick={(e, pointIndex) => {
// Handle Alt+click point deletion FIRST (before other checks)
if (e.evt.altKey && !e.evt.shiftKey && !disabled) {
// Clear multi-selection if the deleted point was selected
if (selectedPoints.has(pointIndex)) {
const newSelection = new Set(selectedPoints);
newSelection.delete(pointIndex);
// Adjust indices for points after the deleted one
const adjustedSelection = new Set<number>();
for (const idx of Array.from(newSelection)) {
if (idx > pointIndex) {
adjustedSelection.add(idx - 1);
} else {
adjustedSelection.add(idx);
}
}
tracker.selectPoints(instanceId, adjustedSelection);
}

deletePoint(
pointIndex,
initialPoints,
Expand All @@ -2288,6 +2351,8 @@ export const KonvaVector = forwardRef<KonvaVectorRef, KonvaVectorProps>((props,
lastAddedPointId,
);
pointSelectionHandled.current = true;
// Stop event propagation to prevent path closing or other handlers from firing
e.evt.stopImmediatePropagation();
return; // Successfully deleted point
}

Expand Down
Loading
Loading