phlex-reactive 0.9.4 → 0.10.0
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 +84 -0
- data/README.md +49 -44
- data/app/controllers/phlex/reactive/actions_controller.rb +14 -1
- data/app/javascript/phlex/reactive/reactive_controller.js +202 -15
- 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/client_bindings.rb +57 -0
- data/lib/phlex/reactive/component/dsl.rb +37 -0
- data/lib/phlex/reactive/component/helpers.rb +183 -86
- data/lib/phlex/reactive/component/registry.rb +2 -0
- data/lib/phlex/reactive/component.rb +23 -9
- data/lib/phlex/reactive/show_conditions.rb +249 -0
- data/lib/phlex/reactive/streamable.rb +62 -50
- data/lib/phlex/reactive/test_helpers.rb +9 -1
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +3 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Controller as p}from"@hotwired/stimulus";import{confirmResolver as m}from"phlex/reactive/confirm";import{computeReducer as c}from"phlex/reactive/compute";function g(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:visit"])return;j["reactive:visit"]=function(){let Q=this.getAttribute("data-url");if(Q)window.Turbo.visit(Q,{action:"advance"})}}function d(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:token"])return;j["reactive:token"]=function(){let Q=this.getAttribute("data-reactive-token-value"),W=this.getAttribute("target");if(!Q||!W)return;let X=document.getElementById(W);if(X)X.setAttribute("data-reactive-token-value",Q)}}function l(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:js"])return;j["reactive:js"]=function(){let Q=f(this.getAttribute("data-reactive-ops"));if(!Q.length)return;let W=this.getAttribute("target"),X=W?document.getElementById(W):null;if(W&&!X)return;u(Q,(Z)=>Mj(Z,X))}}var U=new Map;function Oj(){U.clear(),P=!1}function xj(j){return U.get(j)?.via}var P=!1;function s(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:defer"])return;if(j["reactive:defer"]=function(){let Q=this.getAttribute("target");if(!Q)return;if(this.getAttribute("data-reactive-defer-via")==="stream"){n(Q,this);return}let W=this.getAttribute("data-reactive-defer-token");if(!W)return;L(Q,W)},!P&&typeof document<"u"&&document.addEventListener)P=!0,document.addEventListener("turbo:before-stream-render",o)}function o(j){let W=j.target?.getAttribute?.("target");if(!W)return;let X=W.startsWith("reactive-defer-src-")?W.slice(19):W;if(U.get(X)?.via==="stream")U.delete(X)}function L(j,Q){let W=document.getElementById(j);if(!W){console.warn(`[phlex-reactive] reactive:defer target #${j} is not on the page — skipped`);return}b(j),h(W);let X={via:"fetch",abort:new AbortController,timedOut:!1};U.set(j,X),i(j,X,Q)}function n(j,Q){let W=document.getElementById(j);if(!W){console.warn(`[phlex-reactive] reactive:defer target #${j} is not on the page — skipped`);return}let X=Q.getAttribute("data-reactive-defer-src");if(!X)return;if(!globalThis.customElements?.get?.("pgbus-stream-source")){let $=Q.getAttribute("data-reactive-defer-token");if($){L(j,$);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}b(j),h(W);let Z=document.createElement("pgbus-stream-source");Z.id=w(j),Z.setAttribute("src",X),Z.setAttribute("since-id",Q.getAttribute("data-reactive-defer-since-id")??"0"),Z.setAttribute("hidden",""),document.body.appendChild(Z),U.set(j,{via:"stream"})}function w(j){return`reactive-defer-src-${j}`}async function i(j,Q,W){let X=setTimeout(()=>{Q.timedOut=!0,Q.abort.abort()},t()),Z;try{Z=await fetch(a(),{method:"POST",headers:{Accept:"text/vnd.turbo-stream.html","Content-Type":"application/json","X-CSRF-Token":r()},body:JSON.stringify({token:W}),credentials:"same-origin",signal:Q.abort.signal})}catch(G){if(clearTimeout(X),U.get(j)!==Q)return;console.error("[phlex-reactive] deferred render failed",G),x(j,W);return}if(U.get(j)!==Q){clearTimeout(X);return}if(Z.status===204){clearTimeout(X),I(j);return}if(!Z.ok){clearTimeout(X),console.error(`[phlex-reactive] deferred render failed: HTTP ${Z.status}`),x(j,W,Z.status);return}let $;try{$=await Z.text()}catch(G){if(clearTimeout(X),U.get(j)!==Q)return;console.error("[phlex-reactive] deferred render failed reading the body",G),x(j,W);return}if(clearTimeout(X),U.get(j)!==Q)return;I(j),window.Turbo.renderStreamMessage($)}function b(j){let Q=U.get(j);if(!Q)return;if(U.delete(j),Q.via==="fetch")Q.abort.abort();else document.getElementById(w(j))?.remove?.()}function h(j){j.setAttribute("data-reactive-defer-pending","true"),j.setAttribute("aria-busy","true")}function y(j){j.removeAttribute("data-reactive-defer-pending"),j.removeAttribute("aria-busy")}function I(j){U.delete(j);let Q=document.getElementById(j);if(!Q)return;y(Q),Q.removeAttribute("data-reactive-error")}function x(j,Q,W){U.delete(j);let X=document.getElementById(j);if(!X)return;y(X),X.setAttribute("data-reactive-error","defer");let Z=()=>{let $=document.getElementById(j);if(!$){console.warn("[phlex-reactive] defer retry() ignored — the target left the DOM");return}$.removeAttribute("data-reactive-error"),L(j,Q)};X.dispatchEvent(new CustomEvent("reactive:error",{bubbles:!0,composed:!0,detail:{kind:"defer",target:j,status:W,retry:Z}}))}function a(){return document.querySelector('meta[name="phlex-reactive-defer-path"]')?.content||"/reactive/defer"}function r(){return document.querySelector('meta[name="csrf-token"]')?.content??""}function t(){let j=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Q=Number(j);return Number.isFinite(Q)&&Q>0?Q:30000}var F=!1;function e(){if(F)return;if(typeof document>"u"||!document.addEventListener)return;F=!0,document.addEventListener("turbo:before-stream-render",jj)}function jj(j){let Q=j.detail,W=Q?.render;if(typeof W!=="function"||W.__reactiveDismissWrapped){if(typeof requestAnimationFrame==="function")requestAnimationFrame(B);else setTimeout(B,0);return}let X=async(Z)=>{await W(Z),B()};X.__reactiveDismissWrapped=!0,Q.render=X}function B(){let j=document.querySelectorAll("[data-reactive-dismiss-after]");for(let Q of j){if(Q.hasAttribute("data-reactive-dismiss-scheduled"))continue;let W=Number(Q.getAttribute("data-reactive-dismiss-after"));if(!Number.isFinite(W)||W<=0)continue;Q.setAttribute("data-reactive-dismiss-scheduled",""),setTimeout(()=>Q.remove(),W)}}function Bj(){F=!1}var R=!1;function Qj(){if(R)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;R=!0;let j=()=>{let Q=document.documentElement;if(typeof Q?.toggleAttribute!=="function")return;Q.toggleAttribute("data-reactive-offline",globalThis.navigator?.onLine===!1)};j(),window.addEventListener("online",j),window.addEventListener("offline",j)}function Cj(){R=!1}var D="phlex-reactive:latency",A=!1;function Wj(j){if(typeof sessionStorage>"u")return;sessionStorage.setItem(D,String(j))}function Xj(){if(typeof sessionStorage>"u")return;sessionStorage.removeItem(D),A=!1}function Zj(){if(typeof window>"u"||typeof document>"u")return;if(document.querySelector?.('meta[name="phlex-reactive-env"]')?.content!=="development")return;window.PhlexReactive={enableLatencySim:Wj,disableLatencySim:Xj}}function Ej(){A=!1}function S(){g(),d(),l(),s(),e(),Qj(),Zj()}function $j(j){return j.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}if(typeof window<"u")if(window.Turbo)S();else document.addEventListener("turbo:load",S,{once:!0});var O=!1;function Gj(){if(O)return;if(typeof document>"u")return;let j=document.querySelectorAll('[data-controller~="reactive"]');if(!j||j.length===0)return;console.warn("[phlex-reactive] found "+j.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 Pj(){O=!1}function Fj(){O=!0}if(typeof window<"u"&&typeof document<"u"){let j=()=>setTimeout(Gj,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",j,{once:!0});else j()}var Jj=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function Kj(j){let Q=String(j).toLowerCase();return Q.startsWith("on")||Jj.has(Q)}function zj(j,Q,W){let[X,Z,$]=Q;j.classList.add(X,Z),W(),requestAnimationFrame(()=>{j.classList.remove(Z),j.classList.add($)});let G=!1,J=()=>{if(G)return;G=!0,j.classList.remove(X,$)};j.addEventListener("animationend",J,{once:!0}),setTimeout(J,350)}var k=Object.freeze({show:(j,Q)=>C(j,!1,Q),hide:(j,Q)=>C(j,!0,Q),toggle:(j,Q)=>C(j,!j.hidden,Q),add_class:(j,Q)=>j.classList.add(...Q.classes??[]),remove_class:(j,Q)=>j.classList.remove(...Q.classes??[]),toggle_class:(j,Q)=>(Q.classes??[]).forEach((W)=>j.classList.toggle(W)),set_attr:(j,Q)=>{if(E(Q.name))j.setAttribute(Q.name,Q.value??"")},remove_attr:(j,Q)=>{if(E(Q.name))j.removeAttribute(Q.name)},toggle_attr:(j,Q)=>{if(!E(Q.name))return;if(j.hasAttribute(Q.name))j.removeAttribute(Q.name);else j.setAttribute(Q.name,"")},focus:(j)=>j.focus?.(),focus_first:(j)=>_j(j)?.focus?.(),text:(j,Q)=>{let W=String(Q.value??"");if(j.textContent!==W)j.textContent=W},dispatch:(j,Q)=>{j.dispatchEvent(new CustomEvent(Q.name,{bubbles:!0,composed:!0,detail:Q.detail??{}}))}});function C(j,Q,W){if(W?.transition)zj(j,W.transition,()=>j.hidden=Q);else j.hidden=Q}function E(j){if(!Kj(j))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(j)} — skipped`),!1}var v=/^#[A-Za-z_][\w-]*$/;function Yj(j){if(typeof j==="string"&&v.test(j))return!0;return console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(j)} — skipped`),!1}function qj(j,Q){let W=j.getAttribute("data-reactive-show-equals");if(W!==null)return Q===W;let X=j.getAttribute("data-reactive-show-not");if(X!==null)return Q!==X;let Z=j.getAttribute("data-reactive-show-in");if(Z!==null){try{let $=JSON.parse(Z);if(Array.isArray($))return $.includes(Q)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(Z)} — skipped`),null}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function Hj(j,Q){if(!j||typeof j!=="object")return null;if(typeof j.equals==="string")return Q===j.equals;if(typeof j.not==="string")return Q!==j.not;if(Array.isArray(j.in))return j.in.includes(Q);return null}function Uj(j){if(typeof j==="string"&&v.test(j))return!0;return console.warn(`[phlex-reactive] refused cross-root show target ${JSON.stringify(j)} — skipped`),!1}var Vj='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function _j(j){return j.querySelectorAll?.(Vj)?.[0]??null}function f(j){if(Array.isArray(j))return j;if(typeof j!=="string")return[];try{let Q=JSON.parse(j);return Array.isArray(Q)?Q:[]}catch{return[]}}function u(j,Q){for(let W of j){if(!Array.isArray(W))continue;let[X,Z={}]=W;if(!Object.hasOwn(k,X)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(X)} — skipped`);continue}for(let $ of Q(Z))k[X]($,Z)}}function Mj(j,Q){let W=j.to;if(Q){if(W==="@root")return[Q];if(typeof W!=="string"||W==="")return[];if(j.global)return[...document.querySelectorAll(W)];return[...Q.querySelectorAll(W)]}if(typeof W!=="string"||W===""||W==="@root")return[];return[...document.querySelectorAll(W)]}class Rj extends p{static values={token:String};#R;#V=new Map;#K=new Map;#g;#L;#D;#O=0;#z=new Map;#x=new WeakMap;#_=new Map;#Y;#q;#H;#j;#W;#M;connect(){if(O=!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.#T(),this.#M=()=>this.#T(),this.element.addEventListener?.("turbo:morph-element",this.#M);if(this.#d()){if(this.#Y=()=>this.#E(),this.element.addEventListener?.("turbo:morph-element",this.#Y),this.#E(),this.element.getAttribute?.("data-reactive-warn-unsaved")==="true")this.#Yj()}if(this.#Hj())this.#j=()=>this.#f(),this.element.addEventListener?.("input",this.#j),this.element.addEventListener?.("change",this.#j),this.element.addEventListener?.("turbo:morph-element",this.#j),this.#f();if(this.#Mj())this.#W=(j)=>{if(j?.type==="input"&&!this.#Nj(j))return;this.#p()},this.element.addEventListener?.("input",this.#W),this.element.addEventListener?.("turbo:morph-element",this.#W),this.#p()}#d(){if((this.element.getAttribute?.("data-action")??"").includes("reactive#trackDirty"))return!0;let j=this.element.querySelectorAll?.('[data-action*="reactive#trackDirty"]')??[];for(let Q of j)if(this.#Q(Q))return!0;return!1}disconnect(){if(this.#r(),this.#e(),this.#qj(),this.#_j(),this.#Aj(),this.#M)this.element.removeEventListener?.("turbo:morph-element",this.#M)}#T(){let j=this.element;if(!j?.id)return;let Q=j.getAttribute?.("data-reactive-defer-token");if(!Q)return;if(j.getAttribute?.("data-reactive-defer-pending")!=="true")return;L(j.id,Q)}dispatch(j){let{action:Q,params:W,debounce:X,throttle:Z,confirm:$,outside:G,window:J,optimistic:K,loading:q}=j.params;if(!Q)return;if(G&&this.element.contains(j.target))return;let H=j.currentTarget??j.target;if(!J&&!this.#Cj(K,H))j.preventDefault();if(!$)return this.#w(H,Q,W,X,Z,K,q);Promise.resolve().then(()=>m($)).catch(()=>!1).then((z)=>{if(z)this.#w(H,Q,W,X,Z,K,q)})}runOps(j){let{ops:Q,outside:W,window:X}=j.params;if(W&&this.element.contains(j.target))return;if(!X)j.preventDefault();this.#Bj(this.#xj(Q))}trackDirty(){this.#E()}recompute(j){let Q=this.#s(),W=Q.map(([z])=>z),X=this.#U(),Z=new Map,$=(z)=>{if(Z.has(z))return Z.get(z);let Y=null;for(let _ of this.element.querySelectorAll(`[name="${z}"]`))if(X(_)){Y=_;break}return Z.set(z,Y),Y};for(let z of W)this.#S(z,$(z)?.value??"");let G=this.element.getAttribute("data-reactive-compute-reducer-param"),J=G?c(G):null;if(!J){this.#k({},$);return}let K=this.#l("data-reactive-compute-outputs-param"),q={};for(let[z,Y]of Q){let _=$(z);if(Y==="string")q[z]=_?.value??"";else{let M=Number(_?.value);q[z]=Number.isFinite(M)?M:0}}let H=J(q,{changed:this.#o(j,W)})||{};for(let z of K){if(!(z in H))continue;let Y=$(z);if(Y){if(String(H[z])===Y.value)continue;Y.value=H[z],Y.dispatchEvent(new Event("input",{bubbles:!0}))}else this.#S(z,H[z])}this.#k(H,$)}listnavNext(j){this.#I(j,1)}listnavPrev(j){this.#I(j,-1)}listnavPick(j){let Q=this.#B(j),W=Q.findIndex((X)=>X.hasAttribute("data-reactive-highlighted"));if(W<0)return;j.preventDefault(),Q[W].click()}listnavClose(j){for(let Q of this.#B(j))Q.removeAttribute("data-reactive-highlighted")}#I(j,Q){let W=this.#B(j);if(!W.length)return;j.preventDefault();let X=W.findIndex((G)=>G.hasAttribute("data-reactive-highlighted")),Z=X<0?Q>0?0:W.length-1:(X+Q+W.length)%W.length;for(let G of W)G.removeAttribute("data-reactive-highlighted");let $=W[Z];$.setAttribute("data-reactive-highlighted","true"),$.scrollIntoView?.({block:"nearest"})}#B(j){let W=(j?.currentTarget??j?.target??this.element).getAttribute?.("data-reactive-listnav-option-param")??this.element.getAttribute("data-reactive-listnav-option-param");if(!W)return[];let X=this.#U();return Array.from(this.element.querySelectorAll(W)).filter((Z)=>!Z.hidden&&X(Z))}#l(j){let Q=this.element.getAttribute(j);if(!Q)return[];try{let W=JSON.parse(Q);return Array.isArray(W)?W:[]}catch{return[]}}#s(){let j=this.element.getAttribute("data-reactive-compute-inputs-param");if(!j)return[];try{let Q=JSON.parse(j);if(Array.isArray(Q))return Q.map((W)=>[W,"number"]);if(Q&&typeof Q==="object")return Object.entries(Q);return[]}catch{return[]}}#o(j,Q){let W=j?.target;if(!W?.name||typeof W.closest!=="function")return null;if(!Q.includes(W.name))return null;return this.#Q(W)?W.name:null}#S(j,Q){let W=String(Q);for(let X of this.#n(j)){if(X.textContent===W)continue;X.textContent=W}}#n(j){let Q=this.element.querySelectorAll(`[data-reactive-text="${j}"]`);return Array.from(Q).filter((W)=>this.#Q(W))}#k(j,Q){let W=this.#i();for(let[X,Z]of Object.entries(W)){let $=X in j?j[X]:Q(X)?.value;if($===void 0||$===null)continue;let G=String($);for(let J of Array.isArray(Z)?Z:[Z]){if(!Yj(J))continue;for(let K of document.querySelectorAll(J)){if(K.textContent===G)continue;K.textContent=G}}}}#i(){let j=this.element.getAttribute("data-reactive-compute-mirror-param");if(!j)return{};try{let Q=JSON.parse(j);return Q&&typeof Q==="object"&&!Array.isArray(Q)?Q:{}}catch{return{}}}#w(j,Q,W,X,Z,$,G){if(this.#A("reactive:before-dispatch",{action:Q,params:this.#m(W),element:this.element},{cancelable:!0}).defaultPrevented)return;let K=Number(X)||0;if(K>0)return this.#a(j,K,Q,W,$,G);let q=Number(Z)||0;if(q>0)return this.#t(j,q,Q,W,$,G);return this.#N(Q,W,$,j,G)}#N(j,Q,W,X,Z){let $=this.#Ej(W,X),G=this.#Fj(j,X,Z);return this.queue=(this.queue??Promise.resolve()).then(()=>this.#Gj(j,Q,$,G)),this.queue}#a(j,Q,W,X,Z,$){this.#C(j);let G=()=>{this.#C(j),this.#N(W,X,Z,j,$)},J=setTimeout(G,Q);j?.addEventListener?.("blur",G,{once:!0}),this.#V.set(j,{timer:J,flush:G})}#C(j){let Q=this.#V.get(j);if(!Q)return;clearTimeout(Q.timer),j?.removeEventListener?.("blur",Q.flush),this.#V.delete(j)}#r(){for(let j of[...this.#V.keys()])this.#C(j)}#t(j,Q,W,X,Z,$){let G=this.#K.get(j)??new Map;if(G.has(W))return;let J=setTimeout(()=>{if(G.delete(W),G.size===0)this.#K.delete(j)},Q);return G.set(W,J),this.#K.set(j,G),this.#N(W,X,Z,j,$)}#e(){for(let j of this.#K.values())for(let Q of j.values())clearTimeout(Q);this.#K.clear()}#A(j,Q,{cancelable:W=!1}={}){let X=new CustomEvent(j,{bubbles:!0,composed:!0,cancelable:W,detail:Q});return(this.element.isConnected?this.element:document).dispatchEvent(X),X}#X(j,Q,W,X){let Z=()=>{if(!this.element.isConnected){console.warn("[phlex-reactive] retry() ignored — the reactive root left the DOM");return}return this.#N(j,Q)};this.#A("reactive:error",{action:j,params:W,...X,retry:Z})}#Z(j){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",j)}#jj(){this.element?.removeAttribute?.("data-reactive-error")}#Qj(){let j=document.querySelector("[data-reactive-error-flash]");if(!j?.content)return;let Q=j.getAttribute("data-reactive-error-flash")||"flash",W=document.getElementById(Q);if(!W)return;W.appendChild(j.content.cloneNode(!0))}#Wj(){if(typeof sessionStorage>"u")return Promise.resolve();let j=Number(sessionStorage.getItem(D));if(!Number.isFinite(j)||j<=0)return Promise.resolve();if(!A)A=!0,console.warn(`[phlex-reactive] latency simulator ACTIVE — every action is delayed by ${j}ms. Call PhlexReactive.disableLatencySim() (or clear sessionStorage) to turn it off.`);return new Promise((Q)=>setTimeout(Q,j))}#Xj(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#b(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}#Zj(j){if(!j)return[];let Q=[],W=/<turbo-stream\b([^>]*)>/g,X;while((X=W.exec(j))!==null){let Z=X[1],$=Z.match(/\baction="([^"]*)"/)?.[1]??"?",G=Z.match(/\btarget="([^"]*)"/)?.[1];Q.push(G?`${$} → #${G}`:$)}return Q}#$j(j){let{action:Q,status:W,ms:X}=j,$=`reactive ${this.element?.id?`#${this.element.id} `:""}${Q} → ${W??"—"} (${Math.round(X)}ms)`;if(console.groupCollapsed($),console.log(`params: [${j.paramNames.join(", ")}] + collected: [${j.fieldNames.join(", ")}]`),console.log(`encoding: ${j.encoding}`),j.streams.length)console.log(`streams: ${j.streams.join(" ")}`);console.log(`token: ${j.tokenRefreshed?"refreshed ✓":"unchanged"}`),console.groupEnd()}async#Gj(j,Q,W,X){let{fields:Z,files:$}=this.#Kj(),G=this.#m(Q),J={...Z,...G},K=this.#$,q=$.length>0,H=q?this.#Lj(K,j,J,$):JSON.stringify({token:K,act:j,params:J}),z=this.#Xj()?{action:j,paramNames:Object.keys(G),fieldNames:Object.keys(Z),encoding:q?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#b()}:null;await this.#Wj();try{if(navigator.onLine===!1){this.#G(W),this.#Z("offline"),this.#X(j,Q,J,{kind:"offline"});return}let Y;try{let V={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#bj()};if(!q)V["Content-Type"]="application/json";let N=this.#hj();if(N)V["X-Pgbus-Connection"]=N;Y=await fetch(this.#kj(),{method:"POST",headers:V,body:H,credentials:"same-origin",signal:AbortSignal.timeout(this.#wj())})}catch(V){if(console.error("[phlex-reactive] action error",V),this.#G(W),V?.name==="TimeoutError"||V?.name==="AbortError"){this.#Z("timeout"),this.#X(j,Q,J,{kind:"timeout"});return}this.#Qj(),this.#Z("network"),this.#X(j,Q,J,{kind:"network"});return}if(z)z.status=Y.status;if(Y.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#G(W),this.#Z("redirected"),this.#X(j,Q,J,{kind:"redirected",status:Y.status});return}if(!Y.ok){let V=await Y.text();if(console.error(`[phlex-reactive] action failed: HTTP ${Y.status}`,V),this.#G(W),(Y.headers.get("Content-Type")||"").includes("turbo-stream")){let N=this.#y(V);if(this.#$=N??this.#$,z)this.#h(z,V,N);window.Turbo.renderStreamMessage(V)}this.#Z("http"),this.#X(j,Q,J,{kind:"http",status:Y.status,body:V});return}let _=Y.headers.get("Content-Type")||"";if(!_.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${_}" — no update applied`),this.#G(W),this.#Z("content-type"),this.#X(j,Q,J,{kind:"content-type",status:Y.status});return}let M=await Y.text(),T=this.#y(M);if(this.#$=T??this.#$,z)this.#h(z,M,T);window.Turbo.renderStreamMessage(M),this.#jj(),this.#A("reactive:applied",{action:j,params:J,html:M})}catch(Y){console.error("[phlex-reactive] action error",Y),this.#G(W),this.#A("reactive:error",{action:j,params:J,kind:"apply"})}finally{if(X?.(),z)this.#$j({...z,ms:this.#b()-z.started})}}#h(j,Q,W){j.streams=this.#Zj(Q),j.tokenRefreshed=W!=null}get#$(){return this.#R??this.tokenValue}set#$(j){this.#R=j}#y(j){let Q=this.element.id;if(!Q)return j.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:W,self:X}=this.#Jj(Q),Z=j.match(W);if(Z)return Z[1];let $=j.match(X);if($)return $[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#Jj(j){let Q=this.#D;if(Q&&Q.id===j)return Q;let W=$j(j);return this.#D={id:j,token:new RegExp(`<turbo-stream\\b[^>]*\\baction="reactive:token"[^>]*\\btarget="${W}"[^>]*\\bdata-reactive-token-value="([^"]+)"`),self:new RegExp(`<turbo-stream\\b[^>]*\\baction="(?:replace|update)"[^>]*\\btarget="${W}"[^>]*>([\\s\\S]*?)</turbo-stream>`)}}#Q(j){return j.closest('[data-controller~="reactive"]')===this.element}#U(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(Q)=>this.#Q(Q)}#Kj(){let j={},Q=[],W=this.#U();return this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((X)=>{if(!W(X))return;if(X.type==="file")for(let Z of X.files??[])Q.push({name:X.name,file:Z,multiple:X.multiple});else if(X.type==="checkbox")j[X.name]=X.checked;else if(X.type==="radio"){if(X.checked)j[X.name]=X.value}else j[X.name]=X.value}),this.element.querySelectorAll("[name]:is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])").forEach((X)=>{if(!W(X))return;let Z=X.getAttribute("name");if(!Z)return;let $=j[Z];if($==null||$==="")j[Z]=X.value??X.textContent??X.innerHTML??""}),{fields:j,files:Q}}#E(){if(typeof this.element?.querySelectorAll!=="function")return;let j=0;if(this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Q)=>{if(!this.#Q(Q))return;if(Q.type==="file")return;if(this.#zj(Q))Q.setAttribute("data-reactive-dirty","true"),j++;else Q.removeAttribute("data-reactive-dirty")}),j>0)this.element.setAttribute("data-reactive-dirty",String(j));else this.element.removeAttribute("data-reactive-dirty")}#zj(j){if(j.type==="checkbox"||j.type==="radio")return j.checked!==j.defaultChecked;if(j.tag==="select"||j.options)return Array.from(j.options??[]).some((Q)=>Q.selected!==Q.defaultSelected);return j.value!==j.defaultValue}#v(){let j=this.element.getAttribute?.("data-reactive-dirty"),Q=Number(j);return Number.isFinite(Q)&&Q>0?Q:0}#Yj(){if(typeof window>"u"||typeof window.addEventListener!=="function")return;this.#q=(j)=>{if(this.#v()===0)return;return j.preventDefault(),j.returnValue="You have unsaved changes.",j.returnValue},this.#H=(j)=>{if(this.#v()===0)return;if(!(typeof window.confirm==="function"?window.confirm("You have unsaved changes. Leave anyway?"):!0))j.preventDefault?.()},window.addEventListener("beforeunload",this.#q),window.addEventListener("turbo:before-visit",this.#H)}#qj(){if(this.#Y)this.element.removeEventListener?.("turbo:morph-element",this.#Y),this.#Y=void 0;if(typeof window<"u"&&typeof window.removeEventListener==="function"){if(this.#q)window.removeEventListener("beforeunload",this.#q);if(this.#H)window.removeEventListener("turbo:before-visit",this.#H)}this.#q=void 0,this.#H=void 0}#Hj(){if(this.element.getAttribute?.("data-reactive-show-targets"))return!0;let j=this.element.querySelectorAll?.("[data-reactive-show-field]")??[];for(let Q of j)if(this.#Q(Q))return!0;return!1}#f(){if(typeof this.element?.querySelectorAll!=="function")return;let j=this.#U(),Q=new Map;for(let W of this.element.querySelectorAll("[data-reactive-show-field]")){if(!j(W))continue;let X=W.getAttribute("data-reactive-show-field");if(!X)continue;if(!Q.has(X))Q.set(X,this.#u(X,j));let Z=Q.get(X);if(Z===null)continue;let $=qj(W,Z);if($===null)continue;W.hidden=!$}this.#Uj(j,Q)}#Uj(j,Q){let W=this.#Vj();for(let[X,Z]of Object.entries(W)){if(!Z||typeof Z!=="object"||Array.isArray(Z))continue;if(!Q.has(X))Q.set(X,this.#u(X,j));let $=Q.get(X);if($===null)continue;for(let[G,J]of Object.entries(Z)){if(!Uj(G))continue;let K=Hj(J,$);if(K===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${G} — skipped`);continue}for(let q of document.querySelectorAll(G))q.hidden=!K}}}#Vj(){let j=this.element.getAttribute?.("data-reactive-show-targets");if(!j)return{};try{let Q=JSON.parse(j);if(Q&&typeof Q==="object"&&!Array.isArray(Q))return Q}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: { ... })"),{}}#u(j,Q){let W=!1,X=null;for(let Z of this.element.querySelectorAll(`[name="${j}"]`)){if(!Q(Z))continue;if(Z.type==="checkbox")return Z.checked?"true":"false";if(Z.type==="radio"){if(Z.checked)return Z.value??"";W=!0;continue}X??=Z}if(X)return X.value??"";return W?"":null}#_j(){if(!this.#j)return;this.element.removeEventListener?.("input",this.#j),this.element.removeEventListener?.("change",this.#j),this.element.removeEventListener?.("turbo:morph-element",this.#j),this.#j=void 0}#Mj(){return!!(this.element.getAttribute?.("data-reactive-filter-input")&&this.element.getAttribute?.("data-reactive-filter-option"))}#Nj(j){let Q=this.element.getAttribute("data-reactive-filter-input");return!!Q&&typeof j.target?.matches==="function"&&j.target.matches(Q)}#p(){if(typeof this.element?.querySelectorAll!=="function")return;let j=this.element.getAttribute("data-reactive-filter-input"),Q=this.element.getAttribute("data-reactive-filter-option");if(!j||!Q)return;let W=this.#U(),X=[...this.element.querySelectorAll(j)].find(W);if(!X)return;let Z=(X.value??"").trim().toLowerCase(),$=0;for(let K of this.element.querySelectorAll(Q)){if(!W(K))continue;let q=(K.getAttribute("data-reactive-filter-text")??K.textContent??"").toLowerCase(),H=Z!==""&&!q.includes(Z);if(K.hidden=H,H)K.removeAttribute("data-reactive-highlighted");else $++}let G=this.element.getAttribute("data-reactive-filter-group");if(G)for(let K of this.element.querySelectorAll(G)){if(!W(K))continue;let q=[...K.querySelectorAll(Q)].filter(W);if(q.length===0)continue;K.hidden=q.every((H)=>H.hidden)}let J=this.element.getAttribute("data-reactive-filter-empty");if(J){for(let K of this.element.querySelectorAll(J))if(W(K))K.hidden=$>0}}#Aj(){if(!this.#W)return;this.element.removeEventListener?.("input",this.#W),this.element.removeEventListener?.("turbo:morph-element",this.#W),this.#W=void 0}#Lj(j,Q,W,X){let Z=new FormData;Z.append("token",j),Z.append("act",Q);for(let[G,J]of Object.entries(W))this.#P(Z,`params[${G}]`,J);let $=this.#Oj(X);for(let{name:G,file:J,multiple:K}of X){let H=K||$.has(G)?`params[${G}][]`:`params[${G}]`;Z.append(H,J,J.name)}return Z}#P(j,Q,W){if(W==null)j.append(Q,"");else if(Array.isArray(W))W.forEach((X,Z)=>this.#P(j,`${Q}[${Z}]`,X));else if(typeof W==="object")for(let[X,Z]of Object.entries(W))this.#P(j,`${Q}[${X}]`,Z);else j.append(Q,String(W))}#Oj(j){let Q=new Map;for(let{name:W}of j)Q.set(W,(Q.get(W)??0)+1);return new Set([...Q].filter(([,W])=>W>1).map(([W])=>W))}#m(j){if(!j)return{};try{return typeof j==="string"?JSON.parse(j):j}catch{return{}}}#xj(j){return f(j)}#Bj(j){u(j,(Q)=>this.#F(Q))}#F(j){let Q=j.to;if(Q==="@root")return[this.element];if(typeof Q!=="string"||Q==="")return[];if(j.global)return[...document.querySelectorAll(Q)];return[...this.element.querySelectorAll(Q)].filter((W)=>this.#Q(W))}#Cj(j,Q){if(j?.checked!=="keep")return!1;let W=Q?.type;return W==="checkbox"||W==="radio"}#Ej(j,Q){if(!j)return null;let W=this.#Pj(j,Q),X=[];for(let Z of W){if(j.add_class){let $=j.add_class.filter((G)=>!Z.classList.contains(G));if(Z.classList.add(...$),$.length)X.push(()=>Z.classList.remove(...$))}if(j.remove_class){let $=j.remove_class.filter((G)=>Z.classList.contains(G));if(Z.classList.remove(...$),$.length)X.push(()=>Z.classList.add(...$))}if(j.toggle_class)j.toggle_class.forEach(($)=>Z.classList.toggle($)),X.push(()=>j.toggle_class.forEach(($)=>Z.classList.toggle($)));if(j.hide)Z.hidden=!0,X.push(()=>Z.hidden=!1)}if(j.checked==="keep"&&Q&&"checked"in Q){let Z=Q.checked;X.push(()=>Q.checked=!Z)}return X.length?X:null}#G(j){if(!j)return;if(!this.element.isConnected)return;for(let Q of j)Q()}#Pj(j,Q){if(j.to==null)return Q?[Q]:[];return this.#F({to:j.to})}#Fj(j,Q,W){this.#Rj(j,Q);let X=this.#Tj(j,Q,W),Z=!1;return()=>{if(Z)return;Z=!0,this.#Dj(j,Q),X()}}#Rj(j,Q){if(this.#J(Q,j,1),this.#J(this.element,j,1),this.#z.set(j,(this.#z.get(j)??0)+1),this.#O++===0)this.element.setAttribute("aria-busy","true");for(let W of this.#c(j))this.#J(W,j,1)}#Dj(j,Q){this.#J(Q,j,-1),this.#J(this.element,j,-1);let W=(this.#z.get(j)??1)-1;if(W<=0)this.#z.delete(j);else this.#z.set(j,W);if(--this.#O<=0)this.#O=0,this.element.removeAttribute("aria-busy");for(let X of this.#c(j))this.#J(X,j,-1)}#J(j,Q,W){if(!j||typeof j.getAttribute!=="function")return;let X=this.#x.get(j)??new Map,Z=(X.get(Q)??0)+W;if(Z<=0)X.delete(Q);else X.set(Q,Z);if(X.size===0){this.#x.delete(j),j.removeAttribute("data-reactive-busy");return}this.#x.set(j,X),j.setAttribute("data-reactive-busy",[...X.keys()].join(" "))}#c(j){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((W)=>W.getAttribute("data-reactive-busy-on")===j&&this.#Q(W))}#Tj(j,Q,W){if(!W||!Q)return()=>{};let X=this.#Sj(W,Q),Z=Array.isArray(W.class)?W.class:[],$=[];for(let J of X){let K=Z.filter((q)=>!J.classList.contains(q));if(J.classList.add(...K),K.length)$.push([J,K])}let G=this.#_.get(Q);if(G)G.count++;else if(W.disable||W.text!=null)this.#_.set(Q,{count:1,disabled:Q.disabled,text:Q.textContent,hadText:W.text!=null});if(W.disable)Q.disabled=!0;if(W.text!=null)Q.textContent=W.text;return()=>{for(let[J,K]of $)if(J.isConnected)J.classList.remove(...K);this.#Ij(Q,W)}}#Ij(j,Q){let W=this.#_.get(j);if(!W)return;if(--W.count>0)return;if(this.#_.delete(j),!j.isConnected)return;if(Q.disable)j.disabled=W.disabled;if(W.hadText&&j.textContent===Q.text)j.textContent=W.text}#Sj(j,Q){if(j.to==null)return Q?[Q]:[];return this.#F({to:j.to})}#kj(){return this.#g??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#wj(){if(this.#L!=null)return this.#L;let j=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Q=Number(j);return this.#L=Number.isFinite(Q)&&Q>0?Q:30000}#bj(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#hj(){return document.querySelector("pgbus-stream-source[connection-id]")?.getAttribute("connection-id")||document.querySelector('meta[name="pgbus-connection-id"]')?.content||null}}export{Oj as resetReactiveDefers,g as registerReactiveVisit,d as registerReactiveToken,Qj as registerReactiveOffline,l as registerReactiveJs,e as registerReactiveDismiss,s as registerReactiveDefer,S as registerReactiveActions,xj as pendingDeferVia,$j as escapeRegExp,Wj as enableLatencySim,Xj as disableLatencySim,Rj as default,Gj as checkReactiveRegistration,Pj as __resetReactiveRegistrationForTest,Cj as __resetReactiveOfflineForTest,Ej as __resetReactiveLatencyForTest,Bj as __resetReactiveDismissForTest,Fj as __markReactiveConnectedForTest,D as LATENCY_KEY};
|
|
1
|
+
import{Controller as l}from"@hotwired/stimulus";import{confirmResolver as s}from"phlex/reactive/confirm";import{computeReducer as o}from"phlex/reactive/compute";function n(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:visit"])return;j["reactive:visit"]=function(){let Q=this.getAttribute("data-url");if(Q)window.Turbo.visit(Q,{action:"advance"})}}function i(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:token"])return;j["reactive:token"]=function(){let Q=this.getAttribute("data-reactive-token-value"),X=this.getAttribute("target");if(!Q||!X)return;let Z=document.getElementById(X);if(Z)Z.setAttribute("data-reactive-token-value",Q)}}function a(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:js"])return;j["reactive:js"]=function(){let Q=g(this.getAttribute("data-reactive-ops"));if(!Q.length)return;let X=this.getAttribute("target"),Z=X?document.getElementById(X):null;if(X&&!Z)return;d(Q,($)=>Pj($,Z))}}var H=new Map;function Dj(){H.clear(),E=!1}function Tj(j){return H.get(j)?.via}var E=!1;function r(){let j=window.Turbo?.StreamActions;if(!j||j["reactive:defer"])return;if(j["reactive:defer"]=function(){let Q=this.getAttribute("target");if(!Q)return;if(this.getAttribute("data-reactive-defer-via")==="stream"){e(Q,this);return}let X=this.getAttribute("data-reactive-defer-token");if(!X)return;M(Q,X)},!E&&typeof document<"u"&&document.addEventListener)E=!0,document.addEventListener("turbo:before-stream-render",t)}function t(j){let X=j.target?.getAttribute?.("target");if(!X)return;let Z=X.startsWith("reactive-defer-src-")?X.slice(19):X;if(H.get(Z)?.via==="stream")H.delete(Z)}function M(j,Q){let X=document.getElementById(j);if(!X){console.warn(`[phlex-reactive] reactive:defer target #${j} is not on the page — skipped`);return}y(j),v(X);let Z={via:"fetch",abort:new AbortController,timedOut:!1};H.set(j,Z),jj(j,Z,Q)}function e(j,Q){let X=document.getElementById(j);if(!X){console.warn(`[phlex-reactive] reactive:defer target #${j} is not on the page — skipped`);return}let Z=Q.getAttribute("data-reactive-defer-src");if(!Z)return;if(!globalThis.customElements?.get?.("pgbus-stream-source")){let J=Q.getAttribute("data-reactive-defer-token");if(J){M(j,J);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}y(j),v(X);let $=document.createElement("pgbus-stream-source");$.id=h(j),$.setAttribute("src",Z),$.setAttribute("since-id",Q.getAttribute("data-reactive-defer-since-id")??"0"),$.setAttribute("hidden",""),document.body.appendChild($),H.set(j,{via:"stream"})}function h(j){return`reactive-defer-src-${j}`}async function jj(j,Q,X){let Z=setTimeout(()=>{Q.timedOut=!0,Q.abort.abort()},Zj()),$;try{$=await fetch(Qj(),{method:"POST",headers:{Accept:"text/vnd.turbo-stream.html","Content-Type":"application/json","X-CSRF-Token":Xj()},body:JSON.stringify({token:X}),credentials:"same-origin",signal:Q.abort.signal})}catch(G){if(clearTimeout(Z),H.get(j)!==Q)return;console.error("[phlex-reactive] deferred render failed",G),O(j,X);return}if(H.get(j)!==Q){clearTimeout(Z);return}if($.status===204){clearTimeout(Z),S(j);return}if(!$.ok){clearTimeout(Z),console.error(`[phlex-reactive] deferred render failed: HTTP ${$.status}`),O(j,X,$.status);return}let J;try{J=await $.text()}catch(G){if(clearTimeout(Z),H.get(j)!==Q)return;console.error("[phlex-reactive] deferred render failed reading the body",G),O(j,X);return}if(clearTimeout(Z),H.get(j)!==Q)return;S(j),window.Turbo.renderStreamMessage(J)}function y(j){let Q=H.get(j);if(!Q)return;if(H.delete(j),Q.via==="fetch")Q.abort.abort();else document.getElementById(h(j))?.remove?.()}function v(j){j.setAttribute("data-reactive-defer-pending","true"),j.setAttribute("aria-busy","true")}function f(j){j.removeAttribute("data-reactive-defer-pending"),j.removeAttribute("aria-busy")}function S(j){H.delete(j);let Q=document.getElementById(j);if(!Q)return;f(Q),Q.removeAttribute("data-reactive-error")}function O(j,Q,X){H.delete(j);let Z=document.getElementById(j);if(!Z)return;f(Z),Z.setAttribute("data-reactive-error","defer");let $=()=>{let J=document.getElementById(j);if(!J){console.warn("[phlex-reactive] defer retry() ignored — the target left the DOM");return}J.removeAttribute("data-reactive-error"),M(j,Q)};Z.dispatchEvent(new CustomEvent("reactive:error",{bubbles:!0,composed:!0,detail:{kind:"defer",target:j,status:X,retry:$}}))}function Qj(){return document.querySelector('meta[name="phlex-reactive-defer-path"]')?.content||"/reactive/defer"}function Xj(){return document.querySelector('meta[name="csrf-token"]')?.content??""}function Zj(){let j=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Q=Number(j);return Number.isFinite(Q)&&Q>0?Q:30000}var F=!1;function $j(){if(F)return;if(typeof document>"u"||!document.addEventListener)return;F=!0,document.addEventListener("turbo:before-stream-render",Jj)}function Jj(j){let Q=j.detail,X=Q?.render;if(typeof X!=="function"||X.__reactiveDismissWrapped){if(typeof requestAnimationFrame==="function")requestAnimationFrame(B);else setTimeout(B,0);return}let Z=async($)=>{await X($),B()};Z.__reactiveDismissWrapped=!0,Q.render=Z}function B(){let j=document.querySelectorAll("[data-reactive-dismiss-after]");for(let Q of j){if(Q.hasAttribute("data-reactive-dismiss-scheduled"))continue;let X=Number(Q.getAttribute("data-reactive-dismiss-after"));if(!Number.isFinite(X)||X<=0)continue;Q.setAttribute("data-reactive-dismiss-scheduled",""),setTimeout(()=>Q.remove(),X)}}function Ij(){F=!1}var R=!1;function Gj(){if(R)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;R=!0;let j=()=>{let Q=document.documentElement;if(typeof Q?.toggleAttribute!=="function")return;Q.toggleAttribute("data-reactive-offline",globalThis.navigator?.onLine===!1)};j(),window.addEventListener("online",j),window.addEventListener("offline",j)}function Sj(){R=!1}var D="phlex-reactive:latency",L=!1;function Wj(j){if(typeof sessionStorage>"u")return;sessionStorage.setItem(D,String(j))}function zj(){if(typeof sessionStorage>"u")return;sessionStorage.removeItem(D),L=!1}function Kj(){if(typeof window>"u"||typeof document>"u")return;if(document.querySelector?.('meta[name="phlex-reactive-env"]')?.content!=="development")return;window.PhlexReactive={enableLatencySim:Wj,disableLatencySim:zj}}function kj(){L=!1}function k(){n(),i(),a(),r(),$j(),Gj(),Kj()}function qj(j){return j.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}if(typeof window<"u")if(window.Turbo)k();else document.addEventListener("turbo:load",k,{once:!0});var x=!1;function Yj(){if(x)return;if(typeof document>"u")return;let j=document.querySelectorAll('[data-controller~="reactive"]');if(!j||j.length===0)return;console.warn("[phlex-reactive] found "+j.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 bj(){x=!1}function wj(){x=!0}if(typeof window<"u"&&typeof document<"u"){let j=()=>setTimeout(Yj,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",j,{once:!0});else j()}var Uj=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function Hj(j){let Q=String(j).toLowerCase();return Q.startsWith("on")||Uj.has(Q)}function Aj(j,Q,X){let[Z,$,J]=Q;j.classList.add(Z,$),X(),requestAnimationFrame(()=>{j.classList.remove($),j.classList.add(J)});let G=!1,W=()=>{if(G)return;G=!0,j.classList.remove(Z,J)};j.addEventListener("animationend",W,{once:!0}),setTimeout(W,350)}var b=Object.freeze({show:(j,Q)=>C(j,!1,Q),hide:(j,Q)=>C(j,!0,Q),toggle:(j,Q)=>C(j,!j.hidden,Q),add_class:(j,Q)=>j.classList.add(...Q.classes??[]),remove_class:(j,Q)=>j.classList.remove(...Q.classes??[]),toggle_class:(j,Q)=>(Q.classes??[]).forEach((X)=>j.classList.toggle(X)),set_attr:(j,Q)=>{if(P(Q.name))j.setAttribute(Q.name,Q.value??"")},remove_attr:(j,Q)=>{if(P(Q.name))j.removeAttribute(Q.name)},toggle_attr:(j,Q)=>{if(!P(Q.name))return;if(j.hasAttribute(Q.name))j.removeAttribute(Q.name);else j.setAttribute(Q.name,"")},focus:(j)=>j.focus?.(),focus_first:(j)=>Cj(j)?.focus?.(),text:(j,Q)=>{let X=String(Q.value??"");if(j.textContent!==X)j.textContent=X},dispatch:(j,Q)=>{j.dispatchEvent(new CustomEvent(Q.name,{bubbles:!0,composed:!0,detail:Q.detail??{}}))}});function C(j,Q,X){if(X?.transition)Aj(j,X.transition,()=>j.hidden=Q);else j.hidden=Q}function P(j){if(!Hj(j))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(j)} — skipped`),!1}var u=/^#[A-Za-z_][\w-]*$/;function _j(j){if(typeof j==="string"&&u.test(j))return!0;return console.warn(`[phlex-reactive] refused cross-root mirror target ${JSON.stringify(j)} — skipped`),!1}function Nj(j,Q){let X=j.getAttribute("data-reactive-show-equals");if(X!==null)return Q===X;let Z=j.getAttribute("data-reactive-show-not");if(Z!==null)return Q!==Z;let $=j.getAttribute("data-reactive-show-in");if($!==null){try{let J=JSON.parse($);if(Array.isArray(J))return J.includes(Q)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify($)} — skipped`),null}for(let J of p){let G=j.getAttribute(`data-reactive-show-${J}`);if(G!==null)return m(J,G,Q)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}var p=["gte","gt","lte","lt"];function m(j,Q,X){let Z=Number(Q);if(Number.isNaN(Z))return console.warn(`[phlex-reactive] reactive_show ${j}: needs a numeric literal, got ${JSON.stringify(Q)} — skipped`),null;let $=X==null?"":String(X).trim(),J=$===""?NaN:Number($);if(Number.isNaN(J))return!1;switch(j){case"gte":return J>=Z;case"gt":return J>Z;case"lte":return J<=Z;case"lt":return J<Z;default:return null}}function c(j,Q){if(!j||typeof j!=="object")return null;if(typeof j.equals==="string")return Q===j.equals;if(typeof j.not==="string")return Q!==j.not;if(Array.isArray(j.in))return j.in.includes(Q);for(let X of p)if(X in j)return m(X,j[X],Q);return null}var w="[data-reactive-show-field], [data-reactive-show]";function Vj(j){try{let Q=JSON.parse(j);if(Q&&typeof Q==="object"&&!Array.isArray(Q))return Q}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(j)} — skipped`),null}function T(j,Q){if(!j||typeof j!=="object"||typeof j.field!=="string")return!1;let X=Q(j.field)??"";return c(j,X)===!0}function Lj(j,Q){if(!Array.isArray(j)||j.length===0)return null;return j.some((X)=>Array.isArray(X)&&X.length>0&&X.every((Z)=>T(Z,Q)))}function Mj(j,Q){if(!j||typeof j!=="object")return null;let X=j.any;if(Array.isArray(X)&&(X.length===0||Array.isArray(X[0])))return Lj(X,Q);return xj(j,Q)}function xj(j,Q){let X=Array.isArray(j.all)?"all":Array.isArray(j.any)?"any":null;if(!X)return null;let Z=j[X];if(Z.length===0)return null;let $=Z.map((J)=>T(J,Q));return X==="all"?$.every(Boolean):$.some(Boolean)}function Oj(j){if(typeof j==="string"&&u.test(j))return!0;return console.warn(`[phlex-reactive] refused cross-root show target ${JSON.stringify(j)} — skipped`),!1}var Bj='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function Cj(j){return j.querySelectorAll?.(Bj)?.[0]??null}function g(j){if(Array.isArray(j))return j;if(typeof j!=="string")return[];try{let Q=JSON.parse(j);return Array.isArray(Q)?Q:[]}catch{return[]}}function d(j,Q){for(let X of j){if(!Array.isArray(X))continue;let[Z,$={}]=X;if(!Object.hasOwn(b,Z)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(Z)} — skipped`);continue}for(let J of Q($))b[Z](J,$)}}function Pj(j,Q){let X=j.to;if(Q){if(X==="@root")return[Q];if(typeof X!=="string"||X==="")return[];if(j.global)return[...document.querySelectorAll(X)];return[...Q.querySelectorAll(X)]}if(typeof X!=="string"||X===""||X==="@root")return[];return[...document.querySelectorAll(X)]}class hj extends l{static values={token:String};#R;#A=new Map;#z=new Map;#d;#M;#D;#x=0;#K=new Map;#O=new WeakMap;#_=new Map;#q;#Y;#U;#j;#X;#N;connect(){if(x=!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.#T(),this.#N=()=>this.#T(),this.element.addEventListener?.("turbo:morph-element",this.#N);if(this.#l()){if(this.#q=()=>this.#P(),this.element.addEventListener?.("turbo:morph-element",this.#q),this.#P(),this.element.getAttribute?.("data-reactive-warn-unsaved")==="true")this.#Yj()}if(this.#Hj())this.#j=()=>this.#f(),this.element.addEventListener?.("input",this.#j),this.element.addEventListener?.("change",this.#j),this.element.addEventListener?.("turbo:morph-element",this.#j),this.#f();if(this.#Vj())this.#X=(j)=>{if(j?.type==="input"&&!this.#Lj(j))return;this.#m()},this.element.addEventListener?.("input",this.#X),this.element.addEventListener?.("turbo:morph-element",this.#X),this.#m()}#l(){if((this.element.getAttribute?.("data-action")??"").includes("reactive#trackDirty"))return!0;let j=this.element.querySelectorAll?.('[data-action*="reactive#trackDirty"]')??[];for(let Q of j)if(this.#Q(Q))return!0;return!1}disconnect(){if(this.#t(),this.#jj(),this.#Uj(),this.#Nj(),this.#Mj(),this.#N)this.element.removeEventListener?.("turbo:morph-element",this.#N)}#T(){let j=this.element;if(!j?.id)return;let Q=j.getAttribute?.("data-reactive-defer-token");if(!Q)return;if(j.getAttribute?.("data-reactive-defer-pending")!=="true")return;M(j.id,Q)}dispatch(j){let{action:Q,params:X,debounce:Z,throttle:$,confirm:J,outside:G,window:W,optimistic:z,loading:q}=j.params;if(!Q)return;if(G&&this.element.contains(j.target))return;let U=j.currentTarget??j.target;if(!W&&!this.#Pj(z,U))j.preventDefault();if(!J)return this.#b(U,Q,X,Z,$,z,q);Promise.resolve().then(()=>s(J)).catch(()=>!1).then((K)=>{if(K)this.#b(U,Q,X,Z,$,z,q)})}runOps(j){let{ops:Q,outside:X,window:Z}=j.params;if(X&&this.element.contains(j.target))return;if(!Z)j.preventDefault();this.#Cj(this.#Bj(Q))}trackDirty(){this.#P()}recompute(j){let Q=this.#o(),X=Q.map(([K])=>K),Z=this.#H(),$=new Map,J=(K)=>{if($.has(K))return $.get(K);let Y=null;for(let _ of this.element.querySelectorAll(`[name="${K}"]`))if(Z(_)){Y=_;break}return $.set(K,Y),Y};for(let K of X)this.#S(K,J(K)?.value??"");let G=this.element.getAttribute("data-reactive-compute-reducer-param"),W=G?o(G):null;if(!W){this.#k({},J);return}let z=this.#s("data-reactive-compute-outputs-param"),q={};for(let[K,Y]of Q){let _=J(K);if(Y==="string")q[K]=_?.value??"";else{let N=Number(_?.value);q[K]=Number.isFinite(N)?N:0}}let U=W(q,{changed:this.#n(j,X)})||{};for(let K of z){if(!(K in U))continue;let Y=J(K);if(Y){if(String(U[K])===Y.value)continue;Y.value=U[K],Y.dispatchEvent(new Event("input",{bubbles:!0}))}else this.#S(K,U[K])}this.#k(U,J)}listnavNext(j){this.#I(j,1)}listnavPrev(j){this.#I(j,-1)}listnavPick(j){let Q=this.#B(j),X=Q.findIndex((Z)=>Z.hasAttribute("data-reactive-highlighted"));if(X<0)return;j.preventDefault(),Q[X].click()}listnavClose(j){for(let Q of this.#B(j))Q.removeAttribute("data-reactive-highlighted")}#I(j,Q){let X=this.#B(j);if(!X.length)return;j.preventDefault();let Z=X.findIndex((G)=>G.hasAttribute("data-reactive-highlighted")),$=Z<0?Q>0?0:X.length-1:(Z+Q+X.length)%X.length;for(let G of X)G.removeAttribute("data-reactive-highlighted");let J=X[$];J.setAttribute("data-reactive-highlighted","true"),J.scrollIntoView?.({block:"nearest"})}#B(j){let X=(j?.currentTarget??j?.target??this.element).getAttribute?.("data-reactive-listnav-option-param")??this.element.getAttribute("data-reactive-listnav-option-param");if(!X)return[];let Z=this.#H();return Array.from(this.element.querySelectorAll(X)).filter(($)=>!$.hidden&&Z($))}#s(j){let Q=this.element.getAttribute(j);if(!Q)return[];try{let X=JSON.parse(Q);return Array.isArray(X)?X:[]}catch{return[]}}#o(){let j=this.element.getAttribute("data-reactive-compute-inputs-param");if(!j)return[];try{let Q=JSON.parse(j);if(Array.isArray(Q))return Q.map((X)=>[X,"number"]);if(Q&&typeof Q==="object")return Object.entries(Q);return[]}catch{return[]}}#n(j,Q){let X=j?.target;if(!X?.name||typeof X.closest!=="function")return null;if(!Q.includes(X.name))return null;return this.#Q(X)?X.name:null}#S(j,Q){let X=String(Q);for(let Z of this.#i(j)){if(Z.textContent===X)continue;Z.textContent=X}}#i(j){let Q=this.element.querySelectorAll(`[data-reactive-text="${j}"]`);return Array.from(Q).filter((X)=>this.#Q(X))}#k(j,Q){let X=this.#a();for(let[Z,$]of Object.entries(X)){let J=Z in j?j[Z]:Q(Z)?.value;if(J===void 0||J===null)continue;let G=String(J);for(let W of Array.isArray($)?$:[$]){if(!_j(W))continue;for(let z of document.querySelectorAll(W)){if(z.textContent===G)continue;z.textContent=G}}}}#a(){let j=this.element.getAttribute("data-reactive-compute-mirror-param");if(!j)return{};try{let Q=JSON.parse(j);return Q&&typeof Q==="object"&&!Array.isArray(Q)?Q:{}}catch{return{}}}#b(j,Q,X,Z,$,J,G){if(this.#L("reactive:before-dispatch",{action:Q,params:this.#c(X),element:this.element},{cancelable:!0}).defaultPrevented)return;let z=Number(Z)||0;if(z>0)return this.#r(j,z,Q,X,J,G);let q=Number($)||0;if(q>0)return this.#e(j,q,Q,X,J,G);return this.#V(Q,X,J,j,G)}#V(j,Q,X,Z,$){let J=this.#Ej(X,Z),G=this.#Rj(j,Z,$);return this.queue=(this.queue??Promise.resolve()).then(()=>this.#Wj(j,Q,J,G)),this.queue}#r(j,Q,X,Z,$,J){this.#C(j);let G=()=>{this.#C(j),this.#V(X,Z,$,j,J)},W=setTimeout(G,Q);j?.addEventListener?.("blur",G,{once:!0}),this.#A.set(j,{timer:W,flush:G})}#C(j){let Q=this.#A.get(j);if(!Q)return;clearTimeout(Q.timer),j?.removeEventListener?.("blur",Q.flush),this.#A.delete(j)}#t(){for(let j of[...this.#A.keys()])this.#C(j)}#e(j,Q,X,Z,$,J){let G=this.#z.get(j)??new Map;if(G.has(X))return;let W=setTimeout(()=>{if(G.delete(X),G.size===0)this.#z.delete(j)},Q);return G.set(X,W),this.#z.set(j,G),this.#V(X,Z,$,j,J)}#jj(){for(let j of this.#z.values())for(let Q of j.values())clearTimeout(Q);this.#z.clear()}#L(j,Q,{cancelable:X=!1}={}){let Z=new CustomEvent(j,{bubbles:!0,composed:!0,cancelable:X,detail:Q});return(this.element.isConnected?this.element:document).dispatchEvent(Z),Z}#Z(j,Q,X,Z){let $=()=>{if(!this.element.isConnected){console.warn("[phlex-reactive] retry() ignored — the reactive root left the DOM");return}return this.#V(j,Q)};this.#L("reactive:error",{action:j,params:X,...Z,retry:$})}#$(j){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",j)}#Qj(){this.element?.removeAttribute?.("data-reactive-error")}#Xj(){let j=document.querySelector("[data-reactive-error-flash]");if(!j?.content)return;let Q=j.getAttribute("data-reactive-error-flash")||"flash",X=document.getElementById(Q);if(!X)return;X.appendChild(j.content.cloneNode(!0))}#Zj(){if(typeof sessionStorage>"u")return Promise.resolve();let j=Number(sessionStorage.getItem(D));if(!Number.isFinite(j)||j<=0)return Promise.resolve();if(!L)L=!0,console.warn(`[phlex-reactive] latency simulator ACTIVE — every action is delayed by ${j}ms. Call PhlexReactive.disableLatencySim() (or clear sessionStorage) to turn it off.`);return new Promise((Q)=>setTimeout(Q,j))}#$j(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#w(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}#Jj(j){if(!j)return[];let Q=[],X=/<turbo-stream\b([^>]*)>/g,Z;while((Z=X.exec(j))!==null){let $=Z[1],J=$.match(/\baction="([^"]*)"/)?.[1]??"?",G=$.match(/\btarget="([^"]*)"/)?.[1];Q.push(G?`${J} → #${G}`:J)}return Q}#Gj(j){let{action:Q,status:X,ms:Z}=j,J=`reactive ${this.element?.id?`#${this.element.id} `:""}${Q} → ${X??"—"} (${Math.round(Z)}ms)`;if(console.groupCollapsed(J),console.log(`params: [${j.paramNames.join(", ")}] + collected: [${j.fieldNames.join(", ")}]`),console.log(`encoding: ${j.encoding}`),j.streams.length)console.log(`streams: ${j.streams.join(" ")}`);console.log(`token: ${j.tokenRefreshed?"refreshed ✓":"unchanged"}`),console.groupEnd()}async#Wj(j,Q,X,Z){let{fields:$,files:J}=this.#Kj(),G=this.#c(Q),W={...$,...G},z=this.#J,q=J.length>0,U=q?this.#xj(z,j,W,J):JSON.stringify({token:z,act:j,params:W}),K=this.#$j()?{action:j,paramNames:Object.keys(G),fieldNames:Object.keys($),encoding:q?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#w()}:null;await this.#Zj();try{if(navigator.onLine===!1){this.#G(X),this.#$("offline"),this.#Z(j,Q,W,{kind:"offline"});return}let Y;try{let A={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#hj()};if(!q)A["Content-Type"]="application/json";let V=this.#yj();if(V)A["X-Pgbus-Connection"]=V;Y=await fetch(this.#bj(),{method:"POST",headers:A,body:U,credentials:"same-origin",signal:AbortSignal.timeout(this.#wj())})}catch(A){if(console.error("[phlex-reactive] action error",A),this.#G(X),A?.name==="TimeoutError"||A?.name==="AbortError"){this.#$("timeout"),this.#Z(j,Q,W,{kind:"timeout"});return}this.#Xj(),this.#$("network"),this.#Z(j,Q,W,{kind:"network"});return}if(K)K.status=Y.status;if(Y.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#G(X),this.#$("redirected"),this.#Z(j,Q,W,{kind:"redirected",status:Y.status});return}if(!Y.ok){let A=await Y.text();if(console.error(`[phlex-reactive] action failed: HTTP ${Y.status}`,A),this.#G(X),(Y.headers.get("Content-Type")||"").includes("turbo-stream")){let V=this.#y(A);if(this.#J=V??this.#J,K)this.#h(K,A,V);window.Turbo.renderStreamMessage(A)}this.#$("http"),this.#Z(j,Q,W,{kind:"http",status:Y.status,body:A});return}let _=Y.headers.get("Content-Type")||"";if(!_.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${_}" — no update applied`),this.#G(X),this.#$("content-type"),this.#Z(j,Q,W,{kind:"content-type",status:Y.status});return}let N=await Y.text(),I=this.#y(N);if(this.#J=I??this.#J,K)this.#h(K,N,I);window.Turbo.renderStreamMessage(N),this.#Qj(),this.#L("reactive:applied",{action:j,params:W,html:N})}catch(Y){console.error("[phlex-reactive] action error",Y),this.#G(X),this.#L("reactive:error",{action:j,params:W,kind:"apply"})}finally{if(Z?.(),K)this.#Gj({...K,ms:this.#w()-K.started})}}#h(j,Q,X){j.streams=this.#Jj(Q),j.tokenRefreshed=X!=null}get#J(){return this.#R??this.tokenValue}set#J(j){this.#R=j}#y(j){let Q=this.element.id;if(!Q)return j.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:X,self:Z}=this.#zj(Q),$=j.match(X);if($)return $[1];let J=j.match(Z);if(J)return J[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#zj(j){let Q=this.#D;if(Q&&Q.id===j)return Q;let X=qj(j);return this.#D={id:j,token:new RegExp(`<turbo-stream\\b[^>]*\\baction="reactive:token"[^>]*\\btarget="${X}"[^>]*\\bdata-reactive-token-value="([^"]+)"`),self:new RegExp(`<turbo-stream\\b[^>]*\\baction="(?:replace|update)"[^>]*\\btarget="${X}"[^>]*>([\\s\\S]*?)</turbo-stream>`)}}#Q(j){return j.closest('[data-controller~="reactive"]')===this.element}#H(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(Q)=>this.#Q(Q)}#Kj(){let j={},Q=[],X=this.#H();return this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Z)=>{if(!X(Z))return;if(Z.type==="file")for(let $ of Z.files??[])Q.push({name:Z.name,file:$,multiple:Z.multiple});else if(Z.type==="checkbox")j[Z.name]=Z.checked;else if(Z.type==="radio"){if(Z.checked)j[Z.name]=Z.value}else j[Z.name]=Z.value}),this.element.querySelectorAll("[name]:is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])").forEach((Z)=>{if(!X(Z))return;let $=Z.getAttribute("name");if(!$)return;let J=j[$];if(J==null||J==="")j[$]=Z.value??Z.textContent??Z.innerHTML??""}),{fields:j,files:Q}}#P(){if(typeof this.element?.querySelectorAll!=="function")return;let j=0;if(this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((Q)=>{if(!this.#Q(Q))return;if(Q.type==="file")return;if(this.#qj(Q))Q.setAttribute("data-reactive-dirty","true"),j++;else Q.removeAttribute("data-reactive-dirty")}),j>0)this.element.setAttribute("data-reactive-dirty",String(j));else this.element.removeAttribute("data-reactive-dirty")}#qj(j){if(j.type==="checkbox"||j.type==="radio")return j.checked!==j.defaultChecked;if(j.tag==="select"||j.options)return Array.from(j.options??[]).some((Q)=>Q.selected!==Q.defaultSelected);return j.value!==j.defaultValue}#v(){let j=this.element.getAttribute?.("data-reactive-dirty"),Q=Number(j);return Number.isFinite(Q)&&Q>0?Q:0}#Yj(){if(typeof window>"u"||typeof window.addEventListener!=="function")return;this.#Y=(j)=>{if(this.#v()===0)return;return j.preventDefault(),j.returnValue="You have unsaved changes.",j.returnValue},this.#U=(j)=>{if(this.#v()===0)return;if(!(typeof window.confirm==="function"?window.confirm("You have unsaved changes. Leave anyway?"):!0))j.preventDefault?.()},window.addEventListener("beforeunload",this.#Y),window.addEventListener("turbo:before-visit",this.#U)}#Uj(){if(this.#q)this.element.removeEventListener?.("turbo:morph-element",this.#q),this.#q=void 0;if(typeof window<"u"&&typeof window.removeEventListener==="function"){if(this.#Y)window.removeEventListener("beforeunload",this.#Y);if(this.#U)window.removeEventListener("turbo:before-visit",this.#U)}this.#Y=void 0,this.#U=void 0}#Hj(){if(this.element.getAttribute?.("data-reactive-show-targets"))return!0;let j=this.element.querySelectorAll?.(w)??[];for(let Q of j)if(this.#Q(Q))return!0;return!1}#f(){if(typeof this.element?.querySelectorAll!=="function")return;let j=this.#H(),Q=this.element.getAttribute?.("data-reactive-scope")||null,X=new Map,Z=($)=>{if(!X.has($))X.set($,this.#p($,j,Q));return X.get($)};for(let $ of this.element.querySelectorAll(w)){if(!j($))continue;let J=$.getAttribute("data-reactive-show");if(J!==null){let q=Mj(Vj(J),Z);if(q!==null)this.#u($,q,j,Q);continue}let G=$.getAttribute("data-reactive-show-field");if(!G)continue;let W=Z(G);if(W===null)continue;let z=Nj($,W);if(z===null)continue;this.#u($,z,j,Q)}this.#Aj(j,X,Q)}#u(j,Q,X,Z){if(j.hidden=!Q,j.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof j.querySelectorAll!=="function")return;for(let $ of j.querySelectorAll("input[name], select[name], textarea[name]"))if(X($))$.disabled=!Q;if(j.name&&X(j))j.disabled=!Q}#Aj(j,Q,X){let Z=this.#_j();for(let[$,J]of Object.entries(Z)){if(!J||typeof J!=="object"||Array.isArray(J))continue;if(!Q.has($))Q.set($,this.#p($,j,X));let G=Q.get($);if(G===null)continue;let W=()=>G;for(let[z,q]of Object.entries(J)){if(!Oj(z))continue;let U;if(Array.isArray(q)){if(q.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${z} — skipped`);continue}U=q.every((K)=>T(K,W))}else{let K=c(q,G);if(K===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${z} — skipped`);continue}U=K}for(let K of document.querySelectorAll(z))K.hidden=!U}}}#_j(){let j=this.element.getAttribute?.("data-reactive-show-targets");if(!j)return{};try{let Q=JSON.parse(j);if(Q&&typeof Q==="object"&&!Array.isArray(Q))return Q}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: { ... })"),{}}#p(j,Q,X){let Z=X&&!j.includes("[")?`${X}[${j}]`:j,$=!1,J=null;for(let G of this.element.querySelectorAll(`[name="${Z}"]`)){if(!Q(G))continue;if(G.type==="checkbox")return G.checked?"true":"false";if(G.type==="radio"){if(G.checked)return G.value??"";$=!0;continue}J??=G}if(J)return J.value??"";return $?"":null}#Nj(){if(!this.#j)return;this.element.removeEventListener?.("input",this.#j),this.element.removeEventListener?.("change",this.#j),this.element.removeEventListener?.("turbo:morph-element",this.#j),this.#j=void 0}#Vj(){return!!(this.element.getAttribute?.("data-reactive-filter-input")&&this.element.getAttribute?.("data-reactive-filter-option"))}#Lj(j){let Q=this.element.getAttribute("data-reactive-filter-input");return!!Q&&typeof j.target?.matches==="function"&&j.target.matches(Q)}#m(){if(typeof this.element?.querySelectorAll!=="function")return;let j=this.element.getAttribute("data-reactive-filter-input"),Q=this.element.getAttribute("data-reactive-filter-option");if(!j||!Q)return;let X=this.#H(),Z=[...this.element.querySelectorAll(j)].find(X);if(!Z)return;let $=(Z.value??"").trim().toLowerCase(),J=0;for(let z of this.element.querySelectorAll(Q)){if(!X(z))continue;let q=(z.getAttribute("data-reactive-filter-text")??z.textContent??"").toLowerCase(),U=$!==""&&!q.includes($);if(z.hidden=U,U)z.removeAttribute("data-reactive-highlighted");else J++}let G=this.element.getAttribute("data-reactive-filter-group");if(G)for(let z of this.element.querySelectorAll(G)){if(!X(z))continue;let q=[...z.querySelectorAll(Q)].filter(X);if(q.length===0)continue;z.hidden=q.every((U)=>U.hidden)}let W=this.element.getAttribute("data-reactive-filter-empty");if(W){for(let z of this.element.querySelectorAll(W))if(X(z))z.hidden=J>0}}#Mj(){if(!this.#X)return;this.element.removeEventListener?.("input",this.#X),this.element.removeEventListener?.("turbo:morph-element",this.#X),this.#X=void 0}#xj(j,Q,X,Z){let $=new FormData;$.append("token",j),$.append("act",Q);for(let[G,W]of Object.entries(X))this.#E($,`params[${G}]`,W);let J=this.#Oj(Z);for(let{name:G,file:W,multiple:z}of Z){let U=z||J.has(G)?`params[${G}][]`:`params[${G}]`;$.append(U,W,W.name)}return $}#E(j,Q,X){if(X==null)j.append(Q,"");else if(Array.isArray(X))X.forEach((Z,$)=>this.#E(j,`${Q}[${$}]`,Z));else if(typeof X==="object")for(let[Z,$]of Object.entries(X))this.#E(j,`${Q}[${Z}]`,$);else j.append(Q,String(X))}#Oj(j){let Q=new Map;for(let{name:X}of j)Q.set(X,(Q.get(X)??0)+1);return new Set([...Q].filter(([,X])=>X>1).map(([X])=>X))}#c(j){if(!j)return{};try{return typeof j==="string"?JSON.parse(j):j}catch{return{}}}#Bj(j){return g(j)}#Cj(j){d(j,(Q)=>this.#F(Q))}#F(j){let Q=j.to;if(Q==="@root")return[this.element];if(typeof Q!=="string"||Q==="")return[];if(j.global)return[...document.querySelectorAll(Q)];return[...this.element.querySelectorAll(Q)].filter((X)=>this.#Q(X))}#Pj(j,Q){if(j?.checked!=="keep")return!1;let X=Q?.type;return X==="checkbox"||X==="radio"}#Ej(j,Q){if(!j)return null;let X=this.#Fj(j,Q),Z=[];for(let $ of X){if(j.add_class){let J=j.add_class.filter((G)=>!$.classList.contains(G));if($.classList.add(...J),J.length)Z.push(()=>$.classList.remove(...J))}if(j.remove_class){let J=j.remove_class.filter((G)=>$.classList.contains(G));if($.classList.remove(...J),J.length)Z.push(()=>$.classList.add(...J))}if(j.toggle_class)j.toggle_class.forEach((J)=>$.classList.toggle(J)),Z.push(()=>j.toggle_class.forEach((J)=>$.classList.toggle(J)));if(j.hide)$.hidden=!0,Z.push(()=>$.hidden=!1)}if(j.checked==="keep"&&Q&&"checked"in Q){let $=Q.checked;Z.push(()=>Q.checked=!$)}return Z.length?Z:null}#G(j){if(!j)return;if(!this.element.isConnected)return;for(let Q of j)Q()}#Fj(j,Q){if(j.to==null)return Q?[Q]:[];return this.#F({to:j.to})}#Rj(j,Q,X){this.#Dj(j,Q);let Z=this.#Ij(j,Q,X),$=!1;return()=>{if($)return;$=!0,this.#Tj(j,Q),Z()}}#Dj(j,Q){if(this.#W(Q,j,1),this.#W(this.element,j,1),this.#K.set(j,(this.#K.get(j)??0)+1),this.#x++===0)this.element.setAttribute("aria-busy","true");for(let X of this.#g(j))this.#W(X,j,1)}#Tj(j,Q){this.#W(Q,j,-1),this.#W(this.element,j,-1);let X=(this.#K.get(j)??1)-1;if(X<=0)this.#K.delete(j);else this.#K.set(j,X);if(--this.#x<=0)this.#x=0,this.element.removeAttribute("aria-busy");for(let Z of this.#g(j))this.#W(Z,j,-1)}#W(j,Q,X){if(!j||typeof j.getAttribute!=="function")return;let Z=this.#O.get(j)??new Map,$=(Z.get(Q)??0)+X;if($<=0)Z.delete(Q);else Z.set(Q,$);if(Z.size===0){this.#O.delete(j),j.removeAttribute("data-reactive-busy");return}this.#O.set(j,Z),j.setAttribute("data-reactive-busy",[...Z.keys()].join(" "))}#g(j){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((X)=>X.getAttribute("data-reactive-busy-on")===j&&this.#Q(X))}#Ij(j,Q,X){if(!X||!Q)return()=>{};let Z=this.#kj(X,Q),$=Array.isArray(X.class)?X.class:[],J=[];for(let W of Z){let z=$.filter((q)=>!W.classList.contains(q));if(W.classList.add(...z),z.length)J.push([W,z])}let G=this.#_.get(Q);if(G)G.count++;else if(X.disable||X.text!=null)this.#_.set(Q,{count:1,disabled:Q.disabled,text:Q.textContent,hadText:X.text!=null});if(X.disable)Q.disabled=!0;if(X.text!=null)Q.textContent=X.text;return()=>{for(let[W,z]of J)if(W.isConnected)W.classList.remove(...z);this.#Sj(Q,X)}}#Sj(j,Q){let X=this.#_.get(j);if(!X)return;if(--X.count>0)return;if(this.#_.delete(j),!j.isConnected)return;if(Q.disable)j.disabled=X.disabled;if(X.hadText&&j.textContent===Q.text)j.textContent=X.text}#kj(j,Q){if(j.to==null)return Q?[Q]:[];return this.#F({to:j.to})}#bj(){return this.#d??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#wj(){if(this.#M!=null)return this.#M;let j=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,Q=Number(j);return this.#M=Number.isFinite(Q)&&Q>0?Q:30000}#hj(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#yj(){return document.querySelector("pgbus-stream-source[connection-id]")?.getAttribute("connection-id")||document.querySelector('meta[name="pgbus-connection-id"]')?.content||null}}export{Dj as resetReactiveDefers,n as registerReactiveVisit,i as registerReactiveToken,Gj as registerReactiveOffline,a as registerReactiveJs,$j as registerReactiveDismiss,r as registerReactiveDefer,k as registerReactiveActions,Tj as pendingDeferVia,qj as escapeRegExp,Wj as enableLatencySim,zj as disableLatencySim,hj as default,Yj as checkReactiveRegistration,bj as __resetReactiveRegistrationForTest,Sj as __resetReactiveOfflineForTest,kj as __resetReactiveLatencyForTest,Ij as __resetReactiveDismissForTest,wj as __markReactiveConnectedForTest,D as LATENCY_KEY};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=B4ECABAC7819655164756E2164756E21
|
|
4
4
|
//# sourceMappingURL=reactive_controller.min.js.map
|