Skip to content

Commit b93825e

Browse files
authored
[Enhancement] Support Cloning Custom Elements (#129)
* feat(custom-elements): ✨ obtain children of shadow node for custom elements Inspired by tsayen/dom-to-image#370 If element has `shadowRoot` property it is custom (and the shadow node is open) so fetch it's children. Closes #128 * fix: 🐛 add safety checks to support special/custom elements Introduced by 021f124 Access to shadow node exposes the code to custom elements that break the current code. Was breaking because of elements without a style node. This commit fixes these bugs with simple, NON-BREAKING safety checks. * test(htmltoimage): 🚨 Added tests covering custom elements renders mathfield custom element https://github.com/arnog/mathlive
1 parent 50ed80e commit b93825e

File tree

6 files changed

+55
-3
lines changed

6 files changed

+55
-3
lines changed

src/cloneNode.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ async function cloneChildren(
2727
clonedNode: HTMLElement,
2828
filter?: Function,
2929
): Promise<HTMLElement> {
30-
const children = toArray<HTMLElement>(nativeNode.childNodes)
30+
const children = toArray<HTMLElement>(
31+
(nativeNode.shadowRoot ?? nativeNode).childNodes,
32+
)
3133
if (children.length === 0) {
3234
return Promise.resolve(clonedNode)
3335
}
@@ -65,7 +67,7 @@ async function decorate(
6567
function cloneCssStyle(nativeNode: HTMLElement, clonedNode: HTMLElement) {
6668
const source = window.getComputedStyle(nativeNode)
6769
const target = clonedNode.style
68-
70+
if (!target) return
6971
if (source.cssText) {
7072
target.cssText = source.cssText
7173
} else {

src/embedImages.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ async function embedBackground(
2121
clonedNode: HTMLElement,
2222
options: Options,
2323
): Promise<HTMLElement> {
24-
const background = clonedNode.style.getPropertyValue('background')
24+
const background = clonedNode.style?.getPropertyValue('background')
2525
if (!background) {
2626
return Promise.resolve(clonedNode)
2727
}

test/spec/index.spec.ts

+40
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,46 @@ describe('html to image', () => {
229229
.then(done)
230230
.catch(done)
231231
})
232+
233+
describe('custom element', () => {
234+
let link: HTMLLinkElement
235+
beforeAll(() => {
236+
const script = document.createElement('script')
237+
script.src = 'https://unpkg.com/mathlive/dist/mathlive.min.js'
238+
link = document.createElement('link')
239+
link.rel = 'stylesheet'
240+
link.href = 'https://unpkg.com/mathlive/dist/mathlive-fonts.css'
241+
const tasks = [
242+
new Promise((resolve, reject) => {
243+
script.onload = resolve
244+
script.onerror = reject
245+
}),
246+
new Promise((resolve, reject) => {
247+
link.onload = resolve
248+
link.onerror = reject
249+
}),
250+
]
251+
document.head.append(script, link)
252+
return Promise.all(tasks)
253+
})
254+
255+
afterAll(() => {
256+
link.remove()
257+
})
258+
259+
it('should render content from shadow node of custom element', (done) => {
260+
Helper.bootstrap(
261+
'custom-element/node.html',
262+
'custom-element/style.css',
263+
'custom-element/image',
264+
)
265+
.then(util.delay(1000))
266+
.then(Helper.renderAndCheck)
267+
.then(util.delay(1000))
268+
.then(done)
269+
.catch(done)
270+
})
271+
})
232272
})
233273

234274
describe('work with svg', () => {
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data:image/png;base64,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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<math-field
2+
value="S_{\triangle }=\frac{ab\sin \left(\gamma \right)}{2}"
3+
scrollingelement="[object HTMLHtmlElement]"
4+
class="math no-touch"
5+
role="textbox"
6+
tabindex="0"
7+
read-only=""
8+
>S_{\triangle }=\frac{ab\sin \left(\gamma \right)}{2}
9+
</math-field>

test/spec/resources/custom-element/style.css

Whitespace-only changes.

0 commit comments

Comments
 (0)