Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shadowroot support using getHTML #1795

Merged
merged 5 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions packages/dom/src/clone-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export function cloneNodeAndShadow(ctx) {
clone.shadowRoot.innerHTML = '';
} else {
clone.attachShadow({
mode: 'open'
mode: 'open',
serializable: true
});
}
// clone dom elements
Expand Down Expand Up @@ -84,10 +85,20 @@ export function cloneNodeAndShadow(ctx) {
* Use `getInnerHTML()` to serialize shadow dom as <template> tags. `innerHTML` and `outerHTML` don't do this. Buzzword: "declarative shadow dom"
*/
export function getOuterHTML(docElement) {
// firefox doesn't serialize shadow DOM, we're awaiting API's by firefox to become ready and are not polyfilling it.
if (!docElement.getInnerHTML) { return docElement.outerHTML; }
// All major browsers in latest versions supports getHTML API to get serialized DOM
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getHTML
// old firefox doesn't serialize shadow DOM, we're awaiting API's by firefox to become ready and are not polyfilling it.
// new firefox from 128 onwards serializes it using getHTML
/* istanbul ignore if: Only triggered in firefox <= 128 and tests runs on latest */
if (!docElement.getHTML) { return docElement.outerHTML; }
// chromium gives us declarative shadow DOM serialization API
let innerHTML = docElement.getInnerHTML({ includeShadowRoots: true });
let innerHTML = '';
/* istanbul ignore else if: Only triggered in chrome <= 128 and tests runs on latest */
if (docElement.getHTML) {
innerHTML = docElement.getHTML({ serializableShadowRoots: true });
} else if (docElement.getInnerHTML) {
innerHTML = docElement.getInnerHTML({ includeShadowRoots: true });
}
docElement.textContent = '';
// Note: Here we are specifically passing replacer function to avoid any replacements due to
// special characters in client's dom like $&
Expand Down
6 changes: 3 additions & 3 deletions packages/dom/test/serialize-css.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('serializeCSSOM', () => {
}]));

expect(resultShadowEl.innerHTML).toEqual([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[0].url}">`,
'<p>Percy-0</p>',
'</template>'
Expand Down Expand Up @@ -157,14 +157,14 @@ describe('serializeCSSOM', () => {
const resultShadowElChild = $('#Percy-1')[0];

expect(resultShadowEl.innerHTML).toMatch([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[0].url}">`,
'<p>Percy-0</p>',
'</template>'
].join(''));

expect(resultShadowElChild.innerHTML).toMatch([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[1].url}">`,
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[0].url}">`,
'<p>Percy-1</p>',
Expand Down
12 changes: 6 additions & 6 deletions packages/dom/test/serialize-dom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe('serializeDOM', () => {
shadow.appendChild(paragraphEl);

const html = serializeDOM().html;
expect(html).toMatch('<template shadowrootmode="open">');
expect(html).toMatch('<template shadowrootmode="open" shadowrootserializable="">');
expect(html).toMatch('Hey Percy!');
});

Expand Down Expand Up @@ -162,10 +162,10 @@ describe('serializeDOM', () => {
const html = serializeDOM().html;

expect(html).toMatch(new RegExp([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
'<p>Percy-1</p>',
'<div id="Percy-2" .*>',
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
'<p>Percy-2</p>',
'</template>'
].join('')));
Expand Down Expand Up @@ -193,7 +193,7 @@ describe('serializeDOM', () => {
el = newEl;
matchRegex += [
`<div id="Percy-${j}" .*>`,
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<p>Percy-${j}</p>`
].join('');
}
Expand All @@ -218,7 +218,7 @@ describe('serializeDOM', () => {
baseContent.appendChild(newEl);
matchRegex += [
`<div id="Percy-${j}" .*>`,
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<p>Percy-${j}</p>`,
'</template>',
'</div>'
Expand Down Expand Up @@ -251,7 +251,7 @@ describe('serializeDOM', () => {
constructor() {
super();
// Create a shadow root
const shadow = this.shadowRoot || this.attachShadow({ mode: 'open' });
const shadow = this.shadowRoot || this.attachShadow({ mode: 'open', serializable: true });
const wrapper = document.createElement('h2');
wrapper.innerText = 'Test';
shadow.appendChild(wrapper);
Expand Down
Loading