[web] Migrate framework away from dart:html and package:js (#128580)
Use `package:web` and `dart:js_interop` instead. Part of https://github.com/flutter/flutter/issues/127030
This commit is contained in:
parent
52c4db8d33
commit
95be76ab7e
@ -48,5 +48,6 @@ const Set<String> kCorePackageAllowList = <String>{
|
|||||||
'test_api',
|
'test_api',
|
||||||
'vector_math',
|
'vector_math',
|
||||||
'vm_service',
|
'vm_service',
|
||||||
|
'web',
|
||||||
'webdriver',
|
'webdriver',
|
||||||
};
|
};
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// For now, we're hiding dart:js_interop's `@JS` to avoid a conflict with
|
import 'dart:js_interop';
|
||||||
// package:js' `@JS`. In the future, we should be able to remove package:js
|
|
||||||
// altogether and just import dart:js_interop.
|
|
||||||
import 'dart:js_interop' hide JS;
|
|
||||||
import 'package:js/js.dart';
|
|
||||||
|
|
||||||
// This value is set by the engine. It is used to determine if the application is
|
// This value is set by the engine. It is used to determine if the application is
|
||||||
// using canvaskit.
|
// using canvaskit.
|
||||||
|
@ -2,11 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// For now, we're hiding dart:js_interop's `@JS` to avoid a conflict with
|
import 'dart:js_interop';
|
||||||
// package:js' `@JS`. In the future, we should be able to remove package:js
|
|
||||||
// altogether and just import dart:js_interop.
|
|
||||||
import 'dart:js_interop' hide JS;
|
|
||||||
import 'package:js/js.dart';
|
|
||||||
|
|
||||||
/// This file includes static interop helpers for Flutter Web.
|
/// This file includes static interop helpers for Flutter Web.
|
||||||
// TODO(joshualitt): This file will eventually be removed,
|
// TODO(joshualitt): This file will eventually be removed,
|
||||||
|
@ -9,10 +9,10 @@ dependencies:
|
|||||||
# To update these, use "flutter update-packages --force-upgrade".
|
# To update these, use "flutter update-packages --force-upgrade".
|
||||||
characters: 1.3.0
|
characters: 1.3.0
|
||||||
collection: 1.17.2
|
collection: 1.17.2
|
||||||
js: 0.6.7
|
|
||||||
material_color_utilities: 0.5.0
|
material_color_utilities: 0.5.0
|
||||||
meta: 1.9.1
|
meta: 1.9.1
|
||||||
vector_math: 2.1.4
|
vector_math: 2.1.4
|
||||||
|
web: 0.1.3-beta
|
||||||
sky_engine:
|
sky_engine:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
@ -72,4 +72,4 @@ dev_dependencies:
|
|||||||
webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
webkit_inspection_protocol: 1.2.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||||
yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
yaml: 3.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
|
||||||
|
|
||||||
# PUBSPEC CHECKSUM: dd07
|
# PUBSPEC CHECKSUM: d32a
|
||||||
|
@ -2,14 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// For now, we're hiding dart:js_interop's `@JS` to avoid a conflict with
|
import 'dart:js_interop';
|
||||||
// package:js' `@JS`. In the future, we should be able to remove package:js
|
|
||||||
// altogether and just import dart:js_interop.
|
|
||||||
import 'dart:js_interop' hide JS;
|
|
||||||
|
|
||||||
import 'package:flutter/src/services/dom.dart';
|
import 'package:flutter/src/services/dom.dart';
|
||||||
import 'package:js/js.dart';
|
|
||||||
import 'package:js/js_util.dart' as js_util;
|
|
||||||
|
|
||||||
/// Defines a new property on an Object.
|
/// Defines a new property on an Object.
|
||||||
@JS('Object.defineProperty')
|
@JS('Object.defineProperty')
|
||||||
@ -17,13 +12,12 @@ external JSVoid objectDefineProperty(JSAny o, JSString symbol, JSAny desc);
|
|||||||
|
|
||||||
void createGetter(JSAny mock, String key, JSAny? Function() get) {
|
void createGetter(JSAny mock, String key, JSAny? Function() get) {
|
||||||
objectDefineProperty(
|
objectDefineProperty(
|
||||||
mock,
|
mock,
|
||||||
key.toJS,
|
key.toJS,
|
||||||
js_util.jsify(
|
<String, JSFunction>{
|
||||||
<String, Object>{
|
'get': (() => get()).toJS,
|
||||||
'get': () { return get(); }.toJS
|
}.jsify()!,
|
||||||
}
|
);
|
||||||
) as JSAny);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JS()
|
@JS()
|
||||||
@ -51,13 +45,12 @@ class TestHttpRequest {
|
|||||||
);
|
);
|
||||||
// TODO(srujzs): This is needed for when we reify JS types. Right now, JSAny
|
// TODO(srujzs): This is needed for when we reify JS types. Right now, JSAny
|
||||||
// is a typedef for Object?, but when we reify, it'll be its own type.
|
// is a typedef for Object?, but when we reify, it'll be its own type.
|
||||||
// ignore: unnecessary_cast
|
|
||||||
final JSAny mock = _mock as JSAny;
|
final JSAny mock = _mock as JSAny;
|
||||||
createGetter(mock, 'headers', () => js_util.jsify(headers) as JSAny);
|
createGetter(mock, 'headers', () => headers.jsify());
|
||||||
createGetter(mock,
|
createGetter(mock,
|
||||||
'responseHeaders', () => js_util.jsify(responseHeaders) as JSAny);
|
'responseHeaders', () => responseHeaders.jsify());
|
||||||
createGetter(mock, 'status', () => status.toJS);
|
createGetter(mock, 'status', () => status.toJS);
|
||||||
createGetter(mock, 'response', () => js_util.jsify(response) as JSAny);
|
createGetter(mock, 'response', () => response.jsify());
|
||||||
}
|
}
|
||||||
|
|
||||||
late DomXMLHttpRequestMock _mock;
|
late DomXMLHttpRequestMock _mock;
|
||||||
|
@ -5,20 +5,36 @@
|
|||||||
@TestOn('browser') // This file contains web-only library.
|
@TestOn('browser') // This file contains web-only library.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
import 'dart:html' as html;
|
import 'dart:js_interop';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
|
|
||||||
|
extension on JSString {
|
||||||
|
external JSBoolean includes(JSString searchString);
|
||||||
|
}
|
||||||
|
extension on web.HTMLCollection {
|
||||||
|
Iterable<web.Element> get iterable => _genIterable(length, (JSNumber i) => item(i));
|
||||||
|
}
|
||||||
|
extension on web.CSSRuleList {
|
||||||
|
Iterable<web.CSSRule> get iterable => _genIterable(length, (JSNumber i) => item(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ItemGetter<T> = T? Function(JSNumber index);
|
||||||
|
Iterable<T> _genIterable<T>(JSNumber length, ItemGetter<T> getItem) {
|
||||||
|
return Iterable<T>.generate(length.toDart.toInt(), (int index) => getItem(index.toJS)!);
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
html.Element? element;
|
web.HTMLElement? element;
|
||||||
PlatformSelectableRegionContextMenu.debugOverrideRegisterViewFactory = (String viewType, Object Function(int viewId) fn, {bool isVisible = true}) {
|
PlatformSelectableRegionContextMenu.debugOverrideRegisterViewFactory = (String viewType, Object Function(int viewId) fn, {bool isVisible = true}) {
|
||||||
element = fn(0) as html.Element;
|
element = fn(0) as web.HTMLElement;
|
||||||
// The element needs to be attached to the document body to receive mouse
|
// The element needs to be attached to the document body to receive mouse
|
||||||
// events.
|
// events.
|
||||||
html.document.body!.append(element!);
|
web.document.body!.append(element);
|
||||||
};
|
};
|
||||||
// This force register the dom element.
|
// This force register the dom element.
|
||||||
PlatformSelectableRegionContextMenu(child: const Placeholder());
|
PlatformSelectableRegionContextMenu(child: const Placeholder());
|
||||||
@ -26,19 +42,24 @@ void main() {
|
|||||||
|
|
||||||
test('DOM element is set up correctly', () async {
|
test('DOM element is set up correctly', () async {
|
||||||
expect(element, isNotNull);
|
expect(element, isNotNull);
|
||||||
expect(element!.style.width, '100%');
|
expect(element!.style.width, '100%'.toJS);
|
||||||
expect(element!.style.height, '100%');
|
expect(element!.style.height, '100%'.toJS);
|
||||||
expect(element!.classes.length, 1);
|
expect(element!.classList.length, 1.toJS);
|
||||||
final String className = element!.classes.first;
|
final JSString className = element!.className;
|
||||||
|
|
||||||
expect(html.document.head!.children, isNotEmpty);
|
expect(web.document.head!.children.iterable, isNotEmpty);
|
||||||
bool foundStyle = false;
|
bool foundStyle = false;
|
||||||
for (final html.Element element in html.document.head!.children) {
|
for (final web.Element element in web.document.head!.children.iterable) {
|
||||||
if (element is! html.StyleElement) {
|
if (element.tagName != 'STYLE'.toJS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final html.CssStyleSheet sheet = element.sheet! as html.CssStyleSheet;
|
final web.CSSRuleList? rules = (element as web.HTMLStyleElement).sheet?.rules;
|
||||||
foundStyle = sheet.rules!.any((html.CssRule rule) => rule.cssText!.contains(className));
|
if (rules != null) {
|
||||||
|
foundStyle = rules.iterable.any((web.CSSRule rule) => rule.cssText.includes(className).toDart);
|
||||||
|
}
|
||||||
|
if (foundStyle) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expect(foundStyle, isTrue);
|
expect(foundStyle, isTrue);
|
||||||
});
|
});
|
||||||
@ -62,11 +83,13 @@ void main() {
|
|||||||
|
|
||||||
// Dispatch right click.
|
// Dispatch right click.
|
||||||
element!.dispatchEvent(
|
element!.dispatchEvent(
|
||||||
html.MouseEvent(
|
web.MouseEvent(
|
||||||
'mousedown',
|
'mousedown'.toJS,
|
||||||
button: 2,
|
web.MouseEventInit(
|
||||||
clientX: 200,
|
button: 2.toJS,
|
||||||
clientY: 300,
|
clientX: 200.toJS,
|
||||||
|
clientY: 300.toJS,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final RenderSelectionSpy renderSelectionSpy = tester.renderObject<RenderSelectionSpy>(find.byKey(spy));
|
final RenderSelectionSpy renderSelectionSpy = tester.renderObject<RenderSelectionSpy>(find.byKey(spy));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user