Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit f011591

Browse files
committed
address comments
1 parent a11d81d commit f011591

File tree

2 files changed

+33
-15
lines changed

2 files changed

+33
-15
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@ abstract class PrimaryRoleManager {
605605
/// focus. Not all elements that can take accessibility focus can also take
606606
/// input focus. For example, a plain text node cannot take input focus, but
607607
/// it can take accessibility focus.
608+
///
609+
/// Returns `true` if the this role manager took the focus. Returns `false` if
610+
/// this role manager did not take the focus. The return value can be used to
611+
/// decide whether to stop searching for a node that should take focus.
608612
bool focusAsRouteDefault();
609613
}
610614

@@ -2468,7 +2472,11 @@ AFTER: $description
24682472
_oneTimePostUpdateCallbacks.clear();
24692473
}
24702474

2471-
/// True, if any semantics node requested focus explicitly.
2475+
/// True, if any semantics node requested focus explicitly during the latest
2476+
/// semantics update.
2477+
///
2478+
/// The default value is `false`, and it is reset back to `false` after the
2479+
/// semantics update at the end of [updateSemantics].
24722480
///
24732481
/// Since focus can only be taken by no more than one element, the engine
24742482
/// should not request focus for multiple elements. This flag helps resolve

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,7 +1537,7 @@ void _testIncrementables() {
15371537
};
15381538

15391539
pumpSemantics(isFocused: false);
1540-
final DomElement element = semantics().debugSemanticsTree![0]!.element.querySelector('input')!;
1540+
final DomElement element = owner().debugSemanticsTree![0]!.element.querySelector('input')!;
15411541
expect(capturedActions, isEmpty);
15421542

15431543
pumpSemantics(isFocused: true);
@@ -1905,7 +1905,7 @@ void _testCheckables() {
19051905
};
19061906

19071907
pumpSemantics(isFocused: false);
1908-
final DomElement element = semantics().debugSemanticsTree![0]!.element;
1908+
final DomElement element = owner().debugSemanticsTree![0]!.element;
19091909
expect(capturedActions, isEmpty);
19101910

19111911
pumpSemantics(isFocused: true);
@@ -1914,9 +1914,17 @@ void _testCheckables() {
19141914
]);
19151915
capturedActions.clear();
19161916

1917+
// The framework removes focus from the widget (i.e. "blurs" it). Since the
1918+
// blurring is initiated by the framework, there's no need to send any
1919+
// notifications back to the framework about it.
19171920
pumpSemantics(isFocused: false);
19181921
expect(capturedActions, isEmpty);
19191922

1923+
// If the element is blurred by the browser, then we do want to notify the
1924+
// framework. This is because screen reader can be focused on something
1925+
// other than what the framework is focused on, and notifying the framework
1926+
// about the loss of focus on a node is information that the framework did
1927+
// not have before.
19201928
element.blur();
19211929
expect(capturedActions, <CapturedAction>[
19221930
(0, ui.SemanticsAction.didLoseAccessibilityFocus, null),
@@ -2081,7 +2089,7 @@ void _testTappable() {
20812089
};
20822090

20832091
pumpSemantics(isFocused: false);
2084-
final DomElement element = semantics().debugSemanticsTree![0]!.element;
2092+
final DomElement element = owner().debugSemanticsTree![0]!.element;
20852093
expect(capturedActions, isEmpty);
20862094

20872095
pumpSemantics(isFocused: true);
@@ -2874,7 +2882,7 @@ void _testDialog() {
28742882
});
28752883

28762884
// Test the simple scenario of a dialog coming up and containing focusable
2877-
// descentants that are not initially focused. The expectation is that the
2885+
// descendants that are not initially focused. The expectation is that the
28782886
// first descendant will be auto-focused.
28792887
test('focuses on the first unfocused Focusable', () async {
28802888
semantics()
@@ -2886,14 +2894,16 @@ void _testDialog() {
28862894
capturedActions.add((event.nodeId, event.type, event.arguments));
28872895
};
28882896

2889-
final SemanticsTester tester = SemanticsTester(semantics());
2897+
final SemanticsTester tester = SemanticsTester(owner());
28902898
tester.updateNode(
28912899
id: 0,
28922900
scopesRoute: true,
28932901
transform: Matrix4.identity().toFloat64(),
28942902
children: <SemanticsNodeUpdate>[
28952903
tester.updateNode(
28962904
id: 1,
2905+
// None of the children should have isFocused set to `true` to make
2906+
// sure that the auto-focus logic kicks in.
28972907
children: <SemanticsNodeUpdate>[
28982908
tester.updateNode(
28992909
id: 2,
@@ -2934,7 +2944,7 @@ void _testDialog() {
29342944
});
29352945

29362946
// Test the scenario of a dialog coming up and containing focusable
2937-
// descentants with one of them explicitly requesting focus. The expectation
2947+
// descendants with one of them explicitly requesting focus. The expectation
29382948
// is that the dialog will not attempt to auto-focus on anything and let the
29392949
// respective descendant take focus.
29402950
test('does nothing if a descendant asks for focus explicitly', () async {
@@ -2947,7 +2957,7 @@ void _testDialog() {
29472957
capturedActions.add((event.nodeId, event.type, event.arguments));
29482958
};
29492959

2950-
final SemanticsTester tester = SemanticsTester(semantics());
2960+
final SemanticsTester tester = SemanticsTester(owner());
29512961
tester.updateNode(
29522962
id: 0,
29532963
scopesRoute: true,
@@ -2975,6 +2985,7 @@ void _testDialog() {
29752985
isEnabled: true,
29762986
isButton: true,
29772987
isFocusable: true,
2988+
// Asked for focus explicitly.
29782989
isFocused: true,
29792990
rect: const ui.Rect.fromLTRB(0, 0, 100, 50),
29802991
),
@@ -2995,8 +3006,8 @@ void _testDialog() {
29953006
});
29963007

29973008
// Test the scenario of a dialog coming up and containing non-focusable
2998-
// descentants that can have a11y focus. The expectation is that the first
2999-
// descendant will be auto-focused.
3009+
// descendants that can have a11y focus. The expectation is that the first
3010+
// descendant will be auto-focused, even if it's not input-focusable.
30003011
test('focuses on the first non-focusable descedant', () async {
30013012
semantics()
30023013
..debugOverrideTimestampFunction(() => _testTime)
@@ -3007,7 +3018,7 @@ void _testDialog() {
30073018
capturedActions.add((event.nodeId, event.type, event.arguments));
30083019
};
30093020

3010-
final SemanticsTester tester = SemanticsTester(semantics());
3021+
final SemanticsTester tester = SemanticsTester(owner());
30113022
tester.updateNode(
30123023
id: 0,
30133024
scopesRoute: true,
@@ -3043,7 +3054,7 @@ void _testDialog() {
30433054
expect(capturedActions, isEmpty);
30443055

30453056
// However, the element should have gotten the focus.
3046-
final DomElement element = semantics().debugSemanticsTree![2]!.element;
3057+
final DomElement element = owner().debugSemanticsTree![2]!.element;
30473058
expect(element.tabIndex, -1);
30483059
expect(domDocument.activeElement, element);
30493060

@@ -3062,17 +3073,16 @@ void _testDialog() {
30623073
capturedActions.add((event.nodeId, event.type, event.arguments));
30633074
};
30643075

3065-
final SemanticsTester tester = SemanticsTester(semantics());
3076+
final SemanticsTester tester = SemanticsTester(owner());
30663077
tester.updateNode(
30673078
id: 0,
30683079
scopesRoute: true,
30693080
transform: Matrix4.identity().toFloat64(),
30703081
);
30713082
tester.apply();
30723083

3073-
// The focused node is not focusable, so no notification is sent to the
3074-
// framework.
30753084
expect(capturedActions, isEmpty);
3085+
expect(domDocument.activeElement, domDocument.body);
30763086

30773087
semantics().semanticsEnabled = false;
30783088
});

0 commit comments

Comments
 (0)