@lowdefy/blocks-files 0.0.0-experimental-20260707082859

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.
@@ -0,0 +1,136 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import uploadTheme from '../../schemas/uploadTheme.js';
16
+ export default {
17
+ category: 'input',
18
+ icons: [
19
+ 'AiOutlineLoading',
20
+ 'AiOutlineCamera'
21
+ ],
22
+ valueType: 'object',
23
+ cssKeys: {
24
+ element: 'The outer block wrapper around the upload card and list.',
25
+ trigger: 'The antd upload trigger card (.ant-upload-select) — the dashed upload tile.',
26
+ list: 'The uploaded photos list container.',
27
+ item: 'Each uploaded photo tile in the list.',
28
+ icon: 'The icon shown inside the upload trigger card (camera / loading).',
29
+ title: 'The title text shown below the icon inside the upload trigger card.'
30
+ },
31
+ events: {
32
+ onBeforeUpload: {
33
+ description: 'Triggered before upload starts. If any action throws, the upload is cancelled.',
34
+ event: {
35
+ file: 'The raw File object selected by the user.'
36
+ }
37
+ },
38
+ onChange: {
39
+ description: 'Triggered when the upload state is changing. With emitFileContent, triggered once the file content has been read, with the block value ({ file, fileList }) as the event, where file includes the base64 content.'
40
+ },
41
+ onProgress: {
42
+ description: 'Triggered when the upload state is in progress.',
43
+ event: {
44
+ file: 'The file being uploaded.',
45
+ fileList: 'The full list of files.'
46
+ }
47
+ },
48
+ onSuccess: {
49
+ description: 'Triggered when the upload state is done uploading.',
50
+ event: {
51
+ file: 'The uploaded file.',
52
+ fileList: 'The full list of files.'
53
+ }
54
+ },
55
+ onRemove: {
56
+ description: 'Triggered when the upload has been removed.',
57
+ event: {
58
+ file: 'The removed file.',
59
+ fileList: 'The full list of files.'
60
+ }
61
+ },
62
+ onError: {
63
+ description: 'Triggered when the upload has failed.',
64
+ event: {
65
+ file: 'The file that failed.',
66
+ fileList: 'The full list of files.'
67
+ }
68
+ }
69
+ },
70
+ properties: {
71
+ type: 'object',
72
+ properties: {
73
+ title: {
74
+ type: 'string',
75
+ description: "Title of the file input to be displayed instead of 'Upload image'.",
76
+ default: 'Upload image'
77
+ },
78
+ disabled: {
79
+ type: 'boolean',
80
+ description: 'Disable the file input.'
81
+ },
82
+ emitFileContent: {
83
+ type: 'boolean',
84
+ default: false,
85
+ description: 'Instead of uploading, read the file and emit { name, size, type, content } — content a base64 string — as the block value and onChange event. Use with a CallAPI action to store the file with a server-side write request (e.g. AwsS3PutObject). Replaces uploadPolicyRequestId.'
86
+ },
87
+ maxCount: {
88
+ type: 'number',
89
+ description: 'Maximum number of files that can be uploaded.'
90
+ },
91
+ uploadPolicyRequestId: {
92
+ type: 'string',
93
+ description: 'Id of an upload-policy request (e.g. AwsS3PresignedPostPolicy, GcsSignedPostPolicy, AzureBlobUploadSas) that defines to which storage bucket and how the file should be uploaded. Required unless emitFileContent is true.',
94
+ docs: {
95
+ displayType: 'manual',
96
+ block: {
97
+ id: 'block_properties_uploadPolicyRequestId',
98
+ layout: {
99
+ _global: 'settings_input_layout'
100
+ },
101
+ type: 'Label',
102
+ required: true,
103
+ properties: {
104
+ title: 'uploadPolicyRequestId',
105
+ span: 8,
106
+ align: 'right'
107
+ },
108
+ blocks: [
109
+ {
110
+ id: 'block_properties_uploadPolicyRequestId_text',
111
+ type: 'Markdown',
112
+ style: {
113
+ color: '#8c8c8c'
114
+ },
115
+ properties: {
116
+ content: 'Id of an upload-policy request that defines to which storage bucket and how the file should be uploaded.'
117
+ }
118
+ }
119
+ ]
120
+ }
121
+ }
122
+ },
123
+ showUploadList: {
124
+ type: 'boolean',
125
+ default: true,
126
+ description: 'Whether to show default upload list.'
127
+ },
128
+ singleFile: {
129
+ type: 'boolean',
130
+ default: false,
131
+ description: 'Only allow a single file to be uploaded. Only one file can be selected in the prompt.'
132
+ },
133
+ theme: uploadTheme
134
+ }
135
+ }
136
+ };
@@ -0,0 +1,47 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { type } from '@lowdefy/helpers';
16
+ import readFileAsBase64 from '../../utils/readFileAsBase64.js';
17
+ // customRequest for emitFileContent mode: no upload happens. The file is read
18
+ // as base64 and { name, size, type, content } is emitted as the block value
19
+ // and onChange event, so the app can hand it to an API endpoint routine that
20
+ // stores it with a server-side write request.
21
+ const getEmitFileContent = ({ methods, setFileList, setLoading = ()=>null })=>async ({ file })=>{
22
+ if (type.isNone(file)) {
23
+ console.warn('File is undefined in getEmitFileContent');
24
+ return;
25
+ }
26
+ try {
27
+ setLoading(true);
28
+ file.content = await readFileAsBase64(file);
29
+ const nextState = await setFileList({
30
+ event: 'onSuccess',
31
+ file
32
+ });
33
+ await methods.triggerEvent({
34
+ name: 'onChange',
35
+ event: nextState
36
+ });
37
+ setLoading(false);
38
+ } catch (error) {
39
+ await setFileList({
40
+ event: 'onError',
41
+ file
42
+ });
43
+ setLoading(false);
44
+ throw error;
45
+ }
46
+ };
47
+ export default getEmitFileContent;
@@ -0,0 +1,48 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ const getFileFromEvent = async (event)=>{
16
+ const items = event.clipboardData.items;
17
+ for (const item of items){
18
+ if (item.kind === 'file') {
19
+ return item.getAsFile();
20
+ }
21
+ }
22
+ };
23
+ const getFileFromNavigator = async ()=>{
24
+ const items = await navigator.clipboard.read();
25
+ for (const item of items){
26
+ for (const type of item.types){
27
+ if (type === 'image/png' || type === 'image/jpeg') {
28
+ const blob = await item.getType(type);
29
+ return new File([
30
+ blob
31
+ ], 'clipboard.png', {
32
+ type: blob.type
33
+ });
34
+ }
35
+ }
36
+ }
37
+ };
38
+ const getOnPaste = ({ uploadRequest, properties })=>async (event)=>{
39
+ event?.preventDefault?.();
40
+ if (properties.disabled) return;
41
+ const file = event ? await getFileFromEvent(event) : await getFileFromNavigator();
42
+ if (!file) return;
43
+ file.uid = `${properties.fileName ?? file.name ?? 'clipboard'}-${Date.now()}`;
44
+ await uploadRequest({
45
+ file
46
+ });
47
+ };
48
+ export default getOnPaste;
@@ -0,0 +1,59 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { type } from '@lowdefy/helpers';
16
+ import getUploadPolicy from '../../utils/getUploadPolicy.js';
17
+ import uploadFile from '../../utils/uploadFile.js';
18
+ const getUploadRequest = ({ methods, setFileList, setLoading = ()=>null })=>async ({ file })=>{
19
+ if (type.isNone(file)) {
20
+ console.warn('File is undefined in getUploadRequest');
21
+ return;
22
+ }
23
+ try {
24
+ setLoading(true);
25
+ const descriptor = await getUploadPolicy({
26
+ methods,
27
+ file
28
+ });
29
+ // Object identity comes from the descriptor top level — the PUT branch
30
+ // has no fields object, so fields can never be the source of key/bucket.
31
+ file.bucket = descriptor.bucket;
32
+ file.key = descriptor.key;
33
+ file.percent = 20;
34
+ await uploadFile({
35
+ descriptor,
36
+ file,
37
+ onProgress: async (event)=>{
38
+ await setFileList({
39
+ event: 'onProgress',
40
+ file,
41
+ percent: event.loaded / event.total * 80 + 20
42
+ });
43
+ }
44
+ });
45
+ await setFileList({
46
+ event: 'onSuccess',
47
+ file
48
+ });
49
+ setLoading(false);
50
+ } catch (error) {
51
+ await setFileList({
52
+ event: 'onError',
53
+ file
54
+ });
55
+ setLoading(false);
56
+ throw error;
57
+ }
58
+ };
59
+ export default getUploadRequest;
@@ -0,0 +1,140 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { useState } from 'react';
16
+ import { type } from '@lowdefy/helpers';
17
+ const useFileList = ({ properties, methods, value = {} })=>{
18
+ const checkedValue = (value)=>{
19
+ let file = type.isObject(value?.file) ? value.file : null;
20
+ if (!file && type.isObject(value?.fileList?.[0])) {
21
+ file = value.fileList[0];
22
+ }
23
+ const fileList = type.isArray(value?.fileList) ? value.fileList : [];
24
+ if (properties.singleFile === true) {
25
+ fileList.splice(1);
26
+ }
27
+ if (type.isInt(properties.maxCount)) {
28
+ fileList.splice(properties.maxCount);
29
+ }
30
+ return {
31
+ file,
32
+ fileList
33
+ };
34
+ };
35
+ const [state, setState] = useState(checkedValue(value));
36
+ const setValue = (stateValue)=>{
37
+ setState(()=>{
38
+ return checkedValue(stateValue);
39
+ });
40
+ };
41
+ const setFileList = async ({ event, file, percent })=>{
42
+ if (!file) {
43
+ throw new Error('File is undefined in useFileList');
44
+ }
45
+ // destruct the file object to avoid the file object being mutated.
46
+ const { bucket, content, key, lastModified, name, size, status, type, uid } = file;
47
+ const fileObj = {
48
+ bucket,
49
+ content,
50
+ key,
51
+ lastModified,
52
+ name,
53
+ percent: percent ?? file.percent ?? 0,
54
+ size,
55
+ status,
56
+ type,
57
+ uid,
58
+ url: file instanceof Blob || file instanceof File ? URL.createObjectURL(file) : null
59
+ };
60
+ switch(event){
61
+ case 'onProgress':
62
+ fileObj.status = 'uploading';
63
+ fileObj.percent = percent ?? fileObj.percent;
64
+ break;
65
+ case 'onSuccess':
66
+ fileObj.status = 'done';
67
+ fileObj.percent = 100;
68
+ break;
69
+ case 'onRemove':
70
+ fileObj.status = 'removed';
71
+ break;
72
+ default:
73
+ fileObj.status = 'error';
74
+ break;
75
+ }
76
+ state.fileList.splice(state.fileList.findIndex((f)=>f.uid === fileObj.uid), 1, fileObj);
77
+ const nextState = checkedValue({
78
+ file: fileObj,
79
+ fileList: state.fileList
80
+ });
81
+ await methods.triggerEvent({
82
+ name: event,
83
+ event: nextState
84
+ });
85
+ setValue(nextState);
86
+ methods.setValue(nextState);
87
+ return nextState;
88
+ };
89
+ const loadFileList = async (file, nextFiles)=>{
90
+ if (properties.singleFile === true && nextFiles.filter((f)=>type.isString(f.uid)).length > 1) {
91
+ return false;
92
+ }
93
+ if (type.isInt(properties.maxCount) && nextFiles.filter((f)=>type.isString(f.uid)).length > properties.maxCount) {
94
+ return false;
95
+ }
96
+ // Extract file properties into a serialization-safe plain object.
97
+ // Raw File/Blob objects are destroyed by serializer.copy() in _event resolution.
98
+ const fileData = {
99
+ name: file.name,
100
+ type: file.type,
101
+ size: file.size,
102
+ lastModified: file.lastModified,
103
+ uid: file.uid
104
+ };
105
+ if (file instanceof Blob || file instanceof File) {
106
+ fileData.url = URL.createObjectURL(file);
107
+ }
108
+ const result = await methods.triggerEvent({
109
+ name: 'onBeforeUpload',
110
+ event: {
111
+ file: fileData
112
+ }
113
+ });
114
+ if (result.success === false) {
115
+ return false;
116
+ }
117
+ const nextState = {
118
+ file: fileData,
119
+ fileList: [
120
+ ...nextFiles,
121
+ ...state.fileList
122
+ ]
123
+ };
124
+ setValue(nextState);
125
+ methods.setValue(nextState);
126
+ };
127
+ const removeFile = (file)=>{
128
+ state.fileList.splice(state.fileList.findIndex((f)=>f.uid === file.uid), 1);
129
+ setValue(state);
130
+ methods.setValue(state);
131
+ };
132
+ return [
133
+ state,
134
+ loadFileList,
135
+ setFileList,
136
+ removeFile,
137
+ setValue
138
+ ];
139
+ };
140
+ export default useFileList;
package/dist/blocks.js ADDED
@@ -0,0 +1,18 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ export { default as Download } from './blocks/Download/Download.js';
16
+ export { default as Upload } from './blocks/Upload/Upload.js';
17
+ export { default as UploadDragger } from './blocks/UploadDragger/UploadDragger.js';
18
+ export { default as UploadPhoto } from './blocks/UploadPhoto/UploadPhoto.js';
package/dist/metas.js ADDED
@@ -0,0 +1,18 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ export { default as Download } from './blocks/Download/meta.js';
16
+ export { default as Upload } from './blocks/Upload/meta.js';
17
+ export { default as UploadDragger } from './blocks/UploadDragger/meta.js';
18
+ export { default as UploadPhoto } from './blocks/UploadPhoto/meta.js';
@@ -0,0 +1,53 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ // Shared antd Upload component-token schema for S3 blocks wrapped in
16
+ // `withTheme('Upload', …)`. Values are forwarded into a scoped
17
+ // `<ConfigProvider theme={{ components: { Upload: theme } }}>` wrapper.
18
+ // See https://ant.design/components/upload#design-token.
19
+ const uploadTheme = {
20
+ type: 'object',
21
+ description: 'Antd design token overrides for this block. See <a href="https://ant.design/components/upload#design-token">antd design tokens</a>.',
22
+ docs: {
23
+ displayType: 'yaml',
24
+ link: 'https://ant.design/components/upload#design-token'
25
+ },
26
+ properties: {
27
+ actionsColor: {
28
+ type: 'string',
29
+ description: 'Color of action icons (download, preview, remove).'
30
+ },
31
+ pictureCardSize: {
32
+ type: 'number',
33
+ description: 'Size of list items in card type (affects both picture-card and picture-circle).'
34
+ },
35
+ controlItemBgHover: {
36
+ type: 'string',
37
+ description: 'Background color of file item on hover.'
38
+ },
39
+ colorIcon: {
40
+ type: 'string',
41
+ description: 'Color of file icons.'
42
+ },
43
+ fontSize: {
44
+ type: 'number',
45
+ description: 'Font size of file name text.'
46
+ },
47
+ borderRadiusSM: {
48
+ type: 'number',
49
+ description: 'Border radius of file list items.'
50
+ }
51
+ }
52
+ };
53
+ export default uploadTheme;
package/dist/types.js ADDED
@@ -0,0 +1,19 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { extractBlockTypes } from '@lowdefy/block-utils';
16
+ import * as metas from './metas.js';
17
+ export default {
18
+ ...extractBlockTypes(metas)
19
+ };
@@ -0,0 +1,31 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ // Legacy unsigned object URL derived from an upload descriptor. Only renders
16
+ // for publicly readable objects and bakes in provider URL shapes — kept as a
17
+ // backwards-compatible fallback for callers that have no download request
18
+ // configured. New configs should resolve URLs through a download request
19
+ // (with public: true for stable public URLs) instead.
20
+ function getLegacyObjectUrl({ descriptor }) {
21
+ const { method = 'POST', url, key } = descriptor;
22
+ if (method.toUpperCase() === 'PUT') {
23
+ // The signed PUT url already targets the object — strip the signature.
24
+ return url.split('?')[0];
25
+ }
26
+ const encodedKey = key.split('/').map(encodeURIComponent).join('/');
27
+ // createPresignedPost returns the bucket endpoint with a trailing slash, so only
28
+ // add a separator when it is missing to avoid a double slash before the key.
29
+ return url.endsWith('/') ? `${url}${encodedKey}` : `${url}/${encodedKey}`;
30
+ }
31
+ export default getLegacyObjectUrl;
@@ -0,0 +1,37 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ // Triggers the block's registered __getUploadPolicy event and returns the
16
+ // upload-policy descriptor { method, url, key, bucket, fields | headers }
17
+ // produced by the app's upload-policy request.
18
+ async function getUploadPolicy({ methods, file }) {
19
+ const { lastModified, name, size, type, uid } = file;
20
+ const response = await methods.triggerEvent({
21
+ name: '__getUploadPolicy',
22
+ event: {
23
+ file: {
24
+ name,
25
+ lastModified,
26
+ size,
27
+ type,
28
+ uid
29
+ }
30
+ }
31
+ });
32
+ if (response.success !== true) {
33
+ throw new Error('Upload policy request error.');
34
+ }
35
+ return response.responses.__getUploadPolicy.response[0];
36
+ }
37
+ export default getUploadPolicy;
@@ -0,0 +1,28 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ function readFileAsBase64(file) {
16
+ return new Promise((resolve, reject)=>{
17
+ const reader = new FileReader();
18
+ reader.onload = ()=>{
19
+ // reader.result is a data URL: "data:<mime>;base64,<content>".
20
+ resolve(reader.result.slice(reader.result.indexOf(',') + 1));
21
+ };
22
+ reader.onerror = ()=>{
23
+ reject(new Error(`Failed to read file "${file.name}".`));
24
+ };
25
+ reader.readAsDataURL(file);
26
+ });
27
+ }
28
+ export default readFileAsBase64;