@primer/behaviors 1.0.2 → 1.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/dist/{anchored-position.d.ts → cjs/anchored-position.d.ts} +0 -0
- package/dist/cjs/anchored-position.js +210 -0
- package/dist/cjs/focus-trap.d.ts +1 -0
- package/dist/cjs/focus-trap.js +107 -0
- package/dist/{focus-zone.d.ts → cjs/focus-zone.d.ts} +0 -0
- package/dist/cjs/focus-zone.js +410 -0
- package/dist/{index.d.ts → cjs/index.d.ts} +0 -0
- package/dist/cjs/index.js +16 -0
- package/dist/{polyfills → cjs/polyfills}/event-listener-signal.d.ts +0 -0
- package/dist/cjs/polyfills/event-listener-signal.js +44 -0
- package/dist/{scroll-into-view.d.ts → cjs/scroll-into-view.d.ts} +0 -0
- package/dist/cjs/scroll-into-view.js +21 -0
- package/dist/{utils → cjs/utils}/index.d.ts +0 -0
- package/dist/cjs/utils/index.js +15 -0
- package/dist/{utils → cjs/utils}/iterate-focusable-elements.d.ts +1 -0
- package/dist/cjs/utils/iterate-focusable-elements.js +68 -0
- package/dist/{utils → cjs/utils}/unique-id.d.ts +0 -0
- package/dist/cjs/utils/unique-id.js +8 -0
- package/dist/{utils → cjs/utils}/user-agent.d.ts +0 -0
- package/dist/cjs/utils/user-agent.js +11 -0
- package/dist/esm/anchored-position.d.ts +15 -0
- package/dist/{anchored-position.js → esm/anchored-position.js} +0 -0
- package/dist/esm/focus-trap.d.ts +1 -0
- package/dist/{focus-trap.js → esm/focus-trap.js} +24 -28
- package/dist/esm/focus-zone.d.ts +32 -0
- package/dist/{focus-zone.js → esm/focus-zone.js} +0 -0
- package/dist/{index.js → esm/index.d.ts} +0 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/polyfills/event-listener-signal.d.ts +6 -0
- package/dist/{polyfills → esm/polyfills}/event-listener-signal.js +0 -0
- package/dist/esm/scroll-into-view.d.ts +7 -0
- package/dist/{scroll-into-view.js → esm/scroll-into-view.js} +0 -0
- package/dist/{utils/index.js → esm/utils/index.d.ts} +0 -0
- package/dist/esm/utils/index.js +3 -0
- package/dist/esm/utils/iterate-focusable-elements.d.ts +9 -0
- package/dist/{utils → esm/utils}/iterate-focusable-elements.js +5 -1
- package/dist/esm/utils/unique-id.d.ts +1 -0
- package/dist/{utils → esm/utils}/unique-id.js +0 -0
- package/dist/esm/utils/user-agent.d.ts +1 -0
- package/dist/{utils → esm/utils}/user-agent.js +0 -0
- package/package.json +24 -8
- package/utils/package.json +2 -2
- package/dist/focus-trap.d.ts +0 -2
|
File without changes
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAnchoredPosition = void 0;
|
|
4
|
+
const alternateOrders = {
|
|
5
|
+
'outside-top': ['outside-bottom', 'outside-right', 'outside-left', 'outside-bottom'],
|
|
6
|
+
'outside-bottom': ['outside-top', 'outside-right', 'outside-left', 'outside-bottom'],
|
|
7
|
+
'outside-left': ['outside-right', 'outside-bottom', 'outside-top', 'outside-bottom'],
|
|
8
|
+
'outside-right': ['outside-left', 'outside-bottom', 'outside-top', 'outside-bottom']
|
|
9
|
+
};
|
|
10
|
+
function getAnchoredPosition(floatingElement, anchorElement, settings = {}) {
|
|
11
|
+
const parentElement = getPositionedParent(floatingElement);
|
|
12
|
+
const clippingRect = getClippingRect(parentElement);
|
|
13
|
+
const parentElementStyle = getComputedStyle(parentElement);
|
|
14
|
+
const parentElementRect = parentElement.getBoundingClientRect();
|
|
15
|
+
const [borderTop, borderLeft] = [parentElementStyle.borderTopWidth, parentElementStyle.borderLeftWidth].map(v => parseInt(v, 10) || 0);
|
|
16
|
+
const relativeRect = {
|
|
17
|
+
top: parentElementRect.top + borderTop,
|
|
18
|
+
left: parentElementRect.left + borderLeft
|
|
19
|
+
};
|
|
20
|
+
return pureCalculateAnchoredPosition(clippingRect, relativeRect, floatingElement.getBoundingClientRect(), anchorElement instanceof Element ? anchorElement.getBoundingClientRect() : anchorElement, getDefaultSettings(settings));
|
|
21
|
+
}
|
|
22
|
+
exports.getAnchoredPosition = getAnchoredPosition;
|
|
23
|
+
function getPositionedParent(element) {
|
|
24
|
+
let parentNode = element.parentNode;
|
|
25
|
+
while (parentNode !== null) {
|
|
26
|
+
if (parentNode instanceof HTMLElement && getComputedStyle(parentNode).position !== 'static') {
|
|
27
|
+
return parentNode;
|
|
28
|
+
}
|
|
29
|
+
parentNode = parentNode.parentNode;
|
|
30
|
+
}
|
|
31
|
+
return document.body;
|
|
32
|
+
}
|
|
33
|
+
function getClippingRect(element) {
|
|
34
|
+
let parentNode = element;
|
|
35
|
+
while (parentNode !== null) {
|
|
36
|
+
if (parentNode === document.body) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
const parentNodeStyle = getComputedStyle(parentNode);
|
|
40
|
+
if (parentNodeStyle.overflow !== 'visible') {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
parentNode = parentNode.parentNode;
|
|
44
|
+
}
|
|
45
|
+
const clippingNode = parentNode === document.body || !(parentNode instanceof HTMLElement) ? document.body : parentNode;
|
|
46
|
+
const elemRect = clippingNode.getBoundingClientRect();
|
|
47
|
+
const elemStyle = getComputedStyle(clippingNode);
|
|
48
|
+
const [borderTop, borderLeft, borderRight, borderBottom] = [
|
|
49
|
+
elemStyle.borderTopWidth,
|
|
50
|
+
elemStyle.borderLeftWidth,
|
|
51
|
+
elemStyle.borderRightWidth,
|
|
52
|
+
elemStyle.borderBottomWidth
|
|
53
|
+
].map(v => parseInt(v, 10) || 0);
|
|
54
|
+
return {
|
|
55
|
+
top: elemRect.top + borderTop,
|
|
56
|
+
left: elemRect.left + borderLeft,
|
|
57
|
+
width: elemRect.width - borderRight - borderLeft,
|
|
58
|
+
height: Math.max(elemRect.height - borderTop - borderBottom, clippingNode === document.body ? window.innerHeight : -Infinity)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const positionDefaults = {
|
|
62
|
+
side: 'outside-bottom',
|
|
63
|
+
align: 'start',
|
|
64
|
+
anchorOffset: 4,
|
|
65
|
+
alignmentOffset: 4,
|
|
66
|
+
allowOutOfBounds: false
|
|
67
|
+
};
|
|
68
|
+
function getDefaultSettings(settings = {}) {
|
|
69
|
+
var _a, _b, _c, _d, _e;
|
|
70
|
+
const side = (_a = settings.side) !== null && _a !== void 0 ? _a : positionDefaults.side;
|
|
71
|
+
const align = (_b = settings.align) !== null && _b !== void 0 ? _b : positionDefaults.align;
|
|
72
|
+
return {
|
|
73
|
+
side,
|
|
74
|
+
align,
|
|
75
|
+
anchorOffset: (_c = settings.anchorOffset) !== null && _c !== void 0 ? _c : (side === 'inside-center' ? 0 : positionDefaults.anchorOffset),
|
|
76
|
+
alignmentOffset: (_d = settings.alignmentOffset) !== null && _d !== void 0 ? _d : (align !== 'center' && side.startsWith('inside') ? positionDefaults.alignmentOffset : 0),
|
|
77
|
+
allowOutOfBounds: (_e = settings.allowOutOfBounds) !== null && _e !== void 0 ? _e : positionDefaults.allowOutOfBounds
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function pureCalculateAnchoredPosition(viewportRect, relativePosition, floatingRect, anchorRect, { side, align, allowOutOfBounds, anchorOffset, alignmentOffset }) {
|
|
81
|
+
const relativeViewportRect = {
|
|
82
|
+
top: viewportRect.top - relativePosition.top,
|
|
83
|
+
left: viewportRect.left - relativePosition.left,
|
|
84
|
+
width: viewportRect.width,
|
|
85
|
+
height: viewportRect.height
|
|
86
|
+
};
|
|
87
|
+
let pos = calculatePosition(floatingRect, anchorRect, side, align, anchorOffset, alignmentOffset);
|
|
88
|
+
let anchorSide = side;
|
|
89
|
+
pos.top -= relativePosition.top;
|
|
90
|
+
pos.left -= relativePosition.left;
|
|
91
|
+
if (!allowOutOfBounds) {
|
|
92
|
+
const alternateOrder = alternateOrders[side];
|
|
93
|
+
let positionAttempt = 0;
|
|
94
|
+
if (alternateOrder) {
|
|
95
|
+
let prevSide = side;
|
|
96
|
+
while (positionAttempt < alternateOrder.length &&
|
|
97
|
+
shouldRecalculatePosition(prevSide, pos, relativeViewportRect, floatingRect)) {
|
|
98
|
+
const nextSide = alternateOrder[positionAttempt++];
|
|
99
|
+
prevSide = nextSide;
|
|
100
|
+
pos = calculatePosition(floatingRect, anchorRect, nextSide, align, anchorOffset, alignmentOffset);
|
|
101
|
+
pos.top -= relativePosition.top;
|
|
102
|
+
pos.left -= relativePosition.left;
|
|
103
|
+
anchorSide = nextSide;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (pos.top < relativeViewportRect.top) {
|
|
107
|
+
pos.top = relativeViewportRect.top;
|
|
108
|
+
}
|
|
109
|
+
if (pos.left < relativeViewportRect.left) {
|
|
110
|
+
pos.left = relativeViewportRect.left;
|
|
111
|
+
}
|
|
112
|
+
if (pos.left + floatingRect.width > viewportRect.width + relativeViewportRect.left) {
|
|
113
|
+
pos.left = viewportRect.width + relativeViewportRect.left - floatingRect.width;
|
|
114
|
+
}
|
|
115
|
+
if (alternateOrder && positionAttempt < alternateOrder.length) {
|
|
116
|
+
if (pos.top + floatingRect.height > viewportRect.height + relativeViewportRect.top) {
|
|
117
|
+
pos.top = viewportRect.height + relativeViewportRect.top - floatingRect.height;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return Object.assign(Object.assign({}, pos), { anchorSide });
|
|
122
|
+
}
|
|
123
|
+
function calculatePosition(elementDimensions, anchorPosition, side, align, anchorOffset, alignmentOffset) {
|
|
124
|
+
const anchorRight = anchorPosition.left + anchorPosition.width;
|
|
125
|
+
const anchorBottom = anchorPosition.top + anchorPosition.height;
|
|
126
|
+
let top = -1;
|
|
127
|
+
let left = -1;
|
|
128
|
+
if (side === 'outside-top') {
|
|
129
|
+
top = anchorPosition.top - anchorOffset - elementDimensions.height;
|
|
130
|
+
}
|
|
131
|
+
else if (side === 'outside-bottom') {
|
|
132
|
+
top = anchorBottom + anchorOffset;
|
|
133
|
+
}
|
|
134
|
+
else if (side === 'outside-left') {
|
|
135
|
+
left = anchorPosition.left - anchorOffset - elementDimensions.width;
|
|
136
|
+
}
|
|
137
|
+
else if (side === 'outside-right') {
|
|
138
|
+
left = anchorRight + anchorOffset;
|
|
139
|
+
}
|
|
140
|
+
if (side === 'outside-top' || side === 'outside-bottom') {
|
|
141
|
+
if (align === 'start') {
|
|
142
|
+
left = anchorPosition.left + alignmentOffset;
|
|
143
|
+
}
|
|
144
|
+
else if (align === 'center') {
|
|
145
|
+
left = anchorPosition.left - (elementDimensions.width - anchorPosition.width) / 2 + alignmentOffset;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
left = anchorRight - elementDimensions.width - alignmentOffset;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (side === 'outside-left' || side === 'outside-right') {
|
|
152
|
+
if (align === 'start') {
|
|
153
|
+
top = anchorPosition.top + alignmentOffset;
|
|
154
|
+
}
|
|
155
|
+
else if (align === 'center') {
|
|
156
|
+
top = anchorPosition.top - (elementDimensions.height - anchorPosition.height) / 2 + alignmentOffset;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
top = anchorBottom - elementDimensions.height - alignmentOffset;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (side === 'inside-top') {
|
|
163
|
+
top = anchorPosition.top + anchorOffset;
|
|
164
|
+
}
|
|
165
|
+
else if (side === 'inside-bottom') {
|
|
166
|
+
top = anchorBottom - anchorOffset - elementDimensions.height;
|
|
167
|
+
}
|
|
168
|
+
else if (side === 'inside-left') {
|
|
169
|
+
left = anchorPosition.left + anchorOffset;
|
|
170
|
+
}
|
|
171
|
+
else if (side === 'inside-right') {
|
|
172
|
+
left = anchorRight - anchorOffset - elementDimensions.width;
|
|
173
|
+
}
|
|
174
|
+
else if (side === 'inside-center') {
|
|
175
|
+
left = (anchorRight + anchorPosition.left) / 2 - elementDimensions.width / 2 + anchorOffset;
|
|
176
|
+
}
|
|
177
|
+
if (side === 'inside-top' || side === 'inside-bottom') {
|
|
178
|
+
if (align === 'start') {
|
|
179
|
+
left = anchorPosition.left + alignmentOffset;
|
|
180
|
+
}
|
|
181
|
+
else if (align === 'center') {
|
|
182
|
+
left = anchorPosition.left - (elementDimensions.width - anchorPosition.width) / 2 + alignmentOffset;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
left = anchorRight - elementDimensions.width - alignmentOffset;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
else if (side === 'inside-left' || side === 'inside-right' || side === 'inside-center') {
|
|
189
|
+
if (align === 'start') {
|
|
190
|
+
top = anchorPosition.top + alignmentOffset;
|
|
191
|
+
}
|
|
192
|
+
else if (align === 'center') {
|
|
193
|
+
top = anchorPosition.top - (elementDimensions.height - anchorPosition.height) / 2 + alignmentOffset;
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
top = anchorBottom - elementDimensions.height - alignmentOffset;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return { top, left };
|
|
200
|
+
}
|
|
201
|
+
function shouldRecalculatePosition(side, currentPos, containerDimensions, elementDimensions) {
|
|
202
|
+
if (side === 'outside-top' || side === 'outside-bottom') {
|
|
203
|
+
return (currentPos.top < containerDimensions.top ||
|
|
204
|
+
currentPos.top + elementDimensions.height > containerDimensions.height + containerDimensions.top);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return (currentPos.left < containerDimensions.left ||
|
|
208
|
+
currentPos.left + elementDimensions.width > containerDimensions.width + containerDimensions.left);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function focusTrap(container: HTMLElement, initialFocus?: HTMLElement, abortSignal?: AbortSignal): AbortController | undefined;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.focusTrap = void 0;
|
|
4
|
+
const iterate_focusable_elements_js_1 = require("./utils/iterate-focusable-elements.js");
|
|
5
|
+
const event_listener_signal_js_1 = require("./polyfills/event-listener-signal.js");
|
|
6
|
+
(0, event_listener_signal_js_1.polyfill)();
|
|
7
|
+
const suspendedTrapStack = [];
|
|
8
|
+
let activeTrap = undefined;
|
|
9
|
+
function tryReactivate() {
|
|
10
|
+
const trapToReactivate = suspendedTrapStack.pop();
|
|
11
|
+
if (trapToReactivate) {
|
|
12
|
+
focusTrap(trapToReactivate.container, trapToReactivate.initialFocus, trapToReactivate.originalSignal);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function followSignal(signal) {
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
signal.addEventListener('abort', () => {
|
|
18
|
+
controller.abort();
|
|
19
|
+
});
|
|
20
|
+
return controller;
|
|
21
|
+
}
|
|
22
|
+
function focusTrap(container, initialFocus, abortSignal) {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const signal = abortSignal !== null && abortSignal !== void 0 ? abortSignal : controller.signal;
|
|
25
|
+
container.setAttribute('data-focus-trap', 'active');
|
|
26
|
+
const sentinelStart = document.createElement('span');
|
|
27
|
+
sentinelStart.setAttribute('class', 'sentinel');
|
|
28
|
+
sentinelStart.setAttribute('tabindex', '0');
|
|
29
|
+
sentinelStart.setAttribute('aria-hidden', 'true');
|
|
30
|
+
sentinelStart.onfocus = () => {
|
|
31
|
+
const lastFocusableChild = (0, iterate_focusable_elements_js_1.getFocusableChild)(container, true);
|
|
32
|
+
lastFocusableChild === null || lastFocusableChild === void 0 ? void 0 : lastFocusableChild.focus();
|
|
33
|
+
};
|
|
34
|
+
const sentinelEnd = document.createElement('span');
|
|
35
|
+
sentinelEnd.setAttribute('class', 'sentinel');
|
|
36
|
+
sentinelEnd.setAttribute('tabindex', '0');
|
|
37
|
+
sentinelEnd.setAttribute('aria-hidden', 'true');
|
|
38
|
+
sentinelEnd.onfocus = () => {
|
|
39
|
+
const firstFocusableChild = (0, iterate_focusable_elements_js_1.getFocusableChild)(container);
|
|
40
|
+
firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
|
|
41
|
+
};
|
|
42
|
+
container.prepend(sentinelStart);
|
|
43
|
+
container.append(sentinelEnd);
|
|
44
|
+
let lastFocusedChild = undefined;
|
|
45
|
+
function ensureTrapZoneHasFocus(focusedElement) {
|
|
46
|
+
if (focusedElement instanceof HTMLElement && document.contains(container)) {
|
|
47
|
+
if (container.contains(focusedElement)) {
|
|
48
|
+
lastFocusedChild = focusedElement;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
if (lastFocusedChild && (0, iterate_focusable_elements_js_1.isTabbable)(lastFocusedChild) && container.contains(lastFocusedChild)) {
|
|
53
|
+
lastFocusedChild.focus();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
else if (initialFocus && container.contains(initialFocus)) {
|
|
57
|
+
initialFocus.focus();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const firstFocusableChild = (0, iterate_focusable_elements_js_1.getFocusableChild)(container);
|
|
62
|
+
firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const wrappingController = followSignal(signal);
|
|
69
|
+
if (activeTrap) {
|
|
70
|
+
const suspendedTrap = activeTrap;
|
|
71
|
+
activeTrap.container.setAttribute('data-focus-trap', 'suspended');
|
|
72
|
+
activeTrap.controller.abort();
|
|
73
|
+
suspendedTrapStack.push(suspendedTrap);
|
|
74
|
+
}
|
|
75
|
+
wrappingController.signal.addEventListener('abort', () => {
|
|
76
|
+
activeTrap = undefined;
|
|
77
|
+
});
|
|
78
|
+
signal.addEventListener('abort', () => {
|
|
79
|
+
container.removeAttribute('data-focus-trap');
|
|
80
|
+
const sentinels = container.getElementsByClassName('sentinel');
|
|
81
|
+
while (sentinels.length > 0)
|
|
82
|
+
sentinels[0].remove();
|
|
83
|
+
const suspendedTrapIndex = suspendedTrapStack.findIndex(t => t.container === container);
|
|
84
|
+
if (suspendedTrapIndex >= 0) {
|
|
85
|
+
suspendedTrapStack.splice(suspendedTrapIndex, 1);
|
|
86
|
+
}
|
|
87
|
+
tryReactivate();
|
|
88
|
+
});
|
|
89
|
+
document.addEventListener('focus', event => {
|
|
90
|
+
ensureTrapZoneHasFocus(event.target);
|
|
91
|
+
}, { signal: wrappingController.signal, capture: true });
|
|
92
|
+
ensureTrapZoneHasFocus(document.activeElement);
|
|
93
|
+
activeTrap = {
|
|
94
|
+
container,
|
|
95
|
+
controller: wrappingController,
|
|
96
|
+
initialFocus,
|
|
97
|
+
originalSignal: signal
|
|
98
|
+
};
|
|
99
|
+
const suspendedTrapIndex = suspendedTrapStack.findIndex(t => t.container === container);
|
|
100
|
+
if (suspendedTrapIndex >= 0) {
|
|
101
|
+
suspendedTrapStack.splice(suspendedTrapIndex, 1);
|
|
102
|
+
}
|
|
103
|
+
if (!abortSignal) {
|
|
104
|
+
return controller;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.focusTrap = focusTrap;
|
|
File without changes
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.focusZone = exports.hasActiveDescendantAttribute = exports.activeDescendantActivatedIndirectly = exports.activeDescendantActivatedDirectly = exports.isActiveDescendantAttribute = exports.FocusKeys = void 0;
|
|
4
|
+
const event_listener_signal_js_1 = require("./polyfills/event-listener-signal.js");
|
|
5
|
+
const user_agent_js_1 = require("./utils/user-agent.js");
|
|
6
|
+
const iterate_focusable_elements_js_1 = require("./utils/iterate-focusable-elements.js");
|
|
7
|
+
const unique_id_js_1 = require("./utils/unique-id.js");
|
|
8
|
+
(0, event_listener_signal_js_1.polyfill)();
|
|
9
|
+
var FocusKeys;
|
|
10
|
+
(function (FocusKeys) {
|
|
11
|
+
FocusKeys[FocusKeys["ArrowHorizontal"] = 1] = "ArrowHorizontal";
|
|
12
|
+
FocusKeys[FocusKeys["ArrowVertical"] = 2] = "ArrowVertical";
|
|
13
|
+
FocusKeys[FocusKeys["JK"] = 4] = "JK";
|
|
14
|
+
FocusKeys[FocusKeys["HL"] = 8] = "HL";
|
|
15
|
+
FocusKeys[FocusKeys["HomeAndEnd"] = 16] = "HomeAndEnd";
|
|
16
|
+
FocusKeys[FocusKeys["PageUpDown"] = 256] = "PageUpDown";
|
|
17
|
+
FocusKeys[FocusKeys["WS"] = 32] = "WS";
|
|
18
|
+
FocusKeys[FocusKeys["AD"] = 64] = "AD";
|
|
19
|
+
FocusKeys[FocusKeys["Tab"] = 128] = "Tab";
|
|
20
|
+
FocusKeys[FocusKeys["ArrowAll"] = 3] = "ArrowAll";
|
|
21
|
+
FocusKeys[FocusKeys["HJKL"] = 12] = "HJKL";
|
|
22
|
+
FocusKeys[FocusKeys["WASD"] = 96] = "WASD";
|
|
23
|
+
FocusKeys[FocusKeys["All"] = 511] = "All";
|
|
24
|
+
})(FocusKeys = exports.FocusKeys || (exports.FocusKeys = {}));
|
|
25
|
+
const KEY_TO_BIT = {
|
|
26
|
+
ArrowLeft: FocusKeys.ArrowHorizontal,
|
|
27
|
+
ArrowDown: FocusKeys.ArrowVertical,
|
|
28
|
+
ArrowUp: FocusKeys.ArrowVertical,
|
|
29
|
+
ArrowRight: FocusKeys.ArrowHorizontal,
|
|
30
|
+
h: FocusKeys.HL,
|
|
31
|
+
j: FocusKeys.JK,
|
|
32
|
+
k: FocusKeys.JK,
|
|
33
|
+
l: FocusKeys.HL,
|
|
34
|
+
a: FocusKeys.AD,
|
|
35
|
+
s: FocusKeys.WS,
|
|
36
|
+
w: FocusKeys.WS,
|
|
37
|
+
d: FocusKeys.AD,
|
|
38
|
+
Tab: FocusKeys.Tab,
|
|
39
|
+
Home: FocusKeys.HomeAndEnd,
|
|
40
|
+
End: FocusKeys.HomeAndEnd,
|
|
41
|
+
PageUp: FocusKeys.PageUpDown,
|
|
42
|
+
PageDown: FocusKeys.PageUpDown
|
|
43
|
+
};
|
|
44
|
+
const KEY_TO_DIRECTION = {
|
|
45
|
+
ArrowLeft: 'previous',
|
|
46
|
+
ArrowDown: 'next',
|
|
47
|
+
ArrowUp: 'previous',
|
|
48
|
+
ArrowRight: 'next',
|
|
49
|
+
h: 'previous',
|
|
50
|
+
j: 'next',
|
|
51
|
+
k: 'previous',
|
|
52
|
+
l: 'next',
|
|
53
|
+
a: 'previous',
|
|
54
|
+
s: 'next',
|
|
55
|
+
w: 'previous',
|
|
56
|
+
d: 'next',
|
|
57
|
+
Tab: 'next',
|
|
58
|
+
Home: 'start',
|
|
59
|
+
End: 'end',
|
|
60
|
+
PageUp: 'start',
|
|
61
|
+
PageDown: 'end'
|
|
62
|
+
};
|
|
63
|
+
function getDirection(keyboardEvent) {
|
|
64
|
+
const direction = KEY_TO_DIRECTION[keyboardEvent.key];
|
|
65
|
+
if (keyboardEvent.key === 'Tab' && keyboardEvent.shiftKey) {
|
|
66
|
+
return 'previous';
|
|
67
|
+
}
|
|
68
|
+
const isMac = (0, user_agent_js_1.isMacOS)();
|
|
69
|
+
if ((isMac && keyboardEvent.metaKey) || (!isMac && keyboardEvent.ctrlKey)) {
|
|
70
|
+
if (keyboardEvent.key === 'ArrowLeft' || keyboardEvent.key === 'ArrowUp') {
|
|
71
|
+
return 'start';
|
|
72
|
+
}
|
|
73
|
+
else if (keyboardEvent.key === 'ArrowRight' || keyboardEvent.key === 'ArrowDown') {
|
|
74
|
+
return 'end';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return direction;
|
|
78
|
+
}
|
|
79
|
+
function shouldIgnoreFocusHandling(keyboardEvent, activeElement) {
|
|
80
|
+
const key = keyboardEvent.key;
|
|
81
|
+
const keyLength = [...key].length;
|
|
82
|
+
const isTextInput = (activeElement instanceof HTMLInputElement && activeElement.type === 'text') ||
|
|
83
|
+
activeElement instanceof HTMLTextAreaElement;
|
|
84
|
+
if (isTextInput && (keyLength === 1 || key === 'Home' || key === 'End')) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
if (activeElement instanceof HTMLSelectElement) {
|
|
88
|
+
if (keyLength === 1) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (key === 'ArrowDown' && (0, user_agent_js_1.isMacOS)() && !keyboardEvent.metaKey) {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
if (key === 'ArrowDown' && !(0, user_agent_js_1.isMacOS)() && keyboardEvent.altKey) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (activeElement instanceof HTMLTextAreaElement && (key === 'PageUp' || key === 'PageDown')) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
if (isTextInput) {
|
|
102
|
+
const textInput = activeElement;
|
|
103
|
+
const cursorAtStart = textInput.selectionStart === 0 && textInput.selectionEnd === 0;
|
|
104
|
+
const cursorAtEnd = textInput.selectionStart === textInput.value.length && textInput.selectionEnd === textInput.value.length;
|
|
105
|
+
if (key === 'ArrowLeft' && !cursorAtStart) {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
if (key === 'ArrowRight' && !cursorAtEnd) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (textInput instanceof HTMLTextAreaElement) {
|
|
112
|
+
if (key === 'ArrowUp' && !cursorAtStart) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (key === 'ArrowDown' && !cursorAtEnd) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
exports.isActiveDescendantAttribute = 'data-is-active-descendant';
|
|
123
|
+
exports.activeDescendantActivatedDirectly = 'activated-directly';
|
|
124
|
+
exports.activeDescendantActivatedIndirectly = 'activated-indirectly';
|
|
125
|
+
exports.hasActiveDescendantAttribute = 'data-has-active-descendant';
|
|
126
|
+
function focusZone(container, settings) {
|
|
127
|
+
var _a, _b, _c, _d;
|
|
128
|
+
const focusableElements = [];
|
|
129
|
+
const savedTabIndex = new WeakMap();
|
|
130
|
+
const bindKeys = (_a = settings === null || settings === void 0 ? void 0 : settings.bindKeys) !== null && _a !== void 0 ? _a : ((settings === null || settings === void 0 ? void 0 : settings.getNextFocusable) ? FocusKeys.ArrowAll : FocusKeys.ArrowVertical) | FocusKeys.HomeAndEnd;
|
|
131
|
+
const focusOutBehavior = (_b = settings === null || settings === void 0 ? void 0 : settings.focusOutBehavior) !== null && _b !== void 0 ? _b : 'stop';
|
|
132
|
+
const focusInStrategy = (_c = settings === null || settings === void 0 ? void 0 : settings.focusInStrategy) !== null && _c !== void 0 ? _c : 'previous';
|
|
133
|
+
const activeDescendantControl = settings === null || settings === void 0 ? void 0 : settings.activeDescendantControl;
|
|
134
|
+
const activeDescendantCallback = settings === null || settings === void 0 ? void 0 : settings.onActiveDescendantChanged;
|
|
135
|
+
let currentFocusedElement;
|
|
136
|
+
function getFirstFocusableElement() {
|
|
137
|
+
return focusableElements[0];
|
|
138
|
+
}
|
|
139
|
+
function isActiveDescendantInputFocused() {
|
|
140
|
+
return document.activeElement === activeDescendantControl;
|
|
141
|
+
}
|
|
142
|
+
function updateFocusedElement(to, directlyActivated = false) {
|
|
143
|
+
const from = currentFocusedElement;
|
|
144
|
+
currentFocusedElement = to;
|
|
145
|
+
if (activeDescendantControl) {
|
|
146
|
+
if (to && isActiveDescendantInputFocused()) {
|
|
147
|
+
setActiveDescendant(from, to, directlyActivated);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
clearActiveDescendant();
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (from && from !== to && savedTabIndex.has(from)) {
|
|
155
|
+
from.setAttribute('tabindex', '-1');
|
|
156
|
+
}
|
|
157
|
+
to === null || to === void 0 ? void 0 : to.setAttribute('tabindex', '0');
|
|
158
|
+
}
|
|
159
|
+
function setActiveDescendant(from, to, directlyActivated = false) {
|
|
160
|
+
if (!to.id) {
|
|
161
|
+
to.setAttribute('id', (0, unique_id_js_1.uniqueId)());
|
|
162
|
+
}
|
|
163
|
+
if (from && from !== to) {
|
|
164
|
+
from.removeAttribute(exports.isActiveDescendantAttribute);
|
|
165
|
+
}
|
|
166
|
+
if (!activeDescendantControl ||
|
|
167
|
+
(!directlyActivated && activeDescendantControl.getAttribute('aria-activedescendant') === to.id)) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
activeDescendantControl.setAttribute('aria-activedescendant', to.id);
|
|
171
|
+
container.setAttribute(exports.hasActiveDescendantAttribute, to.id);
|
|
172
|
+
to.setAttribute(exports.isActiveDescendantAttribute, directlyActivated ? exports.activeDescendantActivatedDirectly : exports.activeDescendantActivatedIndirectly);
|
|
173
|
+
activeDescendantCallback === null || activeDescendantCallback === void 0 ? void 0 : activeDescendantCallback(to, from, directlyActivated);
|
|
174
|
+
}
|
|
175
|
+
function clearActiveDescendant(previouslyActiveElement = currentFocusedElement) {
|
|
176
|
+
if (focusInStrategy === 'first') {
|
|
177
|
+
currentFocusedElement = undefined;
|
|
178
|
+
}
|
|
179
|
+
activeDescendantControl === null || activeDescendantControl === void 0 ? void 0 : activeDescendantControl.removeAttribute('aria-activedescendant');
|
|
180
|
+
container.removeAttribute(exports.hasActiveDescendantAttribute);
|
|
181
|
+
previouslyActiveElement === null || previouslyActiveElement === void 0 ? void 0 : previouslyActiveElement.removeAttribute(exports.isActiveDescendantAttribute);
|
|
182
|
+
activeDescendantCallback === null || activeDescendantCallback === void 0 ? void 0 : activeDescendantCallback(undefined, previouslyActiveElement, false);
|
|
183
|
+
}
|
|
184
|
+
function beginFocusManagement(...elements) {
|
|
185
|
+
const filteredElements = elements.filter(e => { var _a, _b; return (_b = (_a = settings === null || settings === void 0 ? void 0 : settings.focusableElementFilter) === null || _a === void 0 ? void 0 : _a.call(settings, e)) !== null && _b !== void 0 ? _b : true; });
|
|
186
|
+
if (filteredElements.length === 0) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const insertIndex = focusableElements.findIndex(e => (e.compareDocumentPosition(filteredElements[0]) & Node.DOCUMENT_POSITION_PRECEDING) > 0);
|
|
190
|
+
focusableElements.splice(insertIndex === -1 ? focusableElements.length : insertIndex, 0, ...filteredElements);
|
|
191
|
+
for (const element of filteredElements) {
|
|
192
|
+
if (!savedTabIndex.has(element)) {
|
|
193
|
+
savedTabIndex.set(element, element.getAttribute('tabindex'));
|
|
194
|
+
}
|
|
195
|
+
element.setAttribute('tabindex', '-1');
|
|
196
|
+
}
|
|
197
|
+
if (!currentFocusedElement) {
|
|
198
|
+
updateFocusedElement(getFirstFocusableElement());
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function endFocusManagement(...elements) {
|
|
202
|
+
for (const element of elements) {
|
|
203
|
+
const focusableElementIndex = focusableElements.indexOf(element);
|
|
204
|
+
if (focusableElementIndex >= 0) {
|
|
205
|
+
focusableElements.splice(focusableElementIndex, 1);
|
|
206
|
+
}
|
|
207
|
+
const savedIndex = savedTabIndex.get(element);
|
|
208
|
+
if (savedIndex !== undefined) {
|
|
209
|
+
if (savedIndex === null) {
|
|
210
|
+
element.removeAttribute('tabindex');
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
element.setAttribute('tabindex', savedIndex);
|
|
214
|
+
}
|
|
215
|
+
savedTabIndex.delete(element);
|
|
216
|
+
}
|
|
217
|
+
if (element === currentFocusedElement) {
|
|
218
|
+
const nextElementToFocus = getFirstFocusableElement();
|
|
219
|
+
updateFocusedElement(nextElementToFocus);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(container));
|
|
224
|
+
updateFocusedElement(getFirstFocusableElement());
|
|
225
|
+
const observer = new MutationObserver(mutations => {
|
|
226
|
+
for (const mutation of mutations) {
|
|
227
|
+
for (const removedNode of mutation.removedNodes) {
|
|
228
|
+
if (removedNode instanceof HTMLElement) {
|
|
229
|
+
endFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(removedNode));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
for (const mutation of mutations) {
|
|
234
|
+
for (const addedNode of mutation.addedNodes) {
|
|
235
|
+
if (addedNode instanceof HTMLElement) {
|
|
236
|
+
beginFocusManagement(...(0, iterate_focusable_elements_js_1.iterateFocusableElements)(addedNode));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
observer.observe(container, {
|
|
242
|
+
subtree: true,
|
|
243
|
+
childList: true
|
|
244
|
+
});
|
|
245
|
+
const controller = new AbortController();
|
|
246
|
+
const signal = (_d = settings === null || settings === void 0 ? void 0 : settings.abortSignal) !== null && _d !== void 0 ? _d : controller.signal;
|
|
247
|
+
signal.addEventListener('abort', () => {
|
|
248
|
+
endFocusManagement(...focusableElements);
|
|
249
|
+
});
|
|
250
|
+
let elementIndexFocusedByClick = undefined;
|
|
251
|
+
container.addEventListener('mousedown', event => {
|
|
252
|
+
if (event.target instanceof HTMLElement && event.target !== document.activeElement) {
|
|
253
|
+
elementIndexFocusedByClick = focusableElements.indexOf(event.target);
|
|
254
|
+
}
|
|
255
|
+
}, { signal });
|
|
256
|
+
if (activeDescendantControl) {
|
|
257
|
+
container.addEventListener('focusin', event => {
|
|
258
|
+
if (event.target instanceof HTMLElement && focusableElements.includes(event.target)) {
|
|
259
|
+
activeDescendantControl.focus();
|
|
260
|
+
updateFocusedElement(event.target);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
container.addEventListener('mousemove', ({ target }) => {
|
|
264
|
+
if (!(target instanceof Node)) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const focusableElement = focusableElements.find(element => element.contains(target));
|
|
268
|
+
if (focusableElement) {
|
|
269
|
+
updateFocusedElement(focusableElement);
|
|
270
|
+
}
|
|
271
|
+
}, { signal, capture: true });
|
|
272
|
+
activeDescendantControl.addEventListener('focusin', () => {
|
|
273
|
+
if (!currentFocusedElement) {
|
|
274
|
+
updateFocusedElement(getFirstFocusableElement());
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
setActiveDescendant(undefined, currentFocusedElement);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
activeDescendantControl.addEventListener('focusout', () => {
|
|
281
|
+
clearActiveDescendant();
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
container.addEventListener('focusin', event => {
|
|
286
|
+
if (event.target instanceof HTMLElement) {
|
|
287
|
+
if (elementIndexFocusedByClick !== undefined) {
|
|
288
|
+
if (elementIndexFocusedByClick >= 0) {
|
|
289
|
+
if (focusableElements[elementIndexFocusedByClick] !== currentFocusedElement) {
|
|
290
|
+
updateFocusedElement(focusableElements[elementIndexFocusedByClick]);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
elementIndexFocusedByClick = undefined;
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
if (focusInStrategy === 'previous') {
|
|
297
|
+
updateFocusedElement(event.target);
|
|
298
|
+
}
|
|
299
|
+
else if (focusInStrategy === 'closest' || focusInStrategy === 'first') {
|
|
300
|
+
if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
|
|
301
|
+
const targetElementIndex = lastKeyboardFocusDirection === 'previous' ? focusableElements.length - 1 : 0;
|
|
302
|
+
const targetElement = focusableElements[targetElementIndex];
|
|
303
|
+
targetElement === null || targetElement === void 0 ? void 0 : targetElement.focus();
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
updateFocusedElement(event.target);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
else if (typeof focusInStrategy === 'function') {
|
|
311
|
+
if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
|
|
312
|
+
const elementToFocus = focusInStrategy(event.relatedTarget);
|
|
313
|
+
const requestedFocusElementIndex = elementToFocus ? focusableElements.indexOf(elementToFocus) : -1;
|
|
314
|
+
if (requestedFocusElementIndex >= 0 && elementToFocus instanceof HTMLElement) {
|
|
315
|
+
elementToFocus.focus();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
console.warn('Element requested is not a known focusable element.');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
updateFocusedElement(event.target);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
lastKeyboardFocusDirection = undefined;
|
|
329
|
+
}, { signal });
|
|
330
|
+
}
|
|
331
|
+
const keyboardEventRecipient = activeDescendantControl !== null && activeDescendantControl !== void 0 ? activeDescendantControl : container;
|
|
332
|
+
let lastKeyboardFocusDirection = undefined;
|
|
333
|
+
if (focusInStrategy === 'closest') {
|
|
334
|
+
document.addEventListener('keydown', event => {
|
|
335
|
+
if (event.key === 'Tab') {
|
|
336
|
+
lastKeyboardFocusDirection = getDirection(event);
|
|
337
|
+
}
|
|
338
|
+
}, { signal, capture: true });
|
|
339
|
+
}
|
|
340
|
+
function getCurrentFocusedIndex() {
|
|
341
|
+
if (!currentFocusedElement) {
|
|
342
|
+
return 0;
|
|
343
|
+
}
|
|
344
|
+
const focusedIndex = focusableElements.indexOf(currentFocusedElement);
|
|
345
|
+
const fallbackIndex = currentFocusedElement === container ? -1 : 0;
|
|
346
|
+
return focusedIndex !== -1 ? focusedIndex : fallbackIndex;
|
|
347
|
+
}
|
|
348
|
+
keyboardEventRecipient.addEventListener('keydown', event => {
|
|
349
|
+
var _a;
|
|
350
|
+
if (event.key in KEY_TO_DIRECTION) {
|
|
351
|
+
const keyBit = KEY_TO_BIT[event.key];
|
|
352
|
+
if (!event.defaultPrevented &&
|
|
353
|
+
(keyBit & bindKeys) > 0 &&
|
|
354
|
+
!shouldIgnoreFocusHandling(event, document.activeElement)) {
|
|
355
|
+
const direction = getDirection(event);
|
|
356
|
+
let nextElementToFocus = undefined;
|
|
357
|
+
if (settings === null || settings === void 0 ? void 0 : settings.getNextFocusable) {
|
|
358
|
+
nextElementToFocus = settings.getNextFocusable(direction, (_a = document.activeElement) !== null && _a !== void 0 ? _a : undefined, event);
|
|
359
|
+
}
|
|
360
|
+
if (!nextElementToFocus) {
|
|
361
|
+
const lastFocusedIndex = getCurrentFocusedIndex();
|
|
362
|
+
let nextFocusedIndex = lastFocusedIndex;
|
|
363
|
+
if (direction === 'previous') {
|
|
364
|
+
nextFocusedIndex -= 1;
|
|
365
|
+
}
|
|
366
|
+
else if (direction === 'start') {
|
|
367
|
+
nextFocusedIndex = 0;
|
|
368
|
+
}
|
|
369
|
+
else if (direction === 'next') {
|
|
370
|
+
nextFocusedIndex += 1;
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
nextFocusedIndex = focusableElements.length - 1;
|
|
374
|
+
}
|
|
375
|
+
if (nextFocusedIndex < 0) {
|
|
376
|
+
if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
|
|
377
|
+
nextFocusedIndex = focusableElements.length - 1;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
nextFocusedIndex = 0;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
if (nextFocusedIndex >= focusableElements.length) {
|
|
384
|
+
if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
|
|
385
|
+
nextFocusedIndex = 0;
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
nextFocusedIndex = focusableElements.length - 1;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (lastFocusedIndex !== nextFocusedIndex) {
|
|
392
|
+
nextElementToFocus = focusableElements[nextFocusedIndex];
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (activeDescendantControl) {
|
|
396
|
+
updateFocusedElement(nextElementToFocus || currentFocusedElement, true);
|
|
397
|
+
}
|
|
398
|
+
else if (nextElementToFocus) {
|
|
399
|
+
lastKeyboardFocusDirection = direction;
|
|
400
|
+
nextElementToFocus.focus();
|
|
401
|
+
}
|
|
402
|
+
if (event.key !== 'Tab' || nextElementToFocus) {
|
|
403
|
+
event.preventDefault();
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}, { signal });
|
|
408
|
+
return controller;
|
|
409
|
+
}
|
|
410
|
+
exports.focusZone = focusZone;
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./anchored-position.js"), exports);
|
|
14
|
+
__exportStar(require("./focus-trap.js"), exports);
|
|
15
|
+
__exportStar(require("./focus-zone.js"), exports);
|
|
16
|
+
__exportStar(require("./scroll-into-view.js"), exports);
|
|
File without changes
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.polyfill = void 0;
|
|
4
|
+
let signalSupported = false;
|
|
5
|
+
function noop() { }
|
|
6
|
+
try {
|
|
7
|
+
const options = Object.create({}, {
|
|
8
|
+
signal: {
|
|
9
|
+
get() {
|
|
10
|
+
signalSupported = true;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
window.addEventListener('test', noop, options);
|
|
15
|
+
window.removeEventListener('test', noop, options);
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
}
|
|
19
|
+
function featureSupported() {
|
|
20
|
+
return signalSupported;
|
|
21
|
+
}
|
|
22
|
+
function monkeyPatch() {
|
|
23
|
+
if (typeof window === 'undefined') {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const originalAddEventListener = EventTarget.prototype.addEventListener;
|
|
27
|
+
EventTarget.prototype.addEventListener = function (name, originalCallback, optionsOrCapture) {
|
|
28
|
+
if (typeof optionsOrCapture === 'object' &&
|
|
29
|
+
'signal' in optionsOrCapture &&
|
|
30
|
+
optionsOrCapture.signal instanceof AbortSignal) {
|
|
31
|
+
originalAddEventListener.call(optionsOrCapture.signal, 'abort', () => {
|
|
32
|
+
this.removeEventListener(name, originalCallback, optionsOrCapture);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return originalAddEventListener.call(this, name, originalCallback, optionsOrCapture);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function polyfill() {
|
|
39
|
+
if (!featureSupported()) {
|
|
40
|
+
monkeyPatch();
|
|
41
|
+
signalSupported = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.polyfill = polyfill;
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scrollIntoView = void 0;
|
|
4
|
+
function scrollIntoView(child, viewingArea, { direction = 'vertical', startMargin = 0, endMargin = 0, behavior = 'smooth' } = {}) {
|
|
5
|
+
const startSide = direction === 'vertical' ? 'top' : 'left';
|
|
6
|
+
const endSide = direction === 'vertical' ? 'bottom' : 'right';
|
|
7
|
+
const scrollSide = direction === 'vertical' ? 'scrollTop' : 'scrollLeft';
|
|
8
|
+
const { [startSide]: childStart, [endSide]: childEnd } = child.getBoundingClientRect();
|
|
9
|
+
const { [startSide]: viewingAreaStart, [endSide]: viewingAreaEnd } = viewingArea.getBoundingClientRect();
|
|
10
|
+
const isChildStartAboveViewingArea = childStart < viewingAreaStart + startMargin;
|
|
11
|
+
const isChildBottomBelowViewingArea = childEnd > viewingAreaEnd - endMargin;
|
|
12
|
+
if (isChildStartAboveViewingArea) {
|
|
13
|
+
const scrollHeightToChildStart = childStart - viewingAreaStart + viewingArea[scrollSide];
|
|
14
|
+
viewingArea.scrollTo({ behavior, [startSide]: scrollHeightToChildStart - startMargin });
|
|
15
|
+
}
|
|
16
|
+
else if (isChildBottomBelowViewingArea) {
|
|
17
|
+
const scrollHeightToChildBottom = childEnd - viewingAreaEnd + viewingArea[scrollSide];
|
|
18
|
+
viewingArea.scrollTo({ behavior, [startSide]: scrollHeightToChildBottom + endMargin });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.scrollIntoView = scrollIntoView;
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./iterate-focusable-elements.js"), exports);
|
|
14
|
+
__exportStar(require("./unique-id.js"), exports);
|
|
15
|
+
__exportStar(require("./user-agent.js"), exports);
|
|
@@ -4,5 +4,6 @@ export interface IterateFocusableElements {
|
|
|
4
4
|
onlyTabbable?: boolean;
|
|
5
5
|
}
|
|
6
6
|
export declare function iterateFocusableElements(container: HTMLElement, options?: IterateFocusableElements): Generator<HTMLElement, undefined, undefined>;
|
|
7
|
+
export declare function getFocusableChild(container: HTMLElement, lastChild?: boolean): HTMLElement | undefined;
|
|
7
8
|
export declare function isFocusable(elem: HTMLElement, strict?: boolean): boolean;
|
|
8
9
|
export declare function isTabbable(elem: HTMLElement, strict?: boolean): boolean;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTabbable = exports.isFocusable = exports.getFocusableChild = exports.iterateFocusableElements = void 0;
|
|
4
|
+
function* iterateFocusableElements(container, options = {}) {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const strict = (_a = options.strict) !== null && _a !== void 0 ? _a : false;
|
|
7
|
+
const acceptFn = ((_b = options.onlyTabbable) !== null && _b !== void 0 ? _b : false) ? isTabbable : isFocusable;
|
|
8
|
+
const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {
|
|
9
|
+
acceptNode: node => node instanceof HTMLElement && acceptFn(node, strict) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
|
|
10
|
+
});
|
|
11
|
+
let nextNode = null;
|
|
12
|
+
if (!options.reverse && acceptFn(container, strict)) {
|
|
13
|
+
yield container;
|
|
14
|
+
}
|
|
15
|
+
if (options.reverse) {
|
|
16
|
+
let lastChild = walker.lastChild();
|
|
17
|
+
while (lastChild) {
|
|
18
|
+
nextNode = lastChild;
|
|
19
|
+
lastChild = walker.lastChild();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
nextNode = walker.firstChild();
|
|
24
|
+
}
|
|
25
|
+
while (nextNode instanceof HTMLElement) {
|
|
26
|
+
yield nextNode;
|
|
27
|
+
nextNode = options.reverse ? walker.previousNode() : walker.nextNode();
|
|
28
|
+
}
|
|
29
|
+
if (options.reverse && acceptFn(container, strict)) {
|
|
30
|
+
yield container;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
exports.iterateFocusableElements = iterateFocusableElements;
|
|
35
|
+
function getFocusableChild(container, lastChild = false) {
|
|
36
|
+
return iterateFocusableElements(container, { reverse: lastChild, strict: true, onlyTabbable: true }).next().value;
|
|
37
|
+
}
|
|
38
|
+
exports.getFocusableChild = getFocusableChild;
|
|
39
|
+
function isFocusable(elem, strict = false) {
|
|
40
|
+
const disabledAttrInert = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'OPTGROUP', 'OPTION', 'FIELDSET'].includes(elem.tagName) &&
|
|
41
|
+
elem.disabled;
|
|
42
|
+
const hiddenInert = elem.hidden;
|
|
43
|
+
const hiddenInputInert = elem instanceof HTMLInputElement && elem.type === 'hidden';
|
|
44
|
+
const sentinelInert = elem.classList.contains('sentinel');
|
|
45
|
+
if (disabledAttrInert || hiddenInert || hiddenInputInert || sentinelInert) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (strict) {
|
|
49
|
+
const sizeInert = elem.offsetWidth === 0 || elem.offsetHeight === 0;
|
|
50
|
+
const visibilityInert = ['hidden', 'collapse'].includes(getComputedStyle(elem).visibility);
|
|
51
|
+
const clientRectsInert = elem.getClientRects().length === 0;
|
|
52
|
+
if (sizeInert || visibilityInert || clientRectsInert) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (elem.getAttribute('tabindex') != null) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (elem instanceof HTMLAnchorElement && elem.getAttribute('href') == null) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return elem.tabIndex !== -1;
|
|
63
|
+
}
|
|
64
|
+
exports.isFocusable = isFocusable;
|
|
65
|
+
function isTabbable(elem, strict = false) {
|
|
66
|
+
return isFocusable(elem, strict) && elem.getAttribute('tabindex') !== '-1';
|
|
67
|
+
}
|
|
68
|
+
exports.isTabbable = isTabbable;
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isMacOS = void 0;
|
|
4
|
+
let isMac = undefined;
|
|
5
|
+
function isMacOS() {
|
|
6
|
+
if (isMac === undefined) {
|
|
7
|
+
isMac = /^mac/i.test(window.navigator.platform);
|
|
8
|
+
}
|
|
9
|
+
return isMac;
|
|
10
|
+
}
|
|
11
|
+
exports.isMacOS = isMacOS;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare type AnchorAlignment = 'start' | 'center' | 'end';
|
|
2
|
+
export declare type AnchorSide = 'inside-top' | 'inside-bottom' | 'inside-left' | 'inside-right' | 'inside-center' | 'outside-top' | 'outside-bottom' | 'outside-left' | 'outside-right';
|
|
3
|
+
export interface PositionSettings {
|
|
4
|
+
side: AnchorSide;
|
|
5
|
+
align: AnchorAlignment;
|
|
6
|
+
anchorOffset: number;
|
|
7
|
+
alignmentOffset: number;
|
|
8
|
+
allowOutOfBounds: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface AnchorPosition {
|
|
11
|
+
top: number;
|
|
12
|
+
left: number;
|
|
13
|
+
anchorSide: AnchorSide;
|
|
14
|
+
}
|
|
15
|
+
export declare function getAnchoredPosition(floatingElement: Element, anchorElement: Element | DOMRect, settings?: Partial<PositionSettings>): AnchorPosition;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function focusTrap(container: HTMLElement, initialFocus?: HTMLElement, abortSignal?: AbortSignal): AbortController | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getFocusableChild, isTabbable } from './utils/iterate-focusable-elements.js';
|
|
2
2
|
import { polyfill as eventListenerSignalPolyfill } from './polyfills/event-listener-signal.js';
|
|
3
3
|
eventListenerSignalPolyfill();
|
|
4
4
|
const suspendedTrapStack = [];
|
|
@@ -16,13 +16,28 @@ function followSignal(signal) {
|
|
|
16
16
|
});
|
|
17
17
|
return controller;
|
|
18
18
|
}
|
|
19
|
-
function getFocusableChild(container, lastChild = false) {
|
|
20
|
-
return iterateFocusableElements(container, { reverse: lastChild, strict: true, onlyTabbable: true }).next().value;
|
|
21
|
-
}
|
|
22
19
|
export function focusTrap(container, initialFocus, abortSignal) {
|
|
23
20
|
const controller = new AbortController();
|
|
24
21
|
const signal = abortSignal !== null && abortSignal !== void 0 ? abortSignal : controller.signal;
|
|
25
22
|
container.setAttribute('data-focus-trap', 'active');
|
|
23
|
+
const sentinelStart = document.createElement('span');
|
|
24
|
+
sentinelStart.setAttribute('class', 'sentinel');
|
|
25
|
+
sentinelStart.setAttribute('tabindex', '0');
|
|
26
|
+
sentinelStart.setAttribute('aria-hidden', 'true');
|
|
27
|
+
sentinelStart.onfocus = () => {
|
|
28
|
+
const lastFocusableChild = getFocusableChild(container, true);
|
|
29
|
+
lastFocusableChild === null || lastFocusableChild === void 0 ? void 0 : lastFocusableChild.focus();
|
|
30
|
+
};
|
|
31
|
+
const sentinelEnd = document.createElement('span');
|
|
32
|
+
sentinelEnd.setAttribute('class', 'sentinel');
|
|
33
|
+
sentinelEnd.setAttribute('tabindex', '0');
|
|
34
|
+
sentinelEnd.setAttribute('aria-hidden', 'true');
|
|
35
|
+
sentinelEnd.onfocus = () => {
|
|
36
|
+
const firstFocusableChild = getFocusableChild(container);
|
|
37
|
+
firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
|
|
38
|
+
};
|
|
39
|
+
container.prepend(sentinelStart);
|
|
40
|
+
container.append(sentinelEnd);
|
|
26
41
|
let lastFocusedChild = undefined;
|
|
27
42
|
function ensureTrapZoneHasFocus(focusedElement) {
|
|
28
43
|
if (focusedElement instanceof HTMLElement && document.contains(container)) {
|
|
@@ -40,36 +55,14 @@ export function focusTrap(container, initialFocus, abortSignal) {
|
|
|
40
55
|
return;
|
|
41
56
|
}
|
|
42
57
|
else {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
container.setAttribute('tabindex', '-1');
|
|
46
|
-
}
|
|
47
|
-
container.focus();
|
|
48
|
-
if (containerNeedsTemporaryTabIndex) {
|
|
49
|
-
container.addEventListener('blur', () => container.removeAttribute('tabindex'), { once: true });
|
|
50
|
-
}
|
|
58
|
+
const firstFocusableChild = getFocusableChild(container);
|
|
59
|
+
firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
|
|
51
60
|
return;
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
const wrappingController = followSignal(signal);
|
|
57
|
-
container.addEventListener('keydown', event => {
|
|
58
|
-
if (event.key !== 'Tab' || event.defaultPrevented) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const { target } = event;
|
|
62
|
-
const firstFocusableChild = getFocusableChild(container);
|
|
63
|
-
const lastFocusableChild = getFocusableChild(container, true);
|
|
64
|
-
if (target === firstFocusableChild && event.shiftKey) {
|
|
65
|
-
event.preventDefault();
|
|
66
|
-
lastFocusableChild === null || lastFocusableChild === void 0 ? void 0 : lastFocusableChild.focus();
|
|
67
|
-
}
|
|
68
|
-
else if (target === lastFocusableChild && !event.shiftKey) {
|
|
69
|
-
event.preventDefault();
|
|
70
|
-
firstFocusableChild === null || firstFocusableChild === void 0 ? void 0 : firstFocusableChild.focus();
|
|
71
|
-
}
|
|
72
|
-
}, { signal: wrappingController.signal });
|
|
73
66
|
if (activeTrap) {
|
|
74
67
|
const suspendedTrap = activeTrap;
|
|
75
68
|
activeTrap.container.setAttribute('data-focus-trap', 'suspended');
|
|
@@ -81,6 +74,9 @@ export function focusTrap(container, initialFocus, abortSignal) {
|
|
|
81
74
|
});
|
|
82
75
|
signal.addEventListener('abort', () => {
|
|
83
76
|
container.removeAttribute('data-focus-trap');
|
|
77
|
+
const sentinels = container.getElementsByClassName('sentinel');
|
|
78
|
+
while (sentinels.length > 0)
|
|
79
|
+
sentinels[0].remove();
|
|
84
80
|
const suspendedTrapIndex = suspendedTrapStack.findIndex(t => t.container === container);
|
|
85
81
|
if (suspendedTrapIndex >= 0) {
|
|
86
82
|
suspendedTrapStack.splice(suspendedTrapIndex, 1);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare type Direction = 'previous' | 'next' | 'start' | 'end';
|
|
2
|
+
export declare type FocusMovementKeys = 'ArrowLeft' | 'ArrowDown' | 'ArrowUp' | 'ArrowRight' | 'h' | 'j' | 'k' | 'l' | 'a' | 's' | 'w' | 'd' | 'Tab' | 'Home' | 'End' | 'PageUp' | 'PageDown';
|
|
3
|
+
export declare enum FocusKeys {
|
|
4
|
+
ArrowHorizontal = 1,
|
|
5
|
+
ArrowVertical = 2,
|
|
6
|
+
JK = 4,
|
|
7
|
+
HL = 8,
|
|
8
|
+
HomeAndEnd = 16,
|
|
9
|
+
PageUpDown = 256,
|
|
10
|
+
WS = 32,
|
|
11
|
+
AD = 64,
|
|
12
|
+
Tab = 128,
|
|
13
|
+
ArrowAll = 3,
|
|
14
|
+
HJKL = 12,
|
|
15
|
+
WASD = 96,
|
|
16
|
+
All = 511
|
|
17
|
+
}
|
|
18
|
+
export interface FocusZoneSettings {
|
|
19
|
+
focusOutBehavior?: 'stop' | 'wrap';
|
|
20
|
+
getNextFocusable?: (direction: Direction, from: Element | undefined, event: KeyboardEvent) => HTMLElement | undefined;
|
|
21
|
+
focusableElementFilter?: (element: HTMLElement) => boolean;
|
|
22
|
+
bindKeys?: FocusKeys;
|
|
23
|
+
abortSignal?: AbortSignal;
|
|
24
|
+
activeDescendantControl?: HTMLElement;
|
|
25
|
+
onActiveDescendantChanged?: (newActiveDescendant: HTMLElement | undefined, previousActiveDescendant: HTMLElement | undefined, directlyActivated: boolean) => void;
|
|
26
|
+
focusInStrategy?: 'first' | 'closest' | 'previous' | ((previousFocusedElement: Element) => HTMLElement | undefined);
|
|
27
|
+
}
|
|
28
|
+
export declare const isActiveDescendantAttribute = "data-is-active-descendant";
|
|
29
|
+
export declare const activeDescendantActivatedDirectly = "activated-directly";
|
|
30
|
+
export declare const activeDescendantActivatedIndirectly = "activated-indirectly";
|
|
31
|
+
export declare const hasActiveDescendantAttribute = "data-has-active-descendant";
|
|
32
|
+
export declare function focusZone(container: HTMLElement, settings?: FocusZoneSettings): AbortController;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface ScrollIntoViewOptions {
|
|
2
|
+
direction?: 'horizontal' | 'vertical';
|
|
3
|
+
startMargin?: number;
|
|
4
|
+
endMargin?: number;
|
|
5
|
+
behavior?: ScrollBehavior;
|
|
6
|
+
}
|
|
7
|
+
export declare function scrollIntoView(child: HTMLElement, viewingArea: HTMLElement, { direction, startMargin, endMargin, behavior }?: ScrollIntoViewOptions): void;
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface IterateFocusableElements {
|
|
2
|
+
reverse?: boolean;
|
|
3
|
+
strict?: boolean;
|
|
4
|
+
onlyTabbable?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function iterateFocusableElements(container: HTMLElement, options?: IterateFocusableElements): Generator<HTMLElement, undefined, undefined>;
|
|
7
|
+
export declare function getFocusableChild(container: HTMLElement, lastChild?: boolean): HTMLElement | undefined;
|
|
8
|
+
export declare function isFocusable(elem: HTMLElement, strict?: boolean): boolean;
|
|
9
|
+
export declare function isTabbable(elem: HTMLElement, strict?: boolean): boolean;
|
|
@@ -28,12 +28,16 @@ export function* iterateFocusableElements(container, options = {}) {
|
|
|
28
28
|
}
|
|
29
29
|
return undefined;
|
|
30
30
|
}
|
|
31
|
+
export function getFocusableChild(container, lastChild = false) {
|
|
32
|
+
return iterateFocusableElements(container, { reverse: lastChild, strict: true, onlyTabbable: true }).next().value;
|
|
33
|
+
}
|
|
31
34
|
export function isFocusable(elem, strict = false) {
|
|
32
35
|
const disabledAttrInert = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'OPTGROUP', 'OPTION', 'FIELDSET'].includes(elem.tagName) &&
|
|
33
36
|
elem.disabled;
|
|
34
37
|
const hiddenInert = elem.hidden;
|
|
35
38
|
const hiddenInputInert = elem instanceof HTMLInputElement && elem.type === 'hidden';
|
|
36
|
-
|
|
39
|
+
const sentinelInert = elem.classList.contains('sentinel');
|
|
40
|
+
if (disabledAttrInert || hiddenInert || hiddenInputInert || sentinelInert) {
|
|
37
41
|
return false;
|
|
38
42
|
}
|
|
39
43
|
if (strict) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uniqueId(): string;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isMacOS(): boolean;
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primer/behaviors",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared behaviors for JavaScript components",
|
|
5
|
-
"main": "
|
|
6
|
-
"
|
|
7
|
-
"
|
|
5
|
+
"main": "dist/cjs/index.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/cjs/index.js",
|
|
11
|
+
"module": "./dist/esm/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./utils": {
|
|
14
|
+
"types": "./dist/utils/index.d.ts",
|
|
15
|
+
"require": "./dist/cjs/utils/index.js",
|
|
16
|
+
"module": "./dist/esm/utils/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"types": "dist/cjs/index.d.ts",
|
|
8
20
|
"files": [
|
|
9
21
|
"dist",
|
|
10
22
|
"utils"
|
|
11
23
|
],
|
|
12
24
|
"sideEffects": [
|
|
13
|
-
"dist/focus-zone.js",
|
|
14
|
-
"dist/focus-trap.js"
|
|
25
|
+
"dist/esm/focus-zone.js",
|
|
26
|
+
"dist/esm/focus-trap.js",
|
|
27
|
+
"dist/cjs/focus-zone.js",
|
|
28
|
+
"dist/cjs/focus-trap.js"
|
|
15
29
|
],
|
|
16
30
|
"scripts": {
|
|
17
31
|
"lint": "eslint src/",
|
|
@@ -20,7 +34,9 @@
|
|
|
20
34
|
"jest": "jest",
|
|
21
35
|
"clean": "rm -rf dist",
|
|
22
36
|
"prebuild": "npm run clean",
|
|
23
|
-
"build": "
|
|
37
|
+
"build": "npm run build:esm && npm run build:cjs",
|
|
38
|
+
"build:esm": "tsc",
|
|
39
|
+
"build:cjs": "tsc --module commonjs --outDir dist/cjs",
|
|
24
40
|
"size-limit": "npm run build && size-limit",
|
|
25
41
|
"release": "npm run build && changeset publish"
|
|
26
42
|
},
|
|
@@ -44,7 +60,7 @@
|
|
|
44
60
|
"size-limit": [
|
|
45
61
|
{
|
|
46
62
|
"limit": "10kb",
|
|
47
|
-
"path": "dist/index.js"
|
|
63
|
+
"path": "dist/esm/index.js"
|
|
48
64
|
}
|
|
49
65
|
],
|
|
50
66
|
"devDependencies": {
|
package/utils/package.json
CHANGED
package/dist/focus-trap.d.ts
DELETED