mirror of
https://github.com/flutter/packages.git
synced 2025-07-01 07:08:10 +08:00
[google_maps_flutter_web] Migrate to package:web (#5254)
This PR migrates `google_maps_flutter_web` from `dart:html` to `package:web`. The `google_maps` package does provide a beta version with support for `package:web`, which is currently what this PR is depending on. Before landing this change, we should change the dependency to the stable release version of that package. Fixes https://github.com/flutter/flutter/issues/137374 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* N/A
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
## NEXT
|
## 0.5.5
|
||||||
|
|
||||||
* Updates minimum supported SDK version to Flutter 3.13/Dart 3.1.
|
* Migrates to `dart:js_interop` and `package:web` APIs.
|
||||||
|
* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3.
|
||||||
|
|
||||||
## 0.5.4+3
|
## 0.5.4+3
|
||||||
|
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:html' as html;
|
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:google_maps/google_maps.dart' as gmaps;
|
import 'package:google_maps/google_maps.dart' as gmaps;
|
||||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:google_maps_flutter_web/src/utils.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
import 'package:mockito/annotations.dart';
|
import 'package:mockito/annotations.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
@ -230,7 +231,7 @@ void main() {
|
|||||||
polygons = MockPolygonsController();
|
polygons = MockPolygonsController();
|
||||||
polylines = MockPolylinesController();
|
polylines = MockPolylinesController();
|
||||||
tileOverlays = MockTileOverlaysController();
|
tileOverlays = MockTileOverlaysController();
|
||||||
map = gmaps.GMap(html.DivElement());
|
map = gmaps.GMap(createDivElement());
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('listens to map events', (WidgetTester tester) async {
|
testWidgets('listens to map events', (WidgetTester tester) async {
|
||||||
@ -471,7 +472,7 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
map = gmaps.GMap(
|
map = gmaps.GMap(
|
||||||
html.DivElement(),
|
createDivElement(),
|
||||||
gmaps.MapOptions()
|
gmaps.MapOptions()
|
||||||
..zoom = 10
|
..zoom = 10
|
||||||
..center = gmaps.LatLng(0, 0),
|
..center = gmaps.LatLng(0, 0),
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:html' as html;
|
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:google_maps/google_maps.dart' as gmaps;
|
import 'package:google_maps/google_maps.dart' as gmaps;
|
||||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:google_maps_flutter_web/src/utils.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
/// Test Markers
|
/// Test Markers
|
||||||
@ -123,7 +124,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('showInfoWindow', (WidgetTester tester) async {
|
testWidgets('showInfoWindow', (WidgetTester tester) async {
|
||||||
final gmaps.InfoWindow infoWindow = gmaps.InfoWindow();
|
final gmaps.InfoWindow infoWindow = gmaps.InfoWindow();
|
||||||
final gmaps.GMap map = gmaps.GMap(html.DivElement());
|
final gmaps.GMap map = gmaps.GMap(createDivElement());
|
||||||
marker.set('map', map);
|
marker.set('map', map);
|
||||||
final MarkerController controller = MarkerController(
|
final MarkerController controller = MarkerController(
|
||||||
marker: marker,
|
marker: marker,
|
||||||
@ -138,7 +139,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('hideInfoWindow', (WidgetTester tester) async {
|
testWidgets('hideInfoWindow', (WidgetTester tester) async {
|
||||||
final gmaps.InfoWindow infoWindow = gmaps.InfoWindow();
|
final gmaps.InfoWindow infoWindow = gmaps.InfoWindow();
|
||||||
final gmaps.GMap map = gmaps.GMap(html.DivElement());
|
final gmaps.GMap map = gmaps.GMap(createDivElement());
|
||||||
marker.set('map', map);
|
marker.set('map', map);
|
||||||
final MarkerController controller = MarkerController(
|
final MarkerController controller = MarkerController(
|
||||||
marker: marker,
|
marker: marker,
|
||||||
@ -156,7 +157,7 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
final gmaps.InfoWindow infoWindow = gmaps.InfoWindow();
|
final gmaps.InfoWindow infoWindow = gmaps.InfoWindow();
|
||||||
final gmaps.GMap map = gmaps.GMap(html.DivElement());
|
final gmaps.GMap map = gmaps.GMap(createDivElement());
|
||||||
marker.set('map', map);
|
marker.set('map', map);
|
||||||
controller = MarkerController(marker: marker, infoWindow: infoWindow);
|
controller = MarkerController(marker: marker, infoWindow: infoWindow);
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:html' as html;
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
@ -12,8 +11,11 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'package:google_maps/google_maps.dart' as gmaps;
|
import 'package:google_maps/google_maps.dart' as gmaps;
|
||||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:google_maps_flutter_web/src/utils.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:web/web.dart';
|
||||||
|
|
||||||
import 'resources/icon_image_base64.dart';
|
import 'resources/icon_image_base64.dart';
|
||||||
|
|
||||||
@ -28,7 +30,7 @@ void main() {
|
|||||||
setUp(() {
|
setUp(() {
|
||||||
events = StreamController<MapEvent<Object?>>();
|
events = StreamController<MapEvent<Object?>>();
|
||||||
controller = MarkersController(stream: events);
|
controller = MarkersController(stream: events);
|
||||||
map = gmaps.GMap(html.DivElement());
|
map = gmaps.GMap(createDivElement());
|
||||||
controller.bindToMap(123, map);
|
controller.bindToMap(123, map);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -274,11 +276,11 @@ void main() {
|
|||||||
controller.addMarkers(markers);
|
controller.addMarkers(markers);
|
||||||
|
|
||||||
expect(controller.markers.length, 1);
|
expect(controller.markers.length, 1);
|
||||||
final html.HtmlElement? content = controller.markers[const MarkerId('1')]
|
final HTMLElement? content = controller
|
||||||
?.infoWindow?.content as html.HtmlElement?;
|
.markers[const MarkerId('1')]?.infoWindow?.content as HTMLElement?;
|
||||||
expect(content?.innerHtml, contains('title for test'));
|
expect(content?.innerHTML, contains('title for test'));
|
||||||
expect(
|
expect(
|
||||||
content?.innerHtml,
|
content?.innerHTML,
|
||||||
contains(
|
contains(
|
||||||
'<a href="https://www.google.com">Go to Google >>></a>',
|
'<a href="https://www.google.com">Go to Google >>></a>',
|
||||||
));
|
));
|
||||||
@ -299,8 +301,8 @@ void main() {
|
|||||||
controller.addMarkers(markers);
|
controller.addMarkers(markers);
|
||||||
|
|
||||||
expect(controller.markers.length, 1);
|
expect(controller.markers.length, 1);
|
||||||
final html.HtmlElement? content = controller.markers[const MarkerId('1')]
|
final HTMLElement? content = controller
|
||||||
?.infoWindow?.content as html.HtmlElement?;
|
.markers[const MarkerId('1')]?.infoWindow?.content as HTMLElement?;
|
||||||
|
|
||||||
content?.click();
|
content?.click();
|
||||||
|
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:html' as html;
|
import 'dart:js_interop';
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:google_maps/google_maps.dart' as gmaps;
|
import 'package:google_maps/google_maps.dart' as gmaps;
|
||||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:web/web.dart';
|
||||||
|
|
||||||
import 'resources/tile16_base64.dart';
|
import 'resources/tile16_base64.dart';
|
||||||
|
|
||||||
@ -43,8 +44,10 @@ void main() {
|
|||||||
final gmaps.Size size = controller.gmMapType.tileSize!;
|
final gmaps.Size size = controller.gmMapType.tileSize!;
|
||||||
expect(size.width, TileOverlayController.logicalTileSize);
|
expect(size.width, TileOverlayController.logicalTileSize);
|
||||||
expect(size.height, TileOverlayController.logicalTileSize);
|
expect(size.height, TileOverlayController.logicalTileSize);
|
||||||
expect(controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, html.document),
|
expect(
|
||||||
null);
|
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, document),
|
||||||
|
null,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('produces image tiles', (WidgetTester tester) async {
|
testWidgets('produces image tiles', (WidgetTester tester) async {
|
||||||
@ -55,16 +58,16 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final html.ImageElement img =
|
final HTMLImageElement img =
|
||||||
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, html.document)!
|
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, document)!
|
||||||
as html.ImageElement;
|
as HTMLImageElement;
|
||||||
expect(img.naturalWidth, 0);
|
expect(img.naturalWidth, 0);
|
||||||
expect(img.naturalHeight, 0);
|
expect(img.naturalHeight, 0);
|
||||||
expect(img.hidden, true);
|
expect(img.hidden, true);
|
||||||
|
|
||||||
// Wait until the image is fully loaded and decoded before re-reading its attributes.
|
|
||||||
await img.onLoad.first;
|
await img.onLoad.first;
|
||||||
await img.decode();
|
|
||||||
|
await img.decode().toDart;
|
||||||
|
|
||||||
expect(img.hidden, false);
|
expect(img.hidden, false);
|
||||||
expect(img.naturalWidth, 16);
|
expect(img.naturalWidth, 16);
|
||||||
@ -79,9 +82,9 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
{
|
{
|
||||||
final html.ImageElement img =
|
final HTMLImageElement img =
|
||||||
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, html.document)!
|
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, document)!
|
||||||
as html.ImageElement;
|
as HTMLImageElement;
|
||||||
await null; // let `getTile` `then` complete
|
await null; // let `getTile` `then` complete
|
||||||
expect(
|
expect(
|
||||||
img.src,
|
img.src,
|
||||||
@ -95,10 +98,12 @@ void main() {
|
|||||||
tileProvider: TestTileProvider(),
|
tileProvider: TestTileProvider(),
|
||||||
));
|
));
|
||||||
{
|
{
|
||||||
final html.ImageElement img =
|
final HTMLImageElement img =
|
||||||
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, html.document)!
|
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, document)!
|
||||||
as html.ImageElement;
|
as HTMLImageElement;
|
||||||
|
|
||||||
await img.onLoad.first;
|
await img.onLoad.first;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
img.src,
|
img.src,
|
||||||
isNotEmpty,
|
isNotEmpty,
|
||||||
@ -109,7 +114,7 @@ void main() {
|
|||||||
controller.update(const TileOverlay(tileOverlayId: id));
|
controller.update(const TileOverlay(tileOverlayId: id));
|
||||||
{
|
{
|
||||||
expect(
|
expect(
|
||||||
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, html.document),
|
controller.gmMapType.getTile!(gmaps.Point(0, 0), 0, document),
|
||||||
null,
|
null,
|
||||||
reason: 'Setting a null tileProvider should work.',
|
reason: 'Setting a null tileProvider should work.',
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:html' as html;
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
@ -11,9 +10,12 @@ import 'package:google_maps/google_maps.dart' as gmaps;
|
|||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'
|
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart'
|
||||||
hide GoogleMapController;
|
hide GoogleMapController;
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:google_maps_flutter_web/src/utils.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
import 'package:mockito/annotations.dart';
|
import 'package:mockito/annotations.dart';
|
||||||
import 'package:mockito/mockito.dart';
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:web/web.dart';
|
||||||
|
|
||||||
@GenerateNiceMocks(<MockSpec<dynamic>>[MockSpec<TileProvider>()])
|
@GenerateNiceMocks(<MockSpec<dynamic>>[MockSpec<TileProvider>()])
|
||||||
import 'overlays_test.mocks.dart';
|
import 'overlays_test.mocks.dart';
|
||||||
@ -38,13 +40,13 @@ void main() {
|
|||||||
/// 0.
|
/// 0.
|
||||||
void probeTiles() {
|
void probeTiles() {
|
||||||
for (final gmaps.MapType? mapType in map.overlayMapTypes!.array!) {
|
for (final gmaps.MapType? mapType in map.overlayMapTypes!.array!) {
|
||||||
mapType?.getTile!(gmaps.Point(0, 0), 0, html.document);
|
mapType?.getTile!(gmaps.Point(0, 0), 0, document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
controller = TileOverlaysController();
|
controller = TileOverlaysController();
|
||||||
map = gmaps.GMap(html.DivElement());
|
map = gmaps.GMap(createDivElement());
|
||||||
controller.googleMap = map;
|
controller.googleMap = map;
|
||||||
|
|
||||||
tileProviders = <MockTileProvider>[
|
tileProviders = <MockTileProvider>[
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:html' as html;
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
@ -11,6 +10,8 @@ import 'package:google_maps/google_maps.dart' as gmaps;
|
|||||||
import 'package:google_maps/google_maps_geometry.dart' as geometry;
|
import 'package:google_maps/google_maps_geometry.dart' as geometry;
|
||||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||||
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
import 'package:google_maps_flutter_web/google_maps_flutter_web.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:google_maps_flutter_web/src/utils.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
// This value is used when comparing the results of
|
// This value is used when comparing the results of
|
||||||
@ -25,7 +26,7 @@ void main() {
|
|||||||
late gmaps.GMap map;
|
late gmaps.GMap map;
|
||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
map = gmaps.GMap(html.DivElement());
|
map = gmaps.GMap(createDivElement());
|
||||||
});
|
});
|
||||||
|
|
||||||
group('CirclesController', () {
|
group('CirclesController', () {
|
||||||
|
@ -20,6 +20,9 @@ class MyApp extends StatefulWidget {
|
|||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return const Text('Testing... Look at the console output for results!');
|
return const Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Text('Testing... Look at the console output for results!'),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ publish_to: none
|
|||||||
|
|
||||||
# Tests require flutter beta or greater to run.
|
# Tests require flutter beta or greater to run.
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.1.0
|
sdk: ^3.3.0
|
||||||
flutter: ">=3.13.0"
|
flutter: ">=3.19.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
@ -12,12 +12,13 @@ dependencies:
|
|||||||
google_maps_flutter_platform_interface: ^2.4.0
|
google_maps_flutter_platform_interface: ^2.4.0
|
||||||
google_maps_flutter_web:
|
google_maps_flutter_web:
|
||||||
path: ../
|
path: ../
|
||||||
|
web: ^0.5.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.1.1
|
build_runner: ^2.1.1
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
google_maps: ^6.1.0
|
google_maps: ^7.1.0
|
||||||
google_maps_flutter: ^2.2.0 # Needed for projection_test.dart
|
google_maps_flutter: ^2.2.0 # Needed for projection_test.dart
|
||||||
http: ">=0.13.0 <2.0.0"
|
http: ">=0.13.0 <2.0.0"
|
||||||
integration_test:
|
integration_test:
|
||||||
|
@ -6,8 +6,7 @@ library google_maps_flutter_web;
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:html' hide VoidCallback;
|
import 'dart:js_interop';
|
||||||
import 'dart:js_util';
|
|
||||||
import 'dart:ui_web' as ui_web;
|
import 'dart:ui_web' as ui_web;
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
@ -20,10 +19,14 @@ import 'package:google_maps/google_maps.dart' as gmaps;
|
|||||||
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart';
|
||||||
import 'package:sanitize_html/sanitize_html.dart';
|
import 'package:sanitize_html/sanitize_html.dart';
|
||||||
import 'package:stream_transform/stream_transform.dart';
|
import 'package:stream_transform/stream_transform.dart';
|
||||||
|
import 'package:web/web.dart';
|
||||||
|
|
||||||
|
import 'src/dom_window_extension.dart';
|
||||||
import 'src/google_maps_inspector_web.dart';
|
import 'src/google_maps_inspector_web.dart';
|
||||||
|
import 'src/map_styler.dart';
|
||||||
import 'src/third_party/to_screen_location/to_screen_location.dart';
|
import 'src/third_party/to_screen_location/to_screen_location.dart';
|
||||||
import 'src/types.dart';
|
import 'src/types.dart';
|
||||||
|
import 'src/utils.dart';
|
||||||
|
|
||||||
part 'src/circle.dart';
|
part 'src/circle.dart';
|
||||||
part 'src/circles.dart';
|
part 'src/circles.dart';
|
||||||
|
@ -28,7 +28,7 @@ double _getCssOpacity(Color color) {
|
|||||||
// mapToolbarEnabled is unused in web, there's no "map toolbar"
|
// mapToolbarEnabled is unused in web, there's no "map toolbar"
|
||||||
// myLocationButtonEnabled Widget not available in web yet, it needs to be built on top of the maps widget
|
// myLocationButtonEnabled Widget not available in web yet, it needs to be built on top of the maps widget
|
||||||
// See: https://developers.google.com/maps/documentation/javascript/examples/control-custom
|
// See: https://developers.google.com/maps/documentation/javascript/examples/control-custom
|
||||||
// myLocationEnabled needs to be built through dart:html navigator.geolocation
|
// myLocationEnabled needs to be built through `navigator.geolocation` from package:web.
|
||||||
// See: https://api.dart.dev/stable/2.8.4/dart-html/Geolocation-class.html
|
// See: https://api.dart.dev/stable/2.8.4/dart-html/Geolocation-class.html
|
||||||
// trafficEnabled is handled when creating the GMap object, since it needs to be added as a layer.
|
// trafficEnabled is handled when creating the GMap object, since it needs to be added as a layer.
|
||||||
// trackCameraPosition is just a boolean value that indicates if the map has an onCameraMove handler.
|
// trackCameraPosition is just a boolean value that indicates if the map has an onCameraMove handler.
|
||||||
@ -139,10 +139,11 @@ List<gmaps.MapTypeStyle> _mapStyles(String? mapStyleJson) {
|
|||||||
styles =
|
styles =
|
||||||
(json.decode(mapStyleJson, reviver: (Object? key, Object? value) {
|
(json.decode(mapStyleJson, reviver: (Object? key, Object? value) {
|
||||||
if (value is Map && _isJsonMapStyle(value as Map<String, Object?>)) {
|
if (value is Map && _isJsonMapStyle(value as Map<String, Object?>)) {
|
||||||
List<Object?> stylers = <Object?>[];
|
List<MapStyler> stylers = <MapStyler>[];
|
||||||
if (value['stylers'] != null) {
|
if (value['stylers'] != null) {
|
||||||
stylers = (value['stylers']! as List<Object?>)
|
stylers = (value['stylers']! as List<Object?>)
|
||||||
.map<Object?>((Object? e) => e != null ? jsify(e) : null)
|
.whereType<Map<String, Object?>>()
|
||||||
|
.map(MapStyler.fromJson)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
return gmaps.MapTypeStyle()
|
return gmaps.MapTypeStyle()
|
||||||
@ -203,30 +204,44 @@ gmaps.InfoWindowOptions? _infoWindowOptionsFromMarker(Marker marker) {
|
|||||||
|
|
||||||
// Add an outer wrapper to the contents of the infowindow, we need it to listen
|
// Add an outer wrapper to the contents of the infowindow, we need it to listen
|
||||||
// to click events...
|
// to click events...
|
||||||
final HtmlElement container = DivElement()
|
final HTMLElement container = createDivElement()
|
||||||
..id = 'gmaps-marker-${marker.markerId.value}-infowindow';
|
..id = 'gmaps-marker-${marker.markerId.value}-infowindow';
|
||||||
|
|
||||||
if (markerTitle.isNotEmpty) {
|
if (markerTitle.isNotEmpty) {
|
||||||
final HtmlElement title = HeadingElement.h3()
|
final HTMLHeadingElement title =
|
||||||
..className = 'infowindow-title'
|
(document.createElement('h3') as HTMLHeadingElement)
|
||||||
..innerText = markerTitle;
|
..className = 'infowindow-title'
|
||||||
container.children.add(title);
|
..innerText = markerTitle;
|
||||||
|
container.appendChild(title);
|
||||||
}
|
}
|
||||||
if (markerSnippet.isNotEmpty) {
|
if (markerSnippet.isNotEmpty) {
|
||||||
final HtmlElement snippet = DivElement()
|
final HTMLElement snippet = createDivElement()
|
||||||
..className = 'infowindow-snippet'
|
..className = 'infowindow-snippet';
|
||||||
|
|
||||||
|
// Firefox and Safari don't support Trusted Types yet.
|
||||||
|
// See https://developer.mozilla.org/en-US/docs/Web/API/TrustedTypePolicyFactory#browser_compatibility
|
||||||
|
if (window.nullableTrustedTypes != null) {
|
||||||
|
final GoogleMapsTrustedTypePolicy trustedTypePolicy =
|
||||||
|
window.nullableTrustedTypes!.getGoogleMapsTrustedTypesPolicy(
|
||||||
|
GoogleMapsTrustedTypePolicyOptions(
|
||||||
|
createHTML: (String html, JSAny? arguments) {
|
||||||
|
return sanitizeHtml(html);
|
||||||
|
}.toJS,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
snippet.trustedInnerHTML =
|
||||||
|
trustedTypePolicy.createHTML(markerSnippet, null);
|
||||||
|
} else {
|
||||||
// `sanitizeHtml` is used to clean the (potential) user input from (potential)
|
// `sanitizeHtml` is used to clean the (potential) user input from (potential)
|
||||||
// XSS attacks through the contents of the marker InfoWindow.
|
// XSS attacks through the contents of the marker InfoWindow.
|
||||||
// See: https://pub.dev/documentation/sanitize_html/latest/sanitize_html/sanitizeHtml.html
|
// See: https://pub.dev/documentation/sanitize_html/latest/sanitize_html/sanitizeHtml.html
|
||||||
// See: b/159137885, b/159598165
|
// See: b/159137885, b/159598165
|
||||||
// The NodeTreeSanitizer.trusted just tells setInnerHtml to leave the output
|
|
||||||
// of `sanitizeHtml` untouched.
|
|
||||||
// ignore: unsafe_html
|
// ignore: unsafe_html
|
||||||
..setInnerHtml(
|
snippet.innerHTML = sanitizeHtml(markerSnippet);
|
||||||
sanitizeHtml(markerSnippet),
|
}
|
||||||
treeSanitizer: NodeTreeSanitizer.trusted,
|
|
||||||
);
|
container.appendChild(snippet);
|
||||||
container.children.add(snippet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return gmaps.InfoWindowOptions()
|
return gmaps.InfoWindowOptions()
|
||||||
@ -274,8 +289,18 @@ gmaps.Icon? _gmIconFromBitmapDescriptor(BitmapDescriptor bitmapDescriptor) {
|
|||||||
// Grab the bytes, and put them into a blob
|
// Grab the bytes, and put them into a blob
|
||||||
final List<int> bytes = iconConfig[1]! as List<int>;
|
final List<int> bytes = iconConfig[1]! as List<int>;
|
||||||
// Create a Blob from bytes, but let the browser figure out the encoding
|
// Create a Blob from bytes, but let the browser figure out the encoding
|
||||||
final Blob blob = Blob(<dynamic>[bytes]);
|
final Blob blob;
|
||||||
icon = gmaps.Icon()..url = Url.createObjectUrlFromBlob(blob);
|
|
||||||
|
assert(
|
||||||
|
bytes is Uint8List,
|
||||||
|
'The bytes for a BitmapDescriptor icon must be a Uint8List',
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO(ditman): Improve this conversion
|
||||||
|
// See https://github.com/dart-lang/web/issues/180
|
||||||
|
blob = Blob(<JSUint8Array>[(bytes as Uint8List).toJS].toJS);
|
||||||
|
|
||||||
|
icon = gmaps.Icon()..url = URL.createObjectURL(blob as JSObject);
|
||||||
|
|
||||||
final gmaps.Size? size = _gmSizeFromIconConfig(iconConfig, 2);
|
final gmaps.Size? size = _gmSizeFromIconConfig(iconConfig, 2);
|
||||||
if (size != null) {
|
if (size != null) {
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:js_interop';
|
||||||
|
|
||||||
|
import 'package:web/web.dart' as web;
|
||||||
|
|
||||||
|
/// This extension gives [web.Window] a nullable getter to the `trustedTypes`
|
||||||
|
/// property, which is used to check for feature support.
|
||||||
|
extension NullableTrustedTypesGetter on web.Window {
|
||||||
|
/// (Nullable) Bindings to window.trustedTypes.
|
||||||
|
///
|
||||||
|
/// This may be null if the browser doesn't support the Trusted Types API.
|
||||||
|
///
|
||||||
|
/// See: https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API
|
||||||
|
@JS('trustedTypes')
|
||||||
|
external GoogleMapsTrustedTypePolicyFactory? get nullableTrustedTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ditman): remove this extension type when we depend on package:web 0.5.1
|
||||||
|
/// This extension exists as a stop gap until `package:web 0.5.1` is released.
|
||||||
|
/// That version provides the `TrustedTypes` API.
|
||||||
|
@JS('TrustedTypePolicyFactory')
|
||||||
|
extension type GoogleMapsTrustedTypePolicyFactory._(JSObject _)
|
||||||
|
implements JSObject {
|
||||||
|
/// The `TrustedTypePolicy` for Google Maps Flutter.
|
||||||
|
static GoogleMapsTrustedTypePolicy? _policy;
|
||||||
|
|
||||||
|
@JS('createPolicy')
|
||||||
|
external GoogleMapsTrustedTypePolicy _createPolicy(
|
||||||
|
String policyName, [
|
||||||
|
GoogleMapsTrustedTypePolicyOptions policyOptions,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/// Get a new [GoogleMapsTrustedTypePolicy].
|
||||||
|
///
|
||||||
|
/// If a policy already exists, it will be returned.
|
||||||
|
/// Otherwise, a new policy is created.
|
||||||
|
///
|
||||||
|
/// Because of we only cache one _policy, this method
|
||||||
|
/// specifically hardcoded to the GoogleMaps use case.
|
||||||
|
GoogleMapsTrustedTypePolicy getGoogleMapsTrustedTypesPolicy(
|
||||||
|
GoogleMapsTrustedTypePolicyOptions policyOptions,
|
||||||
|
) {
|
||||||
|
const String policyName = 'google_maps_flutter_sanitize';
|
||||||
|
_policy ??= _createPolicy(policyName, policyOptions);
|
||||||
|
|
||||||
|
return _policy!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ditman): remove this extension type when we depend on package:web 0.5.1
|
||||||
|
/// This extension exists as a stop gap until `package:web 0.5.1` is released.
|
||||||
|
/// That version provides the `TrustedTypes` API.
|
||||||
|
@JS('TrustedTypePolicy')
|
||||||
|
extension type GoogleMapsTrustedTypePolicy._(JSObject _) implements JSObject {
|
||||||
|
/// Create a new `TrustedHTML` instance with the given [input] and [arguments].
|
||||||
|
external GoogleMapsTrustedHTML createHTML(
|
||||||
|
String input,
|
||||||
|
JSAny? arguments,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ditman): remove this extension type when we depend on package:web 0.5.1
|
||||||
|
/// This extension exists as a stop gap until `package:web 0.5.1` is released.
|
||||||
|
/// That version provides the `TrustedTypes` API.
|
||||||
|
@JS('TrustedTypePolicyOptions')
|
||||||
|
extension type GoogleMapsTrustedTypePolicyOptions._(JSObject _)
|
||||||
|
implements JSObject {
|
||||||
|
/// Create a new `TrustedTypePolicyOptions` instance.
|
||||||
|
external factory GoogleMapsTrustedTypePolicyOptions({
|
||||||
|
JSFunction createHTML,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ditman): remove this extension type when we depend on package:web 0.5.1
|
||||||
|
/// This extension exists as a stop gap until `package:web 0.5.1` is released.
|
||||||
|
/// That version provides the `TrustedTypes` API.
|
||||||
|
@JS('TrustedHTML')
|
||||||
|
extension type GoogleMapsTrustedHTML._(JSObject _) implements JSObject {}
|
||||||
|
|
||||||
|
/// This extension provides a setter for the [web.HTMLElement] `innerHTML` property,
|
||||||
|
/// that accepts trusted HTML only.
|
||||||
|
extension TrustedInnerHTML on web.HTMLElement {
|
||||||
|
/// Set the inner HTML of this element to the given [trustedHTML].
|
||||||
|
@JS('innerHTML')
|
||||||
|
external set trustedInnerHTML(GoogleMapsTrustedHTML trustedHTML);
|
||||||
|
}
|
@ -7,7 +7,7 @@ part of '../google_maps_flutter_web.dart';
|
|||||||
/// Type used when passing an override to the _createMap function.
|
/// Type used when passing an override to the _createMap function.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
typedef DebugCreateMapFunction = gmaps.GMap Function(
|
typedef DebugCreateMapFunction = gmaps.GMap Function(
|
||||||
HtmlElement div, gmaps.MapOptions options);
|
HTMLElement div, gmaps.MapOptions options);
|
||||||
|
|
||||||
/// Encapsulates a [gmaps.GMap], its events, and where in the DOM it's rendered.
|
/// Encapsulates a [gmaps.GMap], its events, and where in the DOM it's rendered.
|
||||||
class GoogleMapController {
|
class GoogleMapController {
|
||||||
@ -36,7 +36,7 @@ class GoogleMapController {
|
|||||||
// Register the view factory that will hold the `_div` that holds the map in the DOM.
|
// Register the view factory that will hold the `_div` that holds the map in the DOM.
|
||||||
// The `_div` needs to be created outside of the ViewFactory (and cached!) so we can
|
// The `_div` needs to be created outside of the ViewFactory (and cached!) so we can
|
||||||
// use it to create the [gmaps.GMap] in the `init()` method of this class.
|
// use it to create the [gmaps.GMap] in the `init()` method of this class.
|
||||||
_div = DivElement()
|
_div = createDivElement()
|
||||||
..id = _getViewType(mapId)
|
..id = _getViewType(mapId)
|
||||||
..style.width = '100%'
|
..style.width = '100%'
|
||||||
..style.height = '100%';
|
..style.height = '100%';
|
||||||
@ -74,7 +74,7 @@ class GoogleMapController {
|
|||||||
|
|
||||||
// The Flutter widget that contains the rendered Map.
|
// The Flutter widget that contains the rendered Map.
|
||||||
HtmlElementView? _widget;
|
HtmlElementView? _widget;
|
||||||
late HtmlElement _div;
|
late HTMLElement _div;
|
||||||
|
|
||||||
/// The Flutter widget that will contain the rendered Map. Used for caching.
|
/// The Flutter widget that will contain the rendered Map. Used for caching.
|
||||||
Widget? get widget {
|
Widget? get widget {
|
||||||
@ -138,7 +138,7 @@ class GoogleMapController {
|
|||||||
|
|
||||||
DebugCreateMapFunction? _overrideCreateMap;
|
DebugCreateMapFunction? _overrideCreateMap;
|
||||||
|
|
||||||
gmaps.GMap _createMap(HtmlElement div, gmaps.MapOptions options) {
|
gmaps.GMap _createMap(HTMLElement div, gmaps.MapOptions options) {
|
||||||
if (_overrideCreateMap != null) {
|
if (_overrideCreateMap != null) {
|
||||||
return _overrideCreateMap!(div, options);
|
return _overrideCreateMap!(div, options);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:js_interop';
|
||||||
|
|
||||||
|
/// The interop type for a Google Maps Map Styler.
|
||||||
|
///
|
||||||
|
/// See: https://developers.google.com/maps/documentation/javascript/style-reference#stylers
|
||||||
|
@JS()
|
||||||
|
@staticInterop
|
||||||
|
@anonymous
|
||||||
|
extension type MapStyler._(JSObject _) implements JSObject {
|
||||||
|
/// Create a new [MapStyler] instance.
|
||||||
|
external factory MapStyler({
|
||||||
|
String? hue,
|
||||||
|
num? lightness,
|
||||||
|
num? saturation,
|
||||||
|
num? gamma,
|
||||||
|
// ignore: non_constant_identifier_names
|
||||||
|
bool? invert_lightness,
|
||||||
|
String? visibility,
|
||||||
|
String? color,
|
||||||
|
int? weight,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Create a new [MapStyler] instance from the given [json].
|
||||||
|
factory MapStyler.fromJson(Map<String, Object?> json) {
|
||||||
|
return MapStyler(
|
||||||
|
hue: json['hue'] as String?,
|
||||||
|
lightness: json['lightness'] as num?,
|
||||||
|
saturation: json['saturation'] as num?,
|
||||||
|
gamma: json['gamma'] as num?,
|
||||||
|
invert_lightness: json['invert_lightness'] as bool?,
|
||||||
|
visibility: json['visibility'] as String?,
|
||||||
|
color: json['color'] as String?,
|
||||||
|
weight: json['weight'] as int?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -69,12 +69,12 @@ class MarkerController {
|
|||||||
/// This cannot be called after [remove].
|
/// This cannot be called after [remove].
|
||||||
void update(
|
void update(
|
||||||
gmaps.MarkerOptions options, {
|
gmaps.MarkerOptions options, {
|
||||||
HtmlElement? newInfoWindowContent,
|
HTMLElement? newInfoWindowContent,
|
||||||
}) {
|
}) {
|
||||||
assert(_marker != null, 'Cannot `update` Marker after calling `remove`.');
|
assert(_marker != null, 'Cannot `update` Marker after calling `remove`.');
|
||||||
_marker!.options = options;
|
_marker!.options = options;
|
||||||
if (_infoWindow != null && newInfoWindowContent != null) {
|
if (_infoWindow != null && newInfoWindowContent != null) {
|
||||||
_infoWindow!.content = newInfoWindowContent;
|
_infoWindow.content = newInfoWindowContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ class MarkerController {
|
|||||||
void hideInfoWindow() {
|
void hideInfoWindow() {
|
||||||
assert(_marker != null, 'Cannot `hideInfoWindow` on a `remove`d Marker.');
|
assert(_marker != null, 'Cannot `hideInfoWindow` on a `remove`d Marker.');
|
||||||
if (_infoWindow != null) {
|
if (_infoWindow != null) {
|
||||||
_infoWindow!.close();
|
_infoWindow.close();
|
||||||
_infoWindowShown = false;
|
_infoWindowShown = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ class MarkerController {
|
|||||||
void showInfoWindow() {
|
void showInfoWindow() {
|
||||||
assert(_marker != null, 'Cannot `showInfoWindow` on a `remove`d Marker.');
|
assert(_marker != null, 'Cannot `showInfoWindow` on a `remove`d Marker.');
|
||||||
if (_infoWindow != null) {
|
if (_infoWindow != null) {
|
||||||
_infoWindow!.open(_marker!.map, _marker);
|
_infoWindow.open(_marker!.map, _marker);
|
||||||
_infoWindowShown = true;
|
_infoWindowShown = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,12 @@ class MarkersController extends GeometryController {
|
|||||||
// Google Maps' JS SDK does not have a click event on the InfoWindow, so
|
// Google Maps' JS SDK does not have a click event on the InfoWindow, so
|
||||||
// we make one...
|
// we make one...
|
||||||
if (infoWindowOptions.content != null &&
|
if (infoWindowOptions.content != null &&
|
||||||
infoWindowOptions.content is HtmlElement) {
|
infoWindowOptions.content is HTMLElement) {
|
||||||
final HtmlElement content = infoWindowOptions.content! as HtmlElement;
|
final HTMLElement content = infoWindowOptions.content! as HTMLElement;
|
||||||
content.onClick.listen((_) {
|
|
||||||
|
content.onclick = (JSAny? _) {
|
||||||
_onInfoWindowTap(marker.markerId);
|
_onInfoWindowTap(marker.markerId);
|
||||||
});
|
}.toJS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ class MarkersController extends GeometryController {
|
|||||||
_infoWindowOptionsFromMarker(marker);
|
_infoWindowOptionsFromMarker(marker);
|
||||||
markerController.update(
|
markerController.update(
|
||||||
markerOptions,
|
markerOptions,
|
||||||
newInfoWindowContent: infoWindow?.content as HtmlElement?,
|
newInfoWindowContent: infoWindow?.content as HTMLElement?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class TileOverlayController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Renders a Tile for gmaps; delegating to the configured [TileProvider].
|
/// Renders a Tile for gmaps; delegating to the configured [TileProvider].
|
||||||
HtmlElement? _getTile(
|
HTMLElement? _getTile(
|
||||||
gmaps.Point? tileCoord,
|
gmaps.Point? tileCoord,
|
||||||
num? zoom,
|
num? zoom,
|
||||||
Document? ownerDocument,
|
Document? ownerDocument,
|
||||||
@ -42,10 +42,10 @@ class TileOverlayController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ImageElement img =
|
final HTMLImageElement img =
|
||||||
ownerDocument!.createElement('img') as ImageElement;
|
ownerDocument!.createElement('img') as HTMLImageElement;
|
||||||
img.width = img.height = logicalTileSize;
|
img.width = img.height = logicalTileSize;
|
||||||
img.hidden = true;
|
img.hidden = true.toJS;
|
||||||
img.setAttribute('decoding', 'async');
|
img.setAttribute('decoding', 'async');
|
||||||
|
|
||||||
_tileOverlay.tileProvider!
|
_tileOverlay.tileProvider!
|
||||||
@ -55,12 +55,14 @@ class TileOverlayController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Using img lets us take advantage of native decoding.
|
// Using img lets us take advantage of native decoding.
|
||||||
final String src = Url.createObjectUrl(Blob(<Object?>[tile.data]));
|
final String src = URL.createObjectURL(
|
||||||
|
Blob(<JSUint8Array>[tile.data!.toJS].toJS) as JSObject,
|
||||||
|
);
|
||||||
img.src = src;
|
img.src = src;
|
||||||
img.addEventListener('load', (_) {
|
img.onload = (JSAny? _) {
|
||||||
img.hidden = false;
|
img.hidden = false.toJS;
|
||||||
Url.revokeObjectUrl(src);
|
URL.revokeObjectURL(src);
|
||||||
});
|
}.toJS;
|
||||||
});
|
});
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:web/web.dart';
|
||||||
|
|
||||||
|
/// Convenience method to create a new [HTMLDivElement] element.
|
||||||
|
HTMLDivElement createDivElement() {
|
||||||
|
return document.createElement('div') as HTMLDivElement;
|
||||||
|
}
|
@ -2,11 +2,11 @@ name: google_maps_flutter_web
|
|||||||
description: Web platform implementation of google_maps_flutter
|
description: Web platform implementation of google_maps_flutter
|
||||||
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_web
|
repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_web
|
||||||
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
|
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22
|
||||||
version: 0.5.4+3
|
version: 0.5.5
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.1.0 <4.0.0"
|
sdk: ^3.3.0
|
||||||
flutter: ">=3.13.0"
|
flutter: ">=3.19.0"
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
plugin:
|
plugin:
|
||||||
@ -22,10 +22,11 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
google_maps: ^6.1.0
|
google_maps: ^7.1.0
|
||||||
google_maps_flutter_platform_interface: ^2.4.0
|
google_maps_flutter_platform_interface: ^2.4.0
|
||||||
sanitize_html: ^2.0.0
|
sanitize_html: ^2.0.0
|
||||||
stream_transform: ^2.0.0
|
stream_transform: ^2.0.0
|
||||||
|
web: ^0.5.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user