@gateweb/react-utils 1.12.2 → 1.13.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/cjs/index.d.ts +59 -4
- package/dist/cjs/index.js +96 -31
- package/dist/es/index.d.mts +59 -4
- package/dist/es/index.mjs +93 -32
- package/package.json +1 -1
package/dist/cjs/index.d.ts
CHANGED
|
@@ -474,11 +474,33 @@ declare const fakeApi: <T>(returnValue: T, result?: boolean, time?: number) => P
|
|
|
474
474
|
message: string;
|
|
475
475
|
}>;
|
|
476
476
|
|
|
477
|
+
declare const MimeTypeMap: {
|
|
478
|
+
readonly jpeg: "image/jpeg";
|
|
479
|
+
readonly jpg: "image/jpeg";
|
|
480
|
+
readonly gif: "image/gif";
|
|
481
|
+
readonly png: "image/png";
|
|
482
|
+
readonly pdf: "application/pdf";
|
|
483
|
+
readonly zip: "application/zip";
|
|
484
|
+
readonly csv: "text/csv";
|
|
485
|
+
readonly ppt: "application/vnd.ms-powerpoint";
|
|
486
|
+
readonly pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
487
|
+
readonly xls: "application/vnd.ms-excel";
|
|
488
|
+
readonly xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
489
|
+
readonly doc: "application/msword";
|
|
490
|
+
readonly docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
491
|
+
readonly txt: "text/plain";
|
|
492
|
+
};
|
|
493
|
+
declare const OtherMimeType = "application/octet-stream";
|
|
494
|
+
type MimeTypeExtension = keyof typeof MimeTypeMap;
|
|
495
|
+
type MimeTypeValue = (typeof MimeTypeMap)[MimeTypeExtension] | typeof OtherMimeType;
|
|
496
|
+
|
|
477
497
|
/**
|
|
478
|
-
*
|
|
498
|
+
* 檢查檔案是否為合法的檔案類型
|
|
499
|
+
*
|
|
500
|
+
* `accepts` 可同時接受副檔名以及 MIME 類型
|
|
479
501
|
*
|
|
480
502
|
* @param file 檔案
|
|
481
|
-
* @param accepts
|
|
503
|
+
* @param accepts 允許的類型
|
|
482
504
|
*
|
|
483
505
|
* @example
|
|
484
506
|
*
|
|
@@ -486,6 +508,7 @@ declare const fakeApi: <T>(returnValue: T, result?: boolean, time?: number) => P
|
|
|
486
508
|
* validateFileType({ type: 'image/png' }, ['image/png', 'image/jpeg']) // true
|
|
487
509
|
* validateFileType({ type: 'image/png' }, ['image/jpeg']) // false
|
|
488
510
|
* validateFileType({ type: 'image/png' }, ['image/*']) // true
|
|
511
|
+
* validateFileType({ name: '圖片.png', type: 'image/png' }, ['.png']) // true
|
|
489
512
|
* ```
|
|
490
513
|
*/
|
|
491
514
|
declare const validateFileType: (file: File, accepts: string[]) => boolean;
|
|
@@ -511,8 +534,40 @@ declare const validateFileType: (file: File, accepts: string[]) => boolean;
|
|
|
511
534
|
* getMimeType('xlsx') // 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
512
535
|
* getMimeType('doc') // 'application/msword'
|
|
513
536
|
* getMimeType('docx') // 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
537
|
+
*
|
|
538
|
+
* @deprecated use `parseFileInfoFromFilename` instead
|
|
539
|
+
*/
|
|
540
|
+
declare const getMimeType: (fileName: string) => "image/jpeg" | "image/gif" | "image/png" | "application/pdf" | "application/zip" | "text/csv" | "application/vnd.ms-powerpoint" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "text/plain";
|
|
541
|
+
/**
|
|
542
|
+
* 用來解析後端在 response header content-disposition 的內容
|
|
543
|
+
*
|
|
544
|
+
* 一般來說格式會有以下兩種
|
|
545
|
+
*
|
|
546
|
+
* - Content-Disposition: attachment; filename="file name.jpg"
|
|
547
|
+
* - Content-Disposition: attachment; filename*=UTF-8''file%20name2.jpg
|
|
548
|
+
*
|
|
549
|
+
* 如果格式正確就會取得檔案名稱(包含副檔名),優先取 filename* 內的內容
|
|
550
|
+
*
|
|
551
|
+
* @param disposition Content-Disposition
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
*
|
|
555
|
+
* parseFilenameFromDisposition('attachment; filename="file name1.jpg') // file name.jpg
|
|
556
|
+
* parseFilenameFromDisposition('attachment; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
557
|
+
* parseFilenameFromDisposition('attachment; filename="file name.jpg; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
558
|
+
*/
|
|
559
|
+
declare const parseFilenameFromDisposition: (disposition: string) => string | undefined;
|
|
560
|
+
/**
|
|
561
|
+
* 解析 `filename` 回傳檔名、副檔名、MIME type
|
|
562
|
+
*
|
|
563
|
+
* @param filename 檔案名稱
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
*
|
|
567
|
+
* parseFileInfoFromFilename('image.jpg') // ['image', 'jpg', 'image/jpeg']
|
|
568
|
+
* parseFileInfoFromFilename('image') // ['image', '', 'application/octet-stream']
|
|
514
569
|
*/
|
|
515
|
-
declare const
|
|
570
|
+
declare const parseFileInfoFromFilename: (filename: string) => [string, string, MimeTypeValue];
|
|
516
571
|
|
|
517
572
|
declare function invariant(condition: any, message?: string | (() => string)): asserts condition;
|
|
518
573
|
|
|
@@ -1149,4 +1204,4 @@ declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefin
|
|
|
1149
1204
|
*/
|
|
1150
1205
|
declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
|
|
1151
1206
|
|
|
1152
|
-
export { ByteSize, type PartialBy, QueryProvider, type RequiredBy, type TCountdownActions, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, deepMerge, downloadFile, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeRefs, objectToSearchParams, omit, omitByValue, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, searchParamsToObject, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
|
|
1207
|
+
export { ByteSize, type MimeTypeExtension, MimeTypeMap, type MimeTypeValue, OtherMimeType, type PartialBy, QueryProvider, type RequiredBy, type TCountdownActions, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, deepMerge, downloadFile, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeRefs, objectToSearchParams, omit, omitByValue, parseFileInfoFromFilename, parseFilenameFromDisposition, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, searchParamsToObject, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
|
package/dist/cjs/index.js
CHANGED
|
@@ -238,11 +238,31 @@ function createEnumLikeObject(obj, name, scene) {
|
|
|
238
238
|
}, time);
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
+
const MimeTypeMap = {
|
|
242
|
+
jpeg: 'image/jpeg',
|
|
243
|
+
jpg: 'image/jpeg',
|
|
244
|
+
gif: 'image/gif',
|
|
245
|
+
png: 'image/png',
|
|
246
|
+
pdf: 'application/pdf',
|
|
247
|
+
zip: 'application/zip',
|
|
248
|
+
csv: 'text/csv',
|
|
249
|
+
ppt: 'application/vnd.ms-powerpoint',
|
|
250
|
+
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
251
|
+
xls: 'application/vnd.ms-excel',
|
|
252
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
253
|
+
doc: 'application/msword',
|
|
254
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
255
|
+
txt: 'text/plain'
|
|
256
|
+
};
|
|
257
|
+
const OtherMimeType = 'application/octet-stream';
|
|
258
|
+
|
|
241
259
|
/**
|
|
242
|
-
*
|
|
260
|
+
* 檢查檔案是否為合法的檔案類型
|
|
261
|
+
*
|
|
262
|
+
* `accepts` 可同時接受副檔名以及 MIME 類型
|
|
243
263
|
*
|
|
244
264
|
* @param file 檔案
|
|
245
|
-
* @param accepts
|
|
265
|
+
* @param accepts 允許的類型
|
|
246
266
|
*
|
|
247
267
|
* @example
|
|
248
268
|
*
|
|
@@ -250,21 +270,24 @@ function createEnumLikeObject(obj, name, scene) {
|
|
|
250
270
|
* validateFileType({ type: 'image/png' }, ['image/png', 'image/jpeg']) // true
|
|
251
271
|
* validateFileType({ type: 'image/png' }, ['image/jpeg']) // false
|
|
252
272
|
* validateFileType({ type: 'image/png' }, ['image/*']) // true
|
|
273
|
+
* validateFileType({ name: '圖片.png', type: 'image/png' }, ['.png']) // true
|
|
253
274
|
* ```
|
|
254
275
|
*/ const validateFileType = (file, accepts)=>{
|
|
255
276
|
if (accepts.length === 0) return true;
|
|
256
277
|
// 獲取文件的MIME類型
|
|
257
278
|
const fileMimeType = file.type;
|
|
279
|
+
// 提取副檔名(含 .,且轉小寫)
|
|
280
|
+
const fileExt = file.name.includes('.') ? `.${file.name.split('.').pop().toLowerCase()}` : '';
|
|
258
281
|
return accepts.some((accept)=>{
|
|
282
|
+
if (accept.startsWith('.')) {
|
|
283
|
+
// 以副檔名檢查,忽略大小寫
|
|
284
|
+
return fileExt === accept.toLowerCase();
|
|
285
|
+
}
|
|
259
286
|
if (accept === fileMimeType) {
|
|
260
287
|
return true;
|
|
261
288
|
}
|
|
262
289
|
if (accept.endsWith('/*')) {
|
|
263
|
-
|
|
264
|
-
const fileCategory = fileMimeType.split('/')[0];
|
|
265
|
-
if (acceptedCategory === fileCategory) {
|
|
266
|
-
return true;
|
|
267
|
-
}
|
|
290
|
+
return accept.split('/')[0] === fileMimeType.split('/')[0];
|
|
268
291
|
}
|
|
269
292
|
return false;
|
|
270
293
|
});
|
|
@@ -291,32 +314,70 @@ function createEnumLikeObject(obj, name, scene) {
|
|
|
291
314
|
* getMimeType('xlsx') // 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
292
315
|
* getMimeType('doc') // 'application/msword'
|
|
293
316
|
* getMimeType('docx') // 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
317
|
+
*
|
|
318
|
+
* @deprecated use `parseFileInfoFromFilename` instead
|
|
294
319
|
*/ const getMimeType = (fileName)=>{
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
320
|
+
const ext = (fileName.split('.').pop() || '').toLowerCase();
|
|
321
|
+
return MimeTypeMap[ext] ?? OtherMimeType;
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* 用來解析後端在 response header content-disposition 的內容
|
|
325
|
+
*
|
|
326
|
+
* 一般來說格式會有以下兩種
|
|
327
|
+
*
|
|
328
|
+
* - Content-Disposition: attachment; filename="file name.jpg"
|
|
329
|
+
* - Content-Disposition: attachment; filename*=UTF-8''file%20name2.jpg
|
|
330
|
+
*
|
|
331
|
+
* 如果格式正確就會取得檔案名稱(包含副檔名),優先取 filename* 內的內容
|
|
332
|
+
*
|
|
333
|
+
* @param disposition Content-Disposition
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
*
|
|
337
|
+
* parseFilenameFromDisposition('attachment; filename="file name1.jpg') // file name.jpg
|
|
338
|
+
* parseFilenameFromDisposition('attachment; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
339
|
+
* parseFilenameFromDisposition('attachment; filename="file name.jpg; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
340
|
+
*/ const parseFilenameFromDisposition = (disposition)=>{
|
|
341
|
+
// 1. 先找 filename*
|
|
342
|
+
const filenameStarMatch = disposition.match(/filename\*\s*=\s*(?:UTF-8'')?([^;]+)/i);
|
|
343
|
+
if (filenameStarMatch && filenameStarMatch[1]) {
|
|
344
|
+
// 依 RFC 5987 格式(UTF-8''URL-ENCODED),要先 decode
|
|
345
|
+
try {
|
|
346
|
+
return decodeURIComponent(filenameStarMatch[1].replace(/(^['"]|['"]$)/g, ''));
|
|
347
|
+
} catch {
|
|
348
|
+
// fallback,如果 decode 失敗,直接傳回原值
|
|
349
|
+
return filenameStarMatch[1];
|
|
350
|
+
}
|
|
319
351
|
}
|
|
352
|
+
// 2. 沒有 filename*,再找 filename
|
|
353
|
+
const filenameMatch = disposition.match(/filename\s*=\s*("?)([^";]+)\1/i);
|
|
354
|
+
if (filenameMatch && filenameMatch[2]) {
|
|
355
|
+
return filenameMatch[2];
|
|
356
|
+
}
|
|
357
|
+
// 3. 都沒有則 undefined
|
|
358
|
+
return undefined;
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
* 解析 `filename` 回傳檔名、副檔名、MIME type
|
|
362
|
+
*
|
|
363
|
+
* @param filename 檔案名稱
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
*
|
|
367
|
+
* parseFileInfoFromFilename('image.jpg') // ['image', 'jpg', 'image/jpeg']
|
|
368
|
+
* parseFileInfoFromFilename('image') // ['image', '', 'application/octet-stream']
|
|
369
|
+
*/ const parseFileInfoFromFilename = (filename)=>{
|
|
370
|
+
const lastDot = filename.lastIndexOf('.');
|
|
371
|
+
if (lastDot === -1) return [
|
|
372
|
+
filename,
|
|
373
|
+
'',
|
|
374
|
+
OtherMimeType
|
|
375
|
+
]; // 沒有副檔名
|
|
376
|
+
return [
|
|
377
|
+
filename.slice(0, lastDot),
|
|
378
|
+
filename.slice(lastDot + 1),
|
|
379
|
+
MimeTypeMap[filename.slice(lastDot + 1)] ?? OtherMimeType
|
|
380
|
+
];
|
|
320
381
|
};
|
|
321
382
|
|
|
322
383
|
// const isProduction: boolean = process.env.NODE_ENV === 'production';
|
|
@@ -1238,6 +1299,8 @@ exports.downloadFile = downloadClient.downloadFile;
|
|
|
1238
1299
|
exports.getLocalStorage = webStorageClient.getLocalStorage;
|
|
1239
1300
|
exports.setLocalStorage = webStorageClient.setLocalStorage;
|
|
1240
1301
|
exports.ByteSize = ByteSize;
|
|
1302
|
+
exports.MimeTypeMap = MimeTypeMap;
|
|
1303
|
+
exports.OtherMimeType = OtherMimeType;
|
|
1241
1304
|
exports.adToRocEra = adToRocEra;
|
|
1242
1305
|
exports.camelCase2PascalCase = camelCase2PascalCase;
|
|
1243
1306
|
exports.camelCase2SnakeCase = camelCase2SnakeCase;
|
|
@@ -1278,6 +1341,8 @@ exports.mergeRefs = mergeRefs;
|
|
|
1278
1341
|
exports.objectToSearchParams = objectToSearchParams;
|
|
1279
1342
|
exports.omit = omit;
|
|
1280
1343
|
exports.omitByValue = omitByValue;
|
|
1344
|
+
exports.parseFileInfoFromFilename = parseFileInfoFromFilename;
|
|
1345
|
+
exports.parseFilenameFromDisposition = parseFilenameFromDisposition;
|
|
1281
1346
|
exports.pascalCase2CamelCase = pascalCase2CamelCase;
|
|
1282
1347
|
exports.pascalCase2SnakeCase = pascalCase2SnakeCase;
|
|
1283
1348
|
exports.pascalString2CamelString = pascalString2CamelString;
|
package/dist/es/index.d.mts
CHANGED
|
@@ -474,11 +474,33 @@ declare const fakeApi: <T>(returnValue: T, result?: boolean, time?: number) => P
|
|
|
474
474
|
message: string;
|
|
475
475
|
}>;
|
|
476
476
|
|
|
477
|
+
declare const MimeTypeMap: {
|
|
478
|
+
readonly jpeg: "image/jpeg";
|
|
479
|
+
readonly jpg: "image/jpeg";
|
|
480
|
+
readonly gif: "image/gif";
|
|
481
|
+
readonly png: "image/png";
|
|
482
|
+
readonly pdf: "application/pdf";
|
|
483
|
+
readonly zip: "application/zip";
|
|
484
|
+
readonly csv: "text/csv";
|
|
485
|
+
readonly ppt: "application/vnd.ms-powerpoint";
|
|
486
|
+
readonly pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
|
487
|
+
readonly xls: "application/vnd.ms-excel";
|
|
488
|
+
readonly xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
489
|
+
readonly doc: "application/msword";
|
|
490
|
+
readonly docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
|
491
|
+
readonly txt: "text/plain";
|
|
492
|
+
};
|
|
493
|
+
declare const OtherMimeType = "application/octet-stream";
|
|
494
|
+
type MimeTypeExtension = keyof typeof MimeTypeMap;
|
|
495
|
+
type MimeTypeValue = (typeof MimeTypeMap)[MimeTypeExtension] | typeof OtherMimeType;
|
|
496
|
+
|
|
477
497
|
/**
|
|
478
|
-
*
|
|
498
|
+
* 檢查檔案是否為合法的檔案類型
|
|
499
|
+
*
|
|
500
|
+
* `accepts` 可同時接受副檔名以及 MIME 類型
|
|
479
501
|
*
|
|
480
502
|
* @param file 檔案
|
|
481
|
-
* @param accepts
|
|
503
|
+
* @param accepts 允許的類型
|
|
482
504
|
*
|
|
483
505
|
* @example
|
|
484
506
|
*
|
|
@@ -486,6 +508,7 @@ declare const fakeApi: <T>(returnValue: T, result?: boolean, time?: number) => P
|
|
|
486
508
|
* validateFileType({ type: 'image/png' }, ['image/png', 'image/jpeg']) // true
|
|
487
509
|
* validateFileType({ type: 'image/png' }, ['image/jpeg']) // false
|
|
488
510
|
* validateFileType({ type: 'image/png' }, ['image/*']) // true
|
|
511
|
+
* validateFileType({ name: '圖片.png', type: 'image/png' }, ['.png']) // true
|
|
489
512
|
* ```
|
|
490
513
|
*/
|
|
491
514
|
declare const validateFileType: (file: File, accepts: string[]) => boolean;
|
|
@@ -511,8 +534,40 @@ declare const validateFileType: (file: File, accepts: string[]) => boolean;
|
|
|
511
534
|
* getMimeType('xlsx') // 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
512
535
|
* getMimeType('doc') // 'application/msword'
|
|
513
536
|
* getMimeType('docx') // 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
537
|
+
*
|
|
538
|
+
* @deprecated use `parseFileInfoFromFilename` instead
|
|
539
|
+
*/
|
|
540
|
+
declare const getMimeType: (fileName: string) => "image/jpeg" | "image/gif" | "image/png" | "application/pdf" | "application/zip" | "text/csv" | "application/vnd.ms-powerpoint" | "application/vnd.openxmlformats-officedocument.presentationml.presentation" | "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" | "application/msword" | "application/vnd.openxmlformats-officedocument.wordprocessingml.document" | "text/plain";
|
|
541
|
+
/**
|
|
542
|
+
* 用來解析後端在 response header content-disposition 的內容
|
|
543
|
+
*
|
|
544
|
+
* 一般來說格式會有以下兩種
|
|
545
|
+
*
|
|
546
|
+
* - Content-Disposition: attachment; filename="file name.jpg"
|
|
547
|
+
* - Content-Disposition: attachment; filename*=UTF-8''file%20name2.jpg
|
|
548
|
+
*
|
|
549
|
+
* 如果格式正確就會取得檔案名稱(包含副檔名),優先取 filename* 內的內容
|
|
550
|
+
*
|
|
551
|
+
* @param disposition Content-Disposition
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
*
|
|
555
|
+
* parseFilenameFromDisposition('attachment; filename="file name1.jpg') // file name.jpg
|
|
556
|
+
* parseFilenameFromDisposition('attachment; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
557
|
+
* parseFilenameFromDisposition('attachment; filename="file name.jpg; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
558
|
+
*/
|
|
559
|
+
declare const parseFilenameFromDisposition: (disposition: string) => string | undefined;
|
|
560
|
+
/**
|
|
561
|
+
* 解析 `filename` 回傳檔名、副檔名、MIME type
|
|
562
|
+
*
|
|
563
|
+
* @param filename 檔案名稱
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
*
|
|
567
|
+
* parseFileInfoFromFilename('image.jpg') // ['image', 'jpg', 'image/jpeg']
|
|
568
|
+
* parseFileInfoFromFilename('image') // ['image', '', 'application/octet-stream']
|
|
514
569
|
*/
|
|
515
|
-
declare const
|
|
570
|
+
declare const parseFileInfoFromFilename: (filename: string) => [string, string, MimeTypeValue];
|
|
516
571
|
|
|
517
572
|
declare function invariant(condition: any, message?: string | (() => string)): asserts condition;
|
|
518
573
|
|
|
@@ -1149,4 +1204,4 @@ declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefin
|
|
|
1149
1204
|
*/
|
|
1150
1205
|
declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
|
|
1151
1206
|
|
|
1152
|
-
export { ByteSize, type PartialBy, QueryProvider, type RequiredBy, type TCountdownActions, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, deepMerge, downloadFile, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeRefs, objectToSearchParams, omit, omitByValue, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, searchParamsToObject, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
|
|
1207
|
+
export { ByteSize, type MimeTypeExtension, MimeTypeMap, type MimeTypeValue, OtherMimeType, type PartialBy, QueryProvider, type RequiredBy, type TCountdownActions, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, deepMerge, downloadFile, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getLocalStorage, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeRefs, objectToSearchParams, omit, omitByValue, parseFileInfoFromFilename, parseFilenameFromDisposition, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, searchParamsToObject, setLocalStorage, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useCountdown, useQueryContext, useValue, validTaxId, validateDateString, validateFileType, wait };
|
package/dist/es/index.mjs
CHANGED
|
@@ -231,11 +231,31 @@ function createEnumLikeObject(obj, name, scene) {
|
|
|
231
231
|
}, time);
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
+
const MimeTypeMap = {
|
|
235
|
+
jpeg: 'image/jpeg',
|
|
236
|
+
jpg: 'image/jpeg',
|
|
237
|
+
gif: 'image/gif',
|
|
238
|
+
png: 'image/png',
|
|
239
|
+
pdf: 'application/pdf',
|
|
240
|
+
zip: 'application/zip',
|
|
241
|
+
csv: 'text/csv',
|
|
242
|
+
ppt: 'application/vnd.ms-powerpoint',
|
|
243
|
+
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
244
|
+
xls: 'application/vnd.ms-excel',
|
|
245
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
246
|
+
doc: 'application/msword',
|
|
247
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
248
|
+
txt: 'text/plain'
|
|
249
|
+
};
|
|
250
|
+
const OtherMimeType = 'application/octet-stream';
|
|
251
|
+
|
|
234
252
|
/**
|
|
235
|
-
*
|
|
253
|
+
* 檢查檔案是否為合法的檔案類型
|
|
254
|
+
*
|
|
255
|
+
* `accepts` 可同時接受副檔名以及 MIME 類型
|
|
236
256
|
*
|
|
237
257
|
* @param file 檔案
|
|
238
|
-
* @param accepts
|
|
258
|
+
* @param accepts 允許的類型
|
|
239
259
|
*
|
|
240
260
|
* @example
|
|
241
261
|
*
|
|
@@ -243,21 +263,24 @@ function createEnumLikeObject(obj, name, scene) {
|
|
|
243
263
|
* validateFileType({ type: 'image/png' }, ['image/png', 'image/jpeg']) // true
|
|
244
264
|
* validateFileType({ type: 'image/png' }, ['image/jpeg']) // false
|
|
245
265
|
* validateFileType({ type: 'image/png' }, ['image/*']) // true
|
|
266
|
+
* validateFileType({ name: '圖片.png', type: 'image/png' }, ['.png']) // true
|
|
246
267
|
* ```
|
|
247
268
|
*/ const validateFileType = (file, accepts)=>{
|
|
248
269
|
if (accepts.length === 0) return true;
|
|
249
270
|
// 獲取文件的MIME類型
|
|
250
271
|
const fileMimeType = file.type;
|
|
272
|
+
// 提取副檔名(含 .,且轉小寫)
|
|
273
|
+
const fileExt = file.name.includes('.') ? `.${file.name.split('.').pop().toLowerCase()}` : '';
|
|
251
274
|
return accepts.some((accept)=>{
|
|
275
|
+
if (accept.startsWith('.')) {
|
|
276
|
+
// 以副檔名檢查,忽略大小寫
|
|
277
|
+
return fileExt === accept.toLowerCase();
|
|
278
|
+
}
|
|
252
279
|
if (accept === fileMimeType) {
|
|
253
280
|
return true;
|
|
254
281
|
}
|
|
255
282
|
if (accept.endsWith('/*')) {
|
|
256
|
-
|
|
257
|
-
const fileCategory = fileMimeType.split('/')[0];
|
|
258
|
-
if (acceptedCategory === fileCategory) {
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
283
|
+
return accept.split('/')[0] === fileMimeType.split('/')[0];
|
|
261
284
|
}
|
|
262
285
|
return false;
|
|
263
286
|
});
|
|
@@ -284,32 +307,70 @@ function createEnumLikeObject(obj, name, scene) {
|
|
|
284
307
|
* getMimeType('xlsx') // 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
285
308
|
* getMimeType('doc') // 'application/msword'
|
|
286
309
|
* getMimeType('docx') // 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
|
310
|
+
*
|
|
311
|
+
* @deprecated use `parseFileInfoFromFilename` instead
|
|
287
312
|
*/ const getMimeType = (fileName)=>{
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
313
|
+
const ext = (fileName.split('.').pop() || '').toLowerCase();
|
|
314
|
+
return MimeTypeMap[ext] ?? OtherMimeType;
|
|
315
|
+
};
|
|
316
|
+
/**
|
|
317
|
+
* 用來解析後端在 response header content-disposition 的內容
|
|
318
|
+
*
|
|
319
|
+
* 一般來說格式會有以下兩種
|
|
320
|
+
*
|
|
321
|
+
* - Content-Disposition: attachment; filename="file name.jpg"
|
|
322
|
+
* - Content-Disposition: attachment; filename*=UTF-8''file%20name2.jpg
|
|
323
|
+
*
|
|
324
|
+
* 如果格式正確就會取得檔案名稱(包含副檔名),優先取 filename* 內的內容
|
|
325
|
+
*
|
|
326
|
+
* @param disposition Content-Disposition
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
*
|
|
330
|
+
* parseFilenameFromDisposition('attachment; filename="file name1.jpg') // file name.jpg
|
|
331
|
+
* parseFilenameFromDisposition('attachment; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
332
|
+
* parseFilenameFromDisposition('attachment; filename="file name.jpg; filename*=UTF-8''file%20name2.jpg') // file name2.jpg
|
|
333
|
+
*/ const parseFilenameFromDisposition = (disposition)=>{
|
|
334
|
+
// 1. 先找 filename*
|
|
335
|
+
const filenameStarMatch = disposition.match(/filename\*\s*=\s*(?:UTF-8'')?([^;]+)/i);
|
|
336
|
+
if (filenameStarMatch && filenameStarMatch[1]) {
|
|
337
|
+
// 依 RFC 5987 格式(UTF-8''URL-ENCODED),要先 decode
|
|
338
|
+
try {
|
|
339
|
+
return decodeURIComponent(filenameStarMatch[1].replace(/(^['"]|['"]$)/g, ''));
|
|
340
|
+
} catch {
|
|
341
|
+
// fallback,如果 decode 失敗,直接傳回原值
|
|
342
|
+
return filenameStarMatch[1];
|
|
343
|
+
}
|
|
312
344
|
}
|
|
345
|
+
// 2. 沒有 filename*,再找 filename
|
|
346
|
+
const filenameMatch = disposition.match(/filename\s*=\s*("?)([^";]+)\1/i);
|
|
347
|
+
if (filenameMatch && filenameMatch[2]) {
|
|
348
|
+
return filenameMatch[2];
|
|
349
|
+
}
|
|
350
|
+
// 3. 都沒有則 undefined
|
|
351
|
+
return undefined;
|
|
352
|
+
};
|
|
353
|
+
/**
|
|
354
|
+
* 解析 `filename` 回傳檔名、副檔名、MIME type
|
|
355
|
+
*
|
|
356
|
+
* @param filename 檔案名稱
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
*
|
|
360
|
+
* parseFileInfoFromFilename('image.jpg') // ['image', 'jpg', 'image/jpeg']
|
|
361
|
+
* parseFileInfoFromFilename('image') // ['image', '', 'application/octet-stream']
|
|
362
|
+
*/ const parseFileInfoFromFilename = (filename)=>{
|
|
363
|
+
const lastDot = filename.lastIndexOf('.');
|
|
364
|
+
if (lastDot === -1) return [
|
|
365
|
+
filename,
|
|
366
|
+
'',
|
|
367
|
+
OtherMimeType
|
|
368
|
+
]; // 沒有副檔名
|
|
369
|
+
return [
|
|
370
|
+
filename.slice(0, lastDot),
|
|
371
|
+
filename.slice(lastDot + 1),
|
|
372
|
+
MimeTypeMap[filename.slice(lastDot + 1)] ?? OtherMimeType
|
|
373
|
+
];
|
|
313
374
|
};
|
|
314
375
|
|
|
315
376
|
// const isProduction: boolean = process.env.NODE_ENV === 'production';
|
|
@@ -1224,4 +1285,4 @@ function mergeRefs(refs) {
|
|
|
1224
1285
|
return dayjs(endMonth, 'YYYYMM').subtract(1911, 'year').format('YYYYMM').substring(1);
|
|
1225
1286
|
};
|
|
1226
1287
|
|
|
1227
|
-
export { ByteSize, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, deepMerge, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeRefs, objectToSearchParams, omit, omitByValue, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, searchParamsToObject, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useValue, validTaxId, validateDateString, validateFileType, wait };
|
|
1288
|
+
export { ByteSize, MimeTypeMap, OtherMimeType, adToRocEra, camelCase2PascalCase, camelCase2SnakeCase, camelString2PascalString, camelString2SnakeString, convertBytes, createDataContext, createEnumLikeObject, debounce, deepMerge, extractEnumLikeObject, fakeApi, formatAmount, formatBytes, formatStarMask, generatePeriodArray, getCurrentPeriod, getMimeType, invariant, isChinese, isDateString, isDateTimeString, isEmail, isEnglish, isEqual, isNonZeroStart, isNumber, isNumberAtLeastN, isNumberN, isNumberNM, isServer, isTWMobile, isTWPhone, isTimeString, isValidPassword, maskString, mergeRefs, objectToSearchParams, omit, omitByValue, parseFileInfoFromFilename, parseFilenameFromDisposition, pascalCase2CamelCase, pascalCase2SnakeCase, pascalString2CamelString, pascalString2SnakeString, pick, pickByValue, rocEraToAd, searchParamsToObject, snakeCase2CamelCase, snakeCase2PascalCase, snakeString2CamelString, snakeString2PascalString, throttle, useValue, validTaxId, validateDateString, validateFileType, wait };
|