From d861ad98a9269958c608a95266da8c6d296a7055 Mon Sep 17 00:00:00 2001 From: Kevin Moore Date: Thu, 16 Nov 2023 16:40:15 -0800 Subject: [PATCH] [file_selector_web] migrate to pkg:web (#5413) This allows this package to be used in a web app compiled to Wasm. Helps unblock https://github.com/flutter/devtools/issues/6606 --- .../file_selector_web/CHANGELOG.md | 4 ++ .../integration_test/dom_helper_test.dart | 25 +++++++---- .../file_selector_web_test.dart | 4 +- .../file_selector_web/example/pubspec.yaml | 1 + .../file_selector_web/lib/src/dom_helper.dart | 42 ++++++++++++------- .../file_selector_web/pubspec.yaml | 7 ++-- script/configs/allowed_unpinned_deps.yaml | 1 + script/tool/lib/src/common/core.dart | 1 + 8 files changed, 55 insertions(+), 30 deletions(-) diff --git a/packages/file_selector/file_selector_web/CHANGELOG.md b/packages/file_selector/file_selector_web/CHANGELOG.md index f81c7921f0b1..7391ceb875eb 100644 --- a/packages/file_selector/file_selector_web/CHANGELOG.md +++ b/packages/file_selector/file_selector_web/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.3 + +* Updates minimum supported SDK version to Dart 3.2. + ## 0.9.2+1 * Adds pub topics to package metadata. diff --git a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart index d6cb47fe45b6..09b15c2f0d7e 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart @@ -2,23 +2,29 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:html'; +import 'dart:js_interop'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:file_selector_web/src/dom_helper.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; +import 'package:web/helpers.dart'; void main() { group('dom_helper', () { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); late DomHelper domHelper; - late FileUploadInputElement input; + late HTMLInputElement input; FileList? createFileList(List files) { final DataTransfer dataTransfer = DataTransfer(); - files.forEach(dataTransfer.items!.add); - return dataTransfer.files as FileList?; + for (final File e in files) { + // TODO(srujzs): This is necessary in order to support package:web 0.4.0. + // This was not needed with 0.3.0, hence the lint. + // ignore: unnecessary_cast + dataTransfer.items.add(e as JSAny); + } + return dataTransfer.files; } void setFilesAndTriggerEvent(List files, Event event) { @@ -36,12 +42,13 @@ void main() { setUp(() { domHelper = DomHelper(); - input = FileUploadInputElement(); + input = (createElementTag('input') as HTMLInputElement)..type = 'file'; }); group('getFiles', () { - final File mockFile1 = File(['123456'], 'file1.txt'); - final File mockFile2 = File([], 'file2.txt'); + final File mockFile1 = + File(['123456'].jsify as JSArray, 'file1.txt'); + final File mockFile2 = File([].jsify as JSArray, 'file2.txt'); testWidgets('works', (_) async { final Future> futureFiles = domHelper.getFiles( @@ -114,7 +121,7 @@ void main() { input: input, ); - expect(input.matchesWithAncestors('body'), true); + expect(input.matches('body'), true); expect(input.accept, accept); expect(input.multiple, multiple); expect( @@ -128,7 +135,7 @@ void main() { await futureFile; // It should be already removed from the DOM after the file is resolved. - expect(input.parent, isNull); + expect(input.parentElement, isNull); }); }); }); diff --git a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart index f64c08de0564..f3d4c1ebf3e7 100644 --- a/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart +++ b/packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:html'; import 'dart:typed_data'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; @@ -10,6 +9,7 @@ import 'package:file_selector_web/file_selector_web.dart'; import 'package:file_selector_web/src/dom_helper.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; +import 'package:web/helpers.dart'; void main() { group('FileSelectorWeb', () { @@ -121,7 +121,7 @@ class MockDomHelper implements DomHelper { Future> getFiles({ String accept = '', bool multiple = false, - FileUploadInputElement? input, + HTMLInputElement? input, }) { expect(accept, _expectedAccept, reason: 'Expected "accept" value does not match.'); diff --git a/packages/file_selector/file_selector_web/example/pubspec.yaml b/packages/file_selector/file_selector_web/example/pubspec.yaml index 0efe95c570c4..b5166a65d70f 100644 --- a/packages/file_selector/file_selector_web/example/pubspec.yaml +++ b/packages/file_selector/file_selector_web/example/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: path: ../ flutter: sdk: flutter + web: '>=0.3.0 <0.5.0' dev_dependencies: flutter_test: diff --git a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart index e600778b7dc7..7684a12286d7 100644 --- a/packages/file_selector/file_selector_web/lib/src/dom_helper.dart +++ b/packages/file_selector/file_selector_web/lib/src/dom_helper.dart @@ -3,41 +3,46 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:html'; +import 'dart:js_interop'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:flutter/foundation.dart' show visibleForTesting; import 'package:flutter/services.dart'; +import 'package:web/helpers.dart'; /// Class to manipulate the DOM with the intention of reading files from it. class DomHelper { /// Default constructor, initializes the container DOM element. DomHelper() { final Element body = querySelector('body')!; - body.children.add(_container); + body.appendChild(_container); } - final Element _container = Element.tag('file-selector'); + final Element _container = createElementTag('file-selector'); /// Sets the attributes and waits for a file to be selected. Future> getFiles({ String accept = '', bool multiple = false, - @visibleForTesting FileUploadInputElement? input, + @visibleForTesting HTMLInputElement? input, }) { final Completer> completer = Completer>(); - final FileUploadInputElement inputElement = - input ?? FileUploadInputElement(); + final HTMLInputElement inputElement = + input ?? (createElementTag('input') as HTMLInputElement) + ..type = 'file'; - _container.children.add( + _container.appendChild( inputElement ..accept = accept ..multiple = multiple, ); inputElement.onChange.first.then((_) { - final List files = - inputElement.files!.map(_convertFileToXFile).toList(); + final List files = Iterable.generate( + inputElement.files!.length, + (int i) => inputElement.files!.item(i)!) + .map(_convertFileToXFile) + .toList(); inputElement.remove(); completer.complete(files); }); @@ -52,10 +57,13 @@ class DomHelper { completer.completeError(platformException); }); - inputElement.addEventListener('cancel', (Event event) { - inputElement.remove(); - completer.complete([]); - }); + inputElement.addEventListener( + 'cancel', + (Event event) { + inputElement.remove(); + completer.complete([]); + }.toJS, + ); // TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365 inputElement.click(); @@ -64,10 +72,12 @@ class DomHelper { } XFile _convertFileToXFile(File file) => XFile( - Url.createObjectUrl(file), + // TODO(srujzs): This is necessary in order to support package:web 0.4.0. + // This was not needed with 0.3.0, hence the lint. + // ignore: unnecessary_cast + URL.createObjectURL(file as JSObject), name: file.name, length: file.size, - lastModified: DateTime.fromMillisecondsSinceEpoch( - file.lastModified ?? DateTime.now().millisecondsSinceEpoch), + lastModified: DateTime.fromMillisecondsSinceEpoch(file.lastModified), ); } diff --git a/packages/file_selector/file_selector_web/pubspec.yaml b/packages/file_selector/file_selector_web/pubspec.yaml index 8198aae05e88..3c3ca15c3aa9 100644 --- a/packages/file_selector/file_selector_web/pubspec.yaml +++ b/packages/file_selector/file_selector_web/pubspec.yaml @@ -2,11 +2,11 @@ name: file_selector_web description: Web platform implementation of file_selector repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22 -version: 0.9.2+1 +version: 0.9.3 environment: - sdk: ">=2.19.0 <4.0.0" - flutter: ">=3.7.0" + sdk: ^3.2.0 + flutter: ">=3.16.0" flutter: plugin: @@ -22,6 +22,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter + web: '>=0.3.0 <0.5.0' dev_dependencies: flutter_test: diff --git a/script/configs/allowed_unpinned_deps.yaml b/script/configs/allowed_unpinned_deps.yaml index 2c2345da9ae3..fe4c138b0a63 100644 --- a/script/configs/allowed_unpinned_deps.yaml +++ b/script/configs/allowed_unpinned_deps.yaml @@ -51,6 +51,7 @@ - test_api - vm_service - wasm +- web - yaml # Google-owned packages - _discoveryapis_commons diff --git a/script/tool/lib/src/common/core.dart b/script/tool/lib/src/common/core.dart index 5e96c6214b24..2910301cda9c 100644 --- a/script/tool/lib/src/common/core.dart +++ b/script/tool/lib/src/common/core.dart @@ -68,6 +68,7 @@ final Map _dartSdkForFlutterSdk = { Version(3, 10, 0): Version(3, 0, 0), Version(3, 10, 6): Version(3, 0, 6), Version(3, 13, 0): Version(3, 1, 0), + Version(3, 16, 0): Version(3, 2, 0), }; /// Returns the version of the Dart SDK that shipped with the given Flutter