@@ -318,21 +318,61 @@ function handleMoveHotkey(e: KeyboardEvent) {
318318 const target = e .target as HTMLElement
319319 if (target .id === ' input-box' || target .closest ?.(' #input-box' )) return
320320 if (host .value ?.querySelector (' #input-box' )) return
321- const current = mind .currentNode
322- if (! current ) return
323- const nodeObj = current .nodeObj
324- if (! nodeObj .parent ) return
321+ const nodes = (mind .currentNodes ?.length ? mind .currentNodes : mind .currentNode ? [mind .currentNode ] : []) as Array <NonNullable <MindElixirInstance [' currentNode' ]>>
322+ if (! nodes .length ) return
323+ const firstObj = nodes [0 ].nodeObj
324+ if (! firstObj .parent ) return
325+ if (nodes .length > 1 ) {
326+ const parentId = firstObj .parent .id
327+ if (! nodes .every ((n ) => (n .nodeObj .parent as { id: string } | undefined )?.id === parentId )) return
328+ }
325329
326330 e .preventDefault ()
327331 e .stopImmediatePropagation ()
328332
329- if (e .key === ' ArrowUp' ) return mind .moveUpNode (current )
330- if (e .key === ' ArrowDown' ) return mind .moveDownNode (current )
333+ const parent = firstObj .parent as NodeObj
334+ const siblings = parent .children ?? []
335+ const sortedNodes = [... nodes ].sort (
336+ (a , b ) =>
337+ siblings .findIndex ((c ) => c .id === a .nodeObj .id ) -
338+ siblings .findIndex ((c ) => c .id === b .nodeObj .id )
339+ )
331340
332- const onLeft = isOnLeftSide (current as unknown as HTMLElement )
341+ if (e .key === ' ArrowUp' ) {
342+ const firstIdx = siblings .findIndex ((c ) => c .id === sortedNodes [0 ].nodeObj .id )
343+ if (firstIdx <= 0 ) return
344+ const prev = siblings [firstIdx - 1 ]
345+ const prevEl = MindElixir .E (prev .id )
346+ mind .moveNodeBefore (sortedNodes , prevEl )
347+ return
348+ }
349+ if (e .key === ' ArrowDown' ) {
350+ const lastIdx = siblings .findIndex (
351+ (c ) => c .id === sortedNodes [sortedNodes .length - 1 ].nodeObj .id
352+ )
353+ if (lastIdx >= siblings .length - 1 ) return
354+ const next = siblings [lastIdx + 1 ]
355+ const nextEl = MindElixir .E (next .id )
356+ mind .moveNodeAfter (sortedNodes , nextEl )
357+ return
358+ }
359+
360+ const onLeft = isOnLeftSide (sortedNodes [0 ] as unknown as HTMLElement )
333361 const goingIn = (e .key === ' ArrowRight' && ! onLeft ) || (e .key === ' ArrowLeft' && onLeft )
334- if (goingIn ) moveIn (current )
335- else moveOut (current )
362+ if (goingIn ) {
363+ const firstIdx = siblings .findIndex ((c ) => c .id === sortedNodes [0 ].nodeObj .id )
364+ const lastIdx = siblings .findIndex (
365+ (c ) => c .id === sortedNodes [sortedNodes .length - 1 ].nodeObj .id
366+ )
367+ let into: { id: string } | undefined
368+ if (firstIdx > 0 ) into = siblings [firstIdx - 1 ]
369+ else if (lastIdx < siblings .length - 1 ) into = siblings [lastIdx + 1 ]
370+ if (! into ) return
371+ mind .moveNodeIn (sortedNodes , MindElixir .E (into .id ))
372+ } else {
373+ if (! parent .parent ) return
374+ mind .moveNodeAfter (sortedNodes , MindElixir .E (parent .id ))
375+ }
336376}
337377
338378function findNearestNode(
@@ -431,7 +471,10 @@ function handleTypeToEdit(e: KeyboardEvent) {
431471 e .preventDefault ()
432472 e .stopImmediatePropagation ()
433473 if (e .shiftKey ) {
434- mind .removeNodes ([mind .currentNode ])
474+ const nodes = (mind .currentNodes ?.length
475+ ? mind .currentNodes
476+ : [mind .currentNode ]) as Array <NonNullable <MindElixirInstance [' currentNode' ]>>
477+ mind .removeNodes (nodes )
435478 } else {
436479 mind .beginEdit (mind .currentNode )
437480 }
@@ -454,7 +497,7 @@ function handleTypeToEdit(e: KeyboardEvent) {
454497}
455498
456499function handleSpatialNav(e : KeyboardEvent ) {
457- if (e .metaKey || e .ctrlKey || e .altKey || e . shiftKey ) return
500+ if (e .metaKey || e .ctrlKey || e .altKey ) return
458501 if (! [' ArrowUp' , ' ArrowDown' , ' ArrowLeft' , ' ArrowRight' ].includes (e .key )) return
459502 if (! mind || ! mind .currentNode ) return
460503 const target = e .target as HTMLElement
@@ -463,30 +506,50 @@ function handleSpatialNav(e: KeyboardEvent) {
463506 e .preventDefault ()
464507 e .stopImmediatePropagation ()
465508
509+ const extend = e .shiftKey
466510 const cur = mind .currentNode
467511 const nodeObj = cur .nodeObj
468512 const dir = e .key as ' ArrowUp' | ' ArrowDown' | ' ArrowLeft' | ' ArrowRight'
469513
514+ const select = (id : string ) => {
515+ if (! mind ) return false
516+ try {
517+ const el = MindElixir .E (id )
518+ if (! el ) return false
519+ if (extend ) {
520+ mind .selection ?.select (el as unknown as Parameters <NonNullable <MindElixirInstance [' selection' ]>[' select' ]>[0 ])
521+ } else {
522+ mind .selectNode (el )
523+ }
524+ return true
525+ } catch {
526+ return false
527+ }
528+ }
529+
470530 if (dir === ' ArrowDown' || dir === ' ArrowUp' ) {
471531 const sibling = findSiblingNode (nodeObj , dir === ' ArrowDown' ? ' next' : ' prev' )
472- if (sibling && trySelectById (sibling .id )) return
532+ if (sibling && select (sibling .id )) return
473533 } else {
474534 const onLeft = isOnLeftSide (cur as unknown as HTMLElement )
475535 const goingIn = (dir === ' ArrowRight' && ! onLeft ) || (dir === ' ArrowLeft' && onLeft )
476536 if (goingIn ) {
477537 if (nodeObj .expanded !== false && nodeObj .children ?.length ) {
478538 const remembered = lastChildMap .get (nodeObj .id )
479- const target = nodeObj .children .find ((c ) => c .id === remembered ) ?? nodeObj .children [0 ]
480- if (trySelectById ( target .id )) return
539+ const targetNode = nodeObj .children .find ((c ) => c .id === remembered ) ?? nodeObj .children [0 ]
540+ if (select ( targetNode .id )) return
481541 }
482542 } else {
483543 const parent = nodeObj .parent as NodeObj | undefined
484- if (parent && parent .parent && trySelectById (parent .id )) return
544+ if (parent && parent .parent && select (parent .id )) return
485545 }
486546 }
487547
488548 const nearest = findNearestNode (cur as unknown as HTMLElement , dir )
489- if (nearest ) mind .selectNode (nearest as Parameters <MindElixirInstance [' selectNode' ]>[0 ])
549+ if (nearest ) {
550+ const id = (nearest as unknown as { nodeObj? : { id: string } }).nodeObj ?.id
551+ if (id ) select (id )
552+ }
490553}
491554
492555onMounted (() => {
0 commit comments