expo-document-picker 11.0.1 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,22 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 11.2.0 — 2023-02-03
14
+
15
+ ### 💡 Others
16
+
17
+ - On Android bump `compileSdkVersion` and `targetSdkVersion` to `33`. ([#20721](https://github.com/expo/expo/pull/20721) by [@lukmccall](https://github.com/lukmccall))
18
+
19
+ ## 11.1.0 — 2022-12-30
20
+
21
+ ### 🎉 New features
22
+
23
+ - Migrated to Expo Modules API. ([#20336](https://github.com/expo/expo/pull/20336) by [@alanhughes](https://github.com/alanjhughes))
24
+
25
+ ### 💡 Others
26
+
27
+ - Avoid dependency on `uuid`. ([#20477](https://github.com/expo/expo/pull/20477) by [@LinusU](https://github.com/LinusU))
28
+
13
29
  ## 11.0.1 — 2022-10-28
14
30
 
15
31
  _This version does not introduce any user-facing changes._
@@ -56,6 +72,7 @@ _This version does not introduce any user-facing changes._
56
72
 
57
73
  - Fix `Plugin with id 'maven' not found` build error from Android Gradle 7. ([#16080](https://github.com/expo/expo/pull/16080) by [@kudo](https://github.com/kudo))
58
74
  - Handle nil MIME type. ([#16156](https://github.com/expo/expo/pull/16156) by [@brentvatne](https://github.com/brentvatne))
75
+ - Fix incorrectly allowing multiple document selection ([#20363](https://github.com/expo/expo/pull/20363)) by [@alanhughes](https://github.com/alanjhughes)
59
76
 
60
77
  ## 10.1.1 - 2022-01-26
61
78
 
package/README.md CHANGED
@@ -4,7 +4,7 @@ Provides access to the system's UI for selecting documents from the available pr
4
4
 
5
5
  # API documentation
6
6
 
7
- - [Documentation for the main branch](https://github.com/expo/expo/blob/main/docs/pages/versions/unversioned/sdk/document-picker.md)
7
+ - [Documentation for the main branch](https://github.com/expo/expo/blob/main/docs/pages/versions/unversioned/sdk/document-picker.mdx)
8
8
  - [Documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/document-picker/)
9
9
 
10
10
  # Installation in managed Expo projects
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '11.0.1'
6
+ version = '11.2.0'
7
7
 
8
8
  buildscript {
9
9
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -59,7 +59,7 @@ afterEvaluate {
59
59
  }
60
60
 
61
61
  android {
62
- compileSdkVersion safeExtGet("compileSdkVersion", 31)
62
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
63
63
 
64
64
  compileOptions {
65
65
  sourceCompatibility JavaVersion.VERSION_11
@@ -72,9 +72,9 @@ android {
72
72
 
73
73
  defaultConfig {
74
74
  minSdkVersion safeExtGet("minSdkVersion", 21)
75
- targetSdkVersion safeExtGet("targetSdkVersion", 31)
75
+ targetSdkVersion safeExtGet("targetSdkVersion", 33)
76
76
  versionCode 17
77
- versionName '11.0.1'
77
+ versionName '11.2.0'
78
78
  }
79
79
  lintOptions {
80
80
  abortOnError false
@@ -13,7 +13,8 @@ class DocumentDetailsReader(private val context: Context) {
13
13
  .query(uri, null, null, null, null)
14
14
  ?.use { cursor ->
15
15
  cursor.moveToFirst()
16
- val name = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME))
16
+ val columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
17
+ val name = cursor.getString(columnIndex)
17
18
  val uriString = uri.toString()
18
19
  val size = cursor.getColumnIndex(OpenableColumns.SIZE).let { sizeColumnIndex ->
19
20
  if (!cursor.isNull(sizeColumnIndex)) {
@@ -0,0 +1,12 @@
1
+ package expo.modules.documentpicker
2
+
3
+ import expo.modules.kotlin.exception.CodedException
4
+
5
+ class PickingInProgressException :
6
+ CodedException("Different document picking in progress. Await other document picking first.")
7
+
8
+ class FailedToCopyToCacheException :
9
+ CodedException("Failed to copy to cache directory.")
10
+
11
+ class FailedToReadDocumentException :
12
+ CodedException("Failed to read the selected document.")
@@ -4,117 +4,85 @@ import android.app.Activity
4
4
  import android.content.Context
5
5
  import android.content.Intent
6
6
  import android.net.Uri
7
- import android.os.Bundle
7
+ import expo.modules.core.utilities.FileUtilities
8
+ import expo.modules.kotlin.Promise
9
+ import expo.modules.kotlin.exception.Exceptions
10
+ import expo.modules.kotlin.modules.Module
11
+ import expo.modules.kotlin.modules.ModuleDefinition
8
12
  import org.apache.commons.io.FilenameUtils
9
13
  import org.apache.commons.io.IOUtils
10
- import expo.modules.core.ExportedModule
11
- import expo.modules.core.ModuleRegistry
12
- import expo.modules.core.ModuleRegistryDelegate
13
- import expo.modules.core.Promise
14
- import expo.modules.core.interfaces.ActivityEventListener
15
- import expo.modules.core.interfaces.ActivityProvider
16
- import expo.modules.core.interfaces.ExpoMethod
17
- import expo.modules.core.interfaces.services.UIManager
18
- import expo.modules.core.utilities.FileUtilities
19
14
  import java.io.File
20
15
  import java.io.FileOutputStream
21
16
  import java.io.IOException
22
17
 
23
- private const val TAG = "ExpoDocumentPicker"
24
18
  private const val OPEN_DOCUMENT_CODE = 4137
25
19
 
26
- class DocumentPickerModule(
27
- mContext: Context,
28
- private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
29
- ) : ExportedModule(mContext), ActivityEventListener {
30
- private var mPromise: Promise? = null
31
- private var mCopyToCacheDirectory = true
32
-
33
- private val mActivityProvider: ActivityProvider by moduleRegistry()
34
- private val mUIManager: UIManager by moduleRegistry()
20
+ class DocumentPickerModule : Module() {
21
+ private val context: Context
22
+ get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
23
+ private val currentActivity
24
+ get() = appContext.currentActivity ?: throw Exceptions.MissingActivity()
25
+ private var pendingPromise: Promise? = null
26
+ private var copyToCacheDirectory = true
35
27
 
36
- private inline fun <reified T> moduleRegistry() = moduleRegistryDelegate.getFromModuleRegistry<T>()
37
-
38
- override fun getName() = TAG
39
-
40
- override fun onCreate(moduleRegistry: ModuleRegistry) {
41
- moduleRegistryDelegate.onCreate(moduleRegistry)
42
- mUIManager.registerActivityEventListener(this)
43
- }
28
+ override fun definition() = ModuleDefinition {
29
+ Name("ExpoDocumentPicker")
44
30
 
45
- @ExpoMethod
46
- fun getDocumentAsync(options: Map<String, Any?>, promise: Promise) {
47
- if (mPromise != null) {
48
- promise.reject("E_DOCUMENT_PICKER", "Different document picking in progress. Await other document picking first.")
49
- return
50
- }
51
- val pickerOptions = DocumentPickerOptions.optionsFromMap(options, promise) ?: return
52
- mPromise = promise
53
- mCopyToCacheDirectory = pickerOptions.copyToCacheDirectory
54
- val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
55
- addCategory(Intent.CATEGORY_OPENABLE)
56
- type = if (pickerOptions.types.size > 1) {
57
- putExtra(Intent.EXTRA_MIME_TYPES, pickerOptions.types)
58
- "*/*"
59
- } else {
60
- pickerOptions.types[0]
31
+ AsyncFunction("getDocumentAsync") { options: DocumentPickerOptions, promise: Promise ->
32
+ if (pendingPromise != null) {
33
+ throw PickingInProgressException()
34
+ }
35
+ pendingPromise = promise
36
+ copyToCacheDirectory = options.copyToCacheDirectory
37
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
38
+ addCategory(Intent.CATEGORY_OPENABLE)
39
+ type = if (options.type.size > 1) {
40
+ putExtra(Intent.EXTRA_MIME_TYPES, options.type.toTypedArray())
41
+ "*/*"
42
+ } else {
43
+ options.type[0]
44
+ }
61
45
  }
46
+ currentActivity.startActivityForResult(intent, OPEN_DOCUMENT_CODE)
62
47
  }
63
- mActivityProvider.currentActivity.startActivityForResult(intent, OPEN_DOCUMENT_CODE)
64
- }
65
48
 
66
- override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, intent: Intent?) {
67
- if (requestCode != OPEN_DOCUMENT_CODE) {
68
- return
69
- }
49
+ OnActivityResult { _, (requestCode, resultCode, intent) ->
50
+ if (requestCode != OPEN_DOCUMENT_CODE || pendingPromise == null) {
51
+ return@OnActivityResult
52
+ }
70
53
 
71
- if (mPromise == null) {
72
- return
73
- }
74
- val promise = mPromise!!
75
- mPromise = null
54
+ val promise = pendingPromise!!
76
55
 
77
- if (resultCode == Activity.RESULT_OK) {
78
- val documentDetails = intent?.data?.let { uri ->
79
- val originalDocumentDetails = DocumentDetailsReader(context).read(uri)
80
- if (!mCopyToCacheDirectory || originalDocumentDetails == null) {
81
- originalDocumentDetails
82
- } else {
83
- val copyPath = copyDocumentToCacheDirectory(uri, originalDocumentDetails.name)
84
- if (copyPath == null) {
85
- promise.reject("E_DOCUMENT_PICKER", "Failed to copy to cache directory.")
86
- return
56
+ if (resultCode == Activity.RESULT_OK) {
57
+ intent?.data?.let { uri ->
58
+ val originalDocumentDetails = DocumentDetailsReader(context).read(uri)
59
+ if (!copyToCacheDirectory || originalDocumentDetails == null) {
60
+ originalDocumentDetails
87
61
  } else {
88
- originalDocumentDetails.copy(uri = copyPath)
62
+ val copyPath = copyDocumentToCacheDirectory(uri, originalDocumentDetails.name)
63
+ copyPath?.let {
64
+ originalDocumentDetails.copy(uri = it)
65
+ } ?: throw FailedToCopyToCacheException()
89
66
  }
90
- }
91
- }
92
- if (documentDetails == null) {
93
- promise.reject("E_DOCUMENT_PICKER", "Failed to read the selected document.")
67
+ }?.let { details ->
68
+ val result = DocumentPickerResult(
69
+ type = "success",
70
+ uri = details.uri,
71
+ name = details.name,
72
+ mimeType = details.mimeType,
73
+ size = details.size
74
+ )
75
+ promise.resolve(result)
76
+ } ?: throw FailedToReadDocumentException()
94
77
  } else {
95
- val result = Bundle().apply {
96
- putString("type", "success")
97
- putString("uri", documentDetails.uri)
98
- putString("name", documentDetails.name)
99
- documentDetails.mimeType?.let {
100
- putString("mimeType", documentDetails.mimeType)
101
- }
102
- documentDetails.size?.let {
103
- putInt("size", documentDetails.size)
104
- }
105
- }
106
- promise.resolve(result)
78
+ promise.resolve(
79
+ DocumentPickerCancelled(type = "cancel")
80
+ )
107
81
  }
108
- } else {
109
- val result = Bundle().apply {
110
- putString("type", "cancel")
111
- }
112
- promise.resolve(result)
82
+ pendingPromise = null
113
83
  }
114
84
  }
115
85
 
116
- override fun onNewIntent(intent: Intent) = Unit
117
-
118
86
  private fun copyDocumentToCacheDirectory(documentUri: Uri, name: String): String? {
119
87
  val outputFilePath = FileUtilities.generateOutputPath(
120
88
  context.cacheDir,
@@ -1,51 +1,14 @@
1
1
  package expo.modules.documentpicker
2
2
 
3
- import expo.modules.core.Promise
4
-
5
- data class DocumentPickerOptions(val copyToCacheDirectory: Boolean, val types: Array<String>) {
6
- companion object {
7
- fun optionsFromMap(options: Map<String, Any?>, promise: Promise): DocumentPickerOptions? {
8
- if (options.containsKey("type") && options["type"] == null) {
9
- promise.reject("ERR_INVALID_OPTION", "type must be a list of strings")
10
- return null
11
- }
12
- var mimeTypes = arrayListOf("*/*")
13
- options["type"]?.let {
14
- val types = it as ArrayList<*>
15
- if (types.isEmpty() || types[0] !is String) {
16
- promise.reject("ERR_INVALID_OPTION", "type must be a list of strings")
17
- return null
18
- } else {
19
- @Suppress("UNCHECKED_CAST")
20
- mimeTypes = types as ArrayList<String>
21
- }
22
- }
23
- val copyToCacheDirectory = options["copyToCacheDirectory"]?.let {
24
- if (it is Boolean) {
25
- return@let it
26
- }
27
- promise.reject("ERR_INVALID_OPTION", "copyToCacheDirectory must be a boolean")
28
- return null
29
- } ?: true
30
- return DocumentPickerOptions(copyToCacheDirectory, mimeTypes.toTypedArray())
31
- }
32
- }
33
-
34
- override fun equals(other: Any?): Boolean {
35
- if (this === other) return true
36
- if (javaClass != other?.javaClass) return false
37
-
38
- other as DocumentPickerOptions
39
-
40
- if (copyToCacheDirectory != other.copyToCacheDirectory) return false
41
- if (!types.contentEquals(other.types)) return false
42
-
43
- return true
44
- }
45
-
46
- override fun hashCode(): Int {
47
- var result = copyToCacheDirectory.hashCode()
48
- result = 31 * result + types.contentHashCode()
49
- return result
50
- }
51
- }
3
+ import expo.modules.kotlin.records.Field
4
+ import expo.modules.kotlin.records.IsNotEmpty
5
+ import expo.modules.kotlin.records.Record
6
+
7
+ data class DocumentPickerOptions(
8
+ @Field
9
+ val copyToCacheDirectory: Boolean,
10
+
11
+ @Field
12
+ @IsNotEmpty
13
+ val type: List<String>
14
+ ) : Record
@@ -0,0 +1,26 @@
1
+ package expo.modules.documentpicker
2
+
3
+ import expo.modules.kotlin.records.Field
4
+ import expo.modules.kotlin.records.Record
5
+
6
+ data class DocumentPickerResult(
7
+ @Field
8
+ val type: String,
9
+
10
+ @Field
11
+ val uri: String,
12
+
13
+ @Field
14
+ val name: String,
15
+
16
+ @Field
17
+ val mimeType: String?,
18
+
19
+ @Field
20
+ val size: Int?
21
+ ) : Record
22
+
23
+ data class DocumentPickerCancelled(
24
+ @Field
25
+ val type: String
26
+ )
@@ -1,3 +1,3 @@
1
- declare const _default: import("expo-modules-core").ProxyNativeModule;
1
+ declare const _default: any;
2
2
  export default _default;
3
3
  //# sourceMappingURL=ExpoDocumentPicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoDocumentPicker.d.ts","sourceRoot":"","sources":["../src/ExpoDocumentPicker.ts"],"names":[],"mappings":";AAEA,wBAAqD"}
1
+ {"version":3,"file":"ExpoDocumentPicker.d.ts","sourceRoot":"","sources":["../src/ExpoDocumentPicker.ts"],"names":[],"mappings":";AACA,wBAAyD"}
@@ -1,3 +1,3 @@
1
- import { NativeModulesProxy } from 'expo-modules-core';
2
- export default NativeModulesProxy.ExpoDocumentPicker;
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ export default requireNativeModule('ExpoDocumentPicker');
3
3
  //# sourceMappingURL=ExpoDocumentPicker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoDocumentPicker.js","sourceRoot":"","sources":["../src/ExpoDocumentPicker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,eAAe,kBAAkB,CAAC,kBAAkB,CAAC","sourcesContent":["import { NativeModulesProxy } from 'expo-modules-core';\n\nexport default NativeModulesProxy.ExpoDocumentPicker;\n"]}
1
+ {"version":3,"file":"ExpoDocumentPicker.js","sourceRoot":"","sources":["../src/ExpoDocumentPicker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,eAAe,mBAAmB,CAAC,oBAAoB,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nexport default requireNativeModule('ExpoDocumentPicker');\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoDocumentPicker.web.d.ts","sourceRoot":"","sources":["../src/ExpoDocumentPicker.web.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;;;0CAU3D,qBAAqB,GAAG,QAAQ,cAAc,CAAC;;AARpD,wBA4DE"}
1
+ {"version":3,"file":"ExpoDocumentPicker.web.d.ts","sourceRoot":"","sources":["../src/ExpoDocumentPicker.web.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;;;0CAU3D,qBAAqB,GAAG,QAAQ,cAAc,CAAC;;AARpD,wBA4DE"}
@@ -1,5 +1,4 @@
1
1
  import { Platform } from 'expo-modules-core';
2
- import { v4 as uuidv4 } from 'uuid';
3
2
  export default {
4
3
  get name() {
5
4
  return 'ExpoDocumentPicker';
@@ -13,7 +12,7 @@ export default {
13
12
  input.style.display = 'none';
14
13
  input.setAttribute('type', 'file');
15
14
  input.setAttribute('accept', Array.isArray(type) ? type.join(',') : type);
16
- input.setAttribute('id', uuidv4());
15
+ input.setAttribute('id', String(Math.random()));
17
16
  if (multiple) {
18
17
  input.setAttribute('multiple', 'multiple');
19
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoDocumentPicker.web.js","sourceRoot":"","sources":["../src/ExpoDocumentPicker.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAIpC,eAAe;IACb,IAAI,IAAI;QACN,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,EACrB,IAAI,GAAG,KAAK,EACZ,QAAQ,GAAG,KAAK,GACM;QACtB,YAAY;QACZ,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE;YAC5B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;SAC3B;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAC7B,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1E,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACnC,IAAI,QAAQ,EAAE;YACZ,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;SAC5C;QAED,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAEjC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACpC,IAAI,KAAK,CAAC,KAAK,EAAE;oBACf,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAClC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC;oBACjC,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;oBAChC,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;wBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC,CAAC;oBACvF,CAAC,CAAC;oBACF,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;wBAC7B,MAAM,GAAG,GAAI,MAAc,CAAC,MAAM,CAAC;wBACnC,OAAO,CAAC;4BACN,IAAI,EAAE,SAAS;4BACf,GAAG;4BACH,QAAQ;4BACR,IAAI,EAAE,UAAU,CAAC,IAAI;4BACrB,IAAI,EAAE,UAAU;4BAChB,YAAY,EAAE,UAAU,CAAC,YAAY;4BACrC,IAAI,EAAE,UAAU,CAAC,IAAI;4BACrB,MAAM,EAAE,KAAK,CAAC,KAAK;yBACpB,CAAC,CAAC;oBACL,CAAC,CAAC;oBACF,6CAA6C;oBAC7C,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;iBAClC;qBAAM;oBACL,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;iBAC7B;gBAED,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;YAEH,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;YACtC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC","sourcesContent":["import { Platform } from 'expo-modules-core';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { DocumentPickerOptions, DocumentResult } from './types';\n\nexport default {\n get name(): string {\n return 'ExpoDocumentPicker';\n },\n\n async getDocumentAsync({\n type = '*/*',\n multiple = false,\n }: DocumentPickerOptions): Promise<DocumentResult> {\n // SSR guard\n if (!Platform.isDOMAvailable) {\n return { type: 'cancel' };\n }\n\n const input = document.createElement('input');\n input.style.display = 'none';\n input.setAttribute('type', 'file');\n input.setAttribute('accept', Array.isArray(type) ? type.join(',') : type);\n input.setAttribute('id', uuidv4());\n if (multiple) {\n input.setAttribute('multiple', 'multiple');\n }\n\n document.body.appendChild(input);\n\n return new Promise((resolve, reject) => {\n input.addEventListener('change', () => {\n if (input.files) {\n const targetFile = input.files[0];\n const mimeType = targetFile.type;\n const reader = new FileReader();\n reader.onerror = () => {\n reject(new Error(`Failed to read the selected media because the operation failed.`));\n };\n reader.onload = ({ target }) => {\n const uri = (target as any).result;\n resolve({\n type: 'success',\n uri,\n mimeType,\n name: targetFile.name,\n file: targetFile,\n lastModified: targetFile.lastModified,\n size: targetFile.size,\n output: input.files,\n });\n };\n // Read in the image file as a binary string.\n reader.readAsDataURL(targetFile);\n } else {\n resolve({ type: 'cancel' });\n }\n\n document.body.removeChild(input);\n });\n\n const event = new MouseEvent('click');\n input.dispatchEvent(event);\n });\n },\n};\n"]}
1
+ {"version":3,"file":"ExpoDocumentPicker.web.js","sourceRoot":"","sources":["../src/ExpoDocumentPicker.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI7C,eAAe;IACb,IAAI,IAAI;QACN,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,EACrB,IAAI,GAAG,KAAK,EACZ,QAAQ,GAAG,KAAK,GACM;QACtB,YAAY;QACZ,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE;YAC5B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;SAC3B;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QAC7B,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1E,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,QAAQ,EAAE;YACZ,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;SAC5C;QAED,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAEjC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;gBACpC,IAAI,KAAK,CAAC,KAAK,EAAE;oBACf,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAClC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC;oBACjC,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;oBAChC,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;wBACpB,MAAM,CAAC,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC,CAAC;oBACvF,CAAC,CAAC;oBACF,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;wBAC7B,MAAM,GAAG,GAAI,MAAc,CAAC,MAAM,CAAC;wBACnC,OAAO,CAAC;4BACN,IAAI,EAAE,SAAS;4BACf,GAAG;4BACH,QAAQ;4BACR,IAAI,EAAE,UAAU,CAAC,IAAI;4BACrB,IAAI,EAAE,UAAU;4BAChB,YAAY,EAAE,UAAU,CAAC,YAAY;4BACrC,IAAI,EAAE,UAAU,CAAC,IAAI;4BACrB,MAAM,EAAE,KAAK,CAAC,KAAK;yBACpB,CAAC,CAAC;oBACL,CAAC,CAAC;oBACF,6CAA6C;oBAC7C,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;iBAClC;qBAAM;oBACL,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;iBAC7B;gBAED,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC,CAAC,CAAC;YAEH,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC;YACtC,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC","sourcesContent":["import { Platform } from 'expo-modules-core';\n\nimport { DocumentPickerOptions, DocumentResult } from './types';\n\nexport default {\n get name(): string {\n return 'ExpoDocumentPicker';\n },\n\n async getDocumentAsync({\n type = '*/*',\n multiple = false,\n }: DocumentPickerOptions): Promise<DocumentResult> {\n // SSR guard\n if (!Platform.isDOMAvailable) {\n return { type: 'cancel' };\n }\n\n const input = document.createElement('input');\n input.style.display = 'none';\n input.setAttribute('type', 'file');\n input.setAttribute('accept', Array.isArray(type) ? type.join(',') : type);\n input.setAttribute('id', String(Math.random()));\n if (multiple) {\n input.setAttribute('multiple', 'multiple');\n }\n\n document.body.appendChild(input);\n\n return new Promise((resolve, reject) => {\n input.addEventListener('change', () => {\n if (input.files) {\n const targetFile = input.files[0];\n const mimeType = targetFile.type;\n const reader = new FileReader();\n reader.onerror = () => {\n reject(new Error(`Failed to read the selected media because the operation failed.`));\n };\n reader.onload = ({ target }) => {\n const uri = (target as any).result;\n resolve({\n type: 'success',\n uri,\n mimeType,\n name: targetFile.name,\n file: targetFile,\n lastModified: targetFile.lastModified,\n size: targetFile.size,\n output: input.files,\n });\n };\n // Read in the image file as a binary string.\n reader.readAsDataURL(targetFile);\n } else {\n resolve({ type: 'cancel' });\n }\n\n document.body.removeChild(input);\n });\n\n const event = new MouseEvent('click');\n input.dispatchEvent(event);\n });\n },\n};\n"]}
package/build/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare type DocumentPickerOptions = {
1
+ export type DocumentPickerOptions = {
2
2
  /**
3
3
  * The [MIME type(s)](https://en.wikipedia.org/wiki/Media_type) of the documents that are available
4
4
  * to be picked. Is also supports wildcards like `'image/*'` to choose any image. To allow any type
@@ -21,9 +21,19 @@ export declare type DocumentPickerOptions = {
21
21
  */
22
22
  multiple?: boolean;
23
23
  };
24
- export declare type DocumentResult = {
24
+ /**
25
+ * First object represents the result when the document pick has been cancelled.
26
+ * The second one represents the successful document pick result.
27
+ */
28
+ export type DocumentResult = {
29
+ /**
30
+ * Field indicating that the document pick has been cancelled.
31
+ */
25
32
  type: 'cancel';
26
33
  } | {
34
+ /**
35
+ * Field indicating that the document pick has been successful.
36
+ */
27
37
  type: 'success';
28
38
  /**
29
39
  * Document original name.
@@ -45,7 +55,15 @@ export declare type DocumentResult = {
45
55
  * Timestamp of last document modification.
46
56
  */
47
57
  lastModified?: number;
58
+ /**
59
+ * `File` object for the parity with web File API.
60
+ * @platform web
61
+ */
48
62
  file?: File;
63
+ /**
64
+ * `FileList` object for the parity with web File API.
65
+ * @platform web
66
+ */
49
67
  output?: FileList | null;
50
68
  };
51
69
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,oBAAY,qBAAqB,GAAG;IAClC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAGF,oBAAY,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IACE,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC1B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,qBAAqB,GAAG;IAClC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAGF;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB;IACE;;OAEG;IACH,IAAI,EAAE,QAAQ,CAAC;CAChB,GACD;IACE;;OAEG;IACH,IAAI,EAAE,SAAS,CAAC;IAChB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC1B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["// @needsAudit\nexport type DocumentPickerOptions = {\n /**\n * The [MIME type(s)](https://en.wikipedia.org/wiki/Media_type) of the documents that are available\n * to be picked. Is also supports wildcards like `'image/*'` to choose any image. To allow any type\n * of document you can use `'&ast;/*'`.\n * @default '&ast;/*'\n */\n type?: string | string[];\n /**\n * If `true`, the picked file is copied to [`FileSystem.CacheDirectory`](./filesystem#filesystemcachedirectory),\n * which allows other Expo APIs to read the file immediately. This may impact performance for\n * large files, so you should consider setting this to `false` if you expect users to pick\n * particularly large files and your app does not need immediate read access.\n * @default true\n */\n copyToCacheDirectory?: boolean;\n /**\n * Allows multiple files to be selected from the system UI.\n * @default false\n * @platform web\n */\n multiple?: boolean;\n};\n\n// @needsAudit @docsMissing\nexport type DocumentResult =\n | { type: 'cancel' }\n | {\n type: 'success';\n /**\n * Document original name.\n */\n name: string;\n /**\n * Document size in bytes.\n */\n size?: number;\n /**\n * An URI to the local document file.\n */\n uri: string;\n /**\n * Document MIME type.\n */\n mimeType?: string;\n /**\n * Timestamp of last document modification.\n */\n lastModified?: number;\n file?: File;\n output?: FileList | null;\n };\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["// @needsAudit\nexport type DocumentPickerOptions = {\n /**\n * The [MIME type(s)](https://en.wikipedia.org/wiki/Media_type) of the documents that are available\n * to be picked. Is also supports wildcards like `'image/*'` to choose any image. To allow any type\n * of document you can use `'&ast;/*'`.\n * @default '&ast;/*'\n */\n type?: string | string[];\n /**\n * If `true`, the picked file is copied to [`FileSystem.CacheDirectory`](./filesystem#filesystemcachedirectory),\n * which allows other Expo APIs to read the file immediately. This may impact performance for\n * large files, so you should consider setting this to `false` if you expect users to pick\n * particularly large files and your app does not need immediate read access.\n * @default true\n */\n copyToCacheDirectory?: boolean;\n /**\n * Allows multiple files to be selected from the system UI.\n * @default false\n * @platform web\n */\n multiple?: boolean;\n};\n\n// @needsAudit @docsMissing\n/**\n * First object represents the result when the document pick has been cancelled.\n * The second one represents the successful document pick result.\n */\nexport type DocumentResult =\n | {\n /**\n * Field indicating that the document pick has been cancelled.\n */\n type: 'cancel';\n }\n | {\n /**\n * Field indicating that the document pick has been successful.\n */\n type: 'success';\n /**\n * Document original name.\n */\n name: string;\n /**\n * Document size in bytes.\n */\n size?: number;\n /**\n * An URI to the local document file.\n */\n uri: string;\n /**\n * Document MIME type.\n */\n mimeType?: string;\n /**\n * Timestamp of last document modification.\n */\n lastModified?: number;\n /**\n * `File` object for the parity with web File API.\n * @platform web\n */\n file?: File;\n /**\n * `FileList` object for the parity with web File API.\n * @platform web\n */\n output?: FileList | null;\n };\n"]}
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "expo-document-picker",
3
+ "platforms": ["ios", "android"],
4
+ "android": {
5
+ "modules": ["expo.modules.documentpicker.DocumentPickerModule"]
6
+ }
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-document-picker",
3
- "version": "11.0.1",
3
+ "version": "11.2.0",
4
4
  "description": "Provides access to the system's UI for selecting documents from the available providers on the user's device.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -34,14 +34,11 @@
34
34
  "jest": {
35
35
  "preset": "expo-module-scripts"
36
36
  },
37
- "dependencies": {
38
- "uuid": "^3.3.2"
39
- },
40
37
  "devDependencies": {
41
38
  "expo-module-scripts": "^3.0.0"
42
39
  },
43
40
  "peerDependencies": {
44
41
  "expo": "*"
45
42
  },
46
- "gitHead": "59081bb17e727b10f2a00cd07bb45cd283a6f6a5"
43
+ "gitHead": "1815e2eaad8c753588c7b1eb74420174a28e01f4"
47
44
  }
@@ -1,6 +1,6 @@
1
1
  import { ExpoConfig } from 'expo/config';
2
2
  import { ConfigPlugin } from 'expo/config-plugins';
3
- export declare type IosProps = {
3
+ export type IosProps = {
4
4
  /**
5
5
  * Sets the `com.apple.developer.icloud-container-environment` entitlement which is read by EAS CLI to set
6
6
  * the `iCloudContainerEnvironment` in the `xcodebuild` `exportOptionsPlist`.
@@ -1,3 +1,2 @@
1
- import { NativeModulesProxy } from 'expo-modules-core';
2
-
3
- export default NativeModulesProxy.ExpoDocumentPicker;
1
+ import { requireNativeModule } from 'expo-modules-core';
2
+ export default requireNativeModule('ExpoDocumentPicker');
@@ -1,5 +1,4 @@
1
1
  import { Platform } from 'expo-modules-core';
2
- import { v4 as uuidv4 } from 'uuid';
3
2
 
4
3
  import { DocumentPickerOptions, DocumentResult } from './types';
5
4
 
@@ -21,7 +20,7 @@ export default {
21
20
  input.style.display = 'none';
22
21
  input.setAttribute('type', 'file');
23
22
  input.setAttribute('accept', Array.isArray(type) ? type.join(',') : type);
24
- input.setAttribute('id', uuidv4());
23
+ input.setAttribute('id', String(Math.random()));
25
24
  if (multiple) {
26
25
  input.setAttribute('multiple', 'multiple');
27
26
  }
package/src/types.ts CHANGED
@@ -24,9 +24,21 @@ export type DocumentPickerOptions = {
24
24
  };
25
25
 
26
26
  // @needsAudit @docsMissing
27
+ /**
28
+ * First object represents the result when the document pick has been cancelled.
29
+ * The second one represents the successful document pick result.
30
+ */
27
31
  export type DocumentResult =
28
- | { type: 'cancel' }
29
32
  | {
33
+ /**
34
+ * Field indicating that the document pick has been cancelled.
35
+ */
36
+ type: 'cancel';
37
+ }
38
+ | {
39
+ /**
40
+ * Field indicating that the document pick has been successful.
41
+ */
30
42
  type: 'success';
31
43
  /**
32
44
  * Document original name.
@@ -48,6 +60,14 @@ export type DocumentResult =
48
60
  * Timestamp of last document modification.
49
61
  */
50
62
  lastModified?: number;
63
+ /**
64
+ * `File` object for the parity with web File API.
65
+ * @platform web
66
+ */
51
67
  file?: File;
68
+ /**
69
+ * `FileList` object for the parity with web File API.
70
+ * @platform web
71
+ */
52
72
  output?: FileList | null;
53
73
  };
@@ -1,8 +0,0 @@
1
- package expo.modules.documentpicker
2
-
3
- import android.content.Context
4
- import expo.modules.core.BasePackage
5
-
6
- class DocumentPickerPackage : BasePackage() {
7
- override fun createExportedModules(context: Context) = listOf(DocumentPickerModule(context))
8
- }