Skip to content

167114 add keyboard focus support for cupertino context menu action - #179225

Closed
O-Hannonen wants to merge 18 commits into
flutter:masterfrom
O-Hannonen:167114-add-keyboard-focus-support-for-cupertino-context-menu-action
Closed

O-Hannonen wants to merge 18 commits into
flutter:masterfrom
O-Hannonen:167114-add-keyboard-focus-support-for-cupertino-context-menu-action

Conversation

@O-Hannonen

@O-Hannonen O-Hannonen commented Nov 28, 2025 •

Copy link
Copy Markdown
Contributor

This PR

  • fixes CupertinoContextMenuAction: Add focus support #167114 by adding focus support for CupertinoContextMenuAction
  • makes it possible to focus CupertinoContextMenu
  • makes it possible to open CupertinoContextMenu with tab + m keyboard shortcut (iOS system keyboard traversal default behavior)
  • updates CupertinoFocusHalo to use superellipse borders

Sample how the new code looks and behaves

Simulator.Screen.Recording.-.iPhone.16.Plus.-.2025-11-28.at.22.26.35.mov

Sample how context menu traversal looks and behaves on iOS

Simulator.Screen.Recording.-.iPhone.16e.-.2025-11-28.at.22.27.28.mov

Code sample

Code sample
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(const ContextMenuApp());

class ContextMenuApp extends StatelessWidget {
  const ContextMenuApp({super.key});

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      theme: CupertinoThemeData(brightness: Brightness.light),
      home: ContextMenuExample(),
    );
  }
}

class ContextMenuExample extends StatefulWidget {
  const ContextMenuExample({super.key});

  @override
  State<ContextMenuExample> createState() => _ContextMenuExampleState();
}

class _ContextMenuExampleState extends State<ContextMenuExample> {
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,

        middle: Text('Context Menu Example'),
      ),
      child: Center(
        child: Column(
          spacing: 16,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            CupertinoContextMenu(
              actions: <Widget>[
                CupertinoContextMenuAction(
                  child: Text('Action 1'),
                  onPressed: () {
                    print('Action 1');
                    Navigator.pop(context);
                  },
                ),
                CupertinoContextMenuAction(
                  child: Text('Action 2'),
                  onPressed: () {
                    print('Action 2');
                    Navigator.pop(context);
                  },
                ),
                CupertinoContextMenuAction(
                  isDestructiveAction: true,
                  child: Text('Delete'),
                  onPressed: () {
                    print('Delete');
                    Navigator.pop(context);
                  },
                ),
              ],

              child: Material(
                child: Container(
                  width: 100,
                  height: 100,
                  color: Colors.orange,
                  child: Center(child: Text('Hold me')),
                ),
              ),
            ),
            TextButton(
              onPressed: () {
                print('TextButton1 pressed');
              },
              child: Text('Another button 1'),
            ),
            TextButton(
              onPressed: () {
                print('TextButton2 pressed');
              },
              child: Text('Another button 2'),
            ),
          ],
        ),
      ),
    );
  }
}
## Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. p: cupertino_ui cupertino_ui package in flutter/packages f: focus Focus traversal, gaining or losing focus labels Nov 28, 2025

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds keyboard focus support to CupertinoContextMenu and CupertinoContextMenuAction. It introduces focusNode and focusBorderRadius properties to CupertinoContextMenu, and focusNode and focusColor to CupertinoContextMenuAction. The implementation uses FocusableActionDetector to manage focus and actions, and a Shortcuts widget to enable opening the context menu with a Tab+M keyboard shortcut. Additionally, CupertinoFocusHalo is updated to use RoundedSuperellipseBorder for a more native iOS appearance, and FocusableActionDetector is extended with an onKeyEvent callback to support custom key event handling.

@dkwingsmt dkwingsmt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally ok except for how we handle the tab key

Comment on lines +632 to +654
void _onShowFocusHighlight(bool showHighlight) {
setState(() {
_lastKeyEvent = null;
});
}

KeyEventResult _onKeyEvent(FocusNode node, KeyEvent event) {
if (event case KeyDownEvent(logicalKey: LogicalKeyboardKey.tab)) {
_lastKeyEvent = event;
return KeyEventResult.handled;
}

if (event case KeyUpEvent(logicalKey: LogicalKeyboardKey.tab)) {
if (_lastKeyEvent case KeyDownEvent(logicalKey: LogicalKeyboardKey.tab)) {
FocusScope.of(context).nextFocus();
}
_lastKeyEvent = event;
return KeyEventResult.handled;
}

_lastKeyEvent = event;

return KeyEventResult.ignored;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you have to handle key events manually instead of using the Shortcuts framework? What's the recorded _lastKeyEvent used for?

@O-Hannonen O-Hannonen Jan 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Shortcuts framework handles tab quite poorly as a modifier. Immediately when tab is pressed down, the focus moves to next item. So its not really possible to use only it if we want to have a focusable widget that uses tab as modifier key for the shortcut.

The reason for manually listening to key events is to prevent the tab down from bubbling up and only move focus when the tab is released.

But now that I'm saying this aloud, should that be fixed elsewhere so we could use the shortcuts here? So eg. should tab focus traversal be modified to only move to next item when tab is released (vs. the on tab down that its now)? Or should a similar fix to this be added to the Shortcuts (so is it a common use case that we want to support that tab can be modifier)?

Here is a small reproduction highlighting the issue:

Sample code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tab as modifier key bug',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const TabModifierKeyBugDemo(),
    );
  }
}

class TabModifierKeyBugDemo extends StatefulWidget {
  const TabModifierKeyBugDemo({super.key});

  @override
  State<TabModifierKeyBugDemo> createState() => _TabModifierKeyBugDemoState();
}

class _TabModifierKeyBugDemoState extends State<TabModifierKeyBugDemo> {
  int tabMCount = 0;
  void _handleTabM() {
    setState(() {
      tabMCount++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tab + Modifier Key Bug Reproduction'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          spacing: 16,
          children: [
            const Card(
              color: Color.fromARGB(255, 255, 240, 245),
              child: Padding(
                padding: EdgeInsets.all(12.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Instructions:',
                    ),
                    SizedBox(height: 8),
                    Text(
                      '1. Press Tab to navigate between buttons\n'
                      '2. When focused on Button 2, press Tab down. While holding Tab, press M.\n'
                      'BUG: Focus should NOT move to Button 3, only Tab+M action should trigger. Focus should move to next button only if Tab is released and no other key is pressed.\n',
                    ),
                  ],
                ),
              ),
            ),
            Text(
              'Tab+M pressed count: $tabMCount',
            ),
            ElevatedButton( 
              onPressed: () {},
              child: const Text('Button 1'),
            ),
            Shortcuts(
              shortcuts: {
                LogicalKeySet(LogicalKeyboardKey.tab, LogicalKeyboardKey.keyM):
                    const _TabMIntent(),
              },
              child: Actions(
                actions: {
                  _TabMIntent: CallbackAction<_TabMIntent>(
                    onInvoke: (_) {
                      _handleTabM();
                      return null;
                    },
                  ),
                },
                child: Container(
                  decoration: BoxDecoration(
                    border: Border.all(color: Colors.orange, width: 2),
                    borderRadius: BorderRadius.circular(8),
                  ),
                  padding: const EdgeInsets.all(12),
                  child: ElevatedButton(
                    onPressed: () {},
                    child: const Text('Button 2 (Has Tab+M shortcut)'),
                  ),
                ),
              ),
            ),
            ElevatedButton(
              onPressed: () {},
              child: const Text('Button 3'),  
            ),
          ],
        ),
      ),
    );
  }
}

class _TabMIntent extends Intent {
  const _TabMIntent();
}

github-merge-queue Bot pushed a commit that referenced this pull request Jan 15, 2026
This PR closes #180719

Related to
[this](#179224 (comment))
and
[this](#179225 (comment)).

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
@github-actions github-actions Bot removed the f: focus Focus traversal, gaining or losing focus label Jan 15, 2026
ikramhasan pushed a commit to ikramhasan/flutter that referenced this pull request Jan 15, 2026
This PR closes flutter#180719

Related to
[this](flutter#179224 (comment))
and
[this](flutter#179225 (comment)).

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
@dkwingsmt
dkwingsmt self-requested a review January 21, 2026 19:12
@dkwingsmt

Copy link
Copy Markdown
Contributor

Ok I did more testing and found a couple of things. (I might be wrong; feel free to test further)

  • There's an iPadOS option, Full Keyboard Access, that controls lots of behaviors.
    • FKA off: Only limited components are focusable unless explicitly set .focusable(), and displays a gray ring when focused. Almost no shortcuts enabled.
    • FKA on: Much more things are focusable and displays the blue ring (the focus halo), lots of shortcuts enabled (including but not limited to Tab-M).
  • There is no API to query whether FKA is enabled. Also, the shortcuts enabled by FKA are customizable, including Tab-M, and there is no API to query them either.
  • Tab-M only works for context menu on the main screen, but not app widgets that use .contextMenu { }.
  • Flutter comes with focus halo support by default. I guess this is actually related to a11y. Following is the material MenuAnchor displaying the focus halo on an iPad simulator with FKA on.
image

@dkwingsmt

Copy link
Copy Markdown
Contributor

Hi @O-Hannonen ! When you have a moment, can you check my comment above? Just wanted to make sure it came through correctly. Thank you again for your contribution.

@O-Hannonen

Copy link
Copy Markdown
Contributor Author

Sorry for the delay, did some further testing myself now too:

There is no API to query whether FKA is enabled. Also, the shortcuts enabled by FKA are customizable, including Tab-M, and there is no API to query them either.

This is quite unfortunate :/

Tab-M only works for context menu on the main screen, but not app widgets that use .contextMenu { }.
Interesting finding, I had only tested on the main screen. Super weird and inconsistent decision from Apple.

Did you figure out any way to open the context menu on keyboard inside apps? Eg. while testing in the Photos app, I was not able to open the context menu in any way with keyboard...

Flutter comes with focus halo support by default. I guess this is actually related to a11y. Following is the material MenuAnchor displaying the focus halo on an iPad simulator with FKA on.

MenuAnchor is quite similar but has few key differences. AFAIK the menu anchor is not intended to have any other onTap action than opening the anchor? Context menu usually has both onTap action in addition to opening the context menu (so both onTap and onLongPress) -> can't just use the regular tap event (space on keyboard) to open the menu.

If its really true that Apple FKA does not support opening context menu on keyboard (other than on home screen), we could simply remove the keyboard shortcut part from this PR? So just make ContextMenuAction focusable by keyboard? Any thoughts?

@dkwingsmt

dkwingsmt commented Feb 25, 2026 •

Copy link
Copy Markdown
Contributor

Did you figure out any way to open the context menu on keyboard inside apps? Eg. while testing in the Photos app, I was not able to open the context menu in any way with keyboard...

No, I couldn't either. I think we don't need this shortcut support at all.

Overall, here's my theory: I think that the entire focus halo feature is meant to be handled by iOS automatically. It probably reads accessibility data - I'm not certain about it since I'm not familiar with a11y and don't know what's in there, but I'm guessing so mostly because of how MenuAnchor gets a focus halo without any explicit support. If this is true, this means that we actually shouldn't have created a widget that draws focus halo by ourselves. Flutter already supports focus halo, and it (almost) correctly shows whenever FKA is enabled.

However this doesn't explain why iOS has this explicit focus halo component. My guess is that it does some kind of customization (such as shape). If that's true, our focus halo widget should instead modify the a11y data to specify the shape.

Even if that is true, it's still a mystery how some iOS components allow a different kind of focus effect that doesn't show focus halo at all (I might be wrong but I vaguely remember that iOS's design guide says that focus halo should not be shown for things like navigation bar buttons.)

If you're interested, I'd apprecaite if you can investigate into the detailed mechanism here. :)

@O-Hannonen

Copy link
Copy Markdown
Contributor Author

I've removed the keyboard shortcut from this PR for now. I still need to dig a bit deeper into the other points discussed, which I’m hoping to find time for shortly.

Based on what I've seen so far, I have two potential theories on how we should move forward (though further investigation might prove both wrong! 😄). Either way, I don't think creating CupertinoFocusHalo was a mistake. Because Flutter supports basic keyboard traversal even when Full Keyboard Access (FKA) is OFF, we are going to need a focus ring widget for that situation regardless. Then, when FKA is ON, this widget could potentially serve as the mechanism that passes the relevant data to the accessibility bridge.

Here is how I'm thinking about the two paths forward:

Scenario 1: FKA is customizable

If iOS allows us to customize the native FKA focus ring, CupertinoFocusHalo would serve a dual purpose. For basic keyboard traversal (FKA OFF), it would render the visual halo itself. For FKA traversal (FKA ON), it would pass the custom shape through the accessibility bridge to the platform. As FKA overlay is so intrusive, we wouldn't necessarily even have to know if FKA is on or not (AFAIK we have no way of knowing), but we could render the visual halo ourselves and let FKA render its own halo on top of it.

In this case, CupertinoFocusHalo would function exactly as you suspected UIFocusHaloEffect does natively, acting as the bridge to style the FKA halo. I still need to investigate exactly how UIFocusHaloEffect behaves on iOS to confirm this.

Scenario 2: FKA is strictly separate and not customizable

It’s also possible that FKA is (and is intended to be) a completely separate system from basic keyboard traversal, with no room for customization. If that’s the case, our goal is simpler: we just need to ensure that our Cupertino components look and behave correctly under both systems independently. So handling our own basic traversal visuals when FKA is OFF, and letting the system take over when FKA is ON.

@victorsanni
victorsanni removed the request for review from MitchellGoodwin March 10, 2026 02:59
@dkwingsmt

dkwingsmt commented Mar 24, 2026 •

Copy link
Copy Markdown
Contributor

Sorry for late reply!

Because Flutter supports basic keyboard traversal even when Full Keyboard Access (FKA) is OFF, we are going to need a focus ring widget for that situation regardless.

That's true! This reminded me that, if you add .focusable() to a Swift widget, it can then be focused by keyboard traversal and displays a weaker halo when focused. This is can indeed be fulfilled by Flutter's focus halo widget.

I think what I'm observing is leaning towards Scenario 2, and I agree with everything you said.

Also if we're expecting more discussion (which I do), then we probably want to close this PR for now and start this discussion in a new issue for better tracking. Thank you for your contribution!

@O-Hannonen

Copy link
Copy Markdown
Contributor Author

Sounds good! I'll open a new issue, let's continue the discussion there. I'll close this PR for now until its clear what to do.

@O-Hannonen O-Hannonen closed this Mar 29, 2026
chunhtai pushed a commit to chunhtai/packages that referenced this pull request Jun 12, 2026
This PR closes #180719

Related to
[this](flutter/flutter#179224 (comment))
and
[this](flutter/flutter#179225 (comment)).

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Nakiha pushed a commit to Nakiha/VoidPlayer-Flutter that referenced this pull request Sep 28, 2026
This PR closes #180719

Related to
[this](flutter/flutter#179224 (comment))
and
[this](flutter/flutter#179225 (comment)).

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

framework flutter/packages/flutter repository. See also f: labels. p: cupertino_ui cupertino_ui package in flutter/packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CupertinoContextMenuAction: Add focus support

3 participants