phlex-reactive 0.11.7 → 0.12.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +74 -0
- data/README.md +90 -6
- data/app/assets/stylesheets/phlex/reactive/effects.css +106 -0
- data/app/javascript/phlex/reactive/confirm.js +8 -0
- data/app/javascript/phlex/reactive/confirm.min.js.map +2 -2
- data/app/javascript/phlex/reactive/reactive_controller.js +341 -5
- data/app/javascript/phlex/reactive/reactive_controller.min.js +2 -2
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +3 -3
- data/lib/phlex/reactive/component/dsl.rb +66 -0
- data/lib/phlex/reactive/component/helpers.rb +24 -2
- data/lib/phlex/reactive/component/registry.rb +2 -0
- data/lib/phlex/reactive/effects.rb +169 -0
- data/lib/phlex/reactive/engine.rb +5 -0
- data/lib/phlex/reactive/reply.rb +20 -15
- data/lib/phlex/reactive/response.rb +28 -19
- data/lib/phlex/reactive/streamable.rb +69 -32
- data/lib/phlex/reactive/version.rb +1 -1
- data/lib/phlex/reactive.rb +30 -2
- metadata +3 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Controller as $X}from"@hotwired/stimulus";import{confirmResolver as h}from"phlex/reactive/confirm";import{computeReducer as QX}from"phlex/reactive/compute";import{confirmPredicate as jX}from"phlex/reactive/confirm_predicate";function GX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:visit"])return;X["reactive:visit"]=function(){let Z=this.getAttribute("data-url");if(Z)window.Turbo.visit(Z,{action:"advance"})}}function zX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:token"])return;X["reactive:token"]=function(){let Z=this.getAttribute("data-reactive-token-value"),$=this.getAttribute("target");if(!Z||!$)return;let Q=document.getElementById($);if(Q)Q.setAttribute("data-reactive-token-value",Z)}}function qX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:js"])return;X["reactive:js"]=function(){let Z=XX(this.getAttribute("data-reactive-ops"));if(!Z.length)return;let $=this.getAttribute("target"),Q=$?document.getElementById($):null;if($&&!Q)return;ZX(Z,(j)=>wX(j,Q))}}var A=new Map;function u(X,Z){let $=!A.has(X);if(A.set(X,Z),$)i()}function P(X){if(A.delete(X))s()}function pX(){A.clear(),T=!1}function mX(X){return A.get(X)?.via}var T=!1;function KX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:defer"])return;if(X["reactive:defer"]=function(){let Z=this.getAttribute("target");if(!Z)return;if(this.getAttribute("data-reactive-defer-via")==="stream"){UX(Z,this);return}let $=this.getAttribute("data-reactive-defer-token");if(!$)return;N(Z,$)},!T&&typeof document<"u"&&document.addEventListener)T=!0,document.addEventListener("turbo:before-stream-render",YX)}function YX(X){let $=X.target?.getAttribute?.("target");if(!$)return;let Q=$.startsWith("reactive-defer-src-")?$.slice(19):$;if(A.get(Q)?.via==="stream")P(Q)}function N(X,Z){let $=document.getElementById(X);if(!$){console.warn(`[phlex-reactive] reactive:defer target #${X} is not on the page — skipped`);return}c(X),d($);let Q={via:"fetch",abort:new AbortController,timedOut:!1};u(X,Q),HX(X,Q,Z)}function UX(X,Z){let $=document.getElementById(X);if(!$){console.warn(`[phlex-reactive] reactive:defer target #${X} is not on the page — skipped`);return}let Q=Z.getAttribute("data-reactive-defer-src");if(!Q)return;if(!globalThis.customElements?.get?.("pgbus-stream-source")){let G=Z.getAttribute("data-reactive-defer-token");if(G){N(X,G);return}console.error("[phlex-reactive] reactive:defer via=stream but <pgbus-stream-source> is not registered "+"and no fallback token was provided — is the pgbus client loaded on this page?");return}c(X),d($);let j=document.createElement("pgbus-stream-source");j.id=g(X),j.setAttribute("src",Q),j.setAttribute("since-id",Z.getAttribute("data-reactive-defer-since-id")??"0"),j.setAttribute("hidden",""),document.body.appendChild(j),u(X,{via:"stream"})}function g(X){return`reactive-defer-src-${X}`}async function HX(X,Z,$){let Q=setTimeout(()=>{Z.timedOut=!0,Z.abort.abort()},LX()),j;try{j=await fetch(WX(),{method:"POST",headers:{Accept:"text/vnd.turbo-stream.html","Content-Type":"application/json","X-CSRF-Token":_X()},body:JSON.stringify({token:$}),credentials:"same-origin",signal:Z.abort.signal})}catch(z){if(clearTimeout(Q),A.get(X)!==Z)return;console.error("[phlex-reactive] deferred render failed",z),C(X,$);return}if(A.get(X)!==Z){clearTimeout(Q);return}if(j.status===204){clearTimeout(Q),v(X);return}if(!j.ok){clearTimeout(Q),console.error(`[phlex-reactive] deferred render failed: HTTP ${j.status}`),C(X,$,j.status);return}let G;try{G=await j.text()}catch(z){if(clearTimeout(Q),A.get(X)!==Z)return;console.error("[phlex-reactive] deferred render failed reading the body",z),C(X,$);return}if(clearTimeout(Q),A.get(X)!==Z)return;v(X),window.Turbo.renderStreamMessage(G)}function c(X){let Z=A.get(X);if(!Z)return;if(P(X),Z.via==="fetch")Z.abort.abort();else document.getElementById(g(X))?.remove?.()}function d(X){X.setAttribute("data-reactive-defer-pending","true"),X.setAttribute("aria-busy","true")}function l(X){X.removeAttribute("data-reactive-defer-pending"),X.removeAttribute("aria-busy")}function v(X){P(X);let Z=document.getElementById(X);if(!Z)return;l(Z),Z.removeAttribute("data-reactive-error")}function C(X,Z,$){P(X);let Q=document.getElementById(X);if(!Q)return;l(Q),Q.setAttribute("data-reactive-error","defer");let j=()=>{let G=document.getElementById(X);if(!G){console.warn("[phlex-reactive] defer retry() ignored — the target left the DOM");return}G.removeAttribute("data-reactive-error"),N(X,Z)};Q.dispatchEvent(new CustomEvent("reactive:error",{bubbles:!0,composed:!0,detail:{kind:"defer",target:X,status:$,retry:j}}))}function WX(){return document.querySelector('meta[name="phlex-reactive-defer-path"]')?.content||"/reactive/defer"}function _X(){return document.querySelector('meta[name="csrf-token"]')?.content??""}function LX(){let X=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Z=Number(X);return Number.isFinite(Z)&&Z>0?Z:30000}var I=!1;function JX(){if(I)return;if(typeof document>"u"||!document.addEventListener)return;I=!0,document.addEventListener("turbo:before-stream-render",MX)}function MX(X){let Z=X.detail,$=Z?.render;if(typeof $!=="function"||$.__reactiveDismissWrapped){if(typeof requestAnimationFrame==="function")requestAnimationFrame(R);else setTimeout(R,0);return}let Q=async(j)=>{await $(j),R()};Q.__reactiveDismissWrapped=!0,Z.render=Q}function R(){let X=document.querySelectorAll("[data-reactive-dismiss-after]");for(let Z of X){if(Z.hasAttribute("data-reactive-dismiss-scheduled"))continue;let $=Number(Z.getAttribute("data-reactive-dismiss-after"));if(!Number.isFinite($)||$<=0)continue;Z.setAttribute("data-reactive-dismiss-scheduled",""),setTimeout(()=>Z.remove(),$)}}function uX(){I=!1}var k=!1;function AX(){if(k)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;k=!0;let X=()=>{let Z=document.documentElement;if(typeof Z?.toggleAttribute!=="function")return;Z.toggleAttribute("data-reactive-offline",globalThis.navigator?.onLine===!1)};X(),window.addEventListener("online",X),window.addEventListener("offline",X)}function gX(){k=!1}var b="phlex-reactive:latency",x=!1;function BX(X){if(typeof sessionStorage>"u")return;sessionStorage.setItem(b,String(X))}function VX(){if(typeof sessionStorage>"u")return;sessionStorage.removeItem(b),x=!1}function OX(){if(typeof window>"u"||typeof document>"u")return;if(document.querySelector?.('meta[name="phlex-reactive-env"]')?.content!=="development")return;window.PhlexReactive={enableLatencySim:BX,disableLatencySim:VX}}function cX(){x=!1}var o="data-reactive-active",B=0;function i(){if(B++,B===1)n("reactive:busy")}function s(){if(B===0)return;if(B--,B===0)n("reactive:idle")}function dX(){return B}function lX(){B=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(o)}function n(X){if(typeof document>"u")return;let Z=document.documentElement;if(typeof Z?.toggleAttribute==="function")Z.toggleAttribute(o,B>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(X,{detail:{count:B}}))}function y(){GX(),zX(),qX(),KX(),JX(),AX(),OX()}function xX(X){return X.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}if(typeof window<"u")if(window.Turbo)y();else document.addEventListener("turbo:load",y,{once:!0});var E=!1;function PX(){if(E)return;if(typeof document>"u")return;let X=document.querySelectorAll('[data-controller~="reactive"]');if(!X||X.length===0)return;console.warn("[phlex-reactive] found "+X.length+' element(s) with data-controller="reactive" '+"but the reactive controller never connected. It is loaded but not registered — "+'add `application.register("reactive", ReactiveController)` (importmap) or import it into app/javascript/controllers/ for lazyLoadControllersFrom apps. See the README.')}function oX(){E=!1}function iX(){E=!0}if(typeof window<"u"&&typeof document<"u"){let X=()=>setTimeout(PX,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",X,{once:!0});else X()}var NX=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function EX(X){let Z=String(X).toLowerCase();return Z.startsWith("on")||NX.has(Z)}function CX(X,Z,$){let[Q,j,G]=Z;X.classList.add(Q,j),$(),requestAnimationFrame(()=>{X.classList.remove(j),X.classList.add(G)});let z=!1,q=()=>{if(z)return;z=!0,X.classList.remove(Q,G)};X.addEventListener("animationend",q,{once:!0}),setTimeout(q,350)}var f=Object.freeze({show:(X,Z)=>F(X,!1,Z),hide:(X,Z)=>F(X,!0,Z),toggle:(X,Z)=>F(X,!X.hidden,Z),add_class:(X,Z)=>X.classList.add(...Z.classes??[]),remove_class:(X,Z)=>X.classList.remove(...Z.classes??[]),toggle_class:(X,Z)=>(Z.classes??[]).forEach(($)=>X.classList.toggle($)),set_attr:(X,Z)=>{if(D(Z.name))X.setAttribute(Z.name,Z.value??"")},remove_attr:(X,Z)=>{if(D(Z.name))X.removeAttribute(Z.name)},toggle_attr:(X,Z)=>{if(!D(Z.name))return;if(X.hasAttribute(Z.name))X.removeAttribute(Z.name);else X.setAttribute(Z.name,"")},focus:(X)=>X.focus?.(),focus_first:(X)=>bX(X)?.focus?.(),text:(X,Z)=>{let $=String(Z.value??"");if(X.textContent!==$)X.textContent=$},dispatch:(X,Z)=>{X.dispatchEvent(new CustomEvent(Z.name,{bubbles:!0,composed:!0,detail:Z.detail??{}}))}});function F(X,Z,$){if($?.transition)CX(X,$.transition,()=>X.hidden=Z);else X.hidden=Z}function D(X){if(!EX(X))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(X)} — skipped`),!1}var a=/^#[A-Za-z_][\w-]*$/;function RX(X){if(typeof X==="string"&&a.test(X))return!0;return console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(X)} — skipped`),!1}function FX(X,Z){let $=X.getAttribute("data-reactive-show-equals");if($!==null)return Z===$;let Q=X.getAttribute("data-reactive-show-not");if(Q!==null)return Z!==Q;let j=X.getAttribute("data-reactive-show-in");if(j!==null){try{let G=JSON.parse(j);if(Array.isArray(G))return G.includes(Z)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(j)} — skipped`),null}for(let G of r){let z=X.getAttribute(`data-reactive-show-${G}`);if(z!==null)return t(G,z,Z)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}var r=["gte","gt","lte","lt"];function t(X,Z,$){let Q=Number(Z);if(Number.isNaN(Q))return console.warn(`[phlex-reactive] reactive_show ${X}: needs a numeric literal, got ${JSON.stringify(Z)} — skipped`),null;let j=$==null?"":String($).trim(),G=j===""?NaN:Number(j);if(Number.isNaN(G))return!1;switch(X){case"gte":return G>=Q;case"gt":return G>Q;case"lte":return G<=Q;case"lt":return G<Q;default:return null}}function e(X,Z){if(!X||typeof X!=="object")return null;if(typeof X.equals==="string")return Z===X.equals;if(typeof X.not==="string")return Z!==X.not;if(Array.isArray(X.in))return X.in.includes(Z);for(let $ of r)if($ in X)return t($,X[$],Z);return null}var p="[data-reactive-show-field], [data-reactive-show]";function DX(X){try{let Z=JSON.parse(X);if(Z&&typeof Z==="object"&&!Array.isArray(Z))return Z}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(X)} — skipped`),null}function w(X,Z){if(!X||typeof X!=="object"||typeof X.field!=="string")return!1;let $=Z(X.field)??"";return e(X,$)===!0}function S(X,Z){if(!Array.isArray(X)||X.length===0)return null;return X.some(($)=>Array.isArray($)&&$.length>0&&$.every((Q)=>w(Q,Z)))}function TX(X){if(!Array.isArray(X)||X.length===0)return null;let Z=new Set;for(let $ of X){if(!Array.isArray($))continue;for(let Q of $)if(Q&&typeof Q==="object"&&typeof Q.field==="string")Z.add(Q.field)}return Z.size>0?[...Z]:null}function IX(X,Z){if(!X||typeof X!=="object")return null;let $=X.any;if(Array.isArray($)&&($.length===0||Array.isArray($[0])))return S($,Z);return kX(X,Z)}function kX(X,Z){let $=Array.isArray(X.all)?"all":Array.isArray(X.any)?"any":null;if(!$)return null;let Q=X[$];if(Q.length===0)return null;let j=Q.map((G)=>w(G,Z));return $==="all"?j.every(Boolean):j.some(Boolean)}function m(X){if(typeof X==="string"&&a.test(X))return!0;return console.warn(`[phlex-reactive] refused cross-root show target ${JSON.stringify(X)} — skipped`),!1}var SX='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function bX(X){return X.querySelectorAll?.(SX)?.[0]??null}function XX(X){if(Array.isArray(X))return X;if(typeof X!=="string")return[];try{let Z=JSON.parse(X);return Array.isArray(Z)?Z:[]}catch{return[]}}function ZX(X,Z){for(let $ of X){if(!Array.isArray($))continue;let[Q,j={}]=$;if(!Object.hasOwn(f,Q)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(Q)} — skipped`);continue}for(let G of Z(j))f[Q](G,j)}}function wX(X,Z){let $=X.to;if(Z){if($==="@root")return[Z];if(typeof $!=="string"||$==="")return[];if(X.global)return[...document.querySelectorAll($)];return[...Z.querySelectorAll($)]}if(typeof $!=="string"||$===""||$==="@root")return[];return[...document.querySelectorAll($)]}class sX extends $X{static values={token:String};#p;#V=new Map;#U=new Map;#JX;#D;#m;#T=0;#H=new Map;#I=new WeakMap;#O=new Map;#u=new WeakSet;#W;#_;#L;#Z;#Q;#J;#g=!1;#k=0;#c=!1;#j;#M;#A;#x;connect(){if(E=!0,this.element.id==="")console.warn("[phlex-reactive] a reactive root has no id; its next-action token can't self-match "+"and may fall back to the first token in the response → a silent HTTP 403 on the NEXT action. "+"Put id: on the SAME element as reactive_attrs — use div(**reactive_root) (emits id + token together), "+"or div(id:, **reactive_attrs). The id: must NOT be on a child. See the README.");if(this.element.getAttribute?.("data-reactive-defer-token"))this.#d(),this.#x=()=>this.#d(),this.element.addEventListener?.("turbo:morph-element",this.#x);if(this.#MX()){if(this.#W=()=>this.#w(),this.element.addEventListener?.("turbo:morph-element",this.#W),this.#w(),this.element.getAttribute?.("data-reactive-warn-unsaved")==="true")this.#uX()}if(this.#cX())this.#Z=()=>this.#jX(),this.element.addEventListener?.("input",this.#Z),this.element.addEventListener?.("change",this.#Z),this.element.addEventListener?.("turbo:morph-element",this.#Z),this.#jX();if(this.#R())this.#Q=(X)=>{if(X?.type==="input"&&!this.#aX(X))return;this.#B()},this.element.addEventListener?.("input",this.#Q),this.element.addEventListener?.("turbo:morph-element",this.#Q),this.#B();if(this.#F())this.#J=()=>this.#y(),this.element.addEventListener?.("turbo:morph-element",this.#J),this.#y();if(this.#tX())this.#j=(X)=>this.syncNestedJson(X),this.#M=()=>this.#N(),this.element.addEventListener?.("input",this.#j),this.element.addEventListener?.("change",this.#j),this.element.addEventListener?.("turbo:morph-element",this.#M),this.#N();if(this.#nX())this.#A=()=>this.recompute(),this.element.addEventListener?.("turbo:morph-element",this.#A),this.recompute()}#MX(){if((this.element.getAttribute?.("data-action")??"").includes("reactive#trackDirty"))return!0;let X=this.element.querySelectorAll?.('[data-action*="reactive#trackDirty"]')??[];for(let Z of X)if(this.#$(Z))return!0;return!1}disconnect(){if(this.#IX(),this.#SX(),this.#gX(),this.#sX(),this.#rX(),this.#GZ(),this.#zZ(),this.#qZ(),this.#x)this.element.removeEventListener?.("turbo:morph-element",this.#x)}#d(){let X=this.element;if(!X?.id)return;let Z=X.getAttribute?.("data-reactive-defer-token");if(!Z)return;if(X.getAttribute?.("data-reactive-defer-pending")!=="true")return;N(X.id,Z)}dispatch(X){let{action:Z,params:$,debounce:Q,throttle:j,confirm:G,confirmWhen:z,outside:q,window:K,optimistic:Y}=X.params;if(!Z)return;let W=X.params.busy??this.#AZ(X.params.loading);if(q&&this.element.contains(X.target))return;let M=X.currentTarget??X.target;if(!K&&!this.#UZ(Y,M))X.preventDefault();let _=this.#ZX(G,z);if(!_)return this.#a(M,Z,$,Q,j,Y,W);Promise.resolve().then(()=>h(_)).catch(()=>!1).then((L)=>{if(L)this.#a(M,Z,$,Q,j,Y,W)})}runOps(X){let{ops:Z,confirm:$,confirmWhen:Q,outside:j,window:G}=X.params;if(j&&this.element.contains(X.target))return;if(!G)X.preventDefault();let z=this.#ZX($,Q);if(!z)return this.#UX(this.#YX(Z));Promise.resolve().then(()=>h(z)).catch(()=>!1).then((q)=>{if(q)this.#UX(this.#YX(Z))})}trackDirty(){this.#w()}recompute(X){if(X&&this.#u.has(X))return;let Z=this.#NX(),$=Z.map(([U])=>U),Q=this.element.getAttribute?.("data-reactive-scope")||null,j=(U)=>Q&&!U.includes("[")?`${Q}[${U}]`:U,G=this.#X(),z=new Map,q=(U)=>{if(z.has(U))return z.get(U);let H=null;for(let V of this.element.querySelectorAll(`[name="${j(U)}"]`))if(G(V)){H=V;break}return z.set(U,H),H};for(let U of $)this.#s(U,q(U)?.value??"");let K=this.element.getAttribute("data-reactive-compute-reducer-param"),Y=K?QX(K):null;if(!Y){this.#n({},q);return}let W=this.#PX("data-reactive-compute-outputs-param"),M={};for(let[U,H]of Z){let V=q(U);if(H==="string")M[U]=V?.value??"";else{let J=Number(V?.value);M[U]=Number.isFinite(J)?J:0}}let _=Y(M,{changed:this.#EX(X,$,Q)})||{},L=[];for(let U of W){if(!(U in _))continue;let H=q(U);if(!H)continue;if(String(_[U])===H.value)continue;H.value=_[U],L.push(H)}for(let U of Object.keys(_)){let H=_[U];if(H===void 0||H===null)continue;this.#s(U,H)}this.#n(_,q);for(let U of L){let H=new Event("input",{bubbles:!0});this.#u.add(H),U.dispatchEvent(H)}}listnavNext(X){this.#l(X,1)}listnavPrev(X){this.#l(X,-1)}listnavPick(X){let Z=this.#P(X),$=Z.findIndex((Q)=>Q.hasAttribute("data-reactive-highlighted"));if($<0)return;X.preventDefault(),Z[$].click()}listnavClose(X){for(let Z of this.#P(X))Z.removeAttribute("data-reactive-highlighted")}#l(X,Z){let $=this.#P(X);if(!$.length)return;X.preventDefault();let Q=$.findIndex((z)=>z.hasAttribute("data-reactive-highlighted")),j=Q<0?Z>0?0:$.length-1:(Q+Z+$.length)%$.length;for(let z of $)z.removeAttribute("data-reactive-highlighted");let G=$[j];G.setAttribute("data-reactive-highlighted","true"),G.scrollIntoView?.({block:"nearest"})}#P(X){let $=(X?.currentTarget??X?.target??this.element).getAttribute?.("data-reactive-listnav-option-param")??this.element.getAttribute("data-reactive-listnav-option-param");if(!$)return[];let Q=this.#X();return Array.from(this.element.querySelectorAll($)).filter((j)=>!j.hidden&&Q(j))}tagsAdd(X){if(!this.#F())return;if(X?.defaultPrevented)return;if(this.#P(X).some((Q)=>Q.hasAttribute?.("data-reactive-highlighted")))return;X?.preventDefault?.();let Z=X?.currentTarget??X?.target;if(!Z)return;if(!this.#zX(String(Z.value??"").split(",")))return;if(Z.value="",this.#R())this.#B()}tagsPick(X){if(!this.#F())return;X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.getAttribute?.("data-reactive-tag-param");if(!$)return;if(!this.#zX([$]))return;let Q=this.#eX();if(!Q)return;Q.value="",this.#B(),Q.focus?.()}tagsRemove(X){if(!this.#F())return;X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.getAttribute?.("data-reactive-tag-param");if(!$)return;let Q=this.#h();if(!Q)return;let j=this.#v(Q),G=j.filter((z)=>z.toLowerCase()!==$.toLowerCase());if(G.length===j.length)return;this.#qX(Q,G)}nestedAdd(X){X?.preventDefault?.();let Z=X?.currentTarget??X?.target,$=Z?.getAttribute?.("data-reactive-association-param");if(!$)return;if(typeof this.element?.querySelectorAll!=="function")return;let Q=this.#X(),j=[...this.element.querySelectorAll(`[data-reactive-nested-list="${$}"]`)].find(Q),z=[...this.element.querySelectorAll(`[data-reactive-nested-template="${$}"]`)].find(Q)?.content?.firstElementChild;if(!j||!z){this.#jZ($);return}let q=z.cloneNode(!0);this.#QZ(q,this.#$Z()),j.appendChild(q);let K=Z?.getAttribute?.("data-reactive-nested-from-param"),Y=Z?.getAttribute?.("data-reactive-nested-clear-param")==="true",W=this.#AX(q,K,Y);if(K)W?.focus?.();else[...q.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(j.getAttribute?.("data-reactive-nested-json")===$)this.#o($)}#AX(X,Z,$){if(!Z)return null;let Q;try{Q=JSON.parse(Z)}catch{return null}if(!Q||typeof Q!=="object")return null;let j=this.#X(),G=[...X.querySelectorAll?.("input, select, textarea")??[]],z=[];for(let[q,K]of Object.entries(Q)){let Y=[...this.element.querySelectorAll?.(K)??[]].find(j);if(!Y)continue;let W=G.find((M)=>this.#i(M.getAttribute?.("name"))===q);if(!W)continue;this.#BX(W,Y),z.push(Y)}if($)for(let q of z)this.#VX(q);return z[0]??null}#BX(X,Z){if(X.type==="checkbox")X.checked=Z.type==="checkbox"?!!Z.checked:this.#S(Z)!=="";else X.value=this.#S(Z);if(typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}))}#VX(X){if(X.type==="checkbox")X.checked=!1;else X.value="";if(typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}))}nestedRemove(X){X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.closest?.("[data-reactive-nested-row]");if(!$)return;if($.closest?.('[data-controller~="reactive"]')!==this.element)return;let Q=[...$.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(Q){if(Q.value="1",typeof Q.dispatchEvent==="function")Q.dispatchEvent(new Event("input",{bubbles:!0}));$.hidden=!0}else $.parentNode?.removeChild?.($);this.#N()}syncNestedJson(X){let Z=X?.target;if(!Z||!this.#$(Z))return;this.#N()}#N(){if(typeof this.element?.querySelectorAll!=="function")return;let X=this.#X();for(let Z of[...this.element.querySelectorAll("[data-reactive-nested-json]")].filter(X))this.#o(Z.getAttribute("data-reactive-nested-json"))}#o(X){let Z=this.#X(),$=[...this.element.querySelectorAll(`[data-reactive-nested-list="${X}"]`)].find(Z);if(!$)return;let Q=this.#OX($);if(!Q)return;let j=[];for(let z of[...$.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!Z(z)||z.hidden)continue;j.push(this.#xX(z))}let G=JSON.stringify(j);if(Q.value===G)return;if(Q.value=G,typeof Q.dispatchEvent==="function")Q.dispatchEvent(new Event("input",{bubbles:!0}))}#OX(X){let Z=X.getAttribute?.("data-reactive-nested-json-field");if(!Z)return null;let $=this.#X();return[...this.element.querySelectorAll(Z)].find($)??null}#xX(X){let Z={};for(let $ of[...X.querySelectorAll?.("input, select, textarea")??[]]){let Q=this.#i($.getAttribute?.("name"));if(Q===null||Q==="_destroy")continue;Z[Q]=this.#S($)}return Z}#i(X){if(!X)return null;let Z=X.match(/\[([^\][]+)\]$/);return Z?Z[1]:X}#S(X){if(X.type==="checkbox")return X.checked?X.value||"on":"";return X.value??""}#PX(X){let Z=this.element.getAttribute(X);if(!Z)return[];try{let $=JSON.parse(Z);return Array.isArray($)?$:[]}catch{return[]}}#NX(){let X=this.element.getAttribute("data-reactive-compute-inputs-param");if(!X)return[];try{let Z=JSON.parse(X);if(Array.isArray(Z))return Z.map(($)=>[$,"number"]);if(Z&&typeof Z==="object")return Object.entries(Z);return[]}catch{return[]}}#EX(X,Z,$){let Q=X?.target;if(!Q?.name||typeof Q.closest!=="function")return null;let j=this.#CX(Q.name,$);if(!Z.includes(j))return null;return this.#$(Q)?j:null}#CX(X,Z){if(!Z)return X;let $=`${Z}[`;return X.startsWith($)&&X.endsWith("]")?X.slice($.length,-1):X}#s(X,Z){let $=String(Z);for(let Q of this.#RX(X)){if(Q.textContent===$)continue;Q.textContent=$}}#RX(X){let Z=this.element.querySelectorAll(`[data-reactive-text="${X}"]`);return Array.from(Z).filter(($)=>this.#$($))}#n(X,Z){let $=this.#FX();for(let[Q,j]of Object.entries($)){let G=Q in X?X[Q]:Z(Q)?.value;if(G===void 0||G===null)continue;let z=String(G);for(let q of Array.isArray(j)?j:[j]){if(!RX(q))continue;for(let K of document.querySelectorAll(q)){if(K.textContent===z)continue;K.textContent=z}}}}#FX(){let X=this.element.getAttribute("data-reactive-compute-mirror-param");if(!X)return{};try{let Z=JSON.parse(X);return Z&&typeof Z==="object"&&!Array.isArray(Z)?Z:{}}catch{return{}}}#a(X,Z,$,Q,j,G,z){if(this.#C("reactive:before-dispatch",{action:Z,params:this.#KX($),element:this.element},{cancelable:!0}).defaultPrevented)return;let K=Number(Q)||0;if(K>0)return this.#TX(X,K,Z,$,G,z);let Y=Number(j)||0;if(Y>0)return this.#kX(X,Y,Z,$,G,z);return this.#E(Z,$,G,X,z)}#E(X,Z,$,Q,j){let G=this.#HZ($,Q),z=this.#WZ(X,Q,j),q=this.#r()?this.#DX($,Q):null;return this.queue=(this.queue??Promise.resolve()).then(()=>this.#fX(X,Z,G,z,q)),this.queue}#DX(X,Z){if(!X?.hide)return null;let $=this.#_X(X,Z);if(!$.length)return null;return()=>{let Q=$.filter((j)=>j.isConnected&&!j.hidden);if(!Q.length)return;console.warn("[phlex-reactive] optimistic: { hide: true } was undone by the reply's re-render — "+"the element is visible again. For an instant delete, return reply.remove so the server removes it; otherwise the hide only flashes.",Q)}}#TX(X,Z,$,Q,j,G){this.#b(X);let z=()=>{this.#b(X),this.#E($,Q,j,X,G)},q=setTimeout(z,Z);X?.addEventListener?.("blur",z,{once:!0}),this.#V.set(X,{timer:q,flush:z})}#b(X){let Z=this.#V.get(X);if(!Z)return;clearTimeout(Z.timer),X?.removeEventListener?.("blur",Z.flush),this.#V.delete(X)}#IX(){for(let X of[...this.#V.keys()])this.#b(X)}#kX(X,Z,$,Q,j,G){let z=this.#U.get(X)??new Map;if(z.has($))return;let q=setTimeout(()=>{if(z.delete($),z.size===0)this.#U.delete(X)},Z);return z.set($,q),this.#U.set(X,z),this.#E($,Q,j,X,G)}#SX(){for(let X of this.#U.values())for(let Z of X.values())clearTimeout(Z);this.#U.clear()}#C(X,Z,{cancelable:$=!1}={}){let Q=new CustomEvent(X,{bubbles:!0,composed:!0,cancelable:$,detail:Z});return(this.element.isConnected?this.element:document).dispatchEvent(Q),Q}#G(X,Z,$,Q){let j=()=>{if(!this.element.isConnected){console.warn("[phlex-reactive] retry() ignored — the reactive root left the DOM");return}return this.#E(X,Z)};this.#C("reactive:error",{action:X,params:$,...Q,retry:j})}#z(X){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",X)}#bX(){this.element?.removeAttribute?.("data-reactive-error")}#wX(){let X=document.querySelector("[data-reactive-error-flash]");if(!X?.content)return;let Z=X.getAttribute("data-reactive-error-flash")||"flash",$=document.getElementById(Z);if(!$)return;$.appendChild(X.content.cloneNode(!0))}#hX(){if(typeof sessionStorage>"u")return Promise.resolve();let X=Number(sessionStorage.getItem(b));if(!Number.isFinite(X)||X<=0)return Promise.resolve();if(!x)x=!0,console.warn(`[phlex-reactive] latency simulator ACTIVE — every action is delayed by ${X}ms. Call PhlexReactive.disableLatencySim() (or clear sessionStorage) to turn it off.`);return new Promise((Z)=>setTimeout(Z,X))}#r(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#t(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}#vX(X){if(!X)return[];let Z=[],$=/<turbo-stream\b([^>]*)>/g,Q;while((Q=$.exec(X))!==null){let j=Q[1],G=j.match(/\baction="([^"]*)"/)?.[1]??"?",z=j.match(/\btarget="([^"]*)"/)?.[1];Z.push(z?`${G} → #${z}`:G)}return Z}#yX(X){let{action:Z,status:$,ms:Q}=X,G=`reactive ${this.element?.id?`#${this.element.id} `:""}${Z} → ${$??"—"} (${Math.round(Q)}ms)`;if(console.groupCollapsed(G),console.log(`params: [${X.paramNames.join(", ")}] + collected: [${X.fieldNames.join(", ")}]`),console.log(`encoding: ${X.encoding}`),X.streams.length)console.log(`streams: ${X.streams.join(" ")}`);console.log(`token: ${X.tokenRefreshed?"refreshed ✓":"unchanged"}`),console.groupEnd()}async#fX(X,Z,$,Q,j){let{fields:G,files:z}=this.#$X(),q=this.#KX(Z),K={...G,...q},Y=this.#q,W=z.length>0,M=W?this.#KZ(Y,X,K,z):JSON.stringify({token:Y,act:X,params:K}),_=this.#r()?{action:X,paramNames:Object.keys(q),fieldNames:Object.keys(G),encoding:W?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#t()}:null;await this.#hX();try{if(navigator.onLine===!1){this.#K($),this.#z("offline"),this.#G(X,Z,K,{kind:"offline"});return}let L;try{let J={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#OZ()};if(!W)J["Content-Type"]="application/json";let O=this.#xZ();if(O)J["X-Pgbus-Connection"]=O;L=await fetch(this.#BZ(),{method:"POST",headers:J,body:M,credentials:"same-origin",signal:AbortSignal.timeout(this.#VZ())})}catch(J){if(console.error("[phlex-reactive] action error",J),this.#K($),J?.name==="TimeoutError"||J?.name==="AbortError"){this.#z("timeout"),this.#G(X,Z,K,{kind:"timeout"});return}this.#wX(),this.#z("network"),this.#G(X,Z,K,{kind:"network"});return}if(_)_.status=L.status;if(L.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#K($),this.#z("redirected"),this.#G(X,Z,K,{kind:"redirected",status:L.status});return}if(!L.ok){let J=await L.text();if(console.error(`[phlex-reactive] action failed: HTTP ${L.status}`,J),this.#K($),(L.headers.get("Content-Type")||"").includes("turbo-stream")){let O=this.#XX(J);if(this.#q=O??this.#q,_)this.#e(_,J,O);window.Turbo.renderStreamMessage(J)}this.#z("http"),this.#G(X,Z,K,{kind:"http",status:L.status,body:J});return}let U=L.headers.get("Content-Type")||"";if(!U.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${U}" — no update applied`),this.#K($),this.#z("content-type"),this.#G(X,Z,K,{kind:"content-type",status:L.status});return}let H=await L.text(),V=this.#XX(H);if(this.#q=V??this.#q,_)this.#e(_,H,V);if(window.Turbo.renderStreamMessage(H),j)queueMicrotask(j);this.#bX(),this.#C("reactive:applied",{action:X,params:K,html:H})}catch(L){console.error("[phlex-reactive] action error",L),this.#K($),this.#C("reactive:error",{action:X,params:K,kind:"apply"})}finally{if(Q?.(),_)this.#yX({..._,ms:this.#t()-_.started})}}#e(X,Z,$){X.streams=this.#vX(Z),X.tokenRefreshed=$!=null}get#q(){return this.#p??this.tokenValue}set#q(X){this.#p=X}#XX(X){let Z=this.element.id;if(!Z)return X.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:$,self:Q}=this.#pX(Z),j=X.match($);if(j)return j[1];let G=X.match(Q);if(G)return G[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#pX(X){let Z=this.#m;if(Z&&Z.id===X)return Z;let $=xX(X);return this.#m={id:X,token:new RegExp(`<turbo-stream\\b[^>]*\\baction="reactive:token"[^>]*\\btarget="${$}"[^>]*\\bdata-reactive-token-value="([^"]+)"`),self:new RegExp(`<turbo-stream\\b[^>]*\\baction="(?:replace|update)"[^>]*\\btarget="${$}"[^>]*>([\\s\\S]*?)</turbo-stream>`)}}#$(X){return X.closest('[data-controller~="reactive"]')===this.element}#X(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(Z)=>this.#$(Z)}#ZX(X,Z){if(X)return X;if(!Z)return null;let $=Z;if(typeof Z==="string")try{$=JSON.parse(Z)}catch{return console.warn(`[phlex-reactive] malformed conditional confirm payload ${JSON.stringify(Z)} — skipped`),null}if(!$||typeof $!=="object")return null;let{fields:Q}=this.#$X(),j=(z)=>Q[z],G;if(typeof $.predicate==="string"){let z=jX($.predicate);if(!z)return console.warn(`[phlex-reactive] confirm predicate "${$.predicate}" is not registered — proceeding without a dialog (register it with setConfirmPredicate)`),null;G=!!z(Q)}else G=S($.groups?.any,j)===!0;return G?$.message:null}#$X(){let X={},Z=[],$=this.#X();return this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Q)=>{if(!$(Q))return;if(Q.type==="file")for(let j of Q.files??[])Z.push({name:Q.name,file:j,multiple:Q.multiple});else if(Q.type==="checkbox")X[Q.name]=Q.checked;else if(Q.type==="radio"){if(Q.checked)X[Q.name]=Q.value}else X[Q.name]=Q.value}),this.element.querySelectorAll("[name]:is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])").forEach((Q)=>{if(!$(Q))return;let j=Q.getAttribute("name");if(!j)return;let G=X[j];if(G==null||G==="")X[j]=Q.value??Q.textContent??Q.innerHTML??""}),{fields:X,files:Z}}#w(){if(typeof this.element?.querySelectorAll!=="function")return;let X=0;if(this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Z)=>{if(!this.#$(Z))return;if(Z.type==="file")return;if(this.#mX(Z))Z.setAttribute("data-reactive-dirty","true"),X++;else Z.removeAttribute("data-reactive-dirty")}),X>0)this.element.setAttribute("data-reactive-dirty",String(X));else this.element.removeAttribute("data-reactive-dirty")}#mX(X){if(X.type==="checkbox"||X.type==="radio")return X.checked!==X.defaultChecked;if(X.tag==="select"||X.options)return Array.from(X.options??[]).some((Z)=>Z.selected!==Z.defaultSelected);return X.value!==X.defaultValue}#QX(){let X=this.element.getAttribute?.("data-reactive-dirty"),Z=Number(X);return Number.isFinite(Z)&&Z>0?Z:0}#uX(){if(typeof window>"u"||typeof window.addEventListener!=="function")return;this.#_=(X)=>{if(this.#QX()===0)return;return X.preventDefault(),X.returnValue="You have unsaved changes.",X.returnValue},this.#L=(X)=>{if(this.#QX()===0)return;if(!(typeof window.confirm==="function"?window.confirm("You have unsaved changes. Leave anyway?"):!0))X.preventDefault?.()},window.addEventListener("beforeunload",this.#_),window.addEventListener("turbo:before-visit",this.#L)}#gX(){if(this.#W)this.element.removeEventListener?.("turbo:morph-element",this.#W),this.#W=void 0;if(typeof window<"u"&&typeof window.removeEventListener==="function"){if(this.#_)window.removeEventListener("beforeunload",this.#_);if(this.#L)window.removeEventListener("turbo:before-visit",this.#L)}this.#_=void 0,this.#L=void 0}#cX(){if(this.element.getAttribute?.("data-reactive-show-targets"))return!0;let X=this.element.querySelectorAll?.(p)??[];for(let Z of X)if(this.#$(Z))return!0;return!1}#jX(){if(typeof this.element?.querySelectorAll!=="function")return;let X=this.#X(),Z=this.element.getAttribute?.("data-reactive-scope")||null,$=new Map,Q=(j)=>{if(!$.has(j))$.set(j,this.#iX(j,X,Z));return $.get(j)};for(let j of this.element.querySelectorAll(p)){if(!X(j))continue;let G=j.getAttribute("data-reactive-show");if(G!==null){let Y=IX(DX(G),Q);if(Y!==null)this.#GX(j,Y,X,Z);continue}let z=j.getAttribute("data-reactive-show-field");if(!z)continue;let q=Q(z);if(q===null)continue;let K=FX(j,q);if(K===null)continue;this.#GX(j,K,X,Z)}this.#dX(Q)}#GX(X,Z,$,Q){if(X.hidden=!Z,X.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof X.querySelectorAll!=="function")return;for(let j of X.querySelectorAll("input[name], select[name], textarea[name]"))if($(j))j.disabled=!Z;if(X.name&&$(X))X.disabled=!Z}#dX(X){let Z=this.#oX();for(let[$,Q]of Object.entries(Z)){if($.startsWith("#")){this.#lX($,Q,X);continue}if(!Q||typeof Q!=="object"||Array.isArray(Q))continue;let j=X($);if(j===null)continue;let G=()=>j;for(let[z,q]of Object.entries(Q)){if(!m(z))continue;let K;if(Array.isArray(q)){if(q.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${z} — skipped`);continue}K=q.every((Y)=>w(Y,G))}else{let Y=e(q,j);if(Y===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${z} — skipped`);continue}K=Y}for(let Y of document.querySelectorAll(z))Y.hidden=!K}}}#lX(X,Z,$){if(!m(X))return;let Q=Z&&typeof Z==="object"&&!Array.isArray(Z)?Z.any:null,j=TX(Q);if(j===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${X} — skipped`);return}if(j.every((z)=>$(z)===null))return;let G=S(Q,$);if(G===null)return;for(let z of document.querySelectorAll(X))z.hidden=!G}#oX(){let X=this.element.getAttribute?.("data-reactive-show-targets");if(!X)return{};try{let Z=JSON.parse(X);if(Z&&typeof Z==="object"&&!Array.isArray(Z))return Z}catch{}return console.warn("[phlex-reactive] malformed data-reactive-show-targets — ignored. "+"Did two reactive_show_targets calls collide on one root? Declare every field in ONE call: reactive_show_targets(mode: { ... }, kind: { ... })"),{}}#iX(X,Z,$){let Q=$&&!X.includes("[")?`${$}[${X}]`:X,j=!1,G=null;for(let z of this.element.querySelectorAll(`[name="${Q}"]`)){if(!Z(z))continue;if(z.type==="checkbox")return z.checked?"true":"false";if(z.type==="radio"){if(z.checked)return z.value??"";j=!0;continue}G??=z}if(G)return G.value??"";return j?"":null}#sX(){if(!this.#Z)return;this.element.removeEventListener?.("input",this.#Z),this.element.removeEventListener?.("change",this.#Z),this.element.removeEventListener?.("turbo:morph-element",this.#Z),this.#Z=void 0}#R(){return!!(this.element.getAttribute?.("data-reactive-filter-input")&&this.element.getAttribute?.("data-reactive-filter-option"))}#nX(){return this.element.getAttribute?.("data-reactive-compute-seed")==="true"}#aX(X){let Z=this.element.getAttribute("data-reactive-filter-input");return!!Z&&typeof X.target?.matches==="function"&&X.target.matches(Z)}#B(){if(typeof this.element?.querySelectorAll!=="function")return;let X=this.element.getAttribute("data-reactive-filter-input"),Z=this.element.getAttribute("data-reactive-filter-option");if(!X||!Z)return;let $=this.#X(),Q=[...this.element.querySelectorAll(X)].find($);if(!Q)return;let j=(Q.value??"").trim().toLowerCase(),G=0;for(let K of this.element.querySelectorAll(Z)){if(!$(K))continue;let Y=(K.getAttribute("data-reactive-filter-text")??K.textContent??"").toLowerCase(),W=K.hasAttribute?.("data-reactive-tags-selected")||j!==""&&!Y.includes(j);if(K.hidden=W,W)K.removeAttribute("data-reactive-highlighted");else G++}let z=this.element.getAttribute("data-reactive-filter-group");if(z)for(let K of this.element.querySelectorAll(z)){if(!$(K))continue;let Y=[...K.querySelectorAll(Z)].filter($);if(Y.length===0)continue;K.hidden=Y.every((W)=>W.hidden)}let q=this.element.getAttribute("data-reactive-filter-empty");if(q){for(let K of this.element.querySelectorAll(q))if($(K))K.hidden=G>0}}#rX(){if(!this.#Q)return;this.element.removeEventListener?.("input",this.#Q),this.element.removeEventListener?.("turbo:morph-element",this.#Q),this.#Q=void 0}#F(){return!!this.element.getAttribute?.("data-reactive-tags-field")}#tX(){if(typeof this.element?.querySelector!=="function")return!1;return!!this.element.querySelector("[data-reactive-nested-json]")}#h(){if(typeof this.element?.querySelectorAll!=="function")return null;let X=this.element.getAttribute("data-reactive-tags-field");if(!X)return null;let Z=this.#X();return[...this.element.querySelectorAll(X)].find(Z)??null}#v(X){let Z=new Set,$=[];for(let Q of String(X.value??"").split(",")){let j=Q.trim();if(j===""||Z.has(j.toLowerCase()))continue;Z.add(j.toLowerCase()),$.push(j)}return $}#zX(X){let Z=this.#h();if(!Z)return!1;let $=this.#v(Z),Q=new Set($.map((G)=>G.toLowerCase())),j=!1;for(let G of X){let z=String(G??"").trim();if(z===""||Q.has(z.toLowerCase()))continue;Q.add(z.toLowerCase()),$.push(z),j=!0}if(j)this.#qX(Z,$);return j}#qX(X,Z){if(X.value=Z.join(","),typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}));this.#y()}#eX(){if(typeof this.element?.querySelectorAll!=="function")return null;let X=this.element.getAttribute("data-reactive-filter-input");if(!X)return null;let Z=this.#X();return[...this.element.querySelectorAll(X)].find(Z)??null}#y(){let X=this.#h();if(!X)return;let Z=this.#v(X),$=this.#X();this.#XZ(Z,$),this.#ZZ(Z,$)}#XZ(X,Z){let $=[...this.element.querySelectorAll("[data-reactive-tags-list]")].find(Z);if(!$)return;let j=[...this.element.querySelectorAll("[data-reactive-tags-template]")].find(Z)?.content?.firstElementChild;if(!j){if(!this.#g)console.warn("[phlex-reactive] reactive_tags: no chip <template data-reactive-tags-template> found in this root — "+"chips will not render (the hidden field still updates). Add a template with a [data-reactive-tag-text] node and a reactive_tags_remove button."),this.#g=!0;return}while($.firstChild)$.removeChild($.firstChild);for(let G of X){let z=j.cloneNode(!0);z.setAttribute?.("data-reactive-tag",G);let q=z.matches?.("[data-reactive-tag-text]")?z:(z.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(q)q.textContent=G;let K=[...z.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(z.matches?.('[data-action*="reactive#tagsRemove"]'))K.push(z);for(let Y of K)Y.setAttribute?.("data-reactive-tag-param",G);$.appendChild(z)}}#ZZ(X,Z){let $=new Set(X.map((Q)=>Q.toLowerCase()));for(let Q of this.element.querySelectorAll("[role=option]")){if(!Z(Q))continue;let j=Q.getAttribute?.("data-reactive-tag-param");if(!j)continue;if($.has(j.toLowerCase()))Q.setAttribute("data-reactive-tags-selected","true"),Q.hidden=!0,Q.removeAttribute?.("data-reactive-highlighted");else if(Q.hasAttribute?.("data-reactive-tags-selected")){if(Q.removeAttribute("data-reactive-tags-selected"),!this.#R())Q.hidden=!1}}if(this.#R())this.#B()}#$Z(){return this.#k=Math.max(this.#k+1,Date.now()),this.#k}#QZ(X,Z){let $=[X,...X.querySelectorAll?.("*")??[]];for(let Q of $)for(let j of["name","id","for"]){let G=Q.getAttribute?.(j);if(G&&G.includes("NEW_ROW"))Q.setAttribute?.(j,G.replaceAll("NEW_ROW",String(Z)))}}#jZ(X){if(this.#c)return;console.warn(`[phlex-reactive] nested rows: no owned [data-reactive-nested-list="${X}"] container + <template data-reactive-nested-template="${X}"> pair found in this root — the add `+"trigger did nothing. Render both inside the same reactive root (reactive_nested_list / reactive_nested_template)."),this.#c=!0}#GZ(){if(!this.#J)return;this.element.removeEventListener?.("turbo:morph-element",this.#J),this.#J=void 0}#zZ(){if(this.#j)this.element.removeEventListener?.("input",this.#j),this.element.removeEventListener?.("change",this.#j),this.#j=void 0;if(this.#M)this.element.removeEventListener?.("turbo:morph-element",this.#M),this.#M=void 0}#qZ(){if(!this.#A)return;this.element.removeEventListener?.("turbo:morph-element",this.#A),this.#A=void 0}#KZ(X,Z,$,Q){let j=new FormData;j.append("token",X),j.append("act",Z);for(let[z,q]of Object.entries($))this.#f(j,`params[${z}]`,q);let G=this.#YZ(Q);for(let{name:z,file:q,multiple:K}of Q){let W=K||G.has(z)?`params[${z}][]`:`params[${z}]`;j.append(W,q,q.name)}return j}#f(X,Z,$){if($==null)X.append(Z,"");else if(Array.isArray($))$.forEach((Q,j)=>this.#f(X,`${Z}[${j}]`,Q));else if(typeof $==="object")for(let[Q,j]of Object.entries($))this.#f(X,`${Z}[${Q}]`,j);else X.append(Z,String($))}#YZ(X){let Z=new Map;for(let{name:$}of X)Z.set($,(Z.get($)??0)+1);return new Set([...Z].filter(([,$])=>$>1).map(([$])=>$))}#KX(X){if(!X)return{};try{return typeof X==="string"?JSON.parse(X):X}catch{return{}}}#YX(X){return XX(X)}#UX(X){ZX(X,(Z)=>this.#HX(Z))}#HX(X){let Z=X.to;if(Z==="@root")return[this.element];if(typeof Z!=="string"||Z==="")return[];if(X.global)return[...document.querySelectorAll(Z)];return[...this.element.querySelectorAll(Z)].filter(($)=>this.#$($))}#UZ(X,Z){if(X?.checked!=="keep")return!1;let $=Z?.type;return $==="checkbox"||$==="radio"}#HZ(X,Z){if(!X)return null;let $=this.#WX(X,Z,!0);return $.length?$:null}#K(X){if(!X)return;if(!this.element.isConnected)return;for(let Z of X)Z()}#WZ(X,Z,$){this.#LZ(X,Z);let Q=$?this.#WX($,Z,!1):[];i();let j=!1;return()=>{if(j)return;j=!0,this.#JZ(X,Z),s();for(let G of Q)G()}}#WX(X,Z,$){let Q=[];for(let j of this.#_X(X,Z)){if(X.add_class){let G=X.add_class.filter((z)=>!j.classList.contains(z));if(j.classList.add(...G),G.length)Q.push(()=>j.classList.remove(...G))}if(X.remove_class){let G=X.remove_class.filter((z)=>j.classList.contains(z));if(j.classList.remove(...G),G.length)Q.push(()=>j.classList.add(...G))}if(X.toggle_class)X.toggle_class.forEach((G)=>j.classList.toggle(G)),Q.push(()=>X.toggle_class.forEach((G)=>j.classList.toggle(G)));if(X.hide)j.hidden=!0,Q.push(()=>j.hidden=!1);if(X.show)j.hidden=!1,Q.push(()=>j.hidden=!0)}if(Z&&(X.disable||X.text!=null))Q.push(this.#_Z(X,Z));if($&&X.checked==="keep"&&Z&&"checked"in Z){let j=Z.checked;Q.push(()=>Z.checked=!j)}return Q}#_X(X,Z){if(X.to==null)return Z?[Z]:[];return this.#HX({to:X.to})}#_Z(X,Z){let $=this.#O.get(Z);if($)$.count++;else this.#O.set(Z,{count:1,disabled:Z.disabled,html:Z.innerHTML,hadText:X.text!=null,swappedTo:X.text});if(X.disable)Z.disabled=!0;if(X.text!=null)Z.innerHTML=X.text;return()=>this.#MZ(Z,X)}#LZ(X,Z){if(this.#Y(Z,X,1),this.#Y(this.element,X,1),this.#H.set(X,(this.#H.get(X)??0)+1),this.#T++===0)this.element.setAttribute("aria-busy","true");for(let $ of this.#LX(X))this.#Y($,X,1)}#JZ(X,Z){this.#Y(Z,X,-1),this.#Y(this.element,X,-1);let $=(this.#H.get(X)??1)-1;if($<=0)this.#H.delete(X);else this.#H.set(X,$);if(--this.#T<=0)this.#T=0,this.element.removeAttribute("aria-busy");for(let Q of this.#LX(X))this.#Y(Q,X,-1)}#Y(X,Z,$){if(!X||typeof X.getAttribute!=="function")return;let Q=this.#I.get(X)??new Map,j=(Q.get(Z)??0)+$;if(j<=0)Q.delete(Z);else Q.set(Z,j);if(Q.size===0){this.#I.delete(X),X.removeAttribute("data-reactive-busy");return}this.#I.set(X,Q),X.setAttribute("data-reactive-busy",[...Q.keys()].join(" "))}#LX(X){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter(($)=>$.getAttribute("data-reactive-busy-on")===X&&this.#$($))}#MZ(X,Z){let $=this.#O.get(X);if(!$)return;if(--$.count>0)return;if(this.#O.delete(X),!X.isConnected)return;if(Z.disable)X.disabled=$.disabled;if($.hadText&&X.innerHTML===$.swappedTo)X.innerHTML=$.html}#AZ(X){if(!X||typeof X!=="object")return null;let{class:Z,...$}=X;return Z==null?X:{...$,add_class:Z}}#BZ(){return this.#JX??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#VZ(){if(this.#D!=null)return this.#D;let X=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Z=Number(X);return this.#D=Number.isFinite(Z)&&Z>0?Z:30000}#OZ(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#xZ(){return document.querySelector("pgbus-stream-source[connection-id]")?.getAttribute("connection-id")||document.querySelector('meta[name="pgbus-connection-id"]')?.content||null}}export{pX as resetReactiveDefers,lX as resetReactiveActivity,GX as registerReactiveVisit,zX as registerReactiveToken,AX as registerReactiveOffline,qX as registerReactiveJs,JX as registerReactiveDismiss,KX as registerReactiveDefer,y as registerReactiveActions,dX as reactiveActivityCount,mX as pendingDeferVia,s as exitReactiveActivity,xX as escapeRegExp,i as enterReactiveActivity,BX as enableLatencySim,VX as disableLatencySim,sX as default,PX as checkReactiveRegistration,oX as __resetReactiveRegistrationForTest,gX as __resetReactiveOfflineForTest,cX as __resetReactiveLatencyForTest,uX as __resetReactiveDismissForTest,iX as __markReactiveConnectedForTest,b as LATENCY_KEY,o as ACTIVE_ATTR};
|
|
1
|
+
import{Controller as WX}from"@hotwired/stimulus";import{confirmResolver as R}from"phlex/reactive/confirm";import{computeReducer as JX}from"phlex/reactive/compute";import{confirmPredicate as LX}from"phlex/reactive/confirm_predicate";function VX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:visit"])return;X["reactive:visit"]=function(){let Z=this.getAttribute("data-url");if(Z)window.Turbo.visit(Z,{action:"advance"})}}function BX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:token"])return;X["reactive:token"]=function(){let Z=this.getAttribute("data-reactive-token-value"),$=this.getAttribute("target");if(!Z||!$)return;let Q=document.getElementById($);if(Q)Q.setAttribute("data-reactive-token-value",Z)}}function _X(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:js"])return;X["reactive:js"]=function(){let Z=HX(this.getAttribute("data-reactive-ops"));if(!Z.length)return;let $=this.getAttribute("target"),Q=$?document.getElementById($):null;if($&&!Q)return;UX(Z,(j)=>ZZ(j,Q))}}var _=new Map;function s(X,Z){let $=!_.has(X);if(_.set(X,Z),$)QX()}function N(X){if(_.delete(X))jX()}function GZ(){_.clear(),S=!1}function qZ(X){return _.get(X)?.via}var S=!1;function AX(){let X=window.Turbo?.StreamActions;if(!X||X["reactive:defer"])return;if(X["reactive:defer"]=function(){let Z=this.getAttribute("target");if(!Z)return;if(this.getAttribute("data-reactive-defer-via")==="stream"){OX(Z,this);return}let $=this.getAttribute("data-reactive-defer-token");if(!$)return;C(Z,$)},!S&&typeof document<"u"&&document.addEventListener)S=!0,document.addEventListener("turbo:before-stream-render",MX)}function MX(X){let $=X.target?.getAttribute?.("target");if(!$)return;let Q=$.startsWith("reactive-defer-src-")?$.slice(19):$;if(_.get(Q)?.via==="stream")N(Q)}function C(X,Z){let $=document.getElementById(X);if(!$){console.warn(`[phlex-reactive] reactive:defer target #${X} is not on the page — skipped`);return}a(X),r($);let Q={via:"fetch",abort:new AbortController,timedOut:!1};s(X,Q),xX(X,Q,Z)}function OX(X,Z){let $=document.getElementById(X);if(!$){console.warn(`[phlex-reactive] reactive:defer target #${X} is not on the page — skipped`);return}let Q=Z.getAttribute("data-reactive-defer-src");if(!Q)return;if(!globalThis.customElements?.get?.("pgbus-stream-source")){let z=Z.getAttribute("data-reactive-defer-token");if(z){C(X,z);return}console.error("[phlex-reactive] reactive:defer via=stream but <pgbus-stream-source> is not registered "+"and no fallback token was provided — is the pgbus client loaded on this page?");return}a(X),r($);let j=document.createElement("pgbus-stream-source");j.id=n(X),j.setAttribute("src",Q),j.setAttribute("since-id",Z.getAttribute("data-reactive-defer-since-id")??"0"),j.setAttribute("hidden",""),document.body.appendChild(j),s(X,{via:"stream"})}function n(X){return`reactive-defer-src-${X}`}async function xX(X,Z,$){let Q=setTimeout(()=>{Z.timedOut=!0,Z.abort.abort()},CX()),j;try{j=await fetch(PX(),{method:"POST",headers:{Accept:"text/vnd.turbo-stream.html","Content-Type":"application/json","X-CSRF-Token":NX()},body:JSON.stringify({token:$}),credentials:"same-origin",signal:Z.abort.signal})}catch(G){if(clearTimeout(Q),_.get(X)!==Z)return;console.error("[phlex-reactive] deferred render failed",G),F(X,$);return}if(_.get(X)!==Z){clearTimeout(Q);return}if(j.status===204){clearTimeout(Q),g(X);return}if(!j.ok){clearTimeout(Q),console.error(`[phlex-reactive] deferred render failed: HTTP ${j.status}`),F(X,$,j.status);return}let z;try{z=await j.text()}catch(G){if(clearTimeout(Q),_.get(X)!==Z)return;console.error("[phlex-reactive] deferred render failed reading the body",G),F(X,$);return}if(clearTimeout(Q),_.get(X)!==Z)return;g(X),window.Turbo.renderStreamMessage(z)}function a(X){let Z=_.get(X);if(!Z)return;if(N(X),Z.via==="fetch")Z.abort.abort();else document.getElementById(n(X))?.remove?.()}function r(X){X.setAttribute("data-reactive-defer-pending","true"),X.setAttribute("aria-busy","true")}function t(X){X.removeAttribute("data-reactive-defer-pending"),X.removeAttribute("aria-busy")}function g(X){N(X);let Z=document.getElementById(X);if(!Z)return;t(Z),Z.removeAttribute("data-reactive-error")}function F(X,Z,$){N(X);let Q=document.getElementById(X);if(!Q)return;t(Q),Q.setAttribute("data-reactive-error","defer");let j=()=>{let z=document.getElementById(X);if(!z){console.warn("[phlex-reactive] defer retry() ignored — the target left the DOM");return}z.removeAttribute("data-reactive-error"),C(X,Z)};Q.dispatchEvent(new CustomEvent("reactive:error",{bubbles:!0,composed:!0,detail:{kind:"defer",target:X,status:$,retry:j}}))}function PX(){return document.querySelector('meta[name="phlex-reactive-defer-path"]')?.content||"/reactive/defer"}function NX(){return document.querySelector('meta[name="csrf-token"]')?.content??""}function CX(){let X=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Z=Number(X);return Number.isFinite(Z)&&Z>0?Z:30000}var b=!1;function DX(){if(b)return;if(typeof document>"u"||!document.addEventListener)return;b=!0,document.addEventListener("turbo:before-stream-render",RX)}function RX(X){let Z=X.detail,$=Z?.render;if(typeof $!=="function"||$.__reactiveDismissWrapped){if(typeof requestAnimationFrame==="function")requestAnimationFrame(I);else setTimeout(I,0);return}let Q=async(j)=>{await $(j),I()};Q.__reactiveDismissWrapped=!0,Z.render=Q}function I(){let X=document.querySelectorAll("[data-reactive-dismiss-after]");for(let Z of X){if(Z.hasAttribute("data-reactive-dismiss-scheduled"))continue;let $=Number(Z.getAttribute("data-reactive-dismiss-after"));if(!Number.isFinite($)||$<=0)continue;Z.setAttribute("data-reactive-dismiss-scheduled",""),setTimeout(()=>Z.remove(),$)}}function YZ(){b=!1}var FX=Object.freeze({append:"enter",prepend:"enter",replace:"update",update:"update",remove:"exit"}),T=Object.freeze(["fade","slide","scale","highlight","shake"]),w="data-reactive-fx-pending",e=1000,h=!1;function IX(){if(h)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;h=!0,document.addEventListener("turbo:before-stream-render",TX)}function KZ(){h=!1}function TX(X){let Z=X.detail,$=Z?.render;if(typeof $!=="function"||$.__reactiveEffectsWrapped)return;let Q=Z?.newStream??X.target,j=FX[Q?.getAttribute?.("action")];if(!j||SX())return;let z=EX(Q,j);if(!z)return;let G=j==="exit"?async(q)=>{await hX(x(Q),z),await $(q)}:async(q)=>{let Y=j==="enter"?bX(Q):null;if(await $(q),j==="enter")wX(Y,z);else XX(x(Q),z)};G.__reactiveEffectsWrapped=!0,Z.render=G}function EX(X,Z){let $=X.getAttribute?.("data-reactive-effect");if($==="off")return null;if($)return c($,Z);let j=(Z==="enter"?kX(X):x(X))?.getAttribute?.(`data-reactive-effect-${Z}`);return j?c(j,Z):null}function x(X){let Z=X.getAttribute?.("target");return Z?document.getElementById?.(Z)??null:null}function kX(X){return X.querySelector?.("template")?.content?.firstElementChild??null}function c(X,Z){if(X.startsWith("[")){let Q=null;try{let j=JSON.parse(X);if(Array.isArray(j)&&j.length===3)Q=j.map(String)}catch{}if(Q)return{legs:Q};return console.warn(`[phlex-reactive] malformed effect legs ${JSON.stringify(X)} — skipped`),null}let $=X==="random"?T[Math.floor(Math.random()*T.length)]:X;if(!T.includes($))return console.warn(`[phlex-reactive] unknown effect ${JSON.stringify(X)} — skipped`),null;return{className:`reactive-fx--${$}-${Z}`}}function SX(){try{return typeof matchMedia==="function"&&matchMedia("(prefers-reduced-motion: reduce)").matches}catch{return!1}}function bX(X){let Z=X.querySelector?.("template")?.content;if(!Z)return null;for(let $ of Array.from(Z.children??[]))$.setAttribute?.(w,"");return x(X)}function wX(X,Z){if(typeof X?.querySelectorAll!=="function")return;for(let $ of Array.from(X.querySelectorAll(`[${w}]`)))$.removeAttribute(w),XX($,Z)}async function hX(X,Z){if(!X?.classList)return;if(Z.legs){await ZX(X,Z.legs);return}X.classList.add(Z.className);let $=p(X);if($<=0){X.classList.remove(Z.className);return}await f(X,$),X.classList.remove(Z.className)}function XX(X,Z){if(!X?.classList)return;if(Z.legs){ZX(X,Z.legs);return}if(X.classList.contains(Z.className))X.classList.remove(Z.className),X.offsetWidth;X.classList.add(Z.className);let $=p(X);if($<=0){X.classList.remove(Z.className);return}let Q=X.__reactiveFxToken=(X.__reactiveFxToken??0)+1;f(X,$).then(()=>{if(X.__reactiveFxToken===Q)X.classList.remove(Z.className)})}async function ZX(X,Z){let[$,Q,j]=Z.map(yX),z=X.__reactiveFxToken=(X.__reactiveFxToken??0)+1;if(X.classList.remove(...$,...Q,...j),X.classList.add(...$,...Q),await vX(),X.__reactiveFxToken!==z)return;X.classList.remove(...Q),X.classList.add(...j);let G=p(X);if(G>0)await f(X,G);if(X.__reactiveFxToken!==z)return;X.classList.remove(...$,...j)}function yX(X){return String(X??"").split(/\s+/).filter(Boolean)}function p(X){if(typeof getComputedStyle!=="function")return 0;try{let Z=getComputedStyle(X),$=(z)=>String(z??"").split(",").reduce((G,q)=>Math.max(G,parseFloat(q)||0),0),Q=$(Z.animationDuration)+$(Z.animationDelay),j=$(Z.transitionDuration)+$(Z.transitionDelay);return Math.min(Math.max(Q,j)*1000,e)}catch{return 0}}function f(X,Z){return new Promise(($)=>{let Q=!1,j=()=>{if(Q)return;Q=!0,$()};X.addEventListener?.("animationend",j,{once:!0}),X.addEventListener?.("transitionend",j,{once:!0}),setTimeout(j,Math.min(Z+50,e))})}function vX(){return new Promise((X)=>{if(typeof requestAnimationFrame==="function")requestAnimationFrame(()=>X());else setTimeout(X,16)})}var y=!1;function pX(){if(y)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;y=!0;let X=()=>{let Z=document.documentElement;if(typeof Z?.toggleAttribute!=="function")return;Z.toggleAttribute("data-reactive-offline",globalThis.navigator?.onLine===!1)};X(),window.addEventListener("online",X),window.addEventListener("offline",X)}function HZ(){y=!1}var m="phlex-reactive:latency",P=!1;function fX(X){if(typeof sessionStorage>"u")return;sessionStorage.setItem(m,String(X))}function mX(){if(typeof sessionStorage>"u")return;sessionStorage.removeItem(m),P=!1}function uX(){if(typeof window>"u"||typeof document>"u")return;if(document.querySelector?.('meta[name="phlex-reactive-env"]')?.content!=="development")return;window.PhlexReactive={enableLatencySim:fX,disableLatencySim:mX}}function UZ(){P=!1}var $X="data-reactive-active",A=0;function QX(){if(A++,A===1)zX("reactive:busy")}function jX(){if(A===0)return;if(A--,A===0)zX("reactive:idle")}function WZ(){return A}function JZ(){A=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.($X)}function zX(X){if(typeof document>"u")return;let Z=document.documentElement;if(typeof Z?.toggleAttribute==="function")Z.toggleAttribute($X,A>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(X,{detail:{count:A}}))}function d(){VX(),BX(),_X(),AX(),DX(),IX(),pX(),uX()}function gX(X){return X.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}if(typeof window<"u")if(window.Turbo)d();else document.addEventListener("turbo:load",d,{once:!0});var D=!1;function cX(){if(D)return;if(typeof document>"u")return;let X=document.querySelectorAll('[data-controller~="reactive"]');if(!X||X.length===0)return;console.warn("[phlex-reactive] found "+X.length+' element(s) with data-controller="reactive" '+"but the reactive controller never connected. It is loaded but not registered — "+'add `application.register("reactive", ReactiveController)` (importmap) or import it into app/javascript/controllers/ for lazyLoadControllersFrom apps. See the README.')}function LZ(){D=!1}function VZ(){D=!0}if(typeof window<"u"&&typeof document<"u"){let X=()=>setTimeout(cX,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",X,{once:!0});else X()}var dX=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function lX(X){let Z=String(X).toLowerCase();return Z.startsWith("on")||dX.has(Z)}function iX(X,Z,$){let[Q,j,z]=Z;X.classList.add(Q,j),$(),requestAnimationFrame(()=>{X.classList.remove(j),X.classList.add(z)});let G=!1,q=()=>{if(G)return;G=!0,X.classList.remove(Q,z)};X.addEventListener("animationend",q,{once:!0}),setTimeout(q,350)}var l=Object.freeze({show:(X,Z)=>E(X,!1,Z),hide:(X,Z)=>E(X,!0,Z),toggle:(X,Z)=>E(X,!X.hidden,Z),add_class:(X,Z)=>X.classList.add(...Z.classes??[]),remove_class:(X,Z)=>X.classList.remove(...Z.classes??[]),toggle_class:(X,Z)=>(Z.classes??[]).forEach(($)=>X.classList.toggle($)),set_attr:(X,Z)=>{if(k(Z.name))X.setAttribute(Z.name,Z.value??"")},remove_attr:(X,Z)=>{if(k(Z.name))X.removeAttribute(Z.name)},toggle_attr:(X,Z)=>{if(!k(Z.name))return;if(X.hasAttribute(Z.name))X.removeAttribute(Z.name);else X.setAttribute(Z.name,"")},focus:(X)=>X.focus?.(),focus_first:(X)=>XZ(X)?.focus?.(),text:(X,Z)=>{let $=String(Z.value??"");if(X.textContent!==$)X.textContent=$},dispatch:(X,Z)=>{X.dispatchEvent(new CustomEvent(Z.name,{bubbles:!0,composed:!0,detail:Z.detail??{}}))}});function E(X,Z,$){if($?.transition)iX(X,$.transition,()=>X.hidden=Z);else X.hidden=Z}function k(X){if(!lX(X))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(X)} — skipped`),!1}var GX=/^#[A-Za-z_][\w-]*$/;function oX(X){if(typeof X==="string"&&GX.test(X))return!0;return console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(X)} — skipped`),!1}function sX(X,Z){let $=X.getAttribute("data-reactive-show-equals");if($!==null)return Z===$;let Q=X.getAttribute("data-reactive-show-not");if(Q!==null)return Z!==Q;let j=X.getAttribute("data-reactive-show-in");if(j!==null){try{let z=JSON.parse(j);if(Array.isArray(z))return z.includes(Z)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(j)} — skipped`),null}for(let z of qX){let G=X.getAttribute(`data-reactive-show-${z}`);if(G!==null)return YX(z,G,Z)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}var qX=["gte","gt","lte","lt"];function YX(X,Z,$){let Q=Number(Z);if(Number.isNaN(Q))return console.warn(`[phlex-reactive] reactive_show ${X}: needs a numeric literal, got ${JSON.stringify(Z)} — skipped`),null;let j=$==null?"":String($).trim(),z=j===""?NaN:Number(j);if(Number.isNaN(z))return!1;switch(X){case"gte":return z>=Q;case"gt":return z>Q;case"lte":return z<=Q;case"lt":return z<Q;default:return null}}function KX(X,Z){if(!X||typeof X!=="object")return null;if(typeof X.equals==="string")return Z===X.equals;if(typeof X.not==="string")return Z!==X.not;if(Array.isArray(X.in))return X.in.includes(Z);for(let $ of qX)if($ in X)return YX($,X[$],Z);return null}var i="[data-reactive-show-field], [data-reactive-show]";function nX(X){try{let Z=JSON.parse(X);if(Z&&typeof Z==="object"&&!Array.isArray(Z))return Z}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(X)} — skipped`),null}function u(X,Z){if(!X||typeof X!=="object"||typeof X.field!=="string")return!1;let $=Z(X.field)??"";return KX(X,$)===!0}function v(X,Z){if(!Array.isArray(X)||X.length===0)return null;return X.some(($)=>Array.isArray($)&&$.length>0&&$.every((Q)=>u(Q,Z)))}function aX(X){if(!Array.isArray(X)||X.length===0)return null;let Z=new Set;for(let $ of X){if(!Array.isArray($))continue;for(let Q of $)if(Q&&typeof Q==="object"&&typeof Q.field==="string")Z.add(Q.field)}return Z.size>0?[...Z]:null}function rX(X,Z){if(!X||typeof X!=="object")return null;let $=X.any;if(Array.isArray($)&&($.length===0||Array.isArray($[0])))return v($,Z);return tX(X,Z)}function tX(X,Z){let $=Array.isArray(X.all)?"all":Array.isArray(X.any)?"any":null;if(!$)return null;let Q=X[$];if(Q.length===0)return null;let j=Q.map((z)=>u(z,Z));return $==="all"?j.every(Boolean):j.some(Boolean)}function o(X){if(typeof X==="string"&&GX.test(X))return!0;return console.warn(`[phlex-reactive] refused cross-root show target ${JSON.stringify(X)} — skipped`),!1}var eX='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function XZ(X){return X.querySelectorAll?.(eX)?.[0]??null}function HX(X){if(Array.isArray(X))return X;if(typeof X!=="string")return[];try{let Z=JSON.parse(X);return Array.isArray(Z)?Z:[]}catch{return[]}}function UX(X,Z){for(let $ of X){if(!Array.isArray($))continue;let[Q,j={}]=$;if(!Object.hasOwn(l,Q)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(Q)} — skipped`);continue}for(let z of Z(j))l[Q](z,j)}}function ZZ(X,Z){let $=X.to;if(Z){if($==="@root")return[Z];if(typeof $!=="string"||$==="")return[];if(X.global)return[...document.querySelectorAll($)];return[...Z.querySelectorAll($)]}if(typeof $!=="string"||$===""||$==="@root")return[];return[...document.querySelectorAll($)]}class BZ extends WX{static values={token:String};#m;#M=new Map;#H=new Map;#_X;#I;#u;#T=0;#U=new Map;#E=new WeakMap;#O=new Map;#g=new WeakSet;#W;#J;#L;#Z;#Q;#V;#c=!1;#k=0;#d=!1;#j;#B;#_;#x;connect(){if(D=!0,this.element.id==="")console.warn("[phlex-reactive] a reactive root has no id; its next-action token can't self-match "+"and may fall back to the first token in the response → a silent HTTP 403 on the NEXT action. "+"Put id: on the SAME element as reactive_attrs — use div(**reactive_root) (emits id + token together), "+"or div(id:, **reactive_attrs). The id: must NOT be on a child. See the README.");if(this.element.getAttribute?.("data-reactive-defer-token"))this.#l(),this.#x=()=>this.#l(),this.element.addEventListener?.("turbo:morph-element",this.#x);if(this.#AX()){if(this.#W=()=>this.#h(),this.element.addEventListener?.("turbo:morph-element",this.#W),this.#h(),this.element.getAttribute?.("data-reactive-warn-unsaved")==="true")this.#cX()}if(this.#lX())this.#Z=()=>this.#GX(),this.element.addEventListener?.("input",this.#Z),this.element.addEventListener?.("change",this.#Z),this.element.addEventListener?.("turbo:morph-element",this.#Z),this.#GX();if(this.#R())this.#Q=(X)=>{if(X?.type==="input"&&!this.#tX(X))return;this.#A()},this.element.addEventListener?.("input",this.#Q),this.element.addEventListener?.("turbo:morph-element",this.#Q),this.#A();if(this.#F())this.#V=()=>this.#p(),this.element.addEventListener?.("turbo:morph-element",this.#V),this.#p();if(this.#XZ())this.#j=(X)=>this.syncNestedJson(X),this.#B=()=>this.#N(),this.element.addEventListener?.("input",this.#j),this.element.addEventListener?.("change",this.#j),this.element.addEventListener?.("turbo:morph-element",this.#B),this.#N();if(this.#rX())this.#_=()=>this.recompute(),this.element.addEventListener?.("turbo:morph-element",this.#_),this.recompute()}#AX(){if((this.element.getAttribute?.("data-action")??"").includes("reactive#trackDirty"))return!0;let X=this.element.querySelectorAll?.('[data-action*="reactive#trackDirty"]')??[];for(let Z of X)if(this.#$(Z))return!0;return!1}disconnect(){if(this.#SX(),this.#wX(),this.#dX(),this.#aX(),this.#eX(),this.#qZ(),this.#YZ(),this.#KZ(),this.#x)this.element.removeEventListener?.("turbo:morph-element",this.#x)}#l(){let X=this.element;if(!X?.id)return;let Z=X.getAttribute?.("data-reactive-defer-token");if(!Z)return;if(X.getAttribute?.("data-reactive-defer-pending")!=="true")return;C(X.id,Z)}dispatch(X){let{action:Z,params:$,debounce:Q,throttle:j,confirm:z,confirmWhen:G,outside:q,window:Y,optimistic:K}=X.params;if(!Z)return;let W=X.params.busy??this.#MZ(X.params.loading);if(q&&this.element.contains(X.target))return;let B=X.currentTarget??X.target;if(!Y&&!this.#WZ(K,B))X.preventDefault();let J=this.#w(z,G);if(!J)return this.#e(B,Z,$,Q,j,K,W);Promise.resolve().then(()=>R(J,{el:B})).catch(()=>!1).then((L)=>{if(L)this.#e(B,Z,$,Q,j,K,W)})}runOps(X){let{ops:Z,confirm:$,confirmWhen:Q,outside:j,window:z}=X.params,G=X.currentTarget??X.target;if(j&&this.element.contains(X.target))return;if(!z)X.preventDefault();let q=this.#w($,Q);if(!q)return this.#WX(this.#UX(Z));Promise.resolve().then(()=>R(q,{el:G})).catch(()=>!1).then((Y)=>{if(Y)this.#WX(this.#UX(Z))})}trackDirty(){this.#h()}recompute(X){if(X&&this.#g.has(X))return;let Z=this.#DX(),$=Z.map(([H])=>H),Q=this.element.getAttribute?.("data-reactive-scope")||null,j=(H)=>Q&&!H.includes("[")?`${Q}[${H}]`:H,z=this.#X(),G=new Map,q=(H)=>{if(G.has(H))return G.get(H);let U=null;for(let M of this.element.querySelectorAll(`[name="${j(H)}"]`))if(z(M)){U=M;break}return G.set(H,U),U};for(let H of $)this.#r(H,q(H)?.value??"");let Y=this.element.getAttribute("data-reactive-compute-reducer-param"),K=Y?JX(Y):null;if(!K){this.#t({},q);return}let W=this.#CX("data-reactive-compute-outputs-param"),B={};for(let[H,U]of Z){let M=q(H);if(U==="string")B[H]=M?.value??"";else{let V=Number(M?.value);B[H]=Number.isFinite(V)?V:0}}let J=K(B,{changed:this.#RX(X,$,Q)})||{},L=[];for(let H of W){if(!(H in J))continue;let U=q(H);if(!U)continue;if(String(J[H])===U.value)continue;U.value=J[H],L.push(U)}for(let H of Object.keys(J)){let U=J[H];if(U===void 0||U===null)continue;this.#r(H,U)}this.#t(J,q);for(let H of L){let U=new Event("input",{bubbles:!0});this.#g.add(U),H.dispatchEvent(U)}}listnavNext(X){this.#i(X,1)}listnavPrev(X){this.#i(X,-1)}listnavPick(X){let Z=this.#P(X),$=Z.findIndex((Q)=>Q.hasAttribute("data-reactive-highlighted"));if($<0)return;X.preventDefault(),Z[$].click()}listnavClose(X){for(let Z of this.#P(X))Z.removeAttribute("data-reactive-highlighted")}#i(X,Z){let $=this.#P(X);if(!$.length)return;X.preventDefault();let Q=$.findIndex((G)=>G.hasAttribute("data-reactive-highlighted")),j=Q<0?Z>0?0:$.length-1:(Q+Z+$.length)%$.length;for(let G of $)G.removeAttribute("data-reactive-highlighted");let z=$[j];z.setAttribute("data-reactive-highlighted","true"),z.scrollIntoView?.({block:"nearest"})}#P(X){let $=(X?.currentTarget??X?.target??this.element).getAttribute?.("data-reactive-listnav-option-param")??this.element.getAttribute("data-reactive-listnav-option-param");if(!$)return[];let Q=this.#X();return Array.from(this.element.querySelectorAll($)).filter((j)=>!j.hidden&&Q(j))}tagsAdd(X){if(!this.#F())return;if(X?.defaultPrevented)return;if(this.#P(X).some((Q)=>Q.hasAttribute?.("data-reactive-highlighted")))return;X?.preventDefault?.();let Z=X?.currentTarget??X?.target;if(!Z)return;if(!this.#YX(String(Z.value??"").split(",")))return;if(Z.value="",this.#R())this.#A()}tagsPick(X){if(!this.#F())return;X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.getAttribute?.("data-reactive-tag-param");if(!$)return;if(!this.#YX([$]))return;let Q=this.#ZZ();if(!Q)return;Q.value="",this.#A(),Q.focus?.()}tagsRemove(X){if(!this.#F())return;X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.getAttribute?.("data-reactive-tag-param");if(!$)return;let Q=this.#y();if(!Q)return;let j=this.#v(Q),z=j.filter((G)=>G.toLowerCase()!==$.toLowerCase());if(z.length===j.length)return;this.#KX(Q,z)}nestedAdd(X){X?.preventDefault?.();let Z=X?.currentTarget??X?.target,$=Z?.getAttribute?.("data-reactive-association-param");if(!$)return;if(typeof this.element?.querySelectorAll!=="function")return;let Q=this.#X(),j=[...this.element.querySelectorAll(`[data-reactive-nested-list="${$}"]`)].find(Q),G=[...this.element.querySelectorAll(`[data-reactive-nested-template="${$}"]`)].find(Q)?.content?.firstElementChild;if(!j||!G){this.#GZ($);return}let q=G.cloneNode(!0);this.#zZ(q,this.#jZ()),j.appendChild(q);let Y=Z?.getAttribute?.("data-reactive-nested-from-param"),K=Z?.getAttribute?.("data-reactive-nested-clear-param")==="true",W=this.#MX(q,Y,K);if(Y)W?.focus?.();else[...q.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(j.getAttribute?.("data-reactive-nested-json")===$)this.#s($)}#MX(X,Z,$){if(!Z)return null;let Q;try{Q=JSON.parse(Z)}catch{return null}if(!Q||typeof Q!=="object")return null;let j=this.#X(),z=[...X.querySelectorAll?.("input, select, textarea")??[]],G=[];for(let[q,Y]of Object.entries(Q)){let K=[...this.element.querySelectorAll?.(Y)??[]].find(j);if(!K)continue;let W=z.find((B)=>this.#a(B.getAttribute?.("name"))===q);if(!W)continue;this.#OX(W,K),G.push(K)}if($)for(let q of G)this.#xX(q);return G[0]??null}#OX(X,Z){if(X.type==="checkbox")X.checked=Z.type==="checkbox"?!!Z.checked:this.#S(Z)!=="";else X.value=this.#S(Z);if(typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}))}#xX(X){if(X.type==="checkbox")X.checked=!1;else X.value="";if(typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}))}nestedRemove(X){X?.preventDefault?.();let Z=X?.currentTarget??X?.target,$=Z?.closest?.("[data-reactive-nested-row]");if(!$)return;if($.closest?.('[data-controller~="reactive"]')!==this.element)return;let Q=Z?.getAttribute?.("data-reactive-confirm-param"),j=Z?.getAttribute?.("data-reactive-confirm-when-param"),z=this.#w(Q,j);if(!z)return this.#o($);let G=this.#n($),q=this.#PX(z,G);return Promise.resolve().then(()=>R(q,{el:Z,row:$,fields:G})).catch(()=>!1).then((Y)=>{if(Y)this.#o($)})}#PX(X,Z){if(!X.includes("%{"))return X;return X.replace(/%\{(\w+)\}/g,($,Q)=>Object.prototype.hasOwnProperty.call(Z,Q)?Z[Q]:$)}#o(X){let Z=[...X.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(Z){if(Z.value="1",typeof Z.dispatchEvent==="function")Z.dispatchEvent(new Event("input",{bubbles:!0}));X.hidden=!0}else X.parentNode?.removeChild?.(X);this.#N()}syncNestedJson(X){let Z=X?.target;if(!Z||!this.#$(Z))return;this.#N()}#N(){if(typeof this.element?.querySelectorAll!=="function")return;let X=this.#X();for(let Z of[...this.element.querySelectorAll("[data-reactive-nested-json]")].filter(X))this.#s(Z.getAttribute("data-reactive-nested-json"))}#s(X){let Z=this.#X(),$=[...this.element.querySelectorAll(`[data-reactive-nested-list="${X}"]`)].find(Z);if(!$)return;let Q=this.#NX($);if(!Q)return;let j=[];for(let G of[...$.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!Z(G)||G.hidden)continue;j.push(this.#n(G))}let z=JSON.stringify(j);if(Q.value===z)return;if(Q.value=z,typeof Q.dispatchEvent==="function")Q.dispatchEvent(new Event("input",{bubbles:!0}))}#NX(X){let Z=X.getAttribute?.("data-reactive-nested-json-field");if(!Z)return null;let $=this.#X();return[...this.element.querySelectorAll(Z)].find($)??null}#n(X){let Z={};for(let $ of[...X.querySelectorAll?.("input, select, textarea")??[]]){let Q=this.#a($.getAttribute?.("name"));if(Q===null||Q==="_destroy")continue;Z[Q]=this.#S($)}return Z}#a(X){if(!X)return null;let Z=X.match(/\[([^\][]+)\]$/);return Z?Z[1]:X}#S(X){if(X.type==="checkbox")return X.checked?X.value||"on":"";return X.value??""}#CX(X){let Z=this.element.getAttribute(X);if(!Z)return[];try{let $=JSON.parse(Z);return Array.isArray($)?$:[]}catch{return[]}}#DX(){let X=this.element.getAttribute("data-reactive-compute-inputs-param");if(!X)return[];try{let Z=JSON.parse(X);if(Array.isArray(Z))return Z.map(($)=>[$,"number"]);if(Z&&typeof Z==="object")return Object.entries(Z);return[]}catch{return[]}}#RX(X,Z,$){let Q=X?.target;if(!Q?.name||typeof Q.closest!=="function")return null;let j=this.#FX(Q.name,$);if(!Z.includes(j))return null;return this.#$(Q)?j:null}#FX(X,Z){if(!Z)return X;let $=`${Z}[`;return X.startsWith($)&&X.endsWith("]")?X.slice($.length,-1):X}#r(X,Z){let $=String(Z);for(let Q of this.#IX(X)){if(Q.textContent===$)continue;Q.textContent=$}}#IX(X){let Z=this.element.querySelectorAll(`[data-reactive-text="${X}"]`);return Array.from(Z).filter(($)=>this.#$($))}#t(X,Z){let $=this.#TX();for(let[Q,j]of Object.entries($)){let z=Q in X?X[Q]:Z(Q)?.value;if(z===void 0||z===null)continue;let G=String(z);for(let q of Array.isArray(j)?j:[j]){if(!oX(q))continue;for(let Y of document.querySelectorAll(q)){if(Y.textContent===G)continue;Y.textContent=G}}}}#TX(){let X=this.element.getAttribute("data-reactive-compute-mirror-param");if(!X)return{};try{let Z=JSON.parse(X);return Z&&typeof Z==="object"&&!Array.isArray(Z)?Z:{}}catch{return{}}}#e(X,Z,$,Q,j,z,G){if(this.#D("reactive:before-dispatch",{action:Z,params:this.#HX($),element:this.element},{cancelable:!0}).defaultPrevented)return;let Y=Number(Q)||0;if(Y>0)return this.#kX(X,Y,Z,$,z,G);let K=Number(j)||0;if(K>0)return this.#bX(X,K,Z,$,z,G);return this.#C(Z,$,z,X,G)}#C(X,Z,$,Q,j){let z=this.#JZ($,Q),G=this.#LZ(X,Q,j),q=this.#XX()?this.#EX($,Q):null;return this.queue=(this.queue??Promise.resolve()).then(()=>this.#mX(X,Z,z,G,q)),this.queue}#EX(X,Z){if(!X?.hide)return null;let $=this.#VX(X,Z);if(!$.length)return null;return()=>{let Q=$.filter((j)=>j.isConnected&&!j.hidden);if(!Q.length)return;console.warn("[phlex-reactive] optimistic: { hide: true } was undone by the reply's re-render — "+"the element is visible again. For an instant delete, return reply.remove so the server removes it; otherwise the hide only flashes.",Q)}}#kX(X,Z,$,Q,j,z){this.#b(X);let G=()=>{this.#b(X),this.#C($,Q,j,X,z)},q=setTimeout(G,Z);X?.addEventListener?.("blur",G,{once:!0}),this.#M.set(X,{timer:q,flush:G})}#b(X){let Z=this.#M.get(X);if(!Z)return;clearTimeout(Z.timer),X?.removeEventListener?.("blur",Z.flush),this.#M.delete(X)}#SX(){for(let X of[...this.#M.keys()])this.#b(X)}#bX(X,Z,$,Q,j,z){let G=this.#H.get(X)??new Map;if(G.has($))return;let q=setTimeout(()=>{if(G.delete($),G.size===0)this.#H.delete(X)},Z);return G.set($,q),this.#H.set(X,G),this.#C($,Q,j,X,z)}#wX(){for(let X of this.#H.values())for(let Z of X.values())clearTimeout(Z);this.#H.clear()}#D(X,Z,{cancelable:$=!1}={}){let Q=new CustomEvent(X,{bubbles:!0,composed:!0,cancelable:$,detail:Z});return(this.element.isConnected?this.element:document).dispatchEvent(Q),Q}#z(X,Z,$,Q){let j=()=>{if(!this.element.isConnected){console.warn("[phlex-reactive] retry() ignored — the reactive root left the DOM");return}return this.#C(X,Z)};this.#D("reactive:error",{action:X,params:$,...Q,retry:j})}#G(X){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",X)}#hX(){this.element?.removeAttribute?.("data-reactive-error")}#yX(){let X=document.querySelector("[data-reactive-error-flash]");if(!X?.content)return;let Z=X.getAttribute("data-reactive-error-flash")||"flash",$=document.getElementById(Z);if(!$)return;$.appendChild(X.content.cloneNode(!0))}#vX(){if(typeof sessionStorage>"u")return Promise.resolve();let X=Number(sessionStorage.getItem(m));if(!Number.isFinite(X)||X<=0)return Promise.resolve();if(!P)P=!0,console.warn(`[phlex-reactive] latency simulator ACTIVE — every action is delayed by ${X}ms. Call PhlexReactive.disableLatencySim() (or clear sessionStorage) to turn it off.`);return new Promise((Z)=>setTimeout(Z,X))}#XX(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#ZX(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}#pX(X){if(!X)return[];let Z=[],$=/<turbo-stream\b([^>]*)>/g,Q;while((Q=$.exec(X))!==null){let j=Q[1],z=j.match(/\baction="([^"]*)"/)?.[1]??"?",G=j.match(/\btarget="([^"]*)"/)?.[1];Z.push(G?`${z} → #${G}`:z)}return Z}#fX(X){let{action:Z,status:$,ms:Q}=X,z=`reactive ${this.element?.id?`#${this.element.id} `:""}${Z} → ${$??"—"} (${Math.round(Q)}ms)`;if(console.groupCollapsed(z),console.log(`params: [${X.paramNames.join(", ")}] + collected: [${X.fieldNames.join(", ")}]`),console.log(`encoding: ${X.encoding}`),X.streams.length)console.log(`streams: ${X.streams.join(" ")}`);console.log(`token: ${X.tokenRefreshed?"refreshed ✓":"unchanged"}`),console.groupEnd()}async#mX(X,Z,$,Q,j){let{fields:z,files:G}=this.#jX(),q=this.#HX(Z),Y={...z,...q},K=this.#q,W=G.length>0,B=W?this.#HZ(K,X,Y,G):JSON.stringify({token:K,act:X,params:Y}),J=this.#XX()?{action:X,paramNames:Object.keys(q),fieldNames:Object.keys(z),encoding:W?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#ZX()}:null;await this.#vX();try{if(navigator.onLine===!1){this.#Y($),this.#G("offline"),this.#z(X,Z,Y,{kind:"offline"});return}let L;try{let V={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#PZ()};if(!W)V["Content-Type"]="application/json";let O=this.#NZ();if(O)V["X-Pgbus-Connection"]=O;L=await fetch(this.#OZ(),{method:"POST",headers:V,body:B,credentials:"same-origin",signal:AbortSignal.timeout(this.#xZ())})}catch(V){if(console.error("[phlex-reactive] action error",V),this.#Y($),V?.name==="TimeoutError"||V?.name==="AbortError"){this.#G("timeout"),this.#z(X,Z,Y,{kind:"timeout"});return}this.#yX(),this.#G("network"),this.#z(X,Z,Y,{kind:"network"});return}if(J)J.status=L.status;if(L.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#Y($),this.#G("redirected"),this.#z(X,Z,Y,{kind:"redirected",status:L.status});return}if(!L.ok){let V=await L.text();if(console.error(`[phlex-reactive] action failed: HTTP ${L.status}`,V),this.#Y($),(L.headers.get("Content-Type")||"").includes("turbo-stream")){let O=this.#QX(V);if(this.#q=O??this.#q,J)this.#$X(J,V,O);window.Turbo.renderStreamMessage(V)}this.#G("http"),this.#z(X,Z,Y,{kind:"http",status:L.status,body:V});return}let H=L.headers.get("Content-Type")||"";if(!H.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${H}" — no update applied`),this.#Y($),this.#G("content-type"),this.#z(X,Z,Y,{kind:"content-type",status:L.status});return}let U=await L.text(),M=this.#QX(U);if(this.#q=M??this.#q,J)this.#$X(J,U,M);if(window.Turbo.renderStreamMessage(U),j)queueMicrotask(j);this.#hX(),this.#D("reactive:applied",{action:X,params:Y,html:U})}catch(L){console.error("[phlex-reactive] action error",L),this.#Y($),this.#D("reactive:error",{action:X,params:Y,kind:"apply"})}finally{if(Q?.(),J)this.#fX({...J,ms:this.#ZX()-J.started})}}#$X(X,Z,$){X.streams=this.#pX(Z),X.tokenRefreshed=$!=null}get#q(){return this.#m??this.tokenValue}set#q(X){this.#m=X}#QX(X){let Z=this.element.id;if(!Z)return X.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:$,self:Q}=this.#uX(Z),j=X.match($);if(j)return j[1];let z=X.match(Q);if(z)return z[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#uX(X){let Z=this.#u;if(Z&&Z.id===X)return Z;let $=gX(X);return this.#u={id:X,token:new RegExp(`<turbo-stream\\b[^>]*\\baction="reactive:token"[^>]*\\btarget="${$}"[^>]*\\bdata-reactive-token-value="([^"]+)"`),self:new RegExp(`<turbo-stream\\b[^>]*\\baction="(?:replace|update)"[^>]*\\btarget="${$}"[^>]*>([\\s\\S]*?)</turbo-stream>`)}}#$(X){return X.closest('[data-controller~="reactive"]')===this.element}#X(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(Z)=>this.#$(Z)}#w(X,Z){if(X)return X;if(!Z)return null;let $=Z;if(typeof Z==="string")try{$=JSON.parse(Z)}catch{return console.warn(`[phlex-reactive] malformed conditional confirm payload ${JSON.stringify(Z)} — skipped`),null}if(!$||typeof $!=="object")return null;let{fields:Q}=this.#jX(),j=(G)=>Q[G],z;if(typeof $.predicate==="string"){let G=LX($.predicate);if(!G)return console.warn(`[phlex-reactive] confirm predicate "${$.predicate}" is not registered — proceeding without a dialog (register it with setConfirmPredicate)`),null;z=!!G(Q)}else z=v($.groups?.any,j)===!0;return z?$.message:null}#jX(){let X={},Z=[],$=this.#X();return this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Q)=>{if(!$(Q))return;if(Q.type==="file")for(let j of Q.files??[])Z.push({name:Q.name,file:j,multiple:Q.multiple});else if(Q.type==="checkbox")X[Q.name]=Q.checked;else if(Q.type==="radio"){if(Q.checked)X[Q.name]=Q.value}else X[Q.name]=Q.value}),this.element.querySelectorAll("[name]:is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])").forEach((Q)=>{if(!$(Q))return;let j=Q.getAttribute("name");if(!j)return;let z=X[j];if(z==null||z==="")X[j]=Q.value??Q.textContent??Q.innerHTML??""}),{fields:X,files:Z}}#h(){if(typeof this.element?.querySelectorAll!=="function")return;let X=0;if(this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Z)=>{if(!this.#$(Z))return;if(Z.type==="file")return;if(this.#gX(Z))Z.setAttribute("data-reactive-dirty","true"),X++;else Z.removeAttribute("data-reactive-dirty")}),X>0)this.element.setAttribute("data-reactive-dirty",String(X));else this.element.removeAttribute("data-reactive-dirty")}#gX(X){if(X.type==="checkbox"||X.type==="radio")return X.checked!==X.defaultChecked;if(X.tag==="select"||X.options)return Array.from(X.options??[]).some((Z)=>Z.selected!==Z.defaultSelected);return X.value!==X.defaultValue}#zX(){let X=this.element.getAttribute?.("data-reactive-dirty"),Z=Number(X);return Number.isFinite(Z)&&Z>0?Z:0}#cX(){if(typeof window>"u"||typeof window.addEventListener!=="function")return;this.#J=(X)=>{if(this.#zX()===0)return;return X.preventDefault(),X.returnValue="You have unsaved changes.",X.returnValue},this.#L=(X)=>{if(this.#zX()===0)return;if(!(typeof window.confirm==="function"?window.confirm("You have unsaved changes. Leave anyway?"):!0))X.preventDefault?.()},window.addEventListener("beforeunload",this.#J),window.addEventListener("turbo:before-visit",this.#L)}#dX(){if(this.#W)this.element.removeEventListener?.("turbo:morph-element",this.#W),this.#W=void 0;if(typeof window<"u"&&typeof window.removeEventListener==="function"){if(this.#J)window.removeEventListener("beforeunload",this.#J);if(this.#L)window.removeEventListener("turbo:before-visit",this.#L)}this.#J=void 0,this.#L=void 0}#lX(){if(this.element.getAttribute?.("data-reactive-show-targets"))return!0;let X=this.element.querySelectorAll?.(i)??[];for(let Z of X)if(this.#$(Z))return!0;return!1}#GX(){if(typeof this.element?.querySelectorAll!=="function")return;let X=this.#X(),Z=this.element.getAttribute?.("data-reactive-scope")||null,$=new Map,Q=(j)=>{if(!$.has(j))$.set(j,this.#nX(j,X,Z));return $.get(j)};for(let j of this.element.querySelectorAll(i)){if(!X(j))continue;let z=j.getAttribute("data-reactive-show");if(z!==null){let K=rX(nX(z),Q);if(K!==null)this.#qX(j,K,X,Z);continue}let G=j.getAttribute("data-reactive-show-field");if(!G)continue;let q=Q(G);if(q===null)continue;let Y=sX(j,q);if(Y===null)continue;this.#qX(j,Y,X,Z)}this.#iX(Q)}#qX(X,Z,$,Q){if(X.hidden=!Z,X.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof X.querySelectorAll!=="function")return;for(let j of X.querySelectorAll("input[name], select[name], textarea[name]"))if($(j))j.disabled=!Z;if(X.name&&$(X))X.disabled=!Z}#iX(X){let Z=this.#sX();for(let[$,Q]of Object.entries(Z)){if($.startsWith("#")){this.#oX($,Q,X);continue}if(!Q||typeof Q!=="object"||Array.isArray(Q))continue;let j=X($);if(j===null)continue;let z=()=>j;for(let[G,q]of Object.entries(Q)){if(!o(G))continue;let Y;if(Array.isArray(q)){if(q.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${G} — skipped`);continue}Y=q.every((K)=>u(K,z))}else{let K=KX(q,j);if(K===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${G} — skipped`);continue}Y=K}for(let K of document.querySelectorAll(G))K.hidden=!Y}}}#oX(X,Z,$){if(!o(X))return;let Q=Z&&typeof Z==="object"&&!Array.isArray(Z)?Z.any:null,j=aX(Q);if(j===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${X} — skipped`);return}if(j.every((G)=>$(G)===null))return;let z=v(Q,$);if(z===null)return;for(let G of document.querySelectorAll(X))G.hidden=!z}#sX(){let X=this.element.getAttribute?.("data-reactive-show-targets");if(!X)return{};try{let Z=JSON.parse(X);if(Z&&typeof Z==="object"&&!Array.isArray(Z))return Z}catch{}return console.warn("[phlex-reactive] malformed data-reactive-show-targets — ignored. "+"Did two reactive_show_targets calls collide on one root? Declare every field in ONE call: reactive_show_targets(mode: { ... }, kind: { ... })"),{}}#nX(X,Z,$){let Q=$&&!X.includes("[")?`${$}[${X}]`:X,j=!1,z=null;for(let G of this.element.querySelectorAll(`[name="${Q}"]`)){if(!Z(G))continue;if(G.type==="checkbox")return G.checked?"true":"false";if(G.type==="radio"){if(G.checked)return G.value??"";j=!0;continue}z??=G}if(z)return z.value??"";return j?"":null}#aX(){if(!this.#Z)return;this.element.removeEventListener?.("input",this.#Z),this.element.removeEventListener?.("change",this.#Z),this.element.removeEventListener?.("turbo:morph-element",this.#Z),this.#Z=void 0}#R(){return!!(this.element.getAttribute?.("data-reactive-filter-input")&&this.element.getAttribute?.("data-reactive-filter-option"))}#rX(){return this.element.getAttribute?.("data-reactive-compute-seed")==="true"}#tX(X){let Z=this.element.getAttribute("data-reactive-filter-input");return!!Z&&typeof X.target?.matches==="function"&&X.target.matches(Z)}#A(){if(typeof this.element?.querySelectorAll!=="function")return;let X=this.element.getAttribute("data-reactive-filter-input"),Z=this.element.getAttribute("data-reactive-filter-option");if(!X||!Z)return;let $=this.#X(),Q=[...this.element.querySelectorAll(X)].find($);if(!Q)return;let j=(Q.value??"").trim().toLowerCase(),z=0;for(let Y of this.element.querySelectorAll(Z)){if(!$(Y))continue;let K=(Y.getAttribute("data-reactive-filter-text")??Y.textContent??"").toLowerCase(),W=Y.hasAttribute?.("data-reactive-tags-selected")||j!==""&&!K.includes(j);if(Y.hidden=W,W)Y.removeAttribute("data-reactive-highlighted");else z++}let G=this.element.getAttribute("data-reactive-filter-group");if(G)for(let Y of this.element.querySelectorAll(G)){if(!$(Y))continue;let K=[...Y.querySelectorAll(Z)].filter($);if(K.length===0)continue;Y.hidden=K.every((W)=>W.hidden)}let q=this.element.getAttribute("data-reactive-filter-empty");if(q){for(let Y of this.element.querySelectorAll(q))if($(Y))Y.hidden=z>0}}#eX(){if(!this.#Q)return;this.element.removeEventListener?.("input",this.#Q),this.element.removeEventListener?.("turbo:morph-element",this.#Q),this.#Q=void 0}#F(){return!!this.element.getAttribute?.("data-reactive-tags-field")}#XZ(){if(typeof this.element?.querySelector!=="function")return!1;return!!this.element.querySelector("[data-reactive-nested-json]")}#y(){if(typeof this.element?.querySelectorAll!=="function")return null;let X=this.element.getAttribute("data-reactive-tags-field");if(!X)return null;let Z=this.#X();return[...this.element.querySelectorAll(X)].find(Z)??null}#v(X){let Z=new Set,$=[];for(let Q of String(X.value??"").split(",")){let j=Q.trim();if(j===""||Z.has(j.toLowerCase()))continue;Z.add(j.toLowerCase()),$.push(j)}return $}#YX(X){let Z=this.#y();if(!Z)return!1;let $=this.#v(Z),Q=new Set($.map((z)=>z.toLowerCase())),j=!1;for(let z of X){let G=String(z??"").trim();if(G===""||Q.has(G.toLowerCase()))continue;Q.add(G.toLowerCase()),$.push(G),j=!0}if(j)this.#KX(Z,$);return j}#KX(X,Z){if(X.value=Z.join(","),typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}));this.#p()}#ZZ(){if(typeof this.element?.querySelectorAll!=="function")return null;let X=this.element.getAttribute("data-reactive-filter-input");if(!X)return null;let Z=this.#X();return[...this.element.querySelectorAll(X)].find(Z)??null}#p(){let X=this.#y();if(!X)return;let Z=this.#v(X),$=this.#X();this.#$Z(Z,$),this.#QZ(Z,$)}#$Z(X,Z){let $=[...this.element.querySelectorAll("[data-reactive-tags-list]")].find(Z);if(!$)return;let j=[...this.element.querySelectorAll("[data-reactive-tags-template]")].find(Z)?.content?.firstElementChild;if(!j){if(!this.#c)console.warn("[phlex-reactive] reactive_tags: no chip <template data-reactive-tags-template> found in this root — "+"chips will not render (the hidden field still updates). Add a template with a [data-reactive-tag-text] node and a reactive_tags_remove button."),this.#c=!0;return}while($.firstChild)$.removeChild($.firstChild);for(let z of X){let G=j.cloneNode(!0);G.setAttribute?.("data-reactive-tag",z);let q=G.matches?.("[data-reactive-tag-text]")?G:(G.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(q)q.textContent=z;let Y=[...G.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(G.matches?.('[data-action*="reactive#tagsRemove"]'))Y.push(G);for(let K of Y)K.setAttribute?.("data-reactive-tag-param",z);$.appendChild(G)}}#QZ(X,Z){let $=new Set(X.map((Q)=>Q.toLowerCase()));for(let Q of this.element.querySelectorAll("[role=option]")){if(!Z(Q))continue;let j=Q.getAttribute?.("data-reactive-tag-param");if(!j)continue;if($.has(j.toLowerCase()))Q.setAttribute("data-reactive-tags-selected","true"),Q.hidden=!0,Q.removeAttribute?.("data-reactive-highlighted");else if(Q.hasAttribute?.("data-reactive-tags-selected")){if(Q.removeAttribute("data-reactive-tags-selected"),!this.#R())Q.hidden=!1}}if(this.#R())this.#A()}#jZ(){return this.#k=Math.max(this.#k+1,Date.now()),this.#k}#zZ(X,Z){let $=[X,...X.querySelectorAll?.("*")??[]];for(let Q of $)for(let j of["name","id","for"]){let z=Q.getAttribute?.(j);if(z&&z.includes("NEW_ROW"))Q.setAttribute?.(j,z.replaceAll("NEW_ROW",String(Z)))}}#GZ(X){if(this.#d)return;console.warn(`[phlex-reactive] nested rows: no owned [data-reactive-nested-list="${X}"] container + <template data-reactive-nested-template="${X}"> pair found in this root — the add `+"trigger did nothing. Render both inside the same reactive root (reactive_nested_list / reactive_nested_template)."),this.#d=!0}#qZ(){if(!this.#V)return;this.element.removeEventListener?.("turbo:morph-element",this.#V),this.#V=void 0}#YZ(){if(this.#j)this.element.removeEventListener?.("input",this.#j),this.element.removeEventListener?.("change",this.#j),this.#j=void 0;if(this.#B)this.element.removeEventListener?.("turbo:morph-element",this.#B),this.#B=void 0}#KZ(){if(!this.#_)return;this.element.removeEventListener?.("turbo:morph-element",this.#_),this.#_=void 0}#HZ(X,Z,$,Q){let j=new FormData;j.append("token",X),j.append("act",Z);for(let[G,q]of Object.entries($))this.#f(j,`params[${G}]`,q);let z=this.#UZ(Q);for(let{name:G,file:q,multiple:Y}of Q){let W=Y||z.has(G)?`params[${G}][]`:`params[${G}]`;j.append(W,q,q.name)}return j}#f(X,Z,$){if($==null)X.append(Z,"");else if(Array.isArray($))$.forEach((Q,j)=>this.#f(X,`${Z}[${j}]`,Q));else if(typeof $==="object")for(let[Q,j]of Object.entries($))this.#f(X,`${Z}[${Q}]`,j);else X.append(Z,String($))}#UZ(X){let Z=new Map;for(let{name:$}of X)Z.set($,(Z.get($)??0)+1);return new Set([...Z].filter(([,$])=>$>1).map(([$])=>$))}#HX(X){if(!X)return{};try{return typeof X==="string"?JSON.parse(X):X}catch{return{}}}#UX(X){return HX(X)}#WX(X){UX(X,(Z)=>this.#JX(Z))}#JX(X){let Z=X.to;if(Z==="@root")return[this.element];if(typeof Z!=="string"||Z==="")return[];if(X.global)return[...document.querySelectorAll(Z)];return[...this.element.querySelectorAll(Z)].filter(($)=>this.#$($))}#WZ(X,Z){if(X?.checked!=="keep")return!1;let $=Z?.type;return $==="checkbox"||$==="radio"}#JZ(X,Z){if(!X)return null;let $=this.#LX(X,Z,!0);return $.length?$:null}#Y(X){if(!X)return;if(!this.element.isConnected)return;for(let Z of X)Z()}#LZ(X,Z,$){this.#BZ(X,Z);let Q=$?this.#LX($,Z,!1):[];QX();let j=!1;return()=>{if(j)return;j=!0,this.#_Z(X,Z),jX();for(let z of Q)z()}}#LX(X,Z,$){let Q=[];for(let j of this.#VX(X,Z)){if(X.add_class){let z=X.add_class.filter((G)=>!j.classList.contains(G));if(j.classList.add(...z),z.length)Q.push(()=>j.classList.remove(...z))}if(X.remove_class){let z=X.remove_class.filter((G)=>j.classList.contains(G));if(j.classList.remove(...z),z.length)Q.push(()=>j.classList.add(...z))}if(X.toggle_class)X.toggle_class.forEach((z)=>j.classList.toggle(z)),Q.push(()=>X.toggle_class.forEach((z)=>j.classList.toggle(z)));if(X.hide)j.hidden=!0,Q.push(()=>j.hidden=!1);if(X.show)j.hidden=!1,Q.push(()=>j.hidden=!0)}if(Z&&(X.disable||X.text!=null))Q.push(this.#VZ(X,Z));if($&&X.checked==="keep"&&Z&&"checked"in Z){let j=Z.checked;Q.push(()=>Z.checked=!j)}return Q}#VX(X,Z){if(X.to==null)return Z?[Z]:[];return this.#JX({to:X.to})}#VZ(X,Z){let $=this.#O.get(Z);if($)$.count++;else this.#O.set(Z,{count:1,disabled:Z.disabled,html:Z.innerHTML,hadText:X.text!=null,swappedTo:X.text});if(X.disable)Z.disabled=!0;if(X.text!=null)Z.innerHTML=X.text;return()=>this.#AZ(Z,X)}#BZ(X,Z){if(this.#K(Z,X,1),this.#K(this.element,X,1),this.#U.set(X,(this.#U.get(X)??0)+1),this.#T++===0)this.element.setAttribute("aria-busy","true");for(let $ of this.#BX(X))this.#K($,X,1)}#_Z(X,Z){this.#K(Z,X,-1),this.#K(this.element,X,-1);let $=(this.#U.get(X)??1)-1;if($<=0)this.#U.delete(X);else this.#U.set(X,$);if(--this.#T<=0)this.#T=0,this.element.removeAttribute("aria-busy");for(let Q of this.#BX(X))this.#K(Q,X,-1)}#K(X,Z,$){if(!X||typeof X.getAttribute!=="function")return;let Q=this.#E.get(X)??new Map,j=(Q.get(Z)??0)+$;if(j<=0)Q.delete(Z);else Q.set(Z,j);if(Q.size===0){this.#E.delete(X),X.removeAttribute("data-reactive-busy");return}this.#E.set(X,Q),X.setAttribute("data-reactive-busy",[...Q.keys()].join(" "))}#BX(X){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter(($)=>$.getAttribute("data-reactive-busy-on")===X&&this.#$($))}#AZ(X,Z){let $=this.#O.get(X);if(!$)return;if(--$.count>0)return;if(this.#O.delete(X),!X.isConnected)return;if(Z.disable)X.disabled=$.disabled;if($.hadText&&X.innerHTML===$.swappedTo)X.innerHTML=$.html}#MZ(X){if(!X||typeof X!=="object")return null;let{class:Z,...$}=X;return Z==null?X:{...$,add_class:Z}}#OZ(){return this.#_X??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#xZ(){if(this.#I!=null)return this.#I;let X=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Z=Number(X);return this.#I=Number.isFinite(Z)&&Z>0?Z:30000}#PZ(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#NZ(){return document.querySelector("pgbus-stream-source[connection-id]")?.getAttribute("connection-id")||document.querySelector('meta[name="pgbus-connection-id"]')?.content||null}}export{GZ as resetReactiveDefers,JZ as resetReactiveActivity,VX as registerReactiveVisit,BX as registerReactiveToken,pX as registerReactiveOffline,_X as registerReactiveJs,IX as registerReactiveEffects,DX as registerReactiveDismiss,AX as registerReactiveDefer,d as registerReactiveActions,WZ as reactiveActivityCount,qZ as pendingDeferVia,jX as exitReactiveActivity,gX as escapeRegExp,QX as enterReactiveActivity,fX as enableLatencySim,mX as disableLatencySim,BZ as default,cX as checkReactiveRegistration,LZ as __resetReactiveRegistrationForTest,HZ as __resetReactiveOfflineForTest,UZ as __resetReactiveLatencyForTest,KZ as __resetReactiveEffectsForTest,YZ as __resetReactiveDismissForTest,VZ as __markReactiveConnectedForTest,m as LATENCY_KEY,$X as ACTIVE_ATTR};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=3D36FCC8A2F9938464756E2164756E21
|
|
4
4
|
//# sourceMappingURL=reactive_controller.min.js.map
|