Skip to content

Upgrade to latest Blockly keyboard navigation plugin #10512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
574f53d
Upgrade keyboard nav plugin
microbit-matt-hillsdon Apr 9, 2025
2c60e92
Don't show connection lines when moving blocks via keyboard
microbit-robert Apr 11, 2025
8fd7376
Don't show trash icon unless overlapping toolbox when keyboard moving…
microbit-grace Apr 15, 2025
27c8a75
Upgrade keyboard navigation plugin
microbit-robert Apr 16, 2025
f945abb
Override clean_up_workspace shortcut to use flow function (#36)
microbit-grace Apr 16, 2025
893197d
Rebase fix
microbit-robert Apr 22, 2025
0eaa51e
Use latest published version of keyboard experiment plugin
microbit-robert Apr 22, 2025
4a542e9
Revert changes that are not required / workarounds
microbit-robert Apr 22, 2025
aa39ba3
Update ThirdPartyNotice
microbit-robert Apr 22, 2025
ef660be
Tidy and minimize diff
microbit-robert Apr 22, 2025
8e0bb98
Avoid focus-visible style on toolbox categories on click
microbit-robert Apr 22, 2025
ab48b57
Consistent approach to determine a mouse drag vs keyboard move
microbit-robert Apr 22, 2025
8770e21
Enable accessible blocks via settings option instead of experiments (…
microbit-grace Apr 30, 2025
0ae8719
Merge branch 'master' into blockly-12-keyboard-exp
microbit-robert Apr 30, 2025
d5f19f0
Add workaround for flyout cursor after new caching implementation
microbit-robert Apr 30, 2025
4fc0ad4
Disable clipboard overwrite when accessible blocks enabled (#41)
microbit-grace Apr 30, 2025
d0d6bb0
Tidy up following review comments
microbit-robert May 1, 2025
39f657a
Use 'f' as shortcut to format code
microbit-robert May 1, 2025
ae4f56b
Remove unused import
microbit-robert May 2, 2025
e13240a
Fix CSS formatting
microbit-robert May 2, 2025
3312769
Remove stray quotes
microbit-robert May 2, 2025
242de2a
Fix tabs/spaces in function
microbit-robert May 2, 2025
2d62a69
Single quotes -> double quotes
microbit-robert May 2, 2025
4b72884
Add and use method to return SVGElement to CachingFlyout
microbit-robert May 2, 2025
a52729d
Tidy isFlyoutItemDisposed and prevent unnecessary flyout re-render
microbit-robert May 2, 2025
7d14034
Merge branch 'master' into blockly-12-keyboard-exp
riknoll May 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ThirdPartyNotice
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,7 @@ General Public License.
863. dashjs 4.4.0 (https://www.npmjs.com/package/dashjs/v/4.4.0)
864. @fortawesome/fontawesome-free 5.15.4 (https://www.npmjs.com/package/@fortawesome/fontawesome-free/v/5.15.4)
865. @blockly/plugin-workspace-search 4.0.10 (https://www.npmjs.com/package/@blockly/plugin-workspace-search/v/4.0.10)
866. @blockly/keyboard-navigation 0.1.18 (https://www.npmjs.com/package/@blockly/keyboard-navigation/v/0.1.18)
866. @blockly/keyboard-experiment 0.0.7 (https://www.npmjs.com/package/@blockly/keyboard-experiment/v/0.0.7)



Expand Down Expand Up @@ -28749,7 +28749,7 @@ to represent the company, product, or service to which they refer.**
END OF @blockly/plugin-workspace-search 4.0.10 NOTICES AND INFORMATION


%% @blockly/keyboard-navigation 0.1.18 NOTICES AND INFORMATION BEGIN HERE (https://www.npmjs.com/package/@blockly/keyboard-navigation/v/0.1.18)
%% @blockly/keyboard-experiment 0.0.7 NOTICES AND INFORMATION BEGIN HERE (https://www.npmjs.com/package/@blockly/keyboard-experiment/v/0.0.7)
=========================================

Apache License
Expand Down Expand Up @@ -28954,4 +28954,4 @@ END OF @blockly/plugin-workspace-search 4.0.10 NOTICES AND INFORMATION
See the License for the specific language governing permissions and
limitations under the License.
=========================================
END OF @blockly/keyboard-navigation 0.1.18 NOTICES AND INFORMATION
END OF @blockly/keyboard-experiment 0.0.7 NOTICES AND INFORMATION
Binary file removed docs/static/experiments/accessibleblocks.png
Binary file not shown.
7 changes: 7 additions & 0 deletions localtypings/blockly-keyboard-experiment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module "@blockly/keyboard-experiment" {
import { WorkspaceSvg } from "blockly";

class KeyboardNavigation {
constructor(workspace: WorkspaceSvg)
}
}
20 changes: 0 additions & 20 deletions localtypings/navigationController.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion localtypings/pxtarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,6 @@ declare namespace pxt {
extendEditor?: boolean; // whether a target specific editor.js is loaded
extendFieldEditors?: boolean; // wether a target specific fieldeditors.js is loaded
highContrast?: boolean; // simulator has a high contrast mode
accessibleBlocks?: boolean; // enable keyboard navigation in blockly
print?: boolean; //Print blocks and text feature
greenScreen?: boolean; // display webcam stream in background
instructions?: boolean; // display make instructions
Expand Down
1 change: 0 additions & 1 deletion localtypings/pxteditor.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,6 @@ declare namespace pxt.editor {
setHighContrast(on: boolean): void;
toggleGreenScreen(): void;
toggleAccessibleBlocks(): void;
setAccessibleBlocks(enabled: boolean): void;
launchFullEditor(): void;
resetWorkspace(): void;

Expand Down
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
},
"dependencies": {
"@blockly/field-colour": "5.0.12",
"@blockly/keyboard-navigation": "0.6.5",
"@blockly/keyboard-experiment": "0.0.7",
"@blockly/plugin-workspace-search": "9.1.0",
"@crowdin/crowdin-api-client": "^1.33.0",
"@fortawesome/fontawesome-free": "^5.15.4",
Expand Down Expand Up @@ -161,9 +161,6 @@
},
"@blockly/plugin-workspace-search": {
"blockly": "^12.0.0-beta.4"
},
"@blockly/keyboard-navigation": {
"blockly": "^12.0.0-beta.4"
}
},
"scripts": {
Expand Down
8 changes: 7 additions & 1 deletion pxtblocks/blockDragger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ export class BlockDragger extends Blockly.dragging.Dragger {
|| document.getElementsByClassName('blocklyFlyout')[0] as HTMLElement;
const trashIcon = document.getElementById("blocklyTrashIcon");
if (blocklyTreeRoot && trashIcon) {
const rect = blocklyTreeRoot.getBoundingClientRect()
const distance = calculateDistance(blocklyTreeRoot.getBoundingClientRect(), e.clientX);
if (distance < 200) {
const isMouseDrag = Blockly.Gesture.inProgress();
if ((isMouseDrag && distance < 200) || (!isMouseDrag && isOverlappingRect(rect, e.clientX))) {
const opacity = distance / 200;
trashIcon.style.opacity = `${1 - opacity}`;
trashIcon.style.display = 'block';
Expand Down Expand Up @@ -45,4 +47,8 @@ export class BlockDragger extends Blockly.dragging.Dragger {

function calculateDistance(elemBounds: DOMRect, mouseX: number) {
return Math.abs(mouseX - (elemBounds.left + (elemBounds.width / 2)));
}

function isOverlappingRect(elemBounds: DOMRect, mouseX: number) {
return (mouseX - (elemBounds.left + (elemBounds.width))) < 0;
}
12 changes: 10 additions & 2 deletions pxtblocks/contextMenu/blockItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,16 @@ export function registerBlockitems() {
registerHelp();

// Fix the weights of the builtin options we do use
Blockly.ContextMenuRegistry.registry.getItem("blockDelete").weight = BlockContextWeight.DeleteBlock;
Blockly.ContextMenuRegistry.registry.getItem("blockComment").weight = BlockContextWeight.AddComment;
// Defensiveness due to action changes in the keyboard navigation plugin.
// Needs revisiting when actions are final.
const blockDelete = Blockly.ContextMenuRegistry.registry.getItem("blockDelete");
if (blockDelete) {
blockDelete.weight = BlockContextWeight.DeleteBlock;
}
const blockComment = Blockly.ContextMenuRegistry.registry.getItem("blockComment");
if (blockComment) {
blockComment.weight = BlockContextWeight.AddComment;
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion pxtblocks/copyPaste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let oldCut: Blockly.ShortcutRegistry.KeyboardShortcut;
let oldPaste: Blockly.ShortcutRegistry.KeyboardShortcut;

export function initCopyPaste() {
if (oldCopy) return;
if (oldCopy || !getCopyPasteHandlers()) return;

const shortcuts = Blockly.ShortcutRegistry.registry.getRegistry()

Expand Down
2 changes: 2 additions & 0 deletions pxtblocks/fields/field_ledmatrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ export class FieldMatrix extends Blockly.Field implements FieldCustom {
// Clear event listeners and selection used for keyboard navigation.
this.removeKeyboardFocusHandlers();
this.clearSelection();
// This enables keyboard navigation in the Blockly workspace if not focused already.
(this.sourceBlock_.workspace as Blockly.WorkspaceSvg).markFocused();
}, false));
}

Expand Down
1 change: 1 addition & 0 deletions pxtblocks/plugins/duplicateOnDrag/dragStrategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import * as Blockly from "blockly";
import { ConnectionPreviewer } from "../renderer";

import { DUPLICATE_ON_DRAG_MUTATION_KEY, isAllowlistedShadow, shouldDuplicateOnDrag } from "./duplicateOnDrag";
import eventUtils = Blockly.Events;
Expand Down
4 changes: 3 additions & 1 deletion pxtblocks/plugins/flyout/blockInflater.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as Blockly from "blockly";

const HIDDEN_CLASS_NAME = "pxtFlyoutHidden";
export const HIDDEN_CLASS_NAME = "pxtFlyoutHidden";

export class MultiFlyoutRecyclableBlockInflater extends Blockly.BlockFlyoutInflater {
protected keyToBlock: Map<string, Blockly.BlockSvg> = new Map();
Expand Down Expand Up @@ -43,6 +43,7 @@ export class MultiFlyoutRecyclableBlockInflater extends Blockly.BlockFlyoutInfla
this.blockToKey.set(block, key);

block.removeClass(HIDDEN_CLASS_NAME);
block.setDisabledReason(false, HIDDEN_CLASS_NAME);
return block;
}

Expand Down Expand Up @@ -72,6 +73,7 @@ export class MultiFlyoutRecyclableBlockInflater extends Blockly.BlockFlyoutInfla
const xy = block.getRelativeToSurfaceXY();
block.moveBy(-xy.x, -xy.y);
block.addClass(HIDDEN_CLASS_NAME);
block.setDisabledReason(true, HIDDEN_CLASS_NAME);
const key = this.blockToKey.get(block);
this.keyToBlock.set(key, block);
this.removeListeners(block.id);
Expand Down
7 changes: 4 additions & 3 deletions pxtblocks/plugins/renderer/connectionPreviewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ export class ConnectionPreviewer extends Blockly.InsertionMarkerPreviewer {
const atan = Math.atan2(dy, dx);

const len = Math.sqrt(dx * dx + dy * dy);
// When the indicators are overlapping, we hide the line
if (len < radius * 2 + 1) {
const isMouseDrag = Blockly.Gesture.inProgress();
// When the indicators are overlapping, or if the drag is keyboard driven, we hide the line
if (len < radius * 2 + 1 || !isMouseDrag) {
Blockly.utils.dom.addClass(this.connectionLine, "hidden");
} else {
} else if (isMouseDrag) {
Blockly.utils.dom.removeClass(this.connectionLine, "hidden");
this.connectionLine.setAttribute("x1", String(offset.x + Math.cos(atan) * radius));
this.connectionLine.setAttribute("y1", String(offset.y + Math.sin(atan) * radius));
Expand Down
6 changes: 0 additions & 6 deletions pxteditor/experiments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,6 @@ export function all(): Experiment[] {
name: lf("Open in New Connected Tab"),
description: lf("Open connected editors in different browser tabs.")
},
{
id: "accessibleBlocks",
name: lf("Accessible Blocks"),
description: lf("Use the WASD keys to move and modify blocks."),
feedbackUrl: "https://github.com/microsoft/pxt/issues/6850"
},
{
id: "errorList",
name: lf("Error List"),
Expand Down
2 changes: 2 additions & 0 deletions pxtlib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ namespace pxt.auth {
export type UserPreferences = {
language?: string;
highContrast?: boolean;
accessibleBlocks?: boolean;
colorThemeIds?: ColorThemeIdsState;
reader?: string;
skillmap?: UserSkillmapState;
Expand All @@ -72,6 +73,7 @@ namespace pxt.auth {
export const DEFAULT_USER_PREFERENCES: () => UserPreferences = () => ({
language: pxt.appTarget.appTheme.defaultLocale,
highContrast: false,
accessibleBlocks: false,
colorThemeIds: {}, // Will lookup pxt.appTarget.appTheme.defaultColorTheme for active target
reader: "",
skillmap: { mapProgress: {}, completedTags: {} },
Expand Down
62 changes: 62 additions & 0 deletions theme/blockly-core.less
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ svg.blocklySvg {
}
}



.blocklyMainBackground {
stroke: none !important;
}
Expand Down Expand Up @@ -283,6 +285,24 @@ text.blocklyCheckbox {
}
}

/* Keyboard navigation plugin styles */

.passiveBlockFocus.blocklyPath {
stroke-dasharray: 5 3;
stroke-width: 3;
stroke: #ffa200;
}

.passiveNextIndicator {
stroke: #ffa200;
fill: #ffa200;
}

.inputActiveFocus {
stroke-width: 3;
stroke: #ffa200;
}

/*******************************
Scrollbars
*******************************/
Expand Down Expand Up @@ -373,3 +393,45 @@ text.blocklyCheckbox {
font-size: 17pt !important;
}
}


/*******************************
Focus styles
*******************************/

.accessibleBlocks .blocklyWorkspace:focus,.blocklyWorkspaceFocusLayer:focus {
outline: none;
}

.accessibleBlocks .blocklyWorkspaceFocusRingLayer {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
pointer-events: none;
z-index: 99;
}

.accessibleBlocks .blocklyWorkspaceFocusRingLayer[data-focused = 'true'] {
outline: 3px solid black;
outline-offset: -3px;
}

div.blocklyTreeRoot > div > div[role="tree"]:focus-visible {
outline: none;
}

.accessibleBlocks div.blocklyTreeRoot > div > div[role="tree"]:focus-visible {
outline: 3px solid black;
outline-offset: -3px;
}

.accessibleBlocks .blocklyFlyout:focus {
outline: none;
}

.accessibleBlocks .blocklyFlyout:focus-visible {
outline: 3px solid black;
outline-offset: -3px;
}
4 changes: 4 additions & 0 deletions theme/toolbox.less
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ div.blocklyTreeIcon span {
background-color: var(--pxt-target-background3-hover);
}

.blocklyToolbox .blocklyTreeRoot [role="treeitem"] {
outline: none;
}

/*******************************
Inverted Toolbox
*******************************/
Expand Down
6 changes: 6 additions & 0 deletions webapp/src/accessibility.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export class EditorAccessibilityMenu extends data.Component<EditorAccessibilityM
this.showLanguagePicker = this.showLanguagePicker.bind(this);
this.showThemePicker = this.showThemePicker.bind(this);
this.goHome = this.goHome.bind(this);
this.openBlocks = this.openBlocks.bind(this);
}

openBlocks(e: React.MouseEvent<HTMLElement>) {
this.props.parent.openBlocks();
}

openJavaScript() {
Expand Down Expand Up @@ -73,6 +78,7 @@ export class EditorAccessibilityMenu extends data.Component<EditorAccessibilityM
const hasHome = !pxt.shell.isControllerMode();

return <div className="ui accessibleMenu borderless fixed menu" role="menubar">
{this.getData<boolean>(auth.ACCESSIBLE_BLOCKS) ? <sui.Item className={`${targetTheme.invertedMenu ? `inverted` : ''} menu`} role="menuitem" icon="xicon blocks" text={lf("Skip to Blocks workspace")} onClick={this.openBlocks} /> : undefined}
<sui.Item className={`${targetTheme.invertedMenu ? `inverted` : ''} menu`} role="menuitem" icon="xicon js" text={lf("Skip to JavaScript editor")} onClick={this.openJavaScript} />
{targetTheme.python ? <sui.Item className={`${targetTheme.invertedMenu ? `inverted` : ''} menu`} role="menuitem" icon="xicon python" text={lf("Skip to Python editor")} onClick={this.openPython} /> : undefined}
{targetTheme.selectLanguage ? <sui.Item className={`${targetTheme.invertedMenu ? `inverted` : ''} menu`} role="menuitem" icon="xicon globe" text={lf("Select Language")} onClick={this.showLanguagePicker} /> : undefined}
Expand Down
46 changes: 0 additions & 46 deletions webapp/src/accessibleblocks.tsx

This file was deleted.

Loading