1import { Platform } from 'expo-modules-core';
2
3import { DocumentPickerAsset, DocumentPickerOptions, DocumentPickerResult } from './types';
4
5export default {
6  get name(): string {
7    return 'ExpoDocumentPicker';
8  },
9
10  async getDocumentAsync({
11    type = '*/*',
12    multiple = false,
13  }: DocumentPickerOptions): Promise<DocumentPickerResult> {
14    // SSR guard
15    if (!Platform.isDOMAvailable) {
16      return { canceled: true, assets: null };
17    }
18
19    const input = document.createElement('input');
20    input.style.display = 'none';
21    input.setAttribute('type', 'file');
22    input.setAttribute('accept', Array.isArray(type) ? type.join(',') : type);
23    input.setAttribute('id', String(Math.random()));
24    if (multiple) {
25      input.setAttribute('multiple', 'multiple');
26    }
27
28    document.body.appendChild(input);
29
30    return new Promise((resolve, reject) => {
31      input.addEventListener('change', async () => {
32        if (input.files) {
33          const results: Promise<DocumentPickerAsset>[] = [];
34          for (let i = 0; i < input.files.length; i++) {
35            results.push(readFileAsync(input.files[i]));
36          }
37          try {
38            const assets = await Promise.all(results);
39            resolve({ canceled: false, assets, output: input.files });
40          } catch (e) {
41            reject(e);
42          }
43        } else {
44          resolve({ canceled: true, assets: null });
45        }
46
47        document.body.removeChild(input);
48      });
49
50      const event = new MouseEvent('click');
51      input.dispatchEvent(event);
52    });
53  },
54};
55
56function readFileAsync(targetFile: File): Promise<DocumentPickerAsset> {
57  return new Promise((resolve, reject) => {
58    const mimeType = targetFile.type;
59
60    const reader = new FileReader();
61    reader.onerror = () => {
62      reject(new Error(`Failed to read the selected media because the operation failed.`));
63    };
64    reader.onload = ({ target }) => {
65      const uri = (target as any).result;
66      resolve({
67        uri,
68        mimeType,
69        name: targetFile.name,
70        lastModified: targetFile.lastModified,
71        size: targetFile.size,
72        file: targetFile,
73      });
74    };
75
76    // Read in the image file as a binary string.
77    reader.readAsDataURL(targetFile);
78  });
79}
80