@zag-js/file-utils 0.30.0 → 0.31.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/dist/index.d.mts CHANGED
@@ -1,4 +1,29 @@
1
- declare function downloadFile(fileOrUrl: File | string, win: typeof window): void;
1
+ declare function dataURItoBlob(uri: string): Blob;
2
+
3
+ declare function isMSEdge(win: Window): win is Window & {
4
+ navigator: {
5
+ msSaveOrOpenBlob: Function;
6
+ };
7
+ };
8
+ interface DownloadFileOptions {
9
+ /**
10
+ * The name of the file
11
+ */
12
+ name?: string;
13
+ /**
14
+ * The MIME type of the file
15
+ */
16
+ type?: string;
17
+ /**
18
+ * The file contents
19
+ */
20
+ file: File | Blob | string;
21
+ /**
22
+ * The window environment
23
+ */
24
+ win: typeof window;
25
+ }
26
+ declare function downloadFile(options: DownloadFileOptions): void;
2
27
 
3
28
  interface FormatByteOptions {
4
29
  locale?: string;
@@ -13,8 +38,10 @@ declare const getTotalFileSize: (files: File[]) => number;
13
38
 
14
39
  declare const isFileEqual: (file1: File, file2: File) => boolean;
15
40
 
16
- declare function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, string | null];
41
+ type FileError = "TOO_MANY_FILES" | "FILE_INVALID_TYPE" | "FILE_TOO_LARGE" | "FILE_TOO_SMALL";
42
+
43
+ declare function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, FileError | null];
17
44
 
18
- declare function isValidFileType(file: File, accept: string | undefined): [boolean, string | null];
45
+ declare function isValidFileType(file: File, accept: string | undefined): [boolean, FileError | null];
19
46
 
20
- export { downloadFile, formatFileSize, getAcceptAttrString, getFileDataUrl, getTotalFileSize, isFileEqual, isValidFileSize, isValidFileType };
47
+ export { type FileError, dataURItoBlob, downloadFile, formatFileSize, getAcceptAttrString, getFileDataUrl, getTotalFileSize, isFileEqual, isMSEdge, isValidFileSize, isValidFileType };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,29 @@
1
- declare function downloadFile(fileOrUrl: File | string, win: typeof window): void;
1
+ declare function dataURItoBlob(uri: string): Blob;
2
+
3
+ declare function isMSEdge(win: Window): win is Window & {
4
+ navigator: {
5
+ msSaveOrOpenBlob: Function;
6
+ };
7
+ };
8
+ interface DownloadFileOptions {
9
+ /**
10
+ * The name of the file
11
+ */
12
+ name?: string;
13
+ /**
14
+ * The MIME type of the file
15
+ */
16
+ type?: string;
17
+ /**
18
+ * The file contents
19
+ */
20
+ file: File | Blob | string;
21
+ /**
22
+ * The window environment
23
+ */
24
+ win: typeof window;
25
+ }
26
+ declare function downloadFile(options: DownloadFileOptions): void;
2
27
 
3
28
  interface FormatByteOptions {
4
29
  locale?: string;
@@ -13,8 +38,10 @@ declare const getTotalFileSize: (files: File[]) => number;
13
38
 
14
39
  declare const isFileEqual: (file1: File, file2: File) => boolean;
15
40
 
16
- declare function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, string | null];
41
+ type FileError = "TOO_MANY_FILES" | "FILE_INVALID_TYPE" | "FILE_TOO_LARGE" | "FILE_TOO_SMALL";
42
+
43
+ declare function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, FileError | null];
17
44
 
18
- declare function isValidFileType(file: File, accept: string | undefined): [boolean, string | null];
45
+ declare function isValidFileType(file: File, accept: string | undefined): [boolean, FileError | null];
19
46
 
20
- export { downloadFile, formatFileSize, getAcceptAttrString, getFileDataUrl, getTotalFileSize, isFileEqual, isValidFileSize, isValidFileType };
47
+ export { type FileError, dataURItoBlob, downloadFile, formatFileSize, getAcceptAttrString, getFileDataUrl, getTotalFileSize, isFileEqual, isMSEdge, isValidFileSize, isValidFileType };
package/dist/index.js CHANGED
@@ -20,32 +20,55 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ dataURItoBlob: () => dataURItoBlob,
23
24
  downloadFile: () => downloadFile,
24
25
  formatFileSize: () => formatFileSize,
25
26
  getAcceptAttrString: () => getAcceptAttrString,
26
27
  getFileDataUrl: () => getFileDataUrl,
27
28
  getTotalFileSize: () => getTotalFileSize,
28
29
  isFileEqual: () => isFileEqual,
30
+ isMSEdge: () => isMSEdge,
29
31
  isValidFileSize: () => isValidFileSize,
30
32
  isValidFileType: () => isValidFileType
31
33
  });
32
34
  module.exports = __toCommonJS(src_exports);
33
35
 
36
+ // src/data-url-to-blob.ts
37
+ function dataURItoBlob(uri) {
38
+ const binary = atob(uri.split(",")[1]);
39
+ const mimeString = uri.split(",")[0].split(":")[1].split(";")[0];
40
+ const buffer = new ArrayBuffer(binary.length);
41
+ const intArray = new Uint8Array(buffer);
42
+ for (let i = 0; i < binary.length; i++) {
43
+ intArray[i] = binary.charCodeAt(i);
44
+ }
45
+ return new Blob([buffer], { type: mimeString });
46
+ }
47
+
34
48
  // src/download-file.ts
35
- function downloadFile(fileOrUrl, win) {
49
+ function isMSEdge(win) {
50
+ return Boolean(win.navigator && win.navigator.msSaveOrOpenBlob);
51
+ }
52
+ function downloadFile(options) {
53
+ const { file, win, type, name } = options;
36
54
  const doc = win.document;
37
- const objectUrl = typeof fileOrUrl === "string" ? fileOrUrl : win.URL.createObjectURL(fileOrUrl);
55
+ const obj = typeof file === "string" ? new Blob([file], { type }) : file;
56
+ const fileName = typeof file === "string" ? name : file instanceof File ? file.name : void 0;
57
+ if (isMSEdge(win)) {
58
+ win.navigator.msSaveOrOpenBlob(obj, fileName || "file-download");
59
+ return;
60
+ }
61
+ const url = win.URL.createObjectURL(obj);
38
62
  const anchor = doc.createElement("a");
39
63
  anchor.style.display = "none";
40
- anchor.href = objectUrl;
41
- anchor.download = typeof fileOrUrl === "string" ? objectUrl : fileOrUrl.name;
42
- doc.body.appendChild(anchor);
64
+ anchor.href = url;
65
+ anchor.rel = "noopener";
66
+ anchor.download = fileName || "file-download";
67
+ doc.documentElement.appendChild(anchor);
43
68
  anchor.click();
44
69
  setTimeout(() => {
45
- if (typeof fileOrUrl !== "string") {
46
- win.URL.revokeObjectURL(objectUrl);
47
- }
48
- anchor?.parentNode?.removeChild(anchor);
70
+ win.URL.revokeObjectURL(url);
71
+ anchor.remove();
49
72
  }, 0);
50
73
  }
51
74
 
@@ -113,13 +136,13 @@ function isValidFileSize(file, minSize, maxSize) {
113
136
  if (isDefined(file.size)) {
114
137
  if (isDefined(minSize) && isDefined(maxSize)) {
115
138
  if (file.size > maxSize)
116
- return [false, "TOO_LARGE"];
139
+ return [false, "FILE_TOO_LARGE"];
117
140
  if (file.size < minSize)
118
- return [false, "TOO_SMALL"];
141
+ return [false, "FILE_TOO_SMALL"];
119
142
  } else if (isDefined(minSize) && file.size < minSize) {
120
- return [false, "TOO_SMALL"];
143
+ return [false, "FILE_TOO_SMALL"];
121
144
  } else if (isDefined(maxSize) && file.size > maxSize) {
122
- return [false, "TOO_LARGE"];
145
+ return [false, "FILE_TOO_LARGE"];
123
146
  }
124
147
  }
125
148
  return [true, null];
@@ -151,12 +174,14 @@ function isValidFileType(file, accept) {
151
174
  }
152
175
  // Annotate the CommonJS export names for ESM import in node:
153
176
  0 && (module.exports = {
177
+ dataURItoBlob,
154
178
  downloadFile,
155
179
  formatFileSize,
156
180
  getAcceptAttrString,
157
181
  getFileDataUrl,
158
182
  getTotalFileSize,
159
183
  isFileEqual,
184
+ isMSEdge,
160
185
  isValidFileSize,
161
186
  isValidFileType
162
187
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/download-file.ts","../src/format-file-size.ts","../src/get-accept-attr.ts","../src/get-file-data-url.ts","../src/get-total-file-size.ts","../src/is-file-equal.ts","../src/is-valid-file-size.ts","../src/is-valid-file-type.ts"],"sourcesContent":["export * from \"./download-file\"\nexport * from \"./format-file-size\"\nexport * from \"./get-accept-attr\"\nexport * from \"./get-file-data-url\"\nexport * from \"./get-total-file-size\"\nexport * from \"./is-file-equal\"\nexport * from \"./is-valid-file-size\"\nexport * from \"./is-valid-file-type\"\n","export function downloadFile(fileOrUrl: File | string, win: typeof window) {\n const doc = win.document\n const objectUrl = typeof fileOrUrl === \"string\" ? fileOrUrl : win.URL.createObjectURL(fileOrUrl)\n\n const anchor = doc.createElement(\"a\")\n anchor.style.display = \"none\"\n anchor.href = objectUrl\n anchor.download = typeof fileOrUrl === \"string\" ? objectUrl : fileOrUrl.name\n\n doc.body.appendChild(anchor)\n anchor.click()\n\n setTimeout(() => {\n if (typeof fileOrUrl !== \"string\") {\n win.URL.revokeObjectURL(objectUrl)\n }\n anchor?.parentNode?.removeChild(anchor)\n }, 0)\n}\n","const SIZES = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"]\nconst KILO = 1024\n\ninterface FormatByteOptions {\n locale?: string\n}\n\nexport const formatFileSize = (bytes: number, options: FormatByteOptions = {}) => {\n const { locale = \"en-US\" } = options\n if (bytes === 0) return \"0 B\"\n\n const i = Math.floor(Math.log(bytes) / Math.log(KILO))\n const fileSize = bytes / Math.pow(KILO, i)\n\n const formattedSize = new Intl.NumberFormat(locale).format(fileSize)\n return `${formattedSize} ${SIZES[i]}`\n}\n","function isMIMEType(v: string) {\n return v === \"audio/*\" || v === \"video/*\" || v === \"image/*\" || v === \"text/*\" || /\\w+\\/[-+.\\w]+/g.test(v)\n}\n\nfunction isExt(v: string) {\n return /^.*\\.[\\w]+$/.test(v)\n}\n\nexport function getAcceptAttrString(accept: Record<string, string[]> | string | undefined) {\n if (!accept) return\n if (typeof accept === \"string\") return accept\n return Object.entries(accept)\n .reduce((a, [mimeType, ext]) => [...a, mimeType, ...ext], [] as string[])\n .filter((v) => isMIMEType(v) || isExt(v))\n .join(\",\")\n}\n","export const getFileDataUrl = async (file: File | Blob) => {\n const reader = new FileReader()\n return new Promise<string | undefined>((resolve, reject) => {\n reader.onerror = () => {\n reader.abort()\n reject(new Error(\"There was an error reading a file\"))\n }\n\n reader.onloadend = () => {\n const { result } = reader\n if (result instanceof ArrayBuffer) {\n reject(new Error(\"Expected DataURL as string from Blob/File, got ArrayBuffer\"))\n } else {\n resolve(result || undefined)\n }\n }\n\n reader.readAsDataURL(file)\n })\n}\n","export const getTotalFileSize = (files: File[]) => {\n return files.reduce((acc, file) => acc + file.size, 0)\n}\n","export const isFileEqual = (file1: File, file2: File) => {\n return file1.name === file2.name && file1.size === file2.size && file1.type === file2.type\n}\n","const isDefined = <T>(v: T | undefined): v is T => v !== undefined && v !== null\n\nexport function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, string | null] {\n if (isDefined(file.size)) {\n if (isDefined(minSize) && isDefined(maxSize)) {\n if (file.size > maxSize) return [false, \"TOO_LARGE\"]\n if (file.size < minSize) return [false, \"TOO_SMALL\"]\n } else if (isDefined(minSize) && file.size < minSize) {\n return [false, \"TOO_SMALL\"]\n } else if (isDefined(maxSize) && file.size > maxSize) {\n return [false, \"TOO_LARGE\"]\n }\n }\n return [true, null]\n}\n","function isFileAccepted(file: File | null, accept: string[] | string | undefined) {\n if (file && accept) {\n const types = Array.isArray(accept) ? accept : accept.split(\",\")\n\n const fileName = file.name || \"\"\n const mimeType = (file.type || \"\").toLowerCase()\n const baseMimeType = mimeType.replace(/\\/.*$/, \"\")\n\n return types.some((type) => {\n const validType = type.trim().toLowerCase()\n\n if (validType.charAt(0) === \".\") {\n return fileName.toLowerCase().endsWith(validType)\n }\n\n if (validType.endsWith(\"/*\")) {\n return baseMimeType === validType.replace(/\\/.*$/, \"\")\n }\n\n return mimeType === validType\n })\n }\n return true\n}\n\nexport function isValidFileType(file: File, accept: string | undefined): [boolean, string | null] {\n const isAcceptable = file.type === \"application/x-moz-file\" || isFileAccepted(file, accept)\n return [isAcceptable, isAcceptable ? null : \"FILE_INVALID_TYPE\"]\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/data-url-to-blob.ts","../src/download-file.ts","../src/format-file-size.ts","../src/get-accept-attr.ts","../src/get-file-data-url.ts","../src/get-total-file-size.ts","../src/is-file-equal.ts","../src/is-valid-file-size.ts","../src/is-valid-file-type.ts"],"sourcesContent":["export * from \"./data-url-to-blob\"\nexport * from \"./download-file\"\nexport * from \"./format-file-size\"\nexport * from \"./get-accept-attr\"\nexport * from \"./get-file-data-url\"\nexport * from \"./get-total-file-size\"\nexport * from \"./is-file-equal\"\nexport * from \"./is-valid-file-size\"\nexport * from \"./is-valid-file-type\"\nexport type * from \"./types.ts\"\n","export function dataURItoBlob(uri: string): Blob {\n const binary = atob(uri.split(\",\")[1])\n\n // separate out the mime component\n const mimeString = uri.split(\",\")[0].split(\":\")[1].split(\";\")[0]\n\n // write the bytes of the string to an ArrayBuffer\n const buffer = new ArrayBuffer(binary.length)\n\n // create a view into the buffer\n const intArray = new Uint8Array(buffer)\n\n for (let i = 0; i < binary.length; i++) {\n intArray[i] = binary.charCodeAt(i)\n }\n\n return new Blob([buffer], { type: mimeString })\n}\n","export function isMSEdge(win: Window): win is Window & { navigator: { msSaveOrOpenBlob: Function } } {\n // @ts-ignore\n return Boolean(win.navigator && win.navigator.msSaveOrOpenBlob)\n}\n\ninterface DownloadFileOptions {\n /**\n * The name of the file\n */\n name?: string\n /**\n * The MIME type of the file\n */\n type?: string\n /**\n * The file contents\n */\n file: File | Blob | string\n /**\n * The window environment\n */\n win: typeof window\n}\n\nexport function downloadFile(options: DownloadFileOptions) {\n const { file, win, type, name } = options\n\n const doc = win.document\n\n const obj = typeof file === \"string\" ? new Blob([file], { type }) : file\n const fileName = typeof file === \"string\" ? name : file instanceof File ? file.name : undefined\n\n if (isMSEdge(win)) {\n win.navigator.msSaveOrOpenBlob(obj, fileName || \"file-download\")\n return\n }\n\n const url = win.URL.createObjectURL(obj)\n\n const anchor = doc.createElement(\"a\")\n anchor.style.display = \"none\"\n anchor.href = url\n anchor.rel = \"noopener\"\n anchor.download = fileName || \"file-download\"\n\n doc.documentElement.appendChild(anchor)\n anchor.click()\n\n setTimeout(() => {\n win.URL.revokeObjectURL(url)\n anchor.remove()\n }, 0)\n}\n","const SIZES = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"]\nconst KILO = 1024\n\ninterface FormatByteOptions {\n locale?: string\n}\n\nexport const formatFileSize = (bytes: number, options: FormatByteOptions = {}) => {\n const { locale = \"en-US\" } = options\n if (bytes === 0) return \"0 B\"\n\n const i = Math.floor(Math.log(bytes) / Math.log(KILO))\n const fileSize = bytes / Math.pow(KILO, i)\n\n const formattedSize = new Intl.NumberFormat(locale).format(fileSize)\n return `${formattedSize} ${SIZES[i]}`\n}\n","function isMIMEType(v: string) {\n return v === \"audio/*\" || v === \"video/*\" || v === \"image/*\" || v === \"text/*\" || /\\w+\\/[-+.\\w]+/g.test(v)\n}\n\nfunction isExt(v: string) {\n return /^.*\\.[\\w]+$/.test(v)\n}\n\nexport function getAcceptAttrString(accept: Record<string, string[]> | string | undefined) {\n if (!accept) return\n if (typeof accept === \"string\") return accept\n return Object.entries(accept)\n .reduce((a, [mimeType, ext]) => [...a, mimeType, ...ext], [] as string[])\n .filter((v) => isMIMEType(v) || isExt(v))\n .join(\",\")\n}\n","export const getFileDataUrl = async (file: File | Blob) => {\n const reader = new FileReader()\n return new Promise<string | undefined>((resolve, reject) => {\n reader.onerror = () => {\n reader.abort()\n reject(new Error(\"There was an error reading a file\"))\n }\n\n reader.onloadend = () => {\n const { result } = reader\n if (result instanceof ArrayBuffer) {\n reject(new Error(\"Expected DataURL as string from Blob/File, got ArrayBuffer\"))\n } else {\n resolve(result || undefined)\n }\n }\n\n reader.readAsDataURL(file)\n })\n}\n","export const getTotalFileSize = (files: File[]) => {\n return files.reduce((acc, file) => acc + file.size, 0)\n}\n","export const isFileEqual = (file1: File, file2: File) => {\n return file1.name === file2.name && file1.size === file2.size && file1.type === file2.type\n}\n","import type { FileError } from \"./types\"\n\nconst isDefined = <T>(v: T | undefined): v is T => v !== undefined && v !== null\n\nexport function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, FileError | null] {\n if (isDefined(file.size)) {\n if (isDefined(minSize) && isDefined(maxSize)) {\n if (file.size > maxSize) return [false, \"FILE_TOO_LARGE\"]\n if (file.size < minSize) return [false, \"FILE_TOO_SMALL\"]\n } else if (isDefined(minSize) && file.size < minSize) {\n return [false, \"FILE_TOO_SMALL\"]\n } else if (isDefined(maxSize) && file.size > maxSize) {\n return [false, \"FILE_TOO_LARGE\"]\n }\n }\n return [true, null]\n}\n","import type { FileError } from \"./types\"\n\nfunction isFileAccepted(file: File | null, accept: string[] | string | undefined) {\n if (file && accept) {\n const types = Array.isArray(accept) ? accept : accept.split(\",\")\n\n const fileName = file.name || \"\"\n const mimeType = (file.type || \"\").toLowerCase()\n const baseMimeType = mimeType.replace(/\\/.*$/, \"\")\n\n return types.some((type) => {\n const validType = type.trim().toLowerCase()\n\n if (validType.charAt(0) === \".\") {\n return fileName.toLowerCase().endsWith(validType)\n }\n\n if (validType.endsWith(\"/*\")) {\n return baseMimeType === validType.replace(/\\/.*$/, \"\")\n }\n\n return mimeType === validType\n })\n }\n return true\n}\n\nexport function isValidFileType(file: File, accept: string | undefined): [boolean, FileError | null] {\n const isAcceptable = file.type === \"application/x-moz-file\" || isFileAccepted(file, accept)\n return [isAcceptable, isAcceptable ? null : \"FILE_INVALID_TYPE\"]\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -1,18 +1,39 @@
1
+ // src/data-url-to-blob.ts
2
+ function dataURItoBlob(uri) {
3
+ const binary = atob(uri.split(",")[1]);
4
+ const mimeString = uri.split(",")[0].split(":")[1].split(";")[0];
5
+ const buffer = new ArrayBuffer(binary.length);
6
+ const intArray = new Uint8Array(buffer);
7
+ for (let i = 0; i < binary.length; i++) {
8
+ intArray[i] = binary.charCodeAt(i);
9
+ }
10
+ return new Blob([buffer], { type: mimeString });
11
+ }
12
+
1
13
  // src/download-file.ts
2
- function downloadFile(fileOrUrl, win) {
14
+ function isMSEdge(win) {
15
+ return Boolean(win.navigator && win.navigator.msSaveOrOpenBlob);
16
+ }
17
+ function downloadFile(options) {
18
+ const { file, win, type, name } = options;
3
19
  const doc = win.document;
4
- const objectUrl = typeof fileOrUrl === "string" ? fileOrUrl : win.URL.createObjectURL(fileOrUrl);
20
+ const obj = typeof file === "string" ? new Blob([file], { type }) : file;
21
+ const fileName = typeof file === "string" ? name : file instanceof File ? file.name : void 0;
22
+ if (isMSEdge(win)) {
23
+ win.navigator.msSaveOrOpenBlob(obj, fileName || "file-download");
24
+ return;
25
+ }
26
+ const url = win.URL.createObjectURL(obj);
5
27
  const anchor = doc.createElement("a");
6
28
  anchor.style.display = "none";
7
- anchor.href = objectUrl;
8
- anchor.download = typeof fileOrUrl === "string" ? objectUrl : fileOrUrl.name;
9
- doc.body.appendChild(anchor);
29
+ anchor.href = url;
30
+ anchor.rel = "noopener";
31
+ anchor.download = fileName || "file-download";
32
+ doc.documentElement.appendChild(anchor);
10
33
  anchor.click();
11
34
  setTimeout(() => {
12
- if (typeof fileOrUrl !== "string") {
13
- win.URL.revokeObjectURL(objectUrl);
14
- }
15
- anchor?.parentNode?.removeChild(anchor);
35
+ win.URL.revokeObjectURL(url);
36
+ anchor.remove();
16
37
  }, 0);
17
38
  }
18
39
 
@@ -80,13 +101,13 @@ function isValidFileSize(file, minSize, maxSize) {
80
101
  if (isDefined(file.size)) {
81
102
  if (isDefined(minSize) && isDefined(maxSize)) {
82
103
  if (file.size > maxSize)
83
- return [false, "TOO_LARGE"];
104
+ return [false, "FILE_TOO_LARGE"];
84
105
  if (file.size < minSize)
85
- return [false, "TOO_SMALL"];
106
+ return [false, "FILE_TOO_SMALL"];
86
107
  } else if (isDefined(minSize) && file.size < minSize) {
87
- return [false, "TOO_SMALL"];
108
+ return [false, "FILE_TOO_SMALL"];
88
109
  } else if (isDefined(maxSize) && file.size > maxSize) {
89
- return [false, "TOO_LARGE"];
110
+ return [false, "FILE_TOO_LARGE"];
90
111
  }
91
112
  }
92
113
  return [true, null];
@@ -117,12 +138,14 @@ function isValidFileType(file, accept) {
117
138
  return [isAcceptable, isAcceptable ? null : "FILE_INVALID_TYPE"];
118
139
  }
119
140
  export {
141
+ dataURItoBlob,
120
142
  downloadFile,
121
143
  formatFileSize,
122
144
  getAcceptAttrString,
123
145
  getFileDataUrl,
124
146
  getTotalFileSize,
125
147
  isFileEqual,
148
+ isMSEdge,
126
149
  isValidFileSize,
127
150
  isValidFileType
128
151
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/download-file.ts","../src/format-file-size.ts","../src/get-accept-attr.ts","../src/get-file-data-url.ts","../src/get-total-file-size.ts","../src/is-file-equal.ts","../src/is-valid-file-size.ts","../src/is-valid-file-type.ts"],"sourcesContent":["export function downloadFile(fileOrUrl: File | string, win: typeof window) {\n const doc = win.document\n const objectUrl = typeof fileOrUrl === \"string\" ? fileOrUrl : win.URL.createObjectURL(fileOrUrl)\n\n const anchor = doc.createElement(\"a\")\n anchor.style.display = \"none\"\n anchor.href = objectUrl\n anchor.download = typeof fileOrUrl === \"string\" ? objectUrl : fileOrUrl.name\n\n doc.body.appendChild(anchor)\n anchor.click()\n\n setTimeout(() => {\n if (typeof fileOrUrl !== \"string\") {\n win.URL.revokeObjectURL(objectUrl)\n }\n anchor?.parentNode?.removeChild(anchor)\n }, 0)\n}\n","const SIZES = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"]\nconst KILO = 1024\n\ninterface FormatByteOptions {\n locale?: string\n}\n\nexport const formatFileSize = (bytes: number, options: FormatByteOptions = {}) => {\n const { locale = \"en-US\" } = options\n if (bytes === 0) return \"0 B\"\n\n const i = Math.floor(Math.log(bytes) / Math.log(KILO))\n const fileSize = bytes / Math.pow(KILO, i)\n\n const formattedSize = new Intl.NumberFormat(locale).format(fileSize)\n return `${formattedSize} ${SIZES[i]}`\n}\n","function isMIMEType(v: string) {\n return v === \"audio/*\" || v === \"video/*\" || v === \"image/*\" || v === \"text/*\" || /\\w+\\/[-+.\\w]+/g.test(v)\n}\n\nfunction isExt(v: string) {\n return /^.*\\.[\\w]+$/.test(v)\n}\n\nexport function getAcceptAttrString(accept: Record<string, string[]> | string | undefined) {\n if (!accept) return\n if (typeof accept === \"string\") return accept\n return Object.entries(accept)\n .reduce((a, [mimeType, ext]) => [...a, mimeType, ...ext], [] as string[])\n .filter((v) => isMIMEType(v) || isExt(v))\n .join(\",\")\n}\n","export const getFileDataUrl = async (file: File | Blob) => {\n const reader = new FileReader()\n return new Promise<string | undefined>((resolve, reject) => {\n reader.onerror = () => {\n reader.abort()\n reject(new Error(\"There was an error reading a file\"))\n }\n\n reader.onloadend = () => {\n const { result } = reader\n if (result instanceof ArrayBuffer) {\n reject(new Error(\"Expected DataURL as string from Blob/File, got ArrayBuffer\"))\n } else {\n resolve(result || undefined)\n }\n }\n\n reader.readAsDataURL(file)\n })\n}\n","export const getTotalFileSize = (files: File[]) => {\n return files.reduce((acc, file) => acc + file.size, 0)\n}\n","export const isFileEqual = (file1: File, file2: File) => {\n return file1.name === file2.name && file1.size === file2.size && file1.type === file2.type\n}\n","const isDefined = <T>(v: T | undefined): v is T => v !== undefined && v !== null\n\nexport function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, string | null] {\n if (isDefined(file.size)) {\n if (isDefined(minSize) && isDefined(maxSize)) {\n if (file.size > maxSize) return [false, \"TOO_LARGE\"]\n if (file.size < minSize) return [false, \"TOO_SMALL\"]\n } else if (isDefined(minSize) && file.size < minSize) {\n return [false, \"TOO_SMALL\"]\n } else if (isDefined(maxSize) && file.size > maxSize) {\n return [false, \"TOO_LARGE\"]\n }\n }\n return [true, null]\n}\n","function isFileAccepted(file: File | null, accept: string[] | string | undefined) {\n if (file && accept) {\n const types = Array.isArray(accept) ? accept : accept.split(\",\")\n\n const fileName = file.name || \"\"\n const mimeType = (file.type || \"\").toLowerCase()\n const baseMimeType = mimeType.replace(/\\/.*$/, \"\")\n\n return types.some((type) => {\n const validType = type.trim().toLowerCase()\n\n if (validType.charAt(0) === \".\") {\n return fileName.toLowerCase().endsWith(validType)\n }\n\n if (validType.endsWith(\"/*\")) {\n return baseMimeType === validType.replace(/\\/.*$/, \"\")\n }\n\n return mimeType === validType\n })\n }\n return true\n}\n\nexport function isValidFileType(file: File, accept: string | undefined): [boolean, string | null] {\n const isAcceptable = file.type === \"application/x-moz-file\" || isFileAccepted(file, accept)\n return [isAcceptable, isAcceptable ? null : \"FILE_INVALID_TYPE\"]\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/data-url-to-blob.ts","../src/download-file.ts","../src/format-file-size.ts","../src/get-accept-attr.ts","../src/get-file-data-url.ts","../src/get-total-file-size.ts","../src/is-file-equal.ts","../src/is-valid-file-size.ts","../src/is-valid-file-type.ts"],"sourcesContent":["export function dataURItoBlob(uri: string): Blob {\n const binary = atob(uri.split(\",\")[1])\n\n // separate out the mime component\n const mimeString = uri.split(\",\")[0].split(\":\")[1].split(\";\")[0]\n\n // write the bytes of the string to an ArrayBuffer\n const buffer = new ArrayBuffer(binary.length)\n\n // create a view into the buffer\n const intArray = new Uint8Array(buffer)\n\n for (let i = 0; i < binary.length; i++) {\n intArray[i] = binary.charCodeAt(i)\n }\n\n return new Blob([buffer], { type: mimeString })\n}\n","export function isMSEdge(win: Window): win is Window & { navigator: { msSaveOrOpenBlob: Function } } {\n // @ts-ignore\n return Boolean(win.navigator && win.navigator.msSaveOrOpenBlob)\n}\n\ninterface DownloadFileOptions {\n /**\n * The name of the file\n */\n name?: string\n /**\n * The MIME type of the file\n */\n type?: string\n /**\n * The file contents\n */\n file: File | Blob | string\n /**\n * The window environment\n */\n win: typeof window\n}\n\nexport function downloadFile(options: DownloadFileOptions) {\n const { file, win, type, name } = options\n\n const doc = win.document\n\n const obj = typeof file === \"string\" ? new Blob([file], { type }) : file\n const fileName = typeof file === \"string\" ? name : file instanceof File ? file.name : undefined\n\n if (isMSEdge(win)) {\n win.navigator.msSaveOrOpenBlob(obj, fileName || \"file-download\")\n return\n }\n\n const url = win.URL.createObjectURL(obj)\n\n const anchor = doc.createElement(\"a\")\n anchor.style.display = \"none\"\n anchor.href = url\n anchor.rel = \"noopener\"\n anchor.download = fileName || \"file-download\"\n\n doc.documentElement.appendChild(anchor)\n anchor.click()\n\n setTimeout(() => {\n win.URL.revokeObjectURL(url)\n anchor.remove()\n }, 0)\n}\n","const SIZES = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"]\nconst KILO = 1024\n\ninterface FormatByteOptions {\n locale?: string\n}\n\nexport const formatFileSize = (bytes: number, options: FormatByteOptions = {}) => {\n const { locale = \"en-US\" } = options\n if (bytes === 0) return \"0 B\"\n\n const i = Math.floor(Math.log(bytes) / Math.log(KILO))\n const fileSize = bytes / Math.pow(KILO, i)\n\n const formattedSize = new Intl.NumberFormat(locale).format(fileSize)\n return `${formattedSize} ${SIZES[i]}`\n}\n","function isMIMEType(v: string) {\n return v === \"audio/*\" || v === \"video/*\" || v === \"image/*\" || v === \"text/*\" || /\\w+\\/[-+.\\w]+/g.test(v)\n}\n\nfunction isExt(v: string) {\n return /^.*\\.[\\w]+$/.test(v)\n}\n\nexport function getAcceptAttrString(accept: Record<string, string[]> | string | undefined) {\n if (!accept) return\n if (typeof accept === \"string\") return accept\n return Object.entries(accept)\n .reduce((a, [mimeType, ext]) => [...a, mimeType, ...ext], [] as string[])\n .filter((v) => isMIMEType(v) || isExt(v))\n .join(\",\")\n}\n","export const getFileDataUrl = async (file: File | Blob) => {\n const reader = new FileReader()\n return new Promise<string | undefined>((resolve, reject) => {\n reader.onerror = () => {\n reader.abort()\n reject(new Error(\"There was an error reading a file\"))\n }\n\n reader.onloadend = () => {\n const { result } = reader\n if (result instanceof ArrayBuffer) {\n reject(new Error(\"Expected DataURL as string from Blob/File, got ArrayBuffer\"))\n } else {\n resolve(result || undefined)\n }\n }\n\n reader.readAsDataURL(file)\n })\n}\n","export const getTotalFileSize = (files: File[]) => {\n return files.reduce((acc, file) => acc + file.size, 0)\n}\n","export const isFileEqual = (file1: File, file2: File) => {\n return file1.name === file2.name && file1.size === file2.size && file1.type === file2.type\n}\n","import type { FileError } from \"./types\"\n\nconst isDefined = <T>(v: T | undefined): v is T => v !== undefined && v !== null\n\nexport function isValidFileSize(file: File, minSize?: number, maxSize?: number): [boolean, FileError | null] {\n if (isDefined(file.size)) {\n if (isDefined(minSize) && isDefined(maxSize)) {\n if (file.size > maxSize) return [false, \"FILE_TOO_LARGE\"]\n if (file.size < minSize) return [false, \"FILE_TOO_SMALL\"]\n } else if (isDefined(minSize) && file.size < minSize) {\n return [false, \"FILE_TOO_SMALL\"]\n } else if (isDefined(maxSize) && file.size > maxSize) {\n return [false, \"FILE_TOO_LARGE\"]\n }\n }\n return [true, null]\n}\n","import type { FileError } from \"./types\"\n\nfunction isFileAccepted(file: File | null, accept: string[] | string | undefined) {\n if (file && accept) {\n const types = Array.isArray(accept) ? accept : accept.split(\",\")\n\n const fileName = file.name || \"\"\n const mimeType = (file.type || \"\").toLowerCase()\n const baseMimeType = mimeType.replace(/\\/.*$/, \"\")\n\n return types.some((type) => {\n const validType = type.trim().toLowerCase()\n\n if (validType.charAt(0) === \".\") {\n return fileName.toLowerCase().endsWith(validType)\n }\n\n if (validType.endsWith(\"/*\")) {\n return baseMimeType === validType.replace(/\\/.*$/, \"\")\n }\n\n return mimeType === validType\n })\n }\n return true\n}\n\nexport function isValidFileType(file: File, accept: string | undefined): [boolean, FileError | null] {\n const isAcceptable = file.type === \"application/x-moz-file\" || isFileAccepted(file, accept)\n return [isAcceptable, isAcceptable ? null : \"FILE_INVALID_TYPE\"]\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zag-js/file-utils",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "JS File API utilities",
5
5
  "keywords": [
6
6
  "js",