@@ -150,15 +150,9 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
150150 const dir = this . currentDragDirection ;
151151 while ( potential && ! candidateConnection ) {
152152 if ( dir === Direction . Up || dir === Direction . Left ) {
153- potential = cursor . getPreviousNode ( potential , ( node ) => {
154- // @ts -expect-error isConnectionType is private.
155- return node && ASTNode . isConnectionType ( node . getType ( ) ) ;
156- } ) ;
153+ potential = this . getPreviousNode ( potential , cursor ) ;
157154 } else if ( dir === Direction . Down || dir === Direction . Right ) {
158- potential = cursor . getNextNode ( potential , ( node ) => {
159- // @ts -expect-error isConnectionType is private.
160- return node && ASTNode . isConnectionType ( node . getType ( ) ) ;
161- } ) ;
155+ potential = this . getNextNode ( potential , cursor ) ;
162156 }
163157
164158 localConns . forEach ( ( conn : RenderedConnection ) => {
@@ -289,4 +283,77 @@ export class KeyboardDragStrategy extends dragging.BlockDragStrategy {
289283 override shouldHealStack ( e : PointerEvent | undefined ) : boolean {
290284 return true ;
291285 }
286+
287+ /**
288+ * Get the previous node in the tree, with loopback to the last
289+ * stack on the workspace if needed.
290+ *
291+ * @param start Where to start traversal.
292+ * @param cursor The workspace's cursor
293+ * @returns The previous node, or null if there were no valid nodes
294+ * on the workspace.
295+ */
296+ private getPreviousNode ( start : ASTNode , cursor : LineCursor ) {
297+ let potential : ASTNode | null = start ;
298+ potential = cursor . getPreviousNode ( potential , ( node ) => {
299+ // @ts -expect-error isConnectionType is private.
300+ return node && ASTNode . isConnectionType ( node . getType ( ) ) ;
301+ } ) ;
302+ if ( ! potential ) {
303+ // Loop back to last block if it exists.
304+ // @ts -expect-error workspace is private
305+ const topBlocks = this . workspace . getTopBlocks ( true ) ;
306+ if ( ! topBlocks . length ) return null ;
307+
308+ // Find the last stack.
309+ const lastTopBlockNode = ASTNode . createStackNode (
310+ topBlocks [ topBlocks . length - 1 ] ,
311+ ) ;
312+ let prevNode = lastTopBlockNode ;
313+ let nextNode : ASTNode | null = lastTopBlockNode ;
314+ // Iterate until you fall off the end of the stack.
315+ while ( nextNode ) {
316+ prevNode = nextNode ;
317+ nextNode = cursor . getNextNode ( prevNode , ( node ) => {
318+ return ! ! node ;
319+ } ) ;
320+ }
321+
322+ // Resume searching.
323+ potential = cursor . getPreviousNode ( prevNode , ( node ) => {
324+ // @ts -expect-error isConnectionType is private.
325+ return node && ASTNode . isConnectionType ( node . getType ( ) ) ;
326+ } ) ;
327+ }
328+ return potential ;
329+ }
330+
331+ /**
332+ * Get the next node in the tree, with loopback to the first
333+ * stack on the workspace if needed.
334+ *
335+ * @param start Where to start traversal.
336+ * @param cursor The workspace's cursor
337+ * @returns The next node, or null if there were no valid nodes
338+ * on the workspace.
339+ */
340+ private getNextNode ( start : ASTNode , cursor : LineCursor ) {
341+ let potential : ASTNode | null = start ;
342+ potential = cursor . getNextNode ( potential , ( node ) => {
343+ // @ts -expect-error isConnectionType is private.
344+ return node && ASTNode . isConnectionType ( node . getType ( ) ) ;
345+ } ) ;
346+ if ( ! potential ) {
347+ // Loop back to first block if it exists.
348+ // @ts -expect-error workspace is private
349+ const topBlocks = this . workspace . getTopBlocks ( true ) ;
350+ if ( ! topBlocks . length ) return null ;
351+ const initial = ASTNode . createTopNode ( topBlocks [ 0 ] ) ;
352+ potential = cursor . getNextNode ( initial , ( node ) => {
353+ // @ts -expect-error isConnectionType is private.
354+ return node && ASTNode . isConnectionType ( node . getType ( ) ) ;
355+ } ) ;
356+ }
357+ return potential ;
358+ }
292359}
0 commit comments