mirror of
https://github.com/flutter/packages.git
synced 2025-07-02 08:34:31 +08:00
[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
This commit is contained in:
@ -1,3 +1,7 @@
|
|||||||
|
## 0.9.3
|
||||||
|
|
||||||
|
* Updates minimum supported SDK version to Dart 3.2.
|
||||||
|
|
||||||
## 0.9.2+1
|
## 0.9.2+1
|
||||||
|
|
||||||
* Adds pub topics to package metadata.
|
* Adds pub topics to package metadata.
|
||||||
|
@ -2,23 +2,29 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
import 'dart:html';
|
import 'dart:js_interop';
|
||||||
|
|
||||||
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
|
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
|
||||||
import 'package:file_selector_web/src/dom_helper.dart';
|
import 'package:file_selector_web/src/dom_helper.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:web/helpers.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('dom_helper', () {
|
group('dom_helper', () {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
late DomHelper domHelper;
|
late DomHelper domHelper;
|
||||||
late FileUploadInputElement input;
|
late HTMLInputElement input;
|
||||||
|
|
||||||
FileList? createFileList(List<File> files) {
|
FileList? createFileList(List<File> files) {
|
||||||
final DataTransfer dataTransfer = DataTransfer();
|
final DataTransfer dataTransfer = DataTransfer();
|
||||||
files.forEach(dataTransfer.items!.add);
|
for (final File e in files) {
|
||||||
return dataTransfer.files as FileList?;
|
// 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) {
|
void setFilesAndTriggerEvent(List<File> files, Event event) {
|
||||||
@ -36,12 +42,13 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
domHelper = DomHelper();
|
domHelper = DomHelper();
|
||||||
input = FileUploadInputElement();
|
input = (createElementTag('input') as HTMLInputElement)..type = 'file';
|
||||||
});
|
});
|
||||||
|
|
||||||
group('getFiles', () {
|
group('getFiles', () {
|
||||||
final File mockFile1 = File(<Object>['123456'], 'file1.txt');
|
final File mockFile1 =
|
||||||
final File mockFile2 = File(<Object>[], 'file2.txt');
|
File(<Object>['123456'].jsify as JSArray, 'file1.txt');
|
||||||
|
final File mockFile2 = File(<Object>[].jsify as JSArray, 'file2.txt');
|
||||||
|
|
||||||
testWidgets('works', (_) async {
|
testWidgets('works', (_) async {
|
||||||
final Future<List<XFile>> futureFiles = domHelper.getFiles(
|
final Future<List<XFile>> futureFiles = domHelper.getFiles(
|
||||||
@ -114,7 +121,7 @@ void main() {
|
|||||||
input: input,
|
input: input,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(input.matchesWithAncestors('body'), true);
|
expect(input.matches('body'), true);
|
||||||
expect(input.accept, accept);
|
expect(input.accept, accept);
|
||||||
expect(input.multiple, multiple);
|
expect(input.multiple, multiple);
|
||||||
expect(
|
expect(
|
||||||
@ -128,7 +135,7 @@ void main() {
|
|||||||
await futureFile;
|
await futureFile;
|
||||||
|
|
||||||
// It should be already removed from the DOM after the file is resolved.
|
// It should be already removed from the DOM after the file is resolved.
|
||||||
expect(input.parent, isNull);
|
expect(input.parentElement, isNull);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
import 'dart:html';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
|
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:file_selector_web/src/dom_helper.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:web/helpers.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('FileSelectorWeb', () {
|
group('FileSelectorWeb', () {
|
||||||
@ -121,7 +121,7 @@ class MockDomHelper implements DomHelper {
|
|||||||
Future<List<XFile>> getFiles({
|
Future<List<XFile>> getFiles({
|
||||||
String accept = '',
|
String accept = '',
|
||||||
bool multiple = false,
|
bool multiple = false,
|
||||||
FileUploadInputElement? input,
|
HTMLInputElement? input,
|
||||||
}) {
|
}) {
|
||||||
expect(accept, _expectedAccept,
|
expect(accept, _expectedAccept,
|
||||||
reason: 'Expected "accept" value does not match.');
|
reason: 'Expected "accept" value does not match.');
|
||||||
|
@ -11,6 +11,7 @@ dependencies:
|
|||||||
path: ../
|
path: ../
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
web: '>=0.3.0 <0.5.0'
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -3,41 +3,46 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:html';
|
import 'dart:js_interop';
|
||||||
|
|
||||||
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
|
import 'package:file_selector_platform_interface/file_selector_platform_interface.dart';
|
||||||
import 'package:flutter/foundation.dart' show visibleForTesting;
|
import 'package:flutter/foundation.dart' show visibleForTesting;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:web/helpers.dart';
|
||||||
|
|
||||||
/// Class to manipulate the DOM with the intention of reading files from it.
|
/// Class to manipulate the DOM with the intention of reading files from it.
|
||||||
class DomHelper {
|
class DomHelper {
|
||||||
/// Default constructor, initializes the container DOM element.
|
/// Default constructor, initializes the container DOM element.
|
||||||
DomHelper() {
|
DomHelper() {
|
||||||
final Element body = querySelector('body')!;
|
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.
|
/// Sets the <input /> attributes and waits for a file to be selected.
|
||||||
Future<List<XFile>> getFiles({
|
Future<List<XFile>> getFiles({
|
||||||
String accept = '',
|
String accept = '',
|
||||||
bool multiple = false,
|
bool multiple = false,
|
||||||
@visibleForTesting FileUploadInputElement? input,
|
@visibleForTesting HTMLInputElement? input,
|
||||||
}) {
|
}) {
|
||||||
final Completer<List<XFile>> completer = Completer<List<XFile>>();
|
final Completer<List<XFile>> completer = Completer<List<XFile>>();
|
||||||
final FileUploadInputElement inputElement =
|
final HTMLInputElement inputElement =
|
||||||
input ?? FileUploadInputElement();
|
input ?? (createElementTag('input') as HTMLInputElement)
|
||||||
|
..type = 'file';
|
||||||
|
|
||||||
_container.children.add(
|
_container.appendChild(
|
||||||
inputElement
|
inputElement
|
||||||
..accept = accept
|
..accept = accept
|
||||||
..multiple = multiple,
|
..multiple = multiple,
|
||||||
);
|
);
|
||||||
|
|
||||||
inputElement.onChange.first.then((_) {
|
inputElement.onChange.first.then((_) {
|
||||||
final List<XFile> files =
|
final List<XFile> files = Iterable<File>.generate(
|
||||||
inputElement.files!.map(_convertFileToXFile).toList();
|
inputElement.files!.length,
|
||||||
|
(int i) => inputElement.files!.item(i)!)
|
||||||
|
.map(_convertFileToXFile)
|
||||||
|
.toList();
|
||||||
inputElement.remove();
|
inputElement.remove();
|
||||||
completer.complete(files);
|
completer.complete(files);
|
||||||
});
|
});
|
||||||
@ -52,10 +57,13 @@ class DomHelper {
|
|||||||
completer.completeError(platformException);
|
completer.completeError(platformException);
|
||||||
});
|
});
|
||||||
|
|
||||||
inputElement.addEventListener('cancel', (Event event) {
|
inputElement.addEventListener(
|
||||||
|
'cancel',
|
||||||
|
(Event event) {
|
||||||
inputElement.remove();
|
inputElement.remove();
|
||||||
completer.complete(<XFile>[]);
|
completer.complete(<XFile>[]);
|
||||||
});
|
}.toJS,
|
||||||
|
);
|
||||||
|
|
||||||
// TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365
|
// TODO(dit): Reimplement this with the showPicker() API, https://github.com/flutter/flutter/issues/130365
|
||||||
inputElement.click();
|
inputElement.click();
|
||||||
@ -64,10 +72,12 @@ class DomHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XFile _convertFileToXFile(File file) => XFile(
|
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,
|
name: file.name,
|
||||||
length: file.size,
|
length: file.size,
|
||||||
lastModified: DateTime.fromMillisecondsSinceEpoch(
|
lastModified: DateTime.fromMillisecondsSinceEpoch(file.lastModified),
|
||||||
file.lastModified ?? DateTime.now().millisecondsSinceEpoch),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,11 @@ name: file_selector_web
|
|||||||
description: Web platform implementation of file_selector
|
description: Web platform implementation of file_selector
|
||||||
repository: https://github.com/flutter/packages/tree/main/packages/file_selector/file_selector_web
|
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
|
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:
|
environment:
|
||||||
sdk: ">=2.19.0 <4.0.0"
|
sdk: ^3.2.0
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.16.0"
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
plugin:
|
plugin:
|
||||||
@ -22,6 +22,7 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
web: '>=0.3.0 <0.5.0'
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
- test_api
|
- test_api
|
||||||
- vm_service
|
- vm_service
|
||||||
- wasm
|
- wasm
|
||||||
|
- web
|
||||||
- yaml
|
- yaml
|
||||||
# Google-owned packages
|
# Google-owned packages
|
||||||
- _discoveryapis_commons
|
- _discoveryapis_commons
|
||||||
|
@ -68,6 +68,7 @@ final Map<Version, Version> _dartSdkForFlutterSdk = <Version, Version>{
|
|||||||
Version(3, 10, 0): Version(3, 0, 0),
|
Version(3, 10, 0): Version(3, 0, 0),
|
||||||
Version(3, 10, 6): Version(3, 0, 6),
|
Version(3, 10, 6): Version(3, 0, 6),
|
||||||
Version(3, 13, 0): Version(3, 1, 0),
|
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
|
/// Returns the version of the Dart SDK that shipped with the given Flutter
|
||||||
|
Reference in New Issue
Block a user