@wordpress/dom 4.55.0 → 4.55.2-next.v.202609171837.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/CHANGELOG.md +7 -0
- package/README.md +73 -73
- package/build/dom/get-rectangle-from-range.cjs +47 -22
- package/build/dom/get-rectangle-from-range.cjs.map +2 -2
- package/build/focusable.cjs +5 -8
- package/build/focusable.cjs.map +2 -2
- package/build-module/dom/get-rectangle-from-range.mjs +47 -22
- package/build-module/dom/get-rectangle-from-range.mjs.map +2 -2
- package/build-module/focusable.mjs +5 -8
- package/build-module/focusable.mjs.map +2 -2
- package/build-types/dom/get-rectangle-from-range.d.ts.map +1 -1
- package/build-types/focusable.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/dom/get-rectangle-from-range.js +64 -31
- package/src/dom/test/get-rectangle-from-range.browser.test.js +128 -0
- package/src/focusable.js +8 -11
- package/src/test/focusable-area.jsdom.test.js +43 -0
- package/src/test/focusable.browser.test.js +243 -2
- package/src/test/{tabbable.jsdom.test.js → tabbable.browser.test.js} +11 -5
- package/src/test/focusable.jsdom.test.js +0 -193
- package/src/test/utils/create-element.js +0 -54
|
@@ -35,7 +35,7 @@ describe( 'focusable.find() CSS visibility', () => {
|
|
|
35
35
|
expect( input.offsetHeight ).toBeGreaterThan( 0 );
|
|
36
36
|
expect( input.getClientRects().length ).toBeGreaterThan( 0 );
|
|
37
37
|
input.focus();
|
|
38
|
-
expect(
|
|
38
|
+
expect( input ).not.toHaveFocus();
|
|
39
39
|
expect( find( node ) ).toEqual( [] );
|
|
40
40
|
expect( checkVisibility ).toHaveBeenCalledWith( {
|
|
41
41
|
visibilityProperty: true,
|
|
@@ -49,7 +49,7 @@ describe( 'focusable.find() CSS visibility', () => {
|
|
|
49
49
|
const input = node.querySelector( 'input' );
|
|
50
50
|
|
|
51
51
|
input.focus();
|
|
52
|
-
expect(
|
|
52
|
+
expect( input ).toHaveFocus();
|
|
53
53
|
expect( find( node ) ).toEqual( [ input ] );
|
|
54
54
|
} );
|
|
55
55
|
|
|
@@ -81,3 +81,244 @@ describe( 'focusable.find() CSS visibility', () => {
|
|
|
81
81
|
expect( getComputedStyle ).toHaveBeenCalledWith( visibleInput );
|
|
82
82
|
} );
|
|
83
83
|
} );
|
|
84
|
+
|
|
85
|
+
const createElement = ( type ) => document.createElement( type );
|
|
86
|
+
const IMAGE_SOURCE =
|
|
87
|
+
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
|
88
|
+
|
|
89
|
+
function findFocusable( context ) {
|
|
90
|
+
if ( ! context.isConnected ) {
|
|
91
|
+
document.body.appendChild( context );
|
|
92
|
+
}
|
|
93
|
+
return find( context );
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe( 'focusable', () => {
|
|
97
|
+
beforeEach( () => {
|
|
98
|
+
document.body.innerHTML = '';
|
|
99
|
+
} );
|
|
100
|
+
|
|
101
|
+
describe( 'find()', () => {
|
|
102
|
+
it( 'returns empty array if no children', () => {
|
|
103
|
+
const node = createElement( 'div' );
|
|
104
|
+
|
|
105
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
106
|
+
} );
|
|
107
|
+
|
|
108
|
+
it( 'returns empty array if no focusable children', () => {
|
|
109
|
+
const node = createElement( 'div' );
|
|
110
|
+
node.appendChild( createElement( 'div' ) );
|
|
111
|
+
|
|
112
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
113
|
+
} );
|
|
114
|
+
|
|
115
|
+
it( 'returns array of focusable children', () => {
|
|
116
|
+
const node = createElement( 'div' );
|
|
117
|
+
node.appendChild( createElement( 'input' ) );
|
|
118
|
+
|
|
119
|
+
const focusable = findFocusable( node );
|
|
120
|
+
|
|
121
|
+
expect( focusable ).toHaveLength( 1 );
|
|
122
|
+
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
123
|
+
} );
|
|
124
|
+
|
|
125
|
+
it( 'finds nested focusable child', () => {
|
|
126
|
+
const node = createElement( 'div' );
|
|
127
|
+
node.appendChild( createElement( 'div' ) );
|
|
128
|
+
node.firstChild.appendChild( createElement( 'input' ) );
|
|
129
|
+
|
|
130
|
+
const focusable = findFocusable( node );
|
|
131
|
+
|
|
132
|
+
expect( focusable ).toHaveLength( 1 );
|
|
133
|
+
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
134
|
+
} );
|
|
135
|
+
|
|
136
|
+
it( 'finds link with no href but tabindex', () => {
|
|
137
|
+
const node = createElement( 'div' );
|
|
138
|
+
const link = createElement( 'a' );
|
|
139
|
+
link.tabIndex = 0;
|
|
140
|
+
node.appendChild( link );
|
|
141
|
+
|
|
142
|
+
expect( findFocusable( node ) ).toEqual( [ link ] );
|
|
143
|
+
} );
|
|
144
|
+
|
|
145
|
+
it( 'finds a mapped area whose referenced image is visible', async () => {
|
|
146
|
+
const node = createElement( 'div' );
|
|
147
|
+
node.innerHTML = `
|
|
148
|
+
<map name="testfocus">
|
|
149
|
+
<area href="#target" shape="rect" coords="0,0,30,30" alt="Target">
|
|
150
|
+
</map>
|
|
151
|
+
<img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="">
|
|
152
|
+
`;
|
|
153
|
+
const area = node.querySelector( 'area' );
|
|
154
|
+
const image = node.querySelector( 'img' );
|
|
155
|
+
|
|
156
|
+
document.body.appendChild( node );
|
|
157
|
+
await image.decode();
|
|
158
|
+
|
|
159
|
+
expect( area.getClientRects() ).toHaveLength( 0 );
|
|
160
|
+
expect( image.getClientRects().length ).toBeGreaterThan( 0 );
|
|
161
|
+
area.focus();
|
|
162
|
+
expect( area ).toHaveFocus();
|
|
163
|
+
expect( find( node ) ).toEqual( [ area ] );
|
|
164
|
+
} );
|
|
165
|
+
|
|
166
|
+
it( 'ignores a mapped area whose referenced image is hidden', () => {
|
|
167
|
+
const node = createElement( 'div' );
|
|
168
|
+
node.innerHTML = `
|
|
169
|
+
<map name="testfocus">
|
|
170
|
+
<area href="#target" shape="rect" coords="0,0,30,30" alt="Target">
|
|
171
|
+
</map>
|
|
172
|
+
<img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="" style="visibility: hidden">
|
|
173
|
+
`;
|
|
174
|
+
const image = node.querySelector( 'img' );
|
|
175
|
+
|
|
176
|
+
document.body.appendChild( node );
|
|
177
|
+
|
|
178
|
+
expect( image.getClientRects().length ).toBeGreaterThan( 0 );
|
|
179
|
+
expect( find( node ) ).toEqual( [] );
|
|
180
|
+
} );
|
|
181
|
+
|
|
182
|
+
it( 'ignores a mapped area whose referenced image is inside an inert subtree', () => {
|
|
183
|
+
const node = createElement( 'div' );
|
|
184
|
+
node.innerHTML = `
|
|
185
|
+
<map name="testfocus">
|
|
186
|
+
<area href="#target" shape="rect" coords="0,0,30,30" alt="Target">
|
|
187
|
+
</map>
|
|
188
|
+
<div inert>
|
|
189
|
+
<img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="">
|
|
190
|
+
</div>
|
|
191
|
+
`;
|
|
192
|
+
|
|
193
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
194
|
+
} );
|
|
195
|
+
|
|
196
|
+
it( "finds a mapped area whose referenced image is outside the map's inert subtree", async () => {
|
|
197
|
+
const node = createElement( 'div' );
|
|
198
|
+
node.innerHTML = `
|
|
199
|
+
<div inert>
|
|
200
|
+
<map name="testfocus">
|
|
201
|
+
<area href="#target" shape="rect" coords="0,0,30,30" alt="Target">
|
|
202
|
+
</map>
|
|
203
|
+
</div>
|
|
204
|
+
<img src="${ IMAGE_SOURCE }" usemap="#testfocus" width="40" height="40" alt="">
|
|
205
|
+
`;
|
|
206
|
+
const area = node.querySelector( 'area' );
|
|
207
|
+
const image = node.querySelector( 'img' );
|
|
208
|
+
|
|
209
|
+
document.body.appendChild( node );
|
|
210
|
+
await image.decode();
|
|
211
|
+
|
|
212
|
+
area.focus();
|
|
213
|
+
expect( area ).toHaveFocus();
|
|
214
|
+
expect( find( node ) ).toEqual( [ area ] );
|
|
215
|
+
} );
|
|
216
|
+
|
|
217
|
+
it( 'finds contenteditable', () => {
|
|
218
|
+
const node = createElement( 'div' );
|
|
219
|
+
const div = createElement( 'div' );
|
|
220
|
+
node.appendChild( div );
|
|
221
|
+
|
|
222
|
+
div.setAttribute( 'contenteditable', '' );
|
|
223
|
+
expect( findFocusable( node ) ).toEqual( [ div ] );
|
|
224
|
+
|
|
225
|
+
div.setAttribute( 'contenteditable', 'true' );
|
|
226
|
+
expect( findFocusable( node ) ).toEqual( [ div ] );
|
|
227
|
+
} );
|
|
228
|
+
|
|
229
|
+
it( 'ignores contenteditable=false', () => {
|
|
230
|
+
const node = createElement( 'div' );
|
|
231
|
+
const div = createElement( 'div' );
|
|
232
|
+
node.appendChild( div );
|
|
233
|
+
|
|
234
|
+
div.setAttribute( 'contenteditable', 'false' );
|
|
235
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
236
|
+
} );
|
|
237
|
+
|
|
238
|
+
it( 'ignores invisible inputs', () => {
|
|
239
|
+
const node = createElement( 'div' );
|
|
240
|
+
const input = createElement( 'input' );
|
|
241
|
+
node.appendChild( input );
|
|
242
|
+
// Keep the fixture connected so JSDOM invalidates computed styles.
|
|
243
|
+
document.body.appendChild( node );
|
|
244
|
+
|
|
245
|
+
input.style.visibility = 'hidden';
|
|
246
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
247
|
+
|
|
248
|
+
input.style.visibility = 'visible';
|
|
249
|
+
input.style.display = 'none';
|
|
250
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
251
|
+
|
|
252
|
+
input.style.display = 'inline-block';
|
|
253
|
+
const focusable = findFocusable( node );
|
|
254
|
+
expect( focusable ).toHaveLength( 1 );
|
|
255
|
+
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
256
|
+
} );
|
|
257
|
+
|
|
258
|
+
it( 'ignores inputs in invisible ancestors', () => {
|
|
259
|
+
const node = createElement( 'div' );
|
|
260
|
+
const input = createElement( 'input' );
|
|
261
|
+
node.appendChild( input );
|
|
262
|
+
// Keep the fixture connected so JSDOM invalidates computed styles.
|
|
263
|
+
document.body.appendChild( node );
|
|
264
|
+
|
|
265
|
+
node.style.visibility = 'hidden';
|
|
266
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
267
|
+
|
|
268
|
+
node.style.visibility = 'visible';
|
|
269
|
+
node.style.display = 'none';
|
|
270
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
271
|
+
|
|
272
|
+
node.style.display = 'block';
|
|
273
|
+
const focusable = findFocusable( node );
|
|
274
|
+
expect( focusable ).toHaveLength( 1 );
|
|
275
|
+
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
276
|
+
} );
|
|
277
|
+
|
|
278
|
+
it( 'does not return context even if focusable', () => {
|
|
279
|
+
const node = createElement( 'div' );
|
|
280
|
+
node.tabIndex = 0;
|
|
281
|
+
|
|
282
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
283
|
+
} );
|
|
284
|
+
|
|
285
|
+
it( 'limits found focusables to specific context', () => {
|
|
286
|
+
const node = createElement( 'div' );
|
|
287
|
+
node.appendChild( createElement( 'div' ) );
|
|
288
|
+
document.body.appendChild( node );
|
|
289
|
+
document.body.appendChild( createElement( 'input' ) );
|
|
290
|
+
|
|
291
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
292
|
+
} );
|
|
293
|
+
|
|
294
|
+
it( 'ignores elements inside inert containers', () => {
|
|
295
|
+
const node = createElement( 'div' );
|
|
296
|
+
const inertDiv = createElement( 'div' );
|
|
297
|
+
inertDiv.setAttribute( 'inert', '' );
|
|
298
|
+
const input = createElement( 'input' );
|
|
299
|
+
inertDiv.appendChild( input );
|
|
300
|
+
node.appendChild( inertDiv );
|
|
301
|
+
|
|
302
|
+
expect( findFocusable( node ) ).toEqual( [] );
|
|
303
|
+
} );
|
|
304
|
+
|
|
305
|
+
it( 'returns focusable elements outside inert containers', () => {
|
|
306
|
+
const node = createElement( 'div' );
|
|
307
|
+
|
|
308
|
+
// Inert container with input
|
|
309
|
+
const inertDiv = createElement( 'div' );
|
|
310
|
+
inertDiv.setAttribute( 'inert', '' );
|
|
311
|
+
const inertInput = createElement( 'input' );
|
|
312
|
+
inertDiv.appendChild( inertInput );
|
|
313
|
+
node.appendChild( inertDiv );
|
|
314
|
+
|
|
315
|
+
// Non-inert input
|
|
316
|
+
const visibleInput = createElement( 'input' );
|
|
317
|
+
node.appendChild( visibleInput );
|
|
318
|
+
|
|
319
|
+
const focusable = findFocusable( node );
|
|
320
|
+
expect( focusable ).toHaveLength( 1 );
|
|
321
|
+
expect( focusable[ 0 ] ).toBe( visibleInput );
|
|
322
|
+
} );
|
|
323
|
+
} );
|
|
324
|
+
} );
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import createElement from './utils/create-element';
|
|
3
2
|
import { find } from '../tabbable';
|
|
4
3
|
|
|
4
|
+
const createElement = ( type ) => document.createElement( type );
|
|
5
|
+
|
|
6
|
+
function findTabbable( context ) {
|
|
7
|
+
document.body.appendChild( context );
|
|
8
|
+
return find( context );
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
describe( 'tabbable', () => {
|
|
6
12
|
beforeEach( () => {
|
|
7
13
|
document.body.innerHTML = '';
|
|
@@ -22,7 +28,7 @@ describe( 'tabbable', () => {
|
|
|
22
28
|
node.appendChild( second );
|
|
23
29
|
node.appendChild( absent );
|
|
24
30
|
|
|
25
|
-
const tabbables =
|
|
31
|
+
const tabbables = findTabbable( node );
|
|
26
32
|
|
|
27
33
|
expect( tabbables ).toEqual( [ first, second, third ] );
|
|
28
34
|
} );
|
|
@@ -59,7 +65,7 @@ describe( 'tabbable', () => {
|
|
|
59
65
|
node.appendChild( fourthRadio );
|
|
60
66
|
node.appendChild( fifthRadio );
|
|
61
67
|
|
|
62
|
-
const tabbables =
|
|
68
|
+
const tabbables = findTabbable( node );
|
|
63
69
|
|
|
64
70
|
expect( tabbables ).toEqual( [ firstRadio, text, fourthRadio ] );
|
|
65
71
|
} );
|
|
@@ -87,7 +93,7 @@ describe( 'tabbable', () => {
|
|
|
87
93
|
node.appendChild( text );
|
|
88
94
|
node.appendChild( thirdRadio );
|
|
89
95
|
|
|
90
|
-
const tabbables =
|
|
96
|
+
const tabbables = findTabbable( node );
|
|
91
97
|
|
|
92
98
|
expect( tabbables ).toEqual( [ text, thirdRadio ] );
|
|
93
99
|
} );
|
|
@@ -107,7 +113,7 @@ describe( 'tabbable', () => {
|
|
|
107
113
|
node.appendChild( text );
|
|
108
114
|
node.appendChild( secondRadio );
|
|
109
115
|
|
|
110
|
-
const tabbables =
|
|
116
|
+
const tabbables = findTabbable( node );
|
|
111
117
|
|
|
112
118
|
expect( tabbables ).toEqual( [ firstRadio, text, secondRadio ] );
|
|
113
119
|
} );
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import createElement from './utils/create-element';
|
|
3
|
-
import { find } from '../focusable';
|
|
4
|
-
|
|
5
|
-
describe( 'focusable', () => {
|
|
6
|
-
beforeEach( () => {
|
|
7
|
-
document.body.innerHTML = '';
|
|
8
|
-
} );
|
|
9
|
-
|
|
10
|
-
describe( 'find()', () => {
|
|
11
|
-
it( 'returns empty array if no children', () => {
|
|
12
|
-
const node = createElement( 'div' );
|
|
13
|
-
|
|
14
|
-
expect( find( node ) ).toEqual( [] );
|
|
15
|
-
} );
|
|
16
|
-
|
|
17
|
-
it( 'returns empty array if no focusable children', () => {
|
|
18
|
-
const node = createElement( 'div' );
|
|
19
|
-
node.appendChild( createElement( 'div' ) );
|
|
20
|
-
|
|
21
|
-
expect( find( node ) ).toEqual( [] );
|
|
22
|
-
} );
|
|
23
|
-
|
|
24
|
-
it( 'returns array of focusable children', () => {
|
|
25
|
-
const node = createElement( 'div' );
|
|
26
|
-
node.appendChild( createElement( 'input' ) );
|
|
27
|
-
|
|
28
|
-
const focusable = find( node );
|
|
29
|
-
|
|
30
|
-
expect( focusable ).toHaveLength( 1 );
|
|
31
|
-
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
32
|
-
} );
|
|
33
|
-
|
|
34
|
-
it( 'finds nested focusable child', () => {
|
|
35
|
-
const node = createElement( 'div' );
|
|
36
|
-
node.appendChild( createElement( 'div' ) );
|
|
37
|
-
node.firstChild.appendChild( createElement( 'input' ) );
|
|
38
|
-
|
|
39
|
-
const focusable = find( node );
|
|
40
|
-
|
|
41
|
-
expect( focusable ).toHaveLength( 1 );
|
|
42
|
-
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
43
|
-
} );
|
|
44
|
-
|
|
45
|
-
it( 'finds link with no href but tabindex', () => {
|
|
46
|
-
const node = createElement( 'div' );
|
|
47
|
-
const link = createElement( 'a' );
|
|
48
|
-
link.tabIndex = 0;
|
|
49
|
-
node.appendChild( link );
|
|
50
|
-
|
|
51
|
-
expect( find( node ) ).toEqual( [ link ] );
|
|
52
|
-
} );
|
|
53
|
-
|
|
54
|
-
it( 'finds valid area focusable', () => {
|
|
55
|
-
const map = createElement( 'map' );
|
|
56
|
-
map.name = 'testfocus';
|
|
57
|
-
const area = createElement( 'area' );
|
|
58
|
-
area.href = '';
|
|
59
|
-
map.appendChild( area );
|
|
60
|
-
const img = createElement( 'img' );
|
|
61
|
-
img.setAttribute( 'usemap', '#testfocus' );
|
|
62
|
-
document.body.appendChild( map );
|
|
63
|
-
document.body.appendChild( img );
|
|
64
|
-
|
|
65
|
-
const focusable = find( map );
|
|
66
|
-
|
|
67
|
-
expect( focusable ).toHaveLength( 1 );
|
|
68
|
-
expect( focusable[ 0 ].nodeName ).toBe( 'AREA' );
|
|
69
|
-
} );
|
|
70
|
-
|
|
71
|
-
it( 'ignores invalid area focusable', () => {
|
|
72
|
-
const map = createElement( 'map' );
|
|
73
|
-
map.name = 'testfocus';
|
|
74
|
-
const area = createElement( 'area' );
|
|
75
|
-
area.href = '';
|
|
76
|
-
map.appendChild( area );
|
|
77
|
-
const img = createElement( 'img' );
|
|
78
|
-
img.setAttribute( 'usemap', '#testfocus' );
|
|
79
|
-
img.style.display = 'none';
|
|
80
|
-
document.body.appendChild( map );
|
|
81
|
-
document.body.appendChild( img );
|
|
82
|
-
|
|
83
|
-
expect( find( map ) ).toEqual( [] );
|
|
84
|
-
} );
|
|
85
|
-
|
|
86
|
-
it( 'finds contenteditable', () => {
|
|
87
|
-
const node = createElement( 'div' );
|
|
88
|
-
const div = createElement( 'div' );
|
|
89
|
-
node.appendChild( div );
|
|
90
|
-
|
|
91
|
-
div.setAttribute( 'contenteditable', '' );
|
|
92
|
-
expect( find( node ) ).toEqual( [ div ] );
|
|
93
|
-
|
|
94
|
-
div.setAttribute( 'contenteditable', 'true' );
|
|
95
|
-
expect( find( node ) ).toEqual( [ div ] );
|
|
96
|
-
} );
|
|
97
|
-
|
|
98
|
-
it( 'ignores contenteditable=false', () => {
|
|
99
|
-
const node = createElement( 'div' );
|
|
100
|
-
const div = createElement( 'div' );
|
|
101
|
-
node.appendChild( div );
|
|
102
|
-
|
|
103
|
-
div.setAttribute( 'contenteditable', 'false' );
|
|
104
|
-
expect( find( node ) ).toEqual( [] );
|
|
105
|
-
} );
|
|
106
|
-
|
|
107
|
-
it( 'ignores invisible inputs', () => {
|
|
108
|
-
const node = createElement( 'div' );
|
|
109
|
-
const input = createElement( 'input' );
|
|
110
|
-
node.appendChild( input );
|
|
111
|
-
// Keep the fixture connected so JSDOM invalidates computed styles.
|
|
112
|
-
document.body.appendChild( node );
|
|
113
|
-
|
|
114
|
-
input.style.visibility = 'hidden';
|
|
115
|
-
expect( find( node ) ).toEqual( [] );
|
|
116
|
-
|
|
117
|
-
input.style.visibility = 'visible';
|
|
118
|
-
input.style.display = 'none';
|
|
119
|
-
expect( find( node ) ).toEqual( [] );
|
|
120
|
-
|
|
121
|
-
input.style.display = 'inline-block';
|
|
122
|
-
const focusable = find( node );
|
|
123
|
-
expect( focusable ).toHaveLength( 1 );
|
|
124
|
-
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
125
|
-
} );
|
|
126
|
-
|
|
127
|
-
it( 'ignores inputs in invisible ancestors', () => {
|
|
128
|
-
const node = createElement( 'div' );
|
|
129
|
-
const input = createElement( 'input' );
|
|
130
|
-
node.appendChild( input );
|
|
131
|
-
// Keep the fixture connected so JSDOM invalidates computed styles.
|
|
132
|
-
document.body.appendChild( node );
|
|
133
|
-
|
|
134
|
-
node.style.visibility = 'hidden';
|
|
135
|
-
expect( find( node ) ).toEqual( [] );
|
|
136
|
-
|
|
137
|
-
node.style.visibility = 'visible';
|
|
138
|
-
node.style.display = 'none';
|
|
139
|
-
expect( find( node ) ).toEqual( [] );
|
|
140
|
-
|
|
141
|
-
node.style.display = 'block';
|
|
142
|
-
const focusable = find( node );
|
|
143
|
-
expect( focusable ).toHaveLength( 1 );
|
|
144
|
-
expect( focusable[ 0 ].nodeName ).toBe( 'INPUT' );
|
|
145
|
-
} );
|
|
146
|
-
|
|
147
|
-
it( 'does not return context even if focusable', () => {
|
|
148
|
-
const node = createElement( 'div' );
|
|
149
|
-
node.tabIndex = 0;
|
|
150
|
-
|
|
151
|
-
expect( find( node ) ).toEqual( [] );
|
|
152
|
-
} );
|
|
153
|
-
|
|
154
|
-
it( 'limits found focusables to specific context', () => {
|
|
155
|
-
const node = createElement( 'div' );
|
|
156
|
-
node.appendChild( createElement( 'div' ) );
|
|
157
|
-
document.body.appendChild( node );
|
|
158
|
-
document.body.appendChild( createElement( 'input' ) );
|
|
159
|
-
|
|
160
|
-
expect( find( node ) ).toEqual( [] );
|
|
161
|
-
} );
|
|
162
|
-
|
|
163
|
-
it( 'ignores elements inside inert containers', () => {
|
|
164
|
-
const node = createElement( 'div' );
|
|
165
|
-
const inertDiv = createElement( 'div' );
|
|
166
|
-
inertDiv.setAttribute( 'inert', '' );
|
|
167
|
-
const input = createElement( 'input' );
|
|
168
|
-
inertDiv.appendChild( input );
|
|
169
|
-
node.appendChild( inertDiv );
|
|
170
|
-
|
|
171
|
-
expect( find( node ) ).toEqual( [] );
|
|
172
|
-
} );
|
|
173
|
-
|
|
174
|
-
it( 'returns focusable elements outside inert containers', () => {
|
|
175
|
-
const node = createElement( 'div' );
|
|
176
|
-
|
|
177
|
-
// Inert container with input
|
|
178
|
-
const inertDiv = createElement( 'div' );
|
|
179
|
-
inertDiv.setAttribute( 'inert', '' );
|
|
180
|
-
const inertInput = createElement( 'input' );
|
|
181
|
-
inertDiv.appendChild( inertInput );
|
|
182
|
-
node.appendChild( inertDiv );
|
|
183
|
-
|
|
184
|
-
// Non-inert input
|
|
185
|
-
const visibleInput = createElement( 'input' );
|
|
186
|
-
node.appendChild( visibleInput );
|
|
187
|
-
|
|
188
|
-
const focusable = find( node );
|
|
189
|
-
expect( focusable ).toHaveLength( 1 );
|
|
190
|
-
expect( focusable[ 0 ] ).toBe( visibleInput );
|
|
191
|
-
} );
|
|
192
|
-
} );
|
|
193
|
-
} );
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Given an element type, returns an HTMLElement with an emulated layout,
|
|
3
|
-
* since JSDOM does not have its own internal layout engine.
|
|
4
|
-
*
|
|
5
|
-
* @param {string} type Element type.
|
|
6
|
-
*
|
|
7
|
-
* @return {HTMLElement} Layout-emulated element.
|
|
8
|
-
*/
|
|
9
|
-
export default function createElement( type ) {
|
|
10
|
-
const element = document.createElement( type );
|
|
11
|
-
|
|
12
|
-
const ifNotHidden = ( value, elseValue ) =>
|
|
13
|
-
function () {
|
|
14
|
-
let isHidden = false;
|
|
15
|
-
let node = this;
|
|
16
|
-
do {
|
|
17
|
-
// CSS visibility does not remove an element's layout box.
|
|
18
|
-
isHidden = node.style.display === 'none';
|
|
19
|
-
|
|
20
|
-
node = node.parentNode;
|
|
21
|
-
} while (
|
|
22
|
-
! isHidden &&
|
|
23
|
-
node &&
|
|
24
|
-
node.nodeType === node.ELEMENT_NODE
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
return isHidden ? elseValue : value;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
Object.defineProperties( element, {
|
|
31
|
-
offsetHeight: {
|
|
32
|
-
get: ifNotHidden( 10, 0 ),
|
|
33
|
-
},
|
|
34
|
-
offsetWidth: {
|
|
35
|
-
get: ifNotHidden( 10, 0 ),
|
|
36
|
-
},
|
|
37
|
-
} );
|
|
38
|
-
|
|
39
|
-
element.getClientRects = ifNotHidden(
|
|
40
|
-
[
|
|
41
|
-
{
|
|
42
|
-
width: 10,
|
|
43
|
-
height: 10,
|
|
44
|
-
top: 0,
|
|
45
|
-
right: 10,
|
|
46
|
-
bottom: 10,
|
|
47
|
-
left: 0,
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
[]
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
return element;
|
|
54
|
-
}
|