Skip to content

Commit 9c6e622

Browse files
feat: start a move when inserting a block from the flyout (RaspberryPiFoundation#406)
* feat: drag on move, first pass * chore: cleanup and lint * feat: always heal stack
1 parent 83753bd commit 9c6e622

File tree

4 files changed

+95
-7
lines changed

4 files changed

+95
-7
lines changed

src/actions/enter.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ import type {
2222

2323
import * as Constants from '../constants';
2424
import type {Navigation} from '../navigation';
25+
import {Mover} from './mover';
2526

2627
const KeyCodes = BlocklyUtils.KeyCodes;
2728

2829
/**
2930
* Class for registering a shortcut for the enter action.
3031
*/
3132
export class EnterAction {
32-
constructor(private navigation: Navigation) {}
33+
constructor(
34+
private mover: Mover,
35+
private navigation: Navigation,
36+
) {}
3337

3438
/**
3539
* Adds the enter action shortcut to the registry.
@@ -149,6 +153,7 @@ export class EnterAction {
149153
this.navigation.focusWorkspace(workspace);
150154
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
151155
workspace.getCursor()?.setCurNode(ASTNode.createBlockNode(newBlock)!);
156+
this.mover.startMove(workspace);
152157
}
153158

154159
/**

src/actions/mover.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ export class Mover {
121121
this.moves.set(workspace, info);
122122
// Begin drag.
123123
dragger.onDragStart(info.fakePointerEvent('pointerdown'));
124-
info.dragger.onDrag(info.fakePointerEvent('pointermove'), info.totalDelta);
125124
return true;
126125
}
127126

src/keyboard_drag_strategy.ts

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import {
88
ASTNode,
99
BlockSvg,
10-
RenderedConnection,
10+
ConnectionType,
1111
LineCursor,
12+
RenderedConnection,
1213
dragging,
1314
utils,
1415
} from 'blockly';
@@ -40,8 +41,9 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
4041
// to the top left of the workspace.
4142
// @ts-expect-error block and startLoc are private.
4243
this.block.moveDuringDrag(this.startLoc);
43-
// @ts-expect-error startParentConn is private.
44-
this.searchNode = ASTNode.createConnectionNode(this.startParentConn);
44+
// @ts-expect-error connectionCandidate is private.
45+
this.connectionCandidate = this.createInitialCandidate();
46+
this.forceShowPreview();
4547
}
4648

4749
override drag(newLoc: utils.Coordinate, e?: PointerEvent): void {
@@ -60,7 +62,7 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
6062
this.searchNode = ASTNode.createConnectionNode(neighbour);
6163
// The moving block will be positioned slightly down and to the
6264
// right of the connection it found.
63-
// @ts-expect-error block and startLoc are private.
65+
// @ts-expect-error block is private.
6466
this.block.moveDuringDrag(
6567
new utils.Coordinate(neighbour.x + 10, neighbour.y + 10),
6668
);
@@ -205,4 +207,86 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
205207
private isConstrainedMovement(): boolean {
206208
return !!this.currentDragDirection;
207209
}
210+
211+
/**
212+
* Force the preview (replacement or insertion marker) to be shown
213+
* immediately. Keyboard drags should always show a preview, even when
214+
* the drag has just started; this forces it.
215+
*/
216+
private forceShowPreview() {
217+
// @ts-expect-error connectionPreviewer is private
218+
const previewer = this.connectionPreviewer;
219+
// @ts-expect-error connectionCandidate is private
220+
const candidate = this.connectionCandidate as ConnectionCandidate;
221+
if (!candidate || !previewer) return;
222+
// @ts-expect-error block is private
223+
const block = this.block;
224+
225+
// This is essentially a copy of the second half of updateConnectionPreview
226+
// in BlockDragStrategy. It adds a `moveDuringDrag` call at the end.
227+
const {local, neighbour} = candidate;
228+
const localIsOutputOrPrevious =
229+
local.type === ConnectionType.OUTPUT_VALUE ||
230+
local.type === ConnectionType.PREVIOUS_STATEMENT;
231+
232+
const target = neighbour.targetBlock();
233+
const neighbourIsConnectedToRealBlock =
234+
target && !target.isInsertionMarker();
235+
236+
const orphanCanConnectAtEnd =
237+
target &&
238+
// @ts-expect-error orphanCanConnectAtEnd is private
239+
this.orphanCanConnectAtEnd(block, target, local.type);
240+
if (
241+
localIsOutputOrPrevious &&
242+
neighbourIsConnectedToRealBlock &&
243+
!orphanCanConnectAtEnd
244+
) {
245+
previewer.previewReplacement(local, neighbour, target);
246+
} else {
247+
previewer.previewConnection(local, neighbour);
248+
}
249+
// The moving block will be positioned slightly down and to the
250+
// right of the connection it found.
251+
block.moveDuringDrag(
252+
new utils.Coordinate(neighbour.x + 10, neighbour.y + 10),
253+
);
254+
}
255+
256+
/**
257+
* Create a candidate representing where the block was previously connected.
258+
* Used to render the block position after picking up the block but before
259+
* moving during a drag.
260+
*
261+
* @returns A connection candidate representing where the block was at the
262+
* start of the drag.
263+
*/
264+
private createInitialCandidate(): ConnectionCandidate | null {
265+
// @ts-expect-error startParentConn is private.
266+
const neighbour = this.startParentConn;
267+
if (neighbour) {
268+
this.searchNode = ASTNode.createConnectionNode(neighbour);
269+
switch (neighbour.type) {
270+
case ConnectionType.INPUT_VALUE:
271+
return {
272+
neighbour: neighbour,
273+
// @ts-expect-error block is private.
274+
local: this.block.outputConnection,
275+
distance: 0,
276+
};
277+
case ConnectionType.NEXT_STATEMENT:
278+
return {
279+
neighbour: neighbour,
280+
// @ts-expect-error block is private.
281+
local: this.block.previousConnection,
282+
distance: 0,
283+
};
284+
}
285+
}
286+
return null;
287+
}
288+
289+
override shouldHealStack(e: PointerEvent | undefined): boolean {
290+
return true;
291+
}
208292
}

src/navigation_controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class NavigationController {
7171

7272
exitAction: ExitAction = new ExitAction(this.navigation);
7373

74-
enterAction: EnterAction = new EnterAction(this.navigation);
74+
enterAction: EnterAction = new EnterAction(this.mover, this.navigation);
7575

7676
undoRedoAction: UndoRedoAction = new UndoRedoAction();
7777

0 commit comments

Comments
 (0)