Skip to content

Instantly share code, notes, and snippets.

@yjbanov
Created May 7, 2024 18:14
Show Gist options
  • Save yjbanov/f7755838910ccf1a873286e7bb2f1244 to your computer and use it in GitHub Desktop.
Save yjbanov/f7755838910ccf1a873286e7bb2f1244 to your computer and use it in GitHub Desktop.
diff --git a/lib/web_ui/lib/src/engine/semantics/label_and_value.dart b/lib/web_ui/lib/src/engine/semantics/label_and_value.dart
index 843c4dedda..74ccc08d2a 100644
--- a/lib/web_ui/lib/src/engine/semantics/label_and_value.dart
+++ b/lib/web_ui/lib/src/engine/semantics/label_and_value.dart
@@ -16,7 +16,7 @@ import 'semantics.dart';
/// respect the `aria-label` without a [DomText] node. Crawlers typically do not
/// need this information, as they primarily scan visible text, which is
/// communicated in semantics as leaf text and heading nodes.
-enum LabelRepresentation {
+sealed class LabelRepresentation {
/// Represents the label as an `aria-label` attribute.
///
/// This representation is the most efficient as all it does is pass a string
@@ -27,7 +27,7 @@ enum LabelRepresentation {
/// role) JAWS on Windows. However, this role is still the most common, as it
/// applies to all container nodes, and many ARIA roles (e.g. checkboxes,
/// radios, scrollables, sliders).
- ariaLabel(AriaLabelRepresentation),
+ static const LabelRepresentation ariaLabel = _AriaLabel();
/// Represents the label as a [DomText] node.
///
@@ -37,7 +37,7 @@ enum LabelRepresentation {
///
/// This representation is compatible with most web crawlers, and it is the
/// best option for certain ARIA roles, such as buttons, links, and headings.
- domText(DomTextRepresentation),
+ static const LabelRepresentation domText = _DomText();
/// Represents the label as a sized span.
///
@@ -45,17 +45,38 @@ enum LabelRepresentation {
/// need to be laid out to compute the right size. It is compatible with most
/// web crawlers, and it is the best options for certain ARIA roles, such as
/// the implicit "generic" role used for plain text (not headings).
- sizedSpan(SizedSpanRepresentation);
-
- const LabelRepresentation(this.implementation);
+ static const LabelRepresentation sizedSpan = _SizedSpan();
/// The type used to implement this representation.
- final Type implementation;
+ LabelRepresentationBehavior createBehavior(PrimaryRoleManager owner);
+}
+
+final class _AriaLabel implements LabelRepresentation {
+ const _AriaLabel();
+
+ @override
+ LabelRepresentationBehavior createBehavior(PrimaryRoleManager owner) => AriaLabelRepresentation._(owner);
+}
+
+final class _DomText implements LabelRepresentation {
+ const _DomText();
+
+ @override
+ LabelRepresentationBehavior createBehavior(PrimaryRoleManager owner) => DomTextRepresentation._(owner);
+}
+
+final class _SizedSpan implements LabelRepresentation {
+ const _SizedSpan();
+
+ @override
+ LabelRepresentationBehavior createBehavior(PrimaryRoleManager owner) => SizedSpanRepresentation._(owner);
}
/// Provides a DOM behavior for a [LabelRepresentation].
abstract final class LabelRepresentationBehavior {
- LabelRepresentationBehavior(this.owner);
+ LabelRepresentationBehavior(this.kind, this.owner);
+
+ final LabelRepresentation kind;
/// The role manager that this label representation is attached to.
final PrimaryRoleManager owner;
@@ -103,7 +124,7 @@ abstract final class LabelRepresentationBehavior {
///
/// <flt-semantics aria-label="Hello, World!"></flt-semantics>
final class AriaLabelRepresentation extends LabelRepresentationBehavior {
- AriaLabelRepresentation._(super.owner);
+ AriaLabelRepresentation._(PrimaryRoleManager owner) : super(LabelRepresentation.ariaLabel, owner);
String? _previousLabel;
@@ -137,7 +158,7 @@ final class AriaLabelRepresentation extends LabelRepresentationBehavior {
/// no ARIA role set, or the role does not size the element, then the
/// [SizedSpanRepresentation] representation can be used.
final class DomTextRepresentation extends LabelRepresentationBehavior {
- DomTextRepresentation._(super.owner);
+ DomTextRepresentation._(PrimaryRoleManager owner) : super(LabelRepresentation.domText, owner);
DomText? _domText;
String? _previousLabel;
@@ -200,7 +221,7 @@ typedef _Measurement = ({
/// Text scaling is used to control the size of the screen reader focus ring.
/// This is used for plain text nodes (e.g. paragraphs of text).
final class SizedSpanRepresentation extends LabelRepresentationBehavior {
- SizedSpanRepresentation._(super.owner) {
+ SizedSpanRepresentation._(PrimaryRoleManager owner) : super(LabelRepresentation.sizedSpan, owner) {
_domText.style
// `inline-block` is needed for two reasons:
// - It supports measuring the true size of the text. Pure `block` would
@@ -423,13 +444,9 @@ class LabelAndValue extends RoleManager {
: preferredRepresentation;
LabelRepresentationBehavior? representation = _representation;
- if (representation == null || representation.runtimeType != effectiveRepresentation.implementation) {
+ if (representation == null || representation.kind != effectiveRepresentation) {
representation?.cleanUp();
- _representation = representation = switch (effectiveRepresentation) {
- LabelRepresentation.ariaLabel => AriaLabelRepresentation._(owner),
- LabelRepresentation.domText => DomTextRepresentation._(owner),
- LabelRepresentation.sizedSpan => SizedSpanRepresentation._(owner),
- };
+ _representation = representation = effectiveRepresentation.createBehavior(owner);
}
return representation;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment