phlex-reactive 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9485caea574a48c678bd25443d86cb159e7650180431ac6d4086b0b7089ed899
4
- data.tar.gz: f228b7d8b191a1996160b1146ddc9ba3dd94a4be7e16f804a47dd9c32fa44fd0
3
+ metadata.gz: da91cf678610a49eedda39afbad34c05d879bd4a37b30d6a722bb7400178291c
4
+ data.tar.gz: ce7e5870c7e8a9e33d0f61a05b1b18da1e3adea553a7ed2c7402b72fbfda4110
5
5
  SHA512:
6
- metadata.gz: f3ec2c78f75154372430c805be4b6fa70d852b83724ec2f02cf209465e768e1c9f39b52026f16f1dd7411e242647f75ee347a35044453f27f17cf2df603a3a86
7
- data.tar.gz: 7b272fe7a924faee9e3536c6f6f174ea01da8b4e2f41fb2ef6d09c05b4c05a114953f644772289f7e051d76508a8b147dc57723cc7490a0ff5ec8742f969dc9b
6
+ metadata.gz: 36dd243fdc59218e08608ced77ec11aa152a476e483269408b5713c75f9c72c4386b2436143d10ba5d18f5c0456a01f9ee1275d9143678b1feb7c22123dc0b6e
7
+ data.tar.gz: f0f0185d456b4d01db104731e93b56e60dafd8dc6bda77b4aec581290baa067297eb318b5004dfb3d30004d21afe2647f479574786829c98a9f2d0727a32f9a3
data/CHANGELOG.md CHANGED
@@ -6,6 +6,34 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.14.1] - 2026-10-07
10
+
11
+ ### Added
12
+
13
+ - **`js.check_group(group, checked = true, global: false)` — "clear selection"
14
+ without a controller (#342).** A client op that ticks or unticks every owned
15
+ box of a checkbox group from any control (a bulk-action bar's ✕), dispatching
16
+ `input` + `change` on each box it flips and re-syncing the header,
17
+ `reactive_count`, `reactive_show` and `reactive_enable` once — the select-all
18
+ header's own path. A nested root's boxes are left alone; `global: true` (a
19
+ trigger outside the owning root) flips the group in every connected reactive
20
+ root that owns boxes of it. Actor-only: `broadcast_to(js:)` refuses it. A form
21
+ `reset` inside the root now re-syncs the group bindings and re-arms
22
+ checked-count `reactive_on_complete` latches.
23
+
24
+ - **A count and an enable outside the root that owns the checkboxes (#343).**
25
+ `reactive_group_targets("ids[]", count: "#bulk-count", enable: { "#bulk-archive" => 1.. })`,
26
+ spread on the root that owns a checkbox group, drives outside, id-allowlisted
27
+ elements: the ticked count as text, and `disabled` from an Integer (exact
28
+ count), a Range (threshold) or a full conditions Hash. It is the count and
29
+ enable sibling of `reactive_show_targets`, so a list that is its own reactive
30
+ root can drive a bulk bar the page renders. Targets re-sync on every change,
31
+ the header's flip, `js.check_group`, a morph of the owning root and rows
32
+ added or removed; a non-id selector raises at render and is warn-skipped on
33
+ the client. `reactive_group_target_attrs(group, :count)` /
34
+ `(group, :enable, 1..)` give the outside markup its first paint from
35
+ `reactive_values`.
36
+
9
37
  ## [0.14.0] - 2026-10-07
10
38
 
11
39
  This section also covers 0.10.0 through 0.13.4, which were released without
@@ -3366,7 +3394,8 @@ room for dogfood fixes.
3366
3394
  scaffolds a reactive component (and an RSpec spec when the app uses RSpec),
3367
3395
  state-backed by default or record-backed with `--record`.
3368
3396
 
3369
- [Unreleased]: https://github.com/mhenrixon/phlex-reactive/compare/v0.14.0...HEAD
3397
+ [Unreleased]: https://github.com/mhenrixon/phlex-reactive/compare/v0.14.1...HEAD
3398
+ [0.14.1]: https://github.com/mhenrixon/phlex-reactive/compare/v0.14.0...v0.14.1
3370
3399
  [0.14.0]: https://github.com/mhenrixon/phlex-reactive/compare/v0.9.0...v0.14.0
3371
3400
  [0.9.0]: https://github.com/mhenrixon/phlex-reactive/compare/v0.2.6...v0.9.0
3372
3401
  [0.2.6]: https://github.com/mhenrixon/phlex-reactive/compare/v0.2.5...v0.2.6
data/README.md CHANGED
@@ -678,12 +678,13 @@ Use in controllers: `render turbo_stream: Counter.replace(counter)`.
678
678
  | `busy_on(:save)` | Mark any element so it carries `data-reactive-busy` **only while `save` is in flight** — a spinner styled with pure CSS, zero Ruby. See [Loading states](#declarative-loading-states-loading--disable_with). |
679
679
  | `on(:action, once: true)` | Fire at most once, then unbind (Stimulus's native `:once`). |
680
680
  | `on_client(:click, js.toggle("#menu"))` | **Client-only** trigger: applies declared DOM ops with ZERO round trip — no token, no POST, ever. Takes the same `window:`/`once:`/`outside:` modifiers. See [Client-only ops](#client-only-ops-on_client--js--zero-round-trips). |
681
- | `js` | The immutable op builder behind `on_client`: `show`/`hide`/`toggle` (the `hidden` attribute, with an optional `transition:` and `expanded:`), `add_class`/`remove_class`/`toggle_class`, `set_attr`/`remove_attr`/`toggle_attr` (allowlisted names; `toggle_attr` also flips between two values), `focus`/`focus_first`, `text` (set `textContent` — XSS-safe), `dispatch`, `submit` (requestSubmit the target's own form, optionally through a `submitter:`), `paste_into` (read the clipboard into a field, gesture-gated), and `persist_state`/`persist_clear` (the `reactive_persist` draft) — chainable. |
681
+ | `js` | The immutable op builder behind `on_client`: `show`/`hide`/`toggle` (the `hidden` attribute, with an optional `transition:` and `expanded:`), `add_class`/`remove_class`/`toggle_class`, `set_attr`/`remove_attr`/`toggle_attr` (allowlisted names; `toggle_attr` also flips between two values), `focus`/`focus_first`, `text` (set `textContent` — XSS-safe), `dispatch`, `submit` (requestSubmit the target's own form, optionally through a `submitter:`), `paste_into` (read the clipboard into a field, gesture-gated), `check_group` (tick or untick a checkbox group, then re-sync its bindings), and `persist_state`/`persist_clear` (the `reactive_persist` draft) — chainable. |
682
682
  | `reactive_field(:param, **attrs)` | The attribute hash that binds a control to an action param (no magic `name:`) — spread onto any control: `input(**reactive_field(:value, value: @record.name))`, `select(**reactive_field(:status)) { … }`. |
683
683
  | `reactive_text(:name, initial)` | Mirror a compute output (or a declared input) into a **text node** — a live preview heading, a character counter, `"Hello, {name}"` — via `textContent` (XSS-safe). The text sibling of `reactive_field`; carries no `name`, so it's never POSTed. See [Client-side computes](#client-side-computes-reactive_compute--reactive_text). |
684
684
  | `reactive_show(if:/if_any:/unless:)` | **Value-conditional visibility** (the `x-show`/`data-show` case): spread onto the element to show/hide — it toggles `hidden` from the fields' **current values**, client-only, zero round trip. One conditions language: a **Hash is an AND**, an **Array is membership**, a **Range is a threshold**, `if_any:` is OR-of-AND, `unless:` negates. `reactive_values` computes first paint; `disable:` disables a hidden section's controls. See [Value-conditional visibility](#value-conditional-visibility-reactive_show). |
685
685
  | `reactive_enable(if:/if_any:/unless:)` | The sibling of `reactive_show` that flips the element's **own `disabled`** (a button, a fieldset) instead of `hidden` — same conditions, same `reactive_values` first paint. `button(**reactive_enable(if: { "ids[]" => { checked: 1.. } }))`. See [Bulk selection](#bulk-selection-reactive_select_all-reactive_count-reactive_enable). |
686
686
  | `reactive_select_all("ids[]")` / `reactive_count("ids[]")` | A checkbox **group**'s header box (ticks/unticks every owned box; shows checked / indeterminate / unchecked) and its ticked count as text — re-synced on every change and when rows are appended or removed. See [Bulk selection](#bulk-selection-reactive_select_all-reactive_count-reactive_enable). |
687
+ | `reactive_group_targets("ids[]", count: "#c", enable: { "#b" => 1.. })` | Spread on the root that **owns** a checkbox group: drives a count and an enable on outside, id-allowlisted elements (a bulk bar the page renders). `reactive_group_target_attrs` gives that outside markup its first paint. See [A bulk bar outside the list's root](#a-bulk-bar-outside-the-lists-root-reactive_group_targets). |
687
688
  | `reactive_show_targets(:field, "#id" => value)` | **Cross-root visibility**: the component that owns the field declares which **outside**, id-allowlisted elements it governs (a nav tab, a panel in another pane) — the visibility parallel of `mirror:`. Spread on the **root** via `mix(reactive_root, …)`, **once per root** — several fields go in one call via the hash form. The value uses the same `where`-style vocabulary (`"advanced"`, `%w[a b]`, `10..`); a `"#id"` **key** takes a full conditions Hash for a **multi-field** predicate (`"#warn" => { if: { type: "trade", price: ..0 } }`). Id selectors only (raise at render + client warn-skip); toggles `hidden` only. See [Value-conditional visibility](#value-conditional-visibility-reactive_show). |
688
689
  | `reactive_persist(key:, ttl: 7.days)` | **Client-only drafts**: spread on the **root** (once) and the generic controller keeps a `localStorage` draft of every **owned** control — debounced write on `input`, immediate on `change`, flushed on disconnect, restored into **blank** controls on the next connect (`restore: :always` lets the draft win), cleared by a successful Turbo submit / `ttl` / `js.persist_clear`. Never hidden/file/password; `reactive_persist_skip` opts a control out; `fields:` narrows. See [Client-only drafts](#client-only-drafts-reactive_persist). |
689
690
  | `js.persist_state(step: 2)` / `js.persist_clear` | The draft ops (actor-only): merge a flat state bag into the draft (restored as `data-reactive-persist-state` + the `reactive:persist-restored` event) / forget the draft. |
@@ -1564,6 +1565,52 @@ end
1564
1565
  - **`js.submit(to, submitter:)`** submits the form through the hidden submit
1565
1566
  button, so the POST carries `bulk_action=delete` (see the
1566
1567
  [op vocabulary](#client-only-ops-on_client--js--zero-round-trips)).
1568
+ - **`js.check_group(group, checked = true)`** ticks (or, with `false`, unticks)
1569
+ every owned box of the group from any other control — the "Clear selection ✕"
1570
+ of a bulk-action bar — the way the header does: every box first, then `input`
1571
+ + `change` on each one it flipped, then one re-sync of the header, the count,
1572
+ the shows and the enables. `global: true` is for a trigger outside the root
1573
+ that owns the group: every connected reactive root on the page flips the boxes
1574
+ of that name it owns (a root not yet connected takes no part). Actor-only: a broadcast refuses it.
1575
+
1576
+ ```ruby
1577
+ button(type: "button", **on_client(:click, js.check_group("ids[]", false))) { "✕" }
1578
+ ```
1579
+ - **A form `reset`** inside the root re-syncs the group bindings once the reset
1580
+ has applied, so `button(type: "reset")` never leaves a stale count.
1581
+
1582
+ #### A bulk bar outside the list's root (`reactive_group_targets`)
1583
+
1584
+ When the list is its own reactive root (an action filters, sorts or paginates
1585
+ it), its boxes are not the page's (#15), so a bulk bar the page renders outside
1586
+ it cannot count them. The root that **owns** the boxes declares the outside
1587
+ ids it drives instead, next to `reactive_show_targets`:
1588
+
1589
+ ```ruby
1590
+ # The list (its own reactive root):
1591
+ div(**mix(reactive_root,
1592
+ reactive_show_targets("#bulk-bar" => { if: { "ids[]" => { checked: 1.. } } }),
1593
+ reactive_group_targets("ids[]",
1594
+ count: "#bulk-count", # textContent = ticked count
1595
+ enable: { "#bulk-archive" => 1.. }))) # disabled = !(count in range)
1596
+
1597
+ # The page, outside the list's root (first paint from ITS reactive_values):
1598
+ span(id: "bulk-count") { reactive_group_target_attrs("ids[]", :count).to_s }
1599
+ button(id: "bulk-archive", **reactive_group_target_attrs("ids[]", :enable, 1..)) { "Archive" }
1600
+ ```
1601
+
1602
+ - Targets are **id selectors only** (a raise at render, a warn-skip on the
1603
+ client), resolved document-wide: inside another root or outside every root.
1604
+ A missing one is skipped. `count:` takes one id or an Array of them.
1605
+ - An `enable:` value is an Integer (an exact count), a Range (a threshold) or a
1606
+ full `{ if:/if_any:/unless: }` conditions Hash.
1607
+ - They re-sync on every change, on the select-all header's flip, on a morph of
1608
+ the owning root, and when rows are added or removed.
1609
+ - **One call per root**; several groups go in the hash form:
1610
+ `reactive_group_targets("ids[]" => { count: "#c" }, "tags[]" => { enable: { "#t" => 1.. } })`.
1611
+ - `reactive_group_target_attrs(group, :count)` is the Integer seed;
1612
+ `(group, :enable, condition)` is `{ disabled: }` (or `{}` when
1613
+ `reactive_values` does not cover the group, and the client seeds it).
1567
1614
 
1568
1615
  ### Client-only drafts (`reactive_persist`)
1569
1616
 
@@ -2725,9 +2772,10 @@ Notifications::Badge.broadcast_to(user, :alerts,
2725
2772
  ```
2726
2773
 
2727
2774
  `broadcast_to` with `js:` **refuses the actor-only ops** (`focus`/`focus_first`/
2728
- `submit`/`paste_into` raise `ArgumentError`): broadcasting focus would steal it
2729
- in every subscriber's tab, a broadcast submit would force-submit every
2730
- subscriber's form, and a broadcast clipboard read would be hostile — these
2775
+ `submit`/`paste_into`/`persist_state`/`persist_clear`/`check_group` raise
2776
+ `ArgumentError`): broadcasting focus would steal it in every subscriber's tab, a
2777
+ broadcast submit would force-submit every subscriber's form, and a broadcast
2778
+ clipboard read, draft write or selection change would be hostile — these
2731
2779
  belong to the actor's own reply or gesture. Everything else is a fair broadcast
2732
2780
  (class and attribute toggles, `text`, `dispatch`). As with `on_client`, the ops are
2733
2781
  whitelist-interpreted client-side — an unknown op warns and is skipped — and the
@@ -1,4 +1,4 @@
1
- import{Controller as Ae}from"@hotwired/stimulus";import{confirmResolver as U}from"phlex/reactive/confirm";function Ee(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:visit"])return;e["reactive:visit"]=function(){let t=this.getAttribute("data-url");if(t)window.Turbo.visit(t,{action:"advance"})}}function Fe(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:token"])return;e["reactive:token"]=function(){let t=this.getAttribute("data-reactive-token-value"),r=this.getAttribute("target");if(!t||!r)return;let n=document.getElementById(r);if(n)n.setAttribute("data-reactive-token-value",t)}}function ke(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:js"])return;e["reactive:js"]=function(){let t=W(this.getAttribute("data-reactive-ops"));if(!t.length)return;let r=this.getAttribute("target"),n=this.getAttribute("data-reactive-verbose")==="true",i=r?document.getElementById(r):null;if(r&&!i){if(n)_("devtools",(o)=>o.missingRoot(r));return}q(t,(o)=>Qe(o,i),n?(o,a)=>_("devtools",(s)=>s.diagnoseStream(o,a,i)):void 0)}}function Le(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:defer"])return;e["reactive:defer"]=function(){_("defer",(t)=>t.streamAction(this))}}var J=!1,D=null;function Re(){if(J)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;J=!0,document.addEventListener("turbo:before-stream-render",(e)=>{if(D)D(e,m.get("effects"));else m.get("effects")?.wrap(e)})}function oe(e){D=e}var K=!1;function z(e){return e===document.activeElement&&(e.localName==="input"||e.localName==="textarea")&&!e.hasAttribute("data-reactive-morph-value")&&!!e.closest('[data-controller~="reactive"]')}function xe(){if(K)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;K=!0,document.addEventListener("turbo:before-morph-element",(e)=>{let t=e.target,r=e.detail?.newElement;if(!r||e.defaultPrevented||t.localName!=="input"||!z(t))return;let n=r.getAttribute("value");if(n==null)t.removeAttribute("value");else if(t.getAttribute("value")!==n)t.setAttribute("value",n)}),document.addEventListener("turbo:before-morph-attribute",(e)=>{if(e.detail?.attributeName==="value"&&z(e.target))e.preventDefault()})}var Pe="__materialize",H=!1;function Ie(){if(H)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;H=!0;let e=()=>{let t=document.documentElement;if(typeof t?.toggleAttribute!=="function")return;t.toggleAttribute("data-reactive-offline",globalThis.navigator?.onLine===!1)};e(),window.addEventListener("online",e),window.addEventListener("offline",e)}var Ne="phlex-reactive:latency";function ae(){return typeof sessionStorage<"u"&&Boolean(sessionStorage.getItem(Ne))}function B(){if(typeof document>"u")return;if(!m.has("devtools")&&!b.get("devtools")[1])return;let e=document.querySelector?.('meta[name="phlex-reactive-env"]')?.content==="development";if(e||ae())_("devtools",(t)=>e&&t.attach())}var ce="data-reactive-active",v=0;function ue(){if(v++,v===1)fe("reactive:busy")}function le(){if(v===0)return;if(v--,v===0)fe("reactive:idle")}function Et(){return v}function Ft(){v=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(ce)}function fe(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.toggleAttribute==="function")t.toggleAttribute(ce,v>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(e,{detail:{count:v}}))}var de="data-reactive-requests";function he(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.setAttribute!=="function"||!Oe(t))return;let r=Me(t);r[e]=(Number(r[e])||0)+1,t.setAttribute(de,JSON.stringify(r))}function Oe(e){return e.hasAttribute?.("data-reactive-verbose")||!!document.querySelector?.('[data-reactive-verbose="true"]')}function Me(e){try{let t=JSON.parse(e.getAttribute(de));if(t&&typeof t==="object")return{action:0,defer:0,...t}}catch{}return{action:0,defer:0}}function V(){Ee(),Fe(),ke(),Le(),Re(),xe(),Ie(),B()}function Ce(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var me=Symbol.for("phlex-reactive.core");if(globalThis[me])console.error("[phlex-reactive] the client was loaded twice. Import EITHER phlex/reactive/reactive_controller (the default, "+"everything in one file) OR phlex/reactive/core (features on demand), not both — each carries its own state.");globalThis[me]=!0;var pe=!1;function De(){if(pe)return;if(typeof document>"u")return;let e=document.querySelectorAll('[data-controller~="reactive"]');if(!e||e.length===0)return;console.warn("[phlex-reactive] found "+e.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.')}if(typeof window<"u"&&typeof document<"u"){let e=()=>setTimeout(De,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",e,{once:!0});else e()}var qe=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function $e(e){let t=String(e).toLowerCase();return t.startsWith("on")||qe.has(t)}var I=new WeakMap;function Be(e,t,r){let[n,i,o]=t;I.get(e)?.(),e.classList.add(n,i),r();let a=!1,s=requestAnimationFrame(()=>{if(a)return;e.classList.remove(i),e.classList.add(o)}),c=(h)=>{if(a||h&&h.target!==e)return;a=!0,I.delete(e),clearTimeout(l),globalThis.cancelAnimationFrame?.(s),e.removeEventListener("animationend",c),e.removeEventListener("transitionend",c),e.classList.remove(n,i,o)};I.set(e,c),e.addEventListener("animationend",c),e.addEventListener("transitionend",c);let l=setTimeout(c,We(e))}function We(e){let t=0;try{let r=getComputedStyle(e);for(let n of["transition","animation"]){let[i,o]=["Duration","Delay"].map((s)=>String(r[n+s]).split(",").map((c)=>parseFloat(c)*(/ms/.test(c)?1:1000)||0)),a=String(r[n+"IterationCount"]).split(",").map((s)=>/inf/.test(s)?1/0:parseFloat(s)>=0?parseFloat(s):1);for(let s=0;s<i.length||s<o.length||s<a.length;s++){let c=i[s%i.length]*a[s%a.length]||0;t=Math.max(t,c+o[s%o.length])}}}catch{}return Math.min(Math.max(t+50,350),5000)}var je=":is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])",Ue=new Set(["lexxy-editor","trix-editor"]);function Je(e){return Ue.has(e.localName)?typeof e.value==="string":!0}var Y=Object.freeze({show:(e,t,r)=>N(e,!1,t,r),hide:(e,t,r)=>N(e,!0,t,r),toggle:(e,t,r)=>N(e,!e.hidden,t,r),add_class:(e,t)=>e.classList.add(...t.classes??[]),remove_class:(e,t)=>e.classList.remove(...t.classes??[]),toggle_class:(e,t)=>(t.classes??[]).forEach((r)=>e.classList.toggle(r)),set_attr:(e,t)=>{if(O(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(O(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!O(t.name))return;if(Array.isArray(t.values)){let[r,n]=t.values;e.setAttribute(t.name,e.getAttribute(t.name)===r?n:r)}else if(e.hasAttribute(t.name))e.removeAttribute(t.name);else e.setAttribute(t.name,"")},focus:(e)=>e.focus?.(),focus_first:(e)=>Ye(e)?.focus?.(),text:(e,t)=>{let r=String(t.value??"");if(e.textContent!==r)e.textContent=r},dispatch:(e,t)=>{e.dispatchEvent(new CustomEvent(t.name,{bubbles:!0,composed:!0,detail:t.detail??{}}))},submit:(e,t,r)=>{let n=Ke(e);if(!n)return;let i=null;if(t?.submitter!=null&&typeof r==="function"){if(i=r({...t,to:t.submitter})[0]??null,!(i?.form===n&&(i.type==="submit"||i.type==="image")))console.warn(`[phlex-reactive] submitter ${t.submitter} is not a submit control of the form — ignored`),i=null}i?n.requestSubmit?.(i):n.requestSubmit?.()},paste_into:(e)=>ze(e),persist_state:(e,t)=>_("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>_("persist",(t)=>t.clearRoot(e))});function Ke(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function ze(e){let t=globalThis.navigator?.clipboard;if(typeof t?.readText!=="function")return;t.readText().then((r)=>{if(!r)return;if(e.value=r,typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}));e.focus?.()}).catch(()=>{})}function He(e,t,r){if(r?.transition)Be(e,r.transition,()=>e.hidden=t);else e.hidden=t}function N(e,t,r,n){if(He(e,t,r),r?.expanded==null||typeof n!=="function")return;for(let i of n({...r,to:r.expanded}))i.setAttribute?.("aria-expanded",String(!t))}function O(e){if(!$e(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}var Ve='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function Ye(e){return e.querySelectorAll?.(Ve)?.[0]??null}function W(e){if(Array.isArray(e))return e;if(typeof e!=="string")return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}var G=Object.freeze({enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"}),X=Object.freeze(["meta","ctrl","alt","shift"]);function j(e,t,r){let n=e.split("+");for(let a of X)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!X.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let o=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(G,i)?G[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof o==="string"&&o.toLowerCase()===t.key.toLowerCase()}function Ge(e){if(Array.isArray(e))return[{ops:e,legacy:!0}];if(e&&typeof e==="object")return[e];if(typeof e!=="string")return[];let t=e.trim();if(t.startsWith("["))return[{ops:W(t),legacy:!0}];let r=[];for(let n of t.split(" ")){if(n==="")continue;let i=null;try{i=JSON.parse(n)}catch{i=null}if(i&&typeof i==="object"&&!Array.isArray(i))r.push(i);else console.warn(`[phlex-reactive] malformed on_client binding record ${JSON.stringify(n)} — skipped`)}return r}function Z(e,t,r){if(e.legacy)return!0;let n=e.on;if(typeof n!=="string"||n==="")return!1;let i=n.indexOf(".");if(t.type!==(i<0?n:n.slice(0,i)))return!1;if(Boolean(e.window)!==_e(t.currentTarget))return!1;return i<0||r===null||j(n.slice(i+1),t,r)}var Q=new WeakMap;function Xe(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=Q.get(e);if(!i)i=new WeakMap,Q.set(e,i);let o=i.get(n);if(!o)o=new Set,i.set(n,o);let a=t.params?.ops,c=(n===globalThis.window?`${typeof a==="string"?a:JSON.stringify(a??null)}|`:"")+JSON.stringify(r);if(o.has(c))return!0;return o.add(c),!1}var ee=new WeakMap;function Ze(e,t){if(e===null||typeof e!=="object")return!1;let r=e.params?.ops,n=typeof r==="string"?r:JSON.stringify(r??null),i=ee.get(e);if(!i)i=new WeakMap,ee.set(e,i);let o=i.get(t);if(!o)o=new Map,i.set(t,o);let a=o.get(e.currentTarget);if(!a)a=new Set,o.set(e.currentTarget,a);if(a.has(n))return!0;return a.add(n),!1}function q(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,o={}]=n;if(!Object.hasOwn(Y,i)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(i)} — skipped`);continue}let a=t(o);if(a.length===0&&r)r(i,o);for(let s of a)Y[i](s,o,t)}}function Qe(e,t){let r=e.to;if(t){if(r==="@root")return[t];if(typeof r!=="string"||r==="")return[];if(e.global)return[...document.querySelectorAll(r)];return[...t.querySelectorAll(r)]}if(typeof r!=="string"||r===""||r==="@root")return[];return[...document.querySelectorAll(r)]}function et(e){let t=e.getAttribute?.("data-reactive-persist");return Boolean(t)&&t!=="off"}function ge(e){return["defer-token","defer-src","lazy-on","lazy-visible"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)}function tt(e){return(e.getAttribute?.("data-action")??"").includes("reactive#trackDirty")||e.getAttribute?.("data-reactive-clipboard")!=null||e.querySelector?.('[data-action*="reactive#trackDirty"],[data-reactive-clipboard]')!=null}function rt(e){return["show-targets","on-complete","filter-input","tags-field"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)||(e.querySelectorAll?.("[data-reactive-show-field], [data-reactive-show]")??[]).length>0||e.querySelector?.("[data-reactive-nested-json], [data-reactive-nested-list], [data-reactive-confirm-when-param], [data-reactive-enable], [data-reactive-select-all], [data-reactive-count]")!=null}function nt(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}var it=[["persist",[et,null,null,!0]],["defer",[ge,null]],["form",[tt,null]],["bindings",[rt,null,null,!0]],["compute",[nt,null,null,!0]],["effects",[(e)=>["enter","update","exit"].some((t)=>e.getAttribute?.(`data-reactive-effect-${t}`)!=null),null]],["hints",[(e)=>e.querySelector?.("[data-reactive-optimistic-param], [data-reactive-busy-param], [data-reactive-loading-param]")!=null,null]],["devtools",[(e)=>e.getAttribute?.("data-reactive-debug")==="true",null]]],b=new Map(it),te=new Map,m=new Map,st=new Map;function w(e,t,r){ye.set(e,[t,r]),ot(e)}var ye=new Map;function ot(e){let t=b.get(e),[r,n]=ye.get(e);t[1]=r,t[2]=n}function kt(e,t){t.install?.(F),m.set(e,t),st.set(e,t)}function be(e){let t=[];for(let[r,[n]]of b){if(!n||m.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function ve(e){return E(e).catch((t)=>R(e,"load",t))}function E(e){let t=te.get(e);if(!t)t=(b.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(F),m.set(e,n),n)),te.set(e,t);return t}var re=new Set;function R(e,t,r){let n=e+t;if(re.has(n))return;re.add(n),console.error(`[phlex-reactive] the "${e}" feature module (phlex/reactive/features/${e}) is unavailable: ${t}. If you bundle or vendor the client, alias or pin phlex/reactive/features/* (README: esbuild / webpack / bun).`,r)}function _(e,t){let r=m.get(e);if(r)return t(r);E(e).then(t,(n)=>R(e,"load",n))}var at=1e4;function M(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:at}function Lt(){return[...b.keys()]}var ne=Promise.resolve();function ie(e,t,r){let n=F.waiting.get(e);if(n&&n[t]===r)delete n[t]}var F={enter:ue,exit:le,count:he,waiting:new WeakMap};var k=Symbol.for("phlex-reactive.early"),ct=1e4,ut=1500,_e=(e)=>e!=null&&(e===globalThis.window||e.window===e);function C(){return globalThis[k]??={queue:[],connected:new WeakSet},globalThis[k]}function lt(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:ct}function ft(e){let t={};for(let{name:r,value:n}of Array.from(e.attributes??[])){let i=/^data-reactive-(.+)-param$/i.exec(r);if(!i)continue;let o;try{o=JSON.parse(n)}catch{o=n}t[i[1].replace(/[-_]([a-z0-9])/g,(a,s)=>s.toUpperCase())]=o}return t}function dt(e,t,r){return{[k]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:ft(t),key:e.key,code:e.code,metaKey:e.metaKey,ctrlKey:e.ctrlKey,altKey:e.altKey,shiftKey:e.shiftKey,button:e.button,submitter:e.submitter,bubbles:e.bubbles,timeStamp:e.timeStamp,defaultPrevented:e.defaultPrevented,preventDefault(){},stopPropagation(){},stopImmediatePropagation(){}}}var x=new WeakMap;function ht(e,{token:t,type:r,method:n,filter:i,win:o},a){let s=x.get(e);if(!s)x.set(e,s=new Map);let c=o?`${t} ${a}`:t;if(s.has(c))return!1;return s.set(c,{type:r,method:n,filter:i,win:o,params:a,armed:!0}),!0}function se(e,t,r,n){if(e?.[k])return!1;let i=_e(e?.currentTarget),o=i?n:e?.currentTarget,a=pt(e,o,i?`@${t}`:t),s=x.get(o),c=i&&JSON.stringify(e.params);for(let l of s?.values()??[]){if(!l.armed||l.method!==t||l.type!==e.type||Boolean(l.win)!==i)continue;if(i&&l.params!==c)continue;if(l.filter&&!j(l.filter,e,r))continue;return l.armed=!1,!0}return a}var L=new WeakMap;function mt(e,t,r){let n=L.get(e);if(!n)L.set(e,n=new Map),setTimeout(()=>L.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function pt(e,t,r){let n=e&&L.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class we extends Ae{static values={token:String};#v;#_=new Map;#u=new Map;#Q;#L;#j;#R=0;#l=new Map;#x=new WeakMap;#w;featuresReady=ne;#t=new Map;#P=new Set;#f=!1;#r=null;#d=new Map;#S=new Map;#h=new Map;#m=0;#U;#Ne=0;#Oe=0;connect(){if(pe=!0,C().connected.add(this.element),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-token-value")!=null||ge(this.element))this.#w=(e)=>{if(e.target!==this.element)return;this.#J(!0)},this.element.addEventListener?.("turbo:morph-element",this.#w);this.#m++,this.featuresReady=ne,this.#J(),this.#ie()}#Me(e){}#Ce(e,t,r,n){}#De(){}#qe(e,t){}#J(e){{let t=this.#m,r=[];for(let[o,[a]]of b){if(!a||this.#P.has(o))continue;let s=m.get(o);if(s&&!s.connect)continue;try{if(a(this.element))r.push(o)}catch(c){this.#p(o,"detect",c)}}if(r.length===0)return;for(let o of r)this.#P.add(o);if(!this.#f&&r.every((o)=>m.has(o))){for(let o of r)this.#I(t,o,m.get(o),e);return}for(let o of r){let a=this.#ee(t,o),s=[];for(let l of b.keys()){if(l===o)break;if(this.#h.has(l))s.push(this.#h.get(l))}let c=Promise.all(s).then(()=>a).then((l)=>l&&this.#I(t,o,l,e));if(this.#h.set(o,c),b.get(o)[3])this.#r=c}let n=this.#r;n?.then(()=>{if(this.#r===n)this.#r=null}),this.#f=!0;let i=Promise.all(this.#h.values()).then(()=>{if(this.featuresReady===i)this.#f=!1});this.featuresReady=i}}#ee(e,t){{let r=()=>e===this.#m;return this.#te(t),new Promise((n)=>{let i=!1,o=setTimeout(()=>{if(this.#d.delete(o),i=!0,r())this.#p(t,"timeout",Error(`not loaded after ${M()} ms`));n(null)},M());this.#d.set(o,n);let a=()=>{clearTimeout(o),this.#d.delete(o)};E(t).then((s)=>{if(a(),i)queueMicrotask(()=>this.#I(e,t,s));else n(s)},(s)=>{if(a(),r())this.#p(t,"load",s);n(null)})})}}#te(e){{let t=b.get(e)[2];if(!t)return;let r={};try{this.#S.set(e,[t(this.element,r),r]),F.waiting.set(this.element,{...F.waiting.get(this.element),[e]:r})}catch(n){this.#p(e,"detect",n)}}}#K(e,t){{let[r,n]=this.#S.get(e)??[];if(this.#S.delete(e),!t)ie(this.element,e,n);try{r?.()}catch(i){console.error(`[phlex-reactive] the "${e}" feature module failed to stop waiting`,i)}return n}}#I(e,t,r,n){{if(e!==this.#m)return;let i=this.#K(t);try{r.connect?.(this,this.#e(),n,i),this.#t.set(t,r)}catch(o){this.#p(t,"connect",o)}}}#e(){return this.#U??={emit:(e,t,r)=>this.#i(e,t,r),reseed:()=>this.#re(),proceed:(e,t,r)=>this.#O(e,t,r),forgetToken:()=>{this.#v=void 0},owns:(e)=>this.#F(e),ownership:()=>this.#D(),opTargets:(e)=>this.#W(e),diagnose:(e,t)=>this.#B(e,t),applyOps:(e,t)=>q(e,(r)=>this.#W(t!=null&&r.to==null?{...r,to:t}:r),(r,n)=>this.#B(`client op "${r}"`,n)),listnavOptions:(e)=>this.#y(e),collectFields:()=>this.#G(),confirm:(e,t)=>Promise.resolve().then(()=>U(e,t)).catch(()=>!1)},this.#U}#re(){this.#t.get("form")?.scan(this,this.#e()),this.#t.get("bindings")?.reseed(this),this.#t.get("compute")?.seed(this)}#p(e,t,r){if(R(e,t,r),this.#n("feature"),t==="load"&&this.element.getAttribute?.("data-reactive-defer-pending"))this.element.removeAttribute("data-reactive-defer-pending"),this.element.removeAttribute("aria-busy");this.#i("reactive:error",{kind:"feature",feature:e,phase:t,error:r})}#ne(){{this.#m++;for(let[t,r]of this.#d)clearTimeout(t),r(null);this.#d.clear();for(let t of[...this.#S.keys()]){let r=this.#K(t,!0),n=this.element;_(t,(i)=>{i.abandon?.(n,r),ie(n,t,r)})}this.#P.clear(),this.#h.clear(),this.#f=!1,this.#r=null;let e=[...this.#t];this.#t.clear();for(let[t,r]of e)try{r.disconnect?.(this,this.#e())}catch(n){console.error(`[phlex-reactive] the "${t}" feature module failed to disconnect`,n)}}}#ie(){if(this.element.setAttribute?.("data-reactive-connected",""),this.element.isConnected)this.element.dispatchEvent?.(new CustomEvent("reactive:connect",{bubbles:!0,composed:!0,detail:{id:this.element.id}}));this.#se()}#N=new Set;#se(){let{queue:e}=C();if(e.length===0)return;let t=[];for(let i=e.length-1;i>=0;i--){let{root:o}=e[i];if(o===this.element||!o.isConnected)t.unshift(...e.splice(i,1))}let r=lt(),n=new Map;for(let i of t){let o=n.get(i.event)??[new Set,new Set];n.set(i.event,o);let a=o[+!!i.win];if(a.has(i.el))continue;a.add(i.el);let s=i.win?Math.min(ut,r):r,c=i.root!==this.element?"its root left the page before a controller connected":performance.now()-i.at>s?`it is older than the ${s} ms ${i.win?"window-trigger":"early-event"} TTL`:i.el.isConnected&&this.element.contains(i.el)?null:"its element left the root before the controller connected";if(c){if(this.#$())console.warn(`[phlex-reactive] dropped an early "${i.event.type}" trigger: ${c}`);continue}this.#oe(i)}}#oe({event:e,el:t,descs:r,win:n}){let i=dt(e,t,n),o=this.application?.schema?.keyMappings,a=(t.getAttribute("data-action")??"").split(/\s+/),s=n?this.element:t;for(let c of r){if(!a.includes(c.token))continue;if(c.filter&&!j(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!ht(s,c,n&&JSON.stringify(i.params)))continue;this.#N.add(s)}if(mt(e,s,n?`@${c.method}`:c.method),c.method==="runOps")this.runOps(i);else this.dispatch(i)}}disconnect(){if(this.#ne(),this.#fe(),this.#he(),this.#w)this.element.removeEventListener?.("turbo:morph-element",this.#w);C().connected.delete(this.element),this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#N)x.delete(e);this.#N.clear()}dispatch(e){if(se(e,"dispatch",this.application?.schema?.keyMappings,this.element))return;let{action:t,params:r,debounce:n,throttle:i,confirm:o,confirmWhen:a,outside:s,window:c,optimistic:l}=e.params;if(!t)return;let h=e.params.busy??e.params.loading;if(s&&this.element.contains(e.target))return;let d=e.currentTarget??e.target;if(!c&&!this.#Ee(l,d))e.preventDefault();if(t===Pe){let y=()=>{{let T=this.#t.get("defer");if(T)return T.materialize(this)}if(this.tokenValue)return this.#O(d,t,"{}")};return this.#f?this.featuresReady.then(y):y()}let f=this.#z(o,a),g=()=>this.#O(d,t,r,n,i,l,h);if(!f)return g();if(f instanceof Promise)return f.then((y)=>y?this.#T(y,d,g):g());this.#T(f,d,g)}#T(e,t,r){return Promise.resolve().then(()=>U(e,{el:t})).catch(()=>!1).then((n)=>{if(n)r()})}#z(e,t){if(e)return e;if(!t)return null;{let r=m.get("bindings");if(r)return r.confirmMessage(this,this.#e(),t);return this.#H("bindings").then((n)=>n&&n.confirmMessage(this,this.#e(),t))}}#H(e){{let t;return Promise.race([E(e).catch((r)=>(R(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),M()))]).finally(()=>clearTimeout(t))}}runOps(e){if(se(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(Ze(e,this))return;let t=e.params??{},r=e.currentTarget??e.target,n=Ge(t.ops),i=n.filter((a)=>Z(a,e,null)),o=i.length<=1?i:i.filter((a)=>Z(a,e,this.application?.schema?.keyMappings));if(o.length===0&&n.length>0){if(this.#$())this.#b((a)=>a.noBinding(this,e));return}for(let a of o){if(a.outside&&e[k])continue;if(Xe(this,e,a))continue;this.#ae(a.legacy?{...t,ops:a.ops}:a,e,r)}}#ae({ops:e,confirm:t,confirmWhen:r,outside:n,window:i},o,a){if(n&&this.element.contains(o.target))return;if(!i)o.preventDefault();let s=this.#z(t,r),c=()=>this.#Ae(this.#Te(e));if(!s)return c();if(s instanceof Promise)return s.then((l)=>l?this.#T(l,a,c):c());this.#T(s,a,c)}recompute(e){return m.get("compute")?.recompute(this,this.#e(),e)}tagsAdd(e){if(e?.defaultPrevented)return;if(this.#y(e).some((t)=>t.hasAttribute?.("data-reactive-highlighted")))return;return this.#g("tagsAdd",e)}tagsPick(e){return this.#g("tagsPick",e)}tagsRemove(e){return this.#g("tagsRemove",e)}nestedAdd(e){return this.#g("nestedAdd",e)}nestedRemove(e){return this.#g("nestedRemove",e)}syncNestedJson(e){return m.get("bindings")?.syncNestedJson(this,this.#e(),e)}#g(e,t){{let r=m.get("bindings");if(r)return r[e](this,this.#e(),t);t?.preventDefault?.();let n={currentTarget:t?.currentTarget??null,target:t?.target??null,preventDefault(){}};return _("bindings",(i)=>i[e](this,this.#e(),n))}}trackDirty(){(this.#t.get("form")??m.get("form"))?.scan(this,this.#e())}listnavNext(e){this.#A(e,(t,r)=>t<0?0:(t+1)%r)}listnavPrev(e){this.#A(e,(t,r)=>t<0?r-1:(t-1+r)%r)}listnavFirst(e){this.#A(e,()=>0)}listnavLast(e){this.#A(e,(t,r)=>r-1)}listnavPick(e){let t=this.#y(e),r=t.findIndex((n)=>n.hasAttribute("data-reactive-highlighted"));if(r<0)return;e.preventDefault(),t[r].click()}listnavClose(e){for(let t of this.#y(e))t.removeAttribute("data-reactive-highlighted")}#A(e,t){let r=this.#y(e);if(!r.length)return;e.preventDefault();let n=this.#ce(e),i=globalThis.document?.activeElement,o=n?r.findIndex((s)=>s===i||i!=null&&s.contains?.(i)):r.findIndex((s)=>s.hasAttribute("data-reactive-highlighted")),a=r[t(o,r.length)];if(n)a.focus?.();else{for(let s of r)s.removeAttribute("data-reactive-highlighted");a.setAttribute("data-reactive-highlighted","true")}a.scrollIntoView?.({block:"nearest"})}#ce(e){return(e?.currentTarget??e?.target??this.element).getAttribute?.("data-reactive-listnav-focus-param")==="true"}#y(e){let r=(e?.currentTarget??e?.target??this.element).getAttribute?.("data-reactive-listnav-option-param")??this.element.getAttribute("data-reactive-listnav-option-param");if(!r)return[];let n=this.#D();return Array.from(this.element.querySelectorAll(r)).filter((i)=>!i.hidden&&n(i))}#O(e,t,r,n,i,o,a){if(this.#i("reactive:before-dispatch",{action:t,params:this.#X(r),element:this.element},{cancelable:!0}).defaultPrevented)return;let c=Number(n)||0;if(c>0)return this.#le(e,c,t,r,o,a);let l=Number(i)||0;if(l>0)return this.#de(e,l,t,r,o,a);return this.#E(t,r,o,e,a)}#E(e,t,r,n,i){let o={inverse:null,undo:[],resurrect:null},a=this.#Fe(e,n,o),s=Boolean(r||i),c=(f)=>{if(!s||!f)return;let g=this.#e();if(o.inverse=f.optimistic(this,g,r,n),o.undo.push(...f.busy(this,g,i,n)),this.#C())o.resurrect=f.resurrection(this,g,r,n)},l=m.get("hints");if(!s||l)c(l);let h=()=>this.#ye(e,t,o,a),d=()=>this.#r?this.#r.then(h):h();return this.queue=(this.queue??Promise.resolve()).then(()=>s&&!l?this.#ue().then(c).then(d):d()),this.queue}#ue(){return this.#H("hints")}#le(e,t,r,n,i,o){this.#M(e);let a=()=>{this.#M(e),this.#E(r,n,i,e,o)},s=setTimeout(a,t);e?.addEventListener?.("blur",a,{once:!0}),this.#_.set(e,{timer:s,flush:a})}#M(e){let t=this.#_.get(e);if(!t)return;clearTimeout(t.timer),e?.removeEventListener?.("blur",t.flush),this.#_.delete(e)}#fe(){for(let e of[...this.#_.keys()])this.#M(e)}#de(e,t,r,n,i,o){let a=this.#u.get(e)??new Map;if(a.has(r))return;let s=setTimeout(()=>{if(a.delete(r),a.size===0)this.#u.delete(e)},t);return a.set(r,s),this.#u.set(e,a),this.#E(r,n,i,e,o)}#he(){for(let e of this.#u.values())for(let t of e.values())clearTimeout(t);this.#u.clear()}#i(e,t,{cancelable:r=!1}={}){let n=new CustomEvent(e,{bubbles:!0,composed:!0,cancelable:r,detail:t});return(this.element.isConnected?this.element:document).dispatchEvent(n),n}#s(e,t,r,n){let i=()=>{if(!this.element.isConnected){console.warn("[phlex-reactive] retry() ignored — the reactive root left the DOM");return}return this.#E(e,t)};this.#i("reactive:error",{action:e,params:r,...n,retry:i})}#n(e){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",e)}#me(){this.element?.removeAttribute?.("data-reactive-error")}#pe(){let e=document.querySelector("[data-reactive-error-flash]");if(!e?.content)return;let t=e.getAttribute("data-reactive-error-flash")||"flash",r=document.getElementById(t);if(!r)return;r.appendChild(e.content.cloneNode(!0))}#ge(){{let e=m.get("devtools");if(e)return e.delay();if(ae())return E("devtools").then((t)=>t.delay(),()=>{})}}#C(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#V(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}async#ye(e,t,r,n){let{fields:i,files:o}=this.#G(),a=this.#X(t),s={...i,...a},c=this.#o,l=o.length>0,h=l?this.#we(c,e,s,o):JSON.stringify({token:c,act:e,params:s}),d=this.#C()?{action:e,paramNames:Object.keys(a),fieldNames:Object.keys(i),encoding:l?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#V()}:null;await this.#ge();try{if(navigator.onLine===!1){this.#a(r.inverse),this.#n("offline"),this.#s(e,t,s,{kind:"offline"});return}let f;try{let p={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#Pe()};if(!l)p["Content-Type"]="application/json";let A=this.#Ie();if(A)p["X-Pgbus-Connection"]=A;he("action"),f=await fetch(this.#Re(),{method:"POST",headers:p,body:h,credentials:"same-origin",signal:AbortSignal.timeout(this.#xe())})}catch(p){if(console.error("[phlex-reactive] action error",p),this.#a(r.inverse),p?.name==="TimeoutError"||p?.name==="AbortError"){this.#n("timeout"),this.#s(e,t,s,{kind:"timeout"});return}this.#pe(),this.#n("network"),this.#s(e,t,s,{kind:"network"});return}if(d)d.status=f.status;if(f.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#a(r.inverse),this.#n("redirected"),this.#s(e,t,s,{kind:"redirected",status:f.status});return}if(!f.ok){let p=await f.text();if(console.error(`[phlex-reactive] action failed: HTTP ${f.status}`,p),this.#a(r.inverse),(f.headers.get("Content-Type")||"").includes("turbo-stream")){let A=this.#Y(p);if(this.#o=A??this.#o,d)this.#b((Te)=>Te.recordBody(d,p,A));window.Turbo.renderStreamMessage(p)}this.#n("http"),this.#s(e,t,s,{kind:"http",status:f.status,body:p});return}let g=f.headers.get("Content-Type")||"";if(!g.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${g}" — no update applied`),this.#a(r.inverse),this.#n("content-type"),this.#s(e,t,s,{kind:"content-type",status:f.status});return}let y=await f.text(),T=this.#Y(y);if(this.#o=T??this.#o,d)this.#b((p)=>p.recordBody(d,y,T));if(window.Turbo.renderStreamMessage(y),r.resurrect)queueMicrotask(r.resurrect);this.#me(),this.#i("reactive:applied",{action:e,params:s,html:y})}catch(f){console.error("[phlex-reactive] action error",f),this.#a(r.inverse),this.#i("reactive:error",{action:e,params:s,kind:"apply"})}finally{if(n?.(),d)this.#b((f)=>f.trace(this,{...d,ms:this.#V()-d.started}))}}get#o(){return this.#v??this.tokenValue}set#o(e){this.#v=e}tokenValueChanged(){this.#v=void 0}#Y(e){let t=this.element.id;if(!t)return e.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:r,self:n}=this.#be(t),i=e.match(r);if(i)return i[1];let o=e.match(n);if(o)return o[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#be(e){let t=this.#j;if(t&&t.id===e)return t;let r=Ce(e);return this.#j={id:e,token:new RegExp(`<turbo-stream\\b[^>]*\\baction="reactive:token"[^>]*\\btarget="${r}"[^>]*\\bdata-reactive-token-value="([^"]+)"`),self:new RegExp(`<turbo-stream\\b[^>]*\\baction="(?:replace|update)"[^>]*\\btarget="${r}"[^>]*>([\\s\\S]*?)</turbo-stream>`)}}#F(e){return e.closest('[data-controller~="reactive"]')===this.element}#D(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(t)=>this.#F(t)}#G(){let e={},t=[],r=this.#D(),n=[];this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((s)=>{if(!r(s))return;if(s.type==="file")for(let c of s.files??[])t.push({name:s.name,file:c,multiple:s.multiple});else n.push(s)});let i=[];this.element.querySelectorAll(`[name]${je}`).forEach((s)=>{if(r(s))i.push(s)});let o=this.#ve(n),a=this.#_e(n);for(let s of n)if(o.has(s.name)){let c=e[s.name]??(e[s.name]=[]);if(s.type==="checkbox"||s.type==="radio"){if(s.checked)c.push(s.value)}else if(s.type==="hidden"){if(!a.has(s.name))c.push(s.value)}else if(s.multiple&&s.options){for(let l of s.options)if(l.selected)c.push(l.value)}else c.push(s.value)}else if(s.type==="checkbox")e[s.name]=s.checked;else if(s.type==="radio"){if(s.checked)e[s.name]=s.value}else e[s.name]=s.value;return i.forEach((s)=>{let c=s.getAttribute("name");if(!c)return;let l=s.value??s.textContent??s.innerHTML??"",h=e[c];if(String(c).endsWith("[]")&&!Je(s))return;if(String(c).endsWith("[]")&&(h===void 0||Array.isArray(h))){(Array.isArray(h)?h:e[c]=[]).push(l);return}if(h==null||h==="")e[c]=l}),{fields:e,files:t}}#ve(e){let t=new Set;for(let r of e){if(r.type==="radio")continue;if(String(r.name).endsWith("[]"))t.add(r.name)}return t}#_e(e){let t=new Set;for(let r of e)if(r.type==="checkbox")t.add(r.name);return t}#we(e,t,r,n){let i=new FormData;i.append("token",e),i.append("act",t);let o=[];for(let[s,c]of Object.entries(r))if(Array.isArray(c)&&String(s).endsWith("[]"))if(c.length===0)o.push(String(s).slice(0,-2));else{let l=`${this.#k(s)}[]`;for(let h of c)i.append(l,String(h))}else this.#q(i,this.#k(s),c);for(let s of o)i.append("empty_groups[]",s);let a=this.#Se(n);for(let{name:s,file:c,multiple:l}of n){let d=l||a.has(s)?`${this.#k(s)}[]`:this.#k(s);i.append(d,c,c.name)}return i}#k(e){let t=String(e),r=t.indexOf("[");if(r===-1)return`params[${t}]`;return`params${[t.slice(0,r),...t.slice(r).match(/[^\[\]]+/g)??[]].map((i)=>`[${i}]`).join("")}`}#q(e,t,r){if(r==null)e.append(t,"");else if(Array.isArray(r))r.forEach((n,i)=>this.#q(e,`${t}[${i}]`,n));else if(typeof r==="object")for(let[n,i]of Object.entries(r))this.#q(e,`${t}[${n}]`,i);else e.append(t,String(r))}#Se(e){let t=new Map;for(let{name:r}of e)t.set(r,(t.get(r)??0)+1);return new Set([...t].filter(([,r])=>r>1).map(([r])=>r))}#X(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#Te(e){return W(e)}#Ae(e){q(e,(t)=>this.#W(t),(t,r)=>this.#B(`client op "${t}"`,r))}#$(){return this.element?.getAttribute?.("data-reactive-verbose")==="true"||this.#C()}#B(e,t){if(!this.#$())return;this.#b((r)=>r.diagnose(this,e,t))}#b(e){_("devtools",e)}#W(e){let t=e.to;if(t==="@root")return[this.element];if(typeof t!=="string"||t==="")return[];if(e.global)return[...document.querySelectorAll(t)];return[...this.element.querySelectorAll(t)].filter((r)=>this.#F(r))}#Ee(e,t){if(e?.checked!=="keep")return!1;let r=t?.type;return r==="checkbox"||r==="radio"}#a(e){if(!e)return;if(!this.element.isConnected)return;for(let t of e)t()}#Fe(e,t,r){this.#ke(e,t),ue();let n=!1;return()=>{if(n)return;n=!0,this.#Le(e,t),le();for(let i of r.undo)i()}}#ke(e,t){if(this.#c(t,e,1),this.#c(this.element,e,1),this.#l.set(e,(this.#l.get(e)??0)+1),this.#R++===0)this.element.setAttribute("aria-busy","true");for(let r of this.#Z(e))this.#c(r,e,1)}#Le(e,t){this.#c(t,e,-1),this.#c(this.element,e,-1);let r=(this.#l.get(e)??1)-1;if(r<=0)this.#l.delete(e);else this.#l.set(e,r);if(--this.#R<=0)this.#R=0,this.element.removeAttribute("aria-busy");for(let n of this.#Z(e))this.#c(n,e,-1)}#c(e,t,r){if(!e||typeof e.getAttribute!=="function")return;let n=this.#x.get(e)??new Map,i=(n.get(t)??0)+r;if(i<=0)n.delete(t);else n.set(t,i);if(n.size===0){this.#x.delete(e),e.removeAttribute("data-reactive-busy");return}this.#x.set(e,n),e.setAttribute("data-reactive-busy",[...n.keys()].join(" "))}#Z(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#F(r))}#Re(){return this.#Q??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#xe(){if(this.#L!=null)return this.#L;let e=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,t=Number(e);return this.#L=Number.isFinite(t)&&t>0?t:30000}#Pe(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#Ie(){return document.querySelector("pgbus-stream-source[connection-id]")?.getAttribute("connection-id")||document.querySelector('meta[name="pgbus-connection-id"]')?.content||null}}if(typeof window<"u")if(window.Turbo)V();else document.addEventListener("turbo:load",V,{once:!0});w("persist",()=>import("phlex/reactive/features/persist"),gt);w("defer",()=>import("phlex/reactive/features/defer"));w("form",()=>import("phlex/reactive/features/form"));w("bindings",()=>import("phlex/reactive/features/bindings"));w("compute",()=>import("phlex/reactive/features/compute"),yt);w("effects",()=>import("phlex/reactive/features/effects"));w("hints",()=>import("phlex/reactive/features/hints"));w("devtools",()=>import("phlex/reactive/features/devtools"));B();function gt(e,t){let r=()=>{t.edited=!0},n=(o)=>{let a=o.target;if(o.detail?.success&&a?.tagName==="FORM"&&a.contains?.(e))t.submitted=!0},i=["input","change","lexxy:change","trix-change"];for(let o of i)e.addEventListener?.(o,r);return document.addEventListener("turbo:submit-end",n),()=>{for(let o of i)e.removeEventListener?.(o,r);document.removeEventListener("turbo:submit-end",n)}}function yt(e,t){let r=()=>{t.edited=!0};return e.addEventListener?.("input",r),e.addEventListener?.("change",r),()=>{e.removeEventListener?.("input",r),e.removeEventListener?.("change",r)}}var bt=1000,S=null,Se,P=new Set;function vt(e){return ve(e).then((t)=>{if(e!=="effects")return;Se=t,t?.sweep()})}oe((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,o=be(_t(i)).filter((s)=>!P.has(s));if(!t&&!P.has("effects")&&wt(i))o.push("effects");if(o.length===0&&!S)return t?.wrap(e);if(o.length>0){for(let c of o)P.add(c);let s=S=Promise.race([Promise.all([S,...o.map(vt)]),new Promise((c)=>setTimeout(c,bt))]).then(()=>{if(S!==s)return;S=null,P.clear()})}let a=S;r.render=async(s)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??Se)?.wrap(c),await c.detail.render(s)}});function _t(e){let t=e?.querySelector?.("template")?.content;if(!t)return[];let r=[...t.querySelectorAll?.('[data-controller~="reactive"]')??[]];for(let n of t.children??[])if(n.matches?.('[data-controller~="reactive"]')&&!r.includes(n))r.unshift(n);return r}function wt(e){return Boolean(e?.hasAttribute?.("data-reactive-effect")||document.getElementById?.(e?.getAttribute?.("target"))?.matches?.("[data-reactive-effect-update],[data-reactive-effect-exit]")||e?.querySelector?.("template")?.content?.querySelector?.("[data-reactive-effect-enter],[data-reactive-dismiss-after]")||document.querySelector?.("[data-reactive-dismiss-after]:not([data-reactive-dismiss-scheduled])"))}var Ot=we;export{ce as ACTIVE_ATTR,je as EDITOR_SELECTOR,Ue as EDITOR_TAGS,de as REQUESTS_ATTR,De as checkReactiveRegistration,he as countReactiveRequest,Ot as default,ue as enterReactiveActivity,Ce as escapeRegExp,le as exitReactiveActivity,ve as loadReactiveFeature,oe as onReactiveStreamWithoutEffects,Et as reactiveActivityCount,Lt as reactiveFeatureNames,V as registerReactiveActions,Le as registerReactiveDefer,B as registerReactiveDev,Re as registerReactiveDismiss,Re as registerReactiveEffects,kt as registerReactiveFeature,w as registerReactiveFeatureLoader,ke as registerReactiveJs,xe as registerReactiveMorphFocus,Ie as registerReactiveOffline,Re as registerReactiveStreamRender,Fe as registerReactiveToken,Ee as registerReactiveVisit,Ft as resetReactiveActivity,be as unloadedFeaturesFor};
1
+ import{Controller as Ae}from"@hotwired/stimulus";import{confirmResolver as U}from"phlex/reactive/confirm";function Ee(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:visit"])return;e["reactive:visit"]=function(){let t=this.getAttribute("data-url");if(t)window.Turbo.visit(t,{action:"advance"})}}function Fe(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:token"])return;e["reactive:token"]=function(){let t=this.getAttribute("data-reactive-token-value"),r=this.getAttribute("target");if(!t||!r)return;let n=document.getElementById(r);if(n)n.setAttribute("data-reactive-token-value",t)}}function ke(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:js"])return;e["reactive:js"]=function(){let t=W(this.getAttribute("data-reactive-ops"));if(!t.length)return;let r=this.getAttribute("target"),n=this.getAttribute("data-reactive-verbose")==="true",i=r?document.getElementById(r):null;if(r&&!i){if(n)b("devtools",(o)=>o.missingRoot(r));return}q(t,(o)=>Qe(o,i),n?(o,a)=>b("devtools",(s)=>s.diagnoseStream(o,a,i)):void 0)}}function Le(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:defer"])return;e["reactive:defer"]=function(){b("defer",(t)=>t.streamAction(this))}}var J=!1,D=null;function Re(){if(J)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;J=!0,document.addEventListener("turbo:before-stream-render",(e)=>{if(D)D(e,m.get("effects"));else m.get("effects")?.wrap(e)})}function oe(e){D=e}var K=!1;function z(e){return e===document.activeElement&&(e.localName==="input"||e.localName==="textarea")&&!e.hasAttribute("data-reactive-morph-value")&&!!e.closest('[data-controller~="reactive"]')}function xe(){if(K)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;K=!0,document.addEventListener("turbo:before-morph-element",(e)=>{let t=e.target,r=e.detail?.newElement;if(!r||e.defaultPrevented||t.localName!=="input"||!z(t))return;let n=r.getAttribute("value");if(n==null)t.removeAttribute("value");else if(t.getAttribute("value")!==n)t.setAttribute("value",n)}),document.addEventListener("turbo:before-morph-attribute",(e)=>{if(e.detail?.attributeName==="value"&&z(e.target))e.preventDefault()})}var Pe="__materialize",H=!1;function Ie(){if(H)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;H=!0;let e=()=>{let t=document.documentElement;if(typeof t?.toggleAttribute!=="function")return;t.toggleAttribute("data-reactive-offline",globalThis.navigator?.onLine===!1)};e(),window.addEventListener("online",e),window.addEventListener("offline",e)}var Ne="phlex-reactive:latency";function ae(){return typeof sessionStorage<"u"&&Boolean(sessionStorage.getItem(Ne))}function B(){if(typeof document>"u")return;if(!m.has("devtools")&&!v.get("devtools")[1])return;let e=document.querySelector?.('meta[name="phlex-reactive-env"]')?.content==="development";if(e||ae())b("devtools",(t)=>e&&t.attach())}var ce="data-reactive-active",_=0;function ue(){if(_++,_===1)fe("reactive:busy")}function le(){if(_===0)return;if(_--,_===0)fe("reactive:idle")}function Et(){return _}function Ft(){_=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(ce)}function fe(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.toggleAttribute==="function")t.toggleAttribute(ce,_>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(e,{detail:{count:_}}))}var de="data-reactive-requests";function he(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.setAttribute!=="function"||!Oe(t))return;let r=Me(t);r[e]=(Number(r[e])||0)+1,t.setAttribute(de,JSON.stringify(r))}function Oe(e){return e.hasAttribute?.("data-reactive-verbose")||!!document.querySelector?.('[data-reactive-verbose="true"]')}function Me(e){try{let t=JSON.parse(e.getAttribute(de));if(t&&typeof t==="object")return{action:0,defer:0,...t}}catch{}return{action:0,defer:0}}function G(){Ee(),Fe(),ke(),Le(),Re(),xe(),Ie(),B()}function Ce(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var me=Symbol.for("phlex-reactive.core");if(globalThis[me])console.error("[phlex-reactive] the client was loaded twice. Import EITHER phlex/reactive/reactive_controller (the default, "+"everything in one file) OR phlex/reactive/core (features on demand), not both — each carries its own state.");globalThis[me]=!0;var pe=!1;function De(){if(pe)return;if(typeof document>"u")return;let e=document.querySelectorAll('[data-controller~="reactive"]');if(!e||e.length===0)return;console.warn("[phlex-reactive] found "+e.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.')}if(typeof window<"u"&&typeof document<"u"){let e=()=>setTimeout(De,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",e,{once:!0});else e()}var qe=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function $e(e){let t=String(e).toLowerCase();return t.startsWith("on")||qe.has(t)}var I=new WeakMap;function Be(e,t,r){let[n,i,o]=t;I.get(e)?.(),e.classList.add(n,i),r();let a=!1,s=requestAnimationFrame(()=>{if(a)return;e.classList.remove(i),e.classList.add(o)}),c=(h)=>{if(a||h&&h.target!==e)return;a=!0,I.delete(e),clearTimeout(l),globalThis.cancelAnimationFrame?.(s),e.removeEventListener("animationend",c),e.removeEventListener("transitionend",c),e.classList.remove(n,i,o)};I.set(e,c),e.addEventListener("animationend",c),e.addEventListener("transitionend",c);let l=setTimeout(c,We(e))}function We(e){let t=0;try{let r=getComputedStyle(e);for(let n of["transition","animation"]){let[i,o]=["Duration","Delay"].map((s)=>String(r[n+s]).split(",").map((c)=>parseFloat(c)*(/ms/.test(c)?1:1000)||0)),a=String(r[n+"IterationCount"]).split(",").map((s)=>/inf/.test(s)?1/0:parseFloat(s)>=0?parseFloat(s):1);for(let s=0;s<i.length||s<o.length||s<a.length;s++){let c=i[s%i.length]*a[s%a.length]||0;t=Math.max(t,c+o[s%o.length])}}}catch{}return Math.min(Math.max(t+50,350),5000)}var je=":is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])",Ue=new Set(["lexxy-editor","trix-editor"]);function Je(e){return Ue.has(e.localName)?typeof e.value==="string":!0}var V=Object.freeze({show:(e,t,r)=>N(e,!1,t,r),hide:(e,t,r)=>N(e,!0,t,r),toggle:(e,t,r)=>N(e,!e.hidden,t,r),add_class:(e,t)=>e.classList.add(...t.classes??[]),remove_class:(e,t)=>e.classList.remove(...t.classes??[]),toggle_class:(e,t)=>(t.classes??[]).forEach((r)=>e.classList.toggle(r)),set_attr:(e,t)=>{if(O(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(O(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!O(t.name))return;if(Array.isArray(t.values)){let[r,n]=t.values;e.setAttribute(t.name,e.getAttribute(t.name)===r?n:r)}else if(e.hasAttribute(t.name))e.removeAttribute(t.name);else e.setAttribute(t.name,"")},focus:(e)=>e.focus?.(),focus_first:(e)=>Ve(e)?.focus?.(),text:(e,t)=>{let r=String(t.value??"");if(e.textContent!==r)e.textContent=r},check_group:(e,t)=>{let r=t.global?document.querySelectorAll('[data-controller~="reactive"]'):[e];for(let n of r)b("bindings",(i)=>i.checkGroup(n,t.group,t.checked))},dispatch:(e,t)=>{e.dispatchEvent(new CustomEvent(t.name,{bubbles:!0,composed:!0,detail:t.detail??{}}))},submit:(e,t,r)=>{let n=Ke(e);if(!n)return;let i=null;if(t?.submitter!=null&&typeof r==="function"){if(i=r({...t,to:t.submitter})[0]??null,!(i?.form===n&&(i.type==="submit"||i.type==="image")))console.warn(`[phlex-reactive] submitter ${t.submitter} is not a submit control of the form — ignored`),i=null}i?n.requestSubmit?.(i):n.requestSubmit?.()},paste_into:(e)=>ze(e),persist_state:(e,t)=>b("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>b("persist",(t)=>t.clearRoot(e))});function Ke(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function ze(e){let t=globalThis.navigator?.clipboard;if(typeof t?.readText!=="function")return;t.readText().then((r)=>{if(!r)return;if(e.value=r,typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}));e.focus?.()}).catch(()=>{})}function He(e,t,r){if(r?.transition)Be(e,r.transition,()=>e.hidden=t);else e.hidden=t}function N(e,t,r,n){if(He(e,t,r),r?.expanded==null||typeof n!=="function")return;for(let i of n({...r,to:r.expanded}))i.setAttribute?.("aria-expanded",String(!t))}function O(e){if(!$e(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}var Ge='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function Ve(e){return e.querySelectorAll?.(Ge)?.[0]??null}function W(e){if(Array.isArray(e))return e;if(typeof e!=="string")return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}var Y=Object.freeze({enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"}),X=Object.freeze(["meta","ctrl","alt","shift"]);function j(e,t,r){let n=e.split("+");for(let a of X)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!X.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let o=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(Y,i)?Y[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof o==="string"&&o.toLowerCase()===t.key.toLowerCase()}function Ye(e){if(Array.isArray(e))return[{ops:e,legacy:!0}];if(e&&typeof e==="object")return[e];if(typeof e!=="string")return[];let t=e.trim();if(t.startsWith("["))return[{ops:W(t),legacy:!0}];let r=[];for(let n of t.split(" ")){if(n==="")continue;let i=null;try{i=JSON.parse(n)}catch{i=null}if(i&&typeof i==="object"&&!Array.isArray(i))r.push(i);else console.warn(`[phlex-reactive] malformed on_client binding record ${JSON.stringify(n)} — skipped`)}return r}function Z(e,t,r){if(e.legacy)return!0;let n=e.on;if(typeof n!=="string"||n==="")return!1;let i=n.indexOf(".");if(t.type!==(i<0?n:n.slice(0,i)))return!1;if(Boolean(e.window)!==_e(t.currentTarget))return!1;return i<0||r===null||j(n.slice(i+1),t,r)}var Q=new WeakMap;function Xe(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=Q.get(e);if(!i)i=new WeakMap,Q.set(e,i);let o=i.get(n);if(!o)o=new Set,i.set(n,o);let a=t.params?.ops,c=(n===globalThis.window?`${typeof a==="string"?a:JSON.stringify(a??null)}|`:"")+JSON.stringify(r);if(o.has(c))return!0;return o.add(c),!1}var ee=new WeakMap;function Ze(e,t){if(e===null||typeof e!=="object")return!1;let r=e.params?.ops,n=typeof r==="string"?r:JSON.stringify(r??null),i=ee.get(e);if(!i)i=new WeakMap,ee.set(e,i);let o=i.get(t);if(!o)o=new Map,i.set(t,o);let a=o.get(e.currentTarget);if(!a)a=new Set,o.set(e.currentTarget,a);if(a.has(n))return!0;return a.add(n),!1}function q(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,o={}]=n;if(!Object.hasOwn(V,i)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(i)} — skipped`);continue}let a=t(o);if(a.length===0&&r)r(i,o);for(let s of a)V[i](s,o,t)}}function Qe(e,t){let r=e.to;if(t){if(r==="@root")return[t];if(typeof r!=="string"||r==="")return[];if(e.global)return[...document.querySelectorAll(r)];return[...t.querySelectorAll(r)]}if(typeof r!=="string"||r===""||r==="@root")return[];return[...document.querySelectorAll(r)]}function et(e){let t=e.getAttribute?.("data-reactive-persist");return Boolean(t)&&t!=="off"}function ge(e){return["defer-token","defer-src","lazy-on","lazy-visible"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)}function tt(e){return(e.getAttribute?.("data-action")??"").includes("reactive#trackDirty")||e.getAttribute?.("data-reactive-clipboard")!=null||e.querySelector?.('[data-action*="reactive#trackDirty"],[data-reactive-clipboard]')!=null}function rt(e){return["show-targets","group-targets","on-complete","filter-input","tags-field"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)||(e.querySelectorAll?.("[data-reactive-show-field], [data-reactive-show]")??[]).length>0||e.querySelector?.("[data-reactive-nested-json], [data-reactive-nested-list], [data-reactive-confirm-when-param], [data-reactive-enable], [data-reactive-select-all], [data-reactive-count]")!=null}function nt(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}var it=[["persist",[et,null,null,!0]],["defer",[ge,null]],["form",[tt,null]],["bindings",[rt,null,null,!0]],["compute",[nt,null,null,!0]],["effects",[(e)=>["enter","update","exit"].some((t)=>e.getAttribute?.(`data-reactive-effect-${t}`)!=null),null]],["hints",[(e)=>e.querySelector?.("[data-reactive-optimistic-param], [data-reactive-busy-param], [data-reactive-loading-param]")!=null,null]],["devtools",[(e)=>e.getAttribute?.("data-reactive-debug")==="true",null]]],v=new Map(it),te=new Map,m=new Map,st=new Map;function w(e,t,r){ye.set(e,[t,r]),ot(e)}var ye=new Map;function ot(e){let t=v.get(e),[r,n]=ye.get(e);t[1]=r,t[2]=n}function kt(e,t){t.install?.(F),m.set(e,t),st.set(e,t)}function be(e){let t=[];for(let[r,[n]]of v){if(!n||m.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function ve(e){return E(e).catch((t)=>R(e,"load",t))}function E(e){let t=te.get(e);if(!t)t=(v.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(F),m.set(e,n),n)),te.set(e,t);return t}var re=new Set;function R(e,t,r){let n=e+t;if(re.has(n))return;re.add(n),console.error(`[phlex-reactive] the "${e}" feature module (phlex/reactive/features/${e}) is unavailable: ${t}. If you bundle or vendor the client, alias or pin phlex/reactive/features/* (README: esbuild / webpack / bun).`,r)}function b(e,t){let r=m.get(e);if(r)return t(r);E(e).then(t,(n)=>R(e,"load",n))}var at=1e4;function M(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:at}function Lt(){return[...v.keys()]}var ne=Promise.resolve();function ie(e,t,r){let n=F.waiting.get(e);if(n&&n[t]===r)delete n[t]}var F={enter:ue,exit:le,count:he,waiting:new WeakMap};var k=Symbol.for("phlex-reactive.early"),ct=1e4,ut=1500,_e=(e)=>e!=null&&(e===globalThis.window||e.window===e);function C(){return globalThis[k]??={queue:[],connected:new WeakSet},globalThis[k]}function lt(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:ct}function ft(e){let t={};for(let{name:r,value:n}of Array.from(e.attributes??[])){let i=/^data-reactive-(.+)-param$/i.exec(r);if(!i)continue;let o;try{o=JSON.parse(n)}catch{o=n}t[i[1].replace(/[-_]([a-z0-9])/g,(a,s)=>s.toUpperCase())]=o}return t}function dt(e,t,r){return{[k]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:ft(t),key:e.key,code:e.code,metaKey:e.metaKey,ctrlKey:e.ctrlKey,altKey:e.altKey,shiftKey:e.shiftKey,button:e.button,submitter:e.submitter,bubbles:e.bubbles,timeStamp:e.timeStamp,defaultPrevented:e.defaultPrevented,preventDefault(){},stopPropagation(){},stopImmediatePropagation(){}}}var x=new WeakMap;function ht(e,{token:t,type:r,method:n,filter:i,win:o},a){let s=x.get(e);if(!s)x.set(e,s=new Map);let c=o?`${t} ${a}`:t;if(s.has(c))return!1;return s.set(c,{type:r,method:n,filter:i,win:o,params:a,armed:!0}),!0}function se(e,t,r,n){if(e?.[k])return!1;let i=_e(e?.currentTarget),o=i?n:e?.currentTarget,a=pt(e,o,i?`@${t}`:t),s=x.get(o),c=i&&JSON.stringify(e.params);for(let l of s?.values()??[]){if(!l.armed||l.method!==t||l.type!==e.type||Boolean(l.win)!==i)continue;if(i&&l.params!==c)continue;if(l.filter&&!j(l.filter,e,r))continue;return l.armed=!1,!0}return a}var L=new WeakMap;function mt(e,t,r){let n=L.get(e);if(!n)L.set(e,n=new Map),setTimeout(()=>L.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function pt(e,t,r){let n=e&&L.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class we extends Ae{static values={token:String};#v;#_=new Map;#u=new Map;#Q;#L;#j;#R=0;#l=new Map;#x=new WeakMap;#w;featuresReady=ne;#t=new Map;#P=new Set;#f=!1;#r=null;#d=new Map;#S=new Map;#h=new Map;#m=0;#U;#Ne=0;#Oe=0;connect(){if(pe=!0,C().connected.add(this.element),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-token-value")!=null||ge(this.element))this.#w=(e)=>{if(e.target!==this.element)return;this.#J(!0)},this.element.addEventListener?.("turbo:morph-element",this.#w);this.#m++,this.featuresReady=ne,this.#J(),this.#ie()}#Me(e){}#Ce(e,t,r,n){}#De(){}#qe(e,t){}#J(e){{let t=this.#m,r=[];for(let[o,[a]]of v){if(!a||this.#P.has(o))continue;let s=m.get(o);if(s&&!s.connect)continue;try{if(a(this.element))r.push(o)}catch(c){this.#p(o,"detect",c)}}if(r.length===0)return;for(let o of r)this.#P.add(o);if(!this.#f&&r.every((o)=>m.has(o))){for(let o of r)this.#I(t,o,m.get(o),e);return}for(let o of r){let a=this.#ee(t,o),s=[];for(let l of v.keys()){if(l===o)break;if(this.#h.has(l))s.push(this.#h.get(l))}let c=Promise.all(s).then(()=>a).then((l)=>l&&this.#I(t,o,l,e));if(this.#h.set(o,c),v.get(o)[3])this.#r=c}let n=this.#r;n?.then(()=>{if(this.#r===n)this.#r=null}),this.#f=!0;let i=Promise.all(this.#h.values()).then(()=>{if(this.featuresReady===i)this.#f=!1});this.featuresReady=i}}#ee(e,t){{let r=()=>e===this.#m;return this.#te(t),new Promise((n)=>{let i=!1,o=setTimeout(()=>{if(this.#d.delete(o),i=!0,r())this.#p(t,"timeout",Error(`not loaded after ${M()} ms`));n(null)},M());this.#d.set(o,n);let a=()=>{clearTimeout(o),this.#d.delete(o)};E(t).then((s)=>{if(a(),i)queueMicrotask(()=>this.#I(e,t,s));else n(s)},(s)=>{if(a(),r())this.#p(t,"load",s);n(null)})})}}#te(e){{let t=v.get(e)[2];if(!t)return;let r={};try{this.#S.set(e,[t(this.element,r),r]),F.waiting.set(this.element,{...F.waiting.get(this.element),[e]:r})}catch(n){this.#p(e,"detect",n)}}}#K(e,t){{let[r,n]=this.#S.get(e)??[];if(this.#S.delete(e),!t)ie(this.element,e,n);try{r?.()}catch(i){console.error(`[phlex-reactive] the "${e}" feature module failed to stop waiting`,i)}return n}}#I(e,t,r,n){{if(e!==this.#m)return;let i=this.#K(t);try{r.connect?.(this,this.#e(),n,i),this.#t.set(t,r)}catch(o){this.#p(t,"connect",o)}}}#e(){return this.#U??={emit:(e,t,r)=>this.#i(e,t,r),reseed:()=>this.#re(),proceed:(e,t,r)=>this.#O(e,t,r),forgetToken:()=>{this.#v=void 0},owns:(e)=>this.#F(e),ownership:()=>this.#D(),opTargets:(e)=>this.#W(e),diagnose:(e,t)=>this.#B(e,t),applyOps:(e,t)=>q(e,(r)=>this.#W(t!=null&&r.to==null?{...r,to:t}:r),(r,n)=>this.#B(`client op "${r}"`,n)),listnavOptions:(e)=>this.#y(e),collectFields:()=>this.#Y(),confirm:(e,t)=>Promise.resolve().then(()=>U(e,t)).catch(()=>!1)},this.#U}#re(){this.#t.get("form")?.scan(this,this.#e()),this.#t.get("bindings")?.reseed(this),this.#t.get("compute")?.seed(this)}#p(e,t,r){if(R(e,t,r),this.#n("feature"),t==="load"&&this.element.getAttribute?.("data-reactive-defer-pending"))this.element.removeAttribute("data-reactive-defer-pending"),this.element.removeAttribute("aria-busy");this.#i("reactive:error",{kind:"feature",feature:e,phase:t,error:r})}#ne(){{this.#m++;for(let[t,r]of this.#d)clearTimeout(t),r(null);this.#d.clear();for(let t of[...this.#S.keys()]){let r=this.#K(t,!0),n=this.element;b(t,(i)=>{i.abandon?.(n,r),ie(n,t,r)})}this.#P.clear(),this.#h.clear(),this.#f=!1,this.#r=null;let e=[...this.#t];this.#t.clear();for(let[t,r]of e)try{r.disconnect?.(this,this.#e())}catch(n){console.error(`[phlex-reactive] the "${t}" feature module failed to disconnect`,n)}}}#ie(){if(this.element.setAttribute?.("data-reactive-connected",""),this.element.isConnected)this.element.dispatchEvent?.(new CustomEvent("reactive:connect",{bubbles:!0,composed:!0,detail:{id:this.element.id}}));this.#se()}#N=new Set;#se(){let{queue:e}=C();if(e.length===0)return;let t=[];for(let i=e.length-1;i>=0;i--){let{root:o}=e[i];if(o===this.element||!o.isConnected)t.unshift(...e.splice(i,1))}let r=lt(),n=new Map;for(let i of t){let o=n.get(i.event)??[new Set,new Set];n.set(i.event,o);let a=o[+!!i.win];if(a.has(i.el))continue;a.add(i.el);let s=i.win?Math.min(ut,r):r,c=i.root!==this.element?"its root left the page before a controller connected":performance.now()-i.at>s?`it is older than the ${s} ms ${i.win?"window-trigger":"early-event"} TTL`:i.el.isConnected&&this.element.contains(i.el)?null:"its element left the root before the controller connected";if(c){if(this.#$())console.warn(`[phlex-reactive] dropped an early "${i.event.type}" trigger: ${c}`);continue}this.#oe(i)}}#oe({event:e,el:t,descs:r,win:n}){let i=dt(e,t,n),o=this.application?.schema?.keyMappings,a=(t.getAttribute("data-action")??"").split(/\s+/),s=n?this.element:t;for(let c of r){if(!a.includes(c.token))continue;if(c.filter&&!j(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!ht(s,c,n&&JSON.stringify(i.params)))continue;this.#N.add(s)}if(mt(e,s,n?`@${c.method}`:c.method),c.method==="runOps")this.runOps(i);else this.dispatch(i)}}disconnect(){if(this.#ne(),this.#fe(),this.#he(),this.#w)this.element.removeEventListener?.("turbo:morph-element",this.#w);C().connected.delete(this.element),this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#N)x.delete(e);this.#N.clear()}dispatch(e){if(se(e,"dispatch",this.application?.schema?.keyMappings,this.element))return;let{action:t,params:r,debounce:n,throttle:i,confirm:o,confirmWhen:a,outside:s,window:c,optimistic:l}=e.params;if(!t)return;let h=e.params.busy??e.params.loading;if(s&&this.element.contains(e.target))return;let d=e.currentTarget??e.target;if(!c&&!this.#Ee(l,d))e.preventDefault();if(t===Pe){let y=()=>{{let T=this.#t.get("defer");if(T)return T.materialize(this)}if(this.tokenValue)return this.#O(d,t,"{}")};return this.#f?this.featuresReady.then(y):y()}let f=this.#z(o,a),g=()=>this.#O(d,t,r,n,i,l,h);if(!f)return g();if(f instanceof Promise)return f.then((y)=>y?this.#T(y,d,g):g());this.#T(f,d,g)}#T(e,t,r){return Promise.resolve().then(()=>U(e,{el:t})).catch(()=>!1).then((n)=>{if(n)r()})}#z(e,t){if(e)return e;if(!t)return null;{let r=m.get("bindings");if(r)return r.confirmMessage(this,this.#e(),t);return this.#H("bindings").then((n)=>n&&n.confirmMessage(this,this.#e(),t))}}#H(e){{let t;return Promise.race([E(e).catch((r)=>(R(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),M()))]).finally(()=>clearTimeout(t))}}runOps(e){if(se(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(Ze(e,this))return;let t=e.params??{},r=e.currentTarget??e.target,n=Ye(t.ops),i=n.filter((a)=>Z(a,e,null)),o=i.length<=1?i:i.filter((a)=>Z(a,e,this.application?.schema?.keyMappings));if(o.length===0&&n.length>0){if(this.#$())this.#b((a)=>a.noBinding(this,e));return}for(let a of o){if(a.outside&&e[k])continue;if(Xe(this,e,a))continue;this.#ae(a.legacy?{...t,ops:a.ops}:a,e,r)}}#ae({ops:e,confirm:t,confirmWhen:r,outside:n,window:i},o,a){if(n&&this.element.contains(o.target))return;if(!i)o.preventDefault();let s=this.#z(t,r),c=()=>this.#Ae(this.#Te(e));if(!s)return c();if(s instanceof Promise)return s.then((l)=>l?this.#T(l,a,c):c());this.#T(s,a,c)}recompute(e){return m.get("compute")?.recompute(this,this.#e(),e)}tagsAdd(e){if(e?.defaultPrevented)return;if(this.#y(e).some((t)=>t.hasAttribute?.("data-reactive-highlighted")))return;return this.#g("tagsAdd",e)}tagsPick(e){return this.#g("tagsPick",e)}tagsRemove(e){return this.#g("tagsRemove",e)}nestedAdd(e){return this.#g("nestedAdd",e)}nestedRemove(e){return this.#g("nestedRemove",e)}syncNestedJson(e){return m.get("bindings")?.syncNestedJson(this,this.#e(),e)}#g(e,t){{let r=m.get("bindings");if(r)return r[e](this,this.#e(),t);t?.preventDefault?.();let n={currentTarget:t?.currentTarget??null,target:t?.target??null,preventDefault(){}};return b("bindings",(i)=>i[e](this,this.#e(),n))}}trackDirty(){(this.#t.get("form")??m.get("form"))?.scan(this,this.#e())}listnavNext(e){this.#A(e,(t,r)=>t<0?0:(t+1)%r)}listnavPrev(e){this.#A(e,(t,r)=>t<0?r-1:(t-1+r)%r)}listnavFirst(e){this.#A(e,()=>0)}listnavLast(e){this.#A(e,(t,r)=>r-1)}listnavPick(e){let t=this.#y(e),r=t.findIndex((n)=>n.hasAttribute("data-reactive-highlighted"));if(r<0)return;e.preventDefault(),t[r].click()}listnavClose(e){for(let t of this.#y(e))t.removeAttribute("data-reactive-highlighted")}#A(e,t){let r=this.#y(e);if(!r.length)return;e.preventDefault();let n=this.#ce(e),i=globalThis.document?.activeElement,o=n?r.findIndex((s)=>s===i||i!=null&&s.contains?.(i)):r.findIndex((s)=>s.hasAttribute("data-reactive-highlighted")),a=r[t(o,r.length)];if(n)a.focus?.();else{for(let s of r)s.removeAttribute("data-reactive-highlighted");a.setAttribute("data-reactive-highlighted","true")}a.scrollIntoView?.({block:"nearest"})}#ce(e){return(e?.currentTarget??e?.target??this.element).getAttribute?.("data-reactive-listnav-focus-param")==="true"}#y(e){let r=(e?.currentTarget??e?.target??this.element).getAttribute?.("data-reactive-listnav-option-param")??this.element.getAttribute("data-reactive-listnav-option-param");if(!r)return[];let n=this.#D();return Array.from(this.element.querySelectorAll(r)).filter((i)=>!i.hidden&&n(i))}#O(e,t,r,n,i,o,a){if(this.#i("reactive:before-dispatch",{action:t,params:this.#X(r),element:this.element},{cancelable:!0}).defaultPrevented)return;let c=Number(n)||0;if(c>0)return this.#le(e,c,t,r,o,a);let l=Number(i)||0;if(l>0)return this.#de(e,l,t,r,o,a);return this.#E(t,r,o,e,a)}#E(e,t,r,n,i){let o={inverse:null,undo:[],resurrect:null},a=this.#Fe(e,n,o),s=Boolean(r||i),c=(f)=>{if(!s||!f)return;let g=this.#e();if(o.inverse=f.optimistic(this,g,r,n),o.undo.push(...f.busy(this,g,i,n)),this.#C())o.resurrect=f.resurrection(this,g,r,n)},l=m.get("hints");if(!s||l)c(l);let h=()=>this.#ye(e,t,o,a),d=()=>this.#r?this.#r.then(h):h();return this.queue=(this.queue??Promise.resolve()).then(()=>s&&!l?this.#ue().then(c).then(d):d()),this.queue}#ue(){return this.#H("hints")}#le(e,t,r,n,i,o){this.#M(e);let a=()=>{this.#M(e),this.#E(r,n,i,e,o)},s=setTimeout(a,t);e?.addEventListener?.("blur",a,{once:!0}),this.#_.set(e,{timer:s,flush:a})}#M(e){let t=this.#_.get(e);if(!t)return;clearTimeout(t.timer),e?.removeEventListener?.("blur",t.flush),this.#_.delete(e)}#fe(){for(let e of[...this.#_.keys()])this.#M(e)}#de(e,t,r,n,i,o){let a=this.#u.get(e)??new Map;if(a.has(r))return;let s=setTimeout(()=>{if(a.delete(r),a.size===0)this.#u.delete(e)},t);return a.set(r,s),this.#u.set(e,a),this.#E(r,n,i,e,o)}#he(){for(let e of this.#u.values())for(let t of e.values())clearTimeout(t);this.#u.clear()}#i(e,t,{cancelable:r=!1}={}){let n=new CustomEvent(e,{bubbles:!0,composed:!0,cancelable:r,detail:t});return(this.element.isConnected?this.element:document).dispatchEvent(n),n}#s(e,t,r,n){let i=()=>{if(!this.element.isConnected){console.warn("[phlex-reactive] retry() ignored — the reactive root left the DOM");return}return this.#E(e,t)};this.#i("reactive:error",{action:e,params:r,...n,retry:i})}#n(e){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",e)}#me(){this.element?.removeAttribute?.("data-reactive-error")}#pe(){let e=document.querySelector("[data-reactive-error-flash]");if(!e?.content)return;let t=e.getAttribute("data-reactive-error-flash")||"flash",r=document.getElementById(t);if(!r)return;r.appendChild(e.content.cloneNode(!0))}#ge(){{let e=m.get("devtools");if(e)return e.delay();if(ae())return E("devtools").then((t)=>t.delay(),()=>{})}}#C(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#G(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}async#ye(e,t,r,n){let{fields:i,files:o}=this.#Y(),a=this.#X(t),s={...i,...a},c=this.#o,l=o.length>0,h=l?this.#we(c,e,s,o):JSON.stringify({token:c,act:e,params:s}),d=this.#C()?{action:e,paramNames:Object.keys(a),fieldNames:Object.keys(i),encoding:l?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#G()}:null;await this.#ge();try{if(navigator.onLine===!1){this.#a(r.inverse),this.#n("offline"),this.#s(e,t,s,{kind:"offline"});return}let f;try{let p={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#Pe()};if(!l)p["Content-Type"]="application/json";let A=this.#Ie();if(A)p["X-Pgbus-Connection"]=A;he("action"),f=await fetch(this.#Re(),{method:"POST",headers:p,body:h,credentials:"same-origin",signal:AbortSignal.timeout(this.#xe())})}catch(p){if(console.error("[phlex-reactive] action error",p),this.#a(r.inverse),p?.name==="TimeoutError"||p?.name==="AbortError"){this.#n("timeout"),this.#s(e,t,s,{kind:"timeout"});return}this.#pe(),this.#n("network"),this.#s(e,t,s,{kind:"network"});return}if(d)d.status=f.status;if(f.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#a(r.inverse),this.#n("redirected"),this.#s(e,t,s,{kind:"redirected",status:f.status});return}if(!f.ok){let p=await f.text();if(console.error(`[phlex-reactive] action failed: HTTP ${f.status}`,p),this.#a(r.inverse),(f.headers.get("Content-Type")||"").includes("turbo-stream")){let A=this.#V(p);if(this.#o=A??this.#o,d)this.#b((Te)=>Te.recordBody(d,p,A));window.Turbo.renderStreamMessage(p)}this.#n("http"),this.#s(e,t,s,{kind:"http",status:f.status,body:p});return}let g=f.headers.get("Content-Type")||"";if(!g.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${g}" — no update applied`),this.#a(r.inverse),this.#n("content-type"),this.#s(e,t,s,{kind:"content-type",status:f.status});return}let y=await f.text(),T=this.#V(y);if(this.#o=T??this.#o,d)this.#b((p)=>p.recordBody(d,y,T));if(window.Turbo.renderStreamMessage(y),r.resurrect)queueMicrotask(r.resurrect);this.#me(),this.#i("reactive:applied",{action:e,params:s,html:y})}catch(f){console.error("[phlex-reactive] action error",f),this.#a(r.inverse),this.#i("reactive:error",{action:e,params:s,kind:"apply"})}finally{if(n?.(),d)this.#b((f)=>f.trace(this,{...d,ms:this.#G()-d.started}))}}get#o(){return this.#v??this.tokenValue}set#o(e){this.#v=e}tokenValueChanged(){this.#v=void 0}#V(e){let t=this.element.id;if(!t)return e.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:r,self:n}=this.#be(t),i=e.match(r);if(i)return i[1];let o=e.match(n);if(o)return o[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#be(e){let t=this.#j;if(t&&t.id===e)return t;let r=Ce(e);return this.#j={id:e,token:new RegExp(`<turbo-stream\\b[^>]*\\baction="reactive:token"[^>]*\\btarget="${r}"[^>]*\\bdata-reactive-token-value="([^"]+)"`),self:new RegExp(`<turbo-stream\\b[^>]*\\baction="(?:replace|update)"[^>]*\\btarget="${r}"[^>]*>([\\s\\S]*?)</turbo-stream>`)}}#F(e){return e.closest('[data-controller~="reactive"]')===this.element}#D(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(t)=>this.#F(t)}#Y(){let e={},t=[],r=this.#D(),n=[];this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((s)=>{if(!r(s))return;if(s.type==="file")for(let c of s.files??[])t.push({name:s.name,file:c,multiple:s.multiple});else n.push(s)});let i=[];this.element.querySelectorAll(`[name]${je}`).forEach((s)=>{if(r(s))i.push(s)});let o=this.#ve(n),a=this.#_e(n);for(let s of n)if(o.has(s.name)){let c=e[s.name]??(e[s.name]=[]);if(s.type==="checkbox"||s.type==="radio"){if(s.checked)c.push(s.value)}else if(s.type==="hidden"){if(!a.has(s.name))c.push(s.value)}else if(s.multiple&&s.options){for(let l of s.options)if(l.selected)c.push(l.value)}else c.push(s.value)}else if(s.type==="checkbox")e[s.name]=s.checked;else if(s.type==="radio"){if(s.checked)e[s.name]=s.value}else e[s.name]=s.value;return i.forEach((s)=>{let c=s.getAttribute("name");if(!c)return;let l=s.value??s.textContent??s.innerHTML??"",h=e[c];if(String(c).endsWith("[]")&&!Je(s))return;if(String(c).endsWith("[]")&&(h===void 0||Array.isArray(h))){(Array.isArray(h)?h:e[c]=[]).push(l);return}if(h==null||h==="")e[c]=l}),{fields:e,files:t}}#ve(e){let t=new Set;for(let r of e){if(r.type==="radio")continue;if(String(r.name).endsWith("[]"))t.add(r.name)}return t}#_e(e){let t=new Set;for(let r of e)if(r.type==="checkbox")t.add(r.name);return t}#we(e,t,r,n){let i=new FormData;i.append("token",e),i.append("act",t);let o=[];for(let[s,c]of Object.entries(r))if(Array.isArray(c)&&String(s).endsWith("[]"))if(c.length===0)o.push(String(s).slice(0,-2));else{let l=`${this.#k(s)}[]`;for(let h of c)i.append(l,String(h))}else this.#q(i,this.#k(s),c);for(let s of o)i.append("empty_groups[]",s);let a=this.#Se(n);for(let{name:s,file:c,multiple:l}of n){let d=l||a.has(s)?`${this.#k(s)}[]`:this.#k(s);i.append(d,c,c.name)}return i}#k(e){let t=String(e),r=t.indexOf("[");if(r===-1)return`params[${t}]`;return`params${[t.slice(0,r),...t.slice(r).match(/[^\[\]]+/g)??[]].map((i)=>`[${i}]`).join("")}`}#q(e,t,r){if(r==null)e.append(t,"");else if(Array.isArray(r))r.forEach((n,i)=>this.#q(e,`${t}[${i}]`,n));else if(typeof r==="object")for(let[n,i]of Object.entries(r))this.#q(e,`${t}[${n}]`,i);else e.append(t,String(r))}#Se(e){let t=new Map;for(let{name:r}of e)t.set(r,(t.get(r)??0)+1);return new Set([...t].filter(([,r])=>r>1).map(([r])=>r))}#X(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#Te(e){return W(e)}#Ae(e){q(e,(t)=>this.#W(t),(t,r)=>this.#B(`client op "${t}"`,r))}#$(){return this.element?.getAttribute?.("data-reactive-verbose")==="true"||this.#C()}#B(e,t){if(!this.#$())return;this.#b((r)=>r.diagnose(this,e,t))}#b(e){b("devtools",e)}#W(e){let t=e.to;if(t==="@root")return[this.element];if(typeof t!=="string"||t==="")return[];if(e.global)return[...document.querySelectorAll(t)];return[...this.element.querySelectorAll(t)].filter((r)=>this.#F(r))}#Ee(e,t){if(e?.checked!=="keep")return!1;let r=t?.type;return r==="checkbox"||r==="radio"}#a(e){if(!e)return;if(!this.element.isConnected)return;for(let t of e)t()}#Fe(e,t,r){this.#ke(e,t),ue();let n=!1;return()=>{if(n)return;n=!0,this.#Le(e,t),le();for(let i of r.undo)i()}}#ke(e,t){if(this.#c(t,e,1),this.#c(this.element,e,1),this.#l.set(e,(this.#l.get(e)??0)+1),this.#R++===0)this.element.setAttribute("aria-busy","true");for(let r of this.#Z(e))this.#c(r,e,1)}#Le(e,t){this.#c(t,e,-1),this.#c(this.element,e,-1);let r=(this.#l.get(e)??1)-1;if(r<=0)this.#l.delete(e);else this.#l.set(e,r);if(--this.#R<=0)this.#R=0,this.element.removeAttribute("aria-busy");for(let n of this.#Z(e))this.#c(n,e,-1)}#c(e,t,r){if(!e||typeof e.getAttribute!=="function")return;let n=this.#x.get(e)??new Map,i=(n.get(t)??0)+r;if(i<=0)n.delete(t);else n.set(t,i);if(n.size===0){this.#x.delete(e),e.removeAttribute("data-reactive-busy");return}this.#x.set(e,n),e.setAttribute("data-reactive-busy",[...n.keys()].join(" "))}#Z(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#F(r))}#Re(){return this.#Q??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#xe(){if(this.#L!=null)return this.#L;let e=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,t=Number(e);return this.#L=Number.isFinite(t)&&t>0?t:30000}#Pe(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#Ie(){return document.querySelector("pgbus-stream-source[connection-id]")?.getAttribute("connection-id")||document.querySelector('meta[name="pgbus-connection-id"]')?.content||null}}if(typeof window<"u")if(window.Turbo)G();else document.addEventListener("turbo:load",G,{once:!0});w("persist",()=>import("phlex/reactive/features/persist"),gt);w("defer",()=>import("phlex/reactive/features/defer"));w("form",()=>import("phlex/reactive/features/form"));w("bindings",()=>import("phlex/reactive/features/bindings"));w("compute",()=>import("phlex/reactive/features/compute"),yt);w("effects",()=>import("phlex/reactive/features/effects"));w("hints",()=>import("phlex/reactive/features/hints"));w("devtools",()=>import("phlex/reactive/features/devtools"));B();function gt(e,t){let r=()=>{t.edited=!0},n=(o)=>{let a=o.target;if(o.detail?.success&&a?.tagName==="FORM"&&a.contains?.(e))t.submitted=!0},i=["input","change","lexxy:change","trix-change"];for(let o of i)e.addEventListener?.(o,r);return document.addEventListener("turbo:submit-end",n),()=>{for(let o of i)e.removeEventListener?.(o,r);document.removeEventListener("turbo:submit-end",n)}}function yt(e,t){let r=()=>{t.edited=!0};return e.addEventListener?.("input",r),e.addEventListener?.("change",r),()=>{e.removeEventListener?.("input",r),e.removeEventListener?.("change",r)}}var bt=1000,S=null,Se,P=new Set;function vt(e){return ve(e).then((t)=>{if(e!=="effects")return;Se=t,t?.sweep()})}oe((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,o=be(_t(i)).filter((s)=>!P.has(s));if(!t&&!P.has("effects")&&wt(i))o.push("effects");if(o.length===0&&!S)return t?.wrap(e);if(o.length>0){for(let c of o)P.add(c);let s=S=Promise.race([Promise.all([S,...o.map(vt)]),new Promise((c)=>setTimeout(c,bt))]).then(()=>{if(S!==s)return;S=null,P.clear()})}let a=S;r.render=async(s)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??Se)?.wrap(c),await c.detail.render(s)}});function _t(e){let t=e?.querySelector?.("template")?.content;if(!t)return[];let r=[...t.querySelectorAll?.('[data-controller~="reactive"]')??[]];for(let n of t.children??[])if(n.matches?.('[data-controller~="reactive"]')&&!r.includes(n))r.unshift(n);return r}function wt(e){return Boolean(e?.hasAttribute?.("data-reactive-effect")||document.getElementById?.(e?.getAttribute?.("target"))?.matches?.("[data-reactive-effect-update],[data-reactive-effect-exit]")||e?.querySelector?.("template")?.content?.querySelector?.("[data-reactive-effect-enter],[data-reactive-dismiss-after]")||document.querySelector?.("[data-reactive-dismiss-after]:not([data-reactive-dismiss-scheduled])"))}var Ot=we;export{ce as ACTIVE_ATTR,je as EDITOR_SELECTOR,Ue as EDITOR_TAGS,de as REQUESTS_ATTR,De as checkReactiveRegistration,he as countReactiveRequest,Ot as default,ue as enterReactiveActivity,Ce as escapeRegExp,le as exitReactiveActivity,ve as loadReactiveFeature,oe as onReactiveStreamWithoutEffects,Et as reactiveActivityCount,Lt as reactiveFeatureNames,G as registerReactiveActions,Le as registerReactiveDefer,B as registerReactiveDev,Re as registerReactiveDismiss,Re as registerReactiveEffects,kt as registerReactiveFeature,w as registerReactiveFeatureLoader,ke as registerReactiveJs,xe as registerReactiveMorphFocus,Ie as registerReactiveOffline,Re as registerReactiveStreamRender,Fe as registerReactiveToken,Ee as registerReactiveVisit,Ft as resetReactiveActivity,be as unloadedFeaturesFor};
2
2
 
3
- //# debugId=4D029BB4C93EF11864756E2164756E21
3
+ //# debugId=9AF39057384FC9A664756E2164756E21
4
4
  //# sourceMappingURL=core.min.js.map