Add update/hydrate methods and browser auto-init to sexp.js
Adds Sexp.update() for re-rendering data-sexp elements with new data, Sexp.hydrate() for finding and rendering all [data-sexp] elements, and auto-init on DOMContentLoaded + htmx:afterSwap integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1189,6 +1189,49 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind client-side sexp rendering to elements with data-sexp-* attrs.
|
||||
*
|
||||
* Pattern:
|
||||
* <div data-sexp="(~card :title title)" data-sexp-env='{"title":"Hi"}'>
|
||||
* <!-- server-rendered HTML (hydration target) -->
|
||||
* </div>
|
||||
*
|
||||
* Call Sexp.update(el, {title: "New"}) to re-render with new data.
|
||||
*/
|
||||
update: function (target, newEnv) {
|
||||
var el = typeof target === "string" ? document.querySelector(target) : target;
|
||||
if (!el) return;
|
||||
var source = el.getAttribute("data-sexp");
|
||||
if (!source) return;
|
||||
var baseEnv = {};
|
||||
var envAttr = el.getAttribute("data-sexp-env");
|
||||
if (envAttr) {
|
||||
try { baseEnv = JSON.parse(envAttr); } catch (e) { /* ignore */ }
|
||||
}
|
||||
var env = merge({}, _componentEnv, baseEnv, newEnv || {});
|
||||
var node = renderDOM(parse(source), env);
|
||||
el.textContent = "";
|
||||
el.appendChild(node);
|
||||
if (newEnv) {
|
||||
merge(baseEnv, newEnv);
|
||||
el.setAttribute("data-sexp-env", JSON.stringify(baseEnv));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find all [data-sexp] elements within root and render them.
|
||||
* Useful after HTMX swaps bring in new sexp-enabled elements.
|
||||
*/
|
||||
hydrate: function (root) {
|
||||
var els = (root || document).querySelectorAll("[data-sexp]");
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
if (els[i]._sexpHydrated) continue;
|
||||
els[i]._sexpHydrated = true;
|
||||
Sexp.update(els[i]);
|
||||
}
|
||||
},
|
||||
|
||||
// For testing
|
||||
_types: { NIL: NIL, Symbol: Symbol, Keyword: Keyword, Lambda: Lambda, Component: Component, RawHTML: RawHTML },
|
||||
_eval: sexpEval,
|
||||
@@ -1203,17 +1246,20 @@
|
||||
// =========================================================================
|
||||
|
||||
if (typeof document !== "undefined") {
|
||||
// Process sexp scripts on DOMContentLoaded
|
||||
function init() { Sexp.processScripts(); }
|
||||
var init = function () {
|
||||
Sexp.processScripts();
|
||||
Sexp.hydrate();
|
||||
};
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
|
||||
// Re-process after HTMX swaps (new sexp scripts may have arrived)
|
||||
// Re-process after HTMX swaps
|
||||
document.addEventListener("htmx:afterSwap", function (e) {
|
||||
Sexp.processScripts(e.detail.target);
|
||||
Sexp.hydrate(e.detail.target);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user