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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +184 -0
  3. data/README.md +92 -12
  4. data/app/javascript/phlex/reactive/core.js +1 -0
  5. data/app/javascript/phlex/reactive/core.min.js +6 -6
  6. data/app/javascript/phlex/reactive/core.min.js.map +4 -4
  7. data/app/javascript/phlex/reactive/features/bindings.js +129 -16
  8. data/app/javascript/phlex/reactive/features/bindings.min.js +2 -2
  9. data/app/javascript/phlex/reactive/features/bindings.min.js.map +3 -3
  10. data/app/javascript/phlex/reactive/features/countdown.js +140 -0
  11. data/app/javascript/phlex/reactive/features/countdown.min.js +4 -0
  12. data/app/javascript/phlex/reactive/features/countdown.min.js.map +10 -0
  13. data/app/javascript/phlex/reactive/features/persist.js +10 -6
  14. data/app/javascript/phlex/reactive/features/persist.min.js +2 -2
  15. data/app/javascript/phlex/reactive/features/persist.min.js.map +3 -3
  16. data/app/javascript/phlex/reactive/reactive_controller.js +2 -0
  17. data/app/javascript/phlex/reactive/reactive_controller.min.js +4 -4
  18. data/app/javascript/phlex/reactive/reactive_controller.min.js.map +8 -7
  19. data/app/javascript/phlex/reactive/runtime.js +255 -31
  20. data/lib/phlex/reactive/component/countdown_binding.rb +80 -0
  21. data/lib/phlex/reactive/component/field_references.rb +130 -0
  22. data/lib/phlex/reactive/component/helpers.rb +72 -14
  23. data/lib/phlex/reactive/component/image_fallback_binding.rb +18 -5
  24. data/lib/phlex/reactive/component/media_binding.rb +9 -1
  25. data/lib/phlex/reactive/component/media_pattern.rb +17 -17
  26. data/lib/phlex/reactive/component/selection.rb +24 -2
  27. data/lib/phlex/reactive/component/show_options.rb +91 -0
  28. data/lib/phlex/reactive/engine.rb +2 -2
  29. data/lib/phlex/reactive/js.rb +44 -2
  30. data/lib/phlex/reactive/response.rb +3 -4
  31. data/lib/phlex/reactive/show_conditions/compare_terms.rb +142 -0
  32. data/lib/phlex/reactive/show_conditions.rb +39 -6
  33. data/lib/phlex/reactive/streamable.rb +6 -4
  34. data/lib/phlex/reactive/version.rb +1 -1
  35. 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 !== null) applyShowVisibility(el, match, owns, scope)
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="${scope && !name.includes("[") ? `${scope}[${name}]` : 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`, or one the anchored `match` source
648
- // rejects, is PENDING (issue #380) and never gets `blank`: "keep" leaves the
649
- // preview and label alone, the default clears both. The preview's
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 (typeof wire?.field !== "string" || !wire.pool || typeof wire.pool !== "object" || (wire.match != null && !pattern)) {
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
- function groupBoxes(c, name, owns, scope) {
721
- return [...c.root.querySelectorAll(namedSelector(name, scope))].filter((el) => el.type === "checkbox" && owns(el))
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)) setGroup(c, group, header.checked, 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 boxes = groupBoxes(c, group, owns, scope).filter((box) => box !== el)
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=37913BD89CC3850E64756E2164756E21
3
+ //# debugId=43EEE1B3CF9BBE3564756E2164756E21
4
4
  //# sourceMappingURL=bindings.min.js.map