Skip to content
Open
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
2 changes: 1 addition & 1 deletion packages/dom/src/prepare-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function uid() {

export function markElement(domElement, disableShadowDOM, forceShadowAsLightDOM) {
// Mark elements that are to be serialized later with a data attribute.
if (['input', 'textarea', 'select', 'iframe', 'canvas', 'video', 'style'].includes(domElement.tagName?.toLowerCase())) {
if (['input', 'textarea', 'select', 'iframe', 'canvas', 'video', 'style', 'dialog'].includes(domElement.tagName?.toLowerCase())) {
if (!domElement.getAttribute('data-percy-element-id')) {
domElement.setAttribute('data-percy-element-id', uid());
}
Expand Down
41 changes: 41 additions & 0 deletions packages/dom/src/serialize-dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { handleErrors } from './utils';

// Serializes open <dialog> elements opened via showModal().
//
// The browser's ::backdrop and top-layer positioning are lost during
// DOM serialization. We stamp data-percy-dialog-modal so the renderer
// can call removeAttribute('open') then showModal() to restore them.
//
// The open attribute is kept so the dialog is visible during Percy's
// asset discovery and rendering phases.
export function serializeDialogs(ctx) {
let { dom, clone } = ctx;

for (let elem of dom.querySelectorAll('dialog[open]')) {
try {
let dialogId = elem.getAttribute('data-percy-element-id');
if (!dialogId) continue;

let cloneEl = clone.querySelector(`[data-percy-element-id="${dialogId}"]`);
if (!cloneEl) continue;

if (!cloneEl.hasAttribute('open')) {
cloneEl.setAttribute('open', '');
}

// Detect showModal() vs show():
// showModal() sets position:fixed (top layer). show() is position:absolute.
let dialogPosition = window.getComputedStyle(elem).getPropertyValue('position');
if (dialogPosition !== 'fixed') continue;

// Mark for renderer — it will removeAttribute('open') then showModal()
cloneEl.setAttribute('data-percy-dialog-modal', 'true');
// Pass original viewport height so renderer caps screenshot to viewport
cloneEl.setAttribute('data-percy-dialog-viewport-height', String(window.innerHeight));
} catch (err) {
handleErrors(err, 'Error serializing dialog element: ', elem);
}
}
}

export default serializeDialogs;
2 changes: 2 additions & 0 deletions packages/dom/src/serialize-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import serializeFrames from './serialize-frames';
import serializeCSSOM from './serialize-cssom';
import serializeCanvas from './serialize-canvas';
import serializeVideos from './serialize-video';
import serializeDialogs from './serialize-dialog';
import { serializePseudoClasses, markPseudoClassElements } from './serialize-pseudo-classes';
import { cloneNodeAndShadow, getOuterHTML } from './clone-dom';

Expand Down Expand Up @@ -37,6 +38,7 @@ function serializeElements(ctx) {
serializeInputs(ctx);
serializeFrames(ctx);
serializeVideos(ctx);
serializeDialogs(ctx);

if (!ctx.enableJavaScript) {
serializeCSSOM(ctx);
Expand Down
Loading