phlex-reactive 0.16.6 → 0.16.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,8 @@ import { computeReducer } from "phlex/reactive/compute"
26
26
  // (and ONLY one of ours)
27
27
  // opsSig the reducer's last $ops chain (issue #226), the rising-edge latch
28
28
  // seed the connect-time seed, when the root opts in
29
+ // nested re-seeds when a nested root holding a shared field connects
30
+ // share the input listener for shared fields in nested roots (issue #440)
29
31
  const contexts = new WeakMap()
30
32
 
31
33
  function ctx(controller, core) {
@@ -58,7 +60,22 @@ export function connect(controller, core, _morphed, pending) {
58
60
  if (seeds) {
59
61
  c.seed = () => recompute(c)
60
62
  c.root.addEventListener?.("turbo:morph-element", c.seed)
63
+ // Issue #440: a nested root that comes back through a plain replace (a
64
+ // morph bubbles turbo:morph-element above), or restored a draft without an
65
+ // input event, announces itself with a bubbling event; when it holds a
66
+ // shared field this root reads, its new value is one of this root's inputs.
67
+ c.nested = (event) =>
68
+ event.target !== c.root && [...event.target.querySelectorAll(SHARED_FIELD)].some(c.core.bindingOwns) && c.seed()
69
+ for (const type of NESTED_EVENTS) c.root.addEventListener?.(type, c.nested)
61
70
  }
71
+ // Issue #440: Stimulus never routes an event from inside a nested reactive
72
+ // root to this root's input->reactive#recompute, yet a control there marked
73
+ // data-reactive-shared-field is one of this root's inputs. Its edits come
74
+ // through this listener instead; an owned field's stay Stimulus's (a second
75
+ // run would be a double one); any other edit costs one attribute read.
76
+ c.share = (event) =>
77
+ event.target?.matches?.(SHARED_FIELD) && !c.core.owns(event.target) && c.core.bindingOwns(event.target) && recompute(c, event)
78
+ c.root.addEventListener?.("input", c.share)
62
79
  // The one pass a root that waited for this module owes: its seed, or the
63
80
  // recompute an edit in the window asked for.
64
81
  if (seeds || pending?.edited) recompute(c)
@@ -69,6 +86,8 @@ export function disconnect(controller) {
69
86
  if (!c) return
70
87
  contexts.delete(controller)
71
88
  if (c.seed) c.root.removeEventListener?.("turbo:morph-element", c.seed)
89
+ for (const type of NESTED_EVENTS) c.root.removeEventListener?.(type, c.nested)
90
+ c.root.removeEventListener?.("input", c.share)
72
91
  }
73
92
 
74
93
  // Re-run the seed (for a feature that changed field values after connect:
@@ -84,6 +103,11 @@ function publicRecompute(controller, core, event) {
84
103
  }
85
104
  export { publicRecompute as recompute }
86
105
 
106
+ // The marker reactive_shared_field renders (issue #434), and the bubbling
107
+ // events a nested root announces fresh field values with (issue #440).
108
+ const SHARED_FIELD = "[data-reactive-shared-field]"
109
+ const NESTED_EVENTS = ["reactive:connect", "reactive:persist-restored"]
110
+
87
111
  // The control for a name nothing owned resolves to.
88
112
  const COMPUTE_NO_CONTROL = Object.freeze({ el: null, kind: "" })
89
113
 
@@ -252,8 +276,9 @@ function parseComputeInputs(c) {
252
276
  // The declared compute input the event just edited — the reducer's
253
277
  // meta.changed (issue #75). The triggering field counts only when it is a
254
278
  // named form control OWNED by this root (not a nested reactive root's, issue
255
- // #15) AND its name is among the declared compute inputs; anything else
256
- // (a direct call, an unowned/undeclared target) yields null.
279
+ // #15, unless it is a shared field just below, issue #440) AND its name is
280
+ // among the declared compute inputs; anything else (a direct call, an
281
+ // unowned/undeclared target) yields null.
257
282
  //
258
283
  // Scope-aware (issue #184): under data-reactive-scope, the edited field's DOM
259
284
  // name is scoped (order[allowance]) while the declared inputs are BARE
@@ -265,7 +290,7 @@ function changedComputeField(c, event, inputs, scope) {
265
290
  if (!target?.name || typeof target.closest !== "function") return null
266
291
  const bare = unscopeName(target.name, scope)
267
292
  if (!inputs.includes(bare)) return null
268
- return c.core.owns(target) ? bare : null
293
+ return c.core.bindingOwns(target) ? bare : null
269
294
  }
270
295
 
271
296
  // Strip a leading `scope[…]` wrapper off a DOM field name, returning the bare
@@ -414,7 +439,10 @@ function recompute(c, event) {
414
439
  const scope = c.root.getAttribute?.("data-reactive-scope") || null
415
440
  const scoped = (name) => (scope && !name.includes("[") ? `${scope}[${name}]` : name)
416
441
 
417
- const owns = c.core.ownership()
442
+ // Inputs AND outputs resolve through what the bindings read (issue #440):
443
+ // a control marked data-reactive-shared-field just below is this root's
444
+ // too. Text nodes (reactive_text) stay strictly this root's own.
445
+ const owns = c.core.bindingOwnership()
418
446
  const byName = new Map()
419
447
  const ownedControl = (name) => {
420
448
  const known = byName.get(name)
@@ -1,4 +1,4 @@
1
- import{computeReducer as M}from"phlex/reactive/compute";var g=new WeakMap;function v(e,t){let n=g.get(e);if(!n)g.set(e,n={root:e.element,core:t,ours:new WeakSet,opsSig:null});return n}function G(e,t,n,o){let r=v(e,t),u=V(r);if(u)r.seed=()=>A(r),r.root.addEventListener?.("turbo:morph-element",r.seed);if(u||o?.edited)A(r)}function H(e){let t=g.get(e);if(!t)return;if(g.delete(e),t.seed)t.root.removeEventListener?.("turbo:morph-element",t.seed)}function K(e){g.get(e)?.seed?.()}function Q(e,t,n){return A(v(e,t),n)}var T=Object.freeze({el:null,kind:""}),j=/^#[A-Za-z_][\w-]*$/;function b({el:e,kind:t}){if(!e)return"";if(t==="checkbox")return e.checked?"true":"false";if(t==="radio")return e.checked?e.value??"":"";return e.value??""}function N(e){if(typeof e==="boolean")return e;if(e==null)return!1;let t=String(e);return t!==""&&t!=="0"&&t!=="false"}function L(e,t){if(t==="string")return b(e);let n=e.kind==="checkbox";if(t==="boolean")return n?Boolean(e.el.checked):N(b(e));if(n)return e.el.checked?1:0;let o=Number(b(e));return Number.isFinite(o)?o:0}function _(e,t,{el:n,kind:o},r,u){if(o==="checkbox"){let s=N(u);if(Boolean(n.checked)===s)return null;return n.checked=s,n}if(o==="radio")return J(e,t,r,String(u));if(String(u)===n.value)return null;return n.value=u,n}function J(e,t,n,o){let r=null;for(let u of e.querySelectorAll(`[name="${n}"]`)){if(u.type!=="radio"||!t(u))continue;let s=u.value===o;if(Boolean(u.checked)===s)continue;if(u.checked=s,s)r=u;else r??=u}return r}function W(e){if(e==null)return null;let t=Array.isArray(e)?e:e.ops;if(Array.isArray(t))return t.length>0?t:null;return console.warn("[phlex-reactive] $ops must be an ops chain or a [[op, args], ...] list — skipped"),null}function q(e){if(typeof e==="string"&&j.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(e)} — skipped`),!1}function B(e,t,n){let o=t===null?null:JSON.stringify(t),r=o!==null&&o!==e.opsSig&&n;if(e.opsSig=o,!r)return;e.core.applyOps(t,"@root")}function F(e,t){let n=e.root.getAttribute(t);if(!n)return[];try{let o=JSON.parse(n);return Array.isArray(o)?o:[]}catch{return[]}}function I(e){let t=e.root.getAttribute("data-reactive-compute-inputs-param");if(!t)return[];try{let n=JSON.parse(t);if(Array.isArray(n))return n.map((o)=>[o,"number"]);if(n&&typeof n==="object")return Object.entries(n);return[]}catch{return[]}}function z(e,t,n,o){let r=t?.target;if(!r?.name||typeof r.closest!=="function")return null;let u=P(r.name,o);if(!n.includes(u))return null;return e.core.owns(r)?u:null}function P(e,t){if(!t)return e;let n=`${t}[`;return e.startsWith(n)&&e.endsWith("]")?e.slice(n.length,-1):e}function w(e,t,n){let o=String(n);for(let r of D(e,t)){if(r.textContent===o)continue;r.textContent=o}}function D(e,t){let n=e.root.querySelectorAll(`[data-reactive-text="${t}"]`);return Array.from(n).filter((o)=>e.core.owns(o))}function C(e,t,n){let o=U(e);for(let[r,u]of Object.entries(o)){let s=r in t?null:n(r),a=r in t?t[r]:s.el?b(s):void 0;if(a===void 0||a===null)continue;let f=String(a);for(let h of Array.isArray(u)?u:[u]){if(!q(h))continue;for(let y of document.querySelectorAll(h)){if(y.textContent===f)continue;y.textContent=f}}}}function U(e){let t=e.root.getAttribute("data-reactive-compute-mirror-param");if(!t)return{};try{let n=JSON.parse(t);return n&&typeof n==="object"&&!Array.isArray(n)?n:{}}catch{return{}}}function V(e){return e.root.getAttribute?.("data-reactive-compute-seed")==="true"}function A(e,t){if(t&&e.ours.has(t))return;let n=I(e),o=n.map(([i])=>i),r=e.root.getAttribute?.("data-reactive-scope")||null,u=(i)=>r&&!i.includes("[")?`${r}[${i}]`:i,s=e.core.ownership(),a=new Map,f=(i)=>{let c=a.get(i);if(c)return c;let p=null,x=null,d=null;for(let m of e.root.querySelectorAll(`[name="${u(i)}"]`)){if(!s(m))continue;let k=m.type;if(k==="checkbox"||k==="radio"&&m.checked){d={el:m,kind:k};break}if(k==="radio")p??=m;else x??=m}if(!d)if(p)d={el:p,kind:"radio"};else d=x?{el:x,kind:""}:T;return a.set(i,d),d};for(let i of o)w(e,i,b(f(i)));let h=e.root.getAttribute("data-reactive-compute-reducer-param"),y=h?M(h):null;if(!y){C(e,{},f);return}let E=F(e,"data-reactive-compute-outputs-param"),S={};for(let[i,c]of n)S[i]=L(f(i),c);let l=y(S,{changed:z(e,t,o,r)})||{},R=W(l.$ops),O=[];for(let i of E){if(i==="$ops"||!(i in l))continue;let c=f(i);if(!c.el)continue;let p=_(e.root,s,c,u(i),l[i]);if(p)O.push(p)}for(let i of Object.keys(l)){if(i==="$ops")continue;let c=l[i];if(c===void 0||c===null)continue;w(e,i,c)}C(e,l,f);for(let i of O){let c=new Event("input",{bubbles:!0});e.ours.add(c),i.dispatchEvent(c)}B(e,R,Boolean(t))}export{G as connect,H as disconnect,Q as recompute,K as seed};
1
+ import{computeReducer as _}from"phlex/reactive/compute";var b=new WeakMap;function C(e,t){let n=b.get(e);if(!n)b.set(e,n={root:e.element,core:t,ours:new WeakSet,opsSig:null});return n}function K(e,t,n,o){let r=C(e,t),c=Z(r);if(c){r.seed=()=>A(r),r.root.addEventListener?.("turbo:morph-element",r.seed),r.nested=(s)=>s.target!==r.root&&[...s.target.querySelectorAll(v)].some(r.core.bindingOwns)&&r.seed();for(let s of N)r.root.addEventListener?.(s,r.nested)}if(r.share=(s)=>s.target?.matches?.(v)&&!r.core.owns(s.target)&&r.core.bindingOwns(s.target)&&A(r,s),r.root.addEventListener?.("input",r.share),c||o?.edited)A(r)}function Q(e){let t=b.get(e);if(!t)return;if(b.delete(e),t.seed)t.root.removeEventListener?.("turbo:morph-element",t.seed);for(let n of N)t.root.removeEventListener?.(n,t.nested);t.root.removeEventListener?.("input",t.share)}function X(e){b.get(e)?.seed?.()}function Y(e,t,n){return A(C(e,t),n)}var v="[data-reactive-shared-field]",N=["reactive:connect","reactive:persist-restored"],M=Object.freeze({el:null,kind:""}),j=/^#[A-Za-z_][\w-]*$/;function y({el:e,kind:t}){if(!e)return"";if(t==="checkbox")return e.checked?"true":"false";if(t==="radio")return e.checked?e.value??"":"";return e.value??""}function L(e){if(typeof e==="boolean")return e;if(e==null)return!1;let t=String(e);return t!==""&&t!=="0"&&t!=="false"}function q(e,t){if(t==="string")return y(e);let n=e.kind==="checkbox";if(t==="boolean")return n?Boolean(e.el.checked):L(y(e));if(n)return e.el.checked?1:0;let o=Number(y(e));return Number.isFinite(o)?o:0}function J(e,t,{el:n,kind:o},r,c){if(o==="checkbox"){let s=L(c);if(Boolean(n.checked)===s)return null;return n.checked=s,n}if(o==="radio")return W(e,t,r,String(c));if(String(c)===n.value)return null;return n.value=c,n}function W(e,t,n,o){let r=null;for(let c of e.querySelectorAll(`[name="${n}"]`)){if(c.type!=="radio"||!t(c))continue;let s=c.value===o;if(Boolean(c.checked)===s)continue;if(c.checked=s,s)r=c;else r??=c}return r}function B(e){if(e==null)return null;let t=Array.isArray(e)?e:e.ops;if(Array.isArray(t))return t.length>0?t:null;return console.warn("[phlex-reactive] $ops must be an ops chain or a [[op, args], ...] list — skipped"),null}function D(e){if(typeof e==="string"&&j.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(e)} — skipped`),!1}function F(e,t,n){let o=t===null?null:JSON.stringify(t),r=o!==null&&o!==e.opsSig&&n;if(e.opsSig=o,!r)return;e.core.applyOps(t,"@root")}function I(e,t){let n=e.root.getAttribute(t);if(!n)return[];try{let o=JSON.parse(n);return Array.isArray(o)?o:[]}catch{return[]}}function z(e){let t=e.root.getAttribute("data-reactive-compute-inputs-param");if(!t)return[];try{let n=JSON.parse(t);if(Array.isArray(n))return n.map((o)=>[o,"number"]);if(n&&typeof n==="object")return Object.entries(n);return[]}catch{return[]}}function P(e,t,n,o){let r=t?.target;if(!r?.name||typeof r.closest!=="function")return null;let c=V(r.name,o);if(!n.includes(c))return null;return e.core.bindingOwns(r)?c:null}function V(e,t){if(!t)return e;let n=`${t}[`;return e.startsWith(n)&&e.endsWith("]")?e.slice(n.length,-1):e}function E(e,t,n){let o=String(n);for(let r of H(e,t)){if(r.textContent===o)continue;r.textContent=o}}function H(e,t){let n=e.root.querySelectorAll(`[data-reactive-text="${t}"]`);return Array.from(n).filter((o)=>e.core.owns(o))}function w(e,t,n){let o=U(e);for(let[r,c]of Object.entries(o)){let s=r in t?null:n(r),f=r in t?t[r]:s.el?y(s):void 0;if(f===void 0||f===null)continue;let a=String(f);for(let g of Array.isArray(c)?c:[c]){if(!D(g))continue;for(let h of document.querySelectorAll(g)){if(h.textContent===a)continue;h.textContent=a}}}}function U(e){let t=e.root.getAttribute("data-reactive-compute-mirror-param");if(!t)return{};try{let n=JSON.parse(t);return n&&typeof n==="object"&&!Array.isArray(n)?n:{}}catch{return{}}}function Z(e){return e.root.getAttribute?.("data-reactive-compute-seed")==="true"}function A(e,t){if(t&&e.ours.has(t))return;let n=z(e),o=n.map(([i])=>i),r=e.root.getAttribute?.("data-reactive-scope")||null,c=(i)=>r&&!i.includes("[")?`${r}[${i}]`:i,s=e.core.bindingOwnership(),f=new Map,a=(i)=>{let u=f.get(i);if(u)return u;let p=null,x=null,d=null;for(let m of e.root.querySelectorAll(`[name="${c(i)}"]`)){if(!s(m))continue;let k=m.type;if(k==="checkbox"||k==="radio"&&m.checked){d={el:m,kind:k};break}if(k==="radio")p??=m;else x??=m}if(!d)if(p)d={el:p,kind:"radio"};else d=x?{el:x,kind:""}:M;return f.set(i,d),d};for(let i of o)E(e,i,y(a(i)));let g=e.root.getAttribute("data-reactive-compute-reducer-param"),h=g?_(g):null;if(!h){w(e,{},a);return}let R=I(e,"data-reactive-compute-outputs-param"),S={};for(let[i,u]of n)S[i]=q(a(i),u);let l=h(S,{changed:P(e,t,o,r)})||{},T=B(l.$ops),O=[];for(let i of R){if(i==="$ops"||!(i in l))continue;let u=a(i);if(!u.el)continue;let p=J(e.root,s,u,c(i),l[i]);if(p)O.push(p)}for(let i of Object.keys(l)){if(i==="$ops")continue;let u=l[i];if(u===void 0||u===null)continue;E(e,i,u)}w(e,l,a);for(let i of O){let u=new Event("input",{bubbles:!0});e.ours.add(u),i.dispatchEvent(u)}F(e,T,Boolean(t))}export{K as connect,Q as disconnect,Y as recompute,X as seed};
2
2
 
3
- //# debugId=B0309770BD98DEE764756E2164756E21
3
+ //# debugId=5547A787C6231C5664756E2164756E21
4
4
  //# sourceMappingURL=compute.min.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["features/compute.js"],
4
4
  "sourcesContent": [
5
- "// phlex/reactive/features/compute — client-side computes (data binding,\n// issues #104, #159, #183, #199, #262): `recompute`, the connect-time seed,\n// text mirrors and the reducer's $ops. One of the feature modules the opt-in\n// client imports on demand (issue #275); in the default client it is part of\n// the one file.\n//\n// The reducer registry is the compute seam (phlex/reactive/compute), imported\n// here by its bare name — so the runtime no longer imports it, and a page\n// with no compute binding never resolves it. The seed writes output fields a\n// request collects, so with the opt-in client the feature `gates`: a root's\n// requests wait for it. While the module is on its way, the opt-in entry\n// records that the user edited a field (`pending.edited`), and connect() runs\n// ONE recompute then: the reducer reads the inputs as the user left them, so\n// nothing they typed is overwritten, and a `recompute` the window dispatched\n// has run exactly once when it is over.\n//\n// This module never imports the runtime: it reaches a controller through the\n// `core` handle.\nimport { computeReducer } from \"phlex/reactive/compute\"\n\n// controller -> its context: the root, the core handle, and what used to be\n// the controller's own fields for this feature. Short field names: the\n// minifier never renames a property (issue #310).\n// ours the `input` events recompute dispatched for its OWN output\n// writes (issue #183), so re-entering from one skips the reducer\n// (and ONLY one of ours)\n// opsSig the reducer's last $ops chain (issue #226), the rising-edge latch\n// seed the connect-time seed, when the root opts in\nconst contexts = new WeakMap()\n\nfunction ctx(controller, core) {\n let c = contexts.get(controller)\n if (!c) contexts.set(controller, (c = { root: controller.element, core, ours: new WeakSet(), opsSig: null }))\n return c\n}\n\nexport function connect(controller, core, _morphed, pending) {\n const c = ctx(controller, core)\n // Connect-time compute seed (issue #199) — ONLY when the root carries a\n // reactive_compute binding that opts in (data-reactive-compute-seed). A\n // freshly-rendered compute root (a first paint, or a server validation-error\n // re-render that replaced the body) computed NOTHING until the first user\n // `input`; apps worked around it by dispatching a synthetic seed `input` on\n // connect, but the compute root is a distinct Stimulus controller that may\n // connect a frame later, so the seed raced its own wiring. Running ONE\n // recompute() HERE — after Stimulus has fully connected the controller and\n // wired the input->recompute delegation — runs the whole single-pass write\n // set (issue #183) synchronously, so every declared output, text sink, and\n // cross-root mirror paints from one reducer result. It is client-only\n // (recompute never enqueues a round trip) and idempotent (change-guarded\n // writes make a re-seed a no-op). A plain replace re-connects and re-seeds;\n // an in-place morph keeps the element CONNECTED and fires no Stimulus\n // lifecycle, so ALSO re-seed on turbo:morph-element. No event is passed, so\n // meta.changed is null — the correct \"no field edited yet\" seed semantics; a\n // convergent reducer's default branch computes the full settled set (see\n // compute.js CONVERGENCE REQUIREMENT).\n const seeds = computeSeedEnabled(c)\n if (seeds) {\n c.seed = () => recompute(c)\n c.root.addEventListener?.(\"turbo:morph-element\", c.seed)\n }\n // The one pass a root that waited for this module owes: its seed, or the\n // recompute an edit in the window asked for.\n if (seeds || pending?.edited) recompute(c)\n}\n\nexport function disconnect(controller) {\n const c = contexts.get(controller)\n if (!c) return\n contexts.delete(controller)\n if (c.seed) c.root.removeEventListener?.(\"turbo:morph-element\", c.seed)\n}\n\n// Re-run the seed (for a feature that changed field values after connect:\n// the draft restore).\nexport function seed(controller) {\n contexts.get(controller)?.seed?.()\n}\n\n// The Stimulus action (input->reactive#recompute); the controller's method of\n// the same name hands the event here.\nfunction publicRecompute(controller, core, event) {\n return recompute(ctx(controller, core), event)\n}\nexport { publicRecompute as recompute }\n\n// The control for a name nothing owned resolves to.\nconst COMPUTE_NO_CONTROL = Object.freeze({ el: null, kind: \"\" })\n\n// A cross-root mirror target must be a single ID selector (issue #159) — \"#\" +\n// a CSS identifier, nothing else. The client half of the two-sided default-deny\n// (reactive_compute's `mirror:` validates the SAME shape loudly at declare\n// time): a hand-built mirror attr must not widen a declared text mirror into a\n// page-wide selector write. A refused selector warns + skips (its siblings\n// still apply), matching the attr-allowlist posture.\nconst MIRROR_ID_SELECTOR = /^#[A-Za-z_][\\w-]*$/\n\n// The TEXT reading of a compute control (issue #262) — what a :string input\n// hands the reducer and what the identity/cross-root mirrors paint. A checkbox\n// reads its CHECKED STATE (\"true\"/\"false\", the strings reactive_show compares\n// against): its .value is a constant — \"1\", \"on\", whatever the markup says —\n// so reading it told the reducer nothing. A radio reads its value only while\n// checked (\"\" otherwise; the resolver hands over the checked radio of a group).\n// Anything else reads .value, as it always has.\n//\n// Every compute helper takes a CONTROL — the { el, kind } record #recompute's\n// resolver builds, kind being \"checkbox\", \"radio\" or \"\" — and never re-reads\n// el.type: the resolver reads it ONCE per name. Re-reading it in each helper\n// cost the 30-input calculator bench ~60% (16.8 → 27 µs/iter, measured).\nfunction computeText({ el, kind }) {\n if (!el) return \"\"\n if (kind === \"checkbox\") return el.checked ? \"true\" : \"false\"\n if (kind === \"radio\") return el.checked ? (el.value ?? \"\") : \"\"\n return el.value ?? \"\"\n}\n\n// Whether a value counts as \"on\" — for a :boolean input read off a control that\n// is not a checkbox, and for an output written INTO a checkbox. A boolean is\n// itself; otherwise \"\", \"0\" and \"false\" are off (what a hidden flag field or a\n// reducer returning 0 means) and anything else is on.\nfunction computeTruthy(value) {\n if (typeof value === \"boolean\") return value\n if (value == null) return false\n const text = String(value)\n return text !== \"\" && text !== \"0\" && text !== \"false\"\n}\n\n// One declared input's value for the reducer, coerced by its declared type\n// (issue #104; checked-state controls issue #262):\n//\n// \"string\" → the text reading, raw (blank/absent → \"\")\n// \"boolean\" → a checkbox's checked state; any other control by computeTruthy\n// \"number\" → a checkbox is 1/0; anything else through Number (blank/NaN → 0,\n// the nanToZero the hand-written calculators use)\n//\n// A checkbox is 1/0 and never Number(its value): a box is a yes/no, and a\n// reducer that wants an amount writes `gift ? 25 : 0`.\nfunction computeValue(control, type) {\n if (type === \"string\") return computeText(control)\n const box = control.kind === \"checkbox\"\n if (type === \"boolean\") return box ? Boolean(control.el.checked) : computeTruthy(computeText(control))\n if (box) return control.el.checked ? 1 : 0\n const n = Number(computeText(control))\n return Number.isFinite(n) ? n : 0\n}\n\n// Write one reducer output into the control its name resolved to (issue #262),\n// change-guarded. Returns the element to announce with an `input` event, or\n// null when nothing changed. A checkbox takes the result as its checked state\n// and a radio group checks the radio carrying it — neither ever has its value\n// attribute rewritten, which would change what the control SUBMITS. Anything\n// else takes the result as its .value (issue #76).\nfunction computeWrite(root, owns, { el, kind }, domName, value) {\n if (kind === \"checkbox\") {\n const checked = computeTruthy(value)\n if (Boolean(el.checked) === checked) return null\n el.checked = checked\n return el\n }\n if (kind === \"radio\") return computeCheckRadio(root, owns, domName, String(value))\n if (String(value) === el.value) return null\n el.value = value\n return el\n}\n\n// Check the owned radio of a group whose value is `wanted`, unchecking the\n// rest — the same per-radio rule a restored draft applies. A value no radio\n// carries clears the group. Returns the radio that GAINED the check, or, for a\n// cleared group, the one that lost it; null when the selection already matched.\nfunction computeCheckRadio(root, owns, domName, wanted) {\n let announced = null\n for (const el of root.querySelectorAll(`[name=\"${domName}\"]`)) {\n if (el.type !== \"radio\" || !owns(el)) continue\n const checked = el.value === wanted\n if (Boolean(el.checked) === checked) continue\n el.checked = checked\n if (checked) announced = el\n else announced ??= el\n }\n return announced\n}\n\n// Normalize a reducer's reserved $ops output (issue #226): the compute `ops`\n// builder (its .ops list), a raw [[name, args], ...] array, or null/undefined\n// (no effect this pass). An EMPTY list is the same as null — \"nothing to run\"\n// must not latch the rising edge. Anything else warns + is dropped\n// (default-deny, like every other malformed op source). Reducers are trusted\n// app code, but their ops still run through the frozen CLIENT_OPS whitelist.\nfunction computeOpsList(raw) {\n if (raw == null) return null\n const list = Array.isArray(raw) ? raw : raw.ops\n if (Array.isArray(list)) return list.length > 0 ? list : null\n console.warn(\"[phlex-reactive] $ops must be an ops chain or a [[op, args], ...] list — skipped\")\n return null\n}\n\nfunction guardMirrorSelector(selector) {\n if (typeof selector === \"string\" && MIRROR_ID_SELECTOR.test(selector)) return true\n console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(selector)} — skipped`)\n return false\n}\n\n// Apply a reducer-emitted $ops chain (issue #226) on its RISING EDGE, keyed\n// on CONTENT: fire only when THIS pass's chain differs from the LAST pass's\n// (including from \"absent\"), and only on an event-driven pass. An unchanged\n// chain never re-fires — \"still complete, same submit\" is settled, exactly\n// like the change-guarded field writes. A pass with no $ops re-arms; a pass\n// whose chain CHANGED fires again (per-keystroke focus advance across OTP\n// boxes is a different focus target each time — a deliberately new intent).\n// Ops run through the shared CLIENT_OPS interpreter with runOps's\n// root-scoped target resolution; a missing to: defaults to \"@root\"\n// (hand-written reducer ergonomics).\nfunction applyComputeOps(c, list, eventDriven) {\n const signature = list === null ? null : JSON.stringify(list)\n const fire = signature !== null && signature !== c.opsSig && eventDriven\n c.opsSig = signature\n if (!fire) return\n c.core.applyOps(list, \"@root\")\n}\n\n// Parse a JSON string list from a root data attr; [] on absence/parse error so\n// a malformed binding degrades to \"no fields\" rather than throwing on input.\nfunction parseComputeList(c, attr) {\n const raw = c.root.getAttribute(attr)\n if (!raw) return []\n try {\n const list = JSON.parse(raw)\n return Array.isArray(list) ? list : []\n } catch {\n return []\n }\n}\n\n// Parse the inputs param into [name, type] pairs (issue #104). The wire is a\n// JSON ARRAY of names (array form → every input typed \"number\", the shipped\n// numeric coercion) OR a JSON OBJECT of name→type (hash form → \":string\" read\n// raw, \":number\" coerced). Malformed/absent degrades to [] — a bad binding\n// must never throw on input.\nfunction parseComputeInputs(c) {\n const raw = c.root.getAttribute(\"data-reactive-compute-inputs-param\")\n if (!raw) return []\n try {\n const parsed = JSON.parse(raw)\n if (Array.isArray(parsed)) return parsed.map((name) => [name, \"number\"])\n if (parsed && typeof parsed === \"object\") return Object.entries(parsed)\n return []\n } catch {\n return []\n }\n}\n\n// The declared compute input the event just edited — the reducer's\n// meta.changed (issue #75). The triggering field counts only when it is a\n// named form control OWNED by this root (not a nested reactive root's, issue\n// #15) AND its name is among the declared compute inputs; anything else\n// (a direct call, an unowned/undeclared target) yields null.\n//\n// Scope-aware (issue #184): under data-reactive-scope, the edited field's DOM\n// name is scoped (order[allowance]) while the declared inputs are BARE\n// (allowance). Strip the scope prefix off the DOM name before comparing, and\n// return the BARE name — so a reducer branching on `changed` sees the same\n// names it declared, scoped or not.\nfunction changedComputeField(c, event, inputs, scope) {\n const target = event?.target\n if (!target?.name || typeof target.closest !== \"function\") return null\n const bare = unscopeName(target.name, scope)\n if (!inputs.includes(bare)) return null\n return c.core.owns(target) ? bare : null\n}\n\n// Strip a leading `scope[…]` wrapper off a DOM field name, returning the bare\n// inner name; a name that isn't wrapped in this scope passes through unchanged.\nfunction unscopeName(name, scope) {\n if (!scope) return name\n const prefix = `${scope}[`\n return name.startsWith(prefix) && name.endsWith(\"]\") ? name.slice(prefix.length, -1) : name\n}\n\n// Write `value` into every owned [data-reactive-text=\"<name>\"] node via\n// textContent (issue #104) — XSS-safe by construction (never innerHTML). Drives\n// both the identity mirror (an input's raw value) and a text-node output (a\n// reducer result with no matching field). Change-guarded (skip an unchanged\n// node) and NO input dispatch — a text node has no listener contract. String()\n// so a numeric result renders like the DOM would.\nfunction mirrorText(c, name, value) {\n const text = String(value)\n for (const node of ownedTextNodes(c, name)) {\n if (node.textContent === text) continue\n node.textContent = text\n }\n}\n\n// Every [data-reactive-text=\"<name>\"] mirror OWNED by this root (skips nested\n// reactive roots, issue #15). Empty when none — reactive_text is optional.\nfunction ownedTextNodes(c, name) {\n const nodes = c.root.querySelectorAll(`[data-reactive-text=\"${name}\"]`)\n return Array.from(nodes).filter((el) => c.core.owns(el))\n}\n\n// Cross-root text mirrors (issue #159): paint every DECLARED mirror name into\n// its allowlisted document-wide id targets via textContent — the opt-in escape\n// from root isolation (issue #15) for a recap OUTSIDE the computing root. The\n// value is the reducer's result when it produced one, else the owned field's\n// CURRENT value (an input identity mirror / a just-written output) — one\n// declaration covers all three shapes. A name with NO value this pass is\n// SKIPPED (a mirror never blanks a recap the reducer didn't feed). textContent\n// only (never innerHTML), change-guarded, and NO input dispatch — same\n// contract as #mirrorText. With no mirror declared this is one getAttribute\n// and out — the shipped compute path never touches the document.\nfunction applyComputeMirrors(c, result, ownedControl) {\n const mirror = parseComputeMirror(c)\n for (const [name, selectors] of Object.entries(mirror)) {\n const control = name in result ? null : ownedControl(name)\n const value = name in result ? result[name] : control.el ? computeText(control) : undefined\n if (value === undefined || value === null) continue\n const text = String(value)\n for (const sel of Array.isArray(selectors) ? selectors : [selectors]) {\n if (!guardMirrorSelector(sel)) continue\n for (const node of document.querySelectorAll(sel)) {\n if (node.textContent === text) continue\n node.textContent = text\n }\n }\n }\n}\n\n// The declared cross-root mirror map (issue #159): a JSON object of\n// { name: [id selectors] } from data-reactive-compute-mirror-param (emitted by\n// reactive_compute's `mirror:`). Absent/malformed degrades to {} — a bad\n// binding must never throw on input.\nfunction parseComputeMirror(c) {\n const raw = c.root.getAttribute(\"data-reactive-compute-mirror-param\")\n if (!raw) return {}\n try {\n const parsed = JSON.parse(raw)\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? parsed : {}\n } catch {\n return {}\n }\n}\n\n// Whether this root opts into the connect-time compute seed (issue #199).\n// reactive_compute's root binding emits data-reactive-compute-seed=\"true\"; a\n// root without a compute binding (or with the seed opted out) pays one\n// attribute read and never seeds. A quick read, evaluated once per connect.\nfunction computeSeedEnabled(c) {\n return c.root.getAttribute?.(\"data-reactive-compute-seed\") === \"true\"\n}\n\n// Client-side compute (data binding). Wired by reactive_compute: an `input`\n// trigger (input->reactive#recompute) runs a REGISTERED JS reducer over the\n// named input fields and writes the named output fields WITH NO ROUND TRIP —\n// the \"instant\" half of the new/unpersisted-record UX. If the field ALSO\n// carries on(...) (a persisted record, or a synced draft), that debounced POST\n// still fires and the server reply reconciles; recompute just paints first.\n//\n// Reads inputs/outputs/reducer from the root's data-reactive-compute-* attrs\n// (set once by reactive_compute_attrs). A missing/unregistered reducer is a\n// no-op — a page must never break because a binding wasn't wired up.\n//\n// The reducer gets a second argument, meta = { changed } (issue #75): the\n// name of the declared input the triggering event edited, or null for a\n// direct call / an unowned or undeclared target. A multi-way rebalance\n// branches on it (edit c → derive a; else → derive c). Note that a #76\n// output write dispatches a real input event, so recompute RE-ENTERS with\n// changed = that output's name — the reducer must be convergent (see\n// compute.js) so the change guard settles the chain.\nfunction recompute(c, event) {\n // Issue #183 — single-pass write set: an `input` event this method dispatched\n // for its OWN output writes is self-marked. Re-running the reducer on it would\n // re-enter from a partially-written DOM (the old mid-loop-dispatch corruption\n // class). Skip the reducer for our own event — but ONLY ours: the marker lives\n // in a per-instance WeakSet, so a genuinely different root's compute event (or\n // a real user edit) is never swallowed. The event still bubbled and fired every\n // OTHER listener (dirty tracking, show bindings, sibling roots) before reaching\n // here; we simply don't recompute a second time from our own write.\n if (event && c.ours.has(event)) return\n\n // Inputs may be a JSON ARRAY of names (array form — every input coerced\n // through Number, the shipped behavior) or a JSON OBJECT of name→type (hash\n // form, issue #104 — :number coerced, :string read raw). #parseComputeInputs\n // returns [name, type] pairs either way (array form defaults type \"number\").\n const inputPairs = parseComputeInputs(c)\n const inputs = inputPairs.map(([name]) => name)\n\n // Resolve every declared input AND output through ONE per-call resolver whose\n // ownership probe is computed ONCE (issue #117), replacing the per-name\n // closest() walk #ownedField did on every read — a 30-field calculator paid\n // ~60 closest() sweeps per keystroke. #ownershipFilter returns a constant-true\n // predicate in the common no-nested-root case (skipping closest() entirely)\n // and the exact #ownsField check when a nested reactive root is present\n // (issue #15 scoping, byte-identical to before). Resolution is memoized in a\n // per-CALL Map, so a name read as an input AND written as an output\n // resolves to the SAME element and is queried once.\n //\n // Which element a name resolves to (issue #262, mirroring #showFieldValue): a\n // CHECKBOX wins over the hidden companion Rails renders before it; a radio\n // group resolves to its CHECKED radio (any radio of the group when none is);\n // anything else is first-wins. Resolving first-wins across the board handed\n // the reducer the companion's constant \"0\" and the first radio's value.\n //\n // Why per-name `[name=\"X\"]` queries and not one bare `[name]` sweep: a single\n // sweep is the natural \"one walk\", but the resolver must issue the SAME\n // per-name query shape the field walk always has (the issue-#15 unit fakes\n // answer only `[name=\"X\"]`). It is O(distinct declared names) queries, not the\n // old O(inputs + outputs) — the ownership decision is hoisted out of the loop.\n // The memo is per-CALL only: an output write dispatches `input` (issue #76),\n // re-entering recompute, which correctly rebuilds a fresh map (a morph may\n // have replaced the nodes) — it is NEVER stored on the instance.\n // Scope (issue #183, mirroring #showFieldValue): a bare compute name `cash`\n // under `data-reactive-scope=\"order\"` resolves as `[name=\"order[cash]\"]`. A\n // name already carrying a bracket (a raw wire name the author passed) is used\n // verbatim — so bracketed literals pass through unscoped.\n const scope = c.root.getAttribute?.(\"data-reactive-scope\") || null\n const scoped = (name) => (scope && !name.includes(\"[\") ? `${scope}[${name}]` : name)\n\n const owns = c.core.ownership()\n const byName = new Map()\n const ownedControl = (name) => {\n const known = byName.get(name)\n if (known) return known\n let radio = null\n let first = null\n let control = null\n for (const el of c.root.querySelectorAll(`[name=\"${scoped(name)}\"]`)) {\n if (!owns(el)) continue\n const kind = el.type // read ONCE per element — see computeText\n if (kind === \"checkbox\" || (kind === \"radio\" && el.checked)) {\n control = { el, kind }\n break\n }\n if (kind === \"radio\") radio ??= el\n else first ??= el\n }\n if (!control) {\n if (radio) control = { el: radio, kind: \"radio\" }\n else control = first ? { el: first, kind: \"\" } : COMPUTE_NO_CONTROL\n }\n byName.set(name, control)\n return control\n }\n\n // Identity-mirror pass (issue #104), ALWAYS run — even with NO registered\n // reducer, so reactive_text(:title) mirrors a field into its text node with\n // zero reducer wiring. Each declared input's RAW text reading (computeText —\n // a checkbox paints \"true\"/\"false\", issue #262) is written to its owned\n // [data-reactive-text=\"<name>\"] node(s). It runs BEFORE the reducer\n // early-return below so a reducer-less binding still mirrors.\n for (const name of inputs) mirrorText(c, name, computeText(ownedControl(name)))\n\n const key = c.root.getAttribute(\"data-reactive-compute-reducer-param\")\n const reduce = key ? computeReducer(key) : null\n if (!reduce) {\n // No reducer registered: the identity pass above still ran, so declared\n // cross-root mirrors of the INPUT names still paint (issue #159) — a\n // reducer-less binding mirrors, exactly like the owned-text-node case.\n applyComputeMirrors(c, {}, ownedControl)\n return\n }\n\n const outputs = parseComputeList(c, \"data-reactive-compute-outputs-param\")\n\n // Coerce each input per its declared type (computeValue): \"string\" raw,\n // \"boolean\" a real boolean, else (\"number\", the array-form default) the\n // numeric coercion. A checkbox contributes its CHECKED STATE under every\n // type (issue #262). Reads from the memoized resolver — no re-query.\n const values = {}\n for (const [name, type] of inputPairs) values[name] = computeValue(ownedControl(name), type)\n\n // meta.changed stays on #changedComputeField (its own #ownsField check over\n // the raw event target) — NOT this resolver. The issue-#15 nested-rejection\n // test depends on that path being unchanged. ONE run, from the ONE pre-write\n // snapshot above (issue #183): its result drives the whole single-pass write.\n const result = reduce(values, { changed: changedComputeField(c, event, inputs, scope) }) || {}\n\n // The reserved $ops output (issue #226) is CONSUMED here — normalized once,\n // then excluded from every write phase below (it is an op chain, never a\n // field value, text sink, or mirror), and applied as phase 4.\n const reducerOps = computeOpsList(result.$ops)\n\n // Issue #183 — SINGLE-PASS WRITE SET. Ordered phases, so declared output\n // order stops being semantics and a wrong order can no longer corrupt values:\n //\n // 1. BATCH the field writes from the ONE result. Each output name in the\n // allowlist (outputs:) whose owned field's value actually changes is\n // written now (change-guarded) and remembered — but NO `input` event is\n // dispatched yet, so nothing re-enters mid-batch. A checkbox or radio\n // output is written as its CHECKED state (computeWrite, issue #262).\n // 2. PAINT the sinks from the SETTLED values: any owned reactive_text node by\n // presence (issue #183 change #4 — a text node no longer needs its name in\n // outputs:), then the cross-root mirror: ids (issue #159).\n // 3. DISPATCH a self-marked `input` on each changed field. The marker (a\n // per-instance WeakSet) makes recompute skip re-running the reducer for our\n // own write, while the event still fires every OTHER listener (chained\n // repaint, dirty tracking, show bindings, sibling roots).\n // 4. RUN the reducer's $ops chain (issue #226) — rising-edge, event-gated —\n // so its ops (dispatch a completion event, submit the form) always see\n // the fully settled DOM and every chained listener has already run.\n const changedFields = []\n for (const name of outputs) {\n if (name === \"$ops\" || !(name in result)) continue\n const control = ownedControl(name)\n if (!control.el) continue // a non-field output paints as a text sink in phase 2\n const written = computeWrite(c.root, owns, control, scoped(name), result[name])\n if (written) changedFields.push(written) // null = change-guard, unchanged\n }\n\n // Phase 2 — text sinks declare themselves (issue #183 change #4): every result\n // key paints into any owned [data-reactive-text=\"<name>\"] node by PRESENCE,\n // regardless of outputs: membership. Runs from settled field values. A null/\n // undefined result value is SKIPPED (never stringified to \"null\"/\"undefined\") —\n // the same \"no value this pass, don't paint\" filter #applyComputeMirrors uses.\n for (const name of Object.keys(result)) {\n if (name === \"$ops\") continue\n const value = result[name]\n if (value === undefined || value === null) continue\n mirrorText(c, name, value)\n }\n\n // Cross-root text mirrors (issue #159) — AFTER the batch + text sinks, so a\n // mirror keyed on a just-written output paints the settled value.\n applyComputeMirrors(c, result, ownedControl)\n\n // Phase 3 — dispatch the deferred `input` events (issue #183). Real browsers\n // do NOT fire `input` on a programmatic .value write (issue #76), so we do it\n // ourselves, matching the server's set_value + dispatch(\"input\") contract.\n // Each event is SELF-MARKED so our own re-entry skips the reducer (guard at the\n // top of recompute) — but the event still bubbles and fires every other\n // listener. Dispatched AFTER all writes + paints, so a chained listener reads\n // SETTLED values, never a half-written DOM.\n for (const field of changedFields) {\n const inputEvent = new Event(\"input\", { bubbles: true })\n c.ours.add(inputEvent)\n field.dispatchEvent(inputEvent)\n }\n\n // Phase 4 — the reducer's $ops chain (issue #226), after everything settled.\n // Event-gated: a seed/direct recompute() pass (no event) arms the latch but\n // never fires, so a restored/re-rendered complete value can't auto-fire.\n applyComputeOps(c, reducerOps, Boolean(event))\n}\n"
5
+ "// phlex/reactive/features/compute — client-side computes (data binding,\n// issues #104, #159, #183, #199, #262): `recompute`, the connect-time seed,\n// text mirrors and the reducer's $ops. One of the feature modules the opt-in\n// client imports on demand (issue #275); in the default client it is part of\n// the one file.\n//\n// The reducer registry is the compute seam (phlex/reactive/compute), imported\n// here by its bare name — so the runtime no longer imports it, and a page\n// with no compute binding never resolves it. The seed writes output fields a\n// request collects, so with the opt-in client the feature `gates`: a root's\n// requests wait for it. While the module is on its way, the opt-in entry\n// records that the user edited a field (`pending.edited`), and connect() runs\n// ONE recompute then: the reducer reads the inputs as the user left them, so\n// nothing they typed is overwritten, and a `recompute` the window dispatched\n// has run exactly once when it is over.\n//\n// This module never imports the runtime: it reaches a controller through the\n// `core` handle.\nimport { computeReducer } from \"phlex/reactive/compute\"\n\n// controller -> its context: the root, the core handle, and what used to be\n// the controller's own fields for this feature. Short field names: the\n// minifier never renames a property (issue #310).\n// ours the `input` events recompute dispatched for its OWN output\n// writes (issue #183), so re-entering from one skips the reducer\n// (and ONLY one of ours)\n// opsSig the reducer's last $ops chain (issue #226), the rising-edge latch\n// seed the connect-time seed, when the root opts in\n// nested re-seeds when a nested root holding a shared field connects\n// share the input listener for shared fields in nested roots (issue #440)\nconst contexts = new WeakMap()\n\nfunction ctx(controller, core) {\n let c = contexts.get(controller)\n if (!c) contexts.set(controller, (c = { root: controller.element, core, ours: new WeakSet(), opsSig: null }))\n return c\n}\n\nexport function connect(controller, core, _morphed, pending) {\n const c = ctx(controller, core)\n // Connect-time compute seed (issue #199) — ONLY when the root carries a\n // reactive_compute binding that opts in (data-reactive-compute-seed). A\n // freshly-rendered compute root (a first paint, or a server validation-error\n // re-render that replaced the body) computed NOTHING until the first user\n // `input`; apps worked around it by dispatching a synthetic seed `input` on\n // connect, but the compute root is a distinct Stimulus controller that may\n // connect a frame later, so the seed raced its own wiring. Running ONE\n // recompute() HERE — after Stimulus has fully connected the controller and\n // wired the input->recompute delegation — runs the whole single-pass write\n // set (issue #183) synchronously, so every declared output, text sink, and\n // cross-root mirror paints from one reducer result. It is client-only\n // (recompute never enqueues a round trip) and idempotent (change-guarded\n // writes make a re-seed a no-op). A plain replace re-connects and re-seeds;\n // an in-place morph keeps the element CONNECTED and fires no Stimulus\n // lifecycle, so ALSO re-seed on turbo:morph-element. No event is passed, so\n // meta.changed is null — the correct \"no field edited yet\" seed semantics; a\n // convergent reducer's default branch computes the full settled set (see\n // compute.js CONVERGENCE REQUIREMENT).\n const seeds = computeSeedEnabled(c)\n if (seeds) {\n c.seed = () => recompute(c)\n c.root.addEventListener?.(\"turbo:morph-element\", c.seed)\n // Issue #440: a nested root that comes back through a plain replace (a\n // morph bubbles turbo:morph-element above), or restored a draft without an\n // input event, announces itself with a bubbling event; when it holds a\n // shared field this root reads, its new value is one of this root's inputs.\n c.nested = (event) =>\n event.target !== c.root && [...event.target.querySelectorAll(SHARED_FIELD)].some(c.core.bindingOwns) && c.seed()\n for (const type of NESTED_EVENTS) c.root.addEventListener?.(type, c.nested)\n }\n // Issue #440: Stimulus never routes an event from inside a nested reactive\n // root to this root's input->reactive#recompute, yet a control there marked\n // data-reactive-shared-field is one of this root's inputs. Its edits come\n // through this listener instead; an owned field's stay Stimulus's (a second\n // run would be a double one); any other edit costs one attribute read.\n c.share = (event) =>\n event.target?.matches?.(SHARED_FIELD) && !c.core.owns(event.target) && c.core.bindingOwns(event.target) && recompute(c, event)\n c.root.addEventListener?.(\"input\", c.share)\n // The one pass a root that waited for this module owes: its seed, or the\n // recompute an edit in the window asked for.\n if (seeds || pending?.edited) recompute(c)\n}\n\nexport function disconnect(controller) {\n const c = contexts.get(controller)\n if (!c) return\n contexts.delete(controller)\n if (c.seed) c.root.removeEventListener?.(\"turbo:morph-element\", c.seed)\n for (const type of NESTED_EVENTS) c.root.removeEventListener?.(type, c.nested)\n c.root.removeEventListener?.(\"input\", c.share)\n}\n\n// Re-run the seed (for a feature that changed field values after connect:\n// the draft restore).\nexport function seed(controller) {\n contexts.get(controller)?.seed?.()\n}\n\n// The Stimulus action (input->reactive#recompute); the controller's method of\n// the same name hands the event here.\nfunction publicRecompute(controller, core, event) {\n return recompute(ctx(controller, core), event)\n}\nexport { publicRecompute as recompute }\n\n// The marker reactive_shared_field renders (issue #434), and the bubbling\n// events a nested root announces fresh field values with (issue #440).\nconst SHARED_FIELD = \"[data-reactive-shared-field]\"\nconst NESTED_EVENTS = [\"reactive:connect\", \"reactive:persist-restored\"]\n\n// The control for a name nothing owned resolves to.\nconst COMPUTE_NO_CONTROL = Object.freeze({ el: null, kind: \"\" })\n\n// A cross-root mirror target must be a single ID selector (issue #159) — \"#\" +\n// a CSS identifier, nothing else. The client half of the two-sided default-deny\n// (reactive_compute's `mirror:` validates the SAME shape loudly at declare\n// time): a hand-built mirror attr must not widen a declared text mirror into a\n// page-wide selector write. A refused selector warns + skips (its siblings\n// still apply), matching the attr-allowlist posture.\nconst MIRROR_ID_SELECTOR = /^#[A-Za-z_][\\w-]*$/\n\n// The TEXT reading of a compute control (issue #262) — what a :string input\n// hands the reducer and what the identity/cross-root mirrors paint. A checkbox\n// reads its CHECKED STATE (\"true\"/\"false\", the strings reactive_show compares\n// against): its .value is a constant — \"1\", \"on\", whatever the markup says —\n// so reading it told the reducer nothing. A radio reads its value only while\n// checked (\"\" otherwise; the resolver hands over the checked radio of a group).\n// Anything else reads .value, as it always has.\n//\n// Every compute helper takes a CONTROL — the { el, kind } record #recompute's\n// resolver builds, kind being \"checkbox\", \"radio\" or \"\" — and never re-reads\n// el.type: the resolver reads it ONCE per name. Re-reading it in each helper\n// cost the 30-input calculator bench ~60% (16.8 → 27 µs/iter, measured).\nfunction computeText({ el, kind }) {\n if (!el) return \"\"\n if (kind === \"checkbox\") return el.checked ? \"true\" : \"false\"\n if (kind === \"radio\") return el.checked ? (el.value ?? \"\") : \"\"\n return el.value ?? \"\"\n}\n\n// Whether a value counts as \"on\" — for a :boolean input read off a control that\n// is not a checkbox, and for an output written INTO a checkbox. A boolean is\n// itself; otherwise \"\", \"0\" and \"false\" are off (what a hidden flag field or a\n// reducer returning 0 means) and anything else is on.\nfunction computeTruthy(value) {\n if (typeof value === \"boolean\") return value\n if (value == null) return false\n const text = String(value)\n return text !== \"\" && text !== \"0\" && text !== \"false\"\n}\n\n// One declared input's value for the reducer, coerced by its declared type\n// (issue #104; checked-state controls issue #262):\n//\n// \"string\" → the text reading, raw (blank/absent → \"\")\n// \"boolean\" → a checkbox's checked state; any other control by computeTruthy\n// \"number\" → a checkbox is 1/0; anything else through Number (blank/NaN → 0,\n// the nanToZero the hand-written calculators use)\n//\n// A checkbox is 1/0 and never Number(its value): a box is a yes/no, and a\n// reducer that wants an amount writes `gift ? 25 : 0`.\nfunction computeValue(control, type) {\n if (type === \"string\") return computeText(control)\n const box = control.kind === \"checkbox\"\n if (type === \"boolean\") return box ? Boolean(control.el.checked) : computeTruthy(computeText(control))\n if (box) return control.el.checked ? 1 : 0\n const n = Number(computeText(control))\n return Number.isFinite(n) ? n : 0\n}\n\n// Write one reducer output into the control its name resolved to (issue #262),\n// change-guarded. Returns the element to announce with an `input` event, or\n// null when nothing changed. A checkbox takes the result as its checked state\n// and a radio group checks the radio carrying it — neither ever has its value\n// attribute rewritten, which would change what the control SUBMITS. Anything\n// else takes the result as its .value (issue #76).\nfunction computeWrite(root, owns, { el, kind }, domName, value) {\n if (kind === \"checkbox\") {\n const checked = computeTruthy(value)\n if (Boolean(el.checked) === checked) return null\n el.checked = checked\n return el\n }\n if (kind === \"radio\") return computeCheckRadio(root, owns, domName, String(value))\n if (String(value) === el.value) return null\n el.value = value\n return el\n}\n\n// Check the owned radio of a group whose value is `wanted`, unchecking the\n// rest — the same per-radio rule a restored draft applies. A value no radio\n// carries clears the group. Returns the radio that GAINED the check, or, for a\n// cleared group, the one that lost it; null when the selection already matched.\nfunction computeCheckRadio(root, owns, domName, wanted) {\n let announced = null\n for (const el of root.querySelectorAll(`[name=\"${domName}\"]`)) {\n if (el.type !== \"radio\" || !owns(el)) continue\n const checked = el.value === wanted\n if (Boolean(el.checked) === checked) continue\n el.checked = checked\n if (checked) announced = el\n else announced ??= el\n }\n return announced\n}\n\n// Normalize a reducer's reserved $ops output (issue #226): the compute `ops`\n// builder (its .ops list), a raw [[name, args], ...] array, or null/undefined\n// (no effect this pass). An EMPTY list is the same as null — \"nothing to run\"\n// must not latch the rising edge. Anything else warns + is dropped\n// (default-deny, like every other malformed op source). Reducers are trusted\n// app code, but their ops still run through the frozen CLIENT_OPS whitelist.\nfunction computeOpsList(raw) {\n if (raw == null) return null\n const list = Array.isArray(raw) ? raw : raw.ops\n if (Array.isArray(list)) return list.length > 0 ? list : null\n console.warn(\"[phlex-reactive] $ops must be an ops chain or a [[op, args], ...] list — skipped\")\n return null\n}\n\nfunction guardMirrorSelector(selector) {\n if (typeof selector === \"string\" && MIRROR_ID_SELECTOR.test(selector)) return true\n console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(selector)} — skipped`)\n return false\n}\n\n// Apply a reducer-emitted $ops chain (issue #226) on its RISING EDGE, keyed\n// on CONTENT: fire only when THIS pass's chain differs from the LAST pass's\n// (including from \"absent\"), and only on an event-driven pass. An unchanged\n// chain never re-fires — \"still complete, same submit\" is settled, exactly\n// like the change-guarded field writes. A pass with no $ops re-arms; a pass\n// whose chain CHANGED fires again (per-keystroke focus advance across OTP\n// boxes is a different focus target each time — a deliberately new intent).\n// Ops run through the shared CLIENT_OPS interpreter with runOps's\n// root-scoped target resolution; a missing to: defaults to \"@root\"\n// (hand-written reducer ergonomics).\nfunction applyComputeOps(c, list, eventDriven) {\n const signature = list === null ? null : JSON.stringify(list)\n const fire = signature !== null && signature !== c.opsSig && eventDriven\n c.opsSig = signature\n if (!fire) return\n c.core.applyOps(list, \"@root\")\n}\n\n// Parse a JSON string list from a root data attr; [] on absence/parse error so\n// a malformed binding degrades to \"no fields\" rather than throwing on input.\nfunction parseComputeList(c, attr) {\n const raw = c.root.getAttribute(attr)\n if (!raw) return []\n try {\n const list = JSON.parse(raw)\n return Array.isArray(list) ? list : []\n } catch {\n return []\n }\n}\n\n// Parse the inputs param into [name, type] pairs (issue #104). The wire is a\n// JSON ARRAY of names (array form → every input typed \"number\", the shipped\n// numeric coercion) OR a JSON OBJECT of name→type (hash form → \":string\" read\n// raw, \":number\" coerced). Malformed/absent degrades to [] — a bad binding\n// must never throw on input.\nfunction parseComputeInputs(c) {\n const raw = c.root.getAttribute(\"data-reactive-compute-inputs-param\")\n if (!raw) return []\n try {\n const parsed = JSON.parse(raw)\n if (Array.isArray(parsed)) return parsed.map((name) => [name, \"number\"])\n if (parsed && typeof parsed === \"object\") return Object.entries(parsed)\n return []\n } catch {\n return []\n }\n}\n\n// The declared compute input the event just edited — the reducer's\n// meta.changed (issue #75). The triggering field counts only when it is a\n// named form control OWNED by this root (not a nested reactive root's, issue\n// #15, unless it is a shared field just below, issue #440) AND its name is\n// among the declared compute inputs; anything else (a direct call, an\n// unowned/undeclared target) yields null.\n//\n// Scope-aware (issue #184): under data-reactive-scope, the edited field's DOM\n// name is scoped (order[allowance]) while the declared inputs are BARE\n// (allowance). Strip the scope prefix off the DOM name before comparing, and\n// return the BARE name — so a reducer branching on `changed` sees the same\n// names it declared, scoped or not.\nfunction changedComputeField(c, event, inputs, scope) {\n const target = event?.target\n if (!target?.name || typeof target.closest !== \"function\") return null\n const bare = unscopeName(target.name, scope)\n if (!inputs.includes(bare)) return null\n return c.core.bindingOwns(target) ? bare : null\n}\n\n// Strip a leading `scope[…]` wrapper off a DOM field name, returning the bare\n// inner name; a name that isn't wrapped in this scope passes through unchanged.\nfunction unscopeName(name, scope) {\n if (!scope) return name\n const prefix = `${scope}[`\n return name.startsWith(prefix) && name.endsWith(\"]\") ? name.slice(prefix.length, -1) : name\n}\n\n// Write `value` into every owned [data-reactive-text=\"<name>\"] node via\n// textContent (issue #104) — XSS-safe by construction (never innerHTML). Drives\n// both the identity mirror (an input's raw value) and a text-node output (a\n// reducer result with no matching field). Change-guarded (skip an unchanged\n// node) and NO input dispatch — a text node has no listener contract. String()\n// so a numeric result renders like the DOM would.\nfunction mirrorText(c, name, value) {\n const text = String(value)\n for (const node of ownedTextNodes(c, name)) {\n if (node.textContent === text) continue\n node.textContent = text\n }\n}\n\n// Every [data-reactive-text=\"<name>\"] mirror OWNED by this root (skips nested\n// reactive roots, issue #15). Empty when none — reactive_text is optional.\nfunction ownedTextNodes(c, name) {\n const nodes = c.root.querySelectorAll(`[data-reactive-text=\"${name}\"]`)\n return Array.from(nodes).filter((el) => c.core.owns(el))\n}\n\n// Cross-root text mirrors (issue #159): paint every DECLARED mirror name into\n// its allowlisted document-wide id targets via textContent — the opt-in escape\n// from root isolation (issue #15) for a recap OUTSIDE the computing root. The\n// value is the reducer's result when it produced one, else the owned field's\n// CURRENT value (an input identity mirror / a just-written output) — one\n// declaration covers all three shapes. A name with NO value this pass is\n// SKIPPED (a mirror never blanks a recap the reducer didn't feed). textContent\n// only (never innerHTML), change-guarded, and NO input dispatch — same\n// contract as #mirrorText. With no mirror declared this is one getAttribute\n// and out — the shipped compute path never touches the document.\nfunction applyComputeMirrors(c, result, ownedControl) {\n const mirror = parseComputeMirror(c)\n for (const [name, selectors] of Object.entries(mirror)) {\n const control = name in result ? null : ownedControl(name)\n const value = name in result ? result[name] : control.el ? computeText(control) : undefined\n if (value === undefined || value === null) continue\n const text = String(value)\n for (const sel of Array.isArray(selectors) ? selectors : [selectors]) {\n if (!guardMirrorSelector(sel)) continue\n for (const node of document.querySelectorAll(sel)) {\n if (node.textContent === text) continue\n node.textContent = text\n }\n }\n }\n}\n\n// The declared cross-root mirror map (issue #159): a JSON object of\n// { name: [id selectors] } from data-reactive-compute-mirror-param (emitted by\n// reactive_compute's `mirror:`). Absent/malformed degrades to {} — a bad\n// binding must never throw on input.\nfunction parseComputeMirror(c) {\n const raw = c.root.getAttribute(\"data-reactive-compute-mirror-param\")\n if (!raw) return {}\n try {\n const parsed = JSON.parse(raw)\n return parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? parsed : {}\n } catch {\n return {}\n }\n}\n\n// Whether this root opts into the connect-time compute seed (issue #199).\n// reactive_compute's root binding emits data-reactive-compute-seed=\"true\"; a\n// root without a compute binding (or with the seed opted out) pays one\n// attribute read and never seeds. A quick read, evaluated once per connect.\nfunction computeSeedEnabled(c) {\n return c.root.getAttribute?.(\"data-reactive-compute-seed\") === \"true\"\n}\n\n// Client-side compute (data binding). Wired by reactive_compute: an `input`\n// trigger (input->reactive#recompute) runs a REGISTERED JS reducer over the\n// named input fields and writes the named output fields WITH NO ROUND TRIP —\n// the \"instant\" half of the new/unpersisted-record UX. If the field ALSO\n// carries on(...) (a persisted record, or a synced draft), that debounced POST\n// still fires and the server reply reconciles; recompute just paints first.\n//\n// Reads inputs/outputs/reducer from the root's data-reactive-compute-* attrs\n// (set once by reactive_compute_attrs). A missing/unregistered reducer is a\n// no-op — a page must never break because a binding wasn't wired up.\n//\n// The reducer gets a second argument, meta = { changed } (issue #75): the\n// name of the declared input the triggering event edited, or null for a\n// direct call / an unowned or undeclared target. A multi-way rebalance\n// branches on it (edit c → derive a; else → derive c). Note that a #76\n// output write dispatches a real input event, so recompute RE-ENTERS with\n// changed = that output's name — the reducer must be convergent (see\n// compute.js) so the change guard settles the chain.\nfunction recompute(c, event) {\n // Issue #183 — single-pass write set: an `input` event this method dispatched\n // for its OWN output writes is self-marked. Re-running the reducer on it would\n // re-enter from a partially-written DOM (the old mid-loop-dispatch corruption\n // class). Skip the reducer for our own event — but ONLY ours: the marker lives\n // in a per-instance WeakSet, so a genuinely different root's compute event (or\n // a real user edit) is never swallowed. The event still bubbled and fired every\n // OTHER listener (dirty tracking, show bindings, sibling roots) before reaching\n // here; we simply don't recompute a second time from our own write.\n if (event && c.ours.has(event)) return\n\n // Inputs may be a JSON ARRAY of names (array form — every input coerced\n // through Number, the shipped behavior) or a JSON OBJECT of name→type (hash\n // form, issue #104 — :number coerced, :string read raw). #parseComputeInputs\n // returns [name, type] pairs either way (array form defaults type \"number\").\n const inputPairs = parseComputeInputs(c)\n const inputs = inputPairs.map(([name]) => name)\n\n // Resolve every declared input AND output through ONE per-call resolver whose\n // ownership probe is computed ONCE (issue #117), replacing the per-name\n // closest() walk #ownedField did on every read — a 30-field calculator paid\n // ~60 closest() sweeps per keystroke. #ownershipFilter returns a constant-true\n // predicate in the common no-nested-root case (skipping closest() entirely)\n // and the exact #ownsField check when a nested reactive root is present\n // (issue #15 scoping, byte-identical to before). Resolution is memoized in a\n // per-CALL Map, so a name read as an input AND written as an output\n // resolves to the SAME element and is queried once.\n //\n // Which element a name resolves to (issue #262, mirroring #showFieldValue): a\n // CHECKBOX wins over the hidden companion Rails renders before it; a radio\n // group resolves to its CHECKED radio (any radio of the group when none is);\n // anything else is first-wins. Resolving first-wins across the board handed\n // the reducer the companion's constant \"0\" and the first radio's value.\n //\n // Why per-name `[name=\"X\"]` queries and not one bare `[name]` sweep: a single\n // sweep is the natural \"one walk\", but the resolver must issue the SAME\n // per-name query shape the field walk always has (the issue-#15 unit fakes\n // answer only `[name=\"X\"]`). It is O(distinct declared names) queries, not the\n // old O(inputs + outputs) — the ownership decision is hoisted out of the loop.\n // The memo is per-CALL only: an output write dispatches `input` (issue #76),\n // re-entering recompute, which correctly rebuilds a fresh map (a morph may\n // have replaced the nodes) — it is NEVER stored on the instance.\n // Scope (issue #183, mirroring #showFieldValue): a bare compute name `cash`\n // under `data-reactive-scope=\"order\"` resolves as `[name=\"order[cash]\"]`. A\n // name already carrying a bracket (a raw wire name the author passed) is used\n // verbatim — so bracketed literals pass through unscoped.\n const scope = c.root.getAttribute?.(\"data-reactive-scope\") || null\n const scoped = (name) => (scope && !name.includes(\"[\") ? `${scope}[${name}]` : name)\n\n // Inputs AND outputs resolve through what the bindings read (issue #440):\n // a control marked data-reactive-shared-field just below is this root's\n // too. Text nodes (reactive_text) stay strictly this root's own.\n const owns = c.core.bindingOwnership()\n const byName = new Map()\n const ownedControl = (name) => {\n const known = byName.get(name)\n if (known) return known\n let radio = null\n let first = null\n let control = null\n for (const el of c.root.querySelectorAll(`[name=\"${scoped(name)}\"]`)) {\n if (!owns(el)) continue\n const kind = el.type // read ONCE per element — see computeText\n if (kind === \"checkbox\" || (kind === \"radio\" && el.checked)) {\n control = { el, kind }\n break\n }\n if (kind === \"radio\") radio ??= el\n else first ??= el\n }\n if (!control) {\n if (radio) control = { el: radio, kind: \"radio\" }\n else control = first ? { el: first, kind: \"\" } : COMPUTE_NO_CONTROL\n }\n byName.set(name, control)\n return control\n }\n\n // Identity-mirror pass (issue #104), ALWAYS run — even with NO registered\n // reducer, so reactive_text(:title) mirrors a field into its text node with\n // zero reducer wiring. Each declared input's RAW text reading (computeText —\n // a checkbox paints \"true\"/\"false\", issue #262) is written to its owned\n // [data-reactive-text=\"<name>\"] node(s). It runs BEFORE the reducer\n // early-return below so a reducer-less binding still mirrors.\n for (const name of inputs) mirrorText(c, name, computeText(ownedControl(name)))\n\n const key = c.root.getAttribute(\"data-reactive-compute-reducer-param\")\n const reduce = key ? computeReducer(key) : null\n if (!reduce) {\n // No reducer registered: the identity pass above still ran, so declared\n // cross-root mirrors of the INPUT names still paint (issue #159) — a\n // reducer-less binding mirrors, exactly like the owned-text-node case.\n applyComputeMirrors(c, {}, ownedControl)\n return\n }\n\n const outputs = parseComputeList(c, \"data-reactive-compute-outputs-param\")\n\n // Coerce each input per its declared type (computeValue): \"string\" raw,\n // \"boolean\" a real boolean, else (\"number\", the array-form default) the\n // numeric coercion. A checkbox contributes its CHECKED STATE under every\n // type (issue #262). Reads from the memoized resolver — no re-query.\n const values = {}\n for (const [name, type] of inputPairs) values[name] = computeValue(ownedControl(name), type)\n\n // meta.changed stays on #changedComputeField (its own #ownsField check over\n // the raw event target) — NOT this resolver. The issue-#15 nested-rejection\n // test depends on that path being unchanged. ONE run, from the ONE pre-write\n // snapshot above (issue #183): its result drives the whole single-pass write.\n const result = reduce(values, { changed: changedComputeField(c, event, inputs, scope) }) || {}\n\n // The reserved $ops output (issue #226) is CONSUMED here — normalized once,\n // then excluded from every write phase below (it is an op chain, never a\n // field value, text sink, or mirror), and applied as phase 4.\n const reducerOps = computeOpsList(result.$ops)\n\n // Issue #183 — SINGLE-PASS WRITE SET. Ordered phases, so declared output\n // order stops being semantics and a wrong order can no longer corrupt values:\n //\n // 1. BATCH the field writes from the ONE result. Each output name in the\n // allowlist (outputs:) whose owned field's value actually changes is\n // written now (change-guarded) and remembered — but NO `input` event is\n // dispatched yet, so nothing re-enters mid-batch. A checkbox or radio\n // output is written as its CHECKED state (computeWrite, issue #262).\n // 2. PAINT the sinks from the SETTLED values: any owned reactive_text node by\n // presence (issue #183 change #4 — a text node no longer needs its name in\n // outputs:), then the cross-root mirror: ids (issue #159).\n // 3. DISPATCH a self-marked `input` on each changed field. The marker (a\n // per-instance WeakSet) makes recompute skip re-running the reducer for our\n // own write, while the event still fires every OTHER listener (chained\n // repaint, dirty tracking, show bindings, sibling roots).\n // 4. RUN the reducer's $ops chain (issue #226) — rising-edge, event-gated —\n // so its ops (dispatch a completion event, submit the form) always see\n // the fully settled DOM and every chained listener has already run.\n const changedFields = []\n for (const name of outputs) {\n if (name === \"$ops\" || !(name in result)) continue\n const control = ownedControl(name)\n if (!control.el) continue // a non-field output paints as a text sink in phase 2\n const written = computeWrite(c.root, owns, control, scoped(name), result[name])\n if (written) changedFields.push(written) // null = change-guard, unchanged\n }\n\n // Phase 2 — text sinks declare themselves (issue #183 change #4): every result\n // key paints into any owned [data-reactive-text=\"<name>\"] node by PRESENCE,\n // regardless of outputs: membership. Runs from settled field values. A null/\n // undefined result value is SKIPPED (never stringified to \"null\"/\"undefined\") —\n // the same \"no value this pass, don't paint\" filter #applyComputeMirrors uses.\n for (const name of Object.keys(result)) {\n if (name === \"$ops\") continue\n const value = result[name]\n if (value === undefined || value === null) continue\n mirrorText(c, name, value)\n }\n\n // Cross-root text mirrors (issue #159) — AFTER the batch + text sinks, so a\n // mirror keyed on a just-written output paints the settled value.\n applyComputeMirrors(c, result, ownedControl)\n\n // Phase 3 — dispatch the deferred `input` events (issue #183). Real browsers\n // do NOT fire `input` on a programmatic .value write (issue #76), so we do it\n // ourselves, matching the server's set_value + dispatch(\"input\") contract.\n // Each event is SELF-MARKED so our own re-entry skips the reducer (guard at the\n // top of recompute) — but the event still bubbles and fires every other\n // listener. Dispatched AFTER all writes + paints, so a chained listener reads\n // SETTLED values, never a half-written DOM.\n for (const field of changedFields) {\n const inputEvent = new Event(\"input\", { bubbles: true })\n c.ours.add(inputEvent)\n field.dispatchEvent(inputEvent)\n }\n\n // Phase 4 — the reducer's $ops chain (issue #226), after everything settled.\n // Event-gated: a seed/direct recompute() pass (no event) arms the latch but\n // never fires, so a restored/re-rendered complete value can't auto-fire.\n applyComputeOps(c, reducerOps, Boolean(event))\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "B0309770BD98DEE764756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "5547A787C6231C5664756E2164756E21",
9
9
  "names": []
10
10
  }