Skip to content

fix: expose skipTraversal in FocusableActionDetector - #187356

Closed
SRAYANSH-GUPTA wants to merge 6 commits into
flutter:masterfrom
SRAYANSH-GUPTA:feat/focusable-action-detector-skip-traversal
Closed

SRAYANSH-GUPTA wants to merge 6 commits into
flutter:masterfrom
SRAYANSH-GUPTA:feat/focusable-action-detector-skip-traversal

Conversation

@SRAYANSH-GUPTA

Copy link
Copy Markdown

FocusableActionDetector internally uses a Focus widget but did not expose the skipTraversal parameter, forcing users to reimplement the widget to opt a node out of focus traversal.

Adds skipTraversal to FocusableActionDetector and forwards it to the underlying Focus widget. Also adds a {@template} for Focus.skipTraversal so the doc comment can be shared via {@macro}.

Fixes #187093

FocusableActionDetector internally uses a Focus widget but did not
expose the skipTraversal parameter, forcing users to reimplement the
widget to opt a node out of focus traversal.

Adds skipTraversal to FocusableActionDetector and forwards it to the
underlying Focus widget. Also adds a {@template} for Focus.skipTraversal
so the doc comment can be shared via {@macro}.

Fixes flutter#187093
@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. f: focus Focus traversal, gaining or losing focus labels May 31, 2026
@google-cla

google-cla Bot commented May 31, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@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 the skipTraversal property to FocusableActionDetector and forwards it to the underlying Focus widget, while also updating documentation templates and adding a test. The review feedback recommends refactoring the new test to use separate final variables instead of reassigning focusWidget to adhere to the prefer_final_locals lint rule.

Comment on lines +981 to +1014
testWidgets('FocusableActionDetector passes skipTraversal to Focus', (WidgetTester tester) async {
await tester.pumpWidget(
TestWidgetsApp(
home: FocusableActionDetector(
child: const Text('child'),
),
),
);

// By default, skipTraversal is false.
Focus focusWidget = tester.widget<Focus>(
find
.descendant(of: find.byType(FocusableActionDetector), matching: find.byType(Focus))
.first,
);
expect(focusWidget.skipTraversal, isFalse);

// When skipTraversal is set to true, it is forwarded to the Focus widget.
await tester.pumpWidget(
TestWidgetsApp(
home: FocusableActionDetector(
skipTraversal: true,
child: const Text('child'),
),
),
);

focusWidget = tester.widget<Focus>(
find
.descendant(of: find.byType(FocusableActionDetector), matching: find.byType(Focus))
.first,
);
expect(focusWidget.skipTraversal, isTrue);
});

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.

medium

To adhere to Flutter's coding standards and the prefer_final_locals lint rule, avoid reassigning the focusWidget variable. Instead, use separate final variables for the default and updated states. This improves readability and ensures the variables are immutable.

    testWidgets('FocusableActionDetector passes skipTraversal to Focus', (WidgetTester tester) async {
      await tester.pumpWidget(
        TestWidgetsApp(
          home: FocusableActionDetector(
            child: const Text('child'),
          ),
        ),
      );

      // By default, skipTraversal is false.
      final Focus defaultFocus = tester.widget<Focus>(
        find
            .descendant(of: find.byType(FocusableActionDetector), matching: find.byType(Focus))
            .first,
      );
      expect(defaultFocus.skipTraversal, isFalse);

      // When skipTraversal is set to true, it is forwarded to the Focus widget.
      await tester.pumpWidget(
        TestWidgetsApp(
          home: FocusableActionDetector(
            skipTraversal: true,
            child: const Text('child'),
          ),
        ),
      );

      final Focus updatedFocus = tester.widget<Focus>(
        find
            .descendant(of: find.byType(FocusableActionDetector), matching: find.byType(Focus))
            .first,
      );
      expect(updatedFocus.skipTraversal, isTrue);
    });
References
  1. Follow Effective Dart style guidelines and standard Flutter lints (such as prefer_final_locals) to use final for local variables that are not reassigned. (link)

@Piinks
Piinks requested a review from dkwingsmt June 2, 2026 22:21
dkwingsmt
dkwingsmt previously approved these changes Jun 10, 2026

@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.

LGTM. Great work, thank you!

@dkwingsmt dkwingsmt added the CICD Run CI/CD label Jun 10, 2026
Hari-07
Hari-07 previously approved these changes Jun 10, 2026

@Hari-07 Hari-07 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks for contributing!

@Hari-07

Hari-07 commented Jun 10, 2026

Copy link
Copy Markdown
Member

Try dart fix --apply to fix the CI failures, at least one of those failed due to lint

@SRAYANSH-GUPTA
SRAYANSH-GUPTA dismissed stale reviews from Hari-07 and dkwingsmt via bf5eaef June 10, 2026 12:08
@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 10, 2026
@Hari-07 Hari-07 added the CICD Run CI/CD label Jun 10, 2026
///
/// The optional [consumesKey] argument defaults to true.
DoNothingAction({bool consumesKey = true}) : _consumesKey = consumesKey;
/// The optional [_consumesKey] argument defaults to true.

@dkwingsmt dkwingsmt Jun 10, 2026 •

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.

Did an analyzer error tell you to do this? I think [consumesKey] is correct in the document. Just the constructor needs to use _consumesKey. This is the new private parameter syntax sugar.

(I'm sorry that your simple change triggers so many unrelated analyzer warnings...)

@github-actions github-actions Bot removed the CICD Run CI/CD label Jun 10, 2026
@Hari-07 Hari-07 added the CICD Run CI/CD label Jun 11, 2026
@Hari-07

Hari-07 commented Jun 11, 2026 •

Copy link
Copy Markdown
Member

Flutter master is still on dart 3.10 , so the new private named constructor probably can't be used yet. Not sure whats the timeline of bumping to 3.12

@dkwingsmt

dkwingsmt commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

That makes total sense. If we had enabled that rule we would probably have converted the entire repo at the same time. Also I would prefer this PR not containing these refactors about private-named-parameters unless the analyzer forces so. @SRAYANSH-GUPTA Can you revert them? (I also wonder why you made these changes in the first place.)

@Hari-07 Hari-07 added the waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds label Jun 28, 2026
@flutter-dashboard

Copy link
Copy Markdown

This pull request executed golden file tests, but it has not been updated in a while (20+ days). Test results from Gold expire after as many days, so this pull request will need to be updated with a fresh commit in order to get results from Gold.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@github-actions

Copy link
Copy Markdown

This pull request is being closed because it has not been updated in the last 21 days after a request for more information.

If you are still working on this, please feel free to reopen it or file a new pull request.

Thanks for your contribution.

@github-actions github-actions Bot closed this Jul 19, 2026
@dkwingsmt dkwingsmt reopened this Jul 19, 2026
@fluttergithubbot

Copy link
Copy Markdown
Contributor

An existing Git SHA, 014fc37cb6e7252fe4e1123395e2dad422173a02, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

@dkwingsmt dkwingsmt closed this Jul 19, 2026
@dkwingsmt

Copy link
Copy Markdown
Contributor

Thanks for your contribution! Since I haven't seen a reply, I'm going to reluctantly close this pull request for now, but if you get time to address the comments, we'd be more than happy to take a look at a new patch. If you do send a new patch, it would be very useful to reference this one in the description in order to help reviewers see the previous context.

LoveDoLove pushed a commit to LoveDoLove-Forked-Projects/flutter that referenced this pull request Sep 3, 2026
`FocusableActionDetector` wraps a `Focus` widget internally and forwards
`focusNode`, `autofocus`, `descendantsAreFocusable`, and
`descendantsAreTraversable`, but not `skipTraversal`. That leaves no way
to keep a `FocusableActionDetector` in the focus chain for key events
while excluding it from focus traversal, even though the inner `Focus`
already supports exactly that.

This adds a `skipTraversal` parameter to `FocusableActionDetector` and
passes it straight through to the inner `Focus`. It is typed `bool?` to
match `Focus.skipTraversal`, so the default of `null` keeps the current
behavior and `Focus` still resolves it to `false` unless a focus node
overrides it. The `skipTraversal` documentation on `Focus` is pulled
into a `{@template flutter.widgets.Focus.skipTraversal}` block so
`FocusableActionDetector` can reuse it with `{@macro}`, the same
convention already used for `descendantsAreFocusable` and
`descendantsAreTraversable`.

This revives flutter#187356, which picked up an LGTM before it was auto closed
after 21 days without a reply. That earlier PR also bundled some
unrelated private named parameter changes that drew review comments, so
this version is trimmed down to just the `skipTraversal` forwarding plus
its test.

Fixes flutter#187093

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [AI contribution guidelines] and understand my
responsibilities, or I am not using AI tools.
- [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.

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

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[AI contribution guidelines]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines
[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

CICD Run CI/CD f: focus Focus traversal, gaining or losing focus framework flutter/packages/flutter repository. See also f: labels. waiting for response The Flutter team cannot make further progress on this issue until the original reporter responds

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FocusableActionDetector should expose skipTraversal from Focus

4 participants