phlex-reactive 0.11.6 → 0.11.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c5d8ca344fdd9583bd79ad6e9b162c7a1888d48055dfb36474a3cbc6caf10fe
4
- data.tar.gz: c903ed3e437da570c06924055d0e1ad1c9c611c0086431ae8c7d38fc000f8337
3
+ metadata.gz: ce274b76a614b8510a9fc365e717d0b5391b815743a9cd0e9f3ffa716428c0ec
4
+ data.tar.gz: 9be84dd96ad24ef556935b8b68a60ecdbf48fabe902e1541584d6af6f22e17cf
5
5
  SHA512:
6
- metadata.gz: 749fdfd67d453f51c527eb8e058e5b062d04431d3f099aa35a8b9135a38bd2fdc7baa7251eb0ed7d25775bcb6be7f3370958301a0838d89d7893a37f6dd1306b
7
- data.tar.gz: 6322de1f369d12c6aff0f187749d4a2f6f090939cce2fb4f4389c9b1a6b7ff1cce3de7d90b4b969706c0997c5d481d8816f45d728dded107445a7455a337f640
6
+ metadata.gz: 5e87ae21d988550c315b9ac27a721d5e65b7fdf354ddbaa487cd0e2db7e062ad854198f0a6893ab8e9d0531b6ff698829f7421bd1d8a4fbd3c533992a4485a51
7
+ data.tar.gz: 107d841025bc3d6d2fecb4b30027e417607773edd12c45503a5615ecee40d9cd5994d42c5ddd40a3ec53c354fa49ef482953844b2ee2ee01311e27c0bbf987c2
data/CHANGELOG.md CHANGED
@@ -8,6 +8,25 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
9
  ### Added
10
10
 
11
+ - **Fill-then-add for draft nested rows — `reactive_nested_add(:assoc, from:, clear:)` (#208).**
12
+ The draft-rows primitive's add is *inline-edit* — it clones the template and
13
+ focuses the new row's first field, so you type INTO the row. A common
14
+ alternative puts the add controls OUTSIDE the row (a preset `<select>`, a
15
+ typeahead, plain inputs) and "Add" **snapshots** those values into a new row,
16
+ then clears them for the next entry. `from: { row_field => "#source-selector" }`
17
+ seeds each cloned-row field from its source control's current value (matching
18
+ the field by the same trailing-bracket-segment key inference JSON mode uses),
19
+ keeps focus on the sources rather than stealing it into the row, and `clear:
20
+ true` resets the sources (each via the set-value + dispatch contract, so dirty
21
+ tracking and compute observe the reset). `from:` values are raw CSS selectors
22
+ resolved within the reactive root (#15 ownership); an unresolved source or an
23
+ unmatched row-field key is silently skipped (the row still adds). It composes
24
+ with BOTH wire modes: the seeded values ride the renumbered `_attributes` names
25
+ on submit (`:attributes`) and the end-of-add JSON sync serializes them
26
+ (`as: :json`), with no extra wiring. The no-`from:` inline-edit default is
27
+ unchanged. See the "Draft rows for a new parent" README section and the
28
+ `/docs/example-draft-rows` page.
29
+
11
30
  - **Multi-field cross-root targets — `reactive_show_targets` speaks the full
12
31
  conditions language (#209).** A `"#id"` KEY now takes an `if:`/`if_any:`/
13
32
  `unless:` conditions Hash, so an OUTSIDE element can show/hide from a
data/README.md CHANGED
@@ -397,7 +397,7 @@ Use in controllers: `render turbo_stream: Counter.replace(counter)`.
397
397
  | `reactive_dirty` / `reactive_dirty warn_unsaved: true` / `reactive_dirty only: %i[...]` | **Dirty tracking**, declared once at the class level, against the DOM's own `defaultValue`/`defaultChecked`/`defaultSelected` — no client state. Marks changed fields + the root `data-reactive-dirty`; `warn_unsaved:` arms a `beforeunload`/`turbo:before-visit` guard; `only:` scopes tracking to named fields. Style with `[data-reactive-dirty]`. See [Dirty-field tracking](#dirty-field-tracking-reactive_dirty). |
398
398
  | `nested_update!(:assoc, attrs)` | Map a nested param onto `<assoc>_attributes` with id preservation; update the record. |
399
399
  | `reactive_nested_list(:assoc, as: :attributes \| :json)` / `reactive_nested_template(:assoc)` / `reactive_nested_row` | **Draft nested-attribute rows** (the "new parent + child rows" form): the container rows land in, the `<template>` holding ONE row's markup, and the row wrapper marker — all **client-only** form state, keyed by association (several collections per root). `as: :json` (default `:attributes`) serializes the rows into ONE hidden JSON field instead of posting `accepts_nested_attributes_for` names — for an app whose controller `JSON.parse`s a serialized param. See [Draft rows for a new parent](#draft-rows-for-a-new-parent-reactive_nested_). |
400
- | `reactive_nested_add(:assoc)` / `reactive_nested_remove` | The row triggers, client-only (zero round trips): add clones the template and renumbers its placeholder index; remove deletes a draft row from the DOM, or `_destroy`-marks + hides a persisted row (a hidden `[_destroy]` input present). |
400
+ | `reactive_nested_add(:assoc, from:, clear:)` / `reactive_nested_remove` | The row triggers, client-only (zero round trips): add clones the template and renumbers its placeholder index; remove deletes a draft row from the DOM, or `_destroy`-marks + hides a persisted row (a hidden `[_destroy]` input present). **Fill-then-add**: `from: { row_field => "#source-selector" }` seeds the new row from add controls that live OUTSIDE it (a preset select, a typeahead), and `clear: true` resets them — composes with `as: :attributes` AND `as: :json`. See [Draft rows for a new parent](#draft-rows-for-a-new-parent-reactive_nested_). |
401
401
  | `nested_field_name(:assoc, :field, index: nil)` | The Rails `accepts_nested_attributes_for` wire name for one row field — `order[line_items_attributes][NEW_ROW][quantity]` (the template placeholder) by default, a real index when given. Scope-aware under `reactive_scope`. |
402
402
  | `reactive_collection :name, item:, container:, count:, empty:, size:` | Declare an add/remove-row list once; actions call `reply.append`/`prepend`/`remove`. See [Reactive collections](#reactive-collections-addremove-rows--count--empty-state). |
403
403
  | `reply.replace` / `.morph` / `.update` / `.remove` / `.redirect(url)` / `.with(*)` / `.js(ops)` | Return from an action to control the reply (flash, remove, redirect, multi-stream, server-pushed client ops). See [Controlling the action's reply](#reply--controlling-the-actions-reply). |
@@ -1381,6 +1381,35 @@ marker — an absent row *is* the removal). The per-row `_attributes` names stil
1381
1381
  render but are ignored by a controller that doesn't permit them; the JSON field
1382
1382
  is the single source of truth.
1383
1383
 
1384
+ **Fill-then-add — snapshot add controls that live OUTSIDE the row.** The default
1385
+ `reactive_nested_add` is *inline-edit*: it clones the template and focuses the
1386
+ new row's first field, so you type INTO the row. A common alternative puts the
1387
+ add controls outside the row — a preset `<select>`, a typeahead, plain inputs —
1388
+ and "Add" **snapshots** those values into a new row, then clears them for the
1389
+ next entry. Pass `from:` (a map of row-field → source-control selector) and
1390
+ optionally `clear:`:
1391
+
1392
+ ```ruby
1393
+ input(id: "item-name", type: "text") # the add controls, OUTSIDE the row
1394
+ input(id: "item-qty", type: "number")
1395
+
1396
+ button(**reactive_nested_add(:line_items,
1397
+ from: { name: "#item-name", quantity: "#item-qty" }, # row field => source selector
1398
+ clear: true)) { "Add item" }
1399
+ ```
1400
+
1401
+ On click the client clones the template, fills each cloned-row field from its
1402
+ source control's current value (matching the field by the **same** trailing
1403
+ bracket-segment key inference JSON mode uses), keeps focus on the sources (so
1404
+ you keep entering the next item — it does *not* steal focus into the row), and,
1405
+ with `clear: true`, resets the sources (each via the set-value + dispatch
1406
+ contract, so dirty tracking and compute see it). The `from:` values are raw CSS
1407
+ selectors resolved within this root (`#15` ownership); a selector that resolves
1408
+ nothing, or a row-field key with no matching cloned field, is skipped (the row
1409
+ still adds — never a throw). It composes with **both** wire modes: the seeded
1410
+ values ride the renumbered `_attributes` names on submit (`:attributes`) and the
1411
+ end-of-add JSON sync serializes them (`as: :json`), with no extra wiring.
1412
+
1384
1413
  Relatedly, a **draft parent can now run real server actions too** (issue #208):
1385
1414
  an unsaved record signs a gid-less `{c, state}` token, and the endpoint rebuilds
1386
1415
  the component through the record kwarg's **initialize default** —
@@ -1869,15 +1869,89 @@ export default class extends Controller {
1869
1869
  const row = proto.cloneNode(true)
1870
1870
  this.#renumberNestedRow(row, this.#nextNestedIndex())
1871
1871
  list.appendChild(row)
1872
- const first = [...(row.querySelectorAll?.("input, select, textarea") ?? [])][0]
1873
- first?.focus?.()
1874
1872
 
1875
- // JSON mode (issue #208): a freshly-added empty row must land in the hidden
1876
- // field immediately, so the serialized array reflects the DOM even before
1877
- // the first keystroke. A no-op when this list isn't `as: :json`.
1873
+ // Fill-then-add (issue #208 Scenario A): seed the cloned row from named
1874
+ // source controls OUTSIDE the row, then (optionally) clear the sources.
1875
+ // Runs AFTER renumber+append so a seeded field's name already carries its
1876
+ // final `[<index>][field]` form — the key match agrees with what JSON mode
1877
+ // reads. `seeded` is the FIRST source we cleared/read, so fill-then-add can
1878
+ // return focus to the sources instead of stealing it into the new row.
1879
+ const fromJson = trigger?.getAttribute?.("data-reactive-nested-from-param")
1880
+ const clear = trigger?.getAttribute?.("data-reactive-nested-clear-param") === "true"
1881
+ const firstSource = this.#seedNestedRow(row, fromJson, clear)
1882
+
1883
+ // Focus: inline-edit (no from:) focuses the new row's first field so you
1884
+ // type INTO it; fill-then-add keeps focus on the sources (the first one) so
1885
+ // you keep entering the next item — stealing focus would break that loop.
1886
+ if (fromJson) firstSource?.focus?.()
1887
+ else [...(row.querySelectorAll?.("input, select, textarea") ?? [])][0]?.focus?.()
1888
+
1889
+ // JSON mode (issue #208): a freshly-added row must land in the hidden field
1890
+ // immediately (seeded values included), so the serialized array reflects the
1891
+ // DOM even before the first keystroke. A no-op when not `as: :json`.
1878
1892
  if (list.getAttribute?.("data-reactive-nested-json") === assoc) this.#syncNestedJson(assoc)
1879
1893
  }
1880
1894
 
1895
+ // Fill-then-add (issue #208): copy each source control's value into the
1896
+ // matching cloned-row field, keyed by the trailing bracket segment of the
1897
+ // field's name (#nestedJsonKey — the SAME inference JSON mode uses, so the
1898
+ // two features can't drift). Sources resolve root-scoped and owned (#15); an
1899
+ // unresolved source or an unmatched key is silently skipped (the row still
1900
+ // adds — a half-mapped binding must never throw on click). Returns the FIRST
1901
+ // source control read (for focus), or null. With `clear`, resets every source
1902
+ // it read via the set-value + dispatch contract (#183) so dirty/show/compute
1903
+ // observe the reset.
1904
+ #seedNestedRow(row, fromJson, clear) {
1905
+ if (!fromJson) return null
1906
+ let map
1907
+ try {
1908
+ map = JSON.parse(fromJson)
1909
+ } catch {
1910
+ return null
1911
+ }
1912
+ if (!map || typeof map !== "object") return null
1913
+
1914
+ const owns = this.#ownershipFilter()
1915
+ const rowFields = [...(row.querySelectorAll?.("input, select, textarea") ?? [])]
1916
+ const sources = []
1917
+ for (const [key, selector] of Object.entries(map)) {
1918
+ const source = [...(this.element.querySelectorAll?.(selector) ?? [])].find(owns)
1919
+ if (!source) continue
1920
+ const target = rowFields.find((field) => this.#nestedJsonKey(field.getAttribute?.("name")) === key)
1921
+ if (!target) continue
1922
+ this.#seedNestedField(target, source)
1923
+ sources.push(source)
1924
+ }
1925
+ if (clear) for (const source of sources) this.#clearNestedSource(source)
1926
+ return sources[0] ?? null
1927
+ }
1928
+
1929
+ // Copy a source control's value into a cloned-row field, then dispatch a
1930
+ // bubbling `input` (the set-value + dispatch contract, #183). Checkbox ↔
1931
+ // checkbox copies the checked state; every other target takes the source's
1932
+ // submit-shaped value (#nestedFieldValue), so a checkbox source feeding a
1933
+ // text field lands "on"/"" exactly as a submit would.
1934
+ #seedNestedField(target, source) {
1935
+ if (target.type === "checkbox") {
1936
+ target.checked = source.type === "checkbox" ? !!source.checked : this.#nestedFieldValue(source) !== ""
1937
+ } else {
1938
+ target.value = this.#nestedFieldValue(source)
1939
+ }
1940
+ if (typeof target.dispatchEvent === "function") {
1941
+ target.dispatchEvent(new Event("input", { bubbles: true }))
1942
+ }
1943
+ }
1944
+
1945
+ // Reset a source control after a fill-then-add (issue #208), dispatching a
1946
+ // bubbling `input` so dirty tracking / reactive_show / compute see the reset.
1947
+ #clearNestedSource(source) {
1948
+ if (source.type === "checkbox") source.checked = false
1949
+ else source.value = ""
1950
+ if (typeof source.dispatchEvent === "function") {
1951
+ source.dispatchEvent(new Event("input", { bubbles: true }))
1952
+ }
1953
+ }
1954
+
1881
1955
  // Remove the trigger's closest row wrapper. A DRAFT row (no [_destroy]
1882
1956
  // input) leaves the DOM — it was never persisted, so removing its fields IS
1883
1957
  // the removal. A PERSISTED row (an edit form rendered a hidden [_destroy]
@@ -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 KX(){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)=>bX(j,Q))}}var M=new Map;function u(X,Z){let $=!M.has(X);if(M.set(X,Z),$)i()}function x(X){if(M.delete(X))s()}function pX(){M.clear(),T=!1}function mX(X){return M.get(X)?.via}var T=!1;function qX(){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;P(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(M.get(Q)?.via==="stream")x(Q)}function P(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){P(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()},JX()),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),M.get(X)!==Z)return;console.error("[phlex-reactive] deferred render failed",z),C(X,$);return}if(M.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),M.get(X)!==Z)return;console.error("[phlex-reactive] deferred render failed reading the body",z),C(X,$);return}if(clearTimeout(Q),M.get(X)!==Z)return;v(X),window.Turbo.renderStreamMessage(G)}function c(X){let Z=M.get(X);if(!Z)return;if(x(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){x(X);let Z=document.getElementById(X);if(!Z)return;l(Z),Z.removeAttribute("data-reactive-error")}function C(X,Z,$){x(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"),P(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 JX(){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 LX(){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(F);else setTimeout(F,0);return}let Q=async(j)=>{await $(j),F()};Q.__reactiveDismissWrapped=!0,Z.render=Q}function F(){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 w="phlex-reactive:latency",N=!1;function BX(X){if(typeof sessionStorage>"u")return;sessionStorage.setItem(w,String(X))}function VX(){if(typeof sessionStorage>"u")return;sessionStorage.removeItem(w),N=!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(){N=!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(),KX(),qX(),LX(),AX(),OX()}function NX(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 xX(){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(xX,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",X,{once:!0});else X()}var PX=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function EX(X){let Z=String(X).toLowerCase();return Z.startsWith("on")||PX.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,K=()=>{if(z)return;z=!0,X.classList.remove(Q,G)};X.addEventListener("animationend",K,{once:!0}),setTimeout(K,350)}var f=Object.freeze({show:(X,Z)=>R(X,!1,Z),hide:(X,Z)=>R(X,!0,Z),toggle:(X,Z)=>R(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)=>wX(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 R(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 FX(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 RX(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 b(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)=>b(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)=>b(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 wX(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 bX(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};#f;#V=new Map;#U=new Map;#_X;#D;#p;#T=0;#H=new Map;#I=new WeakMap;#O=new Map;#m=new WeakSet;#W;#_;#J;#Z;#Q;#L;#u=!1;#k=0;#g=!1;#j;#M;#A;#N;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.#c(),this.#N=()=>this.#c(),this.element.addEventListener?.("turbo:morph-element",this.#N);if(this.#JX()){if(this.#W=()=>this.#w(),this.element.addEventListener?.("turbo:morph-element",this.#W),this.#w(),this.element.getAttribute?.("data-reactive-warn-unsaved")==="true")this.#fX()}if(this.#mX())this.#Z=()=>this.#$X(),this.element.addEventListener?.("input",this.#Z),this.element.addEventListener?.("change",this.#Z),this.element.addEventListener?.("turbo:morph-element",this.#Z),this.#$X();if(this.#F())this.#Q=(X)=>{if(X?.type==="input"&&!this.#iX(X))return;this.#B()},this.element.addEventListener?.("input",this.#Q),this.element.addEventListener?.("turbo:morph-element",this.#Q),this.#B();if(this.#R())this.#L=()=>this.#v(),this.element.addEventListener?.("turbo:morph-element",this.#L),this.#v();if(this.#nX())this.#j=(X)=>this.syncNestedJson(X),this.#M=()=>this.#P(),this.element.addEventListener?.("input",this.#j),this.element.addEventListener?.("change",this.#j),this.element.addEventListener?.("turbo:morph-element",this.#M),this.#P();if(this.#oX())this.#A=()=>this.recompute(),this.element.addEventListener?.("turbo:morph-element",this.#A),this.recompute()}#JX(){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.#RX(),this.#TX(),this.#pX(),this.#lX(),this.#sX(),this.#$Z(),this.#QZ(),this.#jZ(),this.#N)this.element.removeEventListener?.("turbo:morph-element",this.#N)}#c(){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;P(X.id,Z)}dispatch(X){let{action:Z,params:$,debounce:Q,throttle:j,confirm:G,confirmWhen:z,outside:K,window:q,optimistic:Y}=X.params;if(!Z)return;let L=X.params.busy??this.#JZ(X.params.loading);if(K&&this.element.contains(X.target))return;let A=X.currentTarget??X.target;if(!q&&!this.#KZ(Y,A))X.preventDefault();let W=this.#e(G,z);if(!W)return this.#s(A,Z,$,Q,j,Y,L);Promise.resolve().then(()=>h(W)).catch(()=>!1).then((_)=>{if(_)this.#s(A,Z,$,Q,j,Y,L)})}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.#e($,Q);if(!z)return this.#qX(this.#KX(Z));Promise.resolve().then(()=>h(z)).catch(()=>!1).then((K)=>{if(K)this.#qX(this.#KX(Z))})}trackDirty(){this.#w()}recompute(X){if(X&&this.#m.has(X))return;let Z=this.#OX(),$=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,K=(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.#o(U,K(U)?.value??"");let q=this.element.getAttribute("data-reactive-compute-reducer-param"),Y=q?QX(q):null;if(!Y){this.#i({},K);return}let L=this.#VX("data-reactive-compute-outputs-param"),A={};for(let[U,H]of Z){let V=K(U);if(H==="string")A[U]=V?.value??"";else{let J=Number(V?.value);A[U]=Number.isFinite(J)?J:0}}let W=Y(A,{changed:this.#NX(X,$,Q)})||{},_=[];for(let U of L){if(!(U in W))continue;let H=K(U);if(!H)continue;if(String(W[U])===H.value)continue;H.value=W[U],_.push(H)}for(let U of Object.keys(W)){let H=W[U];if(H===void 0||H===null)continue;this.#o(U,H)}this.#i(W,K);for(let U of _){let H=new Event("input",{bubbles:!0});this.#m.add(H),U.dispatchEvent(H)}}listnavNext(X){this.#d(X,1)}listnavPrev(X){this.#d(X,-1)}listnavPick(X){let Z=this.#x(X),$=Z.findIndex((Q)=>Q.hasAttribute("data-reactive-highlighted"));if($<0)return;X.preventDefault(),Z[$].click()}listnavClose(X){for(let Z of this.#x(X))Z.removeAttribute("data-reactive-highlighted")}#d(X,Z){let $=this.#x(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"})}#x(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.#R())return;if(X?.defaultPrevented)return;if(this.#x(X).some((Q)=>Q.hasAttribute?.("data-reactive-highlighted")))return;X?.preventDefault?.();let Z=X?.currentTarget??X?.target;if(!Z)return;if(!this.#jX(String(Z.value??"").split(",")))return;if(Z.value="",this.#F())this.#B()}tagsPick(X){if(!this.#R())return;X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.getAttribute?.("data-reactive-tag-param");if(!$)return;if(!this.#jX([$]))return;let Q=this.#aX();if(!Q)return;Q.value="",this.#B(),Q.focus?.()}tagsRemove(X){if(!this.#R())return;X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.getAttribute?.("data-reactive-tag-param");if(!$)return;let Q=this.#b();if(!Q)return;let j=this.#h(Q),G=j.filter((z)=>z.toLowerCase()!==$.toLowerCase());if(G.length===j.length)return;this.#GX(Q,G)}nestedAdd(X){X?.preventDefault?.();let $=(X?.currentTarget??X?.target)?.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.#ZZ($);return}let K=z.cloneNode(!0);if(this.#XZ(K,this.#eX()),j.appendChild(K),[...K.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.(),j.getAttribute?.("data-reactive-nested-json")===$)this.#l($)}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.#P()}syncNestedJson(X){let Z=X?.target;if(!Z||!this.#$(Z))return;this.#P()}#P(){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.#l(Z.getAttribute("data-reactive-nested-json"))}#l(X){let Z=this.#X(),$=[...this.element.querySelectorAll(`[data-reactive-nested-list="${X}"]`)].find(Z);if(!$)return;let Q=this.#LX($);if(!Q)return;let j=[];for(let z of[...$.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!Z(z)||z.hidden)continue;j.push(this.#MX(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}))}#LX(X){let Z=X.getAttribute?.("data-reactive-nested-json-field");if(!Z)return null;let $=this.#X();return[...this.element.querySelectorAll(Z)].find($)??null}#MX(X){let Z={};for(let $ of[...X.querySelectorAll?.("input, select, textarea")??[]]){let Q=this.#AX($.getAttribute?.("name"));if(Q===null||Q==="_destroy")continue;Z[Q]=this.#BX($)}return Z}#AX(X){if(!X)return null;let Z=X.match(/\[([^\][]+)\]$/);return Z?Z[1]:X}#BX(X){if(X.type==="checkbox")return X.checked?X.value||"on":"";return X.value??""}#VX(X){let Z=this.element.getAttribute(X);if(!Z)return[];try{let $=JSON.parse(Z);return Array.isArray($)?$:[]}catch{return[]}}#OX(){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[]}}#NX(X,Z,$){let Q=X?.target;if(!Q?.name||typeof Q.closest!=="function")return null;let j=this.#xX(Q.name,$);if(!Z.includes(j))return null;return this.#$(Q)?j:null}#xX(X,Z){if(!Z)return X;let $=`${Z}[`;return X.startsWith($)&&X.endsWith("]")?X.slice($.length,-1):X}#o(X,Z){let $=String(Z);for(let Q of this.#PX(X)){if(Q.textContent===$)continue;Q.textContent=$}}#PX(X){let Z=this.element.querySelectorAll(`[data-reactive-text="${X}"]`);return Array.from(Z).filter(($)=>this.#$($))}#i(X,Z){let $=this.#EX();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 K of Array.isArray(j)?j:[j]){if(!FX(K))continue;for(let q of document.querySelectorAll(K)){if(q.textContent===z)continue;q.textContent=z}}}}#EX(){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{}}}#s(X,Z,$,Q,j,G,z){if(this.#C("reactive:before-dispatch",{action:Z,params:this.#zX($),element:this.element},{cancelable:!0}).defaultPrevented)return;let q=Number(Q)||0;if(q>0)return this.#FX(X,q,Z,$,G,z);let Y=Number(j)||0;if(Y>0)return this.#DX(X,Y,Z,$,G,z);return this.#E(Z,$,G,X,z)}#E(X,Z,$,Q,j){let G=this.#qZ($,Q),z=this.#YZ(X,Q,j),K=this.#n()?this.#CX($,Q):null;return this.queue=(this.queue??Promise.resolve()).then(()=>this.#hX(X,Z,G,z,K)),this.queue}#CX(X,Z){if(!X?.hide)return null;let $=this.#HX(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)}}#FX(X,Z,$,Q,j,G){this.#S(X);let z=()=>{this.#S(X),this.#E($,Q,j,X,G)},K=setTimeout(z,Z);X?.addEventListener?.("blur",z,{once:!0}),this.#V.set(X,{timer:K,flush:z})}#S(X){let Z=this.#V.get(X);if(!Z)return;clearTimeout(Z.timer),X?.removeEventListener?.("blur",Z.flush),this.#V.delete(X)}#RX(){for(let X of[...this.#V.keys()])this.#S(X)}#DX(X,Z,$,Q,j,G){let z=this.#U.get(X)??new Map;if(z.has($))return;let K=setTimeout(()=>{if(z.delete($),z.size===0)this.#U.delete(X)},Z);return z.set($,K),this.#U.set(X,z),this.#E($,Q,j,X,G)}#TX(){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)}#IX(){this.element?.removeAttribute?.("data-reactive-error")}#kX(){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))}#SX(){if(typeof sessionStorage>"u")return Promise.resolve();let X=Number(sessionStorage.getItem(w));if(!Number.isFinite(X)||X<=0)return Promise.resolve();if(!N)N=!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))}#n(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#a(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}#wX(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}#bX(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#hX(X,Z,$,Q,j){let{fields:G,files:z}=this.#XX(),K=this.#zX(Z),q={...G,...K},Y=this.#K,L=z.length>0,A=L?this.#GZ(Y,X,q,z):JSON.stringify({token:Y,act:X,params:q}),W=this.#n()?{action:X,paramNames:Object.keys(K),fieldNames:Object.keys(G),encoding:L?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#a()}:null;await this.#SX();try{if(navigator.onLine===!1){this.#q($),this.#z("offline"),this.#G(X,Z,q,{kind:"offline"});return}let _;try{let J={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#AZ()};if(!L)J["Content-Type"]="application/json";let O=this.#BZ();if(O)J["X-Pgbus-Connection"]=O;_=await fetch(this.#LZ(),{method:"POST",headers:J,body:A,credentials:"same-origin",signal:AbortSignal.timeout(this.#MZ())})}catch(J){if(console.error("[phlex-reactive] action error",J),this.#q($),J?.name==="TimeoutError"||J?.name==="AbortError"){this.#z("timeout"),this.#G(X,Z,q,{kind:"timeout"});return}this.#kX(),this.#z("network"),this.#G(X,Z,q,{kind:"network"});return}if(W)W.status=_.status;if(_.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#q($),this.#z("redirected"),this.#G(X,Z,q,{kind:"redirected",status:_.status});return}if(!_.ok){let J=await _.text();if(console.error(`[phlex-reactive] action failed: HTTP ${_.status}`,J),this.#q($),(_.headers.get("Content-Type")||"").includes("turbo-stream")){let O=this.#t(J);if(this.#K=O??this.#K,W)this.#r(W,J,O);window.Turbo.renderStreamMessage(J)}this.#z("http"),this.#G(X,Z,q,{kind:"http",status:_.status,body:J});return}let U=_.headers.get("Content-Type")||"";if(!U.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${U}" — no update applied`),this.#q($),this.#z("content-type"),this.#G(X,Z,q,{kind:"content-type",status:_.status});return}let H=await _.text(),V=this.#t(H);if(this.#K=V??this.#K,W)this.#r(W,H,V);if(window.Turbo.renderStreamMessage(H),j)queueMicrotask(j);this.#IX(),this.#C("reactive:applied",{action:X,params:q,html:H})}catch(_){console.error("[phlex-reactive] action error",_),this.#q($),this.#C("reactive:error",{action:X,params:q,kind:"apply"})}finally{if(Q?.(),W)this.#bX({...W,ms:this.#a()-W.started})}}#r(X,Z,$){X.streams=this.#wX(Z),X.tokenRefreshed=$!=null}get#K(){return this.#f??this.tokenValue}set#K(X){this.#f=X}#t(X){let Z=this.element.id;if(!Z)return X.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:$,self:Q}=this.#vX(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}#vX(X){let Z=this.#p;if(Z&&Z.id===X)return Z;let $=NX(X);return this.#p={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)}#e(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.#XX(),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}#XX(){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.#yX(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")}#yX(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}#fX(){if(typeof window>"u"||typeof window.addEventListener!=="function")return;this.#_=(X)=>{if(this.#ZX()===0)return;return X.preventDefault(),X.returnValue="You have unsaved changes.",X.returnValue},this.#J=(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.#_),window.addEventListener("turbo:before-visit",this.#J)}#pX(){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.#J)window.removeEventListener("turbo:before-visit",this.#J)}this.#_=void 0,this.#J=void 0}#mX(){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}#$X(){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.#dX(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.#QX(j,Y,X,Z);continue}let z=j.getAttribute("data-reactive-show-field");if(!z)continue;let K=Q(z);if(K===null)continue;let q=RX(j,K);if(q===null)continue;this.#QX(j,q,X,Z)}this.#uX(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}#uX(X){let Z=this.#cX();for(let[$,Q]of Object.entries(Z)){if($.startsWith("#")){this.#gX($,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,K]of Object.entries(Q)){if(!m(z))continue;let q;if(Array.isArray(K)){if(K.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${z} — skipped`);continue}q=K.every((Y)=>b(Y,G))}else{let Y=e(K,j);if(Y===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${z} — skipped`);continue}q=Y}for(let Y of document.querySelectorAll(z))Y.hidden=!q}}}#gX(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}#cX(){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: { ... })"),{}}#dX(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}#lX(){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}#F(){return!!(this.element.getAttribute?.("data-reactive-filter-input")&&this.element.getAttribute?.("data-reactive-filter-option"))}#oX(){return this.element.getAttribute?.("data-reactive-compute-seed")==="true"}#iX(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 q of this.element.querySelectorAll(Z)){if(!$(q))continue;let Y=(q.getAttribute("data-reactive-filter-text")??q.textContent??"").toLowerCase(),L=q.hasAttribute?.("data-reactive-tags-selected")||j!==""&&!Y.includes(j);if(q.hidden=L,L)q.removeAttribute("data-reactive-highlighted");else G++}let z=this.element.getAttribute("data-reactive-filter-group");if(z)for(let q of this.element.querySelectorAll(z)){if(!$(q))continue;let Y=[...q.querySelectorAll(Z)].filter($);if(Y.length===0)continue;q.hidden=Y.every((L)=>L.hidden)}let K=this.element.getAttribute("data-reactive-filter-empty");if(K){for(let q of this.element.querySelectorAll(K))if($(q))q.hidden=G>0}}#sX(){if(!this.#Q)return;this.element.removeEventListener?.("input",this.#Q),this.element.removeEventListener?.("turbo:morph-element",this.#Q),this.#Q=void 0}#R(){return!!this.element.getAttribute?.("data-reactive-tags-field")}#nX(){if(typeof this.element?.querySelector!=="function")return!1;return!!this.element.querySelector("[data-reactive-nested-json]")}#b(){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}#h(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 $}#jX(X){let Z=this.#b();if(!Z)return!1;let $=this.#h(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.#GX(Z,$);return j}#GX(X,Z){if(X.value=Z.join(","),typeof X.dispatchEvent==="function")X.dispatchEvent(new Event("input",{bubbles:!0}));this.#v()}#aX(){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}#v(){let X=this.#b();if(!X)return;let Z=this.#h(X),$=this.#X();this.#rX(Z,$),this.#tX(Z,$)}#rX(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.#u)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.#u=!0;return}while($.firstChild)$.removeChild($.firstChild);for(let G of X){let z=j.cloneNode(!0);z.setAttribute?.("data-reactive-tag",G);let K=z.matches?.("[data-reactive-tag-text]")?z:(z.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(K)K.textContent=G;let q=[...z.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(z.matches?.('[data-action*="reactive#tagsRemove"]'))q.push(z);for(let Y of q)Y.setAttribute?.("data-reactive-tag-param",G);$.appendChild(z)}}#tX(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.#F())Q.hidden=!1}}if(this.#F())this.#B()}#eX(){return this.#k=Math.max(this.#k+1,Date.now()),this.#k}#XZ(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)))}}#ZZ(X){if(this.#g)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.#g=!0}#$Z(){if(!this.#L)return;this.element.removeEventListener?.("turbo:morph-element",this.#L),this.#L=void 0}#QZ(){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}#jZ(){if(!this.#A)return;this.element.removeEventListener?.("turbo:morph-element",this.#A),this.#A=void 0}#GZ(X,Z,$,Q){let j=new FormData;j.append("token",X),j.append("act",Z);for(let[z,K]of Object.entries($))this.#y(j,`params[${z}]`,K);let G=this.#zZ(Q);for(let{name:z,file:K,multiple:q}of Q){let L=q||G.has(z)?`params[${z}][]`:`params[${z}]`;j.append(L,K,K.name)}return j}#y(X,Z,$){if($==null)X.append(Z,"");else if(Array.isArray($))$.forEach((Q,j)=>this.#y(X,`${Z}[${j}]`,Q));else if(typeof $==="object")for(let[Q,j]of Object.entries($))this.#y(X,`${Z}[${Q}]`,j);else X.append(Z,String($))}#zZ(X){let Z=new Map;for(let{name:$}of X)Z.set($,(Z.get($)??0)+1);return new Set([...Z].filter(([,$])=>$>1).map(([$])=>$))}#zX(X){if(!X)return{};try{return typeof X==="string"?JSON.parse(X):X}catch{return{}}}#KX(X){return XX(X)}#qX(X){ZX(X,(Z)=>this.#YX(Z))}#YX(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.#$($))}#KZ(X,Z){if(X?.checked!=="keep")return!1;let $=Z?.type;return $==="checkbox"||$==="radio"}#qZ(X,Z){if(!X)return null;let $=this.#UX(X,Z,!0);return $.length?$:null}#q(X){if(!X)return;if(!this.element.isConnected)return;for(let Z of X)Z()}#YZ(X,Z,$){this.#HZ(X,Z);let Q=$?this.#UX($,Z,!1):[];i();let j=!1;return()=>{if(j)return;j=!0,this.#WZ(X,Z),s();for(let G of Q)G()}}#UX(X,Z,$){let Q=[];for(let j of this.#HX(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.#UZ(X,Z));if($&&X.checked==="keep"&&Z&&"checked"in Z){let j=Z.checked;Q.push(()=>Z.checked=!j)}return Q}#HX(X,Z){if(X.to==null)return Z?[Z]:[];return this.#YX({to:X.to})}#UZ(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.#_Z(Z,X)}#HZ(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.#WX(X))this.#Y($,X,1)}#WZ(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.#WX(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(" "))}#WX(X){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter(($)=>$.getAttribute("data-reactive-busy-on")===X&&this.#$($))}#_Z(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}#JZ(X){if(!X||typeof X!=="object")return null;let{class:Z,...$}=X;return Z==null?X:{...$,add_class:Z}}#LZ(){return this.#_X??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#MZ(){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}#AZ(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#BZ(){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,KX as registerReactiveJs,LX as registerReactiveDismiss,qX as registerReactiveDefer,y as registerReactiveActions,dX as reactiveActivityCount,mX as pendingDeferVia,s as exitReactiveActivity,NX as escapeRegExp,i as enterReactiveActivity,BX as enableLatencySim,VX as disableLatencySim,sX as default,xX as checkReactiveRegistration,oX as __resetReactiveRegistrationForTest,gX as __resetReactiveOfflineForTest,cX as __resetReactiveLatencyForTest,uX as __resetReactiveDismissForTest,iX as __markReactiveConnectedForTest,w as LATENCY_KEY,o as ACTIVE_ATTR};
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};
2
2
 
3
- //# debugId=01D39E17DBA3F0CE64756E2164756E21
3
+ //# debugId=C4C54B2DD084172064756E2164756E21
4
4
  //# sourceMappingURL=reactive_controller.min.js.map