@react-native-documents/picker 9.3.1

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.
Files changed (139) hide show
  1. package/LICENSE.md +21 -0
  2. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  3. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  4. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  5. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  6. package/android/.gradle/8.9/gc.properties +0 -0
  7. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  8. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  9. package/android/.gradle/vcs-1/gc.properties +0 -0
  10. package/android/build.gradle +80 -0
  11. package/android/src/main/AndroidManifest.xml +3 -0
  12. package/android/src/main/java/com/reactnativedocumentpicker/CopyDestination.kt +12 -0
  13. package/android/src/main/java/com/reactnativedocumentpicker/DocumentMetadataBuilder.kt +79 -0
  14. package/android/src/main/java/com/reactnativedocumentpicker/FileOperations.kt +203 -0
  15. package/android/src/main/java/com/reactnativedocumentpicker/IntentFactory.kt +36 -0
  16. package/android/src/main/java/com/reactnativedocumentpicker/IsKnownTypeImpl.kt +40 -0
  17. package/android/src/main/java/com/reactnativedocumentpicker/MetadataGetter.kt +150 -0
  18. package/android/src/main/java/com/reactnativedocumentpicker/PickOptions.kt +63 -0
  19. package/android/src/main/java/com/reactnativedocumentpicker/PromiseWrapper.java +105 -0
  20. package/android/src/main/java/com/reactnativedocumentpicker/RNDocumentPickerModule.kt +352 -0
  21. package/android/src/main/java/com/reactnativedocumentpicker/RNDocumentPickerPackage.java +49 -0
  22. package/android/src/paper/java/com/reactnativedocumentpicker/NativeDocumentPickerSpec.java +69 -0
  23. package/ios/RCTConvert+RNDocumentPicker.h +8 -0
  24. package/ios/RCTConvert+RNDocumentPicker.mm +16 -0
  25. package/ios/RNDocumentPicker.h +19 -0
  26. package/ios/RNDocumentPicker.mm +128 -0
  27. package/ios/swift/DocPicker.swift +84 -0
  28. package/ios/swift/DocSaver.swift +41 -0
  29. package/ios/swift/DocumentMetadataBuilder.swift +69 -0
  30. package/ios/swift/FileOperations.swift +68 -0
  31. package/ios/swift/IsKnownTypeImpl.swift +42 -0
  32. package/ios/swift/LocalCopyResponse.swift +27 -0
  33. package/ios/swift/PickerBase.swift +78 -0
  34. package/ios/swift/PickerOptions.swift +44 -0
  35. package/ios/swift/PromiseSupport.swift +2 -0
  36. package/ios/swift/PromiseWrapper.swift +92 -0
  37. package/ios/swift/SaverOptions.swift +30 -0
  38. package/jest/build/jest/setup.js +70 -0
  39. package/jest/build/src/errors.js +47 -0
  40. package/jest/build/src/fileTypes.js +53 -0
  41. package/jest/build/src/index.js +22 -0
  42. package/jest/build/src/isKnownType.js +16 -0
  43. package/jest/build/src/keepLocalCopy.js +17 -0
  44. package/jest/build/src/pick.js +50 -0
  45. package/jest/build/src/pickDirectory.js +31 -0
  46. package/jest/build/src/release.js +22 -0
  47. package/jest/build/src/saveDocuments.js +40 -0
  48. package/jest/build/src/spec/NativeDocumentPicker.js +5 -0
  49. package/jest/build/src/types.js +4 -0
  50. package/jest/build/src/validateTypes.js +23 -0
  51. package/jest/build/tsconfig.tsbuildinfo +1 -0
  52. package/lib/commonjs/errors.js +53 -0
  53. package/lib/commonjs/errors.js.map +1 -0
  54. package/lib/commonjs/fileTypes.js +84 -0
  55. package/lib/commonjs/fileTypes.js.map +1 -0
  56. package/lib/commonjs/index.js +74 -0
  57. package/lib/commonjs/index.js.map +1 -0
  58. package/lib/commonjs/isKnownType.js +27 -0
  59. package/lib/commonjs/isKnownType.js.map +1 -0
  60. package/lib/commonjs/keepLocalCopy.js +34 -0
  61. package/lib/commonjs/keepLocalCopy.js.map +1 -0
  62. package/lib/commonjs/package.json +1 -0
  63. package/lib/commonjs/pick.js +93 -0
  64. package/lib/commonjs/pick.js.map +1 -0
  65. package/lib/commonjs/pickDirectory.js +71 -0
  66. package/lib/commonjs/pickDirectory.js.map +1 -0
  67. package/lib/commonjs/release.js +31 -0
  68. package/lib/commonjs/release.js.map +1 -0
  69. package/lib/commonjs/saveDocuments.js +55 -0
  70. package/lib/commonjs/saveDocuments.js.map +1 -0
  71. package/lib/commonjs/spec/NativeDocumentPicker.js +16 -0
  72. package/lib/commonjs/spec/NativeDocumentPicker.js.map +1 -0
  73. package/lib/commonjs/types.js +37 -0
  74. package/lib/commonjs/types.js.map +1 -0
  75. package/lib/commonjs/validateTypes.js +29 -0
  76. package/lib/commonjs/validateTypes.js.map +1 -0
  77. package/lib/module/errors.js +48 -0
  78. package/lib/module/errors.js.map +1 -0
  79. package/lib/module/fileTypes.js +81 -0
  80. package/lib/module/fileTypes.js.map +1 -0
  81. package/lib/module/index.js +13 -0
  82. package/lib/module/index.js.map +1 -0
  83. package/lib/module/isKnownType.js +24 -0
  84. package/lib/module/isKnownType.js.map +1 -0
  85. package/lib/module/keepLocalCopy.js +31 -0
  86. package/lib/module/keepLocalCopy.js.map +1 -0
  87. package/lib/module/package.json +1 -0
  88. package/lib/module/pick.js +90 -0
  89. package/lib/module/pick.js.map +1 -0
  90. package/lib/module/pickDirectory.js +68 -0
  91. package/lib/module/pickDirectory.js.map +1 -0
  92. package/lib/module/release.js +26 -0
  93. package/lib/module/release.js.map +1 -0
  94. package/lib/module/saveDocuments.js +52 -0
  95. package/lib/module/saveDocuments.js.map +1 -0
  96. package/lib/module/spec/NativeDocumentPicker.js +13 -0
  97. package/lib/module/spec/NativeDocumentPicker.js.map +1 -0
  98. package/lib/module/types.js +33 -0
  99. package/lib/module/types.js.map +1 -0
  100. package/lib/module/validateTypes.js +24 -0
  101. package/lib/module/validateTypes.js.map +1 -0
  102. package/lib/typescript/errors.d.ts +40 -0
  103. package/lib/typescript/errors.d.ts.map +1 -0
  104. package/lib/typescript/fileTypes.d.ts +94 -0
  105. package/lib/typescript/fileTypes.d.ts.map +1 -0
  106. package/lib/typescript/index.d.ts +13 -0
  107. package/lib/typescript/index.d.ts.map +1 -0
  108. package/lib/typescript/isKnownType.d.ts +41 -0
  109. package/lib/typescript/isKnownType.d.ts.map +1 -0
  110. package/lib/typescript/keepLocalCopy.d.ts +46 -0
  111. package/lib/typescript/keepLocalCopy.d.ts.map +1 -0
  112. package/lib/typescript/pick.d.ts +84 -0
  113. package/lib/typescript/pick.d.ts.map +1 -0
  114. package/lib/typescript/pickDirectory.d.ts +62 -0
  115. package/lib/typescript/pickDirectory.d.ts.map +1 -0
  116. package/lib/typescript/release.d.ts +24 -0
  117. package/lib/typescript/release.d.ts.map +1 -0
  118. package/lib/typescript/saveDocuments.d.ts +55 -0
  119. package/lib/typescript/saveDocuments.d.ts.map +1 -0
  120. package/lib/typescript/spec/NativeDocumentPicker.d.ts +29 -0
  121. package/lib/typescript/spec/NativeDocumentPicker.d.ts.map +1 -0
  122. package/lib/typescript/types.d.ts +95 -0
  123. package/lib/typescript/types.d.ts.map +1 -0
  124. package/lib/typescript/validateTypes.d.ts +3 -0
  125. package/lib/typescript/validateTypes.d.ts.map +1 -0
  126. package/package.json +92 -0
  127. package/react-native-document-picker.podspec +30 -0
  128. package/src/errors.ts +49 -0
  129. package/src/fileTypes.ts +92 -0
  130. package/src/index.ts +47 -0
  131. package/src/isKnownType.ts +48 -0
  132. package/src/keepLocalCopy.ts +51 -0
  133. package/src/pick.ts +151 -0
  134. package/src/pickDirectory.ts +93 -0
  135. package/src/release.ts +36 -0
  136. package/src/saveDocuments.ts +99 -0
  137. package/src/spec/NativeDocumentPicker.ts +31 -0
  138. package/src/types.ts +119 -0
  139. package/src/validateTypes.ts +26 -0
@@ -0,0 +1,92 @@
1
+ import { Platform } from 'react-native'
2
+
3
+ // TODO split this into platform-specific files, and / or topic-specific files
4
+
5
+ const mimeTypes = Object.freeze({
6
+ allFiles: '*/*',
7
+ audio: 'audio/*',
8
+ csv: ['text/csv', 'text/comma-separated-values'],
9
+ doc: 'application/msword',
10
+ docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
11
+ images: 'image/*',
12
+ pdf: 'application/pdf',
13
+ plainText: 'text/plain',
14
+ json: 'application/json',
15
+ ppt: 'application/vnd.ms-powerpoint',
16
+ pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
17
+ video: 'video/*',
18
+ xls: 'application/vnd.ms-excel',
19
+ xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
20
+ zip: 'application/zip',
21
+ } as const) //satisfies TypeOfFileTypes
22
+
23
+ const utis = Object.freeze({
24
+ allFiles: 'public.item',
25
+ audio: 'public.audio',
26
+ csv: 'public.comma-separated-values-text',
27
+ doc: 'com.microsoft.word.doc',
28
+ docx: 'org.openxmlformats.wordprocessingml.document',
29
+ images: 'public.image',
30
+ pdf: 'com.adobe.pdf',
31
+ plainText: 'public.plain-text',
32
+ json: 'public.json',
33
+ ppt: 'com.microsoft.powerpoint.ppt',
34
+ pptx: 'org.openxmlformats.presentationml.presentation',
35
+ video: 'public.movie',
36
+ xls: 'com.microsoft.excel.xls',
37
+ xlsx: 'org.openxmlformats.spreadsheetml.sheet',
38
+ zip: 'public.zip-archive',
39
+ } as const) // satisfies TypeOfFileTypes
40
+
41
+ const perPlatformTypes = {
42
+ android: mimeTypes,
43
+ ios: utis,
44
+ // unsupported, but added to make TS happy
45
+ macos: utis,
46
+ windows: mimeTypes,
47
+ web: mimeTypes,
48
+ }
49
+
50
+ /**
51
+ * @hidden
52
+ * */
53
+ export const types = perPlatformTypes[Platform.OS]
54
+
55
+ type ValuesOf<T> = T[keyof T]
56
+ type Flatten<T> = T extends Array<infer U> ? U : T
57
+
58
+ type AllMimeTypes = Flatten<ValuesOf<typeof mimeTypes>>
59
+ type AllAppleUTIs = ValuesOf<typeof utis>
60
+
61
+ /**
62
+ * You'd rarely use this type directly.
63
+ * It represents the predefined file types which are exported as `types` and can be used to limit the kinds of files that can be picked.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import {
68
+ * pick,
69
+ * types,
70
+ * } from '@react-native-documents/picker'
71
+ * // ...
72
+ * const result = await pick({
73
+ * type: [types.pdf, types.docx],
74
+ * })
75
+ * ```
76
+ * */
77
+ export type PredefinedFileTypes = Flatten<AllMimeTypes> | AllAppleUTIs
78
+
79
+ // export type PlatformTypes = typeof perPlatformTypes
80
+
81
+ // ensure shapes of platformTypes are the same: https://stackoverflow.com/a/67027347/2070942
82
+ // let me know if there's a nicer way
83
+
84
+ type AssertEqualKeys<T1 extends object, T2 extends object> = [
85
+ keyof T1 extends keyof T2 ? 1 : 0,
86
+ keyof T2 extends keyof T1 ? 1 : 0,
87
+ ] extends [1, 1]
88
+ ? true
89
+ : false
90
+
91
+ const mimesAndUtisAreEqual: AssertEqualKeys<typeof mimeTypes, typeof utis> = true
92
+ export const typesAreEqual = mimesAndUtisAreEqual
package/src/index.ts ADDED
@@ -0,0 +1,47 @@
1
+ export { isKnownType, type IsKnownTypeResponse, type IsKnownTypeOptions } from './isKnownType'
2
+ export {
3
+ keepLocalCopy,
4
+ type KeepLocalCopyOptions,
5
+ type KeepLocalCopyResponse,
6
+ type FileToCopy,
7
+ } from './keepLocalCopy'
8
+
9
+ // TODO expose from /fileTypes?
10
+ export { types, type PredefinedFileTypes } from './fileTypes'
11
+ export { errorCodes, isErrorWithCode } from './errors'
12
+ export { pickDirectory } from './pickDirectory'
13
+ export type {
14
+ PickDirectoryResponse,
15
+ DirectoryPickerOptions,
16
+ DirectoryPickerOptionsLongTerm,
17
+ DirectoryPickerResponse,
18
+ DirectoryPickerResponseLongTerm,
19
+ DirectoryPickerOptionsBase,
20
+ } from './pickDirectory'
21
+ export { pick, type DocumentPickerOptionsBase } from './pick'
22
+ export {
23
+ saveDocuments,
24
+ type SaveDocumentsResponse,
25
+ type SaveDocumentsOptions,
26
+ } from './saveDocuments'
27
+ export type {
28
+ NonEmptyArray,
29
+ TransitionStyle,
30
+ BookmarkingResponse,
31
+ DocumentPickerResponse,
32
+ PresentationStyle,
33
+ VirtualFileMeta,
34
+ } from './types'
35
+ export type {
36
+ DocumentPickerOptions,
37
+ DocumentPickerOptionsImport,
38
+ DocumentPickerOptionsOpenOnce,
39
+ DocumentPickerOptionsOpenLongTerm,
40
+ DocumentPickerResponseOpenLongTerm,
41
+ } from './pick'
42
+ export type { LocalCopyResponse } from './spec/NativeDocumentPicker'
43
+ export {
44
+ releaseLongTermAccess,
45
+ releaseSecureAccess,
46
+ type ReleaseLongTermAccessResult,
47
+ } from './release'
@@ -0,0 +1,48 @@
1
+ import { NativeDocumentPicker } from './spec/NativeDocumentPicker'
2
+
3
+ /**
4
+ * The result of calling {@link isKnownType}
5
+ * */
6
+ export type IsKnownTypeResponse = {
7
+ /**
8
+ * On iOS, this is true if the type is known to the device. That means it can be used with the document picker to filter what files can be picked.
9
+ * On Android, this is true if the internal mime type database contains the given value.
10
+ * */
11
+ isKnown: boolean
12
+ /**
13
+ * the preferred filename extension for the given value, if any
14
+ * */
15
+ preferredFilenameExtension: string | null
16
+ /**
17
+ * the mime type for the given value, if any
18
+ * */
19
+ mimeType: string | null
20
+ /**
21
+ * the UTType identifier for the given value, if any
22
+ * */
23
+ UTType: string | null
24
+ }
25
+
26
+ export type IsKnownTypeOptions = {
27
+ /**
28
+ * the kind of value you're passing
29
+ * */
30
+ kind: 'UTType' | 'mimeType' | 'extension'
31
+ /**
32
+ * the value you're checking, for example: application/pdf, com.adobe.pdf, pdf
33
+ * */
34
+ value: string
35
+ }
36
+
37
+ /**
38
+ *
39
+ * Checks if the given value (which can be a file extension, UTType identifier or mime) is known to the system.
40
+ * Also returns the mime type which you can use to filter files on Android.
41
+ *
42
+ * @group DocumentPicker
43
+ * */
44
+ export function isKnownType(options: IsKnownTypeOptions): IsKnownTypeResponse {
45
+ const { kind, value } = options
46
+ const result = NativeDocumentPicker.isKnownType(kind, value) as IsKnownTypeResponse
47
+ return result
48
+ }
@@ -0,0 +1,51 @@
1
+ import type { NonEmptyArray } from './types'
2
+ import { type LocalCopyResponse, NativeDocumentPicker } from './spec/NativeDocumentPicker'
3
+
4
+ /**
5
+ * Parameter of {@link keepLocalCopy}. Object type representing the file(s) whose copy should be kept in the app's storage.
6
+ * */
7
+ export type FileToCopy = {
8
+ /**
9
+ * The uri to keep a local copy of. This would be a `content://` uri (Android), or a `file://` uri (iOS) that the user has previously picked.
10
+ * */
11
+ uri: string
12
+ /**
13
+ * The name of the resulting file, with the file extension. You can use the `name` field from the response of the `pick()` method.
14
+ *
15
+ * Example: someFile.pdf
16
+ *
17
+ * */
18
+ fileName: string
19
+ /**
20
+ * Only for Android virtual files: the type of the file to export to. For example, `application/pdf` or `text/plain`.
21
+ * Use one of the values from `convertibleToMimeTypes` from the response of the `pick()` method: {@link DocumentPickerResponse}.
22
+ * */
23
+ convertVirtualFileToType?: string
24
+ }
25
+ /**
26
+ * options for {@link keepLocalCopy}
27
+ *
28
+ * */
29
+ export type KeepLocalCopyOptions = {
30
+ files: NonEmptyArray<FileToCopy>
31
+ destination: 'cachesDirectory' | 'documentDirectory'
32
+ }
33
+
34
+ /**
35
+ * Result of the call to {@link keepLocalCopy}. Please note the promise always resolves, even if there was an error processing any uri(s) (as indicated by the `status` field, and `copyError` field).
36
+ * */
37
+ export type KeepLocalCopyResponse = NonEmptyArray<LocalCopyResponse>
38
+
39
+ /**
40
+ * Makes the file available in the app's storage. The behavior is different on iOS and Android, and for simple use cases (such as uploading file to remote server), you may not need to call this method at all.
41
+ *
42
+ * On Android, it can be used to "convert" a `content://` Uri into a local file. It also "exports" virtual files (such as Google docs or sheets) into local files.
43
+ *
44
+ * However, note that for some use cases, such as uploading the picked file to a server, you may not need to call `keepLocalCopy` at all. React Native's `fetch` can handle `content://` uris.
45
+ *
46
+ * @group DocumentPicker
47
+ * */
48
+ export function keepLocalCopy(options: KeepLocalCopyOptions): Promise<KeepLocalCopyResponse> {
49
+ const response = NativeDocumentPicker.keepLocalCopy(options)
50
+ return response as Promise<KeepLocalCopyResponse>
51
+ }
package/src/pick.ts ADDED
@@ -0,0 +1,151 @@
1
+ import { NativeDocumentPicker } from './spec/NativeDocumentPicker'
2
+
3
+ import { PredefinedFileTypes, types } from './fileTypes'
4
+ import type {
5
+ BookmarkingResponse,
6
+ DocumentPickerResponse,
7
+ NonEmptyArray,
8
+ TransitionStyle,
9
+ PresentationStyle,
10
+ } from './types'
11
+ import { Platform } from 'react-native'
12
+ import { safeValidate } from './validateTypes'
13
+
14
+ /**
15
+ * Base options object for the document picker.
16
+ * You'd rarely use this type directly, but instead use one of
17
+ *
18
+ * {@link DocumentPickerOptionsImport}, {@link DocumentPickerOptionsOpenOnce} or {@link DocumentPickerOptionsOpenLongTerm}
19
+ *
20
+ * which extend this type
21
+ * @group pick() types
22
+ */
23
+ export type DocumentPickerOptionsBase = {
24
+ /**
25
+ * Specify file type(s) that you want to pick. Use `types` for some predefined values.
26
+ * */
27
+ type?: string | PredefinedFileTypes | Array<PredefinedFileTypes | string>
28
+
29
+ // TODO: implement these
30
+ // initialDirectoryUrl?: string
31
+ // showFileExtensions?: boolean
32
+ // localOnly?: boolean
33
+ /**
34
+ * Whether to allow multiple files to be picked. False by default.
35
+ * */
36
+ allowMultiSelection?: boolean
37
+ // allowVirtualFiles is available for ACTION_OPEN_DOCUMENT only (or so it seems)
38
+ // https://developer.android.com/reference/android/content/Intent#ACTION_OPEN_DOCUMENT
39
+ // https://developer.android.com/reference/android/content/Intent#ACTION_GET_CONTENT
40
+ /**
41
+ * Android only - Whether to allow virtual files (such as Google docs or sheets) to be picked. False by default.
42
+ * */
43
+ allowVirtualFiles?: boolean
44
+ /**
45
+ * iOS only - Controls how the picker is presented, e.g. on an iPad you may want to present it fullscreen. Defaults to `pageSheet`.
46
+ * */
47
+ presentationStyle?: PresentationStyle
48
+ /**
49
+ * iOS only - Configures the transition style of the picker. Defaults to coverVertical, when the picker is presented, its view slides up from the bottom of the screen.
50
+ * */
51
+ transitionStyle?: TransitionStyle
52
+ }
53
+
54
+ /**
55
+ * Present the document picker in import mode.
56
+ *
57
+ * @group pick() types
58
+ */
59
+ export type DocumentPickerOptionsImport = DocumentPickerOptionsBase & {
60
+ mode?: 'import'
61
+ requestLongTermAccess?: never
62
+ }
63
+ /**
64
+ * Present the document picker in open mode, with permissions to access the file for a limited time (until the app terminates).
65
+ *
66
+ * @group pick() types
67
+ */
68
+ export type DocumentPickerOptionsOpenOnce = DocumentPickerOptionsBase & {
69
+ mode: 'open'
70
+ requestLongTermAccess?: false
71
+ }
72
+ /**
73
+ * Present the document picker in open mode, with long-term permissions to access the opened file.
74
+ *
75
+ * @group pick() types
76
+ */
77
+ export type DocumentPickerOptionsOpenLongTerm = DocumentPickerOptionsBase & {
78
+ mode: 'open'
79
+ requestLongTermAccess: true
80
+ }
81
+
82
+ type DocumentPickerOptionsOpen = DocumentPickerOptionsOpenOnce | DocumentPickerOptionsOpenLongTerm
83
+ /**
84
+ * @hidden
85
+ */
86
+ export type DocumentPickerOptions = DocumentPickerOptionsImport | DocumentPickerOptionsOpen
87
+
88
+ /**
89
+ * The result of calling {@link pick} with `mode: 'open'` and `requestLongTermAccess: true`
90
+ *
91
+ * @group pick() types
92
+ */
93
+ export type DocumentPickerResponseOpenLongTerm = DocumentPickerResponse & BookmarkingResponse
94
+
95
+ // TODO not entirely sure this is a good idea but let's try
96
+ type PickResponse<O extends DocumentPickerOptions> = Promise<
97
+ O extends DocumentPickerOptionsOpenLongTerm
98
+ ? NonEmptyArray<DocumentPickerResponseOpenLongTerm>
99
+ : NonEmptyArray<DocumentPickerResponse>
100
+ >
101
+
102
+ type DoPickOptions = DocumentPickerOptionsBase & { mode: 'import' | 'open'; type: string[] }
103
+
104
+ /**
105
+ * The method for picking a file, both for `import` and `open` modes.
106
+ *
107
+ * For result types, see {@link DocumentPickerResponse} or {@link DocumentPickerResponseOpenLongTerm}.
108
+ *
109
+ * For options, see {@link DocumentPickerOptionsImport}, {@link DocumentPickerOptionsOpenOnce} or {@link DocumentPickerOptionsOpenLongTerm}.
110
+ *
111
+ * @group DocumentPicker
112
+ * */
113
+ export async function pick<O extends DocumentPickerOptions>(options?: O): PickResponse<O> {
114
+ const type: string[] = (() => {
115
+ if (!options?.type) {
116
+ return [types.allFiles]
117
+ }
118
+ const newType = Array.isArray(options.type) ? options.type : [options.type]
119
+ return newType.flat().map((it) => it.trim())
120
+ })()
121
+ const newOpts: DoPickOptions = {
122
+ mode: 'import',
123
+ // allowMultiSelection must be false to maintain old (v5) behavior
124
+ allowMultiSelection: false,
125
+ allowVirtualFiles: false,
126
+ ...options,
127
+ type,
128
+ }
129
+
130
+ if (!newOpts.type.every((it: unknown) => typeof it === 'string')) {
131
+ throw new TypeError(
132
+ `Unexpected type option in ${newOpts.type}, did you try using a DocumentPicker.types.* that does not exist?`,
133
+ )
134
+ }
135
+
136
+ if ('mode' in newOpts && !['import', 'open'].includes(newOpts.mode)) {
137
+ throw new TypeError('Invalid mode option: ' + newOpts.mode)
138
+ }
139
+
140
+ const response: Promise<DocumentPickerResponse[]> = NativeDocumentPicker.pick(newOpts)
141
+ const awaitedResult = await response
142
+ for (const res of awaitedResult) {
143
+ if (Platform.OS === 'android') {
144
+ res.hasRequestedType = safeValidate(newOpts.type, res)
145
+ } else {
146
+ res.hasRequestedType = true
147
+ }
148
+ }
149
+
150
+ return awaitedResult as unknown as PickResponse<O>
151
+ }
@@ -0,0 +1,93 @@
1
+ import { BookmarkingResponse, PresentationStyle, type TransitionStyle } from './types'
2
+ import { Platform } from 'react-native'
3
+ import { NativeDocumentPicker } from './spec/NativeDocumentPicker'
4
+
5
+ /**
6
+ * Base options object for the directory picker. They only slightly influence the appearance of the picker modal on iOS.
7
+ * You'd rarely use this type directly, but instead use {@link DirectoryPickerOptions}
8
+ *
9
+ * which extend this type
10
+ * @group pickDirectory() types
11
+ */
12
+ export type DirectoryPickerOptionsBase = {
13
+ /**
14
+ * iOS only - Controls how the picker is presented, e.g. on an iPad you may want to present it fullscreen. Defaults to `pageSheet`.
15
+ * */
16
+ presentationStyle?: PresentationStyle
17
+ /**
18
+ * iOS only - Configures the transition style of the picker. Defaults to coverVertical, when the picker is presented, its view slides up from the bottom of the screen.
19
+ * */
20
+ transitionStyle?: TransitionStyle
21
+ }
22
+ /**
23
+ * @hidden
24
+ * */
25
+ export type DirectoryPickerOptionsLongTerm = DirectoryPickerOptionsBase & {
26
+ requestLongTermAccess: true
27
+ }
28
+ /**
29
+ * Options for {@link pickDirectory}.
30
+ *
31
+ * @group pickDirectory() types
32
+ * */
33
+ export type DirectoryPickerOptions = DirectoryPickerOptionsBase & { requestLongTermAccess: boolean }
34
+
35
+ /**
36
+ * This object represents the response from the directory picker, when long-term access was not requested.
37
+ *
38
+ * @group pickDirectory() types
39
+ * */
40
+ export type DirectoryPickerResponse = {
41
+ /**
42
+ * The (percent-encoded) directory selected by user.
43
+ * */
44
+ uri: string
45
+ }
46
+ /**
47
+ * This object represents the response from the directory picker, when long-term access was requested.
48
+ *
49
+ * @group pickDirectory() types
50
+ * */
51
+ export type DirectoryPickerResponseLongTerm = DirectoryPickerResponse & BookmarkingResponse
52
+
53
+ // TODO not entirely sure this is a good idea but let's try
54
+ /**
55
+ * You likely won't use this type directly, but instead use {@link DirectoryPickerResponse} or {@link DirectoryPickerResponseLongTerm}.
56
+ *
57
+ * @group pickDirectory() types
58
+ * */
59
+ export type PickDirectoryResponse<O extends DirectoryPickerOptions> = Promise<
60
+ O extends DirectoryPickerOptionsLongTerm
61
+ ? DirectoryPickerResponseLongTerm
62
+ : DirectoryPickerResponse
63
+ >
64
+
65
+ /**
66
+ * Opens a directory picker.
67
+ *
68
+ * @group DocumentPicker
69
+ * */
70
+ export async function pickDirectory<O extends DirectoryPickerOptions>(
71
+ options?: O,
72
+ ): PickDirectoryResponse<O> {
73
+ const optionsOverride = (() => {
74
+ if (Platform.OS === 'ios') {
75
+ return {
76
+ ...options,
77
+ mode: 'open',
78
+ allowMultiSelection: false,
79
+ type: ['public.folder'],
80
+ }
81
+ } else {
82
+ return {
83
+ // technically, "mode" is ignored here, and we shouldn't need to specify anything but the PickOptions data class
84
+ // requires mode to be set
85
+ mode: 'open',
86
+ ...options,
87
+ }
88
+ }
89
+ })()
90
+ return NativeDocumentPicker.pickDirectory(optionsOverride) as unknown as Promise<
91
+ PickDirectoryResponse<O>
92
+ >
93
+ }
package/src/release.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { NativeDocumentPicker } from './spec/NativeDocumentPicker'
2
+
3
+ /**
4
+ * For each uri whose release was requested, the result will contain an object with the uri and a status.
5
+ * */
6
+ export type ReleaseLongTermAccessResult = Array<
7
+ | {
8
+ uri: string
9
+ status: 'success'
10
+ }
11
+ | {
12
+ uri: string
13
+ status: 'error'
14
+ errorMessage: string
15
+ }
16
+ >
17
+
18
+ /**
19
+ * Android only - Releases long-term access to the given URIs. There's no need to call this method on iOS - there's no iOS equivalent.
20
+ *
21
+ * See [Android documentation](https://developer.android.com/reference/android/content/ContentResolver#releasePersistableUriPermission(android.net.Uri,%20int)) for more information.
22
+ */
23
+ export const releaseLongTermAccess = async (
24
+ uris: string[],
25
+ ): Promise<ReleaseLongTermAccessResult> => {
26
+ return NativeDocumentPicker.releaseLongTermAccess(uris) as Promise<ReleaseLongTermAccessResult>
27
+ }
28
+
29
+ /**
30
+ * iOS only - Releases (stops) secure access to the given URIs. Use with URIs obtained with Open mode or with the Directory Picker.
31
+ * See [iOS documentation](https://developer.apple.com/documentation/foundation/nsurl/1413736-stopaccessingsecurityscopedresou) for more information.
32
+ * There's no need to call this method on Android - there's no equivalent method on Android.
33
+ * */
34
+ export const releaseSecureAccess = async (uris: string[]): Promise<null> => {
35
+ return NativeDocumentPicker.releaseSecureAccess(uris)
36
+ }
@@ -0,0 +1,99 @@
1
+ import { NativeDocumentPicker } from './spec/NativeDocumentPicker'
2
+
3
+ import type { DocumentPickerResponse, NonEmptyArray } from './types'
4
+ import { Platform } from 'react-native'
5
+
6
+ /**
7
+ * Options object for the {@link saveDocuments} method. `sourceUris` is the only required field.
8
+ *
9
+ * @group saveDocuments() types
10
+ */
11
+ export type SaveDocumentsOptions = {
12
+ /**
13
+ * The source URIs of the files to save, percentage-encoded. Android only allows to save one file at a time, iOS allows multiple.
14
+ * */
15
+ sourceUris: string[]
16
+ /**
17
+ * Android-only: The MIME type of the file to be stored.
18
+ * It is recommended to provide this value, otherwise the system will try to infer it from the sourceUri using ContentResolver.
19
+ * */
20
+ mimeType?: string
21
+ /**
22
+ * Android-only: The suggested title of the file to be stored, which will be pre-filled in the UI.
23
+ * On iOS, the target name is taken from the source uri, and is changeable only when exactly one file is being saved.
24
+ * */
25
+ fileName?: string
26
+ /**
27
+ * iOS-only: Whether to copy the file to a new location, or move it (default).
28
+ * On Android, file is always copied.
29
+ * */
30
+ copy?: boolean
31
+ // initialUri?: string
32
+ }
33
+
34
+ /**
35
+ * The result of calling {@link saveDocuments}. It is very unlikely that the metadata fields would be `null`, but in theory, it can happen.
36
+ *
37
+ * @group saveDocuments() types
38
+ */
39
+ export type SaveDocumentsResponse = {
40
+ /**
41
+ * The target URI - the one user saved to. This is a percent-encoded `content://` uri (Android), or a `file://` uri (iOS).
42
+ * */
43
+ uri: string
44
+ /**
45
+ * The name of the file that user entered, including extension.
46
+ * */
47
+ name: string | null
48
+ /**
49
+ * Error in case the file could not be written or some metadata could not be obtained.
50
+ * */
51
+ error: string | null
52
+
53
+ // type: string | null
54
+ // nativeType: string | null
55
+
56
+ // later if needed; iOS doesn't allow to read the info from the target file
57
+ // should be the same as the source anyway
58
+ // size: number | null
59
+ }
60
+
61
+ /**
62
+ * The method for opening a "save as" dialog and saving source file(s) to a new location.
63
+ *
64
+ * On Android, only one file can be saved at a time.
65
+ *
66
+ * @group DocumentPicker
67
+ * */
68
+ export async function saveDocuments(
69
+ options: SaveDocumentsOptions,
70
+ ): Promise<NonEmptyArray<SaveDocumentsResponse>> {
71
+ const writeDocumentResponse = await (async () => {
72
+ if (Platform.OS === 'android') {
73
+ const length = options.sourceUris.length
74
+ if (length > 1) {
75
+ console.warn(`DocumentPicker.saveDocuments: Android only allows to save one file at a time.\n
76
+ You provided an array with ${length} entries.`)
77
+ }
78
+ // making this division into 2 calls might be an overkill... but who knows
79
+ const objectWithSingleUri = await NativeDocumentPicker.saveDocument(options)
80
+ const response = await NativeDocumentPicker.writeDocuments(objectWithSingleUri)
81
+ return response as NonEmptyArray<DocumentPickerResponse>
82
+ } else {
83
+ return NativeDocumentPicker.writeDocuments(options) as Promise<
84
+ NonEmptyArray<DocumentPickerResponse>
85
+ >
86
+ }
87
+ })()
88
+ return writeDocumentResponse.map(keepOnlySpecifiedFields) as NonEmptyArray<SaveDocumentsResponse>
89
+ }
90
+
91
+ function keepOnlySpecifiedFields(source: DocumentPickerResponse): SaveDocumentsResponse {
92
+ return {
93
+ uri: source.uri,
94
+ name: source.name,
95
+ error: source.error,
96
+ // type: source.type,
97
+ // nativeType: source.nativeType,
98
+ }
99
+ }
@@ -0,0 +1,31 @@
1
+ import type { TurboModule } from 'react-native'
2
+ import { TurboModuleRegistry } from 'react-native'
3
+ import { DocumentPickerResponse } from '../types'
4
+
5
+ /**
6
+ * Indicates, for each Uri that was passed to {@link keepLocalCopy}, whether the local copy was successfully created or not.
7
+ *
8
+ * If the copy was successful, the status field is `success` and `localUri` contains the local Uri.
9
+ * If the copy was not successful, the status field is `error` and `copyError` field contains the error message.
10
+ * */
11
+ export type LocalCopyResponse =
12
+ | {
13
+ status: 'success'
14
+ sourceUri: string
15
+ localUri: string
16
+ }
17
+ | { status: 'error'; sourceUri: string; copyError: string }
18
+
19
+ export interface Spec extends TurboModule {
20
+ // we use "Object" to have backward compatibility with old arch
21
+ pick(options: Object): Promise<DocumentPickerResponse[]>
22
+ saveDocument(options: Object): Promise<Object>
23
+ writeDocuments(options: Object): Promise<Object[]>
24
+ pickDirectory(options: Object): Promise<Object>
25
+ keepLocalCopy(options: Object): Promise<LocalCopyResponse[]>
26
+ isKnownType(kind: string, value: string): Object
27
+ releaseSecureAccess(uris: string[]): Promise<null>
28
+ releaseLongTermAccess(uris: string[]): Promise<Object>
29
+ }
30
+
31
+ export const NativeDocumentPicker = TurboModuleRegistry.getEnforcing<Spec>('RNDocumentPicker')