Skip to content
Merged
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
124 changes: 81 additions & 43 deletions configurator/src/components/shell/PreviewPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -481,70 +481,108 @@ ${BODIES[template]}
let htmlLight = $derived(buildIframeHTML({}, "light", previewMotion, previewTemplate, frameworkCSSStatic));
let htmlDark = $derived(buildIframeHTML({}, "dark", previewMotion, previewTemplate, frameworkCSSStatic));

// SL-020: the DOM writes below (style/attribute mutation on the iframe
// document, plus bumpPreviewVersion()'s resolveCache.clear()) are cheap
// individually but these effects re-run on every override tick — e.g. every
// input event while dragging a slider, many times per animation frame.
// rAF-coalescing collapses a burst of same-frame reruns into a single
// apply using the latest captured values ("coalesce to latest"), since only
// the frame actually painted to the user matters. The effect body above
// this comment still runs synchronously on every change (so Svelte's
// dependency tracking is unaffected) — only the DOM-writing work below is
// deferred. The `return () => cancelAnimationFrame(rafId)` cleanup fires
// before Svelte re-runs this effect (or on unmount), so a still-pending
// frame from a superseded run is cancelled before scheduling the next one.
$effect(() => {
const _ov = overrides;
const _theme = previewTheme;
const _count = loadCount;
const _lock = lumlockerPreview.value;

const iframe = iframeEl;
if (_count === 0 || !iframe) return;
const doc = iframe.contentDocument;
if (!doc) return;
const rafId = requestAnimationFrame(() => {
const iframe = iframeEl;
if (_count === 0 || !iframe) return;
const doc = iframe.contentDocument;
if (!doc) return;

const styleEl = doc.getElementById("slashed-overrides");
if (styleEl) {
styleEl.textContent = generateCSS(withDerivedOverrides(_ov), { mode: "root", banner: false });
}
const styleEl = doc.getElementById("slashed-overrides");
if (styleEl) {
styleEl.textContent = generateCSS(withDerivedOverrides(_ov), { mode: "root", banner: false });
}

injectFontsIntoDoc(doc, _ov);

injectFontsIntoDoc(doc, _ov);
// Framework activates dark mode via [data-theme="dark"] (color-scheme +
// light-dark()), NOT a class — keep this in sync with buildIframeHTML.
doc.documentElement.setAttribute("data-theme", _theme);

// Framework activates dark mode via [data-theme="dark"] (color-scheme +
// light-dark()), NOT a class — keep this in sync with buildIframeHTML.
doc.documentElement.setAttribute("data-theme", _theme);
// Luminance lock preview — mirrors :root[data-lumlocker] in core/themes.css.
if (_lock) doc.documentElement.setAttribute("data-lumlocker", "");
else doc.documentElement.removeAttribute("data-lumlocker");

// Luminance lock preview — mirrors :root[data-lumlocker] in core/themes.css.
if (_lock) doc.documentElement.setAttribute("data-lumlocker", "");
else doc.documentElement.removeAttribute("data-lumlocker");
// This single-mode iframe is the canonical resolver source.
// registerPreviewDoc() always bumps internally (both its
// activeDoc-unchanged early-return and its replace-doc path do), so an
// explicit bumpPreviewVersion() here would double-bump/double-clear
// resolveCache for no reason.
registerPreviewDoc(doc);
});
Comment thread
qodo-code-review[bot] marked this conversation as resolved.

// This single-mode iframe is the canonical resolver source.
registerPreviewDoc(doc);
bumpPreviewVersion();
return () => cancelAnimationFrame(rafId);
});

$effect(() => {
const _splitMode = splitMode;
const _ov = overrides;
const _lightCount = splitLightLoadCount;
const _darkCount = splitDarkLoadCount;
const _lock = lumlockerPreview.value;
const css = generateCSS(withDerivedOverrides(_ov), { mode: "root", banner: false });

const applyLock = (doc: Document) => {
if (_lock) doc.documentElement.setAttribute("data-lumlocker", "");
else doc.documentElement.removeAttribute("data-lumlocker");
};

if (splitLightEl && _lightCount > 0) {
const doc = splitLightEl.contentDocument;
if (doc) {
const styleEl = doc.getElementById("slashed-overrides");
if (styleEl) styleEl.textContent = css;
injectFontsIntoDoc(doc, _ov);
applyLock(doc);
// In split mode the light pane is the canonical resolver source.
registerPreviewDoc(doc);
// Split iframes only exist in the DOM under {#if splitMode} below — skip
// scheduling entirely rather than doing per-frame no-op work while the
// single-iframe effect above is the one actually driving the preview.
if (!_splitMode) return;

const rafId = requestAnimationFrame(() => {
const css = generateCSS(withDerivedOverrides(_ov), { mode: "root", banner: false });

const applyLock = (doc: Document) => {
if (_lock) doc.documentElement.setAttribute("data-lumlocker", "");
else doc.documentElement.removeAttribute("data-lumlocker");
};

// registerPreviewDoc() (light pane) already bumps internally; only
// bump explicitly when the dark pane was the sole one updated this
// frame, so consumers still get notified without double-bumping.
let lightApplied = false;
let darkApplied = false;

if (splitLightEl && _lightCount > 0) {
const doc = splitLightEl.contentDocument;
if (doc) {
const styleEl = doc.getElementById("slashed-overrides");
if (styleEl) styleEl.textContent = css;
injectFontsIntoDoc(doc, _ov);
applyLock(doc);
// In split mode the light pane is the canonical resolver source.
registerPreviewDoc(doc);
lightApplied = true;
}
}
}
if (splitDarkEl && _darkCount > 0) {
const doc = splitDarkEl.contentDocument;
if (doc) {
const styleEl = doc.getElementById("slashed-overrides");
if (styleEl) styleEl.textContent = css;
injectFontsIntoDoc(doc, _ov);
applyLock(doc);
if (splitDarkEl && _darkCount > 0) {
const doc = splitDarkEl.contentDocument;
if (doc) {
const styleEl = doc.getElementById("slashed-overrides");
if (styleEl) styleEl.textContent = css;
injectFontsIntoDoc(doc, _ov);
applyLock(doc);
darkApplied = true;
}
}
}
bumpPreviewVersion();
if (darkApplied && !lightApplied) bumpPreviewVersion();
});

return () => cancelAnimationFrame(rafId);
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
});

let isConstrained = $derived(previewWidth !== "fluid");
Expand Down