Skip to content

Commit

Permalink
[file_selector_web] migrate to pkg:web (#5413)
Browse files Browse the repository at this point in the history
This allows this package to be used in a web app compiled to Wasm.

Helps unblock flutter/devtools#6606
  • Loading branch information
kevmoo authored Nov 17, 2023
1 parent 25574f9 commit 42dbb75
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 30 deletions.
4 changes: 4 additions & 0 deletions packages/file_selector/file_selector_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<File> 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<File> files, Event event) {
Expand All @@ -36,12 +42,13 @@ void main() {

setUp(() {
domHelper = DomHelper();
input = FileUploadInputElement();
input = (createElementTag('input') as HTMLInputElement)..type = 'file';
});

group('getFiles', () {
final File mockFile1 = File(<Object>['123456'], 'file1.txt');
final File mockFile2 = File(<Object>[], 'file2.txt');
final File mockFile1 =
File(<Object>['123456'].jsify as JSArray, 'file1.txt');
final File mockFile2 = File(<Object>[].jsify as JSArray, 'file2.txt');

testWidgets('works', (_) async {
final Future<List<XFile>> futureFiles = domHelper.getFiles(
Expand Down Expand Up @@ -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(
Expand All @@ -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);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
// 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';
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', () {
Expand Down Expand Up @@ -121,7 +121,7 @@ class MockDomHelper implements DomHelper {
Future<List<XFile>> getFiles({
String accept = '',
bool multiple = false,
FileUploadInputElement? input,
HTMLInputElement? input,
}) {
expect(accept, _expectedAccept,
reason: 'Expected "accept" value does not match.');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies:
path: ../
flutter:
sdk: flutter
web: '>=0.3.0 <0.5.0'

dev_dependencies:
flutter_test:
Expand Down
42 changes: 26 additions & 16 deletions packages/file_selector/file_selector_web/lib/src/dom_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 <input /> attributes and waits for a file to be selected.
Future<List<XFile>> getFiles({
String accept = '',
bool multiple = false,
@visibleForTesting FileUploadInputElement? input,
@visibleForTesting HTMLInputElement? input,
}) {
final Completer<List<XFile>> completer = Completer<List<XFile>>();
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<XFile> files =
inputElement.files!.map(_convertFileToXFile).toList();
final List<XFile> files = Iterable<File>.generate(
inputElement.files!.length,
(int i) => inputElement.files!.item(i)!)
.map(_convertFileToXFile)
.toList();
inputElement.remove();
completer.complete(files);
});
Expand All @@ -52,10 +57,13 @@ class DomHelper {
completer.completeError(platformException);
});

inputElement.addEventListener('cancel', (Event event) {
inputElement.remove();
completer.complete(<XFile>[]);
});
inputElement.addEventListener(
'cancel',
(Event event) {
inputElement.remove();
completer.complete(<XFile>[]);
}.toJS,
);

// TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365
inputElement.click();
Expand All @@ -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),
);
}
7 changes: 4 additions & 3 deletions packages/file_selector/file_selector_web/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -22,6 +22,7 @@ dependencies:
sdk: flutter
flutter_web_plugins:
sdk: flutter
web: '>=0.3.0 <0.5.0'

dev_dependencies:
flutter_test:
Expand Down
1 change: 1 addition & 0 deletions script/configs/allowed_unpinned_deps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
- test_api
- vm_service
- wasm
- web
- yaml
# Google-owned packages
- _discoveryapis_commons
Expand Down
1 change: 1 addition & 0 deletions script/tool/lib/src/common/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ final Map<Version, Version> _dartSdkForFlutterSdk = <Version, Version>{
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
Expand Down

0 comments on commit 42dbb75

Please sign in to comment.