mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add web support for tooltip (flutter/engine#28966)
This commit is contained in:
parent
c5791ff96e
commit
406668ff08
@ -52,17 +52,24 @@ class LabelAndValue extends RoleManager {
|
||||
void update() {
|
||||
final bool hasValue = semanticsObject.hasValue;
|
||||
final bool hasLabel = semanticsObject.hasLabel;
|
||||
final bool hasTooltip = semanticsObject.hasTooltip;
|
||||
|
||||
// If the node is incrementable the value is reported to the browser via
|
||||
// the respective role manager. We do not need to also render it again here.
|
||||
final bool shouldDisplayValue = hasValue && !semanticsObject.isIncrementable;
|
||||
|
||||
if (!hasLabel && !shouldDisplayValue) {
|
||||
if (!hasLabel && !shouldDisplayValue && !hasTooltip) {
|
||||
_cleanUpDom();
|
||||
return;
|
||||
}
|
||||
|
||||
final StringBuffer combinedValue = StringBuffer();
|
||||
if (hasTooltip) {
|
||||
combinedValue.write(semanticsObject.tooltip);
|
||||
if (hasLabel || shouldDisplayValue) {
|
||||
combinedValue.write('\n');
|
||||
}
|
||||
}
|
||||
if (hasLabel) {
|
||||
combinedValue.write(semanticsObject.label);
|
||||
if (shouldDisplayValue) {
|
||||
|
||||
@ -600,6 +600,22 @@ class SemanticsObject {
|
||||
_dirtyFields |= _additionalActionsIndex;
|
||||
}
|
||||
|
||||
/// See [ui.SemanticsUpdateBuilder.updateNode].
|
||||
String? get tooltip => _tooltip;
|
||||
String? _tooltip;
|
||||
|
||||
/// Whether this object contains a non-empty tooltip.
|
||||
bool get hasTooltip => _tooltip != null && _tooltip!.isNotEmpty;
|
||||
|
||||
static const int _tooltipIndex = 1 << 22;
|
||||
|
||||
/// Whether the [tooltip] field has been updated but has not been
|
||||
/// applied to the DOM yet.
|
||||
bool get isTooltipDirty => _isDirty(_tooltipIndex);
|
||||
void _markTooltipDirty() {
|
||||
_dirtyFields |= _tooltipIndex;
|
||||
}
|
||||
|
||||
/// A unique permanent identifier of the semantics node in the tree.
|
||||
final int id;
|
||||
|
||||
@ -812,6 +828,11 @@ class SemanticsObject {
|
||||
_markDecreasedValueDirty();
|
||||
}
|
||||
|
||||
if (_tooltip != update.tooltip) {
|
||||
_tooltip = update.tooltip;
|
||||
_markTooltipDirty();
|
||||
}
|
||||
|
||||
if (_textDirection != update.textDirection) {
|
||||
_textDirection = update.textDirection;
|
||||
_markTextDirectionDirty();
|
||||
@ -882,7 +903,7 @@ class SemanticsObject {
|
||||
/// Detects the roles that this semantics object corresponds to and manages
|
||||
/// the lifecycles of [SemanticsObjectRole] objects.
|
||||
void _updateRoles() {
|
||||
_updateRole(Role.labelAndValue, (hasLabel || hasValue) && !isTextField && !isVisualOnly);
|
||||
_updateRole(Role.labelAndValue, (hasLabel || hasValue || hasTooltip) && !isTextField && !isVisualOnly);
|
||||
_updateRole(Role.textField, isTextField);
|
||||
|
||||
final bool shouldUseTappableRole =
|
||||
|
||||
@ -131,7 +131,7 @@ void _testEngineSemanticsOwner() {
|
||||
expect(placeholder.isConnected, isFalse);
|
||||
});
|
||||
|
||||
void renderLabel(String label) {
|
||||
void renderSemantics({String? label, String? tooltip}) {
|
||||
final ui.SemanticsUpdateBuilder builder = ui.SemanticsUpdateBuilder();
|
||||
updateNode(
|
||||
builder,
|
||||
@ -148,13 +148,18 @@ void _testEngineSemanticsOwner() {
|
||||
id: 1,
|
||||
actions: 0,
|
||||
flags: 0,
|
||||
label: label,
|
||||
label: label ?? '',
|
||||
tooltip: tooltip ?? '',
|
||||
transform: Matrix4.identity().toFloat64(),
|
||||
rect: const ui.Rect.fromLTRB(0, 0, 20, 20),
|
||||
);
|
||||
semantics().updateSemantics(builder.build());
|
||||
}
|
||||
|
||||
void renderLabel(String label) {
|
||||
renderSemantics(label: label);
|
||||
}
|
||||
|
||||
test('produces an aria-label', () async {
|
||||
semantics().semanticsEnabled = true;
|
||||
|
||||
@ -202,6 +207,53 @@ void _testEngineSemanticsOwner() {
|
||||
semantics().semanticsEnabled = false;
|
||||
});
|
||||
|
||||
test('tooltip is part of label', () async {
|
||||
semantics().semanticsEnabled = true;
|
||||
|
||||
// Create
|
||||
renderSemantics(tooltip: 'tooltip');
|
||||
|
||||
final Map<int, SemanticsObject> tree = semantics().debugSemanticsTree!;
|
||||
expect(tree.length, 2);
|
||||
expect(tree[0]!.id, 0);
|
||||
expect(tree[0]!.element.tagName.toLowerCase(), 'flt-semantics');
|
||||
expect(tree[1]!.id, 1);
|
||||
expect(tree[1]!.tooltip, 'tooltip');
|
||||
|
||||
expectSemanticsTree('''
|
||||
<sem style="$rootSemanticStyle">
|
||||
<sem-c>
|
||||
<sem aria-label="tooltip">
|
||||
<sem-v>tooltip</sem-v>
|
||||
</sem>
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
// Update
|
||||
renderSemantics(label: 'Hello', tooltip: 'tooltip');
|
||||
|
||||
expectSemanticsTree('''
|
||||
<sem style="$rootSemanticStyle">
|
||||
<sem-c>
|
||||
<sem aria-label="tooltip\nHello">
|
||||
<sem-v>tooltip\nHello</sem-v>
|
||||
</sem>
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
// Remove
|
||||
renderSemantics();
|
||||
|
||||
expectSemanticsTree('''
|
||||
<sem style="$rootSemanticStyle">
|
||||
<sem-c>
|
||||
<sem></sem>
|
||||
</sem-c>
|
||||
</sem>''');
|
||||
|
||||
semantics().semanticsEnabled = false;
|
||||
});
|
||||
|
||||
test('clears semantics tree when disabled', () {
|
||||
expect(semantics().debugSemanticsTree, isEmpty);
|
||||
semantics().semanticsEnabled = true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user