domma-cms 0.36.3 → 0.36.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/admin/css/admin.css +1 -1
  2. package/admin/js/lib/card-builder.js +3 -3
  3. package/admin/js/lib/editor-folding.js +1 -1
  4. package/admin/js/lib/effects-builder.js +2 -2
  5. package/admin/js/lib/markdown-toolbar.js +3 -3
  6. package/admin/js/lib/shortcode-modal.js +1 -1
  7. package/admin/js/lib/timeline-builder.js +2 -2
  8. package/admin/js/views/actions-list.js +1 -1
  9. package/admin/js/views/api-endpoint-editor.js +3 -3
  10. package/admin/js/views/api-endpoints.js +2 -2
  11. package/admin/js/views/api-tokens.js +4 -4
  12. package/admin/js/views/blocks.js +5 -5
  13. package/admin/js/views/collection-editor.js +4 -4
  14. package/admin/js/views/collection-entries.js +1 -1
  15. package/admin/js/views/component-editor.js +1 -1
  16. package/admin/js/views/components.js +2 -2
  17. package/admin/js/views/effects.js +1 -1
  18. package/admin/js/views/form-editor.js +7 -7
  19. package/admin/js/views/layouts.js +1 -1
  20. package/admin/js/views/login.js +1 -1
  21. package/admin/js/views/menu-editor.js +8 -8
  22. package/admin/js/views/menu-locations.js +1 -1
  23. package/admin/js/views/menus.js +3 -3
  24. package/admin/js/views/my-profile.js +1 -1
  25. package/admin/js/views/notifications.js +1 -1
  26. package/admin/js/views/page-editor.js +29 -29
  27. package/admin/js/views/project-detail.js +1 -1
  28. package/admin/js/views/project-editor.js +1 -1
  29. package/admin/js/views/project-settings.js +1 -1
  30. package/admin/js/views/projects.js +2 -2
  31. package/admin/js/views/user-editor.js +1 -1
  32. package/admin/js/views/view-editor.js +1 -1
  33. package/admin/js/views/view-preview.js +1 -1
  34. package/admin/js/views/views-list.js +1 -1
  35. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import{api as w}from"../api.js";const ee=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"hidden",label:"Hidden field"}],Q=new Set(["select","radio","checkbox-group"]),ae=["public","token","subscriber","editor","manager","admin"],te=["create","read","update","delete"];let g=[],h=null,S=!0,F=null,B="file",X={};function le(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function ne(e){return ee.find(t=>t.value===e)?.label||e}function oe(e){const t={...g[e]},n=document.getElementById(`fb-label-${e}`),d=document.getElementById(`fb-name-${e}`),s=document.getElementById(`fb-type-${e}`),r=document.getElementById(`fb-required-${e}`),u=document.getElementById(`fb-placeholder-${e}`),l=document.getElementById(`fb-helper-${e}`);if(n&&(t.label=n.value.trim()||t.label),d&&(t.name=d.value.trim()||t.name),s&&(t.type=s.value||t.type),r&&(t.required=r.checked),u&&(t.placeholder=u.value.trim()),l&&(t.helper=l.value.trim()),Q.has(t.type)){const a=document.getElementById(`fb-options-${e}`);a&&(t.options=a.value.split(`
2
- `).filter(c=>c.trim()).map(c=>{const[p,...y]=c.split(":");return{value:p.trim(),label:y.join(":").trim()||p.trim()}}))}const o=document.getElementById(`fb-span-${e}`);if(document.getElementById(`fb-fullwidth-${e}`)?.checked)t.fullWidth=!0,delete t.span;else{delete t.fullWidth;const a=parseInt(o?.value,10);a>1?t.span=a:delete t.span}return t}function Z(){return g.map((e,t)=>oe(t))}function de(e,t){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border,#333);border-radius:8px;margin-bottom:.75rem;overflow:hidden;";const d=document.createElement("div");d.className="fb-field-header",d.style.cssText="display:flex;align-items:center;gap:.5rem;padding:.6rem .75rem;background:var(--dm-card-header-bg,rgba(255,255,255,.03));cursor:pointer;user-select:none;";const s=document.createElement("span");s.textContent="\u283F",s.style.cssText="cursor:grab;opacity:.4;font-size:1.1rem;flex-shrink:0;",n.draggable=!0,s.addEventListener("mousedown",()=>{n.draggable=!0}),n.addEventListener("dragstart",i=>{F=t,i.dataTransfer.effectAllowed="move",n.style.opacity="0.4"}),n.addEventListener("dragend",()=>{n.style.opacity="",document.querySelectorAll(".fb-field-card").forEach(i=>i.classList.remove("fb-drag-over"))}),n.addEventListener("dragover",i=>{i.preventDefault(),i.dataTransfer.dropEffect="move",document.querySelectorAll(".fb-field-card").forEach(C=>C.classList.remove("fb-drag-over")),n.classList.add("fb-drag-over")}),n.addEventListener("dragleave",()=>{n.classList.remove("fb-drag-over")}),n.addEventListener("drop",i=>{if(i.preventDefault(),n.classList.remove("fb-drag-over"),F===null||F===t)return;g=Z();const[C]=g.splice(F,1);g.splice(t,0,C),F=null,H(document.getElementById("fields-list"))});const r=document.createElement("span");r.className="fb-field-summary",r.style.cssText="flex:1;font-weight:500;font-size:.9rem;",r.textContent=e.label||"(Untitled field)";const u=document.createElement("span");u.style.cssText="font-size:.75rem;opacity:.5;",u.textContent=ne(e.type);const l=document.createElement("span");l.className="fb-field-chevron",l.textContent="\u25BE",l.style.cssText="opacity:.5;transition:transform .2s;";const o=document.createElement("button");o.type="button",o.innerHTML='<span data-icon="x"></span>',o.className="btn btn-sm btn-ghost",o.style.cssText="padding:.15rem .45rem;line-height:1;opacity:.6;",o.title="Remove field",o.addEventListener("click",i=>{i.stopPropagation(),g.splice(t,1),H(document.getElementById("fields-list"))}),d.appendChild(s),d.appendChild(r),d.appendChild(u),d.appendChild(l),d.appendChild(o),Domma.icons.scan(o);const a=document.createElement("div");a.className="fb-field-body",a.style.cssText="padding:.75rem;display:none;";const c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:1fr 1fr 1fr;gap:.6rem;margin-bottom:.6rem;";const p=document.createElement("div"),y=document.createElement("label");y.className="form-label",y.textContent="Label";const b=document.createElement("input");b.id=`fb-label-${t}`,b.type="text",b.className="form-input",b.value=e.label||"",b.addEventListener("input",()=>{r.textContent=b.value.trim()||"(Untitled field)";const i=document.getElementById(`fb-name-${t}`);i&&!i.dataset.manual&&(i.value=le(b.value).replace(/-/g,"_"))}),p.appendChild(y),p.appendChild(b);const f=document.createElement("div"),$=document.createElement("label");$.className="form-label",$.textContent="Name (key)";const v=document.createElement("input");v.id=`fb-name-${t}`,v.type="text",v.className="form-input",v.value=e.name||"",v.addEventListener("input",()=>{v.dataset.manual="1"}),f.appendChild($),f.appendChild(v);const T=document.createElement("div"),L=document.createElement("label");L.className="form-label",L.textContent="Type";const m=document.createElement("select");m.id=`fb-type-${t}`,m.className="form-input",ee.forEach(i=>{const C=document.createElement("option");C.value=i.value,C.textContent=i.label,i.value===e.type&&(C.selected=!0),m.appendChild(C)}),m.addEventListener("change",()=>{u.textContent=ne(m.value);const i=a.querySelector(".fb-options-wrap");i&&(i.style.display=Q.has(m.value)?"":"none")}),T.appendChild(L),T.appendChild(m),c.appendChild(p),c.appendChild(f),c.appendChild(T);const N=document.createElement("div");N.style.cssText="display:grid;grid-template-columns:1fr 1fr auto;gap:.6rem;align-items:end;margin-bottom:.6rem;";const I=document.createElement("div"),P=document.createElement("label");P.className="form-label",P.textContent="Placeholder";const j=document.createElement("input");j.id=`fb-placeholder-${t}`,j.type="text",j.className="form-input",j.value=e.placeholder||"",I.appendChild(P),I.appendChild(j);const O=document.createElement("div"),V=document.createElement("label");V.className="form-label",V.textContent="Helper text";const q=document.createElement("input");q.id=`fb-helper-${t}`,q.type="text",q.className="form-input",q.value=e.helper||"",O.appendChild(V),O.appendChild(q);const Y=document.createElement("div");Y.style.cssText="padding-bottom:.35rem;";const M=document.createElement("label");M.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const z=document.createElement("input");z.id=`fb-required-${t}`,z.type="checkbox",z.checked=!!e.required,M.appendChild(z),M.appendChild(document.createTextNode("Required")),Y.appendChild(M),N.appendChild(I),N.appendChild(O),N.appendChild(Y);const A=document.createElement("div");A.className="fb-options-wrap",A.style.display=Q.has(e.type)?"":"none";const _=document.createElement("label");_.className="form-label",_.textContent="Options (one per line: value: Label)";const D=document.createElement("textarea");D.id=`fb-options-${t}`,D.className="form-input",D.rows=4,D.value=(e.options||[]).map(i=>typeof i=="string"?`${i}: ${i}`:`${i.value??""}: ${i.label??i.value??""}`).join(`
3
- `),A.appendChild(_),A.appendChild(D);const x=document.createElement("div");x.className="fb-grid-row",x.style.gridTemplateColumns="1fr auto",x.style.gap=".6rem",x.style.alignItems="end",x.style.marginBottom=".6rem",x.style.display=document.getElementById("collection-layout")?.value==="grid"?"grid":"none";const G=document.createElement("div"),J=document.createElement("label");J.className="form-label",J.textContent="Column Span";const k=document.createElement("input");k.id=`fb-span-${t}`,k.type="number",k.className="form-input",k.min="1",k.max="6",k.value=e.span>1?String(e.span):"1",G.appendChild(J),G.appendChild(k);const K=document.createElement("div");K.style.cssText="padding-bottom:.35rem;";const U=document.createElement("label");U.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const W=document.createElement("input");return W.id=`fb-fullwidth-${t}`,W.type="checkbox",W.checked=!!e.fullWidth,U.appendChild(W),U.appendChild(document.createTextNode("Full Width")),K.appendChild(U),x.appendChild(G),x.appendChild(K),a.appendChild(c),a.appendChild(N),a.appendChild(A),a.appendChild(x),d.addEventListener("click",()=>{const i=a.style.display!=="none";a.style.display=i?"none":"",l.style.transform=i?"":"rotate(180deg)"}),n.appendChild(d),n.appendChild(a),n}function H(e){if(e){if(e.textContent="",g.length===0){const t=document.createElement("p");t.className="text-muted",t.id="fields-empty-msg",t.style.cssText="text-align:center;padding:2rem 0;",t.textContent='No fields yet. Click "Add Field" to get started.',e.appendChild(t);return}g.forEach((t,n)=>{e.appendChild(de(t,n))})}}function ie(e,t){t.textContent="",te.forEach(n=>{const d=e?.[n]||{enabled:!1,access:"admin"},s=document.createElement("div");s.style.cssText="display:grid;grid-template-columns:140px 1fr 160px;gap:.75rem;align-items:center;padding:.6rem 0;border-bottom:1px solid var(--dm-border,#333);";const r=document.createElement("strong");r.textContent=n.charAt(0).toUpperCase()+n.slice(1),r.style.cssText="font-size:.9rem;";const u=document.createElement("label");u.style.cssText="display:flex;align-items:center;gap:.45rem;cursor:pointer;font-size:.875rem;";const l=document.createElement("input");l.type="checkbox",l.id=`api-${n}-enabled`,l.checked=!!d.enabled,u.appendChild(l),u.appendChild(document.createTextNode("Enable public access"));const o=document.createElement("select");if(o.id=`api-${n}-access`,o.className="form-input",ae.forEach(a=>{const c=document.createElement("option");c.value=a,c.textContent=a.charAt(0).toUpperCase()+a.slice(1),a===d.access&&(c.selected=!0),o.appendChild(c)}),s.appendChild(r),s.appendChild(u),s.appendChild(o),t.appendChild(s),n==="read"){const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:140px 1fr;gap:.75rem;align-items:center;padding:.6rem 0;border-bottom:1px solid var(--dm-border,#333);";const c=document.createElement("label");c.htmlFor="api-read-fields",c.style.cssText="font-size:.85rem;color:var(--dm-text-muted,#aaa);",c.textContent="Read fields";const p=document.createElement("input");p.type="text",p.id="api-read-fields",p.className="form-input",p.placeholder="Comma-separated allowlist \u2014 empty = all fields",p.value=Array.isArray(d.fields)?d.fields.join(", "):"",a.appendChild(c),a.appendChild(p),t.appendChild(a)}})}function ce(e,t){E.dropdown("#storage-adapter-trigger",{items:[{label:"File (default)",value:"file"},{label:"MongoDB",value:"mongodb"}],onSelect:({item:d})=>{e.find("#storage-adapter").val(d.value),e.find("#storage-adapter-label").text(d.label);const s=d.value==="mongodb";e.find("#storage-connection-group").toggle(s),e.find("#storage-migration-warning").toggle(s&&!S)}});const n=t.map(d=>({label:d,value:d}));E.dropdown("#storage-connection-trigger",{items:n.length?n:[{label:"default",value:"default"}],onSelect:({item:d})=>{e.find("#storage-connection").val(d.value),e.find("#storage-connection-label").text(d.label)}})}function se(){return(document.getElementById("storage-adapter")?.value||"file")==="mongodb"?{adapter:"mongodb",connection:document.getElementById("storage-connection")?.value||"default"}:{adapter:"file"}}function re(){const e={};return te.forEach(t=>{const n=document.getElementById(`api-${t}-enabled`)?.checked??!1,d=document.getElementById(`api-${t}-access`)?.value||"admin";if(e[t]={enabled:n,access:d},t==="read"){const s=(document.getElementById("api-read-fields")?.value||"").split(",").map(r=>r.trim()).filter(Boolean);s.length&&(e[t].fields=s)}}),e}export const collectionEditorView={templateUrl:"/admin/js/templates/collection-editor.html",async onMount(e){g=[],h=null,S=!0;const t=window.location.hash.match(/\/collections\/edit\/([^/?#]+)/);t&&(h=t[1],S=!1),E.tabs(e.find("#collection-tabs").get(0)),e.find("#collection-layout").get(0)?.addEventListener("change",function(){const l=this.value==="grid";e.find("#collection-columns-group").get(0).style.display=l?"":"none",document.querySelectorAll(".fb-grid-row").forEach(o=>{o.style.display=l?"grid":"none"})});const n=e.find("#fields-list").get(0),d=e.find("#api-access-rows").get(0);X={};const s=e.find("#collection-project").get(0);if(s)try{(await w.projects.list()).forEach(o=>{const a=document.createElement("option");a.value=o.slug,a.textContent=o.name||o.slug,s.appendChild(a)})}catch{}const r=await w.collections.proStatus();r?.pro&&h!=="roles"&&(e.find("#storage-tab-btn").show(),ce(e,r.connections));let u={create:{enabled:!1,access:"admin"},read:{enabled:!0,access:"public"},update:{enabled:!1,access:"admin"},delete:{enabled:!1,access:"admin"}};if(S){const l=e.find("#field-title").get(0),o=e.find("#field-slug").get(0);l&&o&&(l.addEventListener("input",()=>{o.dataset.manual||(o.value=le(l.value))}),o.addEventListener("input",()=>{o.dataset.manual="1"}))}else try{const l=await w.collections.get(h);if(!l){E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const o=e.find("#editor-title-text").get(0);o&&(o.textContent=l.title),e.find("#field-title").val(l.title||""),e.find("#field-slug").val(l.slug||""),e.find("#field-slug").prop("readonly",!0),e.find("#slug-hint").get(0).textContent="Slug cannot be changed after creation.",e.find("#field-description").val(l.description||""),e.find("#collection-layout").val(l.layout||"stacked"),e.find("#collection-columns").val(l.columns||2),e.find("#collection-bundled").prop("checked",!!l.bundled),X=l.meta||{},e.find("#collection-project").val(l.meta?.project||""),e.find("#collection-columns-group").get(0).style.display=l.layout==="grid"?"":"none",g=l.fields||[],u=l.api||u,B=l.storage?.adapter||"file",l.storage&&(e.find("#storage-adapter").val(l.storage.adapter||"file"),e.find("#storage-adapter-label").text(l.storage.adapter==="mongodb"?"MongoDB":"File (default)"),l.storage.adapter==="mongodb"&&(e.find("#storage-connection-group").show(),e.find("#storage-connection").val(l.storage.connection||"default"),e.find("#storage-connection-label").text(l.storage.connection||"default"))),h==="roles"&&e.find("#storage-tab-btn").hide()}catch{E.toast("Failed to load collection.",{type:"error"}),R.navigate("/collections");return}H(n),ie(u,d),e.find("#add-field-btn").off("click").on("click",()=>{g=Z(),g.push({id:`field-${Date.now()}`,name:"",label:"",type:"string",required:!1,placeholder:"",helper:"",options:[],validation:[],logic:null}),H(n);const l=n.querySelectorAll(".fb-field-card");if(l.length){const o=l[l.length-1],a=o.querySelector(".fb-field-body"),c=o.querySelector(".fb-field-chevron");a&&(a.style.display=""),c&&(c.style.transform="rotate(180deg)"),o.querySelector(`#fb-label-${g.length-1}`)?.focus()}}),e.find("#save-collection-btn").off("click").on("click",async()=>{const l=e.find("#field-title").val().trim(),o=e.find("#field-slug").val().trim(),a=e.find("#field-description").val().trim();if(!l){E.toast("Title is required.",{type:"warning"});return}const c=Z(),p=re(),y=e.find("#collection-layout").val()||"stacked",b=parseInt(e.find("#collection-columns").val(),10)||2,f=se(),$=e.find("#collection-bundled").is(":checked"),v=e.find("#collection-project").val()||"",T={...X||{},project:v||null},L=e.find("#save-collection-btn");L.prop("disabled",!0);try{if(S){const m=await w.collections.create({title:l,slug:o,description:a,layout:y,columns:b,fields:c,api:p,storage:f,meta:T,...$?{bundled:!0}:{}});h=m.slug,B=f.adapter||"file",S=!1,E.toast("Collection created.",{type:"success"}),R.navigate(`/collections/edit/${m.slug}`)}else if((f.adapter||"file")!==B){let m=0;try{m=(await w.collections.listEntries(h,{limit:1}))?.total??0}catch{}const N=B==="file"?`file \u2192 ${f.adapter}`:`${B} \u2192 ${f.adapter||"file"}`;if(m>0&&await E.confirm(`You changed the storage adapter (${N}).
1
+ import{api as w}from"../api.js";const ee=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"hidden",label:"Hidden field"}],Q=new Set(["select","radio","checkbox-group"]),ae=["public","token","subscriber","editor","manager","admin"],te=["create","read","update","delete"];let g=[],y=null,S=!0,M=null,L="file",X={};function le(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function ne(e){return ee.find(t=>t.value===e)?.label||e}function oe(e){const t={...g[e]},n=document.getElementById(`fb-label-${e}`),d=document.getElementById(`fb-name-${e}`),s=document.getElementById(`fb-type-${e}`),r=document.getElementById(`fb-required-${e}`),u=document.getElementById(`fb-placeholder-${e}`),l=document.getElementById(`fb-helper-${e}`);if(n&&(t.label=n.value.trim()||t.label),d&&(t.name=d.value.trim()||t.name),s&&(t.type=s.value||t.type),r&&(t.required=r.checked),u&&(t.placeholder=u.value.trim()),l&&(t.helper=l.value.trim()),Q.has(t.type)){const a=document.getElementById(`fb-options-${e}`);a&&(t.options=a.value.split(`
2
+ `).filter(c=>c.trim()).map(c=>{const[p,...h]=c.split(":");return{value:p.trim(),label:h.join(":").trim()||p.trim()}}))}const o=document.getElementById(`fb-span-${e}`);if(document.getElementById(`fb-fullwidth-${e}`)?.checked)t.fullWidth=!0,delete t.span;else{delete t.fullWidth;const a=parseInt(o?.value,10);a>1?t.span=a:delete t.span}return t}function Z(){return g.map((e,t)=>oe(t))}function de(e,t){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border,#333);border-radius:8px;margin-bottom:.75rem;overflow:hidden;";const d=document.createElement("div");d.className="fb-field-header",d.style.cssText="display:flex;align-items:center;gap:.5rem;padding:.6rem .75rem;background:var(--dm-card-header-bg,rgba(255,255,255,.03));cursor:pointer;user-select:none;";const s=document.createElement("span");s.innerHTML='<span data-icon="menu" data-icon-size="14" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',s.title="Drag to reorder",s.style.cssText="cursor:grab;opacity:.4;flex-shrink:0;display:inline-flex;align-items:center;",n.draggable=!0,s.addEventListener("mousedown",()=>{n.draggable=!0}),n.addEventListener("dragstart",i=>{M=t,i.dataTransfer.effectAllowed="move",n.style.opacity="0.4"}),n.addEventListener("dragend",()=>{n.style.opacity="",document.querySelectorAll(".fb-field-card").forEach(i=>i.classList.remove("fb-drag-over"))}),n.addEventListener("dragover",i=>{i.preventDefault(),i.dataTransfer.dropEffect="move",document.querySelectorAll(".fb-field-card").forEach(C=>C.classList.remove("fb-drag-over")),n.classList.add("fb-drag-over")}),n.addEventListener("dragleave",()=>{n.classList.remove("fb-drag-over")}),n.addEventListener("drop",i=>{if(i.preventDefault(),n.classList.remove("fb-drag-over"),M===null||M===t)return;g=Z();const[C]=g.splice(M,1);g.splice(t,0,C),M=null,W(document.getElementById("fields-list"))});const r=document.createElement("span");r.className="fb-field-summary",r.style.cssText="flex:1;font-weight:500;font-size:.9rem;",r.textContent=e.label||"(Untitled field)";const u=document.createElement("span");u.style.cssText="font-size:.75rem;opacity:.5;",u.textContent=ne(e.type);const l=document.createElement("span");l.className="fb-field-chevron",l.innerHTML='<span data-icon="chevron-down" data-icon-size="12" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',l.style.cssText="opacity:.5;transition:transform .2s;display:inline-flex;align-items:center;";const o=document.createElement("button");o.type="button",o.innerHTML='<span data-icon="x" data-icon-size="13" style="display:inline-flex;align-items:center;vertical-align:middle;"></span>',o.className="btn btn-sm btn-ghost",o.style.cssText="padding:.15rem .45rem;line-height:1;opacity:.6;",o.title="Remove field",o.addEventListener("click",i=>{i.stopPropagation(),g.splice(t,1),W(document.getElementById("fields-list"))}),d.appendChild(s),d.appendChild(r),d.appendChild(u),d.appendChild(l),d.appendChild(o),Domma.icons.scan(d);const a=document.createElement("div");a.className="fb-field-body",a.style.cssText="padding:.75rem;display:none;";const c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:1fr 1fr 1fr;gap:.6rem;margin-bottom:.6rem;";const p=document.createElement("div"),h=document.createElement("label");h.className="form-label",h.textContent="Label";const b=document.createElement("input");b.id=`fb-label-${t}`,b.type="text",b.className="form-input",b.value=e.label||"",b.addEventListener("input",()=>{r.textContent=b.value.trim()||"(Untitled field)";const i=document.getElementById(`fb-name-${t}`);i&&!i.dataset.manual&&(i.value=le(b.value).replace(/-/g,"_"))}),p.appendChild(h),p.appendChild(b);const f=document.createElement("div"),$=document.createElement("label");$.className="form-label",$.textContent="Name (key)";const v=document.createElement("input");v.id=`fb-name-${t}`,v.type="text",v.className="form-input",v.value=e.name||"",v.addEventListener("input",()=>{v.dataset.manual="1"}),f.appendChild($),f.appendChild(v);const T=document.createElement("div"),B=document.createElement("label");B.className="form-label",B.textContent="Type";const m=document.createElement("select");m.id=`fb-type-${t}`,m.className="form-input",ee.forEach(i=>{const C=document.createElement("option");C.value=i.value,C.textContent=i.label,i.value===e.type&&(C.selected=!0),m.appendChild(C)}),m.addEventListener("change",()=>{u.textContent=ne(m.value);const i=a.querySelector(".fb-options-wrap");i&&(i.style.display=Q.has(m.value)?"":"none")}),T.appendChild(B),T.appendChild(m),c.appendChild(p),c.appendChild(f),c.appendChild(T);const N=document.createElement("div");N.style.cssText="display:grid;grid-template-columns:1fr 1fr auto;gap:.6rem;align-items:end;margin-bottom:.6rem;";const I=document.createElement("div"),P=document.createElement("label");P.className="form-label",P.textContent="Placeholder";const j=document.createElement("input");j.id=`fb-placeholder-${t}`,j.type="text",j.className="form-input",j.value=e.placeholder||"",I.appendChild(P),I.appendChild(j);const O=document.createElement("div"),V=document.createElement("label");V.className="form-label",V.textContent="Helper text";const q=document.createElement("input");q.id=`fb-helper-${t}`,q.type="text",q.className="form-input",q.value=e.helper||"",O.appendChild(V),O.appendChild(q);const Y=document.createElement("div");Y.style.cssText="padding-bottom:.35rem;";const z=document.createElement("label");z.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const F=document.createElement("input");F.id=`fb-required-${t}`,F.type="checkbox",F.checked=!!e.required,z.appendChild(F),z.appendChild(document.createTextNode("Required")),Y.appendChild(z),N.appendChild(I),N.appendChild(O),N.appendChild(Y);const A=document.createElement("div");A.className="fb-options-wrap",A.style.display=Q.has(e.type)?"":"none";const _=document.createElement("label");_.className="form-label",_.textContent="Options (one per line: value: Label)";const D=document.createElement("textarea");D.id=`fb-options-${t}`,D.className="form-input",D.rows=4,D.value=(e.options||[]).map(i=>typeof i=="string"?`${i}: ${i}`:`${i.value??""}: ${i.label??i.value??""}`).join(`
3
+ `),A.appendChild(_),A.appendChild(D);const x=document.createElement("div");x.className="fb-grid-row",x.style.gridTemplateColumns="1fr auto",x.style.gap=".6rem",x.style.alignItems="end",x.style.marginBottom=".6rem",x.style.display=document.getElementById("collection-layout")?.value==="grid"?"grid":"none";const G=document.createElement("div"),J=document.createElement("label");J.className="form-label",J.textContent="Column Span";const k=document.createElement("input");k.id=`fb-span-${t}`,k.type="number",k.className="form-input",k.min="1",k.max="6",k.value=e.span>1?String(e.span):"1",G.appendChild(J),G.appendChild(k);const K=document.createElement("div");K.style.cssText="padding-bottom:.35rem;";const U=document.createElement("label");U.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const H=document.createElement("input");return H.id=`fb-fullwidth-${t}`,H.type="checkbox",H.checked=!!e.fullWidth,U.appendChild(H),U.appendChild(document.createTextNode("Full Width")),K.appendChild(U),x.appendChild(G),x.appendChild(K),a.appendChild(c),a.appendChild(N),a.appendChild(A),a.appendChild(x),d.addEventListener("click",()=>{const i=a.style.display!=="none";a.style.display=i?"none":"",l.style.transform=i?"":"rotate(180deg)"}),n.appendChild(d),n.appendChild(a),n}function W(e){if(e){if(e.textContent="",g.length===0){const t=document.createElement("p");t.className="text-muted",t.id="fields-empty-msg",t.style.cssText="text-align:center;padding:2rem 0;",t.textContent='No fields yet. Click "Add Field" to get started.',e.appendChild(t);return}g.forEach((t,n)=>{e.appendChild(de(t,n))})}}function ie(e,t){t.textContent="",te.forEach(n=>{const d=e?.[n]||{enabled:!1,access:"admin"},s=document.createElement("div");s.style.cssText="display:grid;grid-template-columns:140px 1fr 160px;gap:.75rem;align-items:center;padding:.6rem 0;border-bottom:1px solid var(--dm-border,#333);";const r=document.createElement("strong");r.textContent=n.charAt(0).toUpperCase()+n.slice(1),r.style.cssText="font-size:.9rem;";const u=document.createElement("label");u.style.cssText="display:flex;align-items:center;gap:.45rem;cursor:pointer;font-size:.875rem;";const l=document.createElement("input");l.type="checkbox",l.id=`api-${n}-enabled`,l.checked=!!d.enabled,u.appendChild(l),u.appendChild(document.createTextNode("Enable public access"));const o=document.createElement("select");if(o.id=`api-${n}-access`,o.className="form-input",ae.forEach(a=>{const c=document.createElement("option");c.value=a,c.textContent=a.charAt(0).toUpperCase()+a.slice(1),a===d.access&&(c.selected=!0),o.appendChild(c)}),s.appendChild(r),s.appendChild(u),s.appendChild(o),t.appendChild(s),n==="read"){const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:140px 1fr;gap:.75rem;align-items:center;padding:.6rem 0;border-bottom:1px solid var(--dm-border,#333);";const c=document.createElement("label");c.htmlFor="api-read-fields",c.style.cssText="font-size:.85rem;color:var(--dm-text-muted,#aaa);",c.textContent="Read fields";const p=document.createElement("input");p.type="text",p.id="api-read-fields",p.className="form-input",p.placeholder="Comma-separated allowlist \u2014 empty = all fields",p.value=Array.isArray(d.fields)?d.fields.join(", "):"",a.appendChild(c),a.appendChild(p),t.appendChild(a)}})}function ce(e,t){E.dropdown("#storage-adapter-trigger",{items:[{label:"File (default)",value:"file"},{label:"MongoDB",value:"mongodb"}],onSelect:({item:d})=>{e.find("#storage-adapter").val(d.value),e.find("#storage-adapter-label").text(d.label);const s=d.value==="mongodb";e.find("#storage-connection-group").toggle(s),e.find("#storage-migration-warning").toggle(s&&!S)}});const n=t.map(d=>({label:d,value:d}));E.dropdown("#storage-connection-trigger",{items:n.length?n:[{label:"default",value:"default"}],onSelect:({item:d})=>{e.find("#storage-connection").val(d.value),e.find("#storage-connection-label").text(d.label)}})}function se(){return(document.getElementById("storage-adapter")?.value||"file")==="mongodb"?{adapter:"mongodb",connection:document.getElementById("storage-connection")?.value||"default"}:{adapter:"file"}}function re(){const e={};return te.forEach(t=>{const n=document.getElementById(`api-${t}-enabled`)?.checked??!1,d=document.getElementById(`api-${t}-access`)?.value||"admin";if(e[t]={enabled:n,access:d},t==="read"){const s=(document.getElementById("api-read-fields")?.value||"").split(",").map(r=>r.trim()).filter(Boolean);s.length&&(e[t].fields=s)}}),e}export const collectionEditorView={templateUrl:"/admin/js/templates/collection-editor.html",async onMount(e){g=[],y=null,S=!0;const t=window.location.hash.match(/\/collections\/edit\/([^/?#]+)/);t&&(y=t[1],S=!1),E.tabs(e.find("#collection-tabs").get(0)),e.find("#collection-layout").get(0)?.addEventListener("change",function(){const l=this.value==="grid";e.find("#collection-columns-group").get(0).style.display=l?"":"none",document.querySelectorAll(".fb-grid-row").forEach(o=>{o.style.display=l?"grid":"none"})});const n=e.find("#fields-list").get(0),d=e.find("#api-access-rows").get(0);X={};const s=e.find("#collection-project").get(0);if(s)try{(await w.projects.list()).forEach(o=>{const a=document.createElement("option");a.value=o.slug,a.textContent=o.name||o.slug,s.appendChild(a)})}catch{}const r=await w.collections.proStatus();r?.pro&&y!=="roles"&&(e.find("#storage-tab-btn").show(),ce(e,r.connections));let u={create:{enabled:!1,access:"admin"},read:{enabled:!0,access:"public"},update:{enabled:!1,access:"admin"},delete:{enabled:!1,access:"admin"}};if(S){const l=e.find("#field-title").get(0),o=e.find("#field-slug").get(0);l&&o&&(l.addEventListener("input",()=>{o.dataset.manual||(o.value=le(l.value))}),o.addEventListener("input",()=>{o.dataset.manual="1"}))}else try{const l=await w.collections.get(y);if(!l){E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const o=e.find("#editor-title-text").get(0);o&&(o.textContent=l.title),e.find("#field-title").val(l.title||""),e.find("#field-slug").val(l.slug||""),e.find("#field-slug").prop("readonly",!0),e.find("#slug-hint").get(0).textContent="Slug cannot be changed after creation.",e.find("#field-description").val(l.description||""),e.find("#collection-layout").val(l.layout||"stacked"),e.find("#collection-columns").val(l.columns||2),e.find("#collection-bundled").prop("checked",!!l.bundled),X=l.meta||{},e.find("#collection-project").val(l.meta?.project||""),e.find("#collection-columns-group").get(0).style.display=l.layout==="grid"?"":"none",g=l.fields||[],u=l.api||u,L=l.storage?.adapter||"file",l.storage&&(e.find("#storage-adapter").val(l.storage.adapter||"file"),e.find("#storage-adapter-label").text(l.storage.adapter==="mongodb"?"MongoDB":"File (default)"),l.storage.adapter==="mongodb"&&(e.find("#storage-connection-group").show(),e.find("#storage-connection").val(l.storage.connection||"default"),e.find("#storage-connection-label").text(l.storage.connection||"default"))),y==="roles"&&e.find("#storage-tab-btn").hide()}catch{E.toast("Failed to load collection.",{type:"error"}),R.navigate("/collections");return}W(n),ie(u,d),e.find("#add-field-btn").off("click").on("click",()=>{g=Z(),g.push({id:`field-${Date.now()}`,name:"",label:"",type:"string",required:!1,placeholder:"",helper:"",options:[],validation:[],logic:null}),W(n);const l=n.querySelectorAll(".fb-field-card");if(l.length){const o=l[l.length-1],a=o.querySelector(".fb-field-body"),c=o.querySelector(".fb-field-chevron");a&&(a.style.display=""),c&&(c.style.transform="rotate(180deg)"),o.querySelector(`#fb-label-${g.length-1}`)?.focus()}}),e.find("#save-collection-btn").off("click").on("click",async()=>{const l=e.find("#field-title").val().trim(),o=e.find("#field-slug").val().trim(),a=e.find("#field-description").val().trim();if(!l){E.toast("Title is required.",{type:"warning"});return}const c=Z(),p=re(),h=e.find("#collection-layout").val()||"stacked",b=parseInt(e.find("#collection-columns").val(),10)||2,f=se(),$=e.find("#collection-bundled").is(":checked"),v=e.find("#collection-project").val()||"",T={...X||{},project:v||null},B=e.find("#save-collection-btn");B.prop("disabled",!0);try{if(S){const m=await w.collections.create({title:l,slug:o,description:a,layout:h,columns:b,fields:c,api:p,storage:f,meta:T,...$?{bundled:!0}:{}});y=m.slug,L=f.adapter||"file",S=!1,E.toast("Collection created.",{type:"success"}),R.navigate(`/collections/edit/${m.slug}`)}else if((f.adapter||"file")!==L){let m=0;try{m=(await w.collections.listEntries(y,{limit:1}))?.total??0}catch{}const N=L==="file"?`file \u2192 ${f.adapter}`:`${L} \u2192 ${f.adapter||"file"}`;if(m>0&&await E.confirm(`You changed the storage adapter (${N}).
4
4
 
5
- Migrate ${m} existing ${m===1?"entry":"entries"} to the new storage?`)){const I=await w.collections.migrateStorage(h,f);B=f.adapter||"file",E.toast(`Migrated ${I.migrated} of ${I.total} entries.`,{type:"success"})}else await w.collections.update(h,{title:l,description:a,layout:y,columns:b,fields:c,api:p,storage:f,meta:T,...$?{bundled:!0}:{bundled:!1}}),B=f.adapter||"file",E.toast("Collection saved.",{type:"success"})}else await w.collections.update(h,{title:l,description:a,layout:y,columns:b,fields:c,api:p,storage:f,meta:T,...$?{bundled:!0}:{bundled:!1}}),E.toast("Collection saved.",{type:"success"})}catch(m){E.toast(m.message||"Failed to save.",{type:"error"})}finally{L.prop("disabled",!1)}}),Domma.icons.scan()}};
5
+ Migrate ${m} existing ${m===1?"entry":"entries"} to the new storage?`)){const I=await w.collections.migrateStorage(y,f);L=f.adapter||"file",E.toast(`Migrated ${I.migrated} of ${I.total} entries.`,{type:"success"})}else await w.collections.update(y,{title:l,description:a,layout:h,columns:b,fields:c,api:p,storage:f,meta:T,...$?{bundled:!0}:{bundled:!1}}),L=f.adapter||"file",E.toast("Collection saved.",{type:"success"})}else await w.collections.update(y,{title:l,description:a,layout:h,columns:b,fields:c,api:p,storage:f,meta:T,...$?{bundled:!0}:{bundled:!1}}),E.toast("Collection saved.",{type:"success"})}catch(m){E.toast(m.message||"Failed to save.",{type:"error"})}finally{B.prop("disabled",!1)}}),Domma.icons.scan()}};
@@ -1 +1 @@
1
- import{api as h}from"../api.js";function M(t){return String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}let f=null,g=null,p=[],j=1,w=[],x={};const z=50;export const collectionEntriesView={templateUrl:"/admin/js/templates/collection-entries.html",async onMount(t){p=[],j=1,g=null,w=[],x={};const d=window.location.hash.match(/\/collections\/([^/?#]+)\/entries/);if(f=d?d[1]:null,!f){E.toast("No collection selected.",{type:"error"});return}try{if(g=await h.collections.get(f),!g){E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const a=t.find("#entries-title").get(0);a&&(a.textContent=g.title+" \u2014 Entries");const o=t.find("#edit-schema-btn").get(0);o&&o.setAttribute("href",`#/collections/edit/${f}`);const e=t.find("#form-btn").get(0);e&&(new Set(["roles","user-profiles"]).has(f)?e.style.display="none":e.setAttribute("href",`#/forms/edit/${f}`))}catch{E.toast("Failed to load collection schema.",{type:"error"});return}try{w=await h.actions.forCollection(f)}catch{w=[]}await v(t),await k(t);const n=t.find("#entry-search").get(0);n&&n.addEventListener("input",()=>{const a=n.value.toLowerCase().trim(),o=a?p.filter(e=>Object.values(e.data||{}).some(l=>String(l).toLowerCase().includes(a))):p;C(o,t)}),t.find("#add-entry-btn").off("click").on("click",()=>{A(null,t)}),t.find("#export-btn").off("click").on("click",()=>{const a=E.slideover({title:"Export Entries",size:"sm",position:"right"}),o=document.createElement("div");o.style.cssText="padding:1.25rem;display:flex;flex-direction:column;gap:1rem;",["json","csv"].forEach(e=>{const l=document.createElement("button");l.className="btn btn-ghost",l.style.cssText="justify-content:flex-start;gap:.5rem;",l.textContent=e==="json"?"Export as JSON":"Export as CSV",l.addEventListener("click",()=>{fetch(`/api/collections/${f}/export?format=${e}`,{headers:{Authorization:`Bearer ${S.get("auth_token")||""}`}}).then(s=>s.blob()).then(s=>{const r=document.createElement("a");r.href=URL.createObjectURL(s),r.download=`${f}-entries.${e}`,document.body.appendChild(r),r.click(),document.body.removeChild(r),URL.revokeObjectURL(r.href),a.close()}).catch(()=>E.toast("Export failed.",{type:"error"}))}),o.appendChild(l)}),a.setContent(o),a.open()}),t.find("#import-btn").off("click").on("click",()=>{B(t)}),t.find("#clear-all-btn").off("click").on("click",async()=>{if(await E.confirm("Delete ALL entries? This cannot be undone."))try{await h.collections.clearEntries(f),p=[],E.toast("All entries cleared.",{type:"success"}),C([],t)}catch{E.toast("Failed to clear entries.",{type:"error"})}}),Domma.icons.scan()}};async function k(t){const m=w.filter(n=>n.access?.rowLevel);if(m.length===0)return;const d=p.map(n=>n.id);d.length!==0&&(await Promise.all(m.map(async n=>{try{const{allowed:a}=await h.actions.checkAccess(n.slug,d);x[n.slug]=new Set(a)}catch{x[n.slug]=null}})),C(p,t))}async function v(t){try{const m=await h.collections.listEntries(f,{limit:500});p=m.entries||m||[]}catch{p=[],E.toast("Could not load entries.",{type:"error"})}C(p,t),await k(t)}function C(t,m){const d=m.find("#entry-count").get(0);d&&(d.textContent=t.length===p.length?`${p.length} entr${p.length!==1?"ies":"y"}`:`Showing ${t.length} of ${p.length}`);const a=[...(g?.fields||[]).slice(0,5).map(e=>({key:`data.${e.name}`,title:e.label||e.name,render:(l,s)=>{const r=s.data?.[e.name]??"",c=String(r),i=document.createElement("span");return i.title=c,i.textContent=c.length>60?c.slice(0,60)+"\u2026":c,i.outerHTML}})),{key:"meta",title:"Created",render:e=>D(e?.createdAt).format("DD MMM YYYY HH:mm")},{key:"id",title:"",render:e=>{const l=document.createElement("div");l.style.cssText="display:flex;gap:.3rem;justify-content:flex-end;flex-wrap:wrap;",w.forEach(c=>{if(x[c.slug]!==void 0&&x[c.slug]!==null&&!x[c.slug].has(e))return;const i=document.createElement("button");i.className="btn btn-sm btn-ghost js-run-action",i.dataset.actionSlug=c.slug,i.dataset.entryId=e,i.dataset.confirmMessage=c.trigger?.confirmMessage||"",i.title=c.title||c.slug;const y=document.createElement("span");y.setAttribute("data-icon",M(c.trigger?.icon||"zap")),i.appendChild(y),i.appendChild(document.createTextNode(" "+(c.trigger?.label||c.title))),l.appendChild(i)});const s=document.createElement("button");s.className="btn btn-sm btn-ghost js-edit-entry",s.dataset.id=e,s.setAttribute("data-tooltip","Edit"),s.innerHTML='<span data-icon="edit"></span>';const r=document.createElement("button");return r.className="btn btn-sm btn-danger js-delete-entry",r.dataset.id=e,r.setAttribute("data-tooltip","Delete"),r.innerHTML='<span data-icon="trash"></span>',l.appendChild(s),l.appendChild(r),l.outerHTML}}];T.create("#entries-table",{data:t,columns:a,emptyMessage:'No entries yet. Click "Add Entry" to get started.'});const o=document.querySelector("#entries-table");o&&(o.querySelectorAll(".js-run-action").forEach(e=>{e.addEventListener("click",async l=>{l.stopPropagation();const{actionSlug:s,entryId:r,confirmMessage:c}=e.dataset;if(!(c&&!await E.confirm(c))){e.disabled=!0;try{const i=await h.actions.execute(s,r);if(i.success)E.toast(`Action completed (${i.stepsCompleted} step${i.stepsCompleted!==1?"s":""}).`,{type:"success"}),await v({find:y=>({get:u=>document.querySelector(y)})});else{const y=i.results?.find(u=>!u.success);E.toast(y?.error||"Action failed.",{type:"error"})}}catch(i){E.toast(i.message||"Action failed.",{type:"error"})}finally{e.disabled=!1}}})}),o.querySelectorAll(".js-edit-entry").forEach(e=>{e.addEventListener("click",l=>{l.stopPropagation();const s=p.find(r=>r.id===e.dataset.id);s&&A(s,null)})}),o.querySelectorAll(".js-delete-entry").forEach(e=>{e.addEventListener("click",async l=>{if(l.stopPropagation(),!!await E.confirm("Delete this entry?"))try{await h.collections.deleteEntry(f,e.dataset.id),p=p.filter(r=>r.id!==e.dataset.id),E.toast("Entry deleted.",{type:"success"}),C(p,{find:r=>({get:c=>document.querySelector(r)})})}catch{E.toast("Failed to delete entry.",{type:"error"})}})}),o.querySelectorAll("tbody tr").forEach((e,l)=>{const s=t[l];s&&(e.style.cursor="pointer",e.addEventListener("click",r=>{r.target.closest(".js-edit-entry, .js-delete-entry")||q(s)}))}),Domma.icons.scan(o),o.querySelectorAll("[data-tooltip]").forEach(e=>{E.tooltip(e,{content:e.getAttribute("data-tooltip"),position:"top"})}))}function N(t,m){const d={};return t.forEach(n=>{const a={};n.fullWidth?a.span=m:n.span>1&&(a.span=n.span),n.placeholder&&(a.placeholder=n.placeholder),n.helper&&(a.hint=n.helper);const o=n.type==="checkbox"?"boolean":n.type==="date"?"string":n.type;d[n.name]={type:o,label:n.label,required:n.required,options:n.options,...Object.keys(a).length?{formConfig:a}:{}}}),d}function A(t,m){const d=!!t,n=E.modal({title:d?"Edit Entry":"Add Entry",size:"md"}),a=document.createElement("div");a.style.cssText="padding:.25rem 0 .5rem;";const o=g?.fields||[],e=g?.columns||2,l=g?.layout||"stacked",s=document.createElement("div");F.create(N(o,e),t?.data||{},{layout:l,columns:e,showSubmitButton:!1}).renderTo(s),(o||[]).forEach(y=>{if(y.type!=="date"||!y.name)return;const u=s.querySelector(`[name="${y.name}"]`);u&&u.type!=="date"&&(u.type="date")}),a.appendChild(s);const r=document.createElement("div");r.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.5rem;";const c=document.createElement("button");c.className="btn btn-ghost",c.textContent="Cancel";const i=document.createElement("button");i.className="btn btn-primary",i.textContent=d?"Save Changes":"Add Entry",r.appendChild(c),r.appendChild(i),a.appendChild(r),n.element.appendChild(a),n.open(),c.addEventListener("click",()=>n.close()),i.addEventListener("click",async()=>{const y={};o.forEach(u=>{const b=s.querySelector(`[name="${u.name}"]`);b&&(y[u.name]=u.type==="checkbox"?b.checked:b.value)}),i.disabled=!0;try{if(d){const u=await h.collections.updateEntry(f,t.id,y),b=p.findIndex(L=>L.id===t.id);b!==-1&&(p[b]=u),E.toast("Entry updated.",{type:"success"})}else{const u=await h.collections.createEntry(f,y);p.unshift(u),E.toast("Entry added.",{type:"success"})}n.close(),C(p,m||{find:()=>({get:()=>null})})}catch(u){E.toast(u.message||"Failed to save entry.",{type:"error"}),i.disabled=!1}})}function q(t){const m=document.createElement("div"),d=g?.fields||[],n=document.createElement("div");n.style.cssText="display:flex;flex-direction:column;gap:.75rem;margin-bottom:1.25rem;",d.forEach(e=>{const l=t.data?.[e.name];if(l==null||l==="")return;const s=document.createElement("div");s.style.cssText="border-bottom:1px solid var(--dm-border,#333);padding-bottom:.6rem;";const r=document.createElement("strong");r.textContent=e.label||e.name,r.style.cssText="display:block;font-size:.8rem;color:var(--dm-text-muted,#888);margin-bottom:.2rem;";const c=document.createElement("p");c.textContent=String(l),c.style.cssText="margin:0;word-break:break-word;",s.appendChild(r),s.appendChild(c),n.appendChild(s)});const a=document.createElement("div");if(a.style.cssText="font-size:.8rem;color:var(--dm-text-muted,#888);display:flex;flex-direction:column;gap:.3rem;border-top:1px solid var(--dm-border,#333);padding-top:.75rem;",t.meta?.createdAt){const e=document.createElement("span");e.textContent=`Created: ${D(t.meta.createdAt).format("DD MMM YYYY HH:mm")}`,a.appendChild(e)}if(t.meta?.source){const e=document.createElement("span");e.textContent=`Source: ${t.meta.source}`,a.appendChild(e)}m.appendChild(n),m.appendChild(a);const o=E.modal({title:"Entry Details",size:"md"});o.element.appendChild(m),o.open()}function B(t){const m=E.modal({title:"Import Entries",size:"md"}),d=document.createElement("div");d.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const n=document.createElement("p");n.textContent='Paste a JSON array of entries. Each item should have a "data" object with field values.',n.style.cssText="font-size:.875rem;color:var(--dm-text-muted,#888);margin:0;",d.appendChild(n);const a=document.createElement("textarea");a.className="form-input",a.rows=10,a.placeholder='[{"data": {"name": "Example"}}, ...]',d.appendChild(a);const o=document.createElement("p");o.style.cssText="font-size:.875rem;margin:0;display:none;",d.appendChild(o);const e=document.createElement("div");e.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;";const l=document.createElement("button");l.className="btn btn-ghost",l.textContent="Cancel";const s=document.createElement("button");s.className="btn btn-primary",s.textContent="Import",e.appendChild(l),e.appendChild(s),d.appendChild(e),m.element.appendChild(d),m.open(),l.addEventListener("click",()=>m.close()),s.addEventListener("click",async()=>{let r;try{if(r=JSON.parse(a.value),!Array.isArray(r))throw new Error("Must be a JSON array")}catch(c){o.style.display="",o.style.color="var(--dm-danger,#f87171)",o.textContent=`Invalid JSON: ${c.message}`;return}s.disabled=!0;try{const c=await h.collections.import(f,r);o.style.display="",o.style.color="var(--dm-success,#4ade80)",o.textContent=`Imported ${c.imported} entries. Skipped: ${c.skipped}.`,await v(t||{find:()=>({get:()=>null,off:()=>({on:()=>{}})})}),setTimeout(()=>m.close(),1500)}catch(c){o.style.display="",o.style.color="var(--dm-danger,#f87171)",o.textContent=c.message||"Import failed."}finally{s.disabled=!1}})}
1
+ import{api as h}from"../api.js";function M(t){return String(t).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}let y=null,g=null,p=[],j=1,w=[],x={};const z=50;export const collectionEntriesView={templateUrl:"/admin/js/templates/collection-entries.html",async onMount(t){p=[],j=1,g=null,w=[],x={};const d=window.location.hash.match(/\/collections\/([^/?#]+)\/entries/);if(y=d?d[1]:null,!y){E.toast("No collection selected.",{type:"error"});return}const a=E.loader(t.get(0),{type:"dots"});try{if(g=await h.collections.get(y),!g){a.destroy(),E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const s=t.find("#entries-title").get(0);s&&(s.textContent=g.title+" \u2014 Entries");const e=t.find("#edit-schema-btn").get(0);e&&e.setAttribute("href",`#/collections/edit/${y}`);const r=t.find("#form-btn").get(0);r&&(new Set(["roles","user-profiles"]).has(y)?r.style.display="none":r.setAttribute("href",`#/forms/edit/${y}`))}catch{a.destroy(),E.toast("Failed to load collection schema.",{type:"error"});return}try{w=await h.actions.forCollection(y)}catch{w=[]}try{await v(t)}finally{a.destroy()}await k(t);const c=t.find("#entry-search").get(0);c&&c.addEventListener("input",()=>{const s=c.value.toLowerCase().trim(),e=s?p.filter(r=>Object.values(r.data||{}).some(n=>String(n).toLowerCase().includes(s))):p;C(e,t)}),t.find("#add-entry-btn").off("click").on("click",()=>{A(null,t)}),t.find("#export-btn").off("click").on("click",()=>{const s=E.slideover({title:"Export Entries",size:"sm",position:"right"}),e=document.createElement("div");e.style.cssText="padding:1.25rem;display:flex;flex-direction:column;gap:1rem;",["json","csv"].forEach(r=>{const n=document.createElement("button");n.className="btn btn-ghost",n.style.cssText="justify-content:flex-start;gap:.5rem;",n.textContent=r==="json"?"Export as JSON":"Export as CSV",n.addEventListener("click",()=>{fetch(`/api/collections/${y}/export?format=${r}`,{headers:{Authorization:`Bearer ${S.get("auth_token")||""}`}}).then(l=>l.blob()).then(l=>{const o=document.createElement("a");o.href=URL.createObjectURL(l),o.download=`${y}-entries.${r}`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(o.href),s.close()}).catch(()=>E.toast("Export failed.",{type:"error"}))}),e.appendChild(n)}),s.setContent(e),s.open()}),t.find("#import-btn").off("click").on("click",()=>{B(t)}),t.find("#clear-all-btn").off("click").on("click",async()=>{if(await E.confirm("Delete ALL entries? This cannot be undone."))try{await h.collections.clearEntries(y),p=[],E.toast("All entries cleared.",{type:"success"}),C([],t)}catch{E.toast("Failed to clear entries.",{type:"error"})}}),Domma.icons.scan()}};async function k(t){const m=w.filter(a=>a.access?.rowLevel);if(m.length===0)return;const d=p.map(a=>a.id);d.length!==0&&(await Promise.all(m.map(async a=>{try{const{allowed:c}=await h.actions.checkAccess(a.slug,d);x[a.slug]=new Set(c)}catch{x[a.slug]=null}})),C(p,t))}async function v(t){try{const m=await h.collections.listEntries(y,{limit:500});p=m.entries||m||[]}catch{p=[],E.toast("Could not load entries.",{type:"error"})}C(p,t),await k(t)}function C(t,m){const d=m.find("#entry-count").get(0);d&&(d.textContent=t.length===p.length?`${p.length} entr${p.length!==1?"ies":"y"}`:`Showing ${t.length} of ${p.length}`);const c=[...(g?.fields||[]).slice(0,5).map(e=>({key:`data.${e.name}`,title:e.label||e.name,render:(r,n)=>{const l=n.data?.[e.name]??"",o=String(l),i=document.createElement("span");return i.title=o,i.textContent=o.length>60?o.slice(0,60)+"\u2026":o,i.outerHTML}})),{key:"meta",title:"Created",render:e=>D(e?.createdAt).format("DD MMM YYYY HH:mm")},{key:"id",title:"",render:e=>{const r=document.createElement("div");r.style.cssText="display:flex;gap:.3rem;justify-content:flex-end;flex-wrap:wrap;",w.forEach(o=>{if(x[o.slug]!==void 0&&x[o.slug]!==null&&!x[o.slug].has(e))return;const i=document.createElement("button");i.className="btn btn-sm btn-ghost js-run-action",i.dataset.actionSlug=o.slug,i.dataset.entryId=e,i.dataset.confirmMessage=o.trigger?.confirmMessage||"",i.title=o.title||o.slug;const f=document.createElement("span");f.setAttribute("data-icon",M(o.trigger?.icon||"zap")),i.appendChild(f),i.appendChild(document.createTextNode(" "+(o.trigger?.label||o.title))),r.appendChild(i)});const n=document.createElement("button");n.className="btn btn-sm btn-ghost js-edit-entry",n.dataset.id=e,n.setAttribute("data-tooltip","Edit"),n.innerHTML='<span data-icon="edit"></span>';const l=document.createElement("button");return l.className="btn btn-sm btn-danger js-delete-entry",l.dataset.id=e,l.setAttribute("data-tooltip","Delete"),l.innerHTML='<span data-icon="trash"></span>',r.appendChild(n),r.appendChild(l),r.outerHTML}}];T.create("#entries-table",{data:t,columns:c,emptyMessage:'No entries yet. Click "Add Entry" to get started.'});const s=document.querySelector("#entries-table");s&&(s.querySelectorAll(".js-run-action").forEach(e=>{e.addEventListener("click",async r=>{r.stopPropagation();const{actionSlug:n,entryId:l,confirmMessage:o}=e.dataset;if(!(o&&!await E.confirm(o))){e.disabled=!0;try{const i=await h.actions.execute(n,l);if(i.success)E.toast(`Action completed (${i.stepsCompleted} step${i.stepsCompleted!==1?"s":""}).`,{type:"success"}),await v({find:f=>({get:u=>document.querySelector(f)})});else{const f=i.results?.find(u=>!u.success);E.toast(f?.error||"Action failed.",{type:"error"})}}catch(i){E.toast(i.message||"Action failed.",{type:"error"})}finally{e.disabled=!1}}})}),s.querySelectorAll(".js-edit-entry").forEach(e=>{e.addEventListener("click",r=>{r.stopPropagation();const n=p.find(l=>l.id===e.dataset.id);n&&A(n,null)})}),s.querySelectorAll(".js-delete-entry").forEach(e=>{e.addEventListener("click",async r=>{if(r.stopPropagation(),!!await E.confirm("Delete this entry?"))try{await h.collections.deleteEntry(y,e.dataset.id),p=p.filter(l=>l.id!==e.dataset.id),E.toast("Entry deleted.",{type:"success"}),C(p,{find:l=>({get:o=>document.querySelector(l)})})}catch{E.toast("Failed to delete entry.",{type:"error"})}})}),s.querySelectorAll("tbody tr").forEach((e,r)=>{const n=t[r];n&&(e.style.cursor="pointer",e.addEventListener("click",l=>{l.target.closest(".js-edit-entry, .js-delete-entry")||q(n)}))}),Domma.icons.scan(s),s.querySelectorAll("[data-tooltip]").forEach(e=>{E.tooltip(e,{content:e.getAttribute("data-tooltip"),position:"top"})}))}function N(t,m){const d={};return t.forEach(a=>{const c={};a.fullWidth?c.span=m:a.span>1&&(c.span=a.span),a.placeholder&&(c.placeholder=a.placeholder),a.helper&&(c.hint=a.helper);const s=a.type==="checkbox"?"boolean":a.type==="date"?"string":a.type;d[a.name]={type:s,label:a.label,required:a.required,options:a.options,...Object.keys(c).length?{formConfig:c}:{}}}),d}function A(t,m){const d=!!t,a=E.modal({title:d?"Edit Entry":"Add Entry",size:"md"}),c=document.createElement("div");c.style.cssText="padding:.25rem 0 .5rem;";const s=g?.fields||[],e=g?.columns||2,r=g?.layout||"stacked",n=document.createElement("div");F.create(N(s,e),t?.data||{},{layout:r,columns:e,showSubmitButton:!1}).renderTo(n),(s||[]).forEach(f=>{if(f.type!=="date"||!f.name)return;const u=n.querySelector(`[name="${f.name}"]`);u&&u.type!=="date"&&(u.type="date")}),c.appendChild(n);const l=document.createElement("div");l.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.5rem;";const o=document.createElement("button");o.className="btn btn-ghost",o.textContent="Cancel";const i=document.createElement("button");i.className="btn btn-primary",i.textContent=d?"Save Changes":"Add Entry",l.appendChild(o),l.appendChild(i),c.appendChild(l),a.element.appendChild(c),a.open(),o.addEventListener("click",()=>a.close()),i.addEventListener("click",async()=>{const f={};s.forEach(u=>{const b=n.querySelector(`[name="${u.name}"]`);b&&(f[u.name]=u.type==="checkbox"?b.checked:b.value)}),i.disabled=!0;try{if(d){const u=await h.collections.updateEntry(y,t.id,f),b=p.findIndex(L=>L.id===t.id);b!==-1&&(p[b]=u),E.toast("Entry updated.",{type:"success"})}else{const u=await h.collections.createEntry(y,f);p.unshift(u),E.toast("Entry added.",{type:"success"})}a.close(),C(p,m||{find:()=>({get:()=>null})})}catch(u){E.toast(u.message||"Failed to save entry.",{type:"error"}),i.disabled=!1}})}function q(t){const m=document.createElement("div"),d=g?.fields||[],a=document.createElement("div");a.style.cssText="display:flex;flex-direction:column;gap:.75rem;margin-bottom:1.25rem;",d.forEach(e=>{const r=t.data?.[e.name];if(r==null||r==="")return;const n=document.createElement("div");n.style.cssText="border-bottom:1px solid var(--dm-border,#333);padding-bottom:.6rem;";const l=document.createElement("strong");l.textContent=e.label||e.name,l.style.cssText="display:block;font-size:.8rem;color:var(--dm-text-muted,#888);margin-bottom:.2rem;";const o=document.createElement("p");o.textContent=String(r),o.style.cssText="margin:0;word-break:break-word;",n.appendChild(l),n.appendChild(o),a.appendChild(n)});const c=document.createElement("div");if(c.style.cssText="font-size:.8rem;color:var(--dm-text-muted,#888);display:flex;flex-direction:column;gap:.3rem;border-top:1px solid var(--dm-border,#333);padding-top:.75rem;",t.meta?.createdAt){const e=document.createElement("span");e.textContent=`Created: ${D(t.meta.createdAt).format("DD MMM YYYY HH:mm")}`,c.appendChild(e)}if(t.meta?.source){const e=document.createElement("span");e.textContent=`Source: ${t.meta.source}`,c.appendChild(e)}m.appendChild(a),m.appendChild(c);const s=E.modal({title:"Entry Details",size:"md"});s.element.appendChild(m),s.open()}function B(t){const m=E.modal({title:"Import Entries",size:"md"}),d=document.createElement("div");d.style.cssText="padding:.25rem 0 .5rem;display:flex;flex-direction:column;gap:.75rem;";const a=document.createElement("p");a.textContent='Paste a JSON array of entries. Each item should have a "data" object with field values.',a.style.cssText="font-size:.875rem;color:var(--dm-text-muted,#888);margin:0;",d.appendChild(a);const c=document.createElement("textarea");c.className="form-input",c.rows=10,c.placeholder='[{"data": {"name": "Example"}}, ...]',d.appendChild(c);const s=document.createElement("p");s.style.cssText="font-size:.875rem;margin:0;display:none;",d.appendChild(s);const e=document.createElement("div");e.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;";const r=document.createElement("button");r.className="btn btn-ghost",r.textContent="Cancel";const n=document.createElement("button");n.className="btn btn-primary",n.textContent="Import",e.appendChild(r),e.appendChild(n),d.appendChild(e),m.element.appendChild(d),m.open(),r.addEventListener("click",()=>m.close()),n.addEventListener("click",async()=>{let l;try{if(l=JSON.parse(c.value),!Array.isArray(l))throw new Error("Must be a JSON array")}catch(o){s.style.display="",s.style.color="var(--dm-danger,#f87171)",s.textContent=`Invalid JSON: ${o.message}`;return}n.disabled=!0;try{const o=await h.collections.import(y,l);s.style.display="",s.style.color="var(--dm-success,#4ade80)",s.textContent=`Imported ${o.imported} entries. Skipped: ${o.skipped}.`,await v(t||{find:()=>({get:()=>null,off:()=>({on:()=>{}})})}),setTimeout(()=>m.close(),1500)}catch(o){s.style.display="",s.style.color="var(--dm-danger,#f87171)",s.textContent=o.message||"Import failed."}finally{n.disabled=!1}})}
@@ -1,4 +1,4 @@
1
- import{api as u}from"../api.js";import{createSimpleEditor as S}from"../lib/simple-editor.js";let p=null,b=null,f=null,l={},v={};const c={};export const componentEditorView={templateUrl:"/admin/js/templates/component-editor.html",async onMount(e){p=null,f=null,l={},v={};for(const t of Object.keys(c))c[t]?.destroy?.(),delete c[t];const n=window.location.hash.match(/\/components\/edit\/([^/?#]+)/);n&&(p=decodeURIComponent(n[1])),A(e),await T(e),L(e),z(e),await D(e);const o=e.find("#component-preview-iframe").get(0);o.contentDocument?.readyState==="complete"?h(e):o.addEventListener("load",()=>h(e),{once:!0}),Domma.icons.scan(e.get(0))}};async function T(e){const n=e.find("#component-name").get(0),o=e.find("#component-tag-hint").get(0),t=e.find("#component-editor-title").get(0),s=e.find("#export-component-btn").get(0),r=()=>{const i=(n.value||"").trim()||"\u2026";o.textContent=`<dm-${i}>`},a=e.find("#component-project").get(0);if(a)try{const i=await u.projects.list();for(const m of i){const d=document.createElement("option");d.value=m.slug,d.textContent=m.name||m.slug,a.appendChild(d)}}catch{}if(p){t.textContent="Edit Component",n.value=p,n.disabled=!0,s&&(s.style.display="");try{const i=await u.components.get(p);w(e,i.source),e.find("#component-bundled").prop("checked",!!i.bundled),v=i.meta||{},a&&(a.value=i.meta?.project||"")}catch(i){E.toast(i.message||"Component not found.",{type:"error"}),R.navigate("/components");return}}else t.textContent="New Component",w(e,V);r(),n.addEventListener("input",r)}const V=`<template>
1
+ import{api as u}from"../api.js";import{createSimpleEditor as S}from"../lib/simple-editor.js";let p=null,b=null,f=null,l={},v={};const c={};export const componentEditorView={templateUrl:"/admin/js/templates/component-editor.html",async onMount(e){p=null,f=null,l={},v={};for(const s of Object.keys(c))c[s]?.destroy?.(),delete c[s];const n=window.location.hash.match(/\/components\/edit\/([^/?#]+)/);n&&(p=decodeURIComponent(n[1]));const o=E.loader(e.get(0),{type:"dots"});try{A(e),await T(e),L(e),z(e),await D(e)}finally{o.destroy()}const t=e.find("#component-preview-iframe").get(0);t.contentDocument?.readyState==="complete"?h(e):t.addEventListener("load",()=>h(e),{once:!0}),Domma.icons.scan(e.get(0))}};async function T(e){const n=e.find("#component-name").get(0),o=e.find("#component-tag-hint").get(0),t=e.find("#component-editor-title").get(0),s=e.find("#export-component-btn").get(0),r=()=>{const i=(n.value||"").trim()||"\u2026";o.textContent=`<dm-${i}>`},a=e.find("#component-project").get(0);if(a)try{const i=await u.projects.list();for(const m of i){const d=document.createElement("option");d.value=m.slug,d.textContent=m.name||m.slug,a.appendChild(d)}}catch{}if(p){t.textContent="Edit Component",n.value=p,n.disabled=!0,s&&(s.style.display="");try{const i=await u.components.get(p);w(e,i.source),e.find("#component-bundled").prop("checked",!!i.bundled),v=i.meta||{},a&&(a.value=i.meta?.project||"")}catch(i){E.toast(i.message||"Component not found.",{type:"error"}),R.navigate("/components");return}}else t.textContent="New Component",w(e,V);r(),n.addEventListener("input",r)}const V=`<template>
2
2
  <div>Hello, <span>{{name}}</span>.</div>
3
3
  </template>
4
4
  <props>
@@ -1,5 +1,5 @@
1
- import{api as i}from"../api.js";import{filterByProject as u,getProjectFromHash as f}from"../lib/project-context.js";function p(t){return String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function g(t){for(;t.firstChild;)t.removeChild(t.firstChild)}export const componentsView={templateUrl:"/admin/js/templates/components.html",async onMount(t){y(),await l(t),k(t),Domma.icons.scan(t.get(0))}};let d=!1;function y(){d||(d=!0,I.register("download",{viewBox:"0 0 24 24",paths:["M12 3v12","M7 10l5 5 5-5","M5 19h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("upload",{viewBox:"0 0 24 24",paths:["M12 21V9","M7 14l5-5 5 5","M5 5h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("plus",{viewBox:"0 0 24 24",paths:["M12 5v14","M5 12h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}async function l(t){const o=t.find("#components-table-container").get(0);if(!o)return;let r=[];try{r=await i.components.list()}catch(e){g(o);const n=document.createElement("p");n.className="text-muted",n.textContent=`Failed to load components: ${e.message}`,o.appendChild(n);return}const s=f();s&&(r=u(r,s)),T.create(o,{data:r,emptyMessage:'No components yet. Click "New Component" to create your first one.',columns:[{key:"name",title:"Name",render:(e,n)=>{const a=n.origin==="plugin"?' <span class="badge badge-secondary" title="Provided by a plugin \u2014 read-only">plugin</span>':"";return`<a href="#/components/edit/${p(e)}">${p(e)}.dmc</a>${a}`}},{key:"props",title:"Props",render:e=>{const n=Object.keys(e||{});return n.length===0?'<span class="text-muted">\u2014</span>':n.map(a=>`<span class="badge badge-secondary" style="margin-right:.25rem;">${p(a)}</span>`).join("")}},{key:"size",title:"Size",render:e=>`${e} B`},{key:"updatedAt",title:"Updated",render:e=>e?new Date(e).toLocaleString():"\u2014"},{key:"name",title:"Actions",render:(e,n)=>{const a=p(e),m=n.origin==="plugin"?"":`<button class="btn btn-sm btn-danger js-delete-component" data-name="${a}" data-tooltip="Delete"><span data-icon="trash"></span></button>`;return`<div style="display:flex;gap:.4rem;justify-content:flex-end;">
1
+ import{api as c}from"../api.js";import{filterByProject as u,getProjectFromHash as f}from"../lib/project-context.js";function l(t){return String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function g(t){for(;t.firstChild;)t.removeChild(t.firstChild)}export const componentsView={templateUrl:"/admin/js/templates/components.html",async onMount(t){y(),await d(t),k(t),Domma.icons.scan(t.get(0))}};let p=!1;function y(){p||(p=!0,I.register("download",{viewBox:"0 0 24 24",paths:["M12 3v12","M7 10l5 5 5-5","M5 19h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("upload",{viewBox:"0 0 24 24",paths:["M12 21V9","M7 14l5-5 5 5","M5 5h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("plus",{viewBox:"0 0 24 24",paths:["M12 5v14","M5 12h14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}async function d(t){const o=t.find("#components-table-container").get(0);if(!o)return;let r=[];const i=E.loader(t.get(0),{type:"dots"});try{r=await c.components.list()}catch(e){g(o);const n=document.createElement("p");n.className="text-muted",n.textContent=`Failed to load components: ${e.message}`,o.appendChild(n);return}finally{i.destroy()}const s=f();s&&(r=u(r,s)),T.create(o,{data:r,emptyMessage:'No components yet. Click "New Component" to create your first one.',columns:[{key:"name",title:"Name",render:(e,n)=>{const a=n.origin==="plugin"?' <span class="badge badge-secondary" title="Provided by a plugin \u2014 read-only">plugin</span>':"";return`<a href="#/components/edit/${l(e)}">${l(e)}.dmc</a>${a}`}},{key:"props",title:"Props",render:e=>{const n=Object.keys(e||{});return n.length===0?'<span class="text-muted">\u2014</span>':n.map(a=>`<span class="badge badge-secondary" style="margin-right:.25rem;">${l(a)}</span>`).join("")}},{key:"size",title:"Size",render:e=>`${e} B`},{key:"updatedAt",title:"Updated",render:e=>e?new Date(e).toLocaleString():"\u2014"},{key:"name",title:"Actions",render:(e,n)=>{const a=l(e),m=n.origin==="plugin"?"":`<button class="btn btn-sm btn-danger js-delete-component" data-name="${a}" data-tooltip="Delete"><span data-icon="trash"></span></button>`;return`<div style="display:flex;gap:.4rem;justify-content:flex-end;">
2
2
  <a href="#/components/edit/${a}" class="btn btn-sm btn-ghost" data-tooltip="Edit"><span data-icon="edit"></span></a>
3
3
  <button class="btn btn-sm btn-ghost js-export-component" data-name="${a}" data-tooltip="Export as .dmcomponent.json"><span data-icon="download"></span></button>
4
4
  ${m}
5
- </div>`}}]}),o.querySelectorAll(".js-delete-component").forEach(e=>{e.addEventListener("click",async()=>{await h(e.dataset.name,t)})}),o.querySelectorAll(".js-export-component").forEach(e=>{e.addEventListener("click",async()=>{try{await i.components.exportBundle(e.dataset.name)}catch(n){E.toast(n.message||"Export failed.",{type:"error"})}})}),Domma.icons.scan(o),o.querySelectorAll("[data-tooltip]").forEach(e=>{E.tooltip(e,{content:e.getAttribute("data-tooltip"),position:"top"})})}async function h(t,o){if(await E.confirm(`Delete component "${t}"? This cannot be undone.`))try{await i.components.delete(t),E.toast("Component deleted.",{type:"success"}),await l(o)}catch(s){E.toast(s.message||"Failed to delete component.",{type:"error"})}}function k(t){const o=t.find("#import-component-btn").get(0),r=t.find("#import-component-file").get(0);!o||!r||(o.addEventListener("click",()=>r.click()),r.addEventListener("change",async()=>{const s=r.files?.[0];if(!s)return;r.value="";let e;try{const n=await s.text();e=JSON.parse(n)}catch{E.toast("Not a valid .dmcomponent.json file (could not parse JSON).",{type:"error"});return}if(!e||typeof e!="object"||!e.name||typeof e.source!="string"){E.toast("Bundle is missing a name or source field.",{type:"error"});return}try{const n=await i.components.importBundle(e);E.toast(`Imported "${n.name}".`,{type:"success"}),await l(t)}catch(n){if(n.code==="CONFLICT"){if(!await E.confirm(`A component named "${n.name}" already exists. Overwrite it with the imported version?`)){E.toast("Import cancelled.",{type:"info"});return}try{const c=await i.components.importBundle(e,{overwrite:!0});E.toast(`Overwrote "${c.name}".`,{type:"success"}),await l(t)}catch(c){E.toast(c.message||"Import failed.",{type:"error"})}return}E.toast(n.message||"Import failed.",{type:"error"})}}))}
5
+ </div>`}}]}),o.querySelectorAll(".js-delete-component").forEach(e=>{e.addEventListener("click",async()=>{await h(e.dataset.name,t)})}),o.querySelectorAll(".js-export-component").forEach(e=>{e.addEventListener("click",async()=>{try{await c.components.exportBundle(e.dataset.name)}catch(n){E.toast(n.message||"Export failed.",{type:"error"})}})}),Domma.icons.scan(o),o.querySelectorAll("[data-tooltip]").forEach(e=>{E.tooltip(e,{content:e.getAttribute("data-tooltip"),position:"top"})})}async function h(t,o){if(await E.confirm(`Delete component "${t}"? This cannot be undone.`))try{await c.components.delete(t),E.toast("Component deleted.",{type:"success"}),await d(o)}catch(i){E.toast(i.message||"Failed to delete component.",{type:"error"})}}function k(t){const o=t.find("#import-component-btn").get(0),r=t.find("#import-component-file").get(0);!o||!r||(o.addEventListener("click",()=>r.click()),r.addEventListener("change",async()=>{const i=r.files?.[0];if(!i)return;r.value="";let s;try{const e=await i.text();s=JSON.parse(e)}catch{E.toast("Not a valid .dmcomponent.json file (could not parse JSON).",{type:"error"});return}if(!s||typeof s!="object"||!s.name||typeof s.source!="string"){E.toast("Bundle is missing a name or source field.",{type:"error"});return}try{const e=await c.components.importBundle(s);E.toast(`Imported "${e.name}".`,{type:"success"}),await d(t)}catch(e){if(e.code==="CONFLICT"){if(!await E.confirm(`A component named "${e.name}" already exists. Overwrite it with the imported version?`)){E.toast("Import cancelled.",{type:"info"});return}try{const a=await c.components.importBundle(s,{overwrite:!0});E.toast(`Overwrote "${a.name}".`,{type:"success"}),await d(t)}catch(a){E.toast(a.message||"Import failed.",{type:"error"})}return}E.toast(e.message||"Import failed.",{type:"error"})}}))}
@@ -1 +1 @@
1
- import{apiRequest as a}from"/admin/js/api.js";export const effectsView={templateUrl:"/admin/js/templates/effects.html",async onMount(t){let e={};try{e=await a("/effects/settings")}catch{E.toast("Could not load settings.",{type:"error"})}t.find("#field-respect-motion").prop("checked",e.respectMotion!==!1),t.find("#field-default-duration").val(e.defaultDuration??600),t.find("#field-default-animation").val(e.defaultAnimation||"fade"),t.find("#field-default-threshold").val(e.defaultThreshold??.1),t.find("#save-settings-btn").off("click").on("click",async()=>{const s={respectMotion:t.find("#field-respect-motion").prop("checked"),defaultDuration:parseInt(t.find("#field-default-duration").val(),10)||600,defaultAnimation:t.find("#field-default-animation").val(),defaultThreshold:parseFloat(t.find("#field-default-threshold").val())||.1};try{await a("/effects/settings",{method:"PUT",body:JSON.stringify(s)}),E.toast("Settings saved.",{type:"success"})}catch{E.toast("Failed to save settings.",{type:"error"})}}),E.tabs(t.find("#effects-tabs").get(0)),t.find(".effects-tab-btn").on("click",function(){const s=this.getAttribute("data-fx-tab");t.find(".effects-tab-btn").removeClass("active"),$(this).addClass("active"),t.find(".effects-tab-panel").hide(),t.find(`#tab-${s}`).show()}),t.find(".effects-tab-panel").hide(),t.find("#tab-entrance").show(),Domma.icons.scan()}};
1
+ import{apiRequest as a}from"/admin/js/api.js";export const effectsView={templateUrl:"/admin/js/templates/effects.html",async onMount(t){let e={};const f=E.loader(t.get(0),{type:"dots"});try{e=await a("/effects/settings")}catch{E.toast("Could not load settings.",{type:"error"})}finally{f.destroy()}t.find("#field-respect-motion").prop("checked",e.respectMotion!==!1),t.find("#field-default-duration").val(e.defaultDuration??600),t.find("#field-default-animation").val(e.defaultAnimation||"fade"),t.find("#field-default-threshold").val(e.defaultThreshold??.1),t.find("#save-settings-btn").off("click").on("click",async()=>{const s={respectMotion:t.find("#field-respect-motion").prop("checked"),defaultDuration:parseInt(t.find("#field-default-duration").val(),10)||600,defaultAnimation:t.find("#field-default-animation").val(),defaultThreshold:parseFloat(t.find("#field-default-threshold").val())||.1};try{await a("/effects/settings",{method:"PUT",body:JSON.stringify(s)}),E.toast("Settings saved.",{type:"success"})}catch{E.toast("Failed to save settings.",{type:"error"})}}),E.tabs(t.find("#effects-tabs").get(0)),t.find(".effects-tab-btn").on("click",function(){const s=this.getAttribute("data-fx-tab");t.find(".effects-tab-btn").removeClass("active"),$(this).addClass("active"),t.find(".effects-tab-panel").hide(),t.find(`#tab-${s}`).show()}),t.find(".effects-tab-panel").hide(),t.find("#tab-entrance").show(),Domma.icons.scan()}};
@@ -1,8 +1,8 @@
1
- import{apiRequest as I}from"/admin/js/api.js";import{makeIconInput as me}from"/admin/js/lib/shortcode-modal.js";const K=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"chooser",label:"Chooser (visual options)"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"password",label:"Password"},{value:"file",label:"File upload"},{value:"hidden",label:"Hidden field"}],J=new Set(["select","radio","checkbox-group","chooser"]);let b=[],L=null,P=null,M=null,G={};function x(e,t,s=14){e.textContent="";const n=document.createElement("span");return n.setAttribute("data-icon",t),n.setAttribute("data-icon-size",String(s)),n.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;",e.appendChild(n),window.I?.scan?.(e),e}function j(e,t,s,n=14){return x(e,t,n),e.appendChild(document.createTextNode(" "+s)),e}let _=null,X=null;function W(){clearTimeout(X),X=setTimeout(()=>{_&&_()},350)}function Z(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function ee(e){return K.find(t=>t.value===e)?.label||e}function te(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function ue(e){const t={...b[e]};if(t.type==="spacer")return t;if(t.type==="page-break"){const h=document.getElementById(`fb-pb-label-${e}`),g=document.getElementById(`fb-pb-desc-${e}`);return h&&(t.label=h.value.trim()||t.label),g&&(t.description=g.value.trim()),t}const s=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),o=document.getElementById(`fb-type-${e}`),l=document.getElementById(`fb-required-${e}`),c=document.getElementById(`fb-placeholder-${e}`),p=document.getElementById(`fb-helper-${e}`),d=document.getElementById(`fb-tooltip-${e}`);if(s&&(t.label=s.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),o&&(t.type=o.value||t.type),l&&(t.required=l.checked),c&&(t.placeholder=c.value.trim()),p&&(t.helper=p.value.trim()),d&&(t.tooltip=d.value.trim()),t.type==="chooser"){const h=document.getElementById(`fb-chooser-variant-${e}`)?.value;h&&(t.variant=h);const g=document.getElementById(`fb-chooser-multiple-${e}`);g&&(t.multiple=g.checked);const v=document.getElementById(`fb-chooser-density-${e}`)?.value;v&&(t.density=v);const w=document.getElementById(`fb-chooser-columns-${e}`)?.value;w!==""&&w!==void 0&&(t.columns=parseInt(w,10)||3);const C=document.getElementById(`fb-chooser-accent-${e}`)?.value.trim();C?t.accent=C:delete t.accent;const q=document.getElementById(`fb-chooser-accent-style-${e}`)?.value;q?t.accentStyle=q:delete t.accentStyle;const z=document.getElementById(`fb-chooser-glow-${e}`);z&&(t.glow=z.checked);const B=document.getElementById(`fb-chooser-glow-colour-${e}`)?.value.trim();B?t.glowColour=B:delete t.glowColour;const $=document.getElementById(`fb-chooser-shadow-${e}`)?.value;$&&$!=="none"?t.shadow=$:delete t.shadow;const A=document.getElementById(`fb-chooser-shadow-colour-${e}`)?.value.trim();A?t.shadowColour=A:delete t.shadowColour,U(e),b[e]&&Array.isArray(b[e].options)&&(t.options=b[e].options)}else if(J.has(t.type)){const h=document.getElementById(`fb-options-${e}`);h&&(t.options=h.value.split(`
2
- `).filter(g=>g.trim()).map(g=>{const[v,...w]=g.split(":");return{value:v.trim(),label:w.join(":").trim()||v.trim()}}))}if(t.type==="textarea"){const h=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);h>0&&(t.formConfig={...t.formConfig||{},rows:h})}const a=document.getElementById(`fb-span-${e}`),r=document.getElementById(`fb-fullwidth-${e}`);if(a||r){const h={...t.formConfig||{}};if(r?.checked)h.span="full";else{const g=parseInt(a?.value,10);g>1?h.span=g:delete h.span}t.formConfig=Object.keys(h).length?h:void 0}const i=document.getElementById(`fb-minlength-${e}`)?.value;i&&(t.minLength=parseInt(i,10));const u=document.getElementById(`fb-maxlength-${e}`)?.value;u&&(t.maxLength=parseInt(u,10));const m=document.getElementById(`fb-min-${e}`)?.value;m!==""&&m!==void 0&&(t.min=parseFloat(m));const f=document.getElementById(`fb-max-${e}`)?.value;f!==""&&f!==void 0&&(t.max=parseFloat(f));const y=fe(e);return y?t.logic=y:delete t.logic,t}function fe(e){const t=document.querySelector(`.fb-field-card[data-index="${e}"]`);if(!t)return;const s=t.querySelector(".fb-field-logic");if(!s)return;const n={};let o=!1;const l=s.querySelector('[data-logic-section="visibility"]');if(l){const a=l.querySelector(".fb-logic-vis-default"),r=l.querySelector(".fb-logic-vis-transition"),i=Array.from(l.querySelectorAll(".fb-logic-cond-row")).map(f=>{const y=f.querySelector(".fb-logic-cond-field"),h=f.querySelector(".fb-logic-cond-op"),g=f.querySelector(".fb-logic-cond-val"),v=f.querySelector(".fb-logic-vis-then");return y?.value?{when:{all:[{field:y.value,operator:h.value,value:g.value}]},then:v.value}:null}).filter(Boolean),u=a?.value||"visible",m=r?.value||"none";(u!=="visible"||i.length>0||m!=="none")&&(n.visibility={default:u,conditions:i},m!=="none"&&(n.visibility.transition=m),o=!0)}const c=s.querySelector('[data-logic-section="requirement"]');if(c){const a=c.querySelector(".fb-logic-req-default"),r=Array.from(c.querySelectorAll(".fb-logic-cond-row")).map(i=>{const u=i.querySelector(".fb-logic-cond-field"),m=i.querySelector(".fb-logic-cond-op"),f=i.querySelector(".fb-logic-cond-val"),y=i.querySelector(".fb-logic-req-then");return u?.value?{when:{all:[{field:u.value,operator:m.value,value:f.value}]},then:y.value==="true"}:null}).filter(Boolean);r.length>0&&(n.requirement={default:a?.checked===!0,conditions:r},o=!0)}const p=s.querySelector('[data-logic-section="validation"]');if(p){const a=Array.from(p.querySelectorAll(".fb-logic-val-rule")).map(r=>{const i=r.querySelector(".fb-logic-val-type"),u=r.querySelector(".fb-logic-val-pattern"),m=r.querySelector(".fb-logic-val-flags"),f=r.querySelector(".fb-logic-val-message");if(!u?.value.trim())return null;const y=i?.value||"regex",h={type:y,message:f?.value.trim()||"Invalid value."};return y==="regex"?(h.pattern=u.value.trim(),m?.value.trim()&&(h.flags=m.value.trim())):h.field=u.value.trim(),h}).filter(Boolean);a.length>0&&(n.validation=a,o=!0)}const d=s.querySelector('[data-logic-section="cascade"]');if(d){const a=d.querySelector(".fb-logic-cascade-source"),r=d.querySelector(".fb-logic-cascade-mapping"),i=d.querySelector(".fb-logic-cascade-defaults"),u=a?.value?.trim();if(u){let m={};try{m=JSON.parse(r?.value||"{}")}catch{}const f=(i?.value||"").split(`
3
- `).filter(y=>y.trim()).map(y=>{const[h,...g]=y.split(":");return{value:h.trim(),label:g.join(":").trim()||h.trim()}});n.cascade={sourceField:u,mapping:m,defaultOptions:f},o=!0}}return o?n:void 0}function T(){b=b.map((e,t)=>ue(t))}function N(e){const t=e.find("#fields-list").get(0),s=e.find("#fields-empty-msg").get(0);if(t){if(Array.from(t.querySelectorAll(".fb-field-card")).forEach(n=>n.remove()),b.length===0){s&&(s.style.display=""),W();return}s&&(s.style.display="none"),b.forEach((n,o)=>{const l=n.type==="page-break"?be(n,o,e):n.type==="spacer"?he(n,o,e):ge(n,o,e);t.appendChild(l)}),W()}}function be(e,t,s){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--dm-border,#444);border-radius:6px;overflow:hidden;margin-bottom:.5rem;background:var(--dm-card-bg,rgba(255,255,255,.02));";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent="\u2014 Page Break \u2014",l.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:color-mix(in srgb, var(--dm-text-muted) 20%, transparent);color:var(--dm-text-muted,#888);white-space:nowrap;flex-shrink:0;font-style:italic;";const c=document.createElement("span");c.textContent=e.label||"Untitled Step",c.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text-muted,#888);";const p=document.createElement("div");if(p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move up",x(m,"arrow-up"),m.addEventListener("click",f=>{f.stopPropagation(),T(),[b[t-1],b[t]]=[b[t],b[t-1]],N(s)}),p.appendChild(m)}if(t<b.length-1){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move down",x(m,"arrow-down"),m.addEventListener("click",f=>{f.stopPropagation(),T(),[b[t],b[t+1]]=[b[t+1],b[t]],N(s)}),p.appendChild(m)}const d=document.createElement("button");d.className="btn btn-xs btn-ghost",d.title="Edit step",x(d,"more-horizontal"),d.addEventListener("click",m=>{m.stopPropagation(),r.style.display=r.style.display==="none"?"":"none"}),p.appendChild(d);const a=document.createElement("button");a.className="btn btn-xs btn-ghost",a.style.cssText="line-height:1;opacity:.6;",a.title="Remove page break",x(a,"x"),a.addEventListener("click",async m=>{m.stopPropagation(),await E.confirm("Remove this page break?")&&(T(),b.splice(t,1),N(s))}),p.appendChild(a),o.appendChild(l),o.appendChild(c),o.appendChild(p),o.addEventListener("click",()=>{r.style.display=r.style.display==="none"?"":"none"});const r=document.createElement("div");r.className="fb-field-body",r.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border,#444);display:none;";const i=k([S("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),S("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),u=i.querySelector(`#fb-pb-label-${t}`);return u&&u.addEventListener("input",()=>{c.textContent=u.value||"Untitled Step"}),r.appendChild(i),n.appendChild(o),n.appendChild(r),n}function he(e,t,s){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--dm-border,#444);border-radius:6px;margin-bottom:.5rem;background:transparent;";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const l=document.createElement("div");l.style.cssText="flex:1;height:1px;background:var(--dm-border,#444);";const c=document.createElement("span");c.textContent="Spacer",c.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const p=document.createElement("div");p.style.cssText="flex:1;height:1px;background:var(--dm-border,#444);";const d=document.createElement("div");if(d.style.cssText="display:flex;gap:.25rem;flex-shrink:0;",t>0){const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Move up",x(r,"arrow-up"),r.addEventListener("click",i=>{i.stopPropagation(),T(),[b[t-1],b[t]]=[b[t],b[t-1]],N(s)}),d.appendChild(r)}if(t<b.length-1){const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Move down",x(r,"arrow-down"),r.addEventListener("click",i=>{i.stopPropagation(),T(),[b[t],b[t+1]]=[b[t+1],b[t]],N(s)}),d.appendChild(r)}const a=document.createElement("button");return a.className="btn btn-xs btn-ghost",a.style.cssText="line-height:1;opacity:.6;",a.title="Remove spacer",x(a,"x"),a.addEventListener("click",async r=>{r.stopPropagation(),T(),b.splice(t,1),N(s)}),d.appendChild(a),o.appendChild(l),o.appendChild(c),o.appendChild(p),o.appendChild(d),n.appendChild(o),n}function ge(e,t,s){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border,#333);border-radius:6px;overflow:hidden;margin-bottom:.5rem;";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;background:var(--dm-card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=ee(e.type),l.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:color-mix(in srgb, var(--dm-primary) 14%, transparent);color:var(--dm-primary,#6366f1);white-space:nowrap;flex-shrink:0;";const c=document.createElement("span");c.textContent=e.label||"(unlabelled)",c.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const p=document.createElement("div");if(p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const i=document.createElement("button");i.className="btn btn-xs btn-ghost",i.title="Move up",x(i,"arrow-up"),i.addEventListener("click",u=>{u.stopPropagation(),T(),[b[t-1],b[t]]=[b[t],b[t-1]],N(s)}),p.appendChild(i)}if(t<b.length-1){const i=document.createElement("button");i.className="btn btn-xs btn-ghost",i.title="Move down",x(i,"arrow-down"),i.addEventListener("click",u=>{u.stopPropagation(),T(),[b[t],b[t+1]]=[b[t+1],b[t]],N(s)}),p.appendChild(i)}const d=document.createElement("button");d.className="btn btn-xs btn-ghost",d.title="Edit field",x(d,"more-horizontal"),d.addEventListener("click",i=>{i.stopPropagation(),r.style.display=r.style.display==="none"?"":"none"}),p.appendChild(d);const a=document.createElement("button");if(a.className="btn btn-xs btn-ghost",a.style.cssText="line-height:1;opacity:.6;",a.title="Remove field",x(a,"x"),a.addEventListener("click",async i=>{i.stopPropagation(),await E.confirm("Remove this field?")&&(T(),b.splice(t,1),N(s))}),p.appendChild(a),o.appendChild(l),o.appendChild(c),e.required){const i=document.createElement("span");i.textContent="required",i.style.cssText="font-size:.7rem;color:var(--dm-danger,#ef4444);flex-shrink:0;",o.appendChild(i)}if(te(e.logic)){const i=document.createElement("span");x(i,"zap"),i.title="Has conditional logic",i.style.cssText="font-size:.75rem;color:var(--dm-primary,#6366f1);flex-shrink:0;",o.appendChild(i)}o.appendChild(p),o.addEventListener("click",()=>{r.style.display=r.style.display==="none"?"":"none"});const r=ye(e,t,c);return r.style.display="none",n.appendChild(o),n.appendChild(r),n}function ye(e,t,s){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:.8rem;border-top:1px solid var(--dm-border,#333);";const o=k([S("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),S("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),l=k([ze("Type",`fb-type-${t}`,K,e.type||"string"),ce("Required",`fb-required-${t}`,e.required||!1)]),c=k([S("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field")]),p=k([S("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field"),S("Tooltip",`fb-tooltip-${t}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),d=e.formConfig?.span,a=k([S("Column Span",`fb-span-${t}`,"number",d&&d!=="full"?String(d):"1","Columns to span (grid only)"),ce("Full Width",`fb-fullwidth-${t}`,d==="full")]);a.classList.add("fb-grid-row"),a.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(o),n.appendChild(l),n.appendChild(c),n.appendChild(p),n.appendChild(a);const r=n.querySelector(`#fb-label-${t}`),i=n.querySelector(`#fb-name-${t}`);r&&r.addEventListener("input",()=>{s&&(s.textContent=r.value||"(unlabelled)"),i&&!i.dataset.manuallyEdited&&(i.value=Z(r.value))}),i&&i.addEventListener("input",()=>{i.dataset.manuallyEdited="1"});const u=n.querySelector(`#fb-type-${t}`);u&&u.addEventListener("change",()=>{const f=n.closest(".fb-field-card");if(f){const g=f.querySelector("span");g&&(g.textContent=ee(u.value))}const y=n.querySelector(".fb-field-extras");y&&y.remove();const h=oe(u.value,e,t);h&&n.appendChild(h)});const m=oe(e.type,e,t);return m&&n.appendChild(m),n.appendChild(ke(e,t)),n}const ve=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],ne=new Set(["is_empty","is_not_empty"]);function D(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--dm-text-muted,#888);margin:.6rem 0 .3rem;text-transform:uppercase;letter-spacing:.04em;",t}function V(e,t,s,n,o){const l=document.createElement("div");l.className="fb-logic-cond-row",l.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const c=document.createElement("span");c.textContent="When",c.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);flex-shrink:0;";const p=document.createElement("select");p.className="form-select fb-logic-cond-field",p.style.cssText="flex:1 1 140px;min-width:140px;",t.forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,e&&m.value===e.field&&(f.selected=!0),p.appendChild(f)});const d=document.createElement("select");d.className="form-select fb-logic-cond-op",d.style.cssText="flex:1 1 160px;min-width:140px;",ve.forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,e&&m.value===e.operator&&(f.selected=!0),d.appendChild(f)});const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-cond-val",a.placeholder="value",a.style.cssText="flex:1 1 120px;min-width:100px;",a.value=e?.value||"",e&&ne.has(e.operator)&&(a.style.display="none"),d.addEventListener("change",()=>{a.style.display=ne.has(d.value)?"none":""});const r=document.createElement("span");x(r,"arrow-right"),r.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);flex-shrink:0;";const i=document.createElement("select");i.className=`form-select ${n}`,i.style.cssText="flex:1 1 140px;min-width:120px;",s.forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,m.value===o&&(f.selected=!0),i.appendChild(f)});const u=document.createElement("button");return u.type="button",u.className="btn btn-xs btn-ghost",u.style.cssText="line-height:1;opacity:.6;",x(u,"x"),u.style.flexShrink="0",u.addEventListener("click",()=>l.remove()),l.appendChild(c),l.appendChild(p),l.appendChild(d),l.appendChild(a),l.appendChild(r),l.appendChild(i),l.appendChild(u),l}function xe(e,t,s){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(D("Visibility"));const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const l=document.createElement("span");l.textContent="Default:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const c=document.createElement("select");c.className="form-select fb-logic-vis-default",c.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,m.value===(e.default||"visible")&&(f.selected=!0),c.appendChild(f)}),o.appendChild(l),o.appendChild(c),n.appendChild(o);const p=document.createElement("div");p.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const d=document.createElement("span");d.textContent="Transition:",d.style.cssText="font-size:.8rem;flex-shrink:0;";const a=document.createElement("select");a.className="form-select fb-logic-vis-transition",a.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,m.value===(e.transition||"none")&&(f.selected=!0),a.appendChild(f)}),p.appendChild(d),p.appendChild(a),n.appendChild(p);const r=document.createElement("div");r.className="fb-logic-vis-rules";const i=s.map(m=>({value:m.name,label:m.label||m.name})),u=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(m=>{const f=(m.when?.all||m.when?.any||[])[0],y=m.then==="hidden"?"hidden":"visible";i.length>0&&r.appendChild(V(f,i,u,"fb-logic-vis-then",y))}),n.appendChild(r),i.length>0){const m=document.createElement("button");m.type="button",m.className="btn btn-xs btn-ghost",m.style.cssText="font-size:.73rem;margin-top:.2rem;",j(m,"plus","Add visibility rule"),m.addEventListener("click",()=>r.appendChild(V(null,i,u,"fb-logic-vis-then","visible"))),n.appendChild(m)}return n}function Ce(e,t,s){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(D("Conditional Requirement"));const o=document.createElement("label");o.style.cssText="display:flex;align-items:center;gap:.4rem;font-size:.8rem;cursor:pointer;margin-bottom:.4rem;";const l=document.createElement("input");l.type="checkbox",l.className="fb-logic-req-default",l.checked=e.default===!0,o.appendChild(l),o.appendChild(document.createTextNode("Required by default")),n.appendChild(o);const c=document.createElement("div");c.className="fb-logic-req-rules";const p=s.map(a=>({value:a.name,label:a.label||a.name})),d=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(a=>{const r=(a.when?.all||a.when?.any||[])[0],i=a.then===!0?"true":"false";p.length>0&&c.appendChild(V(r,p,d,"fb-logic-req-then",i))}),n.appendChild(c),p.length>0){const a=document.createElement("button");a.type="button",a.className="btn btn-xs btn-ghost",a.style.cssText="font-size:.73rem;margin-top:.2rem;",j(a,"plus","Add requirement rule"),a.addEventListener("click",()=>c.appendChild(V(null,p,d,"fb-logic-req-then","true"))),n.appendChild(a)}return n}function le(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const s=document.createElement("select");s.className="form-select fb-logic-val-type",s.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(p=>{const d=document.createElement("option");d.value=p.value,d.textContent=p.label,p.value===(e?.type||"regex")&&(d.selected=!0),s.appendChild(d)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;";const o=document.createElement("input");o.type="text",o.className="form-input fb-logic-val-flags",o.placeholder="flags",o.value=e?.flags||"",o.style.cssText="flex:0 0 55px;",e?.type==="match"&&(o.style.display="none"),s.addEventListener("change",()=>{o.style.display=s.value==="match"?"none":"",n.placeholder=s.value==="match"?"field name":"pattern"});const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-message",l.placeholder="Error message",l.value=e?.message||"",l.style.cssText="flex:4;";const c=document.createElement("button");return c.type="button",c.className="btn btn-xs btn-ghost",c.style.cssText="line-height:1;opacity:.6;",x(c,"x"),c.style.flexShrink="0",c.addEventListener("click",()=>t.remove()),t.appendChild(s),t.appendChild(n),t.appendChild(o),t.appendChild(l),t.appendChild(c),t}function Ee(e,t,s){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(D("Custom Validation"));const o=document.createElement("div");o.className="fb-logic-val-rules",(e||[]).forEach(c=>o.appendChild(le(c))),n.appendChild(o);const l=document.createElement("button");return l.type="button",l.className="btn btn-xs btn-ghost",l.style.cssText="font-size:.73rem;margin-top:.2rem;",j(l,"plus","Add validation rule"),l.addEventListener("click",()=>o.appendChild(le(null))),n.appendChild(l),n}function we(e,t,s){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(D("Cascade Options"));const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const l=document.createElement("span");l.textContent="Source field:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const c=document.createElement("select");c.className="form-select fb-logic-cascade-source",c.style.cssText="flex:1;";const p=document.createElement("option");p.value="",p.textContent="\u2014 none \u2014",c.appendChild(p),s.forEach(u=>{const m=document.createElement("option");m.value=u.name,m.textContent=u.label||u.name,u.name===e.sourceField&&(m.selected=!0),c.appendChild(m)}),o.appendChild(l),o.appendChild(c),n.appendChild(o);const d=document.createElement("p");d.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',d.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);margin:.3rem 0 .2rem;";const a=document.createElement("textarea");a.className="form-input fb-logic-cascade-mapping",a.rows=4,a.style.cssText="font-family:monospace;",a.placeholder='{"uk": [{"value": "london", "label": "London"}]}',a.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(d),n.appendChild(a);const r=document.createElement("p");r.textContent="Default options (one per line: value:Label)",r.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);margin:.3rem 0 .2rem;";const i=document.createElement("textarea");return i.className="form-input fb-logic-cascade-defaults",i.rows=3,i.style.cssText="font-family:monospace;",i.placeholder=`option1:Option 1
4
- option2:Option 2`,i.value=(e.defaultOptions||[]).map(u=>{const m=typeof u=="string"?u:u.value??"",f=typeof u=="string"?u:u.label??m;return m===f?m:`${m}:${f}`}).join(`
5
- `),n.appendChild(r),n.appendChild(i),n}function ke(e,t){const s=e.logic||{},n=b.filter((i,u)=>u!==t&&i.type!=="page-break"&&i.type!=="spacer"),o=document.createElement("div");o.className="fb-field-logic",o.style.cssText="margin-top:.75rem;border-top:1px solid var(--dm-border,#333);padding-top:.5rem;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const c=document.createElement("span");c.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted,#888);",c.textContent="\u26A1 Conditional Logic";const p=te(s),d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",x(d,p?"chevron-down":"chevron-right",12);const a=document.createElement("div");a.className="fb-logic-body",a.style.cssText="padding:.25rem 0 .25rem;"+(p?"":"display:none;"),l.addEventListener("click",()=>{const i=a.style.display==="none";a.style.display=i?"":"none",d.textContent=i?"\u25BE":"\u25B8"}),l.appendChild(c),l.appendChild(d),o.appendChild(l),a.appendChild(xe(s.visibility||{},t,n)),a.appendChild(Ce(s.requirement||{},t,n)),a.appendChild(Ee(s.validation||[],t,n));const r=document.getElementById(`fb-type-${t}`)?.value||e.type;return J.has(r)&&a.appendChild(we(s.cascade||{},t,n)),o.appendChild(a),o}function oe(e,t,s){const n=document.createElement("div");return n.className="fb-field-extras",e==="chooser"?(n.appendChild(Se(t,s)),n.appendChild(Ne(t.options||[],s))):(J.has(e)&&n.appendChild(Be(t.options||[],s)),e==="textarea"&&n.appendChild(k([S("Rows",`fb-rows-${s}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(k([S("Min Length",`fb-minlength-${s}`,"number",t.minLength||"",""),S("Max Length",`fb-maxlength-${s}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(k([S("Min",`fb-min-${s}`,"number",t.min??"",""),S("Max",`fb-max-${s}`,"number",t.max??"","")]))),n.children.length?n:null}function ae(e){const t=document.createElement("div");t.className="fb-chooser-section",t.style.cssText="border:1px solid var(--dm-border, #e5e7eb); border-radius:6px; margin-top:.5rem; overflow:hidden;";const s=document.createElement("div");s.style.cssText="padding:.4rem .6rem; background:color-mix(in srgb, var(--dm-background, #f9fafb) 60%, transparent); font-weight:600; font-size:.82rem; border-bottom:1px solid var(--dm-border, #e5e7eb);",s.textContent=e,t.appendChild(s);const n=document.createElement("div");return n.className="fb-chooser-section-body",n.style.cssText="padding:.55rem .6rem; display:flex; flex-direction:column; gap:.45rem;",t.appendChild(n),{wrap:t,body:n}}function H(e,t,s,n,o){const l=document.createElement("div");l.style.flex="1";const c=document.createElement("label");c.htmlFor=e,c.className="form-label",c.textContent=t,c.style.fontSize=".8rem";const p=document.createElement("select");if(p.id=e,p.className="form-input",n.forEach(([d,a])=>{const r=document.createElement("option");r.value=d,r.textContent=a,String(d)===String(s)&&(r.selected=!0),p.appendChild(r)}),l.appendChild(c),l.appendChild(p),o){const d=document.createElement("p");d.className="form-hint text-muted",d.textContent=o,d.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(d)}return l}function se(e,t,s,n){const o=document.createElement("div");o.style.flex="1";const l=document.createElement("label");l.style.cssText="display:inline-flex;align-items:center;gap:.4rem;font-size:.82rem;";const c=document.createElement("input");if(c.id=e,c.type="checkbox",c.checked=!!s,l.appendChild(c),l.appendChild(document.createTextNode(" "+t)),o.appendChild(l),n){const p=document.createElement("p");p.className="form-hint text-muted",p.textContent=n,p.style.cssText="font-size:.72rem;margin-top:.2rem;",o.appendChild(p)}return o}function Q(e,t,s,n,o){const l=document.createElement("div");l.style.flex="1";const c=document.createElement("label");c.htmlFor=e,c.className="form-label",c.textContent=t,c.style.fontSize=".8rem",l.appendChild(c);const p=document.createElement("div");p.style.cssText="display:flex;gap:.4rem;align-items:stretch;";const d=document.createElement("input");d.id=e,d.type="text",d.className="form-input",d.value=s||"",n&&(d.placeholder=n),d.style.flex="1";const a=document.createElement("input");a.type="color",a.title="Pick a colour",a.style.cssText="width:36px;height:auto;padding:0;border:1px solid var(--dm-border,#e5e7eb);border-radius:4px;cursor:pointer;";const r=String(d.value).match(/^#[0-9a-fA-F]{3,8}$/);if(a.value=r?d.value:"#000000",a.addEventListener("input",()=>{d.value=a.value,d.dispatchEvent(new Event("input",{bubbles:!0}))}),p.appendChild(d),p.appendChild(a),l.appendChild(p),o){const i=document.createElement("p");i.className="form-hint text-muted",i.textContent=o,i.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(i)}return l}function Se(e,t){const s=document.createElement("div");s.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const n=ae("Layout");n.body.appendChild(k([H(`fb-chooser-variant-${t}`,"Variant",e.variant||"card",[["card","Card \u2014 rich tiles"],["chip","Chip \u2014 compact pills"]],"Card supports description and grid columns; chips wrap."),se(`fb-chooser-multiple-${t}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),n.body.appendChild(k([H(`fb-chooser-density-${t}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),S("Columns",`fb-chooser-columns-${t}`,"number",e.columns||3,"Card grid (1\u20136). Ignored for chips.")])),s.appendChild(n.wrap);const o=ae("Visual");return o.body.appendChild(k([Q(`fb-chooser-accent-${t}`,"Accent",e.accent||"","primary / success / #ec4899","Selected highlight colour \u2014 semantic name or any CSS colour."),H(`fb-chooser-accent-style-${t}`,"Accent style",e.accentStyle||"border",[["border","Border (default)"],["solid","Solid"],["glow","Glow"],["overlay","Overlay"],["underline","Underline"]],"Visual treatment of the selected state.")])),o.body.appendChild(k([se(`fb-chooser-glow-${t}`,"Glow on selected",!!e.glow,"Soft outer glow."),Q(`fb-chooser-glow-colour-${t}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),o.body.appendChild(k([H(`fb-chooser-shadow-${t}`,"Shadow",e.shadow||"none",[["none","None"],["sm","Small"],["md","Medium"],["lg","Large"],["xl","Extra Large"]],"Drop shadow on every option."),Q(`fb-chooser-shadow-colour-${t}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),s.appendChild(o.wrap),s}function Te(e,t,s,n){const o=document.createElement("div");o.className="fb-chooser-option-row",o.dataset.optIdx=String(s),o.style.cssText="border:1px solid var(--dm-border,#e5e7eb); border-radius:4px; padding:.5rem; background:var(--dm-background-alt, color-mix(in srgb, var(--dm-card-bg, #fff) 92%, var(--dm-text, #111))); display:flex; flex-direction:column; gap:.35rem;";const l=document.createElement("div");l.style.cssText="display:flex; gap:.4rem; align-items:center;";const c=document.createElement("div");c.style.cssText="display:flex; flex-direction:column; gap:1px;";const p=document.createElement("button");p.type="button",p.className="btn btn-xs btn-ghost",p.title="Move up",x(p,"arrow-up"),p.addEventListener("click",$=>{$.preventDefault(),ie(t,s,-1,n)});const d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",d.title="Move down",x(d,"arrow-down"),d.addEventListener("click",$=>{$.preventDefault(),ie(t,s,1,n)}),c.appendChild(p),c.appendChild(d),l.appendChild(c);const a=document.createElement("input");a.type="text",a.className="form-input fb-chooser-opt-value",a.placeholder="value",a.value=e.value||"",a.style.flex="1",l.appendChild(a);const r=document.createElement("input");r.type="text",r.className="form-input fb-chooser-opt-label",r.placeholder="label (visible to users)",r.value=e.label||"",r.style.flex="2",l.appendChild(r);const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="line-height:1;opacity:.6;",i.title="Remove option",x(i,"x"),i.addEventListener("click",$=>{$.preventDefault(),Le(t,s,n)}),l.appendChild(i),o.appendChild(l);const u=document.createElement("div");u.style.cssText="display:flex; gap:.4rem;";const m=me("icon name (optional)",e.icon||"");m.input.classList.add("fb-chooser-opt-icon"),m.el.style.flex="1",u.appendChild(m.el);const f=document.createElement("input");f.type="text",f.className="form-input fb-chooser-opt-description",f.placeholder="description (card + comfortable only)",f.value=e.description||"",f.style.flex="2",u.appendChild(f),o.appendChild(u);const y=document.createElement("div");y.style.cssText="display:flex; gap:.4rem;";const h=document.createElement("input");h.type="text",h.className="form-input fb-chooser-opt-tooltip",h.placeholder="tooltip (hover hint)",h.value=e.tooltip||"",h.style.flex="2",y.appendChild(h);const g=document.createElement("input");g.type="text",g.className="form-input fb-chooser-opt-badge-text",g.placeholder="badge text",g.value=e.badge?.text||"",g.style.flex="1",y.appendChild(g);const v=document.createElement("select");v.className="form-input fb-chooser-opt-badge-type",v.style.flex="1",[["","no badge"],["primary","primary"],["success","success"],["info","info"],["warning","warning"],["danger","danger"]].forEach(([$,A])=>{const O=document.createElement("option");O.value=$,O.textContent=A,(e.badge?.type||"")===$&&(O.selected=!0),v.appendChild(O)}),y.appendChild(v),o.appendChild(y);const w=document.createElement("div");w.style.cssText="display:flex; gap:1rem; font-size:.8rem;";const C=document.createElement("label");C.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const q=document.createElement("input");q.type="checkbox",q.className="fb-chooser-opt-recommended",q.checked=!!e.recommended,C.appendChild(q),C.appendChild(document.createTextNode(" Recommended")),w.appendChild(C);const z=document.createElement("label");z.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const B=document.createElement("input");return B.type="checkbox",B.className="fb-chooser-opt-disabled",B.checked=!!e.disabled,z.appendChild(B),z.appendChild(document.createTextNode(" Disabled")),w.appendChild(z),o.appendChild(w),o}function Ne(e,t){const s=document.createElement("div");s.style.cssText="margin-top:.5rem;";const n=document.createElement("div");n.style.cssText="display:flex; align-items:center; justify-content:space-between; margin-bottom:.4rem;";const o=document.createElement("p");o.textContent="Options",o.style.cssText="font-size:.85rem;font-weight:600;margin:0;",n.appendChild(o);const l=document.createElement("button");l.type="button",l.className="btn btn-xs btn-ghost",j(l,"plus","Add option"),n.appendChild(l),s.appendChild(n);const c=document.createElement("div");c.className="fb-chooser-options-list",c.id=`fb-chooser-options-${t}`,c.style.cssText="display:flex; flex-direction:column; gap:.4rem;",s.appendChild(c);const p=()=>{c.replaceChildren();const d=qe(t);(d.length?d:e||[]).forEach((r,i)=>{c.appendChild(Te(r,t,i,p))})};return l.addEventListener("click",d=>{d.preventDefault(),$e(t,p)}),p(),s}function qe(e){const t=b[e];return!t||!Array.isArray(t.options)?[]:t.options}function Y(e){return b[e]?(Array.isArray(b[e].options)||(b[e].options=[]),b[e].options):[]}function $e(e,t){U(e),Y(e).push({value:"new",label:"New option"}),t()}function Le(e,t,s){U(e),Y(e).splice(t,1),s()}function ie(e,t,s,n){U(e);const o=Y(e),l=t+s;if(l<0||l>=o.length)return;const[c]=o.splice(t,1);o.splice(l,0,c),n()}function U(e){const t=document.getElementById(`fb-chooser-options-${e}`);if(!t)return;const s=t.querySelectorAll(".fb-chooser-option-row"),n=[];s.forEach(o=>{const l={value:o.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:o.querySelector(".fb-chooser-opt-label")?.value.trim()||""},c=o.querySelector(".fb-chooser-opt-icon")?.value.trim();c&&(l.icon=c);const p=o.querySelector(".fb-chooser-opt-description")?.value.trim();p&&(l.description=p);const d=o.querySelector(".fb-chooser-opt-tooltip")?.value.trim();d&&(l.tooltip=d);const a=o.querySelector(".fb-chooser-opt-badge-text")?.value.trim(),r=o.querySelector(".fb-chooser-opt-badge-type")?.value;(a||r)&&(l.badge={},a&&(l.badge.text=a),r&&(l.badge.type=r)),o.querySelector(".fb-chooser-opt-recommended")?.checked&&(l.recommended=!0),o.querySelector(".fb-chooser-opt-disabled")?.checked&&(l.disabled=!0),n.push(l)}),b[e]&&(b[e].options=n)}function k(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.75rem;margin-bottom:.6rem;",e.forEach(s=>{s&&t.appendChild(s)}),t}function S(e,t,s,n,o){const l=document.createElement("div");l.style.flex="1";const c=document.createElement("label");c.htmlFor=t,c.className="form-label",c.textContent=e,c.style.fontSize=".8rem";const p=document.createElement("input");if(p.id=t,p.type=s||"text",p.className="form-input",p.value=n??"",l.appendChild(c),l.appendChild(p),o){const d=document.createElement("p");d.className="form-hint text-muted",d.textContent=o,d.style.cssText="font-size:.73rem;margin-top:.2rem;",l.appendChild(d)}return l}function ze(e,t,s,n){const o=document.createElement("div");o.style.flex="1";const l=document.createElement("label");l.htmlFor=t,l.className="form-label",l.textContent=e,l.style.fontSize=".8rem";const c=document.createElement("select");return c.id=t,c.className="form-select",s.forEach(p=>{const d=document.createElement("option");d.value=p.value,d.textContent=p.label,p.value===n&&(d.selected=!0),c.appendChild(d)}),o.appendChild(l),o.appendChild(c),o}function ce(e,t,s){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const o=document.createElement("label");o.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const l=document.createElement("input");return l.id=t,l.type="checkbox",l.checked=s,o.appendChild(l),o.appendChild(document.createTextNode(e)),n.appendChild(o),n}function Be(e,t){const s=document.createElement("div");s.style.cssText="margin-top:.4rem;";const n=document.createElement("p");n.textContent="Options (one per line: value or value:Label)",n.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const o=document.createElement("textarea");return o.id=`fb-options-${t}`,o.className="form-input",o.rows=4,o.placeholder=`yes:Yes
1
+ import{apiRequest as A}from"/admin/js/api.js";import{makeIconInput as ue}from"/admin/js/lib/shortcode-modal.js";const X=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"chooser",label:"Chooser (visual options)"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"password",label:"Password"},{value:"file",label:"File upload"},{value:"hidden",label:"Hidden field"}],G=new Set(["select","radio","checkbox-group","chooser"]);let g=[],q=null,P=null,M=null,W={};function w(e,n,s=14){e.textContent="";const t=document.createElement("span");return t.setAttribute("data-icon",n),t.setAttribute("data-icon-size",String(s)),t.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;",e.appendChild(t),window.I?.scan?.(e),e}function D(e,n,s,t=14){return w(e,n,t),e.appendChild(document.createTextNode(" "+s)),e}let _=null,Z=null;function Q(){clearTimeout(Z),Z=setTimeout(()=>{_&&_()},350)}function ee(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function te(e){return X.find(n=>n.value===e)?.label||e}function ne(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function fe(e){const n={...g[e]};if(n.type==="spacer")return n;if(n.type==="page-break"){const h=document.getElementById(`fb-pb-label-${e}`),b=document.getElementById(`fb-pb-desc-${e}`);return h&&(n.label=h.value.trim()||n.label),b&&(n.description=b.value.trim()),n}const s=document.getElementById(`fb-label-${e}`),t=document.getElementById(`fb-name-${e}`),o=document.getElementById(`fb-type-${e}`),l=document.getElementById(`fb-required-${e}`),i=document.getElementById(`fb-placeholder-${e}`),p=document.getElementById(`fb-helper-${e}`),r=document.getElementById(`fb-tooltip-${e}`);if(s&&(n.label=s.value.trim()||n.label),t&&(n.name=t.value.trim()||n.name),o&&(n.type=o.value||n.type),l&&(n.required=l.checked),i&&(n.placeholder=i.value.trim()),p&&(n.helper=p.value.trim()),r&&(n.tooltip=r.value.trim()),n.type==="chooser"){const h=document.getElementById(`fb-chooser-variant-${e}`)?.value;h&&(n.variant=h);const b=document.getElementById(`fb-chooser-multiple-${e}`);b&&(n.multiple=b.checked);const v=document.getElementById(`fb-chooser-density-${e}`)?.value;v&&(n.density=v);const C=document.getElementById(`fb-chooser-columns-${e}`)?.value;C!==""&&C!==void 0&&(n.columns=parseInt(C,10)||3);const x=document.getElementById(`fb-chooser-accent-${e}`)?.value.trim();x?n.accent=x:delete n.accent;const k=document.getElementById(`fb-chooser-accent-style-${e}`)?.value;k?n.accentStyle=k:delete n.accentStyle;const z=document.getElementById(`fb-chooser-glow-${e}`);z&&(n.glow=z.checked);const B=document.getElementById(`fb-chooser-glow-colour-${e}`)?.value.trim();B?n.glowColour=B:delete n.glowColour;const N=document.getElementById(`fb-chooser-shadow-${e}`)?.value;N&&N!=="none"?n.shadow=N:delete n.shadow;const O=document.getElementById(`fb-chooser-shadow-colour-${e}`)?.value.trim();O?n.shadowColour=O:delete n.shadowColour,J(e),g[e]&&Array.isArray(g[e].options)&&(n.options=g[e].options)}else if(G.has(n.type)){const h=document.getElementById(`fb-options-${e}`);h&&(n.options=h.value.split(`
2
+ `).filter(b=>b.trim()).map(b=>{const[v,...C]=b.split(":");return{value:v.trim(),label:C.join(":").trim()||v.trim()}}))}if(n.type==="textarea"){const h=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);h>0&&(n.formConfig={...n.formConfig||{},rows:h})}const a=document.getElementById(`fb-span-${e}`),d=document.getElementById(`fb-fullwidth-${e}`);if(a||d){const h={...n.formConfig||{}};if(d?.checked)h.span="full";else{const b=parseInt(a?.value,10);b>1?h.span=b:delete h.span}n.formConfig=Object.keys(h).length?h:void 0}const c=document.getElementById(`fb-minlength-${e}`)?.value;c&&(n.minLength=parseInt(c,10));const u=document.getElementById(`fb-maxlength-${e}`)?.value;u&&(n.maxLength=parseInt(u,10));const m=document.getElementById(`fb-min-${e}`)?.value;m!==""&&m!==void 0&&(n.min=parseFloat(m));const f=document.getElementById(`fb-max-${e}`)?.value;f!==""&&f!==void 0&&(n.max=parseFloat(f));const y=he(e);return y?n.logic=y:delete n.logic,n}function he(e){const n=document.querySelector(`.fb-field-card[data-index="${e}"]`);if(!n)return;const s=n.querySelector(".fb-field-logic");if(!s)return;const t={};let o=!1;const l=s.querySelector('[data-logic-section="visibility"]');if(l){const a=l.querySelector(".fb-logic-vis-default"),d=l.querySelector(".fb-logic-vis-transition"),c=Array.from(l.querySelectorAll(".fb-logic-cond-row")).map(f=>{const y=f.querySelector(".fb-logic-cond-field"),h=f.querySelector(".fb-logic-cond-op"),b=f.querySelector(".fb-logic-cond-val"),v=f.querySelector(".fb-logic-vis-then");return y?.value?{when:{all:[{field:y.value,operator:h.value,value:b.value}]},then:v.value}:null}).filter(Boolean),u=a?.value||"visible",m=d?.value||"none";(u!=="visible"||c.length>0||m!=="none")&&(t.visibility={default:u,conditions:c},m!=="none"&&(t.visibility.transition=m),o=!0)}const i=s.querySelector('[data-logic-section="requirement"]');if(i){const a=i.querySelector(".fb-logic-req-default"),d=Array.from(i.querySelectorAll(".fb-logic-cond-row")).map(c=>{const u=c.querySelector(".fb-logic-cond-field"),m=c.querySelector(".fb-logic-cond-op"),f=c.querySelector(".fb-logic-cond-val"),y=c.querySelector(".fb-logic-req-then");return u?.value?{when:{all:[{field:u.value,operator:m.value,value:f.value}]},then:y.value==="true"}:null}).filter(Boolean);d.length>0&&(t.requirement={default:a?.checked===!0,conditions:d},o=!0)}const p=s.querySelector('[data-logic-section="validation"]');if(p){const a=Array.from(p.querySelectorAll(".fb-logic-val-rule")).map(d=>{const c=d.querySelector(".fb-logic-val-type"),u=d.querySelector(".fb-logic-val-pattern"),m=d.querySelector(".fb-logic-val-flags"),f=d.querySelector(".fb-logic-val-message");if(!u?.value.trim())return null;const y=c?.value||"regex",h={type:y,message:f?.value.trim()||"Invalid value."};return y==="regex"?(h.pattern=u.value.trim(),m?.value.trim()&&(h.flags=m.value.trim())):h.field=u.value.trim(),h}).filter(Boolean);a.length>0&&(t.validation=a,o=!0)}const r=s.querySelector('[data-logic-section="cascade"]');if(r){const a=r.querySelector(".fb-logic-cascade-source"),d=r.querySelector(".fb-logic-cascade-mapping"),c=r.querySelector(".fb-logic-cascade-defaults"),u=a?.value?.trim();if(u){let m={};try{m=JSON.parse(d?.value||"{}")}catch{}const f=(c?.value||"").split(`
3
+ `).filter(y=>y.trim()).map(y=>{const[h,...b]=y.split(":");return{value:h.trim(),label:b.join(":").trim()||h.trim()}});t.cascade={sourceField:u,mapping:m,defaultOptions:f},o=!0}}return o?t:void 0}function $(){g=g.map((e,n)=>fe(n))}let I=null;function be(e,n,s){const t=e.firstElementChild;if(!t)return;const o=document.createElement("span");o.setAttribute("data-icon","menu"),o.setAttribute("data-icon-size","13"),o.title="Drag to reorder",o.style.cssText="cursor:grab;opacity:.35;flex-shrink:0;display:inline-flex;align-items:center;",t.insertBefore(o,t.firstChild),window.I?.scan?.(t),t.draggable=!0,t.addEventListener("dragstart",l=>{I=n,l.dataTransfer.effectAllowed="move",e.style.opacity="0.4"}),t.addEventListener("dragend",()=>{e.style.opacity="",document.querySelectorAll("#fields-list .fb-field-card").forEach(l=>l.classList.remove("fb-drag-over"))}),e.addEventListener("dragover",l=>{I!=null&&(l.preventDefault(),l.dataTransfer.dropEffect="move",document.querySelectorAll("#fields-list .fb-field-card").forEach(i=>i.classList.remove("fb-drag-over")),e.classList.add("fb-drag-over"))}),e.addEventListener("dragleave",()=>e.classList.remove("fb-drag-over")),e.addEventListener("drop",l=>{if(l.preventDefault(),e.classList.remove("fb-drag-over"),I==null||I===n){I=null;return}$();const[i]=g.splice(I,1);g.splice(n,0,i),I=null,L(s)})}function L(e){const n=e.find("#fields-list").get(0),s=e.find("#fields-empty-msg").get(0);if(n){if(Array.from(n.querySelectorAll(".fb-field-card")).forEach(t=>t.remove()),g.length===0){s&&(s.style.display=""),Q();return}s&&(s.style.display="none"),g.forEach((t,o)=>{const l=t.type==="page-break"?ge(t,o,e):t.type==="spacer"?ye(t,o,e):ve(t,o,e);be(l,o,e),n.appendChild(l)}),Q()}}function ge(e,n,s){const t=document.createElement("div");t.className="fb-field-card",t.dataset.index=n,t.style.cssText="border:2px dashed var(--dm-border,#444);border-radius:6px;overflow:hidden;margin-bottom:.5rem;background:var(--dm-card-bg,rgba(255,255,255,.02));";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent="\u2014 Page Break \u2014",l.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:color-mix(in srgb, var(--dm-text-muted) 20%, transparent);color:var(--dm-text-muted,#888);white-space:nowrap;flex-shrink:0;font-style:italic;";const i=document.createElement("span");i.textContent=e.label||"Untitled Step",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text-muted,#888);";const p=document.createElement("div");p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Edit step",w(r,"more-horizontal"),r.addEventListener("click",m=>{m.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),p.appendChild(r);const a=document.createElement("button");a.className="btn btn-xs btn-ghost",a.style.cssText="line-height:1;opacity:.6;",a.title="Remove page break",w(a,"x"),a.addEventListener("click",async m=>{m.stopPropagation(),await E.confirm("Remove this page break?")&&($(),g.splice(n,1),L(s))}),p.appendChild(a),o.appendChild(l),o.appendChild(i),o.appendChild(p),o.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=document.createElement("div");d.className="fb-field-body",d.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border,#444);display:none;";const c=S([T("Step Title",`fb-pb-label-${n}`,"text",e.label||"","Shown as the wizard step heading"),T("Step Description",`fb-pb-desc-${n}`,"text",e.description||"","Optional sub-heading")]),u=c.querySelector(`#fb-pb-label-${n}`);return u&&u.addEventListener("input",()=>{i.textContent=u.value||"Untitled Step"}),d.appendChild(c),t.appendChild(o),t.appendChild(d),t}function ye(e,n,s){const t=document.createElement("div");t.className="fb-field-card",t.dataset.index=n,t.style.cssText="border:1px dashed var(--dm-border,#444);border-radius:6px;margin-bottom:.5rem;background:transparent;";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const l=document.createElement("div");l.style.cssText="flex:1;height:1px;background:var(--dm-border,#444);";const i=document.createElement("span");i.textContent="Spacer",i.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const p=document.createElement("div");p.style.cssText="flex:1;height:1px;background:var(--dm-border,#444);";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;";const a=document.createElement("button");return a.className="btn btn-xs btn-ghost",a.style.cssText="line-height:1;opacity:.6;",a.title="Remove spacer",w(a,"x"),a.addEventListener("click",async d=>{d.stopPropagation(),$(),g.splice(n,1),L(s)}),r.appendChild(a),o.appendChild(l),o.appendChild(i),o.appendChild(p),o.appendChild(r),t.appendChild(o),t}function ve(e,n,s){const t=document.createElement("div");t.className="fb-field-card",t.dataset.index=n,t.style.cssText="border:1px solid var(--dm-border,#333);border-radius:6px;overflow:hidden;margin-bottom:.5rem;";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;background:var(--dm-card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=te(e.type),l.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:color-mix(in srgb, var(--dm-primary) 14%, transparent);color:var(--dm-primary,#6366f1);white-space:nowrap;flex-shrink:0;";const i=document.createElement("span");i.textContent=e.label||"(unlabelled)",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const p=document.createElement("div");p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Edit field",w(r,"more-horizontal"),r.addEventListener("click",c=>{c.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),p.appendChild(r);const a=document.createElement("button");if(a.className="btn btn-xs btn-ghost",a.style.cssText="line-height:1;opacity:.6;",a.title="Remove field",w(a,"x"),a.addEventListener("click",async c=>{c.stopPropagation(),await E.confirm("Remove this field?")&&($(),g.splice(n,1),L(s))}),p.appendChild(a),o.appendChild(l),o.appendChild(i),e.required){const c=document.createElement("span");c.textContent="required",c.style.cssText="font-size:.7rem;color:var(--dm-danger,#ef4444);flex-shrink:0;",o.appendChild(c)}if(ne(e.logic)){const c=document.createElement("span");w(c,"zap"),c.title="Has conditional logic",c.style.cssText="font-size:.75rem;color:var(--dm-primary,#6366f1);flex-shrink:0;",o.appendChild(c)}o.appendChild(p),o.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=xe(e,n,i);return d.style.display="none",t.appendChild(o),t.appendChild(d),t}function xe(e,n,s){const t=document.createElement("div");t.className="fb-field-body",t.style.cssText="padding:.8rem;border-top:1px solid var(--dm-border,#333);";const o=S([T("Label",`fb-label-${n}`,"text",e.label||"","Shown above the field"),T("Field Name",`fb-name-${n}`,"text",e.name||"","Used as data key")]),l=S([Ie("Type",`fb-type-${n}`,X,e.type||"string"),re("Required",`fb-required-${n}`,e.required||!1)]),i=S([T("Placeholder",`fb-placeholder-${n}`,"text",e.placeholder||"","Hint text inside the field")]),p=S([T("Helper Text",`fb-helper-${n}`,"text",e.helper||"","Shown below the field"),T("Tooltip",`fb-tooltip-${n}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),r=e.formConfig?.span,a=S([T("Column Span",`fb-span-${n}`,"number",r&&r!=="full"?String(r):"1","Columns to span (grid only)"),re("Full Width",`fb-fullwidth-${n}`,r==="full")]);a.classList.add("fb-grid-row"),a.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",t.appendChild(o),t.appendChild(l),t.appendChild(i),t.appendChild(p),t.appendChild(a);const d=t.querySelector(`#fb-label-${n}`),c=t.querySelector(`#fb-name-${n}`);d&&d.addEventListener("input",()=>{s&&(s.textContent=d.value||"(unlabelled)"),c&&!c.dataset.manuallyEdited&&(c.value=ee(d.value))}),c&&c.addEventListener("input",()=>{c.dataset.manuallyEdited="1"});const u=t.querySelector(`#fb-type-${n}`);u&&u.addEventListener("change",()=>{const f=t.closest(".fb-field-card");if(f){const b=f.querySelector("span");b&&(b.textContent=te(u.value))}const y=t.querySelector(".fb-field-extras");y&&y.remove();const h=ae(u.value,e,n);h&&t.appendChild(h)});const m=ae(e.type,e,n);return m&&t.appendChild(m),t.appendChild(ke(e,n)),t}const Ce=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],le=new Set(["is_empty","is_not_empty"]);function V(e){const n=document.createElement("p");return n.textContent=e,n.style.cssText="font-size:.75rem;font-weight:700;color:var(--dm-text-muted,#888);margin:.6rem 0 .3rem;text-transform:uppercase;letter-spacing:.04em;",n}function H(e,n,s,t,o){const l=document.createElement("div");l.className="fb-logic-cond-row",l.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const i=document.createElement("span");i.textContent="When",i.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);flex-shrink:0;";const p=document.createElement("select");p.className="form-select fb-logic-cond-field",p.style.cssText="flex:1 1 140px;min-width:140px;",n.forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,e&&m.value===e.field&&(f.selected=!0),p.appendChild(f)});const r=document.createElement("select");r.className="form-select fb-logic-cond-op",r.style.cssText="flex:1 1 160px;min-width:140px;",Ce.forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,e&&m.value===e.operator&&(f.selected=!0),r.appendChild(f)});const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-cond-val",a.placeholder="value",a.style.cssText="flex:1 1 120px;min-width:100px;",a.value=e?.value||"",e&&le.has(e.operator)&&(a.style.display="none"),r.addEventListener("change",()=>{a.style.display=le.has(r.value)?"none":""});const d=document.createElement("span");w(d,"arrow-right"),d.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);flex-shrink:0;";const c=document.createElement("select");c.className=`form-select ${t}`,c.style.cssText="flex:1 1 140px;min-width:120px;",s.forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,m.value===o&&(f.selected=!0),c.appendChild(f)});const u=document.createElement("button");return u.type="button",u.className="btn btn-xs btn-ghost",u.style.cssText="line-height:1;opacity:.6;",w(u,"x"),u.style.flexShrink="0",u.addEventListener("click",()=>l.remove()),l.appendChild(i),l.appendChild(p),l.appendChild(r),l.appendChild(a),l.appendChild(d),l.appendChild(c),l.appendChild(u),l}function Ee(e,n,s){const t=document.createElement("div");t.dataset.logicSection="visibility",t.appendChild(V("Visibility"));const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const l=document.createElement("span");l.textContent="Default:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-vis-default",i.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,m.value===(e.default||"visible")&&(f.selected=!0),i.appendChild(f)}),o.appendChild(l),o.appendChild(i),t.appendChild(o);const p=document.createElement("div");p.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const r=document.createElement("span");r.textContent="Transition:",r.style.cssText="font-size:.8rem;flex-shrink:0;";const a=document.createElement("select");a.className="form-select fb-logic-vis-transition",a.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(m=>{const f=document.createElement("option");f.value=m.value,f.textContent=m.label,m.value===(e.transition||"none")&&(f.selected=!0),a.appendChild(f)}),p.appendChild(r),p.appendChild(a),t.appendChild(p);const d=document.createElement("div");d.className="fb-logic-vis-rules";const c=s.map(m=>({value:m.name,label:m.label||m.name})),u=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(m=>{const f=(m.when?.all||m.when?.any||[])[0],y=m.then==="hidden"?"hidden":"visible";c.length>0&&d.appendChild(H(f,c,u,"fb-logic-vis-then",y))}),t.appendChild(d),c.length>0){const m=document.createElement("button");m.type="button",m.className="btn btn-xs btn-ghost",m.style.cssText="font-size:.73rem;margin-top:.2rem;",D(m,"plus","Add visibility rule"),m.addEventListener("click",()=>d.appendChild(H(null,c,u,"fb-logic-vis-then","visible"))),t.appendChild(m)}return t}function we(e,n,s){const t=document.createElement("div");t.dataset.logicSection="requirement",t.appendChild(V("Conditional Requirement"));const o=document.createElement("label");o.style.cssText="display:flex;align-items:center;gap:.4rem;font-size:.8rem;cursor:pointer;margin-bottom:.4rem;";const l=document.createElement("input");l.type="checkbox",l.className="fb-logic-req-default",l.checked=e.default===!0,o.appendChild(l),o.appendChild(document.createTextNode("Required by default")),t.appendChild(o);const i=document.createElement("div");i.className="fb-logic-req-rules";const p=s.map(a=>({value:a.name,label:a.label||a.name})),r=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(a=>{const d=(a.when?.all||a.when?.any||[])[0],c=a.then===!0?"true":"false";p.length>0&&i.appendChild(H(d,p,r,"fb-logic-req-then",c))}),t.appendChild(i),p.length>0){const a=document.createElement("button");a.type="button",a.className="btn btn-xs btn-ghost",a.style.cssText="font-size:.73rem;margin-top:.2rem;",D(a,"plus","Add requirement rule"),a.addEventListener("click",()=>i.appendChild(H(null,p,r,"fb-logic-req-then","true"))),t.appendChild(a)}return t}function oe(e){const n=document.createElement("div");n.className="fb-logic-val-rule",n.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const s=document.createElement("select");s.className="form-select fb-logic-val-type",s.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(p=>{const r=document.createElement("option");r.value=p.value,r.textContent=p.label,p.value===(e?.type||"regex")&&(r.selected=!0),s.appendChild(r)});const t=document.createElement("input");t.type="text",t.className="form-input fb-logic-val-pattern",t.placeholder=e?.type==="match"?"field name":"pattern",t.value=e?.pattern||e?.field||"",t.style.cssText="flex:3;";const o=document.createElement("input");o.type="text",o.className="form-input fb-logic-val-flags",o.placeholder="flags",o.value=e?.flags||"",o.style.cssText="flex:0 0 55px;",e?.type==="match"&&(o.style.display="none"),s.addEventListener("change",()=>{o.style.display=s.value==="match"?"none":"",t.placeholder=s.value==="match"?"field name":"pattern"});const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-message",l.placeholder="Error message",l.value=e?.message||"",l.style.cssText="flex:4;";const i=document.createElement("button");return i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="line-height:1;opacity:.6;",w(i,"x"),i.style.flexShrink="0",i.addEventListener("click",()=>n.remove()),n.appendChild(s),n.appendChild(t),n.appendChild(o),n.appendChild(l),n.appendChild(i),n}function Se(e,n,s){const t=document.createElement("div");t.dataset.logicSection="validation",t.appendChild(V("Custom Validation"));const o=document.createElement("div");o.className="fb-logic-val-rules",(e||[]).forEach(i=>o.appendChild(oe(i))),t.appendChild(o);const l=document.createElement("button");return l.type="button",l.className="btn btn-xs btn-ghost",l.style.cssText="font-size:.73rem;margin-top:.2rem;",D(l,"plus","Add validation rule"),l.addEventListener("click",()=>o.appendChild(oe(null))),t.appendChild(l),t}function Te(e,n,s){const t=document.createElement("div");t.dataset.logicSection="cascade",t.appendChild(V("Cascade Options"));const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const l=document.createElement("span");l.textContent="Source field:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-cascade-source",i.style.cssText="flex:1;";const p=document.createElement("option");p.value="",p.textContent="\u2014 none \u2014",i.appendChild(p),s.forEach(u=>{const m=document.createElement("option");m.value=u.name,m.textContent=u.label||u.name,u.name===e.sourceField&&(m.selected=!0),i.appendChild(m)}),o.appendChild(l),o.appendChild(i),t.appendChild(o);const r=document.createElement("p");r.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',r.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);margin:.3rem 0 .2rem;";const a=document.createElement("textarea");a.className="form-input fb-logic-cascade-mapping",a.rows=4,a.style.cssText="font-family:monospace;",a.placeholder='{"uk": [{"value": "london", "label": "London"}]}',a.value=e.mapping?JSON.stringify(e.mapping,null,2):"",t.appendChild(r),t.appendChild(a);const d=document.createElement("p");d.textContent="Default options (one per line: value:Label)",d.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);margin:.3rem 0 .2rem;";const c=document.createElement("textarea");return c.className="form-input fb-logic-cascade-defaults",c.rows=3,c.style.cssText="font-family:monospace;",c.placeholder=`option1:Option 1
4
+ option2:Option 2`,c.value=(e.defaultOptions||[]).map(u=>{const m=typeof u=="string"?u:u.value??"",f=typeof u=="string"?u:u.label??m;return m===f?m:`${m}:${f}`}).join(`
5
+ `),t.appendChild(d),t.appendChild(c),t}function ke(e,n){const s=e.logic||{},t=g.filter((c,u)=>u!==n&&c.type!=="page-break"&&c.type!=="spacer"),o=document.createElement("div");o.className="fb-field-logic",o.style.cssText="margin-top:.75rem;border-top:1px solid var(--dm-border,#333);padding-top:.5rem;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const i=document.createElement("span");i.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted,#888);",i.textContent="\u26A1 Conditional Logic";const p=ne(s),r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",w(r,p?"chevron-down":"chevron-right",12);const a=document.createElement("div");a.className="fb-logic-body",a.style.cssText="padding:.25rem 0 .25rem;"+(p?"":"display:none;"),l.addEventListener("click",()=>{const c=a.style.display==="none";a.style.display=c?"":"none",w(r,c?"chevron-down":"chevron-right",12)}),l.appendChild(i),l.appendChild(r),o.appendChild(l),a.appendChild(Ee(s.visibility||{},n,t)),a.appendChild(we(s.requirement||{},n,t)),a.appendChild(Se(s.validation||[],n,t));const d=document.getElementById(`fb-type-${n}`)?.value||e.type;return G.has(d)&&a.appendChild(Te(s.cascade||{},n,t)),o.appendChild(a),o}function ae(e,n,s){const t=document.createElement("div");return t.className="fb-field-extras",e==="chooser"?(t.appendChild(Ne(n,s)),t.appendChild($e(n.options||[],s))):(G.has(e)&&t.appendChild(Ae(n.options||[],s)),e==="textarea"&&t.appendChild(S([T("Rows",`fb-rows-${s}`,"number",n.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&t.appendChild(S([T("Min Length",`fb-minlength-${s}`,"number",n.minLength||"",""),T("Max Length",`fb-maxlength-${s}`,"number",n.maxLength||"","")])),e==="number"&&t.appendChild(S([T("Min",`fb-min-${s}`,"number",n.min??"",""),T("Max",`fb-max-${s}`,"number",n.max??"","")]))),t.children.length?t:null}function se(e){const n=document.createElement("div");n.className="fb-chooser-section",n.style.cssText="border:1px solid var(--dm-border, #e5e7eb); border-radius:6px; margin-top:.5rem; overflow:hidden;";const s=document.createElement("div");s.style.cssText="padding:.4rem .6rem; background:color-mix(in srgb, var(--dm-background, #f9fafb) 60%, transparent); font-weight:600; font-size:.82rem; border-bottom:1px solid var(--dm-border, #e5e7eb);",s.textContent=e,n.appendChild(s);const t=document.createElement("div");return t.className="fb-chooser-section-body",t.style.cssText="padding:.55rem .6rem; display:flex; flex-direction:column; gap:.45rem;",n.appendChild(t),{wrap:n,body:t}}function U(e,n,s,t,o){const l=document.createElement("div");l.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=n,i.style.fontSize=".8rem";const p=document.createElement("select");if(p.id=e,p.className="form-input",t.forEach(([r,a])=>{const d=document.createElement("option");d.value=r,d.textContent=a,String(r)===String(s)&&(d.selected=!0),p.appendChild(d)}),l.appendChild(i),l.appendChild(p),o){const r=document.createElement("p");r.className="form-hint text-muted",r.textContent=o,r.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(r)}return l}function ie(e,n,s,t){const o=document.createElement("div");o.style.flex="1";const l=document.createElement("label");l.style.cssText="display:inline-flex;align-items:center;gap:.4rem;font-size:.82rem;";const i=document.createElement("input");if(i.id=e,i.type="checkbox",i.checked=!!s,l.appendChild(i),l.appendChild(document.createTextNode(" "+n)),o.appendChild(l),t){const p=document.createElement("p");p.className="form-hint text-muted",p.textContent=t,p.style.cssText="font-size:.72rem;margin-top:.2rem;",o.appendChild(p)}return o}function Y(e,n,s,t,o){const l=document.createElement("div");l.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=n,i.style.fontSize=".8rem",l.appendChild(i);const p=document.createElement("div");p.style.cssText="display:flex;gap:.4rem;align-items:stretch;";const r=document.createElement("input");r.id=e,r.type="text",r.className="form-input",r.value=s||"",t&&(r.placeholder=t),r.style.flex="1";const a=document.createElement("input");a.type="color",a.title="Pick a colour",a.style.cssText="width:36px;height:auto;padding:0;border:1px solid var(--dm-border,#e5e7eb);border-radius:4px;cursor:pointer;";const d=String(r.value).match(/^#[0-9a-fA-F]{3,8}$/);if(a.value=d?r.value:"#000000",a.addEventListener("input",()=>{r.value=a.value,r.dispatchEvent(new Event("input",{bubbles:!0}))}),p.appendChild(r),p.appendChild(a),l.appendChild(p),o){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=o,c.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(c)}return l}function Ne(e,n){const s=document.createElement("div");s.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const t=se("Layout");t.body.appendChild(S([U(`fb-chooser-variant-${n}`,"Variant",e.variant||"card",[["card","Card \u2014 rich tiles"],["chip","Chip \u2014 compact pills"]],"Card supports description and grid columns; chips wrap."),ie(`fb-chooser-multiple-${n}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),t.body.appendChild(S([U(`fb-chooser-density-${n}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),T("Columns",`fb-chooser-columns-${n}`,"number",e.columns||3,"Card grid (1\u20136). Ignored for chips.")])),s.appendChild(t.wrap);const o=se("Visual");return o.body.appendChild(S([Y(`fb-chooser-accent-${n}`,"Accent",e.accent||"","primary / success / #ec4899","Selected highlight colour \u2014 semantic name or any CSS colour."),U(`fb-chooser-accent-style-${n}`,"Accent style",e.accentStyle||"border",[["border","Border (default)"],["solid","Solid"],["glow","Glow"],["overlay","Overlay"],["underline","Underline"]],"Visual treatment of the selected state.")])),o.body.appendChild(S([ie(`fb-chooser-glow-${n}`,"Glow on selected",!!e.glow,"Soft outer glow."),Y(`fb-chooser-glow-colour-${n}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),o.body.appendChild(S([U(`fb-chooser-shadow-${n}`,"Shadow",e.shadow||"none",[["none","None"],["sm","Small"],["md","Medium"],["lg","Large"],["xl","Extra Large"]],"Drop shadow on every option."),Y(`fb-chooser-shadow-colour-${n}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),s.appendChild(o.wrap),s}function qe(e,n,s,t){const o=document.createElement("div");o.className="fb-chooser-option-row",o.dataset.optIdx=String(s),o.style.cssText="border:1px solid var(--dm-border,#e5e7eb); border-radius:4px; padding:.5rem; background:var(--dm-background-alt, color-mix(in srgb, var(--dm-card-bg, #fff) 92%, var(--dm-text, #111))); display:flex; flex-direction:column; gap:.35rem;";const l=document.createElement("div");l.style.cssText="display:flex; gap:.4rem; align-items:center;";const i=document.createElement("div");i.style.cssText="display:flex; flex-direction:column; gap:1px;";const p=document.createElement("button");p.type="button",p.className="btn btn-xs btn-ghost",p.title="Move up",w(p,"arrow-up"),p.addEventListener("click",N=>{N.preventDefault(),ce(n,s,-1,t)});const r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",r.title="Move down",w(r,"arrow-down"),r.addEventListener("click",N=>{N.preventDefault(),ce(n,s,1,t)}),i.appendChild(p),i.appendChild(r),l.appendChild(i);const a=document.createElement("input");a.type="text",a.className="form-input fb-chooser-opt-value",a.placeholder="value",a.value=e.value||"",a.style.flex="1",l.appendChild(a);const d=document.createElement("input");d.type="text",d.className="form-input fb-chooser-opt-label",d.placeholder="label (visible to users)",d.value=e.label||"",d.style.flex="2",l.appendChild(d);const c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",c.style.cssText="line-height:1;opacity:.6;",c.title="Remove option",w(c,"x"),c.addEventListener("click",N=>{N.preventDefault(),Be(n,s,t)}),l.appendChild(c),o.appendChild(l);const u=document.createElement("div");u.style.cssText="display:flex; gap:.4rem;";const m=ue("icon name (optional)",e.icon||"");m.input.classList.add("fb-chooser-opt-icon"),m.el.style.flex="1",u.appendChild(m.el);const f=document.createElement("input");f.type="text",f.className="form-input fb-chooser-opt-description",f.placeholder="description (card + comfortable only)",f.value=e.description||"",f.style.flex="2",u.appendChild(f),o.appendChild(u);const y=document.createElement("div");y.style.cssText="display:flex; gap:.4rem;";const h=document.createElement("input");h.type="text",h.className="form-input fb-chooser-opt-tooltip",h.placeholder="tooltip (hover hint)",h.value=e.tooltip||"",h.style.flex="2",y.appendChild(h);const b=document.createElement("input");b.type="text",b.className="form-input fb-chooser-opt-badge-text",b.placeholder="badge text",b.value=e.badge?.text||"",b.style.flex="1",y.appendChild(b);const v=document.createElement("select");v.className="form-input fb-chooser-opt-badge-type",v.style.flex="1",[["","no badge"],["primary","primary"],["success","success"],["info","info"],["warning","warning"],["danger","danger"]].forEach(([N,O])=>{const j=document.createElement("option");j.value=N,j.textContent=O,(e.badge?.type||"")===N&&(j.selected=!0),v.appendChild(j)}),y.appendChild(v),o.appendChild(y);const C=document.createElement("div");C.style.cssText="display:flex; gap:1rem; font-size:.8rem;";const x=document.createElement("label");x.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const k=document.createElement("input");k.type="checkbox",k.className="fb-chooser-opt-recommended",k.checked=!!e.recommended,x.appendChild(k),x.appendChild(document.createTextNode(" Recommended")),C.appendChild(x);const z=document.createElement("label");z.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const B=document.createElement("input");return B.type="checkbox",B.className="fb-chooser-opt-disabled",B.checked=!!e.disabled,z.appendChild(B),z.appendChild(document.createTextNode(" Disabled")),C.appendChild(z),o.appendChild(C),o}function $e(e,n){const s=document.createElement("div");s.style.cssText="margin-top:.5rem;";const t=document.createElement("div");t.style.cssText="display:flex; align-items:center; justify-content:space-between; margin-bottom:.4rem;";const o=document.createElement("p");o.textContent="Options",o.style.cssText="font-size:.85rem;font-weight:600;margin:0;",t.appendChild(o);const l=document.createElement("button");l.type="button",l.className="btn btn-xs btn-ghost",D(l,"plus","Add option"),t.appendChild(l),s.appendChild(t);const i=document.createElement("div");i.className="fb-chooser-options-list",i.id=`fb-chooser-options-${n}`,i.style.cssText="display:flex; flex-direction:column; gap:.4rem;",s.appendChild(i);const p=()=>{i.replaceChildren();const r=Le(n);(r.length?r:e||[]).forEach((d,c)=>{i.appendChild(qe(d,n,c,p))})};return l.addEventListener("click",r=>{r.preventDefault(),ze(n,p)}),p(),s}function Le(e){const n=g[e];return!n||!Array.isArray(n.options)?[]:n.options}function K(e){return g[e]?(Array.isArray(g[e].options)||(g[e].options=[]),g[e].options):[]}function ze(e,n){J(e),K(e).push({value:"new",label:"New option"}),n()}function Be(e,n,s){J(e),K(e).splice(n,1),s()}function ce(e,n,s,t){J(e);const o=K(e),l=n+s;if(l<0||l>=o.length)return;const[i]=o.splice(n,1);o.splice(l,0,i),t()}function J(e){const n=document.getElementById(`fb-chooser-options-${e}`);if(!n)return;const s=n.querySelectorAll(".fb-chooser-option-row"),t=[];s.forEach(o=>{const l={value:o.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:o.querySelector(".fb-chooser-opt-label")?.value.trim()||""},i=o.querySelector(".fb-chooser-opt-icon")?.value.trim();i&&(l.icon=i);const p=o.querySelector(".fb-chooser-opt-description")?.value.trim();p&&(l.description=p);const r=o.querySelector(".fb-chooser-opt-tooltip")?.value.trim();r&&(l.tooltip=r);const a=o.querySelector(".fb-chooser-opt-badge-text")?.value.trim(),d=o.querySelector(".fb-chooser-opt-badge-type")?.value;(a||d)&&(l.badge={},a&&(l.badge.text=a),d&&(l.badge.type=d)),o.querySelector(".fb-chooser-opt-recommended")?.checked&&(l.recommended=!0),o.querySelector(".fb-chooser-opt-disabled")?.checked&&(l.disabled=!0),t.push(l)}),g[e]&&(g[e].options=t)}function S(e){const n=document.createElement("div");return n.style.cssText="display:flex;gap:.75rem;margin-bottom:.6rem;",e.forEach(s=>{s&&n.appendChild(s)}),n}function T(e,n,s,t,o){const l=document.createElement("div");l.style.flex="1";const i=document.createElement("label");i.htmlFor=n,i.className="form-label",i.textContent=e,i.style.fontSize=".8rem";const p=document.createElement("input");if(p.id=n,p.type=s||"text",p.className="form-input",p.value=t??"",l.appendChild(i),l.appendChild(p),o){const r=document.createElement("p");r.className="form-hint text-muted",r.textContent=o,r.style.cssText="font-size:.73rem;margin-top:.2rem;",l.appendChild(r)}return l}function Ie(e,n,s,t){const o=document.createElement("div");o.style.flex="1";const l=document.createElement("label");l.htmlFor=n,l.className="form-label",l.textContent=e,l.style.fontSize=".8rem";const i=document.createElement("select");return i.id=n,i.className="form-select",s.forEach(p=>{const r=document.createElement("option");r.value=p.value,r.textContent=p.label,p.value===t&&(r.selected=!0),i.appendChild(r)}),o.appendChild(l),o.appendChild(i),o}function re(e,n,s){const t=document.createElement("div");t.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const o=document.createElement("label");o.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const l=document.createElement("input");return l.id=n,l.type="checkbox",l.checked=s,o.appendChild(l),o.appendChild(document.createTextNode(e)),t.appendChild(o),t}function Ae(e,n){const s=document.createElement("div");s.style.cssText="margin-top:.4rem;";const t=document.createElement("p");t.textContent="Options (one per line: value or value:Label)",t.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const o=document.createElement("textarea");return o.id=`fb-options-${n}`,o.className="form-input",o.rows=4,o.placeholder=`yes:Yes
6
6
  no:No
7
- maybe:Maybe`,o.value=(e||[]).map(l=>{const c=typeof l=="string"?l:l.value??"",p=typeof l=="string"?l:l.label??c;return c===p?c:`${c}:${p}`}).join(`
8
- `),o.style.fontFamily="monospace",s.appendChild(n),s.appendChild(o),s}function re(e){const t=e.find("#field-project").val()||"";return T(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},meta:{...G||{},project:t||null},fields:b,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"stacked",columns:parseInt(e.find("#setting-columns").val(),10)||2,submitSpan:e.find("#setting-submit-span").val()||"",honeypot:e.find("#setting-honeypot").prop("checked"),rateLimitPerMinute:parseInt(e.find("#setting-rate-limit").val(),10)||3,successRedirect:e.find("#setting-success-redirect").val().trim()||null,actionSlug:e.find("#action-cms-slug").val()||null},actions:{email:{enabled:e.find("#action-email-enabled").prop("checked"),recipients:e.find("#action-email-recipients").val().trim(),subjectPrefix:e.find("#action-email-subject-prefix").val().trim()},webhook:{enabled:e.find("#action-webhook-enabled").prop("checked"),url:e.find("#action-webhook-url").val().trim(),method:e.find("#action-webhook-method").val()},...P!==null&&{collection:P}}}}function Ie(e){const t=[];let s=[],n="Step 1",o="";return e.forEach(l=>{l.type==="page-break"?(t.push({title:n,description:o,fields:s}),s=[],n=l.label||`Step ${t.length+1}`,o=l.description||""):l.type!=="spacer"&&s.push(l)}),(s.length||t.length===0)&&t.push({title:n,description:o,fields:s}),t}function de(e,t){const s={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const o={...n.formConfig||{}};o.span==="full"&&t&&(o.span=t);const c={type:n.type==="checkbox"?"boolean":n.type==="date"?"string":n.type,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{helperText:n.helper},...n.tooltip&&{tooltip:n.tooltip},...o}};n.type==="chooser"&&(n.variant&&(c.variant=n.variant),n.multiple&&(c.multiple=!0),n.density&&(c.density=n.density),n.columns&&(c.columns=n.columns),n.accent&&(c.accent=n.accent),n.accentStyle&&(c.accentStyle=n.accentStyle),n.glow&&(c.glow=!0),n.glowColour&&(c.glowColour=n.glowColour),n.shadow&&(c.shadow=n.shadow),n.shadowColour&&(c.shadowColour=n.shadowColour)),s[n.name]=c}),s}function pe(e,t){const s=typeof e=="string"?document.querySelector(e):e;s&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const o=s.querySelector(`[name="${n.name}"]`);o&&o.type!=="date"&&(o.type="date")})}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){b=[],L=null,P=null;const t=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);L=t?t[1]:null;let s=null;const n=E.loader(e.get(0),{type:"dots"});if(L)try{s=await I(`/forms/${L}`),b=s.fields||[],P=s.actions?.collection??null}catch{E.toast("Could not load form.",{type:"error"})}G={};try{const a=await I("/projects").catch(()=>[]),r=e.find("#field-project").get(0);r&&(Array.isArray(a)?a:[]).forEach(i=>{const u=document.createElement("option");u.value=i.slug,u.textContent=i.name||i.slug,r.appendChild(u)})}catch{}if(n.destroy(),s?e.find("#editor-title").get(0).textContent=`Edit: ${s.title}`:e.find("#editor-title").get(0).textContent="New Form",L||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(Z(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),s){e.find("#field-title").val(s.title),e.find("#field-slug").val(s.slug),e.find("#field-description").val(s.description||""),e.find("#field-bundled").prop("checked",!!s.bundled),G=s.meta||{},e.find("#field-project").val(s.meta?.project||"");const a=s.settings||{};e.find("#setting-submit-text").val(a.submitText||"Submit"),e.find("#setting-success-message").val(a.successMessage||""),e.find("#setting-layout").val(a.layout||"stacked"),e.find("#setting-columns").val(a.columns||2),e.find("#setting-submit-span").val(a.submitSpan||""),e.find("#columns-group").get(0).style.display=a.layout==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",a.honeypot!==!1),e.find("#setting-rate-limit").val(a.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(a.successRedirect||"");const r=s.actions?.email||{};e.find("#action-email-enabled").prop("checked",r.enabled||!1),e.find("#action-email-recipients").val(r.recipients||""),e.find("#action-email-subject-prefix").val(r.subjectPrefix||"");const i=s.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",i.enabled||!1),e.find("#action-webhook-url").val(i.url||""),e.find("#action-webhook-method").val(i.method||"POST")}const o=s?.settings?.actionSlug||"";try{const a=await I("/actions").catch(()=>[]),r=e.find("#action-cms-slug").get(0);if((Array.isArray(a)?a:[]).forEach(i=>{const u=document.createElement("option");u.value=i.slug,u.textContent=i.title||i.slug,i.slug===o&&(u.selected=!0),r.appendChild(u)}),!a.length){const i=document.createElement("option");i.value="",i.textContent="No actions available",i.disabled=!0,r.appendChild(i)}}catch{}e.find("#setting-layout").get(0)?.addEventListener("change",function(){const a=this.value==="grid";e.find("#columns-group").get(0).style.display=a?"":"none",document.querySelectorAll(".fb-grid-row").forEach(r=>{r.style.display=a?"flex":"none"})}),N(e);const l=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",a=>{a.stopPropagation(),l.style.display=l.style.display==="none"?"":"none"}),M&&document.removeEventListener("click",M),M=()=>{l&&(l.style.display="none")},document.addEventListener("click",M),e.find("#add-field-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),T();const a=b.length;b.push({name:`field_${a+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),N(e);const r=e.find("#fields-list").get(0)?.lastElementChild;if(r){const i=r.querySelector(".fb-field-body");i&&(i.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),T(),b.push({type:"spacer"}),N(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),T();const a=b.filter(r=>r.type==="page-break").length+2;b.push({type:"page-break",label:`Step ${a}`,description:""}),N(e)}),e.find("#save-form-btn").get(0).addEventListener("click",async()=>{const a=re(e);if(!a.title){E.toast("Please enter a form title.",{type:"error"});return}try{L?(await I(`/forms/${L}`,{method:"PUT",body:JSON.stringify(a)}),E.toast("Form saved.",{type:"success"})):(L=(await I("/forms",{method:"POST",body:JSON.stringify(a)})).slug,R.navigate(`/forms/edit/${L}`),E.toast("Form created.",{type:"success"}))}catch(r){E.toast(r.message||"Failed to save form.",{type:"error"})}}),_=()=>{const a=re(e),r=e.find("#preview-container").get(0);if(!r)return;const i=e.find("#preview-test-result").get(0),u=e.find("#preview-test-badge").get(0);i&&(i.style.display="none",i.textContent=""),u&&(u.style.display=L?"":"none"),e.find("#preview-card").get(0).style.display="",r.textContent="";const m=document.createElement("div");m.id="fb-preview-form",r.appendChild(m);const f=L?async h=>{i&&(i.style.display="none",i.textContent="");try{const g=await fetch(`/api/forms/submit/${L}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(h)}),v=await g.json();if(!g.ok)throw new Error(v.error||"Submission failed.");i&&(i.textContent=v.message||a.settings?.successMessage||"Submitted successfully.",i.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-success) 12%, transparent);color:var(--dm-success,#22c55e);"),E.toast("Test submission stored.",{type:"success"})}catch(g){i&&(i.textContent=g.message,i.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-danger) 12%, transparent);color:var(--dm-danger,#ef4444);"),E.toast(g.message,{type:"error"})}return!1}:()=>!1,y=a.fields.some(h=>h.type==="page-break");if(typeof F<"u"){const h=a.settings?.columns||2,g=a.settings?.layout||"stacked";if(y&&F.wizard){const v=Ie(a.fields).map(w=>({title:w.title,description:w.description,fields:de(w.fields,h)}));F.wizard("#fb-preview-form",{schema:{steps:v},onSubmit:f}),pe("#fb-preview-form",a.fields)}else if(F.render){const v=de(a.fields,h),w={};if(a.fields.forEach(C=>{if(!(!C.name||C.type==="page-break"||C.type==="spacer")&&(C.type==="select"||C.type==="multiselect")&&C.required){const q=(C.options||[])[0];q&&(w[C.name]=typeof q=="object"?q.value:q)}}),F.render("#fb-preview-form",v,w,{submitText:a.settings?.submitText||"Submit",layout:g,columns:h,onSubmit:f}),g==="grid"&&a.settings?.submitSpan==="full"){const C=document.querySelector("#fb-preview-form .form-buttons");C&&C.classList.add("col-span-full")}pe("#fb-preview-form",a.fields)}window.FormLogicEngine&&a.fields.some(v=>v.logic)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:a.fields},m).init()})}else{const h=document.createElement("p");h.textContent=`${a.fields.filter(g=>g.type!=="page-break").length} field(s): ${a.fields.filter(g=>g.type!=="page-break").map(g=>g.label).join(", ")}`,h.style.cssText="color:var(--dm-text-muted);font-style:italic;",m.appendChild(h)}},_();const c=e.find("#editor-tabs").get(0),p=e.find("#preview-card").get(0),d=a=>{p&&p.contains(a.target)||W()};c&&(c.addEventListener("input",d),c.addEventListener("change",d))}};
7
+ maybe:Maybe`,o.value=(e||[]).map(l=>{const i=typeof l=="string"?l:l.value??"",p=typeof l=="string"?l:l.label??i;return i===p?i:`${i}:${p}`}).join(`
8
+ `),o.style.fontFamily="monospace",s.appendChild(t),s.appendChild(o),s}function de(e){const n=e.find("#field-project").val()||"";return $(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},meta:{...W||{},project:n||null},fields:g,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"stacked",columns:parseInt(e.find("#setting-columns").val(),10)||2,submitSpan:e.find("#setting-submit-span").val()||"",honeypot:e.find("#setting-honeypot").prop("checked"),rateLimitPerMinute:parseInt(e.find("#setting-rate-limit").val(),10)||3,successRedirect:e.find("#setting-success-redirect").val().trim()||null,actionSlug:e.find("#action-cms-slug").val()||null},actions:{email:{enabled:e.find("#action-email-enabled").prop("checked"),recipients:e.find("#action-email-recipients").val().trim(),subjectPrefix:e.find("#action-email-subject-prefix").val().trim()},webhook:{enabled:e.find("#action-webhook-enabled").prop("checked"),url:e.find("#action-webhook-url").val().trim(),method:e.find("#action-webhook-method").val()},...P!==null&&{collection:P}}}}function Fe(e){const n=[];let s=[],t="Step 1",o="";return e.forEach(l=>{l.type==="page-break"?(n.push({title:t,description:o,fields:s}),s=[],t=l.label||`Step ${n.length+1}`,o=l.description||""):l.type!=="spacer"&&s.push(l)}),(s.length||n.length===0)&&n.push({title:t,description:o,fields:s}),n}function pe(e,n){const s={};return e.forEach(t=>{if(t.type==="page-break"||t.type==="spacer")return;const o={...t.formConfig||{}};o.span==="full"&&n&&(o.span=n);const i={type:t.type==="checkbox"?"boolean":t.type==="date"?"string":t.type,label:t.label,required:t.required,options:t.options,formConfig:{...t.placeholder&&{placeholder:t.placeholder},...t.helper&&{helperText:t.helper},...t.tooltip&&{tooltip:t.tooltip},...o}};t.type==="chooser"&&(t.variant&&(i.variant=t.variant),t.multiple&&(i.multiple=!0),t.density&&(i.density=t.density),t.columns&&(i.columns=t.columns),t.accent&&(i.accent=t.accent),t.accentStyle&&(i.accentStyle=t.accentStyle),t.glow&&(i.glow=!0),t.glowColour&&(i.glowColour=t.glowColour),t.shadow&&(i.shadow=t.shadow),t.shadowColour&&(i.shadowColour=t.shadowColour)),s[t.name]=i}),s}function me(e,n){const s=typeof e=="string"?document.querySelector(e):e;s&&(n||[]).forEach(t=>{if(t.type!=="date"||!t.name)return;const o=s.querySelector(`[name="${t.name}"]`);o&&o.type!=="date"&&(o.type="date")})}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){g=[],q=null,P=null;const n=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);q=n?n[1]:null;let s=null;const t=E.loader(e.get(0),{type:"dots"});if(q)try{s=await A(`/forms/${q}`),g=s.fields||[],P=s.actions?.collection??null}catch{E.toast("Could not load form.",{type:"error"})}W={};try{const a=await A("/projects").catch(()=>[]),d=e.find("#field-project").get(0);d&&(Array.isArray(a)?a:[]).forEach(c=>{const u=document.createElement("option");u.value=c.slug,u.textContent=c.name||c.slug,d.appendChild(u)})}catch{}if(t.destroy(),s?e.find("#editor-title").get(0).textContent=`Edit: ${s.title}`:e.find("#editor-title").get(0).textContent="New Form",q||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(ee(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),s){e.find("#field-title").val(s.title),e.find("#field-slug").val(s.slug),e.find("#field-description").val(s.description||""),e.find("#field-bundled").prop("checked",!!s.bundled),W=s.meta||{},e.find("#field-project").val(s.meta?.project||"");const a=s.settings||{};e.find("#setting-submit-text").val(a.submitText||"Submit"),e.find("#setting-success-message").val(a.successMessage||""),e.find("#setting-layout").val(a.layout||"stacked"),e.find("#setting-columns").val(a.columns||2),e.find("#setting-submit-span").val(a.submitSpan||""),e.find("#columns-group").get(0).style.display=a.layout==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",a.honeypot!==!1),e.find("#setting-rate-limit").val(a.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(a.successRedirect||"");const d=s.actions?.email||{};e.find("#action-email-enabled").prop("checked",d.enabled||!1),e.find("#action-email-recipients").val(d.recipients||""),e.find("#action-email-subject-prefix").val(d.subjectPrefix||"");const c=s.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",c.enabled||!1),e.find("#action-webhook-url").val(c.url||""),e.find("#action-webhook-method").val(c.method||"POST")}const o=s?.settings?.actionSlug||"";try{const a=await A("/actions").catch(()=>[]),d=e.find("#action-cms-slug").get(0);if((Array.isArray(a)?a:[]).forEach(c=>{const u=document.createElement("option");u.value=c.slug,u.textContent=c.title||c.slug,c.slug===o&&(u.selected=!0),d.appendChild(u)}),!a.length){const c=document.createElement("option");c.value="",c.textContent="No actions available",c.disabled=!0,d.appendChild(c)}}catch{}e.find("#setting-layout").get(0)?.addEventListener("change",function(){const a=this.value==="grid";e.find("#columns-group").get(0).style.display=a?"":"none",document.querySelectorAll(".fb-grid-row").forEach(d=>{d.style.display=a?"flex":"none"})}),L(e);const l=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",a=>{a.stopPropagation(),l.style.display=l.style.display==="none"?"":"none"}),M&&document.removeEventListener("click",M),M=()=>{l&&(l.style.display="none")},document.addEventListener("click",M),e.find("#add-field-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),$();const a=g.length;g.push({name:`field_${a+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),L(e);const d=e.find("#fields-list").get(0)?.lastElementChild;if(d){const c=d.querySelector(".fb-field-body");c&&(c.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),$(),g.push({type:"spacer"}),L(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),$();const a=g.filter(d=>d.type==="page-break").length+2;g.push({type:"page-break",label:`Step ${a}`,description:""}),L(e)}),e.find("#save-form-btn").get(0).addEventListener("click",async()=>{const a=de(e);if(!a.title){E.toast("Please enter a form title.",{type:"error"});return}try{q?(await A(`/forms/${q}`,{method:"PUT",body:JSON.stringify(a)}),E.toast("Form saved.",{type:"success"})):(q=(await A("/forms",{method:"POST",body:JSON.stringify(a)})).slug,R.navigate(`/forms/edit/${q}`),E.toast("Form created.",{type:"success"}))}catch(d){E.toast(d.message||"Failed to save form.",{type:"error"})}}),_=()=>{const a=de(e),d=e.find("#preview-container").get(0);if(!d)return;const c=e.find("#preview-test-result").get(0),u=e.find("#preview-test-badge").get(0);c&&(c.style.display="none",c.textContent=""),u&&(u.style.display=q?"":"none"),e.find("#preview-card").get(0).style.display="",d.textContent="";const m=document.createElement("div");m.id="fb-preview-form",d.appendChild(m);const f=q?async h=>{c&&(c.style.display="none",c.textContent="");try{const b=await fetch(`/api/forms/submit/${q}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(h)}),v=await b.json();if(!b.ok)throw new Error(v.error||"Submission failed.");c&&(c.textContent=v.message||a.settings?.successMessage||"Submitted successfully.",c.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-success) 12%, transparent);color:var(--dm-success,#22c55e);"),E.toast("Test submission stored.",{type:"success"})}catch(b){c&&(c.textContent=b.message,c.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-danger) 12%, transparent);color:var(--dm-danger,#ef4444);"),E.toast(b.message,{type:"error"})}return!1}:()=>!1,y=a.fields.some(h=>h.type==="page-break");if(typeof F<"u"){const h=a.settings?.columns||2,b=a.settings?.layout||"stacked";if(y&&F.wizard){const v=Fe(a.fields).map(C=>({title:C.title,description:C.description,fields:pe(C.fields,h)}));F.wizard("#fb-preview-form",{schema:{steps:v},onSubmit:f}),me("#fb-preview-form",a.fields)}else if(F.render){const v=pe(a.fields,h),C={};if(a.fields.forEach(x=>{if(!(!x.name||x.type==="page-break"||x.type==="spacer")&&(x.type==="select"||x.type==="multiselect")&&x.required){const k=(x.options||[])[0];k&&(C[x.name]=typeof k=="object"?k.value:k)}}),F.render("#fb-preview-form",v,C,{submitText:a.settings?.submitText||"Submit",layout:b,columns:h,onSubmit:f}),b==="grid"&&a.settings?.submitSpan==="full"){const x=document.querySelector("#fb-preview-form .form-buttons");x&&x.classList.add("col-span-full")}me("#fb-preview-form",a.fields)}window.FormLogicEngine&&a.fields.some(v=>v.logic)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:a.fields},m).init()})}else{const h=document.createElement("p");h.textContent=`${a.fields.filter(b=>b.type!=="page-break").length} field(s): ${a.fields.filter(b=>b.type!=="page-break").map(b=>b.label).join(", ")}`,h.style.cssText="color:var(--dm-text-muted);font-style:italic;",m.appendChild(h)}},_();const i=e.find("#editor-tabs").get(0),p=e.find("#preview-card").get(0),r=a=>{p&&p.contains(a.target)||Q()};i&&(i.addEventListener("input",r),i.addEventListener("change",r))}};