phlex-reactive 0.14.3 → 0.14.4

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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +67 -4
  4. data/app/javascript/phlex/reactive/core.js +7 -1
  5. data/app/javascript/phlex/reactive/core.min.js +6 -2
  6. data/app/javascript/phlex/reactive/core.min.js.map +4 -4
  7. data/app/javascript/phlex/reactive/features/bindings.js +96 -0
  8. data/app/javascript/phlex/reactive/features/bindings.min.js +2 -2
  9. data/app/javascript/phlex/reactive/features/bindings.min.js.map +3 -3
  10. data/app/javascript/phlex/reactive/features/form.js +12 -5
  11. data/app/javascript/phlex/reactive/features/form.min.js +2 -2
  12. data/app/javascript/phlex/reactive/features/form.min.js.map +3 -3
  13. data/app/javascript/phlex/reactive/features/persist.js +12 -3
  14. data/app/javascript/phlex/reactive/features/persist.min.js +2 -2
  15. data/app/javascript/phlex/reactive/features/persist.min.js.map +3 -3
  16. data/app/javascript/phlex/reactive/features/sortable.js +463 -0
  17. data/app/javascript/phlex/reactive/features/sortable.min.js +4 -0
  18. data/app/javascript/phlex/reactive/features/sortable.min.js.map +10 -0
  19. data/app/javascript/phlex/reactive/reactive_controller.js +2 -0
  20. data/app/javascript/phlex/reactive/reactive_controller.min.js +6 -2
  21. data/app/javascript/phlex/reactive/reactive_controller.min.js.map +9 -8
  22. data/app/javascript/phlex/reactive/runtime.js +117 -10
  23. data/lib/phlex/reactive/component/editable.rb +78 -0
  24. data/lib/phlex/reactive/component/helpers.rb +2 -0
  25. data/lib/phlex/reactive/component/sortable.rb +212 -0
  26. data/lib/phlex/reactive/engine.rb +4 -4
  27. data/lib/phlex/reactive/version.rb +1 -1
  28. metadata +6 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4b8ab0285b176f4fab5221687a3d3364e2311eaa4c08c091eef07763cf22a8e
4
- data.tar.gz: 9072c2d1b802438c7f39c694753308020d65e9a20e38c1ee4f730351b25de49d
3
+ metadata.gz: 6e80c9d7f2587b324d3bd1658fbe09f93dd45d8fb9ed2dd300f302ac9577c3bc
4
+ data.tar.gz: cfd7d489f859f5c591e8d6a391d9c04b2b4b1906ee9d0067ced14539f8f3d2b3
5
5
  SHA512:
6
- metadata.gz: fc1c7ffa6b616154f5ce897f256fbd6d8be501948dc63295163b831b0578c55908c9187e4ac461d00dc2dd4d7481090672c654b28d30f9894a1ec65f079579d2
7
- data.tar.gz: f889193d4bc9bdb381446d93bfcf5ddf3ac7047b84250787a63f83c61844712ba1c511529792381511570740fff8f37e42c385d14fbecaad9809e52ad3064b35
6
+ metadata.gz: 79b0d752c36664dc374c69944d127556732864b3a8582ff68ae29d76ca70ad18289d60a375d99671697f91e5609f27e6cc4b7718240dc9fc632ac2425ecae671
7
+ data.tar.gz: 0d19985aa77283b419e815e35691c626f4646356fc04282f5441b4f434b2b15c6a052ade40b1bde8442bead4eb3b3f1900a15cb937dfe9132a9af2b0b16cb57b
data/CHANGELOG.md CHANGED
@@ -8,6 +8,43 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
9
  ### Added
10
10
 
11
+ - **Sortable lists — `reactive_sortable`, `reactive_sortable_source`,
12
+ `reactive_sortable_item` (#350).** Rows drag to reorder a list with a mouse,
13
+ a finger (a 200 ms press) or the keyboard (Space picks up, arrows move,
14
+ Space drops, Escape cancels, each step announced in the list's own
15
+ translatable words), and one declared action receives `item`, `position`,
16
+ `after` and `from` through the normal action pipeline (declare the ones you
17
+ want in `params:`; undeclared ones are dropped). The row moves at once
18
+ and goes back when the action fails or its reply does not render the list.
19
+ Sortables of one `group:` exchange rows (`name:` and static `params:` for a
20
+ kanban), and a `reactive_sortable_source` list's rows are copied in, routed
21
+ to their own action with `from:`. `handle:`, `disabled:`, `busy:` and the
22
+ `data-reactive-sortable-active` / `-dragging` / `-placeholder` styling hooks
23
+ round it out. The client is a new `sortable` feature module, about 3.1 KB
24
+ gzipped: the default client bundles it, and the split client fetches it only
25
+ for a page with a sortable. `core.proceed` now resolves with the reply's
26
+ HTML on success, so a feature can tell an applied reply from a failure. The
27
+ Project board demo drags its cards. Docs: "Sortable lists".
28
+
29
+ - **`reactive_editable(:title)` — a contenteditable element as a first-class,
30
+ plain-text field (#351).** The helper renders `name` (scope-aware),
31
+ `contenteditable="plaintext-only"`, `role="textbox"`, `aria-multiline`,
32
+ `aria-placeholder` and `data-reactive-placeholder` onto your own element. Its
33
+ value is its text with line breaks as `\n` (folded to spaces when
34
+ single-line). While it is focused a `reply.morph` or broadcast morph keeps its
35
+ text and caret and still applies its attributes; unfocused, the server's text
36
+ wins, and `data-reactive-morph-value` opts out. Paste and drop insert plain
37
+ text (a handler, and a downgrade to `contenteditable="true"`, where the engine
38
+ lacks `plaintext-only`); Enter runs `on_enter:` (a `js` chain or `:submit`)
39
+ and is swallowed in a single-line field; Escape reverts to the last
40
+ server-rendered text (`on_escape: :revert`). `reactive_dirty` diffs it against
41
+ that text and `reactive_persist` drafts it with its line breaks. Bare named
42
+ `[contenteditable]` elements keep the `textContent` reading. An editable that a
43
+ stream appends into a root already on the page gets its keys and paste from
44
+ its first focus (the root loads the bindings feature then, and on the split
45
+ client the stream that brings it starts the import). Bundle: default
46
+ +977 B gzip, split core +412 B, `features/bindings` +524 B.
47
+
11
48
  - **`on_client(…, detail: { success: true })` — run ops only when the event's
12
49
  payload qualifies (#346).** A binding can require top-level `event.detail`
13
50
  keys to strictly equal JSON scalars, so `on_client("turbo:submit-end",
data/README.md CHANGED
@@ -288,14 +288,15 @@ imports one the first time a root on the page needs it:
288
288
 
289
289
  | Module | Gzipped | Default client | Split client |
290
290
  |---|---:|---|---|
291
- | `phlex/reactive/reactive_controller` | 26.1 KB | loaded with your controllers | not loaded |
292
- | `phlex/reactive/core` | 12.4 KB | not loaded (it is inside the file above) | loaded with your controllers |
291
+ | `phlex/reactive/reactive_controller` | 28.9 KB | loaded with your controllers | not loaded |
292
+ | `phlex/reactive/core` | 13.5 KB | not loaded (it is inside the file above) | loaded with your controllers |
293
293
  | `phlex/reactive/features/persist` (`reactive_persist` drafts) | 3.2 KB | inside the one file | fetched when a root declares `reactive_persist`, or a `persist_state` / `persist_clear` op runs |
294
294
  | `phlex/reactive/features/defer` (`reply.defer`, `reactive_lazy`) | 2.8 KB | inside the one file | fetched when a root is a `reactive_lazy` shell, a morph turns one into a shell, or a `reply.defer` arrives |
295
295
  | `phlex/reactive/features/form` (dirty tracking, `warn_unsaved`, the paste-trigger gate) | 1.0 KB | inside the one file | fetched when a root tracks dirty fields or holds a `paste_into` trigger |
296
296
  | `phlex/reactive/features/effects` (`reactive_effects`, `dismiss_after`) | 1.7 KB | inside the one file | fetched when a root declares an effect, or when the first stream that needs it arrives: one with an effect, or with a dismissing flash |
297
297
  | `phlex/reactive/features/bindings` (`reactive_show`, show targets, `reactive_on_complete`, `reactive_filter`, `reactive_tags`, nested rows, the conditional `confirm:`) | 5.4 KB | inside the one file | fetched when a root declares one of them, or holds a trigger with a conditional confirm |
298
298
  | `phlex/reactive/features/compute` (`reactive_compute`, `reactive_text`) | 2.1 KB | inside the one file | fetched when a root carries a compute binding |
299
+ | `phlex/reactive/features/sortable` (`reactive_sortable` drag and drop) | 3.1 KB | inside the one file | fetched when a root is or holds a sortable or source list |
299
300
  | `phlex/reactive/features/hints` (`optimistic:`, `busy:`) | 1.0 KB | inside the one file | fetched when a root holds a trigger that declares a hint |
300
301
  | `phlex/reactive/features/devtools` (the latency simulator, the zero-target warnings, the debug trace) | 1.6 KB | inside the one file | fetched with the core on a page that carries `<meta name="phlex-reactive-env" content="development">` or while a delay is stored for the tab; at connect for a root in debug mode; otherwise the first time a verbose root has something to warn about. In production with none of these, never |
301
302
  | `phlex/reactive/early` | 1.2 KB | on every page, if you import it | the same |
@@ -680,6 +681,7 @@ Use in controllers: `render turbo_stream: Counter.replace(counter)`.
680
681
  | `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). |
681
682
  | `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
683
  | `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)) { … }`. |
684
+ | `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. |
683
685
  | `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
686
  | `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
687
  | `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). |
@@ -1139,8 +1141,9 @@ string is legacy and ignored), and `turbo:before-visit` **does not fire on
1139
1141
  restoration visits** (Back/Forward) — a documented Turbo gap, not a
1140
1142
  phlex-reactive one.
1141
1143
 
1142
- **Out of scope (v1):** rich-text / `contenteditable` editors have no `default*`
1143
- baseline and are **not** tracked. Combining `reactive_field` with your own
1144
+ **Out of scope (v1):** rich-text editors (Lexxy, Trix) and bare
1145
+ `contenteditable` elements have no `default*` baseline and are **not** tracked;
1146
+ a `reactive_editable` is (against the text of its last server render, #351). Combining `reactive_field` with your own
1144
1147
  `data:`/`on(...)` still needs `mix(...)` (a bare merge clobbers the `data-action`
1145
1148
  the descriptor rides on — the same rule as everywhere else).
1146
1149
 
@@ -1635,6 +1638,66 @@ button(id: "bulk-archive", **reactive_group_target_attrs("ids[]", :enable, 1..))
1635
1638
  `(group, :enable, condition)` is `{ disabled: }` (or `{}` when
1636
1639
  `reactive_values` does not cover the group, and the client seeds it).
1637
1640
 
1641
+ ### Sortable lists (`reactive_sortable`)
1642
+
1643
+ Drag rows to reorder a list — with a mouse, a finger or the keyboard — and one
1644
+ declared action receives the row and where it landed. No Stimulus controller,
1645
+ no endpoint of your own: the drop goes through the action pipeline (signed
1646
+ token, request queue, `busy:`, the reply).
1647
+
1648
+ ```ruby
1649
+ class TaskList < Phlex::HTML
1650
+ include Phlex::Reactive::Component
1651
+
1652
+ reactive_record :list
1653
+ action :move, params: { item: :integer, position: :integer }
1654
+
1655
+ def move(item:, position:)
1656
+ authorize! @list, :update?
1657
+ # insert_at is acts_as_list's; any reorder that honours `position` works.
1658
+ @list.tasks.find(item).insert_at(position + 1)
1659
+ reply.morph
1660
+ end
1661
+
1662
+ def view_template
1663
+ ul(**mix(reactive_root, reactive_sortable(:move, handle: "[data-drag-handle]"))) do
1664
+ @list.tasks.each do |task|
1665
+ li(id: dom_id(task), **reactive_sortable_item(task.id)) do
1666
+ span(data: { drag_handle: true }) { "⠿" }
1667
+ plain task.title
1668
+ end
1669
+ end
1670
+ end
1671
+ end
1672
+ end
1673
+ ```
1674
+
1675
+ On drop the action gets `item` (the row's key), `position` (its 0-based index
1676
+ after the drop), `after` (the key of the row it now follows, `nil` when first)
1677
+ and `from` (`"self"` for a reorder) — declare the ones you want. The row moves
1678
+ at once and goes back if the action fails or its reply does not render the
1679
+ list; a reply that morphs the list puts the rows in the server's order.
1680
+
1681
+ - **Drag in from another list**: `reactive_sortable_source(group:, name:)` rows
1682
+ are copied into any sortable of the same group (the source needs no token —
1683
+ it works on a `ClientBindings` root). Route a drag-in to its own action with
1684
+ `from: { templates: :insert }`. Source rows are pointer-only: pass
1685
+ `tabindex: -1` (via `mix`) so they stay out of the tab order.
1686
+ - **Between lists** (a kanban): sortables of one `group:` exchange rows; `name:`
1687
+ is what a row dragged out reports as `from`, and static `params:` (e.g.
1688
+ `{ lane: "doing" }`) tell the action which list it landed in.
1689
+ - **Keyboard**: a row is focusable; Space/Enter picks it up, the arrows move it
1690
+ (← → into the previous/next list of the group), Space/Enter drops it,
1691
+ Escape puts it back. Each step is announced through a live region; translate
1692
+ the words with `messages:` (`{position}`, `{count}`).
1693
+ - **Styling**: `data-reactive-sortable-active` (the list), `-dragging` (the
1694
+ row) and `-placeholder` (the gap) are yours to style.
1695
+ - **Guards**: `disabled: true` on the list or a row, and a request in flight on
1696
+ the root, refuse a drag. A drag starts after a 4 px move, or a 200 ms touch
1697
+ press, so clicks, taps and scrolling still work.
1698
+
1699
+ Full guide: [Sortable lists](https://phlex-reactive.zoolutions.llc/docs/sortable-lists).
1700
+
1638
1701
  ### Client-only drafts (`reactive_persist`)
1639
1702
 
1640
1703
  "Don't make me start over": a public application form, a multi-step wizard,
@@ -26,6 +26,7 @@ registerReactiveFeatureLoader("defer", () => import("phlex/reactive/features/def
26
26
  registerReactiveFeatureLoader("form", () => import("phlex/reactive/features/form"))
27
27
  registerReactiveFeatureLoader("bindings", () => import("phlex/reactive/features/bindings"))
28
28
  registerReactiveFeatureLoader("compute", () => import("phlex/reactive/features/compute"), waitingForEdit)
29
+ registerReactiveFeatureLoader("sortable", () => import("phlex/reactive/features/sortable"))
29
30
  registerReactiveFeatureLoader("effects", () => import("phlex/reactive/features/effects"))
30
31
  registerReactiveFeatureLoader("hints", () => import("phlex/reactive/features/hints"))
31
32
  registerReactiveFeatureLoader("devtools", () => import("phlex/reactive/features/devtools"))
@@ -144,7 +145,8 @@ onReactiveStreamWithoutEffects((event, loadedEffects) => {
144
145
  })
145
146
 
146
147
  // The reactive roots a stream is about to put on the page: the roots in its
147
- // template (the template's own root element included).
148
+ // template (the template's own root element included), and the content
149
+ // itself when it brings an editable.
148
150
  function incomingRoots(streamEl) {
149
151
  const content = streamEl?.querySelector?.("template")?.content
150
152
  if (!content) return []
@@ -152,6 +154,10 @@ function incomingRoots(streamEl) {
152
154
  for (const child of content.children ?? []) {
153
155
  if (child.matches?.('[data-controller~="reactive"]') && !roots.includes(child)) roots.unshift(child)
154
156
  }
157
+ // An editable appended into a root already on the page (issue #351): that
158
+ // root loads the bindings module when the editable is first focused, so
159
+ // start the import now — the module is then here before anything is typed.
160
+ if (content.querySelector?.("[data-reactive-editable]")) roots.push(content)
155
161
  return roots
156
162
  }
157
163
 
@@ -1,4 +1,8 @@
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=j(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)=>et(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 Ft(){return _}function kt(){_=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,je(e))}function je(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 We=":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 j(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 W(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:j(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||W(n.slice(i+1),t,r)}function Xe(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 Q=new WeakMap;function Ze(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 Qe(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 et(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 tt(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 rt(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 nt(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 it(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}var st=[["persist",[tt,null,null,!0]],["defer",[ge,null]],["form",[rt,null]],["bindings",[nt,null,null,!0]],["compute",[it,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(st),te=new Map,m=new Map,ot=new Map;function w(e,t,r){ye.set(e,[t,r]),at(e)}var ye=new Map;function at(e){let t=v.get(e),[r,n]=ye.get(e);t[1]=r,t[2]=n}function Lt(e,t){t.install?.(F),m.set(e,t),ot.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 ct=1e4;function M(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:ct}function Rt(){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"),ut=1e4,lt=1500,_e=(e)=>e!=null&&(e===globalThis.window||e.window===e);function C(){return globalThis[k]??={queue:[],connected:new WeakSet},globalThis[k]}function ft(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:ut}function dt(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 ht(e,t,r){return{[k]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:dt(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 mt(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=gt(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&&!W(l.filter,e,r))continue;return l.armed=!1,!0}return a}var L=new WeakMap;function pt(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 gt(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;#W;#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.#j(e),diagnose:(e,t)=>this.#B(e,t),applyOps:(e,t)=>q(e,(r)=>this.#j(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=ft(),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(lt,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=ht(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&&!W(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!mt(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.#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(Qe(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(a,e))continue;if(Ze(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.#W;if(t&&t.id===e)return t;let r=Ce(e);return this.#W={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]${We}`).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 j(e)}#Ae(e){q(e,(t)=>this.#j(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)}#j(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"),yt);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"),bt);w("effects",()=>import("phlex/reactive/features/effects"));w("hints",()=>import("phlex/reactive/features/hints"));w("devtools",()=>import("phlex/reactive/features/devtools"));B();function yt(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 bt(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 vt=1000,S=null,Se,P=new Set;function _t(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(wt(i)).filter((s)=>!P.has(s));if(!t&&!P.has("effects")&&St(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(_t)]),new Promise((c)=>setTimeout(c,vt))]).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 wt(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 St(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 Mt=we;export{ce as ACTIVE_ATTR,We as EDITOR_SELECTOR,Ue as EDITOR_TAGS,de as REQUESTS_ATTR,De as checkReactiveRegistration,he as countReactiveRequest,Mt as default,ue as enterReactiveActivity,Ce as escapeRegExp,le as exitReactiveActivity,ve as loadReactiveFeature,oe as onReactiveStreamWithoutEffects,Ft as reactiveActivityCount,Rt as reactiveFeatureNames,G as registerReactiveActions,Le as registerReactiveDefer,B as registerReactiveDev,Re as registerReactiveDismiss,Re as registerReactiveEffects,Lt as registerReactiveFeature,w as registerReactiveFeatureLoader,ke as registerReactiveJs,xe as registerReactiveMorphFocus,Ie as registerReactiveOffline,Re as registerReactiveStreamRender,Fe as registerReactiveToken,Ee as registerReactiveVisit,kt as resetReactiveActivity,be as unloadedFeaturesFor};
1
+ import{Controller as Le}from"@hotwired/stimulus";import{confirmResolver as H}from"phlex/reactive/confirm";function xe(){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 Re(){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 Pe(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:js"])return;e["reactive:js"]=function(){let t=K(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)y("devtools",(o)=>o.missingRoot(r));return}j(t,(o)=>it(o,i),n?(o,a)=>y("devtools",(s)=>s.diagnoseStream(o,a,i)):void 0)}}function Ie(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:defer"])return;e["reactive:defer"]=function(){y("defer",(t)=>t.streamAction(this))}}var V=!1,W=null;function Ne(){if(V)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;V=!0,document.addEventListener("turbo:before-stream-render",(e)=>{if(W)W(e,m.get("effects"));else m.get("effects")?.wrap(e)})}function ue(e){W=e}var G=!1;function O(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 Oe(){if(G)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;G=!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(R.set(t,F(r)),!O(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"||!O(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)=>J(e.target)),document.addEventListener("turbo:before-morph-attribute",(e)=>{if(e.detail?.attributeName==="value"&&O(e.target))e.preventDefault()})}var Me="__materialize",Y=!1;function Ce(){if(Y)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;Y=!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 De="phlex-reactive:latency";function le(){return typeof sessionStorage<"u"&&Boolean(sessionStorage.getItem(De))}function U(){if(typeof document>"u")return;if(!m.has("devtools")&&!_.get("devtools")[1])return;let e=document.querySelector?.('meta[name="phlex-reactive-env"]')?.content==="development";if(e||le())y("devtools",(t)=>e&&t.attach())}var de="data-reactive-active",S=0;function fe(){if(S++,S===1)me("reactive:busy")}function he(){if(S===0)return;if(S--,S===0)me("reactive:idle")}function Pt(){return S}function It(){S=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(de)}function me(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.toggleAttribute==="function")t.toggleAttribute(de,S>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(e,{detail:{count:S}}))}var pe="data-reactive-requests";function ge(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.setAttribute!=="function"||!qe(t))return;let r=$e(t);r[e]=(Number(r[e])||0)+1,t.setAttribute(pe,JSON.stringify(r))}function qe(e){return e.hasAttribute?.("data-reactive-verbose")||!!document.querySelector?.('[data-reactive-verbose="true"]')}function $e(e){try{let t=JSON.parse(e.getAttribute(pe));if(t&&typeof t==="object")return{action:0,defer:0,...t}}catch{}return{action:0,defer:0}}function X(){xe(),Re(),Pe(),Ie(),Ne(),Oe(),Ce(),U()}function Be(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var be=Symbol.for("phlex-reactive.core");if(globalThis[be])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[be]=!0;var ye=!1;function We(){if(ye)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(We,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",e,{once:!0});else e()}var je=new Set(["href","src","srcdoc","action","formaction","xlink:href","style"]);function Ue(e){let t=String(e).toLowerCase();return t.startsWith("on")||je.has(t)}var M=new WeakMap;function Je(e,t,r){let[n,i,o]=t;M.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,M.delete(e),clearTimeout(l),globalThis.cancelAnimationFrame?.(s),e.removeEventListener("animationend",c),e.removeEventListener("transitionend",c),e.classList.remove(n,i,o)};M.set(e,c),e.addEventListener("animationend",c),e.addEventListener("transitionend",c);let l=setTimeout(c,Ke(e))}function Ke(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 ze=":is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])",He=new Set(["lexxy-editor","trix-editor"]);function F(e){let t="",r=!1,n=(o)=>{if(r&&t&&!t.endsWith(`
2
+ `))t+=`
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
+ `);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 R=new WeakMap;function J(e){if(e?.hasAttribute?.("data-reactive-editable")&&!R.has(e))R.set(e,F(e))}function ve(e){return J(e),R.get(e)}function Ve(e){return He.has(e.localName)?typeof e.value==="string":!0}var Z=Object.freeze({show:(e,t,r)=>C(e,!1,t,r),hide:(e,t,r)=>C(e,!0,t,r),toggle:(e,t,r)=>C(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(D(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(D(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!D(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)=>Qe(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)y("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=Ge(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)=>Ye(e),persist_state:(e,t)=>y("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>y("persist",(t)=>t.clearRoot(e))});function Ge(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function Ye(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 Xe(e,t,r){if(r?.transition)Je(e,r.transition,()=>e.hidden=t);else e.hidden=t}function C(e,t,r,n){if(Xe(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 D(e){if(!Ue(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}var Ze='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function Qe(e){return e.querySelectorAll?.(Ze)?.[0]??null}function K(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 Q=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"}),ee=Object.freeze(["meta","ctrl","alt","shift"]);function z(e,t,r){let n=e.split("+");for(let a of ee)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!ee.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let o=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(Q,i)?Q[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof o==="string"&&o.toLowerCase()===t.key.toLowerCase()}function et(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:K(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 te(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)!==Te(t.currentTarget))return!1;return i<0||r===null||z(n.slice(i+1),t,r)}function tt(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 re=new WeakMap;function rt(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=re.get(e);if(!i)i=new WeakMap,re.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 ne=new WeakMap;function nt(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=ne.get(e);if(!i)i=new WeakMap,ne.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 j(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,o={}]=n;if(!Object.hasOwn(Z,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)Z[i](s,o,t)}}function it(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 st(e){let t=e.getAttribute?.("data-reactive-persist");return Boolean(t)&&t!=="off"}function _e(e){return["defer-token","defer-src","lazy-on","lazy-visible"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)}function ot(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 at(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 ct(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}function ut(e){return Boolean(e.matches?.("[data-reactive-sortable],[data-reactive-sortable-source]")||e.querySelector?.("[data-reactive-sortable],[data-reactive-sortable-source]"))}var lt=[["persist",[st,null,null,!0]],["defer",[_e,null]],["form",[ot,null]],["bindings",[at,null,null,!0]],["compute",[ct,null,null,!0]],["sortable",[ut,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(lt),ie=new Map,m=new Map,dt=new Map;function v(e,t,r){Se.set(e,[t,r]),ft(e)}var Se=new Map;function ft(e){let t=_.get(e),[r,n]=Se.get(e);t[1]=r,t[2]=n}function Nt(e,t){t.install?.(k),m.set(e,t),dt.set(e,t)}function we(e){let t=[];for(let[r,[n]]of _){if(!n||m.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function Ae(e){return E(e).catch((t)=>P(e,"load",t))}function E(e){let t=ie.get(e);if(!t)t=(_.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(k),m.set(e,n),n)),ie.set(e,t);return t}var se=new Set;function P(e,t,r){let n=e+t;if(se.has(n))return;se.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 y(e,t){let r=m.get(e);if(r)return t(r);E(e).then(t,(n)=>P(e,"load",n))}var ht=1e4;function q(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:ht}function Ot(){return[..._.keys()]}var oe=Promise.resolve();function ae(e,t,r){let n=k.waiting.get(e);if(n&&n[t]===r)delete n[t]}var k={enter:fe,exit:he,count:ge,text:F,served:ve,waiting:new WeakMap};var L=Symbol.for("phlex-reactive.early"),mt=1e4,pt=1500,Te=(e)=>e!=null&&(e===globalThis.window||e.window===e);function B(){return globalThis[L]??={queue:[],connected:new WeakSet},globalThis[L]}function gt(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:mt}function bt(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 yt(e,t,r){return{[L]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:bt(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 I=new WeakMap;function vt(e,{token:t,type:r,method:n,filter:i,win:o},a){let s=I.get(e);if(!s)I.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 ce(e,t,r,n){if(e?.[L])return!1;let i=Te(e?.currentTarget),o=i?n:e?.currentTarget,a=St(e,o,i?`@${t}`:t),s=I.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&&!z(l.filter,e,r))continue;return l.armed=!1,!0}return a}var x=new WeakMap;function _t(e,t,r){let n=x.get(e);if(!n)x.set(e,n=new Map),setTimeout(()=>x.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function St(e,t,r){let n=e&&x.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class Ee extends Le{static values={token:String};#_;#S=new Map;#l=new Map;#Q;#L;#j;#x=0;#d=new Map;#R=new WeakMap;#i;featuresReady=oe;#t=new Map;#P=new Set;#f=!1;#r=null;#h=new Map;#w=new Map;#m=new Map;#p=0;#U;#Ne=0;#Oe=0;connect(){if(ye=!0,B().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||_e(this.element))this.#i=(e)=>{if(e.type==="focusin"?!e.target.hasAttribute?.("data-reactive-editable"):e.target!==this.element)return;this.#J(!0)},this.element.addEventListener?.("turbo:morph-element",this.#i),this.element.addEventListener?.("focusin",this.#i);this.element.querySelectorAll?.("[data-reactive-editable]").forEach(J),this.#p++,this.featuresReady=oe,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=m.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)=>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 _.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.#r=c}let n=this.#r;n?.then(()=>{if(this.#r===n)this.#r=null}),this.#f=!0;let i=Promise.all(this.#m.values()).then(()=>{if(this.featuresReady===i)this.#f=!1});this.featuresReady=i}}#ee(e,t){{let r=()=>e===this.#p;return this.#te(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 ${q()} ms`));n(null)},q());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)})})}}#te(e){{let t=_.get(e)[2];if(!t)return;let r={};try{this.#w.set(e,[t(this.element,r),r]),k.waiting.set(this.element,{...k.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)ae(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.#t.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.#re(),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)=>j(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(),text:F,served:ve,confirm:(e,t)=>Promise.resolve().then(()=>H(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)}#g(e,t,r){if(P(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.#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;y(t,(i)=>{i.abandon?.(n,r),ae(n,t,r)})}this.#P.clear(),this.#m.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}=B();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=gt(),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(pt,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=yt(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&&!z(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!vt(s,c,n&&JSON.stringify(i.params)))continue;this.#N.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.#i)this.element.removeEventListener?.("turbo:morph-element",this.#i),this.element.removeEventListener?.("focusin",this.#i);B().connected.delete(this.element),this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#N)I.delete(e);this.#N.clear()}dispatch(e){if(ce(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 f=e.currentTarget??e.target;if(!c&&!this.#Ee(l,f))e.preventDefault();if(t===Me){let b=()=>{{let A=this.#t.get("defer");if(A)return A.materialize(this)}if(this.tokenValue)return this.#O(f,t,"{}")};return this.#f?this.featuresReady.then(b):b()}let d=this.#z(o,a),g=()=>this.#O(f,t,r,n,i,l,h);if(!d)return g();if(d instanceof Promise)return d.then((b)=>b?this.#A(b,f,g):g());this.#A(d,f,g)}#A(e,t,r){return Promise.resolve().then(()=>H(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)=>(P(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),q()))]).finally(()=>clearTimeout(t))}}runOps(e){if(ce(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(nt(e,this))return;let t=e.params??{},r=e.currentTarget??e.target,n=et(t.ops),i=n.filter((a)=>te(a,e,null)),o=i.length<=1?i:i.filter((a)=>te(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[L])continue;if(!tt(a,e))continue;if(rt(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.#Te(this.#Ae(e));if(!s)return c();if(s instanceof Promise)return s.then((l)=>l?this.#A(l,a,c):c());this.#A(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.#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 m.get("bindings")?.syncNestedJson(this,this.#e(),e)}#b(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 y("bindings",(i)=>i[e](this,this.#e(),n))}}trackDirty(){(this.#t.get("form")??m.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.#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.#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=(d)=>{if(!s||!d)return;let g=this.#e();if(o.inverse=d.optimistic(this,g,r,n),o.undo.push(...d.busy(this,g,i,n)),this.#C())o.resurrect=d.resurrection(this,g,r,n)},l=m.get("hints");if(!s||l)c(l);let h=()=>this.#be(e,t,o,a),f=()=>this.#r?this.#r.then(h):h();return this.queue=(this.queue??Promise.resolve()).then(()=>s&&!l?this.#ue().then(c).then(f):f()),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.#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})}#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(le())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#be(e,t,r,n){let{fields:i,files:o}=this.#Y(),a=this.#X(t),s={...i,...a},c=this.#a,l=o.length>0,h=l?this.#Se(c,e,s,o):JSON.stringify({token:c,act:e,params:s}),f=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.#n("offline"),this.#o(e,t,s,{kind:"offline"});return}let d;try{let p={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#Pe()};if(!l)p["Content-Type"]="application/json";let T=this.#Ie();if(T)p["X-Pgbus-Connection"]=T;ge("action"),d=await fetch(this.#xe(),{method:"POST",headers:p,body:h,credentials:"same-origin",signal:AbortSignal.timeout(this.#Re())})}catch(p){if(console.error("[phlex-reactive] action error",p),this.#c(r.inverse),p?.name==="TimeoutError"||p?.name==="AbortError"){this.#n("timeout"),this.#o(e,t,s,{kind:"timeout"});return}this.#pe(),this.#n("network"),this.#o(e,t,s,{kind:"network"});return}if(f)f.status=d.status;if(d.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#c(r.inverse),this.#n("redirected"),this.#o(e,t,s,{kind:"redirected",status:d.status});return}if(!d.ok){let p=await d.text();if(console.error(`[phlex-reactive] action failed: HTTP ${d.status}`,p),this.#c(r.inverse),(d.headers.get("Content-Type")||"").includes("turbo-stream")){let T=this.#G(p);if(this.#a=T??this.#a,f)this.#v((ke)=>ke.recordBody(f,p,T));window.Turbo.renderStreamMessage(p)}this.#n("http"),this.#o(e,t,s,{kind:"http",status:d.status,body:p});return}let g=d.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.#n("content-type"),this.#o(e,t,s,{kind:"content-type",status:d.status});return}let b=await d.text(),A=this.#G(b);if(this.#a=A??this.#a,f)this.#v((p)=>p.recordBody(f,b,A));if(window.Turbo.renderStreamMessage(b),r.resurrect)queueMicrotask(r.resurrect);return this.#me(),this.#s("reactive:applied",{action:e,params:s,html:b}),b}catch(d){console.error("[phlex-reactive] action error",d),this.#c(r.inverse),this.#s("reactive:error",{action:e,params:s,kind:"apply"})}finally{if(n?.(),f)this.#v((d)=>d.trace(this,{...f,ms:this.#V()-f.started}))}}get#a(){return this.#_??this.tokenValue}set#a(e){this.#_=e}tokenValueChanged(){this.#_=void 0}#G(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=Be(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]${ze}`).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??"",h=e[c];if(String(c).endsWith("[]")&&!Ve(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}#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.#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.#we(n);for(let{name:s,file:c,multiple:l}of n){let f=l||a.has(s)?`${this.#k(s)}[]`:this.#k(s);i.append(f,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))}#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))}#X(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#Ae(e){return K(e)}#Te(e){j(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){y("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.#ke(e,t),fe();let n=!1;return()=>{if(n)return;n=!0,this.#Le(e,t),he();for(let i of r.undo)i()}}#ke(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.#Z(e))this.#u(r,e,1)}#Le(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.#Z(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(" "))}#Z(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#F(r))}#xe(){return this.#Q??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#Re(){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)X();else document.addEventListener("turbo:load",X,{once:!0});v("persist",()=>import("phlex/reactive/features/persist"),wt);v("defer",()=>import("phlex/reactive/features/defer"));v("form",()=>import("phlex/reactive/features/form"));v("bindings",()=>import("phlex/reactive/features/bindings"));v("compute",()=>import("phlex/reactive/features/compute"),At);v("sortable",()=>import("phlex/reactive/features/sortable"));v("effects",()=>import("phlex/reactive/features/effects"));v("hints",()=>import("phlex/reactive/features/hints"));v("devtools",()=>import("phlex/reactive/features/devtools"));U();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 At(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 Tt=1000,w=null,Fe,N=new Set;function Et(e){return Ae(e).then((t)=>{if(e!=="effects")return;Fe=t,t?.sweep()})}ue((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,o=we(Ft(i)).filter((s)=>!N.has(s));if(!t&&!N.has("effects")&&kt(i))o.push("effects");if(o.length===0&&!w)return t?.wrap(e);if(o.length>0){for(let c of o)N.add(c);let s=w=Promise.race([Promise.all([w,...o.map(Et)]),new Promise((c)=>setTimeout(c,Tt))]).then(()=>{if(w!==s)return;w=null,N.clear()})}let a=w;r.render=async(s)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??Fe)?.wrap(c),await c.detail.render(s)}});function Ft(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);if(t.querySelector?.("[data-reactive-editable]"))r.push(t);return r}function kt(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 Bt=Ee;export{de as ACTIVE_ATTR,ze as EDITOR_SELECTOR,He as EDITOR_TAGS,pe as REQUESTS_ATTR,We as checkReactiveRegistration,ge as countReactiveRequest,Bt as default,F as editableValue,fe as enterReactiveActivity,Be as escapeRegExp,he as exitReactiveActivity,Ae as loadReactiveFeature,ue as onReactiveStreamWithoutEffects,Pt as reactiveActivityCount,Ot as reactiveFeatureNames,X as registerReactiveActions,Ie as registerReactiveDefer,U as registerReactiveDev,Ne as registerReactiveDismiss,Ne as registerReactiveEffects,Nt as registerReactiveFeature,v as registerReactiveFeatureLoader,Pe as registerReactiveJs,Oe as registerReactiveMorphFocus,Ce as registerReactiveOffline,Ne as registerReactiveStreamRender,Re as registerReactiveToken,xe as registerReactiveVisit,It as resetReactiveActivity,ve as serverText,we as unloadedFeaturesFor};
2
6
 
3
- //# debugId=A64326901A33E83A64756E2164756E21
7
+ //# debugId=4F52B06C4D4D29E964756E2164756E21
4
8
  //# sourceMappingURL=core.min.js.map