arrowtab 0.0.4 → 0.1.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 +129 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/caret.d.ts +5 -0
- package/dist/lib/caret.js +136 -0
- package/dist/lib/caret.js.map +1 -0
- package/dist/lib/changesValueOnArrowKeys.d.ts +3 -0
- package/dist/lib/changesValueOnArrowKeys.js +15 -0
- package/dist/lib/changesValueOnArrowKeys.js.map +1 -0
- package/dist/lib/debugMode.d.ts +5 -5
- package/dist/lib/debugMode.js +28 -32
- package/dist/lib/debugMode.js.map +1 -1
- package/dist/lib/directions.d.ts +13 -0
- package/dist/lib/directions.js +17 -0
- package/dist/lib/directions.js.map +1 -0
- package/dist/lib/dom.d.ts +16 -0
- package/dist/lib/dom.js +62 -0
- package/dist/lib/dom.js.map +1 -0
- package/dist/lib/focusHistory.d.ts +11 -0
- package/dist/lib/focusHistory.js +72 -0
- package/dist/lib/focusHistory.js.map +1 -0
- package/dist/lib/focusTracker.d.ts +12 -0
- package/dist/lib/focusTracker.js +43 -0
- package/dist/lib/focusTracker.js.map +1 -0
- package/dist/lib/focusable.d.ts +8 -0
- package/dist/lib/focusable.js +135 -0
- package/dist/lib/focusable.js.map +1 -0
- package/dist/lib/geometry.d.ts +35 -0
- package/dist/lib/geometry.js +70 -0
- package/dist/lib/geometry.js.map +1 -0
- package/dist/lib/hasDisabledKeys.d.ts +4 -3
- package/dist/lib/hasDisabledKeys.js +5 -25
- package/dist/lib/hasDisabledKeys.js.map +1 -1
- package/dist/lib/initArrowTab.d.ts +12 -2
- package/dist/lib/initArrowTab.js +133 -70
- package/dist/lib/initArrowTab.js.map +1 -1
- package/dist/lib/initArrowTab.test.d.ts +1 -0
- package/dist/lib/initArrowTab.test.js +689 -0
- package/dist/lib/initArrowTab.test.js.map +1 -0
- package/dist/lib/navigateEvent.d.ts +16 -0
- package/dist/lib/navigateEvent.js +9 -0
- package/dist/lib/navigateEvent.js.map +1 -0
- package/dist/lib/rankCandidates.d.ts +11 -0
- package/dist/lib/rankCandidates.js +31 -0
- package/dist/lib/rankCandidates.js.map +1 -0
- package/dist/lib/scope.d.ts +11 -0
- package/dist/lib/scope.js +60 -0
- package/dist/lib/scope.js.map +1 -0
- package/dist/lib/strategies.d.ts +21 -10
- package/dist/lib/strategies.js +63 -106
- package/dist/lib/strategies.js.map +1 -1
- package/dist/lib/strategies.test.d.ts +1 -0
- package/dist/lib/strategies.test.js +88 -0
- package/dist/lib/strategies.test.js.map +1 -0
- package/dist/lib/widgets.d.ts +5 -0
- package/dist/lib/widgets.js +50 -0
- package/dist/lib/widgets.js.map +1 -0
- package/dist/lib/wrap.d.ts +12 -0
- package/dist/lib/wrap.js +21 -0
- package/dist/lib/wrap.js.map +1 -0
- package/package.json +2 -1
- package/dist/lib/distances.d.ts +0 -13
- package/dist/lib/distances.js +0 -15
- package/dist/lib/distances.js.map +0 -1
- package/dist/lib/getAngle.d.ts +0 -4
- package/dist/lib/getAngle.js +0 -15
- package/dist/lib/getAngle.js.map +0 -1
- package/dist/lib/getFocusable.d.ts +0 -1
- package/dist/lib/getFocusable.js +0 -29
- package/dist/lib/getFocusable.js.map +0 -1
- package/dist/lib/getXyDistance.d.ts +0 -7
- package/dist/lib/getXyDistance.js +0 -12
- package/dist/lib/getXyDistance.js.map +0 -1
- package/dist/lib/hasTextSelection.d.ts +0 -4
- package/dist/lib/hasTextSelection.js +0 -53
- package/dist/lib/hasTextSelection.js.map +0 -1
- package/dist/lib/positions.d.ts +0 -8
- package/dist/lib/positions.js +0 -16
- package/dist/lib/positions.js.map +0 -1
- package/dist/lib/preventNativeArrowKeyPresses.d.ts +0 -4
- package/dist/lib/preventNativeArrowKeyPresses.js +0 -24
- package/dist/lib/preventNativeArrowKeyPresses.js.map +0 -1
- package/dist/lib/sumBy.d.ts +0 -1
- package/dist/lib/sumBy.js +0 -2
- package/dist/lib/sumBy.js.map +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const dialogSelector = '[role="dialog"], [role="alertdialog"], dialog';
|
|
2
|
+
const isOpen = ({ dialog }) => dialog.isConnected &&
|
|
3
|
+
!dialog.closest('[hidden]') &&
|
|
4
|
+
(dialog.tagName !== 'DIALOG' || dialog.hasAttribute('open'));
|
|
5
|
+
const isFocusLost = () => {
|
|
6
|
+
const { activeElement } = document;
|
|
7
|
+
return (!activeElement ||
|
|
8
|
+
activeElement === document.body ||
|
|
9
|
+
!activeElement.isConnected);
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Refocuses the element that was focused before a dialog opened, once the dialog closes.
|
|
13
|
+
* Only kicks in if focus got lost, so dialogs restoring focus themselves are left alone.
|
|
14
|
+
*/
|
|
15
|
+
export const startAutoDetectHistory = ({ active, focusTracker, }) => {
|
|
16
|
+
if (!active) {
|
|
17
|
+
return {
|
|
18
|
+
cleanup: () => { },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Ordered by opening time, nested dialogs come last
|
|
22
|
+
let openDialogs = [];
|
|
23
|
+
const trackOpenedDialogs = ({ root }) => {
|
|
24
|
+
const dialogs = [
|
|
25
|
+
...(root.matches(dialogSelector) ? [root] : []),
|
|
26
|
+
...root.querySelectorAll(dialogSelector),
|
|
27
|
+
];
|
|
28
|
+
for (const dialog of dialogs) {
|
|
29
|
+
if (!isOpen({ dialog }))
|
|
30
|
+
continue;
|
|
31
|
+
if (openDialogs.some((entry) => entry.dialog === dialog))
|
|
32
|
+
continue;
|
|
33
|
+
openDialogs.push({
|
|
34
|
+
dialog,
|
|
35
|
+
returnTo: focusTracker.getRecentlyFocused({ outside: dialog }),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const dialogObserver = new MutationObserver((mutationList) => {
|
|
40
|
+
for (const mutation of mutationList) {
|
|
41
|
+
// Dialogs are often rendered inside a portal wrapper, so search the added subtree
|
|
42
|
+
const roots = mutation.type === 'attributes'
|
|
43
|
+
? [mutation.target]
|
|
44
|
+
: [...mutation.addedNodes];
|
|
45
|
+
for (const root of roots) {
|
|
46
|
+
if (root instanceof Element)
|
|
47
|
+
trackOpenedDialogs({ root });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const closed = openDialogs.filter(({ dialog }) => !isOpen({ dialog }));
|
|
51
|
+
if (closed.length === 0)
|
|
52
|
+
return;
|
|
53
|
+
openDialogs = openDialogs.filter((entry) => !closed.includes(entry));
|
|
54
|
+
// If nested dialogs close at once, return to where the outermost one was opened
|
|
55
|
+
const returnTo = closed[0]?.returnTo;
|
|
56
|
+
if (returnTo?.isConnected && isFocusLost()) {
|
|
57
|
+
returnTo.focus();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
dialogObserver.observe(document.body, {
|
|
61
|
+
childList: true,
|
|
62
|
+
subtree: true,
|
|
63
|
+
attributes: true,
|
|
64
|
+
attributeFilter: ['open', 'hidden'],
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
cleanup: () => {
|
|
68
|
+
dialogObserver.disconnect();
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=focusHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focusHistory.js","sourceRoot":"","sources":["../../src/lib/focusHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Rect } from './geometry.js';
|
|
2
|
+
export type FocusTracker = ReturnType<typeof startFocusTracker>;
|
|
3
|
+
export declare const startFocusTracker: ({ root }?: {
|
|
4
|
+
root?: Element;
|
|
5
|
+
}) => {
|
|
6
|
+
getLastRect: () => Rect | undefined;
|
|
7
|
+
isLastInRoot: () => boolean;
|
|
8
|
+
getRecentlyFocused: ({ outside }: {
|
|
9
|
+
outside: Element;
|
|
10
|
+
}) => HTMLElement | undefined;
|
|
11
|
+
cleanup: () => void;
|
|
12
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { containsComposed } from './dom.js';
|
|
2
|
+
import { getRect, isEmptyRect } from './geometry.js';
|
|
3
|
+
const maxEntries = 20;
|
|
4
|
+
// Remembers recently focused elements and where they were, so focus can be restored after it got lost
|
|
5
|
+
export const startFocusTracker = ({ root } = {}) => {
|
|
6
|
+
// isInRoot is stored, because removed elements can't be checked anymore
|
|
7
|
+
let recent = [];
|
|
8
|
+
const onFocusIn = (event) => {
|
|
9
|
+
// The target is retargeted to the shadow host, the composed path starts at the focused element
|
|
10
|
+
const element = event.composedPath()[0];
|
|
11
|
+
if (!(element instanceof HTMLElement))
|
|
12
|
+
return;
|
|
13
|
+
recent = recent.filter((entry) => entry.element !== element);
|
|
14
|
+
recent.push({
|
|
15
|
+
element,
|
|
16
|
+
rect: getRect({ element }),
|
|
17
|
+
isInRoot: !root || containsComposed({ container: root, element }),
|
|
18
|
+
});
|
|
19
|
+
recent = recent.slice(-maxEntries);
|
|
20
|
+
};
|
|
21
|
+
document.addEventListener('focusin', onFocusIn, { capture: true });
|
|
22
|
+
return {
|
|
23
|
+
// Current position of the last focused element, or its last known position if it was removed / hidden
|
|
24
|
+
getLastRect: () => {
|
|
25
|
+
const last = recent.at(-1);
|
|
26
|
+
if (!last)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (!last.element.isConnected)
|
|
29
|
+
return last.rect;
|
|
30
|
+
const rect = getRect({ element: last.element });
|
|
31
|
+
return isEmptyRect({ rect }) ? last.rect : rect;
|
|
32
|
+
},
|
|
33
|
+
isLastInRoot: () => recent.at(-1)?.isInRoot ?? false,
|
|
34
|
+
getRecentlyFocused: ({ outside }) => [...recent]
|
|
35
|
+
.reverse()
|
|
36
|
+
.find(({ element }) => element.isConnected &&
|
|
37
|
+
!containsComposed({ container: outside, element }))?.element,
|
|
38
|
+
cleanup: () => {
|
|
39
|
+
document.removeEventListener('focusin', onFocusIn, { capture: true });
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=focusTracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focusTracker.js","sourceRoot":"","sources":["../../src/lib/focusTracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAa,MAAM,eAAe,CAAA;AAE/D,MAAM,UAAU,GAAG,EAAE,CAAA;AAIrB,sGAAsG;AACtG,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,EAAE,IAAI,KAAyB,EAAE,EAAE,EAAE;IACrE,wEAAwE;IACxE,IAAI,MAAM,GAA8D,EAAE,CAAA;IAE1E,MAAM,SAAS,GAAG,CAAC,KAAiB,EAAE,EAAE;QACtC,+FAA+F;QAC/F,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAA;QACvC,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC;YAAE,OAAM;QAC7C,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;QAC5D,MAAM,CAAC,IAAI,CAAC;YACV,OAAO;YACP,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;YAC1B,QAAQ,EAAE,CAAC,IAAI,IAAI,gBAAgB,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;SAClE,CAAC,CAAA;QACF,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAA;IACpC,CAAC,CAAA;IAED,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAElE,OAAO;QACL,sGAAsG;QACtG,WAAW,EAAE,GAAqB,EAAE;YAClC,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;YAC1B,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAA;YAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW;gBAAE,OAAO,IAAI,CAAC,IAAI,CAAA;YAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;YAC/C,OAAO,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QACjD,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,IAAI,KAAK;QACpD,kBAAkB,EAAE,CAAC,EAAE,OAAO,EAAwB,EAAE,EAAE,CACxD,CAAC,GAAG,MAAM,CAAC;aACR,OAAO,EAAE;aACT,IAAI,CACH,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CACd,OAAO,CAAC,WAAW;YACnB,CAAC,gBAAgB,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CACrD,EAAE,OAAO;QACd,OAAO,EAAE,GAAG,EAAE;YACZ,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;QACvE,CAAC;KACF,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Candidate } from './strategies.js';
|
|
2
|
+
export declare const isVisible: ({ element }: {
|
|
3
|
+
element: Element;
|
|
4
|
+
}) => boolean;
|
|
5
|
+
export declare const createClipCheck: () => ({ element, rect }: Candidate) => boolean;
|
|
6
|
+
export declare const getFocusable: ({ root }: {
|
|
7
|
+
root: ParentNode;
|
|
8
|
+
}) => Candidate[];
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { closestComposed, getComposedParent, querySelectorAllDeep, } from './dom.js';
|
|
2
|
+
import { getRect, isEmptyRect } from './geometry.js';
|
|
3
|
+
// iframes are left out on purpose: once focused, key events go to the iframe's document and ArrowTab can't navigate back out
|
|
4
|
+
const focusableSelector = [
|
|
5
|
+
'a[href]',
|
|
6
|
+
'area[href]',
|
|
7
|
+
'button',
|
|
8
|
+
'input:not([type="hidden"])',
|
|
9
|
+
'select',
|
|
10
|
+
'textarea',
|
|
11
|
+
'details > summary:first-of-type',
|
|
12
|
+
'audio[controls]',
|
|
13
|
+
'video[controls]',
|
|
14
|
+
'[contenteditable]:not([contenteditable="false"])',
|
|
15
|
+
'[tabindex]',
|
|
16
|
+
].join(', ');
|
|
17
|
+
const excludedSelector = '[inert], [hidden], [aria-hidden="true"], [data-arrowtab~="skip"]';
|
|
18
|
+
export const isVisible = ({ element }) => {
|
|
19
|
+
if (typeof element.checkVisibility === 'function') {
|
|
20
|
+
return element.checkVisibility({
|
|
21
|
+
checkOpacity: true,
|
|
22
|
+
checkVisibilityCSS: true,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
let current = element;
|
|
26
|
+
while (current) {
|
|
27
|
+
const style = window.getComputedStyle(current);
|
|
28
|
+
if (style.display === 'none' || style.opacity === '0')
|
|
29
|
+
return false;
|
|
30
|
+
current = getComposedParent({ element: current });
|
|
31
|
+
}
|
|
32
|
+
return window.getComputedStyle(element).visibility !== 'hidden';
|
|
33
|
+
};
|
|
34
|
+
const isFocusable = ({ element }) => {
|
|
35
|
+
if (!(element instanceof HTMLElement))
|
|
36
|
+
return false;
|
|
37
|
+
if (element.matches(':disabled'))
|
|
38
|
+
return false;
|
|
39
|
+
// Negative tabindex is skipped by Tab, so ArrowTab skips it too
|
|
40
|
+
if (Number(element.getAttribute('tabindex')) < 0)
|
|
41
|
+
return false;
|
|
42
|
+
// Children of a contenteditable are part of the editor, not separate targets.
|
|
43
|
+
// Controls marked with contenteditable="false" and nested editors with a tabindex are independent and stay.
|
|
44
|
+
if (element.isContentEditable &&
|
|
45
|
+
element.parentElement?.isContentEditable &&
|
|
46
|
+
!element.hasAttribute('tabindex')) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (closestComposed({ element, selector: excludedSelector }))
|
|
50
|
+
return false;
|
|
51
|
+
return isVisible({ element });
|
|
52
|
+
};
|
|
53
|
+
const clippingOverflows = ['hidden', 'clip'];
|
|
54
|
+
const scrollingOverflows = ['auto', 'scroll'];
|
|
55
|
+
const getCached = ({ element, cache, }) => {
|
|
56
|
+
let entry = cache.get(element);
|
|
57
|
+
if (!entry) {
|
|
58
|
+
entry = { style: window.getComputedStyle(element) };
|
|
59
|
+
cache.set(element, entry);
|
|
60
|
+
}
|
|
61
|
+
return entry;
|
|
62
|
+
};
|
|
63
|
+
// Padding box of the element without scrollbars, in document coordinates
|
|
64
|
+
const getClipBox = ({ element, cache, }) => {
|
|
65
|
+
const entry = getCached({ element, cache });
|
|
66
|
+
if (!entry.box) {
|
|
67
|
+
const { top, left } = getRect({ element });
|
|
68
|
+
const boxLeft = left + element.clientLeft;
|
|
69
|
+
const boxTop = top + element.clientTop;
|
|
70
|
+
entry.box = {
|
|
71
|
+
top: boxTop,
|
|
72
|
+
left: boxLeft,
|
|
73
|
+
right: boxLeft + element.clientWidth,
|
|
74
|
+
bottom: boxTop + element.clientHeight,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return entry.box;
|
|
78
|
+
};
|
|
79
|
+
const createsContainingBlock = ({ style }) => style.position !== 'static' ||
|
|
80
|
+
(style.transform !== '' && style.transform !== 'none');
|
|
81
|
+
/**
|
|
82
|
+
* Whether the element is completely hidden by an ancestor with `overflow: hidden / clip`, e.g. an inactive carousel slide.
|
|
83
|
+
* Scroll containers don't clip, their content can be scrolled into view anywhere inside of them.
|
|
84
|
+
*/
|
|
85
|
+
const isClipped = ({ element, rect, cache, }) => {
|
|
86
|
+
let position = getCached({ element, cache }).style.position;
|
|
87
|
+
let current = getComposedParent({ element });
|
|
88
|
+
// Where the element can be once inner scroll containers are scrolled
|
|
89
|
+
let reachable = rect;
|
|
90
|
+
while (current &&
|
|
91
|
+
current !== document.body &&
|
|
92
|
+
current !== document.documentElement) {
|
|
93
|
+
// Fixed elements are positioned relative to the viewport (ignoring transformed ancestors)
|
|
94
|
+
if (position === 'fixed')
|
|
95
|
+
return false;
|
|
96
|
+
const { style } = getCached({ element: current, cache });
|
|
97
|
+
// Absolute elements are only clipped by their containing block and its ancestors
|
|
98
|
+
if (position !== 'absolute' || createsContainingBlock({ style })) {
|
|
99
|
+
const clipsX = clippingOverflows.includes(style.overflowX);
|
|
100
|
+
const clipsY = clippingOverflows.includes(style.overflowY);
|
|
101
|
+
const scrollsX = scrollingOverflows.includes(style.overflowX);
|
|
102
|
+
const scrollsY = scrollingOverflows.includes(style.overflowY);
|
|
103
|
+
if (clipsX || clipsY || scrollsX || scrollsY) {
|
|
104
|
+
const box = getClipBox({ element: current, cache });
|
|
105
|
+
if (clipsX &&
|
|
106
|
+
(reachable.right <= box.left || reachable.left >= box.right)) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (clipsY &&
|
|
110
|
+
(reachable.bottom <= box.top || reachable.top >= box.bottom)) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
reachable = {
|
|
114
|
+
left: scrollsX ? box.left : reachable.left,
|
|
115
|
+
right: scrollsX ? box.right : reachable.right,
|
|
116
|
+
top: scrollsY ? box.top : reachable.top,
|
|
117
|
+
bottom: scrollsY ? box.bottom : reachable.bottom,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
position = style.position;
|
|
121
|
+
}
|
|
122
|
+
current = getComposedParent({ element: current });
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
};
|
|
126
|
+
// Checking all candidates is slow on large pages, so only the ones that are about to be focused are checked
|
|
127
|
+
export const createClipCheck = () => {
|
|
128
|
+
const cache = new Map();
|
|
129
|
+
return ({ element, rect }) => isClipped({ element, rect, cache });
|
|
130
|
+
};
|
|
131
|
+
export const getFocusable = ({ root }) => querySelectorAllDeep({ root, selector: focusableSelector })
|
|
132
|
+
.filter((element) => isFocusable({ element }))
|
|
133
|
+
.map((element) => ({ element, rect: getRect({ element }) }))
|
|
134
|
+
.filter(({ rect }) => !isEmptyRect({ rect }));
|
|
135
|
+
//# sourceMappingURL=focusable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focusable.js","sourceRoot":"","sources":["../../src/lib/focusable.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type Direction } from './directions.js';
|
|
2
|
+
export type Rect = {
|
|
3
|
+
top: number;
|
|
4
|
+
right: number;
|
|
5
|
+
bottom: number;
|
|
6
|
+
left: number;
|
|
7
|
+
};
|
|
8
|
+
type RectPair = {
|
|
9
|
+
origin: Rect;
|
|
10
|
+
rect: Rect;
|
|
11
|
+
direction: Direction;
|
|
12
|
+
};
|
|
13
|
+
export declare const getRect: ({ element }: {
|
|
14
|
+
element: Element;
|
|
15
|
+
}) => Rect;
|
|
16
|
+
export declare const isEmptyRect: ({ rect }: {
|
|
17
|
+
rect: Rect;
|
|
18
|
+
}) => boolean;
|
|
19
|
+
export declare const getCenter: ({ rect }: {
|
|
20
|
+
rect: Rect;
|
|
21
|
+
}) => {
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
};
|
|
25
|
+
export declare const getCenterDistance: ({ origin, rect, }: {
|
|
26
|
+
origin: Rect;
|
|
27
|
+
rect: Rect;
|
|
28
|
+
}) => number;
|
|
29
|
+
export declare const getMajorAxisDistance: (params: RectPair) => number;
|
|
30
|
+
export declare const getMajorAxisDistanceToFarEdge: ({ origin, rect, direction, }: RectPair) => number;
|
|
31
|
+
export declare const getMinorAxisDistance: ({ origin, rect, direction }: RectPair) => number;
|
|
32
|
+
export declare const isInBeam: ({ origin, rect, direction }: RectPair) => boolean;
|
|
33
|
+
export declare const isCompletelyInDirection: (params: RectPair) => boolean;
|
|
34
|
+
export declare const isInDirection: ({ origin, rect, direction }: RectPair) => boolean;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { isVertical } from './directions.js';
|
|
2
|
+
// Document coordinates, so rects stay comparable after scrolling
|
|
3
|
+
export const getRect = ({ element }) => {
|
|
4
|
+
const { top, right, bottom, left } = element.getBoundingClientRect();
|
|
5
|
+
return {
|
|
6
|
+
top: top + window.scrollY,
|
|
7
|
+
right: right + window.scrollX,
|
|
8
|
+
bottom: bottom + window.scrollY,
|
|
9
|
+
left: left + window.scrollX,
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export const isEmptyRect = ({ rect }) => rect.right === rect.left && rect.bottom === rect.top;
|
|
13
|
+
export const getCenter = ({ rect }) => ({
|
|
14
|
+
x: (rect.left + rect.right) / 2,
|
|
15
|
+
y: (rect.top + rect.bottom) / 2,
|
|
16
|
+
});
|
|
17
|
+
export const getCenterDistance = ({ origin, rect, }) => {
|
|
18
|
+
const a = getCenter({ rect: origin });
|
|
19
|
+
const b = getCenter({ rect });
|
|
20
|
+
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
21
|
+
};
|
|
22
|
+
// Gap between the origin's leading edge and the rect's near edge. Negative if they overlap.
|
|
23
|
+
const getEdgeGap = ({ origin, rect, direction }) => {
|
|
24
|
+
const gaps = {
|
|
25
|
+
up: origin.top - rect.bottom,
|
|
26
|
+
down: rect.top - origin.bottom,
|
|
27
|
+
left: origin.left - rect.right,
|
|
28
|
+
right: rect.left - origin.right,
|
|
29
|
+
};
|
|
30
|
+
return gaps[direction];
|
|
31
|
+
};
|
|
32
|
+
export const getMajorAxisDistance = (params) => Math.max(0, getEdgeGap(params));
|
|
33
|
+
export const getMajorAxisDistanceToFarEdge = ({ origin, rect, direction, }) => {
|
|
34
|
+
const distances = {
|
|
35
|
+
up: origin.top - rect.top,
|
|
36
|
+
down: rect.bottom - origin.bottom,
|
|
37
|
+
left: origin.left - rect.left,
|
|
38
|
+
right: rect.right - origin.right,
|
|
39
|
+
};
|
|
40
|
+
return Math.max(1, distances[direction]);
|
|
41
|
+
};
|
|
42
|
+
// Offset of the centers perpendicular to the navigation direction
|
|
43
|
+
export const getMinorAxisDistance = ({ origin, rect, direction }) => {
|
|
44
|
+
const a = getCenter({ rect: origin });
|
|
45
|
+
const b = getCenter({ rect });
|
|
46
|
+
return isVertical({ direction }) ? Math.abs(b.x - a.x) : Math.abs(b.y - a.y);
|
|
47
|
+
};
|
|
48
|
+
// The rect overlaps the origin extended in navigation direction, e.g. it is in the same row for left / right
|
|
49
|
+
export const isInBeam = ({ origin, rect, direction }) => isVertical({ direction })
|
|
50
|
+
? rect.right > origin.left && rect.left < origin.right
|
|
51
|
+
: rect.bottom > origin.top && rect.top < origin.bottom;
|
|
52
|
+
export const isCompletelyInDirection = (params) => getEdgeGap(params) >= 0;
|
|
53
|
+
// The rect lies in navigation direction. Overlapping rects count if they extend further.
|
|
54
|
+
export const isInDirection = ({ origin, rect, direction }) => {
|
|
55
|
+
switch (direction) {
|
|
56
|
+
case 'up':
|
|
57
|
+
return ((origin.bottom > rect.bottom || origin.top >= rect.bottom) &&
|
|
58
|
+
origin.top > rect.top);
|
|
59
|
+
case 'down':
|
|
60
|
+
return ((origin.top < rect.top || origin.bottom <= rect.top) &&
|
|
61
|
+
origin.bottom < rect.bottom);
|
|
62
|
+
case 'left':
|
|
63
|
+
return ((origin.right > rect.right || origin.left >= rect.right) &&
|
|
64
|
+
origin.left > rect.left);
|
|
65
|
+
case 'right':
|
|
66
|
+
return ((origin.left < rect.left || origin.right <= rect.left) &&
|
|
67
|
+
origin.right < rect.right);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=geometry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../src/lib/geometry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { Direction } from './directions.js';
|
|
2
|
+
export declare const hasDisabledKeys: ({ element, direction, }: {
|
|
3
|
+
element: Element;
|
|
4
|
+
direction: Direction;
|
|
4
5
|
}) => boolean;
|
|
@@ -1,26 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (keywords.includes('disable')) {
|
|
7
|
-
return true;
|
|
8
|
-
}
|
|
9
|
-
const direction = event.key.toLowerCase().replace('arrow', '');
|
|
10
|
-
console.log({ direction, keywords });
|
|
11
|
-
if (keywords.includes(`disable-${direction}`)) {
|
|
12
|
-
return true;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return false;
|
|
16
|
-
};
|
|
17
|
-
let currentElement = activeElement;
|
|
18
|
-
while (currentElement) {
|
|
19
|
-
if (checkElement(currentElement)) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
currentElement = currentElement.parentElement;
|
|
23
|
-
}
|
|
24
|
-
return false;
|
|
25
|
-
};
|
|
1
|
+
import { closestComposed } from './dom.js';
|
|
2
|
+
export const hasDisabledKeys = ({ element, direction, }) => closestComposed({
|
|
3
|
+
element,
|
|
4
|
+
selector: `[data-arrowtab~="disable"], [data-arrowtab~="disable-${direction}"]`,
|
|
5
|
+
}) !== null;
|
|
26
6
|
//# sourceMappingURL=hasDisabledKeys.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hasDisabledKeys.js","sourceRoot":"","sources":["../../src/lib/hasDisabledKeys.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hasDisabledKeys.js","sourceRoot":"","sources":["../../src/lib/hasDisabledKeys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE1C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAC9B,OAAO,EACP,SAAS,GAIV,EAAE,EAAE,CACH,eAAe,CAAC;IACd,OAAO;IACP,QAAQ,EAAE,wDAAwD,SAAS,IAAI;CAChF,CAAC,KAAK,IAAI,CAAA"}
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { type Strategy } from './strategies.js';
|
|
2
|
+
declare const strategies: {
|
|
3
|
+
spatial: Strategy;
|
|
4
|
+
grid: Strategy;
|
|
5
|
+
};
|
|
6
|
+
export type ArrowTabOptions = {
|
|
2
7
|
debug?: boolean;
|
|
3
|
-
|
|
8
|
+
autoDetectHistory?: boolean;
|
|
9
|
+
strategy?: keyof typeof strategies | Strategy;
|
|
10
|
+
root?: Element;
|
|
11
|
+
};
|
|
12
|
+
export declare const initArrowTab: ({ debug, autoDetectHistory, strategy, root, }?: ArrowTabOptions) => {
|
|
4
13
|
cleanup: () => void;
|
|
5
14
|
};
|
|
15
|
+
export {};
|