Skip to content

Commit 42dbb75

Browse files
authored
[file_selector_web] migrate to pkg:web (#5413)
This allows this package to be used in a web app compiled to Wasm. Helps unblock flutter/devtools#6606
1 parent 25574f9 commit 42dbb75

File tree

8 files changed

+55
-30
lines changed

8 files changed

+55
-30
lines changed

packages/file_selector/file_selector_web/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.9.3
2+
3+
* Updates minimum supported SDK version to Dart 3.2.
4+
15
## 0.9.2+1
26

37
* Adds pub topics to package metadata.

packages/file_selector/file_selector_web/example/integration_test/dom_helper_test.dart

+16-9
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@
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';
5+
import 'dart:js_interop';
66

77
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
88
import 'package:file_selector_web/src/dom_helper.dart';
99
import 'package:flutter_test/flutter_test.dart';
1010
import 'package:integration_test/integration_test.dart';
11+
import 'package:web/helpers.dart';
1112

1213
void main() {
1314
group('dom_helper', () {
1415
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
1516
late DomHelper domHelper;
16-
late FileUploadInputElement input;
17+
late HTMLInputElement input;
1718

1819
FileList? createFileList(List<File> files) {
1920
final DataTransfer dataTransfer = DataTransfer();
20-
files.forEach(dataTransfer.items!.add);
21-
return dataTransfer.files as FileList?;
21+
for (final File e in files) {
22+
// TODO(srujzs): This is necessary in order to support package:web 0.4.0.
23+
// This was not needed with 0.3.0, hence the lint.
24+
// ignore: unnecessary_cast
25+
dataTransfer.items.add(e as JSAny);
26+
}
27+
return dataTransfer.files;
2228
}
2329

2430
void setFilesAndTriggerEvent(List<File> files, Event event) {
@@ -36,12 +42,13 @@ void main() {
3642

3743
setUp(() {
3844
domHelper = DomHelper();
39-
input = FileUploadInputElement();
45+
input = (createElementTag('input') as HTMLInputElement)..type = 'file';
4046
});
4147

4248
group('getFiles', () {
43-
final File mockFile1 = File(<Object>['123456'], 'file1.txt');
44-
final File mockFile2 = File(<Object>[], 'file2.txt');
49+
final File mockFile1 =
50+
File(<Object>['123456'].jsify as JSArray, 'file1.txt');
51+
final File mockFile2 = File(<Object>[].jsify as JSArray, 'file2.txt');
4552

4653
testWidgets('works', (_) async {
4754
final Future<List<XFile>> futureFiles = domHelper.getFiles(
@@ -114,7 +121,7 @@ void main() {
114121
input: input,
115122
);
116123

117-
expect(input.matchesWithAncestors('body'), true);
124+
expect(input.matches('body'), true);
118125
expect(input.accept, accept);
119126
expect(input.multiple, multiple);
120127
expect(
@@ -128,7 +135,7 @@ void main() {
128135
await futureFile;
129136

130137
// It should be already removed from the DOM after the file is resolved.
131-
expect(input.parent, isNull);
138+
expect(input.parentElement, isNull);
132139
});
133140
});
134141
});

packages/file_selector/file_selector_web/example/integration_test/file_selector_web_test.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
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';
65
import 'dart:typed_data';
76

87
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
98
import 'package:file_selector_web/file_selector_web.dart';
109
import 'package:file_selector_web/src/dom_helper.dart';
1110
import 'package:flutter_test/flutter_test.dart';
1211
import 'package:integration_test/integration_test.dart';
12+
import 'package:web/helpers.dart';
1313

1414
void main() {
1515
group('FileSelectorWeb', () {
@@ -121,7 +121,7 @@ class MockDomHelper implements DomHelper {
121121
Future<List<XFile>> getFiles({
122122
String accept = '',
123123
bool multiple = false,
124-
FileUploadInputElement? input,
124+
HTMLInputElement? input,
125125
}) {
126126
expect(accept, _expectedAccept,
127127
reason: 'Expected "accept" value does not match.');

packages/file_selector/file_selector_web/example/pubspec.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies:
1111
path: ../
1212
flutter:
1313
sdk: flutter
14+
web: '>=0.3.0 <0.5.0'
1415

1516
dev_dependencies:
1617
flutter_test:

packages/file_selector/file_selector_web/lib/src/dom_helper.dart

+26-16
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,46 @@
33
// found in the LICENSE file.
44

55
import 'dart:async';
6-
import 'dart:html';
6+
import 'dart:js_interop';
77

88
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
99
import 'package:flutter/foundation.dart' show visibleForTesting;
1010
import 'package:flutter/services.dart';
11+
import 'package:web/helpers.dart';
1112

1213
/// Class to manipulate the DOM with the intention of reading files from it.
1314
class DomHelper {
1415
/// Default constructor, initializes the container DOM element.
1516
DomHelper() {
1617
final Element body = querySelector('body')!;
17-
body.children.add(_container);
18+
body.appendChild(_container);
1819
}
1920

20-
final Element _container = Element.tag('file-selector');
21+
final Element _container = createElementTag('file-selector');
2122

2223
/// Sets the <input /> attributes and waits for a file to be selected.
2324
Future<List<XFile>> getFiles({
2425
String accept = '',
2526
bool multiple = false,
26-
@visibleForTesting FileUploadInputElement? input,
27+
@visibleForTesting HTMLInputElement? input,
2728
}) {
2829
final Completer<List<XFile>> completer = Completer<List<XFile>>();
29-
final FileUploadInputElement inputElement =
30-
input ?? FileUploadInputElement();
30+
final HTMLInputElement inputElement =
31+
input ?? (createElementTag('input') as HTMLInputElement)
32+
..type = 'file';
3133

32-
_container.children.add(
34+
_container.appendChild(
3335
inputElement
3436
..accept = accept
3537
..multiple = multiple,
3638
);
3739

3840
inputElement.onChange.first.then((_) {
39-
final List<XFile> files =
40-
inputElement.files!.map(_convertFileToXFile).toList();
41+
final List<XFile> files = Iterable<File>.generate(
42+
inputElement.files!.length,
43+
(int i) => inputElement.files!.item(i)!)
44+
.map(_convertFileToXFile)
45+
.toList();
4146
inputElement.remove();
4247
completer.complete(files);
4348
});
@@ -52,10 +57,13 @@ class DomHelper {
5257
completer.completeError(platformException);
5358
});
5459

55-
inputElement.addEventListener('cancel', (Event event) {
56-
inputElement.remove();
57-
completer.complete(<XFile>[]);
58-
});
60+
inputElement.addEventListener(
61+
'cancel',
62+
(Event event) {
63+
inputElement.remove();
64+
completer.complete(<XFile>[]);
65+
}.toJS,
66+
);
5967

6068
// TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365
6169
inputElement.click();
@@ -64,10 +72,12 @@ class DomHelper {
6472
}
6573

6674
XFile _convertFileToXFile(File file) => XFile(
67-
Url.createObjectUrl(file),
75+
// TODO(srujzs): This is necessary in order to support package:web 0.4.0.
76+
// This was not needed with 0.3.0, hence the lint.
77+
// ignore: unnecessary_cast
78+
URL.createObjectURL(file as JSObject),
6879
name: file.name,
6980
length: file.size,
70-
lastModified: DateTime.fromMillisecondsSinceEpoch(
71-
file.lastModified ?? DateTime.now().millisecondsSinceEpoch),
81+
lastModified: DateTime.fromMillisecondsSinceEpoch(file.lastModified),
7282
);
7383
}

packages/file_selector/file_selector_web/pubspec.yaml

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ name: file_selector_web
22
description: Web platform implementation of file_selector
33
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_web
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+file_selector%22
5-
version: 0.9.2+1
5+
version: 0.9.3
66

77
environment:
8-
sdk: ">=2.19.0 <4.0.0"
9-
flutter: ">=3.7.0"
8+
sdk: ^3.2.0
9+
flutter: ">=3.16.0"
1010

1111
flutter:
1212
plugin:
@@ -22,6 +22,7 @@ dependencies:
2222
sdk: flutter
2323
flutter_web_plugins:
2424
sdk: flutter
25+
web: '>=0.3.0 <0.5.0'
2526

2627
dev_dependencies:
2728
flutter_test:

script/configs/allowed_unpinned_deps.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
- test_api
5252
- vm_service
5353
- wasm
54+
- web
5455
- yaml
5556
# Google-owned packages
5657
- _discoveryapis_commons

script/tool/lib/src/common/core.dart

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ final Map<Version, Version> _dartSdkForFlutterSdk = <Version, Version>{
6868
Version(3, 10, 0): Version(3, 0, 0),
6969
Version(3, 10, 6): Version(3, 0, 6),
7070
Version(3, 13, 0): Version(3, 1, 0),
71+
Version(3, 16, 0): Version(3, 2, 0),
7172
};
7273

7374
/// Returns the version of the Dart SDK that shipped with the given Flutter

0 commit comments

Comments
 (0)