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

Commit 84fe9ae

Browse files
committed
[web] Migrate Flutter Web DOM usage to JS static interop - 30.
1 parent abf19c4 commit 84fe9ae

13 files changed

+93
-60
lines changed

lib/web_ui/lib/src/engine/dom.dart

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ extension DomElementExtension on DomElement {
219219
external void remove();
220220
external void setAttribute(String name, Object value);
221221
void appendText(String text) => append(createDomText(text));
222+
external void removeAttribute(String name);
223+
external set tabIndex(int? value);
224+
external int? get tabIndex;
225+
external void focus();
226+
int get scrollTop =>
227+
js_util.getProperty(this, 'scrollTop').round();
228+
set scrollTop(int value) =>
229+
js_util.setProperty<int>(this, 'scrollTop', value.round());
230+
int get scrollLeft =>
231+
js_util.getProperty(this, 'scrollLeft').round();
232+
set scrollLeft(int value) =>
233+
js_util.setProperty<int>(this, 'scrollLeft', value.round());
222234
}
223235

224236
@JS()
@@ -289,6 +301,10 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
289301
set alignItems(String value) => setProperty('align-items', value, '');
290302
set margin(String value) => setProperty('margin', value, '');
291303
set background(String value) => setProperty('background', value, '');
304+
set touchAction(String value) => setProperty('touch-action', value, '');
305+
set overflowY(String value) => setProperty('overflow-y', value, '');
306+
set overflowX(String value) => setProperty('overflow-x', value, '');
307+
set outline(String value) => setProperty('outline', value, '');
292308
String get width => getPropertyValue('width');
293309
String get height => getPropertyValue('height');
294310
String get position => getPropertyValue('position');
@@ -344,6 +360,10 @@ extension DomCSSStyleDeclarationExtension on DomCSSStyleDeclaration {
344360
String get alignItems => getPropertyValue('align-items');
345361
String get margin => getPropertyValue('margin');
346362
String get background => getPropertyValue('background');
363+
String get touchAction => getPropertyValue('touch-action');
364+
String get overflowY => getPropertyValue('overflow-y');
365+
String get overflowX => getPropertyValue('overflow-x');
366+
String get outline => getPropertyValue('outline');
347367

348368
external String getPropertyValue(String property);
349369
void setProperty(String propertyName, String value, [String? priority]) {
@@ -361,7 +381,6 @@ class DomHTMLElement extends DomElement {}
361381

362382
extension DomHTMLElementExtension on DomHTMLElement {
363383
int get offsetWidth => js_util.getProperty<num>(this, 'offsetWidth') as int;
364-
external void focus();
365384
}
366385

367386
@JS()
@@ -963,6 +982,23 @@ extension DomTouchExtension on DomTouch {
963982
external num? get clientY;
964983
}
965984

985+
@JS()
986+
@staticInterop
987+
class DomHTMLInputElement extends DomHTMLElement {}
988+
989+
extension DomHTMLInputElementExtension on DomHTMLInputElement {
990+
external set type(String? value);
991+
external set max(String? value);
992+
external set min(String value);
993+
external set value(String? value);
994+
external String? get value;
995+
external bool? get disabled;
996+
external set disabled(bool? value);
997+
}
998+
999+
DomHTMLInputElement createDomHTMLInputElement() =>
1000+
domDocument.createElement('input') as DomHTMLInputElement;
1001+
9661002
Object? domGetConstructor(String constructorName) =>
9671003
js_util.getProperty(domWindow, constructorName);
9681004

lib/web_ui/lib/src/engine/keyboard_binding.dart

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
6-
75
import 'package:ui/ui.dart' as ui;
86

97
import '../engine.dart' show registerHotRestartListener;
@@ -117,7 +115,7 @@ class KeyboardBinding {
117115
if (_debugLogKeyEvents) {
118116
print(event.type);
119117
}
120-
if (EngineSemanticsOwner.instance.receiveGlobalEvent(event as html.Event)) {
118+
if (EngineSemanticsOwner.instance.receiveGlobalEvent(event)) {
121119
return handler(event);
122120
}
123121
return null;

lib/web_ui/lib/src/engine/pointer_binding.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
65
import 'dart:math' as math;
76

87
import 'package:meta/meta.dart';
@@ -216,7 +215,7 @@ abstract class _BaseAdapter {
216215
// Report the event to semantics. This information is used to debounce
217216
// browser gestures. Semantics tells us whether it is safe to forward
218217
// the event to the framework.
219-
if (EngineSemanticsOwner.instance.receiveGlobalEvent(event as html.Event)) {
218+
if (EngineSemanticsOwner.instance.receiveGlobalEvent(event)) {
220219
handler(event);
221220
}
222221
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
// framework. Currently the framework does not report the
1212
// grouping of radio buttons.
1313

14-
import 'dart:html' as html;
15-
1614
import 'package:ui/ui.dart' as ui;
1715

16+
import '../dom.dart';
1817
import 'semantics.dart';
1918

2019
/// The specific type of checkable control.
@@ -104,7 +103,7 @@ class Checkable extends RoleManager {
104103

105104
void _updateDisabledAttribute() {
106105
if (semanticsObject.enabledState() == EnabledState.disabled) {
107-
final html.Element element = semanticsObject.element;
106+
final DomElement element = semanticsObject.element;
108107
element
109108
..setAttribute('aria-disabled', 'true')
110109
..setAttribute('disabled', 'true');
@@ -114,7 +113,7 @@ class Checkable extends RoleManager {
114113
}
115114

116115
void _removeDisabledAttribute() {
117-
final html.Element element = semanticsObject.element;
116+
final DomElement element = semanticsObject.element;
118117
element..removeAttribute('aria-disabled')..removeAttribute('disabled');
119118
}
120119
}

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
6-
5+
import '../dom.dart';
76
import 'semantics.dart';
87

98
/// Represents semantic objects that deliver information in a visual manner.
@@ -18,13 +17,13 @@ class ImageRoleManager extends RoleManager {
1817
/// The element with role="img" and aria-label could block access to all
1918
/// children elements, therefore create an auxiliary element and describe the
2019
/// image in that if the semantic object have child nodes.
21-
html.Element? _auxiliaryImageElement;
20+
DomElement? _auxiliaryImageElement;
2221

2322
@override
2423
void update() {
2524
if (semanticsObject.isVisualOnly && semanticsObject.hasChildren) {
2625
if (_auxiliaryImageElement == null) {
27-
_auxiliaryImageElement = html.Element.tag('flt-semantics-img');
26+
_auxiliaryImageElement = domDocument.createElement('flt-semantics-img');
2827
// Absolute positioning and sizing of leaf text elements confuses
2928
// VoiceOver. So we let the browser size the value node. The node will
3029
// still have a bigger tap area. However, if the node is a parent to
@@ -54,7 +53,7 @@ class ImageRoleManager extends RoleManager {
5453
}
5554
}
5655

57-
void _setLabel(html.Element? element) {
56+
void _setLabel(DomElement? element) {
5857
if (semanticsObject.hasLabel) {
5958
element!.setAttribute('aria-label', semanticsObject.label!);
6059
}
@@ -69,7 +68,7 @@ class ImageRoleManager extends RoleManager {
6968

7069
void _cleanupElement() {
7170
semanticsObject.setAriaRole('img', false);
72-
semanticsObject.element.attributes.remove('aria-label');
71+
semanticsObject.element.removeAttribute('aria-label');
7372
}
7473

7574
@override

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
6-
75
import 'package:ui/ui.dart' as ui;
86

7+
import '../dom.dart';
98
import '../platform_dispatcher.dart';
9+
import '../safe_browser_api.dart';
1010
import 'semantics.dart';
1111

1212
/// Adds increment/decrement event handling to a semantics object.
@@ -20,7 +20,7 @@ import 'semantics.dart';
2020
/// gestures must be interpreted by the Flutter framework.
2121
class Incrementable extends RoleManager {
2222
/// The HTML element used to render semantics to the browser.
23-
final html.InputElement _element = html.InputElement();
23+
final DomHTMLInputElement _element = createDomHTMLInputElement();
2424

2525
/// The value used by the input element.
2626
///
@@ -49,7 +49,7 @@ class Incrementable extends RoleManager {
4949
_element.type = 'range';
5050
_element.setAttribute('role', 'slider');
5151

52-
_element.addEventListener('change', (_) {
52+
_element.addEventListener('change', allowInterop((_) {
5353
if (_element.disabled!) {
5454
return;
5555
}
@@ -64,7 +64,7 @@ class Incrementable extends RoleManager {
6464
EnginePlatformDispatcher.instance.invokeOnSemanticsAction(
6565
semanticsObject.id, ui.SemanticsAction.decrease, null);
6666
}
67-
});
67+
}));
6868

6969
// Store the callback as a closure because Dart does not guarantee that
7070
// tear-offs produce the same function object.

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
6-
75
import 'package:ui/ui.dart' as ui;
86

97
import '../configuration.dart';
8+
import '../dom.dart';
109
import 'semantics.dart';
1110

1211
/// Renders [_label] and [_value] to the semantics DOM.
@@ -47,7 +46,7 @@ class LabelAndValue extends RoleManager {
4746
/// its label is not reachable via accessibility focus. This happens, for
4847
/// example in popup dialogs, such as the alert dialog. The text of the
4948
/// alert is supplied as a label on the parent node.
50-
html.Element? _auxiliaryValueElement;
49+
DomElement? _auxiliaryValueElement;
5150

5251
@override
5352
void update() {
@@ -90,7 +89,7 @@ class LabelAndValue extends RoleManager {
9089
}
9190

9291
if (_auxiliaryValueElement == null) {
93-
_auxiliaryValueElement = html.Element.tag('flt-semantics-value');
92+
_auxiliaryValueElement = domDocument.createElement('flt-semantics-value');
9493
// Absolute positioning and sizing of leaf text elements confuses
9594
// VoiceOver. So we let the browser size the value node. The node will
9695
// still have a bigger tap area. However, if the node is a parent to other
@@ -119,7 +118,7 @@ class LabelAndValue extends RoleManager {
119118
_auxiliaryValueElement!.remove();
120119
_auxiliaryValueElement = null;
121120
}
122-
semanticsObject.element.attributes.remove('aria-label');
121+
semanticsObject.element.removeAttribute('aria-label');
123122
semanticsObject.setAriaRole('heading', false);
124123
}
125124

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import '../dom.dart';
56
import 'semantics.dart';
67

78
/// Manages semantics configurations that represent live regions.
@@ -31,7 +32,7 @@ class LiveRegion extends RoleManager {
3132
}
3233

3334
void _cleanupDom() {
34-
semanticsObject.element.attributes.remove('aria-live');
35+
semanticsObject.element.removeAttribute('aria-live');
3536
}
3637

3738
@override

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'dart:html' as html;
6-
75
import 'package:ui/ui.dart' as ui;
86

7+
import '../dom.dart';
98
import '../platform_dispatcher.dart';
9+
import '../safe_browser_api.dart';
1010
import 'semantics.dart';
1111

1212
/// Implements vertical and horizontal scrolling functionality for semantics
@@ -37,7 +37,7 @@ class Scrollable extends RoleManager {
3737
///
3838
/// This gesture is converted to [ui.SemanticsAction.scrollUp] or
3939
/// [ui.SemanticsAction.scrollDown], depending on the direction.
40-
html.EventListener? _scrollListener;
40+
DomEventListener? _scrollListener;
4141

4242
/// The value of the "scrollTop" or "scrollLeft" property of this object's
4343
/// [element] that has zero offset relative to the [scrollPosition].
@@ -107,9 +107,9 @@ class Scrollable extends RoleManager {
107107
};
108108
semanticsObject.owner.addGestureModeListener(_gestureModeListener);
109109

110-
_scrollListener = (_) {
110+
_scrollListener = allowInterop((_) {
111111
_recomputeScrollPosition();
112-
};
112+
});
113113
semanticsObject.element.addEventListener('scroll', _scrollListener);
114114
}
115115
}
@@ -138,7 +138,7 @@ class Scrollable extends RoleManager {
138138
// This value is arbitrary.
139139
const int _canonicalNeutralScrollPosition = 10;
140140

141-
final html.Element element = semanticsObject.element;
141+
final DomElement element = semanticsObject.element;
142142
if (semanticsObject.isVerticalScrollContainer) {
143143
element.scrollTop = _canonicalNeutralScrollPosition;
144144
// Read back because the effective value depends on the amount of content.
@@ -159,7 +159,7 @@ class Scrollable extends RoleManager {
159159
}
160160

161161
void _gestureModeDidChange() {
162-
final html.Element element = semanticsObject.element;
162+
final DomElement element = semanticsObject.element;
163163
switch (semanticsObject.owner.gestureMode) {
164164
case GestureMode.browserGestures:
165165
// overflow:scroll will cause the browser report "scroll" events when
@@ -190,7 +190,7 @@ class Scrollable extends RoleManager {
190190

191191
@override
192192
void dispose() {
193-
final html.CssStyleDeclaration style = semanticsObject.element.style;
193+
final DomCSSStyleDeclaration style = semanticsObject.element.style;
194194
assert(_gestureModeListener != null);
195195
style.removeProperty('overflowY');
196196
style.removeProperty('overflowX');

0 commit comments

Comments
 (0)