phlex-reactive 0.15.1 → 0.15.3
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 +188 -0
- data/README.md +82 -9
- data/app/controllers/phlex/reactive/actions_controller.rb +4 -1
- data/app/javascript/phlex/reactive/compute.js +14 -1
- data/app/javascript/phlex/reactive/compute.min.js +2 -2
- data/app/javascript/phlex/reactive/compute.min.js.map +3 -3
- data/app/javascript/phlex/reactive/core.min.js +4 -3
- data/app/javascript/phlex/reactive/core.min.js.map +3 -3
- data/app/javascript/phlex/reactive/features/bindings.js +66 -0
- 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/form.js +54 -22
- data/app/javascript/phlex/reactive/features/form.min.js +2 -2
- data/app/javascript/phlex/reactive/features/form.min.js.map +3 -3
- data/app/javascript/phlex/reactive/features/persist.js +31 -2
- 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.min.js +4 -3
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +6 -6
- data/app/javascript/phlex/reactive/runtime.js +476 -13
- data/lib/phlex/reactive/component/helpers.rb +24 -5
- data/lib/phlex/reactive/component/identity.rb +34 -1
- data/lib/phlex/reactive/component/image_fallback_binding.rb +54 -0
- data/lib/phlex/reactive/component/media_binding.rb +103 -0
- data/lib/phlex/reactive/component/media_pattern.rb +79 -0
- data/lib/phlex/reactive/doctor.rb +20 -8
- data/lib/phlex/reactive/held_fields.rb +87 -0
- data/lib/phlex/reactive/js.rb +153 -29
- data/lib/phlex/reactive/streamable.rb +26 -2
- data/lib/phlex/reactive/test_helpers.rb +11 -2
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +5 -1
|
@@ -377,6 +377,7 @@ function showSyncEnabled(c) {
|
|
|
377
377
|
const nodes = c.root.querySelectorAll?.(SHOW_BINDING_SELECTOR) ?? []
|
|
378
378
|
for (const el of nodes) if (c.core.owns(el)) return true
|
|
379
379
|
for (const el of c.root.querySelectorAll?.(GROUP_BINDING_SELECTOR) ?? []) if (c.core.owns(el)) return true
|
|
380
|
+
for (const el of c.root.querySelectorAll?.(MEDIA_BINDING_SELECTOR) ?? []) if (c.core.owns(el)) return true
|
|
380
381
|
return false
|
|
381
382
|
}
|
|
382
383
|
|
|
@@ -466,6 +467,7 @@ function syncShow(c) {
|
|
|
466
467
|
// The group bindings (issue #319) and the cross-root pass (issue #164)
|
|
467
468
|
// share the same owned-field memo, so a field driving several reads once.
|
|
468
469
|
if (c.groups) syncGroups(c, fieldValue, owns, scope)
|
|
470
|
+
syncMedia(c, fieldValue, owns)
|
|
469
471
|
syncShowTargets(c, fieldValue)
|
|
470
472
|
syncGroupTargets(c, fieldValue)
|
|
471
473
|
}
|
|
@@ -635,6 +637,70 @@ function fieldResolver(c, owns) {
|
|
|
635
637
|
}
|
|
636
638
|
}
|
|
637
639
|
|
|
640
|
+
// --- Media bindings (issue #373) ---------------------------------------------
|
|
641
|
+
// data-reactive-media='{"field","take"?,"match"?,"pending"?,"pool","label"?,"blank"?}'
|
|
642
|
+
// on a preview <img>: the owned field's value (its first `take` characters, or
|
|
643
|
+
// all of it) is a key into `pool`, whose value is a SELECTOR for an <img>
|
|
644
|
+
// inside the root. The core's copyMedia copies that element's src, srcset and
|
|
645
|
+
// alt — a pool value is never assigned to anything. A key, selector or element
|
|
646
|
+
// 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
|
|
650
|
+
// data-reactive-media-state names the outcome (pending | hit | miss). An
|
|
651
|
+
// unowned field leaves the preview alone (the show default-deny); a malformed
|
|
652
|
+
// attr warns and is skipped.
|
|
653
|
+
const MEDIA_BINDING_SELECTOR = "[data-reactive-media]"
|
|
654
|
+
|
|
655
|
+
function syncMedia(c, fieldValue, owns) {
|
|
656
|
+
for (const el of c.root.querySelectorAll(MEDIA_BINDING_SELECTOR)) {
|
|
657
|
+
if (!owns(el)) continue
|
|
658
|
+
let wire, pattern
|
|
659
|
+
try {
|
|
660
|
+
wire = JSON.parse(el.getAttribute("data-reactive-media"))
|
|
661
|
+
if (wire?.match != null) pattern = new RegExp(`^(?:${wire.match})$`)
|
|
662
|
+
} catch {}
|
|
663
|
+
if (typeof wire?.field !== "string" || !wire.pool || typeof wire.pool !== "object" || (wire.match != null && !pattern)) {
|
|
664
|
+
console.warn("[phlex-reactive] malformed data-reactive-media — skipped")
|
|
665
|
+
continue
|
|
666
|
+
}
|
|
667
|
+
const value = fieldValue(wire.field)
|
|
668
|
+
if (value === null) continue
|
|
669
|
+
// Characters (code points), as Ruby counts them — not UTF-16 code units.
|
|
670
|
+
const chars = wire.take > 0 ? [...value] : null
|
|
671
|
+
const key = chars ? chars.slice(0, wire.take).join("") : value
|
|
672
|
+
const pending = chars?.length < wire.take || pattern?.test(key) === false
|
|
673
|
+
if (pending && wire.pending === "keep") {
|
|
674
|
+
mediaState(el, "pending")
|
|
675
|
+
continue
|
|
676
|
+
}
|
|
677
|
+
const source = !pending && Object.hasOwn(wire.pool, key) ? mediaMatches(c, wire.pool[key])[0] : null
|
|
678
|
+
const alt = c.core.copyMedia(el, source ?? null)
|
|
679
|
+
if (alt === null) continue
|
|
680
|
+
mediaState(el, pending ? "pending" : alt === false ? "miss" : "hit")
|
|
681
|
+
if (typeof wire.label !== "string") continue
|
|
682
|
+
const text = pending ? "" : alt === false ? String(wire.blank ?? "") : alt
|
|
683
|
+
for (const node of mediaMatches(c, wire.label)) if (node.textContent !== text) node.textContent = text
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// The outcome a stylesheet (or :has()) can hide a row on, written only when
|
|
688
|
+
// it changes.
|
|
689
|
+
function mediaState(el, state) {
|
|
690
|
+
if (el.getAttribute("data-reactive-media-state") !== state) el.setAttribute("data-reactive-media-state", state)
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// The owned elements a pool or label selector names — none when it does not
|
|
694
|
+
// parse (a URL string is not a selector), and none for the "@root" sentinel:
|
|
695
|
+
// a label naming the root would rewrite the whole root's text.
|
|
696
|
+
function mediaMatches(c, selector) {
|
|
697
|
+
try {
|
|
698
|
+
return selector === "@root" ? [] : c.core.opTargets({ to: selector })
|
|
699
|
+
} catch {
|
|
700
|
+
return []
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
638
704
|
// --- Bulk selection (issue #319) ---------------------------------------------
|
|
639
705
|
// A checkbox GROUP is the owned boxes sharing one name. Three bindings read it:
|
|
640
706
|
// the select-all header (data-reactive-select-all), the ticked count
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{confirmPredicate as oe}from"phlex/reactive/confirm_predicate";var g=new WeakMap,q=new WeakMap;function p(e,r){let t=g.get(e);if(!t){if(g.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 n of r.split(" "))e.root.addEventListener?.(n,t),e.offs.push(()=>e.root.removeEventListener?.(n,t))}function y(e,r){d(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Pe(e,r){let t=p(e,r);t.offs=[],t.seeds=[];let n,o,i,s;(t.wire=()=>{if(!t.show&&le(t))t.show=(a)=>{if(t.flipping)return;if(a?.type==="input"||a?.type==="change")me(t,a.target);else t.groups=ye(t),T(t);de(t)},d(t,"input change",t.show),y(t,t.show);if(!t.arm&&ue(t))d(t,"input change",(a)=>R(t,a)),y(t,t.arm=()=>{R(t,null),T(t)});if(!n&&(n=t.show||t.arm))d(t,"reset",()=>setTimeout(()=>{if(g.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(!o&&(o=b(t)))d(t,"input",(a)=>be(t,a)&&m(t)),y(t,()=>m(t));if(!i&&(i=S(t)))y(t,()=>H(t));if(!s&&(s=we(t)))d(t,"input change",(a)=>Q(t,a)),y(t,()=>O(t))})(),d(t,"keydown",(a)=>Le(t,a)),d(t,"paste drop",(a)=>Me(t,a)),d(t,"input",(a)=>De(t,a))}function We(e){let r=g.get(e);if(!r)return;g.delete(e),q.delete(r.root);for(let t of r.offs??[])t();r.groupObserver?.disconnect()}function Ge(e){let r=g.get(e);if(!r)return;for(let t of r.seeds)t();r.wire()}function h(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function Fe(e,r,t){return Q(p(e,r),t)}function Be(e,r,t){return re(p(e,r),t)}var ie=/^#[A-Za-z_][\w-]*$/,M="[data-reactive-show-field], [data-reactive-show]";function se(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 Z){let s=e.getAttribute(`data-reactive-show-${i}`);if(s!==null)return ee(i,s,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function D(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 ae(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 I(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 v(t,r);return ce(e,r)}function ce(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)=>E(i,r));return t==="all"?o.every(Boolean):o.some(Boolean)}function A(e,r="show"){if(typeof e==="string"&&ie.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function le(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?.(M)??[];for(let t of r)if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(w)??[])if(e.core.owns(t))return!0;return!1}function ue(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function fe(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:ae(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function R(e,r){let t=fe(e);if(!t.length)return;let n=G(e,e.core.ownership());t.forEach((o,i)=>{let s=v(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 de(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,n=G(e,r);for(let o of e.root.querySelectorAll(M)){if(!r(o))continue;let i=o.getAttribute("data-reactive-show");if(i!==null){let c=I(D(i),n);if(c!==null)J(o,c,r,t);continue}let s=o.getAttribute("data-reactive-show-field");if(!s)continue;let a=n(s);if(a===null)continue;let l=se(o,a);if(l===null)continue;J(o,l,r,t)}if(e.groups)ve(e,n,r,t);pe(e,n),Ae(e,n)}function J(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 pe(e,r){let t=P(e);for(let[n,o]of Object.entries(t)){if(n.startsWith("#")){ge(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(!A(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)=>E(u,s))}else{let u=te(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 ge(e,r,t){if(!A(e))return;let n=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,o=Je(n);if(o===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(o.every((s)=>t(s)===null)&&!Te(n))return;let i=v(n,t);if(i===null)return;for(let s of document.querySelectorAll(e))s.hidden=!i}function P(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 he(e,r,t,n){let o=!1,i=null;for(let s of e.root.querySelectorAll(W(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 W(e,r){return`[name="${r&&!e.includes("[")?`${r}[${e}]`:e}"]`}function G(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,o,r,t).filter((a)=>a.checked).length:he(e,o,r,t));return n.get(s)}}var w="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function ye(e){return!!e.root.querySelector?.(w)}function _(e,r,t,n){return[...e.root.querySelectorAll(W(r,n))].filter((o)=>o.type==="checkbox"&&t(o))}function me(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))F(e,t,r.checked,r)}function Ke(e,r,t){if(!r)return;let n=q.get(e)??{root:e,core:{ownership:()=>(o)=>o.closest('[data-controller~="reactive"]')===e}};F(n,r,t!==!1),n.show?.()}function F(e,r,t,n){let o=e.root.getAttribute?.("data-reactive-scope")||null,i=_(e,r,e.core.ownership(),o).filter((s)=>s!==n&&s.checked!==t);for(let s of i)s.checked=t;e.flipping=!0;try{for(let s of i)for(let a of["input","change"])s.dispatchEvent?.(new Event(a,{bubbles:!0}))}finally{e.flipping=!1}}function ve(e,r,t,n){for(let o of e.root.querySelectorAll(w)){if(!t(o))continue;let i=o.getAttribute("data-reactive-enable");if(i!==null){let l=I(D(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=_(e,a,t,n).filter((u)=>u!==o),c=l.filter((u)=>u.checked).length;o.checked=c>0&&c===l.length,o.indeterminate=c>0&&c<l.length}}}function Ae(e,r){for(let[t,n]of Object.entries(P(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(!A(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(!A(s,"group"))continue;let l=v(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 T(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?.(`${w}, [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 b(e){return!!(e.root.getAttribute?.("data-reactive-filter-input")&&e.root.getAttribute?.("data-reactive-filter-option"))}function be(e,r){let t=e.root.getAttribute("data-reactive-filter-input");return!!t&&typeof r.target?.matches==="function"&&r.target.matches(t)}function m(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 S(e){return!!e.root.getAttribute?.("data-reactive-tags-field")}function we(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 k(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 B(e,r){let t=N(e);if(!t)return!1;let n=k(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)K(e,t,n);return i}function K(e,r,t){r.value=t.join(","),h(r),H(e)}function Se(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 H(e){let r=N(e);if(!r)return;let t=k(r),n=e.core.ownership();xe(e,t,n),Ce(e,t,n)}function xe(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 Ce(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"),!b(e))o.hidden=!1}}if(b(e))m(e)}function qe(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function _e(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 Ne(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 ke(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((x)=>Y(x.getAttribute?.("name"))===l);if(!f)continue;Oe(f,u),a.push(u)}if(n)for(let l of a)Ee(l);return a[0]??null}function Oe(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:C(r)!=="";else e.value=C(r);h(e)}function Ee(e){if(e.type==="checkbox")e.checked=!1;else e.value="";h(e)}function $e(e,r){if(!e.includes("%{"))return e;return e.replace(/%\{(\w+)\}/g,(t,n)=>Object.prototype.hasOwnProperty.call(r,n)?r[n]:t)}function L(e,r){let t=[...r.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(t)t.value="1",h(t),r.hidden=!0;else r.parentNode?.removeChild?.(r);O(e)}function O(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))U(e,t.getAttribute("data-reactive-nested-json"))}function je(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 z(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=Y(o.getAttribute?.("name"));if(i===null||i==="_destroy")continue;t[i]=C(o)}return t}function Y(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 U(e,r){let t=e.core.ownership(),n=[...e.root.querySelectorAll(`[data-reactive-nested-list="${r}"]`)].find(t);if(!n)return;let o=je(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(z(e,a))}let s=JSON.stringify(i);if(o.value===s)return;o.value=s,h(o)}function He(e,r,t){let n=p(e,r);if(!S(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(!B(n,String(o.value??"").split(",")))return;if(o.value="",b(n))m(n)}function ze(e,r,t){let n=p(e,r);if(!S(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!B(n,[i]))return;let s=Se(n);if(!s)return;s.value="",m(n),s.focus?.()}function Ye(e,r,t){let n=p(e,r);if(!S(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let s=N(n);if(!s)return;let a=k(s),l=a.filter((c)=>c.toLowerCase()!==i.toLowerCase());if(l.length===a.length)return;K(n,s,l)}function Ue(e,r,t){let n=p(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){Ne(n,i);return}let u=c.cloneNode(!0);_e(u,qe(n)),a.appendChild(u);let f=o?.getAttribute?.("data-reactive-nested-from-param"),x=o?.getAttribute?.("data-reactive-nested-clear-param")==="true",ne=ke(n,u,f,x);if(f)ne?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(a.getAttribute?.("data-reactive-nested-json")===i)U(n,i)}function Qe(e,r,t){let n=p(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?re(n,a):null);if(!l)return L(n,i);let c=z(n,i),u=$e(l,c);return n.core.confirm(u,{el:o,row:i,fields:c}).then((f)=>{if(f)L(n,i)})}function Q(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;O(e)}var Z=["gte","gt","lte","lt"],Re=["len_eq","len_gte","len_gt","len_lte","len_lt"],V=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"];function X(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 ee(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 te(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 Z)if(t in e)return ee(t,e[t],r);for(let t of Re)if(t in e)return X(t,e[t],[...String(r??"")].length);return null}function E(e,r){if(!e||typeof e!=="object"||typeof e.field!=="string")return!1;let t=V.find((o)=>(o in e));if(t){let o=r(e.field,!0);return X(t,e[t],Array.isArray(o)?o.length:Number(o)||0)===!0}let n=r(e.field)??"";return te(e,n)===!0}function v(e,r){if(!Array.isArray(e)||e.length===0)return null;return e.some((t)=>Array.isArray(t)&&t.length>0&&t.every((n)=>E(n,r)))}function Je(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)}return r.size>0?[...r]:null}function Te(e){return e.flat().every((r)=>V.some((t)=>(t in Object(r))))}function re(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=oe(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=v(t.groups?.any,o)===!0;return i?t.message:null}function j(e,r){let t=r.target?.closest?.("[data-reactive-editable]");return t&&e.core.owns(t)?t:null}function Le(e,r){let t=j(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),h(t),t.blur()}function Me(e,r){let t=j(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 De(e,r){let t=j(e,r);if(t?.firstChild&&e.core.text(t)==="")t.replaceChildren()}export{Ke as checkGroup,Be as confirmMessage,Pe as connect,We as disconnect,Ue as nestedAdd,Qe as nestedRemove,Ge as reseed,Fe as syncNestedJson,He as tagsAdd,ze as tagsPick,Ye as tagsRemove};
|
|
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};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=37913BD89CC3850E64756E2164756E21
|
|
4
4
|
//# sourceMappingURL=bindings.min.js.map
|