Skip to content

Commit 7428761

Browse files
feat: support attached shadow dom elements (#618)
Original implementation did not properly handle nested shadow dom elements. Updated the traversal to manually step through the dom to ensure that all shadow dom ancestors are properly handled.
1 parent 1dd42bb commit 7428761

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

src/isAttached.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
* Determine if an element is attached to the DOM
33
* Panzoom requires this so events work properly
44
*/
5-
export default function isAttached(elem: HTMLElement | SVGElement | Document) {
6-
const doc = elem.ownerDocument
7-
const parent = elem.parentNode
8-
return (
9-
doc &&
10-
parent &&
11-
doc.nodeType === 9 &&
12-
parent.nodeType === 1 &&
13-
doc.documentElement.contains(parent)
14-
)
5+
export default function isAttached(node: Node) {
6+
let currentNode = node
7+
while (currentNode && currentNode.parentNode) {
8+
if (currentNode.parentNode === document) return true
9+
currentNode =
10+
currentNode.parentNode instanceof ShadowRoot
11+
? currentNode.parentNode.host
12+
: currentNode.parentNode
13+
}
14+
return false
1515
}

test/unit/isAttached.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,30 @@ describe('isAttached', () => {
88
assert(isAttached(div))
99
document.body.removeChild(div)
1010
})
11+
it('determines if an attached shadow dom element is attached', () => {
12+
const div = document.createElement('div')
13+
const shadowChild = document.createElement('div')
14+
div.attachShadow({ mode: 'open' }).appendChild(shadowChild)
15+
document.body.appendChild(div)
16+
assert(isAttached(shadowChild))
17+
document.body.removeChild(div)
18+
})
19+
it('determines if a nested, attached shadow dom element is attached', () => {
20+
const div = document.createElement('div')
21+
const shadowChild = document.createElement('div')
22+
const shadowGrandChild = document.createElement('div')
23+
shadowChild.attachShadow({ mode: 'open' }).appendChild(shadowGrandChild)
24+
div.attachShadow({ mode: 'open' }).appendChild(shadowChild)
25+
document.body.appendChild(div)
26+
assert(isAttached(shadowGrandChild))
27+
document.body.removeChild(div)
28+
})
29+
it('determines if a detached shadow dom element is attached', () => {
30+
const div = document.createElement('div')
31+
const shadowChild = document.createElement('div')
32+
div.attachShadow({ mode: 'open' }).appendChild(shadowChild)
33+
assert(!isAttached(shadowChild))
34+
})
1135
it('determines if a detached element is attached', () => {
1236
const div = document.createElement('div')
1337
assert(!isAttached(div))

0 commit comments

Comments
 (0)