Skip to content

Commit 00e428a

Browse files
fix(Semantics): Ensure semantics properties take priority over button's (#174473)
Fixes #157689 Flutter packages PR counterpart: - flutter/packages#9815 ## 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. 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](https://developers.google.com/gemini-code-assist/docs/review-github-code). 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.
1 parent 8a5c6df commit 00e428a

File tree

4 files changed

+82
-3
lines changed

4 files changed

+82
-3
lines changed

engine/src/flutter/lib/web_ui/lib/src/engine/semantics/semantics.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,14 +2055,14 @@ class SemanticsObject {
20552055
return EngineSemanticsRole.image;
20562056
} else if (isCheckable) {
20572057
return EngineSemanticsRole.checkable;
2058+
} else if (isLink) {
2059+
return EngineSemanticsRole.link;
20582060
} else if (isButton) {
20592061
return EngineSemanticsRole.button;
20602062
} else if (isScrollContainer) {
20612063
return EngineSemanticsRole.scrollable;
20622064
} else if (scopesRoute) {
20632065
return EngineSemanticsRole.route;
2064-
} else if (isLink) {
2065-
return EngineSemanticsRole.link;
20662066
} else if (isHeader) {
20672067
return EngineSemanticsRole.header;
20682068
} else if (isButtonLike) {

engine/src/flutter/lib/web_ui/test/engine/semantics/semantics_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4377,6 +4377,34 @@ void _testLink() {
43774377
expect(object.element.tagName.toLowerCase(), 'a');
43784378
expect(object.element.getAttribute('href'), 'https://flutter.dev');
43794379
});
4380+
4381+
test('a node that is both a link and a button is rendered as a link', () {
4382+
semantics()
4383+
..debugOverrideTimestampFunction(() => _testTime)
4384+
..semanticsEnabled = true;
4385+
4386+
const String url = 'https://flutter.dev';
4387+
final SemanticsTester tester = SemanticsTester(owner());
4388+
tester.updateNode(
4389+
id: 0,
4390+
linkUrl: url,
4391+
flags: const ui.SemanticsFlags(isLink: true, isButton: true),
4392+
label: 'link button label',
4393+
rect: const ui.Rect.fromLTRB(0, 0, 100, 50),
4394+
);
4395+
tester.apply();
4396+
4397+
tester.expectSemantics('<a style="display: block;">link button label</a>');
4398+
final SemanticsObject node = owner().debugSemanticsTree![0]!;
4399+
expect(node.semanticRole?.kind, EngineSemanticsRole.link);
4400+
expect(node.linkUrl, url);
4401+
expect(
4402+
node.semanticRole?.debugSemanticBehaviorTypes,
4403+
containsAll(<Type>[Focusable, Tappable, LabelAndValue]),
4404+
);
4405+
4406+
semantics().semanticsEnabled = false;
4407+
});
43804408
}
43814409

43824410
void _testTabs() {

packages/flutter/lib/src/semantics/semantics.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6003,6 +6003,7 @@ class SemanticsConfiguration {
60036003
_actionsAsBits |= child._effectiveActionsAsBits;
60046004
_customSemanticsActions.addAll(child._customSemanticsActions);
60056005
_flags = _flags.merge(child._flags);
6006+
_linkUrl ??= child._linkUrl;
60066007
_textSelection ??= child._textSelection;
60076008
_scrollPosition ??= child._scrollPosition;
60086009
_scrollExtentMax ??= child._scrollExtentMax;

packages/flutter/test/widgets/semantics_merge_test.dart

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import 'package:flutter/material.dart';
66
import 'package:flutter/rendering.dart';
7-
import 'package:flutter/widgets.dart';
87
import 'package:flutter_test/flutter_test.dart';
98

109
import 'semantics_tester.dart';
@@ -141,4 +140,55 @@ void main() {
141140

142141
semantics.dispose();
143142
});
143+
144+
testWidgets('LinkUri from child is passed up to the parent when merging nodes', (
145+
WidgetTester tester,
146+
) async {
147+
final SemanticsTester semantics = SemanticsTester(tester);
148+
final Uri uri = Uri.parse('https://flutter.com');
149+
const String label = 'test1';
150+
await tester.pumpWidget(
151+
Directionality(
152+
textDirection: TextDirection.ltr,
153+
child: MergeSemantics(
154+
child: Semantics(
155+
linkUrl: uri,
156+
link: true,
157+
child: ElevatedButton(
158+
onPressed: () {},
159+
child: const Text(label),
160+
onFocusChange: (bool value) {},
161+
),
162+
),
163+
),
164+
),
165+
);
166+
167+
expect(
168+
semantics,
169+
hasSemantics(
170+
TestSemantics.root(
171+
children: <TestSemantics>[
172+
TestSemantics.rootChild(
173+
id: 1,
174+
linkUrl: uri,
175+
flags: <SemanticsFlag>[
176+
SemanticsFlag.isButton,
177+
SemanticsFlag.hasEnabledState,
178+
SemanticsFlag.isEnabled,
179+
SemanticsFlag.isFocusable,
180+
SemanticsFlag.isLink,
181+
],
182+
actions: <SemanticsAction>[SemanticsAction.tap, SemanticsAction.focus],
183+
label: label,
184+
),
185+
],
186+
),
187+
ignoreRect: true,
188+
ignoreTransform: true,
189+
),
190+
);
191+
192+
semantics.dispose();
193+
});
144194
}

0 commit comments

Comments
 (0)