@react-hive/honey-utils 4.2.0 → 5.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 +56 -12
- package/dist/README.md +56 -12
- package/dist/a11y/focus/is-html-element-focusable.d.ts +8 -6
- package/dist/a11y/focus/move-focus-within-container.d.ts +1 -1
- package/dist/array/chunk.d.ts +4 -1
- package/dist/array/compose.d.ts +7 -3
- package/dist/array/get-adjacent-items.d.ts +1 -1
- package/dist/array/index.d.ts +1 -0
- package/dist/array/intersection.d.ts +2 -1
- package/dist/array/is-array.d.ts +6 -0
- package/dist/array/is-empty-array.d.ts +7 -0
- package/dist/array/pipe.d.ts +5 -2
- package/dist/array/to-map-by.d.ts +48 -0
- package/dist/async/async.d.ts +10 -1
- package/dist/async/retry.d.ts +4 -3
- package/dist/dom/data-transfer.d.ts +22 -4
- package/dist/dom/dom.d.ts +7 -5
- package/dist/dom/transform/parse-2d-matrix.d.ts +5 -0
- package/dist/encoding/decode-base64-json.d.ts +22 -1
- package/dist/encoding/decode-base64.d.ts +23 -1
- package/dist/encoding/encode-base64-json.d.ts +16 -0
- package/dist/encoding/encode-base64.d.ts +20 -0
- package/dist/env/storage/index.d.ts +1 -0
- package/dist/env/storage/local-storage-json.d.ts +29 -0
- package/dist/env/storage/local-storage.d.ts +1 -6
- package/dist/file.d.ts +3 -2
- package/dist/function/function.d.ts +12 -0
- package/dist/geometry/apply-inertia-step.d.ts +1 -1
- package/dist/geometry/layout/calculate-center-offset.d.ts +11 -1
- package/dist/geometry/layout/clamp-offset-to-overflow.d.ts +6 -0
- package/dist/geometry/resolve-bounded-delta.d.ts +1 -1
- package/dist/guards.d.ts +24 -3
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.dev.cjs +474 -100
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/intersection/get-dom-rect-intersection-ratio.d.ts +8 -1
- package/dist/intersection/resolve-axis-delta.d.ts +7 -0
- package/dist/json/parse-json.d.ts +22 -1
- package/dist/math/hash-string.d.ts +1 -1
- package/dist/math/math.d.ts +17 -1
- package/dist/object.d.ts +7 -1
- package/dist/string/for-each-char.d.ts +1 -1
- package/dist/string/is-nil-or-empty-string.d.ts +1 -1
- package/dist/string/parse-file-name.d.ts +1 -1
- package/dist/tree/flatten-tree.d.ts +2 -2
- package/dist/tree/get-tree-children.d.ts +2 -2
- package/dist/tree/search-tree.d.ts +2 -2
- package/dist/tree/tree.types.d.ts +1 -1
- package/package.json +8 -7
- package/dist/geometry/apply-inertia-step.spec.d.ts +0 -1
- package/dist/geometry/resolve-bounded-delta.spec.d.ts +0 -1
- package/dist/id/generate-ephemeral-id.spec.d.ts +0 -1
package/dist/index.dev.cjs
CHANGED
|
@@ -12,7 +12,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
12
12
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
13
13
|
/* harmony export */ getFocusableHtmlElements: () => (/* binding */ getFocusableHtmlElements)
|
|
14
14
|
/* harmony export */ });
|
|
15
|
-
/* harmony import */ var
|
|
15
|
+
/* harmony import */ var _is_html_element_focusable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./is-html-element-focusable */ "./src/a11y/focus/is-html-element-focusable.ts");
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Collects all focusable descendant elements within a container.
|
|
@@ -25,7 +25,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
25
25
|
*
|
|
26
26
|
* @returns An array of focusable HTMLElements in DOM order.
|
|
27
27
|
*/
|
|
28
|
-
const getFocusableHtmlElements = (container) => Array.from(container.querySelectorAll('*')).filter(
|
|
28
|
+
const getFocusableHtmlElements = (container) => Array.from(container.querySelectorAll('*')).filter(_is_html_element_focusable__WEBPACK_IMPORTED_MODULE_0__.isHtmlElementFocusable);
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
/***/ },
|
|
@@ -67,16 +67,26 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
67
67
|
/* harmony import */ var _dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~/dom */ "./src/dom/index.ts");
|
|
68
68
|
|
|
69
69
|
const FOCUSABLE_HTML_TAGS = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'A'];
|
|
70
|
+
/**
|
|
71
|
+
* A `tabindex` attribute's value, read by the HTML rules for parsing integers - leading whitespace
|
|
72
|
+
* and a sign allowed, anything after the digits ignored - or `null` where there is none to read.
|
|
73
|
+
*/
|
|
74
|
+
const parseTabIndex = (value) => {
|
|
75
|
+
const match = value === null ? null : /^\s*([+-]?\d+)/.exec(value);
|
|
76
|
+
return match ? parseInt(match[1], 10) : null;
|
|
77
|
+
};
|
|
70
78
|
/**
|
|
71
79
|
* Determines whether an HTMLElement is focusable under standard browser rules.
|
|
72
80
|
*
|
|
73
81
|
* The function checks a combination of factors:
|
|
74
|
-
* - The element must be rendered
|
|
75
|
-
*
|
|
76
|
-
* -
|
|
82
|
+
* - The element must be rendered: neither it nor an ancestor has `display: none`, and it is not
|
|
83
|
+
* `visibility: hidden`.
|
|
84
|
+
* - Disabled form controls are never focusable - including those inside a disabled `<fieldset>`.
|
|
85
|
+
* - Elements with a negative `tabindex` are intentionally removed from the focus order.
|
|
86
|
+
* - Any element with a valid, non-negative `tabindex` is focusable. A `tabindex` that is not an
|
|
87
|
+
* integer is ignored, as browsers ignore it.
|
|
77
88
|
* - Certain native HTML elements are inherently focusable (e.g. inputs, buttons, anchors with `href`).
|
|
78
|
-
* -
|
|
79
|
-
* - Any element with a valid `tabindex` (not null) is considered focusable.
|
|
89
|
+
* - Editable elements (`contenteditable`) are treated as focusable.
|
|
80
90
|
*
|
|
81
91
|
* This logic approximates how browsers and the accessibility tree
|
|
82
92
|
* determine real-world focusability—not just tabindex presence.
|
|
@@ -89,28 +99,30 @@ const isHtmlElementFocusable = (element) => {
|
|
|
89
99
|
if (!element) {
|
|
90
100
|
return false;
|
|
91
101
|
}
|
|
92
|
-
|
|
93
|
-
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
102
|
+
if (window.getComputedStyle(element).visibility === 'hidden') {
|
|
94
103
|
return false;
|
|
95
104
|
}
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
// `display: none` does not inherit, so a hidden ancestor has to be looked for
|
|
106
|
+
for (let node = element; node; node = node.parentElement) {
|
|
107
|
+
if (window.getComputedStyle(node).display === 'none') {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
98
110
|
}
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
if (tabIndex === '-1') {
|
|
111
|
+
// `:disabled` covers a control inside a disabled `<fieldset>`, which `element.disabled` does not
|
|
112
|
+
if (element.matches(':disabled')) {
|
|
102
113
|
return false;
|
|
103
114
|
}
|
|
115
|
+
const tabIndex = parseTabIndex(element.getAttribute('tabindex'));
|
|
116
|
+
if (tabIndex !== null) {
|
|
117
|
+
return tabIndex >= 0;
|
|
118
|
+
}
|
|
104
119
|
if (FOCUSABLE_HTML_TAGS.includes(element.tagName)) {
|
|
105
120
|
if ((0,_dom__WEBPACK_IMPORTED_MODULE_0__.isAnchorHtmlElement)(element)) {
|
|
106
121
|
return element.href !== '';
|
|
107
122
|
}
|
|
108
123
|
return true;
|
|
109
124
|
}
|
|
110
|
-
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
return tabIndex !== null;
|
|
125
|
+
return (0,_dom__WEBPACK_IMPORTED_MODULE_0__.isContentEditableHtmlElement)(element);
|
|
114
126
|
};
|
|
115
127
|
|
|
116
128
|
|
|
@@ -126,7 +138,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
126
138
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
127
139
|
/* harmony export */ moveFocusWithinContainer: () => (/* binding */ moveFocusWithinContainer)
|
|
128
140
|
/* harmony export */ });
|
|
129
|
-
/* harmony import */ var
|
|
141
|
+
/* harmony import */ var _get_focusable_html_elements__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./get-focusable-html-elements */ "./src/a11y/focus/get-focusable-html-elements.ts");
|
|
130
142
|
|
|
131
143
|
/**
|
|
132
144
|
* Moves focus to the next or previous focusable element within a container.
|
|
@@ -158,7 +170,7 @@ const moveFocusWithinContainer = (direction, container = null, { wrap = true, ge
|
|
|
158
170
|
if (!activeElement || !scope) {
|
|
159
171
|
return;
|
|
160
172
|
}
|
|
161
|
-
const focusableElements = (0,
|
|
173
|
+
const focusableElements = (0,_get_focusable_html_elements__WEBPACK_IMPORTED_MODULE_0__.getFocusableHtmlElements)(scope);
|
|
162
174
|
if (focusableElements.length === 0) {
|
|
163
175
|
return;
|
|
164
176
|
}
|
|
@@ -232,11 +244,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
232
244
|
* @template T - The type of the items in the array.
|
|
233
245
|
*
|
|
234
246
|
* @param array - The input array to be chunked.
|
|
235
|
-
* @param size - The size of each chunk. Must be
|
|
247
|
+
* @param size - The size of each chunk. Must be a positive whole number.
|
|
236
248
|
*
|
|
237
249
|
* @returns An array of chunks, where each chunk is an array of the specified size
|
|
238
250
|
* (except possibly the last chunk, which may be smaller).
|
|
239
251
|
*
|
|
252
|
+
* @throws {Error} When `size` is not a positive whole number - a fractional size would give
|
|
253
|
+
* chunks of other sizes, and `Infinity` none at all.
|
|
254
|
+
*
|
|
240
255
|
* @example
|
|
241
256
|
* ```ts
|
|
242
257
|
* chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
|
|
@@ -244,7 +259,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
244
259
|
* ```
|
|
245
260
|
*/
|
|
246
261
|
const chunk = (array, size) => {
|
|
247
|
-
(0,_guards__WEBPACK_IMPORTED_MODULE_0__.assert)(size > 0, 'Chunk size must be
|
|
262
|
+
(0,_guards__WEBPACK_IMPORTED_MODULE_0__.assert)(Number.isInteger(size) && size > 0, 'Chunk size must be a positive whole number');
|
|
248
263
|
return Array.from({ length: Math.ceil(array.length / size) }, (_, index) => array.slice(index * size, (index + 1) * size));
|
|
249
264
|
};
|
|
250
265
|
|
|
@@ -298,7 +313,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
298
313
|
* Composes multiple unary functions into a single function, applying them from **right to left**.
|
|
299
314
|
*
|
|
300
315
|
* Often used for building functional pipelines where the innermost function runs first.
|
|
301
|
-
* Types are inferred up to 5 chained functions for full type safety.
|
|
316
|
+
* Types are inferred up to 5 chained functions for full type safety. Beyond that, it falls back to the unknown.
|
|
302
317
|
*
|
|
303
318
|
* @param fns - A list of unary functions to compose.
|
|
304
319
|
*
|
|
@@ -412,6 +427,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
412
427
|
/* harmony export */ isArray: () => (/* reexport safe */ _is_array__WEBPACK_IMPORTED_MODULE_7__.isArray),
|
|
413
428
|
/* harmony export */ isEmptyArray: () => (/* reexport safe */ _is_empty_array__WEBPACK_IMPORTED_MODULE_8__.isEmptyArray),
|
|
414
429
|
/* harmony export */ pipe: () => (/* reexport safe */ _pipe__WEBPACK_IMPORTED_MODULE_0__.pipe),
|
|
430
|
+
/* harmony export */ toMapBy: () => (/* reexport safe */ _to_map_by__WEBPACK_IMPORTED_MODULE_11__.toMapBy),
|
|
415
431
|
/* harmony export */ toggleArrayItem: () => (/* reexport safe */ _toggle_array_item__WEBPACK_IMPORTED_MODULE_10__.toggleArrayItem),
|
|
416
432
|
/* harmony export */ unique: () => (/* reexport safe */ _unique__WEBPACK_IMPORTED_MODULE_5__.unique)
|
|
417
433
|
/* harmony export */ });
|
|
@@ -426,6 +442,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
426
442
|
/* harmony import */ var _is_empty_array__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./is-empty-array */ "./src/array/is-empty-array.ts");
|
|
427
443
|
/* harmony import */ var _get_adjacent_items__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./get-adjacent-items */ "./src/array/get-adjacent-items.ts");
|
|
428
444
|
/* harmony import */ var _toggle_array_item__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./toggle-array-item */ "./src/array/toggle-array-item.ts");
|
|
445
|
+
/* harmony import */ var _to_map_by__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./to-map-by */ "./src/array/to-map-by.ts");
|
|
446
|
+
|
|
429
447
|
|
|
430
448
|
|
|
431
449
|
|
|
@@ -451,7 +469,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
451
469
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
452
470
|
/* harmony export */ intersection: () => (/* binding */ intersection)
|
|
453
471
|
/* harmony export */ });
|
|
454
|
-
/* harmony import */ var
|
|
472
|
+
/* harmony import */ var _unique__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./unique */ "./src/array/unique.ts");
|
|
455
473
|
|
|
456
474
|
/**
|
|
457
475
|
* Returns an array containing elements that exist in all provided arrays.
|
|
@@ -460,7 +478,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
460
478
|
*
|
|
461
479
|
* @param arrays - Two or more arrays to find common elements from.
|
|
462
480
|
*
|
|
463
|
-
* @returns A new array containing only the elements that exist in all input arrays
|
|
481
|
+
* @returns A new array containing only the elements that exist in all input arrays, each once, in
|
|
482
|
+
* the order of the first array.
|
|
464
483
|
*
|
|
465
484
|
* @example
|
|
466
485
|
* ```ts
|
|
@@ -472,11 +491,8 @@ const intersection = (...arrays) => {
|
|
|
472
491
|
if (arrays.length === 0) {
|
|
473
492
|
return [];
|
|
474
493
|
}
|
|
475
|
-
if (arrays.length === 1) {
|
|
476
|
-
return [...arrays[0]];
|
|
477
|
-
}
|
|
478
494
|
const [first, ...rest] = arrays;
|
|
479
|
-
const uniqueFirst = (0,
|
|
495
|
+
const uniqueFirst = (0,_unique__WEBPACK_IMPORTED_MODULE_0__.unique)(first);
|
|
480
496
|
return uniqueFirst.filter(item => rest.every(array => array.includes(item)));
|
|
481
497
|
};
|
|
482
498
|
|
|
@@ -499,6 +515,12 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
499
515
|
* @param value - The value to check.
|
|
500
516
|
*
|
|
501
517
|
* @returns `true` if the value is an array; otherwise, `false`.
|
|
518
|
+
*
|
|
519
|
+
* @example
|
|
520
|
+
* ```ts
|
|
521
|
+
* isArray([1, 2]); // true
|
|
522
|
+
* isArray('12'); // false
|
|
523
|
+
* ```
|
|
502
524
|
*/
|
|
503
525
|
const isArray = (value) => Array.isArray(value);
|
|
504
526
|
|
|
@@ -515,7 +537,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
515
537
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
516
538
|
/* harmony export */ isEmptyArray: () => (/* binding */ isEmptyArray)
|
|
517
539
|
/* harmony export */ });
|
|
518
|
-
/* harmony import */ var
|
|
540
|
+
/* harmony import */ var _is_array__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./is-array */ "./src/array/is-array.ts");
|
|
519
541
|
|
|
520
542
|
/**
|
|
521
543
|
* Checks if a value is an empty array.
|
|
@@ -523,8 +545,15 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
523
545
|
* @param value - The value to check.
|
|
524
546
|
*
|
|
525
547
|
* @returns `true` if the value is an empty array; otherwise, `false`.
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```ts
|
|
551
|
+
* isEmptyArray([]); // true
|
|
552
|
+
* isEmptyArray([1]); // false
|
|
553
|
+
* isEmptyArray({}); // false
|
|
554
|
+
* ```
|
|
526
555
|
*/
|
|
527
|
-
const isEmptyArray = (value) => (0,
|
|
556
|
+
const isEmptyArray = (value) => (0,_is_array__WEBPACK_IMPORTED_MODULE_0__.isArray)(value) && value.length === 0;
|
|
528
557
|
|
|
529
558
|
|
|
530
559
|
/***/ },
|
|
@@ -563,6 +592,31 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
563
592
|
const pipe = (...fns) => (arg) => fns.reduce((prev, fn) => fn(prev), arg);
|
|
564
593
|
|
|
565
594
|
|
|
595
|
+
/***/ },
|
|
596
|
+
|
|
597
|
+
/***/ "./src/array/to-map-by.ts"
|
|
598
|
+
/*!********************************!*\
|
|
599
|
+
!*** ./src/array/to-map-by.ts ***!
|
|
600
|
+
\********************************/
|
|
601
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
602
|
+
|
|
603
|
+
__webpack_require__.r(__webpack_exports__);
|
|
604
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
605
|
+
/* harmony export */ toMapBy: () => (/* binding */ toMapBy)
|
|
606
|
+
/* harmony export */ });
|
|
607
|
+
/**
|
|
608
|
+
* Overloaded rather than given a default `Value`, which TypeScript would take from whatever type the
|
|
609
|
+
* result is assigned to - so a map of items could be declared a map of anything.
|
|
610
|
+
*/
|
|
611
|
+
function toMapBy(items, getKey, getValue) {
|
|
612
|
+
const map = new Map();
|
|
613
|
+
items.forEach((item, index) => {
|
|
614
|
+
map.set(getKey(item, index), getValue ? getValue(item, index) : item);
|
|
615
|
+
});
|
|
616
|
+
return map;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
|
|
566
620
|
/***/ },
|
|
567
621
|
|
|
568
622
|
/***/ "./src/array/toggle-array-item.ts"
|
|
@@ -663,9 +717,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
663
717
|
/* harmony export */ runSequential: () => (/* binding */ runSequential),
|
|
664
718
|
/* harmony export */ someAsync: () => (/* binding */ someAsync)
|
|
665
719
|
/* harmony export */ });
|
|
666
|
-
/* harmony import */ var
|
|
667
|
-
/* harmony import */ var _function__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ~/function */ "./src/function/index.ts");
|
|
668
|
-
|
|
720
|
+
/* harmony import */ var _function__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~/function */ "./src/function/index.ts");
|
|
669
721
|
|
|
670
722
|
/**
|
|
671
723
|
* Checks if a value is a Promise.
|
|
@@ -676,7 +728,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
676
728
|
*
|
|
677
729
|
* @returns `true` if the value is a Promise; otherwise, `false`.
|
|
678
730
|
*/
|
|
679
|
-
const isPromise = (value) => (0,
|
|
731
|
+
const isPromise = (value) => (0,_function__WEBPACK_IMPORTED_MODULE_0__.isFunction)(value?.then);
|
|
680
732
|
/**
|
|
681
733
|
* Asynchronously iterates over an array and executes an async function on each item sequentially,
|
|
682
734
|
* collecting the results.
|
|
@@ -789,12 +841,15 @@ const filterSequential = async (array, predicate) => {
|
|
|
789
841
|
* ```
|
|
790
842
|
*/
|
|
791
843
|
const filterParallel = async (array, predicate) => {
|
|
792
|
-
const
|
|
793
|
-
return (
|
|
844
|
+
const keep = await runParallel(array, predicate);
|
|
845
|
+
return array.filter((_, index) => keep[index]);
|
|
794
846
|
};
|
|
795
847
|
/**
|
|
796
848
|
* Asynchronously checks if at least one element in the array satisfies the async condition.
|
|
797
849
|
*
|
|
850
|
+
* Runs one item at a time, in order, and stops at the first item that satisfies it - as
|
|
851
|
+
* `Array.prototype.some` does.
|
|
852
|
+
*
|
|
798
853
|
* @param array - The array of items to check.
|
|
799
854
|
* @param predicate - An async function that returns a boolean.
|
|
800
855
|
*
|
|
@@ -811,6 +866,9 @@ const someAsync = async (array, predicate) => {
|
|
|
811
866
|
/**
|
|
812
867
|
* Asynchronously checks if all elements in the array satisfy the async condition.
|
|
813
868
|
*
|
|
869
|
+
* Runs one item at a time, in order, and stops at the first item that fails it - as
|
|
870
|
+
* `Array.prototype.every` does.
|
|
871
|
+
*
|
|
814
872
|
* @param array - The array of items to check.
|
|
815
873
|
* @param predicate - An async function that returns a boolean.
|
|
816
874
|
*
|
|
@@ -846,6 +904,9 @@ const reduceAsync = async (array, fn, initialValue) => {
|
|
|
846
904
|
/**
|
|
847
905
|
* Asynchronously finds the first element that satisfies the async condition.
|
|
848
906
|
*
|
|
907
|
+
* Runs one item at a time, in order, and stops at the first match - as `Array.prototype.find`
|
|
908
|
+
* does.
|
|
909
|
+
*
|
|
849
910
|
* @param array - The array of items to search.
|
|
850
911
|
* @param predicate - An async function that returns a boolean.
|
|
851
912
|
*
|
|
@@ -946,7 +1007,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
946
1007
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
947
1008
|
/* harmony export */ retry: () => (/* binding */ retry)
|
|
948
1009
|
/* harmony export */ });
|
|
949
|
-
/* harmony import */ var
|
|
1010
|
+
/* harmony import */ var _delay__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./delay */ "./src/async/delay.ts");
|
|
950
1011
|
|
|
951
1012
|
/**
|
|
952
1013
|
* Wraps an asynchronous function with retry logic.
|
|
@@ -956,7 +1017,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
956
1017
|
*
|
|
957
1018
|
* Useful for operations that may fail intermittently, such as network requests.
|
|
958
1019
|
*
|
|
959
|
-
* @template
|
|
1020
|
+
* @template Args - The arguments the async function takes.
|
|
960
1021
|
* @template TaskResult - The result type of the async function.
|
|
961
1022
|
*
|
|
962
1023
|
* @param task - The async function to wrap with retry logic.
|
|
@@ -990,18 +1051,19 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
990
1051
|
* ```
|
|
991
1052
|
*/
|
|
992
1053
|
const retry = (task, { maxAttempts = 3, delayMs = 300, backoff = true, onRetry } = {}) => {
|
|
1054
|
+
const attempts = Math.max(1, maxAttempts);
|
|
993
1055
|
return async (...args) => {
|
|
994
1056
|
let lastError;
|
|
995
|
-
for (let attempt = 1; attempt <=
|
|
1057
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
996
1058
|
try {
|
|
997
1059
|
return await task(...args);
|
|
998
1060
|
}
|
|
999
1061
|
catch (e) {
|
|
1000
1062
|
lastError = e;
|
|
1001
|
-
if (attempt <
|
|
1063
|
+
if (attempt < attempts) {
|
|
1002
1064
|
onRetry?.(attempt, e);
|
|
1003
1065
|
const delayTime = backoff ? delayMs * 2 ** (attempt - 1) : delayMs;
|
|
1004
|
-
await (0,
|
|
1066
|
+
await (0,_delay__WEBPACK_IMPORTED_MODULE_0__.delay)(delayTime);
|
|
1005
1067
|
}
|
|
1006
1068
|
}
|
|
1007
1069
|
}
|
|
@@ -1022,8 +1084,6 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1022
1084
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1023
1085
|
/* harmony export */ timeout: () => (/* binding */ timeout)
|
|
1024
1086
|
/* harmony export */ });
|
|
1025
|
-
/* harmony import */ var _async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~/async */ "./src/async/index.ts");
|
|
1026
|
-
|
|
1027
1087
|
/**
|
|
1028
1088
|
* Wraps a promise with a timeout. If the promise does not settle within the specified time,
|
|
1029
1089
|
* it will reject with a timeout error.
|
|
@@ -1047,15 +1107,18 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1047
1107
|
* ```
|
|
1048
1108
|
*/
|
|
1049
1109
|
const timeout = async (promise, timeoutMs, errorMessage = 'Operation timed out') => {
|
|
1050
|
-
|
|
1110
|
+
let timeoutId = null;
|
|
1051
1111
|
try {
|
|
1052
1112
|
return await Promise.race([
|
|
1053
1113
|
promise,
|
|
1054
|
-
(
|
|
1114
|
+
new Promise((_, reject) => {
|
|
1115
|
+
timeoutId = setTimeout(() => reject(new Error(errorMessage)), timeoutMs);
|
|
1116
|
+
}),
|
|
1055
1117
|
]);
|
|
1056
1118
|
}
|
|
1057
1119
|
finally {
|
|
1058
|
-
|
|
1120
|
+
// Cleared however the race ends, so a settled promise leaves no timer behind
|
|
1121
|
+
if (timeoutId !== null) {
|
|
1059
1122
|
clearTimeout(timeoutId);
|
|
1060
1123
|
}
|
|
1061
1124
|
}
|
|
@@ -1157,8 +1220,17 @@ const DATA_TRANSFER_JSON_MIME = 'application/json';
|
|
|
1157
1220
|
*
|
|
1158
1221
|
* Useful for drag-and-drop communication between elements.
|
|
1159
1222
|
*
|
|
1160
|
-
* @
|
|
1161
|
-
*
|
|
1223
|
+
* @template T - The type of the data.
|
|
1224
|
+
*
|
|
1225
|
+
* @param dataTransfer - DataTransfer instance from a drag event.
|
|
1226
|
+
* @param data - Data to serialize.
|
|
1227
|
+
*
|
|
1228
|
+
* @example
|
|
1229
|
+
* ```ts
|
|
1230
|
+
* element.addEventListener('dragstart', event => {
|
|
1231
|
+
* setDataTransferJson(event.dataTransfer, { id: 'card-1' });
|
|
1232
|
+
* });
|
|
1233
|
+
* ```
|
|
1162
1234
|
*/
|
|
1163
1235
|
const setDataTransferJson = (dataTransfer, data) => {
|
|
1164
1236
|
dataTransfer.setData(DATA_TRANSFER_JSON_MIME, JSON.stringify(data));
|
|
@@ -1166,9 +1238,18 @@ const setDataTransferJson = (dataTransfer, data) => {
|
|
|
1166
1238
|
/**
|
|
1167
1239
|
* Retrieves and parses JSON data from a DataTransfer object.
|
|
1168
1240
|
*
|
|
1169
|
-
* @
|
|
1241
|
+
* @template Value - The type the JSON is expected to have.
|
|
1242
|
+
*
|
|
1243
|
+
* @param dataTransfer - DataTransfer instance from a drop event.
|
|
1170
1244
|
*
|
|
1171
1245
|
* @returns Parsed JSON value or null if not present or invalid.
|
|
1246
|
+
*
|
|
1247
|
+
* @example
|
|
1248
|
+
* ```ts
|
|
1249
|
+
* element.addEventListener('drop', event => {
|
|
1250
|
+
* const card = getDataTransferJson<{ id: string }>(event.dataTransfer);
|
|
1251
|
+
* });
|
|
1252
|
+
* ```
|
|
1172
1253
|
*/
|
|
1173
1254
|
const getDataTransferJson = (dataTransfer) => {
|
|
1174
1255
|
const rawData = dataTransfer.getData(DATA_TRANSFER_JSON_MIME);
|
|
@@ -1205,8 +1286,9 @@ const cloneBlob = (blob) => new Blob([blob], { type: blob.type });
|
|
|
1205
1286
|
/**
|
|
1206
1287
|
* Returns the bounding DOMRect of an element based on offset and client dimensions.
|
|
1207
1288
|
*
|
|
1208
|
-
*
|
|
1209
|
-
*
|
|
1289
|
+
* Unlike `getBoundingClientRect()`, the rect is the element's layout box, before any CSS
|
|
1290
|
+
* transform - so it stays put while the element or its container is being translated or scaled.
|
|
1291
|
+
* Reading it still needs layout, as `getBoundingClientRect()` does.
|
|
1210
1292
|
*
|
|
1211
1293
|
* @param element - The target HTML element.
|
|
1212
1294
|
* @returns A `DOMRect` representing the element’s offset position and size.
|
|
@@ -1228,14 +1310,18 @@ const isAnchorHtmlElement = (element) => element.tagName === 'A';
|
|
|
1228
1310
|
/**
|
|
1229
1311
|
* Checks whether an element is explicitly marked as contenteditable.
|
|
1230
1312
|
*
|
|
1231
|
-
* Browsers treat elements
|
|
1232
|
-
*
|
|
1313
|
+
* Browsers treat editable elements as focusable, even if they are not normally
|
|
1314
|
+
* keyboard-focusable. An element is editable with `contenteditable` set to `""` (the bare
|
|
1315
|
+
* attribute), `"true"` or `"plaintext-only"`, in any case.
|
|
1233
1316
|
*
|
|
1234
1317
|
* @param element - The element to inspect.
|
|
1235
1318
|
*
|
|
1236
|
-
* @returns True if `contenteditable
|
|
1319
|
+
* @returns True if the element's own `contenteditable` makes it editable.
|
|
1237
1320
|
*/
|
|
1238
|
-
const isContentEditableHtmlElement = (element) =>
|
|
1321
|
+
const isContentEditableHtmlElement = (element) => {
|
|
1322
|
+
const value = element.getAttribute('contenteditable');
|
|
1323
|
+
return value !== null && ['', 'true', 'plaintext-only'].includes(value.toLowerCase());
|
|
1324
|
+
};
|
|
1239
1325
|
|
|
1240
1326
|
|
|
1241
1327
|
/***/ },
|
|
@@ -1274,8 +1360,8 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1274
1360
|
* @param options - Optional configuration controlling filename and link target.
|
|
1275
1361
|
*/
|
|
1276
1362
|
const downloadFile = (file, { fileName, target } = {}) => {
|
|
1277
|
-
// Browser guard (SSR / non-DOM environments)
|
|
1278
|
-
if (
|
|
1363
|
+
// Browser guard (SSR / non-DOM environments) - `typeof`, as reading an undeclared `document` throws
|
|
1364
|
+
if (typeof document === 'undefined') {
|
|
1279
1365
|
return;
|
|
1280
1366
|
}
|
|
1281
1367
|
const link = document.createElement('a');
|
|
@@ -1415,7 +1501,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1415
1501
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1416
1502
|
/* harmony export */ centerElementInContainer: () => (/* binding */ centerElementInContainer)
|
|
1417
1503
|
/* harmony export */ });
|
|
1418
|
-
/* harmony import */ var
|
|
1504
|
+
/* harmony import */ var _overflow__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./overflow */ "./src/dom/layout/overflow.ts");
|
|
1419
1505
|
/* harmony import */ var _geometry__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ~/geometry */ "./src/geometry/index.ts");
|
|
1420
1506
|
|
|
1421
1507
|
|
|
@@ -1447,7 +1533,7 @@ const centerElementInContainer = (containerElement, elementToCenter, { axis = 'b
|
|
|
1447
1533
|
elementSize: elementToCenter.clientWidth,
|
|
1448
1534
|
});
|
|
1449
1535
|
translateX = shouldClamp
|
|
1450
|
-
? (0,_geometry__WEBPACK_IMPORTED_MODULE_1__.clampOffsetToOverflow)(offsetX, (0,
|
|
1536
|
+
? (0,_geometry__WEBPACK_IMPORTED_MODULE_1__.clampOffsetToOverflow)(offsetX, (0,_overflow__WEBPACK_IMPORTED_MODULE_0__.getXOverflowWidth)(containerElement))
|
|
1451
1537
|
: offsetX;
|
|
1452
1538
|
}
|
|
1453
1539
|
if (axis === 'y' || axis === 'both') {
|
|
@@ -1457,7 +1543,7 @@ const centerElementInContainer = (containerElement, elementToCenter, { axis = 'b
|
|
|
1457
1543
|
elementSize: elementToCenter.clientHeight,
|
|
1458
1544
|
});
|
|
1459
1545
|
translateY = shouldClamp
|
|
1460
|
-
? (0,_geometry__WEBPACK_IMPORTED_MODULE_1__.clampOffsetToOverflow)(offsetY, (0,
|
|
1546
|
+
? (0,_geometry__WEBPACK_IMPORTED_MODULE_1__.clampOffsetToOverflow)(offsetY, (0,_overflow__WEBPACK_IMPORTED_MODULE_0__.getYOverflowHeight)(containerElement))
|
|
1461
1547
|
: offsetY;
|
|
1462
1548
|
}
|
|
1463
1549
|
containerElement.style.transform = `translate(${translateX}px, ${translateY}px)`;
|
|
@@ -1574,6 +1660,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1574
1660
|
*
|
|
1575
1661
|
* Only works with 2D transforms (i.e., `matrix(a, b, c, d, e, f)`).
|
|
1576
1662
|
*
|
|
1663
|
+
* The values are the matrix's own entries rather than decomposed angles and factors: `scaleX` is
|
|
1664
|
+
* `a`, `skewY` is `b`, `skewX` is `c`, `scaleY` is `d`, and the translation is `e` and `f`. They read
|
|
1665
|
+
* as scale and skew only for a transform with no rotation - `rotate(90deg)` gives `scaleX` and
|
|
1666
|
+
* `scaleY` of 0 - and a skew is its tangent (`skewX(30deg)` gives `skewX` ≈ 0.577), not its angle.
|
|
1667
|
+
*
|
|
1577
1668
|
* @param element - The element with a CSS transform applied.
|
|
1578
1669
|
* @returns An object with parsed transformation values.
|
|
1579
1670
|
*
|
|
@@ -1628,6 +1719,27 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1628
1719
|
/* harmony import */ var _decode_base64__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./decode-base64 */ "./src/encoding/decode-base64.ts");
|
|
1629
1720
|
|
|
1630
1721
|
|
|
1722
|
+
/**
|
|
1723
|
+
* Decodes a base64 string and parses the JSON it holds - the reverse of `encodeBase64Json`.
|
|
1724
|
+
*
|
|
1725
|
+
* Never throws: a value that is not valid base64, or does not decode to valid JSON, gives `null`.
|
|
1726
|
+
* The result is only cast to `Value`, not checked against it.
|
|
1727
|
+
*
|
|
1728
|
+
* @template Value - The type the JSON is expected to have.
|
|
1729
|
+
*
|
|
1730
|
+
* @param value - The base64 string to decode.
|
|
1731
|
+
*
|
|
1732
|
+
* @returns The parsed value, or `null` when the value cannot be decoded or parsed.
|
|
1733
|
+
*
|
|
1734
|
+
* @example
|
|
1735
|
+
* ```ts
|
|
1736
|
+
* decodeBase64Json<{ name: string; age: number }>('eyJuYW1lIjoiTWlrZSIsImFnZSI6MzN9');
|
|
1737
|
+
* // ➜ { name: 'Mike', age: 33 }
|
|
1738
|
+
*
|
|
1739
|
+
* decodeBase64Json('SGVsbG8=');
|
|
1740
|
+
* // ➜ null - "Hello" is not JSON
|
|
1741
|
+
* ```
|
|
1742
|
+
*/
|
|
1631
1743
|
const decodeBase64Json = (value) => {
|
|
1632
1744
|
const decodedValue = (0,_decode_base64__WEBPACK_IMPORTED_MODULE_1__.decodeBase64)(value);
|
|
1633
1745
|
if (decodedValue === null) {
|
|
@@ -1664,12 +1776,37 @@ const decodeBase64Bytes = (value) => {
|
|
|
1664
1776
|
}
|
|
1665
1777
|
return bytes;
|
|
1666
1778
|
};
|
|
1779
|
+
/**
|
|
1780
|
+
* Decodes a base64 string to the UTF-8 text it encodes - the reverse of `encodeBase64`.
|
|
1781
|
+
*
|
|
1782
|
+
* Never throws: a value that is not padded base64 of the standard alphabet, or whose bytes are not
|
|
1783
|
+
* valid UTF-8, decodes to `null`.
|
|
1784
|
+
*
|
|
1785
|
+
* Uses `Uint8Array.fromBase64` where the runtime has it, Node's `Buffer` otherwise, and `atob`
|
|
1786
|
+
* last.
|
|
1787
|
+
*
|
|
1788
|
+
* @param value - The base64 string to decode.
|
|
1789
|
+
*
|
|
1790
|
+
* @returns The decoded text, or `null` when the value is not valid base64 of UTF-8 text.
|
|
1791
|
+
*
|
|
1792
|
+
* @example
|
|
1793
|
+
* ```ts
|
|
1794
|
+
* decodeBase64('SGVsbG8=');
|
|
1795
|
+
* // ➜ 'Hello'
|
|
1796
|
+
*
|
|
1797
|
+
* decodeBase64('not base64!');
|
|
1798
|
+
* // ➜ null
|
|
1799
|
+
* ```
|
|
1800
|
+
*/
|
|
1667
1801
|
const decodeBase64 = (value) => {
|
|
1668
1802
|
if (!BASE64_PATTERN.test(value)) {
|
|
1669
1803
|
return null;
|
|
1670
1804
|
}
|
|
1671
1805
|
try {
|
|
1672
|
-
return new TextDecoder('utf-8', {
|
|
1806
|
+
return new TextDecoder('utf-8', {
|
|
1807
|
+
fatal: true,
|
|
1808
|
+
ignoreBOM: true,
|
|
1809
|
+
}).decode(decodeBase64Bytes(value));
|
|
1673
1810
|
}
|
|
1674
1811
|
catch {
|
|
1675
1812
|
return null;
|
|
@@ -1691,6 +1828,22 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1691
1828
|
/* harmony export */ });
|
|
1692
1829
|
/* harmony import */ var _encode_base64__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./encode-base64 */ "./src/encoding/encode-base64.ts");
|
|
1693
1830
|
|
|
1831
|
+
/**
|
|
1832
|
+
* Serialises a value as JSON and encodes it as base64 - a structured value carried in a URL query
|
|
1833
|
+
* parameter, a cookie or a header.
|
|
1834
|
+
*
|
|
1835
|
+
* @template Value - The type of the value.
|
|
1836
|
+
*
|
|
1837
|
+
* @param value - Any JSON-serialisable value.
|
|
1838
|
+
*
|
|
1839
|
+
* @returns The base64 encoding of the value's JSON.
|
|
1840
|
+
*
|
|
1841
|
+
* @example
|
|
1842
|
+
* ```ts
|
|
1843
|
+
* encodeBase64Json({ name: 'Mike', age: 33 });
|
|
1844
|
+
* // ➜ 'eyJuYW1lIjoiTWlrZSIsImFnZSI6MzN9'
|
|
1845
|
+
* ```
|
|
1846
|
+
*/
|
|
1694
1847
|
const encodeBase64Json = (value) => (0,_encode_base64__WEBPACK_IMPORTED_MODULE_0__.encodeBase64)(JSON.stringify(value));
|
|
1695
1848
|
|
|
1696
1849
|
|
|
@@ -1719,6 +1872,26 @@ const encodeBase64Bytes = (bytes) => {
|
|
|
1719
1872
|
}
|
|
1720
1873
|
return btoa(binary);
|
|
1721
1874
|
};
|
|
1875
|
+
/**
|
|
1876
|
+
* Encodes a string as base64, by its UTF-8 bytes - so text outside Latin-1 (accents, emoji, any
|
|
1877
|
+
* script), which `btoa` throws on, encodes as well.
|
|
1878
|
+
*
|
|
1879
|
+
* Uses `Uint8Array.prototype.toBase64` where the runtime has it, Node's `Buffer` otherwise, and
|
|
1880
|
+
* `btoa` last.
|
|
1881
|
+
*
|
|
1882
|
+
* @param value - The string to encode.
|
|
1883
|
+
*
|
|
1884
|
+
* @returns The base64 encoding of the string's UTF-8 bytes.
|
|
1885
|
+
*
|
|
1886
|
+
* @example
|
|
1887
|
+
* ```ts
|
|
1888
|
+
* encodeBase64('Hello');
|
|
1889
|
+
* // ➜ 'SGVsbG8='
|
|
1890
|
+
*
|
|
1891
|
+
* encodeBase64('Привіт');
|
|
1892
|
+
* // ➜ '0J/RgNC40LLRltGC'
|
|
1893
|
+
* ```
|
|
1894
|
+
*/
|
|
1722
1895
|
const encodeBase64 = (value) => encodeBase64Bytes(new TextEncoder().encode(value));
|
|
1723
1896
|
|
|
1724
1897
|
|
|
@@ -1758,7 +1931,9 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1758
1931
|
__webpack_require__.r(__webpack_exports__);
|
|
1759
1932
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1760
1933
|
/* harmony export */ getLocalStorageCapabilities: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.getLocalStorageCapabilities),
|
|
1761
|
-
/* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.isLocalStorageReadable)
|
|
1934
|
+
/* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.isLocalStorageReadable),
|
|
1935
|
+
/* harmony export */ readLocalStorageJson: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.readLocalStorageJson),
|
|
1936
|
+
/* harmony export */ writeLocalStorageJson: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.writeLocalStorageJson)
|
|
1762
1937
|
/* harmony export */ });
|
|
1763
1938
|
/* harmony import */ var _storage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./storage */ "./src/env/storage/index.ts");
|
|
1764
1939
|
|
|
@@ -1775,10 +1950,75 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1775
1950
|
__webpack_require__.r(__webpack_exports__);
|
|
1776
1951
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1777
1952
|
/* harmony export */ getLocalStorageCapabilities: () => (/* reexport safe */ _local_storage__WEBPACK_IMPORTED_MODULE_0__.getLocalStorageCapabilities),
|
|
1778
|
-
/* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _local_storage__WEBPACK_IMPORTED_MODULE_0__.isLocalStorageReadable)
|
|
1953
|
+
/* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _local_storage__WEBPACK_IMPORTED_MODULE_0__.isLocalStorageReadable),
|
|
1954
|
+
/* harmony export */ readLocalStorageJson: () => (/* reexport safe */ _local_storage_json__WEBPACK_IMPORTED_MODULE_1__.readLocalStorageJson),
|
|
1955
|
+
/* harmony export */ writeLocalStorageJson: () => (/* reexport safe */ _local_storage_json__WEBPACK_IMPORTED_MODULE_1__.writeLocalStorageJson)
|
|
1779
1956
|
/* harmony export */ });
|
|
1780
1957
|
/* harmony import */ var _local_storage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./local-storage */ "./src/env/storage/local-storage.ts");
|
|
1958
|
+
/* harmony import */ var _local_storage_json__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./local-storage-json */ "./src/env/storage/local-storage-json.ts");
|
|
1959
|
+
|
|
1960
|
+
|
|
1961
|
+
|
|
1962
|
+
|
|
1963
|
+
/***/ },
|
|
1964
|
+
|
|
1965
|
+
/***/ "./src/env/storage/local-storage-json.ts"
|
|
1966
|
+
/*!***********************************************!*\
|
|
1967
|
+
!*** ./src/env/storage/local-storage-json.ts ***!
|
|
1968
|
+
\***********************************************/
|
|
1969
|
+
(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
1970
|
+
|
|
1971
|
+
__webpack_require__.r(__webpack_exports__);
|
|
1972
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
1973
|
+
/* harmony export */ readLocalStorageJson: () => (/* binding */ readLocalStorageJson),
|
|
1974
|
+
/* harmony export */ writeLocalStorageJson: () => (/* binding */ writeLocalStorageJson)
|
|
1975
|
+
/* harmony export */ });
|
|
1976
|
+
/* harmony import */ var _json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ~/json */ "./src/json/index.ts");
|
|
1781
1977
|
|
|
1978
|
+
/**
|
|
1979
|
+
* Reads the value stored as JSON under a key in `localStorage`.
|
|
1980
|
+
*
|
|
1981
|
+
* Never throws: storage that cannot be read at all (SSR, disabled storage, sandboxed iframes, strict
|
|
1982
|
+
* privacy modes) reads as nothing stored, as does a value that is not JSON.
|
|
1983
|
+
*
|
|
1984
|
+
* The value is only cast to `Value`, not checked against it - something stored by an older version
|
|
1985
|
+
* of the app, or by hand, can be of any shape, so check it before relying on it.
|
|
1986
|
+
*
|
|
1987
|
+
* @param key - The `localStorage` key to read.
|
|
1988
|
+
*
|
|
1989
|
+
* @returns The parsed value, or `null` when nothing is stored under the key, what is stored is not
|
|
1990
|
+
* valid JSON, or storage cannot be read.
|
|
1991
|
+
*/
|
|
1992
|
+
const readLocalStorageJson = (key) => {
|
|
1993
|
+
try {
|
|
1994
|
+
const value = window.localStorage.getItem(key);
|
|
1995
|
+
return value === null ? null : (0,_json__WEBPACK_IMPORTED_MODULE_0__.parseJson)(value);
|
|
1996
|
+
}
|
|
1997
|
+
catch {
|
|
1998
|
+
return null;
|
|
1999
|
+
}
|
|
2000
|
+
};
|
|
2001
|
+
/**
|
|
2002
|
+
* Stores a value under a key in `localStorage`, as JSON.
|
|
2003
|
+
*
|
|
2004
|
+
* Never throws: a write that fails - storage full (`QuotaExceededError`), Safari Private Mode,
|
|
2005
|
+
* security-restricted contexts, SSR, or a value `JSON.stringify()` cannot serialise (a circular
|
|
2006
|
+
* reference, a `BigInt`) - reports `false` instead.
|
|
2007
|
+
*
|
|
2008
|
+
* @param key - The `localStorage` key to write.
|
|
2009
|
+
* @param value - Any JSON-serialisable value.
|
|
2010
|
+
*
|
|
2011
|
+
* @returns `true` once the value is stored, `false` when it could not be.
|
|
2012
|
+
*/
|
|
2013
|
+
const writeLocalStorageJson = (key, value) => {
|
|
2014
|
+
try {
|
|
2015
|
+
window.localStorage.setItem(key, JSON.stringify(value));
|
|
2016
|
+
return true;
|
|
2017
|
+
}
|
|
2018
|
+
catch {
|
|
2019
|
+
return false;
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
1782
2022
|
|
|
1783
2023
|
|
|
1784
2024
|
/***/ },
|
|
@@ -1806,10 +2046,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
1806
2046
|
* throw; otherwise `false`.
|
|
1807
2047
|
*/
|
|
1808
2048
|
const isLocalStorageReadable = () => {
|
|
1809
|
-
if (typeof window === 'undefined'
|
|
2049
|
+
if (typeof window === 'undefined') {
|
|
1810
2050
|
return false;
|
|
1811
2051
|
}
|
|
2052
|
+
// Inside the `try`: in a sandboxed iframe, or with storage blocked, reading the property throws
|
|
1812
2053
|
try {
|
|
2054
|
+
if (!window.localStorage) {
|
|
2055
|
+
return false;
|
|
2056
|
+
}
|
|
1813
2057
|
window.localStorage.getItem('__non_existing_key__');
|
|
1814
2058
|
return true;
|
|
1815
2059
|
}
|
|
@@ -1958,7 +2202,8 @@ const readFileSystemDirectoryEntries = async (directoryEntry) => {
|
|
|
1958
2202
|
*
|
|
1959
2203
|
* This function walks through all subdirectories, resolving each file into a `File` object.
|
|
1960
2204
|
* Directories themselves are not returned. To avoid unnecessary noise, certain system or
|
|
1961
|
-
* OS-generated files can be excluded via the `skipFiles` option
|
|
2205
|
+
* OS-generated files and folders can be excluded via the `skipFiles` option - a folder named there
|
|
2206
|
+
* is not entered.
|
|
1962
2207
|
*
|
|
1963
2208
|
* @param directoryEntry - The starting directory entry to traverse.
|
|
1964
2209
|
* @param options - Optional settings that control traversal behavior.
|
|
@@ -1978,18 +2223,18 @@ const traverseFileSystemDirectory = async (directoryEntry, { skipFiles = [
|
|
|
1978
2223
|
const skipFilesSet = new Set(skipFiles);
|
|
1979
2224
|
const entries = await readFileSystemDirectoryEntries(directoryEntry);
|
|
1980
2225
|
const filePromises = await (0,_async__WEBPACK_IMPORTED_MODULE_0__.runParallel)(entries, async (entry) => {
|
|
2226
|
+
if (skipFilesSet.has(entry.name)) {
|
|
2227
|
+
return [];
|
|
2228
|
+
}
|
|
1981
2229
|
if (entry.isDirectory) {
|
|
1982
2230
|
return traverseFileSystemDirectory(entry, {
|
|
1983
2231
|
skipFiles,
|
|
1984
2232
|
});
|
|
1985
2233
|
}
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
return [file];
|
|
1991
|
-
}
|
|
1992
|
-
return [];
|
|
2234
|
+
const file = await new Promise((resolve, reject) => {
|
|
2235
|
+
entry.file(resolve, reject);
|
|
2236
|
+
});
|
|
2237
|
+
return [file];
|
|
1993
2238
|
});
|
|
1994
2239
|
return filePromises.flat();
|
|
1995
2240
|
};
|
|
@@ -2059,6 +2304,17 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2059
2304
|
/* harmony export */ not: () => (/* binding */ not),
|
|
2060
2305
|
/* harmony export */ once: () => (/* binding */ once)
|
|
2061
2306
|
/* harmony export */ });
|
|
2307
|
+
/**
|
|
2308
|
+
* A function that does nothing and returns `undefined` - a default for an optional callback, so the
|
|
2309
|
+
* caller can call it without checking it is there.
|
|
2310
|
+
*
|
|
2311
|
+
* @example
|
|
2312
|
+
* ```ts
|
|
2313
|
+
* const { onClose = noop } = props;
|
|
2314
|
+
*
|
|
2315
|
+
* onClose();
|
|
2316
|
+
* ```
|
|
2317
|
+
*/
|
|
2062
2318
|
const noop = () => { };
|
|
2063
2319
|
/**
|
|
2064
2320
|
* Checks if a value is a function.
|
|
@@ -2067,6 +2323,7 @@ const noop = () => { };
|
|
|
2067
2323
|
*
|
|
2068
2324
|
* @returns `true` if the value is a function; otherwise, `false`.
|
|
2069
2325
|
*/
|
|
2326
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type -- what `typeof value === 'function'` narrows `unknown` to
|
|
2070
2327
|
const isFunction = (value) => typeof value === 'function';
|
|
2071
2328
|
/**
|
|
2072
2329
|
* Creates a function that negates the result of the given predicate function.
|
|
@@ -2091,6 +2348,7 @@ const not = (fn) => (...args) => !fn(...args);
|
|
|
2091
2348
|
* Wraps a function so that it can only be executed once.
|
|
2092
2349
|
* The wrapped function remembers (caches) the result of the first invocation
|
|
2093
2350
|
* and returns that same result for all subsequent calls, regardless of the arguments provided.
|
|
2351
|
+
* Where the first invocation throws, every call throws that same error - `fn` is not run again.
|
|
2094
2352
|
*
|
|
2095
2353
|
* Common use cases include:
|
|
2096
2354
|
* - initializing singletons
|
|
@@ -2108,10 +2366,21 @@ const not = (fn) => (...args) => !fn(...args);
|
|
|
2108
2366
|
const once = (fn) => {
|
|
2109
2367
|
let called = false;
|
|
2110
2368
|
let result;
|
|
2369
|
+
let hasThrown = false;
|
|
2370
|
+
let error;
|
|
2111
2371
|
return function (...args) {
|
|
2112
2372
|
if (!called) {
|
|
2113
2373
|
called = true;
|
|
2114
|
-
|
|
2374
|
+
try {
|
|
2375
|
+
result = fn.apply(this, args);
|
|
2376
|
+
}
|
|
2377
|
+
catch (e) {
|
|
2378
|
+
hasThrown = true;
|
|
2379
|
+
error = e;
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
if (hasThrown) {
|
|
2383
|
+
throw error;
|
|
2115
2384
|
}
|
|
2116
2385
|
return result;
|
|
2117
2386
|
};
|
|
@@ -2179,7 +2448,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2179
2448
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
2180
2449
|
/* harmony export */ applyInertiaStep: () => (/* binding */ applyInertiaStep)
|
|
2181
2450
|
/* harmony export */ });
|
|
2182
|
-
/* harmony import */ var
|
|
2451
|
+
/* harmony import */ var _resolve_bounded_delta__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./resolve-bounded-delta */ "./src/geometry/resolve-bounded-delta.ts");
|
|
2183
2452
|
|
|
2184
2453
|
/**
|
|
2185
2454
|
* Applies a **single step** of bounded, velocity-based inertia.
|
|
@@ -2224,7 +2493,7 @@ const applyInertiaStep = ({ value, min, max, velocityPxMs, deltaTimeMs, friction
|
|
|
2224
2493
|
if (Math.abs(velocityPxMs) < minVelocityPxMs) {
|
|
2225
2494
|
return null;
|
|
2226
2495
|
}
|
|
2227
|
-
const nextValue = (0,
|
|
2496
|
+
const nextValue = (0,_resolve_bounded_delta__WEBPACK_IMPORTED_MODULE_0__.resolveBoundedDelta)({
|
|
2228
2497
|
delta: velocityPxMs * deltaTimeMs,
|
|
2229
2498
|
value,
|
|
2230
2499
|
min,
|
|
@@ -2289,13 +2558,24 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2289
2558
|
/**
|
|
2290
2559
|
* Calculates the raw offset required to center an element within a container along a single axis.
|
|
2291
2560
|
*
|
|
2292
|
-
* @
|
|
2561
|
+
* @param options - The container's visible size, and the element's offset and size, along the axis.
|
|
2562
|
+
*
|
|
2563
|
+
* @returns The offset to translate the container by: negative for an element past the container's
|
|
2564
|
+
* centre, positive for one before it, and `0` for one already centred. Clamp it with
|
|
2565
|
+
* `clampOffsetToOverflow` to keep the container within its overflow.
|
|
2566
|
+
*
|
|
2567
|
+
* @example
|
|
2568
|
+
* ```ts
|
|
2569
|
+
* calculateCenterOffset({ containerSize: 100, elementOffset: 200, elementSize: 20 });
|
|
2570
|
+
* // -160
|
|
2571
|
+
* ```
|
|
2293
2572
|
*/
|
|
2294
2573
|
const calculateCenterOffset = ({ containerSize, elementOffset, elementSize, }) => {
|
|
2295
2574
|
const containerCenter = containerSize / 2;
|
|
2296
2575
|
const elementCenter = elementOffset + elementSize / 2;
|
|
2297
2576
|
const targetOffset = elementCenter - containerCenter;
|
|
2298
|
-
|
|
2577
|
+
// `|| 0` turns the `-0` of an element already centred into `0`
|
|
2578
|
+
return -targetOffset || 0;
|
|
2299
2579
|
};
|
|
2300
2580
|
|
|
2301
2581
|
|
|
@@ -2318,6 +2598,12 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2318
2598
|
* @param overflowSize - Maximum overflow size along the axis.
|
|
2319
2599
|
*
|
|
2320
2600
|
* @returns Clamped negative offset, or `0` when no overflow exists.
|
|
2601
|
+
*
|
|
2602
|
+
* @example
|
|
2603
|
+
* ```ts
|
|
2604
|
+
* clampOffsetToOverflow(-160, 100); // -100
|
|
2605
|
+
* clampOffsetToOverflow(40, 100); // 0
|
|
2606
|
+
* ```
|
|
2321
2607
|
*/
|
|
2322
2608
|
const clampOffsetToOverflow = (offset, overflowSize) => {
|
|
2323
2609
|
if (overflowSize <= 0) {
|
|
@@ -2455,6 +2741,26 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2455
2741
|
/* harmony export */ isUndefined: () => (/* binding */ isUndefined),
|
|
2456
2742
|
/* harmony export */ isValidDate: () => (/* binding */ isValidDate)
|
|
2457
2743
|
/* harmony export */ });
|
|
2744
|
+
/**
|
|
2745
|
+
* Asserts that a condition holds, narrowing it for the code after the call.
|
|
2746
|
+
*
|
|
2747
|
+
* A `function` declaration rather than an arrow, which TypeScript needs for an `asserts` signature
|
|
2748
|
+
* to narrow at the call site.
|
|
2749
|
+
*
|
|
2750
|
+
* @param condition - The condition expected to be truthy.
|
|
2751
|
+
* @param message - The message of the error thrown when it is not.
|
|
2752
|
+
*
|
|
2753
|
+
* @throws {Error} When `condition` is falsy.
|
|
2754
|
+
*
|
|
2755
|
+
* @example
|
|
2756
|
+
* ```ts
|
|
2757
|
+
* const user = users.find(user => user.id === id);
|
|
2758
|
+
*
|
|
2759
|
+
* assert(user, `User ${id} not found`);
|
|
2760
|
+
*
|
|
2761
|
+
* user.name; // `user` is no longer `undefined` here
|
|
2762
|
+
* ```
|
|
2763
|
+
*/
|
|
2458
2764
|
function assert(condition, message) {
|
|
2459
2765
|
if (!condition) {
|
|
2460
2766
|
throw new Error(message);
|
|
@@ -2509,21 +2815,23 @@ const isNumber = (value) => typeof value === 'number';
|
|
|
2509
2815
|
*/
|
|
2510
2816
|
const isBool = (value) => typeof value === 'boolean';
|
|
2511
2817
|
/**
|
|
2512
|
-
* Checks if a value is an object
|
|
2818
|
+
* Checks if a value is an object - anything `typeof` calls `'object'` (plain objects, arrays,
|
|
2819
|
+
* dates, maps, class instances), except `null`.
|
|
2513
2820
|
*
|
|
2514
2821
|
* @param value - The value to check.
|
|
2515
2822
|
*
|
|
2516
|
-
* @returns `true` if the value is
|
|
2823
|
+
* @returns `true` if the value is a non-null object; otherwise, `false`.
|
|
2517
2824
|
*/
|
|
2518
|
-
const isObject = (value) => typeof value === 'object';
|
|
2825
|
+
const isObject = (value) => typeof value === 'object' && value !== null;
|
|
2519
2826
|
/**
|
|
2520
|
-
* Checks if a value is an empty object (no own enumerable properties).
|
|
2827
|
+
* Checks if a value is an empty object (no own enumerable properties, symbol-keyed ones included).
|
|
2521
2828
|
*
|
|
2522
2829
|
* @param value - The value to check.
|
|
2523
2830
|
*
|
|
2524
2831
|
* @returns `true` if the value is an empty object; otherwise, `false`.
|
|
2525
2832
|
*/
|
|
2526
|
-
const isEmptyObject = (value) => isObject(value) &&
|
|
2833
|
+
const isEmptyObject = (value) => isObject(value) &&
|
|
2834
|
+
Reflect.ownKeys(value).every(key => !Object.prototype.propertyIsEnumerable.call(value, key));
|
|
2527
2835
|
/**
|
|
2528
2836
|
* Checks if a value is a Date object.
|
|
2529
2837
|
*
|
|
@@ -2762,13 +3070,23 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2762
3070
|
* @param sourceRect - The rectangle used to measure overlap against the target.
|
|
2763
3071
|
* @param targetRect - The rectangle whose covered area is measured.
|
|
2764
3072
|
*
|
|
2765
|
-
* @returns A number between `0` and `1` representing the intersection ratio
|
|
3073
|
+
* @returns A number between `0` and `1` representing the intersection ratio - `0` for a target
|
|
3074
|
+
* with no area, which nothing can cover.
|
|
3075
|
+
*
|
|
3076
|
+
* @example
|
|
3077
|
+
* ```ts
|
|
3078
|
+
* getDOMRectIntersectionRatio(new DOMRect(0, 0, 100, 100), new DOMRect(50, 0, 100, 100));
|
|
3079
|
+
* // 0.5
|
|
3080
|
+
* ```
|
|
2766
3081
|
*/
|
|
2767
3082
|
const getDOMRectIntersectionRatio = (sourceRect, targetRect) => {
|
|
2768
3083
|
const xOverlap = Math.max(0, Math.min(sourceRect.right, targetRect.right) - Math.max(sourceRect.left, targetRect.left));
|
|
2769
3084
|
const yOverlap = Math.max(0, Math.min(sourceRect.bottom, targetRect.bottom) - Math.max(sourceRect.top, targetRect.top));
|
|
2770
3085
|
const intersectionArea = xOverlap * yOverlap;
|
|
2771
3086
|
const targetArea = targetRect.width * targetRect.height;
|
|
3087
|
+
if (targetArea <= 0) {
|
|
3088
|
+
return 0;
|
|
3089
|
+
}
|
|
2772
3090
|
return intersectionArea / targetArea;
|
|
2773
3091
|
};
|
|
2774
3092
|
|
|
@@ -2830,26 +3148,35 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2830
3148
|
* @param options - Resolution behavior configuration.
|
|
2831
3149
|
*
|
|
2832
3150
|
* @returns A normalized, axis-aligned delta suitable for further scroll or movement processing.
|
|
3151
|
+
*
|
|
3152
|
+
* @example
|
|
3153
|
+
* ```ts
|
|
3154
|
+
* // A vertical wheel scrolling a horizontal list
|
|
3155
|
+
* resolveAxisDelta({ deltaX: 0, deltaY: 40 }, 'x');
|
|
3156
|
+
* // { deltaX: -40, deltaY: 0 }
|
|
3157
|
+
* ```
|
|
2833
3158
|
*/
|
|
2834
3159
|
const resolveAxisDelta = (delta, axis, { allowFallback = true, invert = true } = {}) => {
|
|
2835
3160
|
const sign = invert ? -1 : 1;
|
|
3161
|
+
// `|| 0` keeps an inverted zero `0` rather than `-0`
|
|
3162
|
+
const resolve = (value) => sign * value || 0;
|
|
2836
3163
|
switch (axis) {
|
|
2837
3164
|
case 'x': {
|
|
2838
3165
|
const value = delta.deltaX !== 0 ? delta.deltaX : allowFallback ? delta.deltaY : 0;
|
|
2839
3166
|
return {
|
|
2840
|
-
deltaX:
|
|
3167
|
+
deltaX: resolve(value),
|
|
2841
3168
|
deltaY: 0,
|
|
2842
3169
|
};
|
|
2843
3170
|
}
|
|
2844
3171
|
case 'y':
|
|
2845
3172
|
return {
|
|
2846
3173
|
deltaX: 0,
|
|
2847
|
-
deltaY:
|
|
3174
|
+
deltaY: resolve(delta.deltaY),
|
|
2848
3175
|
};
|
|
2849
3176
|
default:
|
|
2850
3177
|
return {
|
|
2851
|
-
deltaX:
|
|
2852
|
-
deltaY:
|
|
3178
|
+
deltaX: resolve(delta.deltaX),
|
|
3179
|
+
deltaY: resolve(delta.deltaY),
|
|
2853
3180
|
};
|
|
2854
3181
|
}
|
|
2855
3182
|
};
|
|
@@ -2883,6 +3210,27 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2883
3210
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
2884
3211
|
/* harmony export */ parseJson: () => (/* binding */ parseJson)
|
|
2885
3212
|
/* harmony export */ });
|
|
3213
|
+
/**
|
|
3214
|
+
* Parses a JSON string without throwing.
|
|
3215
|
+
*
|
|
3216
|
+
* The result is only cast to `Value`, not checked against it - check its shape before relying on
|
|
3217
|
+
* it where the string comes from outside the program.
|
|
3218
|
+
*
|
|
3219
|
+
* @template Value - The type the JSON is expected to have.
|
|
3220
|
+
*
|
|
3221
|
+
* @param value - The JSON string to parse.
|
|
3222
|
+
*
|
|
3223
|
+
* @returns The parsed value, or `null` when the string is not valid JSON.
|
|
3224
|
+
*
|
|
3225
|
+
* @example
|
|
3226
|
+
* ```ts
|
|
3227
|
+
* parseJson<{ name: string }>('{"name":"Mike"}');
|
|
3228
|
+
* // ➜ { name: 'Mike' }
|
|
3229
|
+
*
|
|
3230
|
+
* parseJson('{name:"Mike"}');
|
|
3231
|
+
* // ➜ null
|
|
3232
|
+
* ```
|
|
3233
|
+
*/
|
|
2886
3234
|
const parseJson = (value) => {
|
|
2887
3235
|
try {
|
|
2888
3236
|
return JSON.parse(value);
|
|
@@ -2958,7 +3306,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
2958
3306
|
* @example
|
|
2959
3307
|
* ```ts
|
|
2960
3308
|
* const className = hashString('background-color: red;');
|
|
2961
|
-
* // → '
|
|
3309
|
+
* // → '1s0s409'
|
|
2962
3310
|
* ```
|
|
2963
3311
|
*/
|
|
2964
3312
|
const hashString = (input) => {
|
|
@@ -3017,6 +3365,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3017
3365
|
* @param endY - The Y coordinate of the ending point.
|
|
3018
3366
|
*
|
|
3019
3367
|
* @returns The Euclidean distance between the two points.
|
|
3368
|
+
*
|
|
3369
|
+
* @example
|
|
3370
|
+
* ```ts
|
|
3371
|
+
* calculateEuclideanDistance(0, 0, 3, 4); // 5
|
|
3372
|
+
* ```
|
|
3020
3373
|
*/
|
|
3021
3374
|
const calculateEuclideanDistance = (startX, startY, endX, endY) => {
|
|
3022
3375
|
const deltaX = endX - startX;
|
|
@@ -3029,7 +3382,13 @@ const calculateEuclideanDistance = (startX, startY, endX, endY) => {
|
|
|
3029
3382
|
* @param distance - The distance.
|
|
3030
3383
|
* @param elapsedTime - The time taken to move the distance.
|
|
3031
3384
|
*
|
|
3032
|
-
* @returns The calculated speed, which is the absolute value of delta divided by elapsed time
|
|
3385
|
+
* @returns The calculated speed, which is the absolute value of delta divided by elapsed time -
|
|
3386
|
+
* `Infinity` for a distance covered in no time, and `NaN` for none covered in none.
|
|
3387
|
+
*
|
|
3388
|
+
* @example
|
|
3389
|
+
* ```ts
|
|
3390
|
+
* calculateMovingSpeed(-120, 60); // 2
|
|
3391
|
+
* ```
|
|
3033
3392
|
*/
|
|
3034
3393
|
const calculateMovingSpeed = (distance, elapsedTime) => Math.abs(distance / elapsedTime);
|
|
3035
3394
|
/**
|
|
@@ -3039,6 +3398,11 @@ const calculateMovingSpeed = (distance, elapsedTime) => Math.abs(distance / elap
|
|
|
3039
3398
|
* @param percentage - The percentage to calculate.
|
|
3040
3399
|
*
|
|
3041
3400
|
* @returns The calculated percentage of the value.
|
|
3401
|
+
*
|
|
3402
|
+
* @example
|
|
3403
|
+
* ```ts
|
|
3404
|
+
* calculatePercentage(200, 15); // 30
|
|
3405
|
+
* ```
|
|
3042
3406
|
*/
|
|
3043
3407
|
const calculatePercentage = (value, percentage) => (value * percentage) / 100;
|
|
3044
3408
|
|
|
@@ -3070,12 +3434,19 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3070
3434
|
*
|
|
3071
3435
|
* @returns A new object containing only keys whose runtime values are not `undefined`.
|
|
3072
3436
|
*/
|
|
3073
|
-
const definedProps = (obj) =>
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3437
|
+
const definedProps = (obj) => {
|
|
3438
|
+
const result = {};
|
|
3439
|
+
Reflect.ownKeys(obj).forEach(key => {
|
|
3440
|
+
if (!Object.prototype.propertyIsEnumerable.call(obj, key)) {
|
|
3441
|
+
return;
|
|
3442
|
+
}
|
|
3443
|
+
const value = obj[key];
|
|
3444
|
+
if (value !== undefined) {
|
|
3445
|
+
result[key] = value;
|
|
3446
|
+
}
|
|
3447
|
+
});
|
|
3077
3448
|
return result;
|
|
3078
|
-
}
|
|
3449
|
+
};
|
|
3079
3450
|
|
|
3080
3451
|
|
|
3081
3452
|
/***/ },
|
|
@@ -3116,7 +3487,7 @@ const camelToDashCase = (input) => {
|
|
|
3116
3487
|
// Convert the first character to the lowercase without adding a hyphen
|
|
3117
3488
|
const firstCharProcessed = firstChar.toLowerCase();
|
|
3118
3489
|
// Process the rest of the string normally, adding hyphens before uppercase letters
|
|
3119
|
-
const restProcessed = restOfString.replace(/
|
|
3490
|
+
const restProcessed = restOfString.replace(/\p{Lu}/gu, letter => `-${letter.toLowerCase()}`);
|
|
3120
3491
|
return firstCharProcessed + restProcessed;
|
|
3121
3492
|
};
|
|
3122
3493
|
|
|
@@ -3151,7 +3522,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3151
3522
|
* camelToWords('userIDNumber'); // → 'user ID Number'
|
|
3152
3523
|
* ```
|
|
3153
3524
|
*/
|
|
3154
|
-
const camelToWords = (input) => input.replace(/([
|
|
3525
|
+
const camelToWords = (input) => input.replace(/([\p{Ll}\p{N}])(\p{Lu})/gu, '$1 $2').replace(/(\p{Lu})(\p{Lu}\p{Ll})/gu, '$1 $2');
|
|
3155
3526
|
|
|
3156
3527
|
|
|
3157
3528
|
/***/ },
|
|
@@ -3268,7 +3639,7 @@ const getWordsInitials = (input, maxWords = Infinity) => {
|
|
|
3268
3639
|
}
|
|
3269
3640
|
return (0,_split_string_into_words__WEBPACK_IMPORTED_MODULE_0__.splitStringIntoWords)(input)
|
|
3270
3641
|
.slice(0, maxWords)
|
|
3271
|
-
.map(word => word
|
|
3642
|
+
.map(word => String.fromCodePoint(word.codePointAt(0)))
|
|
3272
3643
|
.join('')
|
|
3273
3644
|
.toUpperCase();
|
|
3274
3645
|
};
|
|
@@ -3515,7 +3886,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3515
3886
|
* toKebabCase('hello123World'); // → 'hello123-world'
|
|
3516
3887
|
* ```
|
|
3517
3888
|
*/
|
|
3518
|
-
const toKebabCase = (input) => input.replace(/([
|
|
3889
|
+
const toKebabCase = (input) => input.replace(/([\p{Ll}\p{N}])(\p{Lu})/gu, '$1-$2').toLowerCase();
|
|
3519
3890
|
|
|
3520
3891
|
|
|
3521
3892
|
/***/ },
|
|
@@ -3982,6 +4353,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3982
4353
|
/* harmony export */ parseJson: () => (/* reexport safe */ _json__WEBPACK_IMPORTED_MODULE_17__.parseJson),
|
|
3983
4354
|
/* harmony export */ pipe: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_1__.pipe),
|
|
3984
4355
|
/* harmony export */ readFilesFromDataTransfer: () => (/* reexport safe */ _file__WEBPACK_IMPORTED_MODULE_5__.readFilesFromDataTransfer),
|
|
4356
|
+
/* harmony export */ readLocalStorageJson: () => (/* reexport safe */ _env__WEBPACK_IMPORTED_MODULE_4__.readLocalStorageJson),
|
|
3985
4357
|
/* harmony export */ reduceAsync: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_2__.reduceAsync),
|
|
3986
4358
|
/* harmony export */ replaceHistorySearchParams: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_3__.replaceHistorySearchParams),
|
|
3987
4359
|
/* harmony export */ resolveAxisDelta: () => (/* reexport safe */ _intersection__WEBPACK_IMPORTED_MODULE_10__.resolveAxisDelta),
|
|
@@ -3996,9 +4368,11 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
3996
4368
|
/* harmony export */ splitStringIntoWords: () => (/* reexport safe */ _string__WEBPACK_IMPORTED_MODULE_13__.splitStringIntoWords),
|
|
3997
4369
|
/* harmony export */ timeout: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_2__.timeout),
|
|
3998
4370
|
/* harmony export */ toKebabCase: () => (/* reexport safe */ _string__WEBPACK_IMPORTED_MODULE_13__.toKebabCase),
|
|
4371
|
+
/* harmony export */ toMapBy: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_1__.toMapBy),
|
|
3999
4372
|
/* harmony export */ toggleArrayItem: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_1__.toggleArrayItem),
|
|
4000
4373
|
/* harmony export */ traverseFileSystemDirectory: () => (/* reexport safe */ _file__WEBPACK_IMPORTED_MODULE_5__.traverseFileSystemDirectory),
|
|
4001
|
-
/* harmony export */ unique: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_1__.unique)
|
|
4374
|
+
/* harmony export */ unique: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_1__.unique),
|
|
4375
|
+
/* harmony export */ writeLocalStorageJson: () => (/* reexport safe */ _env__WEBPACK_IMPORTED_MODULE_4__.writeLocalStorageJson)
|
|
4002
4376
|
/* harmony export */ });
|
|
4003
4377
|
/* harmony import */ var _a11y__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./a11y */ "./src/a11y/index.ts");
|
|
4004
4378
|
/* harmony import */ var _array__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./array */ "./src/array/index.ts");
|