feat(framework): make component props reactive

This commit is contained in:
2026-08-09 13:17:36 +05:30
parent 7c584c1d2e
commit a1f671ed5d
5 changed files with 123 additions and 43 deletions
+45 -8
View File
@@ -2600,9 +2600,43 @@ export const REACTIVE_RUNTIME = String.raw`
});
});
if (behavior) {
installBehaviorFunctions(behavior.functions);
var publicScopeApi = {
// Prop expressions belong to the parent that mounted the component. The
// server forwards these markers onto the rendered child root; evaluate
// them here and write changes into the child's prop signals.
Array.prototype.slice
.call(el.querySelectorAll("[data-scope], [data-wrn-scope]"))
.forEach(function (node) {
if (!node.parentNode || ownerScope(node.parentNode) !== el) return;
Array.prototype.slice.call(node.attributes).forEach(function (attr) {
if (attr.name.indexOf("data-wrn-prop-bind-") !== 0) return;
var binding;
try { binding = JSON.parse(attr.value); } catch (_) { return; }
if (!binding || binding.length !== 2) return;
var propName = binding[0];
var template = binding[1];
reactive(function () {
var exact = /^\{([^{}]+)\}$/.exec(template);
var value;
try {
value = exact
? evalExpr(exact[1].trim(), decodeLoopLocals(node))
: template.replace(/\{([^{}]+)\}/g, function (_, expression) {
var part = evalExpr(expression.trim(), decodeLoopLocals(node));
return part == null ? "" : String(part);
});
} catch (_) { return; }
var apply = function () {
if (node.__wrnexusScopeApi) node.__wrnexusScopeApi.set(propName, value);
};
if (node.__wrnexusScopeApi) apply();
else queueMicrotask(apply);
});
});
});
// Every hydrated scope exposes state writes. Prop-only components need the
// same API even when they have no behavior block.
var publicScopeApi = {
get: peekScope,
set: writeScope,
call: function (name) {
@@ -2610,11 +2644,14 @@ export const REACTIVE_RUNTIME = String.raw`
if (typeof fn !== "function") return undefined;
return fn.apply(null, Array.prototype.slice.call(arguments, 1));
},
};
el.__wrnexusScopeApi = publicScopeApi;
el.querySelectorAll("[data-wrn-select]").forEach(function (select) {
select.__wrnexusScopeApi = publicScopeApi;
});
};
el.__wrnexusScopeApi = publicScopeApi;
el.querySelectorAll("[data-wrn-select]").forEach(function (select) {
select.__wrnexusScopeApi = publicScopeApi;
});
if (behavior) {
installBehaviorFunctions(behavior.functions);
(behavior.effects || []).forEach(function (source) {
if (typeof source !== "string" || !source.trim()) return;