phlex-reactive 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +21 -4
- data/app/javascript/phlex/reactive/core.min.js +3 -3
- data/app/javascript/phlex/reactive/core.min.js.map +3 -3
- data/app/javascript/phlex/reactive/early.js +12 -4
- data/app/javascript/phlex/reactive/early.min.js +2 -2
- data/app/javascript/phlex/reactive/early.min.js.map +3 -3
- data/app/javascript/phlex/reactive/reactive_controller.min.js +3 -3
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +3 -3
- data/app/javascript/phlex/reactive/runtime.js +142 -7
- data/lib/phlex/reactive/component/helpers.rb +15 -0
- data/lib/phlex/reactive/js.rb +20 -0
- data/lib/phlex/reactive/shortcut.rb +18 -5
- data/lib/phlex/reactive/streamable.rb +7 -2
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b268544642595b7c8912db0dcbee175ed751fb73290d1bfcfec0c4c9627583b
|
|
4
|
+
data.tar.gz: 459a72f7b048c8db6010213e252d09c552eefb3296eb838bc36973d9ded2a48d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dfcf217a1d1dd7fae8a79c5a4d146409a5528a13a0a7f6cadfa757ba2728c740e90fb3e95ed6957740b4219c9ea7ac5ad0bf3c5c719442671662a1f803b6a6e8
|
|
7
|
+
data.tar.gz: 6636ad3074cd8cba009c507730d901c38afc343b228e0780c4cf50b7404a6b0f1c8f61e75c3b5edeeb5f0fa1a56f5966ea15ed53a8db5ee4987fe320fde85dc5
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,31 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
8
8
|
|
|
9
9
|
### Added
|
|
10
10
|
|
|
11
|
+
- **Modal dialogs — `js.show_modal` / `js.close_dialog` and
|
|
12
|
+
`data-reactive-modal` (#365).** `js.show_modal("#picker")` calls
|
|
13
|
+
`HTMLDialogElement#showModal()`, so an `on_client` dialog gets the browser's
|
|
14
|
+
top layer, focus trap, `::backdrop`, Escape and focus restored to the opener;
|
|
15
|
+
`js.close_dialog("#picker")` calls `close()`. A dialog already open
|
|
16
|
+
non-modally is reopened as a modal; a non-dialog target is skipped. A
|
|
17
|
+
`dialog(open: true, data: { reactive_modal: true })` the server renders (a
|
|
18
|
+
full page, a reply, a broadcast) is made modal at connect, after a morph and
|
|
19
|
+
after a stream that brings a dialog; a morph that renders it without `open`
|
|
20
|
+
closes it with `close()`, so the page behind is interactive again. Both ops
|
|
21
|
+
are actor-only, refused by `broadcast_to(js:)` like `focus`. Client: +499 B
|
|
22
|
+
gzipped in the default bundle, +425 B in the split core. Docs: "Modal
|
|
23
|
+
dialogs" on the client-ops example.
|
|
24
|
+
|
|
25
|
+
- **`shortcut: "delete"` / `"backspace"` (#366).** `on(:remove_selected,
|
|
26
|
+
shortcut: "delete")`, `"backspace"` and `"mod+backspace"` are accepted, on
|
|
27
|
+
`on(...)` and `on_client(:keydown, ...)`. Stimulus's default key map lacks
|
|
28
|
+
these keys (a `keydown.delete` filter throws "unknown key filter" at
|
|
29
|
+
keypress), so such a shortcut renders a bare `keydown@window` descriptor and
|
|
30
|
+
the client matches the chord itself, with the usual rules: prevented, this
|
|
31
|
+
platform's `mod`, skipped while typing unless `in_editable: true`.
|
|
32
|
+
`phlex/reactive/early` queues and prevents the chord before connect and leaves
|
|
33
|
+
every other key alone (+134 B gzipped). `once:` raises on these keys. Existing
|
|
34
|
+
chords render unchanged.
|
|
35
|
+
|
|
11
36
|
- **Presence — `reactive_presence`, `presence`, `js.presence` (#358).** A
|
|
12
37
|
roster component declares the presence stream it shows
|
|
13
38
|
(`reactive_presence :viewers, state: { selected: :integer }, ttl: 45`) and
|
data/README.md
CHANGED
|
@@ -684,7 +684,7 @@ Use in controllers: `render turbo_stream: Counter.replace(counter)`.
|
|
|
684
684
|
| `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). |
|
|
685
685
|
| `on(:action, once: true)` | Fire at most once, then unbind (Stimulus's native `:once`). |
|
|
686
686
|
| `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, plus `detail:` (run only when `event.detail` carries the listed values). See [Client-only ops](#client-only-ops-on_client--js--zero-round-trips). |
|
|
687
|
-
| `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. |
|
|
687
|
+
| `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`, `show_modal`/`close_dialog` (a real modal `<dialog>`), `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. |
|
|
688
688
|
| `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)) { … }`. |
|
|
689
689
|
| `reactive_editable(:name, multiline: false, placeholder: nil, on_enter: nil, on_escape: :revert, spellcheck: true)` | A plain-text **editable element** as a field (issue #351): `h3(**reactive_editable(:title)) { @card.title }`. Its text travels under the scope-aware `name`: with `multiline: true` its line breaks are sent as `\n`; a single-line field (the default) folds them to spaces; a morph keeps the focused element's text and caret (attributes still morph); paste is plain text; Enter runs `on_enter:` (a single-line field swallows it); Escape reverts. `reactive_dirty` and `reactive_persist` treat it like an input. See the [Editable text](https://phlex-reactive.zoolutions.llc/docs/editable-text) page. |
|
|
690
690
|
| `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). |
|
|
@@ -972,7 +972,15 @@ A shortcut is a window `keydown` binding with three rules a plain
|
|
|
972
972
|
`event:`, `window:` or `outside:` raises `ArgumentError`, as does a key outside
|
|
973
973
|
Stimulus's default key map (a letter, a digit, `enter`, `tab`, `esc`, `space`,
|
|
974
974
|
the arrows, `home`, `end`, `page_up`, `page_down`; bind a custom `keyMappings`
|
|
975
|
-
key with `event:` and `window:`)
|
|
975
|
+
key with `event:` and `window:`) other than `delete` and `backspace`. On
|
|
976
|
+
`on_client` the event must be bare `:keydown` or `"keydown"`.
|
|
977
|
+
|
|
978
|
+
`delete` and `backspace` are matched by the library rather than Stimulus (its
|
|
979
|
+
default key map lacks them, and a `keydown.delete` filter makes Stimulus throw
|
|
980
|
+
at keypress): the shortcut binds a bare `keydown@window` and the client matches
|
|
981
|
+
the chord, with every rule above — `on(:remove_selected, shortcut: "delete")`
|
|
982
|
+
never fires while typing in a field. They cannot take `once:` (the first key
|
|
983
|
+
pressed of any kind would spend the bare binding).
|
|
976
984
|
`shortcut` is now a **reserved keyword** on `on(...)`.
|
|
977
985
|
|
|
978
986
|
`once: true` on a shortcut unbinds the Stimulus descriptor after its first
|
|
@@ -1257,6 +1265,15 @@ button(**on_client(:click, js
|
|
|
1257
1265
|
- **`focus(to)`** focuses the first match; **`focus_first(to)`** focuses the first
|
|
1258
1266
|
focusable descendant of the match (e.g. the first menuitem inside an opened
|
|
1259
1267
|
menu).
|
|
1268
|
+
- **`show_modal(to)`** / **`close_dialog(to)`** (#365) call
|
|
1269
|
+
`HTMLDialogElement#showModal()` / `#close()`: the top layer, a focus trap,
|
|
1270
|
+
`::backdrop`, Escape to close and focus back on the opener — all the
|
|
1271
|
+
browser's own. A dialog already open non-modally is reopened as a modal; a
|
|
1272
|
+
target that is not a `<dialog>` is skipped. A dialog the server renders open
|
|
1273
|
+
with `data: { reactive_modal: true }` (a full page, a reply, a broadcast) is
|
|
1274
|
+
made modal as soon as the client sees it, and closed with `close()` when a
|
|
1275
|
+
morph renders it without `open`. **Actor-only like focus**: refused in
|
|
1276
|
+
`broadcast_to(js:)` — render the dialog open or closed, with the marker, instead.
|
|
1260
1277
|
- **`text(to, value)`** sets the target's `textContent` (stringified; `nil`
|
|
1261
1278
|
clears) — **XSS-safe by construction**, never `innerHTML`, strictly less
|
|
1262
1279
|
powerful than `set_attr`. With `global: true` it is the **cross-root text
|
|
@@ -3048,8 +3065,8 @@ Notifications::Badge.broadcast_to(user, :alerts,
|
|
|
3048
3065
|
```
|
|
3049
3066
|
|
|
3050
3067
|
`broadcast_to` with `js:` **refuses the actor-only ops** (`focus`/`focus_first`/
|
|
3051
|
-
`submit`/`paste_into`/`persist_state`/`persist_clear`/`check_group` raise
|
|
3052
|
-
`ArgumentError`): broadcasting focus would steal it in every subscriber's tab, a
|
|
3068
|
+
`show_modal`/`close_dialog`/`submit`/`paste_into`/`persist_state`/`persist_clear`/`check_group` raise
|
|
3069
|
+
`ArgumentError`): broadcasting focus (or a modal) would steal it in every subscriber's tab, a
|
|
3053
3070
|
broadcast submit would force-submit every subscriber's form, and a broadcast
|
|
3054
3071
|
clipboard read, draft write or selection change would be hostile — these
|
|
3055
3072
|
belong to the actor's own reply or gesture. Everything else is a fair broadcast
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{Controller as
|
|
1
|
+
import{Controller as We}from"@hotwired/stimulus";import{confirmResolver as re}from"phlex/reactive/confirm";function je(){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 Ue(){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 Je(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:js"])return;e["reactive:js"]=function(){let t=te(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}Y(t,(o)=>At(o,i),n?(o,a)=>b("devtools",(s)=>s.diagnoseStream(o,a,i)):void 0)}}function Ke(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:defer"])return;e["reactive:defer"]=function(){b("defer",(t)=>t.streamAction(this))}}var ne=!1,V=null;function ze(){if(ne)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;ne=!0,document.addEventListener("turbo:before-stream-render",(e)=>{if(He(e),Ve(e),V)V(e,p.get("effects"));else p.get("effects")?.wrap(e)})}var P="reactive:streamed";function He(e){let t=e.detail,r=t?.render,n=t?.newStream??e.target,i=n?.getAttribute?.("action"),o=/^(append|prepend|update)$/.test(i);if(typeof r!=="function"||!(o||/^(before|after|replace)$/.test(i)))return;let a=n.getAttribute("target"),s=n.getAttribute("targets"),c=new Set;for(let l of a?[document.getElementById(a)]:s?document.querySelectorAll(s):[]){let d=(o?l:l?.parentElement)?.closest?.('[data-controller~="reactive"]');if(d)c.add(d)}if(c.size===0)return;t.render=async(l)=>{await r(l);for(let d of c)if(d.isConnected)d.dispatchEvent(new Event(P))}}function X(e){return e?.tagName==="DIALOG"&&typeof e.showModal==="function"}function Z(e){try{return e.matches(":modal")}catch{return!1}}function _e(e){if(!X(e)){if(e?.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))console.warn(`[phlex-reactive] show_modal targets a <dialog>, not <${e.localName}> — skipped`);return}if(!e.isConnected||Z(e))return;if(e.open)e.close();e.showModal()}function Ge(e){if(X(e)&&e.open)e.close()}function O(e){let r=[...e?.querySelectorAll?.("dialog[data-reactive-modal]")??[]];if(e?.matches?.("dialog[data-reactive-modal]"))r.push(e);for(let n of r)if(n.open&&!Z(n))_e(n)}function Ve(e){let t=e.detail,r=t?.render,n=t?.newStream??e.target;if(typeof r!=="function"||!n?.querySelector?.("template")?.content?.querySelector?.("dialog"))return;t.render=async(i)=>{await r(i),O(document)}}var ie=!1;function Ye(){if(ie)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;ie=!0,document.addEventListener("turbo:morph-element",(t)=>{if(t.target?.matches?.('[data-controller~="reactive"]'))O(t.target)}),document.addEventListener("turbo:morph",()=>O(document));let e=new WeakSet;document.addEventListener("turbo:before-morph-element",(t)=>{let r=t.target,n=t.detail?.newElement;if(!X(r)||!n)return;if(n.hasAttribute?.("open"))e.delete(r);else e.add(r)}),document.addEventListener("turbo:before-morph-attribute",(t)=>{let{target:r,detail:n}=t;if(n?.attributeName!=="open"||n.mutationType!=="remove")return;if(!e.has(r)||!r.open||!Z(r))return;e.delete(r),t.preventDefault(),r.close()})}function we(e){V=e}var R,W=null,se="[data-reactive-editable][contenteditable=plaintext-only]";function Se(){if(R===void 0)try{let e=document.createElement("div");e.contentEditable="plaintext-only",R=e.contentEditable==="plaintext-only"}catch{R=!1}return R}function N(e){if(e.matches?.(se))e.setAttribute("contenteditable","true");e.querySelectorAll?.(se).forEach(N)}function Xe(){if(W||typeof document>"u"||typeof document.createElement!=="function")return;if(Se())return;N(document),W=new MutationObserver((e)=>{for(let t of e)if(t.type==="attributes")N(t.target);else t.addedNodes.forEach(N)}),W.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["contenteditable","data-reactive-editable"]})}var oe=!1;function j(e){return e===document.activeElement&&(e.localName==="input"||e.localName==="textarea"||e.hasAttribute("data-reactive-editable"))&&!e.hasAttribute("data-reactive-morph-value")&&!!e.closest('[data-controller~="reactive"]')}function Ze(){if(oe)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;oe=!0,document.addEventListener("turbo:before-morph-element",(e)=>{let t=e.target,r=e.detail?.newElement;if(!r||e.defaultPrevented)return;if(t.hasAttribute?.("data-reactive-editable")){if(M.set(t,F(r)),!j(t))return;for(let{name:i}of[...t.attributes])if(!r.hasAttribute(i)&&i!=="contenteditable")t.removeAttribute(i);for(let{name:i,value:o}of r.attributes)if(i!=="contenteditable"&&t.getAttribute(i)!==o)t.setAttribute(i,o);return e.preventDefault()}if(t.localName!=="input"||!j(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("focusin",(e)=>ee(e.target)),document.addEventListener("turbo:before-morph-attribute",(e)=>{if(e.detail?.attributeName==="value"&&j(e.target))e.preventDefault()})}var Qe="__materialize",ae=!1;function et(){if(ae)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;ae=!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 tt="phlex-reactive:latency";function Ae(){return typeof sessionStorage<"u"&&Boolean(sessionStorage.getItem(tt))}function Q(){if(typeof document>"u")return;if(!p.has("devtools")&&!_.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 Ee="data-reactive-active",w=0;function Te(){if(w++,w===1)Le("reactive:busy")}function Fe(){if(w===0)return;if(w--,w===0)Le("reactive:idle")}function Yt(){return w}function Xt(){w=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(Ee)}function Le(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.toggleAttribute==="function")t.toggleAttribute(Ee,w>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(e,{detail:{count:w}}))}var ke="data-reactive-requests";function xe(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.setAttribute!=="function"||!rt(t))return;let r=nt(t);r[e]=(Number(r[e])||0)+1,t.setAttribute(ke,JSON.stringify(r))}function rt(e){return e.hasAttribute?.("data-reactive-verbose")||!!document.querySelector?.('[data-reactive-verbose="true"]')}function nt(e){try{let t=JSON.parse(e.getAttribute(ke));if(t&&typeof t==="object")return{action:0,defer:0,...t}}catch{}return{action:0,defer:0}}function ce(){je(),Ue(),Je(),Ke(),ze(),Ze(),Ye(),Xe(),et(),Q()}function it(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var Re=Symbol.for("phlex-reactive.core");if(globalThis[Re])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[Re]=!0;var Pe=!1;function st(){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(st,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",e,{once:!0});else e()}var ot=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function at(e){let t=String(e).toLowerCase();return t.startsWith("on")||ot.has(t)}var U=new WeakMap;function ct(e,t,r){let[n,i,o]=t;U.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=(d)=>{if(a||d&&d.target!==e)return;a=!0,U.delete(e),clearTimeout(l),globalThis.cancelAnimationFrame?.(s),e.removeEventListener("animationend",c),e.removeEventListener("transitionend",c),e.classList.remove(n,i,o)};U.set(e,c),e.addEventListener("animationend",c),e.addEventListener("transitionend",c);let l=setTimeout(c,ut(e))}function ut(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 lt=":is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])",dt=new Set(["lexxy-editor","trix-editor"]);function F(e){let t="",r=!1,n=(o)=>{if(r&&t&&!t.endsWith(`
|
|
2
2
|
`))t+=`
|
|
3
3
|
`;r=!1,t+=o},i=(o)=>{for(let a of o.childNodes){let s=/^(div|p|li)$/.test(a.localName);if(s)r=!0;if(a.nodeType===3)a.data&&n(a.data);else if(a.localName==="br")n(`
|
|
4
4
|
`);else if(a.nodeType===1)i(a);if(s)r=!0}};return i(e),t=t.replace(/\r\n?/g,`
|
|
5
|
-
`).replace(/\n$/,""),e.getAttribute("data-reactive-editable")==="multi"?t:t.replace(/\n/g," ")}var O=new WeakMap;function Y(e){if(e?.hasAttribute?.("data-reactive-editable")&&!O.has(e))O.set(e,F(e))}function Le(e){return Y(e),O.get(e)}function it(e){return nt.has(e.localName)?typeof e.value==="string":!0}var ie=Object.freeze({show:(e,t,r)=>U(e,!1,t,r),hide:(e,t,r)=>U(e,!0,t,r),toggle:(e,t,r)=>U(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(J(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(J(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!J(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)=>ut(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))},presence:(e,t)=>b("presence",(r)=>r.set(e,t.state)),dispatch:(e,t)=>{e.dispatchEvent(new CustomEvent(t.name,{bubbles:!0,composed:!0,detail:t.detail??{}}))},submit:(e,t,r)=>{let n=st(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)=>ot(e),persist_state:(e,t)=>b("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>b("persist",(t)=>t.clearRoot(e))});function st(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function ot(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 at(e,t,r){if(r?.transition)et(e,r.transition,()=>e.hidden=t);else e.hidden=t}function U(e,t,r,n){if(at(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 J(e){if(!Qe(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}var ct='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function ut(e){return e.querySelectorAll?.(ct)?.[0]??null}function X(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 se=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"}),oe=Object.freeze(["meta","ctrl","alt","shift"]);function D(e,t,r){let n=e.split("+");for(let a of oe)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!oe.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let o=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(se,i)?se[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof o==="string"&&o.toLowerCase()===t.key.toLowerCase()}var lt=(e)=>e&&typeof e==="object"?e.keys:String(e);function ae(e,t,r){let n=t.target;if(e?.inEditable!==!0&&(n?.isContentEditable||/^(input|textarea|select)$/.test(n?.localName)))return!1;let i=/[Mm]ac|iP/.test(navigator.userAgentData?.platform??navigator.platform)?"meta":"ctrl";return D(lt(e).replace(/^mod\+/,`${i}+`),t,r)}function dt(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:X(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 ce(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)!==Ne(t.currentTarget))return!1;return i<0||r===null||D(n.slice(i+1),t,r)}function ft(e,t){let r=e.detail;if(r===void 0)return!0;if(r===null||typeof r!=="object"||Array.isArray(r))return!1;let n=t.detail;if(n===null||typeof n!=="object")return!1;return Object.keys(r).every((i)=>n[i]===r[i])}var ue=new WeakMap;function ht(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=ue.get(e);if(!i)i=new WeakMap,ue.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 le=new WeakMap;function mt(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=le.get(e);if(!i)i=new WeakMap,le.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 V(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,o={}]=n;if(!Object.hasOwn(ie,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)ie[i](s,o,t)}}function pt(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 gt(e){let t=e.getAttribute?.("data-reactive-persist");return Boolean(t)&&t!=="off"}function ke(e){return["defer-token","defer-src","lazy-on","lazy-visible"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)}function bt(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 yt(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], [data-reactive-editable]")!=null}function vt(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}function _t(e){return Boolean(e.matches?.("[data-reactive-sortable],[data-reactive-sortable-source]")||e.querySelector?.("[data-reactive-sortable],[data-reactive-sortable-source]"))}function xe(e){return e.getAttribute?.("data-reactive-presence")!=null}var St=[["persist",[gt,null,null,!0]],["defer",[ke,null]],["form",[bt,null]],["bindings",[yt,null,null,!0]],["compute",[vt,null,null,!0]],["sortable",[_t,null]],["presence",[xe,null]],["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]]],_=new Map(St),de=new Map,p=new Map,wt=new Map;function y(e,t,r){Re.set(e,[t,r]),At(e)}var Re=new Map;function At(e){let t=_.get(e),[r,n]=Re.get(e);t[1]=r,t[2]=n}function Jt(e,t){t.install?.(L),p.set(e,t),wt.set(e,t)}function Pe(e){let t=[];for(let[r,[n]]of _){if(!n||p.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function Ie(e){return E(e).catch((t)=>M(e,"load",t))}function E(e){let t=de.get(e);if(!t)t=(_.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(L),p.set(e,n),n)),de.set(e,t);return t}var fe=new Set;function M(e,t,r){let n=e+t;if(fe.has(n))return;fe.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=p.get(e);if(r)return t(r);E(e).then(t,(n)=>M(e,"load",n))}var Tt=1e4;function K(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:Tt}function Kt(){return[..._.keys()]}var he=Promise.resolve();function me(e,t,r){let n=L.waiting.get(e);if(n&&n[t]===r)delete n[t]}var L={enter:_e,exit:Se,count:Te,text:F,served:Le,waiting:new WeakMap};var k=Symbol.for("phlex-reactive.early"),Et=1e4,Ft=1500,Ne=(e)=>e!=null&&(e===globalThis.window||e.window===e);function z(){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:Et}function kt(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 xt(e,t,r){return{[k]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:kt(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 C=new WeakMap;function Rt(e,{token:t,type:r,method:n,filter:i,win:o},a){let s=C.get(e);if(!s)C.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 pe(e,t,r,n){if(e?.[k])return!1;let i=Ne(e?.currentTarget),o=i?n:e?.currentTarget,a=It(e,o,i?`@${t}`:t),s=C.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&&!D(l.filter,e,r))continue;return l.armed=!1,!0}return a}var N=new WeakMap;function Pt(e,t,r){let n=N.get(e);if(!n)N.set(e,n=new Map),setTimeout(()=>N.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function It(e,t,r){let n=e&&N.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class Oe extends Ce{static values={token:String};#_;#S=new Map;#l=new Map;#ee;#k;#j;#x=0;#d=new Map;#R=new WeakMap;#t;featuresReady=he;#r=new Map;#P=new Set;#f=!1;#n=null;#h=new Map;#w=new Map;#m=new Map;#p=0;#U;#Ne=0;#Oe=0;connect(){if(Fe=!0,z().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||ke(this.element))this.#t=(e)=>{if(e.type==="focusin"?!e.target.hasAttribute?.("data-reactive-editable"):e.target!==this.element)return;if(e.type===P)this.#z();this.#J(!0)},this.element.addEventListener?.("turbo:morph-element",this.#t),this.element.addEventListener?.("focusin",this.#t),this.element.addEventListener?.(P,this.#t);this.element.querySelectorAll?.("[data-reactive-editable]").forEach(Y),this.#p++,this.featuresReady=he,this.#J(),this.#ie()}#Me(e){}#Ce(e,t,r,n){}#De(){}#qe(e,t){}#J(e){{let t=this.#p,r=[];for(let[o,[a]]of _){if(!a||this.#P.has(o))continue;let s=p.get(o);if(s&&!s.connect)continue;try{if(a(this.element))r.push(o)}catch(c){this.#g(o,"detect",c)}}if(r.length===0)return;for(let o of r)this.#P.add(o);if(!this.#f&&r.every((o)=>p.has(o))){for(let o of r)this.#I(t,o,p.get(o),e);return}for(let o of r){let a=this.#te(t,o),s=[];for(let l of _.keys()){if(l===o)break;if(this.#m.has(l))s.push(this.#m.get(l))}let c=Promise.all(s).then(()=>a).then((l)=>l&&this.#I(t,o,l,e));if(this.#m.set(o,c),_.get(o)[3])this.#n=c}let n=this.#n;n?.then(()=>{if(this.#n===n)this.#n=null}),this.#f=!0;let i=Promise.all(this.#m.values()).then(()=>{if(this.featuresReady===i)this.#f=!1});this.featuresReady=i}}#te(e,t){{let r=()=>e===this.#p;return this.#re(t),new Promise((n)=>{let i=!1,o=setTimeout(()=>{if(this.#h.delete(o),i=!0,r())this.#g(t,"timeout",Error(`not loaded after ${K()} ms`));n(null)},K());this.#h.set(o,n);let a=()=>{clearTimeout(o),this.#h.delete(o)};E(t).then((s)=>{if(a(),i)queueMicrotask(()=>this.#I(e,t,s));else n(s)},(s)=>{if(a(),r())this.#g(t,"load",s);n(null)})})}}#re(e){{let t=_.get(e)[2];if(!t)return;let r={};try{this.#w.set(e,[t(this.element,r),r]),L.waiting.set(this.element,{...L.waiting.get(this.element),[e]:r})}catch(n){this.#g(e,"detect",n)}}}#K(e,t){{let[r,n]=this.#w.get(e)??[];if(this.#w.delete(e),!t)me(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.#p)return;let i=this.#K(t);try{r.connect?.(this,this.#e(),n,i),this.#r.set(t,r)}catch(o){this.#g(t,"connect",o)}}}#e(){return this.#U??={emit:(e,t,r)=>this.#s(e,t,r),reseed:()=>this.#z(),proceed:(e,t,r,n)=>this.#O(e,t,r,0,0,null,n),forgetToken:()=>{this.#_=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)=>V(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.#X(),plain:be,text:F,served:Le,confirm:(e,t)=>Promise.resolve().then(()=>Z(e,t)).catch(()=>!1)},this.#U}#z(){this.#r.get("form")?.reseed(this),this.#r.get("bindings")?.reseed(this),this.#r.get("compute")?.seed(this)}#g(e,t,r){if(M(e,t,r),this.#i("feature"),t==="load"&&this.element.getAttribute?.("data-reactive-defer-pending"))this.element.removeAttribute("data-reactive-defer-pending"),this.element.removeAttribute("aria-busy");this.#s("reactive:error",{kind:"feature",feature:e,phase:t,error:r})}#ne(){{this.#p++;for(let[t,r]of this.#h)clearTimeout(t),r(null);this.#h.clear();for(let t of[...this.#w.keys()]){let r=this.#K(t,!0),n=this.element;b(t,(i)=>{i.abandon?.(n,r),me(n,t,r)})}this.#P.clear(),this.#m.clear(),this.#f=!1,this.#n=null;let e=[...this.#r];this.#r.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}=z();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(Ft,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=xt(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&&!D(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!Rt(s,c,n&&JSON.stringify(i.params)))continue;this.#N.add(s)}if(Pt(e,s,n?`@${c.method}`:c.method),c.method==="runOps")this.runOps(i);else this.dispatch(i)}}disconnect(){if(this.#ne(),this.#de(),this.#he(),this.#t)this.element.removeEventListener?.("turbo:morph-element",this.#t),this.element.removeEventListener?.("focusin",this.#t),this.element.removeEventListener?.(P,this.#t);z().connected.delete(this.element),this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#N)C.delete(e);this.#N.clear()}dispatch(e){if(pe(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,shortcut:d}=e.params;if(!t)return;if(d!=null&&!ae(d,e,this.application?.schema?.keyMappings))return;let m=e.params.busy??e.params.loading;if(s&&this.element.contains(e.target))return;let f=e.currentTarget??e.target;if((d!=null||!c)&&!this.#Ee(l,f))e.preventDefault();if(t===Ke){let w=()=>{{let h=this.#r.get("defer");if(h)return h.materialize(this)}if(this.tokenValue)return this.#O(f,t,"{}")};return this.#f?this.featuresReady.then(w):w()}let g=this.#H(o,a),v=()=>this.#O(f,t,r,n,i,l,m);if(!g)return v();if(g instanceof Promise)return g.then((w)=>w?this.#A(w,f,v):v());this.#A(g,f,v)}#A(e,t,r){return Promise.resolve().then(()=>Z(e,{el:t})).catch(()=>!1).then((n)=>{if(n)r()})}#H(e,t){if(e)return e;if(!t)return null;{let r=p.get("bindings");if(r)return r.confirmMessage(this,this.#e(),t);return this.#V("bindings").then((n)=>n&&n.confirmMessage(this,this.#e(),t))}}#V(e){{let t;return Promise.race([E(e).catch((r)=>(M(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),K()))]).finally(()=>clearTimeout(t))}}runOps(e){if(pe(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(mt(e,this))return;let t=e.params??{},r=e.currentTarget??e.target,n=dt(t.ops),i=n.filter((a)=>ce(a,e,null)),o=i.length<=1?i:i.filter((a)=>ce(a,e,this.application?.schema?.keyMappings));if(o.length===0&&n.length>0){if(this.#$())this.#v((a)=>a.noBinding(this,e));return}for(let a of o){if(a.outside&&e[k])continue;if(!ft(a,e))continue;if(a.shortcut!=null&&!ae(a.shortcut,e,this.application?.schema?.keyMappings))continue;if(ht(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,shortcut:o},a,s){if(n&&this.element.contains(a.target))return;if(o!=null||!i)a.preventDefault();let c=this.#H(t,r),l=()=>this.#Te(this.#Ae(e));if(!c)return l();if(c instanceof Promise)return c.then((d)=>d?this.#A(d,s,l):l());this.#A(c,s,l)}recompute(e){return p.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.#b("tagsAdd",e)}tagsPick(e){return this.#b("tagsPick",e)}tagsRemove(e){return this.#b("tagsRemove",e)}nestedAdd(e){return this.#b("nestedAdd",e)}nestedRemove(e){return this.#b("nestedRemove",e)}syncNestedJson(e){return p.get("bindings")?.syncNestedJson(this,this.#e(),e)}#b(e,t){{let r=p.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.#r.get("form")??p.get("form"))?.scan(this,this.#e())}listnavNext(e){this.#T(e,(t,r)=>t<0?0:(t+1)%r)}listnavPrev(e){this.#T(e,(t,r)=>t<0?r-1:(t-1+r)%r)}listnavFirst(e){this.#T(e,()=>0)}listnavLast(e){this.#T(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")}#T(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.#s("reactive:before-dispatch",{action:t,params:this.#Z(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.#fe(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=p.get("hints");if(!s||l)c(l);let d=()=>this.#be(e,t,o,a),m=()=>this.#n?this.#n.then(d):d();return this.queue=(this.queue??Promise.resolve()).then(()=>s&&!l?this.#ue().then(c).then(m):m()),this.queue}#ue(){return this.#V("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.#S.set(e,{timer:s,flush:a})}#M(e){let t=this.#S.get(e);if(!t)return;clearTimeout(t.timer),e?.removeEventListener?.("blur",t.flush),this.#S.delete(e)}#de(){for(let e of[...this.#S.keys()])this.#M(e)}#fe(e,t,r,n,i,o){let a=this.#l.get(e)??new Map;if(a.has(r))return;let s=setTimeout(()=>{if(a.delete(r),a.size===0)this.#l.delete(e)},t);return a.set(r,s),this.#l.set(e,a),this.#E(r,n,i,e,o)}#he(){for(let e of this.#l.values())for(let t of e.values())clearTimeout(t);this.#l.clear()}#s(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}#o(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.#s("reactive:error",{action:e,params:r,...n,retry:i})}#i(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=p.get("devtools");if(e)return e.delay();if(ye())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#be(e,t,r,n){let{fields:i,files:o}=this.#X(),a=this.#Z(t),s={...i,...a},c=this.#a,l=o.length>0,d=l?this.#Se(c,e,s,o):JSON.stringify({token:c,act:e,params:s}),m=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.#c(r.inverse),this.#i("offline"),this.#o(e,t,s,{kind:"offline"});return}let f;try{let h={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#Pe()};if(!l)h["Content-Type"]="application/json";let T=this.#Ie();if(T)h["X-Pgbus-Connection"]=T;let x=xe(this.element)&&document.getElementById(`reactive-presence-src-${this.element.id}`)?.getAttribute("connection-id");if(x)h["X-Reactive-Presence"]=x;Te("action"),f=await fetch(this.#xe(),{method:"POST",headers:h,body:d,credentials:"same-origin",signal:AbortSignal.timeout(this.#Re())})}catch(h){if(console.error("[phlex-reactive] action error",h),this.#c(r.inverse),h?.name==="TimeoutError"||h?.name==="AbortError"){this.#i("timeout"),this.#o(e,t,s,{kind:"timeout"});return}this.#pe(),this.#i("network"),this.#o(e,t,s,{kind:"network"});return}if(m)m.status=f.status;if(f.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#c(r.inverse),this.#i("redirected"),this.#o(e,t,s,{kind:"redirected",status:f.status});return}if(!f.ok){let h=await f.text();if(console.error(`[phlex-reactive] action failed: HTTP ${f.status}`,h),this.#c(r.inverse),(f.headers.get("Content-Type")||"").includes("turbo-stream")){let T=this.#Y(h);if(this.#a=T??this.#a,m)this.#v((x)=>x.recordBody(m,h,T));window.Turbo.renderStreamMessage(h)}this.#i("http"),this.#o(e,t,s,{kind:"http",status:f.status,body:h});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.#c(r.inverse),this.#i("content-type"),this.#o(e,t,s,{kind:"content-type",status:f.status});return}let v=await f.text(),w=this.#Y(v);if(this.#a=w??this.#a,m)this.#v((h)=>h.recordBody(m,v,w));if(window.Turbo.renderStreamMessage(v),r.resurrect)queueMicrotask(r.resurrect);return this.#me(),this.#s("reactive:applied",{action:e,params:s,html:v}),v}catch(f){console.error("[phlex-reactive] action error",f),this.#c(r.inverse),this.#s("reactive:error",{action:e,params:s,kind:"apply"})}finally{if(n?.(),m)this.#v((f)=>f.trace(this,{...m,ms:this.#G()-m.started}))}}get#a(){return this.#_??this.tokenValue}set#a(e){this.#_=e}tokenValueChanged(){this.#_=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.#ye(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}#ye(e){let t=this.#j;if(t&&t.id===e)return t;let r=Ye(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)}#X(){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]${rt}`).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.getAttribute("data-reactive-editable")!=null?F(s):s.value??s.textContent??s.innerHTML??"",d=e[c];if(String(c).endsWith("[]")&&!it(s))return;if(String(c).endsWith("[]")&&(d===void 0||Array.isArray(d))){(Array.isArray(d)?d:e[c]=[]).push(l);return}if(d==null||d==="")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}#Se(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.#L(s)}[]`;for(let d of c)i.append(l,String(d))}else this.#q(i,this.#L(s),c);for(let s of o)i.append("empty_groups[]",s);let a=this.#we(n);for(let{name:s,file:c,multiple:l}of n){let m=l||a.has(s)?`${this.#L(s)}[]`:this.#L(s);i.append(m,c,c.name)}return i}#L(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))}#we(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))}#Z(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#Ae(e){return X(e)}#Te(e){V(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.#v((r)=>r.diagnose(this,e,t))}#v(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"}#c(e){if(!e)return;if(!this.element.isConnected)return;for(let t of e)t()}#Fe(e,t,r){this.#Le(e,t),_e();let n=!1;return()=>{if(n)return;n=!0,this.#ke(e,t),Se();for(let i of r.undo)i()}}#Le(e,t){if(this.#u(t,e,1),this.#u(this.element,e,1),this.#d.set(e,(this.#d.get(e)??0)+1),this.#x++===0)this.element.setAttribute("aria-busy","true");for(let r of this.#Q(e))this.#u(r,e,1)}#ke(e,t){this.#u(t,e,-1),this.#u(this.element,e,-1);let r=(this.#d.get(e)??1)-1;if(r<=0)this.#d.delete(e);else this.#d.set(e,r);if(--this.#x<=0)this.#x=0,this.element.removeAttribute("aria-busy");for(let n of this.#Q(e))this.#u(n,e,-1)}#u(e,t,r){if(!e||typeof e.getAttribute!=="function")return;let n=this.#R.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.#R.delete(e),e.removeAttribute("data-reactive-busy");return}this.#R.set(e,n),e.setAttribute("data-reactive-busy",[...n.keys()].join(" "))}#Q(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#F(r))}#xe(){return this.#ee??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#Re(){if(this.#k!=null)return this.#k;let e=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,t=Number(e);return this.#k=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)ne();else document.addEventListener("turbo:load",ne,{once:!0});y("persist",()=>import("phlex/reactive/features/persist"),Nt);y("defer",()=>import("phlex/reactive/features/defer"));y("form",()=>import("phlex/reactive/features/form"));y("bindings",()=>import("phlex/reactive/features/bindings"));y("compute",()=>import("phlex/reactive/features/compute"),Ot);y("sortable",()=>import("phlex/reactive/features/sortable"));y("presence",()=>import("phlex/reactive/features/presence"));y("effects",()=>import("phlex/reactive/features/effects"));y("hints",()=>import("phlex/reactive/features/hints"));y("devtools",()=>import("phlex/reactive/features/devtools"));G();function Nt(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 Ot(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 Mt=1000,A=null,Me,q=new Set;function Ct(e){return Ie(e).then((t)=>{if(e!=="effects")return;Me=t,t?.sweep()})}ge((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,o=Pe(Dt(i)).filter((s)=>!q.has(s));if(!t&&!q.has("effects")&&qt(i))o.push("effects");if(o.length===0&&!A)return t?.wrap(e);if(o.length>0){for(let c of o)q.add(c);let s=A=Promise.race([Promise.all([A,...o.map(Ct)]),new Promise((c)=>setTimeout(c,Mt))]).then(()=>{if(A!==s)return;A=null,q.clear()})}let a=A;r.render=async(s)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??Me)?.wrap(c),await c.detail.render(s)}});function Dt(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.push(t),r}function qt(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 Xt=Oe;export{ve as ACTIVE_ATTR,rt as EDITOR_SELECTOR,nt as EDITOR_TAGS,Ae as REQUESTS_ATTR,Xe as checkReactiveRegistration,Te as countReactiveRequest,Xt as default,F as editableValue,_e as enterReactiveActivity,Ye as escapeRegExp,Se as exitReactiveActivity,Ie as loadReactiveFeature,ge as onReactiveStreamWithoutEffects,jt as reactiveActivityCount,Kt as reactiveFeatureNames,ne as registerReactiveActions,Be as registerReactiveDefer,G as registerReactiveDev,We as registerReactiveDismiss,We as registerReactiveEffects,Jt as registerReactiveFeature,y as registerReactiveFeatureLoader,$e as registerReactiveJs,Je as registerReactiveMorphFocus,ze as registerReactiveOffline,Ue as registerReactivePlaintext,We as registerReactiveStreamRender,qe as registerReactiveToken,De as registerReactiveVisit,Ut as resetReactiveActivity,Le as serverText,Pe as unloadedFeaturesFor};
|
|
5
|
+
`).replace(/\n$/,""),e.getAttribute("data-reactive-editable")==="multi"?t:t.replace(/\n/g," ")}var M=new WeakMap;function ee(e){if(e?.hasAttribute?.("data-reactive-editable")&&!M.has(e))M.set(e,F(e))}function Ne(e){return ee(e),M.get(e)}function ft(e){return dt.has(e.localName)?typeof e.value==="string":!0}var ue=Object.freeze({show:(e,t,r)=>J(e,!1,t,r),hide:(e,t,r)=>J(e,!0,t,r),toggle:(e,t,r)=>J(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(K(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(K(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!K(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)=>bt(e)?.focus?.(),show_modal:(e)=>_e(e),close_dialog:(e)=>Ge(e),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))},presence:(e,t)=>b("presence",(r)=>r.set(e,t.state)),dispatch:(e,t)=>{e.dispatchEvent(new CustomEvent(t.name,{bubbles:!0,composed:!0,detail:t.detail??{}}))},submit:(e,t,r)=>{let n=ht(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)=>mt(e),persist_state:(e,t)=>b("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>b("persist",(t)=>t.clearRoot(e))});function ht(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function mt(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 pt(e,t,r){if(r?.transition)ct(e,r.transition,()=>e.hidden=t);else e.hidden=t}function J(e,t,r,n){if(pt(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 K(e){if(!at(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}var gt='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function bt(e){return e.querySelectorAll?.(gt)?.[0]??null}function te(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 le=Object.freeze({backspace:"Backspace",delete:"Delete",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"}),de=Object.freeze(["meta","ctrl","alt","shift"]);function q(e,t,r){let n=e.split("+");for(let a of de)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!de.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let o=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(le,i)?le[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof o==="string"&&o.toLowerCase()===t.key.toLowerCase()}var yt=(e)=>e&&typeof e==="object"?e.keys:String(e);function z(e,t,r){let n=t.target;if(e?.inEditable!==!0&&(n?.isContentEditable||/^(input|textarea|select)$/.test(n?.localName)))return!1;let i=/[Mm]ac|iP/.test(navigator.userAgentData?.platform??navigator.platform)?"meta":"ctrl";return q(yt(e).replace(/^mod\+/,`${i}+`),t,r)}function vt(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:te(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 fe(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)!==qe(t.currentTarget))return!1;return i<0||r===null||q(n.slice(i+1),t,r)}function _t(e,t){let r=e.detail;if(r===void 0)return!0;if(r===null||typeof r!=="object"||Array.isArray(r))return!1;let n=t.detail;if(n===null||typeof n!=="object")return!1;return Object.keys(r).every((i)=>n[i]===r[i])}var he=new WeakMap;function wt(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=he.get(e);if(!i)i=new WeakMap,he.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 me=new WeakMap;function St(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=me.get(e);if(!i)i=new WeakMap,me.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 Y(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,o={}]=n;if(!Object.hasOwn(ue,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)ue[i](s,o,t)}}function At(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 Ie(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 Ft(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], [data-reactive-editable]")!=null}function Lt(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}function kt(e){return Boolean(e.matches?.("[data-reactive-sortable],[data-reactive-sortable-source]")||e.querySelector?.("[data-reactive-sortable],[data-reactive-sortable-source]"))}function Oe(e){return e.getAttribute?.("data-reactive-presence")!=null}var xt=[["persist",[Et,null,null,!0]],["defer",[Ie,null]],["form",[Tt,null]],["bindings",[Ft,null,null,!0]],["compute",[Lt,null,null,!0]],["sortable",[kt,null]],["presence",[Oe,null]],["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]]],_=new Map(xt),pe=new Map,p=new Map,Rt=new Map;function y(e,t,r){Me.set(e,[t,r]),Pt(e)}var Me=new Map;function Pt(e){let t=_.get(e),[r,n]=Me.get(e);t[1]=r,t[2]=n}function Zt(e,t){t.install?.(L),p.set(e,t),Rt.set(e,t)}function Ce(e){let t=[];for(let[r,[n]]of _){if(!n||p.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function De(e){return T(e).catch((t)=>C(e,"load",t))}function T(e){let t=pe.get(e);if(!t)t=(_.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(L),p.set(e,n),n)),pe.set(e,t);return t}var ge=new Set;function C(e,t,r){let n=e+t;if(ge.has(n))return;ge.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=p.get(e);if(r)return t(r);T(e).then(t,(n)=>C(e,"load",n))}var Nt=1e4;function H(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:Nt}function Qt(){return[..._.keys()]}var be=Promise.resolve();function ye(e,t,r){let n=L.waiting.get(e);if(n&&n[t]===r)delete n[t]}var L={enter:Te,exit:Fe,count:xe,text:F,served:Ne,waiting:new WeakMap};var k=Symbol.for("phlex-reactive.early"),It=1e4,Ot=1500,qe=(e)=>e!=null&&(e===globalThis.window||e.window===e);function G(){return globalThis[k]??={queue:[],connected:new WeakSet},globalThis[k]}function Mt(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:It}function Ct(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:Ct(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 D=new WeakMap;function qt(e,{token:t,type:r,method:n,filter:i,win:o},a){let s=D.get(e);if(!s)D.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 ve(e,t,r,n){if(e?.[k])return!1;let i=qe(e?.currentTarget),o=i?n:e?.currentTarget,a=Bt(e,o,i?`@${t}`:t),s=D.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&&!q(l.filter,e,r))continue;return l.armed=!1,!0}return a}var I=new WeakMap;function $t(e,t,r){let n=I.get(e);if(!n)I.set(e,n=new Map),setTimeout(()=>I.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function Bt(e,t,r){let n=e&&I.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class $e extends We{static values={token:String};#_;#w=new Map;#l=new Map;#ee;#k;#j;#x=0;#d=new Map;#R=new WeakMap;#t;featuresReady=be;#r=new Map;#P=new Set;#f=!1;#n=null;#h=new Map;#S=new Map;#m=new Map;#p=0;#U;#Ie=0;#Oe=0;connect(){if(Pe=!0,G().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||Ie(this.element))this.#t=(e)=>{if(e.type==="focusin"?!e.target.hasAttribute?.("data-reactive-editable"):e.target!==this.element)return;if(e.type===P)this.#z();this.#J(!0)},this.element.addEventListener?.("turbo:morph-element",this.#t),this.element.addEventListener?.("focusin",this.#t),this.element.addEventListener?.(P,this.#t);this.element.querySelectorAll?.("[data-reactive-editable]").forEach(ee),this.#p++,this.featuresReady=be,this.#J(),O(this.element),this.#ie()}#Me(e){}#Ce(e,t,r,n){}#De(){}#qe(e,t){}#J(e){{let t=this.#p,r=[];for(let[o,[a]]of _){if(!a||this.#P.has(o))continue;let s=p.get(o);if(s&&!s.connect)continue;try{if(a(this.element))r.push(o)}catch(c){this.#g(o,"detect",c)}}if(r.length===0)return;for(let o of r)this.#P.add(o);if(!this.#f&&r.every((o)=>p.has(o))){for(let o of r)this.#N(t,o,p.get(o),e);return}for(let o of r){let a=this.#te(t,o),s=[];for(let l of _.keys()){if(l===o)break;if(this.#m.has(l))s.push(this.#m.get(l))}let c=Promise.all(s).then(()=>a).then((l)=>l&&this.#N(t,o,l,e));if(this.#m.set(o,c),_.get(o)[3])this.#n=c}let n=this.#n;n?.then(()=>{if(this.#n===n)this.#n=null}),this.#f=!0;let i=Promise.all(this.#m.values()).then(()=>{if(this.featuresReady===i)this.#f=!1});this.featuresReady=i}}#te(e,t){{let r=()=>e===this.#p;return this.#re(t),new Promise((n)=>{let i=!1,o=setTimeout(()=>{if(this.#h.delete(o),i=!0,r())this.#g(t,"timeout",Error(`not loaded after ${H()} ms`));n(null)},H());this.#h.set(o,n);let a=()=>{clearTimeout(o),this.#h.delete(o)};T(t).then((s)=>{if(a(),i)queueMicrotask(()=>this.#N(e,t,s));else n(s)},(s)=>{if(a(),r())this.#g(t,"load",s);n(null)})})}}#re(e){{let t=_.get(e)[2];if(!t)return;let r={};try{this.#S.set(e,[t(this.element,r),r]),L.waiting.set(this.element,{...L.waiting.get(this.element),[e]:r})}catch(n){this.#g(e,"detect",n)}}}#K(e,t){{let[r,n]=this.#S.get(e)??[];if(this.#S.delete(e),!t)ye(this.element,e,n);try{r?.()}catch(i){console.error(`[phlex-reactive] the "${e}" feature module failed to stop waiting`,i)}return n}}#N(e,t,r,n){{if(e!==this.#p)return;let i=this.#K(t);try{r.connect?.(this,this.#e(),n,i),this.#r.set(t,r)}catch(o){this.#g(t,"connect",o)}}}#e(){return this.#U??={emit:(e,t,r)=>this.#s(e,t,r),reseed:()=>this.#z(),proceed:(e,t,r,n)=>this.#O(e,t,r,0,0,null,n),forgetToken:()=>{this.#_=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)=>Y(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.#X(),plain:Se,text:F,served:Ne,confirm:(e,t)=>Promise.resolve().then(()=>re(e,t)).catch(()=>!1)},this.#U}#z(){this.#r.get("form")?.reseed(this),this.#r.get("bindings")?.reseed(this),this.#r.get("compute")?.seed(this)}#g(e,t,r){if(C(e,t,r),this.#i("feature"),t==="load"&&this.element.getAttribute?.("data-reactive-defer-pending"))this.element.removeAttribute("data-reactive-defer-pending"),this.element.removeAttribute("aria-busy");this.#s("reactive:error",{kind:"feature",feature:e,phase:t,error:r})}#ne(){{this.#p++;for(let[t,r]of this.#h)clearTimeout(t),r(null);this.#h.clear();for(let t of[...this.#S.keys()]){let r=this.#K(t,!0),n=this.element;b(t,(i)=>{i.abandon?.(n,r),ye(n,t,r)})}this.#P.clear(),this.#m.clear(),this.#f=!1,this.#n=null;let e=[...this.#r];this.#r.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()}#I=new Set;#se(){let{queue:e}=G();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=Mt(),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(Ot,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&&!q(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!qt(s,c,n&&JSON.stringify(i.params)))continue;this.#I.add(s)}if($t(e,s,n?`@${c.method}`:c.method),c.method==="runOps")this.runOps(i);else this.dispatch(i)}}disconnect(){if(this.#ne(),this.#de(),this.#he(),this.#t)this.element.removeEventListener?.("turbo:morph-element",this.#t),this.element.removeEventListener?.("focusin",this.#t),this.element.removeEventListener?.(P,this.#t);G().connected.delete(this.element),this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#I)D.delete(e);this.#I.clear()}dispatch(e){let t=e.params?.shortcut;if(t!=null&&!z(t,e,this.application?.schema?.keyMappings))return;if(ve(e,"dispatch",this.application?.schema?.keyMappings,this.element))return;let{action:r,params:n,debounce:i,throttle:o,confirm:a,confirmWhen:s,outside:c,window:l,optimistic:d}=e.params;if(!r)return;let m=e.params.busy??e.params.loading;if(c&&this.element.contains(e.target))return;let f=e.currentTarget??e.target;if((t!=null||!l)&&!this.#Te(d,f))e.preventDefault();if(r===Qe){let S=()=>{{let h=this.#r.get("defer");if(h)return h.materialize(this)}if(this.tokenValue)return this.#O(f,r,"{}")};return this.#f?this.featuresReady.then(S):S()}let g=this.#H(a,s),v=()=>this.#O(f,r,n,i,o,d,m);if(!g)return v();if(g instanceof Promise)return g.then((S)=>S?this.#A(S,f,v):v());this.#A(g,f,v)}#A(e,t,r){return Promise.resolve().then(()=>re(e,{el:t})).catch(()=>!1).then((n)=>{if(n)r()})}#H(e,t){if(e)return e;if(!t)return null;{let r=p.get("bindings");if(r)return r.confirmMessage(this,this.#e(),t);return this.#G("bindings").then((n)=>n&&n.confirmMessage(this,this.#e(),t))}}#G(e){{let t;return Promise.race([T(e).catch((r)=>(C(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),H()))]).finally(()=>clearTimeout(t))}}runOps(e){let t=e.params?.ops;if(t?.shortcut!=null&&!z(t.shortcut,e,this.application?.schema?.keyMappings))return;if(ve(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(St(e,this))return;let r=e.params??{},n=e.currentTarget??e.target,i=vt(r.ops),o=i.filter((s)=>fe(s,e,null)),a=o.length<=1?o:o.filter((s)=>fe(s,e,this.application?.schema?.keyMappings));if(a.length===0&&i.length>0){if(this.#$())this.#v((s)=>s.noBinding(this,e));return}for(let s of a){if(s.outside&&e[k])continue;if(!_t(s,e))continue;if(s.shortcut!=null&&!z(s.shortcut,e,this.application?.schema?.keyMappings))continue;if(wt(this,e,s))continue;this.#ae(s.legacy?{...r,ops:s.ops}:s,e,n)}}#ae({ops:e,confirm:t,confirmWhen:r,outside:n,window:i,shortcut:o},a,s){if(n&&this.element.contains(a.target))return;if(o!=null||!i)a.preventDefault();let c=this.#H(t,r),l=()=>this.#Ee(this.#Ae(e));if(!c)return l();if(c instanceof Promise)return c.then((d)=>d?this.#A(d,s,l):l());this.#A(c,s,l)}recompute(e){return p.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.#b("tagsAdd",e)}tagsPick(e){return this.#b("tagsPick",e)}tagsRemove(e){return this.#b("tagsRemove",e)}nestedAdd(e){return this.#b("nestedAdd",e)}nestedRemove(e){return this.#b("nestedRemove",e)}syncNestedJson(e){return p.get("bindings")?.syncNestedJson(this,this.#e(),e)}#b(e,t){{let r=p.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.#r.get("form")??p.get("form"))?.scan(this,this.#e())}listnavNext(e){this.#E(e,(t,r)=>t<0?0:(t+1)%r)}listnavPrev(e){this.#E(e,(t,r)=>t<0?r-1:(t-1+r)%r)}listnavFirst(e){this.#E(e,()=>0)}listnavLast(e){this.#E(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")}#E(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.#s("reactive:before-dispatch",{action:t,params:this.#Z(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.#fe(e,l,t,r,o,a);return this.#T(t,r,o,e,a)}#T(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=p.get("hints");if(!s||l)c(l);let d=()=>this.#be(e,t,o,a),m=()=>this.#n?this.#n.then(d):d();return this.queue=(this.queue??Promise.resolve()).then(()=>s&&!l?this.#ue().then(c).then(m):m()),this.queue}#ue(){return this.#G("hints")}#le(e,t,r,n,i,o){this.#M(e);let a=()=>{this.#M(e),this.#T(r,n,i,e,o)},s=setTimeout(a,t);e?.addEventListener?.("blur",a,{once:!0}),this.#w.set(e,{timer:s,flush:a})}#M(e){let t=this.#w.get(e);if(!t)return;clearTimeout(t.timer),e?.removeEventListener?.("blur",t.flush),this.#w.delete(e)}#de(){for(let e of[...this.#w.keys()])this.#M(e)}#fe(e,t,r,n,i,o){let a=this.#l.get(e)??new Map;if(a.has(r))return;let s=setTimeout(()=>{if(a.delete(r),a.size===0)this.#l.delete(e)},t);return a.set(r,s),this.#l.set(e,a),this.#T(r,n,i,e,o)}#he(){for(let e of this.#l.values())for(let t of e.values())clearTimeout(t);this.#l.clear()}#s(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}#o(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.#T(e,t)};this.#s("reactive:error",{action:e,params:r,...n,retry:i})}#i(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=p.get("devtools");if(e)return e.delay();if(Ae())return T("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#be(e,t,r,n){let{fields:i,files:o}=this.#X(),a=this.#Z(t),s={...i,...a},c=this.#a,l=o.length>0,d=l?this.#we(c,e,s,o):JSON.stringify({token:c,act:e,params:s}),m=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.#c(r.inverse),this.#i("offline"),this.#o(e,t,s,{kind:"offline"});return}let f;try{let h={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#Pe()};if(!l)h["Content-Type"]="application/json";let E=this.#Ne();if(E)h["X-Pgbus-Connection"]=E;let x=Oe(this.element)&&document.getElementById(`reactive-presence-src-${this.element.id}`)?.getAttribute("connection-id");if(x)h["X-Reactive-Presence"]=x;xe("action"),f=await fetch(this.#xe(),{method:"POST",headers:h,body:d,credentials:"same-origin",signal:AbortSignal.timeout(this.#Re())})}catch(h){if(console.error("[phlex-reactive] action error",h),this.#c(r.inverse),h?.name==="TimeoutError"||h?.name==="AbortError"){this.#i("timeout"),this.#o(e,t,s,{kind:"timeout"});return}this.#pe(),this.#i("network"),this.#o(e,t,s,{kind:"network"});return}if(m)m.status=f.status;if(f.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#c(r.inverse),this.#i("redirected"),this.#o(e,t,s,{kind:"redirected",status:f.status});return}if(!f.ok){let h=await f.text();if(console.error(`[phlex-reactive] action failed: HTTP ${f.status}`,h),this.#c(r.inverse),(f.headers.get("Content-Type")||"").includes("turbo-stream")){let E=this.#Y(h);if(this.#a=E??this.#a,m)this.#v((x)=>x.recordBody(m,h,E));window.Turbo.renderStreamMessage(h)}this.#i("http"),this.#o(e,t,s,{kind:"http",status:f.status,body:h});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.#c(r.inverse),this.#i("content-type"),this.#o(e,t,s,{kind:"content-type",status:f.status});return}let v=await f.text(),S=this.#Y(v);if(this.#a=S??this.#a,m)this.#v((h)=>h.recordBody(m,v,S));if(window.Turbo.renderStreamMessage(v),r.resurrect)queueMicrotask(r.resurrect);return this.#me(),this.#s("reactive:applied",{action:e,params:s,html:v}),v}catch(f){console.error("[phlex-reactive] action error",f),this.#c(r.inverse),this.#s("reactive:error",{action:e,params:s,kind:"apply"})}finally{if(n?.(),m)this.#v((f)=>f.trace(this,{...m,ms:this.#V()-m.started}))}}get#a(){return this.#_??this.tokenValue}set#a(e){this.#_=e}tokenValueChanged(){this.#_=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.#ye(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}#ye(e){let t=this.#j;if(t&&t.id===e)return t;let r=it(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)}#X(){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]${lt}`).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.getAttribute("data-reactive-editable")!=null?F(s):s.value??s.textContent??s.innerHTML??"",d=e[c];if(String(c).endsWith("[]")&&!ft(s))return;if(String(c).endsWith("[]")&&(d===void 0||Array.isArray(d))){(Array.isArray(d)?d:e[c]=[]).push(l);return}if(d==null||d==="")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.#L(s)}[]`;for(let d of c)i.append(l,String(d))}else this.#q(i,this.#L(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 m=l||a.has(s)?`${this.#L(s)}[]`:this.#L(s);i.append(m,c,c.name)}return i}#L(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))}#Z(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#Ae(e){return te(e)}#Ee(e){Y(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.#v((r)=>r.diagnose(this,e,t))}#v(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))}#Te(e,t){if(e?.checked!=="keep")return!1;let r=t?.type;return r==="checkbox"||r==="radio"}#c(e){if(!e)return;if(!this.element.isConnected)return;for(let t of e)t()}#Fe(e,t,r){this.#Le(e,t),Te();let n=!1;return()=>{if(n)return;n=!0,this.#ke(e,t),Fe();for(let i of r.undo)i()}}#Le(e,t){if(this.#u(t,e,1),this.#u(this.element,e,1),this.#d.set(e,(this.#d.get(e)??0)+1),this.#x++===0)this.element.setAttribute("aria-busy","true");for(let r of this.#Q(e))this.#u(r,e,1)}#ke(e,t){this.#u(t,e,-1),this.#u(this.element,e,-1);let r=(this.#d.get(e)??1)-1;if(r<=0)this.#d.delete(e);else this.#d.set(e,r);if(--this.#x<=0)this.#x=0,this.element.removeAttribute("aria-busy");for(let n of this.#Q(e))this.#u(n,e,-1)}#u(e,t,r){if(!e||typeof e.getAttribute!=="function")return;let n=this.#R.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.#R.delete(e),e.removeAttribute("data-reactive-busy");return}this.#R.set(e,n),e.setAttribute("data-reactive-busy",[...n.keys()].join(" "))}#Q(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#F(r))}#xe(){return this.#ee??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#Re(){if(this.#k!=null)return this.#k;let e=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,t=Number(e);return this.#k=Number.isFinite(t)&&t>0?t:30000}#Pe(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#Ne(){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)ce();else document.addEventListener("turbo:load",ce,{once:!0});y("persist",()=>import("phlex/reactive/features/persist"),Wt);y("defer",()=>import("phlex/reactive/features/defer"));y("form",()=>import("phlex/reactive/features/form"));y("bindings",()=>import("phlex/reactive/features/bindings"));y("compute",()=>import("phlex/reactive/features/compute"),jt);y("sortable",()=>import("phlex/reactive/features/sortable"));y("presence",()=>import("phlex/reactive/features/presence"));y("effects",()=>import("phlex/reactive/features/effects"));y("hints",()=>import("phlex/reactive/features/hints"));y("devtools",()=>import("phlex/reactive/features/devtools"));Q();function Wt(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 jt(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 Ut=1000,A=null,Be,B=new Set;function Jt(e){return De(e).then((t)=>{if(e!=="effects")return;Be=t,t?.sweep()})}we((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,o=Ce(Kt(i)).filter((s)=>!B.has(s));if(!t&&!B.has("effects")&&zt(i))o.push("effects");if(o.length===0&&!A)return t?.wrap(e);if(o.length>0){for(let c of o)B.add(c);let s=A=Promise.race([Promise.all([A,...o.map(Jt)]),new Promise((c)=>setTimeout(c,Ut))]).then(()=>{if(A!==s)return;A=null,B.clear()})}let a=A;r.render=async(s)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??Be)?.wrap(c),await c.detail.render(s)}});function Kt(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.push(t),r}function zt(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 sr=$e;export{Ee as ACTIVE_ATTR,lt as EDITOR_SELECTOR,dt as EDITOR_TAGS,ke as REQUESTS_ATTR,st as checkReactiveRegistration,xe as countReactiveRequest,sr as default,F as editableValue,Te as enterReactiveActivity,it as escapeRegExp,Fe as exitReactiveActivity,De as loadReactiveFeature,we as onReactiveStreamWithoutEffects,Yt as reactiveActivityCount,Qt as reactiveFeatureNames,ce as registerReactiveActions,Ke as registerReactiveDefer,Q as registerReactiveDev,ze as registerReactiveDismiss,ze as registerReactiveEffects,Zt as registerReactiveFeature,y as registerReactiveFeatureLoader,Je as registerReactiveJs,Ye as registerReactiveModals,Ze as registerReactiveMorphFocus,et as registerReactiveOffline,Xe as registerReactivePlaintext,ze as registerReactiveStreamRender,Ue as registerReactiveToken,je as registerReactiveVisit,Xt as resetReactiveActivity,Ne as serverText,Ce as unloadedFeaturesFor};
|
|
6
6
|
|
|
7
|
-
//# debugId=
|
|
7
|
+
//# debugId=33F26A90370DFFF564756E2164756E21
|
|
8
8
|
//# sourceMappingURL=core.min.js.map
|