@exmg/exm-upload 1.0.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/README.md +20 -0
- package/index.d.ts +18 -0
- package/index.js +17 -0
- package/package.json +53 -0
- package/src/exm-dialog-upload-base.d.ts +90 -0
- package/src/exm-dialog-upload-base.js +226 -0
- package/src/exm-dialog-upload.d.ts +11 -0
- package/src/exm-dialog-upload.js +15 -0
- package/src/exm-upload-base.d.ts +148 -0
- package/src/exm-upload-base.js +373 -0
- package/src/exm-upload-crop-base.d.ts +16 -0
- package/src/exm-upload-crop-base.js +76 -0
- package/src/exm-upload-crop.d.ts +9 -0
- package/src/exm-upload-crop.js +12 -0
- package/src/exm-upload-drop-area-base.d.ts +8 -0
- package/src/exm-upload-drop-area-base.js +34 -0
- package/src/exm-upload-drop-area.d.ts +9 -0
- package/src/exm-upload-drop-area.js +12 -0
- package/src/exm-upload-input.d.ts +15 -0
- package/src/exm-upload-input.js +84 -0
- package/src/exm-upload-item-base.d.ts +45 -0
- package/src/exm-upload-item-base.js +177 -0
- package/src/exm-upload-item.d.ts +9 -0
- package/src/exm-upload-item.js +12 -0
- package/src/exm-upload.d.ts +19 -0
- package/src/exm-upload.js +22 -0
- package/src/mixins/exm-upload-drag-drop-mixin.d.ts +10 -0
- package/src/mixins/exm-upload-drag-drop-mixin.js +28 -0
- package/src/styles/exm-dialog-upload-css.d.ts +2 -0
- package/src/styles/exm-dialog-upload-css.js +4 -0
- package/src/styles/exm-dialog-upload.scss +22 -0
- package/src/styles/exm-upload-crop-styles-css.d.ts +2 -0
- package/src/styles/exm-upload-crop-styles-css.js +12 -0
- package/src/styles/exm-upload-crop-styles.scss +323 -0
- package/src/styles/exm-upload-drop-area-styles-css.d.ts +2 -0
- package/src/styles/exm-upload-drop-area-styles-css.js +4 -0
- package/src/styles/exm-upload-drop-area-styles.scss +45 -0
- package/src/styles/exm-upload-input-css.d.ts +2 -0
- package/src/styles/exm-upload-input-css.js +4 -0
- package/src/styles/exm-upload-input.scss +18 -0
- package/src/styles/exm-upload-item-styles-css.d.ts +2 -0
- package/src/styles/exm-upload-item-styles-css.js +4 -0
- package/src/styles/exm-upload-item-styles.scss +119 -0
- package/src/styles/exm-upload-styles-css.d.ts +2 -0
- package/src/styles/exm-upload-styles-css.js +4 -0
- package/src/styles/exm-upload-styles.scss +147 -0
- package/src/types.d.ts +33 -0
- package/src/types.js +10 -0
- package/src/upload/adapters/local-adapter.d.ts +6 -0
- package/src/upload/adapters/local-adapter.js +23 -0
- package/src/upload/adapters/xhr-adapter.d.ts +9 -0
- package/src/upload/adapters/xhr-adapter.js +49 -0
- package/src/upload/index.d.ts +1 -0
- package/src/upload/index.js +2 -0
- package/src/upload/service.d.ts +9 -0
- package/src/upload/service.js +42 -0
- package/src/upload/types.d.ts +12 -0
- package/src/upload/types.js +2 -0
- package/src/utils.d.ts +33 -0
- package/src/utils.js +89 -0
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface FileData {
|
|
2
|
+
id: string;
|
|
3
|
+
url?: string;
|
|
4
|
+
file: File;
|
|
5
|
+
invalid: boolean;
|
|
6
|
+
error: string;
|
|
7
|
+
status: FileUploadState;
|
|
8
|
+
progress?: number;
|
|
9
|
+
}
|
|
10
|
+
export type FileUploadState = 'UPLOADING' | 'UPLOADED' | 'INVALID' | 'WARNING';
|
|
11
|
+
export declare enum FileUploadError {
|
|
12
|
+
INVALID_SIZE = "File size too large",
|
|
13
|
+
INVALID_TYPE = "Invalid file type",
|
|
14
|
+
INVALID_AMOUNT = "Max amount of files exceeded",
|
|
15
|
+
INVALID_MULTIPLE = "Multiple files not allowed",
|
|
16
|
+
INVALID_RESOLUTION = "Image resulution is not valid",
|
|
17
|
+
SERVER_ERROR = "Server error occured"
|
|
18
|
+
}
|
|
19
|
+
export interface FileUploadConfig {
|
|
20
|
+
uploadUrl: string;
|
|
21
|
+
formUpload?: boolean;
|
|
22
|
+
}
|
|
23
|
+
declare global {
|
|
24
|
+
interface Window {
|
|
25
|
+
uploadDefaults: {
|
|
26
|
+
customAdapterPath?: string;
|
|
27
|
+
uploadUrl?: string;
|
|
28
|
+
headers?: {
|
|
29
|
+
[key: string]: string;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export var FileUploadError;
|
|
2
|
+
(function (FileUploadError) {
|
|
3
|
+
FileUploadError["INVALID_SIZE"] = "File size too large";
|
|
4
|
+
FileUploadError["INVALID_TYPE"] = "Invalid file type";
|
|
5
|
+
FileUploadError["INVALID_AMOUNT"] = "Max amount of files exceeded";
|
|
6
|
+
FileUploadError["INVALID_MULTIPLE"] = "Multiple files not allowed";
|
|
7
|
+
FileUploadError["INVALID_RESOLUTION"] = "Image resulution is not valid";
|
|
8
|
+
FileUploadError["SERVER_ERROR"] = "Server error occured";
|
|
9
|
+
})(FileUploadError = FileUploadError || (FileUploadError = {}));
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { UploadAdapter } from '../types.js';
|
|
2
|
+
declare class LocalStorageUploadAdapter implements UploadAdapter {
|
|
3
|
+
private readFileAsDataURL;
|
|
4
|
+
upload(file: File, progressCallback: (progress: number) => void): Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
export { LocalStorageUploadAdapter as UploadAdapter };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class LocalStorageUploadAdapter {
|
|
2
|
+
async readFileAsDataURL(file) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const reader = new FileReader();
|
|
5
|
+
reader.onload = () => {
|
|
6
|
+
resolve(reader.result);
|
|
7
|
+
};
|
|
8
|
+
reader.onerror = () => {
|
|
9
|
+
reject(reader.error);
|
|
10
|
+
};
|
|
11
|
+
reader.readAsDataURL(file);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async upload(file, progressCallback) {
|
|
15
|
+
progressCallback(0);
|
|
16
|
+
const fileDataUrl = await this.readFileAsDataURL(file);
|
|
17
|
+
localStorage.setItem(file.name, fileDataUrl);
|
|
18
|
+
progressCallback(100);
|
|
19
|
+
return file.name;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export { LocalStorageUploadAdapter as UploadAdapter };
|
|
23
|
+
//# sourceMappingURL=local-adapter.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { UploadAdapter, UploadConfig } from '../types.js';
|
|
2
|
+
declare class XHRUploadAdapter implements UploadAdapter {
|
|
3
|
+
config: UploadConfig;
|
|
4
|
+
xhr: XMLHttpRequest;
|
|
5
|
+
constructor(config: UploadConfig);
|
|
6
|
+
abort(): void;
|
|
7
|
+
upload(file: File, progressCallback: (progress: number) => void): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
export { XHRUploadAdapter as UploadAdapter };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
class XHRUploadAdapter {
|
|
2
|
+
constructor(config) {
|
|
3
|
+
this.config = config;
|
|
4
|
+
this.xhr = new XMLHttpRequest();
|
|
5
|
+
}
|
|
6
|
+
abort() {
|
|
7
|
+
this.xhr.abort();
|
|
8
|
+
}
|
|
9
|
+
async upload(file, progressCallback) {
|
|
10
|
+
const onProgress = (event) => {
|
|
11
|
+
if (event.lengthComputable) {
|
|
12
|
+
const percentage = (event.loaded / event.total) * 100;
|
|
13
|
+
progressCallback(Math.round(percentage));
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const { xhr } = this;
|
|
17
|
+
xhr.upload.addEventListener('progress', onProgress);
|
|
18
|
+
const formData = new FormData();
|
|
19
|
+
formData.append('filename', file.name);
|
|
20
|
+
formData.append('file', file);
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const { uploadUrl } = this.config;
|
|
23
|
+
if (!uploadUrl)
|
|
24
|
+
reject(new Error(`Upload url not found`));
|
|
25
|
+
xhr.open('POST', uploadUrl, true);
|
|
26
|
+
for (const key in this.config.headers || {}) {
|
|
27
|
+
if (Object.prototype.hasOwnProperty.call(this.config.headers, key)) {
|
|
28
|
+
xhr.setRequestHeader(key, this.config.headers[key]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
xhr.onreadystatechange = () => {
|
|
32
|
+
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
33
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
34
|
+
resolve(xhr.responseText);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
reject(new Error(`Upload failed with status ${xhr.status}`));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
xhr.onerror = () => {
|
|
42
|
+
reject(new Error('Upload failed due to network error'));
|
|
43
|
+
};
|
|
44
|
+
xhr.send(formData);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export { XHRUploadAdapter as UploadAdapter };
|
|
49
|
+
//# sourceMappingURL=xhr-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { UploadService } from './service.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { UploadAdapter, UploadConfig } from './types.js';
|
|
2
|
+
declare class UploadService {
|
|
3
|
+
private adapter;
|
|
4
|
+
constructor(adapter: UploadAdapter);
|
|
5
|
+
upload(file: File, progressCallback: (progress: number) => void): Promise<string>;
|
|
6
|
+
abort(): void;
|
|
7
|
+
static create(destination: 'xhr' | 'local' | 'custom', config?: UploadConfig): Promise<UploadService>;
|
|
8
|
+
}
|
|
9
|
+
export { UploadService };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
async function instantiateClass(path, config) {
|
|
2
|
+
if (!path) {
|
|
3
|
+
throw new Error(`Class UploadAdapter path not set.`);
|
|
4
|
+
}
|
|
5
|
+
const { UploadAdapter } = await import(path);
|
|
6
|
+
if (typeof UploadAdapter === 'function') {
|
|
7
|
+
return new UploadAdapter(config);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
throw new Error(`Class UploadAdapter not found.`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
class UploadService {
|
|
14
|
+
constructor(adapter) {
|
|
15
|
+
this.adapter = adapter;
|
|
16
|
+
}
|
|
17
|
+
async upload(file, progressCallback) {
|
|
18
|
+
return this.adapter.upload(file, progressCallback);
|
|
19
|
+
}
|
|
20
|
+
abort() {
|
|
21
|
+
this.adapter.abort && this.adapter.abort();
|
|
22
|
+
}
|
|
23
|
+
static async create(destination, config) {
|
|
24
|
+
let adapter;
|
|
25
|
+
switch (destination) {
|
|
26
|
+
case 'local':
|
|
27
|
+
adapter = await instantiateClass('./adapters/local-adapter.js', config);
|
|
28
|
+
break;
|
|
29
|
+
case 'xhr':
|
|
30
|
+
adapter = await instantiateClass('./adapters/xhr-adapter.js', config);
|
|
31
|
+
break;
|
|
32
|
+
case 'custom':
|
|
33
|
+
adapter = await instantiateClass(config === null || config === void 0 ? void 0 : config.customAdapterPath, config);
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
throw new Error(`Unknown upload destination: ${destination}`);
|
|
37
|
+
}
|
|
38
|
+
return new UploadService(adapter);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export { UploadService };
|
|
42
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface UploadAdapter {
|
|
2
|
+
upload(file: File, progressCallback: (progress: number) => void): Promise<string>;
|
|
3
|
+
abort?: () => void;
|
|
4
|
+
}
|
|
5
|
+
export interface UploadConfig {
|
|
6
|
+
uploadUrl?: string;
|
|
7
|
+
customAdapterPath?: string;
|
|
8
|
+
headers?: {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
};
|
|
11
|
+
responseType?: '' | 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
12
|
+
}
|
package/src/utils.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare const isMimeType: (value: string) => boolean;
|
|
2
|
+
/**
|
|
3
|
+
* Checks if the type of a file is valid based on the accepted types.
|
|
4
|
+
*
|
|
5
|
+
* @param file - The file object to check.
|
|
6
|
+
* @param accept - A comma-separated list of accepted types.
|
|
7
|
+
* @returns True if the file type is valid, false otherwise.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isTypeValidExtension: (file: File, accept: string) => boolean | "" | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Checks if the size of a file is valid based on the maximum size.
|
|
12
|
+
*
|
|
13
|
+
* @param size - The size of the file in bytes.
|
|
14
|
+
* @param maxSize - The maximum size allowed, with a digital unit (e.g., "10MB").
|
|
15
|
+
* @returns True if the file size is valid, false otherwise.
|
|
16
|
+
* @throws Error if the maximum size is invalid.
|
|
17
|
+
*/
|
|
18
|
+
export declare const isSizeValid: (size: number, maxSize: string) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Formats a byte size into a human-readable string.
|
|
21
|
+
*
|
|
22
|
+
* @param bytes - The size in bytes to format.
|
|
23
|
+
* @returns The formatted size string.
|
|
24
|
+
*/
|
|
25
|
+
export declare const formatBytes: (bytes: number) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if a file is an image based on its type.
|
|
28
|
+
*
|
|
29
|
+
* @param file - The file object to check.
|
|
30
|
+
* @returns True if the file is an image, false otherwise.
|
|
31
|
+
*/
|
|
32
|
+
export declare const isImage: (file: File) => boolean | undefined;
|
|
33
|
+
export declare const isCorrectResolution: (image: File, resolution: string) => Promise<unknown>;
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export const isMimeType = (value) => {
|
|
2
|
+
const mimeTypeRegex = /^[a-zA-Z]+\/[a-zA-Z0-9+\-.]+(\*?)$/;
|
|
3
|
+
return mimeTypeRegex.test(value);
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Checks if the type of a file is valid based on the accepted types.
|
|
7
|
+
*
|
|
8
|
+
* @param file - The file object to check.
|
|
9
|
+
* @param accept - A comma-separated list of accepted types.
|
|
10
|
+
* @returns True if the file type is valid, false otherwise.
|
|
11
|
+
*/
|
|
12
|
+
export const isTypeValidExtension = (file, accept) => {
|
|
13
|
+
var _a;
|
|
14
|
+
if (accept.trim() === '')
|
|
15
|
+
return true;
|
|
16
|
+
const acceptedTypes = new Set(accept.split(','));
|
|
17
|
+
const fileExtensionRegExp = /\.[^.]+$/;
|
|
18
|
+
const name = file.name;
|
|
19
|
+
const type = file.type;
|
|
20
|
+
const hasFileExtension = fileExtensionRegExp.test(name);
|
|
21
|
+
const [fileExtension] = !hasFileExtension ? [undefined] : (_a = fileExtensionRegExp.exec(name)) !== null && _a !== void 0 ? _a : [];
|
|
22
|
+
return acceptedTypes.has(type) || (fileExtension && acceptedTypes.has(fileExtension));
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Checks if the size of a file is valid based on the maximum size.
|
|
26
|
+
*
|
|
27
|
+
* @param size - The size of the file in bytes.
|
|
28
|
+
* @param maxSize - The maximum size allowed, with a digital unit (e.g., "10MB").
|
|
29
|
+
* @returns True if the file size is valid, false otherwise.
|
|
30
|
+
* @throws Error if the maximum size is invalid.
|
|
31
|
+
*/
|
|
32
|
+
export const isSizeValid = (size, maxSize) => {
|
|
33
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
34
|
+
// Extract the size from the digital unit
|
|
35
|
+
const extracted = maxSize.split(/^([\d.]+)\s*(b|kb|mb|gb)$/i).filter((x) => x);
|
|
36
|
+
if (!extracted) {
|
|
37
|
+
throw new Error('Invalid max size set');
|
|
38
|
+
}
|
|
39
|
+
const power = sizes.indexOf(extracted[1].toUpperCase());
|
|
40
|
+
return +extracted[0] * Math.pow(1024, power) > size;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Formats a byte size into a human-readable string.
|
|
44
|
+
*
|
|
45
|
+
* @param bytes - The size in bytes to format.
|
|
46
|
+
* @returns The formatted size string.
|
|
47
|
+
*/
|
|
48
|
+
export const formatBytes = (bytes) => {
|
|
49
|
+
if (!bytes)
|
|
50
|
+
return '0 Bytes';
|
|
51
|
+
const k = 1024;
|
|
52
|
+
const dm = 2;
|
|
53
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
54
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
55
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Checks if a file is an image based on its type.
|
|
59
|
+
*
|
|
60
|
+
* @param file - The file object to check.
|
|
61
|
+
* @returns True if the file is an image, false otherwise.
|
|
62
|
+
*/
|
|
63
|
+
export const isImage = (file) => {
|
|
64
|
+
if (!file) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
return file.type.startsWith('image');
|
|
68
|
+
};
|
|
69
|
+
export const isCorrectResolution = (image, resolution) => {
|
|
70
|
+
if (resolution.split('x').length !== 2) {
|
|
71
|
+
throw new Error('Incorrect fixed resultion format, should be formatted like "600x400"');
|
|
72
|
+
}
|
|
73
|
+
const [width, height] = resolution.split('x');
|
|
74
|
+
const img = new Image();
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
img.onload = () => {
|
|
77
|
+
const correct = img.naturalWidth === parseInt(width, 10) && img.naturalHeight === parseInt(height, 10);
|
|
78
|
+
resolve(correct);
|
|
79
|
+
URL.revokeObjectURL(img.src);
|
|
80
|
+
};
|
|
81
|
+
const objectURL = URL.createObjectURL(image);
|
|
82
|
+
img.src = objectURL;
|
|
83
|
+
img.onerror = () => {
|
|
84
|
+
URL.revokeObjectURL(img.src);
|
|
85
|
+
reject(new Error('Error reading aspect ratio'));
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=utils.js.map
|