@blockly/keyboard-navigation
Version:
A plugin for keyboard navigation.
96 lines (85 loc) • 2.55 kB
text/typescript
/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {
BlockSvg,
Events,
ShortcutRegistry,
utils as BlocklyUtils,
Connection,
ConnectionType,
keyboardNavigationController,
} from 'blockly';
import * as Constants from '../constants';
import type {WorkspaceSvg} from 'blockly';
import {Navigation} from '../navigation';
const KeyCodes = BlocklyUtils.KeyCodes;
/**
* Action to insert a block into the workspace.
*
* This action registers itself as both a keyboard shortcut and a context menu
* item.
*/
export class DisconnectAction {
/**
* Registration name for the keyboard shortcut.
*/
private shortcutName = Constants.SHORTCUT_NAMES.DISCONNECT;
constructor(private navigation: Navigation) {}
/**
* Install this action as both a keyboard shortcut and a context menu item.
*/
install() {
this.registerShortcut();
}
/**
* Uninstall this action as both a keyboard shortcut and a context menu item.
* Reinstall the original context menu action if possible.
*/
uninstall() {
ShortcutRegistry.registry.unregister(this.shortcutName);
}
/**
* Create and register the keyboard shortcut for this action.
*/
private registerShortcut() {
const disconnectShortcut: ShortcutRegistry.KeyboardShortcut = {
name: this.shortcutName,
preconditionFn: (workspace) =>
this.navigation.canCurrentlyEdit(workspace),
callback: (workspace) => {
keyboardNavigationController.setIsActive(true);
switch (this.navigation.getState(workspace)) {
case Constants.STATE.WORKSPACE:
this.disconnectBlocks(workspace);
return true;
default:
return false;
}
},
keyCodes: [KeyCodes.X],
};
ShortcutRegistry.registry.register(disconnectShortcut);
}
/**
* Disconnects the connection that the cursor is pointing to, and bump blocks.
* This is a no-op if the connection cannot be broken or if the cursor is not
* pointing to a connection.
*
* @param workspace The workspace.
*/
disconnectBlocks(workspace: WorkspaceSvg) {
const cursor = workspace.getCursor();
if (!cursor) return;
const curNode = cursor.getCurNode();
if (!(curNode instanceof BlockSvg)) return;
const healStack = !curNode.outputConnection?.isConnected();
Events.setGroup(true);
curNode.unplug(healStack);
Events.setGroup(false);
// Needed or we end up with passive focus.
cursor.setCurNode(curNode);
}
}