@cloudparker/moldex.js 0.0.50 → 0.0.52

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 (50) hide show
  1. package/dist/services/dialog/dialog-service.d.ts +27 -0
  2. package/dist/services/dialog/dialog-service.js +110 -0
  3. package/dist/services/index.d.ts +6 -0
  4. package/dist/services/index.js +6 -1
  5. package/dist/services/navigation/navigation-service.js +5 -5
  6. package/dist/services/utils/color-service.d.ts +46 -0
  7. package/dist/services/utils/color-service.js +73 -0
  8. package/dist/services/utils/download-service.d.ts +91 -0
  9. package/dist/services/utils/download-service.js +159 -0
  10. package/dist/services/utils/file-service.d.ts +138 -0
  11. package/dist/services/utils/file-service.js +258 -0
  12. package/dist/services/utils/http-service.d.ts +77 -0
  13. package/dist/services/utils/http-service.js +158 -0
  14. package/dist/services/utils/image-service.d.ts +81 -0
  15. package/dist/services/utils/image-service.js +194 -0
  16. package/dist/services/utils/utils-service.d.ts +257 -55
  17. package/dist/services/utils/utils-service.js +347 -327
  18. package/dist/tailwind.css +1 -1
  19. package/dist/views/core/index.js +0 -1
  20. package/dist/views/core/input/components/color-field/color-field.svelte +2 -2
  21. package/dist/views/core/input/components/color-field/color-field.svelte.d.ts +2 -11
  22. package/dist/views/core/input/components/combobox-field/combobox-field.svelte +2 -2
  23. package/dist/views/core/input/components/date-field/date-field.svelte +1 -1
  24. package/dist/views/core/input/components/date-field/date-field.svelte.d.ts +1 -10
  25. package/dist/views/core/input/components/datetime-field/datetime-field.svelte +1 -1
  26. package/dist/views/core/input/components/datetime-field/datetime-field.svelte.d.ts +1 -10
  27. package/dist/views/core/input/components/email-field/email-field.svelte +1 -1
  28. package/dist/views/core/input/components/email-field/email-field.svelte.d.ts +1 -10
  29. package/dist/views/core/input/components/file-field/file-field.svelte +15 -8
  30. package/dist/views/core/input/components/file-field/file-field.svelte.d.ts +2 -11
  31. package/dist/views/core/input/components/number-field/number-field.svelte +1 -1
  32. package/dist/views/core/input/components/number-field/number-field.svelte.d.ts +1 -10
  33. package/dist/views/core/input/components/password-field/password-field.svelte +1 -1
  34. package/dist/views/core/input/components/password-field/password-field.svelte.d.ts +1 -10
  35. package/dist/views/core/input/components/phone-field/phone-field.svelte +1 -1
  36. package/dist/views/core/input/components/phone-field/phone-field.svelte.d.ts +1 -10
  37. package/dist/views/core/input/components/search-field/search-field.svelte +1 -1
  38. package/dist/views/core/input/components/search-field/search-field.svelte.d.ts +1 -10
  39. package/dist/views/core/input/components/text-field/text-field.svelte +1 -1
  40. package/dist/views/core/input/components/text-field/text-field.svelte.d.ts +2 -11
  41. package/dist/views/core/input/components/textarea-field/textarea-field.svelte +1 -1
  42. package/dist/views/core/input/components/textarea-field/textarea-field.svelte.d.ts +2 -11
  43. package/dist/views/core/input/components/time-field/time-field.svelte +1 -1
  44. package/dist/views/core/input/components/time-field/time-field.svelte.d.ts +2 -11
  45. package/dist/views/core/text/components/text-copy/text-copy.svelte +3 -3
  46. package/package.json +2 -2
  47. package/dist/views/core/referrer/components/referrer.svelte +0 -16
  48. package/dist/views/core/referrer/components/referrer.svelte.d.ts +0 -18
  49. package/dist/views/core/referrer/index.d.ts +0 -2
  50. package/dist/views/core/referrer/index.js +0 -2
@@ -59,3 +59,30 @@ export declare function openLoadingDialog({ msg, loadingDialogContainerClassName
59
59
  * @returns
60
60
  */
61
61
  export declare function openCropperDialog<T, R>({ outputWidth, outputFormat, outputQuality, outputType, inputImageFile, className, ...params }: DialogPropsType & CropperDialogPropsType): Promise<R | string | File>;
62
+ /**
63
+ * Opens a file picker dialog and returns the selected file or files.
64
+ * This function uses native browser APIs to ensure compatibility across different browsers.
65
+ * @param accepts - A string or array of accepted file types (e.g., 'image/*', '.pdf').
66
+ * @param multiple - A boolean indicating if multiple files can be selected.
67
+ * @returns A promise that resolves to a File or an array of File objects, or null if no files were selected.
68
+ */
69
+ export declare function openFilePickerDialog<T extends File | File[]>({ accepts, multiple }: {
70
+ accepts: string | string[];
71
+ multiple: boolean;
72
+ }): Promise<T | null>;
73
+ /**
74
+ * Opens an image picker dialog that supports mobile devices, camera capture, gallery selection, and file explorer.
75
+ * Allows the user to specify output format and quality for the selected images.
76
+ * @param accepts - A string or array of accepted file types (e.g., 'image/*').
77
+ * @param options - Additional options for capturing images (e.g., required resolution, file size, output format).
78
+ * @returns A promise that resolves to a processed File object or an array of File objects, or null if no file was selected.
79
+ */
80
+ export declare function openImagePickerDialog(accepts?: string | string[], options?: {
81
+ multiple?: boolean;
82
+ capture?: 'user' | 'environment';
83
+ maxWidth?: number;
84
+ maxHeight?: number;
85
+ maxSizeInBytes?: number;
86
+ outputFormat?: 'image/webp' | 'image/jpeg' | 'image/png';
87
+ quality?: number;
88
+ }): Promise<File | File[] | null>;
@@ -7,6 +7,7 @@ import TextareaFieldDialog from '../../views/core/dialog/components/textarea-fie
7
7
  import { mount, } from 'svelte';
8
8
  import { isMobileScreen } from '../screen/screen-service';
9
9
  import CropperDialog, {} from '../../views/core/dialog/components/cropper-dialog/cropper-dialog.svelte';
10
+ import { processImageFile } from '../utils/image-service';
10
11
  function addDialog(props) {
11
12
  const dialog = mount(Dialog, { target: document.getElementsByTagName('body')[0], props });
12
13
  return dialog;
@@ -168,3 +169,112 @@ export async function openCropperDialog({ outputWidth, outputFormat = 'webp', ou
168
169
  size: isMobileScreen() ? 'full' : 'lg',
169
170
  });
170
171
  }
172
+ /**
173
+ * Opens a file picker dialog and returns the selected file or files.
174
+ * This function uses native browser APIs to ensure compatibility across different browsers.
175
+ * @param accepts - A string or array of accepted file types (e.g., 'image/*', '.pdf').
176
+ * @param multiple - A boolean indicating if multiple files can be selected.
177
+ * @returns A promise that resolves to a File or an array of File objects, or null if no files were selected.
178
+ */
179
+ export async function openFilePickerDialog({ accepts = '*/*', multiple = false }) {
180
+ // Check if the browser supports the required File API and input element
181
+ if (typeof window === 'undefined' || typeof document === 'undefined' || !window.File || !window.FileList || !window.FileReader) {
182
+ console.error('File APIs are not fully supported in this browser.');
183
+ return null;
184
+ }
185
+ return new Promise((resolve, reject) => {
186
+ try {
187
+ // Create an input element of type 'file'
188
+ const inputElement = document.createElement('input');
189
+ inputElement.type = 'file';
190
+ inputElement.style.display = 'none'; // Hide the input element
191
+ // Set accepted file types if provided
192
+ if (Array.isArray(accepts)) {
193
+ inputElement.accept = accepts.join(',');
194
+ }
195
+ else {
196
+ inputElement.accept = accepts;
197
+ }
198
+ // Set multiple attribute based on the parameter
199
+ inputElement.multiple = multiple;
200
+ // Listen for changes (i.e., when files are selected)
201
+ inputElement.addEventListener('change', () => {
202
+ // Check if files were selected
203
+ if (inputElement.files) {
204
+ // If multiple is true, return an array of File objects
205
+ if (multiple) {
206
+ resolve(Array.from(inputElement.files));
207
+ }
208
+ else {
209
+ // Otherwise, return the first selected File
210
+ resolve(inputElement.files[0]);
211
+ }
212
+ }
213
+ else {
214
+ resolve(null); // No files selected
215
+ }
216
+ });
217
+ // Append the input element to the body and simulate a click to open the dialog
218
+ document.body.appendChild(inputElement);
219
+ inputElement.click();
220
+ // Remove the input element from the DOM after use to prevent memory leaks
221
+ document.body.removeChild(inputElement);
222
+ }
223
+ catch (error) {
224
+ console.error('An error occurred while opening the file picker dialog:', error);
225
+ reject(error); // Handle any unexpected errors
226
+ }
227
+ });
228
+ }
229
+ /**
230
+ * Opens an image picker dialog that supports mobile devices, camera capture, gallery selection, and file explorer.
231
+ * Allows the user to specify output format and quality for the selected images.
232
+ * @param accepts - A string or array of accepted file types (e.g., 'image/*').
233
+ * @param options - Additional options for capturing images (e.g., required resolution, file size, output format).
234
+ * @returns A promise that resolves to a processed File object or an array of File objects, or null if no file was selected.
235
+ */
236
+ export async function openImagePickerDialog(accepts = 'image/*', options) {
237
+ return new Promise((resolve, reject) => {
238
+ try {
239
+ // Create an input element of type 'file'
240
+ const inputElement = document.createElement('input');
241
+ inputElement.type = 'file';
242
+ inputElement.accept = Array.isArray(accepts) ? accepts.join(',') : accepts;
243
+ inputElement.multiple = options?.multiple || false;
244
+ inputElement.style.display = 'none';
245
+ // Set capture attribute if specified
246
+ if (options?.capture) {
247
+ inputElement.setAttribute('capture', options.capture);
248
+ }
249
+ // Listen for file selection
250
+ inputElement.addEventListener('change', async () => {
251
+ if (!inputElement.files) {
252
+ resolve(null); // No files selected
253
+ return;
254
+ }
255
+ const files = Array.from(inputElement.files);
256
+ try {
257
+ // Process each selected file and resize/compress/convert if required
258
+ const processedFiles = await Promise.all(files.map((file) => processImageFile(file, options)));
259
+ // Return a single file or an array of files based on the multiple option
260
+ if (options?.multiple) {
261
+ resolve(processedFiles);
262
+ }
263
+ else {
264
+ resolve(processedFiles[0] || null);
265
+ }
266
+ }
267
+ catch (error) {
268
+ reject(error);
269
+ }
270
+ });
271
+ // Append and trigger the file picker
272
+ document.body.appendChild(inputElement);
273
+ inputElement.click();
274
+ document.body.removeChild(inputElement);
275
+ }
276
+ catch (error) {
277
+ reject(error);
278
+ }
279
+ });
280
+ }
@@ -1,5 +1,11 @@
1
1
  export * from './date/date-service.js';
2
2
  export * from './dialog/dialog-service.js';
3
+ export * from './navigation/navigation-service.js';
3
4
  export * from './screen/screen-service.js';
4
5
  export * from './toast/toast-service.js';
5
6
  export * from './utils/utils-service.js';
7
+ export * from './utils/color-service.js';
8
+ export * from './utils/download-service.js';
9
+ export * from './utils/file-service.js';
10
+ export * from './utils/http-service.js';
11
+ export * from './utils/image-service.js';
@@ -1,6 +1,11 @@
1
1
  export * from './date/date-service.js';
2
2
  export * from './dialog/dialog-service.js';
3
- // export * from './navigation/navigation-service.js';
3
+ export * from './navigation/navigation-service.js';
4
4
  export * from './screen/screen-service.js';
5
5
  export * from './toast/toast-service.js';
6
6
  export * from './utils/utils-service.js';
7
+ export * from './utils/color-service.js';
8
+ export * from './utils/download-service.js';
9
+ export * from './utils/file-service.js';
10
+ export * from './utils/http-service.js';
11
+ export * from './utils/image-service.js';
@@ -1,4 +1,4 @@
1
- import { goto, pushState } from '$app/navigation';
1
+ // import { goto, pushState } from '$app/navigation';
2
2
  import { createRefererStore } from '../../stores/referrer-store/referrer-store.svelte';
3
3
  import { BROWSER } from 'esm-env';
4
4
  export const referrer = createRefererStore();
@@ -12,7 +12,7 @@ export const popBackState = () => {
12
12
  export const registerBackPress = (state) => {
13
13
  if (BROWSER) {
14
14
  pushBackState(state);
15
- pushState('', {});
15
+ window.history.pushState({}, '');
16
16
  }
17
17
  };
18
18
  export const addBackKeyListener = (callback) => {
@@ -21,11 +21,11 @@ export const addBackKeyListener = (callback) => {
21
21
  if (callback) {
22
22
  let result = callback(event);
23
23
  if (result) {
24
- pushState('', {});
24
+ window.history.pushState({}, '');
25
25
  }
26
26
  }
27
27
  };
28
- pushState('', {});
28
+ window.history.pushState({}, '');
29
29
  window.addEventListener('popstate', listener);
30
30
  return listener;
31
31
  }
@@ -39,7 +39,7 @@ export function goBack() {
39
39
  history.back();
40
40
  }
41
41
  export function goHome() {
42
- goto('/', { replaceState: true });
42
+ history.back();
43
43
  }
44
44
  ;
45
45
  export function createRedirectUrl() {
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Validates whether a given string is a valid hexadecimal color code.
3
+ *
4
+ * This function checks if a given string matches the pattern for a valid hex color code,
5
+ * which can be either 3 or 6 characters long, prefixed with '#'.
6
+ *
7
+ * @param hex - The string to validate as a hex color code.
8
+ * @returns A boolean indicating whether the string is a valid hex color code.
9
+ *
10
+ * @example
11
+ * console.log(isValidHexColor('#FFF')); // Output: true
12
+ * console.log(isValidHexColor('#123ABC')); // Output: true
13
+ * console.log(isValidHexColor('#1234')); // Output: false
14
+ */
15
+ export declare function isValidHexColor(hex: string): boolean;
16
+ /**
17
+ * Converts a named or RGB color string to its hexadecimal representation.
18
+ *
19
+ * This function creates a temporary DOM element, sets its color property to the provided color string,
20
+ * and retrieves the computed color value. It then converts the RGB color to a hexadecimal format.
21
+ *
22
+ * @param color - A color string, such as a named color ('red'), RGB color ('rgb(255, 0, 0)'), or hex color ('#FF0000').
23
+ * @returns The hexadecimal representation of the color.
24
+ *
25
+ * @throws An error if the color cannot be parsed.
26
+ *
27
+ * @example
28
+ * console.log(colorToHex('red')); // Output: #FF0000
29
+ * console.log(colorToHex('rgb(0, 255, 0)')); // Output: #00FF00
30
+ */
31
+ export declare function colorToHex(color: string): string;
32
+ /**
33
+ * Converts RGB values to a hexadecimal color code.
34
+ *
35
+ * This function takes the red, green, and blue components and converts them to a hexadecimal string.
36
+ * The resulting hex code is formatted as '#RRGGBB'.
37
+ *
38
+ * @param r - The red component (0-255).
39
+ * @param g - The green component (0-255).
40
+ * @param b - The blue component (0-255).
41
+ * @returns The hexadecimal color code in the format '#RRGGBB'.
42
+ *
43
+ * @example
44
+ * console.log(rgbToHex(255, 0, 0)); // Output: #FF0000
45
+ */
46
+ export declare function rgbToHex(r: number, g: number, b: number): string;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Validates whether a given string is a valid hexadecimal color code.
3
+ *
4
+ * This function checks if a given string matches the pattern for a valid hex color code,
5
+ * which can be either 3 or 6 characters long, prefixed with '#'.
6
+ *
7
+ * @param hex - The string to validate as a hex color code.
8
+ * @returns A boolean indicating whether the string is a valid hex color code.
9
+ *
10
+ * @example
11
+ * console.log(isValidHexColor('#FFF')); // Output: true
12
+ * console.log(isValidHexColor('#123ABC')); // Output: true
13
+ * console.log(isValidHexColor('#1234')); // Output: false
14
+ */
15
+ export function isValidHexColor(hex) {
16
+ const hexRegex = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
17
+ return hexRegex.test(hex);
18
+ }
19
+ /**
20
+ * Converts a named or RGB color string to its hexadecimal representation.
21
+ *
22
+ * This function creates a temporary DOM element, sets its color property to the provided color string,
23
+ * and retrieves the computed color value. It then converts the RGB color to a hexadecimal format.
24
+ *
25
+ * @param color - A color string, such as a named color ('red'), RGB color ('rgb(255, 0, 0)'), or hex color ('#FF0000').
26
+ * @returns The hexadecimal representation of the color.
27
+ *
28
+ * @throws An error if the color cannot be parsed.
29
+ *
30
+ * @example
31
+ * console.log(colorToHex('red')); // Output: #FF0000
32
+ * console.log(colorToHex('rgb(0, 255, 0)')); // Output: #00FF00
33
+ */
34
+ export function colorToHex(color) {
35
+ // Create a temporary div element to use its computed style
36
+ const tempDiv = document.createElement("div");
37
+ tempDiv.style.color = color;
38
+ document.body.appendChild(tempDiv);
39
+ // Get the computed color from the div element
40
+ const computedColor = window.getComputedStyle(tempDiv).color;
41
+ document.body.removeChild(tempDiv);
42
+ // Extract the RGB values from the computed color
43
+ const rgb = computedColor.match(/\d+/g)?.map(Number);
44
+ if (!rgb || rgb.length !== 3) {
45
+ throw new Error(`Unable to parse color: ${color}`);
46
+ }
47
+ // Convert RGB values to a hex color and return
48
+ return rgbToHex(rgb[0], rgb[1], rgb[2]);
49
+ }
50
+ /**
51
+ * Converts RGB values to a hexadecimal color code.
52
+ *
53
+ * This function takes the red, green, and blue components and converts them to a hexadecimal string.
54
+ * The resulting hex code is formatted as '#RRGGBB'.
55
+ *
56
+ * @param r - The red component (0-255).
57
+ * @param g - The green component (0-255).
58
+ * @param b - The blue component (0-255).
59
+ * @returns The hexadecimal color code in the format '#RRGGBB'.
60
+ *
61
+ * @example
62
+ * console.log(rgbToHex(255, 0, 0)); // Output: #FF0000
63
+ */
64
+ export function rgbToHex(r, g, b) {
65
+ if (![r, g, b].every((value) => typeof value === 'number' && value >= 0 && value <= 255)) {
66
+ throw new Error('RGB values must be numbers between 0 and 255.');
67
+ }
68
+ return ("#" +
69
+ [r, g, b]
70
+ .map((x) => x.toString(16).padStart(2, "0")) // Convert to hex and ensure two characters
71
+ .join("")
72
+ .toUpperCase());
73
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Downloads a file from various data sources (string, URL, Data URL, or File object).
3
+ *
4
+ * This function handles downloading files from a variety of sources, including:
5
+ * - String data (text, JSON, etc.)
6
+ * - URLs (file URLs or remote URLs)
7
+ * - Data URLs (Base64 encoded strings)
8
+ * - File or Blob objects
9
+ *
10
+ * @param data - The data to download. It can be a string, URL, Data URL, or a File/Blob object.
11
+ * @param filename - The name for the downloaded file.
12
+ * @param mimeType - Optional. The MIME type of the file. Default is 'application/octet-stream'.
13
+ *
14
+ * @example
15
+ * // Download a string as a text file
16
+ * downloadFile('Hello, world!', 'example.txt', 'text/plain');
17
+ *
18
+ * @example
19
+ * // Download a file from a URL
20
+ * downloadFile('https://example.com/file.pdf', 'downloaded-file.pdf');
21
+ *
22
+ * @example
23
+ * // Download a file from a Data URL
24
+ * const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...';
25
+ * downloadFile(dataUrl, 'image.png');
26
+ *
27
+ * @example
28
+ * // Download a File object
29
+ * const myFile = new File(['Hello, world!'], 'example.txt', { type: 'text/plain' });
30
+ * downloadFile(myFile);
31
+ */
32
+ export declare function downloadFile(data: string | URL | File | Blob, filename?: string, mimeType?: string): void;
33
+ /**
34
+ * Downloads plain string data as a file.
35
+ *
36
+ * @param data - The string data to download.
37
+ * @param filename - The name for the downloaded file.
38
+ * @param mimeType - The MIME type of the file.
39
+ */
40
+ export declare function downloadStringData(data: string, filename: string, mimeType: string): void;
41
+ /**
42
+ * Downloads a file from a given URL.
43
+ *
44
+ * @param url - The URL to download the file from.
45
+ * @param filename - The name for the downloaded file.
46
+ */
47
+ export declare function downloadFromUrl(url: string, filename: string): void;
48
+ /**
49
+ * Downloads a file from a Data URL (Base64 encoded string).
50
+ *
51
+ * @param dataUrl - The Data URL to download.
52
+ * @param filename - The name for the downloaded file.
53
+ * @param mimeType - Optional. The MIME type of the file.
54
+ */
55
+ export declare function downloadDataUrl(dataUrl: string, filename: string, mimeType?: string): void;
56
+ /**
57
+ * Downloads a File or Blob object.
58
+ *
59
+ * @param file - The File or Blob object to download.
60
+ * @param filename - The name for the downloaded file.
61
+ */
62
+ export declare function downloadBlob(file: Blob, filename: string): void;
63
+ /**
64
+ * Converts a Data URL to a Blob object.
65
+ *
66
+ * @param dataUrl - The Data URL to convert.
67
+ * @param mimeType - Optional. The MIME type of the resulting Blob.
68
+ * @returns A Blob object representing the data.
69
+ */
70
+ export declare function dataUrlToBlob(dataUrl: string, mimeType?: string): Blob;
71
+ /**
72
+ * Determines if a given string is a valid Data URL.
73
+ *
74
+ * @param str - The string to validate.
75
+ * @returns A boolean indicating whether the string is a valid Data URL.
76
+ */
77
+ export declare function isDataUrl(str: string): boolean;
78
+ /**
79
+ * Determines if a given string is a valid URL.
80
+ *
81
+ * @param str - The string to validate.
82
+ * @returns A boolean indicating whether the string is a valid URL.
83
+ */
84
+ export declare function isUrl(str: string): boolean;
85
+ /**
86
+ * Extracts the filename from a URL.
87
+ *
88
+ * @param url - The URL string.
89
+ * @returns The extracted filename, or 'download' if the URL does not contain a filename.
90
+ */
91
+ export declare function getFilenameFromUrl(url: string): string;
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Downloads a file from various data sources (string, URL, Data URL, or File object).
3
+ *
4
+ * This function handles downloading files from a variety of sources, including:
5
+ * - String data (text, JSON, etc.)
6
+ * - URLs (file URLs or remote URLs)
7
+ * - Data URLs (Base64 encoded strings)
8
+ * - File or Blob objects
9
+ *
10
+ * @param data - The data to download. It can be a string, URL, Data URL, or a File/Blob object.
11
+ * @param filename - The name for the downloaded file.
12
+ * @param mimeType - Optional. The MIME type of the file. Default is 'application/octet-stream'.
13
+ *
14
+ * @example
15
+ * // Download a string as a text file
16
+ * downloadFile('Hello, world!', 'example.txt', 'text/plain');
17
+ *
18
+ * @example
19
+ * // Download a file from a URL
20
+ * downloadFile('https://example.com/file.pdf', 'downloaded-file.pdf');
21
+ *
22
+ * @example
23
+ * // Download a file from a Data URL
24
+ * const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...';
25
+ * downloadFile(dataUrl, 'image.png');
26
+ *
27
+ * @example
28
+ * // Download a File object
29
+ * const myFile = new File(['Hello, world!'], 'example.txt', { type: 'text/plain' });
30
+ * downloadFile(myFile);
31
+ */
32
+ export function downloadFile(data, filename, mimeType) {
33
+ // Determine the type of the data and handle accordingly
34
+ if (typeof data === 'string') {
35
+ if (isDataUrl(data)) {
36
+ // Handle Data URL
37
+ downloadDataUrl(data, filename || 'download', mimeType);
38
+ }
39
+ else if (isUrl(data)) {
40
+ // Handle URL download
41
+ downloadFromUrl(data, filename || getFilenameFromUrl(data));
42
+ }
43
+ else {
44
+ // Handle plain string data
45
+ downloadStringData(data, filename || 'download.txt', mimeType || 'application/octet-stream');
46
+ }
47
+ }
48
+ else if (data instanceof File || data instanceof Blob) {
49
+ // Handle File or Blob object
50
+ downloadBlob(data, filename || data.name || 'download');
51
+ }
52
+ else {
53
+ console.error('Unsupported data type for download.');
54
+ }
55
+ }
56
+ /**
57
+ * Downloads plain string data as a file.
58
+ *
59
+ * @param data - The string data to download.
60
+ * @param filename - The name for the downloaded file.
61
+ * @param mimeType - The MIME type of the file.
62
+ */
63
+ export function downloadStringData(data, filename, mimeType) {
64
+ const blob = new Blob([data], { type: mimeType });
65
+ downloadBlob(blob, filename);
66
+ }
67
+ /**
68
+ * Downloads a file from a given URL.
69
+ *
70
+ * @param url - The URL to download the file from.
71
+ * @param filename - The name for the downloaded file.
72
+ */
73
+ export function downloadFromUrl(url, filename) {
74
+ const link = document.createElement('a');
75
+ link.href = url;
76
+ link.download = filename;
77
+ document.body.appendChild(link);
78
+ link.click();
79
+ document.body.removeChild(link);
80
+ }
81
+ /**
82
+ * Downloads a file from a Data URL (Base64 encoded string).
83
+ *
84
+ * @param dataUrl - The Data URL to download.
85
+ * @param filename - The name for the downloaded file.
86
+ * @param mimeType - Optional. The MIME type of the file.
87
+ */
88
+ export function downloadDataUrl(dataUrl, filename, mimeType) {
89
+ const blob = dataUrlToBlob(dataUrl, mimeType);
90
+ downloadBlob(blob, filename);
91
+ }
92
+ /**
93
+ * Downloads a File or Blob object.
94
+ *
95
+ * @param file - The File or Blob object to download.
96
+ * @param filename - The name for the downloaded file.
97
+ */
98
+ export function downloadBlob(file, filename) {
99
+ const link = document.createElement('a');
100
+ link.href = URL.createObjectURL(file);
101
+ link.download = filename;
102
+ document.body.appendChild(link);
103
+ link.click();
104
+ // Clean up the URL object to free up memory
105
+ URL.revokeObjectURL(link.href);
106
+ document.body.removeChild(link);
107
+ }
108
+ /**
109
+ * Converts a Data URL to a Blob object.
110
+ *
111
+ * @param dataUrl - The Data URL to convert.
112
+ * @param mimeType - Optional. The MIME type of the resulting Blob.
113
+ * @returns A Blob object representing the data.
114
+ */
115
+ export function dataUrlToBlob(dataUrl, mimeType) {
116
+ const byteString = atob(dataUrl.split(',')[1]);
117
+ const ab = new ArrayBuffer(byteString.length);
118
+ const ia = new Uint8Array(ab);
119
+ for (let i = 0; i < byteString.length; i++) {
120
+ ia[i] = byteString.charCodeAt(i);
121
+ }
122
+ return new Blob([ab], { type: mimeType || 'application/octet-stream' });
123
+ }
124
+ /**
125
+ * Determines if a given string is a valid Data URL.
126
+ *
127
+ * @param str - The string to validate.
128
+ * @returns A boolean indicating whether the string is a valid Data URL.
129
+ */
130
+ export function isDataUrl(str) {
131
+ const pattern = /^data:([a-zA-Z0-9/+.-]+);base64,/;
132
+ return pattern.test(str);
133
+ }
134
+ /**
135
+ * Determines if a given string is a valid URL.
136
+ *
137
+ * @param str - The string to validate.
138
+ * @returns A boolean indicating whether the string is a valid URL.
139
+ */
140
+ export function isUrl(str) {
141
+ try {
142
+ new URL(str);
143
+ return true;
144
+ }
145
+ catch (_) {
146
+ return false;
147
+ }
148
+ }
149
+ /**
150
+ * Extracts the filename from a URL.
151
+ *
152
+ * @param url - The URL string.
153
+ * @returns The extracted filename, or 'download' if the URL does not contain a filename.
154
+ */
155
+ export function getFilenameFromUrl(url) {
156
+ const segments = url.split('/');
157
+ const filename = segments.pop();
158
+ return filename && filename.includes('.') ? filename : 'download';
159
+ }