Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions packages/material_ui/lib/src/autocomplete.dart
Original file line number Diff line number Diff line change
Expand Up @@ -318,22 +318,19 @@ class _AutocompleteOptionsListState<T extends Object> extends State<_Autocomplet
itemCount: widget.options.length,
itemBuilder: (BuildContext context, int index) {
final T option = widget.options.elementAt(index);
final bool highlight = highlightedIndex == index;
return Semantics(
button: true,
selected: highlight,
child: InkWell(
key: GlobalObjectKey(option),
onTap: () {
widget.onSelected(option);
},
child: Builder(
builder: (BuildContext context) {
final highlight = highlightedIndex == index;
return Container(
color: highlight ? Theme.of(context).focusColor : null,
padding: const EdgeInsets.all(16.0),
child: Text(widget.displayStringForOption(option)),
);
},
child: Container(
color: highlight ? Theme.of(context).focusColor : null,
padding: const EdgeInsets.all(16.0),
child: Text(widget.displayStringForOption(option)),
),
),
);
Expand Down
33 changes: 18 additions & 15 deletions packages/material_ui/lib/src/drawer_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,24 @@ class DrawerHeader extends StatelessWidget {
assert(debugCheckHasMediaQuery(context));
final ThemeData theme = Theme.of(context);
final double statusBarHeight = MediaQuery.paddingOf(context).top;
return Container(
height: statusBarHeight + _kDrawerHeaderHeight,
margin: margin,
decoration: BoxDecoration(border: Border(bottom: Divider.createBorderSide(context))),
child: AnimatedContainer(
padding: padding.add(EdgeInsets.only(top: statusBarHeight)),
decoration: decoration,
duration: duration,
curve: curve,
child: child == null
? null
: DefaultTextStyle(
style: theme.textTheme.bodyLarge!,
child: MediaQuery.removePadding(context: context, removeTop: true, child: child!),
),
return Semantics(
header: true,
child: Container(
height: statusBarHeight + _kDrawerHeaderHeight,
margin: margin,
decoration: BoxDecoration(border: Border(bottom: Divider.createBorderSide(context))),
child: AnimatedContainer(
padding: padding.add(EdgeInsets.only(top: statusBarHeight)),
decoration: decoration,
duration: duration,
curve: curve,
child: child == null
? null
: DefaultTextStyle(
style: theme.textTheme.bodyLarge!,
child: MediaQuery.removePadding(context: context, removeTop: true, child: child!),
),
),
),
);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/material_ui/lib/src/tooltip.dart
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,8 @@ class TooltipState extends State<Tooltip> with SingleTickerProviderStateMixin {
onTriggered: widget.onTriggered,
dismissDelay: widget.exitDuration ?? _tooltipTheme.exitDuration ?? _defaultExitDuration,
positionDelegate: _getDefaultPositionDelegate,
ignorePointer: widget.ignorePointer ?? widget.message != null,
ignorePointer:
widget.ignorePointer ?? _tooltipTheme.ignorePointer ?? widget.message != null,
child: effectiveChild,
);
}
Expand Down
18 changes: 17 additions & 1 deletion packages/material_ui/lib/src/tooltip_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class TooltipThemeData with Diagnosticable {
this.exitDuration,
this.triggerMode,
this.enableFeedback,
this.ignorePointer,
}) : assert(
height == null || constraints == null,
'Only one of `height` and `constraints` may be specified.',
Expand Down Expand Up @@ -137,6 +138,14 @@ class TooltipThemeData with Diagnosticable {
/// * [Feedback], for providing platform-specific feedback to certain actions.
final bool? enableFeedback;

/// Whether the tooltip overlay should be invisible to hit testing.
///
/// If `false`, moving the mouse pointer onto the tooltip overlay keeps the
/// tooltip visible (satisfying WCAG 1.4.13 Hoverable).
///
/// This value is used if [Tooltip.ignorePointer] is null.
final bool? ignorePointer;

/// Creates a copy of this object but with the given fields replaced with the
/// new values.
TooltipThemeData copyWith({
Expand All @@ -159,6 +168,7 @@ class TooltipThemeData with Diagnosticable {
Duration? exitDuration,
TooltipTriggerMode? triggerMode,
bool? enableFeedback,
bool? ignorePointer,
}) {
return TooltipThemeData(
height: height ?? this.height,
Expand All @@ -173,8 +183,10 @@ class TooltipThemeData with Diagnosticable {
textAlign: textAlign ?? this.textAlign,
waitDuration: waitDuration ?? this.waitDuration,
showDuration: showDuration ?? this.showDuration,
exitDuration: exitDuration ?? this.exitDuration,
triggerMode: triggerMode ?? this.triggerMode,
enableFeedback: enableFeedback ?? this.enableFeedback,
ignorePointer: ignorePointer ?? this.ignorePointer,
);
}

Expand All @@ -198,6 +210,7 @@ class TooltipThemeData with Diagnosticable {
decoration: Decoration.lerp(a?.decoration, b?.decoration, t),
textStyle: TextStyle.lerp(a?.textStyle, b?.textStyle, t),
textAlign: t < 0.5 ? a?.textAlign : b?.textAlign,
ignorePointer: t < 0.5 ? a?.ignorePointer : b?.ignorePointer,
);
}

Expand All @@ -218,6 +231,7 @@ class TooltipThemeData with Diagnosticable {
exitDuration,
triggerMode,
enableFeedback,
ignorePointer,
);

@override
Expand All @@ -243,7 +257,8 @@ class TooltipThemeData with Diagnosticable {
other.showDuration == showDuration &&
other.exitDuration == exitDuration &&
other.triggerMode == triggerMode &&
other.enableFeedback == enableFeedback;
other.enableFeedback == enableFeedback &&
other.ignorePointer == ignorePointer;
}

@override
Expand Down Expand Up @@ -283,6 +298,7 @@ class TooltipThemeData with Diagnosticable {
properties.add(
DiagnosticsProperty<TooltipTriggerMode>('triggerMode', triggerMode, defaultValue: null),
);
properties.add(DiagnosticsProperty<bool>('ignorePointer', ignorePointer, defaultValue: null));
properties.add(
FlagProperty('enableFeedback', value: enableFeedback, ifTrue: 'true', showName: true),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
changelog: |
- Exposes `selected` state on `Autocomplete` option semantics.
- Wraps `DrawerHeader` in `Semantics(header: true)`.
- Adds `ignorePointer` to `TooltipThemeData` for WCAG 1.4.13 Hoverable support.
version: minor
16 changes: 15 additions & 1 deletion packages/material_ui/test/autocomplete_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -893,18 +893,32 @@ void main() {
);
await tester.tap(find.byType(TextField));
await tester.pump();
await tester.enterText(find.byType(TextField), 'aa');
await tester.enterText(find.byType(TextField), 'a');
await tester.pump();
expect(
tester.getSemantics(find.text('aardvark')),
matchesSemantics(
isButton: true,
isFocusable: true,
hasSelectedState: true,
isSelected: true,
hasTapAction: true,
hasFocusAction: true,
label: 'aardvark',
),
);
expect(
tester.getSemantics(find.text('bobcat')),
matchesSemantics(
isButton: true,
isFocusable: true,
hasSelectedState: true,
isSelected: false,
hasTapAction: true,
hasFocusAction: true,
label: 'bobcat',
),
);
});

testWidgets('Same option in Autocomplete should be selectable again after text is cleared', (
Expand Down
15 changes: 15 additions & 0 deletions packages/material_ui/test/drawer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1513,4 +1513,19 @@ void main() {
expect(tester.getSize(find.byType(Drawer)), Size.zero);
expect(tester.getSize(find.byType(DrawerHeader)), Size.zero);
});

testWidgets('DrawerHeader provides header semantics', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(body: DrawerHeader(child: Text('Drawer Title'))),
),
);

expect(
tester.getSemantics(find.byType(DrawerHeader)),
matchesSemantics(isHeader: true, label: 'Drawer Title', textDirection: TextDirection.ltr),
);
handle.dispose();
});
}
21 changes: 21 additions & 0 deletions packages/material_ui/test/tooltip_theme_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ void main() {
expect(theme.exitDuration, null);
expect(theme.triggerMode, null);
expect(theme.enableFeedback, null);
expect(theme.ignorePointer, null);
});

testWidgets('Default TooltipThemeData debugFillProperties', (WidgetTester tester) async {
Expand All @@ -62,6 +63,7 @@ void main() {
const exit = Duration(milliseconds: 100);
const TooltipTriggerMode triggerMode = TooltipTriggerMode.longPress;
const enableFeedback = true;
const ignorePointer = false;
const TooltipThemeData(
height: 15.0,
padding: EdgeInsets.all(20.0),
Expand All @@ -76,6 +78,7 @@ void main() {
exitDuration: exit,
triggerMode: triggerMode,
enableFeedback: enableFeedback,
ignorePointer: ignorePointer,
).debugFillProperties(builder);

final List<String> description = builder.properties
Expand All @@ -97,6 +100,7 @@ void main() {
'exit duration: $exit',
'triggerMode: $triggerMode',
'enableFeedback: true',
'ignorePointer: false',
]);
});

Expand Down Expand Up @@ -1540,6 +1544,23 @@ void main() {
);
expect(tester.element(textAncestors.first).size, equals(themeConstraints.biggest));
});

testWidgets('Tooltip respects ignorePointer from the ambient theme', (WidgetTester tester) async {
final tooltipKey = GlobalKey<TooltipState>();
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(tooltipTheme: const TooltipThemeData(ignorePointer: false)),
home: Tooltip(
key: tooltipKey,
message: tooltipText,
child: const SizedBox(width: 100, height: 100),
),
),
);

final RawTooltip rawTooltip = tester.widget<RawTooltip>(find.byType(RawTooltip));
expect(rawTooltip.ignorePointer, isFalse);
});
}

SemanticsNode findDebugSemantics(RenderObject object) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ void main() {
expect(
tester.semantics.find(find.byType(UserAccountsDrawerHeader)),
matchesSemantics(
isHeader: true,
isFocusable: true,
hasFocusAction: true,
label: 'Signed in\nname\nemail',
Expand Down Expand Up @@ -559,6 +560,7 @@ void main() {
expect(
tester.semantics.find(find.byType(UserAccountsDrawerHeader)),
matchesSemantics(
isHeader: true,
label: 'Signed in',
textDirection: TextDirection.ltr,
children: <Matcher>[
Expand Down
Loading