@primer/behaviors 0.0.0-20231220224304 → 0.0.0-20231223202501
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/anchored-position.js +19 -11
- package/dist/cjs/focus-zone.d.ts +2 -3
- package/dist/cjs/focus-zone.js +3 -20
- package/dist/cjs/utils/iterate-focusable-elements.js +2 -7
- package/dist/esm/anchored-position.js +19 -11
- package/dist/esm/focus-zone.d.ts +2 -3
- package/dist/esm/focus-zone.js +3 -20
- package/dist/esm/utils/iterate-focusable-elements.js +2 -7
- package/package.json +1 -1
|
@@ -37,22 +37,27 @@ function getPositionedParent(element) {
|
|
|
37
37
|
}
|
|
38
38
|
return document.body;
|
|
39
39
|
}
|
|
40
|
-
function
|
|
40
|
+
function isModalDialog(element) {
|
|
41
|
+
return element.matches('dialog:modal');
|
|
42
|
+
}
|
|
43
|
+
function isFullscreen(element) {
|
|
44
|
+
return element.matches(':fullscreen');
|
|
45
|
+
}
|
|
46
|
+
function isPopover(element) {
|
|
41
47
|
var _a;
|
|
42
|
-
if (element.tagName === 'DIALOG') {
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
48
|
try {
|
|
46
|
-
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
+
return (element.matches(':popover-open') && /native code/.test((_a = document.body.showPopover) === null || _a === void 0 ? void 0 : _a.toString()));
|
|
49
50
|
}
|
|
50
51
|
catch (_b) {
|
|
51
52
|
return false;
|
|
52
53
|
}
|
|
53
|
-
return false;
|
|
54
54
|
}
|
|
55
|
-
function
|
|
55
|
+
function isOnTopLayer(element) {
|
|
56
|
+
return isModalDialog(element) || isFullscreen(element) || isPopover(element);
|
|
57
|
+
}
|
|
58
|
+
function getClippingParent(element) {
|
|
59
|
+
if (element === document.body)
|
|
60
|
+
return element;
|
|
56
61
|
let parentNode = element;
|
|
57
62
|
while (parentNode !== null) {
|
|
58
63
|
if (!(parentNode instanceof Element)) {
|
|
@@ -64,7 +69,10 @@ function getClippingRect(element) {
|
|
|
64
69
|
}
|
|
65
70
|
parentNode = parentNode.parentNode;
|
|
66
71
|
}
|
|
67
|
-
|
|
72
|
+
return parentNode === document.body || !(parentNode instanceof HTMLElement) ? document.body : parentNode;
|
|
73
|
+
}
|
|
74
|
+
function getClippingRect(element) {
|
|
75
|
+
const clippingNode = getClippingParent(element);
|
|
68
76
|
const elemRect = clippingNode.getBoundingClientRect();
|
|
69
77
|
const elemStyle = getComputedStyle(clippingNode);
|
|
70
78
|
const [borderTop, borderLeft, borderRight, borderBottom] = [
|
|
@@ -151,7 +159,7 @@ function pureCalculateAnchoredPosition(viewportRect, relativePosition, floatingR
|
|
|
151
159
|
}
|
|
152
160
|
if (alternateOrder && positionAttempt < alternateOrder.length) {
|
|
153
161
|
if (pos.top + floatingRect.height > viewportRect.height + relativeViewportRect.top) {
|
|
154
|
-
pos.top =
|
|
162
|
+
pos.top = viewportRect.height + relativeViewportRect.top - floatingRect.height;
|
|
155
163
|
}
|
|
156
164
|
}
|
|
157
165
|
}
|
package/dist/cjs/focus-zone.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { IterateFocusableElements } from './utils/iterate-focusable-elements.js';
|
|
2
1
|
export type Direction = 'previous' | 'next' | 'start' | 'end';
|
|
3
2
|
export type FocusMovementKeys = 'ArrowLeft' | 'ArrowDown' | 'ArrowUp' | 'ArrowRight' | 'h' | 'j' | 'k' | 'l' | 'a' | 's' | 'w' | 'd' | 'Tab' | 'Home' | 'End' | 'PageUp' | 'PageDown' | 'Backspace';
|
|
4
3
|
export declare enum FocusKeys {
|
|
@@ -17,7 +16,7 @@ export declare enum FocusKeys {
|
|
|
17
16
|
WASD = 96,
|
|
18
17
|
All = 511
|
|
19
18
|
}
|
|
20
|
-
export
|
|
19
|
+
export interface FocusZoneSettings {
|
|
21
20
|
focusOutBehavior?: 'stop' | 'wrap';
|
|
22
21
|
getNextFocusable?: (direction: Direction, from: Element | undefined, event: KeyboardEvent) => HTMLElement | undefined;
|
|
23
22
|
focusableElementFilter?: (element: HTMLElement) => boolean;
|
|
@@ -27,7 +26,7 @@ export type FocusZoneSettings = IterateFocusableElements & {
|
|
|
27
26
|
onActiveDescendantChanged?: (newActiveDescendant: HTMLElement | undefined, previousActiveDescendant: HTMLElement | undefined, directlyActivated: boolean) => void;
|
|
28
27
|
focusInStrategy?: 'first' | 'closest' | 'previous' | ((previousFocusedElement: Element) => HTMLElement | undefined);
|
|
29
28
|
preventScroll?: boolean;
|
|
30
|
-
}
|
|
29
|
+
}
|
|
31
30
|
export declare const isActiveDescendantAttribute = "data-is-active-descendant";
|
|
32
31
|
export declare const activeDescendantActivatedDirectly = "activated-directly";
|
|
33
32
|
export declare const activeDescendantActivatedIndirectly = "activated-indirectly";
|
package/dist/cjs/focus-zone.js
CHANGED
|
@@ -244,36 +244,21 @@ function focusZone(container, settings) {
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
|
-
|
|
248
|
-
reverse: settings === null || settings === void 0 ? void 0 : settings.reverse,
|
|
249
|
-
strict: settings === null || settings === void 0 ? void 0 : settings.strict,
|
|
250
|
-
onlyTabbable: settings === null || settings === void 0 ? void 0 : settings.onlyTabbable,
|
|
251
|
-
};
|
|
252
|
-
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(container, iterateFocusableElementsOptions));
|
|
247
|
+
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(container));
|
|
253
248
|
const initialElement = typeof focusInStrategy === 'function' ? focusInStrategy(document.body) : getFirstFocusableElement();
|
|
254
249
|
updateFocusedElement(initialElement);
|
|
255
250
|
const observer = new MutationObserver(mutations => {
|
|
256
251
|
for (const mutation of mutations) {
|
|
257
252
|
for (const removedNode of mutation.removedNodes) {
|
|
258
253
|
if (removedNode instanceof HTMLElement) {
|
|
259
|
-
endFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(removedNode
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
if (mutation.type === 'attributes' && mutation.oldValue === null) {
|
|
263
|
-
if (mutation.target instanceof HTMLElement) {
|
|
264
|
-
endFocusManagement(mutation.target);
|
|
254
|
+
endFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(removedNode));
|
|
265
255
|
}
|
|
266
256
|
}
|
|
267
257
|
}
|
|
268
258
|
for (const mutation of mutations) {
|
|
269
259
|
for (const addedNode of mutation.addedNodes) {
|
|
270
260
|
if (addedNode instanceof HTMLElement) {
|
|
271
|
-
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(addedNode
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
if (mutation.type === 'attributes' && mutation.oldValue !== null) {
|
|
275
|
-
if (mutation.target instanceof HTMLElement) {
|
|
276
|
-
beginFocusManagement(mutation.target);
|
|
261
|
+
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(addedNode));
|
|
277
262
|
}
|
|
278
263
|
}
|
|
279
264
|
}
|
|
@@ -281,8 +266,6 @@ function focusZone(container, settings) {
|
|
|
281
266
|
observer.observe(container, {
|
|
282
267
|
subtree: true,
|
|
283
268
|
childList: true,
|
|
284
|
-
attributeFilter: ['hidden', 'disabled'],
|
|
285
|
-
attributeOldValue: true,
|
|
286
269
|
});
|
|
287
270
|
const controller = new AbortController();
|
|
288
271
|
const signal = (_e = settings === null || settings === void 0 ? void 0 : settings.abortSignal) !== null && _e !== void 0 ? _e : controller.signal;
|
|
@@ -46,21 +46,16 @@ function isFocusable(elem, strict = false) {
|
|
|
46
46
|
return false;
|
|
47
47
|
}
|
|
48
48
|
if (strict) {
|
|
49
|
-
const style = getComputedStyle(elem);
|
|
50
49
|
const sizeInert = elem.offsetWidth === 0 || elem.offsetHeight === 0;
|
|
51
|
-
const visibilityInert = ['hidden', 'collapse'].includes(
|
|
52
|
-
const displayInert = style.display === 'none' || !elem.offsetParent;
|
|
50
|
+
const visibilityInert = ['hidden', 'collapse'].includes(getComputedStyle(elem).visibility);
|
|
53
51
|
const clientRectsInert = elem.getClientRects().length === 0;
|
|
54
|
-
if (sizeInert || visibilityInert || clientRectsInert
|
|
52
|
+
if (sizeInert || visibilityInert || clientRectsInert) {
|
|
55
53
|
return false;
|
|
56
54
|
}
|
|
57
55
|
}
|
|
58
56
|
if (elem.getAttribute('tabindex') != null) {
|
|
59
57
|
return true;
|
|
60
58
|
}
|
|
61
|
-
if (elem.getAttribute('contenteditable') === 'true' || elem.getAttribute('contenteditable') === 'plaintext-only') {
|
|
62
|
-
return true;
|
|
63
|
-
}
|
|
64
59
|
if (elem instanceof HTMLAnchorElement && elem.getAttribute('href') == null) {
|
|
65
60
|
return false;
|
|
66
61
|
}
|
|
@@ -33,22 +33,27 @@ function getPositionedParent(element) {
|
|
|
33
33
|
}
|
|
34
34
|
return document.body;
|
|
35
35
|
}
|
|
36
|
-
function
|
|
36
|
+
function isModalDialog(element) {
|
|
37
|
+
return element.matches('dialog:modal');
|
|
38
|
+
}
|
|
39
|
+
function isFullscreen(element) {
|
|
40
|
+
return element.matches(':fullscreen');
|
|
41
|
+
}
|
|
42
|
+
function isPopover(element) {
|
|
37
43
|
var _a;
|
|
38
|
-
if (element.tagName === 'DIALOG') {
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
44
|
try {
|
|
42
|
-
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
+
return (element.matches(':popover-open') && /native code/.test((_a = document.body.showPopover) === null || _a === void 0 ? void 0 : _a.toString()));
|
|
45
46
|
}
|
|
46
47
|
catch (_b) {
|
|
47
48
|
return false;
|
|
48
49
|
}
|
|
49
|
-
return false;
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function isOnTopLayer(element) {
|
|
52
|
+
return isModalDialog(element) || isFullscreen(element) || isPopover(element);
|
|
53
|
+
}
|
|
54
|
+
function getClippingParent(element) {
|
|
55
|
+
if (element === document.body)
|
|
56
|
+
return element;
|
|
52
57
|
let parentNode = element;
|
|
53
58
|
while (parentNode !== null) {
|
|
54
59
|
if (!(parentNode instanceof Element)) {
|
|
@@ -60,7 +65,10 @@ function getClippingRect(element) {
|
|
|
60
65
|
}
|
|
61
66
|
parentNode = parentNode.parentNode;
|
|
62
67
|
}
|
|
63
|
-
|
|
68
|
+
return parentNode === document.body || !(parentNode instanceof HTMLElement) ? document.body : parentNode;
|
|
69
|
+
}
|
|
70
|
+
function getClippingRect(element) {
|
|
71
|
+
const clippingNode = getClippingParent(element);
|
|
64
72
|
const elemRect = clippingNode.getBoundingClientRect();
|
|
65
73
|
const elemStyle = getComputedStyle(clippingNode);
|
|
66
74
|
const [borderTop, borderLeft, borderRight, borderBottom] = [
|
|
@@ -147,7 +155,7 @@ function pureCalculateAnchoredPosition(viewportRect, relativePosition, floatingR
|
|
|
147
155
|
}
|
|
148
156
|
if (alternateOrder && positionAttempt < alternateOrder.length) {
|
|
149
157
|
if (pos.top + floatingRect.height > viewportRect.height + relativeViewportRect.top) {
|
|
150
|
-
pos.top =
|
|
158
|
+
pos.top = viewportRect.height + relativeViewportRect.top - floatingRect.height;
|
|
151
159
|
}
|
|
152
160
|
}
|
|
153
161
|
}
|
package/dist/esm/focus-zone.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { IterateFocusableElements } from './utils/iterate-focusable-elements.js';
|
|
2
1
|
export type Direction = 'previous' | 'next' | 'start' | 'end';
|
|
3
2
|
export type FocusMovementKeys = 'ArrowLeft' | 'ArrowDown' | 'ArrowUp' | 'ArrowRight' | 'h' | 'j' | 'k' | 'l' | 'a' | 's' | 'w' | 'd' | 'Tab' | 'Home' | 'End' | 'PageUp' | 'PageDown' | 'Backspace';
|
|
4
3
|
export declare enum FocusKeys {
|
|
@@ -17,7 +16,7 @@ export declare enum FocusKeys {
|
|
|
17
16
|
WASD = 96,
|
|
18
17
|
All = 511
|
|
19
18
|
}
|
|
20
|
-
export
|
|
19
|
+
export interface FocusZoneSettings {
|
|
21
20
|
focusOutBehavior?: 'stop' | 'wrap';
|
|
22
21
|
getNextFocusable?: (direction: Direction, from: Element | undefined, event: KeyboardEvent) => HTMLElement | undefined;
|
|
23
22
|
focusableElementFilter?: (element: HTMLElement) => boolean;
|
|
@@ -27,7 +26,7 @@ export type FocusZoneSettings = IterateFocusableElements & {
|
|
|
27
26
|
onActiveDescendantChanged?: (newActiveDescendant: HTMLElement | undefined, previousActiveDescendant: HTMLElement | undefined, directlyActivated: boolean) => void;
|
|
28
27
|
focusInStrategy?: 'first' | 'closest' | 'previous' | ((previousFocusedElement: Element) => HTMLElement | undefined);
|
|
29
28
|
preventScroll?: boolean;
|
|
30
|
-
}
|
|
29
|
+
}
|
|
31
30
|
export declare const isActiveDescendantAttribute = "data-is-active-descendant";
|
|
32
31
|
export declare const activeDescendantActivatedDirectly = "activated-directly";
|
|
33
32
|
export declare const activeDescendantActivatedIndirectly = "activated-indirectly";
|
package/dist/esm/focus-zone.js
CHANGED
|
@@ -241,36 +241,21 @@ export function focusZone(container, settings) {
|
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
|
-
|
|
245
|
-
reverse: settings === null || settings === void 0 ? void 0 : settings.reverse,
|
|
246
|
-
strict: settings === null || settings === void 0 ? void 0 : settings.strict,
|
|
247
|
-
onlyTabbable: settings === null || settings === void 0 ? void 0 : settings.onlyTabbable,
|
|
248
|
-
};
|
|
249
|
-
beginFocusManagement(...iterateFocusableElements(container, iterateFocusableElementsOptions));
|
|
244
|
+
beginFocusManagement(...iterateFocusableElements(container));
|
|
250
245
|
const initialElement = typeof focusInStrategy === 'function' ? focusInStrategy(document.body) : getFirstFocusableElement();
|
|
251
246
|
updateFocusedElement(initialElement);
|
|
252
247
|
const observer = new MutationObserver(mutations => {
|
|
253
248
|
for (const mutation of mutations) {
|
|
254
249
|
for (const removedNode of mutation.removedNodes) {
|
|
255
250
|
if (removedNode instanceof HTMLElement) {
|
|
256
|
-
endFocusManagement(...iterateFocusableElements(removedNode
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
if (mutation.type === 'attributes' && mutation.oldValue === null) {
|
|
260
|
-
if (mutation.target instanceof HTMLElement) {
|
|
261
|
-
endFocusManagement(mutation.target);
|
|
251
|
+
endFocusManagement(...iterateFocusableElements(removedNode));
|
|
262
252
|
}
|
|
263
253
|
}
|
|
264
254
|
}
|
|
265
255
|
for (const mutation of mutations) {
|
|
266
256
|
for (const addedNode of mutation.addedNodes) {
|
|
267
257
|
if (addedNode instanceof HTMLElement) {
|
|
268
|
-
beginFocusManagement(...iterateFocusableElements(addedNode
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
if (mutation.type === 'attributes' && mutation.oldValue !== null) {
|
|
272
|
-
if (mutation.target instanceof HTMLElement) {
|
|
273
|
-
beginFocusManagement(mutation.target);
|
|
258
|
+
beginFocusManagement(...iterateFocusableElements(addedNode));
|
|
274
259
|
}
|
|
275
260
|
}
|
|
276
261
|
}
|
|
@@ -278,8 +263,6 @@ export function focusZone(container, settings) {
|
|
|
278
263
|
observer.observe(container, {
|
|
279
264
|
subtree: true,
|
|
280
265
|
childList: true,
|
|
281
|
-
attributeFilter: ['hidden', 'disabled'],
|
|
282
|
-
attributeOldValue: true,
|
|
283
266
|
});
|
|
284
267
|
const controller = new AbortController();
|
|
285
268
|
const signal = (_e = settings === null || settings === void 0 ? void 0 : settings.abortSignal) !== null && _e !== void 0 ? _e : controller.signal;
|
|
@@ -41,21 +41,16 @@ export function isFocusable(elem, strict = false) {
|
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
43
|
if (strict) {
|
|
44
|
-
const style = getComputedStyle(elem);
|
|
45
44
|
const sizeInert = elem.offsetWidth === 0 || elem.offsetHeight === 0;
|
|
46
|
-
const visibilityInert = ['hidden', 'collapse'].includes(
|
|
47
|
-
const displayInert = style.display === 'none' || !elem.offsetParent;
|
|
45
|
+
const visibilityInert = ['hidden', 'collapse'].includes(getComputedStyle(elem).visibility);
|
|
48
46
|
const clientRectsInert = elem.getClientRects().length === 0;
|
|
49
|
-
if (sizeInert || visibilityInert || clientRectsInert
|
|
47
|
+
if (sizeInert || visibilityInert || clientRectsInert) {
|
|
50
48
|
return false;
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
if (elem.getAttribute('tabindex') != null) {
|
|
54
52
|
return true;
|
|
55
53
|
}
|
|
56
|
-
if (elem.getAttribute('contenteditable') === 'true' || elem.getAttribute('contenteditable') === 'plaintext-only') {
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
54
|
if (elem instanceof HTMLAnchorElement && elem.getAttribute('href') == null) {
|
|
60
55
|
return false;
|
|
61
56
|
}
|