inspector updates

This commit is contained in:
Your Name 2026-08-07 18:40:04 -04:00
parent 324f4abd4b
commit dc947d16b9
2 changed files with 178 additions and 18 deletions

View file

@ -39,7 +39,8 @@
function contextIdFor(element, templateId) {
try {
const ids = JSON.parse(element.dataset.blissTemplateContextIds || "{}");
if (Object.hasOwn(ids, String(templateId))) return ids[String(templateId)];
if (Object.hasOwn(ids, String(templateId)))
return ids[String(templateId)];
} catch (_) {}
return element.dataset.blissTemplateContextId || null;
}
@ -116,7 +117,8 @@
function syncAttributes(element, next) {
for (const attribute of [...element.attributes]) {
if (!next.hasAttribute(attribute.name)) element.removeAttribute(attribute.name);
if (!next.hasAttribute(attribute.name))
element.removeAttribute(attribute.name);
}
for (const attribute of [...next.attributes]) {
if (element.getAttribute(attribute.name) !== attribute.value) {
@ -144,7 +146,8 @@
return;
}
if (current.nodeType !== Node.ELEMENT_NODE) {
if (current.nodeValue !== next.nodeValue) current.nodeValue = next.nodeValue;
if (current.nodeValue !== next.nodeValue)
current.nodeValue = next.nodeValue;
return;
}
@ -178,7 +181,8 @@
}
for (const child of currentChildren) {
if (!used.has(child) && child.isConnected && !keepLiveNode(child)) child.remove();
if (!used.has(child) && child.isConnected && !keepLiveNode(child))
child.remove();
}
}
@ -210,7 +214,8 @@
// A page root must be fetched as a document. Asking for an HTMX
// fragment here used to parse an empty <body> and erase the page.
const response = await fetch(url);
if (!response.ok) throw new Error(`GET ${url} returned ${response.status}`);
if (!response.ok)
throw new Error(`GET ${url} returned ${response.status}`);
await replaceBody(await response.text());
return;
}
@ -230,7 +235,11 @@
});
}
async function refreshTemplateElement(element, templateId, previousRoots = []) {
async function refreshTemplateElement(
element,
templateId,
previousRoots = [],
) {
const response = await fetch("/_bliss/render-template", {
method: "POST",
headers: { "Content-Type": "application/json" },
@ -244,7 +253,24 @@
throw new Error(`Template ${templateId} returned ${response.status}`);
}
const html = await response.text();
if (element === document.body) return replaceBody(html, { morph: true });
// The render-template endpoint re-stamps template provenance but not the
// route/structure provenance (that comes from the route pipeline). Carry it
// over from the element being replaced so the inspector overlay and tree
// stay complete after a live template edit, instead of losing the element's
// route/copy/clone identity.
const provenance = [...element.attributes]
.filter((attribute) => attribute.name.startsWith("data-bliss-"))
.map((attribute) => ({ name: attribute.name, value: attribute.value }));
const carry = (target) => {
for (const { name, value } of provenance) {
if (!target.hasAttribute(name)) target.setAttribute(name, value);
}
};
if (element === document.body) {
await replaceBody(html, { morph: true });
carry(document.body);
return;
}
const fragment = document.createElement("template");
fragment.innerHTML = html;
// A template may legally have several top-level nodes. They share one
@ -253,6 +279,7 @@
for (const root of previousRoots) {
if (root !== element && root.isConnected) root.remove();
}
for (const root of fragment.content.children) carry(root);
element.replaceWith(fragment.content);
htmx.process(document.body);
}
@ -328,6 +355,11 @@
[data-bliss-structure-id], [data-bliss-template-id] {
transition: outline-color 80ms linear, background-color 80ms linear;
}
html.bliss-inspector-open [data-bliss-structure-id],
html.bliss-inspector-open [data-bliss-template-id] {
outline: 1px dashed rgba(255, 0, 168, .5);
outline-offset: -1px;
}
.bliss-source-highlight {
outline: 4px solid #ff00a8 !important;
outline-offset: 3px !important;
@ -346,8 +378,12 @@
document.body.appendChild(trigger);
});
document.addEventListener("bliss:highlight", (event) => highlight(event.detail));
document.addEventListener("bliss:source-saved", (event) => refreshSources(event.detail));
document.addEventListener("bliss:highlight", (event) =>
highlight(event.detail),
);
document.addEventListener("bliss:source-saved", (event) =>
refreshSources(event.detail),
);
document.addEventListener("bliss:inventory-request", publishInventory);
document.addEventListener("bliss:inspector-close", hide);
document.addEventListener("htmx:afterSwap", () => {