@react-hive/honey-utils 3.12.0 → 3.13.1

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.
@@ -2,6 +2,216 @@
2
2
  /******/ "use strict";
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
5
+ /***/ "./src/a11y/focus/get-focusable-html-elements.ts":
6
+ /*!*******************************************************!*\
7
+ !*** ./src/a11y/focus/get-focusable-html-elements.ts ***!
8
+ \*******************************************************/
9
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
10
+
11
+ __webpack_require__.r(__webpack_exports__);
12
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
13
+ /* harmony export */ getFocusableHtmlElements: () => (/* binding */ getFocusableHtmlElements)
14
+ /* harmony export */ });
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
+
17
+ /**
18
+ * Collects all focusable descendant elements within a container.
19
+ *
20
+ * The function queries *all* elements under the container and filters them
21
+ * using `isHtmlElementFocusable`, producing a reliable list of elements
22
+ * that can receive keyboard focus in real-world browser conditions.
23
+ *
24
+ * @param container - The root container whose focusable children will be found.
25
+ *
26
+ * @returns An array of focusable HTMLElements in DOM order.
27
+ */
28
+ const getFocusableHtmlElements = (container) => Array.from(container.querySelectorAll('*')).filter(_is_html_element_focusable__WEBPACK_IMPORTED_MODULE_0__.isHtmlElementFocusable);
29
+
30
+
31
+ /***/ }),
32
+
33
+ /***/ "./src/a11y/focus/index.ts":
34
+ /*!*********************************!*\
35
+ !*** ./src/a11y/focus/index.ts ***!
36
+ \*********************************/
37
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
38
+
39
+ __webpack_require__.r(__webpack_exports__);
40
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
41
+ /* harmony export */ FOCUSABLE_HTML_TAGS: () => (/* reexport safe */ _is_html_element_focusable__WEBPACK_IMPORTED_MODULE_0__.FOCUSABLE_HTML_TAGS),
42
+ /* harmony export */ getFocusableHtmlElements: () => (/* reexport safe */ _get_focusable_html_elements__WEBPACK_IMPORTED_MODULE_1__.getFocusableHtmlElements),
43
+ /* harmony export */ isHtmlElementFocusable: () => (/* reexport safe */ _is_html_element_focusable__WEBPACK_IMPORTED_MODULE_0__.isHtmlElementFocusable),
44
+ /* harmony export */ moveFocusWithinContainer: () => (/* reexport safe */ _move_focus_within_container__WEBPACK_IMPORTED_MODULE_2__.moveFocusWithinContainer)
45
+ /* harmony export */ });
46
+ /* 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");
47
+ /* harmony import */ var _get_focusable_html_elements__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./get-focusable-html-elements */ "./src/a11y/focus/get-focusable-html-elements.ts");
48
+ /* harmony import */ var _move_focus_within_container__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./move-focus-within-container */ "./src/a11y/focus/move-focus-within-container.ts");
49
+
50
+
51
+
52
+
53
+
54
+ /***/ }),
55
+
56
+ /***/ "./src/a11y/focus/is-html-element-focusable.ts":
57
+ /*!*****************************************************!*\
58
+ !*** ./src/a11y/focus/is-html-element-focusable.ts ***!
59
+ \*****************************************************/
60
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
61
+
62
+ __webpack_require__.r(__webpack_exports__);
63
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
64
+ /* harmony export */ FOCUSABLE_HTML_TAGS: () => (/* binding */ FOCUSABLE_HTML_TAGS),
65
+ /* harmony export */ isHtmlElementFocusable: () => (/* binding */ isHtmlElementFocusable)
66
+ /* harmony export */ });
67
+ /* harmony import */ var _dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../dom */ "./src/dom/index.ts");
68
+
69
+ const FOCUSABLE_HTML_TAGS = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'A'];
70
+ /**
71
+ * Determines whether an HTMLElement is focusable under standard browser rules.
72
+ *
73
+ * The function checks a combination of factors:
74
+ * - The element must be rendered (not `display: none` or `visibility: hidden`).
75
+ * - Disabled form controls are never focusable.
76
+ * - Elements with `tabindex="-1"` are intentionally removed from the focus order.
77
+ * - Certain native HTML elements are inherently focusable (e.g. inputs, buttons, anchors with `href`).
78
+ * - Elements with `contenteditable="true"` are treated as focusable.
79
+ * - Any element with a valid `tabindex` (not null) is considered focusable.
80
+ *
81
+ * This logic approximates how browsers and the accessibility tree
82
+ * determine real-world focusability—not just tabindex presence.
83
+ *
84
+ * @param element - The element to test. `null` or `undefined` will return `false`.
85
+ *
86
+ * @returns Whether the element is focusable.
87
+ */
88
+ const isHtmlElementFocusable = (element) => {
89
+ if (!element) {
90
+ return false;
91
+ }
92
+ const style = window.getComputedStyle(element);
93
+ if (style.visibility === 'hidden' || style.display === 'none') {
94
+ return false;
95
+ }
96
+ if ('disabled' in element && element.disabled) {
97
+ return false;
98
+ }
99
+ // Explicitly removed from tab order
100
+ const tabIndex = element.getAttribute('tabindex');
101
+ if (tabIndex === '-1') {
102
+ return false;
103
+ }
104
+ if (FOCUSABLE_HTML_TAGS.includes(element.tagName)) {
105
+ if ((0,_dom__WEBPACK_IMPORTED_MODULE_0__.isAnchorHtmlElement)(element)) {
106
+ return element.href !== '';
107
+ }
108
+ return true;
109
+ }
110
+ if ((0,_dom__WEBPACK_IMPORTED_MODULE_0__.isContentEditableHtmlElement)(element)) {
111
+ return true;
112
+ }
113
+ return tabIndex !== null;
114
+ };
115
+
116
+
117
+ /***/ }),
118
+
119
+ /***/ "./src/a11y/focus/move-focus-within-container.ts":
120
+ /*!*******************************************************!*\
121
+ !*** ./src/a11y/focus/move-focus-within-container.ts ***!
122
+ \*******************************************************/
123
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
124
+
125
+ __webpack_require__.r(__webpack_exports__);
126
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
127
+ /* harmony export */ moveFocusWithinContainer: () => (/* binding */ moveFocusWithinContainer)
128
+ /* harmony export */ });
129
+ /* 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
+
131
+ /**
132
+ * Moves focus to the next or previous focusable element within a container.
133
+ *
134
+ * This utility is commonly used to implement accessible keyboard navigation patterns such as:
135
+ * - roving tabindex
136
+ * - custom dropdowns
137
+ * - tablists
138
+ * - menus
139
+ * - horizontal or vertical navigation groups
140
+ *
141
+ * Focus movement is scoped to a container and operates on the list of
142
+ * focusable descendants returned by `getFocusableHtmlElements`.
143
+ *
144
+ * @param direction - Direction in which focus should move (`'next'` or `'previous'`).
145
+ * @param container - Optional container that defines the focus scope.
146
+ * If omitted, the parent element of the currently focused element is used.
147
+ * @param options - Optional configuration controlling wrapping behavior and custom index resolution.
148
+ *
149
+ * @remarks
150
+ * - This function reads from and mutates the document's focus state.
151
+ * - If no active element exists, no container can be resolved,
152
+ * or the active element is not part of the focusable set, no action is taken.
153
+ * - When `getNextIndex` is provided, it fully overrides the default wrapping and directional logic.
154
+ */
155
+ const moveFocusWithinContainer = (direction, container = null, { wrap = true, getNextIndex } = {}) => {
156
+ const activeElement = document.activeElement;
157
+ const scope = container ?? activeElement?.parentElement;
158
+ if (!activeElement || !scope) {
159
+ return;
160
+ }
161
+ const focusableElements = (0,_get_focusable_html_elements__WEBPACK_IMPORTED_MODULE_0__.getFocusableHtmlElements)(scope);
162
+ if (focusableElements.length === 0) {
163
+ return;
164
+ }
165
+ const currentIndex = focusableElements.indexOf(activeElement);
166
+ if (currentIndex === -1) {
167
+ return;
168
+ }
169
+ let nextIndex;
170
+ if (getNextIndex) {
171
+ nextIndex = getNextIndex(currentIndex, direction, focusableElements);
172
+ }
173
+ else {
174
+ if (direction === 'next') {
175
+ nextIndex = currentIndex + 1;
176
+ if (nextIndex >= focusableElements.length) {
177
+ nextIndex = wrap ? 0 : null;
178
+ }
179
+ }
180
+ else {
181
+ nextIndex = currentIndex - 1;
182
+ if (nextIndex < 0) {
183
+ nextIndex = wrap ? focusableElements.length - 1 : null;
184
+ }
185
+ }
186
+ }
187
+ if (nextIndex === null) {
188
+ return;
189
+ }
190
+ focusableElements[nextIndex]?.focus();
191
+ };
192
+
193
+
194
+ /***/ }),
195
+
196
+ /***/ "./src/a11y/index.ts":
197
+ /*!***************************!*\
198
+ !*** ./src/a11y/index.ts ***!
199
+ \***************************/
200
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
201
+
202
+ __webpack_require__.r(__webpack_exports__);
203
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
204
+ /* harmony export */ FOCUSABLE_HTML_TAGS: () => (/* reexport safe */ _focus__WEBPACK_IMPORTED_MODULE_0__.FOCUSABLE_HTML_TAGS),
205
+ /* harmony export */ getFocusableHtmlElements: () => (/* reexport safe */ _focus__WEBPACK_IMPORTED_MODULE_0__.getFocusableHtmlElements),
206
+ /* harmony export */ isHtmlElementFocusable: () => (/* reexport safe */ _focus__WEBPACK_IMPORTED_MODULE_0__.isHtmlElementFocusable),
207
+ /* harmony export */ moveFocusWithinContainer: () => (/* reexport safe */ _focus__WEBPACK_IMPORTED_MODULE_0__.moveFocusWithinContainer)
208
+ /* harmony export */ });
209
+ /* harmony import */ var _focus__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./focus */ "./src/a11y/focus/index.ts");
210
+
211
+
212
+
213
+ /***/ }),
214
+
5
215
  /***/ "./src/array.ts":
6
216
  /*!**********************!*\
7
217
  !*** ./src/array.ts ***!
@@ -406,80 +616,19 @@ const findAsync = async (array, predicate) => {
406
616
 
407
617
  /***/ }),
408
618
 
409
- /***/ "./src/dom.ts":
410
- /*!********************!*\
411
- !*** ./src/dom.ts ***!
412
- \********************/
619
+ /***/ "./src/dom/dom.ts":
620
+ /*!************************!*\
621
+ !*** ./src/dom/dom.ts ***!
622
+ \************************/
413
623
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
414
624
 
415
625
  __webpack_require__.r(__webpack_exports__);
416
626
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
417
- /* harmony export */ FOCUSABLE_HTML_TAGS: () => (/* binding */ FOCUSABLE_HTML_TAGS),
418
- /* harmony export */ calculateCenterOffset: () => (/* binding */ calculateCenterOffset),
419
- /* harmony export */ centerElementInContainer: () => (/* binding */ centerElementInContainer),
420
627
  /* harmony export */ cloneBlob: () => (/* binding */ cloneBlob),
421
- /* harmony export */ downloadFile: () => (/* binding */ downloadFile),
422
- /* harmony export */ getDOMRectIntersectionRatio: () => (/* binding */ getDOMRectIntersectionRatio),
423
628
  /* harmony export */ getElementOffsetRect: () => (/* binding */ getElementOffsetRect),
424
- /* harmony export */ getFocusableHtmlElements: () => (/* binding */ getFocusableHtmlElements),
425
- /* harmony export */ getLocalStorageCapabilities: () => (/* binding */ getLocalStorageCapabilities),
426
- /* harmony export */ getXOverflowWidth: () => (/* binding */ getXOverflowWidth),
427
- /* harmony export */ getYOverflowHeight: () => (/* binding */ getYOverflowHeight),
428
- /* harmony export */ hasXOverflow: () => (/* binding */ hasXOverflow),
429
- /* harmony export */ hasYOverflow: () => (/* binding */ hasYOverflow),
430
629
  /* harmony export */ isAnchorHtmlElement: () => (/* binding */ isAnchorHtmlElement),
431
- /* harmony export */ isContentEditableHtmlElement: () => (/* binding */ isContentEditableHtmlElement),
432
- /* harmony export */ isHtmlElementFocusable: () => (/* binding */ isHtmlElementFocusable),
433
- /* harmony export */ isLocalStorageReadable: () => (/* binding */ isLocalStorageReadable),
434
- /* harmony export */ moveFocusWithinContainer: () => (/* binding */ moveFocusWithinContainer),
435
- /* harmony export */ parse2DMatrix: () => (/* binding */ parse2DMatrix)
630
+ /* harmony export */ isContentEditableHtmlElement: () => (/* binding */ isContentEditableHtmlElement)
436
631
  /* harmony export */ });
437
- /* harmony import */ var _guards__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./guards */ "./src/guards.ts");
438
- /* harmony import */ var _string__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./string */ "./src/string.ts");
439
-
440
-
441
- const FOCUSABLE_HTML_TAGS = ['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON', 'A'];
442
- /**
443
- * Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element.
444
- *
445
- * Only works with 2D transforms (i.e., `matrix(a, b, c, d, e, f)`).
446
- *
447
- * @param element - The element with a CSS transform applied.
448
- * @returns An object with parsed transformation values.
449
- *
450
- * @example
451
- * ```ts
452
- * const values = parse2DMatrix(myElement);
453
- * console.log(values.translateX);
454
- * console.log(values.scaleX);
455
- * ```
456
- */
457
- const parse2DMatrix = (element) => {
458
- const computedStyles = window.getComputedStyle(element);
459
- const transformValue = computedStyles.getPropertyValue('transform');
460
- const matrixMatch = transformValue.match(/^matrix\((.+)\)$/);
461
- if (!matrixMatch) {
462
- return {
463
- translateX: 0,
464
- translateY: 0,
465
- scaleX: 1,
466
- scaleY: 1,
467
- skewX: 0,
468
- skewY: 0,
469
- };
470
- }
471
- const [scaleX, skewY, skewX, scaleY, translateX, translateY] = matrixMatch[1]
472
- .split(', ')
473
- .map(parseFloat);
474
- return {
475
- translateX,
476
- translateY,
477
- scaleX,
478
- scaleY,
479
- skewX,
480
- skewY,
481
- };
482
- };
483
632
  /**
484
633
  * Creates a clone of a Blob object.
485
634
  *
@@ -488,24 +637,6 @@ const parse2DMatrix = (element) => {
488
637
  * @returns A new Blob with the same content and type as the original.
489
638
  */
490
639
  const cloneBlob = (blob) => new Blob([blob], { type: blob.type });
491
- /**
492
- * Calculates the intersection ratio between two DOM rectangles.
493
- *
494
- * The ratio represents the proportion of the `targetRect` that is covered by `sourceRect`.
495
- * A value of `1` means `sourceRect` completely covers `targetRect`, and `0` means no overlap.
496
- *
497
- * @param sourceRect - The rectangle used to measure overlap against the target.
498
- * @param targetRect - The rectangle whose covered area is measured.
499
- *
500
- * @returns A number between `0` and `1` representing the intersection ratio.
501
- */
502
- const getDOMRectIntersectionRatio = (sourceRect, targetRect) => {
503
- const xOverlap = Math.max(0, Math.min(sourceRect.right, targetRect.right) - Math.max(sourceRect.left, targetRect.left));
504
- const yOverlap = Math.max(0, Math.min(sourceRect.bottom, targetRect.bottom) - Math.max(sourceRect.top, targetRect.top));
505
- const intersectionArea = xOverlap * yOverlap;
506
- const targetArea = targetRect.width * targetRect.height;
507
- return intersectionArea / targetArea;
508
- };
509
640
  /**
510
641
  * Returns the bounding DOMRect of an element based on offset and client dimensions.
511
642
  *
@@ -540,125 +671,219 @@ const isAnchorHtmlElement = (element) => element.tagName === 'A';
540
671
  * @returns True if `contenteditable="true"` is set.
541
672
  */
542
673
  const isContentEditableHtmlElement = (element) => element.getAttribute('contenteditable') === 'true';
674
+
675
+
676
+ /***/ }),
677
+
678
+ /***/ "./src/dom/file/download-file.ts":
679
+ /*!***************************************!*\
680
+ !*** ./src/dom/file/download-file.ts ***!
681
+ \***************************************/
682
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
683
+
684
+ __webpack_require__.r(__webpack_exports__);
685
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
686
+ /* harmony export */ downloadFile: () => (/* binding */ downloadFile)
687
+ /* harmony export */ });
688
+ /* harmony import */ var _string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../string */ "./src/string.ts");
689
+ /* harmony import */ var _guards__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../guards */ "./src/guards.ts");
690
+
691
+
543
692
  /**
544
- * Determines whether an HTMLElement is focusable under standard browser rules.
693
+ * Initiates a file download in a browser environment.
545
694
  *
546
- * The function checks a combination of factors:
547
- * - The element must be rendered (not `display: none` or `visibility: hidden`).
548
- * - Disabled form controls are never focusable.
549
- * - Elements with `tabindex="-1"` are intentionally removed from the focus order.
550
- * - Certain native HTML elements are inherently focusable (e.g. inputs, buttons, anchors with `href`).
551
- * - Elements with `contenteditable="true"` are treated as focusable.
552
- * - Any element with a valid `tabindex` (not null) is considered focusable.
695
+ * This utility supports downloading from:
696
+ * - a URL string
697
+ * - a `Blob`
698
+ * - a `MediaSource`
553
699
  *
554
- * This logic approximates how browsers and the accessibility tree
555
- * determine real-world focusability—not just tabindex presence.
700
+ * For non-string inputs, an object URL is created temporarily and
701
+ * automatically revoked after the download is triggered.
556
702
  *
557
- * @param element - The element to test. `null` or `undefined` will return `false`.
703
+ * @remarks
704
+ * - This function performs direct DOM manipulation and must be executed in a browser environment.
705
+ * - In non-DOM contexts (e.g. SSR), the function exits without side effects.
706
+ * - Object URLs are revoked asynchronously to avoid Safari-related issues.
558
707
  *
559
- * @returns Whether the element is focusable.
708
+ * @param file - The file source to download (URL string or binary object).
709
+ * @param options - Optional configuration controlling filename and link target.
560
710
  */
561
- const isHtmlElementFocusable = (element) => {
562
- if (!element) {
563
- return false;
564
- }
565
- // Hidden or not rendered
566
- const style = window.getComputedStyle(element);
567
- if (style.visibility === 'hidden' || style.display === 'none') {
568
- return false;
569
- }
570
- if ('disabled' in element && element.disabled) {
571
- return false;
572
- }
573
- // Explicitly removed from tab order
574
- const tabIndex = element.getAttribute('tabindex');
575
- if (tabIndex === '-1') {
576
- return false;
711
+ const downloadFile = (file, { fileName, target } = {}) => {
712
+ // Browser guard (SSR / non-DOM environments)
713
+ if ((0,_guards__WEBPACK_IMPORTED_MODULE_1__.isUndefined)(document)) {
714
+ return;
577
715
  }
578
- if (FOCUSABLE_HTML_TAGS.includes(element.tagName)) {
579
- if (isAnchorHtmlElement(element)) {
580
- return element.href !== '';
716
+ const link = document.createElement('a');
717
+ let objectUrl = null;
718
+ try {
719
+ const href = (0,_string__WEBPACK_IMPORTED_MODULE_0__.isString)(file) ? file : (objectUrl = URL.createObjectURL(file));
720
+ link.href = href;
721
+ if (fileName) {
722
+ link.download = fileName;
581
723
  }
582
- return true;
724
+ if (target) {
725
+ link.target = target;
726
+ }
727
+ // Required for Firefox / Safari
728
+ document.body.appendChild(link);
729
+ link.click();
583
730
  }
584
- if (isContentEditableHtmlElement(element)) {
585
- return true;
731
+ finally {
732
+ link.remove();
733
+ if (objectUrl) {
734
+ // Delay revocation to avoid Safari issues
735
+ setTimeout(() => {
736
+ (0,_guards__WEBPACK_IMPORTED_MODULE_1__.assert)(objectUrl, 'Object URL should not be null');
737
+ URL.revokeObjectURL(objectUrl);
738
+ }, 0);
739
+ }
586
740
  }
587
- return tabIndex !== null;
588
741
  };
742
+
743
+
744
+ /***/ }),
745
+
746
+ /***/ "./src/dom/file/index.ts":
747
+ /*!*******************************!*\
748
+ !*** ./src/dom/file/index.ts ***!
749
+ \*******************************/
750
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
751
+
752
+ __webpack_require__.r(__webpack_exports__);
753
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
754
+ /* harmony export */ downloadFile: () => (/* reexport safe */ _download_file__WEBPACK_IMPORTED_MODULE_0__.downloadFile)
755
+ /* harmony export */ });
756
+ /* harmony import */ var _download_file__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./download-file */ "./src/dom/file/download-file.ts");
757
+
758
+
759
+
760
+ /***/ }),
761
+
762
+ /***/ "./src/dom/index.ts":
763
+ /*!**************************!*\
764
+ !*** ./src/dom/index.ts ***!
765
+ \**************************/
766
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
767
+
768
+ __webpack_require__.r(__webpack_exports__);
769
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
770
+ /* harmony export */ centerElementInContainer: () => (/* reexport safe */ _layout__WEBPACK_IMPORTED_MODULE_2__.centerElementInContainer),
771
+ /* harmony export */ cloneBlob: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_0__.cloneBlob),
772
+ /* harmony export */ downloadFile: () => (/* reexport safe */ _file__WEBPACK_IMPORTED_MODULE_1__.downloadFile),
773
+ /* harmony export */ getElementOffsetRect: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_0__.getElementOffsetRect),
774
+ /* harmony export */ getXOverflowWidth: () => (/* reexport safe */ _layout__WEBPACK_IMPORTED_MODULE_2__.getXOverflowWidth),
775
+ /* harmony export */ getYOverflowHeight: () => (/* reexport safe */ _layout__WEBPACK_IMPORTED_MODULE_2__.getYOverflowHeight),
776
+ /* harmony export */ hasXOverflow: () => (/* reexport safe */ _layout__WEBPACK_IMPORTED_MODULE_2__.hasXOverflow),
777
+ /* harmony export */ hasYOverflow: () => (/* reexport safe */ _layout__WEBPACK_IMPORTED_MODULE_2__.hasYOverflow),
778
+ /* harmony export */ isAnchorHtmlElement: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_0__.isAnchorHtmlElement),
779
+ /* harmony export */ isContentEditableHtmlElement: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_0__.isContentEditableHtmlElement),
780
+ /* harmony export */ parse2DMatrix: () => (/* reexport safe */ _transform__WEBPACK_IMPORTED_MODULE_3__.parse2DMatrix)
781
+ /* harmony export */ });
782
+ /* harmony import */ var _dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./dom */ "./src/dom/dom.ts");
783
+ /* harmony import */ var _file__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./file */ "./src/dom/file/index.ts");
784
+ /* harmony import */ var _layout__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./layout */ "./src/dom/layout/index.ts");
785
+ /* harmony import */ var _transform__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./transform */ "./src/dom/transform/index.ts");
786
+
787
+
788
+
789
+
790
+
791
+
792
+ /***/ }),
793
+
794
+ /***/ "./src/dom/layout/center-element-in-container.ts":
795
+ /*!*******************************************************!*\
796
+ !*** ./src/dom/layout/center-element-in-container.ts ***!
797
+ \*******************************************************/
798
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
799
+
800
+ __webpack_require__.r(__webpack_exports__);
801
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
802
+ /* harmony export */ centerElementInContainer: () => (/* binding */ centerElementInContainer)
803
+ /* harmony export */ });
804
+ /* harmony import */ var _overflow__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./overflow */ "./src/dom/layout/overflow.ts");
805
+ /* harmony import */ var _geometry__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../geometry */ "./src/geometry/index.ts");
806
+
807
+
589
808
  /**
590
- * Collects all focusable descendant elements within a container.
591
- *
592
- * The function queries *all* elements under the container and filters them
593
- * using `isHtmlElementFocusable`, producing a reliable list of elements
594
- * that can receive keyboard focus in real-world browser conditions.
595
- *
596
- * @param container - The root container whose focusable children will be found.
597
- *
598
- * @returns An array of focusable HTMLElements in DOM order.
599
- */
600
- const getFocusableHtmlElements = (container) => Array.from(container.querySelectorAll('*')).filter(isHtmlElementFocusable);
601
- /**
602
- * Moves focus to the next or previous focusable element within a container.
809
+ * Translates a container so that a target element is visually centered within its visible bounds.
603
810
  *
604
- * This utility is commonly used to implement accessible keyboard navigation patterns such as:
605
- * - roving tabindex
606
- * - custom dropdowns
607
- * - tablists
608
- * - menus
609
- * - horizontal or vertical navigation groups
811
+ * Centering is achieved by applying a CSS `transform: translate(...)` to the
812
+ * container element rather than using native scrolling.
610
813
  *
611
- * Focus movement is scoped to a container and operates on the list of
612
- * focusable descendants returned by `getFocusableHtmlElements`.
814
+ * ### Behavior
815
+ * - Centering is calculated independently for each enabled axis.
816
+ * - Translation is applied only when the container content overflows on that axis.
817
+ * - When no overflow exists, the container remains untransformed for that axis.
613
818
  *
614
- * @param direction - Direction in which focus should move (`'next'` or `'previous'`).
615
- * @param container - Optional container that defines the focus scope.
616
- * If omitted, the parent element of the currently focused element is used.
617
- * @param options - Optional configuration controlling wrapping behavior and custom index resolution.
819
+ * ### Notes
820
+ * - This function performs immediate DOM reads and writes.
821
+ * - The resulting transform is clamped to valid scrollable bounds.
618
822
  *
619
- * @remarks
620
- * - This function reads from and mutates the document's focus state.
621
- * - If no active element exists, no container can be resolved,
622
- * or the active element is not part of the focusable set, no action is taken.
623
- * - When `getNextIndex` is provided, it fully overrides the default wrapping and directional logic.
823
+ * @param containerElement - The container whose content is translated.
824
+ * @param elementToCenter - The descendant element to align to the container’s center.
825
+ * @param options - Optional configuration controlling which axis or axes are centered.
624
826
  */
625
- const moveFocusWithinContainer = (direction, container = null, { wrap = true, getNextIndex } = {}) => {
626
- const activeElement = document.activeElement;
627
- const scope = container ?? activeElement?.parentElement;
628
- if (!activeElement || !scope) {
629
- return;
630
- }
631
- const focusableElements = getFocusableHtmlElements(scope);
632
- if (focusableElements.length === 0) {
633
- return;
634
- }
635
- const currentIndex = focusableElements.indexOf(activeElement);
636
- if (currentIndex === -1) {
637
- return;
638
- }
639
- let nextIndex;
640
- if (getNextIndex) {
641
- nextIndex = getNextIndex(currentIndex, direction, focusableElements);
642
- }
643
- else {
644
- if (direction === 'next') {
645
- nextIndex = currentIndex + 1;
646
- if (nextIndex >= focusableElements.length) {
647
- nextIndex = wrap ? 0 : null;
648
- }
649
- }
650
- else {
651
- nextIndex = currentIndex - 1;
652
- if (nextIndex < 0) {
653
- nextIndex = wrap ? focusableElements.length - 1 : null;
654
- }
655
- }
827
+ const centerElementInContainer = (containerElement, elementToCenter, { axis = 'both' } = {}) => {
828
+ let translateX = 0;
829
+ let translateY = 0;
830
+ if (axis === 'x' || axis === 'both') {
831
+ translateX = (0,_geometry__WEBPACK_IMPORTED_MODULE_1__.calculateCenterOffset)({
832
+ overflowSize: (0,_overflow__WEBPACK_IMPORTED_MODULE_0__.getXOverflowWidth)(containerElement),
833
+ containerSize: containerElement.clientWidth,
834
+ elementOffset: elementToCenter.offsetLeft,
835
+ elementSize: elementToCenter.clientWidth,
836
+ });
656
837
  }
657
- if (nextIndex === null) {
658
- return;
838
+ if (axis === 'y' || axis === 'both') {
839
+ translateY = (0,_geometry__WEBPACK_IMPORTED_MODULE_1__.calculateCenterOffset)({
840
+ overflowSize: (0,_overflow__WEBPACK_IMPORTED_MODULE_0__.getYOverflowHeight)(containerElement),
841
+ containerSize: containerElement.clientHeight,
842
+ elementOffset: elementToCenter.offsetTop,
843
+ elementSize: elementToCenter.clientHeight,
844
+ });
659
845
  }
660
- focusableElements[nextIndex]?.focus();
846
+ containerElement.style.transform = `translate(${translateX}px, ${translateY}px)`;
661
847
  };
848
+
849
+
850
+ /***/ }),
851
+
852
+ /***/ "./src/dom/layout/index.ts":
853
+ /*!*********************************!*\
854
+ !*** ./src/dom/layout/index.ts ***!
855
+ \*********************************/
856
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
857
+
858
+ __webpack_require__.r(__webpack_exports__);
859
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
860
+ /* harmony export */ centerElementInContainer: () => (/* reexport safe */ _center_element_in_container__WEBPACK_IMPORTED_MODULE_1__.centerElementInContainer),
861
+ /* harmony export */ getXOverflowWidth: () => (/* reexport safe */ _overflow__WEBPACK_IMPORTED_MODULE_0__.getXOverflowWidth),
862
+ /* harmony export */ getYOverflowHeight: () => (/* reexport safe */ _overflow__WEBPACK_IMPORTED_MODULE_0__.getYOverflowHeight),
863
+ /* harmony export */ hasXOverflow: () => (/* reexport safe */ _overflow__WEBPACK_IMPORTED_MODULE_0__.hasXOverflow),
864
+ /* harmony export */ hasYOverflow: () => (/* reexport safe */ _overflow__WEBPACK_IMPORTED_MODULE_0__.hasYOverflow)
865
+ /* harmony export */ });
866
+ /* harmony import */ var _overflow__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./overflow */ "./src/dom/layout/overflow.ts");
867
+ /* harmony import */ var _center_element_in_container__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./center-element-in-container */ "./src/dom/layout/center-element-in-container.ts");
868
+
869
+
870
+
871
+
872
+ /***/ }),
873
+
874
+ /***/ "./src/dom/layout/overflow.ts":
875
+ /*!************************************!*\
876
+ !*** ./src/dom/layout/overflow.ts ***!
877
+ \************************************/
878
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
879
+
880
+ __webpack_require__.r(__webpack_exports__);
881
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
882
+ /* harmony export */ getXOverflowWidth: () => (/* binding */ getXOverflowWidth),
883
+ /* harmony export */ getYOverflowHeight: () => (/* binding */ getYOverflowHeight),
884
+ /* harmony export */ hasXOverflow: () => (/* binding */ hasXOverflow),
885
+ /* harmony export */ hasYOverflow: () => (/* binding */ hasYOverflow)
886
+ /* harmony export */ });
662
887
  /**
663
888
  * Checks whether an element has horizontal overflow.
664
889
  *
@@ -697,66 +922,126 @@ const hasYOverflow = (element) => element.scrollHeight > element.clientHeight;
697
922
  * @returns The overflow height in pixels. Returns `0` when the content does not overflow vertically.
698
923
  */
699
924
  const getYOverflowHeight = (element) => Math.max(0, element.scrollHeight - element.clientHeight);
925
+
926
+
927
+ /***/ }),
928
+
929
+ /***/ "./src/dom/transform/index.ts":
930
+ /*!************************************!*\
931
+ !*** ./src/dom/transform/index.ts ***!
932
+ \************************************/
933
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
934
+
935
+ __webpack_require__.r(__webpack_exports__);
936
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
937
+ /* harmony export */ parse2DMatrix: () => (/* reexport safe */ _parse_2d_matrix__WEBPACK_IMPORTED_MODULE_0__.parse2DMatrix)
938
+ /* harmony export */ });
939
+ /* harmony import */ var _parse_2d_matrix__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./parse-2d-matrix */ "./src/dom/transform/parse-2d-matrix.ts");
940
+
941
+
942
+
943
+ /***/ }),
944
+
945
+ /***/ "./src/dom/transform/parse-2d-matrix.ts":
946
+ /*!**********************************************!*\
947
+ !*** ./src/dom/transform/parse-2d-matrix.ts ***!
948
+ \**********************************************/
949
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
950
+
951
+ __webpack_require__.r(__webpack_exports__);
952
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
953
+ /* harmony export */ parse2DMatrix: () => (/* binding */ parse2DMatrix)
954
+ /* harmony export */ });
700
955
  /**
701
- * Calculates the offset required to center an element within a container along a single axis.
702
- *
703
- * The returned value is clamped so that the resulting translation does not
704
- * exceed the container's scrollable bounds.
705
- *
706
- * This function performs pure math only and does not access the DOM.
707
- *
708
- * @returns A negative offset value suitable for use in a CSS `translate`
709
- * transform, or `0` when no overflow exists on the axis.
710
- */
711
- const calculateCenterOffset = ({ overflowSize, containerSize, elementOffset, elementSize, }) => {
712
- if (overflowSize <= 0) {
713
- return 0;
714
- }
715
- const containerCenter = containerSize / 2;
716
- const elementCenter = elementOffset + elementSize / 2;
717
- const targetOffset = elementCenter - containerCenter;
718
- return -Math.max(0, Math.min(targetOffset, overflowSize));
719
- };
720
- /**
721
- * Translates a container so that a target element is visually centered within its visible bounds.
722
- *
723
- * Centering is achieved by applying a CSS `transform: translate(...)` to the
724
- * container element rather than using native scrolling.
956
+ * Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element.
725
957
  *
726
- * ### Behavior
727
- * - Centering is calculated independently for each enabled axis.
728
- * - Translation is applied only when the container content overflows on that axis.
729
- * - When no overflow exists, the container remains untransformed for that axis.
958
+ * Only works with 2D transforms (i.e., `matrix(a, b, c, d, e, f)`).
730
959
  *
731
- * ### Notes
732
- * - This function performs immediate DOM reads and writes.
733
- * - The resulting transform is clamped to valid scrollable bounds.
960
+ * @param element - The element with a CSS transform applied.
961
+ * @returns An object with parsed transformation values.
734
962
  *
735
- * @param containerElement - The container whose content is translated.
736
- * @param elementToCenter - The descendant element to align to the container’s center.
737
- * @param options - Optional configuration controlling which axis or axes are centered.
963
+ * @example
964
+ * ```ts
965
+ * const values = parse2DMatrix(myElement);
966
+ * console.log(values.translateX);
967
+ * console.log(values.scaleX);
968
+ * ```
738
969
  */
739
- const centerElementInContainer = (containerElement, elementToCenter, { axis = 'both' } = {}) => {
740
- let translateX = 0;
741
- let translateY = 0;
742
- if (axis === 'x' || axis === 'both') {
743
- translateX = calculateCenterOffset({
744
- overflowSize: getXOverflowWidth(containerElement),
745
- containerSize: containerElement.clientWidth,
746
- elementOffset: elementToCenter.offsetLeft,
747
- elementSize: elementToCenter.clientWidth,
748
- });
749
- }
750
- if (axis === 'y' || axis === 'both') {
751
- translateY = calculateCenterOffset({
752
- overflowSize: getYOverflowHeight(containerElement),
753
- containerSize: containerElement.clientHeight,
754
- elementOffset: elementToCenter.offsetTop,
755
- elementSize: elementToCenter.clientHeight,
756
- });
970
+ const parse2DMatrix = (element) => {
971
+ const computedStyles = window.getComputedStyle(element);
972
+ const transformValue = computedStyles.getPropertyValue('transform');
973
+ const matrixMatch = transformValue.match(/^matrix\((.+)\)$/);
974
+ if (!matrixMatch) {
975
+ return {
976
+ translateX: 0,
977
+ translateY: 0,
978
+ scaleX: 1,
979
+ scaleY: 1,
980
+ skewX: 0,
981
+ skewY: 0,
982
+ };
757
983
  }
758
- containerElement.style.transform = `translate(${translateX}px, ${translateY}px)`;
984
+ const [scaleX, skewY, skewX, scaleY, translateX, translateY] = matrixMatch[1]
985
+ .split(', ')
986
+ .map(parseFloat);
987
+ return {
988
+ translateX,
989
+ translateY,
990
+ scaleX,
991
+ scaleY,
992
+ skewX,
993
+ skewY,
994
+ };
759
995
  };
996
+
997
+
998
+ /***/ }),
999
+
1000
+ /***/ "./src/env/index.ts":
1001
+ /*!**************************!*\
1002
+ !*** ./src/env/index.ts ***!
1003
+ \**************************/
1004
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1005
+
1006
+ __webpack_require__.r(__webpack_exports__);
1007
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1008
+ /* harmony export */ getLocalStorageCapabilities: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.getLocalStorageCapabilities),
1009
+ /* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _storage__WEBPACK_IMPORTED_MODULE_0__.isLocalStorageReadable)
1010
+ /* harmony export */ });
1011
+ /* harmony import */ var _storage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./storage */ "./src/env/storage/index.ts");
1012
+
1013
+
1014
+
1015
+ /***/ }),
1016
+
1017
+ /***/ "./src/env/storage/index.ts":
1018
+ /*!**********************************!*\
1019
+ !*** ./src/env/storage/index.ts ***!
1020
+ \**********************************/
1021
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1022
+
1023
+ __webpack_require__.r(__webpack_exports__);
1024
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1025
+ /* harmony export */ getLocalStorageCapabilities: () => (/* reexport safe */ _local_storage__WEBPACK_IMPORTED_MODULE_0__.getLocalStorageCapabilities),
1026
+ /* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _local_storage__WEBPACK_IMPORTED_MODULE_0__.isLocalStorageReadable)
1027
+ /* harmony export */ });
1028
+ /* harmony import */ var _local_storage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./local-storage */ "./src/env/storage/local-storage.ts");
1029
+
1030
+
1031
+
1032
+ /***/ }),
1033
+
1034
+ /***/ "./src/env/storage/local-storage.ts":
1035
+ /*!******************************************!*\
1036
+ !*** ./src/env/storage/local-storage.ts ***!
1037
+ \******************************************/
1038
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1039
+
1040
+ __webpack_require__.r(__webpack_exports__);
1041
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1042
+ /* harmony export */ getLocalStorageCapabilities: () => (/* binding */ getLocalStorageCapabilities),
1043
+ /* harmony export */ isLocalStorageReadable: () => (/* binding */ isLocalStorageReadable)
1044
+ /* harmony export */ });
760
1045
  /**
761
1046
  * Determines whether the browser environment allows safe read access to
762
1047
  * `localStorage`. Some platforms (e.g., Safari Private Mode, sandboxed iframes)
@@ -823,56 +1108,6 @@ const getLocalStorageCapabilities = () => {
823
1108
  writable: false,
824
1109
  };
825
1110
  };
826
- /**
827
- * Initiates a file download in a browser environment.
828
- *
829
- * This utility supports downloading from:
830
- * - a URL string
831
- * - a `Blob`
832
- * - a `MediaSource`
833
- *
834
- * For non-string inputs, an object URL is created temporarily and
835
- * automatically revoked after the download is triggered.
836
- *
837
- * @remarks
838
- * - This function performs direct DOM manipulation and must be executed in a browser environment.
839
- * - In non-DOM contexts (e.g. SSR), the function exits without side effects.
840
- * - Object URLs are revoked asynchronously to avoid Safari-related issues.
841
- *
842
- * @param file - The file source to download (URL string or binary object).
843
- * @param options - Optional configuration controlling filename and link target.
844
- */
845
- const downloadFile = (file, { fileName, target } = {}) => {
846
- // Browser guard (SSR / non-DOM environments)
847
- if ((0,_guards__WEBPACK_IMPORTED_MODULE_0__.isUndefined)(document)) {
848
- return;
849
- }
850
- const link = document.createElement('a');
851
- let objectUrl = null;
852
- try {
853
- const href = (0,_string__WEBPACK_IMPORTED_MODULE_1__.isString)(file) ? file : (objectUrl = URL.createObjectURL(file));
854
- link.href = href;
855
- if (fileName) {
856
- link.download = fileName;
857
- }
858
- if (target) {
859
- link.target = target;
860
- }
861
- // Required for Firefox / Safari
862
- document.body.appendChild(link);
863
- link.click();
864
- }
865
- finally {
866
- link.remove();
867
- if (objectUrl) {
868
- // Delay revocation to avoid Safari issues
869
- setTimeout(() => {
870
- (0,_guards__WEBPACK_IMPORTED_MODULE_0__.assert)(objectUrl, 'Object URL should not be null');
871
- URL.revokeObjectURL(objectUrl);
872
- }, 0);
873
- }
874
- }
875
- };
876
1111
 
877
1112
 
878
1113
  /***/ }),
@@ -1294,6 +1529,72 @@ const once = (fn) => {
1294
1529
  };
1295
1530
 
1296
1531
 
1532
+ /***/ }),
1533
+
1534
+ /***/ "./src/geometry/index.ts":
1535
+ /*!*******************************!*\
1536
+ !*** ./src/geometry/index.ts ***!
1537
+ \*******************************/
1538
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1539
+
1540
+ __webpack_require__.r(__webpack_exports__);
1541
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1542
+ /* harmony export */ calculateCenterOffset: () => (/* reexport safe */ _layout__WEBPACK_IMPORTED_MODULE_0__.calculateCenterOffset)
1543
+ /* harmony export */ });
1544
+ /* harmony import */ var _layout__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./layout */ "./src/geometry/layout/index.ts");
1545
+
1546
+
1547
+
1548
+ /***/ }),
1549
+
1550
+ /***/ "./src/geometry/layout/calculate-center-offset.ts":
1551
+ /*!********************************************************!*\
1552
+ !*** ./src/geometry/layout/calculate-center-offset.ts ***!
1553
+ \********************************************************/
1554
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1555
+
1556
+ __webpack_require__.r(__webpack_exports__);
1557
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1558
+ /* harmony export */ calculateCenterOffset: () => (/* binding */ calculateCenterOffset)
1559
+ /* harmony export */ });
1560
+ /**
1561
+ * Calculates the offset required to center an element within a container along a single axis.
1562
+ *
1563
+ * The returned value is clamped so that the resulting translation does not
1564
+ * exceed the container's scrollable bounds.
1565
+ *
1566
+ * This function performs pure math only and does not access the DOM.
1567
+ *
1568
+ * @returns A negative offset value suitable for use in a CSS `translate`
1569
+ * transform, or `0` when no overflow exists on the axis.
1570
+ */
1571
+ const calculateCenterOffset = ({ overflowSize, containerSize, elementOffset, elementSize, }) => {
1572
+ if (overflowSize <= 0) {
1573
+ return 0;
1574
+ }
1575
+ const containerCenter = containerSize / 2;
1576
+ const elementCenter = elementOffset + elementSize / 2;
1577
+ const targetOffset = elementCenter - containerCenter;
1578
+ return -Math.max(0, Math.min(targetOffset, overflowSize));
1579
+ };
1580
+
1581
+
1582
+ /***/ }),
1583
+
1584
+ /***/ "./src/geometry/layout/index.ts":
1585
+ /*!**************************************!*\
1586
+ !*** ./src/geometry/layout/index.ts ***!
1587
+ \**************************************/
1588
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1589
+
1590
+ __webpack_require__.r(__webpack_exports__);
1591
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1592
+ /* harmony export */ calculateCenterOffset: () => (/* reexport safe */ _calculate_center_offset__WEBPACK_IMPORTED_MODULE_0__.calculateCenterOffset)
1593
+ /* harmony export */ });
1594
+ /* harmony import */ var _calculate_center_offset__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./calculate-center-offset */ "./src/geometry/layout/calculate-center-offset.ts");
1595
+
1596
+
1597
+
1297
1598
  /***/ }),
1298
1599
 
1299
1600
  /***/ "./src/guards.ts":
@@ -1536,6 +1837,120 @@ const isInteger = (value) => isNumber(value) && Number.isInteger(value);
1536
1837
  const isDecimal = (value) => isFiniteNumber(value) && !Number.isInteger(value);
1537
1838
 
1538
1839
 
1840
+ /***/ }),
1841
+
1842
+ /***/ "./src/intersection/get-dom-rect-intersection-ratio.ts":
1843
+ /*!*************************************************************!*\
1844
+ !*** ./src/intersection/get-dom-rect-intersection-ratio.ts ***!
1845
+ \*************************************************************/
1846
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1847
+
1848
+ __webpack_require__.r(__webpack_exports__);
1849
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1850
+ /* harmony export */ getDOMRectIntersectionRatio: () => (/* binding */ getDOMRectIntersectionRatio)
1851
+ /* harmony export */ });
1852
+ /**
1853
+ * Calculates the intersection ratio between two DOM rectangles.
1854
+ *
1855
+ * The ratio represents the proportion of the `targetRect` that is covered by `sourceRect`.
1856
+ * A value of `1` means `sourceRect` completely covers `targetRect`, and `0` means no overlap.
1857
+ *
1858
+ * @param sourceRect - The rectangle used to measure overlap against the target.
1859
+ * @param targetRect - The rectangle whose covered area is measured.
1860
+ *
1861
+ * @returns A number between `0` and `1` representing the intersection ratio.
1862
+ */
1863
+ const getDOMRectIntersectionRatio = (sourceRect, targetRect) => {
1864
+ const xOverlap = Math.max(0, Math.min(sourceRect.right, targetRect.right) - Math.max(sourceRect.left, targetRect.left));
1865
+ const yOverlap = Math.max(0, Math.min(sourceRect.bottom, targetRect.bottom) - Math.max(sourceRect.top, targetRect.top));
1866
+ const intersectionArea = xOverlap * yOverlap;
1867
+ const targetArea = targetRect.width * targetRect.height;
1868
+ return intersectionArea / targetArea;
1869
+ };
1870
+
1871
+
1872
+ /***/ }),
1873
+
1874
+ /***/ "./src/intersection/index.ts":
1875
+ /*!***********************************!*\
1876
+ !*** ./src/intersection/index.ts ***!
1877
+ \***********************************/
1878
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1879
+
1880
+ __webpack_require__.r(__webpack_exports__);
1881
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1882
+ /* harmony export */ getDOMRectIntersectionRatio: () => (/* reexport safe */ _get_dom_rect_intersection_ratio__WEBPACK_IMPORTED_MODULE_0__.getDOMRectIntersectionRatio),
1883
+ /* harmony export */ resolveAxisDelta: () => (/* reexport safe */ _resolve_axis_delta__WEBPACK_IMPORTED_MODULE_1__.resolveAxisDelta)
1884
+ /* harmony export */ });
1885
+ /* harmony import */ var _get_dom_rect_intersection_ratio__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./get-dom-rect-intersection-ratio */ "./src/intersection/get-dom-rect-intersection-ratio.ts");
1886
+ /* harmony import */ var _resolve_axis_delta__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./resolve-axis-delta */ "./src/intersection/resolve-axis-delta.ts");
1887
+
1888
+
1889
+
1890
+
1891
+ /***/ }),
1892
+
1893
+ /***/ "./src/intersection/resolve-axis-delta.ts":
1894
+ /*!************************************************!*\
1895
+ !*** ./src/intersection/resolve-axis-delta.ts ***!
1896
+ \************************************************/
1897
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
1898
+
1899
+ __webpack_require__.r(__webpack_exports__);
1900
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1901
+ /* harmony export */ resolveAxisDelta: () => (/* binding */ resolveAxisDelta)
1902
+ /* harmony export */ });
1903
+ /**
1904
+ * Resolves a raw two-dimensional input delta into an axis-aligned delta
1905
+ * according to the specified axis and resolution rules.
1906
+ *
1907
+ * This function is input-agnostic and does not perform any DOM mutations.
1908
+ * It is intended to be used as a normalization step for wheel, drag,
1909
+ * touch, or other pointer-based input before applying scroll physics.
1910
+ *
1911
+ * ### Resolution rules
1912
+ * - `'x'`:
1913
+ * - Uses horizontal input when available.
1914
+ * - Optionally falls back to vertical input when horizontal input is zero.
1915
+ * - `'y'`:
1916
+ * - Uses vertical input only.
1917
+ * - `'both'`:
1918
+ * - Preserves both horizontal and vertical input.
1919
+ *
1920
+ * ### Direction handling
1921
+ * - When `invert` is enabled, the resolved delta direction is inverted
1922
+ * to match typical synthetic scrolling behavior.
1923
+ *
1924
+ * @param delta - Raw input movement delta.
1925
+ * @param axis - Axis along which movement should be resolved.
1926
+ * @param options - Resolution behavior configuration.
1927
+ *
1928
+ * @returns A normalized, axis-aligned delta suitable for further scroll or movement processing.
1929
+ */
1930
+ const resolveAxisDelta = (delta, axis, { allowFallback = true, invert = true } = {}) => {
1931
+ const sign = invert ? -1 : 1;
1932
+ switch (axis) {
1933
+ case 'x': {
1934
+ const value = delta.deltaX !== 0 ? delta.deltaX : allowFallback ? delta.deltaY : 0;
1935
+ return {
1936
+ deltaX: sign * value,
1937
+ deltaY: 0,
1938
+ };
1939
+ }
1940
+ case 'y':
1941
+ return {
1942
+ deltaX: 0,
1943
+ deltaY: sign * delta.deltaY,
1944
+ };
1945
+ default:
1946
+ return {
1947
+ deltaX: sign * delta.deltaX,
1948
+ deltaY: sign * delta.deltaY,
1949
+ };
1950
+ }
1951
+ };
1952
+
1953
+
1539
1954
  /***/ }),
1540
1955
 
1541
1956
  /***/ "./src/math.ts":
@@ -1834,10 +2249,10 @@ var __webpack_exports__ = {};
1834
2249
  \**********************/
1835
2250
  __webpack_require__.r(__webpack_exports__);
1836
2251
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
1837
- /* harmony export */ FOCUSABLE_HTML_TAGS: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.FOCUSABLE_HTML_TAGS),
2252
+ /* harmony export */ FOCUSABLE_HTML_TAGS: () => (/* reexport safe */ _a11y__WEBPACK_IMPORTED_MODULE_11__.FOCUSABLE_HTML_TAGS),
1838
2253
  /* harmony export */ assert: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.assert),
1839
2254
  /* harmony export */ blobToFile: () => (/* reexport safe */ _file__WEBPACK_IMPORTED_MODULE_7__.blobToFile),
1840
- /* harmony export */ calculateCenterOffset: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.calculateCenterOffset),
2255
+ /* harmony export */ calculateCenterOffset: () => (/* reexport safe */ _geometry__WEBPACK_IMPORTED_MODULE_9__.calculateCenterOffset),
1841
2256
  /* harmony export */ calculateEuclideanDistance: () => (/* reexport safe */ _math__WEBPACK_IMPORTED_MODULE_5__.calculateEuclideanDistance),
1842
2257
  /* harmony export */ calculateMovingSpeed: () => (/* reexport safe */ _math__WEBPACK_IMPORTED_MODULE_5__.calculateMovingSpeed),
1843
2258
  /* harmony export */ calculatePercentage: () => (/* reexport safe */ _math__WEBPACK_IMPORTED_MODULE_5__.calculatePercentage),
@@ -1857,10 +2272,10 @@ __webpack_require__.r(__webpack_exports__);
1857
2272
  /* harmony export */ filterParallel: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_0__.filterParallel),
1858
2273
  /* harmony export */ filterSequential: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_0__.filterSequential),
1859
2274
  /* harmony export */ findAsync: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_0__.findAsync),
1860
- /* harmony export */ getDOMRectIntersectionRatio: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.getDOMRectIntersectionRatio),
2275
+ /* harmony export */ getDOMRectIntersectionRatio: () => (/* reexport safe */ _intersection__WEBPACK_IMPORTED_MODULE_10__.getDOMRectIntersectionRatio),
1861
2276
  /* harmony export */ getElementOffsetRect: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.getElementOffsetRect),
1862
- /* harmony export */ getFocusableHtmlElements: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.getFocusableHtmlElements),
1863
- /* harmony export */ getLocalStorageCapabilities: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.getLocalStorageCapabilities),
2277
+ /* harmony export */ getFocusableHtmlElements: () => (/* reexport safe */ _a11y__WEBPACK_IMPORTED_MODULE_11__.getFocusableHtmlElements),
2278
+ /* harmony export */ getLocalStorageCapabilities: () => (/* reexport safe */ _env__WEBPACK_IMPORTED_MODULE_12__.getLocalStorageCapabilities),
1864
2279
  /* harmony export */ getXOverflowWidth: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.getXOverflowWidth),
1865
2280
  /* harmony export */ getYOverflowHeight: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.getYOverflowHeight),
1866
2281
  /* harmony export */ hasXOverflow: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.hasXOverflow),
@@ -1882,9 +2297,9 @@ __webpack_require__.r(__webpack_exports__);
1882
2297
  /* harmony export */ isFile: () => (/* reexport safe */ _file__WEBPACK_IMPORTED_MODULE_7__.isFile),
1883
2298
  /* harmony export */ isFiniteNumber: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isFiniteNumber),
1884
2299
  /* harmony export */ isFunction: () => (/* reexport safe */ _function__WEBPACK_IMPORTED_MODULE_3__.isFunction),
1885
- /* harmony export */ isHtmlElementFocusable: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.isHtmlElementFocusable),
2300
+ /* harmony export */ isHtmlElementFocusable: () => (/* reexport safe */ _a11y__WEBPACK_IMPORTED_MODULE_11__.isHtmlElementFocusable),
1886
2301
  /* harmony export */ isInteger: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isInteger),
1887
- /* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.isLocalStorageReadable),
2302
+ /* harmony export */ isLocalStorageReadable: () => (/* reexport safe */ _env__WEBPACK_IMPORTED_MODULE_12__.isLocalStorageReadable),
1888
2303
  /* harmony export */ isMap: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isMap),
1889
2304
  /* harmony export */ isNil: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isNil),
1890
2305
  /* harmony export */ isNilOrEmptyString: () => (/* reexport safe */ _string__WEBPACK_IMPORTED_MODULE_1__.isNilOrEmptyString),
@@ -1898,7 +2313,7 @@ __webpack_require__.r(__webpack_exports__);
1898
2313
  /* harmony export */ isSymbol: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isSymbol),
1899
2314
  /* harmony export */ isUndefined: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isUndefined),
1900
2315
  /* harmony export */ isValidDate: () => (/* reexport safe */ _guards__WEBPACK_IMPORTED_MODULE_4__.isValidDate),
1901
- /* harmony export */ moveFocusWithinContainer: () => (/* reexport safe */ _dom__WEBPACK_IMPORTED_MODULE_6__.moveFocusWithinContainer),
2316
+ /* harmony export */ moveFocusWithinContainer: () => (/* reexport safe */ _a11y__WEBPACK_IMPORTED_MODULE_11__.moveFocusWithinContainer),
1902
2317
  /* harmony export */ noop: () => (/* reexport safe */ _function__WEBPACK_IMPORTED_MODULE_3__.noop),
1903
2318
  /* harmony export */ not: () => (/* reexport safe */ _function__WEBPACK_IMPORTED_MODULE_3__.not),
1904
2319
  /* harmony export */ once: () => (/* reexport safe */ _function__WEBPACK_IMPORTED_MODULE_3__.once),
@@ -1907,6 +2322,7 @@ __webpack_require__.r(__webpack_exports__);
1907
2322
  /* harmony export */ pipe: () => (/* reexport safe */ _array__WEBPACK_IMPORTED_MODULE_2__.pipe),
1908
2323
  /* harmony export */ readFilesFromDataTransfer: () => (/* reexport safe */ _file__WEBPACK_IMPORTED_MODULE_7__.readFilesFromDataTransfer),
1909
2324
  /* harmony export */ reduceAsync: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_0__.reduceAsync),
2325
+ /* harmony export */ resolveAxisDelta: () => (/* reexport safe */ _intersection__WEBPACK_IMPORTED_MODULE_10__.resolveAxisDelta),
1910
2326
  /* harmony export */ retry: () => (/* reexport safe */ _function__WEBPACK_IMPORTED_MODULE_3__.retry),
1911
2327
  /* harmony export */ runParallel: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_0__.runParallel),
1912
2328
  /* harmony export */ runSequential: () => (/* reexport safe */ _async__WEBPACK_IMPORTED_MODULE_0__.runSequential),
@@ -1923,9 +2339,17 @@ __webpack_require__.r(__webpack_exports__);
1923
2339
  /* harmony import */ var _function__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./function */ "./src/function.ts");
1924
2340
  /* harmony import */ var _guards__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./guards */ "./src/guards.ts");
1925
2341
  /* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./math */ "./src/math.ts");
1926
- /* harmony import */ var _dom__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./dom */ "./src/dom.ts");
2342
+ /* harmony import */ var _dom__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./dom */ "./src/dom/index.ts");
1927
2343
  /* harmony import */ var _file__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./file */ "./src/file.ts");
1928
2344
  /* harmony import */ var _object__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./object */ "./src/object.ts");
2345
+ /* harmony import */ var _geometry__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./geometry */ "./src/geometry/index.ts");
2346
+ /* harmony import */ var _intersection__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./intersection */ "./src/intersection/index.ts");
2347
+ /* harmony import */ var _a11y__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./a11y */ "./src/a11y/index.ts");
2348
+ /* harmony import */ var _env__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./env */ "./src/env/index.ts");
2349
+
2350
+
2351
+
2352
+
1929
2353
 
1930
2354
 
1931
2355