Ben Henning cac8f0116c feat: Make toolbox and flyout focusable (roll forward) (#8939)
_Note: This is a roll forward of #8920 that was reverted in #8933. See Additional Information below._

## The basics

- [x] I [validated my changes](https://developers.google.com/blockly/guides/contribute/core#making_and_verifying_a_change)

## The details
### Resolves

Fixes #8918
Fixes #8919
Fixes part of #8943
Fixes part of #8771

### Proposed Changes

This updates several classes in order to make toolboxes and flyouts focusable:
- `IFlyout` is now an `IFocusableTree` with corresponding implementations in `FlyoutBase`.
- `IToolbox` is now an `IFocusableTree` with corresponding implementations in `Toolbox`.
- `IToolboxItem` is now an `IFocusableNode` with corresponding implementations in `ToolboxItem`.
- As the primary toolbox items, `ToolboxCategory` and `ToolboxSeparator` were updated to have -1 tab indexes and defined IDs to help `ToolboxItem` fulfill its contracted for `IFocusableNode.getFocusableElement`.
- `FlyoutButton` is now an `IFocusableNode` (with corresponding ID generation, tab index setting, and ID matching for retrieval in `WorkspaceSvg`).

Each of these two new focusable trees have specific noteworthy behaviors behaviors:
- `Toolbox` will automatically indicate that its first item should be focused (if one is present), even overriding the ability to focus the toolbox's root (however there are some cases where that can still happen).
- `Toolbox` will automatically synchronize its selection state with its item nodes being focused.
- `FlyoutBase`, now being a focusable tree, has had a tab index of 0 added. Normally a tab index of -1 is all that's needed, but the keyboard navigation plugin specifically uses 0 for flyout so that the flyout is tabbable. This is a **new** tab stop being introduced.
- `FlyoutBase` holds a workspace (for rendering blocks) and, since `WorkspaceSvg` is already set up to be a focusable tree, it's represented as a subtree to `FlyoutBase`. This does introduce some wonky behaviors: the flyout's root will have passive focus while its contents have active focus. This could be manually disabled with some CSS if it ends up being a confusing user experience.
- Both `FlyoutBase` and `WorkspaceSvg` have built-in behaviors for detecting when a user tries navigating away from an open flyout to ensure that the flyout is closed when it's supposed to be. That is, the flyout is auto-hideable and a non-flyout, non-toolbox node has then been focused. This matches parity with the `T`/`Esc` flows supported in the keyboard navigation plugin playground.

One other thing to note: `Toolbox` had a few tests to update that were trying to reinit a toolbox without first disposing of it (which was caught by one of `FocusManager`'s state guardrails).

This only addresses part of #8943: it adds support for `FlyoutButton` which covers both buttons and labels. However, a longer-term solution may be to change `FlyoutItem` itself to force using an `IFocusableNode` as its element.

### Reason for Changes

This is part of an ongoing effort to ensure key components of Blockly are focusable so that they can be keyboard-navigable (with other needed changes yet both in Core Blockly and the keyboard navigation plugin).

### Test Coverage

No new tests have been added. It's certainly possible to add unit tests for the focusable configurations being introduced in this PR, but it may not be highly beneficial. It's largely assumed that the individual implementations should work due to a highly tested FocusManager, and it may be the case that the interactions of the components working together is far more important to verify (that is, the end user flows). The latter is planned to be tackled as part of #8915.

### Documentation

No documentation changes should be needed here.

### Additional Information

This includes changes that have been pulled from #8875.

This was originally merged in #8916 but was reverted in #8933 due to https://github.com/google/blockly-keyboard-experimentation/issues/481. Note that this does contain a number of differences from the original PR (namely, changes in `WorkspaceSvg` and `FlyoutButton` in order to make `FlyoutButton`s focusable). Otherwise, this has the same caveats as those noted in #8938 with regards to the experimental keyboard navigation plugin.
2025-04-30 15:49:29 -07:00
2024-08-15 03:16:14 +01:00
2019-07-31 12:29:21 -07:00
2023-08-17 00:15:27 +00:00

Blockly

Google's Blockly is a library that adds a visual code editor to web and mobile apps. The Blockly editor uses interlocking, graphical blocks to represent code concepts like variables, logical expressions, loops, and more. It allows users to apply programming principles without having to worry about syntax or the intimidation of a blinking cursor on the command line. All code is free and open source.

Getting Started with Blockly

Blockly has many resources for learning how to use the library. Start at our Google Developers Site to read the documentation on how to get started, configure Blockly, and integrate it into your application. The developers site also contains links to:

Help us focus our development efforts by telling us what you are doing with Blockly. The questionnaire only takes a few minutes and will help us better support the Blockly community.

Installing Blockly

Blockly is available on npm.

npm install blockly

For more information on installing and using Blockly, see the Getting Started article.

Getting Help

  • Report a bug or file a feature request on GitHub
  • Ask a question, or search others' questions, on our developer forum. You can also drop by to say hello and show us your prototypes; collectively we have a lot of experience and can offer hints which will save you time. We actively monitor the forums and typically respond to questions within 2 working days.

blockly-samples

We have a number of resources such as example code, demos, and plugins in another repository called blockly-samples. A plugin is a self-contained piece of code that adds functionality to Blockly. Plugins can add fields, define themes, create renderers, and much more. For more information, see the Plugins documentation.

Contributing to Blockly

Want to make Blockly better? We welcome contributions to Blockly in the form of pull requests, bug reports, documentation, answers on the forum, and more! Check out our Contributing Guidelines for more information. You might also want to look for issues tagged "Help Wanted" which are issues we think would be great for external contributors to help with.

Releases

We release by pushing the latest code to the master branch, followed by updating the npm package, our docs, and demo pages. If there are breaking bugs, such as a crash when performing a standard action or a rendering issue that makes Blockly unusable, we will cherry-pick fixes to master between releases to fix them. The releases page has a list of all releases.

We use semantic versioning. Releases that have breaking changes or are otherwise not backwards compatible will have a new major version. Patch versions are reserved for bug-fix patches between scheduled releases.

We now have a beta release on npm. If you'd like to test the upcoming release, or try out a not-yet-released new API, you can use the beta channel with:

npm install blockly@beta

As it is a beta channel, it may be less stable, and the APIs there are subject to change.

Branches

There are two main branches for Blockly.

master - This is the (mostly) stable current release of Blockly.

develop - This is where most of our work happens. Pull requests should always be made against develop. This branch will generally be usable, but may be less stable than the master branch. Once something is in develop we expect it to merge to master in the next release.

other branches: - Larger changes may have their own branches until they are good enough for people to try out. These will be developed separately until we think they are almost ready for release. These branches typically get merged into develop immediately after a release to allow extra time for testing.

New APIs

Once a new API is merged into master it is considered beta until the following release. We generally try to avoid changing an API after it has been merged to master, but sometimes we need to make changes after seeing how an API is used. If an API has been around for at least two releases we'll do our best to avoid breaking it.

Unreleased APIs may change radically. Anything that is in develop but not master is subject to change without warning.

Issues and Milestones

We typically triage all bugs within 1 week, which includes adding any appropriate labels and assigning it to a milestone. Please keep in mind, we are a small team so even feature requests that everyone agrees on may not be prioritized.

Good to Know

  • Cross-browser Testing Platform and Open Source <3 Provided by Sauce Labs
  • We test browsers using BrowserStack
Description
The web-based visual programming editor.
Readme Apache-2.0 249 MiB
Languages
TypeScript 51.3%
JavaScript 40.6%
Python 2.1%
HTML 1.8%
PHP 1.5%
Other 2.7%