phlex-reactive 0.16.7 → 0.16.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8f1909cfe6e55962d3346a9168c7e87cd9afcdc11745078b8fcf8fe4b37546f
4
- data.tar.gz: c5e3cd10571790af59e2763286c2745a47eae77986e69190e06b9802cf0aed8a
3
+ metadata.gz: 191bb8f520c7970732cf49d9f5176981c0ef0ba48578be88bde3e95ff05561dc
4
+ data.tar.gz: efd1f20cf969df3a3094b0d740865eaef62f5866e4b84c778fc2ec64330d678b
5
5
  SHA512:
6
- metadata.gz: ca11dbe59e2b6db3c60aae38a9ea1bb17b74fdb104c6c340333dc23074fe99357e805d25702f1e31a14811120f0c78aa77b670fb8ebea21eada0e38709d9c5d2
7
- data.tar.gz: 2b1e10b34dadc2aa77f883f7634500c3bda73ca31f0839be10d94d4a15e8616c49358690e44ffea2bd7d3778ca7b239ed6acda65e43db5e0663bd6804ada18e2
6
+ metadata.gz: 5f5dac1699aef36a5dab41ad9f1383f490ef9ade03684a24bd82ae1cd224c760eb5de5c0a9ba05b9465e01f83d24823ddbe2db4cc1b8950c48007005c9577ab9
7
+ data.tar.gz: 3c5028a608dc1d04269f86b112ce03d8c70ffb0ec5f84f4c9cc8ad9e615497008f2fa34fb507f7d2258a96af38c9f67d638a01bbe7e77ea345d34d0ad2f24673
data/CHANGELOG.md CHANGED
@@ -6,6 +6,97 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.16.9] - 2026-10-19
10
+
11
+ ### Added
12
+
13
+ - **One client binding for a whole list: `:trigger`, `from:`/`attr:` reads and
14
+ `on_client(…, within:)` (#442).** Every client-op argument was a literal baked
15
+ at render, so a pickable list whose rows each write their own value and label
16
+ carried a full op chain on every row, differing in two or three literals.
17
+ Three parts now let the list bind once:
18
+ - **`:trigger`** (wire `"@trigger"`) targets the element whose `on_client`
19
+ binding fired, wherever an op takes a target (`to`, `expanded:`,
20
+ `submit(submitter:)`, `copy_media(from:)`). `set_value`, `paste_into` and
21
+ `preview_file` refuse it as their field. `JS.normalize_target` (pending
22
+ hints, `reactive_css_vars`) still refuses it.
23
+ - **`from:` + `attr:`** on `set_value`, `text` and `set_attr` read the value in
24
+ the browser off an element instead of a literal:
25
+ `js.set_value("#item-value", from: :trigger, attr: "data-value")`. `from:` is
26
+ `:trigger`, `:root` or a selector (the op's own scoping, `global:` included,
27
+ first match); `attr:` is a `data-*` attribute or `:text` (textContent),
28
+ enforced at render and again in the client. A missing attribute reads `""`;
29
+ a `from:` matching nothing skips the op. Exactly one of the value or `from:`.
30
+ **`dispatch(…, detail_from: { id: "data-id" })`** builds the event detail off
31
+ the trigger the same way, merged over `detail:` (a key in both raises).
32
+ - **`on_client(:click, ops, within: "[role=option]")`** runs the record only
33
+ for an event from inside an element matching the selector, under the bound
34
+ element and owned by this root; that element is the ops' `:trigger`.
35
+ Anywhere else is a complete no-op (no `preventDefault`, no confirm, no ops).
36
+ Keyboard picking through `reactive_listnav` and a click before the root
37
+ connects reach the same binding; before connect, `phlex/reactive/early`
38
+ leaves a click outside every row alone (a link in the list navigates). A
39
+ `within:` selector that does not parse runs nothing (verbose: warned). The bound element is not forced to
40
+ `type="button"`. `within:` raises with `window:`, `outside:`, `shortcut:` and
41
+ `once:` (Stimulus would drop a `:once` listener on its first event, a miss
42
+ included).
43
+
44
+ A server-pushed op has no trigger: `reply.js`, `broadcast_to(js:)` and
45
+ `reactive_on_complete` refuse `@trigger` and `detail_from:` (a chain or a raw
46
+ list). In the browser a stream op naming `@trigger`, or one in a window-bound
47
+ binding, resolves to nothing (verbose: warned). Every record that
48
+ asks for none of this is byte-identical. Client: the core gains 314 B
49
+ gzipped, the default bundle 364 B, `phlex/reactive/early` 129 B.
50
+
51
+ ## [0.16.8] - 2026-10-19
52
+
53
+ ### Changed
54
+
55
+ - **A `reactive_shared_field` drives its host's client bindings too (#440).**
56
+ A widget with its own root (a `ClientBindings` picker with a filter and
57
+ `on_client` ops, or a server component) that keeps its value field inside
58
+ that root left the host's bindings blind to it: a host
59
+ `reactive_show(if: { choice: "b" })` or `reactive_enable` never followed the
60
+ pick, and a `reactive_show(disable: true)` group around the widget never
61
+ disabled its `required` field, which then blocked a native submit from a
62
+ hidden section. The `data-reactive-shared-field` marker (#434) now also
63
+ counts for the next root up's client bindings, one level, client-only roots
64
+ between skipped (the #434 rule): `reactive_show` (every term, `after:`,
65
+ `clear:`), `disable: true` (the marked control is disabled and re-enabled
66
+ with the group), `reactive_enable`, `reactive_show_targets`,
67
+ `reactive_group_targets`, `checked_*` counts and `reactive_count`,
68
+ `reactive_on_complete`, `reactive_media`, `reactive_css_vars`, and
69
+ `reactive_compute`: a marked control is an input (an edit inside a nested
70
+ root now recomputes the host, which Stimulus never routed there) and, when
71
+ its name is a declared output, an output the host writes. A nested root that
72
+ comes back through a plain replace, or restores a `reactive_persist` draft,
73
+ re-syncs the host's bindings and (when it seeds) its compute, as a morph
74
+ already did. Which bindings a root evaluates is unchanged:
75
+ a nested root's own bindings stay its own. Client ops, listnav, `busy_on`,
76
+ `reactive_filter`, a select-all header (its checked state and the boxes it
77
+ ticks leave the marked box out, while `reactive_count` and `checked_*`
78
+ include it), dirty tracking and `reactive_persist` keep strict ownership. Without the
79
+ marker nothing changes. A root with no nested root keeps the constant-true
80
+ fast path; a compute root reads one attribute per `input` event.
81
+
82
+ ### Fixed
83
+
84
+ - **A reply's `focus`, `focus_first` and `blur` ops stick (#446).** Turbo
85
+ renders every stream message inside its focus preservation: one animation
86
+ frame after the streams render, it focuses the element that had focus
87
+ before again, when that element has an `id` and focus moved. The
88
+ `reactive:js` stream ran its ops inside that window, so a reply's blur or
89
+ focus was undone and the old field's `on_client(:focus, …)` binding ran
90
+ again (a listnav pick that hid its list and blurred the query showed the
91
+ list again). The first focus op in a reply's chain, and the ops after it,
92
+ now run on the next frame (in a hidden tab, once it is visible again), after
93
+ Turbo has found nothing to restore. The ops before it still run in the
94
+ render pass; a chain without a focus op, and a separate `.js` stream in the
95
+ same reply, are unchanged. After a `morph` or `update` that keeps the field,
96
+ its focus binding no longer runs again; a `replace` still hands focus to the
97
+ new field first (Turbo's own restore), so chain `js.blur(…).hide(…)` there.
98
+ `on_client` ops run in no stream render and stay synchronous.
99
+
9
100
  ## [0.16.7] - 2026-10-18
10
101
 
11
102
  ### Added
@@ -4317,7 +4408,9 @@ room for dogfood fixes.
4317
4408
  scaffolds a reactive component (and an RSpec spec when the app uses RSpec),
4318
4409
  state-backed by default or record-backed with `--record`.
4319
4410
 
4320
- [Unreleased]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.7...HEAD
4411
+ [Unreleased]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.9...HEAD
4412
+ [0.16.9]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.8...v0.16.9
4413
+ [0.16.8]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.7...v0.16.8
4321
4414
  [0.16.7]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.6...v0.16.7
4322
4415
  [0.16.6]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.5...v0.16.6
4323
4416
  [0.16.5]: https://github.com/mhenrixon/phlex-reactive/compare/v0.16.4...v0.16.5
data/README.md CHANGED
@@ -691,7 +691,7 @@ Use in controllers: `render turbo_stream: Counter.replace(counter)`.
691
691
  | `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, `debounce:`/`throttle:` waits (ms) and `prevent: false` as `on`, plus `detail:` (run only when `event.detail` carries the listed values). See [Client-only ops](#client-only-ops-on_client--js--zero-round-trips). |
692
692
  | `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`/`blur`, `show_modal`/`close_dialog` (a real modal `<dialog>`), `copy_media` (copy `src`/`srcset`/`alt` from a server-rendered `<img>`, no URL argument), `text` (set `textContent` — XSS-safe), `set_value` (set a field's live `.value` and dispatch `input`), `dispatch`, `submit` (requestSubmit the target's own form, optionally through a `submitter:`), `paste_into` (read the clipboard into a field, gesture-gated), `preview_file` (paint a chosen image file onto an `img` through an object URL the client makes and revokes), `check_group` (tick or untick a checkbox group, then re-sync its bindings), and `persist_state`/`persist_clear` (the `reactive_persist` draft) — chainable. `keep: true` on the visibility, class and attr ops makes their result survive a morph. |
693
693
  | `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)) { … }`. |
694
- | `reactive_shared_field(name:, value: nil, **attrs)` | A control inside a **nested** component that its host's actions post too (#434): `input(type: "hidden", **reactive_shared_field(name: "item[choice]", value: @choice))`. Collected by its own component and by the next server component above it, one level only; `name:` is the host's param, verbatim (never re-scoped); a blank name raises at render. See *Nested reactive components compose* below. |
694
+ | `reactive_shared_field(name:, value: nil, **attrs)` | A control inside a **nested** component that its host's actions post too (#434): `input(type: "hidden", **reactive_shared_field(name: "item[choice]", value: @choice))`. Collected by its own component and by the next server component above it, one level only, and read by that host's client bindings (`reactive_show`, `disable: true`, `reactive_enable`, show targets, computes; #440); `name:` is the host's param, verbatim (never re-scoped); a blank name raises at render. See *Nested reactive components compose* below. |
695
695
  | `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. |
696
696
  | `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). |
697
697
  | `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; `{ same: :email }` compares two fields, `{ digits: 10 }` checks a digit format, `after: :blur` waits for the field's first blur, and `clear:`/`focus:`/`scroll:` run when the section changes visibility. See [Value-conditional visibility](#value-conditional-visibility-reactive_show). |
@@ -944,9 +944,37 @@ action reads it (`action :pick, params: { item: { choice: :string } }`);
944
944
  otherwise the action drops it (with `Phlex::Reactive.verbose_errors` on, the
945
945
  default in development and test, the log's dropped-param line names it).
946
946
  A conditional `confirm:` judges the fields the action is about to post, so
947
- it sees the shared field too. Dirty tracking, `reactive_persist` and the client bindings
948
- (`reactive_show`, computes) keep strict ownership, so the field is the
949
- widget's there. A native `<form>` posts it anyway, like any named control.
947
+ it sees the shared field too.
948
+
949
+ The host's **client bindings** read a shared field as well (#440), with the
950
+ same one-level rule, so a client-only widget (a `ClientBindings` picker with
951
+ its own root for a filter and its `on_client` ops) can keep its value field
952
+ inside that root:
953
+
954
+ ```ruby
955
+ # Inside the picker's root:
956
+ input(**reactive_shared_field(name: "choice", required: true, value: @choice))
957
+
958
+ # In the host, around and beside the picker:
959
+ div(**reactive_show(if: { mode: "other" }, disable: true)) { render Picker.new }
960
+ div(**reactive_show(if: { choice: "b" })) { "b picked" }
961
+ button(**mix(on(:save), reactive_enable(if: { choice: "b" }))) { "Save" }
962
+ ```
963
+
964
+ `reactive_show` (every term, `after:`, `clear:`), `reactive_enable`,
965
+ `reactive_show_targets`, `reactive_group_targets`, the `checked_*` counts,
966
+ `reactive_on_complete`, `reactive_media` and `reactive_css_vars` all read it,
967
+ and a `disable: true` group disables and re-enables it with its own controls,
968
+ so a `required` field in a hidden section never blocks a native submit. For a
969
+ `reactive_compute` it is an input (its edits recompute the host) and, when its
970
+ name is a declared output, an output the host writes. When the widget
971
+ re-renders (a morph or a plain replace) or restores a `reactive_persist`
972
+ draft, the host's bindings re-sync against the new field, and its compute
973
+ re-runs when it seeds (the default). The widget's unmarked fields (its query input) stay its own, and a
974
+ nested root's own bindings are still evaluated by that root alone. Client ops, listnav, `busy_on`, `reactive_filter`, a select-all
975
+ header, dirty tracking and `reactive_persist` keep strict ownership, so the
976
+ field is the widget's there. A native `<form>` posts it anyway, like any named
977
+ control.
950
978
 
951
979
  **Debounced triggers (live-as-you-type).** Pass `debounce:` (milliseconds) to
952
980
  coalesce rapid events — typically keystrokes on an `"input"` trigger — into a
@@ -1329,9 +1357,64 @@ vocabulary is a fixed whitelist mirrored by the client: `show`/`hide`/`toggle`
1329
1357
  flip the `hidden` attribute; `add_class`/`remove_class`/`toggle_class` take one
1330
1358
  or more classes. Targets are CSS selectors resolved **within the component's
1331
1359
  root** (nested reactive components are never touched — same ownership rule as
1332
- field collection); `:root` targets the root element itself; `global: true` on
1333
- an op escapes to the whole document. An op name the client doesn't recognize
1334
- logs a warning and is skipped — the rest of the chain still applies.
1360
+ field collection); `:root` targets the root element itself; `:trigger` (#442)
1361
+ targets the element whose `on_client` binding fired (see "One binding for a
1362
+ list" below); `global: true` on an op escapes to the whole document. An op name
1363
+ the client doesn't recognize logs a warning and is skipped — the rest of the
1364
+ chain still applies.
1365
+
1366
+ **One binding for a list (#442).** A list whose rows each write their own value
1367
+ binds **once**: `within:` delegates the record to the rows, `:trigger` is the
1368
+ row that was picked, and `from:` + `attr:` read the row's value off it instead
1369
+ of baking a literal into every row:
1370
+
1371
+ ```ruby
1372
+ ul(id: "menu", role: "listbox", **on_client(:click, js
1373
+ .set_value("#item-value", from: :trigger, attr: "data-value")
1374
+ .text("#item-label", from: :trigger, attr: "data-label")
1375
+ .remove_attr("[role=option]", "aria-selected")
1376
+ .set_attr(:trigger, "aria-selected", "true")
1377
+ .dispatch("app:item-picked", detail_from: { id: "data-id", text: :text }),
1378
+ within: "[role=option]")) do
1379
+ @items.each do |item|
1380
+ li { button(role: "option", data: { id: item.id, value: item.value, label: item.label }) { item.label } }
1381
+ end
1382
+ end
1383
+ ```
1384
+
1385
+ - **`within: "[role=option]"`** runs the record only for an event from inside an
1386
+ element matching the selector, under the bound element and owned by this root
1387
+ (a row of a nested reactive root is that root's). That element is the ops'
1388
+ `:trigger`. Anywhere else (the list's padding, a heading) is a complete no-op:
1389
+ no `preventDefault`, no confirm, no ops. Keyboard picking needs
1390
+ `reactive_listnav` on the search input (not on the rows): Enter on the row it
1391
+ highlights clicks that row, which goes through the same binding, and so does a click before the
1392
+ root connects (`phlex/reactive/early` queues a row's click and leaves a click
1393
+ outside every row alone, so a link in the list still navigates; a row inside
1394
+ a nested reactive root is held too, and its replay is a miss). A `within:`
1395
+ selector that does not parse runs nothing, warned under `verbose_errors`. The
1396
+ list is not forced to `type="button"`. It raises with
1397
+ `window:`, `outside:`, `shortcut:` and `once:` (Stimulus drops a `:once`
1398
+ listener on its first event, a miss included).
1399
+ - **`:trigger`** is accepted wherever an op takes a target, and by `expanded:`,
1400
+ `submit(submitter:)` and `copy_media(from:)`. Without `within:` it is the
1401
+ element the binding is on. `set_value`, `paste_into` and `preview_file` refuse
1402
+ it as the field they write.
1403
+ - **`from:` + `attr:`** on `set_value`, `text` and `set_attr` replace the literal
1404
+ value: `from:` is `:trigger`, `:root` or a selector (the op's own scoping,
1405
+ `global:` included, first match); `attr:` is a `data-*` attribute or `:text`
1406
+ (the element's `textContent`) — nothing else, at render and again in the
1407
+ client. A missing attribute reads `""` (it clears); a `from:` that matches
1408
+ nothing skips the op. The write side keeps its own rules (`set_attr`'s name
1409
+ allowlist, `text`'s `textContent`, `set_value`'s `.value`).
1410
+ - **`dispatch(…, detail_from: { key => attr })`** builds the event's detail off
1411
+ the trigger, every value a String, merged over `detail:` (a key in both
1412
+ raises).
1413
+ - A server-pushed op has no trigger: `reply.js`, `broadcast_to(js:)` and
1414
+ `reactive_on_complete` raise on `:trigger`, `from: :trigger` and
1415
+ `detail_from:`. Nor does a window-bound `on_client` (`window:`, `outside:`,
1416
+ `shortcut:`): its `:trigger` ops resolve to nothing, warned under
1417
+ `verbose_errors`.
1335
1418
 
1336
1419
  In development and test (`verbose_errors`), an op whose selector resolves to
1337
1420
  **zero elements** also warns once per unique (op, selector, scope) — with a
@@ -1393,10 +1476,10 @@ button(**on_client(:click, js
1393
1476
  powerful than `set_attr`. With `global: true` it is the **cross-root text
1394
1477
  escape**: paint a value into a recap node outside the component's root
1395
1478
  (`js.text("#sum_total", total, global: true)`).
1396
- - **`dispatch(name, to: nil, detail: {})`** emits a **bubbling `CustomEvent`** so
1479
+ - **`dispatch(name, to: nil, detail: {}, detail_from: {})`** emits a **bubbling `CustomEvent`** so
1397
1480
  another component or a plain Stimulus controller can react to a client-only
1398
1481
  interaction — `to:` picks the element (default: the component root), `detail:`
1399
- is the payload.
1482
+ is the payload, and `detail_from:` (#442) adds values read off the trigger.
1400
1483
  - **`submit(to = :root)`** commits the **target's own form** via
1401
1484
  `requestSubmit()`: the target itself when it *is* a form, its form owner for a
1402
1485
  control (`input.form`, honoring a `form=` attribute), else the nearest ancestor
@@ -3083,7 +3166,7 @@ def update(quantity:, price:) = (@item.update!(quantity:, price:); reply.streams
3083
3166
  | `reply.remove` | remove the element (backed by `Streamable#to_stream_remove`) |
3084
3167
  | `reply.redirect(url)` | client-side `Turbo.visit` (pass a `*_url`); rides a `reactive:visit` turbo-stream, not an HTTP 3xx |
3085
3168
  | `reply.streams(*streams)` | **partial update** — emit exactly these streams (no full-self replace) + a tiny token-only refresh, so live inputs survive; for per-field grid editing (issue #30) |
3086
- | `.js(ops, target: …)` | also push **client DOM ops** (focus, dispatch, class/attr toggles) over a `reactive:js` stream, applied AFTER the render — `reply.morph.js(js.focus("[name=next]"))` focuses the morphed field (issue #97) |
3169
+ | `.js(ops, target: …)` | also push **client DOM ops** (focus, dispatch, class/attr toggles) over a `reactive:js` stream, applied AFTER the render — `reply.morph.js(js.focus("[name=next]"))` focuses the morphed field (issue #97); a `focus`/`focus_first`/`blur` op and the ops after it land one frame later (a hidden tab: once visible), past Turbo's stream focus restore (#446) |
3087
3170
  | `.defer(component, placeholder:, morph:)` | take an **expensive segment off the actor's critical path** (issue #165) — the reply returns immediately and the real render streams to the SAME actor when ready; see [Deferred segments](#deferred-segments-replydefer--reactive_lazy) |
3088
3171
  | `reply.pending(records, in:, job:, args:, peers:) { … }` | the action **enqueues** the work: mark the targets pending now and let **your own job** settle them when the work is actually done (issue #248); see [Async actions](#async-actions-replypending--reactive_settle) |
3089
3172
  | `reply.with(*streams)` / `#stream(*more)` | multi-stream (self re-render still injected for the token) |
@@ -3421,6 +3504,19 @@ def save(title:)
3421
3504
  end
3422
3505
  ```
3423
3506
 
3507
+ **Focus ops stick (#446).** Turbo renders every stream message inside its focus
3508
+ preservation: one animation frame after the render, it focuses the element that
3509
+ had focus before again when that element has an `id` and focus moved. So the
3510
+ first `focus`, `focus_first` or `blur` op in a reply's chain, and the ops after
3511
+ it, run on the next frame (in a hidden tab, once it is visible again), when
3512
+ Turbo has found nothing to restore. The ops before it still run in the render
3513
+ pass, and a separate `.js` stream in the same reply does not wait for them.
3514
+ After a `morph` or `update` that keeps the field, a field blurred by a reply
3515
+ stays blurred and its `on_client(:focus, …)` binding does not run again. A
3516
+ `replace` removes the focused field, so Turbo focuses the new one first (its own
3517
+ restore: that binding runs once); chain `js.blur(…).hide(…)` so the hide comes
3518
+ after it. `on_client` ops run in no stream render and stay synchronous.
3519
+
3424
3520
  `target:` scopes op resolution on the client; it defaults to the bound
3425
3521
  component's id for `replace`/`morph`/`update` (so `@root` and component-relative
3426
3522
  selectors just work), and to document-scope for a subject-free `reply.with`.
@@ -1,9 +1,9 @@
1
- import{Controller as xt}from"@hotwired/stimulus";import{confirmResolver as xe}from"phlex/reactive/confirm";function Nt(){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 Ot(){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 It(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:js"])return;e["reactive:js"]=function(){let t=Te(this.getAttribute("data-reactive-ops"));if(!t.length)return;let r=this.getAttribute("target"),n=this.getAttribute("data-reactive-verbose")==="true",i=r?document.getElementById(r):null;if(r&&!i){if(n)y("devtools",(o)=>o.missingRoot(r));return}me(t,(o)=>wr(o,i),n?(o,a)=>y("devtools",(s)=>s.diagnoseStream(o,a,i)):void 0)}}function Pt(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:defer"])return;e["reactive:defer"]=function(){y("defer",(t)=>t.streamAction(this))}}var Ne=!1,le=null;function Mt(){if(Ne)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Ne=!0,document.addEventListener("turbo:before-stream-render",(e)=>{if(Gt(e),Ct(e),$t(e),le)le(e,g.get("effects"));else g.get("effects")?.wrap(e)})}var B="reactive:streamed";function Ct(e){let t=e.detail,r=t?.render,n=t?.newStream??e.target,i=n?.getAttribute?.("action"),o=/^(append|prepend|update)$/.test(i);if(typeof r!=="function"||!(o||/^(before|after|replace)$/.test(i)))return;let a=n.getAttribute("target"),s=n.getAttribute("targets"),c=new Set;for(let u of a?[document.getElementById(a)]:s?document.querySelectorAll(s):[]){let d=(o?u:u?.parentElement)?.closest?.('[data-controller~="reactive"]');if(d)c.add(d)}if(c.size===0)return;t.render=async(u)=>{await r(u);for(let d of c)if(d.isConnected)d.dispatchEvent(new Event(B))}}function ge(e){return e?.tagName==="DIALOG"&&typeof e.showModal==="function"}function be(e){try{return e.matches(":modal")}catch{return!1}}function et(e){if(!ge(e)){if(e?.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))console.warn(`[phlex-reactive] show_modal targets a <dialog>, not <${e.localName}> — skipped`);return}if(!e.isConnected||be(e))return;if(e.open)e.close();e.showModal()}function Dt(e){if(ge(e)&&e.open)e.close()}function K(e){let r=[...e?.querySelectorAll?.("dialog[data-reactive-modal]")??[]];if(e?.matches?.("dialog[data-reactive-modal]"))r.push(e);for(let n of r)if(n.open&&!be(n))et(n)}function $t(e){let t=e.detail,r=t?.render,n=t?.newStream??e.target;if(typeof r!=="function"||!n?.querySelector?.("template")?.content?.querySelector?.("dialog"))return;t.render=async(i)=>{await r(i),K(document)}}var Oe=!1;function qt(){if(Oe)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Oe=!0,document.addEventListener("turbo:morph-element",(t)=>{if(t.target?.matches?.('[data-controller~="reactive"]'))K(t.target)}),document.addEventListener("turbo:morph",()=>K(document));let e=new WeakSet;document.addEventListener("turbo:before-morph-element",(t)=>{let r=t.target,n=t.detail?.newElement;if(!ge(r)||!n)return;if(n.hasAttribute?.("open"))e.delete(r);else e.add(r)}),document.addEventListener("turbo:before-morph-attribute",(t)=>{let{target:r,detail:n}=t;if(n?.attributeName!=="open"||n.mutationType!=="remove")return;if(!e.has(r)||!r.open||!be(r))return;e.delete(r),t.preventDefault(),r.close()})}var de=new WeakMap;function tt(e,t,r,n){let i=de.get(e)??new Map;de.set(e,i);let o=(a,s)=>{i.delete(a),i.set(a,s)};if(t.endsWith("_class"))for(let a of r.classes??[])o(`.${a}`,e.classList.contains(a));else if(t.endsWith("_attr"))vt(r.name)||o(r.name,e.getAttribute(r.name));else if(t==="show"||t==="hide"||t==="toggle"){if(o("hidden",e.getAttribute("hidden")),r.expanded!=null)for(let a of n({...r,to:r.expanded}))tt(a,"set_attr",{name:"aria-expanded"})}}var Ie=!1;function Wt(){if(Ie)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Ie=!0,document.addEventListener("turbo:morph-element",(e)=>{let t=e.target;for(let[r,n]of de.get(t)??[])if(r[0]===".")t.classList.toggle(r.slice(1),n);else if(n==null)t.removeAttribute(r);else if(t.getAttribute(r)!==n)t.setAttribute(r,n)})}var rt="data-reactive-image-fallback",L="data-reactive-image-state",fe="data-reactive-image-hidden",te=null,he="data-reactive-wrap-hidden";function nt(e){if(e.hasAttribute("hidden"))return;e.setAttribute("hidden",""),e.setAttribute(he,"")}function it(e){if(!e.hasAttribute(he))return;e.removeAttribute("hidden"),e.removeAttribute(he)}function R(e){if(e?.localName!=="img")return null;let t=e.getAttribute(rt);if(t==null)return null;try{return JSON.parse(t)||{}}catch{return{}}}var ot=(e)=>e.getAttribute("src")||e.getAttribute("srcset");function ye(e,t){if(typeof t!=="string"||!t)return null;try{return e.closest('[data-controller~="reactive"]')?.querySelector(t)??null}catch{return null}}function st(e,t){let r=ye(e,t.alt);return r&&!r.contains(e)?r:null}function G(e,t,r){if(r==="error"){if(t.hide&&!e.hasAttribute("hidden"))e.setAttribute("hidden",""),e.setAttribute(fe,"");if(t.wrap){let i=ye(e,t.wrap);if(i)nt(i);else console.warn(`[phlex-reactive] reactive_image_fallback wrap: ${JSON.stringify(t.wrap)} is not in the root — skipped`)}let n=st(e,t);if(n)n.textContent=e.getAttribute("alt")??"",n.hidden=!1}else Z(e,t);e.setAttribute(L,r)}function Z(e,t=R(e)){if(!t||e.getAttribute(L)==null)return;if(e.getAttribute(L)==="error"){if(e.hasAttribute(fe))e.removeAttribute("hidden");let r=ye(e,t.wrap);if(r)it(r);let n=st(e,t);if(n)n.hidden=!0}e.removeAttribute(L),e.removeAttribute(fe)}function Pe(e){let t=e.target,r=R(t);if(!r)return;if(e.type==="load")G(t,r,"loaded");else if(ot(t))G(t,r,"error");else Z(t,r)}function Bt(){if(te)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;let e=new WeakMap;te={error:Pe,load:Pe,"turbo:before-morph-element":(t)=>{let r=t.target,n=t.detail?.newElement,i=r?.getAttribute?.(L);if(i==null||!n||!R(r))return;let o=(a)=>r.getAttribute(a)===n.getAttribute?.(a);if(o("src")&&o("srcset"))e.set(r,i)},"turbo:morph-element":(t)=>{let r=t.target,n=e.get(r);if(n===void 0)return;e.delete(r),queueMicrotask(()=>{let i=R(r);if(i)G(r,i,n)})}};for(let[t,r]of Object.entries(te))document.addEventListener(t,r,!0);for(let t of document.querySelectorAll?.(`img[${rt}]`)??[]){if(!t.complete||!ot(t))continue;let r=`${t.getAttribute("src")} ${t.getAttribute("srcset")}`,n=(i)=>`${t.getAttribute("src")} ${t.getAttribute("srcset")}`===r&&G(t,R(t)??{},i);if(t.naturalWidth>0)n("loaded");else if(typeof t.decode==="function")t.decode().then(()=>n("loaded"),()=>n("error"));else n("error")}}function at(e){le=e}var C,re=null,Me="[data-reactive-editable][contenteditable=plaintext-only]";function ct(){if(C===void 0)try{let e=document.createElement("div");e.contentEditable="plaintext-only",C=e.contentEditable==="plaintext-only"}catch{C=!1}return C}function j(e){if(e.matches?.(Me))e.setAttribute("contenteditable","true");e.querySelectorAll?.(Me).forEach(j)}function jt(){if(re||typeof document>"u"||typeof document.createElement!=="function")return;if(ct())return;j(document),re=new MutationObserver((e)=>{for(let t of e)if(t.type==="attributes")j(t.target);else t.addedNodes.forEach(j)}),re.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["contenteditable","data-reactive-editable"]})}var Ce=!1;function De(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 Ut(){if(Ce)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Ce=!0,document.addEventListener("turbo:before-morph-element",(e)=>{let t=e.target,r=e.detail?.newElement;if(!r||e.defaultPrevented)return;let n=De(t);if(n)Ht(t,r);if(t.hasAttribute?.("data-reactive-editable")){if(V.set(t,T(r)),!n)return;for(let{name:o}of[...t.attributes])if(!r.hasAttribute(o)&&o!=="contenteditable"&&o!==_)t.removeAttribute(o);for(let{name:o,value:a}of r.attributes)if(o!=="contenteditable"&&t.getAttribute(o)!==a)t.setAttribute(o,a);return e.preventDefault()}if(t.localName!=="input"||!n)return;let i=r.getAttribute("value");if(i==null)t.removeAttribute("value");else if(t.getAttribute("value")!==i)t.setAttribute("value",i)}),document.addEventListener("focusin",(e)=>Se(e.target)),document.addEventListener("turbo:before-morph-attribute",(e)=>{let t=e.detail?.attributeName;if((t==="value"||t===_)&&De(e.target))e.preventDefault()}),document.addEventListener("input",(e)=>{let t=e.target;if(t?.hasAttribute?.(_)&&_e(t)===we(t))t.removeAttribute(_)})}var _="data-reactive-held",ve='[data-controller~="reactive"]',U=null,F=new Map;function _e(e){return e.hasAttribute("data-reactive-editable")?T(e):e.value}function we(e){return e.hasAttribute("data-reactive-editable")?Ee(e):e.defaultValue}function Jt(e){if(e.hasAttribute("data-reactive-editable"))return T(e);return e.localName==="textarea"?e.textContent:e.getAttribute("value")??""}function Ht(e,t){let r=e.getAttribute("name");if(!r||/^(checkbox|radio)$/.test(e.type)||F.has(e.closest(ve)))return;let n=Jt(t);if(n===_e(e))return e.removeAttribute(_);if(n===we(e))return;e.setAttribute(_,""),e.dispatchEvent(new CustomEvent("reactive:held",{bubbles:!0,detail:{name:r,theirs:n}}))}function zt(e){let t=[];for(let r of e.querySelectorAll(`[${_}]`)){if(r.closest(ve)!==e)continue;let n=r.getAttribute("name");if(_e(r)===we(r))r.removeAttribute(_);else if(n&&!t.includes(n))t.push(n)}if(t.length===0)return null;return JSON.stringify(t).replace(/[\u007f-￿]/g,(r)=>`\\u${r.charCodeAt(0).toString(16).padStart(4,"0")}`)}function ut(e,t){if(t===!0)return;for(let r of e.querySelectorAll(`[${_}]`))if(r.closest(ve)===e&&!t?.includes(r.getAttribute("name")))r.removeAttribute(_)}function Kt(e){let t=e.headers.get("X-Reactive-Refused");if(t==="*")return!0;try{let r=JSON.parse(t);return Array.isArray(r)?r:null}catch{return null}}function $e(e,t,r=null){let n={root:e,streams:0,keep:r},i=U;U=n;try{window.Turbo.renderStreamMessage(t)}finally{U=i}if(n.streams===0)ut(e,r)}function Gt(e){let t=U,r=e.detail,n=r?.render;if(!t||typeof n!=="function")return;t.streams++,r.render=async(i)=>{F.set(t.root,(F.get(t.root)||0)+1);try{return await n(i)}finally{let o=F.get(t.root)-1;if(o)F.set(t.root,o);else F.delete(t.root);ut(t.root,t.keep)}}}var qe="__materialize",We=!1;function Vt(){if(We)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;We=!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 Yt="phlex-reactive:latency";function lt(){return typeof sessionStorage<"u"&&Boolean(sessionStorage.getItem(Yt))}function Ae(){if(typeof document>"u")return;if(!g.has("devtools")&&!w.get("devtools")[1])return;let e=document.querySelector?.('meta[name="phlex-reactive-env"]')?.content==="development";if(e||lt())y("devtools",(t)=>e&&t.attach())}var dt="data-reactive-active",A=0;function ft(){if(A++,A===1)mt("reactive:busy")}function ht(){if(A===0)return;if(A--,A===0)mt("reactive:idle")}function Zr(){return A}function Qr(){A=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(dt)}function mt(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.toggleAttribute==="function")t.toggleAttribute(dt,A>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(e,{detail:{count:A}}))}var pt="data-reactive-requests";function gt(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.setAttribute!=="function"||!Xt(t))return;let r=Zt(t);r[e]=(Number(r[e])||0)+1,t.setAttribute(pt,JSON.stringify(r))}function Xt(e){return e.hasAttribute?.("data-reactive-verbose")||!!document.querySelector?.('[data-reactive-verbose="true"]')}function Zt(e){try{let t=JSON.parse(e.getAttribute(pt));if(t&&typeof t==="object")return{action:0,defer:0,...t}}catch{}return{action:0,defer:0}}function Be(){Nt(),Ot(),It(),Pt(),Mt(),Ut(),qt(),Wt(),Bt(),jt(),Vt(),Ae()}function Qt(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var bt=Symbol.for("phlex-reactive.core");if(globalThis[bt])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[bt]=!0;var yt=!1;function er(){if(yt)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(er,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",e,{once:!0});else e()}var tr=new Set(["href","src","srcset","srcdoc","action","formaction","xlink:href","style"]);function vt(e){let t=String(e).toLowerCase();return t.startsWith("on")||tr.has(t)}var ne=new WeakMap;function rr(e,t,r){let[n,i,o]=t;ne.get(e)?.(),e.classList.add(n,i),r();let a=!1,s=requestAnimationFrame(()=>{if(a)return;e.classList.remove(i),e.classList.add(o)}),c=(d)=>{if(a||d&&d.target!==e)return;a=!0,ne.delete(e),clearTimeout(u),globalThis.cancelAnimationFrame?.(s),e.removeEventListener("animationend",c),e.removeEventListener("transitionend",c),e.classList.remove(n,i,o)};ne.set(e,c),e.addEventListener("animationend",c),e.addEventListener("transitionend",c);let u=setTimeout(c,nr(e))}function nr(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 ir=":is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])",or=new Set(["lexxy-editor","trix-editor"]);function T(e){let t="",r=!1,n=(o)=>{if(r&&t&&!t.endsWith(`
1
+ import{Controller as Rt}from"@hotwired/stimulus";import{confirmResolver as Re}from"phlex/reactive/confirm";function Nt(){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 Ot(){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)}}var Pt=["focus","focus_first","blur"];function It(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:js"])return;e["reactive:js"]=function(){let t=Te(this.getAttribute("data-reactive-ops"));if(!t.length)return;let r=this.getAttribute("target"),n=this.getAttribute("data-reactive-verbose")==="true",i=r?document.getElementById(r):null;if(r&&!i){if(n)v("devtools",(o)=>o.missingRoot(r));return}let s=(o)=>me(o,(c)=>Tr(c,i),n?(c,u)=>v("devtools",(d)=>d.diagnoseStream(c,u,i)):void 0),a=t.findIndex((o)=>Pt.includes(o?.[0]));if(a<0||typeof requestAnimationFrame!=="function")return s(t);s(t.slice(0,a)),requestAnimationFrame(()=>s(t.slice(a)))}}function Mt(){let e=window.Turbo?.StreamActions;if(!e||e["reactive:defer"])return;e["reactive:defer"]=function(){v("defer",(t)=>t.streamAction(this))}}var Ne=!1,le=null;function Ct(){if(Ne)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Ne=!0,document.addEventListener("turbo:before-stream-render",(e)=>{if(Gt(e),Dt(e),qt(e),le)le(e,g.get("effects"));else g.get("effects")?.wrap(e)})}var U="reactive:streamed";function Dt(e){let t=e.detail,r=t?.render,n=t?.newStream??e.target,i=n?.getAttribute?.("action"),s=/^(append|prepend|update)$/.test(i);if(typeof r!=="function"||!(s||/^(before|after|replace)$/.test(i)))return;let a=n.getAttribute("target"),o=n.getAttribute("targets"),c=new Set;for(let u of a?[document.getElementById(a)]:o?document.querySelectorAll(o):[]){let d=(s?u:u?.parentElement)?.closest?.('[data-controller~="reactive"]');if(d)c.add(d)}if(c.size===0)return;t.render=async(u)=>{await r(u);for(let d of c)if(d.isConnected)d.dispatchEvent(new Event(U))}}function ge(e){return e?.tagName==="DIALOG"&&typeof e.showModal==="function"}function be(e){try{return e.matches(":modal")}catch{return!1}}function et(e){if(!ge(e)){if(e?.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))console.warn(`[phlex-reactive] show_modal targets a <dialog>, not <${e.localName}> — skipped`);return}if(!e.isConnected||be(e))return;if(e.open)e.close();e.showModal()}function $t(e){if(ge(e)&&e.open)e.close()}function G(e){let r=[...e?.querySelectorAll?.("dialog[data-reactive-modal]")??[]];if(e?.matches?.("dialog[data-reactive-modal]"))r.push(e);for(let n of r)if(n.open&&!be(n))et(n)}function qt(e){let t=e.detail,r=t?.render,n=t?.newStream??e.target;if(typeof r!=="function"||!n?.querySelector?.("template")?.content?.querySelector?.("dialog"))return;t.render=async(i)=>{await r(i),G(document)}}var Oe=!1;function Wt(){if(Oe)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Oe=!0,document.addEventListener("turbo:morph-element",(t)=>{if(t.target?.matches?.('[data-controller~="reactive"]'))G(t.target)}),document.addEventListener("turbo:morph",()=>G(document));let e=new WeakSet;document.addEventListener("turbo:before-morph-element",(t)=>{let r=t.target,n=t.detail?.newElement;if(!ge(r)||!n)return;if(n.hasAttribute?.("open"))e.delete(r);else e.add(r)}),document.addEventListener("turbo:before-morph-attribute",(t)=>{let{target:r,detail:n}=t;if(n?.attributeName!=="open"||n.mutationType!=="remove")return;if(!e.has(r)||!r.open||!be(r))return;e.delete(r),t.preventDefault(),r.close()})}var de=new WeakMap;function tt(e,t,r,n){let i=de.get(e)??new Map;de.set(e,i);let s=(a,o)=>{i.delete(a),i.set(a,o)};if(t.endsWith("_class"))for(let a of r.classes??[])s(`.${a}`,e.classList.contains(a));else if(t.endsWith("_attr"))vt(r.name)||s(r.name,e.getAttribute(r.name));else if(t==="show"||t==="hide"||t==="toggle"){if(s("hidden",e.getAttribute("hidden")),r.expanded!=null)for(let a of n({...r,to:r.expanded}))tt(a,"set_attr",{name:"aria-expanded"})}}var Pe=!1;function Bt(){if(Pe)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Pe=!0,document.addEventListener("turbo:morph-element",(e)=>{let t=e.target;for(let[r,n]of de.get(t)??[])if(r[0]===".")t.classList.toggle(r.slice(1),n);else if(n==null)t.removeAttribute(r);else if(t.getAttribute(r)!==n)t.setAttribute(r,n)})}var rt="data-reactive-image-fallback",R="data-reactive-image-state",fe="data-reactive-image-hidden",ne=null,he="data-reactive-wrap-hidden";function nt(e){if(e.hasAttribute("hidden"))return;e.setAttribute("hidden",""),e.setAttribute(he,"")}function it(e){if(!e.hasAttribute(he))return;e.removeAttribute("hidden"),e.removeAttribute(he)}function N(e){if(e?.localName!=="img")return null;let t=e.getAttribute(rt);if(t==null)return null;try{return JSON.parse(t)||{}}catch{return{}}}var ot=(e)=>e.getAttribute("src")||e.getAttribute("srcset");function ye(e,t){if(typeof t!=="string"||!t)return null;try{return e.closest('[data-controller~="reactive"]')?.querySelector(t)??null}catch{return null}}function st(e,t){let r=ye(e,t.alt);return r&&!r.contains(e)?r:null}function Y(e,t,r){if(r==="error"){if(t.hide&&!e.hasAttribute("hidden"))e.setAttribute("hidden",""),e.setAttribute(fe,"");if(t.wrap){let i=ye(e,t.wrap);if(i)nt(i);else console.warn(`[phlex-reactive] reactive_image_fallback wrap: ${JSON.stringify(t.wrap)} is not in the root — skipped`)}let n=st(e,t);if(n)n.textContent=e.getAttribute("alt")??"",n.hidden=!1}else ee(e,t);e.setAttribute(R,r)}function ee(e,t=N(e)){if(!t||e.getAttribute(R)==null)return;if(e.getAttribute(R)==="error"){if(e.hasAttribute(fe))e.removeAttribute("hidden");let r=ye(e,t.wrap);if(r)it(r);let n=st(e,t);if(n)n.hidden=!0}e.removeAttribute(R),e.removeAttribute(fe)}function Ie(e){let t=e.target,r=N(t);if(!r)return;if(e.type==="load")Y(t,r,"loaded");else if(ot(t))Y(t,r,"error");else ee(t,r)}function jt(){if(ne)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;let e=new WeakMap;ne={error:Ie,load:Ie,"turbo:before-morph-element":(t)=>{let r=t.target,n=t.detail?.newElement,i=r?.getAttribute?.(R);if(i==null||!n||!N(r))return;let s=(a)=>r.getAttribute(a)===n.getAttribute?.(a);if(s("src")&&s("srcset"))e.set(r,i)},"turbo:morph-element":(t)=>{let r=t.target,n=e.get(r);if(n===void 0)return;e.delete(r),queueMicrotask(()=>{let i=N(r);if(i)Y(r,i,n)})}};for(let[t,r]of Object.entries(ne))document.addEventListener(t,r,!0);for(let t of document.querySelectorAll?.(`img[${rt}]`)??[]){if(!t.complete||!ot(t))continue;let r=`${t.getAttribute("src")} ${t.getAttribute("srcset")}`,n=(i)=>`${t.getAttribute("src")} ${t.getAttribute("srcset")}`===r&&Y(t,N(t)??{},i);if(t.naturalWidth>0)n("loaded");else if(typeof t.decode==="function")t.decode().then(()=>n("loaded"),()=>n("error"));else n("error")}}function at(e){le=e}var q,ie=null,Me="[data-reactive-editable][contenteditable=plaintext-only]";function ct(){if(q===void 0)try{let e=document.createElement("div");e.contentEditable="plaintext-only",q=e.contentEditable==="plaintext-only"}catch{q=!1}return q}function J(e){if(e.matches?.(Me))e.setAttribute("contenteditable","true");e.querySelectorAll?.(Me).forEach(J)}function Ut(){if(ie||typeof document>"u"||typeof document.createElement!=="function")return;if(ct())return;J(document),ie=new MutationObserver((e)=>{for(let t of e)if(t.type==="attributes")J(t.target);else t.addedNodes.forEach(J)}),ie.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["contenteditable","data-reactive-editable"]})}var Ce=!1;function De(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 Jt(){if(Ce)return;if(typeof document>"u"||typeof document.addEventListener!=="function")return;Ce=!0,document.addEventListener("turbo:before-morph-element",(e)=>{let t=e.target,r=e.detail?.newElement;if(!r||e.defaultPrevented)return;let n=De(t);if(n)Ht(t,r);if(t.hasAttribute?.("data-reactive-editable")){if(X.set(t,T(r)),!n)return;for(let{name:s}of[...t.attributes])if(!r.hasAttribute(s)&&s!=="contenteditable"&&s!==_)t.removeAttribute(s);for(let{name:s,value:a}of r.attributes)if(s!=="contenteditable"&&t.getAttribute(s)!==a)t.setAttribute(s,a);return e.preventDefault()}if(t.localName!=="input"||!n)return;let i=r.getAttribute("value");if(i==null)t.removeAttribute("value");else if(t.getAttribute("value")!==i)t.setAttribute("value",i)}),document.addEventListener("focusin",(e)=>Se(e.target)),document.addEventListener("turbo:before-morph-attribute",(e)=>{let t=e.detail?.attributeName;if((t==="value"||t===_)&&De(e.target))e.preventDefault()}),document.addEventListener("input",(e)=>{let t=e.target;if(t?.hasAttribute?.(_)&&_e(t)===we(t))t.removeAttribute(_)})}var _="data-reactive-held",ve='[data-controller~="reactive"]',z=null,k=new Map;function _e(e){return e.hasAttribute("data-reactive-editable")?T(e):e.value}function we(e){return e.hasAttribute("data-reactive-editable")?Ee(e):e.defaultValue}function zt(e){if(e.hasAttribute("data-reactive-editable"))return T(e);return e.localName==="textarea"?e.textContent:e.getAttribute("value")??""}function Ht(e,t){let r=e.getAttribute("name");if(!r||/^(checkbox|radio)$/.test(e.type)||k.has(e.closest(ve)))return;let n=zt(t);if(n===_e(e))return e.removeAttribute(_);if(n===we(e))return;e.setAttribute(_,""),e.dispatchEvent(new CustomEvent("reactive:held",{bubbles:!0,detail:{name:r,theirs:n}}))}function Kt(e){let t=[];for(let r of e.querySelectorAll(`[${_}]`)){if(r.closest(ve)!==e)continue;let n=r.getAttribute("name");if(_e(r)===we(r))r.removeAttribute(_);else if(n&&!t.includes(n))t.push(n)}if(t.length===0)return null;return JSON.stringify(t).replace(/[\u007f-￿]/g,(r)=>`\\u${r.charCodeAt(0).toString(16).padStart(4,"0")}`)}function ut(e,t){if(t===!0)return;for(let r of e.querySelectorAll(`[${_}]`))if(r.closest(ve)===e&&!t?.includes(r.getAttribute("name")))r.removeAttribute(_)}function Vt(e){let t=e.headers.get("X-Reactive-Refused");if(t==="*")return!0;try{let r=JSON.parse(t);return Array.isArray(r)?r:null}catch{return null}}function $e(e,t,r=null){let n={root:e,streams:0,keep:r},i=z;z=n;try{window.Turbo.renderStreamMessage(t)}finally{z=i}if(n.streams===0)ut(e,r)}function Gt(e){let t=z,r=e.detail,n=r?.render;if(!t||typeof n!=="function")return;t.streams++,r.render=async(i)=>{k.set(t.root,(k.get(t.root)||0)+1);try{return await n(i)}finally{let s=k.get(t.root)-1;if(s)k.set(t.root,s);else k.delete(t.root);ut(t.root,t.keep)}}}var qe="__materialize",We=!1;function Yt(){if(We)return;if(typeof window>"u"||typeof document>"u")return;if(typeof window.addEventListener!=="function")return;We=!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 Xt="phlex-reactive:latency";function lt(){return typeof sessionStorage<"u"&&Boolean(sessionStorage.getItem(Xt))}function Ae(){if(typeof document>"u")return;if(!g.has("devtools")&&!w.get("devtools")[1])return;let e=document.querySelector?.('meta[name="phlex-reactive-env"]')?.content==="development";if(e||lt())v("devtools",(t)=>e&&t.attach())}var dt="data-reactive-active",A=0;function ft(){if(A++,A===1)mt("reactive:busy")}function ht(){if(A===0)return;if(A--,A===0)mt("reactive:idle")}function rn(){return A}function nn(){A=0,(typeof document<"u"?document.documentElement:null)?.removeAttribute?.(dt)}function mt(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.toggleAttribute==="function")t.toggleAttribute(dt,A>0);if(typeof document.dispatchEvent==="function"&&typeof CustomEvent==="function")document.dispatchEvent(new CustomEvent(e,{detail:{count:A}}))}var pt="data-reactive-requests";function gt(e){if(typeof document>"u")return;let t=document.documentElement;if(typeof t?.setAttribute!=="function"||!Qt(t))return;let r=Zt(t);r[e]=(Number(r[e])||0)+1,t.setAttribute(pt,JSON.stringify(r))}function Qt(e){return e.hasAttribute?.("data-reactive-verbose")||!!document.querySelector?.('[data-reactive-verbose="true"]')}function Zt(e){try{let t=JSON.parse(e.getAttribute(pt));if(t&&typeof t==="object")return{action:0,defer:0,...t}}catch{}return{action:0,defer:0}}function Be(){Nt(),Ot(),It(),Mt(),Ct(),Jt(),Wt(),Bt(),jt(),Ut(),Yt(),Ae()}function er(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var bt=Symbol.for("phlex-reactive.core");if(globalThis[bt])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[bt]=!0;var yt=!1;function tr(){if(yt)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(tr,0);if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",e,{once:!0});else e()}var rr=new Set(["href","src","srcset","srcdoc","action","formaction","xlink:href","style"]);function vt(e){let t=String(e).toLowerCase();return t.startsWith("on")||rr.has(t)}var oe=new WeakMap;function nr(e,t,r){let[n,i,s]=t;oe.get(e)?.(),e.classList.add(n,i),r();let a=!1,o=requestAnimationFrame(()=>{if(a)return;e.classList.remove(i),e.classList.add(s)}),c=(d)=>{if(a||d&&d.target!==e)return;a=!0,oe.delete(e),clearTimeout(u),globalThis.cancelAnimationFrame?.(o),e.removeEventListener("animationend",c),e.removeEventListener("transitionend",c),e.classList.remove(n,i,s)};oe.set(e,c),e.addEventListener("animationend",c),e.addEventListener("transitionend",c);let u=setTimeout(c,ir(e))}function ir(e){let t=0;try{let r=getComputedStyle(e);for(let n of["transition","animation"]){let[i,s]=["Duration","Delay"].map((o)=>String(r[n+o]).split(",").map((c)=>parseFloat(c)*(/ms/.test(c)?1:1000)||0)),a=String(r[n+"IterationCount"]).split(",").map((o)=>/inf/.test(o)?1/0:parseFloat(o)>=0?parseFloat(o):1);for(let o=0;o<i.length||o<s.length||o<a.length;o++){let c=i[o%i.length]*a[o%a.length]||0;t=Math.max(t,c+s[o%s.length])}}}catch{}return Math.min(Math.max(t+50,350),5000)}var or=":is(lexxy-editor, trix-editor, [contenteditable=''], [contenteditable=true], [contenteditable=plaintext-only])",sr=new Set(["lexxy-editor","trix-editor"]);function T(e){let t="",r=!1,n=(s)=>{if(r&&t&&!t.endsWith(`
2
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 V=new WeakMap;function Se(e){if(e?.hasAttribute?.("data-reactive-editable")&&!V.has(e))V.set(e,T(e))}function Ee(e){return Se(e),V.get(e)}function sr(e){return or.has(e.localName)?typeof e.value==="string":!0}var je=Object.freeze({show:(e,t,r)=>ie(e,!1,t,r),hide:(e,t,r)=>ie(e,!0,t,r),toggle:(e,t,r)=>ie(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(oe(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(oe(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!oe(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)=>pr(e)?.focus?.(),blur:(e)=>{let t=e.ownerDocument?.activeElement??globalThis.document?.activeElement;if(t&&(t===e||e.contains?.(t)))t.blur?.()},show_modal:(e)=>et(e),close_dialog:(e)=>Dt(e),text:(e,t)=>{let r=String(t.value??"");if(e.textContent!==r)e.textContent=r},copy_media:(e,t,r)=>{let n=null;try{n=r({...t,to:t.from})[0]??null}catch{}St(e,n)},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))},presence:(e,t)=>y("presence",(r)=>r.set(e,t.state)),dispatch:(e,t)=>{e.dispatchEvent(new CustomEvent(t.name,{bubbles:!0,composed:!0,detail:t.detail??{}}))},submit:(e,t,r)=>{let n=ar(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)=>cr(e),preview_file:(e,t,r)=>ur(e,t,r),set_value:(e,t)=>At(e,String(t.value??"")),persist_state:(e,t)=>y("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>y("persist",(t)=>t.clearRoot(e))});function ar(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function cr(e){let t=globalThis.navigator?.clipboard;if(typeof t?.readText!=="function")return;t.readText().then((r)=>{if(!r)return;e.value=r,wt(e),e.focus?.()}).catch(()=>{})}var x=new Map,N=null;function ur(e,t,r){if(e?.tagName!=="INPUT"||e.type!=="file")return J(`reads an input[type=file], not <${e?.localName}>`);let n=typeof r==="function"?r({...t,to:t.into})[0]:null;if(n?.tagName!=="IMG")return J(`paints an <img>, and ${JSON.stringify(t.into)} is ${n?`a <${n.localName}>`:"not on the page"}`);let i=[...t.valid===!0&&e.validity?.valid===!1?[]:e.files??[]],o=dr(e,t.accept),a=(u)=>Number.isInteger(t.max_bytes)&&u.size>t.max_bytes,s=[],c;if(t.per_file===!0&&e.multiple){let u=i.filter((f,h)=>{let p=typeof f?.type==="string"&&o(f)?a(f)&&"size":"type";if(p)s.push({reason:p,file:f,index:h});return!p}),d=s.length>0&&!lr(e,u)?i.length:u.length;for(let f of s)f.remaining=d;c=u.find((f)=>f.type.startsWith("image/"))}else{let u=i.filter((f)=>typeof f?.type==="string"&&o(f));c=u.find((f)=>f.type.startsWith("image/"));let d=i.length>0&&u.length===0?"type":null;if(c&&a(c))d="size";if(d)s.push({reason:d,file:d==="size"?c:i[0]}),c=null}if(_t(n),c){let u=URL.createObjectURL(c);x.set(n,u),n.setAttribute("src",u),fr()}else n.removeAttribute("src");if(Z(n),t.wrap!=null){let u=r({...t,to:t.wrap});if(u.length===0)J(`wrap: ${JSON.stringify(t.wrap)} is not on the page`);for(let d of u)c?it(d):nt(d)}if(t.name!=null)for(let u of r({...t,to:t.name}))u.textContent=c?c.name:"";for(let u of s)e.dispatchEvent(new CustomEvent("reactive:file-rejected",{bubbles:!0,detail:u}))}function lr(e,t){if(typeof DataTransfer!=="function"){if(e.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))J("per_file: has no DataTransfer to drop the refused files from the input");return!1}let r=new DataTransfer;for(let n of t)r.items.add(n);return e.files=r.files,!0}function dr(e,t){let r=String((t===!0?e.getAttribute("accept"):typeof t==="string"&&t)||"").toLowerCase().split(",").map((n)=>n.trim()).filter(Boolean);if(r.length===0)return(n)=>n.type.startsWith("image/");return(n)=>{let i=n.type.toLowerCase();return r.some((o)=>o[0]==="."?String(n.name).toLowerCase().endsWith(o):o.endsWith("/*")?i.startsWith(o.slice(0,-1)):i===o)}}function J(e){console.warn(`[phlex-reactive] preview_file ${e} — skipped`)}function _t(e){let t=x.get(e);if(t===void 0)return;if(x.delete(e),URL.revokeObjectURL(t),x.size===0)N?.disconnect(),N=null}function fr(){if(N||typeof MutationObserver!=="function"||!document?.documentElement)return;N=new MutationObserver(()=>{for(let[e,t]of x)if(!e.isConnected||e.getAttribute("src")!==t)_t(e)}),N.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["src"]})}function wt(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function At(e,t){if(!/^(input|textarea|select)$/.test(e.localName)||e.type==="file"&&t!==""){console.warn("[phlex-reactive] set_value skipped: not a field it can write",e);return}let r=Ue(e);if(e.value=t,Ue(e)!==r)wt(e)}function Ue(e){return e.type==="select-multiple"?[...e.selectedOptions].map((t)=>t.value).join(`
6
- `):e.value}function hr(e,t,r){if(r?.transition)rr(e,r.transition,()=>e.hidden=t);else e.hidden=t}function ie(e,t,r,n){if(hr(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 oe(e){if(!vt(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}function St(e,t){if(e?.localName!=="img")return console.warn(`[phlex-reactive] copy_media targets an <img>, not <${e?.localName}> — skipped`),null;let r=t?.localName==="img"?t:null,n=r?.getAttribute("src"),i=!1;for(let a of["srcset","src"]){let s=n?r.getAttribute(a):null;if(s==null){if(e.hasAttribute(a))i=e.removeAttribute(a)??!0}else if(e.getAttribute(a)!==s)i=e.setAttribute(a,s)??!0}if(i)Z(e);let o=r?.getAttribute("alt")??"";if(e.getAttribute("alt")!==o)e.setAttribute("alt",o);return r?o:!1}var mr='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function pr(e){return e.querySelectorAll?.(mr)?.[0]??null}function Te(e){if(Array.isArray(e))return e;if(typeof e!=="string")return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}var Je=Object.freeze({backspace:"Backspace",delete:"Delete",enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"}),He=Object.freeze(["meta","ctrl","alt","shift"]);function Q(e,t,r){let n=e.split("+");for(let a of He)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!He.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let o=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(Je,i)?Je[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof o==="string"&&o.toLowerCase()===t.key.toLowerCase()}var gr=(e)=>e&&typeof e==="object"?e.keys:String(e),Fe=()=>H().prevented??=new WeakSet;function se(e,t){if(t!=null&&!e.defaultPrevented)Fe().add(e);e.preventDefault()}function D(e,t,r){if(t.defaultPrevented&&e?.handled!==!0&&!Fe().has(t))return!1;let n=t.target;if(e?.inEditable!==!0&&(n?.isContentEditable||/^(input|textarea|select)$/.test(n?.localName)))return!1;let i=/[Mm]ac|iP/.test(navigator.userAgentData?.platform??navigator.platform)?"meta":"ctrl";return Q(gr(e).replace(/^mod\+/,`${i}+`),t,r)}function br(e){if(Array.isArray(e))return[{ops:e,legacy:!0}];if(e&&typeof e==="object")return[e];if(typeof e!=="string")return[];let t=e.trim();if(t.startsWith("["))return[{ops:Te(t),legacy:!0}];let r=[];for(let n of t.split(" ")){if(n==="")continue;let i=null;try{i=JSON.parse(n)}catch{i=null}if(i&&typeof i==="object"&&!Array.isArray(i))r.push(i);else console.warn(`[phlex-reactive] malformed on_client binding record ${JSON.stringify(n)} — skipped`)}return r}function ze(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)!==Le(t.currentTarget))return!1;return i<0||r===null||Q(n.slice(i+1),t,r)}function yr(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 Ke=new WeakMap;function vr(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=Ke.get(e);if(!i)i=new WeakMap,Ke.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 Ge=new WeakMap;function _r(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=Ge.get(e);if(!i)i=new WeakMap,Ge.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 me(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,o={}]=n;if(!Object.hasOwn(je,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)if(je[i](s,o,t),o?.keep===!0)tt(s,i,o,t)}}function wr(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 Ar(e){let t=e.getAttribute?.("data-reactive-persist");return Boolean(t)&&t!=="off"}function ke(e){return["defer-token","defer-src","lazy-on","lazy-visible"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)}var ae='[data-controller~="reactive"]',Sr='[data-controller~="reactive"],[data-reactive-dormant~="reactive"]',pe=(e)=>e.getAttribute?.("data-reactive-token-value")==null&&!ke(e);function ce(e,t,r){let n=e?.closest?.(t);while(n&&n!==r&&pe(n))n=n.parentElement?.closest?.(t);return n??null}var q=new WeakMap,W=new WeakMap;function Er(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 Tr(e){return["show-targets","group-targets","on-complete","filter-input","tags-field","css-vars"].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], [data-reactive-media], [data-reactive-css-vars]")!=null}function Fr(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}function kr(e){return Boolean(e.matches?.("[data-reactive-sortable],[data-reactive-sortable-source]")||e.querySelector?.("[data-reactive-sortable],[data-reactive-sortable-source]"))}function Lr(e){return Boolean(e.matches?.("[data-reactive-frame],[data-reactive-box],[data-reactive-point]")||e.querySelector?.("[data-reactive-frame],[data-reactive-box],[data-reactive-point]"))}function Et(e){return e.getAttribute?.("data-reactive-presence")!=null}function Rr(e){return Boolean(e.matches?.("[data-reactive-countdown]")||e.querySelector?.("[data-reactive-countdown]"))}var xr=[["persist",[Ar,null,null,!0]],["defer",[ke,null]],["form",[Er,null]],["bindings",[Tr,null,null,!0]],["compute",[Fr,null,null,!0]],["sortable",[kr,null]],["drag",[Lr,null]],["presence",[Et,null]],["countdown",[Rr,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]]],w=new Map(xr),Ve=new Map,g=new Map,Nr=new Map;function b(e,t,r){Tt.set(e,[t,r]),Or(e)}var Tt=new Map;function Or(e){let t=w.get(e),[r,n]=Tt.get(e);t[1]=r,t[2]=n}function en(e,t){t.install?.(I),g.set(e,t),Nr.set(e,t)}function Ft(e){let t=[];for(let[r,[n]]of w){if(!n||g.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function kt(e){return O(e).catch((t)=>Y(e,"load",t))}function O(e){let t=Ve.get(e);if(!t)t=(w.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(I),g.set(e,n),n)),Ve.set(e,t);return t}var Ye=new Set;function Y(e,t,r){let n=e+t;if(Ye.has(n))return;Ye.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=g.get(e);if(r)return t(r);O(e).then(t,(n)=>Y(e,"load",n))}var Ir=1e4;function ue(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:Ir}function tn(){return[...w.keys()]}var Xe=Promise.resolve();function Ze(e,t,r){let n=I.waiting.get(e);if(n&&n[t]===r)delete n[t]}var I={enter:ft,exit:ht,count:gt,text:T,served:Ee,waiting:new WeakMap};var P=Symbol.for("phlex-reactive.early"),Pr=1e4,Mr=1500,Le=(e)=>e!=null&&(e===globalThis.window||e.window===e),Cr="dispatch";function H(){return globalThis[P]??={queue:[],connected:new WeakSet},globalThis[P]}function Dr(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:Pr}function $r(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 qr(e,t,r){return{[P]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:$r(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&&!Fe().has(e),preventDefault(){},stopPropagation(){},stopImmediatePropagation(){}}}var X=new WeakMap;function Wr(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 Qe(e,t,r,n){if(e?.[P])return!1;let i=Le(e?.currentTarget),o=i?n:e?.currentTarget,a=jr(e,o,i?`@${t}`:t),s=X.get(o),c=i&&JSON.stringify(e.params);for(let u of s?.values()??[]){if(!u.armed||u.method!==t||u.type!==e.type||Boolean(u.win)!==i)continue;if(i&&u.params!==c)continue;if(u.filter&&!Q(u.filter,e,r))continue;return u.armed=!1,!0}return a}var z=new WeakMap;function Br(e,t,r){let n=z.get(e);if(!n)z.set(e,n=new Map),setTimeout(()=>z.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function jr(e,t,r){let n=e&&z.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class Lt extends xt{static values={token:String};#w;#l=new Map;#d=new Map;#ne;#L;#B;#R=0;#f=new Map;#x=new WeakMap;#t;featuresReady=Xe;#r=new Map;#N=new Set;#h=!1;#n=null;#m=new Map;#A=new Map;#p=new Map;#g=0;#j;#qe=0;#We=0;connect(){if(yt=!0,H().connected.add(this.element),q.set(this.element,this),this.element.id==="")console.warn("[phlex-reactive] a reactive root has no id; its next-action token can't self-match "+"and may fall back to the first token in the response → a silent HTTP 403 on the NEXT action. "+"Put id: on the SAME element as reactive_attrs — use div(**reactive_root) (emits id + token together), "+"or div(id:, **reactive_attrs). The id: must NOT be on a child. See the README.");if(this.element.getAttribute?.("data-reactive-token-value")!=null||ke(this.element))this.#t=(e)=>{if(e.type==="focusin"?!e.target.hasAttribute?.("data-reactive-editable"):e.target!==this.element)return;if(e.type===B)this.#H();this.#U(!0)},this.element.addEventListener?.("turbo:morph-element",this.#t),this.element.addEventListener?.("focusin",this.#t),this.element.addEventListener?.(B,this.#t);this.element.querySelectorAll?.("[data-reactive-editable]").forEach(Se),this.#g++,this.featuresReady=Xe,this.#U(),K(this.element),this.#ae()}#Be(e){}#je(e,t,r,n){}#Ue(){}#Je(e,t){}#U(e){{let t=this.#g,r=[];for(let[o,[a]]of w){if(!a||this.#N.has(o))continue;let s=g.get(o);if(s&&!s.connect)continue;try{if(a(this.element))r.push(o)}catch(c){this.#b(o,"detect",c)}}if(r.length===0)return;for(let o of r)this.#N.add(o);if(!this.#h&&r.every((o)=>g.has(o))){for(let o of r)this.#O(t,o,g.get(o),e);return}for(let o of r){let a=this.#ie(t,o),s=[];for(let u of w.keys()){if(u===o)break;if(this.#p.has(u))s.push(this.#p.get(u))}let c=Promise.all(s).then(()=>a).then((u)=>u&&this.#O(t,o,u,e));if(this.#p.set(o,c),w.get(o)[3])this.#n=c}let n=this.#n;n?.then(()=>{if(this.#n===n)this.#n=null}),this.#h=!0;let i=Promise.all(this.#p.values()).then(()=>{if(this.featuresReady===i)this.#h=!1});this.featuresReady=i}}#ie(e,t){{let r=()=>e===this.#g;return this.#oe(t),new Promise((n)=>{let i=!1,o=setTimeout(()=>{if(this.#m.delete(o),i=!0,r())this.#b(t,"timeout",Error(`not loaded after ${ue()} ms`));n(null)},ue());this.#m.set(o,n);let a=()=>{clearTimeout(o),this.#m.delete(o)};O(t).then((s)=>{if(a(),i)queueMicrotask(()=>this.#O(e,t,s));else n(s)},(s)=>{if(a(),r())this.#b(t,"load",s);n(null)})})}}#oe(e){{let t=w.get(e)[2];if(!t)return;let r={};try{this.#A.set(e,[t(this.element,r),r]),I.waiting.set(this.element,{...I.waiting.get(this.element),[e]:r})}catch(n){this.#b(e,"detect",n)}}}#J(e,t){{let[r,n]=this.#A.get(e)??[];if(this.#A.delete(e),!t)Ze(this.element,e,n);try{r?.()}catch(i){console.error(`[phlex-reactive] the "${e}" feature module failed to stop waiting`,i)}return n}}#O(e,t,r,n){{if(e!==this.#g)return;let i=this.#J(t);try{r.connect?.(this,this.#e(),n,i),this.#r.set(t,r)}catch(o){this.#b(t,"connect",o)}}}#e(){return this.#j??={emit:(e,t,r)=>this.#o(e,t,r),reseed:()=>this.#H(),proceed:(e,t,r,n)=>this.#P(e,t,r,0,0,null,n),forgetToken:()=>{this.#w=void 0},owns:(e)=>this.#F(e),ownership:()=>this.#Z(),opTargets:(e)=>this.#W(e),diagnose:(e,t)=>this.#q(e,t),applyOps:(e,t)=>me(e,(r)=>this.#W(t!=null&&r.to==null?{...r,to:t}:r),(r,n)=>this.#q(`client op "${r}"`,n)),listnavOptions:(e)=>this.#v(e),collectFields:()=>this.#Q(),plain:ct,text:T,served:Ee,copyMedia:St,setValue:At,confirm:(e,t)=>Promise.resolve().then(()=>xe(e,t)).catch(()=>!1)},this.#j}#H(){this.#r.get("form")?.reseed(this),this.#r.get("bindings")?.reseed(this),this.#r.get("compute")?.seed(this)}#b(e,t,r){if(Y(e,t,r),this.#i("feature"),t==="load"&&this.element.getAttribute?.("data-reactive-defer-pending"))this.element.removeAttribute("data-reactive-defer-pending"),this.element.removeAttribute("aria-busy");this.#o("reactive:error",{kind:"feature",feature:e,phase:t,error:r})}#se(){{this.#g++;for(let[t,r]of this.#m)clearTimeout(t),r(null);this.#m.clear();for(let t of[...this.#A.keys()]){let r=this.#J(t,!0),n=this.element;y(t,(i)=>{i.abandon?.(n,r),Ze(n,t,r)})}this.#N.clear(),this.#p.clear(),this.#h=!1,this.#n=null;let e=[...this.#r];this.#r.clear();for(let[t,r]of e)try{r.disconnect?.(this,this.#e())}catch(n){console.error(`[phlex-reactive] the "${t}" feature module failed to disconnect`,n)}}}#ae(){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.#ce();for(let[e,t]of W.get(this.element)??[]){if(e.currentTarget!==t)Object.defineProperty(e,"currentTarget",{value:t,configurable:!0});this.dispatch(e)}W.delete(this.element)}#I=new Set;#ce(){let{queue:e}=H();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=Dr(),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(Mr,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.#ue(i)}}#ue({event:e,el:t,descs:r,win:n}){let i=qr(e,t,n),o=this.application?.schema?.keyMappings,a=(t.getAttribute("data-action")??"").split(/\s+/),s=n?this.element:t;for(let c of r){if(!a.includes(c.token))continue;if(c.filter&&!Q(c.filter,e,o))continue;if(/#\w+.*:once\b/.test(c.token)){if(!Wr(s,c,n&&JSON.stringify(i.params)))continue;this.#I.add(s)}if(Br(e,s,n?`@${c.method}`:c.method),c.method==="runOps")this.runOps(i);else this.dispatch(i)}}disconnect(){if(this.#se(),this.#be(),this.#ve(),this.#t)this.element.removeEventListener?.("turbo:morph-element",this.#t),this.element.removeEventListener?.("focusin",this.#t),this.element.removeEventListener?.(B,this.#t);if(H().connected.delete(this.element),q.get(this.element)===this)q.delete(this.element);this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#I)X.delete(e);this.#I.clear()}dispatch(e){if(e.params?.action&&e.params.action!==qe&&this.#le())return this.#de(e);let t=e.params?.shortcut;if(t!=null&&!D(t,e,this.application?.schema?.keyMappings))return;if(Qe(e,"dispatch",this.application?.schema?.keyMappings,this.element))return;let{action:r,params:n,debounce:i,throttle:o,confirm:a,confirmWhen:s,outside:c,window:u,optimistic:d,prevent:f}=e.params;if(!r)return;let h=e.params.busy??e.params.loading;if(c&&this.element.contains(e.target))return;let p=e.currentTarget??e.target;if((t!=null||!u&&f!==!1)&&!this.#te(d,p))se(e,t);if(r===qe){let m=()=>{{let S=this.#r.get("defer");if(S)return S.materialize(this)}if(this.tokenValue)return this.#P(p,r,"{}")};return this.#h?this.featuresReady.then(m):m()}let v=this.#z(a,s),E=()=>this.#P(p,r,n,i,o,d,h);if(!v)return E();if(v instanceof Promise)return v.then((m)=>m?this.#S(m,p,E):E());this.#S(v,p,E)}#S(e,t,r){return Promise.resolve().then(()=>xe(e,{el:t})).catch(()=>!1).then((n)=>{if(n)r()})}#z(e,t){if(e)return e;if(!t)return null;{let r=g.get("bindings");if(r)return r.confirmMessage(this,this.#e(),t);return this.#K("bindings").then((n)=>n&&n.confirmMessage(this,this.#e(),t))}}#K(e){{let t;return Promise.race([O(e).catch((r)=>(Y(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),ue()))]).finally(()=>clearTimeout(t))}}#le(){return!this.tokenValue&&pe(this.element)}#de(e){let t=ce(this.element.parentElement,Sr);if(!t){if(this.element.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))console.warn(`[phlex-reactive] "${e.params.action}": no token on this root or above, nothing sent`);return}let r=q.get(t);if(r)return r.dispatch(e);let{shortcut:n,window:i,optimistic:o,prevent:a}=e.params;if(n!=null&&!D(n,e,this.application?.schema?.keyMappings))return;let s=e.currentTarget??e.target;if((n!=null||!i&&a!==!1)&&!this.#te(o,s))se(e,n);W.set(t,[...W.get(t)??[],[e,s]]);let c=t.dataset;if(c.reactiveDormant)c.controller=`${c.controller??""} ${c.reactiveDormant}`.trim(),delete c.reactiveDormant}runOps(e){let t=e.params?.ops;if(t?.shortcut!=null&&!D(t.shortcut,e,this.application?.schema?.keyMappings))return;if(Qe(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(_r(e,this))return;let r=e.params??{},n=e.currentTarget??e.target,i=br(r.ops),o=i.filter((s)=>ze(s,e,null)),a=o.length<=1?o:o.filter((s)=>ze(s,e,this.application?.schema?.keyMappings));if(a.length===0&&i.length>0){if(this.#$())this.#_((s)=>s.noBinding(this,e));return}for(let s of a){if(s.outside&&e[P])continue;if(!yr(s,e))continue;if(s.shortcut!=null&&!D(s.shortcut,e,this.application?.schema?.keyMappings))continue;if(vr(this,e,s))continue;this.#fe(s.legacy?{...r,ops:s.ops,debounce:void 0,throttle:void 0,prevent:void 0}:s,e,n,i.indexOf(s))}}#fe(e,t,r,n){let{ops:i,confirm:o,confirmWhen:a,outside:s,window:c,shortcut:u,prevent:d}=e;if(s&&this.element.contains(t.target))return;if(u!=null||!c&&d!==!1)se(t,u);let f=this.#z(o,a),h=this.#he(e,n,r,()=>this.#Ne(this.#xe(i)));if(!f)return h();if(f instanceof Promise)return f.then((p)=>p?this.#S(p,r,h):h());this.#S(f,r,h)}#he(e,t,r,n){let i=Number(e.debounce)||0,o=Number(e.throttle)||0;if(i<=0&&o<=0)return n;let a=JSON.stringify([t,e]);if(i>0)return()=>this.#G(r,a,i,n);return()=>this.#V(r,a,o,n)}recompute(e){return g.get("compute")?.recompute(this,this.#e(),e)}tagsAdd(e){if(e?.defaultPrevented)return;if(this.#v(e).some((t)=>t.hasAttribute?.("data-reactive-highlighted")))return;return this.#y("tagsAdd",e)}tagsPick(e){return this.#y("tagsPick",e)}tagsRemove(e){return this.#y("tagsRemove",e)}nestedAdd(e){return this.#y("nestedAdd",e)}nestedRemove(e){return this.#y("nestedRemove",e)}syncNestedJson(e){return g.get("bindings")?.syncNestedJson(this,this.#e(),e)}#y(e,t){{let r=g.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.#r.get("form")??g.get("form"))?.scan(this,this.#e())}listnavNext(e){this.#E(e,(t,r)=>t<0?0:(t+1)%r)}listnavPrev(e){this.#E(e,(t,r)=>t<0?r-1:(t-1+r)%r)}listnavFirst(e){this.#E(e,()=>0)}listnavLast(e){this.#E(e,(t,r)=>r-1)}listnavPick(e){let t=this.#v(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.#v(e))t.removeAttribute("data-reactive-highlighted")}#E(e,t){let r=this.#v(e);if(!r.length)return;e.preventDefault();let n=this.#me(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"})}#me(e){return(e?.currentTarget??e?.target??this.element).getAttribute?.("data-reactive-listnav-focus-param")==="true"}#v(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.#Z();return Array.from(this.element.querySelectorAll(r)).filter((i)=>!i.hidden&&n(i))}#P(e,t,r,n,i,o,a){if(this.#o("reactive:before-dispatch",{action:t,params:this.#ee(r),element:this.element},{cancelable:!0}).defaultPrevented)return;let c=Number(n)||0;if(c>0)return this.#ge(e,c,t,r,o,a);let u=Number(i)||0;if(u>0)return this.#ye(e,u,t,r,o,a);return this.#T(t,r,o,e,a)}#T(e,t,r,n,i){let o={inverse:null,undo:[],resurrect:null},a=this.#Oe(e,n,o),s=Boolean(r||i),c=(h)=>{if(!s||!h)return;let p=this.#e();if(o.inverse=h.optimistic(this,p,r,n),o.undo.push(...h.busy(this,p,i,n)),this.#C())o.resurrect=h.resurrection(this,p,r,n)},u=g.get("hints");if(!s||u)c(u);let d=()=>this.#Se(e,t,o,a),f=()=>this.#n?this.#n.then(d):d();return this.queue=(this.queue??Promise.resolve()).then(()=>s&&!u?this.#pe().then(c).then(f):f()),this.queue}#pe(){return this.#K("hints")}#ge(e,t,r,n,i,o){this.#G(e,Cr,t,()=>this.#T(r,n,i,e,o))}#G(e,t,r,n){this.#M(e,t);let i=()=>{this.#M(e,t),n()},o=setTimeout(i,r);if(!Le(e))e?.addEventListener?.("blur",i,{once:!0});let a=this.#l.get(e);if(!a)this.#l.set(e,a=new Map);a.set(t,{timer:o,flush:i})}#M(e,t){let r=this.#l.get(e),n=r?.get(t);if(!n)return;if(clearTimeout(n.timer),e?.removeEventListener?.("blur",n.flush),r.delete(t),r.size===0)this.#l.delete(e)}#be(){for(let[e,t]of[...this.#l])for(let r of[...t.keys()])this.#M(e,r)}#ye(e,t,r,n,i,o){return this.#V(e,r,t,()=>this.#T(r,n,i,e,o))}#V(e,t,r,n){let i=this.#d.get(e)??new Map;if(i.has(t))return;let o=setTimeout(()=>{if(i.delete(t),i.size===0)this.#d.delete(e)},r);return i.set(t,o),this.#d.set(e,i),n()}#ve(){for(let e of this.#d.values())for(let t of e.values())clearTimeout(t);this.#d.clear()}#o(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.#T(e,t)};this.#o("reactive:error",{action:e,params:r,...n,retry:i})}#i(e){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",e)}#_e(){this.element?.removeAttribute?.("data-reactive-error")}#we(){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))}#Ae(){{let e=g.get("devtools");if(e)return e.delay();if(lt())return O("devtools").then((t)=>t.delay(),()=>{})}}#C(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#Y(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}async#Se(e,t,r,n){let{fields:i,files:o}=this.#Q(),a=this.#ee(t),s={...i,...a},c=this.#a,u=o.length>0,d=u?this.#Le(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:u?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#Y()}:null;await this.#Ae();try{if(navigator.onLine===!1){this.#c(r.inverse),this.#i("offline"),this.#s(e,t,s,{kind:"offline"});return}let h;try{let m={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#De()};if(!u)m["Content-Type"]="application/json";let S=this.#$e();if(S)m["X-Pgbus-Connection"]=S;let M=Et(this.element)&&document.getElementById(`reactive-presence-src-${this.element.id}`)?.getAttribute("connection-id");if(M)m["X-Reactive-Presence"]=M;let Re=zt(this.element);if(Re)m["X-Reactive-Held"]=Re;gt("action"),h=await fetch(this.#Me(),{method:"POST",headers:m,body:d,credentials:"same-origin",signal:AbortSignal.timeout(this.#Ce())})}catch(m){if(console.error("[phlex-reactive] action error",m),this.#c(r.inverse),m?.name==="TimeoutError"||m?.name==="AbortError"){this.#i("timeout"),this.#s(e,t,s,{kind:"timeout"});return}this.#we(),this.#i("network"),this.#s(e,t,s,{kind:"network"});return}if(f)f.status=h.status;if(h.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#c(r.inverse),this.#i("redirected"),this.#s(e,t,s,{kind:"redirected",status:h.status});return}if(!h.ok){let m=await h.text();if(console.error(`[phlex-reactive] action failed: HTTP ${h.status}`,m),this.#c(r.inverse),(h.headers.get("Content-Type")||"").includes("turbo-stream")){let S=this.#X(m);if(this.#a=S??this.#a,f)this.#_((M)=>M.recordBody(f,m,S));$e(this.element,m,!0)}this.#i("http"),this.#s(e,t,s,{kind:"http",status:h.status,body:m});return}let p=h.headers.get("Content-Type")||"";if(!p.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${p}" — no update applied`),this.#c(r.inverse),this.#i("content-type"),this.#s(e,t,s,{kind:"content-type",status:h.status});return}let v=await h.text(),E=this.#X(v);if(this.#a=E??this.#a,f)this.#_((m)=>m.recordBody(f,v,E));if($e(this.element,v,Kt(h)),r.resurrect)queueMicrotask(r.resurrect);return this.#_e(),this.#o("reactive:applied",{action:e,params:s,html:v}),v}catch(h){console.error("[phlex-reactive] action error",h),this.#c(r.inverse),this.#o("reactive:error",{action:e,params:s,kind:"apply"})}finally{if(n?.(),f)this.#_((h)=>h.trace(this,{...f,ms:this.#Y()-f.started}))}}get#a(){return this.#w??this.tokenValue}set#a(e){this.#w=e}tokenValueChanged(){this.#w=void 0}#X(e){let t=this.element.id;if(!t)return e.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:r,self:n}=this.#Ee(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}#Ee(e){let t=this.#B;if(t&&t.id===e)return t;let r=Qt(e);return this.#B={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}#Z(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(t)=>this.#F(t)}#Te(){let e=this.element.querySelectorAll(ae);if(e.length===0||[...e].every(pe))return()=>!0;return(t)=>{let r=ce(t,ae,this.element);if(r===this.element)return!0;return t.getAttribute("data-reactive-shared-field")!=null&&ce(r.parentElement,ae,this.element)===this.element}}#Q(){let e={},t=[],r=this.#Te(),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]${ir}`).forEach((s)=>{if(r(s))i.push(s)});let o=this.#Fe(n),a=this.#ke(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 u of s.options)if(u.selected)c.push(u.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 u=s.getAttribute("data-reactive-editable")!=null?T(s):s.value??s.textContent??s.innerHTML??"",d=e[c];if(String(c).endsWith("[]")&&!sr(s))return;if(String(c).endsWith("[]")&&(d===void 0||Array.isArray(d))){(Array.isArray(d)?d:e[c]=[]).push(u);return}if(d==null||d==="")e[c]=u}),{fields:e,files:t}}#Fe(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}#ke(e){let t=new Set;for(let r of e)if(r.type==="checkbox")t.add(r.name);return t}#Le(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 u=`${this.#k(s)}[]`;for(let d of c)i.append(u,String(d))}else this.#D(i,this.#k(s),c);for(let s of o)i.append("empty_groups[]",s);let a=this.#Re(n);for(let{name:s,file:c,multiple:u}of n){let f=u||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("")}`}#D(e,t,r){if(r==null)e.append(t,"");else if(Array.isArray(r))r.forEach((n,i)=>this.#D(e,`${t}[${i}]`,n));else if(typeof r==="object")for(let[n,i]of Object.entries(r))this.#D(e,`${t}[${n}]`,i);else e.append(t,String(r))}#Re(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))}#ee(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#xe(e){return Te(e)}#Ne(e){me(e,(t)=>this.#W(t),(t,r)=>this.#q(`client op "${t}"`,r))}#$(){return this.element?.getAttribute?.("data-reactive-verbose")==="true"||this.#C()}#q(e,t){if(!this.#$())return;this.#_((r)=>r.diagnose(this,e,t))}#_(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))}#te(e,t){if(e?.checked!=="keep")return!1;let r=t?.type;return r==="checkbox"||r==="radio"}#c(e){if(!e)return;if(!this.element.isConnected)return;for(let t of e)t()}#Oe(e,t,r){this.#Ie(e,t),ft();let n=!1;return()=>{if(n)return;n=!0,this.#Pe(e,t),ht();for(let i of r.undo)i()}}#Ie(e,t){if(this.#u(t,e,1),this.#u(this.element,e,1),this.#f.set(e,(this.#f.get(e)??0)+1),this.#R++===0)this.element.setAttribute("aria-busy","true");for(let r of this.#re(e))this.#u(r,e,1)}#Pe(e,t){this.#u(t,e,-1),this.#u(this.element,e,-1);let r=(this.#f.get(e)??1)-1;if(r<=0)this.#f.delete(e);else this.#f.set(e,r);if(--this.#R<=0)this.#R=0,this.element.removeAttribute("aria-busy");for(let n of this.#re(e))this.#u(n,e,-1)}#u(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(" "))}#re(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#F(r))}#Me(){return this.#ne??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#Ce(){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}#De(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#$e(){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)Be();else document.addEventListener("turbo:load",Be,{once:!0});b("persist",()=>import("phlex/reactive/features/persist"),Ur);b("defer",()=>import("phlex/reactive/features/defer"));b("form",()=>import("phlex/reactive/features/form"));b("bindings",()=>import("phlex/reactive/features/bindings"));b("compute",()=>import("phlex/reactive/features/compute"),Jr);b("sortable",()=>import("phlex/reactive/features/sortable"));b("drag",()=>import("phlex/reactive/features/drag"));b("presence",()=>import("phlex/reactive/features/presence"));b("countdown",()=>import("phlex/reactive/features/countdown"));b("effects",()=>import("phlex/reactive/features/effects"));b("hints",()=>import("phlex/reactive/features/hints"));b("devtools",()=>import("phlex/reactive/features/devtools"));Ae();function Ur(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 Jr(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 Hr=1000,k=null,Rt,ee=new Set;function zr(e){return kt(e).then((t)=>{if(e!=="effects")return;Rt=t,t?.sweep()})}at((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,o=Ft(Kr(i)).filter((s)=>!ee.has(s));if(!t&&!ee.has("effects")&&Gr(i))o.push("effects");if(o.length===0&&!k)return t?.wrap(e);if(o.length>0){for(let c of o)ee.add(c);let s=k=Promise.race([Promise.all([k,...o.map(zr)]),new Promise((c)=>setTimeout(c,Hr))]).then(()=>{if(k!==s)return;k=null,ee.clear()})}let a=k;r.render=async(s)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??Rt)?.wrap(c),await c.detail.render(s)}});function Kr(e){let t=e?.querySelector?.("template")?.content;if(!t)return[];let r=[...t.querySelectorAll?.('[data-controller~="reactive"]')??[]];for(let n of t.children??[])if(n.matches?.('[data-controller~="reactive"]')&&!r.includes(n))r.unshift(n);return r.push(t),r}function Gr(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 cn=Lt;export{dt as ACTIVE_ATTR,ir as EDITOR_SELECTOR,or as EDITOR_TAGS,pt as REQUESTS_ATTR,er as checkReactiveRegistration,gt as countReactiveRequest,cn as default,T as editableValue,ft as enterReactiveActivity,Qt as escapeRegExp,ht as exitReactiveActivity,kt as loadReactiveFeature,at as onReactiveStreamWithoutEffects,Zr as reactiveActivityCount,tn as reactiveFeatureNames,Be as registerReactiveActions,Pt as registerReactiveDefer,Ae as registerReactiveDev,Mt as registerReactiveDismiss,Mt as registerReactiveEffects,en as registerReactiveFeature,b as registerReactiveFeatureLoader,Bt as registerReactiveImageFallback,It as registerReactiveJs,Wt as registerReactiveKeep,qt as registerReactiveModals,Ut as registerReactiveMorphFocus,Vt as registerReactiveOffline,jt as registerReactivePlaintext,Mt as registerReactiveStreamRender,Ot as registerReactiveToken,Nt as registerReactiveVisit,Qr as resetReactiveActivity,Ee as serverText,Ft as unloadedFeaturesFor};
3
+ `;r=!1,t+=s},i=(s)=>{for(let a of s.childNodes){let o=/^(div|p|li)$/.test(a.localName);if(o)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(o)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 X=new WeakMap;function Se(e){if(e?.hasAttribute?.("data-reactive-editable")&&!X.has(e))X.set(e,T(e))}function Ee(e){return Se(e),X.get(e)}function ar(e){return sr.has(e.localName)?typeof e.value==="string":!0}var je=Object.freeze({show:(e,t,r)=>se(e,!1,t,r),hide:(e,t,r)=>se(e,!0,t,r),toggle:(e,t,r)=>se(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(ae(t.name))e.setAttribute(t.name,t.value??"")},remove_attr:(e,t)=>{if(ae(t.name))e.removeAttribute(t.name)},toggle_attr:(e,t)=>{if(!ae(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)=>gr(e)?.focus?.(),blur:(e)=>{let t=e.ownerDocument?.activeElement??globalThis.document?.activeElement;if(t&&(t===e||e.contains?.(t)))t.blur?.()},show_modal:(e)=>et(e),close_dialog:(e)=>$t(e),text:(e,t)=>{let r=String(t.value??"");if(e.textContent!==r)e.textContent=r},copy_media:(e,t,r)=>{let n=null;try{n=r({...t,to:t.from})[0]??null}catch{}St(e,n)},check_group:(e,t)=>{let r=t.global?document.querySelectorAll('[data-controller~="reactive"]'):[e];for(let n of r)v("bindings",(i)=>i.checkGroup(n,t.group,t.checked))},presence:(e,t)=>v("presence",(r)=>r.set(e,t.state)),dispatch:(e,t)=>{e.dispatchEvent(new CustomEvent(t.name,{bubbles:!0,composed:!0,detail:t.detail??{}}))},submit:(e,t,r)=>{let n=cr(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)=>ur(e),preview_file:(e,t,r)=>lr(e,t,r),set_value:(e,t)=>At(e,String(t.value??"")),persist_state:(e,t)=>v("persist",(r)=>r.writeState(e,t.state)),persist_clear:(e)=>v("persist",(t)=>t.clearRoot(e))});function cr(e){if(e?.tagName==="FORM")return e;return e?.form??e?.closest?.("form")??null}function ur(e){let t=globalThis.navigator?.clipboard;if(typeof t?.readText!=="function")return;t.readText().then((r)=>{if(!r)return;e.value=r,wt(e),e.focus?.()}).catch(()=>{})}var O=new Map,P=null;function lr(e,t,r){if(e?.tagName!=="INPUT"||e.type!=="file")return H(`reads an input[type=file], not <${e?.localName}>`);let n=typeof r==="function"?r({...t,to:t.into})[0]:null;if(n?.tagName!=="IMG")return H(`paints an <img>, and ${JSON.stringify(t.into)} is ${n?`a <${n.localName}>`:"not on the page"}`);let i=[...t.valid===!0&&e.validity?.valid===!1?[]:e.files??[]],s=fr(e,t.accept),a=(u)=>Number.isInteger(t.max_bytes)&&u.size>t.max_bytes,o=[],c;if(t.per_file===!0&&e.multiple){let u=i.filter((f,h)=>{let p=typeof f?.type==="string"&&s(f)?a(f)&&"size":"type";if(p)o.push({reason:p,file:f,index:h});return!p}),d=o.length>0&&!dr(e,u)?i.length:u.length;for(let f of o)f.remaining=d;c=u.find((f)=>f.type.startsWith("image/"))}else{let u=i.filter((f)=>typeof f?.type==="string"&&s(f));c=u.find((f)=>f.type.startsWith("image/"));let d=i.length>0&&u.length===0?"type":null;if(c&&a(c))d="size";if(d)o.push({reason:d,file:d==="size"?c:i[0]}),c=null}if(_t(n),c){let u=URL.createObjectURL(c);O.set(n,u),n.setAttribute("src",u),hr()}else n.removeAttribute("src");if(ee(n),t.wrap!=null){let u=r({...t,to:t.wrap});if(u.length===0)H(`wrap: ${JSON.stringify(t.wrap)} is not on the page`);for(let d of u)c?it(d):nt(d)}if(t.name!=null)for(let u of r({...t,to:t.name}))u.textContent=c?c.name:"";for(let u of o)e.dispatchEvent(new CustomEvent("reactive:file-rejected",{bubbles:!0,detail:u}))}function dr(e,t){if(typeof DataTransfer!=="function"){if(e.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))H("per_file: has no DataTransfer to drop the refused files from the input");return!1}let r=new DataTransfer;for(let n of t)r.items.add(n);return e.files=r.files,!0}function fr(e,t){let r=String((t===!0?e.getAttribute("accept"):typeof t==="string"&&t)||"").toLowerCase().split(",").map((n)=>n.trim()).filter(Boolean);if(r.length===0)return(n)=>n.type.startsWith("image/");return(n)=>{let i=n.type.toLowerCase();return r.some((s)=>s[0]==="."?String(n.name).toLowerCase().endsWith(s):s.endsWith("/*")?i.startsWith(s.slice(0,-1)):i===s)}}function H(e){console.warn(`[phlex-reactive] preview_file ${e} — skipped`)}function _t(e){let t=O.get(e);if(t===void 0)return;if(O.delete(e),URL.revokeObjectURL(t),O.size===0)P?.disconnect(),P=null}function hr(){if(P||typeof MutationObserver!=="function"||!document?.documentElement)return;P=new MutationObserver(()=>{for(let[e,t]of O)if(!e.isConnected||e.getAttribute("src")!==t)_t(e)}),P.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["src"]})}function wt(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function At(e,t){if(!/^(input|textarea|select)$/.test(e.localName)||e.type==="file"&&t!==""){console.warn("[phlex-reactive] set_value skipped: not a field it can write",e);return}let r=Ue(e);if(e.value=t,Ue(e)!==r)wt(e)}function Ue(e){return e.type==="select-multiple"?[...e.selectedOptions].map((t)=>t.value).join(`
6
+ `):e.value}function mr(e,t,r){if(r?.transition)nr(e,r.transition,()=>e.hidden=t);else e.hidden=t}function se(e,t,r,n){if(mr(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 ae(e){if(!vt(e))return!0;return console.warn(`[phlex-reactive] refused client attr op on ${JSON.stringify(e)} — skipped`),!1}function St(e,t){if(e?.localName!=="img")return console.warn(`[phlex-reactive] copy_media targets an <img>, not <${e?.localName}> — skipped`),null;let r=t?.localName==="img"?t:null,n=r?.getAttribute("src"),i=!1;for(let a of["srcset","src"]){let o=n?r.getAttribute(a):null;if(o==null){if(e.hasAttribute(a))i=e.removeAttribute(a)??!0}else if(e.getAttribute(a)!==o)i=e.setAttribute(a,o)??!0}if(i)ee(e);let s=r?.getAttribute("alt")??"";if(e.getAttribute("alt")!==s)e.setAttribute("alt",s);return r?s:!1}var pr='a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';function gr(e){return e.querySelectorAll?.(pr)?.[0]??null}function Te(e){if(Array.isArray(e))return e;if(typeof e!=="string")return[];try{let t=JSON.parse(e);return Array.isArray(t)?t:[]}catch{return[]}}var Je=Object.freeze({backspace:"Backspace",delete:"Delete",enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"}),ze=Object.freeze(["meta","ctrl","alt","shift"]);function te(e,t,r){let n=e.split("+");for(let a of ze)if(n.includes(a)!==Boolean(t[`${a}Key`]))return!1;let i=n.find((a)=>!ze.includes(a));if(i===void 0||typeof t.key!=="string")return!0;let s=r&&Object.hasOwn(r,i)?r[i]:Object.hasOwn(Je,i)?Je[i]:/^[a-z0-9]$/.test(i)?i:null;return typeof s==="string"&&s.toLowerCase()===t.key.toLowerCase()}var br=(e)=>e&&typeof e==="object"?e.keys:String(e),Fe=()=>K().prevented??=new WeakSet;function ce(e,t){if(t!=null&&!e.defaultPrevented)Fe().add(e);e.preventDefault()}function W(e,t,r){if(t.defaultPrevented&&e?.handled!==!0&&!Fe().has(t))return!1;let n=t.target;if(e?.inEditable!==!0&&(n?.isContentEditable||/^(input|textarea|select)$/.test(n?.localName)))return!1;let i=/[Mm]ac|iP/.test(navigator.userAgentData?.platform??navigator.platform)?"meta":"ctrl";return te(br(e).replace(/^mod\+/,`${i}+`),t,r)}function yr(e){if(Array.isArray(e))return[{ops:e,legacy:!0}];if(e&&typeof e==="object")return[e];if(typeof e!=="string")return[];let t=e.trim();if(t.startsWith("["))return[{ops:Te(t),legacy:!0}];let r=[];for(let n of t.split(" ")){if(n==="")continue;let i=null;try{i=JSON.parse(n)}catch{i=null}if(i&&typeof i==="object"&&!Array.isArray(i))r.push(i);else console.warn(`[phlex-reactive] malformed on_client binding record ${JSON.stringify(n)} — skipped`)}return r}function He(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)!==Le(t.currentTarget))return!1;return i<0||r===null||te(n.slice(i+1),t,r)}function vr(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 Ke=new WeakMap;function _r(e,t,r){if(!r.once)return!1;let n=t.currentTarget??e.element,i=Ke.get(e);if(!i)i=new WeakMap,Ke.set(e,i);let s=i.get(n);if(!s)s=new Set,i.set(n,s);let a=t.params?.ops,c=(n===globalThis.window?`${typeof a==="string"?a:JSON.stringify(a??null)}|`:"")+JSON.stringify(r);if(s.has(c))return!0;return s.add(c),!1}var Ve=new WeakMap;function wr(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=Ve.get(e);if(!i)i=new WeakMap,Ve.set(e,i);let s=i.get(t);if(!s)s=new Map,i.set(t,s);let a=s.get(e.currentTarget);if(!a)a=new Set,s.set(e.currentTarget,a);if(a.has(n))return!0;return a.add(n),!1}function me(e,t,r){for(let n of e){if(!Array.isArray(n))continue;let[i,s={}]=n;if(!Object.hasOwn(je,i)){console.warn(`[phlex-reactive] unknown client op ${JSON.stringify(i)} — skipped`);continue}let a=t(s);if(a.length===0&&r)r(i,s);if(a.length>0)s=Sr(i,s,t,r);if(!s)continue;for(let o of a)if(je[i](o,s,t),s?.keep===!0)tt(o,i,s,t)}}var Ar=new Set(["set_value","text","set_attr"]);function Sr(e,t,r,n){let i=e==="dispatch",s=i?t.detail_from:Ar.has(e)&&t.from!=null&&{value:t.attr};if(!s)return t;let a=i?"@trigger":t.from,o;try{o=r({...t,to:a})[0]}catch{}if(!o)return n?.(e,{...t,to:a}),null;let c=i?{...t.detail}:{};for(let[u,d]of Object.entries(s)){let f=Er(o,d);if(f==null)return null;c[u]=f}return i?{...t,detail:c}:{...t,...c}}function Er(e,t){if(t==="@text")return e.textContent??"";if(typeof t==="string"&&/^data-[a-z][a-z0-9-]*$/i.test(t))return e.getAttribute(t)??"";return console.warn(`[phlex-reactive] refused client read of ${JSON.stringify(t)} — skipped`),null}function Tr(e,t){let r=e.to;if(r==="@trigger")return[];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 Fr(e){let t=e.getAttribute?.("data-reactive-persist");return Boolean(t)&&t!=="off"}function ke(e){return["defer-token","defer-src","lazy-on","lazy-visible"].some((t)=>e.getAttribute?.(`data-reactive-${t}`)!=null)}var F='[data-controller~="reactive"]',kr='[data-controller~="reactive"],[data-reactive-dormant~="reactive"]',pe=(e)=>e.getAttribute?.("data-reactive-token-value")==null&&!ke(e);function x(e,t,r){let n=e?.closest?.(t);while(n&&n!==r&&pe(n))n=n.parentElement?.closest?.(t);return n??null}var B=new WeakMap,j=new WeakMap;function Lr(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 xr(e){return["show-targets","group-targets","on-complete","filter-input","tags-field","css-vars"].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], [data-reactive-media], [data-reactive-css-vars]")!=null}function Rr(e){return e.getAttribute?.("data-reactive-compute-inputs-param")!=null}function Nr(e){return Boolean(e.matches?.("[data-reactive-sortable],[data-reactive-sortable-source]")||e.querySelector?.("[data-reactive-sortable],[data-reactive-sortable-source]"))}function Or(e){return Boolean(e.matches?.("[data-reactive-frame],[data-reactive-box],[data-reactive-point]")||e.querySelector?.("[data-reactive-frame],[data-reactive-box],[data-reactive-point]"))}function Et(e){return e.getAttribute?.("data-reactive-presence")!=null}function Pr(e){return Boolean(e.matches?.("[data-reactive-countdown]")||e.querySelector?.("[data-reactive-countdown]"))}var Ir=[["persist",[Fr,null,null,!0]],["defer",[ke,null]],["form",[Lr,null]],["bindings",[xr,null,null,!0]],["compute",[Rr,null,null,!0]],["sortable",[Nr,null]],["drag",[Or,null]],["presence",[Et,null]],["countdown",[Pr,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]]],w=new Map(Ir),Ge=new Map,g=new Map,Mr=new Map;function y(e,t,r){Tt.set(e,[t,r]),Cr(e)}var Tt=new Map;function Cr(e){let t=w.get(e),[r,n]=Tt.get(e);t[1]=r,t[2]=n}function on(e,t){t.install?.(M),g.set(e,t),Mr.set(e,t)}function Ft(e){let t=[];for(let[r,[n]]of w){if(!n||g.has(r))continue;try{if(e.some((i)=>n(i)))t.push(r)}catch{}}return t}function kt(e){return I(e).catch((t)=>Q(e,"load",t))}function I(e){let t=Ge.get(e);if(!t)t=(w.get(e)[1]??(()=>Promise.reject(Error("this entry has no way to import it"))))().then((n)=>(n.install?.(M),g.set(e,n),n)),Ge.set(e,t);return t}var Ye=new Set;function Q(e,t,r){let n=e+t;if(Ye.has(n))return;Ye.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 v(e,t){let r=g.get(e);if(r)return t(r);I(e).then(t,(n)=>Q(e,"load",n))}var Dr=1e4;function ue(){let e=Number(globalThis.document?.head?.querySelector?.('meta[name="phlex-reactive-feature-timeout"]')?.content);return Number.isFinite(e)&&e>0?e:Dr}function sn(){return[...w.keys()]}var Xe=Promise.resolve();function Qe(e,t,r){let n=M.waiting.get(e);if(n&&n[t]===r)delete n[t]}var M={enter:ft,exit:ht,count:gt,text:T,served:Ee,waiting:new WeakMap};var C=Symbol.for("phlex-reactive.early"),$r=1e4,qr=1500,Le=(e)=>e!=null&&(e===globalThis.window||e.window===e),Wr="dispatch";function K(){return globalThis[C]??={queue:[],connected:new WeakSet},globalThis[C]}function Br(){let e=Number(globalThis.document?.querySelector?.('meta[name="phlex-reactive-early-ttl"]')?.content);return Number.isFinite(e)&&e>0?e:$r}function jr(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 s;try{s=JSON.parse(n)}catch{s=n}t[i[1].replace(/[-_]([a-z0-9])/g,(a,o)=>o.toUpperCase())]=s}return t}function Ur(e,t,r){return{[C]:!0,type:e.type,detail:e.detail,target:e.target,currentTarget:r?t.ownerDocument.defaultView:t,params:jr(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&&!Fe().has(e),preventDefault(){},stopPropagation(){},stopImmediatePropagation(){}}}var Z=new WeakMap;function Jr(e,{token:t,type:r,method:n,filter:i,win:s},a){let o=Z.get(e);if(!o)Z.set(e,o=new Map);let c=s?`${t} ${a}`:t;if(o.has(c))return!1;return o.set(c,{type:r,method:n,filter:i,win:s,params:a,armed:!0}),!0}function Ze(e,t,r,n){if(e?.[C])return!1;let i=Le(e?.currentTarget),s=i?n:e?.currentTarget,a=Hr(e,s,i?`@${t}`:t),o=Z.get(s),c=i&&JSON.stringify(e.params);for(let u of o?.values()??[]){if(!u.armed||u.method!==t||u.type!==e.type||Boolean(u.win)!==i)continue;if(i&&u.params!==c)continue;if(u.filter&&!te(u.filter,e,r))continue;return u.armed=!1,!0}return a}var V=new WeakMap;function zr(e,t,r){let n=V.get(e);if(!n)V.set(e,n=new Map),setTimeout(()=>V.delete(e));let i=n.get(t)??{};n.set(t,i),i[r]=(i[r]??0)+1}function Hr(e,t,r){let n=e&&V.get(e)?.get(t);if(!n?.[r])return!1;return n[r]-=1,!0}class Lt extends Rt{static values={token:String};#A;#d=new Map;#f=new Map;#ie;#x;#B;#R=0;#h=new Map;#N=new WeakMap;#t;featuresReady=Xe;#r=new Map;#O=new Set;#m=!1;#n=null;#p=new Map;#S=new Map;#g=new Map;#b=0;#j;#je=0;#Ue=0;connect(){if(yt=!0,K().connected.add(this.element),B.set(this.element,this),this.element.id==="")console.warn("[phlex-reactive] a reactive root has no id; its next-action token can't self-match "+"and may fall back to the first token in the response → a silent HTTP 403 on the NEXT action. "+"Put id: on the SAME element as reactive_attrs — use div(**reactive_root) (emits id + token together), "+"or div(id:, **reactive_attrs). The id: must NOT be on a child. See the README.");if(this.element.getAttribute?.("data-reactive-token-value")!=null||ke(this.element))this.#t=(e)=>{if(e.type==="focusin"?!e.target.hasAttribute?.("data-reactive-editable"):e.target!==this.element)return;if(e.type===U)this.#z();this.#U(!0)},this.element.addEventListener?.("turbo:morph-element",this.#t),this.element.addEventListener?.("focusin",this.#t),this.element.addEventListener?.(U,this.#t);this.element.querySelectorAll?.("[data-reactive-editable]").forEach(Se),this.#b++,this.featuresReady=Xe,this.#U(),G(this.element),this.#ce()}#Je(e){}#ze(e,t,r,n){}#He(){}#Ke(e,t){}#U(e){{let t=this.#b,r=[];for(let[s,[a]]of w){if(!a||this.#O.has(s))continue;let o=g.get(s);if(o&&!o.connect)continue;try{if(a(this.element))r.push(s)}catch(c){this.#y(s,"detect",c)}}if(r.length===0)return;for(let s of r)this.#O.add(s);if(!this.#m&&r.every((s)=>g.has(s))){for(let s of r)this.#P(t,s,g.get(s),e);return}for(let s of r){let a=this.#oe(t,s),o=[];for(let u of w.keys()){if(u===s)break;if(this.#g.has(u))o.push(this.#g.get(u))}let c=Promise.all(o).then(()=>a).then((u)=>u&&this.#P(t,s,u,e));if(this.#g.set(s,c),w.get(s)[3])this.#n=c}let n=this.#n;n?.then(()=>{if(this.#n===n)this.#n=null}),this.#m=!0;let i=Promise.all(this.#g.values()).then(()=>{if(this.featuresReady===i)this.#m=!1});this.featuresReady=i}}#oe(e,t){{let r=()=>e===this.#b;return this.#se(t),new Promise((n)=>{let i=!1,s=setTimeout(()=>{if(this.#p.delete(s),i=!0,r())this.#y(t,"timeout",Error(`not loaded after ${ue()} ms`));n(null)},ue());this.#p.set(s,n);let a=()=>{clearTimeout(s),this.#p.delete(s)};I(t).then((o)=>{if(a(),i)queueMicrotask(()=>this.#P(e,t,o));else n(o)},(o)=>{if(a(),r())this.#y(t,"load",o);n(null)})})}}#se(e){{let t=w.get(e)[2];if(!t)return;let r={};try{this.#S.set(e,[t(this.element,r),r]),M.waiting.set(this.element,{...M.waiting.get(this.element),[e]:r})}catch(n){this.#y(e,"detect",n)}}}#J(e,t){{let[r,n]=this.#S.get(e)??[];if(this.#S.delete(e),!t)Qe(this.element,e,n);try{r?.()}catch(i){console.error(`[phlex-reactive] the "${e}" feature module failed to stop waiting`,i)}return n}}#P(e,t,r,n){{if(e!==this.#b)return;let i=this.#J(t);try{r.connect?.(this,this.#e(),n,i),this.#r.set(t,r)}catch(s){this.#y(t,"connect",s)}}}#e(){return this.#j??={emit:(e,t,r)=>this.#o(e,t,r),reseed:()=>this.#z(),proceed:(e,t,r,n)=>this.#M(e,t,r,0,0,null,n),forgetToken:()=>{this.#A=void 0},owns:(e)=>this.#c(e),ownership:()=>this.#Q(),bindingOwns:(e)=>this.#Z(e),bindingOwnership:()=>this.#Le(),opTargets:(e)=>this.#W(e),diagnose:(e,t)=>this.#q(e,t),applyOps:(e,t)=>me(e,(r)=>this.#W(t!=null&&r.to==null?{...r,to:t}:r),(r,n)=>this.#q(`client op "${r}"`,n)),listnavOptions:(e)=>this.#_(e),collectFields:()=>this.#ee(),plain:ct,text:T,served:Ee,copyMedia:St,setValue:At,confirm:(e,t)=>Promise.resolve().then(()=>Re(e,t)).catch(()=>!1)},this.#j}#z(){this.#r.get("form")?.reseed(this),this.#r.get("bindings")?.reseed(this),this.#r.get("compute")?.seed(this)}#y(e,t,r){if(Q(e,t,r),this.#i("feature"),t==="load"&&this.element.getAttribute?.("data-reactive-defer-pending"))this.element.removeAttribute("data-reactive-defer-pending"),this.element.removeAttribute("aria-busy");this.#o("reactive:error",{kind:"feature",feature:e,phase:t,error:r})}#ae(){{this.#b++;for(let[t,r]of this.#p)clearTimeout(t),r(null);this.#p.clear();for(let t of[...this.#S.keys()]){let r=this.#J(t,!0),n=this.element;v(t,(i)=>{i.abandon?.(n,r),Qe(n,t,r)})}this.#O.clear(),this.#g.clear(),this.#m=!1,this.#n=null;let e=[...this.#r];this.#r.clear();for(let[t,r]of e)try{r.disconnect?.(this,this.#e())}catch(n){console.error(`[phlex-reactive] the "${t}" feature module failed to disconnect`,n)}}}#ce(){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.#ue();for(let[e,t]of j.get(this.element)??[]){if(e.currentTarget!==t)Object.defineProperty(e,"currentTarget",{value:t,configurable:!0});this.dispatch(e)}j.delete(this.element)}#I=new Set;#ue(){let{queue:e}=K();if(e.length===0)return;let t=[];for(let i=e.length-1;i>=0;i--){let{root:s}=e[i];if(s===this.element||!s.isConnected)t.unshift(...e.splice(i,1))}let r=Br(),n=new Map;for(let i of t){let s=n.get(i.event)??[new Set,new Set];n.set(i.event,s);let a=s[+!!i.win];if(a.has(i.el))continue;a.add(i.el);let o=i.win?Math.min(qr,r):r,c=i.root!==this.element?"its root left the page before a controller connected":performance.now()-i.at>o?`it is older than the ${o} 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.#L())console.warn(`[phlex-reactive] dropped an early "${i.event.type}" trigger: ${c}`);continue}this.#le(i)}}#le({event:e,el:t,descs:r,win:n}){let i=Ur(e,t,n),s=this.application?.schema?.keyMappings,a=(t.getAttribute("data-action")??"").split(/\s+/),o=n?this.element:t;for(let c of r){if(!a.includes(c.token))continue;if(c.filter&&!te(c.filter,e,s))continue;if(/#\w+.*:once\b/.test(c.token)){if(!Jr(o,c,n&&JSON.stringify(i.params)))continue;this.#I.add(o)}if(zr(e,o,n?`@${c.method}`:c.method),c.method==="runOps")this.runOps(i);else this.dispatch(i)}}disconnect(){if(this.#ae(),this.#ve(),this.#we(),this.#t)this.element.removeEventListener?.("turbo:morph-element",this.#t),this.element.removeEventListener?.("focusin",this.#t),this.element.removeEventListener?.(U,this.#t);if(K().connected.delete(this.element),B.get(this.element)===this)B.delete(this.element);this.element.removeAttribute?.("data-reactive-connected");for(let e of this.#I)Z.delete(e);this.#I.clear()}dispatch(e){if(e.params?.action&&e.params.action!==qe&&this.#de())return this.#fe(e);let t=e.params?.shortcut;if(t!=null&&!W(t,e,this.application?.schema?.keyMappings))return;if(Ze(e,"dispatch",this.application?.schema?.keyMappings,this.element))return;let{action:r,params:n,debounce:i,throttle:s,confirm:a,confirmWhen:o,outside:c,window:u,optimistic:d,prevent:f}=e.params;if(!r)return;let h=e.params.busy??e.params.loading;if(c&&this.element.contains(e.target))return;let p=e.currentTarget??e.target;if((t!=null||!u&&f!==!1)&&!this.#re(d,p))ce(e,t);if(r===qe){let m=()=>{{let S=this.#r.get("defer");if(S)return S.materialize(this)}if(this.tokenValue)return this.#M(p,r,"{}")};return this.#m?this.featuresReady.then(m):m()}let b=this.#H(a,o),E=()=>this.#M(p,r,n,i,s,d,h);if(!b)return E();if(b instanceof Promise)return b.then((m)=>m?this.#E(m,p,E):E());this.#E(b,p,E)}#E(e,t,r){return Promise.resolve().then(()=>Re(e,{el:t})).catch(()=>!1).then((n)=>{if(n)r()})}#H(e,t){if(e)return e;if(!t)return null;{let r=g.get("bindings");if(r)return r.confirmMessage(this,this.#e(),t);return this.#K("bindings").then((n)=>n&&n.confirmMessage(this,this.#e(),t))}}#K(e){{let t;return Promise.race([I(e).catch((r)=>(Q(e,"load",r),null)),new Promise((r)=>t=setTimeout(()=>r(null),ue()))]).finally(()=>clearTimeout(t))}}#de(){return!this.tokenValue&&pe(this.element)}#fe(e){let t=x(this.element.parentElement,kr);if(!t){if(this.element.closest?.('[data-reactive-verbose="true"], [data-reactive-debug="true"]'))console.warn(`[phlex-reactive] "${e.params.action}": no token on this root or above, nothing sent`);return}let r=B.get(t);if(r)return r.dispatch(e);let{shortcut:n,window:i,optimistic:s,prevent:a}=e.params;if(n!=null&&!W(n,e,this.application?.schema?.keyMappings))return;let o=e.currentTarget??e.target;if((n!=null||!i&&a!==!1)&&!this.#re(s,o))ce(e,n);j.set(t,[...j.get(t)??[],[e,o]]);let c=t.dataset;if(c.reactiveDormant)c.controller=`${c.controller??""} ${c.reactiveDormant}`.trim(),delete c.reactiveDormant}runOps(e){let t=e.params?.ops;if(t?.shortcut!=null&&!W(t.shortcut,e,this.application?.schema?.keyMappings))return;if(Ze(e,"runOps",this.application?.schema?.keyMappings,this.element))return;if(wr(e,this))return;let r=e.params??{},n=e.currentTarget??e.target,i=yr(r.ops),s=i.filter((o)=>He(o,e,null)),a=s.length<=1?s:s.filter((o)=>He(o,e,this.application?.schema?.keyMappings));if(a.length===0&&i.length>0){if(this.#L())this.#w((o)=>o.noBinding(this,e));return}for(let o of a){if(o.outside&&e[C])continue;if(!vr(o,e))continue;let c=o.within==null?n:this.#he(o.within,e);if(o.within!=null&&!c)continue;if(o.shortcut!=null&&!W(o.shortcut,e,this.application?.schema?.keyMappings))continue;if(_r(this,e,o))continue;this.#me(o.legacy?{...r,ops:o.ops,debounce:void 0,throttle:void 0,prevent:void 0}:o,e,c,i.indexOf(o),n)}}#he(e,t){let r=t.currentTarget,n=null;try{n=t.target?.closest?.(e)}catch{if(this.#L())console.warn(`[phlex-reactive] on_client within: ${JSON.stringify(e)} is not a selector — nothing ran`)}return n&&n!==r&&r?.contains?.(n)&&this.#c(n)?n:null}#me(e,t,r,n,i=r){let{ops:s,confirm:a,confirmWhen:o,outside:c,window:u,shortcut:d,prevent:f}=e;if(c&&this.element.contains(t.target))return;if(d!=null||!u&&f!==!1)ce(t,d);let h=this.#H(a,o),p=this.#pe(e,n,i,()=>this.#Ie(this.#Pe(s),r));if(!h)return p();if(h instanceof Promise)return h.then((b)=>b?this.#E(b,r,p):p());this.#E(h,r,p)}#pe(e,t,r,n){let i=Number(e.debounce)||0,s=Number(e.throttle)||0;if(i<=0&&s<=0)return n;let a=JSON.stringify([t,e]);if(i>0)return()=>this.#V(r,a,i,n);return()=>this.#G(r,a,s,n)}recompute(e){return g.get("compute")?.recompute(this,this.#e(),e)}tagsAdd(e){if(e?.defaultPrevented)return;if(this.#_(e).some((t)=>t.hasAttribute?.("data-reactive-highlighted")))return;return this.#v("tagsAdd",e)}tagsPick(e){return this.#v("tagsPick",e)}tagsRemove(e){return this.#v("tagsRemove",e)}nestedAdd(e){return this.#v("nestedAdd",e)}nestedRemove(e){return this.#v("nestedRemove",e)}syncNestedJson(e){return g.get("bindings")?.syncNestedJson(this,this.#e(),e)}#v(e,t){{let r=g.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 v("bindings",(i)=>i[e](this,this.#e(),n))}}trackDirty(){(this.#r.get("form")??g.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.#_(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.#_(e))t.removeAttribute("data-reactive-highlighted")}#T(e,t){let r=this.#_(e);if(!r.length)return;e.preventDefault();let n=this.#ge(e),i=globalThis.document?.activeElement,s=n?r.findIndex((o)=>o===i||i!=null&&o.contains?.(i)):r.findIndex((o)=>o.hasAttribute("data-reactive-highlighted")),a=r[t(s,r.length)];if(n)a.focus?.();else{for(let o of r)o.removeAttribute("data-reactive-highlighted");a.setAttribute("data-reactive-highlighted","true")}a.scrollIntoView?.({block:"nearest"})}#ge(e){return(e?.currentTarget??e?.target??this.element).getAttribute?.("data-reactive-listnav-focus-param")==="true"}#_(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.#Q();return Array.from(this.element.querySelectorAll(r)).filter((i)=>!i.hidden&&n(i))}#M(e,t,r,n,i,s,a){if(this.#o("reactive:before-dispatch",{action:t,params:this.#te(r),element:this.element},{cancelable:!0}).defaultPrevented)return;let c=Number(n)||0;if(c>0)return this.#ye(e,c,t,r,s,a);let u=Number(i)||0;if(u>0)return this.#_e(e,u,t,r,s,a);return this.#F(t,r,s,e,a)}#F(e,t,r,n,i){let s={inverse:null,undo:[],resurrect:null},a=this.#Me(e,n,s),o=Boolean(r||i),c=(h)=>{if(!o||!h)return;let p=this.#e();if(s.inverse=h.optimistic(this,p,r,n),s.undo.push(...h.busy(this,p,i,n)),this.#D())s.resurrect=h.resurrection(this,p,r,n)},u=g.get("hints");if(!o||u)c(u);let d=()=>this.#Te(e,t,s,a),f=()=>this.#n?this.#n.then(d):d();return this.queue=(this.queue??Promise.resolve()).then(()=>o&&!u?this.#be().then(c).then(f):f()),this.queue}#be(){return this.#K("hints")}#ye(e,t,r,n,i,s){this.#V(e,Wr,t,()=>this.#F(r,n,i,e,s))}#V(e,t,r,n){this.#C(e,t);let i=()=>{this.#C(e,t),n()},s=setTimeout(i,r);if(!Le(e))e?.addEventListener?.("blur",i,{once:!0});let a=this.#d.get(e);if(!a)this.#d.set(e,a=new Map);a.set(t,{timer:s,flush:i})}#C(e,t){let r=this.#d.get(e),n=r?.get(t);if(!n)return;if(clearTimeout(n.timer),e?.removeEventListener?.("blur",n.flush),r.delete(t),r.size===0)this.#d.delete(e)}#ve(){for(let[e,t]of[...this.#d])for(let r of[...t.keys()])this.#C(e,r)}#_e(e,t,r,n,i,s){return this.#G(e,r,t,()=>this.#F(r,n,i,e,s))}#G(e,t,r,n){let i=this.#f.get(e)??new Map;if(i.has(t))return;let s=setTimeout(()=>{if(i.delete(t),i.size===0)this.#f.delete(e)},r);return i.set(t,s),this.#f.set(e,i),n()}#we(){for(let e of this.#f.values())for(let t of e.values())clearTimeout(t);this.#f.clear()}#o(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.#F(e,t)};this.#o("reactive:error",{action:e,params:r,...n,retry:i})}#i(e){if(this.element?.isConnected===!1)return;this.element?.setAttribute?.("data-reactive-error",e)}#Ae(){this.element?.removeAttribute?.("data-reactive-error")}#Se(){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))}#Ee(){{let e=g.get("devtools");if(e)return e.delay();if(lt())return I("devtools").then((t)=>t.delay(),()=>{})}}#D(){return this.element?.getAttribute?.("data-reactive-debug")==="true"}#Y(){return typeof performance<"u"&&typeof performance.now==="function"?performance.now():Date.now()}async#Te(e,t,r,n){let{fields:i,files:s}=this.#ee(),a=this.#te(t),o={...i,...a},c=this.#a,u=s.length>0,d=u?this.#Ne(c,e,o,s):JSON.stringify({token:c,act:e,params:o}),f=this.#D()?{action:e,paramNames:Object.keys(a),fieldNames:Object.keys(i),encoding:u?"multipart":"json",status:null,streams:[],tokenRefreshed:!1,started:this.#Y()}:null;await this.#Ee();try{if(navigator.onLine===!1){this.#u(r.inverse),this.#i("offline"),this.#s(e,t,o,{kind:"offline"});return}let h;try{let m={Accept:"text/vnd.turbo-stream.html","X-CSRF-Token":this.#We()};if(!u)m["Content-Type"]="application/json";let S=this.#Be();if(S)m["X-Pgbus-Connection"]=S;let D=Et(this.element)&&document.getElementById(`reactive-presence-src-${this.element.id}`)?.getAttribute("connection-id");if(D)m["X-Reactive-Presence"]=D;let xe=Kt(this.element);if(xe)m["X-Reactive-Held"]=xe;gt("action"),h=await fetch(this.#$e(),{method:"POST",headers:m,body:d,credentials:"same-origin",signal:AbortSignal.timeout(this.#qe())})}catch(m){if(console.error("[phlex-reactive] action error",m),this.#u(r.inverse),m?.name==="TimeoutError"||m?.name==="AbortError"){this.#i("timeout"),this.#s(e,t,o,{kind:"timeout"});return}this.#Se(),this.#i("network"),this.#s(e,t,o,{kind:"network"});return}if(f)f.status=h.status;if(h.redirected){console.error("[phlex-reactive] action was redirected (auth/CSRF?) — no update applied"),this.#u(r.inverse),this.#i("redirected"),this.#s(e,t,o,{kind:"redirected",status:h.status});return}if(!h.ok){let m=await h.text();if(console.error(`[phlex-reactive] action failed: HTTP ${h.status}`,m),this.#u(r.inverse),(h.headers.get("Content-Type")||"").includes("turbo-stream")){let S=this.#X(m);if(this.#a=S??this.#a,f)this.#w((D)=>D.recordBody(f,m,S));$e(this.element,m,!0)}this.#i("http"),this.#s(e,t,o,{kind:"http",status:h.status,body:m});return}let p=h.headers.get("Content-Type")||"";if(!p.includes("turbo-stream")){console.error(`[phlex-reactive] expected a turbo-stream, got "${p}" — no update applied`),this.#u(r.inverse),this.#i("content-type"),this.#s(e,t,o,{kind:"content-type",status:h.status});return}let b=await h.text(),E=this.#X(b);if(this.#a=E??this.#a,f)this.#w((m)=>m.recordBody(f,b,E));if($e(this.element,b,Vt(h)),r.resurrect)queueMicrotask(r.resurrect);return this.#Ae(),this.#o("reactive:applied",{action:e,params:o,html:b}),b}catch(h){console.error("[phlex-reactive] action error",h),this.#u(r.inverse),this.#o("reactive:error",{action:e,params:o,kind:"apply"})}finally{if(n?.(),f)this.#w((h)=>h.trace(this,{...f,ms:this.#Y()-f.started}))}}get#a(){return this.#A??this.tokenValue}set#a(e){this.#A=e}tokenValueChanged(){this.#A=void 0}#X(e){let t=this.element.id;if(!t)return e.match(/data-reactive-token-value="([^"]+)"/)?.[1];let{token:r,self:n}=this.#Fe(t),i=e.match(r);if(i)return i[1];let s=e.match(n);if(s)return s[1].match(/data-reactive-token-value="([^"]+)"/)?.[1];return}#Fe(e){let t=this.#B;if(t&&t.id===e)return t;let r=er(e);return this.#B={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>`)}}#c(e){return e.closest('[data-controller~="reactive"]')===this.element}#Q(){if(this.element.querySelectorAll('[data-controller~="reactive"]').length===0)return()=>!0;return(t)=>this.#c(t)}#ke(){let e=this.element.querySelectorAll(F);if(e.length===0||[...e].every(pe))return()=>!0;return(t)=>{let r=x(t,F,this.element);if(r===this.element)return!0;return t.getAttribute("data-reactive-shared-field")!=null&&x(r.parentElement,F,this.element)===this.element}}#Z(e){if(this.#c(e))return!0;if(e.getAttribute?.("data-reactive-shared-field")==null)return!1;let t=x(e,F,this.element);return t===this.element||x(t?.parentElement,F,this.element)===this.element}#Le(){if(this.element.querySelectorAll(F).length===0)return()=>!0;return(e)=>this.#Z(e)}#ee(){let e={},t=[],r=this.#ke(),n=[];this.element.querySelectorAll("input[name], select[name], textarea[name]").forEach((o)=>{if(!r(o))return;if(o.type==="file")for(let c of o.files??[])t.push({name:o.name,file:c,multiple:o.multiple});else n.push(o)});let i=[];this.element.querySelectorAll(`[name]${or}`).forEach((o)=>{if(r(o))i.push(o)});let s=this.#xe(n),a=this.#Re(n);for(let o of n)if(s.has(o.name)){let c=e[o.name]??(e[o.name]=[]);if(o.type==="checkbox"||o.type==="radio"){if(o.checked)c.push(o.value)}else if(o.type==="hidden"){if(!a.has(o.name))c.push(o.value)}else if(o.multiple&&o.options){for(let u of o.options)if(u.selected)c.push(u.value)}else c.push(o.value)}else if(o.type==="checkbox")e[o.name]=o.checked;else if(o.type==="radio"){if(o.checked)e[o.name]=o.value}else e[o.name]=o.value;return i.forEach((o)=>{let c=o.getAttribute("name");if(!c)return;let u=o.getAttribute("data-reactive-editable")!=null?T(o):o.value??o.textContent??o.innerHTML??"",d=e[c];if(String(c).endsWith("[]")&&!ar(o))return;if(String(c).endsWith("[]")&&(d===void 0||Array.isArray(d))){(Array.isArray(d)?d:e[c]=[]).push(u);return}if(d==null||d==="")e[c]=u}),{fields:e,files:t}}#xe(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}#Re(e){let t=new Set;for(let r of e)if(r.type==="checkbox")t.add(r.name);return t}#Ne(e,t,r,n){let i=new FormData;i.append("token",e),i.append("act",t);let s=[];for(let[o,c]of Object.entries(r))if(Array.isArray(c)&&String(o).endsWith("[]"))if(c.length===0)s.push(String(o).slice(0,-2));else{let u=`${this.#k(o)}[]`;for(let d of c)i.append(u,String(d))}else this.#$(i,this.#k(o),c);for(let o of s)i.append("empty_groups[]",o);let a=this.#Oe(n);for(let{name:o,file:c,multiple:u}of n){let f=u||a.has(o)?`${this.#k(o)}[]`:this.#k(o);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("")}`}#$(e,t,r){if(r==null)e.append(t,"");else if(Array.isArray(r))r.forEach((n,i)=>this.#$(e,`${t}[${i}]`,n));else if(typeof r==="object")for(let[n,i]of Object.entries(r))this.#$(e,`${t}[${n}]`,i);else e.append(t,String(r))}#Oe(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))}#te(e){if(!e)return{};try{return typeof e==="string"?JSON.parse(e):e}catch{return{}}}#Pe(e){return Te(e)}#Ie(e,t){me(e,(r)=>this.#W(r,t),(r,n)=>this.#q(`client op "${r}"`,n))}#L(){return this.element?.getAttribute?.("data-reactive-verbose")==="true"||this.#D()}#q(e,t){if(!this.#L())return;this.#w((r)=>r.diagnose(this,e,t))}#w(e){v("devtools",e)}#W(e,t){let r=e.to;if(r==="@root")return[this.element];if(r==="@trigger")return t?.nodeType===1?[t]:[];if(typeof r!=="string"||r==="")return[];if(e.global)return[...document.querySelectorAll(r)];return[...this.element.querySelectorAll(r)].filter((n)=>this.#c(n))}#re(e,t){if(e?.checked!=="keep")return!1;let r=t?.type;return r==="checkbox"||r==="radio"}#u(e){if(!e)return;if(!this.element.isConnected)return;for(let t of e)t()}#Me(e,t,r){this.#Ce(e,t),ft();let n=!1;return()=>{if(n)return;n=!0,this.#De(e,t),ht();for(let i of r.undo)i()}}#Ce(e,t){if(this.#l(t,e,1),this.#l(this.element,e,1),this.#h.set(e,(this.#h.get(e)??0)+1),this.#R++===0)this.element.setAttribute("aria-busy","true");for(let r of this.#ne(e))this.#l(r,e,1)}#De(e,t){this.#l(t,e,-1),this.#l(this.element,e,-1);let r=(this.#h.get(e)??1)-1;if(r<=0)this.#h.delete(e);else this.#h.set(e,r);if(--this.#R<=0)this.#R=0,this.element.removeAttribute("aria-busy");for(let n of this.#ne(e))this.#l(n,e,-1)}#l(e,t,r){if(!e||typeof e.getAttribute!=="function")return;let n=this.#N.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.#N.delete(e),e.removeAttribute("data-reactive-busy");return}this.#N.set(e,n),e.setAttribute("data-reactive-busy",[...n.keys()].join(" "))}#ne(e){return[...this.element.querySelectorAll?.("[data-reactive-busy-on]")??[]].filter((r)=>r.getAttribute("data-reactive-busy-on")===e&&this.#c(r))}#$e(){return this.#ie??=document.querySelector('meta[name="phlex-reactive-action-path"]')?.content||"/reactive/actions"}#qe(){if(this.#x!=null)return this.#x;let e=document.querySelector('meta[name="phlex-reactive-timeout"]')?.content,t=Number(e);return this.#x=Number.isFinite(t)&&t>0?t:30000}#We(){return document.querySelector('meta[name="csrf-token"]')?.content??""}#Be(){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)Be();else document.addEventListener("turbo:load",Be,{once:!0});y("persist",()=>import("phlex/reactive/features/persist"),Kr);y("defer",()=>import("phlex/reactive/features/defer"));y("form",()=>import("phlex/reactive/features/form"));y("bindings",()=>import("phlex/reactive/features/bindings"));y("compute",()=>import("phlex/reactive/features/compute"),Vr);y("sortable",()=>import("phlex/reactive/features/sortable"));y("drag",()=>import("phlex/reactive/features/drag"));y("presence",()=>import("phlex/reactive/features/presence"));y("countdown",()=>import("phlex/reactive/features/countdown"));y("effects",()=>import("phlex/reactive/features/effects"));y("hints",()=>import("phlex/reactive/features/hints"));y("devtools",()=>import("phlex/reactive/features/devtools"));Ae();function Kr(e,t){let r=()=>{t.edited=!0},n=(s)=>{let a=s.target;if(s.detail?.success&&a?.tagName==="FORM"&&a.contains?.(e))t.submitted=!0},i=["input","change","lexxy:change","trix-change"];for(let s of i)e.addEventListener?.(s,r);return document.addEventListener("turbo:submit-end",n),()=>{for(let s of i)e.removeEventListener?.(s,r);document.removeEventListener("turbo:submit-end",n)}}function Vr(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 Gr=1000,L=null,xt,re=new Set;function Yr(e){return kt(e).then((t)=>{if(e!=="effects")return;xt=t,t?.sweep()})}at((e,t)=>{let r=e.detail,n=r?.render;if(typeof n!=="function")return;let i=r.newStream??e.target,s=Ft(Xr(i)).filter((o)=>!re.has(o));if(!t&&!re.has("effects")&&Qr(i))s.push("effects");if(s.length===0&&!L)return t?.wrap(e);if(s.length>0){for(let c of s)re.add(c);let o=L=Promise.race([Promise.all([L,...s.map(Yr)]),new Promise((c)=>setTimeout(c,Gr))]).then(()=>{if(L!==o)return;L=null,re.clear()})}let a=L;r.render=async(o)=>{await a;let c={target:e.target,detail:{newStream:r.newStream,render:n}};(t??xt)?.wrap(c),await c.detail.render(o)}});function Xr(e){let t=e?.querySelector?.("template")?.content;if(!t)return[];let r=[...t.querySelectorAll?.('[data-controller~="reactive"]')??[]];for(let n of t.children??[])if(n.matches?.('[data-controller~="reactive"]')&&!r.includes(n))r.unshift(n);return r.push(t),r}function Qr(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 fn=Lt;export{dt as ACTIVE_ATTR,or as EDITOR_SELECTOR,sr as EDITOR_TAGS,pt as REQUESTS_ATTR,tr as checkReactiveRegistration,gt as countReactiveRequest,fn as default,T as editableValue,ft as enterReactiveActivity,er as escapeRegExp,ht as exitReactiveActivity,kt as loadReactiveFeature,at as onReactiveStreamWithoutEffects,rn as reactiveActivityCount,sn as reactiveFeatureNames,Be as registerReactiveActions,Mt as registerReactiveDefer,Ae as registerReactiveDev,Ct as registerReactiveDismiss,Ct as registerReactiveEffects,on as registerReactiveFeature,y as registerReactiveFeatureLoader,jt as registerReactiveImageFallback,It as registerReactiveJs,Bt as registerReactiveKeep,Wt as registerReactiveModals,Jt as registerReactiveMorphFocus,Yt as registerReactiveOffline,Ut as registerReactivePlaintext,Ct as registerReactiveStreamRender,Ot as registerReactiveToken,Nt as registerReactiveVisit,nn as resetReactiveActivity,Ee as serverText,Ft as unloadedFeaturesFor};
7
7
 
8
- //# debugId=A4008E3BC0B43BC564756E2164756E21
8
+ //# debugId=22AC2837D88032A464756E2164756E21
9
9
  //# sourceMappingURL=core.min.js.map