From 7d968847c37025f22ec6936996508fec47852712 Mon Sep 17 00:00:00 2001 From: prismiwi2015 Date: Fri, 21 Aug 2026 10:00:39 +0200 Subject: [PATCH 1/2] The custom-rule editor is a real child window, not a dialog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rule being written is about a field the person can still see, select and reread while they write it — so the editor now opens through the shell's own windowing, `windowManager.openChild()`, as a window the builder owns: its own chrome, drag, resize, minimize and taskbar entry, centered over the builder, which stays scrollable and readable beside it but can never sit above its child. Save and the title-bar X both funnel through the window's close; `onClose` is the one place that decides whether that was a cancel, so the picker reverts however the window goes away. The overlay remains as the fallback on the plain admin page, where there is no shell to ask. The editor's UI is built once, by one function, into whichever host is showing it. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp --- assets/css/builder.css | 14 ++ assets/js/builder.js | 374 +++++++++++++++++++++++---------------- assets/js/builder.min.js | 6 +- src/validation-editor.ts | 310 ++++++++++++++++++++++++-------- 4 files changed, 466 insertions(+), 238 deletions(-) diff --git a/assets/css/builder.css b/assets/css/builder.css index b0909f0..2f92717 100644 --- a/assets/css/builder.css +++ b/assets/css/builder.css @@ -2663,6 +2663,20 @@ os-checkbox-label.atfb-check { overflow-y: auto; } +/* The editor as a real shell child window. The window's own chrome carries the + title and the close button, and the body is ours to fill — so the modal's + self-imposed footprint goes, and the content takes the window at whatever + size the person drags it to. `.atfa` on the same element brings the token + palette a child window's body does not inherit from the builder's root. */ +.atfb-valwin--window { + inline-size: auto; + max-block-size: none; + block-size: 100%; + padding: 14px 16px; + overflow-y: auto; + display: block; +} + .atfb-valwin__tabs { display: flex; gap: 4px; diff --git a/assets/js/builder.js b/assets/js/builder.js index f03b7f4..0e13bb9 100644 --- a/assets/js/builder.js +++ b/assets/js/builder.js @@ -2838,6 +2838,97 @@ var allTerrainFormsBuilder = function(exports) { input.focus(); input.setSelectionRange(input.value.length, input.value.length); } + const FORM_TYPE = "allterrain-forms/form"; + function relations() { + const os = window.wp?.os; + return os?.relations ?? null; + } + function windowIdOf(element) { + const host = element.closest("[data-window-id], .os-window"); + if (!host) { + return null; + } + const attribute = host.getAttribute("data-window-id"); + if (attribute) { + return attribute; + } + const id = host.id ?? ""; + return id ? id.replace(/^wp-window-/, "") : null; + } + const ATTACH_TIMEOUT_MS = 6e3; + const ATTACH_POLL_MS = 120; + function setIdentity(element, ref) { + const api2 = relations(); + wanted.set(element, ref); + if (!api2?.set) { + return; + } + const attempt = (deadline) => { + if (pending.get(element) !== token) { + return; + } + const windowId = windowIdOf(element); + if (!windowId) { + if (Date.now() < deadline) { + window.setTimeout(() => attempt(deadline), ATTACH_POLL_MS); + } + return; + } + try { + api2.set(windowId, ref); + } catch (error) { + if (!warned) { + warned = true; + console.error("[AllTerrain Forms] The shell refused a window identity.", error, ref); + } + pending.delete(element); + return; + } + const stuck = !ref || api2.get?.(windowId)?.id === ref.id; + if (stuck || Date.now() >= deadline) { + pending.delete(element); + return; + } + window.setTimeout(() => attempt(deadline), ATTACH_POLL_MS); + }; + const token = Symbol("atf-identity"); + pending.set(element, token); + attempt(Date.now() + ATTACH_TIMEOUT_MS); + } + let warned = false; + const pending = /* @__PURE__ */ new WeakMap(); + const wanted = /* @__PURE__ */ new Map(); + function reapply() { + for (const [element, ref] of wanted) { + if (!element.isConnected) { + wanted.delete(element); + continue; + } + setIdentity(element, ref); + } + } + if (typeof document !== "undefined") { + for (const event of ["os-window-content-loaded", "os-window-opened"]) { + document.addEventListener(event, () => reapply()); + } + } + function formIdentity(form, adminUrl) { + return { + type: FORM_TYPE, + id: form.id, + label: form.title || "Untitled form", + related: [ + { + id: `allterrain-forms/entries-${form.id}`, + label: "Entries for this form", + url: `${adminUrl}admin.php?page=allterrain-forms-entries&form=${form.id}`, + group: "allterrain-forms", + groupLabel: "Forms", + icon: "dashicons-list-view" + } + ] + }; + } const CHAR_GROUPS = { letters: { label: "Letters", chars: "A-Za-zÀ-ÖØ-öø-ÿ" }, numbers: { label: "Numbers", chars: "0-9" }, @@ -2967,21 +3058,69 @@ var allTerrainFormsBuilder = function(exports) { return null; } } + function shellWindows() { + return window.wp?.os?.windowManager ?? null; + } + const EDITOR_WINDOW_BASE = "allterrain-forms-validation"; function openValidationEditor(options) { - const recipe = parseRecipe(String(options.field.validationRecipe ?? "")); - if ("blocks" === recipe.mode && "" === compileRecipe(recipe) && options.field.pattern) { - recipe.mode = "regex"; - recipe.regex = String(options.field.pattern); + const manager = shellWindows(); + const parentId = windowIdOf(options.root); + if (manager?.openChild && parentId) { + openAsChildWindow(manager, parentId, options); + return; } - if (!recipe.message) { - recipe.message = String(options.field.messages?.invalid ?? ""); + openAsOverlay(options); + } + function openAsChildWindow(manager, parentId, options) { + const id = `${EDITOR_WINDOW_BASE}-${options.field.id}`; + if (manager.getById?.(id)) { + manager.remove?.(id); } + const state = { saved: false }; + const close = () => { + const win = manager.getById?.(id); + if (win?.close) { + win.close(); + } else { + manager.remove?.(id); + } + }; + void manager.openChild?.(parentId, { + id, + baseId: EDITOR_WINDOW_BASE, + url: `#${id}`, + title: `Custom rule — ${options.field.label || "this question"}`, + icon: "dashicons-yes-alt", + native: true, + width: 560, + height: 700, + minWidth: 440, + minHeight: 480, + // A rule mid-edit is not worth resurrecting against a field that may + // be gone; children are excluded from snapshots anyway, this says so. + ephemeral: true, + autofocus: ".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea", + render: (body) => { + const host = el("div", { class: "atfa atfb-valwin atfb-valwin--window" }); + buildEditor(host, options, state, close, "window"); + body.append(host); + }, + // Fires however the window closes — Save, Cancel, the title-bar X, + // or its owner closing. One place decides whether that was a cancel. + onClose: () => { + if (!state.saved) { + options.onCancel?.(); + } + } + }); + } + function openAsOverlay(options) { const overlay = el("div", { class: "atfb-overlay" }); - let saved = false; + const state = { saved: false }; const close = () => { overlay.remove(); document.removeEventListener("keydown", onKeydown); - if (!saved) { + if (!state.saved) { options.onCancel?.(); } }; @@ -2990,6 +3129,33 @@ var allTerrainFormsBuilder = function(exports) { close(); } }; + const modal = el("div", { + class: "atfb-modal atfb-valwin", + attrs: { role: "dialog", "aria-label": "Custom validation rule" }, + children: [el("h2", { text: "Custom rule" })] + }); + buildEditor(modal, options, state, close, "overlay"); + overlay.append(modal); + overlay.addEventListener("click", (event) => { + if (event.target === overlay) { + close(); + } + }); + document.addEventListener("keydown", onKeydown); + options.root.append(overlay); + overlay.querySelector( + ".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea" + )?.focus(); + } + function buildEditor(host, options, state, requestClose, chrome) { + const recipe = parseRecipe(String(options.field.validationRecipe ?? "")); + if ("blocks" === recipe.mode && "" === compileRecipe(recipe) && options.field.pattern) { + recipe.mode = "regex"; + recipe.regex = String(options.field.pattern); + } + if (!recipe.message) { + recipe.message = String(options.field.messages?.invalid ?? ""); + } const blockInput = (key, placeholder) => { const input = el("input", { class: "atfb-input", @@ -3141,70 +3307,55 @@ var allTerrainFormsBuilder = function(exports) { verdict.classList.toggle("is-fail", false === result); } }; - overlay.append( + host.append( + el("p", { + class: "atfb-hint", + text: `Describe what a good answer to “${options.field.label || "this question"}” looks like — no code needed.` + }), + tabs, + blocksPane, + regexPane, el("div", { - class: "atfb-modal atfb-valwin", - attrs: { role: "dialog", "aria-label": "Custom validation rule" }, + class: "atfb-valwin__try", children: [ - el("h2", { text: "Custom rule" }), - el("p", { - class: "atfb-hint", - text: `Describe what a good answer to “${options.field.label || "this question"}” looks like — no code needed.` - }), - tabs, - blocksPane, - regexPane, - el("div", { - class: "atfb-valwin__try", - children: [ - el("h3", { text: "Try it out" }), - summary, - samples, - button( - "Add another sample", - () => { - sampleRow(""); - refresh(); - }, - "ghost", - "plus-alt2" - ) - ] - }), - row( - "When it fails, say", - messageInput, - "Shown to the visitor when their answer breaks the rule. Leave empty for the default wording." - ), - el("div", { - class: "atfb-modal__actions", - children: [ - button("Cancel", close), - button( - "Save rule", - () => { - const pattern = compileRecipe(recipe); - recipe.tests = readSamples().filter((value) => "" !== value).slice(0, 10); - saved = true; - options.onSave({ pattern, recipe, message: recipe.message.trim() }); - close(); - }, - "primary" - ) - ] - }) + el("h3", { text: "Try it out" }), + summary, + samples, + button( + "Add another sample", + () => { + sampleRow(""); + refresh(); + }, + "ghost", + "plus-alt2" + ) + ] + }), + row( + "When it fails, say", + messageInput, + "Shown to the visitor when their answer breaks the rule. Leave empty for the default wording." + ), + el("div", { + class: "atfb-modal__actions", + children: [ + button("window" === chrome ? "Close without saving" : "Cancel", requestClose), + button( + "Save rule", + () => { + const pattern = compileRecipe(recipe); + recipe.tests = readSamples().filter((value) => "" !== value).slice(0, 10); + state.saved = true; + options.onSave({ pattern, recipe, message: recipe.message.trim() }); + requestClose(); + }, + "primary" + ) ] }) ); - overlay.addEventListener("click", (event) => { - if (event.target === overlay) { - close(); - } - }); - document.addEventListener("keydown", onKeydown); - options.root.append(overlay); refresh(); - overlay.querySelector(".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea")?.focus(); } const VALIDATION_GROUPS = ["Contact", "Numbers & codes", "Text shape", "Web"]; const VALIDATION_PRESETS = [ @@ -3432,97 +3583,6 @@ var allTerrainFormsBuilder = function(exports) { const separator = url.includes("?") ? "&" : "?"; openPreviewWindow(formId, title, `${url}${separator}atf_r=${Date.now()}`); } - const FORM_TYPE = "allterrain-forms/form"; - function relations() { - const os = window.wp?.os; - return os?.relations ?? null; - } - function windowIdOf(element) { - const host = element.closest("[data-window-id], .os-window"); - if (!host) { - return null; - } - const attribute = host.getAttribute("data-window-id"); - if (attribute) { - return attribute; - } - const id = host.id ?? ""; - return id ? id.replace(/^wp-window-/, "") : null; - } - const ATTACH_TIMEOUT_MS = 6e3; - const ATTACH_POLL_MS = 120; - function setIdentity(element, ref) { - const api2 = relations(); - wanted.set(element, ref); - if (!api2?.set) { - return; - } - const attempt = (deadline) => { - if (pending.get(element) !== token) { - return; - } - const windowId = windowIdOf(element); - if (!windowId) { - if (Date.now() < deadline) { - window.setTimeout(() => attempt(deadline), ATTACH_POLL_MS); - } - return; - } - try { - api2.set(windowId, ref); - } catch (error) { - if (!warned) { - warned = true; - console.error("[AllTerrain Forms] The shell refused a window identity.", error, ref); - } - pending.delete(element); - return; - } - const stuck = !ref || api2.get?.(windowId)?.id === ref.id; - if (stuck || Date.now() >= deadline) { - pending.delete(element); - return; - } - window.setTimeout(() => attempt(deadline), ATTACH_POLL_MS); - }; - const token = Symbol("atf-identity"); - pending.set(element, token); - attempt(Date.now() + ATTACH_TIMEOUT_MS); - } - let warned = false; - const pending = /* @__PURE__ */ new WeakMap(); - const wanted = /* @__PURE__ */ new Map(); - function reapply() { - for (const [element, ref] of wanted) { - if (!element.isConnected) { - wanted.delete(element); - continue; - } - setIdentity(element, ref); - } - } - if (typeof document !== "undefined") { - for (const event of ["os-window-content-loaded", "os-window-opened"]) { - document.addEventListener(event, () => reapply()); - } - } - function formIdentity(form, adminUrl) { - return { - type: FORM_TYPE, - id: form.id, - label: form.title || "Untitled form", - related: [ - { - id: `allterrain-forms/entries-${form.id}`, - label: "Entries for this form", - url: `${adminUrl}admin.php?page=allterrain-forms-entries&form=${form.id}`, - group: "allterrain-forms", - groupLabel: "Forms", - icon: "dashicons-list-view" - } - ] - }; - } const FIELD_PAYLOAD_TYPE = "allterrain-forms/field"; const MEDIA_PAYLOAD_TYPES = ["openstation/file", "desktop-mode/file", "openstation/attachment"]; const LOGIC_MAP_SETTING = "allterrain-forms/logic-map-v2"; diff --git a/assets/js/builder.min.js b/assets/js/builder.min.js index f15fb09..f76f19e 100644 --- a/assets/js/builder.min.js +++ b/assets/js/builder.min.js @@ -1,3 +1,3 @@ -var allTerrainFormsBuilder=function(Y){"use strict";class $t{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,d=null,c=null,h=0,y=0;const m=()=>{document.removeEventListener("pointermove",E),document.removeEventListener("pointerup",D),document.removeEventListener("pointercancel",U),document.removeEventListener("keydown",F),window.removeEventListener("blur",U),d?.remove(),d=null,t.source.classList.remove("atf-is-dragging"),c?.onLeave?.(v),c=null,this.active=null,this.lastEndMs=Date.now()},v={payload:t,isFinished:()=>l,cancel:(g="caller")=>{l||(l=!0,m(),e.onCancel?.(g))}},S=g=>{o=!0,t.source.classList.add("atf-is-dragging");const L=t.source.getBoundingClientRect();h=t.ghost?.offsetX??a-L.left,y=t.ghost?.offsetY??i-L.top,d=t.ghost?.element??t.source.cloneNode(!0),d.classList.add("atf-drag-ghost"),d.style.width=`${L.width}px`,document.body.appendChild(d),_(g)},_=g=>{d&&(d.style.transform=`translate3d(${g.clientX-h}px, ${g.clientY-y}px, 0)`)},E=g=>{if(l)return;if(!o){if(Math.hypot(g.clientX-a,g.clientY-i)<4)return;S(g)}_(g);const L=this.hitTest(g.clientX,g.clientY);L!==c&&(c?.onLeave?.(v),c=L,c?.onEnter?.(v))},D=g=>{if(l)return;if(!o){l=!0,m(),e.onClickOnly?.();return}const L=c;if(l=!0,m(),L&&L.accept(t)){e.onCommit?.(L),L.onDrop(v,{clientX:g.clientX,clientY:g.clientY});return}e.onCancel?.(L?"rejected":"no-target")},U=()=>v.cancel("pointercancel"),F=g=>{g.key==="Escape"&&v.cancel("escape")};return document.addEventListener("pointermove",E),document.addEventListener("pointerup",D),document.addEventListener("pointercancel",U),document.addEventListener("keydown",F),window.addEventListener("blur",U),this.active=v,v}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=Ct(i.element);if(l>a){s=i,a=l;continue}l===a&&s&&Tt(i.element,s.element)&&(s=i)}return s}}function Ct(n){let e=0,t=n;for(;t;)e++,t=t.parentElement;return e}function Tt(n,e){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function ge(){return window.wp?.os??null}let ve=null;function Z(){const n=ge();return n?.dragManager?n.dragManager:(ve||(ve=new $t),ve)}function At(n){const e=a=>{const i=a.detail?.payload;return i&&n.includes(i.type)?i.source:null},t=a=>e(a)?.classList.add("atf-is-dragging"),s=a=>e(a)?.classList.remove("atf-is-dragging");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 Pe(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 Be(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,d,{source:"allterrain-forms"}):(l,d)=>fetch(l,d))(t,{credentials:"same-origin",...e,headers:s});if(!o.ok){let l=`Request failed with status ${o.status}.`,d="";try{const c=await o.json();l=c.message??l,d=c.code??""}catch{}throw new ie(l,o.status,d)}if(o.status!==204)return await o.json()}const B=n=>ye(n);async function It(n){if(!N?.wpRestUrl)throw new ie("AllTerrain Forms is not configured on this page.",0);const e=N.nonce?{"X-WP-Nonce":N.nonce}:{},t=ge(),s=je(N.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 ie(`Request failed with status ${a.status}.`,a.status);return await a.json()}function Ft(n){if(!n||!n.includes("&"))return n;const e=document.createElement("textarea");return e.innerHTML=n,e.value}const V=(n,e)=>ye(n,{method:"POST",body:JSON.stringify(e)}),re=n=>ye(n,{method:"DELETE"});function He(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 oe(n){const e=n?.schema?.settings;return e&&(!e.themeOverrides||Array.isArray(e.themeOverrides))&&(e.themeOverrides={...e.themeOverrides}),n}const I={config:()=>B("/config"),listForms:()=>B("/forms"),getForm:n=>B(`/forms/${n}`).then(oe),createForm:n=>V("/forms",n).then(oe),updateForm:(n,e)=>V(`/forms/${n}`,e).then(oe),duplicateForm:n=>V(`/forms/${n}/duplicate`,{}).then(oe),deleteForm:n=>re(`/forms/${n}`),preview:(n,e)=>V(`/forms/${n}/preview`,e),pages:()=>It("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(n=>n.map(e=>({id:e.id,title:Ft(e.title?.rendered??"")||`#${e.id}`}))),mergeTags:n=>B(`/forms/${n}/merge-tags`).then(e=>e.groups),analytics:(n,e="")=>B(`/forms/${n}/analytics${e?`?dimension=${encodeURIComponent(e)}`:""}`),demoStatus:()=>B("/demo"),demoSeed:n=>V("/demo",n?{count:n}:{}),demoRemove:()=>re("/demo"),listEntries:n=>B(`/entries${He(n)}`),getEntry:n=>B(`/entries/${n}`),updateEntry:(n,e)=>V(`/entries/${n}`,e),deleteEntry:n=>re(`/entries/${n}`),exportEntries:n=>B(`/entries/export${He(n)}`),listThemes:()=>B("/themes"),saveTheme:n=>V("/themes",n),deleteTheme:n=>re(`/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 M(n){n.replaceChildren()}function R(n){return r("span",{class:`dashicons ${n.startsWith("dashicons-")?n:`dashicons-${n}`}`,attrs:{"aria-hidden":"true"}})}function f(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 k(n,e,t=""){return r("input",{class:"atfb-input",type:"text",value:n,placeholder:t,on:{input:s=>e(s.target.value)}})}function j(n,e){if(te("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 le(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 O(n,e,t){if(te("os-select")&&te("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 q(n,e,t){if(te("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 C(n,e,t="secondary",s){const a=[s?R(s):null,r("span",{text:n})];if(te("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 te(n){return typeof customElements<"u"&&!!customElements.get(n)}const qt=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let ce=null;function Dt(){if(ce)return ce;const n=window.wp?.os;return ce=n?.loadComponents?n.loadComponents(qt).catch(()=>{}):Promise.resolve(),ce}async function we(n,e=""){const t=window.wp?.os;return t?.confirm?t.confirm({title:e,message:n,danger:!0}):window.confirm(n)}function P(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 Ot(n){let e=0,t;return(...s)=>{t=s,!e&&(e=window.requestAnimationFrame(()=>{e=0,n(...t)}))}}function xe(n,e){let t=0;return(...s)=>{window.clearTimeout(t),t=window.setTimeout(()=>n(...s),e)}}function Mt(n){try{return window.localStorage.getItem(n)??""}catch{return""}}function Nt(n,e){try{window.localStorage.setItem(n,e)}catch{}}function We(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 Ue(){const n=[window];try{window.parent&&window.parent!==window&&n.push(window.parent)}catch{}return n}function Rt(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 Pt=4e3,Bt=100;function jt(n,e){const t=Date.now()+Pt,s=()=>{const a=Rt(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&&zt(t);for(const a of Ue())if(a.wp?.os?.openWindow?.(e,{source:"handoff",params:s})){window.setTimeout(()=>jt(a,e),0);return}}function Wt(){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 Ue())if(s.wp?.os?.openWindow?.(t,{source:"handoff"}))return})}const Ut="allterrain-forms/requested-form";function zt(n){try{window.sessionStorage.setItem(Ut,String(n))}catch{}}function ze(n){return`allterrain-forms/requested-form-${n}`}function Yt(n){try{const e=window.sessionStorage.getItem(ze(n));return window.sessionStorage.removeItem(ze(n)),Number(e)||0}catch{return 0}}const _e={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"},Ye=["empty","not_empty"];function Ge(n,e){const t=n.find(s=>s.id===e);return t?t.label||"an untitled question":null}function Xe(n,e,t){return n.find(i=>i.id===e)?.choices?.find(i=>i.value===t)?.label||t}function Gt(n,e){const t=_e[n.operator]??String(n.operator);if(Ye.includes(n.operator))return t;const s=Xe(e,n.field,n.value);return`${n.operator==="is"?"":`${t} `}${s!==""?s:"(nothing)"}`}function Ke(n,e,t=0){const s=Ge(e,n.field),a=_e[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(Ye.includes(n.operator))return i;const o=Xe(e,n.field,n.value);return i.push({kind:"value",text:o!==""?o:"(nothing)",raw:n.value,sourceId:n.field,ruleIndex:t}),i}function Xt(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(...Ke(a,e,i))}),s}function Ve(n){return n.map(e=>e.text).join(" ")}function Kt(n,e){return Ve(Ke(n,e))}function de(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:Kt(a,n),short:Gt(a,n),action:s.action,broken:Ge(n,a.field)===null})}return e}function Vt(n){const e=new Map,t=new Set;for(const s of de(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 Ze=10,Je=22,J="http://www.w3.org/2000/svg";class Zt{constructor(e){this.edges=[],this.teardowns=[],this.frame=0,this.host=e,this.svg=document.createElementNS(J,"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,d=s.right-a.left,c=s.top+s.height/2-a.top,h=Math.max(0,a.width-Ze-Math.max(o,d)),y=22+i*11+Math.min(22,Math.abs(c-l)/8),m=Math.max(12,Math.min(y,h*.4)),v=document.createElementNS(J,"path");v.setAttribute("d",`M ${o} ${l} C ${o+m} ${l}, ${d+m} ${c}, ${d} ${c}`),v.setAttribute("class",`atfb-logicmap__path is-${e.action}${e.broken?" is-broken":""}`),v.dataset.from=e.from,v.dataset.to=e.to;const S=document.createElementNS(J,"title");S.textContent=e.label,v.append(S);const _=document.createElementNS(J,"circle");_.setAttribute("cx",String(d)),_.setAttribute("cy",String(c)),_.setAttribute("r","3.5"),_.setAttribute("class",`atfb-logicmap__dot is-${e.action}${e.broken?" is-broken":""}`),_.dataset.from=e.from,_.dataset.to=e.to,this.svg.append(v,_);const E=document.createElementNS(J,"text");E.setAttribute("x",String(a.width-Ze)),E.setAttribute("y",String(c+3)),E.setAttribute("text-anchor","end"),E.setAttribute("class","atfb-logicmap__label"),E.dataset.from=e.from,E.dataset.to=e.to,E.textContent=e.short.length>Je?`${e.short.slice(0,Je-1)}…`:e.short;const D=document.createElementNS(J,"title");D.textContent=e.label,E.append(D),this.svg.append(E)}}const Jt={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:"summary",color:"text",name:"composite",address:"composite",total:"text",hidden:"static",heading:"static",html:"static",divider:"static",spacer:"static",page_break:"static"};function Qt(n){return Jt[n]??"text"}function Qe(n,e){const t=/^choice:(\d+):(label|value)$/.exec(e);return String(t?n.choices?.[Number(t[1])]?.[t[2]]??"":n[e]??"")}function G(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 es(n){const e=r("input",{class:"atf-choice__input",type:n==="checkboxes"||n==="multiselect"?"checkbox":"radio"});return e.disabled=!0,e}function ts(n,e,t){const s=Qt(n.type),a=G({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,ns(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=G({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 ns(n,e,t,s){switch(t){case"text":return ke(n,"atf-input",s);case"textarea":return ke(n,"atf-input atf-textarea",s,!0);case"select":return r("div",{class:"atfb-preview__select",children:[ke(n,"atf-input atf-select",s)]});case"options":return is(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})(),G({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 rs(n,e,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.`}),n.type==="repeater"?as(n,s):null]})}}function ke(n,e,t,s=!1){const a=G({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 Se(n,e,t,s,a,i){return r("span",{class:`atf-button ${t} atfb-preview__button`,children:[G({value:n,placeholder:e,class:"atfb-preview__button-text",bind:s,onInput:o=>a.edit(l=>i(l,o))})]})}function as(n,e){return Se(String(n.addLabel??""),"Add another","atf-button--secondary","addLabel",e,(t,s)=>{t.addLabel=s})}function is(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:[es(n.type),G({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 d=!l.value||l.value===l.label;l.label=i,d&&(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 rs(n,e,t){return n.type==="heading"?G({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:[G({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:[Se(String(n.prevLabel??""),"Back","atf-button--secondary","prevLabel",t,(s,a)=>{s.prevLabel=a}),Se(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 Le=new Map;function Ee(n){let e=Le.get(n);return e||(e=I.mergeTags(n).catch(()=>[]),Le.set(n,e)),e}function os(n){Le.delete(n)}function ls(n){const e=new Map;for(const t of n)for(const s of t.items)e.set(s.tag,s);return e}function cs(n,e){const t=ls(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 X=null;function se(){X?.remove(),X=null}typeof document<"u"&&(document.addEventListener("pointerdown",n=>{const e=n.target;e?.closest(".atfb-tagpick__open")||X&&!X.contains(e)&&se()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&X&&(se(),n.stopPropagation())}));function et(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 hs(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 us(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 d of n){const c=d.items.filter(h=>!o||h.label.toLowerCase().includes(o)||h.tag.toLowerCase().includes(o));if(!c.length){d.empty&&!o&&!d.items.length&&s.append(r("p",{class:"atfb-tagpick__group",text:d.label}),r("p",{class:"atfb-tagpick__empty",text:d.empty}));continue}s.append(r("p",{class:"atfb-tagpick__group",text:d.label}));for(const h of c)l+=1,s.append(r("button",{class:"atfb-tagpick__item",type:"button",on:{click:()=>{e(h.tag),se()}},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 tt(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:[R("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}Ee(e.formId).then(o=>{a.hidden=!1,a.replaceChildren(r("span",{class:"atfb-taggable__preview-label",text:"Reads as"}),r("span",{text:cs(n.value,o)}))})}};return n.addEventListener("input",i),i(),t.addEventListener("click",o=>{if(o.stopPropagation(),X&&s.contains(X)){se();return}se(),Ee(e.formId).then(l=>{const d=us(l,c=>{et(n,c),i()});s.append(d),X=d,(window.innerHeight-d.getBoundingClientRect().tophs(s))&&d.classList.add("atfb-tagpick--above"),d.querySelector(".atfb-tagpick__search")?.focus()})}),s}function st(n,e){const t=parseFloat(String(n??""));return Number.isFinite(t)?t:e}function nt(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:$e.map(({value:n,label:e})=>({value:n,label:e})),owns:["radius-field","radius-button","radius-card","radius-check"],read:n=>nt(st(n["radius-field"],4),$e),apply:n=>{const e=$e.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:Ce.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=>nt(st(n["pad-field-y"],9),Ce),apply:n=>{const e=Ce.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:ps,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:fs,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:ms,owns:["label-position"],read:n=>n["label-position"]??"top",apply:n=>({"label-position":n})}]}function bs(n){return Te().find(e=>e.owns.includes(n))??null}function at(n){let e=n.activeSlug,t={...n.overrides},s=n.themes;const a=u=>{t=u,n.onOverridesReplaced?.({...u})},i=r("div",{class:"atfs-preview__frame"}),o=r("div",{class:"atfs-controls__body"}),l=r("div",{class:"atfs-quick"}),d=r("div",{class:"atfs-themes"}),c=xe(async()=>{try{const u=await n.previewFor(e,t),p=i.closest(".atf-studio__preview"),b=p?.scrollTop??0;i.innerHTML=u,p&&(p.scrollTop=b),document.dispatchEvent(new CustomEvent("atf-refresh"))}catch(u){M(i),i.append(r("p",{class:"atfb-error",text:u instanceof Error?u.message:"Preview failed."}))}},180),h={"label-position":"atf-labels-","field-style":"atf-fields-"},y=(u,p,b)=>{const w=b.replace(/[^a-z0-9_-]/gi,"");for(const x of[...u.classList])x.startsWith(p)&&u.classList.remove(x);w&&u.classList.add(p+w)},m=u=>{const p=i.querySelector(".atf-form-wrap"),b=p?.querySelector(".atf-form");if(p)for(const[w,x]of Object.entries(u))x===""?p.style.removeProperty(`--atf-${w}`):p.style.setProperty(`--atf-${w}`,x),b&&h[w]&&y(b,h[w],x||(s.find(A=>A.slug===e)?.resolved[w]??""))},v=u=>{m(u.resolved);const p=i.querySelector(".atf-form");p&&(y(p,"atf-theme-",u.slug),p.classList.toggle("atf-is-dark",!!u.dark))},S=u=>t[u.token]!==void 0?t[u.token]:s.find(b=>b.slug===e)?.resolved?.[u.token]??u.default,_=()=>{M(d);for(const u of s){const p=r("button",{class:`atfs-theme${u.slug===e?" is-active":""}`,type:"button",attrs:{"aria-pressed":u.slug===e,title:u.description},children:[r("span",{class:"atfs-theme__chip",style:{background:u.resolved.surface??"#fff",borderColor:u.resolved.border??"#ccc",borderRadius:u.resolved["radius-field"]??"4px",boxShadow:u.resolved["shadow-card"]??"none"},children:[r("span",{class:"atfs-theme__accent",style:{background:u.resolved.accent??"#2271b1",borderRadius:u.resolved["radius-button"]??"4px"}})]}),r("span",{class:"atfs-theme__name",text:u.label}),u.custom?r("span",{class:"atfb-badge",text:"yours"}):null],on:{click:()=>{e=u.slug,a({}),n.onTheme(e),v(u),_(),F(),U(),St()}}});d.append(p)}},E=()=>{const p={...s.find(b=>b.slug===e)?.resolved??{}};for(const[b,w]of Object.entries(t))p[b]=w;return p},D=u=>{const p=l.closest(".atf-studio__controls"),b=p?.scrollTop??0;u(),p&&(p.scrollTop=b)},U=xe(()=>D($),150),F=()=>{const u=E(),p=l.querySelectorAll(".atfs-dial");Te().forEach((b,w)=>{const x=p[w];if(!x)return;const A=b.read(u);if(b.kind==="colour"){const T=x.querySelector('input[type="color"]'),H=x.querySelector("input.atfb-input");T&&document.activeElement!==T&&(T.value=he(A)),H&&document.activeElement!==H&&(H.value=A);return}x.querySelectorAll(".atfs-segment").forEach((T,H)=>{const z=b.steps?.[H]?.value===A;T.classList.toggle("is-on",z),T.setAttribute("aria-pressed",String(z))})})},g=(u,p)=>{const b=u.apply(p,E());for(const[w,x]of Object.entries(b))t[w]=x,n.onOverride(w,x);m(b),F(),U()},L=()=>{M(l);const u=E();for(const p of Te()){const b=p.read(u);let w;if(p.kind==="colour"){const x=r("input",{class:"atfs-color",type:"color",value:he(b),attrs:{"aria-label":p.label},on:{input:A=>g(p,A.target.value)}});w=r("div",{class:"atfs-color-row",children:[x,k(b,A=>g(p,A))]})}else w=r("div",{class:`atfs-segmented atfs-segmented--${p.kind}`,attrs:{role:"group","aria-label":p.label},children:(p.steps??[]).map(x=>r("button",{class:`atfs-segment${x.value===b?" is-on":""}`,type:"button",text:x.label,attrs:{"aria-pressed":x.value===b},on:{click:()=>g(p,x.value)}}))});l.append(r("div",{class:"atfs-dial",children:[r("div",{class:"atfs-dial__head",children:[r("span",{class:"atfs-dial__label",text:p.label}),r("span",{class:"atfs-dial__hint",text:p.hint})]}),w]}))}},$=()=>{M(o);const u=new Map;for(const b of n.tokens){const w=u.get(b.group)??[];w.push(b),u.set(b.group,w)}const p={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[b,w]of u)o.append(r("details",{class:"atfs-group",attrs:{open:b==="colour"},children:[r("summary",{text:p[b]??b}),...w.map(x=>K(x))]}))},K=u=>{const p=S(u),b=T=>{T===""?delete t[u.token]:t[u.token]=T,n.onOverride(u.token,T),m({[u.token]:T})};let w;if(u.control==="color"){const T=r("input",{class:"atfs-color",type:"color",value:he(p),attrs:{"aria-label":`${u.label} colour`},on:{input:z=>{const ae=z.target.value;H.value=ae,b(ae)}}}),H=k(p,z=>{T.value=he(z),b(z)});w=r("div",{class:"atfs-color-row",children:[T,H]})}else if(u.control==="select")w=O(p,(u.options??[]).map(T=>({value:T,label:T})),b);else if(u.control==="length"){const T=parseFloat(p)||0,H=u.unit??"px",z=u.token.includes("radius")?60:80,ae=r("input",{class:"atfs-range",type:"range",value:String(T),attrs:{min:"0",max:String(z),step:"1","aria-label":u.label},on:{input:be=>{const Et=`${be.target.value}${H}`;Lt.value=Et,b(Et)}}}),Lt=k(p,be=>{ae.value=String(parseFloat(be)||0),b(be)});w=r("div",{class:"atfs-length-row",children:[ae,Lt]})}else w=k(p,b);const x=f(u.label,w),A=bs(u.token);return A&&(x.classList.add("is-dialled"),x.append(r("span",{class:"atfs-owned",text:A.label}))),t[u.token]!==void 0&&(x.classList.add("is-overridden"),x.append(r("button",{class:"atfs-reset",type:"button",text:"Reset",attrs:{"aria-label":`Reset ${u.label} to the theme's value`},on:{click:()=>{b(""),D($)}}}))),x},ee=async()=>{const u=s.find(w=>w.slug===e),p=u?`${u.label} (mine)`:"My theme",b=window.prompt("Name this theme",p);if(b)try{const w={};for(const A of n.tokens){const T=S(A);T!==A.default&&(w[A.token]=T)}const x=await I.saveTheme({label:b,tokens:w});s=[...s.filter(A=>A.slug!==x.slug),x],n.onThemesChanged(s),e=x.slug,a({}),n.onTheme(e),_(),F(),D($),P("Theme saved",x.label)}catch(w){P("Could not save the theme",w instanceof Error?w.message:"","error")}},zs=async()=>{const u=s.find(p=>p.slug===e);if(u?.custom&&await we(`Delete “${u.label}”? Forms using it fall back to Clean.`,"Delete theme"))try{await I.deleteTheme(u.id),s=s.filter(b=>b.slug!==u.slug),n.onThemesChanged(s),e="clean",a({}),n.onTheme(e),_(),F(),D($);const p=s.find(b=>b.slug===e);p&&v(p)}catch(p){P("Could not delete the theme",p instanceof Error?p.message:"","error")}},Ys=async()=>{const u=s.find(w=>w.slug===e),p={label:u?.label??e,tokens:{...u?.tokens??{},...t}},b=JSON.stringify(p,null," ");try{await navigator.clipboard.writeText(b),P("Theme copied","Paste it into another site to import it.")}catch{window.prompt("Copy this theme",b)}},Gs=()=>{const u=window.prompt("Paste a theme");if(u)try{const p=JSON.parse(u);if(!p.tokens||typeof p.tokens!="object")throw new Error("That does not look like a theme.");for(const[b,w]of Object.entries(p.tokens))t[b]=String(w),n.onOverride(b,String(w));m({...t}),F(),D($)}catch(p){P("Could not read that theme",p instanceof Error?p.message:"","error")}},kt=C("Delete",()=>void zs(),"danger"),St=()=>{const u=s.find(p=>p.slug===e);kt.hidden=!u?.custom};return _(),L(),$(),c(),St(),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:[C("Save as a theme",()=>void ee(),"primary"),C("Export",()=>void Ys()),C("Import",Gs),kt]})]}),d]}),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 Ae(){const n=document.querySelector("[data-atfs-root]");if(!n||n.dataset.atfsMounted)return;n.dataset.atfsMounted="1",We(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){M(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={},d=o.theme;const c=()=>{M(t),t.append(at({themes:a,tokens:s.tokens,activeSlug:d,overrides:l,standalone:!0,onTheme:h=>{d=h},onOverride:(h,y)=>{y===""?delete l[h]:l[h]=y},onOverridesReplaced:h=>{l={...h}},previewFor:async(h,y)=>{const m=await I.getForm(o.id);m.schema.settings.theme=h,m.schema.settings.themeOverrides=y;const{html:v}=await I.preview(o.id,{schema:m.schema,theme:h});return v},onThemesChanged:h=>{a.length=0,a.push(...h)}}))};e&&(M(e),e.append(r("span",{class:"atfs__label",text:"Preview against"}),O(String(o.id),i.map(h=>({value:String(h.id),label:h.title||"(untitled)"})),h=>{o=i.find(y=>String(y.id)===h)??i[0],l={},c()}))),c()}catch(s){M(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 Ae()):Ae(),document.addEventListener("os-window-content-loaded",()=>void Ae()));function he(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 gs={min:-1,max:-1,sum:-1,avg:-1,round:-1,ceil:1,floor:1,abs:1,sqrt:1,pow:2},it={"+":{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 vs(n,e,t=[]){if(!n||!n.trim()||n.length>2e3)return null;const s=ys(n,e,t),a=ws(s);if(!a)return null;const i=_s(a);if(!i)return null;const o=ks(i);return o===null||!Number.isFinite(o)?null:o}function ys(n,e,t){return n.replace(/\{([a-zA-Z0-9_]+)\}/g,(s,a)=>{const i=Object.prototype.hasOwnProperty.call(e,a)?e[a]:null,o=t.find(d=>d.id===a)??null,l=rt(i,o).toFixed(10).replace(/0+$/,"").replace(/\.$/,"");return l===""||l==="-"?"0":l})}function rt(n,e){if(typeof n=="boolean")return n?1:0;if(Array.isArray(n))return n.reduce((a,i)=>a+rt(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 ws(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 ks(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 Ls=["sum","min","max","avg","round","ceil","floor","abs","sqrt","pow"],Es=["number","range","scale","rating","total","select","multiselect","radio","checkboxes","switch","quiz"];function Ie(n,e){return n.filter(t=>t.id!==e&&Es.includes(t.type))}function $s(n,e){const t={};return Ie(n,e).forEach((s,a)=>{t[s.id]=a+1}),t}function Cs(n){const e=r("div",{class:"atfb-overlay"}),t=()=>{e.remove(),document.removeEventListener("keydown",s)},s=m=>{m.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=$s(n.fields,n.field.id),l=()=>{const m=a.value.trim();if(m===""){i.textContent="Empty. Reference a question below to start.",i.classList.remove("is-error");return}const v=vs(m,o,n.fields);if(v===null){i.textContent="This does not compute yet — check the braces and parentheses.",i.classList.add("is-error");return}const S=Ie(n.fields,n.field.id).map((_,E)=>`${_.label||_.id} = ${E+1}`).join(", ");i.textContent=`With sample answers (${S}): ${v}`,i.classList.remove("is-error")};a.addEventListener("input",l);const d=(m,v,S=0)=>r("button",{class:"atfb-formula__chip",type:"button",text:m,on:{click:()=>{if(et(a,v),S>0){const _=(a.selectionStart??a.value.length)-S;a.setSelectionRange(_,_)}}}}),c=Ie(n.fields,n.field.id),h=r("div",{class:"atfb-formula__chips",children:c.length?c.map(m=>d(m.label||m.id,`{${m.id}}`)):[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:Ls.map(m=>d(`${m}()`,`${m}()`,1))});e.append(r("div",{class:"atfb-modal atfb-formula",attrs:{role:"dialog","aria-label":"Formula editor"},children:[r("h2",{text:"Formula"}),a,i,f("Your questions",h,"Click one to reference its answer."),f("Functions",y),r("div",{class:"atfb-modal__actions",children:[C("Cancel",t),C("Save formula",()=>{n.onSave(a.value.trim()),t()},"primary")]})]})),e.addEventListener("click",m=>{m.target===e&&t()}),document.addEventListener("keydown",s),n.root.append(e),l(),a.focus(),a.setSelectionRange(a.value.length,a.value.length)}const ue={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 Ts(){return{mode:"blocks",starts:"",ends:"",contains:"",notContains:"",chars:[],minLen:"",maxLen:"",regex:"",message:"",tests:[]}}function ot(n){const e=Ts();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 ue)),Array.isArray(s.tests)&&(e.tests=s.tests.filter(a=>typeof a=="string").slice(0,10)),e}function pe(n){return n.replace(/[.*+?^${}()|[\]\\/]/g,"\\$&")}function fe(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(`(?=.*${pe(n.contains)})`),n.notContains!==""&&e.push(`(?!.*${pe(n.notContains)})`),n.starts!==""&&e.push(`(?=${pe(n.starts)})`),n.ends!==""&&e.push(`(?=.*${pe(n.ends)}$)`);const a=n.chars.map(o=>ue[o]?.chars??"").join(""),i=a?`[${a}]*$`:".*$";return!e.length&&!a?"":`^${e.join("")}${i}`}function lt(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=>(ue[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 As(n,e){const t=fe(n);if(t==="")return null;try{return new RegExp(t).test(e)}catch{return null}}function Is(n){const e=ot(String(n.field.validationRecipe??""));e.mode==="blocks"&&fe(e)===""&&n.field.pattern&&(e.mode="regex",e.regex=String(n.field.pattern)),e.message||(e.message=String(n.field.messages?.invalid??""));const t=r("div",{class:"atfb-overlay"});let s=!1;const a=()=>{t.remove(),document.removeEventListener("keydown",i),s||n.onCancel?.()},i=g=>{g.key==="Escape"&&a()},o=(g,L)=>{const $=r("input",{class:"atfb-input",value:e[g],placeholder:L,attrs:{type:"text"}});return $.addEventListener("input",()=>{e[g]=$.value,F()}),$},l=(g,L)=>{const $=r("input",{class:"atfb-input atfb-valwin__len",value:e[g],attrs:{type:"number",min:"0","aria-label":L}});return $.addEventListener("input",()=>{e[g]=$.value,F()}),$},d=r("div",{class:"atfb-valwin__chars",children:Object.entries(ue).map(([g,L])=>{const $=r("input",{attrs:{type:"checkbox",checked:e.chars.includes(g)}});return $.addEventListener("change",()=>{e.chars=$.checked?[...e.chars,g]:e.chars.filter(K=>K!==g),F()}),r("label",{class:"atfb-valwin__char",children:[$,r("span",{text:L.label})]})})}),c=r("div",{class:"atfb-valwin__pane",children:[f("Starts with",o("starts","e.g. AT-")),f("Ends with",o("ends","e.g. -2026")),f("Must contain",o("contains","e.g. @")),f("Must not contain",o("notContains","e.g. spaces? type one")),f("Only these characters",d,"Leave every box unticked to allow anything."),f("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=e.regex,h.addEventListener("input",()=>{e.regex=h.value,F()});const y=r("div",{class:"atfb-valwin__pane",children:[f("Expression",h,"A regular expression, without slashes. Checked against the whole answer only if you anchor it with ^ and $.")]}),m=r("div",{class:"atfb-valwin__tabs",attrs:{role:"tablist"}}),v=()=>{m.replaceChildren(...[["blocks","Easy blocks"],["regex","Expression (advanced)"]].map(([g,L])=>{const $=e.mode===g;return r("button",{class:`atfb-valwin__tab${$?" is-active":""}`,type:"button",text:L,attrs:{role:"tab","aria-selected":$?"true":"false"},on:{click:()=>{e.mode=g,c.hidden=g!=="blocks",y.hidden=g!=="regex",v(),F()}}})}))};v(),c.hidden=e.mode!=="blocks",y.hidden=e.mode!=="regex";const S=r("input",{class:"atfb-input",value:e.message,placeholder:"That is not in the expected format.",attrs:{type:"text"}});S.addEventListener("input",()=>{e.message=S.value});const _=r("p",{class:"atfb-valwin__summary",attrs:{"aria-live":"polite"}}),E=r("div",{class:"atfb-valwin__samples"}),D=g=>{const L=r("span",{class:"atfb-valwin__verdict",attrs:{"aria-live":"polite"}}),$=r("input",{class:"atfb-input",value:g,placeholder:"Type a sample answer…",attrs:{type:"text"}});$.addEventListener("input",()=>F()),E.append(r("div",{class:"atfb-valwin__sample",children:[$,L]}))};for(const g of e.tests.length?e.tests:["","",""])D(g);const U=()=>Array.from(E.querySelectorAll("input")).map(g=>g.value),F=()=>{const g=lt(e);_.textContent=g||"Nothing yet — fill in a block above and the rule appears here in plain words.";for(const L of Array.from(E.querySelectorAll(".atfb-valwin__sample"))){const $=L.querySelector("input"),K=L.querySelector(".atfb-valwin__verdict");if(!$||!K)continue;const ee=$.value===""?null:As(e,$.value);K.textContent=ee===null?"·":ee?"✓ passes":"✗ fails",K.classList.toggle("is-pass",ee===!0),K.classList.toggle("is-fail",ee===!1)}};t.append(r("div",{class:"atfb-modal atfb-valwin",attrs:{role:"dialog","aria-label":"Custom validation rule"},children:[r("h2",{text:"Custom rule"}),r("p",{class:"atfb-hint",text:`Describe what a good answer to “${n.field.label||"this question"}” looks like — no code needed.`}),m,c,y,r("div",{class:"atfb-valwin__try",children:[r("h3",{text:"Try it out"}),_,E,C("Add another sample",()=>{D(""),F()},"ghost","plus-alt2")]}),f("When it fails, say",S,"Shown to the visitor when their answer breaks the rule. Leave empty for the default wording."),r("div",{class:"atfb-modal__actions",children:[C("Cancel",a),C("Save rule",()=>{const g=fe(e);e.tests=U().filter(L=>L!=="").slice(0,10),s=!0,n.onSave({pattern:g,recipe:e,message:e.message.trim()}),a()},"primary")]})]})),t.addEventListener("click",g=>{g.target===t&&a()}),document.addEventListener("keydown",i),n.root.append(t),F(),t.querySelector(".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea")?.focus()}const Fs=["Contact","Numbers & codes","Text shape","Web"],ct=[{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 qs(n){return ct.find(e=>e.slug===n)??null}function Fe(){return window.wp?.os??null}const dt="allterrain-forms/preview",qe="allterrain-forms-preview";function Ds(n){const e=Fe();if(!e?.registerTitleBarButton)return()=>{};const t=()=>{try{e.registerTitleBarButton({id:dt,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 ht(n),owner:"allterrain-forms-builder"})}catch{}};return e.ready?e.ready(t):t(),()=>{try{e.unregisterTitleBarButton?.(dt)}catch{}}}async function ht(n){n.isDirty()&&await n.save();const e=n.current();e&&ut(e.id,e.title,e.previewUrl)}function ut(n,e,t){const s=Fe();if(!s?.windowManager?.open){window.open(t,"_blank","noopener");return}s.windowManager.open({id:`${qe}-${n}`,baseId:qe,url:t,title:`Preview: ${e}`,icon:"dashicons-visibility"})}function Os(n,e,t){if(!Fe()?.windowManager?.open||!document.querySelector(`[data-window-id="${qe}-${n}"]`))return;const i=t.includes("?")?"&":"?";ut(n,e,`${t}${i}atf_r=${Date.now()}`)}const Ms="allterrain-forms/form";function Ns(){return window.wp?.os?.relations??null}function Rs(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 Ps=6e3,pt=120;function ft(n,e){const t=Ns();if(De.set(n,e),!t?.set)return;const s=i=>{if(me.get(n)!==a)return;const o=Rs(n);if(!o){Date.now()s(i),pt);return}try{t.set(o,e)}catch(d){mt||(mt=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",d,e)),me.delete(n);return}if(!e||t.get?.(o)?.id===e.id||Date.now()>=i){me.delete(n);return}window.setTimeout(()=>s(i),pt)},a=Symbol("atf-identity");me.set(n,a),s(Date.now()+Ps)}let mt=!1;const me=new WeakMap,De=new Map;function Bs(){for(const[n,e]of De){if(!n.isConnected){De.delete(n);continue}ft(n,e)}}if(typeof document<"u")for(const n of["os-window-content-loaded","os-window-opened"])document.addEventListener(n,()=>Bs());function js(n,e){return{type:Ms,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 ne="allterrain-forms/field",Hs=["openstation/file","desktop-mode/file","openstation/attachment"],bt="allterrain-forms/logic-map-v2";function W(n,e){return n.dataset.atfbBind=e,n}const gt={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"}},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"}}},Ws={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 vt(n,e,t){const s=n[e.key],a=i=>t(e.key,i);if(e.control==="checkbox")return q(e.label,!!s,a);if(e.control==="commas"){const i=Array.isArray(s)?s:[];return f(e.label,k(i.join(", "),o=>{a(o.split(",").map(l=>l.trim().replace(/^\./,"").toLowerCase()).filter(Boolean))}),e.hint)}return e.control==="select"?f(e.label,O(String(s??""),e.options??[],a),e.hint):e.control==="textarea"?f(e.label,le(String(s??""),a),e.hint):e.control==="number"?f(e.label,j(String(s??""),a),e.hint):f(e.label,W(k(String(s??""),a),e.key),e.hint)}function yt(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 wt(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 Oe=[{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}"}],Us=["About the person filling it in","The date and time","About this site"],Me=(n,e)=>N?.i18n?.[n]??e;class xt{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=Mt(bt)!=="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=xe(()=>{this.save(!0)},2500),this.renderInspector=Ot(()=>{if(M(this.inspector),!this.schema||(this.root.classList.toggle("atfb--build-only-panes",this.tab!=="build"),this.tab!=="build"))return;const t=this.schema.fields.find(o=>o.id===this.selected);if(this.root.classList.toggle("atfb--has-selection",!!t),!t){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 s=this.config?.fieldTypes.find(o=>o.type===t.type),a=s?.supports??[],i=(o,l)=>{const d=this.liveField(t.id);d&&(d[o]=l,this.markDirty(),this.renderCanvas())};this.inspector.append(r("h3",{class:"atfb-inspector__title",text:s?.label??t.type}),r("p",{class:"atfb-hint",text:`Reference this field as {field:${t.id}}`})),a.includes("label")&&this.inspector.append(f("Label",W(k(t.label,o=>i("label",o)),"label"))),a.includes("placeholder")&&this.inspector.append(f("Placeholder",W(k(t.placeholder,o=>i("placeholder",o)),"placeholder"))),a.includes("hint")&&this.inspector.append(f("Hint",W(k(t.hint,o=>i("hint",o)),"hint"),"Shown under the field, and read out with it.")),a.includes("nextlabel")&&this.inspector.append(f("Next button",W(k(String(t.nextLabel??""),o=>i("nextLabel",o)),"nextLabel"),"Leave empty for “Next”.")),a.includes("prevlabel")&&this.inspector.append(f("Back button",W(k(String(t.prevLabel??""),o=>i("prevLabel",o)),"prevLabel"),"Leave empty for “Back”.")),a.includes("addlabel")&&this.inspector.append(f("Add button",W(k(String(t.addLabel??""),o=>i("addLabel",o)),"addLabel"),"Leave empty for “Add another”.")),a.includes("required")&&this.inspector.append(q("Required",t.required,o=>i("required",o))),a.includes("width")&&this.inspector.append(f("Width",O(t.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"}],o=>i("width",o)))),s?.choices&&this.inspector.append(this.renderChoicesEditor(t,i)),this.renderTypeSettings(t,s,a,i),(t.type==="total"||a.includes("formula"))&&this.inspector.append(f("Formula",r("div",{class:"atfb-formula__row",children:[k(String(t.formula??""),o=>i("formula",o)),C("Formula editor",()=>Cs({root:this.root,fields:this.schema?.fields??[],field:t,onSave:o=>{i("formula",o),this.renderInspector()}}))]}),"Reference answers with braces — {f1} * {f2} + 10 — or open the editor and click them in."),f("Currency symbol",k(String(t.currency??""),o=>i("currency",o)))),this.inspector.append(this.renderValidationSection(t,a,i)),this.inspector.append(this.renderLogicSection(t,i)),a.includes("prefill")&&this.inspector.append(this.prefillControl(t,i)),a.includes("css")&&this.inspector.append(f("CSS class",k(t.cssClass,o=>i("cssClass",o))))}),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(At([ne])),this.teardowns.push(Ds({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=Yt("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){M(this.bar),this.bar.append(r("p",{class:"atfb-error",text:e instanceof Error?e.message:"Something went wrong loading your forms."}))}renderBar(){M(this.bar);const e=O(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),C("New",()=>void this.showTemplates(),"secondary","plus-alt2"),C("Export",()=>void this.exportForm(),"secondary","download"),C("Import",()=>void this.importForm(),"secondary","upload"),C("Preview",()=>void this.preview(),"secondary","visibility"),C("Entries",()=>this.openEntries(),"secondary","list-view"),this.logicMapButton(),this.saveButton()]}))}liveField(e){return this.schema?.fields.find(t=>t.id===e)}syncCanvas(e){const t=this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`);if(t)for(const s of t.querySelectorAll(".atfb-editable[data-atfb-bind]")){const a=Qe(e,s.dataset.atfbBind??"");s.textContent!==a&&(s.textContent=a)}}syncInspector(e){if(this.selected===e.id)for(const t of this.inspector.querySelectorAll("[data-atfb-bind]")){const s=Qe(e,t.dataset.atfbBind??"");t.value!==s&&("value"in t?t.value=s:t.setAttribute("value",s))}}rebindCanvas(){if(this.tab!=="build")return;const e=document.activeElement;if(e instanceof HTMLElement&&this.canvas.contains(e)){e.addEventListener("blur",()=>this.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=C(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(),P("Form imported",a.title)}catch(s){P("Could not import that file",s instanceof Error?s.message:"","error")}}),e.click()}saveButton(){const e=C("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)}os(s.id);const a=this.forms.find(i=>i.id===s.id);a&&(a.title=s.title),Os(s.id,s.title,s.previewUrl),e||P("Form saved",s.title)}catch(s){P(Me("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 we("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&&ft(this.root,js(this.form,N?.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){P("Could not create the form",o instanceof Error?o.message:"","error")}}},children:[R(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,r("div",{class:"atfb-modal__actions",children:[C("Cancel",s)]})]})),e.addEventListener("click",i=>{i.target===e&&s()}),document.addEventListener("keydown",t),this.root.append(e),a.querySelector("button")?.focus()}renderFormsList(){M(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."}),C("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(`${N?.adminUrl??""}admin.php?page=allterrain-forms-entries`)}renderPalette(){if(!this.config)return;M(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:[R(e.icon),r("span",{text:e.label})]});return t.addEventListener("pointerdown",s=>{const a=r("div",{class:"atfb-chip atfb-chip--ghost",children:[R(e.icon),r("span",{text:e.label})]});Z().start({payload:Pe(ne,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(M(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:Me("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=Oe.some(m=>m.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"}),d=m=>{if(o.replaceChildren(),l.replaceChildren(),m==="query"){const v=e.prefill.startsWith("query:")?e.prefill.slice(6):"";o.append(k(v,S=>{const _=S.trim();t("prefill",_?`query:${_}`:""),c(`query:${_}`)},"utm_source"),r("p",{class:"atfb-row__hint",text:"The name of the parameter in the link people arrive on."}))}m==="custom"&&o.append(k(e.prefill,v=>{t("prefill",v),c(v)},"myplugin:something"),r("p",{class:"atfb-row__hint",text:"For a source another plugin has added through atf_resolve_prefill."})),c(e.prefill)},c=m=>{if(l.replaceChildren(),!m)return;if(m.startsWith("query:")){const S=m.slice(6);S&&(l.textContent=`A visit to …/your-page/?${S}=abc opens the form with “abc” in it.`);return}const v=Oe.find(S=>S.value===m)?.tag;v&&Ee(this.form?.id??0).then(S=>{for(const _ of S)for(const E of _.items)if(E.tag===v){const D=m.startsWith("user:");if(!E.sample){l.textContent="Empty unless the visitor is signed in.";return}l.textContent=D?`Opens with “${E.sample}” for you — empty for a visitor who is not signed in.`:`Opens with “${E.sample}”.`;return}})};d(i);const h=r("select",{class:"atfb-input atfb-select",on:{change:m=>{const v=m.target.value;t("prefill",v==="query"||v==="custom"?"":v),d(v)}}});h.append(r("option",{value:"",text:"Nothing — leave it empty",attrs:{selected:i===""}}));for(const m of Us){const v=document.createElement("optgroup");v.label=m;for(const S of Oe.filter(_=>_.group===m))v.append(r("option",{value:S.value,text:S.label,attrs:{selected:S.value===i}}));h.append(v)}const y=document.createElement("optgroup");return y.label="From the link they arrived on",y.append(r("option",{value:"query",text:"A parameter in the web address",attrs:{selected:i==="query"}})),h.append(y,r("option",{value:"custom",text:"Something else (advanced)",attrs:{selected:i==="custom"}})),f("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":Ve(t)},children:[R("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(de(this.schema?.fields??[]));return}this.renderCanvas(),this.renderInspector(),a&&window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-cond="${CSS.escape(a)}"]`)?.focus()})}}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 r("select",{class:"atfb-cond__op",title:"How the answer is compared.",attrs:{"aria-label":"How the answer is compared","data-cond":s},on:{change:a=>{const i=a.target.value;this.editCondition(e.id,o=>{const l=o.rules[t.ruleIndex];l&&(l.operator=i)},!0,s)}},children:Object.entries(_e).map(([a,i])=>r("option",{value:a,text:i,attrs:{selected:a===t.operator}}))})}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(d=>d.id===t.sourceId),i=(d,c)=>this.editCondition(e.id,h=>{const y=h.rules[t.ruleIndex];y&&(y.value=d)},c,s);if(a?.choices?.length){const d=a.choices.map(c=>r("option",{value:c.value,text:c.label||c.value,attrs:{selected:c.value===t.raw}}));return t.raw!==""&&!a.choices.some(c=>c.value===t.raw)&&d.unshift(r("option",{value:t.raw,text:t.text,attrs:{selected:!0}})),r("select",{class:"atfb-cond__chip atfb-cond__chip--value atfb-cond__value",title:"The answer that triggers this.",attrs:{"aria-label":"The answer that triggers this","data-cond":s},on:{change:c=>i(c.target.value,!0)},children:d})}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",d=>{d.key==="Enter"&&(d.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=de(this.schema?.fields??[]).length>0,t=C(this.logicMapOn?"Hide logic":"Show logic",()=>{this.logicMapOn=!this.logicMapOn,Nt(bt,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=de(t);if(!s.length||!this.logicMapOn)return;e.classList.add("has-logicmap");const a=new Zt(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(c=>c.type===e.type),a=this.selected===e.id,i=this.schema?.fields??[],o=Xt(e,i),l=Vt(i).get(e.id)??0,d=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__grip",attrs:{"aria-hidden":"true"},children:[R("menu")]}),r("div",{class:"atfb-card__body",children:[r("div",{class:"atfb-card__head",children:[R(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]}),ts(e,s,{edit:c=>{const h=this.liveField(e.id);h&&(c(h),this.markDirty(),this.syncInspector(h))},restructure:c=>{const h=this.liveField(e.id);h&&(this.snapshot(),c(h),this.markDirty(),this.renderCanvas(),this.renderInspector())}}),o.length?this.renderCondition(e,o):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))]})]});return d.addEventListener("click",c=>{c.target.closest(".atfb-card__actions")||Z().recentlyEndedDrag()||this.selectField(e.id)}),d.addEventListener("keydown",c=>{if(c.key==="Enter"||c.key===" "){c.preventDefault(),this.selectField(e.id);return}c.altKey&&(c.key==="ArrowUp"||c.key==="ArrowDown")&&(c.preventDefault(),this.moveField(e.id,c.key==="ArrowUp"?t-1:t+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})),(c.key==="Delete"||c.key==="Backspace")&&(c.preventDefault(),this.deleteField(e.id))}),d.addEventListener("pointerdown",c=>{c.target.closest(".atfb-card__actions")||Z().start({payload:Pe(ne,d,{fieldId:e.id,field:e,isNew:!1},c),origin:c})}),d}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:[R(e)]})}registerCanvasTarget(e){this.canvasTarget?.(),this.canvasTarget=null;const t=r("div",{class:"atfb-marker",attrs:{"aria-hidden":"true"}}),s=Z().registerDropTarget({id:`atfb-canvas-${this.form?.id??0}`,element:e,accept:i=>i.type===ne,onEnter:()=>e.classList.add("is-dropping"),onLeave:()=>{e.classList.remove("is-dropping"),t.remove()},onDrop:(i,o)=>{e.classList.remove("is-dropping"),t.remove();const l=i.payload.data,d=l.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(l.fieldId)}"]`):null,c=Be(e,".atfb-card",o.clientY,d??void 0);if(l.isNew&&l.fieldType){this.addField(l.fieldType,c);return}if(l.fieldId&&this.schema?.fields.some(h=>h.id===l.fieldId)){this.moveField(l.fieldId,c);return}l.field&&this.insertField({...l.field,id:""},c)}}),a=i=>{const o=i.detail;if(o?.payload?.type!==ne||!e.classList.contains("is-dropping"))return;const l=o.payload.data?.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(o.payload.data.fieldId)}"]`):null,d=o.clientY??0,c=Be(e,".atfb-card",d,l??void 0),h=Array.from(e.querySelectorAll(".atfb-card")).filter(y=>y!==l);c>=h.length?e.append(t):h[c].before(t)};document.addEventListener("os.drag.move",a),this.canvasTarget=()=>{s(),document.removeEventListener("os.drag.move",a)}}addField(e,t){const s=this.config?.fieldTypes.find(i=>i.type===e);if(!s||!this.schema)return;const a={id:this.nextFieldId(),type:e,label:s.input?s.label:"",placeholder:"",hint:"",required:!1,width:"full",cssClass:"",default:"",choices:s.choices?[{label:"First choice",value:"first"},{label:"Second choice",value:"second"}]:[],logic:{enabled:!1,action:"show",match:"all",rules:[]},messages:{},prefill:"",...s.settings};this.insertField(a,t)}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=wt(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.schema.fields.findIndex(a=>a.id===e);if(t<0)return;const s=JSON.parse(JSON.stringify(this.schema.fields[t]));s.id=this.nextFieldId(),this.insertField(s,t+1)}async deleteField(e){if(!this.schema)return;const t=this.schema.fields.filter(a=>a.logic?.rules?.some(i=>i.field===e)),s=t.length?`Delete this field? ${t.length} other field${t.length===1?"":"s"} use it in a condition, and those conditions will stop working.`:Me("confirmDelete","Delete this? It cannot be undone.");await we(s,"Delete field")&&(this.snapshot(),this.schema.fields=this.schema.fields.filter(a=>a.id!==e),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")}this.logicMap?.highlight(e),this.renderInspector()}nextFieldId(){const e=new Set((this.schema?.fields??[]).map(s=>s.id));let t=e.size+1;for(;e.has(`f${t}`);)t++;return`f${t}`}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=gt[i];o&&(this.inspector.append(vt(e,o,a)),o.also&&this.inspector.append(vt(e,{...o,key:o.also.key,label:o.also.label,hint:o.also.hint},a)))}s.includes("rows")&&e.type!=="likert"&&this.inspector.append(f("Lines tall",j(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 f("Statements",le(s.map(a=>a.label??"").join(` -`),a=>t("rows",yt(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=>q(l.label,i.includes(l.key),d=>{const c=a.map(h=>h.key).filter(h=>h===l.key?d:i.includes(h));s("parts",c.length?c:[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"?q("On by default",!!e.default,i=>s("default",i)):t?.choices&&(e.choices??[]).length?f("Default answer",O(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):f("Default answer",k(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 d=r("div",{class:"atfb-choice-row",children:[e.type==="image_choice"?this.choiceImageWell(o,l,e):null,W(k(o.label,c=>{const h=a(l);if(!h)return;const y=!h.value||h.value===h.label;h.label=c,y&&(h.value=c),this.markDirty();const m=this.liveField(e.id);m&&this.syncCanvas(m)}),`choice:${l}:label`),W(k(o.value,c=>{const h=a(l);h&&(h.value=c,this.markDirty())},"value"),`choice:${l}:value`),e.type==="quiz"||o.points!==void 0?j(String(o.points??""),c=>{const h=a(l);h&&(h.points=c===""?void 0:Number(c),this.markDirty())}):j(String(o.price??""),c=>{const h=a(l);h&&(h.price=c===""?void 0:Number(c),this.markDirty())}),r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":`Remove ${o.label}`},on:{click:()=>{const c=this.liveField(e.id);c&&((c.choices??[]).splice(l,1),t("choices",c.choices),this.renderInspector())}},children:[R("trash")]})]});i.append(d)}),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,C("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"?f("Correct answer",O(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}`}):R("format-image")]}),i=Z().registerDropTarget({id:`atfb-well-${s.id}-${t}`,element:a,accept:o=>Hs.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,d=Number(l.attachmentId??l.id??l.file?.id??0);if(!d){P("That is not an image this field can use","","error");return}const c=this.liveField(s.id)?.choices?.[t];c&&(c.image=d,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,d]of i)a.push(f(d,k(String(e[l]??""),c=>s(l,c))));t.includes("pattern")&&a.push(...this.renderAnswerShapeRows(e,s)),t.includes("unique")&&a.push(q("No two people may submit the same value",!!e.unique,l=>s("unique",l)));const o=e.messages??{};return t.includes("required")&&a.push(f("Message when required",k(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"})}renderAnswerShapeRows(e,t){const a=(typeof e.validation=="string"?e.validation:"")||(e.pattern?"custom":""),i=()=>Is({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 y={...this.liveField(e.id)?.messages??{}};y.invalid=h.message,t("messages",y),this.renderInspector()},onCancel:()=>this.renderInspector()}),o=r("select",{class:"atfb-input atfb-select",attrs:{"aria-label":"What the answer should look like"},on:{change:h=>{const y=h.target.value;if(y==="custom"){i();return}t("validation",y),t("pattern",""),t("validationRecipe",""),this.renderInspector()}}});o.append(r("option",{value:"",text:"Anything at all",attrs:{selected:a===""}}));for(const h of Fs){const y=document.createElement("optgroup");y.label=h;for(const m of ct.filter(v=>v.group===h))y.append(r("option",{value:m.slug,text:m.label,attrs:{selected:m.slug===a}}));o.append(y)}const l=document.createElement("optgroup");l.label="Your own",l.append(r("option",{value:"custom",text:"A custom rule…",attrs:{selected:a==="custom"}})),o.append(l);const d=qs(a),c=[f("The answer should be",o,d?`e.g. ${d.example}`:"Checked as they type, and again on the server.")];if(a==="custom"){const h=ot(String(e.validationRecipe??"")),y=lt(h)||(e.pattern?`Matches the expression ${String(e.pattern)}`:"No rule yet — open the builder.");c.push(f("Your rule",r("div",{class:"atfb-valrule",children:[r("p",{class:"atfb-valrule__words",text:y}),C("Edit the rule…",i,"secondary","edit")]}),fe(h)||e.pattern?"Built in the rule builder, with a playground to test it.":void 0))}return c}renderLogicSection(e,t){const s=e.logic,a=()=>this.liveField(e.id)?.logic,i=(this.schema?.fields??[]).filter(l=>l.id!==e.id&&l.type!=="page_break"),o=r("div",{class:"atfb-rules"});return s.rules.forEach((l,d)=>{o.append(r("div",{class:"atfb-rule",children:[O(l.field,i.map(c=>({value:c.id,label:c.label||c.id})),c=>{const h=a()?.rules[d];h&&(h.field=c,this.markDirty())}),O(l.operator,Object.entries(this.config?.operators??{}).map(([c,h])=>({value:c,label:h})),c=>{const h=a()?.rules[d];h&&(h.operator=c,this.markDirty())}),k(l.value,c=>{const h=a()?.rules[d];h&&(h.value=c,this.markDirty())}),r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":"Remove this rule"},on:{click:()=>{const c=a();c&&(c.rules.splice(d,1),t("logic",c),this.renderInspector())}},children:[R("trash")]})]}))}),this.section(`logic:${e.id}`,"Conditional logic",[q("Only show this field sometimes",s.enabled,l=>{const d=a();d&&(d.enabled=l,t("logic",d),this.renderInspector())}),s.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[O(s.action,[{value:"show",label:"Show"},{value:"hide",label:"Hide"}],l=>{const d=a();d&&(d.action=l,t("logic",d))}),r("span",{text:"this field when"}),O(s.match,[{value:"all",label:"all"},{value:"any",label:"any"}],l=>{const d=a();d&&(d.match=l,t("logic",d))}),r("span",{text:"of these match:"})]}),o,C("Add rule",()=>{const l=a();l&&(l.rules.push({field:i[0]?.id??"",operator:"is",value:""}),t("logic",l),this.renderInspector())},"ghost","plus-alt2")]}):null],s.enabled)}renderTabCanvas(){return this.schema?this.tab==="theme"?at({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=/