phlex-reactive 0.14.3 → 0.14.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +37 -0
- data/README.md +67 -4
- data/app/javascript/phlex/reactive/core.js +7 -1
- data/app/javascript/phlex/reactive/core.min.js +6 -2
- data/app/javascript/phlex/reactive/core.min.js.map +4 -4
- data/app/javascript/phlex/reactive/features/bindings.js +96 -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 +12 -5
- 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 +12 -3
- 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/features/sortable.js +463 -0
- data/app/javascript/phlex/reactive/features/sortable.min.js +4 -0
- data/app/javascript/phlex/reactive/features/sortable.min.js.map +10 -0
- data/app/javascript/phlex/reactive/reactive_controller.js +2 -0
- data/app/javascript/phlex/reactive/reactive_controller.min.js +6 -2
- data/app/javascript/phlex/reactive/reactive_controller.min.js.map +9 -8
- data/app/javascript/phlex/reactive/runtime.js +117 -10
- data/lib/phlex/reactive/component/editable.rb +78 -0
- data/lib/phlex/reactive/component/helpers.rb +2 -0
- data/lib/phlex/reactive/component/sortable.rb +212 -0
- data/lib/phlex/reactive/engine.rb +4 -4
- data/lib/phlex/reactive/version.rb +1 -1
- metadata +6 -1
|
@@ -174,6 +174,17 @@ export function connect(controller, core) {
|
|
|
174
174
|
listen(c, "input change", (event) => syncNestedJson(c, event))
|
|
175
175
|
seed(c, () => syncAllNestedJson(c))
|
|
176
176
|
}
|
|
177
|
+
|
|
178
|
+
// Editable text (issue #351). Delegated keys, paste and drop on the root,
|
|
179
|
+
// whether or not it owns an editable yet: a stream can append the first one
|
|
180
|
+
// into a root whose bindings connected for another marker (each handler
|
|
181
|
+
// returns at once for an event that is not an owned editable's). The seed
|
|
182
|
+
// downgrades plaintext-only where the engine lacks it, again after a morph
|
|
183
|
+
// (which writes the server's attribute back).
|
|
184
|
+
seed(c, () => downgradeEditables(c))
|
|
185
|
+
listen(c, "keydown", (event) => editableKey(c, event))
|
|
186
|
+
listen(c, "paste drop", (event) => editablePaste(c, event))
|
|
187
|
+
listen(c, "input", (event) => editableEmptied(c, event))
|
|
177
188
|
}
|
|
178
189
|
|
|
179
190
|
// Remove every listener connect() added, so a stray event after a Turbo
|
|
@@ -1588,3 +1599,88 @@ function conditionalConfirmMessage(c, confirmWhen) {
|
|
|
1588
1599
|
|
|
1589
1600
|
return fires ? payload.message : null
|
|
1590
1601
|
}
|
|
1602
|
+
|
|
1603
|
+
// --- Editable text (issue #351) ----------------------------------------------
|
|
1604
|
+
// reactive_editable renders contenteditable="plaintext-only": the browser
|
|
1605
|
+
// itself then pastes plain text and inserts "\n" for Enter. An engine without
|
|
1606
|
+
// it reads the value as invalid — NOT editable — so the seed downgrades to
|
|
1607
|
+
// "true" there and the paste handler below does the plain-text part. Detected
|
|
1608
|
+
// once per page.
|
|
1609
|
+
let plaintextOnly
|
|
1610
|
+
|
|
1611
|
+
export function __setPlaintextOnlyForTest(value) {
|
|
1612
|
+
plaintextOnly = value
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
function plaintextSupported() {
|
|
1616
|
+
if (plaintextOnly === undefined) {
|
|
1617
|
+
try {
|
|
1618
|
+
const probe = document.createElement("div")
|
|
1619
|
+
probe.contentEditable = "plaintext-only"
|
|
1620
|
+
plaintextOnly = probe.contentEditable === "plaintext-only"
|
|
1621
|
+
} catch {
|
|
1622
|
+
plaintextOnly = false
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
return plaintextOnly
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
// The owned editable an event came from, or null — a nested reactive root's
|
|
1629
|
+
// editables are its own (#15).
|
|
1630
|
+
function ownedEditable(c, event) {
|
|
1631
|
+
const el = event.target?.closest?.("[data-reactive-editable]")
|
|
1632
|
+
return el && c.core.owns(el) ? el : null
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
function downgradeEditables(c) {
|
|
1636
|
+
if (plaintextSupported()) return
|
|
1637
|
+
for (const el of c.root.querySelectorAll("[data-reactive-editable][contenteditable=plaintext-only]")) {
|
|
1638
|
+
el.setAttribute("contenteditable", "true")
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
// Enter: a single-line field swallows it; on_enter runs its ops (root-scoped,
|
|
1643
|
+
// as on_client) or submits the field's form — in a multiline field only a
|
|
1644
|
+
// plain Enter, so Shift+Enter still breaks the line. Never while an IME is
|
|
1645
|
+
// composing (its Enter commits the composition). Escape with on_escape:
|
|
1646
|
+
// :revert restores the last server-rendered text, announces it as an edit
|
|
1647
|
+
// (dirty, show, an input-bound save) and blurs.
|
|
1648
|
+
function editableKey(c, event) {
|
|
1649
|
+
const el = ownedEditable(c, event)
|
|
1650
|
+
if (!el || event.isComposing || event.keyCode === 229) return
|
|
1651
|
+
if (event.key === "Enter") {
|
|
1652
|
+
const enter = el.getAttribute("data-reactive-editable-enter")
|
|
1653
|
+
const multi = el.getAttribute("data-reactive-editable") === "multi"
|
|
1654
|
+
if (multi && (enter == null || event.shiftKey)) return
|
|
1655
|
+
event.preventDefault()
|
|
1656
|
+
if (enter === "submit") el.closest("form")?.requestSubmit()
|
|
1657
|
+
else if (enter) c.core.applyOps(JSON.parse(enter), "@root")
|
|
1658
|
+
} else if (event.key === "Escape" && el.hasAttribute("data-reactive-editable-escape")) {
|
|
1659
|
+
event.preventDefault()
|
|
1660
|
+
el.textContent = c.core.served(el)
|
|
1661
|
+
fireInput(el)
|
|
1662
|
+
el.blur()
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
// Paste and drop insert the clipboard's PLAIN text — handled here where the
|
|
1667
|
+
// engine has no plaintext-only, and for a single-line field everywhere (its
|
|
1668
|
+
// line breaks fold to spaces). insertText keeps the browser's undo stack. A
|
|
1669
|
+
// drop lands at the caret, not under the pointer.
|
|
1670
|
+
function editablePaste(c, event) {
|
|
1671
|
+
const el = ownedEditable(c, event)
|
|
1672
|
+
const single = el?.getAttribute("data-reactive-editable") !== "multi"
|
|
1673
|
+
let text = (event.clipboardData ?? event.dataTransfer)?.getData("text/plain")
|
|
1674
|
+
if (!el || text == null || (plaintextSupported() && !(single && /[\r\n]/.test(text)))) return
|
|
1675
|
+
event.preventDefault()
|
|
1676
|
+
if (single) text = text.replace(/\r?\n|\r/g, " ")
|
|
1677
|
+
el.focus()
|
|
1678
|
+
document.execCommand("insertText", false, text)
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
// A field the user emptied keeps the <br> browsers leave behind, so
|
|
1682
|
+
// :empty::before (the placeholder) would never match: drop it.
|
|
1683
|
+
function editableEmptied(c, event) {
|
|
1684
|
+
const el = ownedEditable(c, event)
|
|
1685
|
+
if (el?.firstChild && c.core.text(el) === "") el.replaceChildren()
|
|
1686
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{confirmPredicate as ne}from"phlex/reactive/confirm_predicate";var g=new WeakMap,q=new WeakMap;function d(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 p(e,r,t){for(let n of r.split(" "))e.root.addEventListener?.(n,t),e.offs.push(()=>e.root.removeEventListener?.(n,t))}function h(e,r){p(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Le(e,r){let t=d(e,r);if(t.offs=[],t.seeds=[],ce(t))t.show=(n)=>{if(t.flipping)return;if(n?.type==="input"||n?.type==="change")ye(t,n.target);else t.groups=he(t),J(t);fe(t)},p(t,"input change",t.show),h(t,t.show);if(le(t))p(t,"input change",(n)=>j(t,n)),h(t,t.arm=()=>{j(t,null),J(t)});if(t.show||t.arm)p(t,"reset",()=>setTimeout(()=>{if(g.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(b(t))p(t,"input",(n)=>Ae(t,n)&&y(t)),h(t,()=>y(t));if(S(t))h(t,()=>H(t));if(be(t))p(t,"input change",(n)=>U(t,n)),h(t,()=>k(t))}function Me(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 Ie(e){for(let r of g.get(e)?.seeds??[])r()}function v(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function Pe(e,r,t){return U(d(e,r),t)}function We(e,r,t){return te(d(e,r),t)}var oe=/^#[A-Za-z_][\w-]*$/,L="[data-reactive-show-field], [data-reactive-show]";function ie(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 Q){let s=e.getAttribute(`data-reactive-show-${i}`);if(s!==null)return X(i,s,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function M(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 se(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 m(t,r);return ae(e,r)}function ae(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"&&oe.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function ce(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?.(L)??[];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 le(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function ue(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:se(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function j(e,r){let t=ue(e);if(!t.length)return;let n=D(e,e.core.ownership());t.forEach((o,i)=>{let s=m(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 fe(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,n=D(e,r);for(let o of e.root.querySelectorAll(L)){if(!r(o))continue;let i=o.getAttribute("data-reactive-show");if(i!==null){let c=I(M(i),n);if(c!==null)R(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=ie(o,a);if(l===null)continue;R(o,l,r,t)}if(e.groups)ve(e,n,r,t);de(e,n),me(e,n)}function R(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 de(e,r){let t=P(e);for(let[n,o]of Object.entries(t)){if(n.startsWith("#")){pe(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=ee(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 pe(e,r,t){if(!A(e))return;let n=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,o=Re(n);if(o===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(o.every((s)=>t(s)===null)&&!Je(n))return;let i=m(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 ge(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 D(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?N(e,o,r,t).filter((a)=>a.checked).length:ge(e,o,r,t));return n.get(s)}}var w="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function he(e){return!!e.root.querySelector?.(w)}function N(e,r,t,n){return[...e.root.querySelectorAll(W(r,n))].filter((o)=>o.type==="checkbox"&&t(o))}function ye(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))G(e,t,r.checked,r)}function De(e,r,t){if(!r)return;let n=q.get(e)??{root:e,core:{ownership:()=>(o)=>o.closest('[data-controller~="reactive"]')===e}};G(n,r,t!==!1),n.show?.()}function G(e,r,t,n){let o=e.root.getAttribute?.("data-reactive-scope")||null,i=N(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(M(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=N(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 me(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=m(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 J(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 Ae(e,r){let t=e.root.getAttribute("data-reactive-filter-input");return!!t&&typeof r.target?.matches==="function"&&r.target.matches(t)}function y(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 be(e){if(typeof e.root?.querySelector!=="function")return!1;return!!e.root.querySelector("[data-reactive-nested-json]")}function C(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 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 F(e,r){let t=C(e);if(!t)return!1;let n=O(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)B(e,t,n);return i}function B(e,r,t){r.value=t.join(","),v(r),H(e)}function we(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=C(e);if(!r)return;let t=O(r),n=e.core.ownership();Se(e,t,n),xe(e,t,n)}function Se(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 xe(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))y(e)}function _e(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function qe(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 Ce(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)ke(l);return a[0]??null}function Oe(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:_(r)!=="";else e.value=_(r);v(e)}function ke(e){if(e.type==="checkbox")e.checked=!1;else e.value="";v(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 T(e,r){let t=[...r.querySelectorAll?.('input[name$="[_destroy]"]')??[]][0];if(t)t.value="1",v(t),r.hidden=!0;else r.parentNode?.removeChild?.(r);k(e)}function k(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))z(e,t.getAttribute("data-reactive-nested-json"))}function Ee(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 K(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]=_(o)}return t}function Y(e){if(!e)return null;let r=e.match(/\[([^\][]+)\]$/);return r?r[1]:e}function _(e){if(e.type==="checkbox")return e.checked?e.value||"on":"";return e.value??""}function z(e,r){let t=e.core.ownership(),n=[...e.root.querySelectorAll(`[data-reactive-nested-list="${r}"]`)].find(t);if(!n)return;let o=Ee(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(K(e,a))}let s=JSON.stringify(i);if(o.value===s)return;o.value=s,v(o)}function Ge(e,r,t){let n=d(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(!F(n,String(o.value??"").split(",")))return;if(o.value="",b(n))y(n)}function Fe(e,r,t){let n=d(e,r);if(!S(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!F(n,[i]))return;let s=we(n);if(!s)return;s.value="",y(n),s.focus?.()}function Be(e,r,t){let n=d(e,r);if(!S(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let s=C(n);if(!s)return;let a=O(s),l=a.filter((c)=>c.toLowerCase()!==i.toLowerCase());if(l.length===a.length)return;B(n,s,l)}function He(e,r,t){let n=d(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);qe(u,_e(n)),a.appendChild(u);let f=o?.getAttribute?.("data-reactive-nested-from-param"),x=o?.getAttribute?.("data-reactive-nested-clear-param")==="true",re=Ce(n,u,f,x);if(f)re?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(a.getAttribute?.("data-reactive-nested-json")===i)z(n,i)}function Ke(e,r,t){let n=d(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?te(n,a):null);if(!l)return T(n,i);let c=K(n,i),u=$e(l,c);return n.core.confirm(u,{el:o,row:i,fields:c}).then((f)=>{if(f)T(n,i)})}function U(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;k(e)}var Q=["gte","gt","lte","lt"],je=["len_eq","len_gte","len_gt","len_lte","len_lt"],Z=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"];function V(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 X(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 ee(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 Q)if(t in e)return X(t,e[t],r);for(let t of je)if(t in e)return V(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=Z.find((o)=>(o in e));if(t){let o=r(e.field,!0);return V(t,e[t],Array.isArray(o)?o.length:Number(o)||0)===!0}let n=r(e.field)??"";return ee(e,n)===!0}function m(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 Re(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 Je(e){return e.flat().every((r)=>Z.some((t)=>(t in Object(r))))}function te(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=ne(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=m(t.groups?.any,o)===!0;return i?t.message:null}export{De as checkGroup,We as confirmMessage,Le as connect,Me as disconnect,He as nestedAdd,Ke as nestedRemove,Ie as reseed,Pe as syncNestedJson,Ge as tagsAdd,Fe as tagsPick,Be as tagsRemove};
|
|
1
|
+
import{confirmPredicate as ae}from"phlex/reactive/confirm_predicate";var h=new WeakMap,C=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)C.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 g(e,r){d(e,"turbo:morph-element",r),e.seeds.push(r),r()}function Fe(e,r){let t=p(e,r);if(t.offs=[],t.seeds=[],fe(t))t.show=(n)=>{if(t.flipping)return;if(n?.type==="input"||n?.type==="change")be(t,n.target);else t.groups=ve(t),L(t);ge(t)},d(t,"input change",t.show),g(t,t.show);if(de(t))d(t,"input change",(n)=>J(t,n)),g(t,t.arm=()=>{J(t,null),L(t)});if(t.show||t.arm)d(t,"reset",()=>setTimeout(()=>{if(h.get(e)!==t)return;t.show?.(),t.arm?.()},0));if(w(t))d(t,"input",(n)=>Se(t,n)&&v(t)),g(t,()=>v(t));if(x(t))g(t,()=>Y(t));if(xe(t))d(t,"input change",(n)=>Z(t,n)),g(t,()=>E(t));g(t,()=>De(t)),d(t,"keydown",(n)=>Ie(t,n)),d(t,"paste drop",(n)=>Pe(t,n)),d(t,"input",(n)=>We(t,n))}function Be(e){let r=h.get(e);if(!r)return;h.delete(e),C.delete(r.root);for(let t of r.offs??[])t();r.groupObserver?.disconnect()}function Ke(e){for(let r of h.get(e)?.seeds??[])r()}function y(e){if(typeof e.dispatchEvent==="function")e.dispatchEvent(new Event("input",{bubbles:!0}))}function He(e,r,t){return Z(p(e,r),t)}function Ye(e,r,t){return ne(p(e,r),t)}var se=/^#[A-Za-z_][\w-]*$/,D="[data-reactive-show-field], [data-reactive-show]";function ce(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 V){let a=e.getAttribute(`data-reactive-show-${i}`);if(a!==null)return te(i,a,r)}return console.warn("[phlex-reactive] a reactive_show binding declares no predicate — skipped"),null}function I(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 le(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 P(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 ue(e,r)}function ue(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 A(e,r="show"){if(typeof e==="string"&&se.test(e))return!0;return console.warn(`[phlex-reactive] refused cross-root ${r} target ${JSON.stringify(e)} — skipped`),!1}function fe(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?.(D)??[];for(let t of r)if(e.core.owns(t))return!0;for(let t of e.root.querySelectorAll?.(S)??[])if(e.core.owns(t))return!0;return!1}function de(e){return!!e.root.getAttribute?.("data-reactive-on-complete")}function pe(e){let r=e.root.getAttribute?.("data-reactive-on-complete")??null;if(r!==e.onCompleteRaw)e.onCompleteRaw=r,e.onCompleteParsed=r==null?[]:le(r),e.onCompleteStates=e.onCompleteParsed.map(()=>!1);return e.onCompleteParsed}function J(e,r){let t=pe(e);if(!t.length)return;let n=F(e,e.core.ownership());t.forEach((o,i)=>{let a=b(o.any,n);if(a===null)return;let s=a&&!e.onCompleteStates[i]&&Boolean(r);if(e.onCompleteStates[i]=a,s)e.core.applyOps(o.ops,"@root")})}function ge(e){if(typeof e.root?.querySelectorAll!=="function")return;let r=e.core.ownership(),t=e.root.getAttribute?.("data-reactive-scope")||null,n=F(e,r);for(let o of e.root.querySelectorAll(D)){if(!r(o))continue;let i=o.getAttribute("data-reactive-show");if(i!==null){let c=P(I(i),n);if(c!==null)T(o,c,r,t);continue}let a=o.getAttribute("data-reactive-show-field");if(!a)continue;let s=n(a);if(s===null)continue;let l=ce(o,s);if(l===null)continue;T(o,l,r,t)}if(e.groups)Ae(e,n,r,t);he(e,n),we(e,n)}function T(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 he(e,r){let t=W(e);for(let[n,o]of Object.entries(t)){if(n.startsWith("#")){ye(n,o,r);continue}if(!o||typeof o!=="object"||Array.isArray(o))continue;let i=r(n);if(i===null)continue;let a=(s,l)=>l?r(n,!0):i;for(let[s,l]of Object.entries(o)){if(!A(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=re(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 ye(e,r,t){if(!A(e))return;let n=r&&typeof r==="object"&&!Array.isArray(r)?r.any:null,o=Le(n);if(o===null){console.warn(`[phlex-reactive] malformed reactive_show_targets conditions for ${e} — skipped`);return}if(o.every((a)=>t(a)===null)&&!Me(n))return;let i=b(n,t);if(i===null)return;for(let a of document.querySelectorAll(e))a.hidden=!i}function W(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 me(e,r,t,n){let o=!1,i=null;for(let a of e.root.querySelectorAll(G(r,n))){if(!t(a))continue;if(a.type==="checkbox")return a.checked?"true":"false";if(a.type==="radio"){if(a.checked)return a.value??"";o=!0;continue}i??=a}if(i)return i.value??"";return o?"":null}function G(e,r){return`[name="${r&&!e.includes("[")?`${r}[${e}]`:e}"]`}function F(e,r){let t=e.root.getAttribute?.("data-reactive-scope")||null,n=new Map;return(o,i)=>{let a=i?`#${o}`:o;if(!n.has(a))n.set(a,i?N(e,o,r,t).filter((s)=>s.checked).length:me(e,o,r,t));return n.get(a)}}var S="[data-reactive-enable], [data-reactive-select-all], [data-reactive-count]";function ve(e){return!!e.root.querySelector?.(S)}function N(e,r,t,n){return[...e.root.querySelectorAll(G(r,n))].filter((o)=>o.type==="checkbox"&&t(o))}function be(e,r){let t=r?.getAttribute?.("data-reactive-select-all");if(t&&e.core.owns(r))B(e,t,r.checked,r)}function ze(e,r,t){if(!r)return;let n=C.get(e)??{root:e,core:{ownership:()=>(o)=>o.closest('[data-controller~="reactive"]')===e}};B(n,r,t!==!1),n.show?.()}function B(e,r,t,n){let o=e.root.getAttribute?.("data-reactive-scope")||null,i=N(e,r,e.core.ownership(),o).filter((a)=>a!==n&&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 Ae(e,r,t,n){for(let o of e.root.querySelectorAll(S)){if(!t(o))continue;let i=o.getAttribute("data-reactive-enable");if(i!==null){let l=P(I(i),r);if(l!==null)o.disabled=!l}let a=o.getAttribute("data-reactive-count");if(a){let l=String(r(a,!0));if(o.textContent!==l)o.textContent=l}let s=o.getAttribute("data-reactive-select-all");if(s){let l=N(e,s,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 we(e,r){for(let[t,n]of Object.entries(W(e,"group",'"ids[]" => { ... }, "tags[]" => { ... }'))){if(!n||typeof n!=="object"||Array.isArray(n))continue;let o=String(r(t,!0));for(let a of Array.isArray(n.count)?n.count:[]){if(!A(a,"group"))continue;for(let s of document.querySelectorAll(a))if(s.textContent!==o)s.textContent=o}let i=n.enable&&typeof n.enable==="object"?n.enable:{};for(let[a,s]of Object.entries(i)){if(!A(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 L(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?.(`${S}, [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 w(e){return!!(e.root.getAttribute?.("data-reactive-filter-input")&&e.root.getAttribute?.("data-reactive-filter-option"))}function Se(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 n=e.core.ownership(),o=[...e.root.querySelectorAll(r)].find(n);if(!o)return;let i=(o.value??"").trim().toLowerCase(),a=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 a++}let s=e.root.getAttribute("data-reactive-filter-group");if(s)for(let c of e.root.querySelectorAll(s)){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=a>0}}function x(e){return!!e.root.getAttribute?.("data-reactive-tags-field")}function xe(e){if(typeof e.root?.querySelector!=="function")return!1;return!!e.root.querySelector("[data-reactive-nested-json]")}function O(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 K(e,r){let t=O(e);if(!t)return!1;let n=k(t),o=new Set(n.map((a)=>a.toLowerCase())),i=!1;for(let a of r){let s=String(a??"").trim();if(s===""||o.has(s.toLowerCase()))continue;o.add(s.toLowerCase()),n.push(s),i=!0}if(i)H(e,t,n);return i}function H(e,r,t){r.value=t.join(","),y(r),Y(e)}function _e(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 Y(e){let r=O(e);if(!r)return;let t=k(r),n=e.core.ownership();qe(e,t,n),Ce(e,t,n)}function qe(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 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);n.appendChild(s)}}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"),!w(e))o.hidden=!1}}if(w(e))v(e)}function Ne(e){return e.nestedIndex=Math.max(e.nestedIndex+1,Date.now()),e.nestedIndex}function Oe(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 ke(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 Ee(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(),a=[...r.querySelectorAll?.("input, select, textarea")??[]],s=[];for(let[l,c]of Object.entries(o)){let u=[...e.root.querySelectorAll?.(c)??[]].find(i);if(!u)continue;let f=a.find((_)=>U(_.getAttribute?.("name"))===l);if(!f)continue;$e(f,u),s.push(u)}if(n)for(let l of s)je(l);return s[0]??null}function $e(e,r){if(e.type==="checkbox")e.checked=r.type==="checkbox"?!!r.checked:q(r)!=="";else e.value=q(r);y(e)}function je(e){if(e.type==="checkbox")e.checked=!1;else e.value="";y(e)}function Re(e,r){if(!e.includes("%{"))return e;return e.replace(/%\{(\w+)\}/g,(t,n)=>Object.prototype.hasOwnProperty.call(r,n)?r[n]:t)}function M(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))Q(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=U(o.getAttribute?.("name"));if(i===null||i==="_destroy")continue;t[i]=q(o)}return t}function U(e){if(!e)return null;let r=e.match(/\[([^\][]+)\]$/);return r?r[1]:e}function q(e){if(e.type==="checkbox")return e.checked?e.value||"on":"";return e.value??""}function Q(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 s of[...n.querySelectorAll?.("[data-reactive-nested-row]")??[]]){if(!t(s)||s.hidden)continue;i.push(z(e,s))}let a=JSON.stringify(i);if(o.value===a)return;o.value=a,y(o)}function Ue(e,r,t){let n=p(e,r);if(!x(n))return;if(t?.defaultPrevented)return;if(n.core.listnavOptions(t).some((a)=>a.hasAttribute?.("data-reactive-highlighted")))return;t?.preventDefault?.();let o=t?.currentTarget??t?.target;if(!o)return;if(!K(n,String(o.value??"").split(",")))return;if(o.value="",w(n))v(n)}function Qe(e,r,t){let n=p(e,r);if(!x(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;if(!K(n,[i]))return;let a=_e(n);if(!a)return;a.value="",v(n),a.focus?.()}function Ze(e,r,t){let n=p(e,r);if(!x(n))return;t?.preventDefault?.();let i=(t?.currentTarget??t?.target)?.getAttribute?.("data-reactive-tag-param");if(!i)return;let a=O(n);if(!a)return;let s=k(a),l=s.filter((c)=>c.toLowerCase()!==i.toLowerCase());if(l.length===s.length)return;H(n,a,l)}function Ve(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 a=n.core.ownership(),s=[...n.root.querySelectorAll(`[data-reactive-nested-list="${i}"]`)].find(a),c=[...n.root.querySelectorAll(`[data-reactive-nested-template="${i}"]`)].find(a)?.content?.firstElementChild;if(!s||!c){ke(n,i);return}let u=c.cloneNode(!0);Oe(u,Ne(n)),s.appendChild(u);let f=o?.getAttribute?.("data-reactive-nested-from-param"),_=o?.getAttribute?.("data-reactive-nested-clear-param")==="true",ie=Ee(n,u,f,_);if(f)ie?.focus?.();else[...u.querySelectorAll?.("input, select, textarea")??[]][0]?.focus?.();if(s.getAttribute?.("data-reactive-nested-json")===i)Q(n,i)}function Xe(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 a=o?.getAttribute?.("data-reactive-confirm-param"),s=o?.getAttribute?.("data-reactive-confirm-when-param"),l=a||(s?ne(n,s):null);if(!l)return M(n,i);let c=z(n,i),u=Re(l,c);return n.core.confirm(u,{el:o,row:i,fields:c}).then((f)=>{if(f)M(n,i)})}function Z(e,r){let t=r?.target;if(!t||!e.core.owns(t))return;E(e)}var V=["gte","gt","lte","lt"],Te=["len_eq","len_gte","len_gt","len_lte","len_lt"],X=["checked_eq","checked_gte","checked_gt","checked_lte","checked_lt"];function ee(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 te(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 re(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 V)if(t in e)return te(t,e[t],r);for(let t of Te)if(t in e)return ee(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=X.find((o)=>(o in e));if(t){let o=r(e.field,!0);return ee(t,e[t],Array.isArray(o)?o.length:Number(o)||0)===!0}let n=r(e.field)??"";return re(e,n)===!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((n)=>j(n,r)))}function Le(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 Me(e){return e.flat().every((r)=>X.some((t)=>(t in Object(r))))}function ne(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=(a)=>n[a],i;if(typeof t.predicate==="string"){let a=ae(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(n)}else i=b(t.groups?.any,o)===!0;return i?t.message:null}var m;function et(e){m=e}function oe(){if(m===void 0)try{let e=document.createElement("div");e.contentEditable="plaintext-only",m=e.contentEditable==="plaintext-only"}catch{m=!1}return m}function R(e,r){let t=r.target?.closest?.("[data-reactive-editable]");return t&&e.core.owns(t)?t:null}function De(e){if(oe())return;for(let r of e.root.querySelectorAll("[data-reactive-editable][contenteditable=plaintext-only]"))r.setAttribute("contenteditable","true")}function Ie(e,r){let t=R(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 Pe(e,r){let t=R(e,r),n=t?.getAttribute("data-reactive-editable")!=="multi",o=(r.clipboardData??r.dataTransfer)?.getData("text/plain");if(!t||o==null||oe()&&!(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 We(e,r){let t=R(e,r);if(t?.firstChild&&e.core.text(t)==="")t.replaceChildren()}export{et as __setPlaintextOnlyForTest,ze as checkGroup,Ye as confirmMessage,Fe as connect,Be as disconnect,Ve as nestedAdd,Xe as nestedRemove,Ke as reseed,He as syncNestedJson,Ue as tagsAdd,Qe as tagsPick,Ze as tagsRemove};
|
|
2
2
|
|
|
3
|
-
//# debugId=
|
|
3
|
+
//# debugId=1B8B852C90C8A7F964756E2164756E21
|
|
4
4
|
//# sourceMappingURL=bindings.min.js.map
|