@react-hive/honey-utils 2.4.0 → 3.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 CHANGED
@@ -53,22 +53,26 @@ import { toKebabCase, camelToDashCase, splitStringIntoWords, hashString } from '
53
53
  /**
54
54
  * Convert string to kebab-case
55
55
  */
56
- toKebabCase('helloWorld'); // 'hello-world'
56
+ toKebabCase('helloWorld');
57
+ // ➜ 'hello-world'
57
58
 
58
59
  /**
59
60
  * Convert camelCase to dash-case
60
61
  */
61
- camelToDashCase('helloWorld'); // 'hello-world'
62
+ camelToDashCase('helloWorld');
63
+ // ➜ 'hello-world'
62
64
 
63
65
  /**
64
66
  * Split string into words
65
67
  */
66
- splitStringIntoWords('hello world'); // ['hello', 'world']
68
+ splitStringIntoWords('hello world');
69
+ // ➜ ['hello', 'world']
67
70
 
68
71
  /**
69
72
  * Generate a hash from a string
70
73
  */
71
- const hash = hashString('background-color: red;'); // 'e4k1z0x'
74
+ const hash = hashString('background-color: red;');
75
+ // ➜ 'e4k1z0x'
72
76
  ```
73
77
 
74
78
  ### Array Utilities
@@ -223,7 +227,8 @@ noop();
223
227
  const fn = (x: number) => x * 2;
224
228
 
225
229
  invokeIfFunction(fn, 5); // 10
226
- invokeIfFunction('not a function', 5); // 'not a function'
230
+ invokeIfFunction('not a function', 5);
231
+ // ➜ 'not a function'
227
232
 
228
233
  /**
229
234
  * Waits for 1 second before continuing
@@ -284,94 +289,126 @@ import {
284
289
  /**
285
290
  * Check if value is a string
286
291
  */
287
- isString('hello'); // true
288
- isString(123); // false
292
+ isString('hello');
293
+ // ➜ true
294
+ isString(123);
295
+ // ➜ false
289
296
 
290
297
  /**
291
298
  * Check if value is a number
292
299
  */
293
- isNumber(123); // true
294
- isNumber('123'); // false
300
+ isNumber(123);
301
+ // ➜ true
302
+ isNumber('123');
303
+ // ➜ false
295
304
 
296
305
  /**
297
306
  * Check if value is a boolean
298
307
  */
299
- isBool(true); // true
300
- isBool('true'); // false
308
+ isBool(true);
309
+ // ➜ true
310
+ isBool('true');
311
+ // ➜ false
301
312
 
302
313
  /**
303
314
  * Check if value is an object
304
315
  */
305
- isObject({}); // true
306
- isObject('object'); // false
316
+ isObject({});
317
+ // ➜ true
318
+ isObject('object');
319
+ // ➜ false
307
320
 
308
321
  /**
309
322
  * Check if value is a function
310
323
  */
311
- isFunction(() => {}); // true
312
- isFunction({}); // false
324
+ isFunction(() => {});
325
+ // ➜ true
326
+ isFunction({});
327
+ // ➜ false
313
328
 
314
329
  /**
315
330
  * Check if value is a Promise
316
331
  */
317
- isPromise(Promise.resolve()); // true
318
- isPromise({}); // false
332
+ isPromise(Promise.resolve());
333
+ // ➜ true
334
+ isPromise({});
335
+ // ➜ false
319
336
 
320
337
  /**
321
338
  * Check if value is null or undefined
322
339
  */
323
- isNil(null); // true
324
- isNil(undefined); // true
325
- isNil(''); // false
340
+ isNil(null);
341
+ // true
342
+ isNil(undefined);
343
+ // ➜ true
344
+ isNil('');
345
+ // ➜ false
326
346
 
327
347
  /**
328
348
  * Check if value is null, undefined, or empty string
329
349
  */
330
- isNilOrEmptyString(''); // true
331
- isNilOrEmptyString(null); // true
332
- isNilOrEmptyString('hello'); // false
350
+ isNilOrEmptyString('');
351
+ // true
352
+ isNilOrEmptyString(null);
353
+ // ➜ true
354
+ isNilOrEmptyString('hello');
355
+ // ➜ false
333
356
 
334
357
  /**
335
358
  * Check if value is an array
336
359
  */
337
- isArray([1, 2, 3]); // true
338
- isArray({}); // false
360
+ isArray([1, 2, 3]);
361
+ // ➜ true
362
+ isArray({});
363
+ // ➜ false
339
364
 
340
365
  /**
341
366
  * Check if value is an empty array
342
367
  */
343
- isEmptyArray([]); // true
344
- isEmptyArray([1, 2, 3]); // false
368
+ isEmptyArray([]);
369
+ // true
370
+ isEmptyArray([1, 2, 3]);
371
+ // ➜ false
345
372
 
346
373
  /**
347
374
  * Check if value is an empty object
348
375
  */
349
- isEmptyObject({}); // true
350
- isEmptyObject({ key: 'value' }); // false
376
+ isEmptyObject({});
377
+ // true
378
+ isEmptyObject({ key: 'value' });
379
+ // ➜ false
351
380
 
352
381
  /**
353
382
  * Check if value is a Date object
354
383
  */
355
- isDate(new Date()); // true
356
- isDate('2023-01-01'); // false
384
+ isDate(new Date());
385
+ // ➜ true
386
+ isDate('2023-01-01');
387
+ // ➜ false
357
388
 
358
389
  /**
359
390
  * Check if value is a valid Date object
360
391
  */
361
- isValidDate(new Date()); // true
362
- isValidDate(new Date('invalid')); // false
392
+ isValidDate(new Date());
393
+ // true
394
+ isValidDate(new Date('invalid'));
395
+ // ➜ false
363
396
 
364
397
  /**
365
398
  * Check if value is a RegExp
366
399
  */
367
- isRegExp(/test/); // true
368
- isRegExp('test'); // false
400
+ isRegExp(/test/);
401
+ // ➜ true
402
+ isRegExp('test');
403
+ // ➜ false
369
404
 
370
405
  /**
371
406
  * Check if value is a Map or Set
372
407
  */
373
- isMap(new Map()); // true
374
- isSet(new Set()); // true
408
+ isMap(new Map());
409
+ // true
410
+ isSet(new Set());
411
+ // ➜ true
375
412
  ```
376
413
 
377
414
  ### Math Utilities
@@ -386,25 +423,30 @@ import {
386
423
  /**
387
424
  * Calculate Euclidean distance between two points
388
425
  */
389
- calculateEuclideanDistance(0, 0, 3, 4); // 5
426
+ calculateEuclideanDistance(0, 0, 3, 4);
427
+ // ➜ 5
390
428
 
391
429
  /**
392
430
  * Calculate moving speed
393
431
  */
394
- calculateMovingSpeed(100, 5); // 20
432
+ calculateMovingSpeed(100, 5);
433
+ // ➜ 20
395
434
 
396
435
  /**
397
436
  * Calculate percentage of a value
398
437
  */
399
- calculatePercentage(200, 25); // 50
438
+ calculatePercentage(200, 25);
439
+ // ➜ 50
400
440
  ```
401
441
 
402
442
  ### DOM Utilities
403
443
 
404
444
  ```ts
405
- import { parse2DMatrix, cloneBlob, convertBlobToFile } from '@react-hive/honey-utils';
445
+ import { parse2DMatrix, cloneBlob } from '@react-hive/honey-utils';
406
446
 
407
- // Extract transformation values from an HTML element's 2D matrix
447
+ /**
448
+ * Extract transformation values from an HTML element's 2D matrix
449
+ */
408
450
  const element = document.getElementById('my-element');
409
451
  if (element) {
410
452
  const { translateX, translateY, scaleX, scaleY, skewX, skewY } = parse2DMatrix(element);
@@ -414,19 +456,68 @@ if (element) {
414
456
  console.log(`Element is skewed by ${skewX} horizontally and ${skewY} vertically`);
415
457
  }
416
458
 
417
- // Clone a Blob object
459
+ /**
460
+ * Clone a Blob object
461
+ */
418
462
  const originalBlob = new Blob(['Hello World'], { type: 'text/plain' });
419
463
  const clonedBlob = cloneBlob(originalBlob);
420
464
 
421
- console.log(clonedBlob.type); // 'text/plain'
465
+ console.log(clonedBlob.type);
466
+ // ➜ 'text/plain'
467
+ ```
468
+
469
+ ### File Utilities
422
470
 
423
- // Convert a Blob to a File
471
+ ```ts
472
+ import { parseFileName, fileListToFile, blobToFile } from '@react-hive/honey-utils';
473
+
474
+ /**
475
+ * Parse a file name into base name + extension
476
+ */
477
+ const [base, ext] = parseFileName('archive.tar.gz');
478
+
479
+ console.log(base);
480
+ // ➜ 'archive.tar'
481
+ console.log(ext);
482
+ // ➜ 'gz'
483
+
484
+ /**
485
+ * Hidden file (no name)
486
+ */
487
+ parseFileName('.gitignore');
488
+ // ➜ ['.gitignore', '']
489
+
490
+ /**
491
+ * No file extension
492
+ */
493
+ parseFileName('README');
494
+ // ➜ ['README', '']
495
+
496
+ /**
497
+ * Convert a FileList to an array
498
+ */
499
+ const input = document.querySelector('input[type="file"]')!;
500
+ input.addEventListener('change', () => {
501
+ const files = fileListToFiles(input.files);
502
+
503
+ console.log(Array.isArray(files));
504
+ // ➜ true
505
+ console.log(files[0] instanceof File);
506
+ // ➜ true
507
+ });
508
+
509
+ /**
510
+ * Convert a Blob to a File
511
+ */
424
512
  const blob = new Blob(['Hello world'], { type: 'text/plain' });
425
- const file = convertBlobToFile(blob, 'hello.txt');
513
+ const file = blobToFile(blob, 'hello.txt');
426
514
 
427
- console.log(file instanceof File); // true
428
- console.log(file.name); // 'hello.txt'
429
- console.log(file.type); // 'text/plain'
515
+ console.log(file instanceof File);
516
+ // ➜ true
517
+ console.log(file.name);
518
+ // ➜ 'hello.txt'
519
+ console.log(file.type);
520
+ // ➜ 'text/plain'
430
521
  ```
431
522
 
432
523
  ### Assert Function
@@ -505,7 +596,6 @@ function divide(a: number, b: number): number {
505
596
 
506
597
  - `parse2DMatrix(element: HTMLElement): { translateX: number, translateY: number, scaleX: number, scaleY: number, skewX: number, skewY: number }` - Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element.
507
598
  - `cloneBlob(blob: Blob): Blob` - Creates a clone of a Blob object with the same content and type as the original.
508
- - `convertBlobToFile(blob: Blob, fileName: string): File` - Converts a Blob object into a File object with the specified name.
509
599
  - `getDOMRectIntersectionRatio(sourceRect: DOMRect, targetRect: DOMRect): number` - Calculates the ratio of the `targetRect` that is overlapped by the `sourceRect`. Returns a number between `0` (no overlap) and `1` (fully covered).
510
600
  - `getElementOffsetRect(element: HTMLElement): DOMRect` - Returns a `DOMRect` representing the element's layout position using `offsetLeft`, `offsetTop`, and `clientWidth`/`clientHeight`.
511
601
  - `isAnchorHtmlElement(element: HTMLElement): element is HTMLAnchorElement` - Determines whether the provided element is an `<a>` tag. Acts as a type guard that narrows the element to `HTMLAnchorElement`.
@@ -513,6 +603,12 @@ function divide(a: number, b: number): number {
513
603
  - `isHtmlElementFocusable(element: Nullable<HTMLElement>): boolean` - Checks whether an element is considered focusable according to browser rules. Factors include: visibility, `display`, `disabled`, `tabindex`, native focusable tags, `contenteditable`, and presence of a non-null `tabindex`.
514
604
  - `getFocusableHtmlElements(container: HTMLElement): HTMLElement[]` - Returns all focusable descendant elements within a container, using `isHtmlElementFocusable` to filter them.
515
605
 
606
+ ### File Utilities
607
+
608
+ - `parseFileName(fileName: string): [baseName: string, extension: string]` - Splits a file name into its base name and extension using the last `.` as the separator. Handles edge cases such as hidden files (`.gitignore`), multi-dot names (`archive.tar.gz`), and names ending with a dot (`"file."`). The extension is returned in lowercase.
609
+ - `fileListToFiles(fileList: FileList | null): File[]` - Converts a `FileList` object (such as the one returned from an `<input type="file">`) into a standard array of `File` objects. Returns an empty array when the input is `null`.
610
+ - `blobToFile(blob: Blob, fileName: string): File` - Converts a Blob object into a File object with the specified name.
611
+
516
612
  ### Asynchronous Utilities
517
613
 
518
614
  - `runSequential<Item, Result>(array: Item[], fn: (item, index, array) => Promise<Result>): Promise<Result[]>` - Runs asynchronous operations on each array item *sequentially* and returns the results in the original order.
package/dist/README.md CHANGED
@@ -53,22 +53,26 @@ import { toKebabCase, camelToDashCase, splitStringIntoWords, hashString } from '
53
53
  /**
54
54
  * Convert string to kebab-case
55
55
  */
56
- toKebabCase('helloWorld'); // 'hello-world'
56
+ toKebabCase('helloWorld');
57
+ // ➜ 'hello-world'
57
58
 
58
59
  /**
59
60
  * Convert camelCase to dash-case
60
61
  */
61
- camelToDashCase('helloWorld'); // 'hello-world'
62
+ camelToDashCase('helloWorld');
63
+ // ➜ 'hello-world'
62
64
 
63
65
  /**
64
66
  * Split string into words
65
67
  */
66
- splitStringIntoWords('hello world'); // ['hello', 'world']
68
+ splitStringIntoWords('hello world');
69
+ // ➜ ['hello', 'world']
67
70
 
68
71
  /**
69
72
  * Generate a hash from a string
70
73
  */
71
- const hash = hashString('background-color: red;'); // 'e4k1z0x'
74
+ const hash = hashString('background-color: red;');
75
+ // ➜ 'e4k1z0x'
72
76
  ```
73
77
 
74
78
  ### Array Utilities
@@ -223,7 +227,8 @@ noop();
223
227
  const fn = (x: number) => x * 2;
224
228
 
225
229
  invokeIfFunction(fn, 5); // 10
226
- invokeIfFunction('not a function', 5); // 'not a function'
230
+ invokeIfFunction('not a function', 5);
231
+ // ➜ 'not a function'
227
232
 
228
233
  /**
229
234
  * Waits for 1 second before continuing
@@ -284,94 +289,126 @@ import {
284
289
  /**
285
290
  * Check if value is a string
286
291
  */
287
- isString('hello'); // true
288
- isString(123); // false
292
+ isString('hello');
293
+ // ➜ true
294
+ isString(123);
295
+ // ➜ false
289
296
 
290
297
  /**
291
298
  * Check if value is a number
292
299
  */
293
- isNumber(123); // true
294
- isNumber('123'); // false
300
+ isNumber(123);
301
+ // ➜ true
302
+ isNumber('123');
303
+ // ➜ false
295
304
 
296
305
  /**
297
306
  * Check if value is a boolean
298
307
  */
299
- isBool(true); // true
300
- isBool('true'); // false
308
+ isBool(true);
309
+ // ➜ true
310
+ isBool('true');
311
+ // ➜ false
301
312
 
302
313
  /**
303
314
  * Check if value is an object
304
315
  */
305
- isObject({}); // true
306
- isObject('object'); // false
316
+ isObject({});
317
+ // ➜ true
318
+ isObject('object');
319
+ // ➜ false
307
320
 
308
321
  /**
309
322
  * Check if value is a function
310
323
  */
311
- isFunction(() => {}); // true
312
- isFunction({}); // false
324
+ isFunction(() => {});
325
+ // ➜ true
326
+ isFunction({});
327
+ // ➜ false
313
328
 
314
329
  /**
315
330
  * Check if value is a Promise
316
331
  */
317
- isPromise(Promise.resolve()); // true
318
- isPromise({}); // false
332
+ isPromise(Promise.resolve());
333
+ // ➜ true
334
+ isPromise({});
335
+ // ➜ false
319
336
 
320
337
  /**
321
338
  * Check if value is null or undefined
322
339
  */
323
- isNil(null); // true
324
- isNil(undefined); // true
325
- isNil(''); // false
340
+ isNil(null);
341
+ // true
342
+ isNil(undefined);
343
+ // ➜ true
344
+ isNil('');
345
+ // ➜ false
326
346
 
327
347
  /**
328
348
  * Check if value is null, undefined, or empty string
329
349
  */
330
- isNilOrEmptyString(''); // true
331
- isNilOrEmptyString(null); // true
332
- isNilOrEmptyString('hello'); // false
350
+ isNilOrEmptyString('');
351
+ // true
352
+ isNilOrEmptyString(null);
353
+ // ➜ true
354
+ isNilOrEmptyString('hello');
355
+ // ➜ false
333
356
 
334
357
  /**
335
358
  * Check if value is an array
336
359
  */
337
- isArray([1, 2, 3]); // true
338
- isArray({}); // false
360
+ isArray([1, 2, 3]);
361
+ // ➜ true
362
+ isArray({});
363
+ // ➜ false
339
364
 
340
365
  /**
341
366
  * Check if value is an empty array
342
367
  */
343
- isEmptyArray([]); // true
344
- isEmptyArray([1, 2, 3]); // false
368
+ isEmptyArray([]);
369
+ // true
370
+ isEmptyArray([1, 2, 3]);
371
+ // ➜ false
345
372
 
346
373
  /**
347
374
  * Check if value is an empty object
348
375
  */
349
- isEmptyObject({}); // true
350
- isEmptyObject({ key: 'value' }); // false
376
+ isEmptyObject({});
377
+ // true
378
+ isEmptyObject({ key: 'value' });
379
+ // ➜ false
351
380
 
352
381
  /**
353
382
  * Check if value is a Date object
354
383
  */
355
- isDate(new Date()); // true
356
- isDate('2023-01-01'); // false
384
+ isDate(new Date());
385
+ // ➜ true
386
+ isDate('2023-01-01');
387
+ // ➜ false
357
388
 
358
389
  /**
359
390
  * Check if value is a valid Date object
360
391
  */
361
- isValidDate(new Date()); // true
362
- isValidDate(new Date('invalid')); // false
392
+ isValidDate(new Date());
393
+ // true
394
+ isValidDate(new Date('invalid'));
395
+ // ➜ false
363
396
 
364
397
  /**
365
398
  * Check if value is a RegExp
366
399
  */
367
- isRegExp(/test/); // true
368
- isRegExp('test'); // false
400
+ isRegExp(/test/);
401
+ // ➜ true
402
+ isRegExp('test');
403
+ // ➜ false
369
404
 
370
405
  /**
371
406
  * Check if value is a Map or Set
372
407
  */
373
- isMap(new Map()); // true
374
- isSet(new Set()); // true
408
+ isMap(new Map());
409
+ // true
410
+ isSet(new Set());
411
+ // ➜ true
375
412
  ```
376
413
 
377
414
  ### Math Utilities
@@ -386,25 +423,30 @@ import {
386
423
  /**
387
424
  * Calculate Euclidean distance between two points
388
425
  */
389
- calculateEuclideanDistance(0, 0, 3, 4); // 5
426
+ calculateEuclideanDistance(0, 0, 3, 4);
427
+ // ➜ 5
390
428
 
391
429
  /**
392
430
  * Calculate moving speed
393
431
  */
394
- calculateMovingSpeed(100, 5); // 20
432
+ calculateMovingSpeed(100, 5);
433
+ // ➜ 20
395
434
 
396
435
  /**
397
436
  * Calculate percentage of a value
398
437
  */
399
- calculatePercentage(200, 25); // 50
438
+ calculatePercentage(200, 25);
439
+ // ➜ 50
400
440
  ```
401
441
 
402
442
  ### DOM Utilities
403
443
 
404
444
  ```ts
405
- import { parse2DMatrix, cloneBlob, convertBlobToFile } from '@react-hive/honey-utils';
445
+ import { parse2DMatrix, cloneBlob } from '@react-hive/honey-utils';
406
446
 
407
- // Extract transformation values from an HTML element's 2D matrix
447
+ /**
448
+ * Extract transformation values from an HTML element's 2D matrix
449
+ */
408
450
  const element = document.getElementById('my-element');
409
451
  if (element) {
410
452
  const { translateX, translateY, scaleX, scaleY, skewX, skewY } = parse2DMatrix(element);
@@ -414,19 +456,68 @@ if (element) {
414
456
  console.log(`Element is skewed by ${skewX} horizontally and ${skewY} vertically`);
415
457
  }
416
458
 
417
- // Clone a Blob object
459
+ /**
460
+ * Clone a Blob object
461
+ */
418
462
  const originalBlob = new Blob(['Hello World'], { type: 'text/plain' });
419
463
  const clonedBlob = cloneBlob(originalBlob);
420
464
 
421
- console.log(clonedBlob.type); // 'text/plain'
465
+ console.log(clonedBlob.type);
466
+ // ➜ 'text/plain'
467
+ ```
468
+
469
+ ### File Utilities
422
470
 
423
- // Convert a Blob to a File
471
+ ```ts
472
+ import { parseFileName, fileListToFile, blobToFile } from '@react-hive/honey-utils';
473
+
474
+ /**
475
+ * Parse a file name into base name + extension
476
+ */
477
+ const [base, ext] = parseFileName('archive.tar.gz');
478
+
479
+ console.log(base);
480
+ // ➜ 'archive.tar'
481
+ console.log(ext);
482
+ // ➜ 'gz'
483
+
484
+ /**
485
+ * Hidden file (no name)
486
+ */
487
+ parseFileName('.gitignore');
488
+ // ➜ ['.gitignore', '']
489
+
490
+ /**
491
+ * No file extension
492
+ */
493
+ parseFileName('README');
494
+ // ➜ ['README', '']
495
+
496
+ /**
497
+ * Convert a FileList to an array
498
+ */
499
+ const input = document.querySelector('input[type="file"]')!;
500
+ input.addEventListener('change', () => {
501
+ const files = fileListToFiles(input.files);
502
+
503
+ console.log(Array.isArray(files));
504
+ // ➜ true
505
+ console.log(files[0] instanceof File);
506
+ // ➜ true
507
+ });
508
+
509
+ /**
510
+ * Convert a Blob to a File
511
+ */
424
512
  const blob = new Blob(['Hello world'], { type: 'text/plain' });
425
- const file = convertBlobToFile(blob, 'hello.txt');
513
+ const file = blobToFile(blob, 'hello.txt');
426
514
 
427
- console.log(file instanceof File); // true
428
- console.log(file.name); // 'hello.txt'
429
- console.log(file.type); // 'text/plain'
515
+ console.log(file instanceof File);
516
+ // ➜ true
517
+ console.log(file.name);
518
+ // ➜ 'hello.txt'
519
+ console.log(file.type);
520
+ // ➜ 'text/plain'
430
521
  ```
431
522
 
432
523
  ### Assert Function
@@ -505,7 +596,6 @@ function divide(a: number, b: number): number {
505
596
 
506
597
  - `parse2DMatrix(element: HTMLElement): { translateX: number, translateY: number, scaleX: number, scaleY: number, skewX: number, skewY: number }` - Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element.
507
598
  - `cloneBlob(blob: Blob): Blob` - Creates a clone of a Blob object with the same content and type as the original.
508
- - `convertBlobToFile(blob: Blob, fileName: string): File` - Converts a Blob object into a File object with the specified name.
509
599
  - `getDOMRectIntersectionRatio(sourceRect: DOMRect, targetRect: DOMRect): number` - Calculates the ratio of the `targetRect` that is overlapped by the `sourceRect`. Returns a number between `0` (no overlap) and `1` (fully covered).
510
600
  - `getElementOffsetRect(element: HTMLElement): DOMRect` - Returns a `DOMRect` representing the element's layout position using `offsetLeft`, `offsetTop`, and `clientWidth`/`clientHeight`.
511
601
  - `isAnchorHtmlElement(element: HTMLElement): element is HTMLAnchorElement` - Determines whether the provided element is an `<a>` tag. Acts as a type guard that narrows the element to `HTMLAnchorElement`.
@@ -513,6 +603,12 @@ function divide(a: number, b: number): number {
513
603
  - `isHtmlElementFocusable(element: Nullable<HTMLElement>): boolean` - Checks whether an element is considered focusable according to browser rules. Factors include: visibility, `display`, `disabled`, `tabindex`, native focusable tags, `contenteditable`, and presence of a non-null `tabindex`.
514
604
  - `getFocusableHtmlElements(container: HTMLElement): HTMLElement[]` - Returns all focusable descendant elements within a container, using `isHtmlElementFocusable` to filter them.
515
605
 
606
+ ### File Utilities
607
+
608
+ - `parseFileName(fileName: string): [baseName: string, extension: string]` - Splits a file name into its base name and extension using the last `.` as the separator. Handles edge cases such as hidden files (`.gitignore`), multi-dot names (`archive.tar.gz`), and names ending with a dot (`"file."`). The extension is returned in lowercase.
609
+ - `fileListToFiles(fileList: FileList | null): File[]` - Converts a `FileList` object (such as the one returned from an `<input type="file">`) into a standard array of `File` objects. Returns an empty array when the input is `null`.
610
+ - `blobToFile(blob: Blob, fileName: string): File` - Converts a Blob object into a File object with the specified name.
611
+
516
612
  ### Asynchronous Utilities
517
613
 
518
614
  - `runSequential<Item, Result>(array: Item[], fn: (item, index, array) => Promise<Result>): Promise<Result[]>` - Runs asynchronous operations on each array item *sequentially* and returns the results in the original order.
package/dist/dom.d.ts CHANGED
@@ -31,26 +31,6 @@ export declare const parse2DMatrix: (element: HTMLElement) => HTMLElementTransfo
31
31
  * @returns A new Blob with the same content and type as the original.
32
32
  */
33
33
  export declare const cloneBlob: (blob: Blob) => Blob;
34
- /**
35
- * Converts a `Blob` object into a `File` object with the specified name.
36
- *
37
- * This is useful when you receive a `Blob` (e.g., from canvas, fetch, or file manipulation)
38
- * and need to convert it into a `File` to upload via `FormData` or file inputs.
39
- *
40
- * @param blob - The `Blob` to convert.
41
- * @param fileName - The desired name for the resulting file (including extension).
42
- *
43
- * @returns A `File` instance with the same content and MIME type as the input `Blob`.
44
- *
45
- * @example
46
- * ```ts
47
- * const blob = new Blob(['Hello world'], { type: 'text/plain' });
48
- * const file = convertBlobToFile(blob, 'hello.txt');
49
- *
50
- * console.log(file instanceof File); // true
51
- * ```
52
- */
53
- export declare const convertBlobToFile: (blob: Blob, fileName: string) => File;
54
34
  /**
55
35
  * Calculates the intersection ratio between two DOM rectangles.
56
36
  *