@primer/behaviors 0.0.0-20240222105352 → 0.0.0-20240229000302
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 +20 -11
- package/dist/cjs/focus-zone.d.ts +2 -3
- package/dist/cjs/focus-zone.js +3 -8
- package/dist/cjs/utils/iterate-focusable-elements.js +2 -7
- package/dist/esm/anchored-position.js +20 -11
- package/dist/esm/focus-zone.d.ts +2 -3
- package/dist/esm/focus-zone.js +3 -8
- package/dist/esm/utils/iterate-focusable-elements.js +2 -7
- package/package.json +6 -7
|
@@ -37,21 +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 element.matches(':modal');
|
|
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) {
|
|
52
|
+
return false;
|
|
51
53
|
}
|
|
52
|
-
return element.matches(':fullscreen');
|
|
53
54
|
}
|
|
54
|
-
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;
|
|
55
61
|
let parentNode = element;
|
|
56
62
|
while (parentNode !== null) {
|
|
57
63
|
if (!(parentNode instanceof Element)) {
|
|
@@ -63,7 +69,10 @@ function getClippingRect(element) {
|
|
|
63
69
|
}
|
|
64
70
|
parentNode = parentNode.parentNode;
|
|
65
71
|
}
|
|
66
|
-
|
|
72
|
+
return parentNode === document.body || !(parentNode instanceof HTMLElement) ? document.body : parentNode;
|
|
73
|
+
}
|
|
74
|
+
function getClippingRect(element) {
|
|
75
|
+
const clippingNode = getClippingParent(element);
|
|
67
76
|
const elemRect = clippingNode.getBoundingClientRect();
|
|
68
77
|
const elemStyle = getComputedStyle(clippingNode);
|
|
69
78
|
const [borderTop, borderLeft, borderRight, borderBottom] = [
|
|
@@ -150,7 +159,7 @@ function pureCalculateAnchoredPosition(viewportRect, relativePosition, floatingR
|
|
|
150
159
|
}
|
|
151
160
|
if (alternateOrder && positionAttempt < alternateOrder.length) {
|
|
152
161
|
if (pos.top + floatingRect.height > viewportRect.height + relativeViewportRect.top) {
|
|
153
|
-
pos.top =
|
|
162
|
+
pos.top = viewportRect.height + relativeViewportRect.top - floatingRect.height;
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
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,26 +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
|
|
254
|
+
endFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(removedNode));
|
|
260
255
|
}
|
|
261
256
|
}
|
|
262
257
|
}
|
|
263
258
|
for (const mutation of mutations) {
|
|
264
259
|
for (const addedNode of mutation.addedNodes) {
|
|
265
260
|
if (addedNode instanceof HTMLElement) {
|
|
266
|
-
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(addedNode
|
|
261
|
+
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(addedNode));
|
|
267
262
|
}
|
|
268
263
|
}
|
|
269
264
|
}
|
|
@@ -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,21 +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 element.matches(':modal');
|
|
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) {
|
|
48
|
+
return false;
|
|
47
49
|
}
|
|
48
|
-
return element.matches(':fullscreen');
|
|
49
50
|
}
|
|
50
|
-
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;
|
|
51
57
|
let parentNode = element;
|
|
52
58
|
while (parentNode !== null) {
|
|
53
59
|
if (!(parentNode instanceof Element)) {
|
|
@@ -59,7 +65,10 @@ function getClippingRect(element) {
|
|
|
59
65
|
}
|
|
60
66
|
parentNode = parentNode.parentNode;
|
|
61
67
|
}
|
|
62
|
-
|
|
68
|
+
return parentNode === document.body || !(parentNode instanceof HTMLElement) ? document.body : parentNode;
|
|
69
|
+
}
|
|
70
|
+
function getClippingRect(element) {
|
|
71
|
+
const clippingNode = getClippingParent(element);
|
|
63
72
|
const elemRect = clippingNode.getBoundingClientRect();
|
|
64
73
|
const elemStyle = getComputedStyle(clippingNode);
|
|
65
74
|
const [borderTop, borderLeft, borderRight, borderBottom] = [
|
|
@@ -146,7 +155,7 @@ function pureCalculateAnchoredPosition(viewportRect, relativePosition, floatingR
|
|
|
146
155
|
}
|
|
147
156
|
if (alternateOrder && positionAttempt < alternateOrder.length) {
|
|
148
157
|
if (pos.top + floatingRect.height > viewportRect.height + relativeViewportRect.top) {
|
|
149
|
-
pos.top =
|
|
158
|
+
pos.top = viewportRect.height + relativeViewportRect.top - floatingRect.height;
|
|
150
159
|
}
|
|
151
160
|
}
|
|
152
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,26 +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
|
|
251
|
+
endFocusManagement(...iterateFocusableElements(removedNode));
|
|
257
252
|
}
|
|
258
253
|
}
|
|
259
254
|
}
|
|
260
255
|
for (const mutation of mutations) {
|
|
261
256
|
for (const addedNode of mutation.addedNodes) {
|
|
262
257
|
if (addedNode instanceof HTMLElement) {
|
|
263
|
-
beginFocusManagement(...iterateFocusableElements(addedNode
|
|
258
|
+
beginFocusManagement(...iterateFocusableElements(addedNode));
|
|
264
259
|
}
|
|
265
260
|
}
|
|
266
261
|
}
|
|
@@ -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
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/behaviors",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-20240229000302",
|
|
4
4
|
"description": "Shared behaviors for JavaScript components",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -66,22 +66,21 @@
|
|
|
66
66
|
}
|
|
67
67
|
],
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@changesets/changelog-github": "^0.
|
|
69
|
+
"@changesets/changelog-github": "^0.4.2",
|
|
70
70
|
"@changesets/cli": "^2.18.1",
|
|
71
71
|
"@github/prettier-config": "^0.0.6",
|
|
72
72
|
"@size-limit/preset-small-lib": "^8.2.4",
|
|
73
73
|
"@testing-library/react": "^14.0.0",
|
|
74
74
|
"@testing-library/user-event": "^14.5.1",
|
|
75
|
-
"@types/jest": "^
|
|
76
|
-
"@types/node": "^
|
|
75
|
+
"@types/jest": "^27.0.3",
|
|
76
|
+
"@types/node": "^18.18.0",
|
|
77
77
|
"@types/react": "^18.2.23",
|
|
78
|
-
"esbuild": "^0.
|
|
78
|
+
"esbuild": "^0.19.4",
|
|
79
79
|
"esbuild-jest": "^0.5.0",
|
|
80
80
|
"eslint": "^8.50.0",
|
|
81
81
|
"eslint-plugin-github": "^4.10.0",
|
|
82
82
|
"eslint-plugin-prettier": "^5.0.0",
|
|
83
|
-
"jest": "^
|
|
84
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
83
|
+
"jest": "^27.4.3",
|
|
85
84
|
"prettier": "^3.0.3",
|
|
86
85
|
"react": "^18.2.0",
|
|
87
86
|
"react-dom": "^18.2.0",
|