commit | b6d8eb133e96fe37b18486a67a2194b36a0432f6 | [log] [tgz] |
---|---|---|
author | Tong Mu <dkwingsmt@users.noreply.github.com> | Thu Oct 03 13:09:19 2024 -0700 |
committer | dart-internal-monorepo <dart-internal-monorepo@dart-ci-internal.iam.gserviceaccount.com> | Thu Oct 03 13:19:47 2024 -0700 |
tree | 17cc535b1366f5e2e99e782dedc32971e8147bd9 | |
parent | 3e1cdcfb42625a0c127c6e53b93c43325087de29 [diff] |
Allow arrow keys to navigate `MenuAnchor` independently of global shortcut definition (#155728) This PR adjusts the implementation of handling navigational shortcuts (i.e. arrow keys) on `MenuAnchor` and `DropdownMenu`. ## Motivation The direct outcome of this PR is to allow keyboard to enter submenus on Web: When the focus is on a `MenuAnchor` while the menu is open, pressing arrow keys should move the focus to the menu item. * Before the PR, this works for all platforms but Web, a problem described in https://github.com/flutter/flutter/issues/119532#issuecomment-2274705565. It is caused by the fact that `MenuAnchor` does not wrap itself with a `Shortcuts`, and therefore key events when the focus is on a `MenuAnchor` has been working only because the event falls back to the `Shortcuts` widget defined by `WidgetsApp`, whose default value happens to satisfy `MenuAnchor`'s needs - except on Web where arrow keys are defined to scroll instead of traverse. Instead of defining this problem as "just a patch for Web", I think it's better to define it as a problem of all platforms: `MenuAnchor`'s shortcuts should be independent of `WidgetsApp.shortcuts`. Because even if `WidgetsApp.shortcuts` is redefined as something else, people should probably still expect arrow keys to work on `MenuAnchor`. Therefore this PR makes `MenuAnchor` produce a `Shortcuts` by itself. ### Dropdown menu The fix above breaks `DropdownMenu`. `DropdownMenu` uses `MenuAnchor`, while defining its own shortcuts because, when filter is enabled: * The left and right arrow keys need to move the text carets instead * The up and down arrow keys need to "fake" directional navigation - the focus needs to stay on the text field, while some menu item is highlighted as if it is focused. Before the PR, `DropdownMenu` defines these shortcuts out of `MenuAnchor`. In order for the `DropdownMenu`'s shortcuts to take priority, these shortcuts are moved to between `MenuAnchor` and the `Textfield`. A test is added to verify that the left/right keys move text carets. Below are psuedo-widget-trees after the PR: ``` MenuAnchor |- Shortcuts(arrows->DirectionalFocusIntent) |- MenuAnchor.child |- menu DropdownMenu |- Actions(DirectionalFocusIntent->_dropdownMenuNavigation) |- MenuAnchor |- Shortcuts(arrows->DirectionalFocusIntent) |- Shortcuts(leftright->ExtendSelectionByCharacterIntent, updown->_dropdownMenuArrowIntent) | |- TextField | |- EditableText | |- Actions(DirectionalFocusIntent->DirectionalFocusAction.forTextField) |- menu ``` ## Known issues After this PR, traversing the menu still have quite a few problems, which are left for other PRs. https://dart.googlesource.com/external/github.com/flutter/flutter/+/59e57437dba691e045dc417c705a9dc48db8acfb
Monorepo is:
With depot_tools installed and on your path, create a directory for your monorepo checkout and run these commands to create a gclient solution in that directory:
mkdir monorepo cd monorepo gclient config --unmanaged https://dart.googlesource.com/monorepo gclient sync -D
This gives you a checkout in the monorepo directory that contains:
monorepo/ DEPS - the DEPS used for this gclient checkout commits.json - the pinned commits for Dart, flutter/engine, and flutter/flutter tools/ - scripts used to create monorepo DEPS engine/src/ - the flutter/buildroot repo flutter/ - the flutter/engine repo out/ - the build directory, where Flutter engine builds are created third_party/ - Flutter dependencies checked out by DEPS dart/ - the Dart SDK checkout. third_party - Dart dependencies, also used by Flutter flutter/ - the flutter/flutter repo
Flutter's instructions for building the engine are at Compiling the engine
They can be followed closely, with a few changes:
goma_ctl ensure_start
is sufficient.Example build commands that work on linux:
MONOREPO_PATH=$PWD if [[ ! $PATH =~ (^|:)$MONOREPO_PATH/flutter/bin(:|$) ]]; then PATH=$MONOREPO_PATH/flutter/bin:$PATH fi export GOMA_DIR=$(dirname $(command -v gclient))/.cipd_bin goma_ctl ensure_start pushd engine/src flutter/tools/gn --goma --no-prebuilt-dart-sdk --unoptimized --full-dart-sdk autoninja -C out/host_debug_unopt popd
The Flutter commands used to build and run apps will use the locally built Flutter engine and Dart SDK, instead of the one downloaded by the Flutter tool, if the --local-engine
option is provided.
For example, to build and run the Flutter spinning square sample on the web platform,
MONOREPO_PATH=$PWD cd flutter/examples/layers flutter --local-engine=host_debug_unopt \ -d chrome run widgets/spinning_square.dart cd $MONOREPO_PATH
To build for desktop, specify the desktop platform device in flutter run
as -d macos
or -d linux
or -d windows
. You may also need to run the command
flutter create --platforms=windows,macos,linux
on existing apps, such as sample apps. New apps created with flutter create
already include these support files. Details of desktop support are at Desktop Support for Flutter
Tests in the Flutter source tree can be run with the flutter test
command, run in the directory of a package containing tests. For example:
MONOREPO_PATH=$PWD cd flutter/packages/flutter flutter test --local-engine=host_debug_unopt cd $MONOREPO_PATH
Please file an issue or email the dart-engprod team with any problems with or questions about using monorepo.
We will update this documentation to address them.
flutter
commands may download the engine and Dart SDK files for the configured channel, even though they will be using the local engine and its SDK.gclient sync
needs to be run in an administrator session, because some installed dependencies create symlinks.