diff --git a/assets/css/builder.css b/assets/css/builder.css index f67bfa3..ddf760c 100644 --- a/assets/css/builder.css +++ b/assets/css/builder.css @@ -729,6 +729,12 @@ body.os-active :is( .atfb-editable, .atfb [contenteditable] ) { body.atf-drag-active, html body.atf-drag-active.atf-drag-active.atf-drag-active.atf-drag-active * { cursor: grabbing !important; + /* Mid-drag nothing is being selected either: without this, every move + paints a selection sweep across the page behind the ghost. The drag + manager clears the anchor the press already planted; this stops a new + one taking. */ + -webkit-user-select: none !important; + user-select: none !important; } /* One survivor outweighs even that: the shell restores the I-beam on text @@ -742,12 +748,40 @@ html body.atf-drag-active [contenteditable="true"] { cursor: grabbing !important; } -/* The insertion line that follows the pointer during a drag. */ +/* The slot that follows the pointer during a drag — sized inline to the card + being dragged, so the gap it opens in the list is the gap the card will + fill. The cards around it are slid aside with animated transforms by the + builder, not by this rule. */ .atfb-marker { - block-size: 3px; - border-radius: 2px; - background: var( --atfb-accent ); - margin-block: -1px; + box-sizing: border-box; + min-block-size: 3px; + border: 1.5px dashed var( --atfb-accent ); + border-radius: var( --atfb-radius ); + background: var( --atfb-accent-soft ); +} + +/* The card a drag lifted out of its list — a canvas card or a repeater + sub-card. The ghost under the pointer is the card now and the open slot + marks its landing — left in the flow it would appear twice. */ +.atfb-lifted { + display: none; +} + +/* The wrapper `buildPayload()` puts around a default ghost. It carries the + scope class the source lived under (`.atfb`, `.atfe`, …) so the clone keeps + the custom properties and type it inherited there — appended bare to + `document.body` its fonts and colours visibly shift mid-drag. The scope + root's own layout must not come with it: the class is doubled to outweigh + the root's own rules whichever manager's ghost class it ends up wearing — + the shell dresses ghosts as `os-drag-ghost`, the fallback as + `atf-drag-ghost`. */ +.atf-ghost-scope.atf-ghost-scope { + display: block; + block-size: auto; + min-block-size: 0; + background: transparent; + padding: 0; + margin: 0; } .atf-is-dragging { diff --git a/assets/js/builder.js b/assets/js/builder.js index 0bd64f0..ace83dc 100644 --- a/assets/js/builder.js +++ b/assets/js/builder.js @@ -36,6 +36,11 @@ var allTerrainFormsBuilder = function(exports) { this.active = null; this.lastEndMs = Date.now(); }; + const emit = (name, at) => { + document.dispatchEvent( + new CustomEvent(name, { detail: { payload, clientX: at?.clientX, clientY: at?.clientY } }) + ); + }; const session = { payload, isFinished: () => finished, @@ -45,6 +50,9 @@ var allTerrainFormsBuilder = function(exports) { } finished = true; cleanup(); + if (lifted) { + emit("os.drag.end"); + } opts.onCancel?.(reason); } }; @@ -60,6 +68,7 @@ var allTerrainFormsBuilder = function(exports) { ghost.style.width = `${rect.width}px`; document.body.appendChild(ghost); position(event); + emit("os.drag.start", event); }; const position = (event) => { if (ghost) { @@ -83,6 +92,7 @@ var allTerrainFormsBuilder = function(exports) { hovered = next; hovered?.onEnter?.(session); } + emit("os.drag.move", event); }; const onUp = (event) => { if (finished) { @@ -100,8 +110,10 @@ var allTerrainFormsBuilder = function(exports) { if (target && target.accept(payload)) { opts.onCommit?.(target); void target.onDrop(session, { clientX: event.clientX, clientY: event.clientY }); + emit("os.drag.end", event); return; } + emit("os.drag.end", event); opts.onCancel?.(target ? "rejected" : "no-target"); }; const onCancel = () => session.cancel("pointercancel"); @@ -198,11 +210,14 @@ var allTerrainFormsBuilder = function(exports) { const payload = event.detail?.payload; return payload && payloadTypes.includes(payload.type) ? payload.source : null; }; + const preventSelection = (event) => event.preventDefault(); const onStart = (event) => { const source = sourceOf(event); if (source) { source.classList.add("atf-is-dragging"); document.body.classList.add("atf-drag-active"); + window.getSelection()?.removeAllRanges(); + document.addEventListener("selectstart", preventSelection); } }; const onEnd = (event) => { @@ -210,6 +225,7 @@ var allTerrainFormsBuilder = function(exports) { if (source) { source.classList.remove("atf-is-dragging"); document.body.classList.remove("atf-drag-active"); + document.removeEventListener("selectstart", preventSelection); } }; document.addEventListener("os.drag.start", onStart); @@ -217,10 +233,23 @@ var allTerrainFormsBuilder = function(exports) { return () => { document.removeEventListener("os.drag.start", onStart); document.removeEventListener("os.drag.end", onEnd); + document.removeEventListener("selectstart", preventSelection); }; } + const SCOPE_CLASSES = ["atfb", "atfe", "atfs", "atfm"]; function buildPayload(type, source, data, origin, ghost) { const rect = source.getBoundingClientRect(); + if (!ghost) { + const scope = SCOPE_CLASSES.find((cls) => source.closest(`.${cls}`)); + if (scope) { + const clone = source.cloneNode(true); + clone.style.transition = ""; + clone.style.transform = ""; + ghost = document.createElement("div"); + ghost.className = `${scope} atf-ghost-scope`; + ghost.appendChild(clone); + } + } if (ghost) { ghost.style.width = `${Math.round(rect.width)}px`; ghost.style.maxWidth = `${Math.round(rect.width)}px`; @@ -6549,25 +6578,158 @@ var allTerrainFormsBuilder = function(exports) { * canvas, or from a *second* builder window, which is what the shell's * shared drag manager buys and an iframe could not. */ + /** + * The animated insertion gap for one drop container — the canvas list, or + * a repeater's zone. + * + * While a field payload is over the container, a slot the size of the + * dragged card follows the pointer, the dragged card leaves the flow, and + * the other cards slide out of the way with first/last-position + * transforms — so the list previews, in real time, exactly the layout the + * drop will produce. + * + * @param container The drop target element; the gap shows while it has + * the `is-dropping` class. + * @param itemSelector The cards that reflow, `.atfb-card` or `.atfb-subcard`. + * @param findCard Resolves a dragged field id to its card in this + * container's world, or null for one it doesn't hold. + * @param accepts Optional payload gate mirroring the drop target's + * own `accept()`, so a drag the target will refuse + * never opens a gap it cannot honour. + * @return `enter`/`leave`/`drop` to wire into the drop target, and a + * `teardown` for the document-level listeners. + */ + gapAnimator(container, itemSelector, findCard, accepts) { + const marker = el("div", { class: "atfb-marker", attrs: { "aria-hidden": "true" } }); + let shownIndex = null; + let liftedCard = null; + let slotSize = 0; + const restore = () => { + marker.remove(); + liftedCard?.classList.remove("atfb-lifted"); + liftedCard = null; + shownIndex = null; + }; + const moveAnimated = (mutate) => { + const cards = Array.from(container.querySelectorAll(itemSelector)); + const before = new Map( + cards.filter((card) => !card.classList.contains("atfb-lifted")).map((card) => [card, card.getBoundingClientRect().top]) + ); + mutate(); + for (const card of cards) { + card.style.transition = "none"; + card.style.transform = ""; + } + const moved = cards.filter((card) => { + const from = before.get(card); + if (from === void 0 || !card.isConnected || card.classList.contains("atfb-lifted")) { + return false; + } + const delta = from - card.getBoundingClientRect().top; + if (Math.abs(delta) < 0.5) { + return false; + } + card.style.transform = `translateY(${delta}px)`; + return true; + }); + void container.offsetHeight; + for (const card of cards) { + if (!moved.includes(card)) { + card.style.transition = ""; + continue; + } + card.style.transition = "transform 160ms ease"; + card.style.transform = ""; + card.addEventListener( + "transitionend", + () => { + card.style.transition = ""; + }, + { once: true } + ); + } + }; + const onMove = (event) => { + const detail = event.detail; + if (detail?.payload?.type !== FIELD_PAYLOAD_TYPE || !container.classList.contains("is-dropping")) { + return; + } + if (accepts && !accepts(detail.payload.data ?? {})) { + return; + } + const fieldId = detail.payload.data?.fieldId; + const dragged = typeof fieldId === "string" ? findCard(fieldId) : null; + const index = insertionIndex(container, itemSelector, detail.clientY ?? 0, dragged ?? void 0); + if (index === shownIndex && marker.isConnected) { + return; + } + shownIndex = index; + moveAnimated(() => { + if (dragged && dragged !== liftedCard) { + liftedCard?.classList.remove("atfb-lifted"); + dragged.classList.add("atfb-lifted"); + liftedCard = dragged; + } + marker.style.blockSize = `${Math.max(8, Math.round(slotSize))}px`; + const cards = Array.from(container.querySelectorAll(itemSelector)).filter( + (card) => card !== dragged + ); + if (index >= cards.length) { + container.append(marker); + } else { + cards[index].before(marker); + } + }); + }; + const onEnd = () => { + container.classList.remove("is-dropping"); + window.setTimeout(() => moveAnimated(restore), 0); + }; + document.addEventListener("os.drag.move", onMove); + document.addEventListener("os.drag.end", onEnd); + return { + enter: (fieldId) => { + const card = fieldId ? findCard(fieldId) : null; + slotSize = card && !card.classList.contains("atfb-lifted") ? card.getBoundingClientRect().height : slotSize || 44; + }, + leave: () => moveAnimated(restore), + drop: (clientY, source) => { + const index = shownIndex ?? insertionIndex(container, itemSelector, clientY, source ?? void 0); + restore(); + return index; + }, + teardown: () => { + document.removeEventListener("os.drag.move", onMove); + document.removeEventListener("os.drag.end", onEnd); + restore(); + } + }; + } registerCanvasTarget(list) { this.canvasTarget?.(); this.canvasTarget = null; - const marker = el("div", { class: "atfb-marker", attrs: { "aria-hidden": "true" } }); + const gap = this.gapAnimator( + list, + ".atfb-card", + (fieldId) => this.canvas.querySelector(`[data-atfb-card="${CSS.escape(fieldId)}"]`) + ); const teardown = getDragManager().registerDropTarget({ id: `atfb-canvas-${this.form?.id ?? 0}`, element: list, accept: (payload) => payload.type === FIELD_PAYLOAD_TYPE, - onEnter: () => list.classList.add("is-dropping"), + onEnter: (session) => { + list.classList.add("is-dropping"); + gap.enter(session.payload.data.fieldId); + }, onLeave: () => { list.classList.remove("is-dropping"); - marker.remove(); + gap.leave(); }, onDrop: (session, position) => { list.classList.remove("is-dropping"); - marker.remove(); const data = session.payload.data; const source = data.fieldId ? this.canvas.querySelector(`[data-atfb-card="${CSS.escape(data.fieldId)}"]`) : null; - const index = insertionIndex(list, ".atfb-card", position.clientY, source ?? void 0); + const index = gap.drop(position.clientY, source); if (data.isNew && data.fieldType) { this.addField(data.fieldType, index); return; @@ -6582,30 +6744,10 @@ var allTerrainFormsBuilder = function(exports) { } }); const zoneTeardowns = this.wireRepeaterZones(list); - const onMove = (event) => { - const detail = event.detail; - if (detail?.payload?.type !== FIELD_PAYLOAD_TYPE || !list.classList.contains("is-dropping")) { - return; - } - const dragged = detail.payload.data?.fieldId ? this.canvas.querySelector( - `[data-atfb-card="${CSS.escape(detail.payload.data.fieldId)}"]` - ) : null; - const y = detail.clientY ?? 0; - const index = insertionIndex(list, ".atfb-card", y, dragged ?? void 0); - const cards = Array.from(list.querySelectorAll(".atfb-card")).filter( - (card) => card !== dragged - ); - if (index >= cards.length) { - list.append(marker); - } else { - cards[index].before(marker); - } - }; - document.addEventListener("os.drag.move", onMove); this.canvasTarget = () => { teardown(); zoneTeardowns.forEach((zoneTeardown) => zoneTeardown()); - document.removeEventListener("os.drag.move", onMove); + gap.teardown(); }; } /** @@ -6625,30 +6767,41 @@ var allTerrainFormsBuilder = function(exports) { const teardowns = []; list.querySelectorAll("[data-atfb-repeater-zone]").forEach((zone) => { const repeaterId = zone.dataset.atfbRepeaterZone ?? ""; + const acceptsData = (raw) => { + const data = raw; + if (data.fieldId === repeaterId) { + return false; + } + const type = data.isNew ? data.fieldType : this.locateField(data.fieldId ?? "")?.field.type ?? data.field?.type; + return !!type && this.allowedInRepeater(type); + }; + const gap = this.gapAnimator( + zone, + ".atfb-subcard", + (fieldId) => list.querySelector(`[data-atfb-subfield="${CSS.escape(fieldId)}"]`), + acceptsData + ); + teardowns.push(() => gap.teardown()); teardowns.push( getDragManager().registerDropTarget({ id: `atfb-repzone-${this.form?.id ?? 0}-${repeaterId}`, element: zone, - accept: (payload) => { - if (payload.type !== FIELD_PAYLOAD_TYPE) { - return false; - } - const data = payload.data; - if (data.fieldId === repeaterId) { - return false; - } - const type = data.isNew ? data.fieldType : this.locateField(data.fieldId ?? "")?.field.type ?? data.field?.type; - return !!type && this.allowedInRepeater(type); + accept: (payload) => payload.type === FIELD_PAYLOAD_TYPE && acceptsData(payload.data), + onEnter: (session) => { + zone.classList.add("is-dropping"); + gap.enter(session.payload.data.fieldId); + }, + onLeave: () => { + zone.classList.remove("is-dropping"); + gap.leave(); }, - onEnter: () => zone.classList.add("is-dropping"), - onLeave: () => zone.classList.remove("is-dropping"), onDrop: (session, position) => { zone.classList.remove("is-dropping"); const data = session.payload.data; const source = data.fieldId ? list.querySelector( `[data-atfb-subfield="${CSS.escape(data.fieldId)}"]` ) : null; - const index = insertionIndex(zone, ".atfb-subcard", position.clientY, source ?? void 0); + const index = gap.drop(position.clientY, source); if (data.isNew && data.fieldType) { this.addFieldToRepeater(data.fieldType, repeaterId, index); return; diff --git a/assets/js/builder.min.js b/assets/js/builder.min.js index 76172b6..79d97f2 100644 --- a/assets/js/builder.min.js +++ b/assets/js/builder.min.js @@ -1,5 +1,5 @@ -var allTerrainFormsBuilder=function(ee){"use strict";class Kt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(e){if(this.active||e.origin.button!==0)return null;const{payload:t,origin:s}=e,a=s.clientX,i=s.clientY;let o=!1,l=!1,c=null,d=null,h=0,w=0;const y=()=>{document.removeEventListener("pointermove",f),document.removeEventListener("pointerup",C),document.removeEventListener("pointercancel",P),document.removeEventListener("keydown",L),window.removeEventListener("blur",P),c?.remove(),c=null,t.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),d?.onLeave?.(u),d=null,this.active=null,this.lastEndMs=Date.now()},u={payload:t,isFinished:()=>l,cancel:(T="caller")=>{l||(l=!0,y(),e.onCancel?.(T))}},x=T=>{o=!0,t.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const M=t.source.getBoundingClientRect();h=t.ghost?.offsetX??a-M.left,w=t.ghost?.offsetY??i-M.top,c=t.ghost?.element??t.source.cloneNode(!0),c.classList.add("atf-drag-ghost"),c.style.width=`${M.width}px`,document.body.appendChild(c),v(T)},v=T=>{c&&(c.style.transform=`translate3d(${T.clientX-h}px, ${T.clientY-w}px, 0)`)},f=T=>{if(l)return;if(!o){if(Math.hypot(T.clientX-a,T.clientY-i)<4)return;x(T)}v(T);const M=this.hitTest(T.clientX,T.clientY);M!==d&&(d?.onLeave?.(u),d=M,d?.onEnter?.(u))},C=T=>{if(l)return;if(!o){l=!0,y(),e.onClickOnly?.();return}const M=d;if(l=!0,y(),M&&M.accept(t)){e.onCommit?.(M),M.onDrop(u,{clientX:T.clientX,clientY:T.clientY});return}e.onCancel?.(M?"rejected":"no-target")},P=()=>u.cancel("pointercancel"),L=T=>{T.key==="Escape"&&u.cancel("escape")};return document.addEventListener("pointermove",f),document.addEventListener("pointerup",C),document.addEventListener("pointercancel",P),document.addEventListener("keydown",L),window.addEventListener("blur",P),this.active=u,u}registerDropTarget(e){return this.targets=this.targets.filter(t=>t.id!==e.id),this.targets.push(e),()=>{this.targets=this.targets.filter(t=>t.id!==e.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(e=500){return Date.now()-this.lastEndMso.right||to.bottom)continue;const l=Xt(i.element);if(l>a){s=i,a=l;continue}l===a&&s&&Vt(i.element,s.element)&&(s=i)}return s}}function Xt(n){let e=0,t=n;for(;t;)e++,t=t.parentElement;return e}function Vt(n,e){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function Se(){return window.wp?.os??null}let Ee=null;function K(){const n=Se();return n?.dragManager?n.dragManager:(Ee||(Ee=new Kt),Ee)}function Jt(n){const e=a=>{const i=a.detail?.payload;return i&&n.includes(i.type)?i.source:null},t=a=>{const i=e(a);i&&(i.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"))},s=a=>{const i=e(a);i&&(i.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"))};return document.addEventListener("os.drag.start",t),document.addEventListener("os.drag.end",s),()=>{document.removeEventListener("os.drag.start",t),document.removeEventListener("os.drag.end",s)}}function Le(n,e,t,s,a){const i=e.getBoundingClientRect();return a&&(a.style.width=`${Math.round(i.width)}px`,a.style.maxWidth=`${Math.round(i.width)}px`,a.style.boxSizing="border-box"),{type:n,source:e,data:t,ghost:{element:a,offsetX:s.clientX-i.left,offsetY:s.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}function Ce(n,e,t,s){const a=Array.from(n.querySelectorAll(e)).filter(i=>i!==s&&!i.classList.contains("atf-drag-ghost"));for(let i=0;ia.fetch(l,c,{source:"allterrain-forms"}):(l,c)=>fetch(l,c))(t,{credentials:"same-origin",...e,headers:s});if(!o.ok){let l=`Request failed with status ${o.status}.`,c="";try{const d=await o.json();l=d.message??l,c=d.code??""}catch{}throw new de(l,o.status,c)}if(o.status!==204)return await o.json()}const U=n=>$e(n);async function Qt(n){if(!W?.wpRestUrl)throw new de("AllTerrain Forms is not configured on this page.",0);const e=W.nonce?{"X-WP-Nonce":W.nonce}:{},t=Se(),s=Qe(W.wpRestUrl,n),a=t?.fetch?await t.fetch(s,{credentials:"same-origin",headers:e},{source:"allterrain-forms"}):await fetch(s,{credentials:"same-origin",headers:e});if(!a.ok)throw new de(`Request failed with status ${a.status}.`,a.status);return await a.json()}function es(n){if(!n||!n.includes("&"))return n;const e=document.createElement("textarea");return e.innerHTML=n,e.value}const X=(n,e)=>$e(n,{method:"POST",body:JSON.stringify(e)}),he=n=>$e(n,{method:"DELETE"});function et(n){const e=new URLSearchParams;for(const[s,a]of Object.entries(n))a===void 0||a===""||a===!1||e.set(s,String(a));const t=e.toString();return t?`?${t}`:""}function ue(n){const e=n?.schema?.settings;return e&&(!e.themeOverrides||Array.isArray(e.themeOverrides))&&(e.themeOverrides={...e.themeOverrides}),n}const I={config:()=>U("/config"),mailpoet:()=>U("/mailpoet"),listForms:()=>U("/forms"),listArchivedForms:()=>U("/forms?archived=1"),archiveForm:n=>X(`/forms/${n}/archive`,{}),unarchiveForm:n=>X(`/forms/${n}/unarchive`,{}),getForm:n=>U(`/forms/${n}`).then(ue),createForm:n=>X("/forms",n).then(ue),updateForm:(n,e)=>X(`/forms/${n}`,e).then(ue),duplicateForm:n=>X(`/forms/${n}/duplicate`,{}).then(ue),deleteForm:n=>he(`/forms/${n}`),preview:(n,e)=>X(`/forms/${n}/preview`,e),pages:()=>Qt("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(n=>n.map(e=>({id:e.id,title:es(e.title?.rendered??"")||`#${e.id}`}))),mergeTags:n=>U(`/forms/${n}/merge-tags`).then(e=>e.groups),analytics:(n,e="")=>U(`/forms/${n}/analytics${e?`?dimension=${encodeURIComponent(e)}`:""}`),demoStatus:()=>U("/demo"),demoSeed:n=>X("/demo",n?{count:n}:{}),demoRemove:()=>he("/demo"),listEntries:n=>U(`/entries${et(n)}`),getEntry:n=>U(`/entries/${n}`),updateEntry:(n,e)=>X(`/entries/${n}`,e),deleteEntry:n=>he(`/entries/${n}`),exportEntries:n=>U(`/entries/export${et(n)}`),listThemes:()=>U("/themes"),saveTheme:n=>X("/themes",n),deleteTheme:n=>he(`/themes/${n}`)};function r(n,e={}){const t=document.createElement(n);e.class&&(t.className=e.class),e.text!==void 0&&(t.textContent=e.text),e.html!==void 0&&(t.innerHTML=e.html),e.title&&(t.title=e.title),e.type&&"type"in t&&(t.type=e.type),e.value!==void 0&&"value"in t&&(t.value=e.value),e.placeholder!==void 0&&"placeholder"in t&&(t.placeholder=e.placeholder),e.href&&"href"in t&&(t.href=e.href);for(const[s,a]of Object.entries(e.attrs??{}))a===void 0||a===!1||t.setAttribute(s,a===!0?"":String(a));Object.assign(t.style,e.style??{});for(const[s,a]of Object.entries(e.on??{}))t.addEventListener(s,a);for(const s of e.children??[])s==null||s===!1||t.append(s);return t}function R(n){n.replaceChildren()}function z(n){return r("span",{class:`dashicons ${n.startsWith("dashicons-")?n:`dashicons-${n}`}`,attrs:{"aria-hidden":"true"}})}function g(n,e,t){const s=e.matches("input, select, textarea, button")?e:e.querySelector("input, select, textarea");if(s){const a=s.id||`atf-c-${Math.random().toString(36).slice(2,9)}`;return s.id=a,r("div",{class:"atfb-row",children:[r("label",{class:"atfb-row__label",text:n,attrs:{for:a}}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}return r("div",{class:"atfb-row",children:[r("span",{class:"atfb-row__label",text:n}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}function A(n,e,t=""){return r("input",{class:"atfb-input",type:"text",value:n,placeholder:t,on:{input:s=>e(s.target.value)}})}function G(n,e){if(Y("os-number-field")){const t=document.createElement("os-number-field");return t.setAttribute("value",n),t.classList.add("atfb-field"),t.addEventListener("os-input-change",s=>{e(String(s.detail?.value??""))}),t}return r("input",{class:"atfb-input",type:"number",value:n,on:{input:t=>e(t.target.value)}})}function pe(n,e,t=4){const s=r("textarea",{class:"atfb-input atfb-input--area",attrs:{rows:t},on:{input:a=>e(a.target.value)}});return s.value=n,s}function D(n,e,t){if(Y("os-select")&&Y("os-option")){const s=document.createElement("os-select");s.setAttribute("value",n),s.classList.add("atfb-field");for(const a of e){const i=document.createElement("os-option");i.setAttribute("value",a.value),i.textContent=a.label,s.append(i)}return s.addEventListener("os-pick",a=>{t(String(a.detail?.value??""))}),s}return r("select",{class:"atfb-input atfb-select",on:{change:s=>t(s.target.value)},children:e.map(s=>r("option",{value:s.value,text:s.label,attrs:{selected:s.value===n}}))})}function O(n,e,t){if(Y("os-checkbox-label")){const a=document.createElement("os-checkbox-label");return a.setAttribute("label",n),a.classList.add("atfb-check"),e&&a.setAttribute("checked",""),a.addEventListener("os-checkbox-change",i=>{t(!!i.detail?.checked)}),a}const s=r("input",{type:"checkbox",on:{change:a=>t(a.target.checked)}});return s.checked=e,r("label",{class:"atfb-check",children:[s,r("span",{text:n})]})}function E(n,e,t="secondary",s){const a=[s?z(s):null,r("span",{text:n})];if(Y("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",t),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${t}`),i.addEventListener("click",e);for(const o of a)o&&i.append(o);return i}return r("button",{class:`atfb-button atfb-button--${t}`,type:"button",on:{click:e},children:a})}function Y(n){return typeof customElements<"u"&&!!customElements.get(n)}const ts=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let fe=null;function ss(){if(fe)return fe;const n=window.wp?.os;return fe=n?.loadComponents?n.loadComponents(ts).catch(()=>{}):Promise.resolve(),fe}async function ie(n,e=""){const t=window.wp?.os;return t?.confirm?t.confirm({title:e,message:n,danger:!0}):window.confirm(n)}function N(n,e="",t="info"){const s=window.wp?.os;if(s?.notify){s.notify({title:n,body:e,type:t});return}console.info(`[AllTerrain Forms] ${n}${e?`: ${e}`:""}`)}function ns(n){let e=0,t;return(...s)=>{t=s,!e&&(e=window.requestAnimationFrame(()=>{e=0,n(...t)}))}}function Ae(n,e){let t=0;return(...s)=>{window.clearTimeout(t),t=window.setTimeout(()=>n(...s),e)}}function as(n){try{return window.localStorage.getItem(n)??""}catch{return""}}function is(n,e){try{window.localStorage.setItem(n,e)}catch{}}function Te(n){const e=n.closest(".os-window__body");e&&(e.addEventListener("scroll",()=>{e.scrollTop&&(e.scrollTop=0),e.scrollLeft&&(e.scrollLeft=0)},{passive:!0}),e.scrollTop=0,e.scrollLeft=0)}function tt(){const n=[window];try{window.parent&&window.parent!==window&&n.push(window.parent)}catch{}return n}function rs(n){const e=n.wp?.os?.windowManager?.getAll?.()??[];for(const t of e){const s=t.iframe??t.element?.querySelector?.("iframe");if(s&&s.contentWindow===window)return t}return null}const os=4e3,ls=100;function cs(n,e){const t=Date.now()+os,s=()=>{const a=rs(n);if(a&&a.id!==e){typeof a.close=="function"?a.close():n.wp?.os?.windowManager?.remove?.(a.id);return}!a&&Date.now()0?{form:t}:void 0;t>0&&ps(t);for(const a of tt())if(a.wp?.os?.openWindow?.(e,{source:"handoff",params:s})){window.setTimeout(()=>cs(a,e),0);return}}function hs(){document.addEventListener("click",n=>{const e=n.target?.closest?.("[data-atf-open-window]");if(!e)return;n.preventDefault();const t=e.getAttribute("data-atf-open-window")??"";for(const s of tt())if(s.wp?.os?.openWindow?.(t,{source:"handoff"}))return})}const us="allterrain-forms/requested-form";function ps(n){try{window.sessionStorage.setItem(us,String(n))}catch{}}function st(n){return`allterrain-forms/requested-form-${n}`}function fs(n){try{const e=window.sessionStorage.getItem(st(n));return window.sessionStorage.removeItem(st(n)),Number(e)||0}catch{return 0}}const Me={is:"is",is_not:"is not",contains:"contains",not_contains:"does not contain",starts_with:"starts with",ends_with:"ends with",greater:"is more than",less:"is less than",greater_equal:"is at least",less_equal:"is at most",empty:"is empty",not_empty:"has any answer"},Fe=["empty","not_empty"];function nt(n,e){const t=n.find(s=>s.id===e);return t?t.label||"an untitled question":null}function at(n,e,t){return n.find(i=>i.id===e)?.choices?.find(i=>i.value===t)?.label||t}function ms(n,e){const t=Me[n.operator]??String(n.operator);if(Fe.includes(n.operator))return t;const s=at(e,n.field,n.value);return`${n.operator==="is"?"":`${t} `}${s!==""?s:"(nothing)"}`}function it(n,e,t=0){const s=nt(e,n.field),a=Me[n.operator]??String(n.operator);if(s===null)return[{kind:"field",text:"a question that no longer exists",fieldId:n.field,missing:!0}];const i=[{kind:"field",text:s,fieldId:n.field,missing:!1},{kind:"operator",text:a,operator:n.operator,ruleIndex:t}];if(Fe.includes(n.operator))return i;const o=at(e,n.field,n.value);return i.push({kind:"value",text:o!==""?o:"(nothing)",raw:n.value,sourceId:n.field,ruleIndex:t}),i}function bs(n,e){const t=n.logic;if(!t?.enabled||!t.rules.length)return[];const s=[{kind:"verb",text:t.action==="hide"?"Hidden when":"Shown when"}];return t.rules.forEach((a,i)=>{i>0&&s.push({kind:"join",text:t.match==="all"?"and":"or"}),s.push(...it(a,e,i))}),s}function rt(n){return n.map(e=>e.text).join(" ")}function gs(n,e){return rt(it(n,e))}function me(n){const e=[];for(const t of n){const s=t.logic;if(s?.enabled)for(const a of s.rules)!a.field||a.field===t.id||e.push({from:a.field,to:t.id,label:gs(a,n),short:ms(a,n),action:s.action,broken:nt(n,a.field)===null})}return e}function vs(n){const e=new Map,t=new Set;for(const s of me(n)){const a=`${s.from}->${s.to}`;s.broken||t.has(a)||(t.add(a),e.set(s.from,(e.get(s.from)??0)+1))}return e}const ot=10,lt=22,ne="http://www.w3.org/2000/svg";class ys{constructor(e){this.edges=[],this.teardowns=[],this.frame=0,this.host=e,this.svg=document.createElementNS(ne,"svg"),this.svg.setAttribute("class","atfb-logicmap"),this.svg.setAttribute("aria-hidden","true"),this.svg.setAttribute("focusable","false"),e.append(this.svg);const t=()=>this.schedule();window.addEventListener("resize",t),this.teardowns.push(()=>window.removeEventListener("resize",t));const s=e.closest(".atfb__canvas")??e;if(s.addEventListener("scroll",t,{passive:!0}),this.teardowns.push(()=>s.removeEventListener("scroll",t)),typeof ResizeObserver<"u"){const a=new ResizeObserver(t);a.observe(e),this.teardowns.push(()=>a.disconnect())}}setEdges(e){this.edges=e,this.schedule()}highlight(e){this.svg.classList.toggle("is-focused",!!e),this.svg.querySelectorAll("[data-from]").forEach(t=>{const s=e&&(t.dataset.from===e||t.dataset.to===e);t.classList.toggle("is-lit",!!s)})}destroy(){this.teardowns.forEach(e=>e()),this.teardowns=[],this.svg.remove(),this.frame&&cancelAnimationFrame(this.frame)}schedule(){this.frame||(this.frame=requestAnimationFrame(()=>{this.frame=0,this.draw()}))}draw(){this.svg.replaceChildren();const e=this.host.getBoundingClientRect();this.svg.setAttribute("viewBox",`0 0 ${e.width} ${e.height}`),this.svg.setAttribute("width",String(e.width)),this.svg.setAttribute("height",String(e.height));const t=new Map;for(const s of this.edges){const a=this.cardRect(s.from),i=this.cardRect(s.to);if(!a||!i)continue;const o=t.get(s.from)??0;t.set(s.from,o+1),this.drawEdge(s,a,i,e,o)}}cardRect(e){const t=this.host.querySelector(`[data-atfb-card="${CSS.escape(e)}"]`);return t?t.getBoundingClientRect():null}drawEdge(e,t,s,a,i){const o=t.right-a.left,l=t.top+t.height/2-a.top,c=s.right-a.left,d=s.top+s.height/2-a.top,h=Math.max(0,a.width-ot-Math.max(o,c)),w=22+i*11+Math.min(22,Math.abs(d-l)/8),y=Math.max(12,Math.min(w,h*.4)),u=document.createElementNS(ne,"path");u.setAttribute("d",`M ${o} ${l} C ${o+y} ${l}, ${c+y} ${d}, ${c} ${d}`),u.setAttribute("class",`atfb-logicmap__path is-${e.action}${e.broken?" is-broken":""}`),u.dataset.from=e.from,u.dataset.to=e.to;const x=document.createElementNS(ne,"title");x.textContent=e.label,u.append(x);const v=document.createElementNS(ne,"circle");v.setAttribute("cx",String(c)),v.setAttribute("cy",String(d)),v.setAttribute("r","3.5"),v.setAttribute("class",`atfb-logicmap__dot is-${e.action}${e.broken?" is-broken":""}`),v.dataset.from=e.from,v.dataset.to=e.to,this.svg.append(u,v);const f=document.createElementNS(ne,"text");f.setAttribute("x",String(a.width-ot)),f.setAttribute("y",String(d+3)),f.setAttribute("text-anchor","end"),f.setAttribute("class","atfb-logicmap__label"),f.dataset.from=e.from,f.dataset.to=e.to,f.textContent=e.short.length>lt?`${e.short.slice(0,lt-1)}…`:e.short;const C=document.createElementNS(ne,"title");C.textContent=e.label,f.append(C),this.svg.append(f)}}const ws={text:"text",email:"text",url:"text",tel:"text",number:"text",password:"text",date:"text",time:"text",datetime:"text",date_range:"composite",textarea:"textarea",select:"select",country:"select",multiselect:"options",radio:"options",checkboxes:"options",image_choice:"options",quiz:"options",switch:"toggle",consent:"toggle",file:"file",range:"range",rating:"summary",scale:"summary",likert:"summary",signature:"summary",repeater:"repeater",color:"text",name:"composite",address:"composite",total:"text",hidden:"static",heading:"static",html:"static",divider:"static",spacer:"static",page_break:"static"};function _s(n){return ws[n]??"text"}function ct(n,e){const t=/^choice:(\d+):(label|value)$/.exec(e);return String(t?n.choices?.[Number(t[1])]?.[t[2]]??"":n[e]??"")}function V(n){const{value:e,onInput:t,onCommit:s}=n,a=r("span",{class:`${n.class} atfb-editable`,text:e,attrs:{contenteditable:"plaintext-only",role:"textbox",spellcheck:"false","data-placeholder":n.placeholder}});return n.bind&&(a.dataset.atfbBind=n.bind),a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("input",()=>t(a.textContent??"")),a.addEventListener("keydown",i=>{i.key==="Enter"&&(i.preventDefault(),a.blur()),i.key==="Escape"&&(a.textContent=e,a.blur()),i.stopPropagation()}),a.addEventListener("blur",()=>s?.()),a}function xs(n){const e=r("input",{class:"atf-choice__input",type:n==="checkboxes"||n==="multiselect"?"checkbox":"radio"});return e.disabled=!0,e}function dt(n,e,t){const s=_s(n.type),a=V({value:n.label,placeholder:"Write the question…",class:"atf-label",bind:"label",onInput:o=>t.edit(l=>{l.label=o}),onCommit:()=>t.restructure(()=>{})}),i=[s==="static"||s==="toggle"?null:a,Ss(n,e,s,t),ks(n,e,t)];return r("div",{class:"atfb-preview atf-form",children:[r("div",{class:`atf-field atf-field--${n.type}`,children:i})]})}function ks(n,e,t){if(!e?.supports.includes("hint"))return null;const s=V({value:n.hint??"",placeholder:"Add a hint…",class:"atf-hint",bind:"hint",onInput:a=>t.edit(i=>{i.hint=a})});return s.setAttribute("aria-label","Hint"),r("p",{class:"atfb-preview__hint",children:[s]})}function Ss(n,e,t,s){switch(t){case"text":return Ie(n,"atf-input",s);case"textarea":return Ie(n,"atf-input atf-textarea",s,!0);case"select":return r("div",{class:"atfb-preview__select",children:[Ie(n,"atf-input atf-select",s)]});case"options":return $s(n,s);case"toggle":return r("div",{class:n.type==="switch"?"atf-toggle atf-toggle--switch":"atf-toggle",children:[(()=>{const a=r("input",{class:"atf-toggle__input",type:"checkbox"});return a.disabled=!0,a})(),V({value:n.label||"",placeholder:n.type==="consent"?"What are they agreeing to?…":"What does this turn on?…",class:"atf-toggle__label",bind:"label",onInput:a=>s.edit(i=>{i.label=a}),onCommit:()=>s.restructure(()=>{})})]});case"file":return r("div",{class:"atf-file",children:[r("input",{class:"atf-file__input",type:"file"})]});case"range":return r("input",{class:"atf-range__input",type:"range"});case"composite":return r("div",{class:"atf-composite__parts",children:[r("span",{class:"atf-input atfb-preview__ghost",text:""}),r("span",{class:"atf-input atfb-preview__ghost",text:""})]});case"static":return As(n,e,s);case"repeater":return Es(n,s);default:return r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — set this up in the panel on the right.`})]})}}function Es(n,e){const t=n.fields??[],s=r("div",{class:"atfb-repeater__zone",attrs:{"data-atfb-repeater-zone":n.id}});return t.forEach(a=>s.append(Ls(n,a,e))),t.length||s.append(r("p",{class:"atfb-repeater__empty",text:"Drag fields from the palette in here — the visitor gets a fresh copy of each with every row they add."})),r("div",{class:"atfb-repeater",attrs:{"data-atfb-repeater":n.id},children:[r("div",{class:"atf-repeater__row atfb-repeater__frame",children:[r("div",{class:"atf-repeater__row-head",children:[r("span",{class:"atf-repeater__title atfb-repeater__title",children:[V({value:String(n.itemLabel??""),placeholder:"Row",class:"atfb-repeater__item-label",bind:"itemLabel",onInput:a=>e.edit(i=>{i.itemLabel=a})}),r("span",{class:"atfb-repeater__ordinal",text:"1",attrs:{"aria-hidden":"true"}})]})]}),s]}),Cs(n,e)]})}function Ls(n,e,t){const s=e.id,a=l=>c=>{const d=(c.fields??[]).find(h=>h.id===s);d&&l(d)},i={edit:l=>t.edit(a(l)),restructure:l=>t.restructure(a(l)),types:t.types,selectedId:t.selectedId},o=t.types?.(e.type);return r("div",{class:`atfb-subcard${t.selectedId===s?" is-selected":""}`,attrs:{"data-atfb-subfield":s,"data-atfb-parent":n.id,tabindex:"0",role:"button","aria-label":`${e.label||o?.label||e.type}, inside ${n.label||"the repeater"}`},children:[r("div",{class:"atfb-subcard__head",children:[r("span",{class:"atfb-subcard__type",text:o?.label??e.type}),e.required?r("span",{class:"atfb-subcard__required",text:"Required"}):null,r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this field from the repeater",attrs:{"aria-label":`Remove ${e.label||o?.label||"this field"}`},on:{pointerdown:l=>l.stopPropagation(),click:l=>{l.stopPropagation(),t.restructure(c=>{const d=c.fields??[],h=d.findIndex(w=>w.id===s);h>=0&&d.splice(h,1)})}},children:[r("span",{text:"×"})]})]}),dt(e,o,i)]})}function Ie(n,e,t,s=!1){const a=V({value:n.placeholder??"",placeholder:n.type==="select"||n.type==="country"?"Choose…":"Placeholder…",class:`${e} atfb-preview__box${s?" atfb-preview__box--tall":""}`,bind:"placeholder",onInput:i=>t.edit(o=>{o.placeholder=i})});return a.setAttribute("aria-label","Placeholder"),a}function De(n,e,t,s,a,i){return r("span",{class:`atf-button ${t} atfb-preview__button`,children:[V({value:n,placeholder:e,class:"atfb-preview__button-text",bind:s,onInput:o=>a.edit(l=>i(l,o))})]})}function Cs(n,e){return De(String(n.addLabel??""),"Add another","atf-button--ghost atfb-repeater__add","addLabel",e,(t,s)=>{t.addLabel=s})}function $s(n,e){const t=r("div",{class:"atf-choices__list"});return(n.choices??[]).forEach((s,a)=>{t.append(r("div",{class:"atf-choice atfb-preview__option",children:[xs(n.type),V({value:s.label,placeholder:"Option…",class:"atf-choice__label",bind:`choice:${a}:label`,onInput:i=>{e.edit(o=>{const l=o.choices?.[a];if(!l)return;const c=!l.value||l.value===l.label;l.label=i,c&&(l.value=i)})}}),r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this option",attrs:{"aria-label":`Remove ${s.label||"this option"}`},on:{pointerdown:i=>i.stopPropagation(),click:i=>{i.stopPropagation(),e.restructure(o=>{o.choices.splice(a,1)})}},children:[r("span",{text:"×"})]})]}))}),t.append(r("button",{class:"atfb-preview__add",type:"button",on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.restructure(a=>{const i=a.choices.length+1;a.choices.push({label:`Option ${i}`,value:`Option ${i}`})})}},children:[r("span",{text:"+ Add option"})]})),r("fieldset",{class:"atf-choices",children:[t]})}function As(n,e,t){return n.type==="heading"?V({value:n.label,placeholder:"Section heading…",class:"atf-heading",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})}):n.type==="divider"?r("hr",{class:"atf-divider"}):n.type==="page_break"?r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-progress-name",children:[V({value:n.label,placeholder:"Name this step…",class:"atf-progress__label",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})})]}),r("p",{class:"atfb-preview__summary",text:"Everything after this is a new page."}),r("div",{class:"atf-nav atfb-preview__nav",children:[De(String(n.prevLabel??""),"Back","atf-button--secondary","prevLabel",t,(s,a)=>{s.prevLabel=a}),De(String(n.nextLabel??""),"Next","","nextLabel",t,(s,a)=>{s.nextLabel=a})]})]}):r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — nothing is shown to the visitor here.`})}const qe=new Map;function Oe(n){let e=qe.get(n);return e||(e=I.mergeTags(n).catch(()=>[]),qe.set(n,e)),e}function Ts(n){qe.delete(n)}function Ms(n){const e=new Map;for(const t of n)for(const s of t.items)e.set(s.tag,s);return e}function Fs(n,e){const t=Ms(e);return n.replace(/\{[a-z_]+(?::[^}]*)?\}/gi,s=>{const a=t.get(s.toLowerCase());return a?a.sample:s})}function Is(n){return/\{[a-z_]+(?::[^}]*)?\}/i.test(n)}let te=null;function re(){te?.remove(),te=null}typeof document<"u"&&(document.addEventListener("pointerdown",n=>{const e=n.target;e?.closest(".atfb-tagpick__open")||te&&!te.contains(e)&&re()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&te&&(re(),n.stopPropagation())}));function ht(n,e){const t=n.selectionStart??n.value.length,s=n.selectionEnd??n.value.length;n.value=n.value.slice(0,t)+e+n.value.slice(s);const a=t+e.length;n.setSelectionRange(a,a),n.focus(),n.dispatchEvent(new Event("input",{bubbles:!0}))}function Ds(n){let e=n.parentElement;for(;e&&e!==document.body;){const t=getComputedStyle(e).overflowY;if(t==="auto"||t==="scroll"||t==="hidden")return e.getBoundingClientRect().bottom;e=e.parentElement}return window.innerHeight}function qs(n,e){const t=r("input",{class:"atfb-input atfb-tagpick__search",type:"search",placeholder:"Search values…",attrs:{"aria-label":"Search values"}}),s=r("div",{class:"atfb-tagpick__list"}),a=i=>{s.replaceChildren();const o=i.trim().toLowerCase();let l=0;for(const c of n){const d=c.items.filter(h=>!o||h.label.toLowerCase().includes(o)||h.tag.toLowerCase().includes(o));if(!d.length){c.empty&&!o&&!c.items.length&&s.append(r("p",{class:"atfb-tagpick__group",text:c.label}),r("p",{class:"atfb-tagpick__empty",text:c.empty}));continue}s.append(r("p",{class:"atfb-tagpick__group",text:c.label}));for(const h of d)l+=1,s.append(r("button",{class:"atfb-tagpick__item",type:"button",on:{click:()=>{e(h.tag),re()}},children:[r("span",{class:"atfb-tagpick__item-main",children:[r("span",{class:"atfb-tagpick__label",text:h.label}),r("code",{class:"atfb-tagpick__tag",text:h.tag})]}),h.hint||h.sample?r("span",{class:"atfb-tagpick__meta",text:h.sample?`e.g. ${h.sample}`:h.hint}):null]}))}!l&&o&&s.append(r("p",{class:"atfb-tagpick__empty",text:`Nothing matches “${i}”.`}))};return a(""),t.addEventListener("input",()=>a(t.value)),r("div",{class:"atfb-tagpick",attrs:{role:"dialog","aria-label":"Insert a value"},children:[r("p",{class:"atfb-tagpick__intro",text:"Pick something to drop in. It is filled in when the form is submitted."}),t,s]})}function ut(n,e){const t=r("button",{class:"atfb-button atfb-button--ghost atfb-tagpick__open",type:"button",title:"Insert a value from the submission",children:[z("shortcode"),r("span",{text:"Insert a value"})]}),s=r("div",{class:"atfb-taggable",children:[n,r("div",{class:"atfb-taggable__tools",children:[t]})]}),a=e.preview===!1?null:r("p",{class:"atfb-taggable__preview"});a&&s.append(a);const i=()=>{if(a){if(!Is(n.value)){a.textContent="",a.hidden=!0;return}Oe(e.formId).then(o=>{a.hidden=!1,a.replaceChildren(r("span",{class:"atfb-taggable__preview-label",text:"Reads as"}),r("span",{text:Fs(n.value,o)}))})}};return n.addEventListener("input",i),i(),t.addEventListener("click",o=>{if(o.stopPropagation(),te&&s.contains(te)){re();return}re(),Oe(e.formId).then(l=>{const c=qs(l,d=>{ht(n,d),i()});s.append(c),te=c,(window.innerHeight-c.getBoundingClientRect().topDs(s))&&c.classList.add("atfb-tagpick--above"),c.querySelector(".atfb-tagpick__search")?.focus()})}),s}function pt(n,e){const t=parseFloat(String(n??""));return Number.isFinite(t)?t:e}function ft(n,e){let t=e[0];for(const s of e)Math.abs(s.at-n)n.accent??"#2271b1",apply:n=>({accent:n,"accent-soft":`color-mix( in srgb, ${n} 12%, transparent )`,"border-focus":n,"focus-ring-color":n,"button-bg":n,"button-bg-hover":`color-mix( in srgb, ${n} 88%, #000 )`})},{id:"roundness",label:"Roundness",hint:"Corners, everywhere at once.",kind:"scale",steps:Ne.map(({value:n,label:e})=>({value:n,label:e})),owns:["radius-field","radius-button","radius-card","radius-check"],read:n=>ft(pt(n["radius-field"],4),Ne),apply:n=>{const e=Ne.find(t=>t.value===n)?.at??4;return{"radius-field":`${e}px`,"radius-button":`${e}px`,"radius-card":`${Math.min(e*2,28)}px`,"radius-check":`${Math.min(e,6)}px`}}},{id:"density",label:"Density",hint:"How much air the form has.",kind:"scale",steps:Pe.map(({value:n,label:e})=>({value:n,label:e})),owns:["pad-field-x","pad-field-y","gap-fields","gap-label","button-pad-x","button-pad-y"],read:n=>ft(pt(n["pad-field-y"],9),Pe),apply:n=>{const e=Pe.find(t=>t.value===n)?.at??9;return{"pad-field-y":`${e}px`,"pad-field-x":`${Math.round(e*1.4)}px`,"gap-fields":`${Math.round(e*2.2)}px`,"gap-label":`${Math.max(4,Math.round(e*.7))}px`,"button-pad-y":`${e+2}px`,"button-pad-x":`${Math.round(e*2.2)}px`}}},{id:"shadow",label:"Depth",hint:"How far the form sits off the page.",kind:"scale",steps:Os,owns:["shadow-field","shadow-field-focus","shadow-button","shadow-button-hover","shadow-card"],read:n=>{const e=n["shadow-card"]??"none";return e==="none"||e.trim()===""?n["shadow-field"]&&n["shadow-field"]!=="none"?"hard":"none":e.includes("0 1px")||e.includes("2px")?"subtle":"lifted"},apply:n=>{switch(n){case"subtle":return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"0 1px 2px rgba( 0, 0, 0, 0.12 )","shadow-button-hover":"0 2px 4px rgba( 0, 0, 0, 0.16 )","shadow-card":"0 1px 3px rgba( 0, 0, 0, 0.1 )"};case"lifted":return{"shadow-field":"none","shadow-field-focus":"0 4px 12px rgba( 0, 0, 0, 0.12 )","shadow-button":"0 4px 10px rgba( 0, 0, 0, 0.16 )","shadow-button-hover":"0 8px 20px rgba( 0, 0, 0, 0.2 )","shadow-card":"0 10px 30px rgba( 0, 0, 0, 0.14 )"};case"hard":return{"shadow-field":"3px 3px 0 currentColor","shadow-field-focus":"5px 5px 0 currentColor","shadow-button":"4px 4px 0 currentColor","shadow-button-hover":"2px 2px 0 currentColor","shadow-card":"none"};default:return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"none","shadow-button-hover":"none","shadow-card":"none"}}}},{id:"field-style",label:"Fields",hint:"How an input is drawn.",kind:"choice",steps:Ns,owns:["field-style"],read:n=>n["field-style"]??"outline",apply:n=>({"field-style":n})},{id:"labels",label:"Labels",hint:"Where the question sits relative to the answer.",kind:"choice",steps:Ps,owns:["label-position"],read:n=>n["label-position"]??"top",apply:n=>({"label-position":n})}]}function Rs(n){return Re().find(e=>e.owns.includes(n))??null}function mt(n){let e=n.activeSlug,t={...n.overrides},s=n.themes;const a=p=>{t=p,n.onOverridesReplaced?.({...p})},i=r("div",{class:"atfs-preview__frame"}),o=r("div",{class:"atfs-controls__body"}),l=r("div",{class:"atfs-quick"}),c=r("div",{class:"atfs-themes"}),d=Ae(async()=>{try{const p=await n.previewFor(e,t),b=i.closest(".atf-studio__preview"),_=b?.scrollTop??0;i.innerHTML=p,b&&(b.scrollTop=_),document.dispatchEvent(new CustomEvent("alltfo-refresh"))}catch(p){R(i),i.append(r("p",{class:"atfb-error",text:p instanceof Error?p.message:"Preview failed."}))}},180),h={"label-position":"atf-labels-","field-style":"atf-fields-"},w=(p,b,_)=>{const k=_.replace(/[^a-z0-9_-]/gi,"");for(const $ of[...p.classList])$.startsWith(b)&&p.classList.remove($);k&&p.classList.add(b+k)},y=p=>{const b=i.querySelector(".atf-form-wrap"),_=b?.querySelector(".atf-form");if(b)for(const[k,$]of Object.entries(p))$===""?b.style.removeProperty(`--atf-${k}`):b.style.setProperty(`--atf-${k}`,$),_&&h[k]&&w(_,h[k],$||(s.find(B=>B.slug===e)?.resolved[k]??""))},u=p=>{y(p.resolved);const b=i.querySelector(".atf-form");b&&(w(b,"atf-theme-",p.slug),b.classList.toggle("atf-is-dark",!!p.dark))},x=p=>t[p.token]!==void 0?t[p.token]:s.find(_=>_.slug===e)?.resolved?.[p.token]??p.default,v=()=>{R(c);for(const p of s){const b=r("button",{class:`atfs-theme${p.slug===e?" is-active":""}`,type:"button",attrs:{"aria-pressed":p.slug===e,title:p.description},children:[r("span",{class:"atfs-theme__chip",style:{background:p.resolved.surface??"#fff",borderColor:p.resolved.border??"#ccc",borderRadius:p.resolved["radius-field"]??"4px",boxShadow:p.resolved["shadow-card"]??"none"},children:[r("span",{class:"atfs-theme__accent",style:{background:p.resolved.accent??"#2271b1",borderRadius:p.resolved["radius-button"]??"4px"}})]}),r("span",{class:"atfs-theme__name",text:p.label}),p.custom?r("span",{class:"atfb-badge",text:"yours"}):null],on:{click:()=>{e=p.slug,a({}),n.onTheme(e),u(p),v(),L(),P(),Yt()}}});c.append(b)}},f=()=>{const b={...s.find(_=>_.slug===e)?.resolved??{}};for(const[_,k]of Object.entries(t))b[_]=k;return b},C=p=>{const b=l.closest(".atf-studio__controls"),_=b?.scrollTop??0;p(),b&&(b.scrollTop=_)},P=Ae(()=>C(m),150),L=()=>{const p=f(),b=l.querySelectorAll(".atfs-dial");Re().forEach((_,k)=>{const $=b[k];if(!$)return;const B=_.read(p);if(_.kind==="colour"){const q=$.querySelector('input[type="color"]'),Z=$.querySelector("input.atfb-input");q&&document.activeElement!==q&&(q.value=be(B)),Z&&document.activeElement!==Z&&(Z.value=B);return}$.querySelectorAll(".atfs-segment").forEach((q,Z)=>{const Q=_.steps?.[Z]?.value===B;q.classList.toggle("is-on",Q),q.setAttribute("aria-pressed",String(Q))})})},T=(p,b)=>{const _=p.apply(b,f());for(const[k,$]of Object.entries(_))t[k]=$,n.onOverride(k,$);y(_),L(),P()},M=()=>{R(l);const p=f();for(const b of Re()){const _=b.read(p);let k;if(b.kind==="colour"){const $=r("input",{class:"atfs-color",type:"color",value:be(_),attrs:{"aria-label":b.label},on:{input:B=>T(b,B.target.value)}});k=r("div",{class:"atfs-color-row",children:[$,A(_,B=>T(b,B))]})}else k=r("div",{class:`atfs-segmented atfs-segmented--${b.kind}`,attrs:{role:"group","aria-label":b.label},children:(b.steps??[]).map($=>r("button",{class:`atfs-segment${$.value===_?" is-on":""}`,type:"button",text:$.label,attrs:{"aria-pressed":$.value===_},on:{click:()=>T(b,$.value)}}))});l.append(r("div",{class:"atfs-dial",children:[r("div",{class:"atfs-dial__head",children:[r("span",{class:"atfs-dial__label",text:b.label}),r("span",{class:"atfs-dial__hint",text:b.hint})]}),k]}))}},m=()=>{R(o);const p=new Map;for(const _ of n.tokens){const k=p.get(_.group)??[];k.push(_),p.set(_.group,k)}const b={colour:"Colour",shape:"Corners and borders",shadow:"Shadows",fields:"Field style",space:"Spacing",type:"Type",labels:"Labels",button:"Buttons",focus:"Focus ring",motion:"Motion"};for(const[_,k]of p)o.append(r("details",{class:"atfs-group",attrs:{open:_==="colour"},children:[r("summary",{text:b[_]??_}),...k.map($=>F($))]}))},F=p=>{const b=x(p),_=q=>{q===""?delete t[p.token]:t[p.token]=q,n.onOverride(p.token,q),y({[p.token]:q})};let k;if(p.control==="color"){const q=r("input",{class:"atfs-color",type:"color",value:be(b),attrs:{"aria-label":`${p.label} colour`},on:{input:Q=>{const ce=Q.target.value;Z.value=ce,_(ce)}}}),Z=A(b,Q=>{q.value=be(Q),_(Q)});k=r("div",{class:"atfs-color-row",children:[q,Z]})}else if(p.control==="select")k=D(b,(p.options??[]).map(q=>({value:q,label:q})),_);else if(p.control==="length"){const q=parseFloat(b)||0,Z=p.unit??"px",Q=p.token.includes("radius")?60:80,ce=r("input",{class:"atfs-range",type:"range",value:String(q),attrs:{min:"0",max:String(Q),step:"1","aria-label":p.label},on:{input:ke=>{const Zt=`${ke.target.value}${Z}`;Gt.value=Zt,_(Zt)}}}),Gt=A(b,ke=>{ce.value=String(parseFloat(ke)||0),_(ke)});k=r("div",{class:"atfs-length-row",children:[ce,Gt]})}else k=A(b,_);const $=g(p.label,k),B=Rs(p.token);return B&&($.classList.add("is-dialled"),$.append(r("span",{class:"atfs-owned",text:B.label}))),t[p.token]!==void 0&&($.classList.add("is-overridden"),$.append(r("button",{class:"atfs-reset",type:"button",text:"Reset",attrs:{"aria-label":`Reset ${p.label} to the theme's value`},on:{click:()=>{_(""),C(m)}}}))),$},S=async()=>{const p=s.find(k=>k.slug===e),b=p?`${p.label} (mine)`:"My theme",_=window.prompt("Name this theme",b);if(_)try{const k={};for(const B of n.tokens){const q=x(B);q!==B.default&&(k[B.token]=q)}const $=await I.saveTheme({label:_,tokens:k});s=[...s.filter(B=>B.slug!==$.slug),$],n.onThemesChanged(s),e=$.slug,a({}),n.onTheme(e),v(),L(),C(m),N("Theme saved",$.label)}catch(k){N("Could not save the theme",k instanceof Error?k.message:"","error")}},j=async()=>{const p=s.find(b=>b.slug===e);if(p?.custom&&await ie(`Delete “${p.label}”? Forms using it fall back to Clean.`,"Delete theme"))try{await I.deleteTheme(p.id),s=s.filter(_=>_.slug!==p.slug),n.onThemesChanged(s),e="clean",a({}),n.onTheme(e),v(),L(),C(m);const b=s.find(_=>_.slug===e);b&&u(b)}catch(b){N("Could not delete the theme",b instanceof Error?b.message:"","error")}},H=async()=>{const p=s.find(k=>k.slug===e),b={label:p?.label??e,tokens:{...p?.tokens??{},...t}},_=JSON.stringify(b,null," ");try{await navigator.clipboard.writeText(_),N("Theme copied","Paste it into another site to import it.")}catch{window.prompt("Copy this theme",_)}},le=()=>{const p=window.prompt("Paste a theme");if(p)try{const b=JSON.parse(p);if(!b.tokens||typeof b.tokens!="object")throw new Error("That does not look like a theme.");for(const[_,k]of Object.entries(b.tokens))t[_]=String(k),n.onOverride(_,String(k));y({...t}),L(),C(m)}catch(b){N("Could not read that theme",b instanceof Error?b.message:"","error")}},zt=E("Delete",()=>void j(),"danger"),Yt=()=>{const p=s.find(b=>b.slug===e);zt.hidden=!p?.custom};return v(),M(),m(),d(),Yt(),r("div",{class:"atf-studio",children:[r("div",{class:"atf-studio__top",children:[r("div",{class:"atf-studio__topbar",children:[r("h2",{class:"atf-studio__heading",text:"Theme"}),r("div",{class:"atfs__actions",children:[E("Save as a theme",()=>void S(),"primary"),E("Export",()=>void H()),E("Import",le),zt]})]}),c]}),r("div",{class:"atf-studio__panes",children:[r("aside",{class:"atf-studio__controls",children:[r("p",{class:"atfb-hint",text:"Changes apply to this form only, until you save them as a theme."}),l,r("details",{class:"atfs-advanced",children:[r("summary",{text:"Every setting"}),r("p",{class:"atfb-hint",text:"The full token list. The dials above write into it."}),o]})]}),r("main",{class:"atf-studio__preview",children:[r("h2",{class:"screen-reader-text",text:"Live preview"}),i]})]})]})}async function Be(){const n=document.querySelector("[data-atfs-root]");if(!n||n.dataset.atfsMounted)return;n.dataset.atfsMounted="1",Te(n);const e=n.querySelector("[data-atfs-bar]"),t=n.querySelector(".atfs__body")??n;try{const[s,a,i]=await Promise.all([I.config(),I.listThemes(),I.listForms()]);if(!i.length){R(t),t.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms to preview"}),r("p",{text:"Make a form first — a theme needs something to dress."})]}));return}let o=i[0],l={},c=o.theme;const d=()=>{R(t),t.append(mt({themes:a,tokens:s.tokens,activeSlug:c,overrides:l,standalone:!0,onTheme:h=>{c=h},onOverride:(h,w)=>{w===""?delete l[h]:l[h]=w},onOverridesReplaced:h=>{l={...h}},previewFor:async(h,w)=>{const y=await I.getForm(o.id);y.schema.settings.theme=h,y.schema.settings.themeOverrides=w;const{html:u}=await I.preview(o.id,{schema:y.schema,theme:h});return u},onThemesChanged:h=>{a.length=0,a.push(...h)}}))};e&&(R(e),e.append(r("span",{class:"atfs__label",text:"Preview against"}),D(String(o.id),i.map(h=>({value:String(h.id),label:h.title||"(untitled)"})),h=>{o=i.find(w=>String(w.id)===h)??i[0],l={},d()}))),d()}catch(s){R(t),t.append(r("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load themes."}))}}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void Be()):Be(),document.addEventListener("os-window-content-loaded",()=>void Be()));function be(n){const e=n.trim();return/^#[0-9a-f]{6}$/i.test(e)?e:/^#[0-9a-f]{3}$/i.test(e)?`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`:"#888888"}const Bs="mailpoet",ge="",Hs=["checkbox","checkboxes","toggle","consent","gdpr"],bt=["email"];function gt(n){return n.schema.actions.find(e=>e.type==="mailpoet")}function He(n){const e=n?.settings??{};return{lists:Array.isArray(e.lists)?e.lists.map(Number).filter(Boolean):[],email_field:typeof e.email_field=="string"?e.email_field:"",first_name_field:typeof e.first_name_field=="string"?e.first_name_field:"",last_name_field:typeof e.last_name_field=="string"?e.last_name_field:""}}function js(n){return n?.logic?.enabled?n.logic.rules[0]?.field??ge:ge}function vt(n,e,t){const s=n.find(a=>e.includes(a.type));return s?s.id:t?n.find(a=>t.test(a.label))?.id??"":""}function Ws(n,e,t){const s=r("section",{class:"atfm-form"}),a=l=>r("span",{class:`atfm-form__mark${l?"":" atfm-form__mark--off"}`,children:[r("img",{attrs:{src:e.symbol,alt:"",width:"20",height:"20"}})]}),i=l=>{R(s),s.classList.remove("is-open"),s.append(r("div",{class:"atfm-form__head",children:[a(l.length>0),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`}),l.length?r("span",{class:"atfm-form__status is-on",text:`Subscribing → ${l.join(", ")}`}):r("span",{class:"atfm-form__status",text:"Not connected"})]}),E(l.length?"Edit":"Connect",()=>void o(),"secondary")]}))},o=async()=>{s.classList.add("is-open"),R(s),s.append(r("p",{class:"atfm-hint",text:"Loading the form…"}));let l;try{l=await I.getForm(n.id)}catch{R(s),s.append(r("p",{class:"atfm-hint",text:"Could not load this form."}));return}const c=l.schema.fields.filter(m=>m.type!=="page_break"),d=gt(l),h=He(d),w=new Set(h.lists.filter(m=>e.lists.some(F=>F.id===m)));let y=js(d),u=h.email_field||vt(c,bt,/mail/i),x=h.first_name_field,v=h.last_name_field;c.some(m=>m.id===u)||(u=vt(c,bt,/mail/i));const f=c.filter(m=>Hs.includes(m.type));!d&&f.length&&(y=f[0].id);const C=(m,F)=>[{value:"",label:F},...m.map(S=>({value:S.id,label:S.label||S.id}))],P=r("div",{class:"atfm-lists"});(()=>{R(P);for(const m of e.lists){const F=r("input",{attrs:{type:"checkbox"}});F.checked=w.has(m.id),F.addEventListener("change",()=>{F.checked?w.add(m.id):w.delete(m.id)}),P.append(r("label",{class:"atfm-list",children:[F,r("span",{text:m.name})]}))}})();const T=async(m=!1)=>{const F=l.schema.actions.filter(S=>S.type!=="mailpoet");if(!m){if(!w.size){N("Pick a list","A subscription needs at least one MailPoet list.","error");return}if(!u){N("Pick the email field","MailPoet needs to know which answer is the address.","error");return}F.push({id:Bs,type:"mailpoet",enabled:!0,logic:y===ge?{enabled:!1,action:"show",match:"all",rules:[]}:{enabled:!0,action:"show",match:"all",rules:[{field:y,operator:"not_empty",value:""}]},settings:{lists:[...w],email_field:u,first_name_field:x,last_name_field:v}})}l.schema.actions=F;try{await I.updateForm(l.id,{schema:l.schema})}catch(S){N("Could not save",S instanceof Error?S.message:"","error");return}N(m?"Disconnected":"Connected to MailPoet",m?`${n.title} no longer subscribes anyone.`:`${n.title} now subscribes opted-in visitors.`),i(m?[]:e.lists.filter(S=>w.has(S.id)).map(S=>S.name))};R(s);const M=m=>r("span",{class:"atfm-form__section",text:m});s.append(r("div",{class:"atfm-form__head",children:[a(!!d),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`})]}),E("Close",()=>i(d?e.lists.filter(m=>He(d).lists.includes(m.id)).map(m=>m.name):[]),"ghost")]}),r("div",{class:"atfm-form__body",children:[M("Where they land"),g("Lists",P,"MailPoet sends its own confirmation email before anyone is truly on a list."),M("Who they are"),g("Email address",D(u,C(c,"— pick a field —"),m=>{u=m}),"The answer that carries their address."),g("First name",D(x,C(c,"— none —"),m=>{x=m})),g("Last name",D(v,C(c,"— none —"),m=>{v=m})),M("When to subscribe"),g("Subscribe",D(y,[...f.map(m=>({value:m.id,label:`Only when “${m.label||m.id}” is ticked`})),{value:ge,label:"Everyone who submits"}],m=>{y=m}),f.length?"Bind it to a box they tick. Subscribing everyone is rarely what visitors expect.":"Add a checkbox or toggle field to the form to offer a proper opt-in."),r("div",{class:"atfm-form__actions",children:d?[E("Save connection",()=>void T(),"primary"),E("Disconnect",()=>void T(!0),"danger")]:[E("Save connection",()=>void T(),"primary")]})]}))};return i([]),I.getForm(n.id).then(l=>{const c=gt(l);if(c&&!s.classList.contains("is-open")){const d=e.lists.filter(h=>He(c).lists.includes(h.id)).map(h=>h.name);i(d)}}).catch(()=>{}),t.append(s),s}function Us(n){const e=n.logo?r("span",{class:"atfm-hero__logo",children:[r("img",{attrs:{src:n.logo,alt:"MailPoet",width:"210",height:"105"}})]}):r("span",{class:"atfm-hero__logo atfm-hero__logo--glyph",text:"📬"});return r("header",{class:"atfm-hero",children:[e,r("div",{class:"atfm-hero__words",children:[r("h1",{text:"Turn submissions into subscribers"}),r("p",{text:"Every submission is someone choosing to talk to you. Connect a form to MailPoet and the ones who opt in land on your lists by themselves — named, consented, and confirmed by MailPoet’s own double opt-in."}),n.active?r("p",{class:"atfm-hero__status is-on",text:n.lists.length===1?"Connected — 1 list ready for subscribers":`Connected — ${n.lists.length} lists ready for subscribers`}):r("p",{class:"atfm-hero__status",text:"MailPoet is not installed on this site yet"})]})]})}function zs(){const n=(t,s,a)=>r("div",{class:"atfm-why__card",children:[r("span",{class:"atfm-why__icon",text:t}),r("strong",{text:s}),r("p",{text:a})]}),e=(t,s)=>r("a",{text:s,attrs:{href:t,target:"_blank",rel:"noreferrer"}});return[r("div",{class:"atfm-why",children:[n("✉️","Beautiful emails, made in WordPress","Design newsletters and welcome emails in a drag-and-drop editor that lives in your own admin — no external account to juggle."),n("🤝","Consent you can stand behind","Double opt-in out of the box: every address your forms send over is confirmed by the visitor before a single campaign reaches it."),n("🚀","Free to grow with","Free up to 500 subscribers, welcome automations, WooCommerce emails and open-rate stats included — a paid addon anywhere else.")]}),r("p",{class:"atfm-links",children:[e("https://www.mailpoet.com/features/","Explore MailPoet’s features ↗"),e("https://kb.mailpoet.com/","Guides & docs ↗"),e("https://www.mailpoet.com/pricing/","Plans & the free tier ↗")]})]}function Ys(){const n=(e,t)=>r("div",{class:"atfm-step",children:[r("span",{class:"atfm-step__n",text:e}),r("span",{text:t})]});return r("div",{class:"atfm-steps",children:[n("1","Pick a form below"),n("2","Choose the lists it feeds"),n("3","Bind it to an opt-in — MailPoet confirms the rest")]})}async function je(){const n=document.querySelector("[data-atfm-root]");if(!n||n.dataset.atfmMounted)return;n.dataset.atfmMounted="1",Te(n);const e=n.querySelector("[data-atfm-bar]"),t=n.querySelector("[data-atfm-body]")??n;try{const[s,a]=await Promise.all([I.mailpoet(),I.listForms()]);if(e?.remove(),R(t),t.append(Us(s),...zs()),!s.active){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet sends newsletters from right inside WordPress — no external account, free to start. Install it and every form here gets a subscribe switch: reservations feed your announcements, signups feed your schedule, enquiries feed your news."}),r("a",{class:"atfm-pitch__cta",text:"Install MailPoet — it’s free",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}if(!s.lists.length){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet is here, but it has no list yet. Make one, and your forms will have somewhere to send subscribers."}),r("a",{class:"atfm-pitch__cta",text:"Open MailPoet lists",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}t.append(Ys());const i=r("section",{class:"atfm-forms",children:[r("div",{class:"atfm-forms__head",children:[r("h2",{text:"Your forms"}),r("p",{class:"atfm-hint",text:"Connected forms wear the MailPoet mark in colour."})]})]});if(t.append(i),!a.length){i.append(r("p",{class:"atfm-hint",text:"No forms yet — make one, then come back to connect it."}));return}for(const o of a)Ws(o,s,i)}catch{e&&(e.textContent="Could not reach the site — reload the window to try again.")}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void je()):je(),document.addEventListener("os-window-content-loaded",()=>void je());const ve={plain:"",simple:"✓",minimal:"",card:"🎉",check:"",confetti:"🎉",fireworks:"🎆",sparkles:"✨",typewriter:""};function yt(){return{style:"simple",title:"",icon:"",accent:"",intensity:"medium",showButton:!1,buttonLabel:""}}function We(n){const e={...yt(),...n??{}};return e.style in ve||(e.style="simple"),e}function Gs(){return typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}function Zs(n,e,t){const s=We(e),a=document.createElement("div");if(a.className=`atf-confirmation atf-success atf-success--${s.style}`,a.setAttribute("role","status"),a.setAttribute("tabindex","-1"),s.style==="plain")return a.className="atf-confirmation",a.innerHTML=n,a;s.accent&&a.style.setProperty("--atf-accent",s.accent);const i=document.createElement("div");i.className="atf-success__inner",a.append(i);const o=s.icon||ve[s.style];if(s.style==="check")i.insertAdjacentHTML("beforeend",'');else if(o){const c=document.createElement("span");c.className="atf-success__icon",c.setAttribute("aria-hidden","true"),c.textContent=o,i.append(c)}if(s.title){const c=document.createElement("h2");c.className="atf-success__title",c.textContent=s.title,i.append(c)}const l=document.createElement("div");if(l.className="atf-success__message",l.innerHTML=n,i.append(l),s.style==="typewriter"&&a.setAttribute("aria-label",l.textContent??""),s.showButton){const c=document.createElement("button");c.type="button",c.className="atf-button atf-button--ghost atf-success__again",c.textContent=s.buttonLabel||"Fill it in again",c.addEventListener("click",()=>t?t():window.location.reload()),i.append(c)}return a}function Ks(n,e){const t=We(e);if(Gs())return()=>{};switch(t.style){case"confetti":return Xs(n,t);case"fireworks":return Vs(t);case"sparkles":return Js(n,t);case"typewriter":return Qs(n);default:return()=>{}}}function oe(n){return{low:.5,medium:1,high:1.8}[n.intensity]}function wt(){const n=document.createElement("canvas");n.className="atf-success-canvas",n.setAttribute("aria-hidden","true");const e=Math.min(window.devicePixelRatio||1,2);n.width=Math.floor(window.innerWidth*e),n.height=Math.floor(window.innerHeight*e),document.body.append(n);const t=n.getContext("2d");return t?.scale(e,e),{canvas:n,ctx:t,stop:()=>n.remove()}}const _t=["#f43f5e","#f59e0b","#10b981","#3b82f6","#8b5cf6","#ec4899","#eab308"];function Xs(n,e){const{ctx:t,stop:s}=wt();if(!t)return s(),()=>{};const a=e.accent?[e.accent,..._t]:_t,i=[],o=n.getBoundingClientRect(),l=o.left+o.width/2,c=Math.min(o.top+40,window.innerHeight-20),d=(C,P,L)=>{const T=L?Math.PI*(1.15+.7*Math.random()):0,M=L?9+Math.random()*8:0;return{x:C,y:P,vx:L?Math.cos(T)*M*(Math.random()<.5?1:-1):(Math.random()-.5)*1.5,vy:L?Math.sin(T)*M:1+Math.random()*2,w:6+Math.random()*5,h:8+Math.random()*7,angle:Math.random()*Math.PI,spin:(Math.random()-.5)*.3,color:a[Math.floor(Math.random()*a.length)],wobble:Math.random()*Math.PI*2}},h=Math.round(90*oe(e));for(let C=0;C{if(y>=w){window.clearInterval(u);return}i.push(d(Math.random()*window.innerWidth,-20,!1)),y++},2e3/w);let x=0;const v=performance.now(),f=C=>{t.clearRect(0,0,window.innerWidth,window.innerHeight);let P=!1;for(const L of i)L.vy+=.16,L.vx*=.99,L.vy*=.985,L.wobble+=.1,L.x+=L.vx+Math.sin(L.wobble)*.8,L.y+=L.vy,L.angle+=L.spin,L.y{window.clearInterval(u),window.cancelAnimationFrame(x),s()}}function Vs(n){const{ctx:e,stop:t}=wt();if(!e)return t(),()=>{};const s=[],a=[],i=Math.round(6*oe(n))+2;let o=0;const l=()=>{s.push({x:window.innerWidth*(.15+.7*Math.random()),y:window.innerHeight,vy:-(9+Math.random()*4),targetY:window.innerHeight*(.15+.3*Math.random()),hue:Math.floor(Math.random()*360)}),o++};l();const c=window.setInterval(()=>{if(o>=i){window.clearInterval(c);return}l()},3500/i),d=u=>{const x=Math.round(70*oe(n));for(let v=0;v{e.clearRect(0,0,window.innerWidth,window.innerHeight);for(let v=s.length-1;v>=0;v--){const f=s[v];f.y+=f.vy,f.vy+=.08,e.fillStyle=`hsl(${f.hue} 90% 65%)`,e.fillRect(f.x-1.5,f.y,3,10),(f.y<=f.targetY||f.vy>=-1)&&(d(f),s.splice(v,1))}for(let v=a.length-1;v>=0;v--){const f=a[v];if(f.x+=f.vx,f.y+=f.vy,f.vy+=.045,f.vx*=.985,f.vy*=.985,f.life-=f.decay,f.life<=0){a.splice(v,1);continue}const C=f.life*(.7+.3*Math.random());e.globalAlpha=Math.max(0,C),e.fillStyle=`hsl(${f.hue} 95% ${55+25*f.life}%)`,e.beginPath(),e.arc(f.x,f.y,1.1+1.6*f.life,0,Math.PI*2),e.fill()}e.globalAlpha=1,!(o>=i&&s.length===0&&a.length===0)&&u-w<9e3?h=window.requestAnimationFrame(y):t()};return h=window.requestAnimationFrame(y),()=>{window.clearInterval(c),window.cancelAnimationFrame(h),t()}}function Js(n,e){const t=e.icon||ve.sparkles,s=Math.round(22*oe(e)),a=[];let i=0;const o=()=>{const c=document.createElement("span");c.className="atf-success__spark",c.setAttribute("aria-hidden","true"),c.textContent=t,c.style.insetInlineStart=`${4+Math.random()*92}%`,c.style.animationDuration=`${2.6+Math.random()*1.8}s`,c.style.animationDelay=`${Math.random()*.3}s`,c.style.fontSize=`${14+Math.random()*14}px`,c.addEventListener("animationend",()=>c.remove()),n.append(c),a.push(c),i++};o();const l=window.setInterval(()=>{if(i>=s){window.clearInterval(l);return}o()},2800/s);return()=>{window.clearInterval(l),a.forEach(c=>c.remove())}}function Qs(n){const e=n.querySelector(".atf-success__message");if(!e)return()=>{};const t=e.innerHTML,s=e.textContent??"";if(!s)return()=>{};e.textContent="",e.classList.add("is-typing");const a=Math.min(45,3800/s.length);let i=0;const o=window.setInterval(()=>{i++,e.textContent=s.slice(0,i),i>=s.length&&(window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t)},a);return()=>{window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t}}const en={min:-1,max:-1,sum:-1,avg:-1,round:-1,ceil:1,floor:1,abs:1,sqrt:1,pow:2},xt={"+":{precedence:1,right:!1},"-":{precedence:1,right:!1},"*":{precedence:2,right:!1},"/":{precedence:2,right:!1},"%":{precedence:2,right:!1},"^":{precedence:4,right:!0}};function tn(n,e,t=[]){if(!n||!n.trim()||n.length>2e3)return null;const s=sn(n,e,t),a=on(s);if(!a)return null;const i=cn(a);if(!i)return null;const o=dn(i);return o===null||!Number.isFinite(o)?null:o}function sn(n,e,t){return n.replace(/\{([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_]+))?\}/g,(s,a,i,o)=>nn(n,o,s.length,a,i??"",e,t))}function nn(n,e,t,s,a,i,o){const l=an(o,s),c=Object.prototype.hasOwnProperty.call(i,s)?i[s]:null;if(a===""){const u=l?.type==="repeater"?kt(c).length:Ue(c,l);return St(u)}const h=(l?.fields??[]).find(u=>u.id===a)??null,w=kt(c).map(u=>Ue(u[a]??"",h));if(!w.length)return"0";const y=w.map(St);return rn(n,e,t)?y.join(", "):y.length===1?y[0]:`( ${y.join(" + ")} )`}function an(n,e){for(const t of n){if(t.id===e)return t;for(const s of t.fields??[])if(s.id===e)return s}return null}function rn(n,e,t){const s=n.slice(e+t).replace(/^\s+/,"");if(s===""||s[0]!==")")return!1;const a=n.slice(0,e).replace(/\s+$/,""),i=/([a-zA-Z_][a-zA-Z0-9_]*)\s*\($/.exec(a);return!!i&&["sum","avg","min","max"].includes(i[1].toLowerCase())}function kt(n){if(!Array.isArray(n))return[];const e=[];for(const t of n){if(!t||typeof t!="object"||Array.isArray(t))continue;Object.values(t).some(a=>a!==""&&a!==null&&a!==void 0&&a!==!1&&!(Array.isArray(a)&&!a.length))&&e.push(t)}return e}function St(n){const e=n.toFixed(10).replace(/0+$/,"").replace(/\.$/,"");return e===""||e==="-"?"0":e}function Ue(n,e){if(typeof n=="boolean")return n?1:0;if(Array.isArray(n))return n.reduce((a,i)=>a+Ue(i,e),0);if(n==null||n==="")return 0;const t=e?.choices??[];for(const a of t)if(String(a.value)===String(n)){if(typeof a.price=="number")return a.price;if(typeof a.points=="number")return a.points;break}const s=Number(n);return Number.isFinite(s)?s:0}function on(n){const e=[];let t=0;for(;ti.precedence||l.precedence===i.precedence&&!i.right){e.push(t.pop());continue}break}t.push(a);break}case"(":t.push(a);break;case")":{for(;t.length&&t[t.length-1].type!=="(";)e.push(t.pop());if(!t.length)return null;if(t.pop(),t.length&&t[t.length-1].type==="function"){const i=t.pop();i.arity=s.length?s.pop():1,e.push(i)}break}}for(;t.length;){const a=t.pop();if(a.type==="(")return null;e.push(a)}return e}function dn(n){const e=[];for(const t of n)switch(t.type){case"number":e.push(t.value);break;case"unary":{if(!e.length)return null;e.push(-e.pop());break}case"operator":{if(e.length<2)return null;const s=e.pop(),a=e.pop();switch(t.value){case"+":e.push(a+s);break;case"-":e.push(a-s);break;case"*":e.push(a*s);break;case"/":e.push(s===0?0:a/s);break;case"%":e.push(s===0?0:a%s);break;case"^":e.push(Math.pow(a,s));break;default:return null}break}case"function":{const s=t.arity??1;if(e.lengtht+s,0);case"avg":return e.reduce((t,s)=>t+s,0)/e.length;case"round":{const t=Math.max(-10,Math.min(10,Math.trunc(e[1]??0))),s=Math.pow(10,t);return Math.round(e[0]*s)/s}case"ceil":return Math.ceil(e[0]);case"floor":return Math.floor(e[0]);case"abs":return Math.abs(e[0]);case"sqrt":return e[0]<0?0:Math.sqrt(e[0]);case"pow":return Math.pow(e[0],e[1]??2);default:return null}}const un=["sum","min","max","avg","round","ceil","floor","abs","sqrt","pow"],Et=["number","range","scale","rating","total","select","multiselect","radio","checkboxes","switch","quiz"];function ze(n,e){return n.filter(t=>t.id!==e&&Et.includes(t.type))}function pn(n){const e=[];for(const t of n){if(t.type!=="repeater")continue;const s=t.label||t.id;e.push({label:`${s} (how many)`,insert:`{${t.id}}`});for(const a of t.fields??[])Et.includes(a.type)&&e.push({label:`${s} · ${a.label||a.id}`,insert:`{${t.id}.${a.id}}`})}return e}function fn(n,e){const t={};ze(n,e).forEach((s,a)=>{t[s.id]=a+1});for(const s of n){if(s.type!=="repeater"||s.id===e)continue;const a=s.fields??[],i=o=>Object.fromEntries(a.map((l,c)=>[l.id,c+1+o]));t[s.id]=[i(0),i(1)]}return t}function mn(n){const e=r("div",{class:"atfb-overlay"}),t=()=>{e.remove(),document.removeEventListener("keydown",s)},s=u=>{u.key==="Escape"&&t()},a=r("textarea",{class:"atfb-input atfb-formula__input",attrs:{rows:"3","aria-label":"Formula"}});a.value=String(n.field.formula??"");const i=r("p",{class:"atfb-formula__result",attrs:{"aria-live":"polite"}}),o=fn(n.fields,n.field.id),l=()=>{const u=a.value.trim();if(u===""){i.textContent="Empty. Reference a question below to start.",i.classList.remove("is-error");return}const x=tn(u,o,n.fields);if(x===null){i.textContent="This does not compute yet — check the braces and parentheses.",i.classList.add("is-error");return}const v=ze(n.fields,n.field.id).map((f,C)=>`${f.label||f.id} = ${C+1}`).concat(n.fields.filter(f=>f.type==="repeater"&&f.id!==n.field.id).map(f=>`${f.label||f.id} = 2 sample rows`)).join(", ");i.textContent=`With sample answers (${v}): ${x}`,i.classList.remove("is-error")};a.addEventListener("input",l);const c=(u,x,v=0)=>r("button",{class:"atfb-formula__chip",type:"button",text:u,on:{click:()=>{if(ht(a,x),v>0){const f=(a.selectionStart??a.value.length)-v;a.setSelectionRange(f,f)}}}}),d=ze(n.fields,n.field.id),h=pn(n.fields),w=r("div",{class:"atfb-formula__chips",children:d.length||h.length?[...d.map(u=>c(u.label||u.id,`{${u.id}}`)),...h.map(u=>c(u.label,u.insert))]:[r("p",{class:"atfb-hint",text:"No number-shaped questions yet — add a number, scale or priced choice field and it appears here."})]}),y=r("div",{class:"atfb-formula__chips",children:un.map(u=>c(`${u}()`,`${u}()`,1))});e.append(r("div",{class:"atfb-modal atfb-formula",attrs:{role:"dialog","aria-label":"Formula editor"},children:[r("h2",{text:"Formula"}),a,i,g("Your questions",w,"Click one to reference its answer."),g("Functions",y),r("div",{class:"atfb-modal__actions",children:[E("Cancel",t),E("Save formula",()=>{n.onSave(a.value.trim()),t()},"primary")]})]})),e.addEventListener("click",u=>{u.target===e&&t()}),document.addEventListener("keydown",s),n.root.append(e),l(),a.focus(),a.setSelectionRange(a.value.length,a.value.length)}const bn="allterrain-forms/form";function gn(){return window.wp?.os?.relations??null}function Lt(n){const e=n.closest("[data-window-id], .os-window");if(!e)return null;const t=e.getAttribute("data-window-id");if(t)return t;const s=e.id??"";return s?s.replace(/^wp-window-/,""):null}const vn=6e3,Ct=120;function $t(n,e){const t=gn();if(Ye.set(n,e),!t?.set)return;const s=i=>{if(ye.get(n)!==a)return;const o=Lt(n);if(!o){Date.now()s(i),Ct);return}try{t.set(o,e)}catch(c){At||(At=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",c,e)),ye.delete(n);return}if(!e||t.get?.(o)?.id===e.id||Date.now()>=i){ye.delete(n);return}window.setTimeout(()=>s(i),Ct)},a=Symbol("atf-identity");ye.set(n,a),s(Date.now()+vn)}let At=!1;const ye=new WeakMap,Ye=new Map;function yn(){for(const[n,e]of Ye){if(!n.isConnected){Ye.delete(n);continue}$t(n,e)}}if(typeof document<"u")for(const n of["os-window-content-loaded","os-window-opened"])document.addEventListener(n,()=>yn());function wn(n,e){return{type:bn,id:n.id,label:n.title||"Untitled form",related:[{id:`allterrain-forms/entries-${n.id}`,label:"Entries for this form",url:`${e}admin.php?page=allterrain-forms-entries&form=${n.id}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-list-view"}]}}const we={letters:{label:"Letters",chars:"A-Za-zÀ-ÖØ-öø-ÿ"},numbers:{label:"Numbers",chars:"0-9"},spaces:{label:"Spaces",chars:" "},punctuation:{label:`Punctuation ( . , ! ? ' " - )`,chars:`.,!?'"()\\-:;`},symbols:{label:"Symbols ( @ # & _ / + )",chars:"@#&_/+*%="}};function _n(){return{mode:"blocks",starts:"",ends:"",contains:"",notContains:"",chars:[],minLen:"",maxLen:"",regex:"",message:"",tests:[]}}function Tt(n){const e=_n();let t;try{t=JSON.parse(n)}catch{return e}if(!t||typeof t!="object")return e;const s=t;e.mode=s.mode==="regex"?"regex":"blocks";for(const a of["starts","ends","contains","notContains","minLen","maxLen","regex","message"])typeof s[a]=="string"&&(e[a]=s[a]);return Array.isArray(s.chars)&&(e.chars=s.chars.filter(a=>typeof a=="string"&&a in we)),Array.isArray(s.tests)&&(e.tests=s.tests.filter(a=>typeof a=="string").slice(0,10)),e}function _e(n){return n.replace(/[.*+?^${}()|[\]\\/]/g,"\\$&")}function xe(n){if(n.mode==="regex")return n.regex.trim();const e=[],t=n.minLen.trim(),s=n.maxLen.trim();(t!==""||s!=="")&&e.push(`(?=.{${t===""?"0":parseInt(t,10)||0},${s===""?"":parseInt(s,10)||""}}$)`),n.contains!==""&&e.push(`(?=.*${_e(n.contains)})`),n.notContains!==""&&e.push(`(?!.*${_e(n.notContains)})`),n.starts!==""&&e.push(`(?=${_e(n.starts)})`),n.ends!==""&&e.push(`(?=.*${_e(n.ends)}$)`);const a=n.chars.map(o=>we[o]?.chars??"").join(""),i=a?`[${a}]*$`:".*$";return!e.length&&!a?"":`^${e.join("")}${i}`}function Mt(n){if(n.mode==="regex")return n.regex.trim()?`Matches the expression ${n.regex.trim()}`:"";const e=[];if(n.starts&&e.push(`starts with “${n.starts}”`),n.ends&&e.push(`ends with “${n.ends}”`),n.contains&&e.push(`contains “${n.contains}”`),n.notContains&&e.push(`never contains “${n.notContains}”`),n.chars.length){const i=n.chars.map(o=>(we[o]?.label??o).split(" (")[0].toLowerCase());e.push(`uses only ${i.join(" and ")}`)}const t=n.minLen.trim(),s=n.maxLen.trim();return t&&s?e.push(`is ${t}–${s} characters long`):t?e.push(`is at least ${t} characters long`):s&&e.push(`is at most ${s} characters long`),e.length?`The answer ${e.length>1?`${e.slice(0,-1).join(", ")}, and ${e[e.length-1]}`:e[0]}.`:""}function xn(n,e){const t=xe(n);if(t==="")return null;try{return new RegExp(t).test(e)}catch{return null}}function kn(){return window.wp?.os?.windowManager??null}const Ft="allterrain-forms-validation";function Sn(n){const e=kn(),t=Lt(n.root);if(e?.openChild&&t){En(e,t,n);return}Ln(n)}function En(n,e,t){const s=`${Ft}-${t.field.id}`;n.getById?.(s)&&n.remove?.(s);const a={saved:!1},i=()=>{const o=n.getById?.(s);o?.close?o.close():n.remove?.(s)};n.openChild?.(e,{id:s,baseId:Ft,url:`#${s}`,title:`Custom rule — ${t.field.label||"this question"}`,icon:"dashicons-yes-alt",native:!0,width:560,height:700,minWidth:440,minHeight:480,ephemeral:!0,autofocus:".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea",render:o=>{const l=r("div",{class:"atfa atfb-valwin atfb-valwin--window"}),c=r("div",{class:"atfb-valwin__scroll"});l.append(c),It(c,t,a,i,"window");const d=c.querySelector(".atfb-modal__actions");d&&l.append(d),o.append(l)},onClose:()=>{a.saved||t.onCancel?.()}})}function Ln(n){const e=r("div",{class:"atfb-overlay"}),t={saved:!1},s=()=>{e.remove(),document.removeEventListener("keydown",a),t.saved||n.onCancel?.()},a=o=>{o.key==="Escape"&&s()},i=r("div",{class:"atfb-modal atfb-valwin",attrs:{role:"dialog","aria-label":"Custom validation rule"},children:[r("h2",{text:"Custom rule"})]});It(i,n,t,s,"overlay"),e.append(i),e.addEventListener("click",o=>{o.target===e&&s()}),document.addEventListener("keydown",a),n.root.append(e),e.querySelector(".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea")?.focus()}function It(n,e,t,s,a){const i=Tt(String(e.field.validationRecipe??""));i.mode==="blocks"&&xe(i)===""&&e.field.pattern&&(i.mode="regex",i.regex=String(e.field.pattern)),i.message||(i.message=String(e.field.messages?.invalid??""));const o=(m,F)=>{const S=r("input",{class:"atfb-input",value:i[m],placeholder:F,attrs:{type:"text"}});return S.addEventListener("input",()=>{i[m]=S.value,M()}),S},l=(m,F)=>{const S=r("input",{class:"atfb-input atfb-valwin__len",value:i[m],attrs:{type:"number",min:"0","aria-label":F}});return S.addEventListener("input",()=>{i[m]=S.value,M()}),S},c=r("div",{class:"atfb-valwin__chars",children:Object.entries(we).map(([m,F])=>O(F.label,i.chars.includes(m),S=>{i.chars=S?[...i.chars,m]:i.chars.filter(j=>j!==m),M()}))}),d=r("div",{class:"atfb-valwin__pane",children:[g("Starts with",o("starts","e.g. AT-")),g("Ends with",o("ends","e.g. -2026")),g("Must contain",o("contains","e.g. @")),g("Must not contain",o("notContains","e.g. spaces? type one")),g("Only these characters",c,"Leave every box unticked to allow anything."),g("Length",r("div",{class:"atfb-valwin__lengths",children:[r("span",{text:"between"}),l("minLen","Minimum length"),r("span",{text:"and"}),l("maxLen","Maximum length"),r("span",{text:"characters"})]}),"Leave a box empty for no limit.")]}),h=r("textarea",{class:"atfb-input atfb-valwin__regex",attrs:{rows:"2","aria-label":"Regular expression",placeholder:"^AT-[0-9]{4}$"}});h.value=i.regex,h.addEventListener("input",()=>{i.regex=h.value,M()});const w=r("div",{class:"atfb-valwin__pane",children:[g("Expression",h,"A regular expression, without slashes. Checked against the whole answer only if you anchor it with ^ and $.")]}),y=[["blocks","Easy blocks"],["regex","Expression (advanced)"]],u=m=>{i.mode=m,d.hidden=m!=="blocks",w.hidden=m!=="regex",M()},v=(()=>{if(Y("os-segmented")&&Y("os-segment")){const S=document.createElement("os-segmented");S.setAttribute("value",i.mode),S.setAttribute("label","How to write the rule"),S.classList.add("atfb-valwin__tabs");for(const[j,H]of y){const le=document.createElement("os-segment");le.setAttribute("value",j),le.textContent=H,S.append(le)}return S.addEventListener("os-pick",j=>{const H=j.detail?.value;(H==="blocks"||H==="regex")&&(S.setAttribute("value",H),u(H))}),S}const m=r("div",{class:"atfb-valwin__tabs",attrs:{role:"tablist"}}),F=()=>{m.replaceChildren(...y.map(([S,j])=>{const H=i.mode===S;return r("button",{class:`atfb-valwin__tab${H?" is-active":""}`,type:"button",text:j,attrs:{role:"tab","aria-selected":H?"true":"false"},on:{click:()=>{u(S),F()}}})}))};return F(),m})();d.hidden=i.mode!=="blocks",w.hidden=i.mode!=="regex";const f=r("input",{class:"atfb-input",value:i.message,placeholder:"That is not in the expected format.",attrs:{type:"text"}});f.addEventListener("input",()=>{i.message=f.value});const C=r("p",{class:"atfb-valwin__summary",attrs:{"aria-live":"polite"}}),P=r("div",{class:"atfb-valwin__samples"}),L=m=>{const F=r("span",{class:"atfb-valwin__verdict",attrs:{"aria-live":"polite"}}),S=r("input",{class:"atfb-input",value:m,placeholder:"Type a sample answer…",attrs:{type:"text"}});S.addEventListener("input",()=>M()),P.append(r("div",{class:"atfb-valwin__sample",children:[S,F]}))};for(const m of i.tests.length?i.tests:["","",""])L(m);const T=()=>Array.from(P.querySelectorAll("input")).map(m=>m.value),M=()=>{const m=Mt(i);C.textContent=m||"Nothing yet — fill in a block above and the rule appears here in plain words.";for(const F of Array.from(P.querySelectorAll(".atfb-valwin__sample"))){const S=F.querySelector("input"),j=F.querySelector(".atfb-valwin__verdict");if(!S||!j)continue;const H=S.value===""?null:xn(i,S.value);j.textContent=H===null?"·":H?"✓ passes":"✗ fails",j.classList.toggle("is-pass",H===!0),j.classList.toggle("is-fail",H===!1)}};n.append(r("p",{class:"atfb-hint",text:`Describe what a good answer to “${e.field.label||"this question"}” looks like — no code needed.`}),v,d,w,r("div",{class:"atfb-valwin__try",children:[r("h3",{text:"Try it out"}),C,P,E("Add another sample",()=>{L(""),M()},"ghost","plus-alt2")]}),g("When it fails, say",f,"Shown to the visitor when their answer breaks the rule. Leave empty for the default wording."),r("div",{class:"atfb-modal__actions",children:[E(a==="window"?"Close without saving":"Cancel",s),E("Save rule",()=>{const m=xe(i);i.tests=T().filter(F=>F!=="").slice(0,10),t.saved=!0,e.onSave({pattern:m,recipe:i,message:i.message.trim()}),s()},"primary")]})),M()}const Cn=["Contact","Numbers & codes","Text shape","Web"],Dt=[{slug:"email",label:"An email address",group:"Contact",example:"jane@example.com",pattern:"^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",message:"That does not look like an email address."},{slug:"phone",label:"A phone number",group:"Contact",example:"+34 612 345 678",pattern:"^(?=(?:[^0-9]*[0-9]){5,})\\+?[0-9 ().-]{5,24}$",message:"That does not look like a phone number."},{slug:"handle",label:"A username or @handle",group:"Contact",example:"@yourname",pattern:"^@?[A-Za-z0-9_]{2,30}$",message:"That does not look like a username."},{slug:"digits",label:"Numbers only",group:"Numbers & codes",example:"12345",pattern:"^[0-9]+$",message:"Numbers only, please."},{slug:"decimal",label:"A number, decimals allowed",group:"Numbers & codes",example:"3.14",pattern:"^-?[0-9]+([.,][0-9]+)?$",message:"That does not look like a number."},{slug:"price",label:"A price",group:"Numbers & codes",example:"19.99",pattern:"^[0-9]+([.,][0-9]{1,2})?$",message:"That does not look like a price."},{slug:"zip_us",label:"A ZIP code (US)",group:"Numbers & codes",example:"90210",pattern:"^[0-9]{5}(-[0-9]{4})?$",message:"That does not look like a ZIP code."},{slug:"postcode_uk",label:"A postcode (UK)",group:"Numbers & codes",example:"SW1A 1AA",pattern:"^[A-Za-z]{1,2}[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}$",message:"That does not look like a postcode."},{slug:"iban",label:"An IBAN",group:"Numbers & codes",example:"DE89 3704 0044 0532 0130 00",pattern:"^[A-Za-z]{2}[0-9]{2}(?: ?[A-Za-z0-9]){10,32}$",message:"That does not look like an IBAN."},{slug:"credit_card",label:"A card number",group:"Numbers & codes",example:"4242 4242 4242 4242",pattern:"^[0-9](?:[0-9 -]{9,21})?[0-9]$",message:"That does not look like a card number.",luhn:!0},{slug:"letters",label:"Letters only",group:"Text shape",example:"María López",pattern:"^[\\p{L}\\p{M} .'’-]+$",message:"Letters only, please."},{slug:"alphanumeric",label:"Letters and numbers only",group:"Text shape",example:"abc123",pattern:"^[A-Za-z0-9]+$",message:"Letters and numbers only, please."},{slug:"no_spaces",label:"One word, no spaces",group:"Text shape",example:"one-word",pattern:"^\\S+$",message:"No spaces allowed."},{slug:"url",label:"A web address",group:"Web",example:"https://example.com",pattern:"^(https?://)?([A-Za-z0-9-]+\\.)+[A-Za-z]{2,}([/?#]\\S*)?$",message:"That does not look like a web address."},{slug:"ip",label:"An IP address",group:"Web",example:"192.168.0.1",pattern:"^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$",message:"That does not look like an IP address."},{slug:"slug",label:"A URL slug",group:"Web",example:"my-page-title",pattern:"^[a-z0-9]+(-[a-z0-9]+)*$",message:"Lowercase letters, numbers and dashes only."},{slug:"hex_color",label:"A hex colour",group:"Web",example:"#3366ff",pattern:"^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$",message:"That does not look like a colour code."}];function $n(n){return Dt.find(e=>e.slug===n)??null}function Ge(){return window.wp?.os??null}const qt="allterrain-forms/preview",Ze="allterrain-forms-preview";function An(n){const e=Ge();if(!e?.registerTitleBarButton)return()=>{};const t=()=>{try{e.registerTitleBarButton({id:qt,label:"Preview this form",icon:"dashicons-visibility",placement:"right",order:90,match:s=>{const a=s?.id??s?.config?.id??"";return a==="allterrain-forms"||a.startsWith("allterrain-forms#")},onClick:()=>void Ot(n),owner:"allterrain-forms-builder"})}catch{}};return e.ready?e.ready(t):t(),()=>{try{e.unregisterTitleBarButton?.(qt)}catch{}}}async function Ot(n){n.isDirty()&&await n.save();const e=n.current();e&&Nt(e.id,e.title,e.previewUrl)}function Nt(n,e,t){const s=Ge();if(!s?.windowManager?.open){window.open(t,"_blank","noopener");return}s.windowManager.open({id:`${Ze}-${n}`,baseId:Ze,url:t,title:`Preview: ${e}`,icon:"dashicons-visibility"})}function Tn(n,e,t){if(!Ge()?.windowManager?.open||!document.querySelector(`[data-window-id="${Ze}-${n}"]`))return;const i=t.includes("?")?"&":"?";Nt(n,e,`${t}${i}alltfo_r=${Date.now()}`)}const se="allterrain-forms/field",Mn=["openstation/file","desktop-mode/file","openstation/attachment"],Pt="allterrain-forms/logic-map-v2";function J(n,e){return n.dataset.atfbBind=e,n}const Rt={level:{key:"level",label:"Heading level",control:"select",hint:"Headings should step down one at a time.",options:[{value:"2",label:"Heading 2"},{value:"3",label:"Heading 3"},{value:"4",label:"Heading 4"},{value:"5",label:"Heading 5"},{value:"6",label:"Heading 6"}]},content:{key:"content",label:"HTML",control:"textarea",hint:"Shown as written. Scripts are stripped when the form is saved."},consenttext:{key:"consentText",label:"What they are agreeing to",control:"textarea",hint:"Shown beside the tick box. Links are allowed."},height:{key:"height",label:"Height",control:"number",hint:"In pixels."},columns:{key:"columns",label:"Columns",control:"number",hint:"How many pictures sit side by side."},multiple:{key:"multiple",label:"Let them choose more than one",control:"checkbox"},inline:{key:"inline",label:"Lay the options out in a row",control:"checkbox"},other:{key:"other",label:"Offer an “Other” box",control:"checkbox",hint:"Adds a final option with a box to type in."},filetypes:{key:"filetypes",label:"Accepted file types",control:"commas",hint:"Extensions, separated by commas. Empty accepts anything the site allows."},maxsize:{key:"maxsize",label:"Largest file",control:"number",hint:"In megabytes."},maxfiles:{key:"maxfiles",label:"How many files",control:"number"},minrows:{key:"minRows",label:"Fewest rows",control:"number",also:{key:"maxRows",label:"Most rows"}},itemlabel:{key:"itemLabel",label:"What is one row called?",control:"text",hint:"Names each card — “Attendee 1”, “Attendee 2” — and the Remove button. Also editable on the card itself."},endlabels:{key:"minLabel",label:"Label at the low end",control:"text",also:{key:"maxLabel",label:"Label at the high end"}},points:{key:"points",label:"Points if correct",control:"number"},minchoices:{key:"minChoices",label:"Fewest they may pick",control:"number",also:{key:"maxChoices",label:"Most they may pick"}}},Fn={label:"the canvas edits it in place, and the inspector mirrors it",placeholder:"edited by typing into the control on the canvas",hint:"edited under the control on the canvas",nextlabel:"edited on the page break’s own Next button",prevlabel:"edited on the page break’s own Back button",addlabel:"edited on the repeater’s own Add button",choices:"the choices editor, and the option list on the canvas",required:"the toggle on the card",width:"its own row",css:"its own row",prefill:"its own section",logic:"the conditional logic section",formula:"its own row, with the currency that goes with it",currency:"rendered with the formula",correct:"the choices editor marks the right answer",default:"its own row, typed to match what the field stores",rows:"a row count on a textarea; the statement list on a Likert matrix",parts:"a tick box per part, listed by the server",min:"the validation section, paired with max",max:"the validation section, paired with min",step:"the validation section",minlength:"the validation section, paired with maxlength",maxlength:"the validation section, paired with minlength",mindate:"the validation section, paired with maxdate",maxdate:"the validation section, paired with mindate",mintime:"the validation section, paired with maxtime",maxtime:"the validation section, paired with mintime",pattern:"the validation section",unique:"the validation section",maxchoices:"rendered with minchoices",maxrows:"rendered with minrows"};function Bt(n,e,t){const s=n[e.key],a=i=>t(e.key,i);if(e.control==="checkbox")return O(e.label,!!s,a);if(e.control==="commas"){const i=Array.isArray(s)?s:[];return g(e.label,A(i.join(", "),o=>{a(o.split(",").map(l=>l.trim().replace(/^\./,"").toLowerCase()).filter(Boolean))}),e.hint)}return e.control==="select"?g(e.label,D(String(s??""),e.options??[],a),e.hint):e.control==="textarea"?g(e.label,pe(String(s??""),a),e.hint):e.control==="number"?g(e.label,G(String(s??""),a),e.hint):g(e.label,J(A(String(s??""),a),e.key),e.hint)}function Ht(n,e){const t=new Set(n.map(a=>a.key).filter(Boolean));let s=n.length+1;return e.split(` -`).map(a=>a.trim()).filter(Boolean).map((a,i)=>{const o=n[i]?.key;if(o)return{key:o,label:a};for(;t.has(`r${s}`);)s+=1;return t.add(`r${s}`),{key:`r${s}`,label:a}})}function jt(n,e,t){const s=n.findIndex(i=>i.id===e);if(s<0)return null;const a=Math.max(0,Math.min(t,n.length-1));return a===s?null:{from:s,to:a}}const Ke=[{value:"user:email",label:"Their email address",group:"About the person filling it in",tag:"{user:email}"},{value:"user:display_name",label:"Their name",group:"About the person filling it in",tag:"{user:display_name}"},{value:"user:first_name",label:"Their first name",group:"About the person filling it in"},{value:"user:last_name",label:"Their last name",group:"About the person filling it in"},{value:"user:login",label:"Their username",group:"About the person filling it in"},{value:"date:today",label:"Today’s date",group:"The date and time",tag:"{date}"},{value:"date:now",label:"The time right now",group:"The date and time",tag:"{time}"},{value:"site",label:"This site’s name",group:"About this site",tag:"{site}"},{value:"site:url",label:"This site’s address",group:"About this site",tag:"{site:url}"},{value:"site:admin_email",label:"The site administrator’s email",group:"About this site",tag:"{admin_email}"}],In=["About the person filling it in","The date and time","About this site"],Xe=(n,e)=>W?.i18n?.[n]??e;class Wt{constructor(e){this.config=null,this.themes=[],this.forms=[],this.form=null,this.schema=null,this.selected=null,this.tab="build",this.logicMap=null,this.canvasTheme=r("style"),this.canvasThemeSignature="",this.openSections=new Map,this.logicMapOn=as(Pt)!=="off",this.dirty=!1,this.editGeneration=0,this.saveInFlight=!1,this.queuedSave=null,this.teardowns=[],this.canvasTarget=null,this.history=[],this.historyAt=-1,this.autosave=Ae(()=>{this.save(!0)},2500),this.renderInspector=ns(()=>{if(R(this.inspector),!this.schema||(this.root.classList.toggle("atfb--build-only-panes",this.tab!=="build"),this.tab!=="build"))return;const t=this.selected?this.locateField(this.selected):void 0,s=t?.field,a=t?.parent??null;if(this.root.classList.toggle("atfb--has-selection",!!s),!s){this.inspector.append(r("div",{class:"atfb-placeholder",children:[r("p",{text:"Select a field to change it."}),r("p",{class:"atfb-hint",text:"Drag a field from the palette, or press one to add it to the end."})]}));return}const i=this.config?.fieldTypes.find(c=>c.type===s.type),o=i?.supports??[],l=(c,d)=>{const h=this.liveField(s.id);h&&(h[c]=d,this.markDirty(),this.renderCanvas())};this.inspector.append(r("h3",{class:"atfb-inspector__title",text:i?.label??s.type})),a?this.inspector.append(r("p",{class:"atfb-hint atfb-inspector__crumb",text:`Inside ${a.label||"a repeater"} — the visitor answers this once per ${String(a.itemLabel??"")||"row"}.`}),r("p",{class:"atfb-hint",text:`Formulas aggregate it as {${a.id}.${s.id}} — e.g. sum( {${a.id}.${s.id}} ).`})):this.inspector.append(r("p",{class:"atfb-hint",text:`Reference this field as {field:${s.id}}`})),o.includes("label")&&this.inspector.append(g("Label",J(A(s.label,c=>l("label",c)),"label"))),o.includes("placeholder")&&this.inspector.append(g("Placeholder",J(A(s.placeholder,c=>l("placeholder",c)),"placeholder"))),o.includes("hint")&&this.inspector.append(g("Hint",J(A(s.hint,c=>l("hint",c)),"hint"),"Shown under the field, and read out with it.")),o.includes("nextlabel")&&this.inspector.append(g("Next button",J(A(String(s.nextLabel??""),c=>l("nextLabel",c)),"nextLabel"),"Leave empty for “Next”.")),o.includes("prevlabel")&&this.inspector.append(g("Back button",J(A(String(s.prevLabel??""),c=>l("prevLabel",c)),"prevLabel"),"Leave empty for “Back”.")),o.includes("addlabel")&&this.inspector.append(g("Add button",J(A(String(s.addLabel??""),c=>l("addLabel",c)),"addLabel"),"Leave empty for “Add another”.")),o.includes("required")&&this.inspector.append(O("Required",s.required,c=>l("required",c))),o.includes("width")&&this.inspector.append(g("Width",D(s.width,[{value:"full",label:"Full width"},{value:"two-thirds",label:"Two thirds"},{value:"half",label:"Half"},{value:"third",label:"One third"},{value:"quarter",label:"One quarter"}],c=>l("width",c)))),i?.choices&&this.inspector.append(this.renderChoicesEditor(s,l)),this.renderTypeSettings(s,i,o,l),(s.type==="total"||o.includes("formula"))&&this.inspector.append(g("Formula",r("div",{class:"atfb-formula__row",children:[A(String(s.formula??""),c=>l("formula",c)),E("Formula editor",()=>mn({root:this.root,fields:this.schema?.fields??[],field:s,onSave:c=>{l("formula",c),this.renderInspector()}}))]}),"Reference answers with braces — {f1} * {f2} + 10 — or open the editor and click them in."),g("Currency symbol",A(String(s.currency??""),c=>l("currency",c)))),this.inspector.append(this.renderValidationSection(s,o,l)),a||(this.inspector.append(this.renderLogicSection(s)),o.includes("prefill")&&this.inspector.append(this.prefillControl(s,l))),o.includes("css")&&this.inspector.append(g("CSS class",A(s.cssClass,c=>l("cssClass",c))))}),this.root=e,this.bar=e.querySelector("[data-atfb-bar]")??r("div"),this.palette=e.querySelector("[data-atfb-palette]")??r("div"),this.canvas=e.querySelector("[data-atfb-canvas]")??r("div"),this.inspector=e.querySelector("[data-atfb-inspector]")??r("div"),this.canvas.addEventListener("click",t=>{const s=t.target;if(!(this.tab!=="build"||!this.selected||s.closest("[data-atfb-card], button, os-button, a, input, textarea, select, os-select, label, [contenteditable]"))){this.selected=null;for(const a of this.canvas.querySelectorAll(".atfb-card.is-selected"))a.classList.remove("is-selected");this.renderInspector()}})}async start(){try{const[s,a,i]=await Promise.all([I.config(),I.listThemes(),I.listForms()]);this.config=s,this.themes=a,this.forms=i}catch(s){this.fail(s);return}this.teardowns.push(Jt([se])),this.teardowns.push(An({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)}));const e=s=>{this.dirty&&(s.preventDefault(),s.returnValue="")};window.addEventListener("beforeunload",e),this.teardowns.push(()=>window.removeEventListener("beforeunload",e));const t=s=>{!(s.metaKey||s.ctrlKey)||s.key.toLowerCase()!=="z"||s.target?.closest("input, textarea, [contenteditable]")||(s.preventDefault(),this.travel(s.shiftKey?1:-1))};if(this.root.addEventListener("keydown",t),this.teardowns.push(()=>this.root.removeEventListener("keydown",t)),this.renderBar(),this.renderPalette(),this.forms.length){const s=fs("builder");await this.open(s&&this.forms.some(a=>a.id===s)?s:this.forms[0].id)}else this.renderFormsList()}destroy(){this.canvasTarget?.(),this.canvasTarget=null,this.teardowns.forEach(e=>e()),this.teardowns=[]}fail(e){R(this.bar),this.bar.append(r("p",{class:"atfb-error",text:e instanceof Error?e.message:"Something went wrong loading your forms."}))}renderBar(){R(this.bar);const e=D(String(this.form?.id??""),[...this.forms.map(a=>({value:String(a.id),label:a.title||"(untitled)"}))],a=>void this.open(Number(a)));e.setAttribute("aria-label","Choose a form");const t=r("input",{class:"atfb-title",type:"text",value:this.form?.title??"",placeholder:"Untitled form",attrs:{"aria-label":"Form title"},on:{input:a=>{this.form&&(this.form.title=a.target.value,this.markDirty())}}}),s=r("div",{class:"atfb-tabs",attrs:{role:"tablist"},children:[["build","Build"],["theme","Theme"],["settings","Settings"],["notify","Notifications"],["confirm","Confirmations"]].map(([a,i])=>r("button",{class:`atfb-tab${this.tab===a?" is-active":""}`,type:"button",text:i,attrs:{role:"tab","aria-selected":this.tab===a},on:{click:()=>{this.tab=a,this.renderBar(),this.renderInspector(),this.renderCanvas()}}}))});this.bar.append(r("div",{class:"atfb-bar__left",children:[this.forms.length>1?e:null,t]}),s,r("div",{class:"atfb-bar__right",children:[this.historyButton("undo","Undo",-1),this.historyButton("redo","Redo",1),E("New",()=>void this.showTemplates(),"secondary","plus-alt2"),E("Export",()=>void this.exportForm(),"secondary","download"),E("Import",()=>void this.importForm(),"secondary","upload"),E("Preview",()=>void this.preview(),"secondary","visibility"),E("Entries",()=>this.openEntries(),"secondary","list-view"),this.logicMapButton(),this.saveButton()]}))}liveField(e){return this.locateField(e)?.field}locateField(e){const t=this.schema?.fields??[];for(let s=0;sthis.rebindCanvas(),{once:!0});return}this.renderCanvas()}snapshot(){if(!this.schema)return;const e=JSON.stringify(this.schema);this.history[this.historyAt]!==e&&(this.history=this.history.slice(0,this.historyAt+1),this.history.push(e),this.history.length>60&&this.history.shift(),this.historyAt=this.history.length-1,this.syncHistoryButtons())}travel(e){const t=this.historyAt+e;!this.schema||t<0||t>=this.history.length||(this.historyAt=t,this.schema=JSON.parse(this.history[t]),this.schema.fields.some(s=>s.id===this.selected)||(this.selected=null),this.markDirty(),this.renderBar(),this.renderCanvas(),this.renderInspector())}historyButton(e,t,s){const a=E(t,()=>this.travel(s),"secondary",e);return a.setAttribute("data-atfb-history",String(s)),a.disabled=!this.canTravel(s),a}canTravel(e){const t=this.historyAt+e;return t>=0&&tURL.revokeObjectURL(s),1e3)}async importForm(){const e=r("input",{type:"file",attrs:{accept:"application/json,.json"}});e.addEventListener("change",async()=>{const t=e.files?.[0];if(t)try{const s=JSON.parse(await t.text());if(!s.schema)throw new Error("That file does not contain a form.");const a=await I.createForm({title:s.title??t.name.replace(/\.json$/i,""),schema:s.schema});this.forms.unshift({id:a.id,title:a.title,status:a.status,modified:a.modified,fields:a.schema.fields.length,theme:a.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:a.shortcode}),this.form=a,this.schema=a.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),N("Form imported",a.title)}catch(s){N("Could not import that file",s instanceof Error?s.message:"","error")}}),e.click()}saveButton(){const e=E("Save",()=>void this.save(),"primary");return e.disabled=!this.dirty,e.setAttribute("data-atfb-save",""),e}markDirty(){this.dirty=!0,this.editGeneration+=1;const e=this.bar.querySelector("[data-atfb-save]");e&&(e.disabled=!1),this.autosave()}async save(e=!1){if(!this.form||!this.schema)return;if(this.saveInFlight){this.queuedSave={silent:e&&(this.queuedSave?.silent??!0)};return}this.saveInFlight=!0;const t=this.editGeneration;try{const s=await I.updateForm(this.form.id,{title:this.form.title,schema:this.schema});if(t===this.editGeneration){this.form=s,this.schema=s.schema,this.dirty=!1,this.rebindCanvas();const i=this.bar.querySelector("[data-atfb-save]");i&&(i.disabled=!0)}Ts(s.id);const a=this.forms.find(i=>i.id===s.id);a&&(a.title=s.title),Tn(s.id,s.title,s.previewUrl),e||N("Form saved",s.title)}catch(s){N(Xe("saveFailed","Could not save"),s instanceof Error?s.message:"","error")}finally{this.saveInFlight=!1;const s=this.queuedSave;this.queuedSave=null,s&&this.save(s.silent)}}async openFormById(e){await this.open(e)}async open(e){if(!(this.dirty&&!await ie("You have unsaved changes. Discard them?"))){try{this.form=await I.getForm(e),this.schema=this.form.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot()}catch(t){this.fail(t);return}this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}}announceIdentity(){this.form&&$t(this.root,wn(this.form,W?.adminUrl??""))}async showTemplates(){if(!this.config)return;const e=r("div",{class:"atfb-overlay"}),t=i=>{i.key==="Escape"&&s()},s=()=>{e.remove(),document.removeEventListener("keydown",t)},a=r("div",{class:"atfb-templates",children:this.config.templates.map(i=>r("button",{class:"atfb-template",type:"button",on:{click:async()=>{s();try{const o=await I.createForm({template:i.slug});this.forms.unshift({id:o.id,title:o.title,status:o.status,modified:o.modified,fields:o.schema.fields.length,theme:o.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:o.shortcode}),this.form=o,this.schema=o.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}catch(o){N("Could not create the form",o instanceof Error?o.message:"","error")}}},children:[z(i.icon),r("strong",{text:i.label}),r("span",{text:i.description})]}))});e.append(r("div",{class:"atfb-modal",attrs:{role:"dialog","aria-label":"Start a new form"},children:[r("h2",{text:"Start a new form"}),a,this.archivedFormsSection(s),r("div",{class:"atfb-modal__actions",children:[E("Cancel",s)]})]})),e.addEventListener("click",i=>{i.target===e&&s()}),document.addEventListener("keydown",t),this.root.append(e),a.querySelector("button")?.focus()}archivedFormsSection(e){const t=r("div",{class:"atfb-archived"});return I.listArchivedForms().then(s=>{s.length&&t.append(r("h3",{class:"atfb-archived__title",text:"Or bring one back from the archive"}),...s.map(a=>r("div",{class:"atfb-archived__row",children:[r("div",{class:"atfb-archived__meta",children:[r("strong",{text:a.title||"(untitled)"}),r("span",{class:"atfb-hint",text:`${a.entries} ${a.entries===1?"entry":"entries"} · ${a.submissions} submissions · ${a.views} views`})]}),E("Restore",async()=>{try{const i=await I.unarchiveForm(a.id);e(),this.forms.unshift(i),N("Form restored",`${i.title||"(untitled)"} is back, with its entries and stats.`),await this.open(i.id)}catch(i){N("Could not restore the form",i instanceof Error?i.message:"","error")}},"secondary","undo")]})))}).catch(()=>{}),t}renderFormsList(){R(this.canvas),this.canvas.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms yet"}),r("p",{text:"Start from a template, or build one from nothing."}),E("New form",()=>void this.showTemplates(),"primary","plus-alt2")]}))}openEntries(){const e=window.wp?.os;if(e?.openWindow){e.openWindow("allterrain-forms-entries");return}window.location.assign(`${W?.adminUrl??""}admin.php?page=allterrain-forms-entries`)}renderPalette(){if(!this.config)return;R(this.palette);const e=new Map;for(const s of this.config.fieldTypes){const a=e.get(s.group)??[];a.push(s),e.set(s.group,a)}const t=r("input",{class:"atfb-input atfb-palette__search",type:"search",placeholder:"Search fields",attrs:{"aria-label":"Search field types"},on:{input:s=>{const a=s.target.value.toLowerCase().trim();this.palette.querySelectorAll(".atfb-chip").forEach(i=>{const o=(i.textContent??"").toLowerCase();i.hidden=a!==""&&!o.includes(a)}),this.palette.querySelectorAll(".atfb-group").forEach(i=>{const o=Array.from(i.querySelectorAll(".atfb-chip")).some(l=>!l.hidden);i.hidden=!o})}}});this.palette.append(t);for(const[s,a]of Object.entries(this.config.groups)){const i=e.get(s);i?.length&&this.palette.append(r("div",{class:"atfb-group",children:[r("h3",{class:"atfb-group__title",text:a}),r("div",{class:"atfb-group__items",children:i.map(o=>this.paletteChip(o))})]}))}}paletteChip(e){const t=r("button",{class:"atfb-chip",type:"button",title:e.description,attrs:{"data-atf-type":e.type},children:[z(e.icon),r("span",{text:e.label})]});return t.addEventListener("pointerdown",s=>{const a=r("div",{class:"atfb-chip atfb-chip--ghost",children:[z(e.icon),r("span",{text:e.label})]});K().start({payload:Le(se,t,{fieldType:e.type,isNew:!0},s,a),origin:s,onClickOnly:()=>this.addField(e.type)})}),t.addEventListener("click",s=>{K().recentlyEndedDrag()&&s.preventDefault()}),t}renderCanvas(){if(R(this.canvas),!this.schema||!this.form){this.renderFormsList();return}if(this.tab!=="build"){this.canvas.append(this.renderTabCanvas());return}const e=r("div",{class:"atfb-canvas__list",attrs:{"data-atfb-list":""}});this.schema.fields.length||e.append(r("div",{class:"atfb-placeholder",text:Xe("emptyCanvas","Drag a field from the left to begin.")})),this.schema.fields.forEach((s,a)=>{e.append(this.renderFieldCard(s,a))});const t=r("div",{class:"atfb-canvas__inner",children:[r("p",{class:"atfb-shortcode",text:this.form.shortcode,title:"Paste this anywhere to place the form"}),e]});this.canvas.append(t),this.registerCanvasTarget(e),this.paintLogicMap(t),this.paintCanvasTheme()}prefillControl(e,t){const s=e.prefill.startsWith("query:"),a=Ke.some(y=>y.value===e.prefill),i=s?"query":a&&e.prefill||(e.prefill?"custom":""),o=r("div",{class:"atfb-prefill__detail"}),l=r("p",{class:"atfb-row__hint atfb-prefill__preview"}),c=y=>{if(o.replaceChildren(),l.replaceChildren(),y==="query"){const u=e.prefill.startsWith("query:")?e.prefill.slice(6):"";o.append(A(u,x=>{const v=x.trim();t("prefill",v?`query:${v}`:""),d(`query:${v}`)},"utm_source"),r("p",{class:"atfb-row__hint",text:"The name of the parameter in the link people arrive on."}))}y==="custom"&&o.append(A(e.prefill,u=>{t("prefill",u),d(u)},"myplugin:something"),r("p",{class:"atfb-row__hint",text:"For a source another plugin has added through alltfo_resolve_prefill."})),d(e.prefill)},d=y=>{if(l.replaceChildren(),!y)return;if(y.startsWith("query:")){const x=y.slice(6);x&&(l.textContent=`A visit to …/your-page/?${x}=abc opens the form with “abc” in it.`);return}const u=Ke.find(x=>x.value===y)?.tag;u&&Oe(this.form?.id??0).then(x=>{for(const v of x)for(const f of v.items)if(f.tag===u){const C=y.startsWith("user:");if(!f.sample){l.textContent="Empty unless the visitor is signed in.";return}l.textContent=C?`Opens with “${f.sample}” for you — empty for a visitor who is not signed in.`:`Opens with “${f.sample}”.`;return}})};c(i);const h=r("select",{class:"atfb-input atfb-select",on:{change:y=>{const u=y.target.value;t("prefill",u==="query"||u==="custom"?"":u),c(u)}}});h.append(r("option",{value:"",text:"Nothing — leave it empty",attrs:{selected:i===""}}));for(const y of In){const u=document.createElement("optgroup");u.label=y;for(const x of Ke.filter(v=>v.group===y))u.append(r("option",{value:x.value,text:x.label,attrs:{selected:x.value===i}}));h.append(u)}const w=document.createElement("optgroup");return w.label="From the link they arrived on",w.append(r("option",{value:"query",text:"A parameter in the web address",attrs:{selected:i==="query"}})),h.append(w,r("option",{value:"custom",text:"Something else (advanced)",attrs:{selected:i==="custom"}})),g("Pre-fill this with",r("div",{class:"atfb-prefill",children:[h,o,l]}),"What the box already contains when the form opens. They can still change it.")}renderCondition(e,t){const s=t.some(i=>i.kind==="field"&&i.missing),a=r("span",{class:`atfb-cond${s?" is-broken":""}`,attrs:{"aria-label":rt(t)},children:[z("randomize"),...t.map(i=>this.renderConditionToken(e,i))]});return a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("click",i=>i.stopPropagation()),a.addEventListener("keydown",i=>i.stopPropagation()),a}editCondition(e,t,s=!0,a=""){const i=this.liveField(e)?.logic;if(i){if(t(i),this.markDirty(),!s){this.logicMap?.setEdges(me(this.schema?.fields??[]));return}this.renderCanvas(),this.renderInspector(),a&&window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-cond="${CSS.escape(a)}"]`)?.focus()})}}condSelect(e,t,s,a,i){if(Y("os-select")&&Y("os-option")){const o=document.createElement("os-select");o.setAttribute("value",e),o.setAttribute("aria-label",a),o.setAttribute("data-cond",s),o.className="atfb-cond__control",o.title=a;for(const l of t){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,o.append(c)}return o.addEventListener("os-pick",l=>{i(String(l.detail?.value??""))}),o}return r("select",{class:"atfb-cond__control atfb-cond__control--native",title:a,attrs:{"aria-label":a,"data-cond":s},on:{change:o=>i(o.target.value)},children:t.map(o=>r("option",{value:o.value,text:o.label,attrs:{selected:o.value===e}}))})}renderConditionToken(e,t){if(t.kind==="field"&&!t.missing)return r("button",{class:"atfb-cond__chip atfb-cond__chip--field",type:"button",text:t.text,title:"Go to this question",on:{click:a=>{a.stopPropagation(),this.selectField(t.fieldId),this.canvas.querySelector(`[data-atfb-card="${CSS.escape(t.fieldId)}"]`)?.scrollIntoView({block:"nearest",behavior:"smooth"})}}});if(t.kind==="verb")return r("button",{class:"atfb-cond__verb",type:"button",text:t.text,title:"Switch between showing and hiding this field when the condition matches.",attrs:{"data-cond":`${e.id}:verb`},on:{click:()=>this.editCondition(e.id,s=>{s.action=s.action==="hide"?"show":"hide"},!0,`${e.id}:verb`)}});if(t.kind==="join")return r("button",{class:"atfb-cond__join",type:"button",text:t.text,title:"Switch between needing every rule (and) or any one of them (or).",attrs:{"data-cond":`${e.id}:join`},on:{click:()=>this.editCondition(e.id,s=>{s.match=s.match==="all"?"any":"all"},!0,`${e.id}:join`)}});if(t.kind==="operator"){const s=`${e.id}:op:${t.ruleIndex}`;return this.condSelect(t.operator,Object.entries(Me).map(([a,i])=>({value:a,label:i})),s,"How the answer is compared",a=>this.editCondition(e.id,i=>{const o=i.rules[t.ruleIndex];o&&(o.operator=a)},!0,s))}return t.kind==="value"?this.renderConditionValue(e,t):r("span",{class:"atfb-cond__chip atfb-cond__chip--missing",text:t.text})}renderConditionValue(e,t){const s=`${e.id}:value:${t.ruleIndex}`,a=this.schema?.fields.find(c=>c.id===t.sourceId),i=(c,d)=>this.editCondition(e.id,h=>{const w=h.rules[t.ruleIndex];w&&(w.value=c)},d,s);if(a?.choices?.length){const c=a.choices.map(d=>({value:d.value,label:d.label||d.value}));return t.raw!==""&&!a.choices.some(d=>d.value===t.raw)&&c.unshift({value:t.raw,label:t.text}),this.condSelect(t.raw,c,s,"The answer that triggers this",d=>i(d,!0))}const o=["number","range","scale","rating","total"].includes(a?.type??""),l=r("input",{class:"atfb-cond__chip atfb-cond__chip--value atfb-cond__value",value:t.raw,title:"The answer that triggers this. Edit it here.",attrs:{type:"text","aria-label":"The answer that triggers this","data-cond":s,inputmode:o?"decimal":void 0,size:String(Math.max(2,Math.min(24,t.raw.length||2)))}});return l.addEventListener("input",()=>{l.size=Math.max(2,Math.min(24,l.value.length||2)),i(l.value,!1)}),l.addEventListener("change",()=>i(l.value,!0)),l.addEventListener("keydown",c=>{c.key==="Enter"&&(c.preventDefault(),i(l.value,!0))}),l}section(e,t,s,a=!1){const i=r("details",{class:"atfb-section",attrs:{open:this.openSections.get(e)??a},children:[r("summary",{text:t}),...s]});return i.addEventListener("toggle",()=>this.openSections.set(e,i.open)),i}logicMapButton(){const e=me(this.schema?.fields??[]).length>0,t=E(this.logicMapOn?"Hide logic":"Show logic",()=>{this.logicMapOn=!this.logicMapOn,is(Pt,this.logicMapOn?"on":"off"),this.renderBar(),this.renderCanvas()},this.logicMapOn?"primary":"secondary","randomize");return t.title="Draw a line from each question to the ones it decides.",t.hidden=!e,t}paintLogicMap(e){this.logicMap?.destroy(),this.logicMap=null;const t=this.schema?.fields??[],s=me(t);if(!s.length||!this.logicMapOn)return;e.classList.add("has-logicmap");const a=new ys(e);a.setEdges(s),a.highlight(this.selected??""),this.logicMap=a,e.addEventListener("pointerover",i=>{const o=i.target.closest("[data-atfb-card]");a.highlight(o?.dataset.atfbCard??this.selected??"")}),e.addEventListener("pointerleave",()=>a.highlight(this.selected??""))}renderFieldCard(e,t){const s=this.config?.fieldTypes.find(d=>d.type===e.type),a=this.selected===e.id,i=this.schema?.fields??[],o=bs(e,i),l=vs(i).get(e.id)??0,c=r("div",{class:`atfb-card${a?" is-selected":""}`,attrs:{"data-atfb-card":e.id,"data-index":t,tabindex:"0",role:"button","aria-pressed":a,"aria-label":`${e.label||s?.label||e.type}, ${t+1} of ${this.schema?.fields.length??0}`},children:[r("div",{class:"atfb-card__bar",children:[r("div",{class:"atfb-card__grip",attrs:{"aria-hidden":"true"},children:[z("menu")]}),r("div",{class:"atfb-card__head",children:[z(s?.icon??"dashicons-forms"),r("span",{class:"atfb-card__type",text:s?.label??e.type}),this.requiredToggle(e),l?r("span",{class:"atfb-badge atfb-badge--controls",text:l===1?"controls 1 field":`controls ${l} fields`,title:"Other questions appear or disappear based on this answer."}):null]}),r("div",{class:"atfb-card__actions",children:[this.cardAction("admin-page","Duplicate",()=>this.duplicateField(e.id)),this.cardAction("trash","Delete",()=>void this.deleteField(e.id))]})]}),r("div",{class:"atfb-card__body",children:[dt(e,s,{edit:d=>{const h=this.liveField(e.id);if(!h)return;d(h),this.markDirty(),this.syncInspector(h);const w=this.selected?this.locateField(this.selected):void 0;w?.parent&&w.parent.id===h.id&&this.syncInspector(w.field)},restructure:d=>{const h=this.liveField(e.id);h&&(this.snapshot(),d(h),this.markDirty(),this.renderCanvas(),this.renderInspector())},types:d=>this.config?.fieldTypes.find(h=>h.type===d),selectedId:this.selected}),o.length?this.renderCondition(e,o):null]})]});return c.addEventListener("click",d=>{d.target.closest(".atfb-card__actions")||K().recentlyEndedDrag()||this.selectField(e.id)}),c.addEventListener("keydown",d=>{if(d.key==="Enter"||d.key===" "){d.preventDefault(),this.selectField(e.id);return}d.altKey&&(d.key==="ArrowUp"||d.key==="ArrowDown")&&(d.preventDefault(),this.moveField(e.id,d.key==="ArrowUp"?t-1:t+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})),(d.key==="Delete"||d.key==="Backspace")&&(d.preventDefault(),this.deleteField(e.id))}),c.addEventListener("pointerdown",d=>{d.target.closest(".atfb-card__actions")||K().start({payload:Le(se,c,{fieldId:e.id,field:e,isNew:!1},d),origin:d})}),c}requiredToggle(e){return r("button",{class:`atfb-req${e.required?" is-on":""}`,type:"button",text:e.required?"Required":"Optional",title:e.required?"This must be answered. Click to make it optional.":"Click to make this required.",attrs:{"aria-pressed":e.required?"true":"false"},on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.required=!e.required,this.markDirty(),this.renderCanvas(),this.renderInspector()}}})}cardAction(e,t,s){return r("button",{class:"atfb-card__action",type:"button",title:t,attrs:{"aria-label":t},on:{click:a=>{a.stopPropagation(),s()}},children:[z(e)]})}registerCanvasTarget(e){this.canvasTarget?.(),this.canvasTarget=null;const t=r("div",{class:"atfb-marker",attrs:{"aria-hidden":"true"}}),s=K().registerDropTarget({id:`atfb-canvas-${this.form?.id??0}`,element:e,accept:o=>o.type===se,onEnter:()=>e.classList.add("is-dropping"),onLeave:()=>{e.classList.remove("is-dropping"),t.remove()},onDrop:(o,l)=>{e.classList.remove("is-dropping"),t.remove();const c=o.payload.data,d=c.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(c.fieldId)}"]`):null,h=Ce(e,".atfb-card",l.clientY,d??void 0);if(c.isNew&&c.fieldType){this.addField(c.fieldType,h);return}if(c.fieldId&&this.locateField(c.fieldId)){this.relocateField(c.fieldId,null,h);return}c.field&&this.insertField({...c.field,id:""},h)}}),a=this.wireRepeaterZones(e),i=o=>{const l=o.detail;if(l?.payload?.type!==se||!e.classList.contains("is-dropping"))return;const c=l.payload.data?.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(l.payload.data.fieldId)}"]`):null,d=l.clientY??0,h=Ce(e,".atfb-card",d,c??void 0),w=Array.from(e.querySelectorAll(".atfb-card")).filter(y=>y!==c);h>=w.length?e.append(t):w[h].before(t)};document.addEventListener("os.drag.move",i),this.canvasTarget=()=>{s(),a.forEach(o=>o()),document.removeEventListener("os.drag.move",i)}}wireRepeaterZones(e){const t=[];return e.querySelectorAll("[data-atfb-repeater-zone]").forEach(s=>{const a=s.dataset.atfbRepeaterZone??"";t.push(K().registerDropTarget({id:`atfb-repzone-${this.form?.id??0}-${a}`,element:s,accept:i=>{if(i.type!==se)return!1;const o=i.data;if(o.fieldId===a)return!1;const l=o.isNew?o.fieldType:this.locateField(o.fieldId??"")?.field.type??o.field?.type;return!!l&&this.allowedInRepeater(l)},onEnter:()=>s.classList.add("is-dropping"),onLeave:()=>s.classList.remove("is-dropping"),onDrop:(i,o)=>{s.classList.remove("is-dropping");const l=i.payload.data,c=l.fieldId?e.querySelector(`[data-atfb-subfield="${CSS.escape(l.fieldId)}"]`):null,d=Ce(s,".atfb-subcard",o.clientY,c??void 0);if(l.isNew&&l.fieldType){this.addFieldToRepeater(l.fieldType,a,d);return}if(l.fieldId&&this.locateField(l.fieldId)){this.relocateField(l.fieldId,a,d);return}l.field&&this.insertFieldIntoRepeater({...l.field,id:""},a,d)}})),s.querySelectorAll(".atfb-subcard").forEach(i=>{const o=i.dataset.atfbSubfield??"";i.addEventListener("click",l=>{l.target.closest(".atfb-preview__remove")||(l.stopPropagation(),!K().recentlyEndedDrag()&&this.selectField(o))}),i.addEventListener("keydown",l=>{if(l.stopPropagation(),l.key==="Enter"||l.key===" "){l.preventDefault(),this.selectField(o);return}if(l.altKey&&(l.key==="ArrowUp"||l.key==="ArrowDown")){l.preventDefault();const c=this.locateField(o);c&&(this.relocateField(o,a,l.key==="ArrowUp"?c.index-1:c.index+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(o)}"]`)?.focus()}));return}(l.key==="Delete"||l.key==="Backspace")&&(l.preventDefault(),this.deleteField(o))}),i.addEventListener("pointerdown",l=>{if(l.stopPropagation(),l.target.closest(".atfb-preview__remove"))return;const c=this.locateField(o);c&&K().start({payload:Le(se,i,{fieldId:o,parentId:a,field:c.field,isNew:!1},l),origin:l})})})}),t}addField(e,t){const s=this.buildField(e);s&&this.insertField(s,t)}buildField(e){const t=this.config?.fieldTypes.find(a=>a.type===e);return!t||!this.schema?void 0:{id:this.nextFieldId(),type:e,label:t.input?t.label:"",placeholder:"",hint:"",required:!1,width:"full",cssClass:"",default:"",choices:t.choices?[{label:"First choice",value:"first"},{label:"Second choice",value:"second"}]:[],logic:{enabled:!1,action:"show",match:"all",rules:[]},messages:{},prefill:"",...t.settings}}allowedInRepeater(e){const t=this.config?.fieldTypes.find(s=>s.type===e);return!t||!t.input?!1:!["repeater","page_break","file","signature","total"].includes(e)}addFieldToRepeater(e,t,s){if(!this.allowedInRepeater(e))return;const a=this.buildField(e);a&&this.insertFieldIntoRepeater(a,t,s)}insertFieldIntoRepeater(e,t,s){const a=this.liveField(t);if(!this.schema||!a||a.type!=="repeater")return;e.id||(e.id=this.nextFieldId()),this.snapshot(),Array.isArray(a.fields)||(a.fields=[]);const i=a.fields,o=s===void 0?i.length:Math.max(0,Math.min(s,i.length));i.splice(o,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(e.id)}"]`)?.focus()})}relocateField(e,t,s){if(!this.schema)return;const a=this.locateField(e);if(!a)return;if(!a.parent&&!t){this.moveField(e,s);return}const i=t?this.liveField(t):null;if(t&&(!i||i.type!=="repeater"||e===t))return;i&&!Array.isArray(i.fields)&&(i.fields=[]);const o=i?i.fields:this.schema.fields;this.snapshot(),a.list.splice(a.index,1);const l=Math.max(0,Math.min(s,o.length));o.splice(l,0,a.field),this.selected=a.field.id,this.markDirty(),this.renderCanvas(),this.renderInspector()}insertField(e,t){if(!this.schema)return;e.id||(e.id=this.nextFieldId()),this.snapshot();const s=t===void 0?this.schema.fields.length:Math.max(0,Math.min(t,this.schema.fields.length));this.schema.fields.splice(s,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})}moveField(e,t){if(!this.schema)return;const s=jt(this.schema.fields,e,t);if(!s)return;this.snapshot();const[a]=this.schema.fields.splice(s.from,1);this.schema.fields.splice(s.to,0,a),this.markDirty(),this.renderCanvas()}duplicateField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=JSON.parse(JSON.stringify(t.field)),a=this.usedFieldIds(),i=()=>{let o=a.size+1;for(;a.has(`f${o}`);)o++;const l=`f${o}`;return a.add(l),l};s.id=i();for(const o of s.fields??[])o.id=i();if(t.parent){this.snapshot(),t.list.splice(t.index+1,0,s),this.selected=s.id,this.markDirty(),this.renderCanvas(),this.renderInspector();return}this.insertField(s,t.index+1)}async deleteField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=this.schema.fields.filter(i=>i.logic?.rules?.some(o=>o.field===e)),a=s.length?`Delete this field? ${s.length} other field${s.length===1?"":"s"} use it in a condition, and those conditions will stop working.`:Xe("confirmDelete","Delete this? It cannot be undone.");await ie(a,"Delete field")&&(this.snapshot(),t.list.splice(t.index,1),this.selected===e&&(this.selected=null),this.markDirty(),this.renderCanvas(),this.renderInspector())}selectField(e){this.selected=e;for(const t of this.canvas.querySelectorAll("[data-atfb-card]")){const s=t.dataset.atfbCard===e;t.classList.toggle("is-selected",s),t.setAttribute("aria-pressed",s?"true":"false")}for(const t of this.canvas.querySelectorAll("[data-atfb-subfield]"))t.classList.toggle("is-selected",t.dataset.atfbSubfield===e);this.logicMap?.highlight(e),this.renderInspector()}nextFieldId(){const e=this.usedFieldIds();let t=e.size+1;for(;e.has(`f${t}`);)t++;return`f${t}`}usedFieldIds(){const e=new Set;for(const t of this.schema?.fields??[]){e.add(t.id);for(const s of t.fields??[])e.add(s.id)}return e}nextEntryId(e,t){const s=new Set(t.map(i=>i.id));let a=t.length+1;for(;s.has(`${e}${a}`);)a++;return`${e}${a}`}renderTypeSettings(e,t,s,a){for(const i of s){const o=Rt[i];o&&(this.inspector.append(Bt(e,o,a)),o.also&&this.inspector.append(Bt(e,{...o,key:o.also.key,label:o.also.label,hint:o.also.hint},a)))}s.includes("rows")&&e.type!=="likert"&&this.inspector.append(g("Lines tall",G(String(e.rows??""),i=>a("rows",i)))),s.includes("rows")&&e.type==="likert"&&this.inspector.append(this.renderStatementList(e,a)),s.includes("parts")&&this.inspector.append(this.renderPartsEditor(e,t,a)),s.includes("default")&&!["files","object"].includes(t?.value??"")&&this.inspector.append(this.renderDefaultControl(e,t,a))}renderStatementList(e,t){const s=Array.isArray(e.rows)?e.rows:[];return g("Statements",pe(s.map(a=>a.label??"").join(` -`),a=>t("rows",Ht(s,a)),5),"One per line. Each becomes a row of the matrix.")}renderPartsEditor(e,t,s){const a=t?.parts??[],i=Array.isArray(e.parts)?e.parts:a.map(l=>l.key),o=a.map(l=>O(l.label,i.includes(l.key),c=>{const d=a.map(h=>h.key).filter(h=>h===l.key?c:i.includes(h));s("parts",d.length?d:[l.key])}));return r("div",{class:"atfb-section",children:[r("h4",{class:"atfb-section__title",text:"Parts to ask for"}),...o]})}renderDefaultControl(e,t,s){const a="Filled in before they start. They can change it.";return e.type==="switch"||e.type==="consent"?O("On by default",!!e.default,i=>s("default",i)):t?.choices&&(e.choices??[]).length?g("Default answer",D(String(e.default??""),[{value:"",label:"Nothing chosen"},...(e.choices??[]).map(i=>({value:String(i.value),label:i.label||String(i.value)}))],i=>s("default",i)),a):g("Default answer",A(String(e.default??""),i=>s("default",i)),a)}renderChoicesEditor(e,t){const s=e.choices??[],a=o=>this.liveField(e.id)?.choices?.[o],i=r("div",{class:"atfb-choices"});return s.forEach((o,l)=>{const c=r("div",{class:"atfb-choice-row",children:[e.type==="image_choice"?this.choiceImageWell(o,l,e):null,J(A(o.label,d=>{const h=a(l);if(!h)return;const w=!h.value||h.value===h.label;h.label=d,w&&(h.value=d),this.markDirty();const y=this.liveField(e.id);y&&this.syncCanvas(y)}),`choice:${l}:label`),J(A(o.value,d=>{const h=a(l);h&&(h.value=d,this.markDirty())},"value"),`choice:${l}:value`),e.type==="quiz"||o.points!==void 0?G(String(o.points??""),d=>{const h=a(l);h&&(h.points=d===""?void 0:Number(d),this.markDirty())}):G(String(o.price??""),d=>{const h=a(l);h&&(h.price=d===""?void 0:Number(d),this.markDirty())}),r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":`Remove ${o.label}`},on:{click:()=>{const d=this.liveField(e.id);d&&((d.choices??[]).splice(l,1),t("choices",d.choices),this.renderInspector())}},children:[z("trash")]})]});i.append(c)}),r("div",{class:"atfb-section",children:[r("h4",{text:"Choices"}),r("p",{class:"atfb-hint",text:e.type==="quiz"?"Label, value, points.":"Label, value, and a price for calculations."}),i,E("Add choice",()=>{const o=this.liveField(e.id);if(!o)return;const l=o.choices??[];l.push({label:"",value:""}),t("choices",l),this.renderInspector()},"ghost","plus-alt2"),e.type==="quiz"?g("Correct answer",D(String(e.correct??""),[{value:"",label:"—"},...s.map(o=>({value:o.value,label:o.label}))],o=>t("correct",o))):null]})}choiceImageWell(e,t,s){const a=r("div",{class:`atfb-well${e.image?" has-image":""}`,attrs:{"data-choice":t,"aria-label":`Image for ${e.label||`choice ${t+1}`}`},children:[e.image?r("span",{class:"atfb-well__id",text:`#${e.image}`}):z("format-image")]}),i=K().registerDropTarget({id:`atfb-well-${s.id}-${t}`,element:a,accept:o=>Mn.includes(o.type),onEnter:()=>a.classList.add("is-dropping"),onLeave:()=>a.classList.remove("is-dropping"),onDrop:o=>{a.classList.remove("is-dropping");const l=o.payload.data,c=Number(l.attachmentId??l.id??l.file?.id??0);if(!c){N("That is not an image this field can use","","error");return}const d=this.liveField(s.id)?.choices?.[t];d&&(d.image=c,this.markDirty(),this.renderInspector())}});return this.teardowns.push(i),a.addEventListener("click",()=>{const o=this.liveField(s.id)?.choices?.[t];o?.image&&(o.image=void 0,this.markDirty(),this.renderInspector())}),a}renderValidationSection(e,t,s){const a=[],i=[];t.includes("minlength")&&i.push(["minlength","Minimum characters"],["maxlength","Maximum characters"]),t.includes("min")?i.push(["min","Minimum"],["max","Maximum"]):t.includes("max")&&i.push(["max","Highest"]),t.includes("step")&&i.push(["step","Steps of"]),t.includes("mindate")&&i.push(["minDate","Earliest date"],["maxDate","Latest date"]),t.includes("mintime")&&i.push(["minTime","Earliest time"],["maxTime","Latest time"]);for(const[l,c]of i)a.push(g(c,A(String(e[l]??""),d=>s(l,d))));t.includes("pattern")&&a.push(...this.renderAnswerShapeRows(e,s)),t.includes("unique")&&a.push(O("No two people may submit the same value",!!e.unique,l=>s("unique",l)));const o=e.messages??{};return t.includes("required")&&a.push(g("Message when required",A(o.required??"",l=>{o.required=l,s("messages",o)}),"Leave empty for the default wording.")),a.length?this.section(`validation:${e.id}`,"Validation",a):r("div",{class:"atfb-section is-empty"})}buildShapePicker(e,t){const s=[{heading:null,options:[{value:"",label:"Anything at all"}]},...Cn.map(i=>({heading:i,options:Dt.filter(o=>o.group===i).map(o=>({value:o.slug,label:o.label}))})),{heading:"Your own",options:[{value:"custom",label:"A custom rule…"}]}];if(Y("os-select")&&Y("os-option")){const i=document.createElement("os-select");i.setAttribute("value",e),i.setAttribute("aria-label","What the answer should look like"),i.classList.add("atfb-field");for(const o of s){if(o.heading){const l=document.createElement("os-option");l.setAttribute("value",`__heading:${o.heading}`),l.setAttribute("disabled",""),l.textContent=o.heading,i.append(l)}for(const l of o.options){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,i.append(c)}}return i.addEventListener("os-pick",o=>{t(String(o.detail?.value??""))}),i}const a=r("select",{class:"atfb-input atfb-select",attrs:{"aria-label":"What the answer should look like"},on:{change:i=>t(i.target.value)}});for(const i of s){const o=i.heading?(()=>{const l=document.createElement("optgroup");return l.label=i.heading,a.append(l),l})():a;for(const l of i.options)o.append(r("option",{value:l.value,text:l.label,attrs:{selected:l.value===e}}))}return a}renderAnswerShapeRows(e,t){const a=(typeof e.validation=="string"?e.validation:"")||(e.pattern?"custom":""),i=()=>Sn({root:this.root,field:this.liveField(e.id)??e,onSave:h=>{t("validation","custom"),t("pattern",h.pattern),t("validationRecipe",JSON.stringify(h.recipe));const w={...this.liveField(e.id)?.messages??{}};w.invalid=h.message,t("messages",w),this.renderInspector()},onCancel:()=>this.renderInspector()}),o=h=>{if(h==="custom"){i();return}t("validation",h),t("pattern",""),t("validationRecipe",""),this.renderInspector()},l=this.buildShapePicker(a,o),c=$n(a),d=[g("The answer should be",l,c?`e.g. ${c.example}`:"Checked as they type, and again on the server.")];if(a==="custom"){const h=Tt(String(e.validationRecipe??"")),w=Mt(h)||(e.pattern?`Matches the expression ${String(e.pattern)}`:"No rule yet — open the builder.");d.push(g("Your rule",r("div",{class:"atfb-valrule",children:[r("p",{class:"atfb-valrule__words",text:w}),E("Edit the rule…",i,"secondary","edit")]}),xe(h)||e.pattern?"Built in the rule builder, with a playground to test it.":void 0))}return d}logicRulesEditor(e,t,s=""){const a=(this.schema?.fields??[]).filter(d=>d.id!==s&&d.type!=="page_break"),i=()=>r("div",{class:"atfb-rule-join",children:[r("button",{class:"atfb-rule-join__chip",type:"button",text:e.match==="all"?"and":"or",title:"Switch between needing every rule (and) or any one of them (or).",on:{click:()=>t(d=>{d.match=d.match==="all"?"any":"all"},!0)}})]}),o=(d,h)=>{const w=r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":"Remove this rule"},title:"Remove this rule",on:{click:()=>t(u=>{u.rules.splice(h,1)},!0)},children:[z("trash")]}),y=[r("div",{class:"atfb-rule__top",children:[D(d.field,a.map(u=>({value:u.id,label:u.label||u.id})),u=>t(x=>{const v=x.rules[h];v&&(v.field=u,v.value="")},!0)),w]}),D(d.operator,Object.entries(this.config?.operators??{}).map(([u,x])=>({value:u,label:x})),u=>t(x=>{const v=x.rules[h];v&&(v.operator=u)},!0))];if(!Fe.includes(d.operator)){const u=this.schema?.fields.find(x=>x.id===d.field);if(u?.choices?.length){const x=u.choices.map(v=>({value:v.value,label:v.label||v.value}));d.value!==""&&!u.choices.some(v=>v.value===d.value)&&x.unshift({value:d.value,label:d.value}),y.push(D(d.value,x,v=>t(f=>{const C=f.rules[h];C&&(C.value=v)})))}else y.push(A(d.value,x=>t(v=>{const f=v.rules[h];f&&(f.value=x)}),"The answer to compare against"))}return r("div",{class:"atfb-rule",children:y})},l=r("div",{class:"atfb-rules"});e.rules.forEach((d,h)=>{h>0&&l.append(i()),l.append(o(d,h))});const c=E("Add rule",()=>{t(d=>{d.rules.push({field:a[0]?.id??"",operator:"is",value:""})},!0)},"ghost","plus-alt2");return[l,c]}conditionsSection(e,t,s){const a=(o,l=!1)=>{o(s),this.markDirty(),l&&this.renderCanvas()},i=t==="confirmation"?"Use":"Send";return this.section(`conditions:${e}`,"Conditions",[O(`Only ${i.toLowerCase()} this ${t} sometimes`,s.enabled,o=>a(l=>{l.enabled=o},!0)),s.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[r("span",{text:`${i} it when`}),D(s.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...this.logicRulesEditor(s,a)]}):null],s.enabled)}renderLogicSection(e){const t=e.logic,s=()=>this.liveField(e.id)?.logic,a=(o,l=!1)=>{const c=s();c&&(o(c),this.markDirty(),this.renderCanvas(),l&&this.renderInspector())},i=this.logicRulesEditor(t,a,e.id);return this.section(`logic:${e.id}`,"Conditional logic",[O("Only show this field sometimes",t.enabled,o=>{a(l=>{l.enabled=o},!0)}),t.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[D(t.action,[{value:"show",label:"Show"},{value:"hide",label:"Hide"}],o=>a(l=>{l.action=o},!0)),r("span",{text:"this field when"}),D(t.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...i]}):null],t.enabled)}renderTabCanvas(){return this.schema?this.tab==="theme"?mt({themes:this.themes,tokens:this.config?.tokens??[],activeSlug:this.schema.settings.theme,overrides:this.schema.settings.themeOverrides,onTheme:e=>{this.schema.settings.theme=e,this.markDirty()},onOverride:(e,t)=>{t===""?delete this.schema.settings.themeOverrides[e]:this.schema.settings.themeOverrides[e]=t,this.markDirty()},onOverridesReplaced:e=>{this.schema.settings.themeOverrides={...e},this.markDirty()},previewFor:(e,t)=>this.previewHtml(e,t),onThemesChanged:e=>{this.themes=e}}):this.tab==="settings"?this.renderSettingsPane():this.tab==="notify"?this.renderNotificationsPane():this.renderConfirmationsPane():r("div")}async paintCanvasTheme(){if(!this.form||!this.schema)return;const e=this.schema.settings.theme,t=JSON.stringify([e,this.schema.settings.themeOverrides]);if(t!==this.canvasThemeSignature){this.canvasThemeSignature=t;try{const s=await this.previewHtml(e,this.schema.settings.themeOverrides??{});this.root.classList.toggle("atfb--dark-form",/atf-is-dark/.test(s));const a=/class="atf-form-wrap"[^>]*\sstyle="([^"]*)"/.exec(s);if(!a)return;const i=a[1].replace(/"/g,'"').replace(/�?39;/g,"'").replace(/&/g,"&");this.canvasTheme.textContent=`.atfb .atfb-preview { +var allTerrainFormsBuilder=function(ee){"use strict";class Zt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(e){if(this.active||e.origin.button!==0)return null;const{payload:t,origin:s}=e,a=s.clientX,i=s.clientY;let o=!1,l=!1,c=null,d=null,h=0,w=0;const _=()=>{document.removeEventListener("pointermove",x),document.removeEventListener("pointerup",I),document.removeEventListener("pointercancel",S),document.removeEventListener("keydown",H),window.removeEventListener("blur",S),c?.remove(),c=null,t.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),d?.onLeave?.(b),d=null,this.active=null,this.lastEndMs=Date.now()},u=(E,f)=>{document.dispatchEvent(new CustomEvent(E,{detail:{payload:t,clientX:f?.clientX,clientY:f?.clientY}}))},b={payload:t,isFinished:()=>l,cancel:(E="caller")=>{l||(l=!0,_(),o&&u("os.drag.end"),e.onCancel?.(E))}},g=E=>{o=!0,t.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const f=t.source.getBoundingClientRect();h=t.ghost?.offsetX??a-f.left,w=t.ghost?.offsetY??i-f.top,c=t.ghost?.element??t.source.cloneNode(!0),c.classList.add("atf-drag-ghost"),c.style.width=`${f.width}px`,document.body.appendChild(c),p(E),u("os.drag.start",E)},p=E=>{c&&(c.style.transform=`translate3d(${E.clientX-h}px, ${E.clientY-w}px, 0)`)},x=E=>{if(l)return;if(!o){if(Math.hypot(E.clientX-a,E.clientY-i)<4)return;g(E)}p(E);const f=this.hitTest(E.clientX,E.clientY);f!==d&&(d?.onLeave?.(b),d=f,d?.onEnter?.(b)),u("os.drag.move",E)},I=E=>{if(l)return;if(!o){l=!0,_(),e.onClickOnly?.();return}const f=d;if(l=!0,_(),f&&f.accept(t)){e.onCommit?.(f),f.onDrop(b,{clientX:E.clientX,clientY:E.clientY}),u("os.drag.end",E);return}u("os.drag.end",E),e.onCancel?.(f?"rejected":"no-target")},S=()=>b.cancel("pointercancel"),H=E=>{E.key==="Escape"&&b.cancel("escape")};return document.addEventListener("pointermove",x),document.addEventListener("pointerup",I),document.addEventListener("pointercancel",S),document.addEventListener("keydown",H),window.addEventListener("blur",S),this.active=b,b}registerDropTarget(e){return this.targets=this.targets.filter(t=>t.id!==e.id),this.targets.push(e),()=>{this.targets=this.targets.filter(t=>t.id!==e.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(e=500){return Date.now()-this.lastEndMso.right||to.bottom)continue;const l=Kt(i.element);if(l>a){s=i,a=l;continue}l===a&&s&&Vt(i.element,s.element)&&(s=i)}return s}}function Kt(n){let e=0,t=n;for(;t;)e++,t=t.parentElement;return e}function Vt(n,e){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function Se(){return window.wp?.os??null}let Le=null;function Z(){const n=Se();return n?.dragManager?n.dragManager:(Le||(Le=new Zt),Le)}function Jt(n){const e=i=>{const o=i.detail?.payload;return o&&n.includes(o.type)?o.source:null},t=i=>i.preventDefault(),s=i=>{const o=e(i);o&&(o.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"),window.getSelection()?.removeAllRanges(),document.addEventListener("selectstart",t))},a=i=>{const o=e(i);o&&(o.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),document.removeEventListener("selectstart",t))};return document.addEventListener("os.drag.start",s),document.addEventListener("os.drag.end",a),()=>{document.removeEventListener("os.drag.start",s),document.removeEventListener("os.drag.end",a),document.removeEventListener("selectstart",t)}}const Qt=["atfb","atfe","atfs","atfm"];function Ee(n,e,t,s,a){const i=e.getBoundingClientRect();if(!a){const o=Qt.find(l=>e.closest(`.${l}`));if(o){const l=e.cloneNode(!0);l.style.transition="",l.style.transform="",a=document.createElement("div"),a.className=`${o} atf-ghost-scope`,a.appendChild(l)}}return a&&(a.style.width=`${Math.round(i.width)}px`,a.style.maxWidth=`${Math.round(i.width)}px`,a.style.boxSizing="border-box"),{type:n,source:e,data:t,ghost:{element:a,offsetX:s.clientX-i.left,offsetY:s.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}function Je(n,e,t,s){const a=Array.from(n.querySelectorAll(e)).filter(i=>i!==s&&!i.classList.contains("atf-drag-ghost"));for(let i=0;ia.fetch(l,c,{source:"allterrain-forms"}):(l,c)=>fetch(l,c))(t,{credentials:"same-origin",...e,headers:s});if(!o.ok){let l=`Request failed with status ${o.status}.`,c="";try{const d=await o.json();l=d.message??l,c=d.code??""}catch{}throw new de(l,o.status,c)}if(o.status!==204)return await o.json()}const U=n=>Ce(n);async function es(n){if(!W?.wpRestUrl)throw new de("AllTerrain Forms is not configured on this page.",0);const e=W.nonce?{"X-WP-Nonce":W.nonce}:{},t=Se(),s=Qe(W.wpRestUrl,n),a=t?.fetch?await t.fetch(s,{credentials:"same-origin",headers:e},{source:"allterrain-forms"}):await fetch(s,{credentials:"same-origin",headers:e});if(!a.ok)throw new de(`Request failed with status ${a.status}.`,a.status);return await a.json()}function ts(n){if(!n||!n.includes("&"))return n;const e=document.createElement("textarea");return e.innerHTML=n,e.value}const K=(n,e)=>Ce(n,{method:"POST",body:JSON.stringify(e)}),he=n=>Ce(n,{method:"DELETE"});function et(n){const e=new URLSearchParams;for(const[s,a]of Object.entries(n))a===void 0||a===""||a===!1||e.set(s,String(a));const t=e.toString();return t?`?${t}`:""}function ue(n){const e=n?.schema?.settings;return e&&(!e.themeOverrides||Array.isArray(e.themeOverrides))&&(e.themeOverrides={...e.themeOverrides}),n}const F={config:()=>U("/config"),mailpoet:()=>U("/mailpoet"),listForms:()=>U("/forms"),listArchivedForms:()=>U("/forms?archived=1"),archiveForm:n=>K(`/forms/${n}/archive`,{}),unarchiveForm:n=>K(`/forms/${n}/unarchive`,{}),getForm:n=>U(`/forms/${n}`).then(ue),createForm:n=>K("/forms",n).then(ue),updateForm:(n,e)=>K(`/forms/${n}`,e).then(ue),duplicateForm:n=>K(`/forms/${n}/duplicate`,{}).then(ue),deleteForm:n=>he(`/forms/${n}`),preview:(n,e)=>K(`/forms/${n}/preview`,e),pages:()=>es("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(n=>n.map(e=>({id:e.id,title:ts(e.title?.rendered??"")||`#${e.id}`}))),mergeTags:n=>U(`/forms/${n}/merge-tags`).then(e=>e.groups),analytics:(n,e="")=>U(`/forms/${n}/analytics${e?`?dimension=${encodeURIComponent(e)}`:""}`),demoStatus:()=>U("/demo"),demoSeed:n=>K("/demo",n?{count:n}:{}),demoRemove:()=>he("/demo"),listEntries:n=>U(`/entries${et(n)}`),getEntry:n=>U(`/entries/${n}`),updateEntry:(n,e)=>K(`/entries/${n}`,e),deleteEntry:n=>he(`/entries/${n}`),exportEntries:n=>U(`/entries/export${et(n)}`),listThemes:()=>U("/themes"),saveTheme:n=>K("/themes",n),deleteTheme:n=>he(`/themes/${n}`)};function r(n,e={}){const t=document.createElement(n);e.class&&(t.className=e.class),e.text!==void 0&&(t.textContent=e.text),e.html!==void 0&&(t.innerHTML=e.html),e.title&&(t.title=e.title),e.type&&"type"in t&&(t.type=e.type),e.value!==void 0&&"value"in t&&(t.value=e.value),e.placeholder!==void 0&&"placeholder"in t&&(t.placeholder=e.placeholder),e.href&&"href"in t&&(t.href=e.href);for(const[s,a]of Object.entries(e.attrs??{}))a===void 0||a===!1||t.setAttribute(s,a===!0?"":String(a));Object.assign(t.style,e.style??{});for(const[s,a]of Object.entries(e.on??{}))t.addEventListener(s,a);for(const s of e.children??[])s==null||s===!1||t.append(s);return t}function R(n){n.replaceChildren()}function z(n){return r("span",{class:`dashicons ${n.startsWith("dashicons-")?n:`dashicons-${n}`}`,attrs:{"aria-hidden":"true"}})}function y(n,e,t){const s=e.matches("input, select, textarea, button")?e:e.querySelector("input, select, textarea");if(s){const a=s.id||`atf-c-${Math.random().toString(36).slice(2,9)}`;return s.id=a,r("div",{class:"atfb-row",children:[r("label",{class:"atfb-row__label",text:n,attrs:{for:a}}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}return r("div",{class:"atfb-row",children:[r("span",{class:"atfb-row__label",text:n}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}function T(n,e,t=""){return r("input",{class:"atfb-input",type:"text",value:n,placeholder:t,on:{input:s=>e(s.target.value)}})}function G(n,e){if(Y("os-number-field")){const t=document.createElement("os-number-field");return t.setAttribute("value",n),t.classList.add("atfb-field"),t.addEventListener("os-input-change",s=>{e(String(s.detail?.value??""))}),t}return r("input",{class:"atfb-input",type:"number",value:n,on:{input:t=>e(t.target.value)}})}function pe(n,e,t=4){const s=r("textarea",{class:"atfb-input atfb-input--area",attrs:{rows:t},on:{input:a=>e(a.target.value)}});return s.value=n,s}function D(n,e,t){if(Y("os-select")&&Y("os-option")){const s=document.createElement("os-select");s.setAttribute("value",n),s.classList.add("atfb-field");for(const a of e){const i=document.createElement("os-option");i.setAttribute("value",a.value),i.textContent=a.label,s.append(i)}return s.addEventListener("os-pick",a=>{t(String(a.detail?.value??""))}),s}return r("select",{class:"atfb-input atfb-select",on:{change:s=>t(s.target.value)},children:e.map(s=>r("option",{value:s.value,text:s.label,attrs:{selected:s.value===n}}))})}function O(n,e,t){if(Y("os-checkbox-label")){const a=document.createElement("os-checkbox-label");return a.setAttribute("label",n),a.classList.add("atfb-check"),e&&a.setAttribute("checked",""),a.addEventListener("os-checkbox-change",i=>{t(!!i.detail?.checked)}),a}const s=r("input",{type:"checkbox",on:{change:a=>t(a.target.checked)}});return s.checked=e,r("label",{class:"atfb-check",children:[s,r("span",{text:n})]})}function $(n,e,t="secondary",s){const a=[s?z(s):null,r("span",{text:n})];if(Y("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",t),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${t}`),i.addEventListener("click",e);for(const o of a)o&&i.append(o);return i}return r("button",{class:`atfb-button atfb-button--${t}`,type:"button",on:{click:e},children:a})}function Y(n){return typeof customElements<"u"&&!!customElements.get(n)}const ss=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let fe=null;function ns(){if(fe)return fe;const n=window.wp?.os;return fe=n?.loadComponents?n.loadComponents(ss).catch(()=>{}):Promise.resolve(),fe}async function ie(n,e=""){const t=window.wp?.os;return t?.confirm?t.confirm({title:e,message:n,danger:!0}):window.confirm(n)}function N(n,e="",t="info"){const s=window.wp?.os;if(s?.notify){s.notify({title:n,body:e,type:t});return}console.info(`[AllTerrain Forms] ${n}${e?`: ${e}`:""}`)}function as(n){let e=0,t;return(...s)=>{t=s,!e&&(e=window.requestAnimationFrame(()=>{e=0,n(...t)}))}}function $e(n,e){let t=0;return(...s)=>{window.clearTimeout(t),t=window.setTimeout(()=>n(...s),e)}}function is(n){try{return window.localStorage.getItem(n)??""}catch{return""}}function rs(n,e){try{window.localStorage.setItem(n,e)}catch{}}function Ae(n){const e=n.closest(".os-window__body");e&&(e.addEventListener("scroll",()=>{e.scrollTop&&(e.scrollTop=0),e.scrollLeft&&(e.scrollLeft=0)},{passive:!0}),e.scrollTop=0,e.scrollLeft=0)}function tt(){const n=[window];try{window.parent&&window.parent!==window&&n.push(window.parent)}catch{}return n}function os(n){const e=n.wp?.os?.windowManager?.getAll?.()??[];for(const t of e){const s=t.iframe??t.element?.querySelector?.("iframe");if(s&&s.contentWindow===window)return t}return null}const ls=4e3,cs=100;function ds(n,e){const t=Date.now()+ls,s=()=>{const a=os(n);if(a&&a.id!==e){typeof a.close=="function"?a.close():n.wp?.os?.windowManager?.remove?.(a.id);return}!a&&Date.now()0?{form:t}:void 0;t>0&&fs(t);for(const a of tt())if(a.wp?.os?.openWindow?.(e,{source:"handoff",params:s})){window.setTimeout(()=>ds(a,e),0);return}}function us(){document.addEventListener("click",n=>{const e=n.target?.closest?.("[data-atf-open-window]");if(!e)return;n.preventDefault();const t=e.getAttribute("data-atf-open-window")??"";for(const s of tt())if(s.wp?.os?.openWindow?.(t,{source:"handoff"}))return})}const ps="allterrain-forms/requested-form";function fs(n){try{window.sessionStorage.setItem(ps,String(n))}catch{}}function st(n){return`allterrain-forms/requested-form-${n}`}function ms(n){try{const e=window.sessionStorage.getItem(st(n));return window.sessionStorage.removeItem(st(n)),Number(e)||0}catch{return 0}}const Te={is:"is",is_not:"is not",contains:"contains",not_contains:"does not contain",starts_with:"starts with",ends_with:"ends with",greater:"is more than",less:"is less than",greater_equal:"is at least",less_equal:"is at most",empty:"is empty",not_empty:"has any answer"},Me=["empty","not_empty"];function nt(n,e){const t=n.find(s=>s.id===e);return t?t.label||"an untitled question":null}function at(n,e,t){return n.find(i=>i.id===e)?.choices?.find(i=>i.value===t)?.label||t}function bs(n,e){const t=Te[n.operator]??String(n.operator);if(Me.includes(n.operator))return t;const s=at(e,n.field,n.value);return`${n.operator==="is"?"":`${t} `}${s!==""?s:"(nothing)"}`}function it(n,e,t=0){const s=nt(e,n.field),a=Te[n.operator]??String(n.operator);if(s===null)return[{kind:"field",text:"a question that no longer exists",fieldId:n.field,missing:!0}];const i=[{kind:"field",text:s,fieldId:n.field,missing:!1},{kind:"operator",text:a,operator:n.operator,ruleIndex:t}];if(Me.includes(n.operator))return i;const o=at(e,n.field,n.value);return i.push({kind:"value",text:o!==""?o:"(nothing)",raw:n.value,sourceId:n.field,ruleIndex:t}),i}function gs(n,e){const t=n.logic;if(!t?.enabled||!t.rules.length)return[];const s=[{kind:"verb",text:t.action==="hide"?"Hidden when":"Shown when"}];return t.rules.forEach((a,i)=>{i>0&&s.push({kind:"join",text:t.match==="all"?"and":"or"}),s.push(...it(a,e,i))}),s}function rt(n){return n.map(e=>e.text).join(" ")}function vs(n,e){return rt(it(n,e))}function me(n){const e=[];for(const t of n){const s=t.logic;if(s?.enabled)for(const a of s.rules)!a.field||a.field===t.id||e.push({from:a.field,to:t.id,label:vs(a,n),short:bs(a,n),action:s.action,broken:nt(n,a.field)===null})}return e}function ys(n){const e=new Map,t=new Set;for(const s of me(n)){const a=`${s.from}->${s.to}`;s.broken||t.has(a)||(t.add(a),e.set(s.from,(e.get(s.from)??0)+1))}return e}const ot=10,lt=22,ne="http://www.w3.org/2000/svg";class ws{constructor(e){this.edges=[],this.teardowns=[],this.frame=0,this.host=e,this.svg=document.createElementNS(ne,"svg"),this.svg.setAttribute("class","atfb-logicmap"),this.svg.setAttribute("aria-hidden","true"),this.svg.setAttribute("focusable","false"),e.append(this.svg);const t=()=>this.schedule();window.addEventListener("resize",t),this.teardowns.push(()=>window.removeEventListener("resize",t));const s=e.closest(".atfb__canvas")??e;if(s.addEventListener("scroll",t,{passive:!0}),this.teardowns.push(()=>s.removeEventListener("scroll",t)),typeof ResizeObserver<"u"){const a=new ResizeObserver(t);a.observe(e),this.teardowns.push(()=>a.disconnect())}}setEdges(e){this.edges=e,this.schedule()}highlight(e){this.svg.classList.toggle("is-focused",!!e),this.svg.querySelectorAll("[data-from]").forEach(t=>{const s=e&&(t.dataset.from===e||t.dataset.to===e);t.classList.toggle("is-lit",!!s)})}destroy(){this.teardowns.forEach(e=>e()),this.teardowns=[],this.svg.remove(),this.frame&&cancelAnimationFrame(this.frame)}schedule(){this.frame||(this.frame=requestAnimationFrame(()=>{this.frame=0,this.draw()}))}draw(){this.svg.replaceChildren();const e=this.host.getBoundingClientRect();this.svg.setAttribute("viewBox",`0 0 ${e.width} ${e.height}`),this.svg.setAttribute("width",String(e.width)),this.svg.setAttribute("height",String(e.height));const t=new Map;for(const s of this.edges){const a=this.cardRect(s.from),i=this.cardRect(s.to);if(!a||!i)continue;const o=t.get(s.from)??0;t.set(s.from,o+1),this.drawEdge(s,a,i,e,o)}}cardRect(e){const t=this.host.querySelector(`[data-atfb-card="${CSS.escape(e)}"]`);return t?t.getBoundingClientRect():null}drawEdge(e,t,s,a,i){const o=t.right-a.left,l=t.top+t.height/2-a.top,c=s.right-a.left,d=s.top+s.height/2-a.top,h=Math.max(0,a.width-ot-Math.max(o,c)),w=22+i*11+Math.min(22,Math.abs(d-l)/8),_=Math.max(12,Math.min(w,h*.4)),u=document.createElementNS(ne,"path");u.setAttribute("d",`M ${o} ${l} C ${o+_} ${l}, ${c+_} ${d}, ${c} ${d}`),u.setAttribute("class",`atfb-logicmap__path is-${e.action}${e.broken?" is-broken":""}`),u.dataset.from=e.from,u.dataset.to=e.to;const b=document.createElementNS(ne,"title");b.textContent=e.label,u.append(b);const g=document.createElementNS(ne,"circle");g.setAttribute("cx",String(c)),g.setAttribute("cy",String(d)),g.setAttribute("r","3.5"),g.setAttribute("class",`atfb-logicmap__dot is-${e.action}${e.broken?" is-broken":""}`),g.dataset.from=e.from,g.dataset.to=e.to,this.svg.append(u,g);const p=document.createElementNS(ne,"text");p.setAttribute("x",String(a.width-ot)),p.setAttribute("y",String(d+3)),p.setAttribute("text-anchor","end"),p.setAttribute("class","atfb-logicmap__label"),p.dataset.from=e.from,p.dataset.to=e.to,p.textContent=e.short.length>lt?`${e.short.slice(0,lt-1)}…`:e.short;const x=document.createElementNS(ne,"title");x.textContent=e.label,p.append(x),this.svg.append(p)}}const _s={text:"text",email:"text",url:"text",tel:"text",number:"text",password:"text",date:"text",time:"text",datetime:"text",date_range:"composite",textarea:"textarea",select:"select",country:"select",multiselect:"options",radio:"options",checkboxes:"options",image_choice:"options",quiz:"options",switch:"toggle",consent:"toggle",file:"file",range:"range",rating:"summary",scale:"summary",likert:"summary",signature:"summary",repeater:"repeater",color:"text",name:"composite",address:"composite",total:"text",hidden:"static",heading:"static",html:"static",divider:"static",spacer:"static",page_break:"static"};function xs(n){return _s[n]??"text"}function ct(n,e){const t=/^choice:(\d+):(label|value)$/.exec(e);return String(t?n.choices?.[Number(t[1])]?.[t[2]]??"":n[e]??"")}function V(n){const{value:e,onInput:t,onCommit:s}=n,a=r("span",{class:`${n.class} atfb-editable`,text:e,attrs:{contenteditable:"plaintext-only",role:"textbox",spellcheck:"false","data-placeholder":n.placeholder}});return n.bind&&(a.dataset.atfbBind=n.bind),a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("input",()=>t(a.textContent??"")),a.addEventListener("keydown",i=>{i.key==="Enter"&&(i.preventDefault(),a.blur()),i.key==="Escape"&&(a.textContent=e,a.blur()),i.stopPropagation()}),a.addEventListener("blur",()=>s?.()),a}function ks(n){const e=r("input",{class:"atf-choice__input",type:n==="checkboxes"||n==="multiselect"?"checkbox":"radio"});return e.disabled=!0,e}function dt(n,e,t){const s=xs(n.type),a=V({value:n.label,placeholder:"Write the question…",class:"atf-label",bind:"label",onInput:o=>t.edit(l=>{l.label=o}),onCommit:()=>t.restructure(()=>{})}),i=[s==="static"||s==="toggle"?null:a,Ls(n,e,s,t),Ss(n,e,t)];return r("div",{class:"atfb-preview atf-form",children:[r("div",{class:`atf-field atf-field--${n.type}`,children:i})]})}function Ss(n,e,t){if(!e?.supports.includes("hint"))return null;const s=V({value:n.hint??"",placeholder:"Add a hint…",class:"atf-hint",bind:"hint",onInput:a=>t.edit(i=>{i.hint=a})});return s.setAttribute("aria-label","Hint"),r("p",{class:"atfb-preview__hint",children:[s]})}function Ls(n,e,t,s){switch(t){case"text":return Fe(n,"atf-input",s);case"textarea":return Fe(n,"atf-input atf-textarea",s,!0);case"select":return r("div",{class:"atfb-preview__select",children:[Fe(n,"atf-input atf-select",s)]});case"options":return As(n,s);case"toggle":return r("div",{class:n.type==="switch"?"atf-toggle atf-toggle--switch":"atf-toggle",children:[(()=>{const a=r("input",{class:"atf-toggle__input",type:"checkbox"});return a.disabled=!0,a})(),V({value:n.label||"",placeholder:n.type==="consent"?"What are they agreeing to?…":"What does this turn on?…",class:"atf-toggle__label",bind:"label",onInput:a=>s.edit(i=>{i.label=a}),onCommit:()=>s.restructure(()=>{})})]});case"file":return r("div",{class:"atf-file",children:[r("input",{class:"atf-file__input",type:"file"})]});case"range":return r("input",{class:"atf-range__input",type:"range"});case"composite":return r("div",{class:"atf-composite__parts",children:[r("span",{class:"atf-input atfb-preview__ghost",text:""}),r("span",{class:"atf-input atfb-preview__ghost",text:""})]});case"static":return Ts(n,e,s);case"repeater":return Es(n,s);default:return r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — set this up in the panel on the right.`})]})}}function Es(n,e){const t=n.fields??[],s=r("div",{class:"atfb-repeater__zone",attrs:{"data-atfb-repeater-zone":n.id}});return t.forEach(a=>s.append(Cs(n,a,e))),t.length||s.append(r("p",{class:"atfb-repeater__empty",text:"Drag fields from the palette in here — the visitor gets a fresh copy of each with every row they add."})),r("div",{class:"atfb-repeater",attrs:{"data-atfb-repeater":n.id},children:[r("div",{class:"atf-repeater__row atfb-repeater__frame",children:[r("div",{class:"atf-repeater__row-head",children:[r("span",{class:"atf-repeater__title atfb-repeater__title",children:[V({value:String(n.itemLabel??""),placeholder:"Row",class:"atfb-repeater__item-label",bind:"itemLabel",onInput:a=>e.edit(i=>{i.itemLabel=a})}),r("span",{class:"atfb-repeater__ordinal",text:"1",attrs:{"aria-hidden":"true"}})]})]}),s]}),$s(n,e)]})}function Cs(n,e,t){const s=e.id,a=l=>c=>{const d=(c.fields??[]).find(h=>h.id===s);d&&l(d)},i={edit:l=>t.edit(a(l)),restructure:l=>t.restructure(a(l)),types:t.types,selectedId:t.selectedId},o=t.types?.(e.type);return r("div",{class:`atfb-subcard${t.selectedId===s?" is-selected":""}`,attrs:{"data-atfb-subfield":s,"data-atfb-parent":n.id,tabindex:"0",role:"button","aria-label":`${e.label||o?.label||e.type}, inside ${n.label||"the repeater"}`},children:[r("div",{class:"atfb-subcard__head",children:[r("span",{class:"atfb-subcard__type",text:o?.label??e.type}),e.required?r("span",{class:"atfb-subcard__required",text:"Required"}):null,r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this field from the repeater",attrs:{"aria-label":`Remove ${e.label||o?.label||"this field"}`},on:{pointerdown:l=>l.stopPropagation(),click:l=>{l.stopPropagation(),t.restructure(c=>{const d=c.fields??[],h=d.findIndex(w=>w.id===s);h>=0&&d.splice(h,1)})}},children:[r("span",{text:"×"})]})]}),dt(e,o,i)]})}function Fe(n,e,t,s=!1){const a=V({value:n.placeholder??"",placeholder:n.type==="select"||n.type==="country"?"Choose…":"Placeholder…",class:`${e} atfb-preview__box${s?" atfb-preview__box--tall":""}`,bind:"placeholder",onInput:i=>t.edit(o=>{o.placeholder=i})});return a.setAttribute("aria-label","Placeholder"),a}function Ie(n,e,t,s,a,i){return r("span",{class:`atf-button ${t} atfb-preview__button`,children:[V({value:n,placeholder:e,class:"atfb-preview__button-text",bind:s,onInput:o=>a.edit(l=>i(l,o))})]})}function $s(n,e){return Ie(String(n.addLabel??""),"Add another","atf-button--ghost atfb-repeater__add","addLabel",e,(t,s)=>{t.addLabel=s})}function As(n,e){const t=r("div",{class:"atf-choices__list"});return(n.choices??[]).forEach((s,a)=>{t.append(r("div",{class:"atf-choice atfb-preview__option",children:[ks(n.type),V({value:s.label,placeholder:"Option…",class:"atf-choice__label",bind:`choice:${a}:label`,onInput:i=>{e.edit(o=>{const l=o.choices?.[a];if(!l)return;const c=!l.value||l.value===l.label;l.label=i,c&&(l.value=i)})}}),r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this option",attrs:{"aria-label":`Remove ${s.label||"this option"}`},on:{pointerdown:i=>i.stopPropagation(),click:i=>{i.stopPropagation(),e.restructure(o=>{o.choices.splice(a,1)})}},children:[r("span",{text:"×"})]})]}))}),t.append(r("button",{class:"atfb-preview__add",type:"button",on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.restructure(a=>{const i=a.choices.length+1;a.choices.push({label:`Option ${i}`,value:`Option ${i}`})})}},children:[r("span",{text:"+ Add option"})]})),r("fieldset",{class:"atf-choices",children:[t]})}function Ts(n,e,t){return n.type==="heading"?V({value:n.label,placeholder:"Section heading…",class:"atf-heading",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})}):n.type==="divider"?r("hr",{class:"atf-divider"}):n.type==="page_break"?r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-progress-name",children:[V({value:n.label,placeholder:"Name this step…",class:"atf-progress__label",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})})]}),r("p",{class:"atfb-preview__summary",text:"Everything after this is a new page."}),r("div",{class:"atf-nav atfb-preview__nav",children:[Ie(String(n.prevLabel??""),"Back","atf-button--secondary","prevLabel",t,(s,a)=>{s.prevLabel=a}),Ie(String(n.nextLabel??""),"Next","","nextLabel",t,(s,a)=>{s.nextLabel=a})]})]}):r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — nothing is shown to the visitor here.`})}const De=new Map;function qe(n){let e=De.get(n);return e||(e=F.mergeTags(n).catch(()=>[]),De.set(n,e)),e}function Ms(n){De.delete(n)}function Fs(n){const e=new Map;for(const t of n)for(const s of t.items)e.set(s.tag,s);return e}function Is(n,e){const t=Fs(e);return n.replace(/\{[a-z_]+(?::[^}]*)?\}/gi,s=>{const a=t.get(s.toLowerCase());return a?a.sample:s})}function Ds(n){return/\{[a-z_]+(?::[^}]*)?\}/i.test(n)}let te=null;function re(){te?.remove(),te=null}typeof document<"u"&&(document.addEventListener("pointerdown",n=>{const e=n.target;e?.closest(".atfb-tagpick__open")||te&&!te.contains(e)&&re()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&te&&(re(),n.stopPropagation())}));function ht(n,e){const t=n.selectionStart??n.value.length,s=n.selectionEnd??n.value.length;n.value=n.value.slice(0,t)+e+n.value.slice(s);const a=t+e.length;n.setSelectionRange(a,a),n.focus(),n.dispatchEvent(new Event("input",{bubbles:!0}))}function qs(n){let e=n.parentElement;for(;e&&e!==document.body;){const t=getComputedStyle(e).overflowY;if(t==="auto"||t==="scroll"||t==="hidden")return e.getBoundingClientRect().bottom;e=e.parentElement}return window.innerHeight}function Os(n,e){const t=r("input",{class:"atfb-input atfb-tagpick__search",type:"search",placeholder:"Search values…",attrs:{"aria-label":"Search values"}}),s=r("div",{class:"atfb-tagpick__list"}),a=i=>{s.replaceChildren();const o=i.trim().toLowerCase();let l=0;for(const c of n){const d=c.items.filter(h=>!o||h.label.toLowerCase().includes(o)||h.tag.toLowerCase().includes(o));if(!d.length){c.empty&&!o&&!c.items.length&&s.append(r("p",{class:"atfb-tagpick__group",text:c.label}),r("p",{class:"atfb-tagpick__empty",text:c.empty}));continue}s.append(r("p",{class:"atfb-tagpick__group",text:c.label}));for(const h of d)l+=1,s.append(r("button",{class:"atfb-tagpick__item",type:"button",on:{click:()=>{e(h.tag),re()}},children:[r("span",{class:"atfb-tagpick__item-main",children:[r("span",{class:"atfb-tagpick__label",text:h.label}),r("code",{class:"atfb-tagpick__tag",text:h.tag})]}),h.hint||h.sample?r("span",{class:"atfb-tagpick__meta",text:h.sample?`e.g. ${h.sample}`:h.hint}):null]}))}!l&&o&&s.append(r("p",{class:"atfb-tagpick__empty",text:`Nothing matches “${i}”.`}))};return a(""),t.addEventListener("input",()=>a(t.value)),r("div",{class:"atfb-tagpick",attrs:{role:"dialog","aria-label":"Insert a value"},children:[r("p",{class:"atfb-tagpick__intro",text:"Pick something to drop in. It is filled in when the form is submitted."}),t,s]})}function ut(n,e){const t=r("button",{class:"atfb-button atfb-button--ghost atfb-tagpick__open",type:"button",title:"Insert a value from the submission",children:[z("shortcode"),r("span",{text:"Insert a value"})]}),s=r("div",{class:"atfb-taggable",children:[n,r("div",{class:"atfb-taggable__tools",children:[t]})]}),a=e.preview===!1?null:r("p",{class:"atfb-taggable__preview"});a&&s.append(a);const i=()=>{if(a){if(!Ds(n.value)){a.textContent="",a.hidden=!0;return}qe(e.formId).then(o=>{a.hidden=!1,a.replaceChildren(r("span",{class:"atfb-taggable__preview-label",text:"Reads as"}),r("span",{text:Is(n.value,o)}))})}};return n.addEventListener("input",i),i(),t.addEventListener("click",o=>{if(o.stopPropagation(),te&&s.contains(te)){re();return}re(),qe(e.formId).then(l=>{const c=Os(l,d=>{ht(n,d),i()});s.append(c),te=c,(window.innerHeight-c.getBoundingClientRect().topqs(s))&&c.classList.add("atfb-tagpick--above"),c.querySelector(".atfb-tagpick__search")?.focus()})}),s}function pt(n,e){const t=parseFloat(String(n??""));return Number.isFinite(t)?t:e}function ft(n,e){let t=e[0];for(const s of e)Math.abs(s.at-n)n.accent??"#2271b1",apply:n=>({accent:n,"accent-soft":`color-mix( in srgb, ${n} 12%, transparent )`,"border-focus":n,"focus-ring-color":n,"button-bg":n,"button-bg-hover":`color-mix( in srgb, ${n} 88%, #000 )`})},{id:"roundness",label:"Roundness",hint:"Corners, everywhere at once.",kind:"scale",steps:Oe.map(({value:n,label:e})=>({value:n,label:e})),owns:["radius-field","radius-button","radius-card","radius-check"],read:n=>ft(pt(n["radius-field"],4),Oe),apply:n=>{const e=Oe.find(t=>t.value===n)?.at??4;return{"radius-field":`${e}px`,"radius-button":`${e}px`,"radius-card":`${Math.min(e*2,28)}px`,"radius-check":`${Math.min(e,6)}px`}}},{id:"density",label:"Density",hint:"How much air the form has.",kind:"scale",steps:Ne.map(({value:n,label:e})=>({value:n,label:e})),owns:["pad-field-x","pad-field-y","gap-fields","gap-label","button-pad-x","button-pad-y"],read:n=>ft(pt(n["pad-field-y"],9),Ne),apply:n=>{const e=Ne.find(t=>t.value===n)?.at??9;return{"pad-field-y":`${e}px`,"pad-field-x":`${Math.round(e*1.4)}px`,"gap-fields":`${Math.round(e*2.2)}px`,"gap-label":`${Math.max(4,Math.round(e*.7))}px`,"button-pad-y":`${e+2}px`,"button-pad-x":`${Math.round(e*2.2)}px`}}},{id:"shadow",label:"Depth",hint:"How far the form sits off the page.",kind:"scale",steps:Ns,owns:["shadow-field","shadow-field-focus","shadow-button","shadow-button-hover","shadow-card"],read:n=>{const e=n["shadow-card"]??"none";return e==="none"||e.trim()===""?n["shadow-field"]&&n["shadow-field"]!=="none"?"hard":"none":e.includes("0 1px")||e.includes("2px")?"subtle":"lifted"},apply:n=>{switch(n){case"subtle":return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"0 1px 2px rgba( 0, 0, 0, 0.12 )","shadow-button-hover":"0 2px 4px rgba( 0, 0, 0, 0.16 )","shadow-card":"0 1px 3px rgba( 0, 0, 0, 0.1 )"};case"lifted":return{"shadow-field":"none","shadow-field-focus":"0 4px 12px rgba( 0, 0, 0, 0.12 )","shadow-button":"0 4px 10px rgba( 0, 0, 0, 0.16 )","shadow-button-hover":"0 8px 20px rgba( 0, 0, 0, 0.2 )","shadow-card":"0 10px 30px rgba( 0, 0, 0, 0.14 )"};case"hard":return{"shadow-field":"3px 3px 0 currentColor","shadow-field-focus":"5px 5px 0 currentColor","shadow-button":"4px 4px 0 currentColor","shadow-button-hover":"2px 2px 0 currentColor","shadow-card":"none"};default:return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"none","shadow-button-hover":"none","shadow-card":"none"}}}},{id:"field-style",label:"Fields",hint:"How an input is drawn.",kind:"choice",steps:Rs,owns:["field-style"],read:n=>n["field-style"]??"outline",apply:n=>({"field-style":n})},{id:"labels",label:"Labels",hint:"Where the question sits relative to the answer.",kind:"choice",steps:Ps,owns:["label-position"],read:n=>n["label-position"]??"top",apply:n=>({"label-position":n})}]}function Bs(n){return Re().find(e=>e.owns.includes(n))??null}function mt(n){let e=n.activeSlug,t={...n.overrides},s=n.themes;const a=m=>{t=m,n.onOverridesReplaced?.({...m})},i=r("div",{class:"atfs-preview__frame"}),o=r("div",{class:"atfs-controls__body"}),l=r("div",{class:"atfs-quick"}),c=r("div",{class:"atfs-themes"}),d=$e(async()=>{try{const m=await n.previewFor(e,t),v=i.closest(".atf-studio__preview"),k=v?.scrollTop??0;i.innerHTML=m,v&&(v.scrollTop=k),document.dispatchEvent(new CustomEvent("alltfo-refresh"))}catch(m){R(i),i.append(r("p",{class:"atfb-error",text:m instanceof Error?m.message:"Preview failed."}))}},180),h={"label-position":"atf-labels-","field-style":"atf-fields-"},w=(m,v,k)=>{const L=k.replace(/[^a-z0-9_-]/gi,"");for(const A of[...m.classList])A.startsWith(v)&&m.classList.remove(A);L&&m.classList.add(v+L)},_=m=>{const v=i.querySelector(".atf-form-wrap"),k=v?.querySelector(".atf-form");if(v)for(const[L,A]of Object.entries(m))A===""?v.style.removeProperty(`--atf-${L}`):v.style.setProperty(`--atf-${L}`,A),k&&h[L]&&w(k,h[L],A||(s.find(P=>P.slug===e)?.resolved[L]??""))},u=m=>{_(m.resolved);const v=i.querySelector(".atf-form");v&&(w(v,"atf-theme-",m.slug),v.classList.toggle("atf-is-dark",!!m.dark))},b=m=>t[m.token]!==void 0?t[m.token]:s.find(k=>k.slug===e)?.resolved?.[m.token]??m.default,g=()=>{R(c);for(const m of s){const v=r("button",{class:`atfs-theme${m.slug===e?" is-active":""}`,type:"button",attrs:{"aria-pressed":m.slug===e,title:m.description},children:[r("span",{class:"atfs-theme__chip",style:{background:m.resolved.surface??"#fff",borderColor:m.resolved.border??"#ccc",borderRadius:m.resolved["radius-field"]??"4px",boxShadow:m.resolved["shadow-card"]??"none"},children:[r("span",{class:"atfs-theme__accent",style:{background:m.resolved.accent??"#2271b1",borderRadius:m.resolved["radius-button"]??"4px"}})]}),r("span",{class:"atfs-theme__name",text:m.label}),m.custom?r("span",{class:"atfb-badge",text:"yours"}):null],on:{click:()=>{e=m.slug,a({}),n.onTheme(e),u(m),g(),S(),I(),Yt()}}});c.append(v)}},p=()=>{const v={...s.find(k=>k.slug===e)?.resolved??{}};for(const[k,L]of Object.entries(t))v[k]=L;return v},x=m=>{const v=l.closest(".atf-studio__controls"),k=v?.scrollTop??0;m(),v&&(v.scrollTop=k)},I=$e(()=>x(f),150),S=()=>{const m=p(),v=l.querySelectorAll(".atfs-dial");Re().forEach((k,L)=>{const A=v[L];if(!A)return;const P=k.read(m);if(k.kind==="colour"){const q=A.querySelector('input[type="color"]'),X=A.querySelector("input.atfb-input");q&&document.activeElement!==q&&(q.value=be(P)),X&&document.activeElement!==X&&(X.value=P);return}A.querySelectorAll(".atfs-segment").forEach((q,X)=>{const Q=k.steps?.[X]?.value===P;q.classList.toggle("is-on",Q),q.setAttribute("aria-pressed",String(Q))})})},H=(m,v)=>{const k=m.apply(v,p());for(const[L,A]of Object.entries(k))t[L]=A,n.onOverride(L,A);_(k),S(),I()},E=()=>{R(l);const m=p();for(const v of Re()){const k=v.read(m);let L;if(v.kind==="colour"){const A=r("input",{class:"atfs-color",type:"color",value:be(k),attrs:{"aria-label":v.label},on:{input:P=>H(v,P.target.value)}});L=r("div",{class:"atfs-color-row",children:[A,T(k,P=>H(v,P))]})}else L=r("div",{class:`atfs-segmented atfs-segmented--${v.kind}`,attrs:{role:"group","aria-label":v.label},children:(v.steps??[]).map(A=>r("button",{class:`atfs-segment${A.value===k?" is-on":""}`,type:"button",text:A.label,attrs:{"aria-pressed":A.value===k},on:{click:()=>H(v,A.value)}}))});l.append(r("div",{class:"atfs-dial",children:[r("div",{class:"atfs-dial__head",children:[r("span",{class:"atfs-dial__label",text:v.label}),r("span",{class:"atfs-dial__hint",text:v.hint})]}),L]}))}},f=()=>{R(o);const m=new Map;for(const k of n.tokens){const L=m.get(k.group)??[];L.push(k),m.set(k.group,L)}const v={colour:"Colour",shape:"Corners and borders",shadow:"Shadows",fields:"Field style",space:"Spacing",type:"Type",labels:"Labels",button:"Buttons",focus:"Focus ring",motion:"Motion"};for(const[k,L]of m)o.append(r("details",{class:"atfs-group",attrs:{open:k==="colour"},children:[r("summary",{text:v[k]??k}),...L.map(A=>M(A))]}))},M=m=>{const v=b(m),k=q=>{q===""?delete t[m.token]:t[m.token]=q,n.onOverride(m.token,q),_({[m.token]:q})};let L;if(m.control==="color"){const q=r("input",{class:"atfs-color",type:"color",value:be(v),attrs:{"aria-label":`${m.label} colour`},on:{input:Q=>{const ce=Q.target.value;X.value=ce,k(ce)}}}),X=T(v,Q=>{q.value=be(Q),k(Q)});L=r("div",{class:"atfs-color-row",children:[q,X]})}else if(m.control==="select")L=D(v,(m.options??[]).map(q=>({value:q,label:q})),k);else if(m.control==="length"){const q=parseFloat(v)||0,X=m.unit??"px",Q=m.token.includes("radius")?60:80,ce=r("input",{class:"atfs-range",type:"range",value:String(q),attrs:{min:"0",max:String(Q),step:"1","aria-label":m.label},on:{input:ke=>{const Xt=`${ke.target.value}${X}`;Gt.value=Xt,k(Xt)}}}),Gt=T(v,ke=>{ce.value=String(parseFloat(ke)||0),k(ke)});L=r("div",{class:"atfs-length-row",children:[ce,Gt]})}else L=T(v,k);const A=y(m.label,L),P=Bs(m.token);return P&&(A.classList.add("is-dialled"),A.append(r("span",{class:"atfs-owned",text:P.label}))),t[m.token]!==void 0&&(A.classList.add("is-overridden"),A.append(r("button",{class:"atfs-reset",type:"button",text:"Reset",attrs:{"aria-label":`Reset ${m.label} to the theme's value`},on:{click:()=>{k(""),x(f)}}}))),A},C=async()=>{const m=s.find(L=>L.slug===e),v=m?`${m.label} (mine)`:"My theme",k=window.prompt("Name this theme",v);if(k)try{const L={};for(const P of n.tokens){const q=b(P);q!==P.default&&(L[P.token]=q)}const A=await F.saveTheme({label:k,tokens:L});s=[...s.filter(P=>P.slug!==A.slug),A],n.onThemesChanged(s),e=A.slug,a({}),n.onTheme(e),g(),S(),x(f),N("Theme saved",A.label)}catch(L){N("Could not save the theme",L instanceof Error?L.message:"","error")}},j=async()=>{const m=s.find(v=>v.slug===e);if(m?.custom&&await ie(`Delete “${m.label}”? Forms using it fall back to Clean.`,"Delete theme"))try{await F.deleteTheme(m.id),s=s.filter(k=>k.slug!==m.slug),n.onThemesChanged(s),e="clean",a({}),n.onTheme(e),g(),S(),x(f);const v=s.find(k=>k.slug===e);v&&u(v)}catch(v){N("Could not delete the theme",v instanceof Error?v.message:"","error")}},B=async()=>{const m=s.find(L=>L.slug===e),v={label:m?.label??e,tokens:{...m?.tokens??{},...t}},k=JSON.stringify(v,null," ");try{await navigator.clipboard.writeText(k),N("Theme copied","Paste it into another site to import it.")}catch{window.prompt("Copy this theme",k)}},le=()=>{const m=window.prompt("Paste a theme");if(m)try{const v=JSON.parse(m);if(!v.tokens||typeof v.tokens!="object")throw new Error("That does not look like a theme.");for(const[k,L]of Object.entries(v.tokens))t[k]=String(L),n.onOverride(k,String(L));_({...t}),S(),x(f)}catch(v){N("Could not read that theme",v instanceof Error?v.message:"","error")}},zt=$("Delete",()=>void j(),"danger"),Yt=()=>{const m=s.find(v=>v.slug===e);zt.hidden=!m?.custom};return g(),E(),f(),d(),Yt(),r("div",{class:"atf-studio",children:[r("div",{class:"atf-studio__top",children:[r("div",{class:"atf-studio__topbar",children:[r("h2",{class:"atf-studio__heading",text:"Theme"}),r("div",{class:"atfs__actions",children:[$("Save as a theme",()=>void C(),"primary"),$("Export",()=>void B()),$("Import",le),zt]})]}),c]}),r("div",{class:"atf-studio__panes",children:[r("aside",{class:"atf-studio__controls",children:[r("p",{class:"atfb-hint",text:"Changes apply to this form only, until you save them as a theme."}),l,r("details",{class:"atfs-advanced",children:[r("summary",{text:"Every setting"}),r("p",{class:"atfb-hint",text:"The full token list. The dials above write into it."}),o]})]}),r("main",{class:"atf-studio__preview",children:[r("h2",{class:"screen-reader-text",text:"Live preview"}),i]})]})]})}async function Pe(){const n=document.querySelector("[data-atfs-root]");if(!n||n.dataset.atfsMounted)return;n.dataset.atfsMounted="1",Ae(n);const e=n.querySelector("[data-atfs-bar]"),t=n.querySelector(".atfs__body")??n;try{const[s,a,i]=await Promise.all([F.config(),F.listThemes(),F.listForms()]);if(!i.length){R(t),t.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms to preview"}),r("p",{text:"Make a form first — a theme needs something to dress."})]}));return}let o=i[0],l={},c=o.theme;const d=()=>{R(t),t.append(mt({themes:a,tokens:s.tokens,activeSlug:c,overrides:l,standalone:!0,onTheme:h=>{c=h},onOverride:(h,w)=>{w===""?delete l[h]:l[h]=w},onOverridesReplaced:h=>{l={...h}},previewFor:async(h,w)=>{const _=await F.getForm(o.id);_.schema.settings.theme=h,_.schema.settings.themeOverrides=w;const{html:u}=await F.preview(o.id,{schema:_.schema,theme:h});return u},onThemesChanged:h=>{a.length=0,a.push(...h)}}))};e&&(R(e),e.append(r("span",{class:"atfs__label",text:"Preview against"}),D(String(o.id),i.map(h=>({value:String(h.id),label:h.title||"(untitled)"})),h=>{o=i.find(w=>String(w.id)===h)??i[0],l={},d()}))),d()}catch(s){R(t),t.append(r("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load themes."}))}}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void Pe()):Pe(),document.addEventListener("os-window-content-loaded",()=>void Pe()));function be(n){const e=n.trim();return/^#[0-9a-f]{6}$/i.test(e)?e:/^#[0-9a-f]{3}$/i.test(e)?`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`:"#888888"}const Hs="mailpoet",ge="",js=["checkbox","checkboxes","toggle","consent","gdpr"],bt=["email"];function gt(n){return n.schema.actions.find(e=>e.type==="mailpoet")}function Be(n){const e=n?.settings??{};return{lists:Array.isArray(e.lists)?e.lists.map(Number).filter(Boolean):[],email_field:typeof e.email_field=="string"?e.email_field:"",first_name_field:typeof e.first_name_field=="string"?e.first_name_field:"",last_name_field:typeof e.last_name_field=="string"?e.last_name_field:""}}function Ws(n){return n?.logic?.enabled?n.logic.rules[0]?.field??ge:ge}function vt(n,e,t){const s=n.find(a=>e.includes(a.type));return s?s.id:t?n.find(a=>t.test(a.label))?.id??"":""}function Us(n,e,t){const s=r("section",{class:"atfm-form"}),a=l=>r("span",{class:`atfm-form__mark${l?"":" atfm-form__mark--off"}`,children:[r("img",{attrs:{src:e.symbol,alt:"",width:"20",height:"20"}})]}),i=l=>{R(s),s.classList.remove("is-open"),s.append(r("div",{class:"atfm-form__head",children:[a(l.length>0),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`}),l.length?r("span",{class:"atfm-form__status is-on",text:`Subscribing → ${l.join(", ")}`}):r("span",{class:"atfm-form__status",text:"Not connected"})]}),$(l.length?"Edit":"Connect",()=>void o(),"secondary")]}))},o=async()=>{s.classList.add("is-open"),R(s),s.append(r("p",{class:"atfm-hint",text:"Loading the form…"}));let l;try{l=await F.getForm(n.id)}catch{R(s),s.append(r("p",{class:"atfm-hint",text:"Could not load this form."}));return}const c=l.schema.fields.filter(f=>f.type!=="page_break"),d=gt(l),h=Be(d),w=new Set(h.lists.filter(f=>e.lists.some(M=>M.id===f)));let _=Ws(d),u=h.email_field||vt(c,bt,/mail/i),b=h.first_name_field,g=h.last_name_field;c.some(f=>f.id===u)||(u=vt(c,bt,/mail/i));const p=c.filter(f=>js.includes(f.type));!d&&p.length&&(_=p[0].id);const x=(f,M)=>[{value:"",label:M},...f.map(C=>({value:C.id,label:C.label||C.id}))],I=r("div",{class:"atfm-lists"});(()=>{R(I);for(const f of e.lists){const M=r("input",{attrs:{type:"checkbox"}});M.checked=w.has(f.id),M.addEventListener("change",()=>{M.checked?w.add(f.id):w.delete(f.id)}),I.append(r("label",{class:"atfm-list",children:[M,r("span",{text:f.name})]}))}})();const H=async(f=!1)=>{const M=l.schema.actions.filter(C=>C.type!=="mailpoet");if(!f){if(!w.size){N("Pick a list","A subscription needs at least one MailPoet list.","error");return}if(!u){N("Pick the email field","MailPoet needs to know which answer is the address.","error");return}M.push({id:Hs,type:"mailpoet",enabled:!0,logic:_===ge?{enabled:!1,action:"show",match:"all",rules:[]}:{enabled:!0,action:"show",match:"all",rules:[{field:_,operator:"not_empty",value:""}]},settings:{lists:[...w],email_field:u,first_name_field:b,last_name_field:g}})}l.schema.actions=M;try{await F.updateForm(l.id,{schema:l.schema})}catch(C){N("Could not save",C instanceof Error?C.message:"","error");return}N(f?"Disconnected":"Connected to MailPoet",f?`${n.title} no longer subscribes anyone.`:`${n.title} now subscribes opted-in visitors.`),i(f?[]:e.lists.filter(C=>w.has(C.id)).map(C=>C.name))};R(s);const E=f=>r("span",{class:"atfm-form__section",text:f});s.append(r("div",{class:"atfm-form__head",children:[a(!!d),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`})]}),$("Close",()=>i(d?e.lists.filter(f=>Be(d).lists.includes(f.id)).map(f=>f.name):[]),"ghost")]}),r("div",{class:"atfm-form__body",children:[E("Where they land"),y("Lists",I,"MailPoet sends its own confirmation email before anyone is truly on a list."),E("Who they are"),y("Email address",D(u,x(c,"— pick a field —"),f=>{u=f}),"The answer that carries their address."),y("First name",D(b,x(c,"— none —"),f=>{b=f})),y("Last name",D(g,x(c,"— none —"),f=>{g=f})),E("When to subscribe"),y("Subscribe",D(_,[...p.map(f=>({value:f.id,label:`Only when “${f.label||f.id}” is ticked`})),{value:ge,label:"Everyone who submits"}],f=>{_=f}),p.length?"Bind it to a box they tick. Subscribing everyone is rarely what visitors expect.":"Add a checkbox or toggle field to the form to offer a proper opt-in."),r("div",{class:"atfm-form__actions",children:d?[$("Save connection",()=>void H(),"primary"),$("Disconnect",()=>void H(!0),"danger")]:[$("Save connection",()=>void H(),"primary")]})]}))};return i([]),F.getForm(n.id).then(l=>{const c=gt(l);if(c&&!s.classList.contains("is-open")){const d=e.lists.filter(h=>Be(c).lists.includes(h.id)).map(h=>h.name);i(d)}}).catch(()=>{}),t.append(s),s}function zs(n){const e=n.logo?r("span",{class:"atfm-hero__logo",children:[r("img",{attrs:{src:n.logo,alt:"MailPoet",width:"210",height:"105"}})]}):r("span",{class:"atfm-hero__logo atfm-hero__logo--glyph",text:"📬"});return r("header",{class:"atfm-hero",children:[e,r("div",{class:"atfm-hero__words",children:[r("h1",{text:"Turn submissions into subscribers"}),r("p",{text:"Every submission is someone choosing to talk to you. Connect a form to MailPoet and the ones who opt in land on your lists by themselves — named, consented, and confirmed by MailPoet’s own double opt-in."}),n.active?r("p",{class:"atfm-hero__status is-on",text:n.lists.length===1?"Connected — 1 list ready for subscribers":`Connected — ${n.lists.length} lists ready for subscribers`}):r("p",{class:"atfm-hero__status",text:"MailPoet is not installed on this site yet"})]})]})}function Ys(){const n=(t,s,a)=>r("div",{class:"atfm-why__card",children:[r("span",{class:"atfm-why__icon",text:t}),r("strong",{text:s}),r("p",{text:a})]}),e=(t,s)=>r("a",{text:s,attrs:{href:t,target:"_blank",rel:"noreferrer"}});return[r("div",{class:"atfm-why",children:[n("✉️","Beautiful emails, made in WordPress","Design newsletters and welcome emails in a drag-and-drop editor that lives in your own admin — no external account to juggle."),n("🤝","Consent you can stand behind","Double opt-in out of the box: every address your forms send over is confirmed by the visitor before a single campaign reaches it."),n("🚀","Free to grow with","Free up to 500 subscribers, welcome automations, WooCommerce emails and open-rate stats included — a paid addon anywhere else.")]}),r("p",{class:"atfm-links",children:[e("https://www.mailpoet.com/features/","Explore MailPoet’s features ↗"),e("https://kb.mailpoet.com/","Guides & docs ↗"),e("https://www.mailpoet.com/pricing/","Plans & the free tier ↗")]})]}function Gs(){const n=(e,t)=>r("div",{class:"atfm-step",children:[r("span",{class:"atfm-step__n",text:e}),r("span",{text:t})]});return r("div",{class:"atfm-steps",children:[n("1","Pick a form below"),n("2","Choose the lists it feeds"),n("3","Bind it to an opt-in — MailPoet confirms the rest")]})}async function He(){const n=document.querySelector("[data-atfm-root]");if(!n||n.dataset.atfmMounted)return;n.dataset.atfmMounted="1",Ae(n);const e=n.querySelector("[data-atfm-bar]"),t=n.querySelector("[data-atfm-body]")??n;try{const[s,a]=await Promise.all([F.mailpoet(),F.listForms()]);if(e?.remove(),R(t),t.append(zs(s),...Ys()),!s.active){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet sends newsletters from right inside WordPress — no external account, free to start. Install it and every form here gets a subscribe switch: reservations feed your announcements, signups feed your schedule, enquiries feed your news."}),r("a",{class:"atfm-pitch__cta",text:"Install MailPoet — it’s free",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}if(!s.lists.length){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet is here, but it has no list yet. Make one, and your forms will have somewhere to send subscribers."}),r("a",{class:"atfm-pitch__cta",text:"Open MailPoet lists",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}t.append(Gs());const i=r("section",{class:"atfm-forms",children:[r("div",{class:"atfm-forms__head",children:[r("h2",{text:"Your forms"}),r("p",{class:"atfm-hint",text:"Connected forms wear the MailPoet mark in colour."})]})]});if(t.append(i),!a.length){i.append(r("p",{class:"atfm-hint",text:"No forms yet — make one, then come back to connect it."}));return}for(const o of a)Us(o,s,i)}catch{e&&(e.textContent="Could not reach the site — reload the window to try again.")}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void He()):He(),document.addEventListener("os-window-content-loaded",()=>void He());const ve={plain:"",simple:"✓",minimal:"",card:"🎉",check:"",confetti:"🎉",fireworks:"🎆",sparkles:"✨",typewriter:""};function yt(){return{style:"simple",title:"",icon:"",accent:"",intensity:"medium",showButton:!1,buttonLabel:""}}function je(n){const e={...yt(),...n??{}};return e.style in ve||(e.style="simple"),e}function Xs(){return typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}function Zs(n,e,t){const s=je(e),a=document.createElement("div");if(a.className=`atf-confirmation atf-success atf-success--${s.style}`,a.setAttribute("role","status"),a.setAttribute("tabindex","-1"),s.style==="plain")return a.className="atf-confirmation",a.innerHTML=n,a;s.accent&&a.style.setProperty("--atf-accent",s.accent);const i=document.createElement("div");i.className="atf-success__inner",a.append(i);const o=s.icon||ve[s.style];if(s.style==="check")i.insertAdjacentHTML("beforeend",'');else if(o){const c=document.createElement("span");c.className="atf-success__icon",c.setAttribute("aria-hidden","true"),c.textContent=o,i.append(c)}if(s.title){const c=document.createElement("h2");c.className="atf-success__title",c.textContent=s.title,i.append(c)}const l=document.createElement("div");if(l.className="atf-success__message",l.innerHTML=n,i.append(l),s.style==="typewriter"&&a.setAttribute("aria-label",l.textContent??""),s.showButton){const c=document.createElement("button");c.type="button",c.className="atf-button atf-button--ghost atf-success__again",c.textContent=s.buttonLabel||"Fill it in again",c.addEventListener("click",()=>t?t():window.location.reload()),i.append(c)}return a}function Ks(n,e){const t=je(e);if(Xs())return()=>{};switch(t.style){case"confetti":return Vs(n,t);case"fireworks":return Js(t);case"sparkles":return Qs(n,t);case"typewriter":return en(n);default:return()=>{}}}function oe(n){return{low:.5,medium:1,high:1.8}[n.intensity]}function wt(){const n=document.createElement("canvas");n.className="atf-success-canvas",n.setAttribute("aria-hidden","true");const e=Math.min(window.devicePixelRatio||1,2);n.width=Math.floor(window.innerWidth*e),n.height=Math.floor(window.innerHeight*e),document.body.append(n);const t=n.getContext("2d");return t?.scale(e,e),{canvas:n,ctx:t,stop:()=>n.remove()}}const _t=["#f43f5e","#f59e0b","#10b981","#3b82f6","#8b5cf6","#ec4899","#eab308"];function Vs(n,e){const{ctx:t,stop:s}=wt();if(!t)return s(),()=>{};const a=e.accent?[e.accent,..._t]:_t,i=[],o=n.getBoundingClientRect(),l=o.left+o.width/2,c=Math.min(o.top+40,window.innerHeight-20),d=(x,I,S)=>{const H=S?Math.PI*(1.15+.7*Math.random()):0,E=S?9+Math.random()*8:0;return{x,y:I,vx:S?Math.cos(H)*E*(Math.random()<.5?1:-1):(Math.random()-.5)*1.5,vy:S?Math.sin(H)*E:1+Math.random()*2,w:6+Math.random()*5,h:8+Math.random()*7,angle:Math.random()*Math.PI,spin:(Math.random()-.5)*.3,color:a[Math.floor(Math.random()*a.length)],wobble:Math.random()*Math.PI*2}},h=Math.round(90*oe(e));for(let x=0;x{if(_>=w){window.clearInterval(u);return}i.push(d(Math.random()*window.innerWidth,-20,!1)),_++},2e3/w);let b=0;const g=performance.now(),p=x=>{t.clearRect(0,0,window.innerWidth,window.innerHeight);let I=!1;for(const S of i)S.vy+=.16,S.vx*=.99,S.vy*=.985,S.wobble+=.1,S.x+=S.vx+Math.sin(S.wobble)*.8,S.y+=S.vy,S.angle+=S.spin,S.y{window.clearInterval(u),window.cancelAnimationFrame(b),s()}}function Js(n){const{ctx:e,stop:t}=wt();if(!e)return t(),()=>{};const s=[],a=[],i=Math.round(6*oe(n))+2;let o=0;const l=()=>{s.push({x:window.innerWidth*(.15+.7*Math.random()),y:window.innerHeight,vy:-(9+Math.random()*4),targetY:window.innerHeight*(.15+.3*Math.random()),hue:Math.floor(Math.random()*360)}),o++};l();const c=window.setInterval(()=>{if(o>=i){window.clearInterval(c);return}l()},3500/i),d=u=>{const b=Math.round(70*oe(n));for(let g=0;g{e.clearRect(0,0,window.innerWidth,window.innerHeight);for(let g=s.length-1;g>=0;g--){const p=s[g];p.y+=p.vy,p.vy+=.08,e.fillStyle=`hsl(${p.hue} 90% 65%)`,e.fillRect(p.x-1.5,p.y,3,10),(p.y<=p.targetY||p.vy>=-1)&&(d(p),s.splice(g,1))}for(let g=a.length-1;g>=0;g--){const p=a[g];if(p.x+=p.vx,p.y+=p.vy,p.vy+=.045,p.vx*=.985,p.vy*=.985,p.life-=p.decay,p.life<=0){a.splice(g,1);continue}const x=p.life*(.7+.3*Math.random());e.globalAlpha=Math.max(0,x),e.fillStyle=`hsl(${p.hue} 95% ${55+25*p.life}%)`,e.beginPath(),e.arc(p.x,p.y,1.1+1.6*p.life,0,Math.PI*2),e.fill()}e.globalAlpha=1,!(o>=i&&s.length===0&&a.length===0)&&u-w<9e3?h=window.requestAnimationFrame(_):t()};return h=window.requestAnimationFrame(_),()=>{window.clearInterval(c),window.cancelAnimationFrame(h),t()}}function Qs(n,e){const t=e.icon||ve.sparkles,s=Math.round(22*oe(e)),a=[];let i=0;const o=()=>{const c=document.createElement("span");c.className="atf-success__spark",c.setAttribute("aria-hidden","true"),c.textContent=t,c.style.insetInlineStart=`${4+Math.random()*92}%`,c.style.animationDuration=`${2.6+Math.random()*1.8}s`,c.style.animationDelay=`${Math.random()*.3}s`,c.style.fontSize=`${14+Math.random()*14}px`,c.addEventListener("animationend",()=>c.remove()),n.append(c),a.push(c),i++};o();const l=window.setInterval(()=>{if(i>=s){window.clearInterval(l);return}o()},2800/s);return()=>{window.clearInterval(l),a.forEach(c=>c.remove())}}function en(n){const e=n.querySelector(".atf-success__message");if(!e)return()=>{};const t=e.innerHTML,s=e.textContent??"";if(!s)return()=>{};e.textContent="",e.classList.add("is-typing");const a=Math.min(45,3800/s.length);let i=0;const o=window.setInterval(()=>{i++,e.textContent=s.slice(0,i),i>=s.length&&(window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t)},a);return()=>{window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t}}const tn={min:-1,max:-1,sum:-1,avg:-1,round:-1,ceil:1,floor:1,abs:1,sqrt:1,pow:2},xt={"+":{precedence:1,right:!1},"-":{precedence:1,right:!1},"*":{precedence:2,right:!1},"/":{precedence:2,right:!1},"%":{precedence:2,right:!1},"^":{precedence:4,right:!0}};function sn(n,e,t=[]){if(!n||!n.trim()||n.length>2e3)return null;const s=nn(n,e,t),a=ln(s);if(!a)return null;const i=dn(a);if(!i)return null;const o=hn(i);return o===null||!Number.isFinite(o)?null:o}function nn(n,e,t){return n.replace(/\{([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_]+))?\}/g,(s,a,i,o)=>an(n,o,s.length,a,i??"",e,t))}function an(n,e,t,s,a,i,o){const l=rn(o,s),c=Object.prototype.hasOwnProperty.call(i,s)?i[s]:null;if(a===""){const u=l?.type==="repeater"?kt(c).length:We(c,l);return St(u)}const h=(l?.fields??[]).find(u=>u.id===a)??null,w=kt(c).map(u=>We(u[a]??"",h));if(!w.length)return"0";const _=w.map(St);return on(n,e,t)?_.join(", "):_.length===1?_[0]:`( ${_.join(" + ")} )`}function rn(n,e){for(const t of n){if(t.id===e)return t;for(const s of t.fields??[])if(s.id===e)return s}return null}function on(n,e,t){const s=n.slice(e+t).replace(/^\s+/,"");if(s===""||s[0]!==")")return!1;const a=n.slice(0,e).replace(/\s+$/,""),i=/([a-zA-Z_][a-zA-Z0-9_]*)\s*\($/.exec(a);return!!i&&["sum","avg","min","max"].includes(i[1].toLowerCase())}function kt(n){if(!Array.isArray(n))return[];const e=[];for(const t of n){if(!t||typeof t!="object"||Array.isArray(t))continue;Object.values(t).some(a=>a!==""&&a!==null&&a!==void 0&&a!==!1&&!(Array.isArray(a)&&!a.length))&&e.push(t)}return e}function St(n){const e=n.toFixed(10).replace(/0+$/,"").replace(/\.$/,"");return e===""||e==="-"?"0":e}function We(n,e){if(typeof n=="boolean")return n?1:0;if(Array.isArray(n))return n.reduce((a,i)=>a+We(i,e),0);if(n==null||n==="")return 0;const t=e?.choices??[];for(const a of t)if(String(a.value)===String(n)){if(typeof a.price=="number")return a.price;if(typeof a.points=="number")return a.points;break}const s=Number(n);return Number.isFinite(s)?s:0}function ln(n){const e=[];let t=0;for(;ti.precedence||l.precedence===i.precedence&&!i.right){e.push(t.pop());continue}break}t.push(a);break}case"(":t.push(a);break;case")":{for(;t.length&&t[t.length-1].type!=="(";)e.push(t.pop());if(!t.length)return null;if(t.pop(),t.length&&t[t.length-1].type==="function"){const i=t.pop();i.arity=s.length?s.pop():1,e.push(i)}break}}for(;t.length;){const a=t.pop();if(a.type==="(")return null;e.push(a)}return e}function hn(n){const e=[];for(const t of n)switch(t.type){case"number":e.push(t.value);break;case"unary":{if(!e.length)return null;e.push(-e.pop());break}case"operator":{if(e.length<2)return null;const s=e.pop(),a=e.pop();switch(t.value){case"+":e.push(a+s);break;case"-":e.push(a-s);break;case"*":e.push(a*s);break;case"/":e.push(s===0?0:a/s);break;case"%":e.push(s===0?0:a%s);break;case"^":e.push(Math.pow(a,s));break;default:return null}break}case"function":{const s=t.arity??1;if(e.lengtht+s,0);case"avg":return e.reduce((t,s)=>t+s,0)/e.length;case"round":{const t=Math.max(-10,Math.min(10,Math.trunc(e[1]??0))),s=Math.pow(10,t);return Math.round(e[0]*s)/s}case"ceil":return Math.ceil(e[0]);case"floor":return Math.floor(e[0]);case"abs":return Math.abs(e[0]);case"sqrt":return e[0]<0?0:Math.sqrt(e[0]);case"pow":return Math.pow(e[0],e[1]??2);default:return null}}const pn=["sum","min","max","avg","round","ceil","floor","abs","sqrt","pow"],Lt=["number","range","scale","rating","total","select","multiselect","radio","checkboxes","switch","quiz"];function Ue(n,e){return n.filter(t=>t.id!==e&&Lt.includes(t.type))}function fn(n){const e=[];for(const t of n){if(t.type!=="repeater")continue;const s=t.label||t.id;e.push({label:`${s} (how many)`,insert:`{${t.id}}`});for(const a of t.fields??[])Lt.includes(a.type)&&e.push({label:`${s} · ${a.label||a.id}`,insert:`{${t.id}.${a.id}}`})}return e}function mn(n,e){const t={};Ue(n,e).forEach((s,a)=>{t[s.id]=a+1});for(const s of n){if(s.type!=="repeater"||s.id===e)continue;const a=s.fields??[],i=o=>Object.fromEntries(a.map((l,c)=>[l.id,c+1+o]));t[s.id]=[i(0),i(1)]}return t}function bn(n){const e=r("div",{class:"atfb-overlay"}),t=()=>{e.remove(),document.removeEventListener("keydown",s)},s=u=>{u.key==="Escape"&&t()},a=r("textarea",{class:"atfb-input atfb-formula__input",attrs:{rows:"3","aria-label":"Formula"}});a.value=String(n.field.formula??"");const i=r("p",{class:"atfb-formula__result",attrs:{"aria-live":"polite"}}),o=mn(n.fields,n.field.id),l=()=>{const u=a.value.trim();if(u===""){i.textContent="Empty. Reference a question below to start.",i.classList.remove("is-error");return}const b=sn(u,o,n.fields);if(b===null){i.textContent="This does not compute yet — check the braces and parentheses.",i.classList.add("is-error");return}const g=Ue(n.fields,n.field.id).map((p,x)=>`${p.label||p.id} = ${x+1}`).concat(n.fields.filter(p=>p.type==="repeater"&&p.id!==n.field.id).map(p=>`${p.label||p.id} = 2 sample rows`)).join(", ");i.textContent=`With sample answers (${g}): ${b}`,i.classList.remove("is-error")};a.addEventListener("input",l);const c=(u,b,g=0)=>r("button",{class:"atfb-formula__chip",type:"button",text:u,on:{click:()=>{if(ht(a,b),g>0){const p=(a.selectionStart??a.value.length)-g;a.setSelectionRange(p,p)}}}}),d=Ue(n.fields,n.field.id),h=fn(n.fields),w=r("div",{class:"atfb-formula__chips",children:d.length||h.length?[...d.map(u=>c(u.label||u.id,`{${u.id}}`)),...h.map(u=>c(u.label,u.insert))]:[r("p",{class:"atfb-hint",text:"No number-shaped questions yet — add a number, scale or priced choice field and it appears here."})]}),_=r("div",{class:"atfb-formula__chips",children:pn.map(u=>c(`${u}()`,`${u}()`,1))});e.append(r("div",{class:"atfb-modal atfb-formula",attrs:{role:"dialog","aria-label":"Formula editor"},children:[r("h2",{text:"Formula"}),a,i,y("Your questions",w,"Click one to reference its answer."),y("Functions",_),r("div",{class:"atfb-modal__actions",children:[$("Cancel",t),$("Save formula",()=>{n.onSave(a.value.trim()),t()},"primary")]})]})),e.addEventListener("click",u=>{u.target===e&&t()}),document.addEventListener("keydown",s),n.root.append(e),l(),a.focus(),a.setSelectionRange(a.value.length,a.value.length)}const gn="allterrain-forms/form";function vn(){return window.wp?.os?.relations??null}function Et(n){const e=n.closest("[data-window-id], .os-window");if(!e)return null;const t=e.getAttribute("data-window-id");if(t)return t;const s=e.id??"";return s?s.replace(/^wp-window-/,""):null}const yn=6e3,Ct=120;function $t(n,e){const t=vn();if(ze.set(n,e),!t?.set)return;const s=i=>{if(ye.get(n)!==a)return;const o=Et(n);if(!o){Date.now()s(i),Ct);return}try{t.set(o,e)}catch(c){At||(At=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",c,e)),ye.delete(n);return}if(!e||t.get?.(o)?.id===e.id||Date.now()>=i){ye.delete(n);return}window.setTimeout(()=>s(i),Ct)},a=Symbol("atf-identity");ye.set(n,a),s(Date.now()+yn)}let At=!1;const ye=new WeakMap,ze=new Map;function wn(){for(const[n,e]of ze){if(!n.isConnected){ze.delete(n);continue}$t(n,e)}}if(typeof document<"u")for(const n of["os-window-content-loaded","os-window-opened"])document.addEventListener(n,()=>wn());function _n(n,e){return{type:gn,id:n.id,label:n.title||"Untitled form",related:[{id:`allterrain-forms/entries-${n.id}`,label:"Entries for this form",url:`${e}admin.php?page=allterrain-forms-entries&form=${n.id}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-list-view"}]}}const we={letters:{label:"Letters",chars:"A-Za-zÀ-ÖØ-öø-ÿ"},numbers:{label:"Numbers",chars:"0-9"},spaces:{label:"Spaces",chars:" "},punctuation:{label:`Punctuation ( . , ! ? ' " - )`,chars:`.,!?'"()\\-:;`},symbols:{label:"Symbols ( @ # & _ / + )",chars:"@#&_/+*%="}};function xn(){return{mode:"blocks",starts:"",ends:"",contains:"",notContains:"",chars:[],minLen:"",maxLen:"",regex:"",message:"",tests:[]}}function Tt(n){const e=xn();let t;try{t=JSON.parse(n)}catch{return e}if(!t||typeof t!="object")return e;const s=t;e.mode=s.mode==="regex"?"regex":"blocks";for(const a of["starts","ends","contains","notContains","minLen","maxLen","regex","message"])typeof s[a]=="string"&&(e[a]=s[a]);return Array.isArray(s.chars)&&(e.chars=s.chars.filter(a=>typeof a=="string"&&a in we)),Array.isArray(s.tests)&&(e.tests=s.tests.filter(a=>typeof a=="string").slice(0,10)),e}function _e(n){return n.replace(/[.*+?^${}()|[\]\\/]/g,"\\$&")}function xe(n){if(n.mode==="regex")return n.regex.trim();const e=[],t=n.minLen.trim(),s=n.maxLen.trim();(t!==""||s!=="")&&e.push(`(?=.{${t===""?"0":parseInt(t,10)||0},${s===""?"":parseInt(s,10)||""}}$)`),n.contains!==""&&e.push(`(?=.*${_e(n.contains)})`),n.notContains!==""&&e.push(`(?!.*${_e(n.notContains)})`),n.starts!==""&&e.push(`(?=${_e(n.starts)})`),n.ends!==""&&e.push(`(?=.*${_e(n.ends)}$)`);const a=n.chars.map(o=>we[o]?.chars??"").join(""),i=a?`[${a}]*$`:".*$";return!e.length&&!a?"":`^${e.join("")}${i}`}function Mt(n){if(n.mode==="regex")return n.regex.trim()?`Matches the expression ${n.regex.trim()}`:"";const e=[];if(n.starts&&e.push(`starts with “${n.starts}”`),n.ends&&e.push(`ends with “${n.ends}”`),n.contains&&e.push(`contains “${n.contains}”`),n.notContains&&e.push(`never contains “${n.notContains}”`),n.chars.length){const i=n.chars.map(o=>(we[o]?.label??o).split(" (")[0].toLowerCase());e.push(`uses only ${i.join(" and ")}`)}const t=n.minLen.trim(),s=n.maxLen.trim();return t&&s?e.push(`is ${t}–${s} characters long`):t?e.push(`is at least ${t} characters long`):s&&e.push(`is at most ${s} characters long`),e.length?`The answer ${e.length>1?`${e.slice(0,-1).join(", ")}, and ${e[e.length-1]}`:e[0]}.`:""}function kn(n,e){const t=xe(n);if(t==="")return null;try{return new RegExp(t).test(e)}catch{return null}}function Sn(){return window.wp?.os?.windowManager??null}const Ft="allterrain-forms-validation";function Ln(n){const e=Sn(),t=Et(n.root);if(e?.openChild&&t){En(e,t,n);return}Cn(n)}function En(n,e,t){const s=`${Ft}-${t.field.id}`;n.getById?.(s)&&n.remove?.(s);const a={saved:!1},i=()=>{const o=n.getById?.(s);o?.close?o.close():n.remove?.(s)};n.openChild?.(e,{id:s,baseId:Ft,url:`#${s}`,title:`Custom rule — ${t.field.label||"this question"}`,icon:"dashicons-yes-alt",native:!0,width:560,height:700,minWidth:440,minHeight:480,ephemeral:!0,autofocus:".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea",render:o=>{const l=r("div",{class:"atfa atfb-valwin atfb-valwin--window"}),c=r("div",{class:"atfb-valwin__scroll"});l.append(c),It(c,t,a,i,"window");const d=c.querySelector(".atfb-modal__actions");d&&l.append(d),o.append(l)},onClose:()=>{a.saved||t.onCancel?.()}})}function Cn(n){const e=r("div",{class:"atfb-overlay"}),t={saved:!1},s=()=>{e.remove(),document.removeEventListener("keydown",a),t.saved||n.onCancel?.()},a=o=>{o.key==="Escape"&&s()},i=r("div",{class:"atfb-modal atfb-valwin",attrs:{role:"dialog","aria-label":"Custom validation rule"},children:[r("h2",{text:"Custom rule"})]});It(i,n,t,s,"overlay"),e.append(i),e.addEventListener("click",o=>{o.target===e&&s()}),document.addEventListener("keydown",a),n.root.append(e),e.querySelector(".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea")?.focus()}function It(n,e,t,s,a){const i=Tt(String(e.field.validationRecipe??""));i.mode==="blocks"&&xe(i)===""&&e.field.pattern&&(i.mode="regex",i.regex=String(e.field.pattern)),i.message||(i.message=String(e.field.messages?.invalid??""));const o=(f,M)=>{const C=r("input",{class:"atfb-input",value:i[f],placeholder:M,attrs:{type:"text"}});return C.addEventListener("input",()=>{i[f]=C.value,E()}),C},l=(f,M)=>{const C=r("input",{class:"atfb-input atfb-valwin__len",value:i[f],attrs:{type:"number",min:"0","aria-label":M}});return C.addEventListener("input",()=>{i[f]=C.value,E()}),C},c=r("div",{class:"atfb-valwin__chars",children:Object.entries(we).map(([f,M])=>O(M.label,i.chars.includes(f),C=>{i.chars=C?[...i.chars,f]:i.chars.filter(j=>j!==f),E()}))}),d=r("div",{class:"atfb-valwin__pane",children:[y("Starts with",o("starts","e.g. AT-")),y("Ends with",o("ends","e.g. -2026")),y("Must contain",o("contains","e.g. @")),y("Must not contain",o("notContains","e.g. spaces? type one")),y("Only these characters",c,"Leave every box unticked to allow anything."),y("Length",r("div",{class:"atfb-valwin__lengths",children:[r("span",{text:"between"}),l("minLen","Minimum length"),r("span",{text:"and"}),l("maxLen","Maximum length"),r("span",{text:"characters"})]}),"Leave a box empty for no limit.")]}),h=r("textarea",{class:"atfb-input atfb-valwin__regex",attrs:{rows:"2","aria-label":"Regular expression",placeholder:"^AT-[0-9]{4}$"}});h.value=i.regex,h.addEventListener("input",()=>{i.regex=h.value,E()});const w=r("div",{class:"atfb-valwin__pane",children:[y("Expression",h,"A regular expression, without slashes. Checked against the whole answer only if you anchor it with ^ and $.")]}),_=[["blocks","Easy blocks"],["regex","Expression (advanced)"]],u=f=>{i.mode=f,d.hidden=f!=="blocks",w.hidden=f!=="regex",E()},g=(()=>{if(Y("os-segmented")&&Y("os-segment")){const C=document.createElement("os-segmented");C.setAttribute("value",i.mode),C.setAttribute("label","How to write the rule"),C.classList.add("atfb-valwin__tabs");for(const[j,B]of _){const le=document.createElement("os-segment");le.setAttribute("value",j),le.textContent=B,C.append(le)}return C.addEventListener("os-pick",j=>{const B=j.detail?.value;(B==="blocks"||B==="regex")&&(C.setAttribute("value",B),u(B))}),C}const f=r("div",{class:"atfb-valwin__tabs",attrs:{role:"tablist"}}),M=()=>{f.replaceChildren(..._.map(([C,j])=>{const B=i.mode===C;return r("button",{class:`atfb-valwin__tab${B?" is-active":""}`,type:"button",text:j,attrs:{role:"tab","aria-selected":B?"true":"false"},on:{click:()=>{u(C),M()}}})}))};return M(),f})();d.hidden=i.mode!=="blocks",w.hidden=i.mode!=="regex";const p=r("input",{class:"atfb-input",value:i.message,placeholder:"That is not in the expected format.",attrs:{type:"text"}});p.addEventListener("input",()=>{i.message=p.value});const x=r("p",{class:"atfb-valwin__summary",attrs:{"aria-live":"polite"}}),I=r("div",{class:"atfb-valwin__samples"}),S=f=>{const M=r("span",{class:"atfb-valwin__verdict",attrs:{"aria-live":"polite"}}),C=r("input",{class:"atfb-input",value:f,placeholder:"Type a sample answer…",attrs:{type:"text"}});C.addEventListener("input",()=>E()),I.append(r("div",{class:"atfb-valwin__sample",children:[C,M]}))};for(const f of i.tests.length?i.tests:["","",""])S(f);const H=()=>Array.from(I.querySelectorAll("input")).map(f=>f.value),E=()=>{const f=Mt(i);x.textContent=f||"Nothing yet — fill in a block above and the rule appears here in plain words.";for(const M of Array.from(I.querySelectorAll(".atfb-valwin__sample"))){const C=M.querySelector("input"),j=M.querySelector(".atfb-valwin__verdict");if(!C||!j)continue;const B=C.value===""?null:kn(i,C.value);j.textContent=B===null?"·":B?"✓ passes":"✗ fails",j.classList.toggle("is-pass",B===!0),j.classList.toggle("is-fail",B===!1)}};n.append(r("p",{class:"atfb-hint",text:`Describe what a good answer to “${e.field.label||"this question"}” looks like — no code needed.`}),g,d,w,r("div",{class:"atfb-valwin__try",children:[r("h3",{text:"Try it out"}),x,I,$("Add another sample",()=>{S(""),E()},"ghost","plus-alt2")]}),y("When it fails, say",p,"Shown to the visitor when their answer breaks the rule. Leave empty for the default wording."),r("div",{class:"atfb-modal__actions",children:[$(a==="window"?"Close without saving":"Cancel",s),$("Save rule",()=>{const f=xe(i);i.tests=H().filter(M=>M!=="").slice(0,10),t.saved=!0,e.onSave({pattern:f,recipe:i,message:i.message.trim()}),s()},"primary")]})),E()}const $n=["Contact","Numbers & codes","Text shape","Web"],Dt=[{slug:"email",label:"An email address",group:"Contact",example:"jane@example.com",pattern:"^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",message:"That does not look like an email address."},{slug:"phone",label:"A phone number",group:"Contact",example:"+34 612 345 678",pattern:"^(?=(?:[^0-9]*[0-9]){5,})\\+?[0-9 ().-]{5,24}$",message:"That does not look like a phone number."},{slug:"handle",label:"A username or @handle",group:"Contact",example:"@yourname",pattern:"^@?[A-Za-z0-9_]{2,30}$",message:"That does not look like a username."},{slug:"digits",label:"Numbers only",group:"Numbers & codes",example:"12345",pattern:"^[0-9]+$",message:"Numbers only, please."},{slug:"decimal",label:"A number, decimals allowed",group:"Numbers & codes",example:"3.14",pattern:"^-?[0-9]+([.,][0-9]+)?$",message:"That does not look like a number."},{slug:"price",label:"A price",group:"Numbers & codes",example:"19.99",pattern:"^[0-9]+([.,][0-9]{1,2})?$",message:"That does not look like a price."},{slug:"zip_us",label:"A ZIP code (US)",group:"Numbers & codes",example:"90210",pattern:"^[0-9]{5}(-[0-9]{4})?$",message:"That does not look like a ZIP code."},{slug:"postcode_uk",label:"A postcode (UK)",group:"Numbers & codes",example:"SW1A 1AA",pattern:"^[A-Za-z]{1,2}[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}$",message:"That does not look like a postcode."},{slug:"iban",label:"An IBAN",group:"Numbers & codes",example:"DE89 3704 0044 0532 0130 00",pattern:"^[A-Za-z]{2}[0-9]{2}(?: ?[A-Za-z0-9]){10,32}$",message:"That does not look like an IBAN."},{slug:"credit_card",label:"A card number",group:"Numbers & codes",example:"4242 4242 4242 4242",pattern:"^[0-9](?:[0-9 -]{9,21})?[0-9]$",message:"That does not look like a card number.",luhn:!0},{slug:"letters",label:"Letters only",group:"Text shape",example:"María López",pattern:"^[\\p{L}\\p{M} .'’-]+$",message:"Letters only, please."},{slug:"alphanumeric",label:"Letters and numbers only",group:"Text shape",example:"abc123",pattern:"^[A-Za-z0-9]+$",message:"Letters and numbers only, please."},{slug:"no_spaces",label:"One word, no spaces",group:"Text shape",example:"one-word",pattern:"^\\S+$",message:"No spaces allowed."},{slug:"url",label:"A web address",group:"Web",example:"https://example.com",pattern:"^(https?://)?([A-Za-z0-9-]+\\.)+[A-Za-z]{2,}([/?#]\\S*)?$",message:"That does not look like a web address."},{slug:"ip",label:"An IP address",group:"Web",example:"192.168.0.1",pattern:"^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$",message:"That does not look like an IP address."},{slug:"slug",label:"A URL slug",group:"Web",example:"my-page-title",pattern:"^[a-z0-9]+(-[a-z0-9]+)*$",message:"Lowercase letters, numbers and dashes only."},{slug:"hex_color",label:"A hex colour",group:"Web",example:"#3366ff",pattern:"^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$",message:"That does not look like a colour code."}];function An(n){return Dt.find(e=>e.slug===n)??null}function Ye(){return window.wp?.os??null}const qt="allterrain-forms/preview",Ge="allterrain-forms-preview";function Tn(n){const e=Ye();if(!e?.registerTitleBarButton)return()=>{};const t=()=>{try{e.registerTitleBarButton({id:qt,label:"Preview this form",icon:"dashicons-visibility",placement:"right",order:90,match:s=>{const a=s?.id??s?.config?.id??"";return a==="allterrain-forms"||a.startsWith("allterrain-forms#")},onClick:()=>void Ot(n),owner:"allterrain-forms-builder"})}catch{}};return e.ready?e.ready(t):t(),()=>{try{e.unregisterTitleBarButton?.(qt)}catch{}}}async function Ot(n){n.isDirty()&&await n.save();const e=n.current();e&&Nt(e.id,e.title,e.previewUrl)}function Nt(n,e,t){const s=Ye();if(!s?.windowManager?.open){window.open(t,"_blank","noopener");return}s.windowManager.open({id:`${Ge}-${n}`,baseId:Ge,url:t,title:`Preview: ${e}`,icon:"dashicons-visibility"})}function Mn(n,e,t){if(!Ye()?.windowManager?.open||!document.querySelector(`[data-window-id="${Ge}-${n}"]`))return;const i=t.includes("?")?"&":"?";Nt(n,e,`${t}${i}alltfo_r=${Date.now()}`)}const se="allterrain-forms/field",Fn=["openstation/file","desktop-mode/file","openstation/attachment"],Rt="allterrain-forms/logic-map-v2";function J(n,e){return n.dataset.atfbBind=e,n}const Pt={level:{key:"level",label:"Heading level",control:"select",hint:"Headings should step down one at a time.",options:[{value:"2",label:"Heading 2"},{value:"3",label:"Heading 3"},{value:"4",label:"Heading 4"},{value:"5",label:"Heading 5"},{value:"6",label:"Heading 6"}]},content:{key:"content",label:"HTML",control:"textarea",hint:"Shown as written. Scripts are stripped when the form is saved."},consenttext:{key:"consentText",label:"What they are agreeing to",control:"textarea",hint:"Shown beside the tick box. Links are allowed."},height:{key:"height",label:"Height",control:"number",hint:"In pixels."},columns:{key:"columns",label:"Columns",control:"number",hint:"How many pictures sit side by side."},multiple:{key:"multiple",label:"Let them choose more than one",control:"checkbox"},inline:{key:"inline",label:"Lay the options out in a row",control:"checkbox"},other:{key:"other",label:"Offer an “Other” box",control:"checkbox",hint:"Adds a final option with a box to type in."},filetypes:{key:"filetypes",label:"Accepted file types",control:"commas",hint:"Extensions, separated by commas. Empty accepts anything the site allows."},maxsize:{key:"maxsize",label:"Largest file",control:"number",hint:"In megabytes."},maxfiles:{key:"maxfiles",label:"How many files",control:"number"},minrows:{key:"minRows",label:"Fewest rows",control:"number",also:{key:"maxRows",label:"Most rows"}},itemlabel:{key:"itemLabel",label:"What is one row called?",control:"text",hint:"Names each card — “Attendee 1”, “Attendee 2” — and the Remove button. Also editable on the card itself."},endlabels:{key:"minLabel",label:"Label at the low end",control:"text",also:{key:"maxLabel",label:"Label at the high end"}},points:{key:"points",label:"Points if correct",control:"number"},minchoices:{key:"minChoices",label:"Fewest they may pick",control:"number",also:{key:"maxChoices",label:"Most they may pick"}}},In={label:"the canvas edits it in place, and the inspector mirrors it",placeholder:"edited by typing into the control on the canvas",hint:"edited under the control on the canvas",nextlabel:"edited on the page break’s own Next button",prevlabel:"edited on the page break’s own Back button",addlabel:"edited on the repeater’s own Add button",choices:"the choices editor, and the option list on the canvas",required:"the toggle on the card",width:"its own row",css:"its own row",prefill:"its own section",logic:"the conditional logic section",formula:"its own row, with the currency that goes with it",currency:"rendered with the formula",correct:"the choices editor marks the right answer",default:"its own row, typed to match what the field stores",rows:"a row count on a textarea; the statement list on a Likert matrix",parts:"a tick box per part, listed by the server",min:"the validation section, paired with max",max:"the validation section, paired with min",step:"the validation section",minlength:"the validation section, paired with maxlength",maxlength:"the validation section, paired with minlength",mindate:"the validation section, paired with maxdate",maxdate:"the validation section, paired with mindate",mintime:"the validation section, paired with maxtime",maxtime:"the validation section, paired with mintime",pattern:"the validation section",unique:"the validation section",maxchoices:"rendered with minchoices",maxrows:"rendered with minrows"};function Bt(n,e,t){const s=n[e.key],a=i=>t(e.key,i);if(e.control==="checkbox")return O(e.label,!!s,a);if(e.control==="commas"){const i=Array.isArray(s)?s:[];return y(e.label,T(i.join(", "),o=>{a(o.split(",").map(l=>l.trim().replace(/^\./,"").toLowerCase()).filter(Boolean))}),e.hint)}return e.control==="select"?y(e.label,D(String(s??""),e.options??[],a),e.hint):e.control==="textarea"?y(e.label,pe(String(s??""),a),e.hint):e.control==="number"?y(e.label,G(String(s??""),a),e.hint):y(e.label,J(T(String(s??""),a),e.key),e.hint)}function Ht(n,e){const t=new Set(n.map(a=>a.key).filter(Boolean));let s=n.length+1;return e.split(` +`).map(a=>a.trim()).filter(Boolean).map((a,i)=>{const o=n[i]?.key;if(o)return{key:o,label:a};for(;t.has(`r${s}`);)s+=1;return t.add(`r${s}`),{key:`r${s}`,label:a}})}function jt(n,e,t){const s=n.findIndex(i=>i.id===e);if(s<0)return null;const a=Math.max(0,Math.min(t,n.length-1));return a===s?null:{from:s,to:a}}const Xe=[{value:"user:email",label:"Their email address",group:"About the person filling it in",tag:"{user:email}"},{value:"user:display_name",label:"Their name",group:"About the person filling it in",tag:"{user:display_name}"},{value:"user:first_name",label:"Their first name",group:"About the person filling it in"},{value:"user:last_name",label:"Their last name",group:"About the person filling it in"},{value:"user:login",label:"Their username",group:"About the person filling it in"},{value:"date:today",label:"Today’s date",group:"The date and time",tag:"{date}"},{value:"date:now",label:"The time right now",group:"The date and time",tag:"{time}"},{value:"site",label:"This site’s name",group:"About this site",tag:"{site}"},{value:"site:url",label:"This site’s address",group:"About this site",tag:"{site:url}"},{value:"site:admin_email",label:"The site administrator’s email",group:"About this site",tag:"{admin_email}"}],Dn=["About the person filling it in","The date and time","About this site"],Ze=(n,e)=>W?.i18n?.[n]??e;class Wt{constructor(e){this.config=null,this.themes=[],this.forms=[],this.form=null,this.schema=null,this.selected=null,this.tab="build",this.logicMap=null,this.canvasTheme=r("style"),this.canvasThemeSignature="",this.openSections=new Map,this.logicMapOn=is(Rt)!=="off",this.dirty=!1,this.editGeneration=0,this.saveInFlight=!1,this.queuedSave=null,this.teardowns=[],this.canvasTarget=null,this.history=[],this.historyAt=-1,this.autosave=$e(()=>{this.save(!0)},2500),this.renderInspector=as(()=>{if(R(this.inspector),!this.schema||(this.root.classList.toggle("atfb--build-only-panes",this.tab!=="build"),this.tab!=="build"))return;const t=this.selected?this.locateField(this.selected):void 0,s=t?.field,a=t?.parent??null;if(this.root.classList.toggle("atfb--has-selection",!!s),!s){this.inspector.append(r("div",{class:"atfb-placeholder",children:[r("p",{text:"Select a field to change it."}),r("p",{class:"atfb-hint",text:"Drag a field from the palette, or press one to add it to the end."})]}));return}const i=this.config?.fieldTypes.find(c=>c.type===s.type),o=i?.supports??[],l=(c,d)=>{const h=this.liveField(s.id);h&&(h[c]=d,this.markDirty(),this.renderCanvas())};this.inspector.append(r("h3",{class:"atfb-inspector__title",text:i?.label??s.type})),a?this.inspector.append(r("p",{class:"atfb-hint atfb-inspector__crumb",text:`Inside ${a.label||"a repeater"} — the visitor answers this once per ${String(a.itemLabel??"")||"row"}.`}),r("p",{class:"atfb-hint",text:`Formulas aggregate it as {${a.id}.${s.id}} — e.g. sum( {${a.id}.${s.id}} ).`})):this.inspector.append(r("p",{class:"atfb-hint",text:`Reference this field as {field:${s.id}}`})),o.includes("label")&&this.inspector.append(y("Label",J(T(s.label,c=>l("label",c)),"label"))),o.includes("placeholder")&&this.inspector.append(y("Placeholder",J(T(s.placeholder,c=>l("placeholder",c)),"placeholder"))),o.includes("hint")&&this.inspector.append(y("Hint",J(T(s.hint,c=>l("hint",c)),"hint"),"Shown under the field, and read out with it.")),o.includes("nextlabel")&&this.inspector.append(y("Next button",J(T(String(s.nextLabel??""),c=>l("nextLabel",c)),"nextLabel"),"Leave empty for “Next”.")),o.includes("prevlabel")&&this.inspector.append(y("Back button",J(T(String(s.prevLabel??""),c=>l("prevLabel",c)),"prevLabel"),"Leave empty for “Back”.")),o.includes("addlabel")&&this.inspector.append(y("Add button",J(T(String(s.addLabel??""),c=>l("addLabel",c)),"addLabel"),"Leave empty for “Add another”.")),o.includes("required")&&this.inspector.append(O("Required",s.required,c=>l("required",c))),o.includes("width")&&this.inspector.append(y("Width",D(s.width,[{value:"full",label:"Full width"},{value:"two-thirds",label:"Two thirds"},{value:"half",label:"Half"},{value:"third",label:"One third"},{value:"quarter",label:"One quarter"}],c=>l("width",c)))),i?.choices&&this.inspector.append(this.renderChoicesEditor(s,l)),this.renderTypeSettings(s,i,o,l),(s.type==="total"||o.includes("formula"))&&this.inspector.append(y("Formula",r("div",{class:"atfb-formula__row",children:[T(String(s.formula??""),c=>l("formula",c)),$("Formula editor",()=>bn({root:this.root,fields:this.schema?.fields??[],field:s,onSave:c=>{l("formula",c),this.renderInspector()}}))]}),"Reference answers with braces — {f1} * {f2} + 10 — or open the editor and click them in."),y("Currency symbol",T(String(s.currency??""),c=>l("currency",c)))),this.inspector.append(this.renderValidationSection(s,o,l)),a||(this.inspector.append(this.renderLogicSection(s)),o.includes("prefill")&&this.inspector.append(this.prefillControl(s,l))),o.includes("css")&&this.inspector.append(y("CSS class",T(s.cssClass,c=>l("cssClass",c))))}),this.root=e,this.bar=e.querySelector("[data-atfb-bar]")??r("div"),this.palette=e.querySelector("[data-atfb-palette]")??r("div"),this.canvas=e.querySelector("[data-atfb-canvas]")??r("div"),this.inspector=e.querySelector("[data-atfb-inspector]")??r("div"),this.canvas.addEventListener("click",t=>{const s=t.target;if(!(this.tab!=="build"||!this.selected||s.closest("[data-atfb-card], button, os-button, a, input, textarea, select, os-select, label, [contenteditable]"))){this.selected=null;for(const a of this.canvas.querySelectorAll(".atfb-card.is-selected"))a.classList.remove("is-selected");this.renderInspector()}})}async start(){try{const[s,a,i]=await Promise.all([F.config(),F.listThemes(),F.listForms()]);this.config=s,this.themes=a,this.forms=i}catch(s){this.fail(s);return}this.teardowns.push(Jt([se])),this.teardowns.push(Tn({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)}));const e=s=>{this.dirty&&(s.preventDefault(),s.returnValue="")};window.addEventListener("beforeunload",e),this.teardowns.push(()=>window.removeEventListener("beforeunload",e));const t=s=>{!(s.metaKey||s.ctrlKey)||s.key.toLowerCase()!=="z"||s.target?.closest("input, textarea, [contenteditable]")||(s.preventDefault(),this.travel(s.shiftKey?1:-1))};if(this.root.addEventListener("keydown",t),this.teardowns.push(()=>this.root.removeEventListener("keydown",t)),this.renderBar(),this.renderPalette(),this.forms.length){const s=ms("builder");await this.open(s&&this.forms.some(a=>a.id===s)?s:this.forms[0].id)}else this.renderFormsList()}destroy(){this.canvasTarget?.(),this.canvasTarget=null,this.teardowns.forEach(e=>e()),this.teardowns=[]}fail(e){R(this.bar),this.bar.append(r("p",{class:"atfb-error",text:e instanceof Error?e.message:"Something went wrong loading your forms."}))}renderBar(){R(this.bar);const e=D(String(this.form?.id??""),[...this.forms.map(a=>({value:String(a.id),label:a.title||"(untitled)"}))],a=>void this.open(Number(a)));e.setAttribute("aria-label","Choose a form");const t=r("input",{class:"atfb-title",type:"text",value:this.form?.title??"",placeholder:"Untitled form",attrs:{"aria-label":"Form title"},on:{input:a=>{this.form&&(this.form.title=a.target.value,this.markDirty())}}}),s=r("div",{class:"atfb-tabs",attrs:{role:"tablist"},children:[["build","Build"],["theme","Theme"],["settings","Settings"],["notify","Notifications"],["confirm","Confirmations"]].map(([a,i])=>r("button",{class:`atfb-tab${this.tab===a?" is-active":""}`,type:"button",text:i,attrs:{role:"tab","aria-selected":this.tab===a},on:{click:()=>{this.tab=a,this.renderBar(),this.renderInspector(),this.renderCanvas()}}}))});this.bar.append(r("div",{class:"atfb-bar__left",children:[this.forms.length>1?e:null,t]}),s,r("div",{class:"atfb-bar__right",children:[this.historyButton("undo","Undo",-1),this.historyButton("redo","Redo",1),$("New",()=>void this.showTemplates(),"secondary","plus-alt2"),$("Export",()=>void this.exportForm(),"secondary","download"),$("Import",()=>void this.importForm(),"secondary","upload"),$("Preview",()=>void this.preview(),"secondary","visibility"),$("Entries",()=>this.openEntries(),"secondary","list-view"),this.logicMapButton(),this.saveButton()]}))}liveField(e){return this.locateField(e)?.field}locateField(e){const t=this.schema?.fields??[];for(let s=0;sthis.rebindCanvas(),{once:!0});return}this.renderCanvas()}snapshot(){if(!this.schema)return;const e=JSON.stringify(this.schema);this.history[this.historyAt]!==e&&(this.history=this.history.slice(0,this.historyAt+1),this.history.push(e),this.history.length>60&&this.history.shift(),this.historyAt=this.history.length-1,this.syncHistoryButtons())}travel(e){const t=this.historyAt+e;!this.schema||t<0||t>=this.history.length||(this.historyAt=t,this.schema=JSON.parse(this.history[t]),this.schema.fields.some(s=>s.id===this.selected)||(this.selected=null),this.markDirty(),this.renderBar(),this.renderCanvas(),this.renderInspector())}historyButton(e,t,s){const a=$(t,()=>this.travel(s),"secondary",e);return a.setAttribute("data-atfb-history",String(s)),a.disabled=!this.canTravel(s),a}canTravel(e){const t=this.historyAt+e;return t>=0&&tURL.revokeObjectURL(s),1e3)}async importForm(){const e=r("input",{type:"file",attrs:{accept:"application/json,.json"}});e.addEventListener("change",async()=>{const t=e.files?.[0];if(t)try{const s=JSON.parse(await t.text());if(!s.schema)throw new Error("That file does not contain a form.");const a=await F.createForm({title:s.title??t.name.replace(/\.json$/i,""),schema:s.schema});this.forms.unshift({id:a.id,title:a.title,status:a.status,modified:a.modified,fields:a.schema.fields.length,theme:a.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:a.shortcode}),this.form=a,this.schema=a.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),N("Form imported",a.title)}catch(s){N("Could not import that file",s instanceof Error?s.message:"","error")}}),e.click()}saveButton(){const e=$("Save",()=>void this.save(),"primary");return e.disabled=!this.dirty,e.setAttribute("data-atfb-save",""),e}markDirty(){this.dirty=!0,this.editGeneration+=1;const e=this.bar.querySelector("[data-atfb-save]");e&&(e.disabled=!1),this.autosave()}async save(e=!1){if(!this.form||!this.schema)return;if(this.saveInFlight){this.queuedSave={silent:e&&(this.queuedSave?.silent??!0)};return}this.saveInFlight=!0;const t=this.editGeneration;try{const s=await F.updateForm(this.form.id,{title:this.form.title,schema:this.schema});if(t===this.editGeneration){this.form=s,this.schema=s.schema,this.dirty=!1,this.rebindCanvas();const i=this.bar.querySelector("[data-atfb-save]");i&&(i.disabled=!0)}Ms(s.id);const a=this.forms.find(i=>i.id===s.id);a&&(a.title=s.title),Mn(s.id,s.title,s.previewUrl),e||N("Form saved",s.title)}catch(s){N(Ze("saveFailed","Could not save"),s instanceof Error?s.message:"","error")}finally{this.saveInFlight=!1;const s=this.queuedSave;this.queuedSave=null,s&&this.save(s.silent)}}async openFormById(e){await this.open(e)}async open(e){if(!(this.dirty&&!await ie("You have unsaved changes. Discard them?"))){try{this.form=await F.getForm(e),this.schema=this.form.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot()}catch(t){this.fail(t);return}this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}}announceIdentity(){this.form&&$t(this.root,_n(this.form,W?.adminUrl??""))}async showTemplates(){if(!this.config)return;const e=r("div",{class:"atfb-overlay"}),t=i=>{i.key==="Escape"&&s()},s=()=>{e.remove(),document.removeEventListener("keydown",t)},a=r("div",{class:"atfb-templates",children:this.config.templates.map(i=>r("button",{class:"atfb-template",type:"button",on:{click:async()=>{s();try{const o=await F.createForm({template:i.slug});this.forms.unshift({id:o.id,title:o.title,status:o.status,modified:o.modified,fields:o.schema.fields.length,theme:o.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:o.shortcode}),this.form=o,this.schema=o.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}catch(o){N("Could not create the form",o instanceof Error?o.message:"","error")}}},children:[z(i.icon),r("strong",{text:i.label}),r("span",{text:i.description})]}))});e.append(r("div",{class:"atfb-modal",attrs:{role:"dialog","aria-label":"Start a new form"},children:[r("h2",{text:"Start a new form"}),a,this.archivedFormsSection(s),r("div",{class:"atfb-modal__actions",children:[$("Cancel",s)]})]})),e.addEventListener("click",i=>{i.target===e&&s()}),document.addEventListener("keydown",t),this.root.append(e),a.querySelector("button")?.focus()}archivedFormsSection(e){const t=r("div",{class:"atfb-archived"});return F.listArchivedForms().then(s=>{s.length&&t.append(r("h3",{class:"atfb-archived__title",text:"Or bring one back from the archive"}),...s.map(a=>r("div",{class:"atfb-archived__row",children:[r("div",{class:"atfb-archived__meta",children:[r("strong",{text:a.title||"(untitled)"}),r("span",{class:"atfb-hint",text:`${a.entries} ${a.entries===1?"entry":"entries"} · ${a.submissions} submissions · ${a.views} views`})]}),$("Restore",async()=>{try{const i=await F.unarchiveForm(a.id);e(),this.forms.unshift(i),N("Form restored",`${i.title||"(untitled)"} is back, with its entries and stats.`),await this.open(i.id)}catch(i){N("Could not restore the form",i instanceof Error?i.message:"","error")}},"secondary","undo")]})))}).catch(()=>{}),t}renderFormsList(){R(this.canvas),this.canvas.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms yet"}),r("p",{text:"Start from a template, or build one from nothing."}),$("New form",()=>void this.showTemplates(),"primary","plus-alt2")]}))}openEntries(){const e=window.wp?.os;if(e?.openWindow){e.openWindow("allterrain-forms-entries");return}window.location.assign(`${W?.adminUrl??""}admin.php?page=allterrain-forms-entries`)}renderPalette(){if(!this.config)return;R(this.palette);const e=new Map;for(const s of this.config.fieldTypes){const a=e.get(s.group)??[];a.push(s),e.set(s.group,a)}const t=r("input",{class:"atfb-input atfb-palette__search",type:"search",placeholder:"Search fields",attrs:{"aria-label":"Search field types"},on:{input:s=>{const a=s.target.value.toLowerCase().trim();this.palette.querySelectorAll(".atfb-chip").forEach(i=>{const o=(i.textContent??"").toLowerCase();i.hidden=a!==""&&!o.includes(a)}),this.palette.querySelectorAll(".atfb-group").forEach(i=>{const o=Array.from(i.querySelectorAll(".atfb-chip")).some(l=>!l.hidden);i.hidden=!o})}}});this.palette.append(t);for(const[s,a]of Object.entries(this.config.groups)){const i=e.get(s);i?.length&&this.palette.append(r("div",{class:"atfb-group",children:[r("h3",{class:"atfb-group__title",text:a}),r("div",{class:"atfb-group__items",children:i.map(o=>this.paletteChip(o))})]}))}}paletteChip(e){const t=r("button",{class:"atfb-chip",type:"button",title:e.description,attrs:{"data-atf-type":e.type},children:[z(e.icon),r("span",{text:e.label})]});return t.addEventListener("pointerdown",s=>{const a=r("div",{class:"atfb-chip atfb-chip--ghost",children:[z(e.icon),r("span",{text:e.label})]});Z().start({payload:Ee(se,t,{fieldType:e.type,isNew:!0},s,a),origin:s,onClickOnly:()=>this.addField(e.type)})}),t.addEventListener("click",s=>{Z().recentlyEndedDrag()&&s.preventDefault()}),t}renderCanvas(){if(R(this.canvas),!this.schema||!this.form){this.renderFormsList();return}if(this.tab!=="build"){this.canvas.append(this.renderTabCanvas());return}const e=r("div",{class:"atfb-canvas__list",attrs:{"data-atfb-list":""}});this.schema.fields.length||e.append(r("div",{class:"atfb-placeholder",text:Ze("emptyCanvas","Drag a field from the left to begin.")})),this.schema.fields.forEach((s,a)=>{e.append(this.renderFieldCard(s,a))});const t=r("div",{class:"atfb-canvas__inner",children:[r("p",{class:"atfb-shortcode",text:this.form.shortcode,title:"Paste this anywhere to place the form"}),e]});this.canvas.append(t),this.registerCanvasTarget(e),this.paintLogicMap(t),this.paintCanvasTheme()}prefillControl(e,t){const s=e.prefill.startsWith("query:"),a=Xe.some(_=>_.value===e.prefill),i=s?"query":a&&e.prefill||(e.prefill?"custom":""),o=r("div",{class:"atfb-prefill__detail"}),l=r("p",{class:"atfb-row__hint atfb-prefill__preview"}),c=_=>{if(o.replaceChildren(),l.replaceChildren(),_==="query"){const u=e.prefill.startsWith("query:")?e.prefill.slice(6):"";o.append(T(u,b=>{const g=b.trim();t("prefill",g?`query:${g}`:""),d(`query:${g}`)},"utm_source"),r("p",{class:"atfb-row__hint",text:"The name of the parameter in the link people arrive on."}))}_==="custom"&&o.append(T(e.prefill,u=>{t("prefill",u),d(u)},"myplugin:something"),r("p",{class:"atfb-row__hint",text:"For a source another plugin has added through alltfo_resolve_prefill."})),d(e.prefill)},d=_=>{if(l.replaceChildren(),!_)return;if(_.startsWith("query:")){const b=_.slice(6);b&&(l.textContent=`A visit to …/your-page/?${b}=abc opens the form with “abc” in it.`);return}const u=Xe.find(b=>b.value===_)?.tag;u&&qe(this.form?.id??0).then(b=>{for(const g of b)for(const p of g.items)if(p.tag===u){const x=_.startsWith("user:");if(!p.sample){l.textContent="Empty unless the visitor is signed in.";return}l.textContent=x?`Opens with “${p.sample}” for you — empty for a visitor who is not signed in.`:`Opens with “${p.sample}”.`;return}})};c(i);const h=r("select",{class:"atfb-input atfb-select",on:{change:_=>{const u=_.target.value;t("prefill",u==="query"||u==="custom"?"":u),c(u)}}});h.append(r("option",{value:"",text:"Nothing — leave it empty",attrs:{selected:i===""}}));for(const _ of Dn){const u=document.createElement("optgroup");u.label=_;for(const b of Xe.filter(g=>g.group===_))u.append(r("option",{value:b.value,text:b.label,attrs:{selected:b.value===i}}));h.append(u)}const w=document.createElement("optgroup");return w.label="From the link they arrived on",w.append(r("option",{value:"query",text:"A parameter in the web address",attrs:{selected:i==="query"}})),h.append(w,r("option",{value:"custom",text:"Something else (advanced)",attrs:{selected:i==="custom"}})),y("Pre-fill this with",r("div",{class:"atfb-prefill",children:[h,o,l]}),"What the box already contains when the form opens. They can still change it.")}renderCondition(e,t){const s=t.some(i=>i.kind==="field"&&i.missing),a=r("span",{class:`atfb-cond${s?" is-broken":""}`,attrs:{"aria-label":rt(t)},children:[z("randomize"),...t.map(i=>this.renderConditionToken(e,i))]});return a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("click",i=>i.stopPropagation()),a.addEventListener("keydown",i=>i.stopPropagation()),a}editCondition(e,t,s=!0,a=""){const i=this.liveField(e)?.logic;if(i){if(t(i),this.markDirty(),!s){this.logicMap?.setEdges(me(this.schema?.fields??[]));return}this.renderCanvas(),this.renderInspector(),a&&window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-cond="${CSS.escape(a)}"]`)?.focus()})}}condSelect(e,t,s,a,i){if(Y("os-select")&&Y("os-option")){const o=document.createElement("os-select");o.setAttribute("value",e),o.setAttribute("aria-label",a),o.setAttribute("data-cond",s),o.className="atfb-cond__control",o.title=a;for(const l of t){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,o.append(c)}return o.addEventListener("os-pick",l=>{i(String(l.detail?.value??""))}),o}return r("select",{class:"atfb-cond__control atfb-cond__control--native",title:a,attrs:{"aria-label":a,"data-cond":s},on:{change:o=>i(o.target.value)},children:t.map(o=>r("option",{value:o.value,text:o.label,attrs:{selected:o.value===e}}))})}renderConditionToken(e,t){if(t.kind==="field"&&!t.missing)return r("button",{class:"atfb-cond__chip atfb-cond__chip--field",type:"button",text:t.text,title:"Go to this question",on:{click:a=>{a.stopPropagation(),this.selectField(t.fieldId),this.canvas.querySelector(`[data-atfb-card="${CSS.escape(t.fieldId)}"]`)?.scrollIntoView({block:"nearest",behavior:"smooth"})}}});if(t.kind==="verb")return r("button",{class:"atfb-cond__verb",type:"button",text:t.text,title:"Switch between showing and hiding this field when the condition matches.",attrs:{"data-cond":`${e.id}:verb`},on:{click:()=>this.editCondition(e.id,s=>{s.action=s.action==="hide"?"show":"hide"},!0,`${e.id}:verb`)}});if(t.kind==="join")return r("button",{class:"atfb-cond__join",type:"button",text:t.text,title:"Switch between needing every rule (and) or any one of them (or).",attrs:{"data-cond":`${e.id}:join`},on:{click:()=>this.editCondition(e.id,s=>{s.match=s.match==="all"?"any":"all"},!0,`${e.id}:join`)}});if(t.kind==="operator"){const s=`${e.id}:op:${t.ruleIndex}`;return this.condSelect(t.operator,Object.entries(Te).map(([a,i])=>({value:a,label:i})),s,"How the answer is compared",a=>this.editCondition(e.id,i=>{const o=i.rules[t.ruleIndex];o&&(o.operator=a)},!0,s))}return t.kind==="value"?this.renderConditionValue(e,t):r("span",{class:"atfb-cond__chip atfb-cond__chip--missing",text:t.text})}renderConditionValue(e,t){const s=`${e.id}:value:${t.ruleIndex}`,a=this.schema?.fields.find(c=>c.id===t.sourceId),i=(c,d)=>this.editCondition(e.id,h=>{const w=h.rules[t.ruleIndex];w&&(w.value=c)},d,s);if(a?.choices?.length){const c=a.choices.map(d=>({value:d.value,label:d.label||d.value}));return t.raw!==""&&!a.choices.some(d=>d.value===t.raw)&&c.unshift({value:t.raw,label:t.text}),this.condSelect(t.raw,c,s,"The answer that triggers this",d=>i(d,!0))}const o=["number","range","scale","rating","total"].includes(a?.type??""),l=r("input",{class:"atfb-cond__chip atfb-cond__chip--value atfb-cond__value",value:t.raw,title:"The answer that triggers this. Edit it here.",attrs:{type:"text","aria-label":"The answer that triggers this","data-cond":s,inputmode:o?"decimal":void 0,size:String(Math.max(2,Math.min(24,t.raw.length||2)))}});return l.addEventListener("input",()=>{l.size=Math.max(2,Math.min(24,l.value.length||2)),i(l.value,!1)}),l.addEventListener("change",()=>i(l.value,!0)),l.addEventListener("keydown",c=>{c.key==="Enter"&&(c.preventDefault(),i(l.value,!0))}),l}section(e,t,s,a=!1){const i=r("details",{class:"atfb-section",attrs:{open:this.openSections.get(e)??a},children:[r("summary",{text:t}),...s]});return i.addEventListener("toggle",()=>this.openSections.set(e,i.open)),i}logicMapButton(){const e=me(this.schema?.fields??[]).length>0,t=$(this.logicMapOn?"Hide logic":"Show logic",()=>{this.logicMapOn=!this.logicMapOn,rs(Rt,this.logicMapOn?"on":"off"),this.renderBar(),this.renderCanvas()},this.logicMapOn?"primary":"secondary","randomize");return t.title="Draw a line from each question to the ones it decides.",t.hidden=!e,t}paintLogicMap(e){this.logicMap?.destroy(),this.logicMap=null;const t=this.schema?.fields??[],s=me(t);if(!s.length||!this.logicMapOn)return;e.classList.add("has-logicmap");const a=new ws(e);a.setEdges(s),a.highlight(this.selected??""),this.logicMap=a,e.addEventListener("pointerover",i=>{const o=i.target.closest("[data-atfb-card]");a.highlight(o?.dataset.atfbCard??this.selected??"")}),e.addEventListener("pointerleave",()=>a.highlight(this.selected??""))}renderFieldCard(e,t){const s=this.config?.fieldTypes.find(d=>d.type===e.type),a=this.selected===e.id,i=this.schema?.fields??[],o=gs(e,i),l=ys(i).get(e.id)??0,c=r("div",{class:`atfb-card${a?" is-selected":""}`,attrs:{"data-atfb-card":e.id,"data-index":t,tabindex:"0",role:"button","aria-pressed":a,"aria-label":`${e.label||s?.label||e.type}, ${t+1} of ${this.schema?.fields.length??0}`},children:[r("div",{class:"atfb-card__bar",children:[r("div",{class:"atfb-card__grip",attrs:{"aria-hidden":"true"},children:[z("menu")]}),r("div",{class:"atfb-card__head",children:[z(s?.icon??"dashicons-forms"),r("span",{class:"atfb-card__type",text:s?.label??e.type}),this.requiredToggle(e),l?r("span",{class:"atfb-badge atfb-badge--controls",text:l===1?"controls 1 field":`controls ${l} fields`,title:"Other questions appear or disappear based on this answer."}):null]}),r("div",{class:"atfb-card__actions",children:[this.cardAction("admin-page","Duplicate",()=>this.duplicateField(e.id)),this.cardAction("trash","Delete",()=>void this.deleteField(e.id))]})]}),r("div",{class:"atfb-card__body",children:[dt(e,s,{edit:d=>{const h=this.liveField(e.id);if(!h)return;d(h),this.markDirty(),this.syncInspector(h);const w=this.selected?this.locateField(this.selected):void 0;w?.parent&&w.parent.id===h.id&&this.syncInspector(w.field)},restructure:d=>{const h=this.liveField(e.id);h&&(this.snapshot(),d(h),this.markDirty(),this.renderCanvas(),this.renderInspector())},types:d=>this.config?.fieldTypes.find(h=>h.type===d),selectedId:this.selected}),o.length?this.renderCondition(e,o):null]})]});return c.addEventListener("click",d=>{d.target.closest(".atfb-card__actions")||Z().recentlyEndedDrag()||this.selectField(e.id)}),c.addEventListener("keydown",d=>{if(d.key==="Enter"||d.key===" "){d.preventDefault(),this.selectField(e.id);return}d.altKey&&(d.key==="ArrowUp"||d.key==="ArrowDown")&&(d.preventDefault(),this.moveField(e.id,d.key==="ArrowUp"?t-1:t+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})),(d.key==="Delete"||d.key==="Backspace")&&(d.preventDefault(),this.deleteField(e.id))}),c.addEventListener("pointerdown",d=>{d.target.closest(".atfb-card__actions")||Z().start({payload:Ee(se,c,{fieldId:e.id,field:e,isNew:!1},d),origin:d})}),c}requiredToggle(e){return r("button",{class:`atfb-req${e.required?" is-on":""}`,type:"button",text:e.required?"Required":"Optional",title:e.required?"This must be answered. Click to make it optional.":"Click to make this required.",attrs:{"aria-pressed":e.required?"true":"false"},on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.required=!e.required,this.markDirty(),this.renderCanvas(),this.renderInspector()}}})}cardAction(e,t,s){return r("button",{class:"atfb-card__action",type:"button",title:t,attrs:{"aria-label":t},on:{click:a=>{a.stopPropagation(),s()}},children:[z(e)]})}gapAnimator(e,t,s,a){const i=r("div",{class:"atfb-marker",attrs:{"aria-hidden":"true"}});let o=null,l=null,c=0;const d=()=>{i.remove(),l?.classList.remove("atfb-lifted"),l=null,o=null},h=u=>{const b=Array.from(e.querySelectorAll(t)),g=new Map(b.filter(x=>!x.classList.contains("atfb-lifted")).map(x=>[x,x.getBoundingClientRect().top]));u();for(const x of b)x.style.transition="none",x.style.transform="";const p=b.filter(x=>{const I=g.get(x);if(I===void 0||!x.isConnected||x.classList.contains("atfb-lifted"))return!1;const S=I-x.getBoundingClientRect().top;return Math.abs(S)<.5?!1:(x.style.transform=`translateY(${S}px)`,!0)});e.offsetHeight;for(const x of b){if(!p.includes(x)){x.style.transition="";continue}x.style.transition="transform 160ms ease",x.style.transform="",x.addEventListener("transitionend",()=>{x.style.transition=""},{once:!0})}},w=u=>{const b=u.detail;if(b?.payload?.type!==se||!e.classList.contains("is-dropping")||a&&!a(b.payload.data??{}))return;const g=b.payload.data?.fieldId,p=typeof g=="string"?s(g):null,x=Je(e,t,b.clientY??0,p??void 0);x===o&&i.isConnected||(o=x,h(()=>{p&&p!==l&&(l?.classList.remove("atfb-lifted"),p.classList.add("atfb-lifted"),l=p),i.style.blockSize=`${Math.max(8,Math.round(c))}px`;const I=Array.from(e.querySelectorAll(t)).filter(S=>S!==p);x>=I.length?e.append(i):I[x].before(i)}))},_=()=>{e.classList.remove("is-dropping"),window.setTimeout(()=>h(d),0)};return document.addEventListener("os.drag.move",w),document.addEventListener("os.drag.end",_),{enter:u=>{const b=u?s(u):null;c=b&&!b.classList.contains("atfb-lifted")?b.getBoundingClientRect().height:c||44},leave:()=>h(d),drop:(u,b)=>{const g=o??Je(e,t,u,b??void 0);return d(),g},teardown:()=>{document.removeEventListener("os.drag.move",w),document.removeEventListener("os.drag.end",_),d()}}}registerCanvasTarget(e){this.canvasTarget?.(),this.canvasTarget=null;const t=this.gapAnimator(e,".atfb-card",i=>this.canvas.querySelector(`[data-atfb-card="${CSS.escape(i)}"]`)),s=Z().registerDropTarget({id:`atfb-canvas-${this.form?.id??0}`,element:e,accept:i=>i.type===se,onEnter:i=>{e.classList.add("is-dropping"),t.enter(i.payload.data.fieldId)},onLeave:()=>{e.classList.remove("is-dropping"),t.leave()},onDrop:(i,o)=>{e.classList.remove("is-dropping");const l=i.payload.data,c=l.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(l.fieldId)}"]`):null,d=t.drop(o.clientY,c);if(l.isNew&&l.fieldType){this.addField(l.fieldType,d);return}if(l.fieldId&&this.locateField(l.fieldId)){this.relocateField(l.fieldId,null,d);return}l.field&&this.insertField({...l.field,id:""},d)}}),a=this.wireRepeaterZones(e);this.canvasTarget=()=>{s(),a.forEach(i=>i()),t.teardown()}}wireRepeaterZones(e){const t=[];return e.querySelectorAll("[data-atfb-repeater-zone]").forEach(s=>{const a=s.dataset.atfbRepeaterZone??"",i=l=>{const c=l;if(c.fieldId===a)return!1;const d=c.isNew?c.fieldType:this.locateField(c.fieldId??"")?.field.type??c.field?.type;return!!d&&this.allowedInRepeater(d)},o=this.gapAnimator(s,".atfb-subcard",l=>e.querySelector(`[data-atfb-subfield="${CSS.escape(l)}"]`),i);t.push(()=>o.teardown()),t.push(Z().registerDropTarget({id:`atfb-repzone-${this.form?.id??0}-${a}`,element:s,accept:l=>l.type===se&&i(l.data),onEnter:l=>{s.classList.add("is-dropping"),o.enter(l.payload.data.fieldId)},onLeave:()=>{s.classList.remove("is-dropping"),o.leave()},onDrop:(l,c)=>{s.classList.remove("is-dropping");const d=l.payload.data,h=d.fieldId?e.querySelector(`[data-atfb-subfield="${CSS.escape(d.fieldId)}"]`):null,w=o.drop(c.clientY,h);if(d.isNew&&d.fieldType){this.addFieldToRepeater(d.fieldType,a,w);return}if(d.fieldId&&this.locateField(d.fieldId)){this.relocateField(d.fieldId,a,w);return}d.field&&this.insertFieldIntoRepeater({...d.field,id:""},a,w)}})),s.querySelectorAll(".atfb-subcard").forEach(l=>{const c=l.dataset.atfbSubfield??"";l.addEventListener("click",d=>{d.target.closest(".atfb-preview__remove")||(d.stopPropagation(),!Z().recentlyEndedDrag()&&this.selectField(c))}),l.addEventListener("keydown",d=>{if(d.stopPropagation(),d.key==="Enter"||d.key===" "){d.preventDefault(),this.selectField(c);return}if(d.altKey&&(d.key==="ArrowUp"||d.key==="ArrowDown")){d.preventDefault();const h=this.locateField(c);h&&(this.relocateField(c,a,d.key==="ArrowUp"?h.index-1:h.index+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(c)}"]`)?.focus()}));return}(d.key==="Delete"||d.key==="Backspace")&&(d.preventDefault(),this.deleteField(c))}),l.addEventListener("pointerdown",d=>{if(d.stopPropagation(),d.target.closest(".atfb-preview__remove"))return;const h=this.locateField(c);h&&Z().start({payload:Ee(se,l,{fieldId:c,parentId:a,field:h.field,isNew:!1},d),origin:d})})})}),t}addField(e,t){const s=this.buildField(e);s&&this.insertField(s,t)}buildField(e){const t=this.config?.fieldTypes.find(a=>a.type===e);return!t||!this.schema?void 0:{id:this.nextFieldId(),type:e,label:t.input?t.label:"",placeholder:"",hint:"",required:!1,width:"full",cssClass:"",default:"",choices:t.choices?[{label:"First choice",value:"first"},{label:"Second choice",value:"second"}]:[],logic:{enabled:!1,action:"show",match:"all",rules:[]},messages:{},prefill:"",...t.settings}}allowedInRepeater(e){const t=this.config?.fieldTypes.find(s=>s.type===e);return!t||!t.input?!1:!["repeater","page_break","file","signature","total"].includes(e)}addFieldToRepeater(e,t,s){if(!this.allowedInRepeater(e))return;const a=this.buildField(e);a&&this.insertFieldIntoRepeater(a,t,s)}insertFieldIntoRepeater(e,t,s){const a=this.liveField(t);if(!this.schema||!a||a.type!=="repeater")return;e.id||(e.id=this.nextFieldId()),this.snapshot(),Array.isArray(a.fields)||(a.fields=[]);const i=a.fields,o=s===void 0?i.length:Math.max(0,Math.min(s,i.length));i.splice(o,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(e.id)}"]`)?.focus()})}relocateField(e,t,s){if(!this.schema)return;const a=this.locateField(e);if(!a)return;if(!a.parent&&!t){this.moveField(e,s);return}const i=t?this.liveField(t):null;if(t&&(!i||i.type!=="repeater"||e===t))return;i&&!Array.isArray(i.fields)&&(i.fields=[]);const o=i?i.fields:this.schema.fields;this.snapshot(),a.list.splice(a.index,1);const l=Math.max(0,Math.min(s,o.length));o.splice(l,0,a.field),this.selected=a.field.id,this.markDirty(),this.renderCanvas(),this.renderInspector()}insertField(e,t){if(!this.schema)return;e.id||(e.id=this.nextFieldId()),this.snapshot();const s=t===void 0?this.schema.fields.length:Math.max(0,Math.min(t,this.schema.fields.length));this.schema.fields.splice(s,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})}moveField(e,t){if(!this.schema)return;const s=jt(this.schema.fields,e,t);if(!s)return;this.snapshot();const[a]=this.schema.fields.splice(s.from,1);this.schema.fields.splice(s.to,0,a),this.markDirty(),this.renderCanvas()}duplicateField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=JSON.parse(JSON.stringify(t.field)),a=this.usedFieldIds(),i=()=>{let o=a.size+1;for(;a.has(`f${o}`);)o++;const l=`f${o}`;return a.add(l),l};s.id=i();for(const o of s.fields??[])o.id=i();if(t.parent){this.snapshot(),t.list.splice(t.index+1,0,s),this.selected=s.id,this.markDirty(),this.renderCanvas(),this.renderInspector();return}this.insertField(s,t.index+1)}async deleteField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=this.schema.fields.filter(i=>i.logic?.rules?.some(o=>o.field===e)),a=s.length?`Delete this field? ${s.length} other field${s.length===1?"":"s"} use it in a condition, and those conditions will stop working.`:Ze("confirmDelete","Delete this? It cannot be undone.");await ie(a,"Delete field")&&(this.snapshot(),t.list.splice(t.index,1),this.selected===e&&(this.selected=null),this.markDirty(),this.renderCanvas(),this.renderInspector())}selectField(e){this.selected=e;for(const t of this.canvas.querySelectorAll("[data-atfb-card]")){const s=t.dataset.atfbCard===e;t.classList.toggle("is-selected",s),t.setAttribute("aria-pressed",s?"true":"false")}for(const t of this.canvas.querySelectorAll("[data-atfb-subfield]"))t.classList.toggle("is-selected",t.dataset.atfbSubfield===e);this.logicMap?.highlight(e),this.renderInspector()}nextFieldId(){const e=this.usedFieldIds();let t=e.size+1;for(;e.has(`f${t}`);)t++;return`f${t}`}usedFieldIds(){const e=new Set;for(const t of this.schema?.fields??[]){e.add(t.id);for(const s of t.fields??[])e.add(s.id)}return e}nextEntryId(e,t){const s=new Set(t.map(i=>i.id));let a=t.length+1;for(;s.has(`${e}${a}`);)a++;return`${e}${a}`}renderTypeSettings(e,t,s,a){for(const i of s){const o=Pt[i];o&&(this.inspector.append(Bt(e,o,a)),o.also&&this.inspector.append(Bt(e,{...o,key:o.also.key,label:o.also.label,hint:o.also.hint},a)))}s.includes("rows")&&e.type!=="likert"&&this.inspector.append(y("Lines tall",G(String(e.rows??""),i=>a("rows",i)))),s.includes("rows")&&e.type==="likert"&&this.inspector.append(this.renderStatementList(e,a)),s.includes("parts")&&this.inspector.append(this.renderPartsEditor(e,t,a)),s.includes("default")&&!["files","object"].includes(t?.value??"")&&this.inspector.append(this.renderDefaultControl(e,t,a))}renderStatementList(e,t){const s=Array.isArray(e.rows)?e.rows:[];return y("Statements",pe(s.map(a=>a.label??"").join(` +`),a=>t("rows",Ht(s,a)),5),"One per line. Each becomes a row of the matrix.")}renderPartsEditor(e,t,s){const a=t?.parts??[],i=Array.isArray(e.parts)?e.parts:a.map(l=>l.key),o=a.map(l=>O(l.label,i.includes(l.key),c=>{const d=a.map(h=>h.key).filter(h=>h===l.key?c:i.includes(h));s("parts",d.length?d:[l.key])}));return r("div",{class:"atfb-section",children:[r("h4",{class:"atfb-section__title",text:"Parts to ask for"}),...o]})}renderDefaultControl(e,t,s){const a="Filled in before they start. They can change it.";return e.type==="switch"||e.type==="consent"?O("On by default",!!e.default,i=>s("default",i)):t?.choices&&(e.choices??[]).length?y("Default answer",D(String(e.default??""),[{value:"",label:"Nothing chosen"},...(e.choices??[]).map(i=>({value:String(i.value),label:i.label||String(i.value)}))],i=>s("default",i)),a):y("Default answer",T(String(e.default??""),i=>s("default",i)),a)}renderChoicesEditor(e,t){const s=e.choices??[],a=o=>this.liveField(e.id)?.choices?.[o],i=r("div",{class:"atfb-choices"});return s.forEach((o,l)=>{const c=r("div",{class:"atfb-choice-row",children:[e.type==="image_choice"?this.choiceImageWell(o,l,e):null,J(T(o.label,d=>{const h=a(l);if(!h)return;const w=!h.value||h.value===h.label;h.label=d,w&&(h.value=d),this.markDirty();const _=this.liveField(e.id);_&&this.syncCanvas(_)}),`choice:${l}:label`),J(T(o.value,d=>{const h=a(l);h&&(h.value=d,this.markDirty())},"value"),`choice:${l}:value`),e.type==="quiz"||o.points!==void 0?G(String(o.points??""),d=>{const h=a(l);h&&(h.points=d===""?void 0:Number(d),this.markDirty())}):G(String(o.price??""),d=>{const h=a(l);h&&(h.price=d===""?void 0:Number(d),this.markDirty())}),r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":`Remove ${o.label}`},on:{click:()=>{const d=this.liveField(e.id);d&&((d.choices??[]).splice(l,1),t("choices",d.choices),this.renderInspector())}},children:[z("trash")]})]});i.append(c)}),r("div",{class:"atfb-section",children:[r("h4",{text:"Choices"}),r("p",{class:"atfb-hint",text:e.type==="quiz"?"Label, value, points.":"Label, value, and a price for calculations."}),i,$("Add choice",()=>{const o=this.liveField(e.id);if(!o)return;const l=o.choices??[];l.push({label:"",value:""}),t("choices",l),this.renderInspector()},"ghost","plus-alt2"),e.type==="quiz"?y("Correct answer",D(String(e.correct??""),[{value:"",label:"—"},...s.map(o=>({value:o.value,label:o.label}))],o=>t("correct",o))):null]})}choiceImageWell(e,t,s){const a=r("div",{class:`atfb-well${e.image?" has-image":""}`,attrs:{"data-choice":t,"aria-label":`Image for ${e.label||`choice ${t+1}`}`},children:[e.image?r("span",{class:"atfb-well__id",text:`#${e.image}`}):z("format-image")]}),i=Z().registerDropTarget({id:`atfb-well-${s.id}-${t}`,element:a,accept:o=>Fn.includes(o.type),onEnter:()=>a.classList.add("is-dropping"),onLeave:()=>a.classList.remove("is-dropping"),onDrop:o=>{a.classList.remove("is-dropping");const l=o.payload.data,c=Number(l.attachmentId??l.id??l.file?.id??0);if(!c){N("That is not an image this field can use","","error");return}const d=this.liveField(s.id)?.choices?.[t];d&&(d.image=c,this.markDirty(),this.renderInspector())}});return this.teardowns.push(i),a.addEventListener("click",()=>{const o=this.liveField(s.id)?.choices?.[t];o?.image&&(o.image=void 0,this.markDirty(),this.renderInspector())}),a}renderValidationSection(e,t,s){const a=[],i=[];t.includes("minlength")&&i.push(["minlength","Minimum characters"],["maxlength","Maximum characters"]),t.includes("min")?i.push(["min","Minimum"],["max","Maximum"]):t.includes("max")&&i.push(["max","Highest"]),t.includes("step")&&i.push(["step","Steps of"]),t.includes("mindate")&&i.push(["minDate","Earliest date"],["maxDate","Latest date"]),t.includes("mintime")&&i.push(["minTime","Earliest time"],["maxTime","Latest time"]);for(const[l,c]of i)a.push(y(c,T(String(e[l]??""),d=>s(l,d))));t.includes("pattern")&&a.push(...this.renderAnswerShapeRows(e,s)),t.includes("unique")&&a.push(O("No two people may submit the same value",!!e.unique,l=>s("unique",l)));const o=e.messages??{};return t.includes("required")&&a.push(y("Message when required",T(o.required??"",l=>{o.required=l,s("messages",o)}),"Leave empty for the default wording.")),a.length?this.section(`validation:${e.id}`,"Validation",a):r("div",{class:"atfb-section is-empty"})}buildShapePicker(e,t){const s=[{heading:null,options:[{value:"",label:"Anything at all"}]},...$n.map(i=>({heading:i,options:Dt.filter(o=>o.group===i).map(o=>({value:o.slug,label:o.label}))})),{heading:"Your own",options:[{value:"custom",label:"A custom rule…"}]}];if(Y("os-select")&&Y("os-option")){const i=document.createElement("os-select");i.setAttribute("value",e),i.setAttribute("aria-label","What the answer should look like"),i.classList.add("atfb-field");for(const o of s){if(o.heading){const l=document.createElement("os-option");l.setAttribute("value",`__heading:${o.heading}`),l.setAttribute("disabled",""),l.textContent=o.heading,i.append(l)}for(const l of o.options){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,i.append(c)}}return i.addEventListener("os-pick",o=>{t(String(o.detail?.value??""))}),i}const a=r("select",{class:"atfb-input atfb-select",attrs:{"aria-label":"What the answer should look like"},on:{change:i=>t(i.target.value)}});for(const i of s){const o=i.heading?(()=>{const l=document.createElement("optgroup");return l.label=i.heading,a.append(l),l})():a;for(const l of i.options)o.append(r("option",{value:l.value,text:l.label,attrs:{selected:l.value===e}}))}return a}renderAnswerShapeRows(e,t){const a=(typeof e.validation=="string"?e.validation:"")||(e.pattern?"custom":""),i=()=>Ln({root:this.root,field:this.liveField(e.id)??e,onSave:h=>{t("validation","custom"),t("pattern",h.pattern),t("validationRecipe",JSON.stringify(h.recipe));const w={...this.liveField(e.id)?.messages??{}};w.invalid=h.message,t("messages",w),this.renderInspector()},onCancel:()=>this.renderInspector()}),o=h=>{if(h==="custom"){i();return}t("validation",h),t("pattern",""),t("validationRecipe",""),this.renderInspector()},l=this.buildShapePicker(a,o),c=An(a),d=[y("The answer should be",l,c?`e.g. ${c.example}`:"Checked as they type, and again on the server.")];if(a==="custom"){const h=Tt(String(e.validationRecipe??"")),w=Mt(h)||(e.pattern?`Matches the expression ${String(e.pattern)}`:"No rule yet — open the builder.");d.push(y("Your rule",r("div",{class:"atfb-valrule",children:[r("p",{class:"atfb-valrule__words",text:w}),$("Edit the rule…",i,"secondary","edit")]}),xe(h)||e.pattern?"Built in the rule builder, with a playground to test it.":void 0))}return d}logicRulesEditor(e,t,s=""){const a=(this.schema?.fields??[]).filter(d=>d.id!==s&&d.type!=="page_break"),i=()=>r("div",{class:"atfb-rule-join",children:[r("button",{class:"atfb-rule-join__chip",type:"button",text:e.match==="all"?"and":"or",title:"Switch between needing every rule (and) or any one of them (or).",on:{click:()=>t(d=>{d.match=d.match==="all"?"any":"all"},!0)}})]}),o=(d,h)=>{const w=r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":"Remove this rule"},title:"Remove this rule",on:{click:()=>t(u=>{u.rules.splice(h,1)},!0)},children:[z("trash")]}),_=[r("div",{class:"atfb-rule__top",children:[D(d.field,a.map(u=>({value:u.id,label:u.label||u.id})),u=>t(b=>{const g=b.rules[h];g&&(g.field=u,g.value="")},!0)),w]}),D(d.operator,Object.entries(this.config?.operators??{}).map(([u,b])=>({value:u,label:b})),u=>t(b=>{const g=b.rules[h];g&&(g.operator=u)},!0))];if(!Me.includes(d.operator)){const u=this.schema?.fields.find(b=>b.id===d.field);if(u?.choices?.length){const b=u.choices.map(g=>({value:g.value,label:g.label||g.value}));d.value!==""&&!u.choices.some(g=>g.value===d.value)&&b.unshift({value:d.value,label:d.value}),_.push(D(d.value,b,g=>t(p=>{const x=p.rules[h];x&&(x.value=g)})))}else _.push(T(d.value,b=>t(g=>{const p=g.rules[h];p&&(p.value=b)}),"The answer to compare against"))}return r("div",{class:"atfb-rule",children:_})},l=r("div",{class:"atfb-rules"});e.rules.forEach((d,h)=>{h>0&&l.append(i()),l.append(o(d,h))});const c=$("Add rule",()=>{t(d=>{d.rules.push({field:a[0]?.id??"",operator:"is",value:""})},!0)},"ghost","plus-alt2");return[l,c]}conditionsSection(e,t,s){const a=(o,l=!1)=>{o(s),this.markDirty(),l&&this.renderCanvas()},i=t==="confirmation"?"Use":"Send";return this.section(`conditions:${e}`,"Conditions",[O(`Only ${i.toLowerCase()} this ${t} sometimes`,s.enabled,o=>a(l=>{l.enabled=o},!0)),s.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[r("span",{text:`${i} it when`}),D(s.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...this.logicRulesEditor(s,a)]}):null],s.enabled)}renderLogicSection(e){const t=e.logic,s=()=>this.liveField(e.id)?.logic,a=(o,l=!1)=>{const c=s();c&&(o(c),this.markDirty(),this.renderCanvas(),l&&this.renderInspector())},i=this.logicRulesEditor(t,a,e.id);return this.section(`logic:${e.id}`,"Conditional logic",[O("Only show this field sometimes",t.enabled,o=>{a(l=>{l.enabled=o},!0)}),t.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[D(t.action,[{value:"show",label:"Show"},{value:"hide",label:"Hide"}],o=>a(l=>{l.action=o},!0)),r("span",{text:"this field when"}),D(t.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...i]}):null],t.enabled)}renderTabCanvas(){return this.schema?this.tab==="theme"?mt({themes:this.themes,tokens:this.config?.tokens??[],activeSlug:this.schema.settings.theme,overrides:this.schema.settings.themeOverrides,onTheme:e=>{this.schema.settings.theme=e,this.markDirty()},onOverride:(e,t)=>{t===""?delete this.schema.settings.themeOverrides[e]:this.schema.settings.themeOverrides[e]=t,this.markDirty()},onOverridesReplaced:e=>{this.schema.settings.themeOverrides={...e},this.markDirty()},previewFor:(e,t)=>this.previewHtml(e,t),onThemesChanged:e=>{this.themes=e}}):this.tab==="settings"?this.renderSettingsPane():this.tab==="notify"?this.renderNotificationsPane():this.renderConfirmationsPane():r("div")}async paintCanvasTheme(){if(!this.form||!this.schema)return;const e=this.schema.settings.theme,t=JSON.stringify([e,this.schema.settings.themeOverrides]);if(t!==this.canvasThemeSignature){this.canvasThemeSignature=t;try{const s=await this.previewHtml(e,this.schema.settings.themeOverrides??{});this.root.classList.toggle("atfb--dark-form",/atf-is-dark/.test(s));const a=/class="atf-form-wrap"[^>]*\sstyle="([^"]*)"/.exec(s);if(!a)return;const i=a[1].replace(/"/g,'"').replace(/�?39;/g,"'").replace(/&/g,"&");this.canvasTheme.textContent=`.atfb .atfb-preview { ${i} -}`,this.canvasTheme.isConnected||this.root.append(this.canvasTheme)}catch{}}}async previewHtml(e,t){if(!this.form||!this.schema)return"";const s=JSON.parse(JSON.stringify(this.schema));s.settings.theme=e,s.settings.themeOverrides=t;const{html:a}=await I.preview(this.form.id,{schema:s,theme:e});return a}renderSettingsPane(){const e=this.schema.settings,t=(s,a)=>{const i=s.split(".");let o=e;for(let l=0;lt("submitLabel",s))),O("Submit without reloading the page",e.ajax,s=>t("ajax",s)),g("Progress indicator",D(e.progressBar,[{value:"steps",label:"Numbered steps"},{value:"bar",label:"A bar"},{value:"none",label:"None"}],s=>t("progressBar",s)),"Only shown on forms with a page break.")]}),r("section",{children:[r("h3",{text:"Who can fill this in"}),O("Only logged-in users",e.requireLogin,s=>t("requireLogin",s)),g("Message for everyone else",A(e.loginMessage,s=>t("loginMessage",s))),g("Open from",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.start,on:{input:s=>t("schedule.start",s.target.value)}})),g("Closes",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.end,on:{input:s=>t("schedule.end",s.target.value)}})),g("Message when closed",A(e.schedule.message,s=>t("schedule.message",s))),g("Stop after this many submissions",G(String(e.limit.total||""),s=>t("limit.total",Number(s)||0)),"0 means no limit."),g("Submissions per logged-in user",G(String(e.limit.perUser||""),s=>t("limit.perUser",Number(s)||0)))]}),r("section",{children:[r("h3",{text:"Spam"}),r("p",{class:"atfb-hint",text:"No captcha. Nothing here asks the visitor to prove anything."}),O("Honeypot field",e.spam.honeypot,s=>t("spam.honeypot",s)),g("Reject submissions faster than (seconds)",G(String(e.spam.timeTrap),s=>t("spam.timeTrap",Number(s)||0)),"A human cannot fill in a form in under a second. A script can."),g("Submissions allowed per hour, per address",G(String(e.spam.rateLimit),s=>t("spam.rateLimit",Number(s)||0))),g("Blocked words",pe(e.spam.blocklist,s=>t("spam.blocklist",s),4),"One per line."),O("Use Akismet when it is installed",e.spam.akismet,s=>t("spam.akismet",s)),O("Ask a simple sum before sending",e.spam.challenge,s=>t("spam.challenge",s)),r("p",{class:"atfb-hint",text:"Only for a form under sustained attack — it is the one check here that asks the visitor to do something. Still kinder than an image captcha: it is answerable by a screen reader, and it hands no data to anyone."})]}),r("section",{children:[r("h3",{text:"Storage and privacy"}),O("Keep entries",e.storage.entries,s=>t("storage.entries",s)),O("Record IP addresses",e.storage.ip,s=>t("storage.ip",s)),O("Anonymise recorded IP addresses",e.storage.anonymise,s=>t("storage.anonymise",s)),g("Delete entries after (days)",G(String(e.storage.retention||""),s=>t("storage.retention",Number(s)||0)),"0 keeps them forever. Anything else deletes automatically, every day.")]}),r("section",{children:[r("h3",{text:"Analytics"}),O("Count views and starts",e.analytics.enabled,s=>t("analytics.enabled",s)),O("Tally device, browser and system",e.analytics.tech,s=>t("analytics.tech",s)),r("p",{class:"atfb-hint",text:"Counters, never people: no cookie, no fingerprint, no per-visitor record — the tallies keep coarse classes like “phone” and “Chrome”, not the visitor’s user-agent string. Nothing here needs a consent banner. Turning the first switch off stops view and start counting entirely."})]}),r("section",{children:[r("h3",{text:"Save and continue later"}),O("Let people save a half-finished form",e.resume.enabled,s=>t("resume.enabled",s)),g("Keep a saved form for (days)",G(String(e.resume.days),s=>t("resume.days",Math.max(1,Number(s)||30)))),r("p",{class:"atfb-hint",text:"The link this creates is the only key to those answers — anyone holding it can read them. For genuinely sensitive questions, require login instead."})]}),r("section",{children:[r("h3",{text:"Archive"}),r("p",{class:"atfb-hint",text:"Retire the form when its moment has passed. It stops accepting responses and leaves every list, and its entries and stats go with it — nothing is deleted, and restoring it brings all of it back exactly as it was."}),E("Archive this form",()=>void this.archiveCurrentForm(),"secondary","archive")]}),r("section",{children:[r("h3",{text:"Delete"}),r("p",{class:"atfb-hint",text:"Deleting is for a form that should never have existed. It moves to the desktop’s Trash, disappears from every list, and any page still carrying its shortcode shows nothing at all. Its entries stay in Entries, and until the Trash is emptied you can bring it back from there. If the form simply had its day, archive it instead."}),E("Delete this form",()=>void this.deleteCurrentForm(),"danger","trash")]})]})}async archiveCurrentForm(){if(!this.form)return;const e=this.form.title||"(untitled)",t=this.forms.find(a=>a.id===this.form.id)?.entries??0;if(await ie(`Archive “${e}”? It stops accepting responses and leaves every list — its ${t} ${t===1?"entry":"entries"} and its stats go with it. Nothing is deleted: restore it any time from “Start a new form”.`,"Archive form"))try{this.dirty&&await this.save(!0),await I.archiveForm(this.form.id),N("Form archived",`${e} — restore it any time from the New form dialog.`),await this.releaseCurrentForm()}catch(a){N("Could not archive the form",a instanceof Error?a.message:"","error")}}async deleteCurrentForm(){if(!this.form)return;const e=this.form.title||"(untitled)",t=this.forms.find(a=>a.id===this.form.id)?.entries??0;if(await ie(`Delete “${e}”? Every page showing it goes blank. ${t?`Its ${t} ${t===1?"entry stays":"entries stay"} in Entries. `:""}It moves to the desktop’s Trash — restore it from there if you change your mind.`,"Delete form"))try{const a=this.form.id;await I.deleteForm(a),window.wp?.os?.announceContentChange?.("alltfo_form","trashed",a,"allterrain-forms"),N("Form deleted",`${e} moved to the desktop’s Trash.`),await this.releaseCurrentForm()}catch(a){N("Could not delete the form",a instanceof Error?a.message:"","error")}}async releaseCurrentForm(){if(this.forms=this.forms.filter(e=>e.id!==this.form.id),this.form=null,this.schema=null,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.forms.length){await this.open(this.forms[0].id);return}this.renderBar(),this.renderCanvas(),this.renderInspector()}taggableInput(e,t,s=""){return ut(A(e,t,s),{formId:this.form.id})}taggableArea(e,t,s=6){return ut(pe(e,t,s),{formId:this.form.id})}recipientControl(e){const t=this.schema.fields.filter(c=>c.type==="email"),s=c=>{if(c.trim()==="{admin_email}")return"admin";const d=c.trim().match(/^\{field:([a-z0-9_-]+)\}$/i);return d&&t.some(h=>h.id===d[1])?`field:${d[1]}`:/\{/.test(c)?"custom":"address"},a=[{value:"admin",label:"Whoever runs this site"},...t.map(c=>({value:`field:${c.id}`,label:`The person who filled it in — ${c.label||"their email answer"}`})),{value:"address",label:"A specific email address"},{value:"custom",label:"Something else (advanced)"}],i=s(e.to),o=r("div",{class:"atfb-recipient__detail"}),l=c=>{if(o.replaceChildren(),c==="address"){o.append(A(/\{/.test(e.to)?"":e.to,d=>{e.to=d,this.markDirty()},"name@example.com"));return}c==="custom"&&o.append(this.taggableInput(e.to,d=>{e.to=d,this.markDirty()},"{admin_email}, sales@example.com"),r("p",{class:"atfb-row__hint",text:"Separate several addresses with commas."}))};return l(i),g("Send it to",r("div",{class:"atfb-recipient",children:[D(i,a,c=>{c==="admin"?e.to="{admin_email}":c.startsWith("field:")?e.to=`{${c}}`:c==="address"&&(e.to=/\{/.test(e.to)?"":e.to),this.markDirty(),l(c)}),o]}),t.length?void 0:"Add an Email question on the Build tab to reply straight back to the visitor.")}renderNotificationsPane(){const e=this.schema.notifications,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, one email goes to the site administrator with every answer in it."})),e.forEach((s,a)=>{t.append(this.section(`notification:${s.id}`,s.name||`Notification ${a+1}`,[g("Name",A(s.name,i=>{s.name=i,this.markDirty()})),this.recipientControl(s),g("Reply to",this.taggableInput(s.replyTo,i=>{s.replyTo=i,this.markDirty()},"Leave empty to reply to you"),"Set this to the visitor’s email address and hitting Reply answers them directly."),g("Subject",this.taggableInput(s.subject,i=>{s.subject=i,this.markDirty()})),g("Message",this.taggableArea(s.message,i=>{s.message=i,this.markDirty()},8)),O("Attach uploaded files",s.attachFiles,i=>{s.attachFiles=i,this.markDirty()}),this.conditionsSection(s.id,"notification",s.logic),E("Delete this notification",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Notifications"}),t,E("Add a notification",()=>{e.push({id:this.nextEntryId("n",e),enabled:!0,name:"Notification",to:"{admin_email}",cc:"",bcc:"",replyTo:"",fromName:"",fromEmail:"",subject:"New submission",message:"{all_fields}",attachFiles:!1,logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}confirmationDetail(e){if(e.type==="message")return r("div",{children:[g("Message",this.taggableArea(e.message,i=>{e.message=i,this.markDirty()},5),"Insert an answer to greet them by name, or show back what they sent."),this.successDesigner(e)]});const t=g("Extra query parameters",this.taggableInput(e.query,i=>{e.query=i,this.markDirty()},"ref={entry:id}&name={field:f1}"),"Added to the address, so the page they land on can read them. Leave empty for none.");if(e.type==="redirect")return r("div",{children:[g("Web address",this.taggableInput(e.url,i=>{e.url=i,this.markDirty()},"https://example.com/thank-you"),"A full address, starting with https://."),t]});const s=r("div",{class:"atfb-pagepicker"}),a=i=>{s.replaceChildren(D(String(e.pageId||0),i,o=>{e.pageId=Number(o)||0,this.markDirty()}))};return a([{value:"0",label:"Loading pages…"}]),I.pages().then(i=>{a([{value:"0",label:"Choose a page…"},...i.map(o=>({value:String(o.id),label:o.title}))])}).catch(()=>{a([{value:"0",label:"Could not load the pages"}])}),g("Page",s,"They are sent to this page after submitting. Its own content is shown, not the form’s message.")}successDesigner(e){e.success=We(e.success);const t=e.success,s=r("div",{class:"atfb-success"}),a=[{key:"plain",label:"Plain",glyph:"¶",blurb:"Just the message."},{key:"simple",label:"Simple",glyph:"✓",blurb:"Check mark and a gentle fade."},{key:"minimal",label:"Minimalistic",glyph:"—",blurb:"Quiet type, generous space."},{key:"card",label:"Card",glyph:"🎫",blurb:"An elevated card that pops in."},{key:"check",label:"Check mark",glyph:"✔",blurb:"A big check draws itself."},{key:"confetti",label:"Confetti",glyph:"🎉",blurb:"Paper rains over the page."},{key:"fireworks",label:"Fireworks",glyph:"🎆",blurb:"The full night-sky show."},{key:"sparkles",label:"Sparkles",glyph:"✨",blurb:"Your emoji floats up around it."},{key:"typewriter",label:"Typewriter",glyph:"⌨",blurb:"Types itself out, letter by letter."}],i=()=>{const o=r("div",{class:"atfb-success__styles",attrs:{role:"radiogroup","aria-label":"Success screen style"},children:a.map(c=>r("button",{class:`atfb-success__style${t.style===c.key?" is-selected":""}`,type:"button",attrs:{role:"radio","aria-checked":t.style===c.key?"true":"false",title:c.blurb},children:[r("span",{class:"atfb-success__style-glyph",text:c.glyph}),r("span",{class:"atfb-success__style-label",text:c.label})],on:{click:()=>{t.style=c.key,this.markDirty(),i(),c.key!=="plain"&&this.previewSuccessScreen(e)}}}))}),l=[];t.style!=="plain"&&(l.push(g("Heading",this.taggableInput(t.title,c=>{t.title=c,this.markDirty()},"Thank you, {field:name}!"),"Shown above the message. Leave empty for none.")),["simple","card","confetti","fireworks","sparkles"].includes(t.style)&&l.push(g("Emoji",A(t.icon,c=>{t.icon=c,this.markDirty()},ve[t.style]||"🎉"),t.style==="sparkles"?"Also the particle that floats up — try 🎈 or ❤️.":"The badge above the heading.")),l.push(this.successAccentRow(t)),["confetti","fireworks","sparkles"].includes(t.style)&&l.push(g("Intensity",D(t.intensity,[{value:"low",label:"Calm"},{value:"medium",label:"Festive"},{value:"high",label:"Over the top"}],c=>{t.intensity=c,this.markDirty()}))),l.push(O("Offer to fill it in again",t.showButton,c=>{t.showButton=c,this.markDirty(),i()})),t.showButton&&l.push(g("Button label",A(t.buttonLabel,c=>{t.buttonLabel=c,this.markDirty()},"Fill it in again")))),s.replaceChildren(r("div",{class:"atfb-success__head",children:[r("h4",{text:"Success screen"}),E("Preview",()=>this.previewSuccessScreen(e),"ghost","controls-play")]}),o,...l)};return i(),s}successAccentRow(e){const t=r("input",{class:"atfb-success__accent",attrs:{type:"color","aria-label":"Accent colour"}});t.value=e.accent||"#3858e9";const s=E("Use the theme accent",()=>{e.accent="",t.value="#3858e9",s.style.display="none",this.markDirty()},"ghost");return s.style.display=e.accent?"":"none",t.addEventListener("input",()=>{e.accent=t.value,s.style.display="",this.markDirty()}),g("Accent",r("div",{class:"atfb-success__accent-row",children:[t,s]}),"Recolours the screen; the theme decides when left alone.")}previewSuccessScreen(e){const t=e.message||"Thank you. Your submission has been received.";let s=()=>{};const a=r("div",{class:"atfb-success-preview",attrs:{role:"dialog","aria-label":"Success screen preview","aria-modal":"true"}}),i=()=>{s(),a.remove(),document.removeEventListener("keydown",o)},o=h=>{h.key==="Escape"&&(h.stopPropagation(),i())},l=Zs(t,e.success,i),c=r("div",{class:"atfb-success-preview__stage atfb-preview atf-form",children:[l]}),d=()=>{s(),s=Ks(l,e.success)};a.append(c,r("div",{class:"atfb-success-preview__bar",children:[E("Replay",d,"secondary","controls-repeat"),E("Close",i,"primary")]})),a.addEventListener("click",h=>{h.target===a&&i()}),document.addEventListener("keydown",o),this.root.append(a),window.requestAnimationFrame(d)}renderConfirmationsPane(){const e=this.schema.confirmations,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, the form says thank you and stops."})),e.forEach((s,a)=>{const i=r("div",{class:"atfb-confirm__detail"}),o=()=>{i.replaceChildren(this.confirmationDetail(s))};o(),t.append(this.section(`confirmation:${s.id}`,s.name||`Confirmation ${a+1}`,[g("Name",A(s.name,l=>{s.name=l,this.markDirty()})),g("What happens",D(s.type,[{value:"message",label:"Show a message"},{value:"redirect",label:"Send them to a URL"},{value:"page",label:"Send them to a page"}],l=>{s.type=l,this.markDirty(),o()})),i,this.conditionsSection(s.id,"confirmation",s.logic),E("Delete this confirmation",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Confirmations"}),r("p",{class:"atfb-hint",text:"The first one whose conditions match is the one they see."}),t,E("Add a confirmation",()=>{e.push({id:this.nextEntryId("c",e),enabled:!0,name:"Confirmation",type:"message",message:"Thank you. Your submission has been received.",url:"",pageId:0,query:"",success:yt(),logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}async preview(){await Ot({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)})}}let ae=null,Ve=null;document.addEventListener("alltfo-open-form",n=>{const e=Number(n.detail?.formId??0);e&&ae?.openFormById(e)});function Je(){if(Ve?.isConnected)return;ae&&(ae.destroy(),ae=null,Ve=null);const n=document.querySelector("[data-atfb-root]:not([data-atfb-mounted])");n&&(n.dataset.atfbMounted="1",Ve=n,Te(n),ss().then(()=>{n.isConnected&&(ae=new Wt(n),ae.start())}))}function Ut(){Je(),ds()}return hs(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ut):Ut(),document.addEventListener("os-window-content-loaded",Je),ee.Builder=Wt,ee.SETTINGS_HANDLED_ELSEWHERE=Fn,ee.SETTING_CONTROLS=Rt,ee.fieldMove=jt,ee.mountBuilder=Je,ee.restatement=Ht,Object.defineProperty(ee,Symbol.toStringTag,{value:"Module"}),ee}({}); +}`,this.canvasTheme.isConnected||this.root.append(this.canvasTheme)}catch{}}}async previewHtml(e,t){if(!this.form||!this.schema)return"";const s=JSON.parse(JSON.stringify(this.schema));s.settings.theme=e,s.settings.themeOverrides=t;const{html:a}=await F.preview(this.form.id,{schema:s,theme:e});return a}renderSettingsPane(){const e=this.schema.settings,t=(s,a)=>{const i=s.split(".");let o=e;for(let l=0;lt("submitLabel",s))),O("Submit without reloading the page",e.ajax,s=>t("ajax",s)),y("Progress indicator",D(e.progressBar,[{value:"steps",label:"Numbered steps"},{value:"bar",label:"A bar"},{value:"none",label:"None"}],s=>t("progressBar",s)),"Only shown on forms with a page break.")]}),r("section",{children:[r("h3",{text:"Who can fill this in"}),O("Only logged-in users",e.requireLogin,s=>t("requireLogin",s)),y("Message for everyone else",T(e.loginMessage,s=>t("loginMessage",s))),y("Open from",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.start,on:{input:s=>t("schedule.start",s.target.value)}})),y("Closes",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.end,on:{input:s=>t("schedule.end",s.target.value)}})),y("Message when closed",T(e.schedule.message,s=>t("schedule.message",s))),y("Stop after this many submissions",G(String(e.limit.total||""),s=>t("limit.total",Number(s)||0)),"0 means no limit."),y("Submissions per logged-in user",G(String(e.limit.perUser||""),s=>t("limit.perUser",Number(s)||0)))]}),r("section",{children:[r("h3",{text:"Spam"}),r("p",{class:"atfb-hint",text:"No captcha. Nothing here asks the visitor to prove anything."}),O("Honeypot field",e.spam.honeypot,s=>t("spam.honeypot",s)),y("Reject submissions faster than (seconds)",G(String(e.spam.timeTrap),s=>t("spam.timeTrap",Number(s)||0)),"A human cannot fill in a form in under a second. A script can."),y("Submissions allowed per hour, per address",G(String(e.spam.rateLimit),s=>t("spam.rateLimit",Number(s)||0))),y("Blocked words",pe(e.spam.blocklist,s=>t("spam.blocklist",s),4),"One per line."),O("Use Akismet when it is installed",e.spam.akismet,s=>t("spam.akismet",s)),O("Ask a simple sum before sending",e.spam.challenge,s=>t("spam.challenge",s)),r("p",{class:"atfb-hint",text:"Only for a form under sustained attack — it is the one check here that asks the visitor to do something. Still kinder than an image captcha: it is answerable by a screen reader, and it hands no data to anyone."})]}),r("section",{children:[r("h3",{text:"Storage and privacy"}),O("Keep entries",e.storage.entries,s=>t("storage.entries",s)),O("Record IP addresses",e.storage.ip,s=>t("storage.ip",s)),O("Anonymise recorded IP addresses",e.storage.anonymise,s=>t("storage.anonymise",s)),y("Delete entries after (days)",G(String(e.storage.retention||""),s=>t("storage.retention",Number(s)||0)),"0 keeps them forever. Anything else deletes automatically, every day.")]}),r("section",{children:[r("h3",{text:"Analytics"}),O("Count views and starts",e.analytics.enabled,s=>t("analytics.enabled",s)),O("Tally device, browser and system",e.analytics.tech,s=>t("analytics.tech",s)),r("p",{class:"atfb-hint",text:"Counters, never people: no cookie, no fingerprint, no per-visitor record — the tallies keep coarse classes like “phone” and “Chrome”, not the visitor’s user-agent string. Nothing here needs a consent banner. Turning the first switch off stops view and start counting entirely."})]}),r("section",{children:[r("h3",{text:"Save and continue later"}),O("Let people save a half-finished form",e.resume.enabled,s=>t("resume.enabled",s)),y("Keep a saved form for (days)",G(String(e.resume.days),s=>t("resume.days",Math.max(1,Number(s)||30)))),r("p",{class:"atfb-hint",text:"The link this creates is the only key to those answers — anyone holding it can read them. For genuinely sensitive questions, require login instead."})]}),r("section",{children:[r("h3",{text:"Archive"}),r("p",{class:"atfb-hint",text:"Retire the form when its moment has passed. It stops accepting responses and leaves every list, and its entries and stats go with it — nothing is deleted, and restoring it brings all of it back exactly as it was."}),$("Archive this form",()=>void this.archiveCurrentForm(),"secondary","archive")]}),r("section",{children:[r("h3",{text:"Delete"}),r("p",{class:"atfb-hint",text:"Deleting is for a form that should never have existed. It moves to the desktop’s Trash, disappears from every list, and any page still carrying its shortcode shows nothing at all. Its entries stay in Entries, and until the Trash is emptied you can bring it back from there. If the form simply had its day, archive it instead."}),$("Delete this form",()=>void this.deleteCurrentForm(),"danger","trash")]})]})}async archiveCurrentForm(){if(!this.form)return;const e=this.form.title||"(untitled)",t=this.forms.find(a=>a.id===this.form.id)?.entries??0;if(await ie(`Archive “${e}”? It stops accepting responses and leaves every list — its ${t} ${t===1?"entry":"entries"} and its stats go with it. Nothing is deleted: restore it any time from “Start a new form”.`,"Archive form"))try{this.dirty&&await this.save(!0),await F.archiveForm(this.form.id),N("Form archived",`${e} — restore it any time from the New form dialog.`),await this.releaseCurrentForm()}catch(a){N("Could not archive the form",a instanceof Error?a.message:"","error")}}async deleteCurrentForm(){if(!this.form)return;const e=this.form.title||"(untitled)",t=this.forms.find(a=>a.id===this.form.id)?.entries??0;if(await ie(`Delete “${e}”? Every page showing it goes blank. ${t?`Its ${t} ${t===1?"entry stays":"entries stay"} in Entries. `:""}It moves to the desktop’s Trash — restore it from there if you change your mind.`,"Delete form"))try{const a=this.form.id;await F.deleteForm(a),window.wp?.os?.announceContentChange?.("alltfo_form","trashed",a,"allterrain-forms"),N("Form deleted",`${e} moved to the desktop’s Trash.`),await this.releaseCurrentForm()}catch(a){N("Could not delete the form",a instanceof Error?a.message:"","error")}}async releaseCurrentForm(){if(this.forms=this.forms.filter(e=>e.id!==this.form.id),this.form=null,this.schema=null,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.forms.length){await this.open(this.forms[0].id);return}this.renderBar(),this.renderCanvas(),this.renderInspector()}taggableInput(e,t,s=""){return ut(T(e,t,s),{formId:this.form.id})}taggableArea(e,t,s=6){return ut(pe(e,t,s),{formId:this.form.id})}recipientControl(e){const t=this.schema.fields.filter(c=>c.type==="email"),s=c=>{if(c.trim()==="{admin_email}")return"admin";const d=c.trim().match(/^\{field:([a-z0-9_-]+)\}$/i);return d&&t.some(h=>h.id===d[1])?`field:${d[1]}`:/\{/.test(c)?"custom":"address"},a=[{value:"admin",label:"Whoever runs this site"},...t.map(c=>({value:`field:${c.id}`,label:`The person who filled it in — ${c.label||"their email answer"}`})),{value:"address",label:"A specific email address"},{value:"custom",label:"Something else (advanced)"}],i=s(e.to),o=r("div",{class:"atfb-recipient__detail"}),l=c=>{if(o.replaceChildren(),c==="address"){o.append(T(/\{/.test(e.to)?"":e.to,d=>{e.to=d,this.markDirty()},"name@example.com"));return}c==="custom"&&o.append(this.taggableInput(e.to,d=>{e.to=d,this.markDirty()},"{admin_email}, sales@example.com"),r("p",{class:"atfb-row__hint",text:"Separate several addresses with commas."}))};return l(i),y("Send it to",r("div",{class:"atfb-recipient",children:[D(i,a,c=>{c==="admin"?e.to="{admin_email}":c.startsWith("field:")?e.to=`{${c}}`:c==="address"&&(e.to=/\{/.test(e.to)?"":e.to),this.markDirty(),l(c)}),o]}),t.length?void 0:"Add an Email question on the Build tab to reply straight back to the visitor.")}renderNotificationsPane(){const e=this.schema.notifications,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, one email goes to the site administrator with every answer in it."})),e.forEach((s,a)=>{t.append(this.section(`notification:${s.id}`,s.name||`Notification ${a+1}`,[y("Name",T(s.name,i=>{s.name=i,this.markDirty()})),this.recipientControl(s),y("Reply to",this.taggableInput(s.replyTo,i=>{s.replyTo=i,this.markDirty()},"Leave empty to reply to you"),"Set this to the visitor’s email address and hitting Reply answers them directly."),y("Subject",this.taggableInput(s.subject,i=>{s.subject=i,this.markDirty()})),y("Message",this.taggableArea(s.message,i=>{s.message=i,this.markDirty()},8)),O("Attach uploaded files",s.attachFiles,i=>{s.attachFiles=i,this.markDirty()}),this.conditionsSection(s.id,"notification",s.logic),$("Delete this notification",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Notifications"}),t,$("Add a notification",()=>{e.push({id:this.nextEntryId("n",e),enabled:!0,name:"Notification",to:"{admin_email}",cc:"",bcc:"",replyTo:"",fromName:"",fromEmail:"",subject:"New submission",message:"{all_fields}",attachFiles:!1,logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}confirmationDetail(e){if(e.type==="message")return r("div",{children:[y("Message",this.taggableArea(e.message,i=>{e.message=i,this.markDirty()},5),"Insert an answer to greet them by name, or show back what they sent."),this.successDesigner(e)]});const t=y("Extra query parameters",this.taggableInput(e.query,i=>{e.query=i,this.markDirty()},"ref={entry:id}&name={field:f1}"),"Added to the address, so the page they land on can read them. Leave empty for none.");if(e.type==="redirect")return r("div",{children:[y("Web address",this.taggableInput(e.url,i=>{e.url=i,this.markDirty()},"https://example.com/thank-you"),"A full address, starting with https://."),t]});const s=r("div",{class:"atfb-pagepicker"}),a=i=>{s.replaceChildren(D(String(e.pageId||0),i,o=>{e.pageId=Number(o)||0,this.markDirty()}))};return a([{value:"0",label:"Loading pages…"}]),F.pages().then(i=>{a([{value:"0",label:"Choose a page…"},...i.map(o=>({value:String(o.id),label:o.title}))])}).catch(()=>{a([{value:"0",label:"Could not load the pages"}])}),y("Page",s,"They are sent to this page after submitting. Its own content is shown, not the form’s message.")}successDesigner(e){e.success=je(e.success);const t=e.success,s=r("div",{class:"atfb-success"}),a=[{key:"plain",label:"Plain",glyph:"¶",blurb:"Just the message."},{key:"simple",label:"Simple",glyph:"✓",blurb:"Check mark and a gentle fade."},{key:"minimal",label:"Minimalistic",glyph:"—",blurb:"Quiet type, generous space."},{key:"card",label:"Card",glyph:"🎫",blurb:"An elevated card that pops in."},{key:"check",label:"Check mark",glyph:"✔",blurb:"A big check draws itself."},{key:"confetti",label:"Confetti",glyph:"🎉",blurb:"Paper rains over the page."},{key:"fireworks",label:"Fireworks",glyph:"🎆",blurb:"The full night-sky show."},{key:"sparkles",label:"Sparkles",glyph:"✨",blurb:"Your emoji floats up around it."},{key:"typewriter",label:"Typewriter",glyph:"⌨",blurb:"Types itself out, letter by letter."}],i=()=>{const o=r("div",{class:"atfb-success__styles",attrs:{role:"radiogroup","aria-label":"Success screen style"},children:a.map(c=>r("button",{class:`atfb-success__style${t.style===c.key?" is-selected":""}`,type:"button",attrs:{role:"radio","aria-checked":t.style===c.key?"true":"false",title:c.blurb},children:[r("span",{class:"atfb-success__style-glyph",text:c.glyph}),r("span",{class:"atfb-success__style-label",text:c.label})],on:{click:()=>{t.style=c.key,this.markDirty(),i(),c.key!=="plain"&&this.previewSuccessScreen(e)}}}))}),l=[];t.style!=="plain"&&(l.push(y("Heading",this.taggableInput(t.title,c=>{t.title=c,this.markDirty()},"Thank you, {field:name}!"),"Shown above the message. Leave empty for none.")),["simple","card","confetti","fireworks","sparkles"].includes(t.style)&&l.push(y("Emoji",T(t.icon,c=>{t.icon=c,this.markDirty()},ve[t.style]||"🎉"),t.style==="sparkles"?"Also the particle that floats up — try 🎈 or ❤️.":"The badge above the heading.")),l.push(this.successAccentRow(t)),["confetti","fireworks","sparkles"].includes(t.style)&&l.push(y("Intensity",D(t.intensity,[{value:"low",label:"Calm"},{value:"medium",label:"Festive"},{value:"high",label:"Over the top"}],c=>{t.intensity=c,this.markDirty()}))),l.push(O("Offer to fill it in again",t.showButton,c=>{t.showButton=c,this.markDirty(),i()})),t.showButton&&l.push(y("Button label",T(t.buttonLabel,c=>{t.buttonLabel=c,this.markDirty()},"Fill it in again")))),s.replaceChildren(r("div",{class:"atfb-success__head",children:[r("h4",{text:"Success screen"}),$("Preview",()=>this.previewSuccessScreen(e),"ghost","controls-play")]}),o,...l)};return i(),s}successAccentRow(e){const t=r("input",{class:"atfb-success__accent",attrs:{type:"color","aria-label":"Accent colour"}});t.value=e.accent||"#3858e9";const s=$("Use the theme accent",()=>{e.accent="",t.value="#3858e9",s.style.display="none",this.markDirty()},"ghost");return s.style.display=e.accent?"":"none",t.addEventListener("input",()=>{e.accent=t.value,s.style.display="",this.markDirty()}),y("Accent",r("div",{class:"atfb-success__accent-row",children:[t,s]}),"Recolours the screen; the theme decides when left alone.")}previewSuccessScreen(e){const t=e.message||"Thank you. Your submission has been received.";let s=()=>{};const a=r("div",{class:"atfb-success-preview",attrs:{role:"dialog","aria-label":"Success screen preview","aria-modal":"true"}}),i=()=>{s(),a.remove(),document.removeEventListener("keydown",o)},o=h=>{h.key==="Escape"&&(h.stopPropagation(),i())},l=Zs(t,e.success,i),c=r("div",{class:"atfb-success-preview__stage atfb-preview atf-form",children:[l]}),d=()=>{s(),s=Ks(l,e.success)};a.append(c,r("div",{class:"atfb-success-preview__bar",children:[$("Replay",d,"secondary","controls-repeat"),$("Close",i,"primary")]})),a.addEventListener("click",h=>{h.target===a&&i()}),document.addEventListener("keydown",o),this.root.append(a),window.requestAnimationFrame(d)}renderConfirmationsPane(){const e=this.schema.confirmations,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, the form says thank you and stops."})),e.forEach((s,a)=>{const i=r("div",{class:"atfb-confirm__detail"}),o=()=>{i.replaceChildren(this.confirmationDetail(s))};o(),t.append(this.section(`confirmation:${s.id}`,s.name||`Confirmation ${a+1}`,[y("Name",T(s.name,l=>{s.name=l,this.markDirty()})),y("What happens",D(s.type,[{value:"message",label:"Show a message"},{value:"redirect",label:"Send them to a URL"},{value:"page",label:"Send them to a page"}],l=>{s.type=l,this.markDirty(),o()})),i,this.conditionsSection(s.id,"confirmation",s.logic),$("Delete this confirmation",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Confirmations"}),r("p",{class:"atfb-hint",text:"The first one whose conditions match is the one they see."}),t,$("Add a confirmation",()=>{e.push({id:this.nextEntryId("c",e),enabled:!0,name:"Confirmation",type:"message",message:"Thank you. Your submission has been received.",url:"",pageId:0,query:"",success:yt(),logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}async preview(){await Ot({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)})}}let ae=null,Ke=null;document.addEventListener("alltfo-open-form",n=>{const e=Number(n.detail?.formId??0);e&&ae?.openFormById(e)});function Ve(){if(Ke?.isConnected)return;ae&&(ae.destroy(),ae=null,Ke=null);const n=document.querySelector("[data-atfb-root]:not([data-atfb-mounted])");n&&(n.dataset.atfbMounted="1",Ke=n,Ae(n),ns().then(()=>{n.isConnected&&(ae=new Wt(n),ae.start())}))}function Ut(){Ve(),hs()}return us(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ut):Ut(),document.addEventListener("os-window-content-loaded",Ve),ee.Builder=Wt,ee.SETTINGS_HANDLED_ELSEWHERE=In,ee.SETTING_CONTROLS=Pt,ee.fieldMove=jt,ee.mountBuilder=Ve,ee.restatement=Ht,Object.defineProperty(ee,Symbol.toStringTag,{value:"Module"}),ee}({}); diff --git a/assets/js/entries.js b/assets/js/entries.js index 1488522..b5e1f59 100644 --- a/assets/js/entries.js +++ b/assets/js/entries.js @@ -141,6 +141,11 @@ var allTerrainFormsEntries = function(exports) { this.active = null; this.lastEndMs = Date.now(); }; + const emit = (name, at) => { + document.dispatchEvent( + new CustomEvent(name, { detail: { payload, clientX: at?.clientX, clientY: at?.clientY } }) + ); + }; const session = { payload, isFinished: () => finished, @@ -150,6 +155,9 @@ var allTerrainFormsEntries = function(exports) { } finished = true; cleanup(); + if (lifted) { + emit("os.drag.end"); + } opts.onCancel?.(reason); } }; @@ -165,6 +173,7 @@ var allTerrainFormsEntries = function(exports) { ghost.style.width = `${rect.width}px`; document.body.appendChild(ghost); position(event); + emit("os.drag.start", event); }; const position = (event) => { if (ghost) { @@ -188,6 +197,7 @@ var allTerrainFormsEntries = function(exports) { hovered = next; hovered?.onEnter?.(session); } + emit("os.drag.move", event); }; const onUp = (event) => { if (finished) { @@ -205,8 +215,10 @@ var allTerrainFormsEntries = function(exports) { if (target && target.accept(payload)) { opts.onCommit?.(target); void target.onDrop(session, { clientX: event.clientX, clientY: event.clientY }); + emit("os.drag.end", event); return; } + emit("os.drag.end", event); opts.onCancel?.(target ? "rejected" : "no-target"); }; const onCancel = () => session.cancel("pointercancel"); @@ -303,11 +315,14 @@ var allTerrainFormsEntries = function(exports) { const payload = event.detail?.payload; return payload && payloadTypes.includes(payload.type) ? payload.source : null; }; + const preventSelection = (event) => event.preventDefault(); const onStart = (event) => { const source = sourceOf(event); if (source) { source.classList.add("atf-is-dragging"); document.body.classList.add("atf-drag-active"); + window.getSelection()?.removeAllRanges(); + document.addEventListener("selectstart", preventSelection); } }; const onEnd = (event) => { @@ -315,6 +330,7 @@ var allTerrainFormsEntries = function(exports) { if (source) { source.classList.remove("atf-is-dragging"); document.body.classList.remove("atf-drag-active"); + document.removeEventListener("selectstart", preventSelection); } }; document.addEventListener("os.drag.start", onStart); @@ -322,10 +338,23 @@ var allTerrainFormsEntries = function(exports) { return () => { document.removeEventListener("os.drag.start", onStart); document.removeEventListener("os.drag.end", onEnd); + document.removeEventListener("selectstart", preventSelection); }; } + const SCOPE_CLASSES = ["atfb", "atfe", "atfs", "atfm"]; function buildPayload(type, source, data, origin, ghost) { const rect = source.getBoundingClientRect(); + if (!ghost) { + const scope = SCOPE_CLASSES.find((cls) => source.closest(`.${cls}`)); + if (scope) { + const clone = source.cloneNode(true); + clone.style.transition = ""; + clone.style.transform = ""; + ghost = document.createElement("div"); + ghost.className = `${scope} atf-ghost-scope`; + ghost.appendChild(clone); + } + } if (ghost) { ghost.style.width = `${Math.round(rect.width)}px`; ghost.style.maxWidth = `${Math.round(rect.width)}px`; diff --git a/assets/js/entries.min.js b/assets/js/entries.min.js index 8bc5df3..c74d348 100644 --- a/assets/js/entries.min.js +++ b/assets/js/entries.min.js @@ -1 +1 @@ -var allTerrainFormsEntries=function(I){"use strict";function N(){const e=[window];try{window.parent&&window.parent!==window&&e.push(window.parent)}catch{}return e}function nt(e){const t=e.wp?.os?.windowManager?.getAll?.()??[];for(const s of t){const n=s.iframe??s.element?.querySelector?.("iframe");if(n&&n.contentWindow===window)return s}return null}const rt=4e3,it=100;function ot(e,t){const s=Date.now()+rt,n=()=>{const r=nt(e);if(r&&r.id!==t){typeof r.close=="function"?r.close():e.wp?.os?.windowManager?.remove?.(r.id);return}!r&&Date.now()0?{form:s}:void 0;s>0&&ct(s);for(const r of N())if(r.wp?.os?.openWindow?.(t,{source:"handoff",params:n})){window.setTimeout(()=>ot(r,t),0);return}}function lt(){document.addEventListener("click",e=>{const t=e.target?.closest?.("[data-atf-open-window]");if(!t)return;e.preventDefault();const s=t.getAttribute("data-atf-open-window")??"";for(const n of N())if(n.wp?.os?.openWindow?.(s,{source:"handoff"}))return})}const A="allterrain-forms/requested-form";function ct(e){try{window.sessionStorage.setItem(A,String(e))}catch{}}function U(e){return`allterrain-forms/requested-form-${e}`}function dt(e){try{const t=window.sessionStorage.getItem(U(e));return window.sessionStorage.removeItem(U(e)),Number(t)||0}catch{return 0}}function ut(){try{const e=window.sessionStorage.getItem(A);return window.sessionStorage.removeItem(A),Number(e)||0}catch{return 0}}const ft=4,ht=500;class mt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(t){if(this.active||t.origin.button!==0)return null;const{payload:s,origin:n}=t,r=n.clientX,i=n.clientY;let a=!1,l=!1,d=null,p=null,V=0,Q=0;const P=()=>{document.removeEventListener("pointermove",tt),document.removeEventListener("pointerup",et),document.removeEventListener("pointercancel",T),document.removeEventListener("keydown",st),window.removeEventListener("blur",T),d?.remove(),d=null,s.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),p?.onLeave?.(b),p=null,this.active=null,this.lastEndMs=Date.now()},b={payload:s,isFinished:()=>l,cancel:(c="caller")=>{l||(l=!0,P(),t.onCancel?.(c))}},qt=c=>{a=!0,s.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const f=s.source.getBoundingClientRect();V=s.ghost?.offsetX??r-f.left,Q=s.ghost?.offsetY??i-f.top,d=s.ghost?.element??s.source.cloneNode(!0),d.classList.add("atf-drag-ghost"),d.style.width=`${f.width}px`,document.body.appendChild(d),Z(c)},Z=c=>{d&&(d.style.transform=`translate3d(${c.clientX-V}px, ${c.clientY-Q}px, 0)`)},tt=c=>{if(l)return;if(!a){if(Math.hypot(c.clientX-r,c.clientY-i){if(l)return;if(!a){l=!0,P(),t.onClickOnly?.();return}const f=p;if(l=!0,P(),f&&f.accept(s)){t.onCommit?.(f),f.onDrop(b,{clientX:c.clientX,clientY:c.clientY});return}t.onCancel?.(f?"rejected":"no-target")},T=()=>b.cancel("pointercancel"),st=c=>{c.key==="Escape"&&b.cancel("escape")};return document.addEventListener("pointermove",tt),document.addEventListener("pointerup",et),document.addEventListener("pointercancel",T),document.addEventListener("keydown",st),window.addEventListener("blur",T),this.active=b,b}registerDropTarget(t){return this.targets=this.targets.filter(s=>s.id!==t.id),this.targets.push(t),()=>{this.targets=this.targets.filter(s=>s.id!==t.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(t=ht){return Date.now()-this.lastEndMsa.right||sa.bottom)continue;const l=pt(i.element);if(l>r){n=i,r=l;continue}l===r&&n&&wt(i.element,n.element)&&(n=i)}return n}}function pt(e){let t=0,s=e;for(;s;)t++,s=s.parentElement;return t}function wt(e,t){return(t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function D(){return window.wp?.os??null}let O=null;function j(){const e=D();return e?.dragManager?e.dragManager:(O||(O=new mt),O)}function gt(e){const t=r=>{const i=r.detail?.payload;return i&&e.includes(i.type)?i.source:null},s=r=>{const i=t(r);i&&(i.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"))},n=r=>{const i=t(r);i&&(i.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"))};return document.addEventListener("os.drag.start",s),document.addEventListener("os.drag.end",n),()=>{document.removeEventListener("os.drag.start",s),document.removeEventListener("os.drag.end",n)}}function bt(e,t,s,n,r){const i=t.getBoundingClientRect();return r&&(r.style.width=`${Math.round(i.width)}px`,r.style.maxWidth=`${Math.round(i.width)}px`,r.style.boxSizing="border-box"),{type:e,source:t,data:s,ghost:{element:r,offsetX:n.clientX-i.left,offsetY:n.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}const h=window.allTerrainForms;class S extends Error{constructor(t,s,n=""){super(t),this.name="ApiError",this.status=s,this.code=n}}function B(e,t){return e.includes("?")?`${e}${t.replace("?","&")}`:`${e}${t}`}async function C(e,t={}){if(!h?.restUrl)throw new S("AllTerrain Forms is not configured on this page.",0);const s=B(h.restUrl,e),n={"Content-Type":"application/json",...t.headers??{}};h.nonce&&(n["X-WP-Nonce"]=h.nonce);const r=D(),a=await(r?.fetch?(l,d)=>r.fetch(l,d,{source:"allterrain-forms"}):(l,d)=>fetch(l,d))(s,{credentials:"same-origin",...t,headers:n});if(!a.ok){let l=`Request failed with status ${a.status}.`,d="";try{const p=await a.json();l=p.message??l,d=p.code??""}catch{}throw new S(l,a.status,d)}if(a.status!==204)return await a.json()}const u=e=>C(e);async function vt(e){if(!h?.wpRestUrl)throw new S("AllTerrain Forms is not configured on this page.",0);const t=h.nonce?{"X-WP-Nonce":h.nonce}:{},s=D(),n=B(h.wpRestUrl,e),r=s?.fetch?await s.fetch(n,{credentials:"same-origin",headers:t},{source:"allterrain-forms"}):await fetch(n,{credentials:"same-origin",headers:t});if(!r.ok)throw new S(`Request failed with status ${r.status}.`,r.status);return await r.json()}function yt(e){if(!e||!e.includes("&"))return e;const t=document.createElement("textarea");return t.innerHTML=e,t.value}const w=(e,t)=>C(e,{method:"POST",body:JSON.stringify(t)}),L=e=>C(e,{method:"DELETE"});function Y(e){const t=new URLSearchParams;for(const[n,r]of Object.entries(e))r===void 0||r===""||r===!1||t.set(n,String(r));const s=t.toString();return s?`?${s}`:""}function $(e){const t=e?.schema?.settings;return t&&(!t.themeOverrides||Array.isArray(t.themeOverrides))&&(t.themeOverrides={...t.themeOverrides}),e}const g={config:()=>u("/config"),mailpoet:()=>u("/mailpoet"),listForms:()=>u("/forms"),listArchivedForms:()=>u("/forms?archived=1"),archiveForm:e=>w(`/forms/${e}/archive`,{}),unarchiveForm:e=>w(`/forms/${e}/unarchive`,{}),getForm:e=>u(`/forms/${e}`).then($),createForm:e=>w("/forms",e).then($),updateForm:(e,t)=>w(`/forms/${e}`,t).then($),duplicateForm:e=>w(`/forms/${e}/duplicate`,{}).then($),deleteForm:e=>L(`/forms/${e}`),preview:(e,t)=>w(`/forms/${e}/preview`,t),pages:()=>vt("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(e=>e.map(t=>({id:t.id,title:yt(t.title?.rendered??"")||`#${t.id}`}))),mergeTags:e=>u(`/forms/${e}/merge-tags`).then(t=>t.groups),analytics:(e,t="")=>u(`/forms/${e}/analytics${t?`?dimension=${encodeURIComponent(t)}`:""}`),demoStatus:()=>u("/demo"),demoSeed:e=>w("/demo",e?{count:e}:{}),demoRemove:()=>L("/demo"),listEntries:e=>u(`/entries${Y(e)}`),getEntry:e=>u(`/entries/${e}`),updateEntry:(e,t)=>w(`/entries/${e}`,t),deleteEntry:e=>L(`/entries/${e}`),exportEntries:e=>u(`/entries/export${Y(e)}`),listThemes:()=>u("/themes"),saveTheme:e=>w("/themes",e),deleteTheme:e=>L(`/themes/${e}`)};function o(e,t={}){const s=document.createElement(e);t.class&&(s.className=t.class),t.text!==void 0&&(s.textContent=t.text),t.html!==void 0&&(s.innerHTML=t.html),t.title&&(s.title=t.title),t.type&&"type"in s&&(s.type=t.type),t.value!==void 0&&"value"in s&&(s.value=t.value),t.placeholder!==void 0&&"placeholder"in s&&(s.placeholder=t.placeholder),t.href&&"href"in s&&(s.href=t.href);for(const[n,r]of Object.entries(t.attrs??{}))r===void 0||r===!1||s.setAttribute(n,r===!0?"":String(r));Object.assign(s.style,t.style??{});for(const[n,r]of Object.entries(t.on??{}))s.addEventListener(n,r);for(const n of t.children??[])n==null||n===!1||s.append(n);return s}function v(e){e.replaceChildren()}function M(e){return o("span",{class:`dashicons ${e.startsWith("dashicons-")?e:`dashicons-${e}`}`,attrs:{"aria-hidden":"true"}})}function Et(e,t,s=""){return o("input",{class:"atfb-input",type:"text",value:e,placeholder:s,on:{input:n=>t(n.target.value)}})}function W(e,t,s){if(x("os-select")&&x("os-option")){const n=document.createElement("os-select");n.setAttribute("value",e),n.classList.add("atfb-field");for(const r of t){const i=document.createElement("os-option");i.setAttribute("value",r.value),i.textContent=r.label,n.append(i)}return n.addEventListener("os-pick",r=>{s(String(r.detail?.value??""))}),n}return o("select",{class:"atfb-input atfb-select",on:{change:n=>s(n.target.value)},children:t.map(n=>o("option",{value:n.value,text:n.label,attrs:{selected:n.value===e}}))})}function St(e,t,s){if(x("os-checkbox-label")){const r=document.createElement("os-checkbox-label");return r.setAttribute("label",e),r.classList.add("atfb-check"),t&&r.setAttribute("checked",""),r.addEventListener("os-checkbox-change",i=>{s(!!i.detail?.checked)}),r}const n=o("input",{type:"checkbox",on:{change:r=>s(r.target.checked)}});return n.checked=t,o("label",{class:"atfb-check",children:[n,o("span",{text:e})]})}function m(e,t,s="secondary",n){const r=[n?M(n):null,o("span",{text:e})];if(x("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",s),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${s}`),i.addEventListener("click",t);for(const a of r)a&&i.append(a);return i}return o("button",{class:`atfb-button atfb-button--${s}`,type:"button",on:{click:t},children:r})}function x(e){return typeof customElements<"u"&&!!customElements.get(e)}const Lt=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let k=null;function $t(){if(k)return k;const e=window.wp?.os;return k=e?.loadComponents?e.loadComponents(Lt).catch(()=>{}):Promise.resolve(),k}async function X(e,t=""){const s=window.wp?.os;return s?.confirm?s.confirm({title:t,message:e,danger:!0}):window.confirm(e)}function E(e,t="",s="info"){const n=window.wp?.os;if(n?.notify){n.notify({title:e,body:t,type:s});return}console.info(`[AllTerrain Forms] ${e}${t?`: ${t}`:""}`)}function xt(e,t){let s=0;return(...n)=>{window.clearTimeout(s),s=window.setTimeout(()=>e(...n),t)}}function kt(e){const t=e.closest(".os-window__body");t&&(t.addEventListener("scroll",()=>{t.scrollTop&&(t.scrollTop=0),t.scrollLeft&&(t.scrollLeft=0)},{passive:!0}),t.scrollTop=0,t.scrollLeft=0)}const _t="allterrain-forms/form",Tt="allterrain-forms/entry";function It(){return window.wp?.os?.relations??null}function At(e){const t=e.closest("[data-window-id], .os-window");if(!t)return null;const s=t.getAttribute("data-window-id");if(s)return s;const n=t.id??"";return n?n.replace(/^wp-window-/,""):null}const Dt=6e3,H=120;function z(e,t){const s=It();if(q.set(e,t),!s?.set)return;const n=i=>{if(_.get(e)!==r)return;const a=At(e);if(!a){Date.now()n(i),H);return}try{s.set(a,t)}catch(d){G||(G=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",d,t)),_.delete(e);return}if(!t||s.get?.(a)?.id===t.id||Date.now()>=i){_.delete(e);return}window.setTimeout(()=>n(i),H)},r=Symbol("atf-identity");_.set(e,r),n(Date.now()+Dt)}let G=!1;const _=new WeakMap,q=new Map;function Ot(){for(const[e,t]of q){if(!e.isConnected){q.delete(e);continue}z(e,t)}}if(typeof document<"u")for(const e of["os-window-content-loaded","os-window-opened"])document.addEventListener(e,()=>Ot());function Ct(e,t){const s=[];e.userId&&s.push({type:"user",id:e.userId,rel:"references"});for(const r of e.fields)if(!(r.type!=="file"||!Array.isArray(r.value)))for(const i of r.value){const a=Number(i);a>0&&s.push({type:"media",id:a,rel:"child"})}const n=[{id:`allterrain-forms/form-${e.formId}`,label:e.formTitle||"The form",url:`${t}admin.php?page=allterrain-forms&form=${e.formId}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-feedback"}];return e.userId&&n.push({id:`allterrain-forms/user-${e.userId}`,label:"Who submitted it",url:`${t}user-edit.php?user_id=${e.userId}`,group:"users",groupLabel:"People",icon:"dashicons-admin-users"}),{type:Tt,id:e.id,root:{type:_t,id:e.formId},label:e.title||`Entry #${e.id}`,links:s.slice(0,32),related:n}}const K="allterrain-forms/entry";class Mt{constructor(t){this.forms=[],this.entries=[],this.selected=null,this.selection=new Set,this.paintedSelectionId=-1,this.loadSeq=0,this.selectSeq=0,this.formId=0,this.status="inbox",this.search="",this.starred=!1,this.page=1,this.pages=1,this.total=0,this.teardowns=[],this.root=t,this.bar=t.querySelector("[data-atfe-bar]")??o("div"),this.list=t.querySelector("[data-atfe-list]")??o("div"),this.detail=t.querySelector("[data-atfe-detail]")??o("div")}async start(){this.teardowns.push(gt([K]));try{this.forms=await g.listForms()}catch(n){v(this.bar),this.bar.append(o("p",{class:"atfb-error",text:n instanceof Error?n.message:"Could not load forms."}));return}const t=dt("entries")||ut();this.formId=(t&&this.forms.some(n=>n.id===t)?t:0)||(this.forms.find(n=>n.unread>0)??this.forms[0])?.id||0,this.renderBar(),await this.load();const s=window.wp?.os;s?.subscribe&&this.teardowns.push(s.subscribe("os.alltfo_entry.changed",()=>{if(!this.root.isConnected){this.destroy();return}this.load()}))}destroy(){this.teardowns.forEach(t=>t()),this.teardowns=[]}renderBar(){v(this.bar);const t=Et(this.search,xt(s=>{this.search=s,this.page=1,this.load()},300),"Search answers");t.type="search",t.setAttribute("aria-label","Search entries"),this.bar.append(W(String(this.formId),this.forms.map(s=>({value:String(s.id),label:s.unread?`${s.title} (${s.unread})`:s.title})),s=>{this.formId=Number(s),this.page=1,this.selection.clear(),this.selected=null,this.load()}),W(this.status,[{value:"inbox",label:"All"},{value:"alltfo-unread",label:"Unread"},{value:"alltfo-read",label:"Read"},{value:"alltfo-spam",label:"Spam"}],s=>{this.status=s,this.page=1,this.load()}),t,St("Starred only",this.starred,s=>{this.starred=s,this.page=1,this.load()}),o("span",{class:"atfe__count",attrs:{role:"status"},text:""}),m("Export CSV",()=>void this.exportEntries("csv"),"secondary","download"),m("JSON",()=>void this.exportEntries("json"),"secondary"))}async showForm(t){this.formId=t,this.page=1,this.selection.clear(),this.selected=null,this.renderBar(),await this.load()}async load(){if(!this.formId){v(this.list),this.list.append(o("p",{class:"atfb-hint",text:"No forms yet."}));return}const t=++this.loadSeq;try{const s=await g.listEntries({form_id:this.formId,status:this.status==="inbox"?void 0:this.status,search:this.search,page:this.page,starred:this.starred});if(t!==this.loadSeq)return;if(this.page>1&&this.page>s.pages)return this.page=Math.max(1,s.pages),this.load();this.entries=s.entries,this.total=s.total,this.pages=s.pages,this.renderList(),this.reconcileSelection();const n=this.bar.querySelector(".atfe__count");n&&(n.textContent=`${this.total} ${this.total===1?"entry":"entries"}`)}catch(s){if(t!==this.loadSeq)return;v(this.list),this.list.append(o("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load entries."}))}}reconcileSelection(){this.selected&&!this.entries.some(t=>t.id===this.selected?.id)&&(this.selected=null),this.paintedSelectionId!==(this.selected?.id??0)&&this.renderDetail()}renderList(){if(v(this.list),!this.entries.length){this.list.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:this.search?"Nothing matches that.":"No entries yet."})]}));return}const t=new Set(this.entries.map(n=>n.id));for(const n of Array.from(this.selection))t.has(n)||this.selection.delete(n);this.list.append(this.renderBulkBar());const s=o("div",{class:"atfe__rows",attrs:{role:"list"}});for(const n of this.entries)s.append(this.renderRow(n));this.list.append(s),this.pages>1&&this.list.append(o("div",{class:"atfe__pager",children:[m("Previous",()=>{this.page=Math.max(1,this.page-1),this.load()}),o("span",{text:`Page ${this.page} of ${this.pages}`}),m("Next",()=>{this.page=Math.min(this.pages,this.page+1),this.load()})]}))}renderBulkBar(){const t=this.selection.size,s=o("input",{type:"checkbox",attrs:{"aria-label":"Select every entry on this page"},on:{change:n=>{const r=n.target.checked;this.entries.forEach(i=>{r?this.selection.add(i.id):this.selection.delete(i.id)}),this.renderList()}}});return s.checked=t>0&&t===this.entries.length,s.indeterminate=t>0&&tvoid this.bulk("alltfo-read")):null,t?m("Unread",()=>void this.bulk("alltfo-unread")):null,t?m("Spam",()=>void this.bulk("alltfo-spam")):null,t&&h?.canEdit?m("Delete",()=>void this.bulkDelete(),"danger"):null]})}async bulk(t){const s=Array.from(this.selection);for(const n of s)try{await g.updateEntry(n,{status:t})}catch{}this.selection.clear(),await this.load()}async bulkDelete(){const t=Array.from(this.selection);if(await X(`Delete ${t.length} ${t.length===1?"entry":"entries"} and any files uploaded with them? It cannot be undone.`,"Delete entries")){for(const n of t)try{await g.deleteEntry(n)}catch{}this.selection.clear(),this.selected=null,await this.load(),this.renderDetail()}}renderRow(t){const s=t.status==="alltfo-unread",n=o("div",{class:`atfe__row${s?" is-unread":""}${this.selected?.id===t.id?" is-selected":""}`,attrs:{role:"listitem",tabindex:"0","data-entry":t.id},children:[o("input",{class:"atfe__select",type:"checkbox",attrs:{"aria-label":`Select ${t.title}`,checked:this.selection.has(t.id)},on:{click:r=>r.stopPropagation(),change:r=>{r.target.checked?this.selection.add(t.id):this.selection.delete(t.id),this.list.querySelector(".atfe__bulk")?.replaceWith(this.renderBulkBar())}}}),o("button",{class:`atfe__star${t.starred?" is-on":""}`,type:"button",attrs:{"aria-label":t.starred?"Unstar this entry":"Star this entry"},on:{click:r=>{r.stopPropagation(),this.toggleStar(t)}},children:[M("star-filled")]}),o("div",{class:"atfe__row-body",children:[o("strong",{text:t.title}),o("span",{class:"atfe__row-meta",text:t.dateHuman})]}),t.notes?o("span",{class:"atfb-badge",text:`💬 ${t.notes}`}):null,t.spam?o("span",{class:"atfb-badge atfb-badge--spam",text:"spam"}):null]});return n.addEventListener("click",()=>{j().recentlyEndedDrag()||this.select(t)}),n.addEventListener("keydown",r=>{(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),this.select(t))}),n.addEventListener("pointerdown",r=>{if(r.target.closest("button"))return;const i=o("div",{class:"atfe__ghost",children:[M("feedback"),o("span",{text:t.title})]});j().start({payload:bt(K,n,{entry:t,formId:t.formId,formTitle:t.formTitle},r,i),origin:r})}),n}async select(t){const s=++this.selectSeq;try{const n=await g.getEntry(t.id);if(s!==this.selectSeq)return;this.selected=n;const r=this.entries.find(i=>i.id===t.id);r&&(r.status=this.selected.status),this.renderList(),this.renderDetail()}catch(n){if(s!==this.selectSeq)return;E("Could not open that entry",n instanceof Error?n.message:"","error")}}renderDetail(){this.paintedSelectionId=this.selected?.id??0,z(this.root,this.selected?Ct(this.selected,h?.adminUrl??""):null),v(this.detail);const t=this.selected;if(!t){this.detail.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:"Pick an entry to read it."})]}));return}const s=o("dl",{class:"atfe__answers"});for(const n of t.fields)n.formatted&&s.append(o("dt",{text:n.label||n.id}),o("dd",{text:n.formatted}));this.detail.append(o("div",{class:"atfe__detail",children:[o("div",{class:"atfe__detail-head",children:[o("h2",{text:t.title}),o("p",{class:"atfb-hint",text:`${t.formTitle} — ${t.dateHuman}`})]}),s,t.quiz?o("p",{class:"atfe__quiz",text:`Score: ${t.quiz.score} of ${t.quiz.total} (${t.quiz.percent}%) — ${t.quiz.passed?"passed":"not passed"}`}):null,o("details",{class:"atfb-section",children:[o("summary",{text:"Where it came from"}),o("p",{class:"atfb-hint",text:t.ip?`IP: ${t.ip}`:"No IP recorded."}),t.referrer?o("p",{class:"atfb-hint",text:`Referrer: ${t.referrer}`}):null,t.userAgent?o("p",{class:"atfb-hint",text:t.userAgent}):null]}),o("div",{class:"atfe__actions",children:[m(t.status==="alltfo-spam"?"Not spam":"Mark as spam",()=>void this.setStatus(t,t.status==="alltfo-spam"?"alltfo-read":"alltfo-spam")),m(t.status==="alltfo-unread"?"Mark read":"Mark unread",()=>void this.setStatus(t,t.status==="alltfo-unread"?"alltfo-read":"alltfo-unread")),t.canDelete?m("Delete",()=>void this.remove(t),"danger"):null]})]}))}async toggleStar(t){try{const s=await g.updateEntry(t.id,{starred:!t.starred});t.starred=s.starred,this.renderList()}catch(s){E("Could not update that entry",s instanceof Error?s.message:"","error")}}async setStatus(t,s){try{const n=await g.updateEntry(t.id,{status:s});this.selected=n,await this.load(),this.renderDetail()}catch(n){E("Could not update that entry",n instanceof Error?n.message:"","error")}}async remove(t){if(await X("Delete this entry and any files uploaded with it? It cannot be undone.","Delete entry"))try{await g.deleteEntry(t.id),this.selected=null,await this.load(),this.renderDetail()}catch(s){E("Could not delete that entry",s instanceof Error?s.message:"","error")}}async exportEntries(t){try{const{filename:s,csv:n}=await g.exportEntries({form_id:this.formId,search:this.search,starred:this.starred,format:t}),r=new Blob([n],{type:t==="json"?"application/json":"text/csv;charset=utf-8"}),i=URL.createObjectURL(r),a=o("a",{href:i,attrs:{download:s}});document.body.append(a),a.click(),a.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),1e3)}catch(s){E("Could not export",s instanceof Error?s.message:"","error")}}}let y=null;document.addEventListener("alltfo-open-entries-form",e=>{const t=Number(e.detail?.formId??0);t&&y?.showForm(t)});let F=null;function R(){if(F?.isConnected)return;y&&(y.destroy(),y=null,F=null);const e=document.querySelector("[data-atfe-root]:not([data-atfe-mounted])");!e||!h?.canRead||(e.dataset.atfeMounted="1",F=e,kt(e),$t().then(()=>{e.isConnected&&(y=new Mt(e),y.start())}))}function J(){R(),at()}return lt(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",J):J(),document.addEventListener("os-window-content-loaded",R),I.mountEntries=R,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"}),I}({}); +var allTerrainFormsEntries=function(I){"use strict";function U(){const e=[window];try{window.parent&&window.parent!==window&&e.push(window.parent)}catch{}return e}function rt(e){const t=e.wp?.os?.windowManager?.getAll?.()??[];for(const s of t){const n=s.iframe??s.element?.querySelector?.("iframe");if(n&&n.contentWindow===window)return s}return null}const it=4e3,ot=100;function at(e,t){const s=Date.now()+it,n=()=>{const r=rt(e);if(r&&r.id!==t){typeof r.close=="function"?r.close():e.wp?.os?.windowManager?.remove?.(r.id);return}!r&&Date.now()0?{form:s}:void 0;s>0&&dt(s);for(const r of U())if(r.wp?.os?.openWindow?.(t,{source:"handoff",params:n})){window.setTimeout(()=>at(r,t),0);return}}function ct(){document.addEventListener("click",e=>{const t=e.target?.closest?.("[data-atf-open-window]");if(!t)return;e.preventDefault();const s=t.getAttribute("data-atf-open-window")??"";for(const n of U())if(n.wp?.os?.openWindow?.(s,{source:"handoff"}))return})}const D="allterrain-forms/requested-form";function dt(e){try{window.sessionStorage.setItem(D,String(e))}catch{}}function Y(e){return`allterrain-forms/requested-form-${e}`}function ut(e){try{const t=window.sessionStorage.getItem(Y(e));return window.sessionStorage.removeItem(Y(e)),Number(t)||0}catch{return 0}}function ft(){try{const e=window.sessionStorage.getItem(D);return window.sessionStorage.removeItem(D),Number(e)||0}catch{return 0}}const ht=4,mt=500;class pt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(t){if(this.active||t.origin.button!==0)return null;const{payload:s,origin:n}=t,r=n.clientX,i=n.clientY;let a=!1,l=!1,d=null,p=null,Q=0,Z=0;const N=()=>{document.removeEventListener("pointermove",et),document.removeEventListener("pointerup",st),document.removeEventListener("pointercancel",A),document.removeEventListener("keydown",nt),window.removeEventListener("blur",A),d?.remove(),d=null,s.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),p?.onLeave?.(v),p=null,this.active=null,this.lastEndMs=Date.now()},S=(c,u)=>{document.dispatchEvent(new CustomEvent(c,{detail:{payload:s,clientX:u?.clientX,clientY:u?.clientY}}))},v={payload:s,isFinished:()=>l,cancel:(c="caller")=>{l||(l=!0,N(),a&&S("os.drag.end"),t.onCancel?.(c))}},Ft=c=>{a=!0,s.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const u=s.source.getBoundingClientRect();Q=s.ghost?.offsetX??r-u.left,Z=s.ghost?.offsetY??i-u.top,d=s.ghost?.element??s.source.cloneNode(!0),d.classList.add("atf-drag-ghost"),d.style.width=`${u.width}px`,document.body.appendChild(d),tt(c),S("os.drag.start",c)},tt=c=>{d&&(d.style.transform=`translate3d(${c.clientX-Q}px, ${c.clientY-Z}px, 0)`)},et=c=>{if(l)return;if(!a){if(Math.hypot(c.clientX-r,c.clientY-i){if(l)return;if(!a){l=!0,N(),t.onClickOnly?.();return}const u=p;if(l=!0,N(),u&&u.accept(s)){t.onCommit?.(u),u.onDrop(v,{clientX:c.clientX,clientY:c.clientY}),S("os.drag.end",c);return}S("os.drag.end",c),t.onCancel?.(u?"rejected":"no-target")},A=()=>v.cancel("pointercancel"),nt=c=>{c.key==="Escape"&&v.cancel("escape")};return document.addEventListener("pointermove",et),document.addEventListener("pointerup",st),document.addEventListener("pointercancel",A),document.addEventListener("keydown",nt),window.addEventListener("blur",A),this.active=v,v}registerDropTarget(t){return this.targets=this.targets.filter(s=>s.id!==t.id),this.targets.push(t),()=>{this.targets=this.targets.filter(s=>s.id!==t.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(t=mt){return Date.now()-this.lastEndMsa.right||sa.bottom)continue;const l=wt(i.element);if(l>r){n=i,r=l;continue}l===r&&n&>(i.element,n.element)&&(n=i)}return n}}function wt(e){let t=0,s=e;for(;s;)t++,s=s.parentElement;return t}function gt(e,t){return(t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function C(){return window.wp?.os??null}let O=null;function j(){const e=C();return e?.dragManager?e.dragManager:(O||(O=new pt),O)}function vt(e){const t=i=>{const a=i.detail?.payload;return a&&e.includes(a.type)?a.source:null},s=i=>i.preventDefault(),n=i=>{const a=t(i);a&&(a.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"),window.getSelection()?.removeAllRanges(),document.addEventListener("selectstart",s))},r=i=>{const a=t(i);a&&(a.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),document.removeEventListener("selectstart",s))};return document.addEventListener("os.drag.start",n),document.addEventListener("os.drag.end",r),()=>{document.removeEventListener("os.drag.start",n),document.removeEventListener("os.drag.end",r),document.removeEventListener("selectstart",s)}}const bt=["atfb","atfe","atfs","atfm"];function yt(e,t,s,n,r){const i=t.getBoundingClientRect();if(!r){const a=bt.find(l=>t.closest(`.${l}`));if(a){const l=t.cloneNode(!0);l.style.transition="",l.style.transform="",r=document.createElement("div"),r.className=`${a} atf-ghost-scope`,r.appendChild(l)}}return r&&(r.style.width=`${Math.round(i.width)}px`,r.style.maxWidth=`${Math.round(i.width)}px`,r.style.boxSizing="border-box"),{type:e,source:t,data:s,ghost:{element:r,offsetX:n.clientX-i.left,offsetY:n.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}const h=window.allTerrainForms;class L extends Error{constructor(t,s,n=""){super(t),this.name="ApiError",this.status=s,this.code=n}}function B(e,t){return e.includes("?")?`${e}${t.replace("?","&")}`:`${e}${t}`}async function M(e,t={}){if(!h?.restUrl)throw new L("AllTerrain Forms is not configured on this page.",0);const s=B(h.restUrl,e),n={"Content-Type":"application/json",...t.headers??{}};h.nonce&&(n["X-WP-Nonce"]=h.nonce);const r=C(),a=await(r?.fetch?(l,d)=>r.fetch(l,d,{source:"allterrain-forms"}):(l,d)=>fetch(l,d))(s,{credentials:"same-origin",...t,headers:n});if(!a.ok){let l=`Request failed with status ${a.status}.`,d="";try{const p=await a.json();l=p.message??l,d=p.code??""}catch{}throw new L(l,a.status,d)}if(a.status!==204)return await a.json()}const f=e=>M(e);async function Et(e){if(!h?.wpRestUrl)throw new L("AllTerrain Forms is not configured on this page.",0);const t=h.nonce?{"X-WP-Nonce":h.nonce}:{},s=C(),n=B(h.wpRestUrl,e),r=s?.fetch?await s.fetch(n,{credentials:"same-origin",headers:t},{source:"allterrain-forms"}):await fetch(n,{credentials:"same-origin",headers:t});if(!r.ok)throw new L(`Request failed with status ${r.status}.`,r.status);return await r.json()}function St(e){if(!e||!e.includes("&"))return e;const t=document.createElement("textarea");return t.innerHTML=e,t.value}const w=(e,t)=>M(e,{method:"POST",body:JSON.stringify(t)}),$=e=>M(e,{method:"DELETE"});function W(e){const t=new URLSearchParams;for(const[n,r]of Object.entries(e))r===void 0||r===""||r===!1||t.set(n,String(r));const s=t.toString();return s?`?${s}`:""}function x(e){const t=e?.schema?.settings;return t&&(!t.themeOverrides||Array.isArray(t.themeOverrides))&&(t.themeOverrides={...t.themeOverrides}),e}const g={config:()=>f("/config"),mailpoet:()=>f("/mailpoet"),listForms:()=>f("/forms"),listArchivedForms:()=>f("/forms?archived=1"),archiveForm:e=>w(`/forms/${e}/archive`,{}),unarchiveForm:e=>w(`/forms/${e}/unarchive`,{}),getForm:e=>f(`/forms/${e}`).then(x),createForm:e=>w("/forms",e).then(x),updateForm:(e,t)=>w(`/forms/${e}`,t).then(x),duplicateForm:e=>w(`/forms/${e}/duplicate`,{}).then(x),deleteForm:e=>$(`/forms/${e}`),preview:(e,t)=>w(`/forms/${e}/preview`,t),pages:()=>Et("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(e=>e.map(t=>({id:t.id,title:St(t.title?.rendered??"")||`#${t.id}`}))),mergeTags:e=>f(`/forms/${e}/merge-tags`).then(t=>t.groups),analytics:(e,t="")=>f(`/forms/${e}/analytics${t?`?dimension=${encodeURIComponent(t)}`:""}`),demoStatus:()=>f("/demo"),demoSeed:e=>w("/demo",e?{count:e}:{}),demoRemove:()=>$("/demo"),listEntries:e=>f(`/entries${W(e)}`),getEntry:e=>f(`/entries/${e}`),updateEntry:(e,t)=>w(`/entries/${e}`,t),deleteEntry:e=>$(`/entries/${e}`),exportEntries:e=>f(`/entries/export${W(e)}`),listThemes:()=>f("/themes"),saveTheme:e=>w("/themes",e),deleteTheme:e=>$(`/themes/${e}`)};function o(e,t={}){const s=document.createElement(e);t.class&&(s.className=t.class),t.text!==void 0&&(s.textContent=t.text),t.html!==void 0&&(s.innerHTML=t.html),t.title&&(s.title=t.title),t.type&&"type"in s&&(s.type=t.type),t.value!==void 0&&"value"in s&&(s.value=t.value),t.placeholder!==void 0&&"placeholder"in s&&(s.placeholder=t.placeholder),t.href&&"href"in s&&(s.href=t.href);for(const[n,r]of Object.entries(t.attrs??{}))r===void 0||r===!1||s.setAttribute(n,r===!0?"":String(r));Object.assign(s.style,t.style??{});for(const[n,r]of Object.entries(t.on??{}))s.addEventListener(n,r);for(const n of t.children??[])n==null||n===!1||s.append(n);return s}function b(e){e.replaceChildren()}function q(e){return o("span",{class:`dashicons ${e.startsWith("dashicons-")?e:`dashicons-${e}`}`,attrs:{"aria-hidden":"true"}})}function Lt(e,t,s=""){return o("input",{class:"atfb-input",type:"text",value:e,placeholder:s,on:{input:n=>t(n.target.value)}})}function X(e,t,s){if(k("os-select")&&k("os-option")){const n=document.createElement("os-select");n.setAttribute("value",e),n.classList.add("atfb-field");for(const r of t){const i=document.createElement("os-option");i.setAttribute("value",r.value),i.textContent=r.label,n.append(i)}return n.addEventListener("os-pick",r=>{s(String(r.detail?.value??""))}),n}return o("select",{class:"atfb-input atfb-select",on:{change:n=>s(n.target.value)},children:t.map(n=>o("option",{value:n.value,text:n.label,attrs:{selected:n.value===e}}))})}function $t(e,t,s){if(k("os-checkbox-label")){const r=document.createElement("os-checkbox-label");return r.setAttribute("label",e),r.classList.add("atfb-check"),t&&r.setAttribute("checked",""),r.addEventListener("os-checkbox-change",i=>{s(!!i.detail?.checked)}),r}const n=o("input",{type:"checkbox",on:{change:r=>s(r.target.checked)}});return n.checked=t,o("label",{class:"atfb-check",children:[n,o("span",{text:e})]})}function m(e,t,s="secondary",n){const r=[n?q(n):null,o("span",{text:e})];if(k("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",s),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${s}`),i.addEventListener("click",t);for(const a of r)a&&i.append(a);return i}return o("button",{class:`atfb-button atfb-button--${s}`,type:"button",on:{click:t},children:r})}function k(e){return typeof customElements<"u"&&!!customElements.get(e)}const xt=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let _=null;function kt(){if(_)return _;const e=window.wp?.os;return _=e?.loadComponents?e.loadComponents(xt).catch(()=>{}):Promise.resolve(),_}async function H(e,t=""){const s=window.wp?.os;return s?.confirm?s.confirm({title:t,message:e,danger:!0}):window.confirm(e)}function E(e,t="",s="info"){const n=window.wp?.os;if(n?.notify){n.notify({title:e,body:t,type:s});return}console.info(`[AllTerrain Forms] ${e}${t?`: ${t}`:""}`)}function _t(e,t){let s=0;return(...n)=>{window.clearTimeout(s),s=window.setTimeout(()=>e(...n),t)}}function Tt(e){const t=e.closest(".os-window__body");t&&(t.addEventListener("scroll",()=>{t.scrollTop&&(t.scrollTop=0),t.scrollLeft&&(t.scrollLeft=0)},{passive:!0}),t.scrollTop=0,t.scrollLeft=0)}const At="allterrain-forms/form",It="allterrain-forms/entry";function Dt(){return window.wp?.os?.relations??null}function Ct(e){const t=e.closest("[data-window-id], .os-window");if(!t)return null;const s=t.getAttribute("data-window-id");if(s)return s;const n=t.id??"";return n?n.replace(/^wp-window-/,""):null}const Ot=6e3,z=120;function G(e,t){const s=Dt();if(R.set(e,t),!s?.set)return;const n=i=>{if(T.get(e)!==r)return;const a=Ct(e);if(!a){Date.now()n(i),z);return}try{s.set(a,t)}catch(d){K||(K=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",d,t)),T.delete(e);return}if(!t||s.get?.(a)?.id===t.id||Date.now()>=i){T.delete(e);return}window.setTimeout(()=>n(i),z)},r=Symbol("atf-identity");T.set(e,r),n(Date.now()+Ot)}let K=!1;const T=new WeakMap,R=new Map;function Mt(){for(const[e,t]of R){if(!e.isConnected){R.delete(e);continue}G(e,t)}}if(typeof document<"u")for(const e of["os-window-content-loaded","os-window-opened"])document.addEventListener(e,()=>Mt());function qt(e,t){const s=[];e.userId&&s.push({type:"user",id:e.userId,rel:"references"});for(const r of e.fields)if(!(r.type!=="file"||!Array.isArray(r.value)))for(const i of r.value){const a=Number(i);a>0&&s.push({type:"media",id:a,rel:"child"})}const n=[{id:`allterrain-forms/form-${e.formId}`,label:e.formTitle||"The form",url:`${t}admin.php?page=allterrain-forms&form=${e.formId}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-feedback"}];return e.userId&&n.push({id:`allterrain-forms/user-${e.userId}`,label:"Who submitted it",url:`${t}user-edit.php?user_id=${e.userId}`,group:"users",groupLabel:"People",icon:"dashicons-admin-users"}),{type:It,id:e.id,root:{type:At,id:e.formId},label:e.title||`Entry #${e.id}`,links:s.slice(0,32),related:n}}const J="allterrain-forms/entry";class Rt{constructor(t){this.forms=[],this.entries=[],this.selected=null,this.selection=new Set,this.paintedSelectionId=-1,this.loadSeq=0,this.selectSeq=0,this.formId=0,this.status="inbox",this.search="",this.starred=!1,this.page=1,this.pages=1,this.total=0,this.teardowns=[],this.root=t,this.bar=t.querySelector("[data-atfe-bar]")??o("div"),this.list=t.querySelector("[data-atfe-list]")??o("div"),this.detail=t.querySelector("[data-atfe-detail]")??o("div")}async start(){this.teardowns.push(vt([J]));try{this.forms=await g.listForms()}catch(n){b(this.bar),this.bar.append(o("p",{class:"atfb-error",text:n instanceof Error?n.message:"Could not load forms."}));return}const t=ut("entries")||ft();this.formId=(t&&this.forms.some(n=>n.id===t)?t:0)||(this.forms.find(n=>n.unread>0)??this.forms[0])?.id||0,this.renderBar(),await this.load();const s=window.wp?.os;s?.subscribe&&this.teardowns.push(s.subscribe("os.alltfo_entry.changed",()=>{if(!this.root.isConnected){this.destroy();return}this.load()}))}destroy(){this.teardowns.forEach(t=>t()),this.teardowns=[]}renderBar(){b(this.bar);const t=Lt(this.search,_t(s=>{this.search=s,this.page=1,this.load()},300),"Search answers");t.type="search",t.setAttribute("aria-label","Search entries"),this.bar.append(X(String(this.formId),this.forms.map(s=>({value:String(s.id),label:s.unread?`${s.title} (${s.unread})`:s.title})),s=>{this.formId=Number(s),this.page=1,this.selection.clear(),this.selected=null,this.load()}),X(this.status,[{value:"inbox",label:"All"},{value:"alltfo-unread",label:"Unread"},{value:"alltfo-read",label:"Read"},{value:"alltfo-spam",label:"Spam"}],s=>{this.status=s,this.page=1,this.load()}),t,$t("Starred only",this.starred,s=>{this.starred=s,this.page=1,this.load()}),o("span",{class:"atfe__count",attrs:{role:"status"},text:""}),m("Export CSV",()=>void this.exportEntries("csv"),"secondary","download"),m("JSON",()=>void this.exportEntries("json"),"secondary"))}async showForm(t){this.formId=t,this.page=1,this.selection.clear(),this.selected=null,this.renderBar(),await this.load()}async load(){if(!this.formId){b(this.list),this.list.append(o("p",{class:"atfb-hint",text:"No forms yet."}));return}const t=++this.loadSeq;try{const s=await g.listEntries({form_id:this.formId,status:this.status==="inbox"?void 0:this.status,search:this.search,page:this.page,starred:this.starred});if(t!==this.loadSeq)return;if(this.page>1&&this.page>s.pages)return this.page=Math.max(1,s.pages),this.load();this.entries=s.entries,this.total=s.total,this.pages=s.pages,this.renderList(),this.reconcileSelection();const n=this.bar.querySelector(".atfe__count");n&&(n.textContent=`${this.total} ${this.total===1?"entry":"entries"}`)}catch(s){if(t!==this.loadSeq)return;b(this.list),this.list.append(o("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load entries."}))}}reconcileSelection(){this.selected&&!this.entries.some(t=>t.id===this.selected?.id)&&(this.selected=null),this.paintedSelectionId!==(this.selected?.id??0)&&this.renderDetail()}renderList(){if(b(this.list),!this.entries.length){this.list.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:this.search?"Nothing matches that.":"No entries yet."})]}));return}const t=new Set(this.entries.map(n=>n.id));for(const n of Array.from(this.selection))t.has(n)||this.selection.delete(n);this.list.append(this.renderBulkBar());const s=o("div",{class:"atfe__rows",attrs:{role:"list"}});for(const n of this.entries)s.append(this.renderRow(n));this.list.append(s),this.pages>1&&this.list.append(o("div",{class:"atfe__pager",children:[m("Previous",()=>{this.page=Math.max(1,this.page-1),this.load()}),o("span",{text:`Page ${this.page} of ${this.pages}`}),m("Next",()=>{this.page=Math.min(this.pages,this.page+1),this.load()})]}))}renderBulkBar(){const t=this.selection.size,s=o("input",{type:"checkbox",attrs:{"aria-label":"Select every entry on this page"},on:{change:n=>{const r=n.target.checked;this.entries.forEach(i=>{r?this.selection.add(i.id):this.selection.delete(i.id)}),this.renderList()}}});return s.checked=t>0&&t===this.entries.length,s.indeterminate=t>0&&tvoid this.bulk("alltfo-read")):null,t?m("Unread",()=>void this.bulk("alltfo-unread")):null,t?m("Spam",()=>void this.bulk("alltfo-spam")):null,t&&h?.canEdit?m("Delete",()=>void this.bulkDelete(),"danger"):null]})}async bulk(t){const s=Array.from(this.selection);for(const n of s)try{await g.updateEntry(n,{status:t})}catch{}this.selection.clear(),await this.load()}async bulkDelete(){const t=Array.from(this.selection);if(await H(`Delete ${t.length} ${t.length===1?"entry":"entries"} and any files uploaded with them? It cannot be undone.`,"Delete entries")){for(const n of t)try{await g.deleteEntry(n)}catch{}this.selection.clear(),this.selected=null,await this.load(),this.renderDetail()}}renderRow(t){const s=t.status==="alltfo-unread",n=o("div",{class:`atfe__row${s?" is-unread":""}${this.selected?.id===t.id?" is-selected":""}`,attrs:{role:"listitem",tabindex:"0","data-entry":t.id},children:[o("input",{class:"atfe__select",type:"checkbox",attrs:{"aria-label":`Select ${t.title}`,checked:this.selection.has(t.id)},on:{click:r=>r.stopPropagation(),change:r=>{r.target.checked?this.selection.add(t.id):this.selection.delete(t.id),this.list.querySelector(".atfe__bulk")?.replaceWith(this.renderBulkBar())}}}),o("button",{class:`atfe__star${t.starred?" is-on":""}`,type:"button",attrs:{"aria-label":t.starred?"Unstar this entry":"Star this entry"},on:{click:r=>{r.stopPropagation(),this.toggleStar(t)}},children:[q("star-filled")]}),o("div",{class:"atfe__row-body",children:[o("strong",{text:t.title}),o("span",{class:"atfe__row-meta",text:t.dateHuman})]}),t.notes?o("span",{class:"atfb-badge",text:`💬 ${t.notes}`}):null,t.spam?o("span",{class:"atfb-badge atfb-badge--spam",text:"spam"}):null]});return n.addEventListener("click",()=>{j().recentlyEndedDrag()||this.select(t)}),n.addEventListener("keydown",r=>{(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),this.select(t))}),n.addEventListener("pointerdown",r=>{if(r.target.closest("button"))return;const i=o("div",{class:"atfe__ghost",children:[q("feedback"),o("span",{text:t.title})]});j().start({payload:yt(J,n,{entry:t,formId:t.formId,formTitle:t.formTitle},r,i),origin:r})}),n}async select(t){const s=++this.selectSeq;try{const n=await g.getEntry(t.id);if(s!==this.selectSeq)return;this.selected=n;const r=this.entries.find(i=>i.id===t.id);r&&(r.status=this.selected.status),this.renderList(),this.renderDetail()}catch(n){if(s!==this.selectSeq)return;E("Could not open that entry",n instanceof Error?n.message:"","error")}}renderDetail(){this.paintedSelectionId=this.selected?.id??0,G(this.root,this.selected?qt(this.selected,h?.adminUrl??""):null),b(this.detail);const t=this.selected;if(!t){this.detail.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:"Pick an entry to read it."})]}));return}const s=o("dl",{class:"atfe__answers"});for(const n of t.fields)n.formatted&&s.append(o("dt",{text:n.label||n.id}),o("dd",{text:n.formatted}));this.detail.append(o("div",{class:"atfe__detail",children:[o("div",{class:"atfe__detail-head",children:[o("h2",{text:t.title}),o("p",{class:"atfb-hint",text:`${t.formTitle} — ${t.dateHuman}`})]}),s,t.quiz?o("p",{class:"atfe__quiz",text:`Score: ${t.quiz.score} of ${t.quiz.total} (${t.quiz.percent}%) — ${t.quiz.passed?"passed":"not passed"}`}):null,o("details",{class:"atfb-section",children:[o("summary",{text:"Where it came from"}),o("p",{class:"atfb-hint",text:t.ip?`IP: ${t.ip}`:"No IP recorded."}),t.referrer?o("p",{class:"atfb-hint",text:`Referrer: ${t.referrer}`}):null,t.userAgent?o("p",{class:"atfb-hint",text:t.userAgent}):null]}),o("div",{class:"atfe__actions",children:[m(t.status==="alltfo-spam"?"Not spam":"Mark as spam",()=>void this.setStatus(t,t.status==="alltfo-spam"?"alltfo-read":"alltfo-spam")),m(t.status==="alltfo-unread"?"Mark read":"Mark unread",()=>void this.setStatus(t,t.status==="alltfo-unread"?"alltfo-read":"alltfo-unread")),t.canDelete?m("Delete",()=>void this.remove(t),"danger"):null]})]}))}async toggleStar(t){try{const s=await g.updateEntry(t.id,{starred:!t.starred});t.starred=s.starred,this.renderList()}catch(s){E("Could not update that entry",s instanceof Error?s.message:"","error")}}async setStatus(t,s){try{const n=await g.updateEntry(t.id,{status:s});this.selected=n,await this.load(),this.renderDetail()}catch(n){E("Could not update that entry",n instanceof Error?n.message:"","error")}}async remove(t){if(await H("Delete this entry and any files uploaded with it? It cannot be undone.","Delete entry"))try{await g.deleteEntry(t.id),this.selected=null,await this.load(),this.renderDetail()}catch(s){E("Could not delete that entry",s instanceof Error?s.message:"","error")}}async exportEntries(t){try{const{filename:s,csv:n}=await g.exportEntries({form_id:this.formId,search:this.search,starred:this.starred,format:t}),r=new Blob([n],{type:t==="json"?"application/json":"text/csv;charset=utf-8"}),i=URL.createObjectURL(r),a=o("a",{href:i,attrs:{download:s}});document.body.append(a),a.click(),a.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),1e3)}catch(s){E("Could not export",s instanceof Error?s.message:"","error")}}}let y=null;document.addEventListener("alltfo-open-entries-form",e=>{const t=Number(e.detail?.formId??0);t&&y?.showForm(t)});let F=null;function P(){if(F?.isConnected)return;y&&(y.destroy(),y=null,F=null);const e=document.querySelector("[data-atfe-root]:not([data-atfe-mounted])");!e||!h?.canRead||(e.dataset.atfeMounted="1",F=e,Tt(e),kt().then(()=>{e.isConnected&&(y=new Rt(e),y.start())}))}function V(){P(),lt()}return ct(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",V):V(),document.addEventListener("os-window-content-loaded",P),I.mountEntries=P,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"}),I}({}); diff --git a/src/builder.ts b/src/builder.ts index a12b58d..c23b2ce 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -2596,6 +2596,232 @@ export class Builder { * canvas, or from a *second* builder window, which is what the shell's * shared drag manager buys and an iframe could not. */ + /** + * The animated insertion gap for one drop container — the canvas list, or + * a repeater's zone. + * + * While a field payload is over the container, a slot the size of the + * dragged card follows the pointer, the dragged card leaves the flow, and + * the other cards slide out of the way with first/last-position + * transforms — so the list previews, in real time, exactly the layout the + * drop will produce. + * + * @param container The drop target element; the gap shows while it has + * the `is-dropping` class. + * @param itemSelector The cards that reflow, `.atfb-card` or `.atfb-subcard`. + * @param findCard Resolves a dragged field id to its card in this + * container's world, or null for one it doesn't hold. + * @param accepts Optional payload gate mirroring the drop target's + * own `accept()`, so a drag the target will refuse + * never opens a gap it cannot honour. + * @return `enter`/`leave`/`drop` to wire into the drop target, and a + * `teardown` for the document-level listeners. + */ + private gapAnimator( + container: HTMLElement, + itemSelector: string, + findCard: ( fieldId: string ) => HTMLElement | null, + accepts?: ( data: Record< string, unknown > ) => boolean + ): { + enter( fieldId?: string ): void; + leave(): void; + drop( clientY: number, source?: HTMLElement | null ): number; + teardown(): void; + } { + const marker = el( 'div', { class: 'atfb-marker', attrs: { 'aria-hidden': 'true' } } ); + + /** + * The slot the marker currently shows, in the same "list without the + * dragged card" indexing the drop uses. Null while no gap is open. + * + * The drop reads this instead of re-measuring the pointer: with a + * card-sized gap open the cards are nowhere near where a measurement + * of the restored layout would put them, so a recomputed index lands + * the field a slot away from where the gap said it would. + */ + let shownIndex: number | null = null; + + /** The card lifted out of the flow while its gap is open, if any. */ + let liftedCard: HTMLElement | null = null; + + /** The gap's height — the dragged card's, measured before it is lifted. */ + let slotSize = 0; + + const restore = () => { + marker.remove(); + liftedCard?.classList.remove( 'atfb-lifted' ); + liftedCard = null; + shownIndex = null; + }; + + // First/last-position animation: measure where every card sits, mutate + // the DOM, transform each card back to its old spot and release — so + // the gap opening, moving and closing reads as cards sliding out of + // the way in real time rather than teleporting. + const moveAnimated = ( mutate: () => void ) => { + const cards = Array.from( container.querySelectorAll< HTMLElement >( itemSelector ) ); + // A lifted card has no box, and a rect of zeros as a start position + // would animate its restore in from the viewport's top corner — so + // only cards visible *before* the mutation get one. + const before = new Map( + cards + .filter( ( card ) => ! card.classList.contains( 'atfb-lifted' ) ) + .map( ( card ) => [ card, card.getBoundingClientRect().top ] ) + ); + + mutate(); + + for ( const card of cards ) { + card.style.transition = 'none'; + card.style.transform = ''; + } + + const moved = cards.filter( ( card ) => { + const from = before.get( card ); + + if ( from === undefined || ! card.isConnected || card.classList.contains( 'atfb-lifted' ) ) { + return false; + } + + const delta = from - card.getBoundingClientRect().top; + + if ( Math.abs( delta ) < 0.5 ) { + return false; + } + + card.style.transform = `translateY(${ delta }px)`; + + return true; + } ); + + // One reflow commits the start positions, then every moved card + // transitions to its natural spot. Cards that didn't move give the + // inline `transition: none` straight back — left on, it would keep + // eating their hover transitions until the next render. + void container.offsetHeight; + + for ( const card of cards ) { + if ( ! moved.includes( card ) ) { + card.style.transition = ''; + continue; + } + + card.style.transition = 'transform 160ms ease'; + card.style.transform = ''; + card.addEventListener( + 'transitionend', + () => { + card.style.transition = ''; + }, + { once: true } + ); + } + }; + + // The gap follows the pointer. Driven from the drag manager's move + // event, which both managers emit. + const onMove = ( event: Event ) => { + const detail = ( + event as CustomEvent< { + payload?: { type: string; data?: Record< string, unknown > }; + clientY?: number; + } > + ).detail; + + if ( detail?.payload?.type !== FIELD_PAYLOAD_TYPE || ! container.classList.contains( 'is-dropping' ) ) { + return; + } + + if ( accepts && ! accepts( detail.payload.data ?? {} ) ) { + return; + } + + // The dragged card is left out of the count, exactly as `drop` + // leaves it out. Gap and drop must be computed in the same + // indexing — counted two different ways, the field lands one slot + // away from where the gap said it would. + const fieldId = detail.payload.data?.fieldId; + const dragged = typeof fieldId === 'string' ? findCard( fieldId ) : null; + const index = insertionIndex( container, itemSelector, detail.clientY ?? 0, dragged ?? undefined ); + + // Every pointer move lands here; only a move that changes the slot + // touches layout. + if ( index === shownIndex && marker.isConnected ) { + return; + } + + shownIndex = index; + + moveAnimated( () => { + // The dragged card leaves the flow the moment its gap first + // opens: the ghost under the pointer is the card now, and the + // gap is where it will land. Both at once would show the field + // twice, one of them stale. + if ( dragged && dragged !== liftedCard ) { + liftedCard?.classList.remove( 'atfb-lifted' ); + dragged.classList.add( 'atfb-lifted' ); + liftedCard = dragged; + } + + marker.style.blockSize = `${ Math.max( 8, Math.round( slotSize ) ) }px`; + + const cards = Array.from( container.querySelectorAll< HTMLElement >( itemSelector ) ).filter( + ( card ) => card !== dragged + ); + + if ( index >= cards.length ) { + container.append( marker ); + } else { + cards[ index ].before( marker ); + } + } ); + }; + + // The safety net for a drag that ends anywhere but a clean drop here — + // Escape, window blur, a drop swallowed by another target. The restore + // is deferred a tick because a manager may emit its end event before + // it delivers the drop, and the drop still needs `shownIndex`; after a + // clean drop this is a no-op. + const onEnd = () => { + container.classList.remove( 'is-dropping' ); + window.setTimeout( () => moveAnimated( restore ), 0 ); + }; + + document.addEventListener( 'os.drag.move', onMove ); + document.addEventListener( 'os.drag.end', onEnd ); + + return { + enter: ( fieldId ) => { + const card = fieldId ? findCard( fieldId ) : null; + + // Measured now, before the card is lifted out of the flow — + // afterwards it has no box left to measure. A palette item has + // no card yet, so its gap is a nominal card height. + slotSize = + card && ! card.classList.contains( 'atfb-lifted' ) + ? card.getBoundingClientRect().height + : slotSize || 44; + }, + leave: () => moveAnimated( restore ), + drop: ( clientY, source ) => { + // The slot the open gap showed, when one is open. Only a drop + // that never opened one — possible with a pointer that never + // moved after entering — falls back to measuring, against a + // layout that in that case was never distorted. + const index = shownIndex ?? insertionIndex( container, itemSelector, clientY, source ?? undefined ); + + restore(); + + return index; + }, + teardown: () => { + document.removeEventListener( 'os.drag.move', onMove ); + document.removeEventListener( 'os.drag.end', onEnd ); + restore(); + }, + }; + } + private registerCanvasTarget( list: HTMLElement ): void { // Every canvas render builds a fresh list element, and this runs on every // render — so the previous registration and its document-level move @@ -2604,20 +2830,24 @@ export class Builder { this.canvasTarget?.(); this.canvasTarget = null; - const marker = el( 'div', { class: 'atfb-marker', attrs: { 'aria-hidden': 'true' } } ); + const gap = this.gapAnimator( list, '.atfb-card', ( fieldId ) => + this.canvas.querySelector< HTMLElement >( `[data-atfb-card="${ CSS.escape( fieldId ) }"]` ) + ); const teardown = getDragManager().registerDropTarget( { id: `atfb-canvas-${ this.form?.id ?? 0 }`, element: list, accept: ( payload ) => payload.type === FIELD_PAYLOAD_TYPE, - onEnter: () => list.classList.add( 'is-dropping' ), + onEnter: ( session ) => { + list.classList.add( 'is-dropping' ); + gap.enter( ( session.payload.data as { fieldId?: string } ).fieldId ); + }, onLeave: () => { list.classList.remove( 'is-dropping' ); - marker.remove(); + gap.leave(); }, onDrop: ( session, position ) => { list.classList.remove( 'is-dropping' ); - marker.remove(); const data = session.payload.data as { fieldType?: string; @@ -2630,7 +2860,7 @@ export class Builder { ? this.canvas.querySelector< HTMLElement >( `[data-atfb-card="${ CSS.escape( data.fieldId ) }"]` ) : null; - const index = insertionIndex( list, '.atfb-card', position.clientY, source ?? undefined ); + const index = gap.drop( position.clientY, source ); if ( data.isNew && data.fieldType ) { this.addField( data.fieldType, index ); @@ -2658,47 +2888,10 @@ export class Builder { const zoneTeardowns = this.wireRepeaterZones( list ); - // The insertion marker follows the pointer while a field is over the - // canvas. Driven from the shell's own move event so it works with either - // manager. - const onMove = ( event: Event ) => { - const detail = ( - event as CustomEvent< { payload?: { type: string; data?: { fieldId?: string } }; clientY?: number } > - ).detail; - - if ( detail?.payload?.type !== FIELD_PAYLOAD_TYPE || ! list.classList.contains( 'is-dropping' ) ) { - return; - } - - // The dragged card is left out of the count, exactly as `onDrop` - // leaves it out. Marker and drop must be computed in the same - // indexing — counted two different ways, the field lands one slot - // away from where the marker said it would. - const dragged = detail.payload.data?.fieldId - ? this.canvas.querySelector< HTMLElement >( - `[data-atfb-card="${ CSS.escape( detail.payload.data.fieldId ) }"]` - ) - : null; - - const y = detail.clientY ?? 0; - const index = insertionIndex( list, '.atfb-card', y, dragged ?? undefined ); - const cards = Array.from( list.querySelectorAll< HTMLElement >( '.atfb-card' ) ).filter( - ( card ) => card !== dragged - ); - - if ( index >= cards.length ) { - list.append( marker ); - } else { - cards[ index ].before( marker ); - } - }; - - document.addEventListener( 'os.drag.move', onMove ); - this.canvasTarget = () => { teardown(); zoneTeardowns.forEach( ( zoneTeardown ) => zoneTeardown() ); - document.removeEventListener( 'os.drag.move', onMove ); + gap.teardown(); }; } @@ -2721,36 +2914,47 @@ export class Builder { list.querySelectorAll< HTMLElement >( '[data-atfb-repeater-zone]' ).forEach( ( zone ) => { const repeaterId = zone.dataset.atfbRepeaterZone ?? ''; - teardowns.push( - getDragManager().registerDropTarget( { - id: `atfb-repzone-${ this.form?.id ?? 0 }-${ repeaterId }`, - element: zone, - accept: ( payload ) => { - if ( payload.type !== FIELD_PAYLOAD_TYPE ) { - return false; - } + // The zone's acceptance rule, shared between the drop target's + // `accept()` and its gap animator — a drag the zone will refuse + // must not open a gap in it either. + const acceptsData = ( raw: Record< string, unknown > ) => { + const data = raw as { fieldType?: string; fieldId?: string; field?: Field; isNew?: boolean }; - const data = payload.data as { - fieldType?: string; - fieldId?: string; - field?: Field; - isNew?: boolean; - }; + // The repeater itself dragged over its own zone must + // fall through to the canvas, not swallow the drop. + if ( data.fieldId === repeaterId ) { + return false; + } - // The repeater itself dragged over its own zone must - // fall through to the canvas, not swallow the drop. - if ( data.fieldId === repeaterId ) { - return false; - } + const type = data.isNew + ? data.fieldType + : this.locateField( data.fieldId ?? '' )?.field.type ?? data.field?.type; + + return !! type && this.allowedInRepeater( type ); + }; + + const gap = this.gapAnimator( + zone, + '.atfb-subcard', + ( fieldId ) => list.querySelector< HTMLElement >( `[data-atfb-subfield="${ CSS.escape( fieldId ) }"]` ), + acceptsData + ); - const type = data.isNew - ? data.fieldType - : this.locateField( data.fieldId ?? '' )?.field.type ?? data.field?.type; + teardowns.push( () => gap.teardown() ); - return !! type && this.allowedInRepeater( type ); + teardowns.push( + getDragManager().registerDropTarget( { + id: `atfb-repzone-${ this.form?.id ?? 0 }-${ repeaterId }`, + element: zone, + accept: ( payload ) => payload.type === FIELD_PAYLOAD_TYPE && acceptsData( payload.data ), + onEnter: ( session ) => { + zone.classList.add( 'is-dropping' ); + gap.enter( ( session.payload.data as { fieldId?: string } ).fieldId ); + }, + onLeave: () => { + zone.classList.remove( 'is-dropping' ); + gap.leave(); }, - onEnter: () => zone.classList.add( 'is-dropping' ), - onLeave: () => zone.classList.remove( 'is-dropping' ), onDrop: ( session, position ) => { zone.classList.remove( 'is-dropping' ); @@ -2767,7 +2971,7 @@ export class Builder { ) : null; - const index = insertionIndex( zone, '.atfb-subcard', position.clientY, source ?? undefined ); + const index = gap.drop( position.clientY, source ); if ( data.isNew && data.fieldType ) { this.addFieldToRepeater( data.fieldType, repeaterId, index ); diff --git a/src/dnd.ts b/src/dnd.ts index 66df3a2..25d4e17 100644 --- a/src/dnd.ts +++ b/src/dnd.ts @@ -76,6 +76,16 @@ class FallbackDragManager implements DragManagerApi { this.lastEndMs = Date.now(); }; + // The same lifecycle events the shell's manager broadcasts, so code + // that draws during a drag — the builder's insertion gap — listens to + // one event stream and works under either manager, instead of the + // fallback silently never showing what the shell shows. + const emit = ( name: 'os.drag.start' | 'os.drag.move' | 'os.drag.end', at?: PointerEvent ) => { + document.dispatchEvent( + new CustomEvent( name, { detail: { payload, clientX: at?.clientX, clientY: at?.clientY } } ) + ); + }; + const session: DragSession = { payload, isFinished: () => finished, @@ -86,6 +96,11 @@ class FallbackDragManager implements DragManagerApi { finished = true; cleanup(); + + if ( lifted ) { + emit( 'os.drag.end' ); + } + opts.onCancel?.( reason ); }, }; @@ -108,6 +123,7 @@ class FallbackDragManager implements DragManagerApi { document.body.appendChild( ghost ); position( event ); + emit( 'os.drag.start', event ); }; const position = ( event: PointerEvent ) => { @@ -138,6 +154,11 @@ class FallbackDragManager implements DragManagerApi { hovered = next; hovered?.onEnter?.( session ); } + + // After the enter/leave bookkeeping, so a listener drawing on this + // event always sees the target already entered — same order as the + // shell. + emit( 'os.drag.move', event ); }; const onUp = ( event: PointerEvent ) => { @@ -164,10 +185,15 @@ class FallbackDragManager implements DragManagerApi { if ( target && target.accept( payload ) ) { opts.onCommit?.( target ); void target.onDrop( session, { clientX: event.clientX, clientY: event.clientY } ); + // End is emitted *after* the drop, so a drop handler can still + // read whatever state the move events built up — the builder's + // insertion gap depends on this ordering. + emit( 'os.drag.end', event ); return; } + emit( 'os.drag.end', event ); opts.onCancel?.( target ? 'rejected' : 'no-target' ); }; @@ -325,6 +351,8 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { return payload && payloadTypes.includes( payload.type ) ? payload.source : null; }; + const preventSelection = ( event: Event ) => event.preventDefault(); + const onStart = ( event: Event ) => { const source = sourceOf( event ); @@ -334,6 +362,15 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { // manager sets at lift — the shell moves the ghost but knows // nothing about this plugin's cursors. document.body.classList.add( 'atf-drag-active' ); + // A drag is not a selection. The press already anchored one during + // the pre-lift travel, and every further move would sweep it across + // the page behind the ghost — so the anchor goes, and `selectstart` + // is refused for the duration in case the browser tries to re-arm + // it mid-drag. The `atf-drag-active` CSS turns off `user-select` + // too; belt and braces, because a half-page blue smear reads as the + // drag having gone wrong. + window.getSelection()?.removeAllRanges(); + document.addEventListener( 'selectstart', preventSelection ); } }; const onEnd = ( event: Event ) => { @@ -342,6 +379,7 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { if ( source ) { source.classList.remove( 'atf-is-dragging' ); document.body.classList.remove( 'atf-drag-active' ); + document.removeEventListener( 'selectstart', preventSelection ); } }; @@ -351,6 +389,7 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { return () => { document.removeEventListener( 'os.drag.start', onStart ); document.removeEventListener( 'os.drag.end', onEnd ); + document.removeEventListener( 'selectstart', preventSelection ); }; } @@ -366,6 +405,13 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { * would snap the element's corner to the cursor at lift time, which reads as the * thing jumping out from under the pointer. */ +/** + * The plugin's style-scope roots. Everything this plugin draws sits under one + * of these classes, which carry the custom properties, font size and line + * height its CSS assumes. + */ +const SCOPE_CLASSES = [ 'atfb', 'atfe', 'atfs', 'atfm' ]; + export function buildPayload( type: string, source: HTMLElement, @@ -375,6 +421,28 @@ export function buildPayload( ): DragPayload { const rect = source.getBoundingClientRect(); + // With no ghost supplied, the manager clones the source — and appends the + // clone to `document.body`, outside the plugin's scope root, where every + // custom property and the root's type settings stop applying: the ghost's + // fonts and colours visibly shift the moment it is lifted. So the default + // ghost is built here instead — the same clone, wrapped in an element + // carrying the scope class the source lived under, with the wrapper's own + // layout neutralised in CSS (`.atf-ghost-scope`). + if ( ! ghost ) { + const scope = SCOPE_CLASSES.find( ( cls ) => source.closest( `.${ cls }` ) ); + + if ( scope ) { + const clone = source.cloneNode( true ) as HTMLElement; + + clone.style.transition = ''; + clone.style.transform = ''; + + ghost = document.createElement( 'div' ); + ghost.className = `${ scope } atf-ghost-scope`; + ghost.appendChild( clone ); + } + } + // The ghost is sized here rather than in CSS. A `position: fixed` element // with no width resolves against the containing block — the viewport — so a // ghost that looks fine in the fallback manager (which sets a width itself)