77import {
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}
0 commit comments