@primer/behaviors 0.0.0-202201881944 → 0.0.0-202201892424
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 +89 -0
- package/dist/focus-trap.d.ts +12 -0
- package/dist/focus-zone.d.ts +137 -0
- package/dist/index.d.ts +4 -0
- package/dist/polyfills/event-listener-signal.d.ts +6 -0
- package/dist/scroll-into-view.d.ts +7 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/iterate-focusable-elements.d.ts +42 -0
- package/dist/utils/unique-id.d.ts +1 -0
- package/dist/utils/user-agent.d.ts +1 -0
- package/package.json +9 -15
- package/utils/package.json +7 -0
- package/lib/__tests__/anchored-position.test.js +0 -388
- package/lib/__tests__/focus-trap.test.js +0 -234
- package/lib/__tests__/focus-zone.test.js +0 -570
- package/lib/__tests__/iterate-focusable-elements.test.js +0 -55
- package/lib/__tests__/scroll-into-view.test.js +0 -245
- package/lib-esm/__tests__/anchored-position.test.js +0 -386
- package/lib-esm/__tests__/focus-trap.test.js +0 -227
- package/lib-esm/__tests__/focus-zone.test.js +0 -487
- package/lib-esm/__tests__/iterate-focusable-elements.test.js +0 -48
- package/lib-esm/__tests__/scroll-into-view.test.js +0 -243
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { fireEvent, render } from '@testing-library/react';
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { focusTrap } from '../focus-trap.js'; // Since we use strict `isTabbable` checks within focus trap, we need to mock these
|
|
4
|
-
// properties that Jest does not populate.
|
|
5
|
-
|
|
6
|
-
beforeAll(() => {
|
|
7
|
-
try {
|
|
8
|
-
Object.defineProperties(HTMLElement.prototype, {
|
|
9
|
-
offsetHeight: {
|
|
10
|
-
get: () => 42
|
|
11
|
-
},
|
|
12
|
-
offsetWidth: {
|
|
13
|
-
get: () => 42
|
|
14
|
-
},
|
|
15
|
-
getClientRects: {
|
|
16
|
-
get: () => () => [42]
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
} catch {// ignore
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
it('Should initially focus the container when activated', () => {
|
|
23
|
-
const {
|
|
24
|
-
container
|
|
25
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("button", {
|
|
26
|
-
tabIndex: 0
|
|
27
|
-
}, "Bad Apple"), /*#__PURE__*/React.createElement("div", {
|
|
28
|
-
id: "trapContainer"
|
|
29
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
30
|
-
tabIndex: 0
|
|
31
|
-
}, "Apple"), /*#__PURE__*/React.createElement("button", {
|
|
32
|
-
tabIndex: 0
|
|
33
|
-
}, "Banana"), /*#__PURE__*/React.createElement("button", {
|
|
34
|
-
tabIndex: 0
|
|
35
|
-
}, "Cantaloupe"))));
|
|
36
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
37
|
-
const controller = focusTrap(trapContainer);
|
|
38
|
-
expect(document.activeElement).toEqual(trapContainer);
|
|
39
|
-
controller.abort();
|
|
40
|
-
});
|
|
41
|
-
it('Should initially focus the initialFocus element when specified', () => {
|
|
42
|
-
const {
|
|
43
|
-
container
|
|
44
|
-
} = render( /*#__PURE__*/React.createElement("div", {
|
|
45
|
-
id: "trapContainer"
|
|
46
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
47
|
-
tabIndex: 0
|
|
48
|
-
}, "Apple"), /*#__PURE__*/React.createElement("button", {
|
|
49
|
-
tabIndex: 0
|
|
50
|
-
}, "Banana"), /*#__PURE__*/React.createElement("button", {
|
|
51
|
-
tabIndex: 0
|
|
52
|
-
}, "Cantaloupe")));
|
|
53
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
54
|
-
const secondButton = trapContainer.querySelectorAll('button')[1];
|
|
55
|
-
const controller = focusTrap(trapContainer, secondButton);
|
|
56
|
-
expect(document.activeElement).toEqual(secondButton);
|
|
57
|
-
controller.abort();
|
|
58
|
-
});
|
|
59
|
-
it('Should prevent focus from exiting the trap, returns focus to previously-focused element', async () => {
|
|
60
|
-
const {
|
|
61
|
-
container
|
|
62
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
63
|
-
id: "trapContainer"
|
|
64
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
65
|
-
tabIndex: 0
|
|
66
|
-
}, "Apple"), /*#__PURE__*/React.createElement("button", {
|
|
67
|
-
tabIndex: 0
|
|
68
|
-
}, "Banana"), /*#__PURE__*/React.createElement("button", {
|
|
69
|
-
tabIndex: 0
|
|
70
|
-
}, "Cantaloupe")), /*#__PURE__*/React.createElement("button", {
|
|
71
|
-
id: "durian",
|
|
72
|
-
tabIndex: 0
|
|
73
|
-
}, "Durian")));
|
|
74
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
75
|
-
const secondButton = trapContainer.querySelectorAll('button')[1];
|
|
76
|
-
const durianButton = container.querySelector('#durian');
|
|
77
|
-
const controller = focusTrap(trapContainer);
|
|
78
|
-
focus(durianButton);
|
|
79
|
-
expect(document.activeElement).toEqual(trapContainer);
|
|
80
|
-
focus(secondButton);
|
|
81
|
-
expect(document.activeElement).toEqual(secondButton);
|
|
82
|
-
focus(durianButton);
|
|
83
|
-
expect(document.activeElement).toEqual(secondButton);
|
|
84
|
-
controller.abort();
|
|
85
|
-
});
|
|
86
|
-
it('Should prevent focus from exiting the trap if there are no focusable children', async () => {
|
|
87
|
-
const {
|
|
88
|
-
container
|
|
89
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
90
|
-
id: "trapContainer"
|
|
91
|
-
}), /*#__PURE__*/React.createElement("button", {
|
|
92
|
-
id: "durian",
|
|
93
|
-
tabIndex: 0
|
|
94
|
-
}, "Durian")));
|
|
95
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
96
|
-
const durianButton = container.querySelector('#durian');
|
|
97
|
-
const controller = focusTrap(trapContainer);
|
|
98
|
-
focus(durianButton);
|
|
99
|
-
expect(document.activeElement === durianButton).toEqual(false);
|
|
100
|
-
controller.abort();
|
|
101
|
-
});
|
|
102
|
-
it('Should cycle focus from last element to first element and vice-versa', async () => {
|
|
103
|
-
const {
|
|
104
|
-
container
|
|
105
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
106
|
-
id: "trapContainer"
|
|
107
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
108
|
-
tabIndex: 0
|
|
109
|
-
}, "Apple"), /*#__PURE__*/React.createElement("button", {
|
|
110
|
-
tabIndex: 0
|
|
111
|
-
}, "Banana"), /*#__PURE__*/React.createElement("button", {
|
|
112
|
-
tabIndex: 0
|
|
113
|
-
}, "Cantaloupe")), /*#__PURE__*/React.createElement("button", {
|
|
114
|
-
id: "durian",
|
|
115
|
-
tabIndex: 0
|
|
116
|
-
}, "Durian")));
|
|
117
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
118
|
-
const firstButton = trapContainer.querySelector('button');
|
|
119
|
-
const lastButton = trapContainer.querySelectorAll('button')[2];
|
|
120
|
-
const controller = focusTrap(trapContainer);
|
|
121
|
-
lastButton.focus();
|
|
122
|
-
fireEvent(lastButton, new KeyboardEvent('keydown', {
|
|
123
|
-
bubbles: true,
|
|
124
|
-
key: 'Tab'
|
|
125
|
-
}));
|
|
126
|
-
expect(document.activeElement).toEqual(firstButton);
|
|
127
|
-
fireEvent(firstButton, new KeyboardEvent('keydown', {
|
|
128
|
-
bubbles: true,
|
|
129
|
-
key: 'Tab',
|
|
130
|
-
shiftKey: true
|
|
131
|
-
}));
|
|
132
|
-
expect(document.activeElement).toEqual(lastButton);
|
|
133
|
-
controller.abort();
|
|
134
|
-
});
|
|
135
|
-
it('Should should release the trap when the signal is aborted', async () => {
|
|
136
|
-
const {
|
|
137
|
-
container
|
|
138
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
139
|
-
id: "trapContainer"
|
|
140
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
141
|
-
tabIndex: 0
|
|
142
|
-
}, "Apple"), /*#__PURE__*/React.createElement("button", {
|
|
143
|
-
tabIndex: 0
|
|
144
|
-
}, "Banana"), /*#__PURE__*/React.createElement("button", {
|
|
145
|
-
tabIndex: 0
|
|
146
|
-
}, "Cantaloupe")), /*#__PURE__*/React.createElement("button", {
|
|
147
|
-
id: "durian",
|
|
148
|
-
tabIndex: 0
|
|
149
|
-
}, "Durian")));
|
|
150
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
151
|
-
const durianButton = container.querySelector('#durian');
|
|
152
|
-
const controller = focusTrap(trapContainer);
|
|
153
|
-
focus(durianButton);
|
|
154
|
-
expect(document.activeElement).toEqual(trapContainer);
|
|
155
|
-
controller.abort();
|
|
156
|
-
focus(durianButton);
|
|
157
|
-
expect(document.activeElement).toEqual(durianButton);
|
|
158
|
-
});
|
|
159
|
-
it('Should should release the trap when the container is removed from the DOM', async () => {
|
|
160
|
-
var _trapContainer$parent;
|
|
161
|
-
|
|
162
|
-
const {
|
|
163
|
-
container
|
|
164
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
165
|
-
id: "trapContainer"
|
|
166
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
167
|
-
tabIndex: 0
|
|
168
|
-
}, "Apple")), /*#__PURE__*/React.createElement("button", {
|
|
169
|
-
id: "durian",
|
|
170
|
-
tabIndex: 0
|
|
171
|
-
}, "Durian")));
|
|
172
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
173
|
-
const durianButton = container.querySelector('#durian');
|
|
174
|
-
const firstButton = trapContainer.querySelector('button');
|
|
175
|
-
focusTrap(trapContainer);
|
|
176
|
-
focus(durianButton);
|
|
177
|
-
expect(document.activeElement).toEqual(trapContainer); // empty trap and remove it from the DOM
|
|
178
|
-
|
|
179
|
-
trapContainer.removeChild(firstButton);
|
|
180
|
-
(_trapContainer$parent = trapContainer.parentElement) === null || _trapContainer$parent === void 0 ? void 0 : _trapContainer$parent.removeChild(trapContainer);
|
|
181
|
-
focus(durianButton);
|
|
182
|
-
expect(document.activeElement).toEqual(durianButton);
|
|
183
|
-
});
|
|
184
|
-
it('Should handle dynamic content', async () => {
|
|
185
|
-
const {
|
|
186
|
-
container
|
|
187
|
-
} = render( /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
188
|
-
id: "trapContainer"
|
|
189
|
-
}, /*#__PURE__*/React.createElement("button", {
|
|
190
|
-
tabIndex: 0
|
|
191
|
-
}, "Apple"), /*#__PURE__*/React.createElement("button", {
|
|
192
|
-
tabIndex: 0
|
|
193
|
-
}, "Banana"), /*#__PURE__*/React.createElement("button", {
|
|
194
|
-
tabIndex: 0
|
|
195
|
-
}, "Cantaloupe")), /*#__PURE__*/React.createElement("button", {
|
|
196
|
-
id: "durian",
|
|
197
|
-
tabIndex: 0
|
|
198
|
-
}, "Durian")));
|
|
199
|
-
const trapContainer = container.querySelector('#trapContainer');
|
|
200
|
-
const [firstButton, secondButton, thirdButton] = trapContainer.querySelectorAll('button');
|
|
201
|
-
const controller = focusTrap(trapContainer);
|
|
202
|
-
secondButton.focus();
|
|
203
|
-
trapContainer.removeChild(thirdButton);
|
|
204
|
-
fireEvent(secondButton, new KeyboardEvent('keydown', {
|
|
205
|
-
bubbles: true,
|
|
206
|
-
key: 'Tab'
|
|
207
|
-
}));
|
|
208
|
-
expect(document.activeElement).toEqual(firstButton);
|
|
209
|
-
fireEvent(firstButton, new KeyboardEvent('keydown', {
|
|
210
|
-
bubbles: true,
|
|
211
|
-
key: 'Tab',
|
|
212
|
-
shiftKey: true
|
|
213
|
-
}));
|
|
214
|
-
expect(document.activeElement).toEqual(secondButton);
|
|
215
|
-
controller.abort();
|
|
216
|
-
});
|
|
217
|
-
/**
|
|
218
|
-
* Helper to handle firing the focusin event, which jest/JSDOM does not do for us.
|
|
219
|
-
* @param element
|
|
220
|
-
*/
|
|
221
|
-
|
|
222
|
-
function focus(element) {
|
|
223
|
-
element.focus();
|
|
224
|
-
fireEvent(element, new FocusEvent('focusin', {
|
|
225
|
-
bubbles: true
|
|
226
|
-
}));
|
|
227
|
-
}
|