Skip to content

Commit af388db

Browse files
committed
feat: ✨ Enhance tooltip accessibility using Semantics live region
1 parent 343efe3 commit af388db

File tree

6 files changed

+42
-3
lines changed

6 files changed

+42
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
- Fixed [#587](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/587) - Fixed ShowcaseView.withWidget container positioning issues on web
55
- Fixed [#588](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/588) & [#593](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/593) - Fixed incorrect ShowcaseView callback scope by adding optional scope parameter
66
- Feature [#600](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/600) - Added dynamic onComplete callback registration with `addOnCompleteCallback` and `removeOnCompleteCallback` methods
7-
- Fixed [#577](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/577) - Resolve issue where long tooltip text was rendered outside the screen bounds
7+
- Fixed [#577](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/577) - Resolve issue where long tooltip text was rendered outside the screen bounds
8+
- Feature [#586](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/586): Enhance tooltip accessibility using Semantics live region
89

910
## [5.0.1]
1011

doc/documentation.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ Reference](https://pub.dev/documentation/showcaseview/latest/showcaseview/).
129129
```dart
130130
ShowcaseView.register(
131131
autoPlayDelay: const Duration(seconds: 3),
132+
semanticEnable: true, // Enable accessibility support globally
132133
globalFloatingActionWidget: (showcaseContext) => FloatingActionWidget(
133134
left: 16,
134135
bottom: 16,

lib/src/showcase/showcase_controller.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ class ShowcaseController {
350350
targetPadding: config.targetPadding,
351351
targetTooltipGap: config.targetTooltipGap,
352352
showcaseController: this,
353+
semanticEnable:
354+
config.semanticEnable || showcaseView.semanticEnable,
353355
),
354356
if (_getFloatingActionWidget case final floatAction?) floatAction,
355357
];
@@ -424,6 +426,8 @@ class ShowcaseController {
424426
child: TooltipActionButtonWidget(
425427
config: actionData[i],
426428
showCaseState: showcaseView,
429+
semanticEnable:
430+
config.semanticEnable || showcaseView.semanticEnable,
427431
),
428432
),
429433
];

lib/src/showcase/showcase_view.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class ShowcaseView {
8080
this.globalTooltipActions,
8181
this.globalFloatingActionWidget,
8282
this.hideFloatingActionWidgetForShowcase = const [],
83+
this.semanticEnable = false,
8384
}) {
8485
ShowcaseService.instance.register(this, scope: scope);
8586
_hideFloatingWidgetKeys = {
@@ -145,6 +146,15 @@ class ShowcaseView {
145146
/// Enable/disable showcase globally.
146147
bool enableShowcase;
147148

149+
/// Whether to enable semantic properties for accessibility.
150+
///
151+
/// When set to true, semantic widgets will be added to improve
152+
/// screen reader support throughout the showcase. When false,
153+
/// semantic properties will not be applied.
154+
///
155+
/// Defaults to false.
156+
bool semanticEnable;
157+
148158
/// Custom static floating action widget to show a static non-animating
149159
/// widget anywhere on the screen for all the showcase widget.
150160
FloatingActionBuilderCallback? globalFloatingActionWidget;

lib/src/tooltip/tooltip_wrapper.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class ToolTipWrapper extends StatefulWidget {
6666
required this.tooltipPadding,
6767
required this.toolTipSlideEndDistance,
6868
required this.targetTooltipGap,
69+
this.semanticEnable = false,
6970
this.scaleAnimationAlignment,
7071
this.tooltipPosition,
7172
this.titlePadding,
@@ -108,6 +109,7 @@ class ToolTipWrapper extends StatefulWidget {
108109
final EdgeInsets targetPadding;
109110
final ShowcaseController showcaseController;
110111
final double targetTooltipGap;
112+
final bool semanticEnable;
111113

112114
@override
113115
State<ToolTipWrapper> createState() => _ToolTipWrapperState();
@@ -254,7 +256,12 @@ class _ToolTipWrapperState extends State<ToolTipWrapper>
254256
_TooltipLayoutId(
255257
id: TooltipLayoutSlot.tooltipBox,
256258
key: UniqueKey(),
257-
child: defaultToolTipWidget,
259+
child: widget.semanticEnable
260+
? Semantics(
261+
liveRegion: true,
262+
child: defaultToolTipWidget,
263+
)
264+
: defaultToolTipWidget,
258265
),
259266
if (widget.tooltipActions.isNotEmpty &&
260267
(widget.tooltipActionConfig.position.isOutside ||

lib/src/widget/tooltip_action_button_widget.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class TooltipActionButtonWidget extends StatelessWidget {
3838
const TooltipActionButtonWidget({
3939
required this.config,
4040
required this.showCaseState,
41+
this.semanticEnable = false,
4142
super.key,
4243
});
4344

@@ -47,11 +48,14 @@ class TooltipActionButtonWidget extends StatelessWidget {
4748
/// This is used for close, next and previous showcase navigation.
4849
final ShowcaseView showCaseState;
4950

51+
/// Whether to enable semantic properties for accessibility.
52+
final bool semanticEnable;
53+
5054
@override
5155
Widget build(BuildContext context) {
5256
final theme = Theme.of(context);
5357

54-
return config.button ??
58+
final child = config.button ??
5559
MouseRegion(
5660
cursor: SystemMouseCursors.click,
5761
child: GestureDetector(
@@ -85,6 +89,18 @@ class TooltipActionButtonWidget extends StatelessWidget {
8589
),
8690
),
8791
);
92+
93+
// Semantics widget is used to improve accessibility for screen readers.
94+
// Only applied when semanticEnable is true.
95+
if (semanticEnable) {
96+
return Semantics(
97+
button: true,
98+
liveRegion: true,
99+
child: child,
100+
);
101+
}
102+
103+
return child;
88104
}
89105

90106
void _handleOnTap() {

0 commit comments

Comments
 (0)