phlex-reactive 0.15.3 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +184 -0
- data/README.md +92 -12
- data/app/javascript/phlex/reactive/core.js +1 -0
- data/app/javascript/phlex/reactive/core.min.js +6 -6
- data/app/javascript/phlex/reactive/core.min.js.map +4 -4
- data/app/javascript/phlex/reactive/features/bindings.js +129 -16
- data/app/javascript/phlex/reactive/features/bindings.min.js +2 -2
- data/app/javascript/phlex/reactive/features/bindings.min.js.map +3 -3
- data/app/javascript/phlex/reactive/features/countdown.js +140 -0
- data/app/javascript/phlex/reactive/features/countdown.min.js +4 -0
- data/app/javascript/phlex/reactive/features/countdown.min.js.map +10 -0
- data/app/javascript/phlex/reactive/features/persist.js +10 -6
- data/app/javascript/phlex/reactive/features/persist.min.js +2 -2
- data/app/javascript/phlex/reactive/features/persist.min.js.map +3 -3
- data/app/javascript/phlex/reactive/reactive_controller.js +2 -0
- data/app/javascript/phlex/reactive/reactive_controller.min.js +4 -4
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +8 -7
- data/app/javascript/phlex/reactive/runtime.js +255 -31
- data/lib/phlex/reactive/component/countdown_binding.rb +80 -0
- data/lib/phlex/reactive/component/field_references.rb +130 -0
- data/lib/phlex/reactive/component/helpers.rb +72 -14
- data/lib/phlex/reactive/component/image_fallback_binding.rb +18 -5
- data/lib/phlex/reactive/component/media_binding.rb +9 -1
- data/lib/phlex/reactive/component/media_pattern.rb +17 -17
- data/lib/phlex/reactive/component/selection.rb +24 -2
- data/lib/phlex/reactive/component/show_options.rb +91 -0
- data/lib/phlex/reactive/engine.rb +2 -2
- data/lib/phlex/reactive/js.rb +44 -2
- data/lib/phlex/reactive/response.rb +3 -4
- data/lib/phlex/reactive/show_conditions/compare_terms.rb +142 -0
- data/lib/phlex/reactive/show_conditions.rb +39 -6
- data/lib/phlex/reactive/streamable.rb +6 -4
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +8 -1
|
@@ -103,6 +103,15 @@ export function connect(controller, core) {
|
|
|
103
103
|
syncShow(c)
|
|
104
104
|
}
|
|
105
105
|
listen(c, "input change", c.show)
|
|
106
|
+
// The after: gate (issue #396): an owned field's first blur marks its
|
|
107
|
+
// name touched for this controller (a morph keeps it, a new one starts
|
|
108
|
+
// without), and re-syncs once if a binding waits on a blur.
|
|
109
|
+
listen(c, "focusout", (event) => {
|
|
110
|
+
const name = event.target?.getAttribute?.("name")
|
|
111
|
+
if (!name || c.touched?.has(name) || !c.core.owns(event.target)) return
|
|
112
|
+
;(c.touched ??= new Set()).add(name)
|
|
113
|
+
if (c.root.querySelector?.("[data-reactive-show-after]")) syncShow(c)
|
|
114
|
+
})
|
|
106
115
|
seed(c, c.show)
|
|
107
116
|
}
|
|
108
117
|
|
|
@@ -441,6 +450,10 @@ function syncShow(c) {
|
|
|
441
450
|
// several bindings (and several DNF terms) reads exactly once. Scope-aware:
|
|
442
451
|
// a bare field `director` resolves as `[name="scope[director]"]` (issue #180).
|
|
443
452
|
const fieldValue = fieldResolver(c, owns)
|
|
453
|
+
// Bindings whose visibility flipped this pass and that declare transition
|
|
454
|
+
// work (issue #394) — run after the pass, so the `input` a clear dispatches
|
|
455
|
+
// re-syncs from fresh values instead of this pass's memo.
|
|
456
|
+
const moved = []
|
|
444
457
|
for (const el of c.root.querySelectorAll(SHOW_BINDING_SELECTOR)) {
|
|
445
458
|
if (!owns(el)) continue // a nested root's binding is its own controller's job
|
|
446
459
|
|
|
@@ -450,7 +463,19 @@ function syncShow(c) {
|
|
|
450
463
|
const payloadRaw = el.getAttribute("data-reactive-show")
|
|
451
464
|
if (payloadRaw !== null) {
|
|
452
465
|
const match = showPayloadMatches(parseShowCompound(payloadRaw), fieldValue)
|
|
453
|
-
if (match
|
|
466
|
+
if (match === null) continue
|
|
467
|
+
// after: (issue #396) keeps it hidden until its field has blurred once.
|
|
468
|
+
const after = el.getAttribute("data-reactive-show-after")
|
|
469
|
+
const visible = match && (after == null || !!c.touched?.has(wireName(after, scope)))
|
|
470
|
+
applyShowVisibility(el, visible, owns, scope)
|
|
471
|
+
// The previous visibility lives on this controller (absent on connect,
|
|
472
|
+
// kept by a morph), so first paint never counts as a change.
|
|
473
|
+
// Tracked for every binding, so a morph that drops the transition attrs
|
|
474
|
+
// and later restores them never compares against a stale value.
|
|
475
|
+
const was = (c.shown ??= new WeakMap()).get(el)
|
|
476
|
+
c.shown.set(el, visible)
|
|
477
|
+
const moves = SHOW_MOVES.some((name) => el.hasAttribute(`data-reactive-show-${name}`))
|
|
478
|
+
if (moves && was !== undefined && was !== visible) moved.push(el)
|
|
454
479
|
continue
|
|
455
480
|
}
|
|
456
481
|
|
|
@@ -470,6 +495,44 @@ function syncShow(c) {
|
|
|
470
495
|
syncMedia(c, fieldValue, owns)
|
|
471
496
|
syncShowTargets(c, fieldValue)
|
|
472
497
|
syncGroupTargets(c, fieldValue)
|
|
498
|
+
for (const el of moved) showMoved(c, el, owns, scope)
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// The transition attrs a show binding may declare (issue #394).
|
|
502
|
+
const SHOW_MOVES = ["clear", "focus", "scroll"]
|
|
503
|
+
|
|
504
|
+
// A binding just changed visibility (issue #394). Hidden: empty each clear:
|
|
505
|
+
// field with set_value's write (which announces only a real change), uncheck a
|
|
506
|
+
// checkbox or radio, skip a file input. Visible: scroll the section into view,
|
|
507
|
+
// then focus the first match of focus: inside the root.
|
|
508
|
+
function showMoved(c, el, owns, scope) {
|
|
509
|
+
if (el.hidden) {
|
|
510
|
+
let names = []
|
|
511
|
+
try {
|
|
512
|
+
names = JSON.parse(el.getAttribute("data-reactive-show-clear") ?? "[]")
|
|
513
|
+
} catch {}
|
|
514
|
+
// Compared by attribute, not a [name="…"] selector, so a name holding a
|
|
515
|
+
// `"` or `\` clears its field instead of throwing.
|
|
516
|
+
const wires = new Set((Array.isArray(names) ? names : []).map((name) => wireName(String(name), scope)))
|
|
517
|
+
for (const field of wires.size ? c.root.querySelectorAll("[name]") : []) {
|
|
518
|
+
if (!wires.has(field.getAttribute("name")) || !owns(field) || field.type === "file") continue
|
|
519
|
+
if (field.type === "checkbox" || field.type === "radio") {
|
|
520
|
+
if (field.checked) {
|
|
521
|
+
field.checked = false
|
|
522
|
+
fireInput(field)
|
|
523
|
+
}
|
|
524
|
+
} else c.core.setValue(field, "")
|
|
525
|
+
}
|
|
526
|
+
return
|
|
527
|
+
}
|
|
528
|
+
const scroll = el.getAttribute("data-reactive-show-scroll") === "true"
|
|
529
|
+
if (scroll) el.scrollIntoView?.({ block: "nearest" })
|
|
530
|
+
const focus = el.getAttribute("data-reactive-show-focus")
|
|
531
|
+
let target = null
|
|
532
|
+
try {
|
|
533
|
+
target = focus ? c.root.querySelector(focus) : null
|
|
534
|
+
} catch {}
|
|
535
|
+
target?.focus?.(scroll ? { preventScroll: true } : undefined)
|
|
473
536
|
}
|
|
474
537
|
|
|
475
538
|
// Toggle `hidden` (and, when the binding declares data-reactive-show-disable,
|
|
@@ -618,7 +681,11 @@ function showFieldValue(c, name, owns, scope) {
|
|
|
618
681
|
// "form"` resolves as `[name="form[director]"]`. A name already carrying a
|
|
619
682
|
// bracket (a raw wire name the author passed, like "ids[]") is used verbatim.
|
|
620
683
|
function namedSelector(name, scope) {
|
|
621
|
-
return `[name="${
|
|
684
|
+
return `[name="${wireName(name, scope)}"]`
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function wireName(name, scope) {
|
|
688
|
+
return scope && !name.includes("[") ? `${scope}[${name}]` : name
|
|
622
689
|
}
|
|
623
690
|
|
|
624
691
|
// The per-pass field resolver every DNF fold reads (show, enable, on-complete).
|
|
@@ -638,15 +705,17 @@ function fieldResolver(c, owns) {
|
|
|
638
705
|
}
|
|
639
706
|
|
|
640
707
|
// --- Media bindings (issue #373) ---------------------------------------------
|
|
641
|
-
// data-reactive-media='{"field","take"?,"match"?,"pending"?,"pool","label"?,"blank"?}'
|
|
708
|
+
// data-reactive-media='{"field","take"?,"match"?,"when"?,"pending"?,"pool","label"?,"blank"?}'
|
|
642
709
|
// on a preview <img>: the owned field's value (its first `take` characters, or
|
|
643
710
|
// all of it) is a key into `pool`, whose value is a SELECTOR for an <img>
|
|
644
711
|
// inside the root. The core's copyMedia copies that element's src, srcset and
|
|
645
712
|
// alt — a pool value is never assigned to anything. A key, selector or element
|
|
646
713
|
// that misses clears the preview; `label` gets the alt (or `blank`) via
|
|
647
|
-
// textContent. A key shorter than `take`,
|
|
648
|
-
// rejects,
|
|
649
|
-
//
|
|
714
|
+
// textContent. A key shorter than `take`, a key the anchored `match` source
|
|
715
|
+
// rejects, or a WHOLE field value the anchored `when` source rejects (issue
|
|
716
|
+
// #390 — tested before the pool lookup; the key stays the prefix) is PENDING
|
|
717
|
+
// (issue #380) and never gets `blank`: "keep" leaves the preview and label
|
|
718
|
+
// alone, the default clears both. The preview's
|
|
650
719
|
// data-reactive-media-state names the outcome (pending | hit | miss). An
|
|
651
720
|
// unowned field leaves the preview alone (the show default-deny); a malformed
|
|
652
721
|
// attr warns and is skipped.
|
|
@@ -655,12 +724,19 @@ const MEDIA_BINDING_SELECTOR = "[data-reactive-media]"
|
|
|
655
724
|
function syncMedia(c, fieldValue, owns) {
|
|
656
725
|
for (const el of c.root.querySelectorAll(MEDIA_BINDING_SELECTOR)) {
|
|
657
726
|
if (!owns(el)) continue
|
|
658
|
-
let wire, pattern
|
|
727
|
+
let wire, pattern, whole
|
|
659
728
|
try {
|
|
660
729
|
wire = JSON.parse(el.getAttribute("data-reactive-media"))
|
|
661
730
|
if (wire?.match != null) pattern = new RegExp(`^(?:${wire.match})$`)
|
|
731
|
+
if (wire?.when != null) whole = new RegExp(`^(?:${wire.when})$`)
|
|
662
732
|
} catch {}
|
|
663
|
-
if (
|
|
733
|
+
if (
|
|
734
|
+
typeof wire?.field !== "string" ||
|
|
735
|
+
!wire.pool ||
|
|
736
|
+
typeof wire.pool !== "object" ||
|
|
737
|
+
(wire.match != null && !pattern) ||
|
|
738
|
+
(wire.when != null && !whole)
|
|
739
|
+
) {
|
|
664
740
|
console.warn("[phlex-reactive] malformed data-reactive-media — skipped")
|
|
665
741
|
continue
|
|
666
742
|
}
|
|
@@ -669,7 +745,7 @@ function syncMedia(c, fieldValue, owns) {
|
|
|
669
745
|
// Characters (code points), as Ruby counts them — not UTF-16 code units.
|
|
670
746
|
const chars = wire.take > 0 ? [...value] : null
|
|
671
747
|
const key = chars ? chars.slice(0, wire.take).join("") : value
|
|
672
|
-
const pending = chars?.length < wire.take || pattern?.test(key) === false
|
|
748
|
+
const pending = chars?.length < wire.take || pattern?.test(key) === false || whole?.test(value) === false
|
|
673
749
|
if (pending && wire.pending === "keep") {
|
|
674
750
|
mediaState(el, "pending")
|
|
675
751
|
continue
|
|
@@ -707,7 +783,9 @@ function mediaMatches(c, selector) {
|
|
|
707
783
|
// (data-reactive-count), and the checked_* terms any condition can use —
|
|
708
784
|
// reactive_enable (data-reactive-enable) flips the element's own `disabled`
|
|
709
785
|
// from one. They re-sync with the show pass: on every input/change, on a
|
|
710
|
-
// morph, and when boxes are added or removed (observeGroups).
|
|
786
|
+
// morph, and when boxes are added or removed (observeGroups). A header with
|
|
787
|
+
// data-reactive-select-all-under (issue #398) is one branch of a tree: it owns
|
|
788
|
+
// the boxes of the name whose data-reactive-group is in its path.
|
|
711
789
|
const GROUP_BINDING_SELECTOR = "[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]"
|
|
712
790
|
|
|
713
791
|
// Whether the root holds any group binding (owned or not — a stray nested
|
|
@@ -717,15 +795,25 @@ function hasGroups(c) {
|
|
|
717
795
|
}
|
|
718
796
|
|
|
719
797
|
// The owned checkboxes of a group (a nested root's boxes are its own, #15).
|
|
720
|
-
|
|
721
|
-
|
|
798
|
+
// With `under` (a nested header, issue #398) only the boxes whose
|
|
799
|
+
// data-reactive-group is that path or below it, on whole segments.
|
|
800
|
+
function groupBoxes(c, name, owns, scope, under) {
|
|
801
|
+
return [...c.root.querySelectorAll(namedSelector(name, scope))].filter(
|
|
802
|
+
(el) => el.type === "checkbox" && owns(el) && (!under || inGroupPath(el.getAttribute("data-reactive-group"), under)),
|
|
803
|
+
)
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function inGroupPath(path, under) {
|
|
807
|
+
return path === under || !!path?.startsWith(`${under}.`)
|
|
722
808
|
}
|
|
723
809
|
|
|
724
810
|
// A header's edit ticks or unticks every owned box of its group (the header
|
|
725
811
|
// itself is never a member). The show listener syncs once afterwards.
|
|
726
812
|
function flipGroup(c, header) {
|
|
727
813
|
const group = header?.getAttribute?.("data-reactive-select-all")
|
|
728
|
-
if (group && c.core.owns(header))
|
|
814
|
+
if (group && c.core.owns(header)) {
|
|
815
|
+
setGroup(c, group, header.checked, header, header.getAttribute("data-reactive-select-all-under"))
|
|
816
|
+
}
|
|
729
817
|
}
|
|
730
818
|
|
|
731
819
|
// The check_group op (issue #342): set a root's group the way its header
|
|
@@ -745,9 +833,9 @@ export function checkGroup(root, group, checked) {
|
|
|
745
833
|
// on each one it flips so computes, shows and on-complete bindings see a real
|
|
746
834
|
// edit. The re-entrant events are skipped by the show listener while this
|
|
747
835
|
// runs (c.flipping); the caller syncs once afterwards.
|
|
748
|
-
function setGroup(c, group, checked, except) {
|
|
836
|
+
function setGroup(c, group, checked, except, under) {
|
|
749
837
|
const scope = c.root.getAttribute?.("data-reactive-scope") || null
|
|
750
|
-
const flipped = groupBoxes(c, group, c.core.ownership(), scope).filter((box) => box !== except && box.checked !== checked)
|
|
838
|
+
const flipped = groupBoxes(c, group, c.core.ownership(), scope, under).filter((box) => box !== except && box.checked !== checked)
|
|
751
839
|
// Every box first, then the events: a listener (a checked-count
|
|
752
840
|
// on_complete) must see the group's final count, never a half-flipped one.
|
|
753
841
|
for (const box of flipped) box.checked = checked
|
|
@@ -780,7 +868,8 @@ function syncGroups(c, fieldValue, owns, scope) {
|
|
|
780
868
|
}
|
|
781
869
|
const group = el.getAttribute("data-reactive-select-all")
|
|
782
870
|
if (group) {
|
|
783
|
-
const
|
|
871
|
+
const under = el.getAttribute("data-reactive-select-all-under")
|
|
872
|
+
const boxes = groupBoxes(c, group, owns, scope, under).filter((box) => box !== el)
|
|
784
873
|
const ticked = boxes.filter((box) => box.checked).length
|
|
785
874
|
el.checked = ticked > 0 && ticked === boxes.length
|
|
786
875
|
el.indeterminate = ticked > 0 && ticked < boxes.length
|
|
@@ -1487,6 +1576,9 @@ const SHOW_LENGTH_KEYS = ["len_eq", "len_gte", "len_gt", "len_lte", "len_lt"]
|
|
|
1487
1576
|
// ShowConditions::CHECKED_KEYS: how many owned boxes of a group are ticked.
|
|
1488
1577
|
const SHOW_CHECKED_KEYS = ["checked_eq", "checked_gte", "checked_gt", "checked_lte", "checked_lt"]
|
|
1489
1578
|
|
|
1579
|
+
// The digit-count keys (issue #396) — Ruby's CompareTerms::DIGITS_KEYS.
|
|
1580
|
+
const SHOW_DIGITS_KEYS = ["digits_eq", "digits_gte", "digits_lt", "digits_lte"]
|
|
1581
|
+
|
|
1490
1582
|
// Evaluate one count predicate (len_* or checked_*). A count is a TOTAL
|
|
1491
1583
|
// function (blank/absent → 0), so every field value is decidable — no
|
|
1492
1584
|
// fail-closed special case like the numeric thresholds ({ length: 0 }
|
|
@@ -1586,6 +1678,26 @@ function dnfTermMatches(term, fieldValue) {
|
|
|
1586
1678
|
const n = fieldValue(term.field, true)
|
|
1587
1679
|
return countPredicateMatches(checked, term[checked], Array.isArray(n) ? n.length : Number(n) || 0) === true
|
|
1588
1680
|
}
|
|
1681
|
+
// A same: term (issue #395) compares this field with ANOTHER owned field,
|
|
1682
|
+
// both as strings (an absent one is ""); fold lowercases ASCII A-Z only, the
|
|
1683
|
+
// exact replace Ruby's tr("A-Z", "a-z") does. negate is unless:'s flip.
|
|
1684
|
+
if (typeof term.same === "string") {
|
|
1685
|
+
const read = (name) => {
|
|
1686
|
+
const v = String(fieldValue(name) ?? "")
|
|
1687
|
+
return term.fold === true ? v.replace(/[A-Z]/g, (ch) => String.fromCharCode(ch.charCodeAt(0) + 32)) : v
|
|
1688
|
+
}
|
|
1689
|
+
return (read(term.field) === read(term.same)) !== (term.negate === true)
|
|
1690
|
+
}
|
|
1691
|
+
// A digits: term (issue #396): ASCII digits only, the count within every
|
|
1692
|
+
// digits_* bound, and the optional prefix; negate flips it. A malformed
|
|
1693
|
+
// literal is false either way (fail-closed, like Ruby).
|
|
1694
|
+
const digits = SHOW_DIGITS_KEYS.filter((key) => key in term)
|
|
1695
|
+
if (digits.length) {
|
|
1696
|
+
const v = String(fieldValue(term.field) ?? "")
|
|
1697
|
+
if (!digits.every((key) => Number.isInteger(term[key])) || (term.prefix != null && typeof term.prefix !== "string")) return false
|
|
1698
|
+
const ok = /^[0-9]*$/.test(v) && digits.every((key) => countPredicateMatches(key, term[key], v.length)) && v.startsWith(term.prefix ?? "")
|
|
1699
|
+
return ok !== (term.negate === true)
|
|
1700
|
+
}
|
|
1589
1701
|
// An absent owned field reads as "" — identical to the server evaluator
|
|
1590
1702
|
// (ShowConditions.match? treats a missing field as blank). This keeps the
|
|
1591
1703
|
// Ruby first-paint and the client live-toggle in exact agreement (the shared
|
|
@@ -1619,6 +1731,7 @@ function dnfGroupFields(groups) {
|
|
|
1619
1731
|
if (!Array.isArray(group)) continue
|
|
1620
1732
|
for (const term of group) {
|
|
1621
1733
|
if (term && typeof term === "object" && typeof term.field === "string") fields.add(term.field)
|
|
1734
|
+
if (typeof term?.same === "string") fields.add(term.same)
|
|
1622
1735
|
}
|
|
1623
1736
|
}
|
|
1624
1737
|
return fields.size > 0 ? [...fields] : null
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{confirmPredicate as se}from"phlex/reactive/confirm_predicate";var h=new WeakMap,q=new WeakMap;function p(e,r){let t=h.get(e);if(!t){if(h.set(e,t={root:e.element,core:r,nestedIndex:0}),t.root)q.set(t.root,t)}return t}function d(e,r,t){for(let o of r.split(" "))e.root.addEventListener?.(o,t),e.offs.push(()=>e.root.removeEventListener?.(o,t))}function m(e,r){d(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Fe(e,r){let t=p(e,r);t.offs=[],t.seeds=[];let o,n,i,a;(t.wire=()=>{if(!t.show&&de(t))t.show=(s)=>{if(t.flipping)return;if(s?.type==="input"||s?.type==="change")we(t,s.target);else t.groups=Ae(t),D(t);he(t)},d(t,"input change",t.show),m(t,t.show);if(!t.arm&&pe(t))d(t,"input change",(s)=>J(t,s)),m(t,t.arm=()=>{J(t,null),D(t)});if(!o&&(o=t.show||t.arm))d(t,"reset",()=>setTimeout(()=>{if(h.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(!n&&(n=S(t)))d(t,"input",(s)=>Ce(t,s)&&v(t)),m(t,()=>v(t));if(!i&&(i=C(t)))m(t,()=>Q(t));if(!a&&(a=ke(t)))d(t,"input change",(s)=>ee(t,s)),m(t,()=>E(t))})(),d(t,"keydown",(s)=>Pe(t,s)),d(t,"paste drop",(s)=>We(t,s)),d(t,"input",(s)=>Ge(t,s))}function Ke(e){let r=h.get(e);if(!r)return;h.delete(e),q.delete(r.root);for(let t of r.offs??[])t();r.groupObserver?.disconnect()}function He(e){let r=h.get(e);if(!r)return;for(let t of r.seeds)t();r.wire()}function y(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function ze(e,r,t){return ee(p(e,r),t)}function Ye(e,r,t){return ae(p(e,r),t)}var ce=/^#[A-Za-z_][\w-]*$/,P="[data-reactive-show-field], [data-reactive-show]";function le(e,r){let t=e.getAttribute("data-reactive-show-equals");if(t!==null)return r===t;let o=e.getAttribute("data-reactive-show-not");if(o!==null)return r!==o;let n=e.getAttribute("data-reactive-show-in");if(n!==null){try{let i=JSON.parse(n);if(Array.isArray(i))return i.includes(r)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(n)} — skipped`),null}for(let i of te){let a=e.getAttribute(`data-reactive-show-${i}`);if(a!==null)return oe(i,a,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function W(e){try{let r=JSON.parse(e);if(r&&typeof r==="object"&&!Array.isArray(r))return r}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(e)} — skipped`),null}function ue(e){try{let r=JSON.parse(e);if(Array.isArray(r)&&r.every((t)=>t&&typeof t==="object"&&Array.isArray(t.any)&&Array.isArray(t.ops)))return r}catch{}return console.warn(`[phlex-reactive] malformed reactive_on_complete payload ${JSON.stringify(e)} — skipped`),[]}function G(e,r){if(!e||typeof e!=="object")return null;let t=e.any;if(Array.isArray(t)&&(t.length===0||Array.isArray(t[0])))return b(t,r);return fe(e,r)}function fe(e,r){let t=Array.isArray(e.all)?"all":Array.isArray(e.any)?"any":null;if(!t)return null;let o=e[t];if(o.length===0)return null;let n=o.map((i)=>j(i,r));return t==="all"?n.every(Boolean):n.some(Boolean)}function w(e,r="show"){if(typeof e==="string"&&ce.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function de(e){if(e.root.getAttribute?.("data-reactive-show-targets"))return!0;if(e.root.getAttribute?.("data-reactive-group-targets"))return!0;let r=e.root.querySelectorAll?.(P)??[];for(let t of r)if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(x)??[])if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(H)??[])if(e.core.owns(t))return!0;return!1}function pe(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function ge(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:ue(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function J(e,r){let t=ge(e);if(!t.length)return;let o=K(e,e.core.ownership());t.forEach((n,i)=>{let a=b(n.any,o);if(a===null)return;let s=a&&!e.onCompleteStates[i]&&Boolean(r);if(e.onCompleteStates[i]=a,s)e.core.applyOps(n.ops,"@root")})}function he(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,o=K(e,r);for(let n of e.root.querySelectorAll(P)){if(!r(n))continue;let i=n.getAttribute("data-reactive-show");if(i!==null){let c=G(W(i),o);if(c!==null)T(n,c,r,t);continue}let a=n.getAttribute("data-reactive-show-field");if(!a)continue;let s=o(a);if(s===null)continue;let l=le(n,s);if(l===null)continue;T(n,l,r,t)}if(e.groups)Se(e,o,r,t);be(e,o,r),ye(e,o),xe(e,o)}function T(e,r,t,o){if(e.hidden=!r,e.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof e.querySelectorAll!=="function")return;for(let n of e.querySelectorAll("input[name], select[name], textarea[name]"))if(t(n))n.disabled=!r;if(e.name&&t(e))e.disabled=!r}function ye(e,r){let t=B(e);for(let[o,n]of Object.entries(t)){if(o.startsWith("#")){me(o,n,r);continue}if(!n||typeof n!=="object"||Array.isArray(n))continue;let i=r(o);if(i===null)continue;let a=(s,l)=>l?r(o,!0):i;for(let[s,l]of Object.entries(n)){if(!w(s))continue;let c;if(Array.isArray(l)){if(l.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${s} — skipped`);continue}c=l.every((u)=>j(u,a))}else{let u=ie(l,i);if(u===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${s} — skipped`);continue}c=u}for(let u of document.querySelectorAll(s))u.hidden=!c}}}function me(e,r,t){if(!w(e))return;let o=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,n=De(o);if(n===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(n.every((a)=>t(a)===null)&&!Ie(o))return;let i=b(o,t);if(i===null)return;for(let a of document.querySelectorAll(e))a.hidden=!i}function B(e,r="show",t="mode: { ... }, kind: { ... }"){let o=e.root.getAttribute?.(`data-reactive-${r}-targets`);if(!o)return{};try{let n=JSON.parse(o);if(n&&typeof n==="object"&&!Array.isArray(n))return n}catch{}return console.warn(`[phlex-reactive] malformed data-reactive-${r}-targets — ignored. `+`Did two reactive_${r}_targets calls collide on one root? Declare every entry in ONE call: reactive_${r}_targets(${t})`),{}}function ve(e,r,t,o){let n=!1,i=null;for(let a of e.root.querySelectorAll(F(r,o))){if(!t(a))continue;if(a.type==="checkbox")return a.checked?"true":"false";if(a.type==="radio"){if(a.checked)return a.value??"";n=!0;continue}i??=a}if(i)return i.value??"";return n?"":null}function F(e,r){return`[name="${r&&!e.includes("[")?`${r}[${e}]`:e}"]`}function K(e,r){let t=e.root.getAttribute?.("data-reactive-scope")||null,o=new Map;return(n,i)=>{let a=i?`#${n}`:n;if(!o.has(a))o.set(a,i?_(e,n,r,t).filter((s)=>s.checked).length:ve(e,n,r,t));return o.get(a)}}var H="[data-reactive-media]";function be(e,r,t){for(let o of e.root.querySelectorAll(H)){if(!t(o))continue;let n,i;try{if(n=JSON.parse(o.getAttribute("data-reactive-media")),n?.match!=null)i=new RegExp(`^(?:${n.match})$`)}catch{}if(typeof n?.field!=="string"||!n.pool||typeof n.pool!=="object"||n.match!=null&&!i){console.warn("[phlex-reactive] malformed data-reactive-media — skipped");continue}let a=r(n.field);if(a===null)continue;let s=n.take>0?[...a]:null,l=s?s.slice(0,n.take).join(""):a,c=s?.length<n.take||i?.test(l)===!1;if(c&&n.pending==="keep"){M(o,"pending");continue}let u=!c&&Object.hasOwn(n.pool,l)?L(e,n.pool[l])[0]:null,f=e.core.copyMedia(o,u??null);if(f===null)continue;if(M(o,c?"pending":f===!1?"miss":"hit"),typeof n.label!=="string")continue;let g=c?"":f===!1?String(n.blank??""):f;for(let A of L(e,n.label))if(A.textContent!==g)A.textContent=g}}function M(e,r){if(e.getAttribute("data-reactive-media-state")!==r)e.setAttribute("data-reactive-media-state",r)}function L(e,r){try{return r==="@root"?[]:e.core.opTargets({to:r})}catch{return[]}}var x="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function Ae(e){return!!e.root.querySelector?.(x)}function _(e,r,t,o){return[...e.root.querySelectorAll(F(r,o))].filter((n)=>n.type==="checkbox"&&t(n))}function we(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))z(e,t,r.checked,r)}function Ue(e,r,t){if(!r)return;let o=q.get(e)??{root:e,core:{ownership:()=>(n)=>n.closest('[data-controller~="reactive"]')===e}};z(o,r,t!==!1),o.show?.()}function z(e,r,t,o){let n=e.root.getAttribute?.("data-reactive-scope")||null,i=_(e,r,e.core.ownership(),n).filter((a)=>a!==o&&a.checked!==t);for(let a of i)a.checked=t;e.flipping=!0;try{for(let a of i)for(let s of["input","change"])a.dispatchEvent?.(new Event(s,{bubbles:!0}))}finally{e.flipping=!1}}function Se(e,r,t,o){for(let n of e.root.querySelectorAll(x)){if(!t(n))continue;let i=n.getAttribute("data-reactive-enable");if(i!==null){let l=G(W(i),r);if(l!==null)n.disabled=!l}let a=n.getAttribute("data-reactive-count");if(a){let l=String(r(a,!0));if(n.textContent!==l)n.textContent=l}let s=n.getAttribute("data-reactive-select-all");if(s){let l=_(e,s,t,o).filter((u)=>u!==n),c=l.filter((u)=>u.checked).length;n.checked=c>0&&c===l.length,n.indeterminate=c>0&&c<l.length}}}function xe(e,r){for(let[t,o]of Object.entries(B(e,"group",'"ids[]" => { ... }, "tags[]" => { ... }'))){if(!o||typeof o!=="object"||Array.isArray(o))continue;let n=String(r(t,!0));for(let a of Array.isArray(o.count)?o.count:[]){if(!w(a,"group"))continue;for(let s of document.querySelectorAll(a))if(s.textContent!==n)s.textContent=n}let i=o.enable&&typeof o.enable==="object"?o.enable:{};for(let[a,s]of Object.entries(i)){if(!w(a,"group"))continue;let l=b(s?.any,r);if(l===null){console.warn(`[phlex-reactive] malformed reactive_group_targets enable for ${a} — skipped`);continue}for(let c of document.querySelectorAll(a))c.disabled=!l}}}function D(e){if(e.groupObserver||typeof MutationObserver!=="function")return;let r=(n)=>e.root.getAttribute?.(`data-reactive-${n}`)?.includes("checked_");if(!e.root.getAttribute?.("data-reactive-group-targets")&&!e.root.querySelector?.(`${x}, [data-reactive-show*=checked_]`)&&!r("show-targets")&&!r("on-complete"))return;let o=(n)=>n.nodeType===1&&(n.matches('input[type="checkbox"]')||!!n.querySelector('input[type="checkbox"]'));e.groupObserver=new MutationObserver((n)=>{if(!n.some((i)=>[...i.addedNodes,...i.removedNodes].some(o)))return;e.show?.(),e.arm?.()}),e.groupObserver.observe(e.root,{childList:!0,subtree:!0})}function S(e){return!!(e.root.getAttribute?.("data-reactive-filter-input")&&e.root.getAttribute?.("data-reactive-filter-option"))}function Ce(e,r){let t=e.root.getAttribute("data-reactive-filter-input");return!!t&&typeof r.target?.matches==="function"&&r.target.matches(t)}function v(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.root.getAttribute("data-reactive-filter-input"),t=e.root.getAttribute("data-reactive-filter-option");if(!r||!t)return;let o=e.core.ownership(),n=[...e.root.querySelectorAll(r)].find(o);if(!n)return;let i=(n.value??"").trim().toLowerCase(),a=0;for(let c of e.root.querySelectorAll(t)){if(!o(c))continue;let u=(c.getAttribute("data-reactive-filter-text")??c.textContent??"").toLowerCase(),f=c.hasAttribute?.("data-reactive-tags-selected")||i!==""&&!u.includes(i);if(c.hidden=f,f)c.removeAttribute("data-reactive-highlighted");else a++}let s=e.root.getAttribute("data-reactive-filter-group");if(s)for(let c of e.root.querySelectorAll(s)){if(!o(c))continue;let u=[...c.querySelectorAll(t)].filter(o);if(u.length===0)continue;c.hidden=u.every((f)=>f.hidden)}let l=e.root.getAttribute("data-reactive-filter-empty");if(l){for(let c of e.root.querySelectorAll(l))if(o(c))c.hidden=a>0}}function C(e){return!!e.root.getAttribute?.("data-reactive-tags-field")}function ke(e){if(typeof e.root?.querySelector!=="function")return!1;return!!e.root.querySelector("[data-reactive-nested-json]")}function N(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-tags-field");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function O(e){let r=new Set,t=[];for(let o of String(e.value??"").split(",")){let n=o.trim();if(n===""||r.has(n.toLowerCase()))continue;r.add(n.toLowerCase()),t.push(n)}return t}function Y(e,r){let t=N(e);if(!t)return!1;let o=O(t),n=new Set(o.map((a)=>a.toLowerCase())),i=!1;for(let a of r){let s=String(a??"").trim();if(s===""||n.has(s.toLowerCase()))continue;n.add(s.toLowerCase()),o.push(s),i=!0}if(i)U(e,t,o);return i}function U(e,r,t){r.value=t.join(","),y(r),Q(e)}function qe(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-filter-input");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function Q(e){let r=N(e);if(!r)return;let t=O(r),o=e.core.ownership();_e(e,t,o),Ne(e,t,o)}function _e(e,r,t){let o=[...e.root.querySelectorAll("[data-reactive-tags-list]")].find(t);if(!o)return;let i=[...e.root.querySelectorAll("[data-reactive-tags-template]")].find(t)?.content?.firstElementChild;if(!i){if(!e.tagsWarnedTemplate)console.warn("[phlex-reactive] reactive_tags: no chip <template data-reactive-tags-template> found in this root — "+"chips will not render (the hidden field still updates). Add a template with a [data-reactive-tag-text] node and a reactive_tags_remove button."),e.tagsWarnedTemplate=!0;return}while(o.firstChild)o.removeChild(o.firstChild);for(let a of r){let s=i.cloneNode(!0);s.setAttribute?.("data-reactive-tag",a);let l=s.matches?.("[data-reactive-tag-text]")?s:(s.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(l)l.textContent=a;let c=[...s.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(s.matches?.('[data-action*="reactive#tagsRemove"]'))c.push(s);for(let u of c)u.setAttribute?.("data-reactive-tag-param",a);o.appendChild(s)}}function Ne(e,r,t){let o=new Set(r.map((n)=>n.toLowerCase()));for(let n of e.root.querySelectorAll("[role=option]")){if(!t(n))continue;let i=n.getAttribute?.("data-reactive-tag-param");if(!i)continue;if(o.has(i.toLowerCase()))n.setAttribute("data-reactive-tags-selected","true"),n.hidden=!0,n.removeAttribute?.("data-reactive-highlighted");else if(n.hasAttribute?.("data-reactive-tags-selected")){if(n.removeAttribute("data-reactive-tags-selected"),!S(e))n.hidden=!1}}if(S(e))v(e)}function Oe(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function Ee(e,r){let t=[e,...e.querySelectorAll?.("*")??[]];for(let o of t)for(let n of["name","id","for"]){let i=o.getAttribute?.(n);if(i&&i.includes("NEW_ROW"))o.setAttribute?.(n,i.replaceAll("NEW_ROW",String(r)))}}function $e(e,r){if(e.nestedWarned)return;console.warn(`[phlex-reactive] nested rows: no owned [data-reactive-nested-list="${r}"] container + <template data-reactive-nested-template="${r}"> pair found in this root — the add `+"trigger did nothing. Render both inside the same reactive root (reactive_nested_list / reactive_nested_template)."),e.nestedWarned=!0}function je(e,r,t,o){if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}if(!n||typeof n!=="object")return null;let i=e.core.ownership(),a=[...r.querySelectorAll?.("input, select, textarea")??[]],s=[];for(let[l,c]of Object.entries(n)){let u=[...e.root.querySelectorAll?.(c)??[]].find(i);if(!u)continue;let f=a.find((g)=>V(g.getAttribute?.("name"))===l);if(!f)continue;Re(f,u),s.push(u)}if(o)for(let l of s)Je(l);return s[0]??null}function Re(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:k(r)!=="";else e.value=k(r);y(e)}function Je(e){if(e.type==="checkbox")e.checked=!1;else e.value="";y(e)}function Te(e,r){if(!e.includes("%{"))return e;return e.replace(/%\{(\w+)\}/g,(t,o)=>Object.prototype.hasOwnProperty.call(r,o)?r[o]:t)}function I(e,r){let t=[...r.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(t)t.value="1",y(t),r.hidden=!0;else r.parentNode?.removeChild?.(r);E(e)}function E(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership();for(let t of[...e.root.querySelectorAll("[data-reactive-nested-json]")].filter(r))X(e,t.getAttribute("data-reactive-nested-json"))}function Me(e,r){let t=r.getAttribute?.("data-reactive-nested-json-field");if(!t)return null;let o=e.core.ownership();return[...e.root.querySelectorAll(t)].find(o)??null}function Z(e,r){let t={},o=e.core.ownership();for(let n of[...r.querySelectorAll?.("input, select, textarea")??[]]){if(n.matches(":disabled")||n.type==="radio"&&!n.checked||!o(n))continue;let i=V(n.getAttribute?.("name"));if(i===null||i==="_destroy")continue;t[i]=k(n)}return t}function V(e){if(!e)return null;let r=e.match(/\[([^\][]+)\]$/);return r?r[1]:e}function k(e){if(e.type==="checkbox")return e.checked?e.value||"on":"";return e.value??""}function X(e,r){let t=e.core.ownership(),o=[...e.root.querySelectorAll(`[data-reactive-nested-list="${r}"]`)].find(t);if(!o)return;let n=Me(e,o);if(!n)return;let i=[];for(let s of[...o.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!t(s)||s.hidden)continue;i.push(Z(e,s))}let a=JSON.stringify(i);if(n.value===a)return;n.value=a,y(n)}function Qe(e,r,t){let o=p(e,r);if(!C(o))return;if(t?.defaultPrevented)return;if(o.core.listnavOptions(t).some((a)=>a.hasAttribute?.("data-reactive-highlighted")))return;t?.preventDefault?.();let n=t?.currentTarget??t?.target;if(!n)return;if(!Y(o,String(n.value??"").split(",")))return;if(n.value="",S(o))v(o)}function Ze(e,r,t){let o=p(e,r);if(!C(o))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!Y(o,[i]))return;let a=qe(o);if(!a)return;a.value="",v(o),a.focus?.()}function Ve(e,r,t){let o=p(e,r);if(!C(o))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let a=N(o);if(!a)return;let s=O(a),l=s.filter((c)=>c.toLowerCase()!==i.toLowerCase());if(l.length===s.length)return;U(o,a,l)}function Xe(e,r,t){let o=p(e,r);t?.preventDefault?.();let n=t?.currentTarget??t?.target,i=n?.getAttribute?.("data-reactive-association-param");if(!i)return;if(typeof o.root?.querySelectorAll!=="function")return;let a=o.core.ownership(),s=[...o.root.querySelectorAll(`[data-reactive-nested-list="${i}"]`)].find(a),c=[...o.root.querySelectorAll(`[data-reactive-nested-template="${i}"]`)].find(a)?.content?.firstElementChild;if(!s||!c){$e(o,i);return}let u=c.cloneNode(!0);Ee(u,Oe(o)),s.appendChild(u);let f=n?.getAttribute?.("data-reactive-nested-from-param"),g=n?.getAttribute?.("data-reactive-nested-clear-param")==="true",A=je(o,u,f,g);if(f)A?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(s.getAttribute?.("data-reactive-nested-json")===i)X(o,i)}function et(e,r,t){let o=p(e,r);t?.preventDefault?.();let n=t?.currentTarget??t?.target,i=n?.closest?.("[data-reactive-nested-row]");if(!i)return;if(i.closest?.('[data-controller~="reactive"]')!==o.root)return;let a=n?.getAttribute?.("data-reactive-confirm-param"),s=n?.getAttribute?.("data-reactive-confirm-when-param"),l=a||(s?ae(o,s):null);if(!l)return I(o,i);let c=Z(o,i),u=Te(l,c);return o.core.confirm(u,{el:n,row:i,fields:c}).then((f)=>{if(f)I(o,i)})}function ee(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;E(e)}var te=["gte","gt","lte","lt"],Le=["len_eq","len_gte","len_gt","len_lte","len_lt"],re=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"];function ne(e,r,t){if(!Number.isInteger(r))return console.warn(`[phlex-reactive] reactive_show ${e}: needs an integer literal, got ${JSON.stringify(r)} — skipped`),null;switch(e.slice(e.indexOf("_")+1)){case"eq":return t===r;case"gte":return t>=r;case"gt":return t>r;case"lte":return t<=r;case"lt":return t<r;default:return null}}function oe(e,r,t){let o=Number(r);if(Number.isNaN(o))return console.warn(`[phlex-reactive] reactive_show ${e}: needs a numeric literal, got ${JSON.stringify(r)} — skipped`),null;let n=t==null?"":String(t).trim(),i=n===""?NaN:Number(n);if(Number.isNaN(i))return!1;switch(e){case"gte":return i>=o;case"gt":return i>o;case"lte":return i<=o;case"lt":return i<o;default:return null}}function ie(e,r){if(!e||typeof e!=="object")return null;if(typeof e.equals==="string")return r===e.equals;if(typeof e.not==="string")return r!==e.not;if(Array.isArray(e.in))return e.in.includes(r);for(let t of te)if(t in e)return oe(t,e[t],r);for(let t of Le)if(t in e)return ne(t,e[t],[...String(r??"")].length);return null}function j(e,r){if(!e||typeof e!=="object"||typeof e.field!=="string")return!1;let t=re.find((n)=>(n in e));if(t){let n=r(e.field,!0);return ne(t,e[t],Array.isArray(n)?n.length:Number(n)||0)===!0}let o=r(e.field)??"";return ie(e,o)===!0}function b(e,r){if(!Array.isArray(e)||e.length===0)return null;return e.some((t)=>Array.isArray(t)&&t.length>0&&t.every((o)=>j(o,r)))}function De(e){if(!Array.isArray(e)||e.length===0)return null;let r=new Set;for(let t of e){if(!Array.isArray(t))continue;for(let o of t)if(o&&typeof o==="object"&&typeof o.field==="string")r.add(o.field)}return r.size>0?[...r]:null}function Ie(e){return e.flat().every((r)=>re.some((t)=>(t in Object(r))))}function ae(e,r){let t=r;if(typeof r==="string")try{t=JSON.parse(r)}catch{return console.warn(`[phlex-reactive] malformed conditional confirm payload ${JSON.stringify(r)} — skipped`),null}if(!t||typeof t!=="object")return null;let{fields:o}=e.core.collectFields(),n=(a)=>o[a],i;if(typeof t.predicate==="string"){let a=se(t.predicate);if(!a)return console.warn(`[phlex-reactive] confirm predicate "${t.predicate}" is not registered — proceeding without a dialog (register it with setConfirmPredicate)`),null;i=!!a(o)}else i=b(t.groups?.any,n)===!0;return i?t.message:null}function R(e,r){let t=r.target?.closest?.("[data-reactive-editable]");return t&&e.core.owns(t)?t:null}function Pe(e,r){let t=R(e,r);if(!t||r.isComposing||r.keyCode===229)return;if(r.key==="Enter"){let o=t.getAttribute("data-reactive-editable-enter");if(t.getAttribute("data-reactive-editable")==="multi"&&(o==null||r.shiftKey))return;if(r.preventDefault(),o==="submit")t.closest("form")?.requestSubmit();else if(o)e.core.applyOps(JSON.parse(o),"@root")}else if(r.key==="Escape"&&t.hasAttribute("data-reactive-editable-escape"))r.preventDefault(),t.textContent=e.core.served(t),y(t),t.blur()}function We(e,r){let t=R(e,r),o=t?.getAttribute("data-reactive-editable")!=="multi",n=(r.clipboardData??r.dataTransfer)?.getData("text/plain");if(!t||n==null||e.core.plain()&&!(o&&/[\r\n]/.test(n)))return;if(r.preventDefault(),o)n=n.replace(/\r?\n|\r/g," ");t.focus(),document.execCommand("insertText",!1,n)}function Ge(e,r){let t=R(e,r);if(t?.firstChild&&e.core.text(t)==="")t.replaceChildren()}export{Ue as checkGroup,Ye as confirmMessage,Fe as connect,Ke as disconnect,Xe as nestedAdd,et as nestedRemove,He as reseed,ze as syncNestedJson,Qe as tagsAdd,Ze as tagsPick,Ve as tagsRemove};
|
|
1
|
+
import{confirmPredicate as fe}from"phlex/reactive/confirm_predicate";var v=new WeakMap,N=new WeakMap;function g(e,r){let t=v.get(e);if(!t){if(v.set(e,t={root:e.element,core:r,nestedIndex:0}),t.root)N.set(t.root,t)}return t}function p(e,r,t){for(let n of r.split(" "))e.root.addEventListener?.(n,t),e.offs.push(()=>e.root.removeEventListener?.(n,t))}function m(e,r){p(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Qe(e,r){let t=g(e,r);t.offs=[],t.seeds=[];let n,o,i,s;(t.wire=()=>{if(!t.show&&ye(t))t.show=(a)=>{if(t.flipping)return;if(a?.type==="input"||a?.type==="change")qe(t,a.target);else t.groups=_e(t),G(t);D(t)},p(t,"input change",t.show),p(t,"focusout",(a)=>{let l=a.target?.getAttribute?.("name");if(!l||t.touched?.has(l)||!t.core.owns(a.target))return;if((t.touched??=new Set).add(l),t.root.querySelector?.("[data-reactive-show-after]"))D(t)}),m(t,t.show);if(!t.arm&&ve(t))p(t,"input change",(a)=>I(t,a)),m(t,t.arm=()=>{I(t,null),G(t)});if(!n&&(n=t.show||t.arm))p(t,"reset",()=>setTimeout(()=>{if(v.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(!o&&(o=S(t)))p(t,"input",(a)=>Ee(t,a)&&b(t)),m(t,()=>b(t));if(!i&&(i=k(t)))m(t,()=>ee(t));if(!s&&(s=$e(t)))p(t,"input change",(a)=>oe(t,a)),m(t,()=>M(t))})(),p(t,"keydown",(a)=>ze(t,a)),p(t,"paste drop",(a)=>Ye(t,a)),p(t,"input",(a)=>Ue(t,a))}function Ve(e){let r=v.get(e);if(!r)return;v.delete(e),N.delete(r.root);for(let t of r.offs??[])t();r.groupObserver?.disconnect()}function Xe(e){let r=v.get(e);if(!r)return;for(let t of r.seeds)t();r.wire()}function y(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function et(e,r,t){return oe(g(e,r),t)}function tt(e,r,t){return le(g(e,r),t)}var de=/^#[A-Za-z_][\w-]*$/,F="[data-reactive-show-field], [data-reactive-show]";function pe(e,r){let t=e.getAttribute("data-reactive-show-equals");if(t!==null)return r===t;let n=e.getAttribute("data-reactive-show-not");if(n!==null)return r!==n;let o=e.getAttribute("data-reactive-show-in");if(o!==null){try{let i=JSON.parse(o);if(Array.isArray(i))return i.includes(r)}catch{}return console.warn(`[phlex-reactive] malformed reactive_show in: list ${JSON.stringify(o)} — skipped`),null}for(let i of ie){let s=e.getAttribute(`data-reactive-show-${i}`);if(s!==null)return se(i,s,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function H(e){try{let r=JSON.parse(e);if(r&&typeof r==="object"&&!Array.isArray(r))return r}catch{}return console.warn(`[phlex-reactive] malformed compound reactive_show payload ${JSON.stringify(e)} — skipped`),null}function ge(e){try{let r=JSON.parse(e);if(Array.isArray(r)&&r.every((t)=>t&&typeof t==="object"&&Array.isArray(t.any)&&Array.isArray(t.ops)))return r}catch{}return console.warn(`[phlex-reactive] malformed reactive_on_complete payload ${JSON.stringify(e)} — skipped`),[]}function K(e,r){if(!e||typeof e!=="object")return null;let t=e.any;if(Array.isArray(t)&&(t.length===0||Array.isArray(t[0])))return A(t,r);return he(e,r)}function he(e,r){let t=Array.isArray(e.all)?"all":Array.isArray(e.any)?"any":null;if(!t)return null;let n=e[t];if(n.length===0)return null;let o=n.map((i)=>J(i,r));return t==="all"?o.every(Boolean):o.some(Boolean)}function w(e,r="show"){if(typeof e==="string"&&de.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function ye(e){if(e.root.getAttribute?.("data-reactive-show-targets"))return!0;if(e.root.getAttribute?.("data-reactive-group-targets"))return!0;let r=e.root.querySelectorAll?.(F)??[];for(let t of r)if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(x)??[])if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(Z)??[])if(e.core.owns(t))return!0;return!1}function ve(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function me(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:ge(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function I(e,r){let t=me(e);if(!t.length)return;let n=U(e,e.core.ownership());t.forEach((o,i)=>{let s=A(o.any,n);if(s===null)return;let a=s&&!e.onCompleteStates[i]&&Boolean(r);if(e.onCompleteStates[i]=s,a)e.core.applyOps(o.ops,"@root")})}function D(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,n=U(e,r),o=[];for(let i of e.root.querySelectorAll(F)){if(!r(i))continue;let s=i.getAttribute("data-reactive-show");if(s!==null){let u=K(H(s),n);if(u===null)continue;let f=i.getAttribute("data-reactive-show-after"),d=u&&(f==null||!!e.touched?.has(O(f,t)));L(i,d,r,t);let h=(e.shown??=new WeakMap).get(i);if(e.shown.set(i,d),be.some((ue)=>i.hasAttribute(`data-reactive-show-${ue}`))&&h!==void 0&&h!==d)o.push(i);continue}let a=i.getAttribute("data-reactive-show-field");if(!a)continue;let l=n(a);if(l===null)continue;let c=pe(i,l);if(c===null)continue;L(i,c,r,t)}if(e.groups)Ne(e,n,r,t);ke(e,n,r),we(e,n),Oe(e,n);for(let i of o)Ae(e,i,r,t)}var be=["clear","focus","scroll"];function Ae(e,r,t,n){if(r.hidden){let a=[];try{a=JSON.parse(r.getAttribute("data-reactive-show-clear")??"[]")}catch{}let l=new Set((Array.isArray(a)?a:[]).map((c)=>O(String(c),n)));for(let c of l.size?e.root.querySelectorAll("[name]"):[]){if(!l.has(c.getAttribute("name"))||!t(c)||c.type==="file")continue;if(c.type==="checkbox"||c.type==="radio"){if(c.checked)c.checked=!1,y(c)}else e.core.setValue(c,"")}return}let o=r.getAttribute("data-reactive-show-scroll")==="true";if(o)r.scrollIntoView?.({block:"nearest"});let i=r.getAttribute("data-reactive-show-focus"),s=null;try{s=i?e.root.querySelector(i):null}catch{}s?.focus?.(o?{preventScroll:!0}:void 0)}function L(e,r,t,n){if(e.hidden=!r,e.getAttribute("data-reactive-show-disable")!=="true")return;if(typeof e.querySelectorAll!=="function")return;for(let o of e.querySelectorAll("input[name], select[name], textarea[name]"))if(t(o))o.disabled=!r;if(e.name&&t(e))e.disabled=!r}function we(e,r){let t=z(e);for(let[n,o]of Object.entries(t)){if(n.startsWith("#")){Se(n,o,r);continue}if(!o||typeof o!=="object"||Array.isArray(o))continue;let i=r(n);if(i===null)continue;let s=(a,l)=>l?r(n,!0):i;for(let[a,l]of Object.entries(o)){if(!w(a))continue;let c;if(Array.isArray(l)){if(l.length===0){console.warn(`[phlex-reactive] malformed reactive_show_targets group for ${a} — skipped`);continue}c=l.every((u)=>J(u,s))}else{let u=ce(l,i);if(u===null){console.warn(`[phlex-reactive] malformed reactive_show_targets predicate for ${a} — skipped`);continue}c=u}for(let u of document.querySelectorAll(a))u.hidden=!c}}}function Se(e,r,t){if(!w(e))return;let n=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,o=He(n);if(o===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(o.every((s)=>t(s)===null)&&!Ke(n))return;let i=A(n,t);if(i===null)return;for(let s of document.querySelectorAll(e))s.hidden=!i}function z(e,r="show",t="mode: { ... }, kind: { ... }"){let n=e.root.getAttribute?.(`data-reactive-${r}-targets`);if(!n)return{};try{let o=JSON.parse(n);if(o&&typeof o==="object"&&!Array.isArray(o))return o}catch{}return console.warn(`[phlex-reactive] malformed data-reactive-${r}-targets — ignored. `+`Did two reactive_${r}_targets calls collide on one root? Declare every entry in ONE call: reactive_${r}_targets(${t})`),{}}function xe(e,r,t,n){let o=!1,i=null;for(let s of e.root.querySelectorAll(Y(r,n))){if(!t(s))continue;if(s.type==="checkbox")return s.checked?"true":"false";if(s.type==="radio"){if(s.checked)return s.value??"";o=!0;continue}i??=s}if(i)return i.value??"";return o?"":null}function Y(e,r){return`[name="${O(e,r)}"]`}function O(e,r){return r&&!e.includes("[")?`${r}[${e}]`:e}function U(e,r){let t=e.root.getAttribute?.("data-reactive-scope")||null,n=new Map;return(o,i)=>{let s=i?`#${o}`:o;if(!n.has(s))n.set(s,i?E(e,o,r,t).filter((a)=>a.checked).length:xe(e,o,r,t));return n.get(s)}}var Z="[data-reactive-media]";function ke(e,r,t){for(let n of e.root.querySelectorAll(Z)){if(!t(n))continue;let o,i,s;try{if(o=JSON.parse(n.getAttribute("data-reactive-media")),o?.match!=null)i=new RegExp(`^(?:${o.match})$`);if(o?.when!=null)s=new RegExp(`^(?:${o.when})$`)}catch{}if(typeof o?.field!=="string"||!o.pool||typeof o.pool!=="object"||o.match!=null&&!i||o.when!=null&&!s){console.warn("[phlex-reactive] malformed data-reactive-media — skipped");continue}let a=r(o.field);if(a===null)continue;let l=o.take>0?[...a]:null,c=l?l.slice(0,o.take).join(""):a,u=l?.length<o.take||i?.test(c)===!1||s?.test(a)===!1;if(u&&o.pending==="keep"){W(n,"pending");continue}let f=!u&&Object.hasOwn(o.pool,c)?P(e,o.pool[c])[0]:null,d=e.core.copyMedia(n,f??null);if(d===null)continue;if(W(n,u?"pending":d===!1?"miss":"hit"),typeof o.label!=="string")continue;let h=u?"":d===!1?String(o.blank??""):d;for(let _ of P(e,o.label))if(_.textContent!==h)_.textContent=h}}function W(e,r){if(e.getAttribute("data-reactive-media-state")!==r)e.setAttribute("data-reactive-media-state",r)}function P(e,r){try{return r==="@root"?[]:e.core.opTargets({to:r})}catch{return[]}}var x="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function _e(e){return!!e.root.querySelector?.(x)}function E(e,r,t,n,o){return[...e.root.querySelectorAll(Y(r,n))].filter((i)=>i.type==="checkbox"&&t(i)&&(!o||Ce(i.getAttribute("data-reactive-group"),o)))}function Ce(e,r){return e===r||!!e?.startsWith(`${r}.`)}function qe(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))Q(e,t,r.checked,r,r.getAttribute("data-reactive-select-all-under"))}function rt(e,r,t){if(!r)return;let n=N.get(e)??{root:e,core:{ownership:()=>(o)=>o.closest('[data-controller~="reactive"]')===e}};Q(n,r,t!==!1),n.show?.()}function Q(e,r,t,n,o){let i=e.root.getAttribute?.("data-reactive-scope")||null,s=E(e,r,e.core.ownership(),i,o).filter((a)=>a!==n&&a.checked!==t);for(let a of s)a.checked=t;e.flipping=!0;try{for(let a of s)for(let l of["input","change"])a.dispatchEvent?.(new Event(l,{bubbles:!0}))}finally{e.flipping=!1}}function Ne(e,r,t,n){for(let o of e.root.querySelectorAll(x)){if(!t(o))continue;let i=o.getAttribute("data-reactive-enable");if(i!==null){let l=K(H(i),r);if(l!==null)o.disabled=!l}let s=o.getAttribute("data-reactive-count");if(s){let l=String(r(s,!0));if(o.textContent!==l)o.textContent=l}let a=o.getAttribute("data-reactive-select-all");if(a){let l=o.getAttribute("data-reactive-select-all-under"),c=E(e,a,t,n,l).filter((f)=>f!==o),u=c.filter((f)=>f.checked).length;o.checked=u>0&&u===c.length,o.indeterminate=u>0&&u<c.length}}}function Oe(e,r){for(let[t,n]of Object.entries(z(e,"group",'"ids[]" => { ... }, "tags[]" => { ... }'))){if(!n||typeof n!=="object"||Array.isArray(n))continue;let o=String(r(t,!0));for(let s of Array.isArray(n.count)?n.count:[]){if(!w(s,"group"))continue;for(let a of document.querySelectorAll(s))if(a.textContent!==o)a.textContent=o}let i=n.enable&&typeof n.enable==="object"?n.enable:{};for(let[s,a]of Object.entries(i)){if(!w(s,"group"))continue;let l=A(a?.any,r);if(l===null){console.warn(`[phlex-reactive] malformed reactive_group_targets enable for ${s} — skipped`);continue}for(let c of document.querySelectorAll(s))c.disabled=!l}}}function G(e){if(e.groupObserver||typeof MutationObserver!=="function")return;let r=(o)=>e.root.getAttribute?.(`data-reactive-${o}`)?.includes("checked_");if(!e.root.getAttribute?.("data-reactive-group-targets")&&!e.root.querySelector?.(`${x}, [data-reactive-show*=checked_]`)&&!r("show-targets")&&!r("on-complete"))return;let n=(o)=>o.nodeType===1&&(o.matches('input[type="checkbox"]')||!!o.querySelector('input[type="checkbox"]'));e.groupObserver=new MutationObserver((o)=>{if(!o.some((i)=>[...i.addedNodes,...i.removedNodes].some(n)))return;e.show?.(),e.arm?.()}),e.groupObserver.observe(e.root,{childList:!0,subtree:!0})}function S(e){return!!(e.root.getAttribute?.("data-reactive-filter-input")&&e.root.getAttribute?.("data-reactive-filter-option"))}function Ee(e,r){let t=e.root.getAttribute("data-reactive-filter-input");return!!t&&typeof r.target?.matches==="function"&&r.target.matches(t)}function b(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.root.getAttribute("data-reactive-filter-input"),t=e.root.getAttribute("data-reactive-filter-option");if(!r||!t)return;let n=e.core.ownership(),o=[...e.root.querySelectorAll(r)].find(n);if(!o)return;let i=(o.value??"").trim().toLowerCase(),s=0;for(let c of e.root.querySelectorAll(t)){if(!n(c))continue;let u=(c.getAttribute("data-reactive-filter-text")??c.textContent??"").toLowerCase(),f=c.hasAttribute?.("data-reactive-tags-selected")||i!==""&&!u.includes(i);if(c.hidden=f,f)c.removeAttribute("data-reactive-highlighted");else s++}let a=e.root.getAttribute("data-reactive-filter-group");if(a)for(let c of e.root.querySelectorAll(a)){if(!n(c))continue;let u=[...c.querySelectorAll(t)].filter(n);if(u.length===0)continue;c.hidden=u.every((f)=>f.hidden)}let l=e.root.getAttribute("data-reactive-filter-empty");if(l){for(let c of e.root.querySelectorAll(l))if(n(c))c.hidden=s>0}}function k(e){return!!e.root.getAttribute?.("data-reactive-tags-field")}function $e(e){if(typeof e.root?.querySelector!=="function")return!1;return!!e.root.querySelector("[data-reactive-nested-json]")}function j(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-tags-field");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function R(e){let r=new Set,t=[];for(let n of String(e.value??"").split(",")){let o=n.trim();if(o===""||r.has(o.toLowerCase()))continue;r.add(o.toLowerCase()),t.push(o)}return t}function V(e,r){let t=j(e);if(!t)return!1;let n=R(t),o=new Set(n.map((s)=>s.toLowerCase())),i=!1;for(let s of r){let a=String(s??"").trim();if(a===""||o.has(a.toLowerCase()))continue;o.add(a.toLowerCase()),n.push(a),i=!0}if(i)X(e,t,n);return i}function X(e,r,t){r.value=t.join(","),y(r),ee(e)}function je(e){if(typeof e.root?.querySelectorAll!=="function")return null;let r=e.root.getAttribute("data-reactive-filter-input");if(!r)return null;let t=e.core.ownership();return[...e.root.querySelectorAll(r)].find(t)??null}function ee(e){let r=j(e);if(!r)return;let t=R(r),n=e.core.ownership();Re(e,t,n),Me(e,t,n)}function Re(e,r,t){let n=[...e.root.querySelectorAll("[data-reactive-tags-list]")].find(t);if(!n)return;let i=[...e.root.querySelectorAll("[data-reactive-tags-template]")].find(t)?.content?.firstElementChild;if(!i){if(!e.tagsWarnedTemplate)console.warn("[phlex-reactive] reactive_tags: no chip <template data-reactive-tags-template> found in this root — "+"chips will not render (the hidden field still updates). Add a template with a [data-reactive-tag-text] node and a reactive_tags_remove button."),e.tagsWarnedTemplate=!0;return}while(n.firstChild)n.removeChild(n.firstChild);for(let s of r){let a=i.cloneNode(!0);a.setAttribute?.("data-reactive-tag",s);let l=a.matches?.("[data-reactive-tag-text]")?a:(a.querySelectorAll?.("[data-reactive-tag-text]")??[])[0];if(l)l.textContent=s;let c=[...a.querySelectorAll?.('[data-action*="reactive#tagsRemove"]')??[]];if(a.matches?.('[data-action*="reactive#tagsRemove"]'))c.push(a);for(let u of c)u.setAttribute?.("data-reactive-tag-param",s);n.appendChild(a)}}function Me(e,r,t){let n=new Set(r.map((o)=>o.toLowerCase()));for(let o of e.root.querySelectorAll("[role=option]")){if(!t(o))continue;let i=o.getAttribute?.("data-reactive-tag-param");if(!i)continue;if(n.has(i.toLowerCase()))o.setAttribute("data-reactive-tags-selected","true"),o.hidden=!0,o.removeAttribute?.("data-reactive-highlighted");else if(o.hasAttribute?.("data-reactive-tags-selected")){if(o.removeAttribute("data-reactive-tags-selected"),!S(e))o.hidden=!1}}if(S(e))b(e)}function Je(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function Te(e,r){let t=[e,...e.querySelectorAll?.("*")??[]];for(let n of t)for(let o of["name","id","for"]){let i=n.getAttribute?.(o);if(i&&i.includes("NEW_ROW"))n.setAttribute?.(o,i.replaceAll("NEW_ROW",String(r)))}}function Ie(e,r){if(e.nestedWarned)return;console.warn(`[phlex-reactive] nested rows: no owned [data-reactive-nested-list="${r}"] container + <template data-reactive-nested-template="${r}"> pair found in this root — the add `+"trigger did nothing. Render both inside the same reactive root (reactive_nested_list / reactive_nested_template)."),e.nestedWarned=!0}function De(e,r,t,n){if(!t)return null;let o;try{o=JSON.parse(t)}catch{return null}if(!o||typeof o!=="object")return null;let i=e.core.ownership(),s=[...r.querySelectorAll?.("input, select, textarea")??[]],a=[];for(let[l,c]of Object.entries(o)){let u=[...e.root.querySelectorAll?.(c)??[]].find(i);if(!u)continue;let f=s.find((d)=>re(d.getAttribute?.("name"))===l);if(!f)continue;Le(f,u),a.push(u)}if(n)for(let l of a)We(l);return a[0]??null}function Le(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:C(r)!=="";else e.value=C(r);y(e)}function We(e){if(e.type==="checkbox")e.checked=!1;else e.value="";y(e)}function Pe(e,r){if(!e.includes("%{"))return e;return e.replace(/%\{(\w+)\}/g,(t,n)=>Object.prototype.hasOwnProperty.call(r,n)?r[n]:t)}function B(e,r){let t=[...r.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(t)t.value="1",y(t),r.hidden=!0;else r.parentNode?.removeChild?.(r);M(e)}function M(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership();for(let t of[...e.root.querySelectorAll("[data-reactive-nested-json]")].filter(r))ne(e,t.getAttribute("data-reactive-nested-json"))}function Ge(e,r){let t=r.getAttribute?.("data-reactive-nested-json-field");if(!t)return null;let n=e.core.ownership();return[...e.root.querySelectorAll(t)].find(n)??null}function te(e,r){let t={},n=e.core.ownership();for(let o of[...r.querySelectorAll?.("input, select, textarea")??[]]){if(o.matches(":disabled")||o.type==="radio"&&!o.checked||!n(o))continue;let i=re(o.getAttribute?.("name"));if(i===null||i==="_destroy")continue;t[i]=C(o)}return t}function re(e){if(!e)return null;let r=e.match(/\[([^\][]+)\]$/);return r?r[1]:e}function C(e){if(e.type==="checkbox")return e.checked?e.value||"on":"";return e.value??""}function ne(e,r){let t=e.core.ownership(),n=[...e.root.querySelectorAll(`[data-reactive-nested-list="${r}"]`)].find(t);if(!n)return;let o=Ge(e,n);if(!o)return;let i=[];for(let a of[...n.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!t(a)||a.hidden)continue;i.push(te(e,a))}let s=JSON.stringify(i);if(o.value===s)return;o.value=s,y(o)}function nt(e,r,t){let n=g(e,r);if(!k(n))return;if(t?.defaultPrevented)return;if(n.core.listnavOptions(t).some((s)=>s.hasAttribute?.("data-reactive-highlighted")))return;t?.preventDefault?.();let o=t?.currentTarget??t?.target;if(!o)return;if(!V(n,String(o.value??"").split(",")))return;if(o.value="",S(n))b(n)}function ot(e,r,t){let n=g(e,r);if(!k(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!V(n,[i]))return;let s=je(n);if(!s)return;s.value="",b(n),s.focus?.()}function it(e,r,t){let n=g(e,r);if(!k(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let s=j(n);if(!s)return;let a=R(s),l=a.filter((c)=>c.toLowerCase()!==i.toLowerCase());if(l.length===a.length)return;X(n,s,l)}function at(e,r,t){let n=g(e,r);t?.preventDefault?.();let o=t?.currentTarget??t?.target,i=o?.getAttribute?.("data-reactive-association-param");if(!i)return;if(typeof n.root?.querySelectorAll!=="function")return;let s=n.core.ownership(),a=[...n.root.querySelectorAll(`[data-reactive-nested-list="${i}"]`)].find(s),c=[...n.root.querySelectorAll(`[data-reactive-nested-template="${i}"]`)].find(s)?.content?.firstElementChild;if(!a||!c){Ie(n,i);return}let u=c.cloneNode(!0);Te(u,Je(n)),a.appendChild(u);let f=o?.getAttribute?.("data-reactive-nested-from-param"),d=o?.getAttribute?.("data-reactive-nested-clear-param")==="true",h=De(n,u,f,d);if(f)h?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(a.getAttribute?.("data-reactive-nested-json")===i)ne(n,i)}function st(e,r,t){let n=g(e,r);t?.preventDefault?.();let o=t?.currentTarget??t?.target,i=o?.closest?.("[data-reactive-nested-row]");if(!i)return;if(i.closest?.('[data-controller~="reactive"]')!==n.root)return;let s=o?.getAttribute?.("data-reactive-confirm-param"),a=o?.getAttribute?.("data-reactive-confirm-when-param"),l=s||(a?le(n,a):null);if(!l)return B(n,i);let c=te(n,i),u=Pe(l,c);return n.core.confirm(u,{el:o,row:i,fields:c}).then((f)=>{if(f)B(n,i)})}function oe(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;M(e)}var ie=["gte","gt","lte","lt"],Be=["len_eq","len_gte","len_gt","len_lte","len_lt"],ae=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"],Fe=["digits_eq","digits_gte","digits_lt","digits_lte"];function q(e,r,t){if(!Number.isInteger(r))return console.warn(`[phlex-reactive] reactive_show ${e}: needs an integer literal, got ${JSON.stringify(r)} — skipped`),null;switch(e.slice(e.indexOf("_")+1)){case"eq":return t===r;case"gte":return t>=r;case"gt":return t>r;case"lte":return t<=r;case"lt":return t<r;default:return null}}function se(e,r,t){let n=Number(r);if(Number.isNaN(n))return console.warn(`[phlex-reactive] reactive_show ${e}: needs a numeric literal, got ${JSON.stringify(r)} — skipped`),null;let o=t==null?"":String(t).trim(),i=o===""?NaN:Number(o);if(Number.isNaN(i))return!1;switch(e){case"gte":return i>=n;case"gt":return i>n;case"lte":return i<=n;case"lt":return i<n;default:return null}}function ce(e,r){if(!e||typeof e!=="object")return null;if(typeof e.equals==="string")return r===e.equals;if(typeof e.not==="string")return r!==e.not;if(Array.isArray(e.in))return e.in.includes(r);for(let t of ie)if(t in e)return se(t,e[t],r);for(let t of Be)if(t in e)return q(t,e[t],[...String(r??"")].length);return null}function J(e,r){if(!e||typeof e!=="object"||typeof e.field!=="string")return!1;let t=ae.find((i)=>(i in e));if(t){let i=r(e.field,!0);return q(t,e[t],Array.isArray(i)?i.length:Number(i)||0)===!0}if(typeof e.same==="string"){let i=(s)=>{let a=String(r(s)??"");return e.fold===!0?a.replace(/[A-Z]/g,(l)=>String.fromCharCode(l.charCodeAt(0)+32)):a};return i(e.field)===i(e.same)!==(e.negate===!0)}let n=Fe.filter((i)=>(i in e));if(n.length){let i=String(r(e.field)??"");if(!n.every((a)=>Number.isInteger(e[a]))||e.prefix!=null&&typeof e.prefix!=="string")return!1;return(/^[0-9]*$/.test(i)&&n.every((a)=>q(a,e[a],i.length))&&i.startsWith(e.prefix??""))!==(e.negate===!0)}let o=r(e.field)??"";return ce(e,o)===!0}function A(e,r){if(!Array.isArray(e)||e.length===0)return null;return e.some((t)=>Array.isArray(t)&&t.length>0&&t.every((n)=>J(n,r)))}function He(e){if(!Array.isArray(e)||e.length===0)return null;let r=new Set;for(let t of e){if(!Array.isArray(t))continue;for(let n of t){if(n&&typeof n==="object"&&typeof n.field==="string")r.add(n.field);if(typeof n?.same==="string")r.add(n.same)}}return r.size>0?[...r]:null}function Ke(e){return e.flat().every((r)=>ae.some((t)=>(t in Object(r))))}function le(e,r){let t=r;if(typeof r==="string")try{t=JSON.parse(r)}catch{return console.warn(`[phlex-reactive] malformed conditional confirm payload ${JSON.stringify(r)} — skipped`),null}if(!t||typeof t!=="object")return null;let{fields:n}=e.core.collectFields(),o=(s)=>n[s],i;if(typeof t.predicate==="string"){let s=fe(t.predicate);if(!s)return console.warn(`[phlex-reactive] confirm predicate "${t.predicate}" is not registered — proceeding without a dialog (register it with setConfirmPredicate)`),null;i=!!s(n)}else i=A(t.groups?.any,o)===!0;return i?t.message:null}function T(e,r){let t=r.target?.closest?.("[data-reactive-editable]");return t&&e.core.owns(t)?t:null}function ze(e,r){let t=T(e,r);if(!t||r.isComposing||r.keyCode===229)return;if(r.key==="Enter"){let n=t.getAttribute("data-reactive-editable-enter");if(t.getAttribute("data-reactive-editable")==="multi"&&(n==null||r.shiftKey))return;if(r.preventDefault(),n==="submit")t.closest("form")?.requestSubmit();else if(n)e.core.applyOps(JSON.parse(n),"@root")}else if(r.key==="Escape"&&t.hasAttribute("data-reactive-editable-escape"))r.preventDefault(),t.textContent=e.core.served(t),y(t),t.blur()}function Ye(e,r){let t=T(e,r),n=t?.getAttribute("data-reactive-editable")!=="multi",o=(r.clipboardData??r.dataTransfer)?.getData("text/plain");if(!t||o==null||e.core.plain()&&!(n&&/[\r\n]/.test(o)))return;if(r.preventDefault(),n)o=o.replace(/\r?\n|\r/g," ");t.focus(),document.execCommand("insertText",!1,o)}function Ue(e,r){let t=T(e,r);if(t?.firstChild&&e.core.text(t)==="")t.replaceChildren()}export{rt as checkGroup,tt as confirmMessage,Qe as connect,Ve as disconnect,at as nestedAdd,st as nestedRemove,Xe as reseed,et as syncNestedJson,nt as tagsAdd,ot as tagsPick,it as tagsRemove};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=43EEE1B3CF9BBE3564756E2164756E21
|
|
4
4
|
//# sourceMappingURL=bindings.min.js.map
|