blogs/sites/art/src/interactives/runtime.tsx
Neeldhara Misra 58310e1944
Some checks are pending
Build / build (push) Waiting to run
Add semantic block parser and PDF export
2026-06-25 12:35:40 +05:30

77 lines
2 KiB
TypeScript

import React from "react";
import { createRoot } from "react-dom/client";
type InteractiveProps = {
id: string;
label: string;
caption?: string;
description?: string;
fallback?: string;
attrs?: Record<string, string>;
};
type InteractiveModule = {
default: React.ComponentType<InteractiveProps>;
};
const modules = import.meta.glob<InteractiveModule>("./*/index.tsx");
function readProps(element: HTMLElement): InteractiveProps {
const encoded = element.dataset.interactiveProps;
if (!encoded) {
return {
id: element.dataset.interactiveId ?? "",
label: "",
};
}
try {
return JSON.parse(decodeURIComponent(encoded)) as InteractiveProps;
} catch {
return {
id: element.dataset.interactiveId ?? "",
label: "",
fallback: element.textContent?.trim() ?? "",
};
}
}
async function mountInteractive(element: HTMLElement) {
const id = element.dataset.interactiveId;
if (!id || element.dataset.interactiveMounted) return;
const modulePath = `./${id}/index.tsx`;
const loader = modules[modulePath];
if (!loader) {
element.dataset.interactiveState = "missing-component";
return;
}
element.dataset.interactiveMounted = "true";
element.dataset.interactiveState = "loading";
try {
const props = readProps(element);
const { default: Component } = await loader();
element.replaceChildren();
createRoot(element).render(<Component {...props} />);
element.dataset.interactiveState = "ready";
} catch (error) {
element.dataset.interactiveState = "failed";
console.error(`Failed to mount interactive "${id}"`, error);
}
}
function mountAllInteractives() {
document
.querySelectorAll<HTMLElement>(".interactive-mount[data-interactive-id]")
.forEach((element) => {
void mountInteractive(element);
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", mountAllInteractives, { once: true });
} else {
mountAllInteractives();
}