diff --git a/core/block_svg.ts b/core/block_svg.ts index 6441cc434cb..c41bf38841a 100644 --- a/core/block_svg.ts +++ b/core/block_svg.ts @@ -243,9 +243,8 @@ export class BlockSvg /** Selects this block. Highlights the block visually. */ select() { - if (this.isShadow() && this.getParent()) { - // Shadow blocks should not be selected. - this.getParent()!.select(); + if (this.isShadow()) { + this.getParent()?.select(); return; } this.addSelect(); @@ -253,6 +252,10 @@ export class BlockSvg /** Unselects this block. Unhighlights the blockv visually. */ unselect() { + if (this.isShadow()) { + this.getParent()?.unselect(); + return; + } this.removeSelect(); } diff --git a/core/dragging/block_drag_strategy.ts b/core/dragging/block_drag_strategy.ts index 84afe2a138f..d3f348e8fbf 100644 --- a/core/dragging/block_drag_strategy.ts +++ b/core/dragging/block_drag_strategy.ts @@ -55,15 +55,24 @@ export class BlockDragStrategy implements IDragStrategy { private dragging = false; + /** + * If this is a shadow block, the offset between this block and the parent + * block, to add to the drag location. In workspace units. + */ + private dragOffset = new Coordinate(0, 0); + constructor(private block: BlockSvg) { this.workspace = block.workspace; } /** Returns true if the block is currently movable. False otherwise. */ isMovable(): boolean { + if (this.block.isShadow()) { + return this.block.getParent()?.isMovable() ?? false; + } + return ( this.block.isOwnMovable() && - !this.block.isShadow() && !this.block.isDeadOrDying() && !this.workspace.options.readOnly && // We never drag blocks in the flyout, only create new blocks that are @@ -77,6 +86,11 @@ export class BlockDragStrategy implements IDragStrategy { * from any parent blocks. */ startDrag(e?: PointerEvent): void { + if (this.block.isShadow()) { + this.startDraggingShadow(e); + return; + } + this.dragging = true; if (!eventUtils.getGroup()) { eventUtils.setGroup(true); @@ -106,6 +120,22 @@ export class BlockDragStrategy implements IDragStrategy { this.workspace.getLayerManager()?.moveToDragLayer(this.block); } + /** Starts a drag on a shadow, recording the drag offset. */ + private startDraggingShadow(e?: PointerEvent) { + const parent = this.block.getParent(); + if (!parent) { + throw new Error( + 'Tried to drag a shadow block with no parent. ' + + 'Shadow blocks should always have parents.', + ); + } + this.dragOffset = Coordinate.difference( + parent.getRelativeToSurfaceXY(), + this.block.getRelativeToSurfaceXY(), + ); + parent.startDrag(e); + } + /** * Whether or not we should disconnect the block when a drag is started. * @@ -174,6 +204,11 @@ export class BlockDragStrategy implements IDragStrategy { /** Moves the block and updates any connection previews. */ drag(newLoc: Coordinate): void { + if (this.block.isShadow()) { + this.block.getParent()?.drag(Coordinate.sum(newLoc, this.dragOffset)); + return; + } + this.block.moveDuringDrag(newLoc); this.updateConnectionPreview( this.block, @@ -317,7 +352,12 @@ export class BlockDragStrategy implements IDragStrategy { * Cleans up any state at the end of the drag. Applies any pending * connections. */ - endDrag(): void { + endDrag(e?: PointerEvent): void { + if (this.block.isShadow()) { + this.block.getParent()?.endDrag(e); + return; + } + this.fireDragEndEvent(); this.fireMoveEvent(); @@ -373,6 +413,11 @@ export class BlockDragStrategy implements IDragStrategy { * including reconnecting connections. */ revertDrag(): void { + if (this.block.isShadow()) { + this.block.getParent()?.revertDrag(); + return; + } + this.startChildConn?.connect(this.block.nextConnection); if (this.startParentConn) { switch (this.startParentConn.type) {