domma-cms 0.38.2 → 0.39.0
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.
- package/CLAUDE.md +20 -110
- package/admin/dist/domma/domma-tools.css +16 -16
- package/admin/dist/domma/domma-tools.min.js +4 -4
- package/admin/index.html +2 -2
- package/admin/js/views/form-editor.js +6 -6
- package/bin/update.js +23 -2
- package/package.json +2 -2
- package/public/css/forms.css +1 -1
- package/public/js/form-logic-engine.js +1 -1
- package/public/js/forms.js +1 -1
- package/public/js/site.js +1 -1
- package/server/templates/page.html +4 -4
package/admin/index.html
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
<link rel="stylesheet" href="/admin/css/dashboard.css">
|
|
21
21
|
|
|
22
22
|
<!-- Forms CSS — needed for conditional logic preview (.fb-field-hidden, etc.) -->
|
|
23
|
-
<link rel="stylesheet" href="/public/css/forms.css">
|
|
23
|
+
<link rel="stylesheet" href="/public/css/forms.css?v=20260817-multi-chooser">
|
|
24
24
|
</head>
|
|
25
25
|
<body class="dm-cloaked dm-theme-charcoal-dark dashboard-layout">
|
|
26
26
|
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
76
76
|
|
|
77
77
|
<!-- Form Logic Engine — needed for conditional logic preview -->
|
|
78
|
-
<script src="/public/js/form-logic-engine.js"></script>
|
|
78
|
+
<script src="/public/js/form-logic-engine.js?v=20260817-multi-chooser"></script>
|
|
79
79
|
|
|
80
80
|
<!-- Admin App (ES module entry) -->
|
|
81
81
|
<script type="module" src="/admin/js/app.js"></script>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{apiRequest as I}from"/admin/js/api.js";import{makeIconInput as
|
|
2
|
-
`).filter(
|
|
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)=>be(n))}let B=null;function ye(e,n,i){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=>{B=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=>{B!=null&&(l.preventDefault(),l.dataTransfer.dropEffect="move",document.querySelectorAll("#fields-list .fb-field-card").forEach(s=>s.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"),B==null||B===n){B=null;return}$();const[s]=g.splice(B,1);g.splice(n,0,s),B=null,L(i)})}function L(e){const n=e.find("#fields-list").get(0),i=e.find("#fields-empty-msg").get(0);if(n){if(Array.from(n.querySelectorAll(".fb-field-card")).forEach(t=>t.remove()),g.length===0){i&&(i.style.display=""),Y();return}i&&(i.style.display="none"),g.forEach((t,o)=>{const l=t.type==="page-break"?ve(t,o,e):t.type==="spacer"?xe(t,o,e):Ce(t,o,e);ye(l,o,e),n.appendChild(l)}),Y()}}function ve(e,n,i){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:8px;overflow:hidden;margin-bottom:.75rem;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 s=document.createElement("span");s.textContent=e.label||"Untitled Step",s.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 d=document.createElement("div");d.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(),p.style.display=p.style.display==="none"?"":"none"}),d.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(i))}),d.appendChild(a),o.appendChild(l),o.appendChild(s),o.appendChild(d),o.addEventListener("click",()=>{p.style.display=p.style.display==="none"?"":"none"});const p=document.createElement("div");p.className="fb-field-body",p.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border,#444);display:none;";const c=k([S("Step Title",`fb-pb-label-${n}`,"text",e.label||"","Shown as the wizard step heading"),S("Step Description",`fb-pb-desc-${n}`,"text",e.description||"","Optional sub-heading")]),u=c.querySelector(`#fb-pb-label-${n}`);return u&&u.addEventListener("input",()=>{s.textContent=u.value||"Untitled Step"}),p.appendChild(c),t.appendChild(o),t.appendChild(p),t}function xe(e,n,i){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 s=document.createElement("span");s.textContent="Spacer",s.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const d=document.createElement("div");d.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 p=>{p.stopPropagation(),$(),g.splice(n,1),L(i)}),r.appendChild(a),o.appendChild(l),o.appendChild(s),o.appendChild(d),o.appendChild(r),t.appendChild(o),t}function Ce(e,n,i){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:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);box-shadow:var(--dm-shadow-sm);";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;background:var(--dm-card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=le(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 s=document.createElement("span");s.textContent=e.label||"(unlabelled)",s.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const d=document.createElement("div");d.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(),p.style.display=p.style.display==="none"?"":"none"}),d.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(i))}),d.appendChild(a),o.appendChild(l),o.appendChild(s),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(oe(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(d),o.addEventListener("click",()=>{p.style.display=p.style.display==="none"?"":"none"});const p=Ee(e,n,s);return p.style.display="none",t.appendChild(o),t.appendChild(p),t}function Ee(e,n,i){const t=document.createElement("div");t.className="fb-field-body",t.style.cssText="padding:1rem .9rem;border-top:1px solid var(--dm-border,#333);";const o=k([S("Label",`fb-label-${n}`,"text",e.label||"","Shown above the field"),S("Field Name",`fb-name-${n}`,"text",e.name||"","Used as data key")]),l=k([Fe("Type",`fb-type-${n}`,ee,e.type||"string"),pe("Required",`fb-required-${n}`,e.required||!1)]),s=k([S("Placeholder",`fb-placeholder-${n}`,"text",e.placeholder||"","Hint text inside the field")]),d=k([S("Helper Text",`fb-helper-${n}`,"text",e.helper||"","Shown below the field"),S("Tooltip",`fb-tooltip-${n}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),r=e.formConfig?.span,a=k([S("Column Span",`fb-span-${n}`,"number",r&&r!=="full"?String(r):"1","Columns to span (grid only)"),pe("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(s),t.appendChild(d),t.appendChild(a);const p=t.querySelector(`#fb-label-${n}`),c=t.querySelector(`#fb-name-${n}`);p&&p.addEventListener("input",()=>{i&&(i.textContent=p.value||"(unlabelled)"),c&&!c.dataset.manuallyEdited&&(c.value=ne(p.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=le(u.value))}const y=t.querySelector(".fb-field-extras");y&&y.remove();const h=se(u.value,e,n);h&&t.appendChild(h)});const m=se(e.type,e,n);return m&&t.appendChild(m),t.appendChild(qe(e,n)),t}const we=[{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"}],ae=new Set(["is_empty","is_not_empty"]);function H(e){const n=document.createElement("p");return n.textContent=e,n.style.cssText="font-size:.72rem;font-weight:700;color:var(--dm-text-muted,#888);margin:1rem 0 .45rem;text-transform:uppercase;letter-spacing:.06em;",n}function V(e,n,i,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 s=document.createElement("span");s.textContent="When",s.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);flex-shrink:0;";const d=document.createElement("select");d.className="form-select fb-logic-cond-field",d.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),d.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;",we.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&&ae.has(e.operator)&&(a.style.display="none"),r.addEventListener("change",()=>{a.style.display=ae.has(r.value)?"none":""});const p=document.createElement("span");w(p,"arrow-right"),p.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;",i.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(s),l.appendChild(d),l.appendChild(r),l.appendChild(a),l.appendChild(p),l.appendChild(c),l.appendChild(u),l}function ke(e,n,i){const t=document.createElement("div");t.dataset.logicSection="visibility",t.appendChild(H("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 s=document.createElement("select");s.className="form-select fb-logic-vis-default",s.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),s.appendChild(f)}),o.appendChild(l),o.appendChild(s),t.appendChild(o);const d=document.createElement("div");d.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)}),d.appendChild(r),d.appendChild(a),t.appendChild(d);const p=document.createElement("div");p.className="fb-logic-vis-rules";const c=i.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&&p.appendChild(V(f,c,u,"fb-logic-vis-then",y))}),t.appendChild(p),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",()=>p.appendChild(V(null,c,u,"fb-logic-vis-then","visible"))),t.appendChild(m)}return t}function Se(e,n,i){const t=document.createElement("div");t.dataset.logicSection="requirement",t.appendChild(H("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 s=document.createElement("div");s.className="fb-logic-req-rules";const d=i.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 p=(a.when?.all||a.when?.any||[])[0],c=a.then===!0?"true":"false";d.length>0&&s.appendChild(V(p,d,r,"fb-logic-req-then",c))}),t.appendChild(s),d.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",()=>s.appendChild(V(null,d,r,"fb-logic-req-then","true"))),t.appendChild(a)}return t}function ie(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 i=document.createElement("select");i.className="form-select fb-logic-val-type",i.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(d=>{const r=document.createElement("option");r.value=d.value,r.textContent=d.label,d.value===(e?.type||"regex")&&(r.selected=!0),i.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"),i.addEventListener("change",()=>{o.style.display=i.value==="match"?"none":"",t.placeholder=i.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 s=document.createElement("button");return s.type="button",s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",w(s,"x"),s.style.flexShrink="0",s.addEventListener("click",()=>n.remove()),n.appendChild(i),n.appendChild(t),n.appendChild(o),n.appendChild(l),n.appendChild(s),n}function Te(e,n,i){const t=document.createElement("div");t.dataset.logicSection="validation",t.appendChild(H("Custom Validation"));const o=document.createElement("div");o.className="fb-logic-val-rules",(e||[]).forEach(s=>o.appendChild(ie(s))),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(ie(null))),t.appendChild(l),t}function Ne(e,n,i){const t=document.createElement("div");t.dataset.logicSection="cascade",t.appendChild(H("Cascade Options")),t.lastChild.appendChild(Q("Make this field's options depend on another field. When the source field changes, the options here are replaced by the mapping entry for its value; if nothing matches, the default options below are shown."));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 s=document.createElement("select");s.className="form-select fb-logic-cascade-source",s.style.cssText="flex:1;";const d=document.createElement("option");d.value="",d.textContent="\u2014 none \u2014",s.appendChild(d),i.forEach(u=>{const m=document.createElement("option");m.value=u.name,m.textContent=u.label||u.name,u.name===e.sourceField&&(m.selected=!0),s.appendChild(m)}),o.appendChild(l),o.appendChild(s),t.appendChild(o);const r=document.createElement("p");r.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',r.appendChild(Q(`Each key is a value of the source field; its list becomes this field's options when that value is picked. Example: {"uk":[{"value":"london","label":"London"}]} shows London when the source is "uk".`)),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 p=document.createElement("p");p.textContent="Default options (one per line: value:Label)",p.appendChild(Q("Shown before the source field has a value, or when its value has no mapping entry.")),p.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
|
|
1
|
+
import{apiRequest as I}from"/admin/js/api.js";import{makeIconInput as ge}from"/admin/js/lib/shortcode-modal.js";import{enhancePickerFields as Z}from"/public/js/forms.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:"chooser",label:"Chooser (visual options)"},{value:"icon",label:"Icon (icon picker)"},{value:"image",label:"Image (media library)"},{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"}],W=new Set(["select","radio","checkbox-group","chooser"]);let y=[],q=null,j=null,P=null,G={};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 M(e,n,s,t=14){return w(e,n,t),e.appendChild(document.createTextNode(" "+s)),e}function Q(e){const n=document.createElement("span");return n.setAttribute("data-icon","help-circle"),n.setAttribute("data-icon-size","12"),n.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;margin-left:.3rem;opacity:.55;cursor:help;",n.title=e,window.I?.scan?.(n),requestAnimationFrame(()=>{try{n.parentNode&&typeof E<"u"&&E.tooltip&&(n.removeAttribute("title"),E.tooltip(n,{content:e,position:"top"}))}catch{}}),n}let D=null,te=null;function Y(){clearTimeout(te),te=setTimeout(()=>{D&&D()},350)}function ne(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function le(e){return ee.find(n=>n.value===e)?.label||e}function oe(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function ye(e){const n={...y[e]};if(n.type==="spacer")return n;if(n.type==="page-break"){const h=document.getElementById(`fb-pb-label-${e}`),g=document.getElementById(`fb-pb-desc-${e}`);return h&&(n.label=h.value.trim()||n.label),g&&(n.description=g.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}`),d=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()),d&&(n.helper=d.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 g=document.getElementById(`fb-chooser-multiple-${e}`);g&&(n.multiple=g.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 T=document.getElementById(`fb-chooser-accent-style-${e}`)?.value;T?n.accentStyle=T:delete n.accentStyle;const z=document.getElementById(`fb-chooser-glow-${e}`);z&&(n.glow=z.checked);const A=document.getElementById(`fb-chooser-glow-colour-${e}`)?.value.trim();A?n.glowColour=A: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),y[e]&&Array.isArray(y[e].options)&&(n.options=y[e].options)}else if(W.has(n.type)){const h=document.getElementById(`fb-options-${e}`);h&&(n.options=h.value.split(`
|
|
2
|
+
`).filter(g=>g.trim()).map(g=>{const[v,...C]=g.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}`),p=document.getElementById(`fb-fullwidth-${e}`);if(a||p){const h={...n.formConfig||{}};if(p?.checked)h.span="full";else{const g=parseInt(a?.value,10);g>1?h.span=g: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 b=ve(e);return b?n.logic=b:delete n.logic,n}function ve(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"),p=l.querySelector(".fb-logic-vis-transition"),c=Array.from(l.querySelectorAll(".fb-logic-cond-row")).map(f=>{const b=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 b?.value?{when:{all:[{field:b.value,operator:h.value,value:g.value}]},then:v.value}:null}).filter(Boolean),u=a?.value||"visible",m=p?.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"),p=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"),b=c.querySelector(".fb-logic-req-then");return u?.value?{when:{all:[{field:u.value,operator:m.value,value:f.value}]},then:b.value==="true"}:null}).filter(Boolean);p.length>0&&(t.requirement={default:a?.checked===!0,conditions:p},o=!0)}const d=s.querySelector('[data-logic-section="validation"]');if(d){const a=Array.from(d.querySelectorAll(".fb-logic-val-rule")).map(p=>{const c=p.querySelector(".fb-logic-val-type"),u=p.querySelector(".fb-logic-val-pattern"),m=p.querySelector(".fb-logic-val-flags"),f=p.querySelector(".fb-logic-val-message");if(!u?.value.trim())return null;const b=c?.value||"regex",h={type:b,message:f?.value.trim()||"Invalid value."};return b==="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"),p=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(p?.value||"{}")}catch{}const f=(c?.value||"").split(`
|
|
3
|
+
`).filter(b=>b.trim()).map(b=>{const[h,...g]=b.split(":");return{value:h.trim(),label:g.join(":").trim()||h.trim()}});t.cascade={sourceField:u,mapping:m,defaultOptions:f},o=!0}}return o?t:void 0}function $(){y=y.map((e,n)=>ye(n))}let B=null;function xe(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=>{B=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=>{B!=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"),B==null||B===n){B=null;return}$();const[i]=y.splice(B,1);y.splice(n,0,i),B=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()),y.length===0){s&&(s.style.display=""),Y();return}s&&(s.style.display="none"),y.forEach((t,o)=>{const l=t.type==="page-break"?Ce(t,o,e):t.type==="spacer"?Ee(t,o,e):we(t,o,e);xe(l,o,e),n.appendChild(l)}),Y()}}function Ce(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:8px;overflow:hidden;margin-bottom:.75rem;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 d=document.createElement("div");d.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(),p.style.display=p.style.display==="none"?"":"none"}),d.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?")&&($(),y.splice(n,1),L(s))}),d.appendChild(a),o.appendChild(l),o.appendChild(i),o.appendChild(d),o.addEventListener("click",()=>{p.style.display=p.style.display==="none"?"":"none"});const p=document.createElement("div");p.className="fb-field-body",p.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border,#444);display:none;";const c=k([S("Step Title",`fb-pb-label-${n}`,"text",e.label||"","Shown as the wizard step heading"),S("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"}),p.appendChild(c),t.appendChild(o),t.appendChild(p),t}function Ee(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 d=document.createElement("div");d.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 p=>{p.stopPropagation(),$(),y.splice(n,1),L(s)}),r.appendChild(a),o.appendChild(l),o.appendChild(i),o.appendChild(d),o.appendChild(r),t.appendChild(o),t}function we(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:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);box-shadow:var(--dm-shadow-sm);";const o=document.createElement("div");o.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;background:var(--dm-card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=le(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 d=document.createElement("div");d.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(),p.style.display=p.style.display==="none"?"":"none"}),d.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?")&&($(),y.splice(n,1),L(s))}),d.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(oe(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(d),o.addEventListener("click",()=>{p.style.display=p.style.display==="none"?"":"none"});const p=ke(e,n,i);return p.style.display="none",t.appendChild(o),t.appendChild(p),t}function ke(e,n,s){const t=document.createElement("div");t.className="fb-field-body",t.style.cssText="padding:1rem .9rem;border-top:1px solid var(--dm-border,#333);";const o=k([S("Label",`fb-label-${n}`,"text",e.label||"","Shown above the field"),S("Field Name",`fb-name-${n}`,"text",e.name||"","Used as data key")]),l=k([_e("Type",`fb-type-${n}`,ee,e.type||"string"),ue("Required",`fb-required-${n}`,e.required||!1)]),i=k([S("Placeholder",`fb-placeholder-${n}`,"text",e.placeholder||"","Hint text inside the field")]),d=k([S("Helper Text",`fb-helper-${n}`,"text",e.helper||"","Shown below the field"),S("Tooltip",`fb-tooltip-${n}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),r=e.formConfig?.span,a=k([S("Column Span",`fb-span-${n}`,"number",r&&r!=="full"?String(r):"1","Columns to span (grid only)"),ue("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(d),t.appendChild(a);const p=t.querySelector(`#fb-label-${n}`),c=t.querySelector(`#fb-name-${n}`);p&&p.addEventListener("input",()=>{s&&(s.textContent=p.value||"(unlabelled)"),c&&!c.dataset.manuallyEdited&&(c.value=ne(p.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 g=f.querySelector("span");g&&(g.textContent=le(u.value))}const b=t.querySelector(".fb-field-extras");b&&b.remove();const h=re(u.value,e,n);h&&t.appendChild(h)});const m=re(e.type,e,n);return m&&t.appendChild(m),t.appendChild(Le(e,n)),t}const ae=[{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"}],se=new Set(["is_empty","is_not_empty"]),Se={equals:"includes",not_equals:"does not include",contains:"any value contains",not_contains:"no value contains",starts_with:"any value starts with",ends_with:"any value ends with",greater_than:"any value is greater than",less_than:"any value is less than",is_empty:"nothing selected",is_not_empty:"something selected",in:"includes one of (comma sep)",not_in:"includes none of (comma sep)",matches_regex:"any value matches regex"};function ie(e){return!!e&&(e.type==="checkbox-group"||!!e.multiple)}function V(e){const n=document.createElement("p");return n.textContent=e,n.style.cssText="font-size:.72rem;font-weight:700;color:var(--dm-text-muted,#888);margin:1rem 0 .45rem;text-transform:uppercase;letter-spacing:.06em;",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 d=document.createElement("select");d.className="form-select fb-logic-cond-field",d.style.cssText="flex:1 1 140px;min-width:140px;",n.forEach(f=>{const b=document.createElement("option");b.value=f.value,b.textContent=f.label,e&&f.value===e.field&&(b.selected=!0),d.appendChild(b)});const r=document.createElement("select");r.className="form-select fb-logic-cond-op",r.style.cssText="flex:1 1 160px;min-width:140px;",ae.forEach(f=>{const b=document.createElement("option");b.value=f.value,b.textContent=f.label,e&&f.value===e.operator&&(b.selected=!0),r.appendChild(b)});const a=()=>{const f=n.find(b=>b.value===d.value);Array.from(r.options).forEach(b=>{const h=ae.find(g=>g.value===b.value);b.textContent=f?.multi&&Se[b.value]||h?.label||b.value})};a(),d.addEventListener("change",a);const p=document.createElement("input");p.type="text",p.className="form-input fb-logic-cond-val",p.placeholder="value",p.style.cssText="flex:1 1 120px;min-width:100px;",p.value=e?.value||"",e&&se.has(e.operator)&&(p.style.display="none"),r.addEventListener("change",()=>{p.style.display=se.has(r.value)?"none":""});const c=document.createElement("span");w(c,"arrow-right"),c.style.cssText="font-size:.73rem;color:var(--dm-text-muted,#888);flex-shrink:0;";const u=document.createElement("select");u.className=`form-select ${t}`,u.style.cssText="flex:1 1 140px;min-width:120px;",s.forEach(f=>{const b=document.createElement("option");b.value=f.value,b.textContent=f.label,f.value===o&&(b.selected=!0),u.appendChild(b)});const m=document.createElement("button");return m.type="button",m.className="btn btn-xs btn-ghost",m.style.cssText="line-height:1;opacity:.6;",w(m,"x"),m.style.flexShrink="0",m.addEventListener("click",()=>l.remove()),l.appendChild(i),l.appendChild(d),l.appendChild(r),l.appendChild(p),l.appendChild(c),l.appendChild(u),l.appendChild(m),l}function Te(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 d=document.createElement("div");d.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)}),d.appendChild(r),d.appendChild(a),t.appendChild(d);const p=document.createElement("div");p.className="fb-logic-vis-rules";const c=s.map(m=>({value:m.name,label:m.label||m.name,multi:ie(m)})),u=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(m=>{const f=(m.when?.all||m.when?.any||[])[0],b=m.then==="hidden"?"hidden":"visible";c.length>0&&p.appendChild(H(f,c,u,"fb-logic-vis-then",b))}),t.appendChild(p),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;",M(m,"plus","Add visibility rule"),m.addEventListener("click",()=>p.appendChild(H(null,c,u,"fb-logic-vis-then","visible"))),t.appendChild(m)}return t}function Ne(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 d=s.map(a=>({value:a.name,label:a.label||a.name,multi:ie(a)})),r=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(a=>{const p=(a.when?.all||a.when?.any||[])[0],c=a.then===!0?"true":"false";d.length>0&&i.appendChild(H(p,d,r,"fb-logic-req-then",c))}),t.appendChild(i),d.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;",M(a,"plus","Add requirement rule"),a.addEventListener("click",()=>i.appendChild(H(null,d,r,"fb-logic-req-then","true"))),t.appendChild(a)}return t}function ce(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(d=>{const r=document.createElement("option");r.value=d.value,r.textContent=d.label,d.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 qe(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(ce(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;",M(l,"plus","Add validation rule"),l.addEventListener("click",()=>o.appendChild(ce(null))),t.appendChild(l),t}function $e(e,n,s){const t=document.createElement("div");t.dataset.logicSection="cascade",t.appendChild(V("Cascade Options")),t.lastChild.appendChild(Q("Make this field's options depend on another field. When the source field changes, the options here are replaced by the mapping entry for its value; if nothing matches, the default options below are shown."));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 d=document.createElement("option");d.value="",d.textContent="\u2014 none \u2014",i.appendChild(d),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.appendChild(Q(`Each key is a value of the source field; its list becomes this field's options when that value is picked. Example: {"uk":[{"value":"london","label":"London"}]} shows London when the source is "uk".`)),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 p=document.createElement("p");p.textContent="Default options (one per line: value:Label)",p.appendChild(Q("Shown before the source field has a value, or when its value has no mapping entry.")),p.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
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(p),t.appendChild(c),t}function qe(e,n){const i=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 s=document.createElement("span");s.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted,#888);",s.textContent="\u26A1 Conditional Logic";const d=oe(i),r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",w(r,d?"chevron-down":"chevron-right",12);const a=document.createElement("div");a.className="fb-logic-body",a.style.cssText="padding:.25rem 0 .25rem;"+(d?"":"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(s),l.appendChild(r),o.appendChild(l),a.appendChild(ke(i.visibility||{},n,t)),a.appendChild(Se(i.requirement||{},n,t)),a.appendChild(Te(i.validation||[],n,t));const p=document.getElementById(`fb-type-${n}`)?.value||e.type;return W.has(p)&&a.appendChild(Ne(i.cascade||{},n,t)),o.appendChild(a),o}function se(e,n,i){const t=document.createElement("div");return t.className="fb-field-extras",e==="chooser"?(t.appendChild($e(n,i)),t.appendChild(ze(n.options||[],i))):(W.has(e)&&t.appendChild(Oe(n.options||[],i)),e==="textarea"&&t.appendChild(k([S("Rows",`fb-rows-${i}`,"number",n.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&t.appendChild(k([S("Min Length",`fb-minlength-${i}`,"number",n.minLength||"",""),S("Max Length",`fb-maxlength-${i}`,"number",n.maxLength||"","")])),e==="number"&&t.appendChild(k([S("Min",`fb-min-${i}`,"number",n.min??"",""),S("Max",`fb-max-${i}`,"number",n.max??"","")]))),t.children.length?t:null}function ce(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 i=document.createElement("div");i.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);",i.textContent=e,n.appendChild(i);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,i,t,o){const l=document.createElement("div");l.style.flex="1";const s=document.createElement("label");s.htmlFor=e,s.className="form-label",s.textContent=n,s.style.fontSize=".8rem";const d=document.createElement("select");if(d.id=e,d.className="form-input",t.forEach(([r,a])=>{const p=document.createElement("option");p.value=r,p.textContent=a,String(r)===String(i)&&(p.selected=!0),d.appendChild(p)}),l.appendChild(s),l.appendChild(d),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 re(e,n,i,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 s=document.createElement("input");if(s.id=e,s.type="checkbox",s.checked=!!i,l.appendChild(s),l.appendChild(document.createTextNode(" "+n)),o.appendChild(l),t){const d=document.createElement("p");d.className="form-hint text-muted",d.textContent=t,d.style.cssText="font-size:.72rem;margin-top:.2rem;",o.appendChild(d)}return o}function K(e,n,i,t,o){const l=document.createElement("div");l.style.flex="1";const s=document.createElement("label");s.htmlFor=e,s.className="form-label",s.textContent=n,s.style.fontSize=".8rem",l.appendChild(s);const d=document.createElement("div");d.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=i||"",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 p=String(r.value).match(/^#[0-9a-fA-F]{3,8}$/);if(a.value=p?r.value:"#000000",a.addEventListener("input",()=>{r.value=a.value,r.dispatchEvent(new Event("input",{bubbles:!0}))}),d.appendChild(r),d.appendChild(a),l.appendChild(d),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 $e(e,n){const i=document.createElement("div");i.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const t=ce("Layout");t.body.appendChild(k([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."),re(`fb-chooser-multiple-${n}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),t.body.appendChild(k([U(`fb-chooser-density-${n}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),S("Columns",`fb-chooser-columns-${n}`,"number",e.columns||3,"Card grid (1\u20136). Ignored for chips.")])),i.appendChild(t.wrap);const o=ce("Visual");return o.body.appendChild(k([K(`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(k([re(`fb-chooser-glow-${n}`,"Glow on selected",!!e.glow,"Soft outer glow."),K(`fb-chooser-glow-colour-${n}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),o.body.appendChild(k([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."),K(`fb-chooser-shadow-colour-${n}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),i.appendChild(o.wrap),i}function Le(e,n,i,t){const o=document.createElement("div");o.className="fb-chooser-option-row",o.dataset.optIdx=String(i),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 s=document.createElement("div");s.style.cssText="display:flex; flex-direction:column; gap:1px;";const d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",d.title="Move up",w(d,"arrow-up"),d.addEventListener("click",N=>{N.preventDefault(),de(n,i,-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(),de(n,i,1,t)}),s.appendChild(d),s.appendChild(r),l.appendChild(s);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 p=document.createElement("input");p.type="text",p.className="form-input fb-chooser-opt-label",p.placeholder="label (visible to users)",p.value=e.label||"",p.style.flex="2",l.appendChild(p);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(),Ie(n,i,t)}),l.appendChild(c),o.appendChild(l);const u=document.createElement("div");u.style.cssText="display:flex; gap:.4rem;";const m=he("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 T=document.createElement("input");T.type="checkbox",T.className="fb-chooser-opt-recommended",T.checked=!!e.recommended,x.appendChild(T),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 A=document.createElement("input");return A.type="checkbox",A.className="fb-chooser-opt-disabled",A.checked=!!e.disabled,z.appendChild(A),z.appendChild(document.createTextNode(" Disabled")),C.appendChild(z),o.appendChild(C),o}function ze(e,n){const i=document.createElement("div");i.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),i.appendChild(t);const s=document.createElement("div");s.className="fb-chooser-options-list",s.id=`fb-chooser-options-${n}`,s.style.cssText="display:flex; flex-direction:column; gap:.4rem;",i.appendChild(s);const d=()=>{s.replaceChildren();const r=Ae(n);(r.length?r:e||[]).forEach((p,c)=>{s.appendChild(Le(p,n,c,d))})};return l.addEventListener("click",r=>{r.preventDefault(),Be(n,d)}),d(),i}function Ae(e){const n=g[e];return!n||!Array.isArray(n.options)?[]:n.options}function X(e){return g[e]?(Array.isArray(g[e].options)||(g[e].options=[]),g[e].options):[]}function Be(e,n){J(e),X(e).push({value:"new",label:"New option"}),n()}function Ie(e,n,i){J(e),X(e).splice(n,1),i()}function de(e,n,i,t){J(e);const o=X(e),l=n+i;if(l<0||l>=o.length)return;const[s]=o.splice(n,1);o.splice(l,0,s),t()}function J(e){const n=document.getElementById(`fb-chooser-options-${e}`);if(!n)return;const i=n.querySelectorAll(".fb-chooser-option-row"),t=[];i.forEach(o=>{const l={value:o.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:o.querySelector(".fb-chooser-opt-label")?.value.trim()||""},s=o.querySelector(".fb-chooser-opt-icon")?.value.trim();s&&(l.icon=s);const d=o.querySelector(".fb-chooser-opt-description")?.value.trim();d&&(l.description=d);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(),p=o.querySelector(".fb-chooser-opt-badge-type")?.value;(a||p)&&(l.badge={},a&&(l.badge.text=a),p&&(l.badge.type=p)),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 k(e){const n=document.createElement("div");return n.style.cssText="display:flex;gap:.85rem;margin-bottom:.75rem;",e.forEach(i=>{i&&n.appendChild(i)}),n}function S(e,n,i,t,o){const l=document.createElement("div");l.style.flex="1";const s=document.createElement("label");s.htmlFor=n,s.className="form-label",s.textContent=e,s.style.fontSize=".8rem";const d=document.createElement("input");if(d.id=n,d.type=i||"text",d.className="form-input",d.value=t??"",l.appendChild(s),l.appendChild(d),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 Fe(e,n,i,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 s=document.createElement("select");return s.id=n,s.className="form-select",i.forEach(d=>{const r=document.createElement("option");r.value=d.value,r.textContent=d.label,d.value===t&&(r.selected=!0),s.appendChild(r)}),o.appendChild(l),o.appendChild(s),o}function pe(e,n,i){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=i,o.appendChild(l),o.appendChild(document.createTextNode(e)),t.appendChild(o),t}function Oe(e,n){const i=document.createElement("div");i.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
|
|
5
|
+
`),t.appendChild(p),t.appendChild(c),t}function Le(e,n){const s=e.logic||{},t=y.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 d=oe(s),r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",w(r,d?"chevron-down":"chevron-right",12);const a=document.createElement("div");a.className="fb-logic-body",a.style.cssText="padding:.25rem 0 .25rem;"+(d?"":"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(Te(s.visibility||{},n,t)),a.appendChild(Ne(s.requirement||{},n,t)),a.appendChild(qe(s.validation||[],n,t));const p=document.getElementById(`fb-type-${n}`)?.value||e.type;return W.has(p)&&a.appendChild($e(s.cascade||{},n,t)),o.appendChild(a),o}function re(e,n,s){const t=document.createElement("div");return t.className="fb-field-extras",e==="chooser"?(t.appendChild(ze(n,s)),t.appendChild(Be(n.options||[],s))):(W.has(e)&&t.appendChild(je(n.options||[],s)),e==="textarea"&&t.appendChild(k([S("Rows",`fb-rows-${s}`,"number",n.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&t.appendChild(k([S("Min Length",`fb-minlength-${s}`,"number",n.minLength||"",""),S("Max Length",`fb-maxlength-${s}`,"number",n.maxLength||"","")])),e==="number"&&t.appendChild(k([S("Min",`fb-min-${s}`,"number",n.min??"",""),S("Max",`fb-max-${s}`,"number",n.max??"","")]))),t.children.length?t:null}function de(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 d=document.createElement("select");if(d.id=e,d.className="form-input",t.forEach(([r,a])=>{const p=document.createElement("option");p.value=r,p.textContent=a,String(r)===String(s)&&(p.selected=!0),d.appendChild(p)}),l.appendChild(i),l.appendChild(d),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 pe(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 d=document.createElement("p");d.className="form-hint text-muted",d.textContent=t,d.style.cssText="font-size:.72rem;margin-top:.2rem;",o.appendChild(d)}return o}function K(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 d=document.createElement("div");d.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 p=String(r.value).match(/^#[0-9a-fA-F]{3,8}$/);if(a.value=p?r.value:"#000000",a.addEventListener("input",()=>{r.value=a.value,r.dispatchEvent(new Event("input",{bubbles:!0}))}),d.appendChild(r),d.appendChild(a),l.appendChild(d),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 ze(e,n){const s=document.createElement("div");s.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const t=de("Layout");t.body.appendChild(k([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."),pe(`fb-chooser-multiple-${n}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),t.body.appendChild(k([U(`fb-chooser-density-${n}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),S("Columns",`fb-chooser-columns-${n}`,"number",e.columns||3,"Card grid (1\u20136). Ignored for chips.")])),s.appendChild(t.wrap);const o=de("Visual");return o.body.appendChild(k([K(`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(k([pe(`fb-chooser-glow-${n}`,"Glow on selected",!!e.glow,"Soft outer glow."),K(`fb-chooser-glow-colour-${n}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),o.body.appendChild(k([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."),K(`fb-chooser-shadow-colour-${n}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),s.appendChild(o.wrap),s}function Ae(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 d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",d.title="Move up",w(d,"arrow-up"),d.addEventListener("click",N=>{N.preventDefault(),me(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(),me(n,s,1,t)}),i.appendChild(d),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 p=document.createElement("input");p.type="text",p.className="form-input fb-chooser-opt-label",p.placeholder="label (visible to users)",p.value=e.label||"",p.style.flex="2",l.appendChild(p);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(),Oe(n,s,t)}),l.appendChild(c),o.appendChild(l);const u=document.createElement("div");u.style.cssText="display:flex; gap:.4rem;";const m=ge("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 b=document.createElement("div");b.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",b.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",b.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(([N,O])=>{const _=document.createElement("option");_.value=N,_.textContent=O,(e.badge?.type||"")===N&&(_.selected=!0),v.appendChild(_)}),b.appendChild(v),o.appendChild(b);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 T=document.createElement("input");T.type="checkbox",T.className="fb-chooser-opt-recommended",T.checked=!!e.recommended,x.appendChild(T),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 A=document.createElement("input");return A.type="checkbox",A.className="fb-chooser-opt-disabled",A.checked=!!e.disabled,z.appendChild(A),z.appendChild(document.createTextNode(" Disabled")),C.appendChild(z),o.appendChild(C),o}function Be(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",M(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 d=()=>{i.replaceChildren();const r=Ie(n);(r.length?r:e||[]).forEach((p,c)=>{i.appendChild(Ae(p,n,c,d))})};return l.addEventListener("click",r=>{r.preventDefault(),Fe(n,d)}),d(),s}function Ie(e){const n=y[e];return!n||!Array.isArray(n.options)?[]:n.options}function X(e){return y[e]?(Array.isArray(y[e].options)||(y[e].options=[]),y[e].options):[]}function Fe(e,n){J(e),X(e).push({value:"new",label:"New option"}),n()}function Oe(e,n,s){J(e),X(e).splice(n,1),s()}function me(e,n,s,t){J(e);const o=X(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 d=o.querySelector(".fb-chooser-opt-description")?.value.trim();d&&(l.description=d);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(),p=o.querySelector(".fb-chooser-opt-badge-type")?.value;(a||p)&&(l.badge={},a&&(l.badge.text=a),p&&(l.badge.type=p)),o.querySelector(".fb-chooser-opt-recommended")?.checked&&(l.recommended=!0),o.querySelector(".fb-chooser-opt-disabled")?.checked&&(l.disabled=!0),t.push(l)}),y[e]&&(y[e].options=t)}function k(e){const n=document.createElement("div");return n.style.cssText="display:flex;gap:.85rem;margin-bottom:.75rem;",e.forEach(s=>{s&&n.appendChild(s)}),n}function S(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 d=document.createElement("input");if(d.id=n,d.type=s||"text",d.className="form-input",d.value=t??"",l.appendChild(i),l.appendChild(d),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 _e(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(d=>{const r=document.createElement("option");r.value=d.value,r.textContent=d.label,d.value===t&&(r.selected=!0),i.appendChild(r)}),o.appendChild(l),o.appendChild(i),o}function ue(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 je(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
|
|
8
|
-
`),o.style.fontFamily="monospace",
|
|
7
|
+
maybe:Maybe`,o.value=(e||[]).map(l=>{const i=typeof l=="string"?l:l.value??"",d=typeof l=="string"?l:l.label??i;return i===d?i:`${i}:${d}`}).join(`
|
|
8
|
+
`),o.style.fontFamily="monospace",s.appendChild(t),s.appendChild(o),s}function fe(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:{...G||{},project:n||null},fields:y,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()},...j!==null&&{collection:j}}}}function Pe(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 he(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 l=t.type==="chooser"||!!(t.variant&&["select","radio","checkbox-group"].includes(t.type)),d={type:t.type==="checkbox"?"boolean":t.type==="date"||t.type==="icon"||t.type==="image"?"string":l?"chooser":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}};l&&(t.variant&&(d.variant=t.variant),(t.multiple||t.type==="checkbox-group")&&(d.multiple=!0),t.density&&(d.density=t.density),t.columns&&(d.columns=t.columns),t.accent&&(d.accent=t.accent),t.accentStyle&&(d.accentStyle=t.accentStyle),t.glow&&(d.glow=!0),t.glowColour&&(d.glowColour=t.glowColour),t.shadow&&(d.shadow=t.shadow),t.shadowColour&&(d.shadowColour=t.shadowColour)),s[t.name]=d}),s}function be(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){y=[],q=null,j=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 I(`/forms/${q}`),y=s.fields||[],j=s.actions?.collection??null}catch{E.toast("Could not load form.",{type:"error"})}G={};try{const a=await I("/projects").catch(()=>[]),p=e.find("#field-project").get(0);p&&(Array.isArray(a)?a:[]).forEach(c=>{const u=document.createElement("option");u.value=c.slug,u.textContent=c.name||c.slug,p.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(ne(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 p=s.actions?.email||{};e.find("#action-email-enabled").prop("checked",p.enabled||!1),e.find("#action-email-recipients").val(p.recipients||""),e.find("#action-email-subject-prefix").val(p.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 I("/actions").catch(()=>[]),p=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),p.appendChild(u)}),!a.length){const c=document.createElement("option");c.value="",c.textContent="No actions available",c.disabled=!0,p.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(p=>{p.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"}),P&&document.removeEventListener("click",P),P=()=>{l&&(l.style.display="none")},document.addEventListener("click",P),e.find("#add-field-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),$();const a=y.length;y.push({name:`field_${a+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),L(e);const p=e.find("#fields-list").get(0)?.lastElementChild;if(p){const c=p.querySelector(".fb-field-body");c&&(c.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),$(),y.push({type:"spacer"}),L(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{l&&(l.style.display="none"),$();const a=y.filter(p=>p.type==="page-break").length+2;y.push({type:"page-break",label:`Step ${a}`,description:""}),L(e)}),e.find("#save-form-btn").get(0).addEventListener("click",async()=>{const a=fe(e);if(!a.title){E.toast("Please enter a form title.",{type:"error"});return}try{q?(await I(`/forms/${q}`,{method:"PUT",body:JSON.stringify(a)}),E.toast("Form saved.",{type:"success"})):(q=(await I("/forms",{method:"POST",body:JSON.stringify(a)})).slug,R.navigate(`/forms/edit/${q}`),E.toast("Form created.",{type:"success"}))}catch(p){E.toast(p.message||"Failed to save form.",{type:"error"})}}),D=()=>{const a=fe(e),p=e.find("#preview-container").get(0);if(!p)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="",p.textContent="";const m=document.createElement("div");m.id="fb-preview-form",p.appendChild(m);const f=q?async h=>{c&&(c.style.display="none",c.textContent="");try{const g=await fetch(`/api/forms/submit/${q}`,{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.");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(g){c&&(c.textContent=g.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(g.message,{type:"error"})}return!1}:()=>!1,b=a.fields.some(h=>h.type==="page-break");if(typeof F<"u"){const h=a.settings?.columns||2,g=a.settings?.layout||"stacked";if(b&&F.wizard){const v=Pe(a.fields).map(C=>({title:C.title,description:C.description,fields:he(C.fields,h)}));F.wizard("#fb-preview-form",{schema:{steps:v},onSubmit:f}),be("#fb-preview-form",a.fields),Z(m,a.fields)}else if(F.render){const v=he(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 T=(x.options||[])[0];T&&(C[x.name]=typeof T=="object"?T.value:T)}}),F.render("#fb-preview-form",v,C,{submitText:a.settings?.submitText||"Submit",layout:g,columns:h,onSubmit:f}),g==="grid"&&a.settings?.submitSpan==="full"){const x=document.querySelector("#fb-preview-form .form-buttons");x&&x.classList.add("col-span-full")}be("#fb-preview-form",a.fields),Z(m,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)}},D();const i=e.find("#editor-tabs").get(0),d=e.find("#preview-card").get(0),r=a=>{d&&d.contains(a.target)||Y()};i&&(i.addEventListener("input",r),i.addEventListener("change",r))}};
|
package/bin/update.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* preserving all user content, config, and custom plugins.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import {cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync,} from 'node:fs';
|
|
11
|
+
import {cpSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync,} from 'node:fs';
|
|
12
12
|
import {spawnSync} from 'node:child_process';
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import {createInterface} from 'node:readline';
|
|
@@ -199,7 +199,11 @@ export default async function update(_positional, flags) {
|
|
|
199
199
|
|
|
200
200
|
info('Upstream directories that would be replaced:');
|
|
201
201
|
for (const dir of UPSTREAM_DIRS) {
|
|
202
|
-
|
|
202
|
+
if (dir === 'public') {
|
|
203
|
+
info(` → ${dir}/ (upstream entries only — site-added files are preserved)`);
|
|
204
|
+
} else {
|
|
205
|
+
info(` → ${dir}/`);
|
|
206
|
+
}
|
|
203
207
|
}
|
|
204
208
|
console.log('');
|
|
205
209
|
|
|
@@ -303,6 +307,23 @@ export default async function update(_positional, flags) {
|
|
|
303
307
|
const dest = path.join(cwd, dir);
|
|
304
308
|
const src = path.join(PACKAGE_ROOT, dir);
|
|
305
309
|
if (!existsSync(src)) continue;
|
|
310
|
+
if (dir === 'public') {
|
|
311
|
+
// public/ is shared ground: upstream ships css/ and js/, but sites
|
|
312
|
+
// add their own subdirs and files (games, images, downloads). Replace
|
|
313
|
+
// only the entries the package ships; everything else stays put.
|
|
314
|
+
mkdirSync(dest, {recursive: true});
|
|
315
|
+
for (const entry of readdirSync(src)) {
|
|
316
|
+
const destEntry = path.join(dest, entry);
|
|
317
|
+
let st = null;
|
|
318
|
+
try { st = lstatSync(destEntry); } catch { /* missing */ }
|
|
319
|
+
// A symlinked entry (e.g. a manager-shared public/js) is owned by
|
|
320
|
+
// whatever it points at — replacing it would silently fork it.
|
|
321
|
+
if (st && st.isSymbolicLink()) continue;
|
|
322
|
+
if (st) rmSync(destEntry, {recursive: true, force: true});
|
|
323
|
+
cpSync(path.join(src, entry), destEntry, {recursive: true});
|
|
324
|
+
}
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
306
327
|
if (existsSync(dest)) rmSync(dest, {recursive: true, force: true});
|
|
307
328
|
cpSync(src, dest, {recursive: true});
|
|
308
329
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domma-cms",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
4
4
|
"description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/server.js",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"@fastify/rate-limit": "^10.3.0",
|
|
82
82
|
"@fastify/static": "9.1.1",
|
|
83
83
|
"bcryptjs": "^3.0.3",
|
|
84
|
-
"domma-js": "0.
|
|
84
|
+
"domma-js": "0.39.0",
|
|
85
85
|
"dotenv": "^17.2.3",
|
|
86
86
|
"fastify": "5.8.5",
|
|
87
87
|
"gray-matter": "^4.0.3",
|
package/public/css/forms.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.fb-form-wrapper{max-width:600px;margin:2rem auto}.fb-form-honeypot{position:absolute;left:-9999px;top:-9999px;width:0;height:0;overflow:hidden;opacity:0;z-index:-1}.fb-form-success{padding:1rem 1.25rem;border-radius:6px;background:color-mix(in srgb,var(--dm-success
|
|
1
|
+
.fb-form-wrapper{max-width:600px;margin:2rem auto}.fb-form-honeypot{position:absolute;left:-9999px;top:-9999px;width:0;height:0;overflow:hidden;opacity:0;z-index:-1}.fb-form-success{padding:1rem 1.25rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-success) 12%,transparent);border:1px solid color-mix(in srgb,var(--dm-success) 30%,transparent);color:var(--dm-success);font-size:.95rem;margin-top:.5rem}.fb-form-error{padding:.75rem 1rem;border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-danger) 10%,transparent);border:1px solid color-mix(in srgb,var(--dm-danger) 25%,transparent);color:var(--dm-danger);font-size:.875rem;margin-top:.75rem}.fb-form-loading{opacity:.6;pointer-events:none}.wizard-progress{height:4px;background:var(--dm-border);border-radius:2px;margin-bottom:1rem}.wizard-progress-bar{height:100%;background:var(--dm-primary);border-radius:2px;transition:width .3s ease}.wizard-step-title{font-size:1.1rem;font-weight:600;margin-bottom:.25rem}.wizard-step-description{font-size:.875rem;color:var(--dm-text-muted);margin-bottom:1rem}.wizard-nav{display:flex;justify-content:space-between;gap:.5rem;margin-top:1rem}.fb-field-hidden{display:none!important}.fb-validation-error{color:var(--dm-danger);font-size:.8rem;margin-top:.25rem}.fb-form-wrapper .domma-form-field{margin-bottom:2rem}.fb-form-wrapper .form-group:not(.form-buttons){margin-bottom:2rem}.fb-spacer{height:2rem}.fb-field-required .picker-label:after,.fb-field-required>.form-label:after{content:" *";color:var(--dm-danger)}.fb-field-required .picker-label .picker-required{display:none}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(c,l){typeof module<"u"&&module.exports?module.exports=l():c.FormLogicEngine=l()})(typeof globalThis<"u"?globalThis:this,function(){"use strict";function c(e){return e===""||e===null||e===void 0?"":String(e)}function l(e){const
|
|
1
|
+
(function(c,l){typeof module<"u"&&module.exports?module.exports=l():c.FormLogicEngine=l()})(typeof globalThis<"u"?globalThis:this,function(){"use strict";function c(e){return e===""||e===null||e===void 0?"":String(e)}function l(e){const r=parseFloat(e);return isNaN(r)?null:r}function f(e){return e==null?!0:typeof e=="string"?e.trim()==="":Array.isArray(e)?e.length===0:!1}const E={not_equals:"equals",not_contains:"contains",not_in:"in"};function m(e,r){const s=c(r),n=c(e.value);switch(e.operator){case"equals":return s===n;case"not_equals":return s!==n;case"contains":return s.toLowerCase().includes(n.toLowerCase());case"not_contains":return!s.toLowerCase().includes(n.toLowerCase());case"starts_with":return s.toLowerCase().startsWith(n.toLowerCase());case"ends_with":return s.toLowerCase().endsWith(n.toLowerCase());case"greater_than":{const t=l(r),i=l(e.value);return t!==null&&i!==null&&t>i}case"less_than":{const t=l(r),i=l(e.value);return t!==null&&i!==null&&t<i}case"is_empty":return f(r);case"is_not_empty":return!f(r);case"in":return(Array.isArray(e.value)?e.value.map(c):String(e.value).split(",").map(i=>i.trim())).includes(s);case"not_in":return!(Array.isArray(e.value)?e.value.map(c):String(e.value).split(",").map(i=>i.trim())).includes(s);case"matches_regex":try{const t=e.flags||"";return new RegExp(e.value,t).test(s)}catch(t){return typeof console<"u"&&console.warn&&console.warn('[FormLogicEngine] Invalid regex in condition for field "'+e.field+'": '+e.value,t&&t.message),!1}default:return!0}}function y(e,r){if(!e||!e.field||!e.operator)return!0;const s=r[e.field];if(!Array.isArray(s))return m(e,s);if(e.operator==="is_empty")return f(s);if(e.operator==="is_not_empty")return!f(s);const n=E[e.operator];if(n){const t=Object.assign({},e,{operator:n});return!s.some(i=>m(t,i))}return s.some(t=>m(e,t))}function p(e,r){return e?Array.isArray(e.all)?e.all.every(s=>s.all||s.any?p(s,r):y(s,r)):Array.isArray(e.any)?e.any.some(s=>s.all||s.any?p(s,r):y(s,r)):e.field&&e.operator?y(e,r):!0:!0}function g(e,r){const s=e.logic;if(!s||!s.visibility)return"visible";const n=s.visibility,t=n.conditions||[];for(const i of t)if(i.when&&p(i.when,r))return i.then==="hidden"?"hidden":"visible";return n.default==="hidden"?"hidden":"visible"}function v(e,r){const s=e.logic;if(!s||!s.requirement)return e.required||!1;const n=s.requirement,t=n.conditions||[];for(const i of t)if(i.when&&p(i.when,r))return i.then===!0;return n.default===!0}function b(e,r,s){const n=e.logic;if(!n||!Array.isArray(n.validation))return[];const t=[];for(const i of n.validation)switch(i.type){case"regex":{if(!f(r))try{new RegExp(i.pattern||"",i.flags||"").test(c(r))||t.push({message:i.message||"Invalid format."})}catch{}break}case"match":{const a=s[i.field];!f(r)&&c(r)!==c(a)&&t.push({message:i.message||"Fields do not match."});break}}return t}function w(e,r){const s=e.logic;if(!s||!s.cascade||!s.cascade.sourceField)return null;const n=s.cascade,t=n.mapping||{},i=r[n.sourceField];if(Array.isArray(i)){const u=new Set,d=[];return i.forEach(function(C){const A=c(C);Object.prototype.hasOwnProperty.call(t,A)&&(t[A]||[]).forEach(function(_){const q=c(_&&_.value);u.has(q)||(u.add(q),d.push(_))})}),d.length?d:n.defaultOptions||null}const a=c(i);return Object.prototype.hasOwnProperty.call(t,a)?t[a]||[]:n.defaultOptions||null}function x(e,r){r==="fade"?(e.style.transition="opacity 0.25s ease",e.style.opacity="1",requestAnimationFrame(function(){e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.opacity=""},260)})):r==="slide"?(e.style.overflow="hidden",e.style.maxHeight=e.scrollHeight+"px",e.style.transition="max-height 0.3s ease, opacity 0.2s ease",requestAnimationFrame(function(){e.style.maxHeight="0",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},320)})):r==="scale"&&(e.style.transition="opacity 0.2s ease, transform 0.2s ease",e.style.transform="scale(1)",e.style.opacity="1",requestAnimationFrame(function(){e.style.transform="scale(0.95)",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.transform="",e.style.opacity=""},220)}))}function F(e,r){e.classList.remove("fb-field-hidden"),r==="fade"?(e.style.opacity="0",e.style.transition="opacity 0.25s ease",requestAnimationFrame(function(){e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.opacity=""},260)})):r==="slide"?(e.style.overflow="hidden",e.style.maxHeight="0",e.style.opacity="0",e.style.transition="max-height 0.3s ease, opacity 0.2s ease",requestAnimationFrame(function(){e.style.maxHeight=e.scrollHeight+"px",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},320)})):r==="scale"&&(e.style.transform="scale(0.95)",e.style.opacity="0",e.style.transition="opacity 0.2s ease, transform 0.2s ease",requestAnimationFrame(function(){e.style.transform="scale(1)",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.transform="",e.style.opacity=""},220)}))}function o(e,r){this._form=e,this._wrapper=r,this._fields=(e.fields||[]).filter(s=>s.type!=="page-break"),this._listeners=[],this._depMap=new Map,this._initialEval=!1}function h(e,r,s){const n=s||"",t=r||"";return n+'[name="'+e+'"]'+t+", "+n+'[name="'+e+'[]"]'+t}function L(e){return String(e||"").replace(/\[\]$/,"")}return o.prototype._fieldInputs=function(e){return this._wrapper.querySelectorAll(h(e))},o.prototype._fieldInput=function(e){return this._wrapper.querySelector(h(e))},o.prototype._buildDepMap=function(){this._depMap.clear();const e=this;e._fields.forEach(function(r){const s=r.logic;if(!s)return;function n(t){if(!t)return;(t.all||t.any||[]).forEach(function(a){a.field?(e._depMap.has(a.field)||e._depMap.set(a.field,new Set),e._depMap.get(a.field).add(r.name)):n(a)})}if(s.visibility&&(s.visibility.conditions||[]).forEach(function(t){n(t.when)}),s.requirement&&(s.requirement.conditions||[]).forEach(function(t){n(t.when)}),s.cascade&&s.cascade.sourceField){const t=s.cascade.sourceField;e._depMap.has(t)||e._depMap.set(t,new Set),e._depMap.get(t).add(r.name)}})},o.prototype._getValues=function(){const e={};return this._fields.forEach(function(r){const s=this._fieldInputs(r.name);if(!s.length)return;const n=s[0];if(n.type==="radio"){const t=this._wrapper.querySelector(h(r.name,":checked"));e[r.name]=t?t.value:""}else if(n.type==="checkbox")if(s.length>1||/\[\]$/.test(n.name||"")){const t=[];s.forEach(function(i){i.checked&&t.push(i.value)}),e[r.name]=t}else e[r.name]=n.checked?n.value||"true":"";else e[r.name]=n.value},this),e},o.prototype._applyVisibility=function(e,r){const n=g(e,r)==="hidden",t=this._findFieldWrapper(e.name);if(!t)return;t.setAttribute("aria-hidden",String(n));const i=this._initialEval?"none":e.logic?.visibility?.transition||"none";if(i==="none"){t.classList.toggle("fb-field-hidden",n);return}t.style.transition="",n?x(t,i):F(t,i)},o.prototype._applyRequirement=function(e,r){const s=v(e,r),n=this._fieldInput(e.name);if(n){if(/\[\]$/.test(n.name||"")||n.closest&&n.closest(".domma-chooser")){const t=this._findFieldWrapper(e.name);n.removeAttribute("required"),t&&(t.setAttribute("aria-required",String(s)),t.classList.toggle("fb-field-required",s));return}s?n.setAttribute("required",""):n.removeAttribute("required")}},o.prototype._applyCascade=function(e,r){const s=w(e,r);if(s===null)return;const n=this._wrapper.querySelector(h(e.name,"","select"));if(!n)return;const t=n.value;n.textContent="",s.forEach(function(i){const a=document.createElement("option");a.value=i.value,a.textContent=i.label||i.value,i.value===t&&(a.selected=!0),n.appendChild(a)})},o.prototype._applyValidation=function(e,r){const s=this._fieldInput(e.name);if(!s)return;const n=b(e,r[e.name],r);let t=s.parentNode.querySelector(".fb-validation-error");n.length?(t||(t=document.createElement("div"),t.className="fb-validation-error",s.parentNode.appendChild(t)),t.textContent=n[0].message):t&&t.remove()},o.prototype._findFieldWrapper=function(e){const r=this._fieldInput(e);if(!r)return null;const s=r.closest("form")||this._wrapper;let n=r;for(;n.parentNode&&n.parentNode!==s;)n=n.parentNode;return n},o.prototype.evaluate=function(e){const r=this._getValues(),s=this;let n;if(e&&this._depMap.has(e)){const t=this._depMap.get(e);n=this._fields.filter(function(i){return t.has(i.name)})}else n=this._fields;n.forEach(function(t){t.logic&&(s._applyVisibility(t,r),s._applyRequirement(t,r),s._applyCascade(t,r))})},o.prototype.init=function(){this._buildDepMap();const e=this;this._wrapper.querySelectorAll("input, select, textarea").forEach(function(n){const t=L(n.getAttribute("name"));if(!t)return;const i=function(){e.evaluate(t)};n.addEventListener("input",i),n.addEventListener("change",i),e._listeners.push({el:n,event:"input",fn:i}),e._listeners.push({el:n,event:"change",fn:i});const a=e._fields.find(function(u){return u.name===t});if(a&&a.logic&&Array.isArray(a.logic.validation)&&a.logic.validation.length){const u=function(){const d=e._getValues();e._applyValidation(a,d)};n.addEventListener("blur",u),e._listeners.push({el:n,event:"blur",fn:u})}}),this._wrapper.querySelectorAll("[data-chooser-field]").forEach(function(n){const t=n.getAttribute("data-chooser-field");if(!t)return;const i=function(){setTimeout(function(){e.evaluate(t)},0)};n.addEventListener("click",i),e._listeners.push({el:n,event:"click",fn:i})}),this._initialEval=!0,this.evaluate(),this._initialEval=!1},o.prototype.destroy=function(){this._listeners.forEach(function(e){e.el.removeEventListener(e.event,e.fn)}),this._listeners=[]},{evaluateCondition:y,evaluateConditionGroup:p,evaluateFieldVisibility:g,evaluateFieldRequirement:v,validateField:b,getCascadeOptions:w,FormLogicRuntime:o}});
|
package/public/js/forms.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const v=document.querySelectorAll("[data-form]");v.length&&v.forEach(D);function y(i,o,t){const e=i.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const a=document.createElement("div");a.className=t==="success"?"fb-form-success":"fb-form-error",a.textContent=o,i.appendChild(a)}function E(i,o){if(i._formLogicRuntime=o,!i.parentNode||typeof MutationObserver>"u")return;const t=new MutationObserver(function(e){for(const a of e)for(const r of a.removedNodes)if(r===i||r.nodeType===1&&r.contains&&r.contains(i)){o.destroy(),t.disconnect();return}});t.observe(i.parentNode,{childList:!0,subtree:!1})}function w(i,o){const t={};return i.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":a?"chooser":e.type,l={...e.formConfig||{}};l.span==="full"&&o&&(l.span=o);const n={type:r,label:e.label||e.name,required:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...l}};e.minLength!==void 0&&(n.minLength=e.minLength),e.maxLength!==void 0&&(n.maxLength=e.maxLength),e.min!==void 0&&(n.min=e.min),e.max!==void 0&&(n.max=e.max),a&&(e.variant&&(n.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(n.multiple=!0),e.density&&(n.density=e.density),e.columns&&(n.columns=e.columns),e.accent&&(n.accent=e.accent),e.accentStyle&&(n.accentStyle=e.accentStyle),e.glow&&(n.glow=!0),e.glowColour&&(n.glowColour=e.glowColour),e.shadow&&(n.shadow=e.shadow),e.shadowColour&&(n.shadowColour=e.shadowColour)),t[e.name]=n}),t}function j(i){const o={};return i.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function C(i,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=i.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}function N(i,o){const t=[];let e=[],a=o||"Step 1",r="";return i.forEach(function(l){l.type==="page-break"?(t.push({title:a,description:r,fieldGroup:e}),e=[],a=l.label||"Step "+(t.length+1),r=l.description||""):l.type!=="spacer"&&e.push(l)}),t.push({title:a,description:r,fieldGroup:e}),t}const k="padding:.45rem .7rem;border:1px solid var(--dm-border,#ccc);border-radius:6px;background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function L(i){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface,#fff);color:var(--dm-text,#111);border:1px solid var(--dm-border,#ddd);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:0 12px 40px rgba(0,0,0,.35);";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const a=document.createElement("strong");a.textContent=i;const r=document.createElement("button");r.type="button",r.textContent="\xD7",r.setAttribute("aria-label","Close"),r.style.cssText=k+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(a),e.appendChild(r),t.appendChild(e);const l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(l),o.appendChild(t);const n=m=>{m.key==="Escape"&&s()};function s(){document.removeEventListener("keydown",n),o.remove()}return r.addEventListener("click",s),o.addEventListener("click",m=>{m.target===o&&s()}),document.addEventListener("keydown",n),document.body.appendChild(o),{body:l,close:s}}function A(i){const{body:o,close:t}=L("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border,#ccc);border-radius:6px;",o.appendChild(e);const a=document.createElement("div");a.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(a);const r=window.I&&typeof I.list=="function"?I.list():[],l=r.map(n=>{const s=document.createElement("button");s.type="button",s.title=n,s.dataset.iconName=n,s.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const m=document.createElement("span");return m.setAttribute("data-icon",n),m.setAttribute("data-icon-size","18"),s.appendChild(m),s.addEventListener("mouseenter",()=>{s.style.borderColor="var(--dm-border,#bbb)"}),s.addEventListener("mouseleave",()=>{s.style.borderColor="transparent"}),s.addEventListener("click",()=>{t(),i(n)}),a.appendChild(s),s});if(!r.length){const n=document.createElement("p");n.textContent="Icon engine unavailable \u2014 type an icon name into the field instead.",a.appendChild(n)}window.I?.scan?.(a),e.addEventListener("input",()=>{const n=e.value.trim().toLowerCase();l.forEach(s=>{s.style.display=!n||s.dataset.iconName.includes(n)?"":"none"})}),e.focus()}async function R(){const i=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!i)return{error:"auth"};const o=a=>fetch("/api/media",{headers:{Authorization:"Bearer "+a}});let t;try{if(t=await o(i),t.status===401&&S.get("auth_refresh_token")){const a=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(a.ok){const{token:r}=await a.json();S.set("auth_token",r),t=await o(r)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(a=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(a.name||a.url||""))}}function _(i){const{body:o,close:t}=L("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;opacity:.7;",o.appendChild(e),R().then(({files:a,error:r})=>{if(r){e.textContent=r==="auth"?"Sign in with media access to browse the library \u2014 or paste an image URL into the field.":"Could not load the media library \u2014 paste an image URL into the field instead.";return}if(!a.length){e.textContent="No images in the media library yet.";return}e.remove();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",a.forEach(n=>{const s=document.createElement("button");s.type="button",s.title=n.name||n.url,s.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border,#ddd);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const m=document.createElement("img");m.src=n.url,m.alt=n.name||"",m.loading="lazy",m.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const u=document.createElement("span");u.textContent=n.name||n.url,u.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",s.appendChild(m),s.appendChild(u),s.addEventListener("click",()=>{t(),i(n.url)}),l.appendChild(s)}),o.appendChild(l)})}function T(i,o){i.value=o,i.dispatchEvent(new Event("input",{bubbles:!0})),i.dispatchEvent(new Event("change",{bubbles:!0}))}function q(i){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",i.parentNode.insertBefore(o,i),o.appendChild(i),i.style.flex="1",i.style.minWidth="0",o}function F(i){const o=document.createElement("button");return o.type="button",o.textContent=i,o.style.cssText=k,o}function B(i){if(!window.I||typeof I.list!="function")return;const o=q(i),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border,#ccc);border-radius:6px;";const e=()=>{t.textContent="";const r=i.value.trim();if(!r)return;const l=document.createElement("span");l.setAttribute("data-icon",r),l.setAttribute("data-icon-size","16"),t.appendChild(l),window.I?.scan?.(t)};i.addEventListener("input",e),e();const a=F("Browse");a.addEventListener("click",()=>A(r=>{T(i,r),e()})),o.appendChild(t),o.appendChild(a)}function z(i){const o=q(i),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border,#ccc);border-radius:6px;display:none;";const e=()=>{const r=i.value.trim();t.style.display=r?"":"none",r&&(t.src=r)};i.addEventListener("input",e),e();const a=F("Browse");a.addEventListener("click",()=>_(r=>{T(i,r),e()})),o.appendChild(t),o.appendChild(a)}export function enhancePickerFields(i,o){const t=typeof i=="string"?document.querySelector(i):i;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const a=t.querySelector('[name="'+e.name+'"]');!a||a.dataset.pickerEnhanced||(a.dataset.pickerEnhanced="1",e.type==="icon"?B(a):z(a))})}function g(i){const o=document.createElement("div");o.className="fb-form-honeypot",o.setAttribute("aria-hidden","true");const t=document.createElement("input");t.name="website",t.type="text",t.tabIndex=-1,t.autocomplete="url",t.placeholder="https://",o.appendChild(t);const e=document.createElement("input");e.name="_t",e.type="hidden",e.value=Date.now(),o.appendChild(e),i.appendChild(o)}function O(i,o){const t=i.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let a=0;o.forEach(function(r){if(r.type==="spacer"){const l=document.createElement("div");l.className="fb-spacer";const n=e[a];if(n)t.insertBefore(l,n);else{const s=t.querySelector('[type="submit"]');s?t.insertBefore(l,s):t.appendChild(l)}}else r.type!=="page-break"&&a++})}function b(i,o,t,e,a){const r=a||e,l=r.querySelector('[name="website"]')?.value||"",n=r.querySelector('[name="_t"]')?.value||"",s=r?Array.from(r.querySelectorAll('input[type="file"]')):[],m=s.some(d=>d.files&&d.files.length>0);let u,c;if(m){const d=new FormData;for(const[h,p]of Object.entries(o||{}))p!=null&&(s.some(f=>f.name===h)||d.append(h,typeof p=="object"?JSON.stringify(p):String(p)));for(const h of s)for(const p of h.files)d.append(h.name,p,p.name);d.append("_hp",l),d.append("_t",n),u=d,c={}}else{const d=Object.assign({},o,{_hp:l,_t:n});u=JSON.stringify(d),c={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+i,{method:"POST",headers:c,body:u}).then(d=>d.json().then(h=>({ok:d.ok,body:h}))).then(d=>{d.ok&&d.body.ok?(e.textContent="",y(e,d.body.message||t.successMessage||"Thank you.","success")):y(e,d.body.error||"Something went wrong.","error")}).catch(()=>{y(e,"Unable to submit. Please check your connection.","error")})}function P(i,o,t,e,a){const r=document.createElement("form");r.noValidate=!0,o.forEach(function(n){const s=document.createElement("div");s.className="form-group",s.style.marginBottom="1.25rem";const m=document.createElement("label");if(m.className="form-label",m.textContent=n.label||n.name,n.required){const c=document.createElement("span");c.textContent=" *",c.style.color="#f87171",m.appendChild(c)}let u;n.type==="textarea"?(u=document.createElement("textarea"),u.rows=n.formConfig?.rows||4,u.className="form-input"):n.type==="select"?(u=document.createElement("select"),u.className="form-input",(n.options||[]).forEach(function(c){const d=document.createElement("option");d.value=typeof c=="string"?c:c.value??"",d.textContent=typeof c=="string"?c:c.label||d.value,u.appendChild(d)})):(u=document.createElement("input"),u.type=n.type==="icon"||n.type==="image"?"text":n.type||"text",u.className="form-input",n.placeholder&&(u.placeholder=n.placeholder),n.type==="file"&&(n.file?.accept&&(u.accept=n.file.accept),n.multiple&&(u.multiple=!0))),u.name=n.name,u.required=n.required||!1,s.appendChild(m),s.appendChild(u),r.appendChild(s)}),t.honeypot&&g(r);const l=document.createElement("button");l.type="submit",l.className="btn btn-primary",l.textContent=t.submitText||"Submit",r.appendChild(l),r.addEventListener("submit",function(n){n.preventDefault();const s={};if(o.forEach(function(m){const u=r.querySelector('[name="'+m.name+'"]');u&&(s[m.name]=u.value)}),window.FormLogicEngine&&a){const m=window.FormLogicEngine,u=[],c=[];if(o.forEach(function(d){if(m.evaluateFieldVisibility(d,s)==="hidden"){delete s[d.name];return}const p=m.evaluateFieldRequirement(d,s),f=s[d.name];p&&(!f||!String(f).trim())&&u.push(d.label||d.name);const x=m.validateField(d,f||"",s);x.length&&c.push(x[0].message)}),u.length||c.length){const d=[];u.length&&d.push("Required: "+u.join(", ")),c.length&&d.push(c.join("; ")),y(i,d.join(". "),"error");return}}i.classList.add("fb-form-loading"),l.disabled=!0,b(e,s,t,i,r).finally(function(){i.classList.remove("fb-form-loading"),l.disabled=!1})}),i.appendChild(r),enhancePickerFields(i,o),window.FormLogicEngine&&a&&o.some(n=>n.logic)&&new window.FormLogicEngine.FormLogicRuntime(a,i).init()}function D(i){const o=i.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],a=t.settings||{},r=document.createElement("div");r.className="fb-form-wrapper",i.appendChild(r);const l=e.some(n=>n.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const n=a.columns||1;if(l&&Domma.forms.wizard){const m=N(e,t.title).map(function(c){return{title:c.title,description:c.description,fields:w(c.fieldGroup,n)}}),u=Domma.forms.wizard(r,{schema:{steps:m},onSubmit:function(c){return b(o,c,a,r,null)}});Promise.resolve(u).then(function(){if(C(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(c=>c.logic)){const c=new window.FormLogicEngine.FormLogicRuntime(t,r);c.init(),E(r,c)}if(a.honeypot){const c=r.querySelector("form");c&&g(c)}})}else if(Domma.forms.render){const s=w(e,n),m=j(e),u=Domma.forms.render(r,s,m,{submitText:a.submitText||"Submit",layout:a.layout||"stacked",columns:n,onSubmit:function(c){return b(o,c,a,r,null)}});Promise.resolve(u).then(function(){if(C(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(c=>c.logic)){const c=new window.FormLogicEngine.FormLogicRuntime(t,r);c.init(),E(r,c)}if(e.some(c=>c.type==="spacer")&&O(r,e),a.honeypot){const c=r.querySelector("form");c&&g(c)}})}}else P(r,e.filter(n=>n.type!=="page-break"&&n.type!=="spacer"),a,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:#f87171;font-style:italic;",i.appendChild(e),console.warn("[forms]",t.message)})}
|
|
1
|
+
const x=document.querySelectorAll("[data-form]");x.length&&x.forEach(D);function y(a,o,t){const e=a.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const i=document.createElement("div");i.className=t==="success"?"fb-form-success":"fb-form-error",i.textContent=o,a.appendChild(i)}function E(a,o){if(a._formLogicRuntime=o,!a.parentNode||typeof MutationObserver>"u")return;const t=new MutationObserver(function(e){for(const i of e)for(const r of i.removedNodes)if(r===a||r.nodeType===1&&r.contains&&r.contains(a)){o.destroy(),t.disconnect();return}});t.observe(a.parentNode,{childList:!0,subtree:!1})}function w(a,o){const t={};return a.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,l={...e.formConfig||{}};l.span==="full"&&o&&(l.span=o);const n={type:r,label:e.label||e.name,required:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...l}};e.minLength!==void 0&&(n.minLength=e.minLength),e.maxLength!==void 0&&(n.maxLength=e.maxLength),e.min!==void 0&&(n.min=e.min),e.max!==void 0&&(n.max=e.max),i&&(e.variant&&(n.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(n.multiple=!0),e.density&&(n.density=e.density),e.columns&&(n.columns=e.columns),e.accent&&(n.accent=e.accent),e.accentStyle&&(n.accentStyle=e.accentStyle),e.glow&&(n.glow=!0),e.glowColour&&(n.glowColour=e.glowColour),e.shadow&&(n.shadow=e.shadow),e.shadowColour&&(n.shadowColour=e.shadowColour)),t[e.name]=n}),t}function j(a){const o={};return a.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function C(a,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=a.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}function N(a,o){const t=[];let e=[],i=o||"Step 1",r="";return a.forEach(function(l){l.type==="page-break"?(t.push({title:i,description:r,fieldGroup:e}),e=[],i=l.label||"Step "+(t.length+1),r=l.description||""):l.type!=="spacer"&&e.push(l)}),t.push({title:i,description:r,fieldGroup:e}),t}const k="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function L(a){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const i=document.createElement("strong");i.textContent=a;const r=document.createElement("button");r.type="button",r.textContent="\xD7",r.setAttribute("aria-label","Close"),r.style.cssText=k+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(i),e.appendChild(r),t.appendChild(e);const l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(l),o.appendChild(t);const n=u=>{u.key==="Escape"&&s()};function s(){document.removeEventListener("keydown",n),o.remove()}return r.addEventListener("click",s),o.addEventListener("click",u=>{u.target===o&&s()}),document.addEventListener("keydown",n),document.body.appendChild(o),{body:l,close:s}}function A(a){const{body:o,close:t}=L("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const i=document.createElement("div");i.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(i);const r=window.I&&typeof I.list=="function"?I.list():[],l=r.map(n=>{const s=document.createElement("button");s.type="button",s.title=n,s.dataset.iconName=n,s.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const u=document.createElement("span");return u.setAttribute("data-icon",n),u.setAttribute("data-icon-size","18"),s.appendChild(u),s.addEventListener("mouseenter",()=>{s.style.borderColor="var(--dm-border)"}),s.addEventListener("mouseleave",()=>{s.style.borderColor="transparent"}),s.addEventListener("click",()=>{t(),a(n)}),i.appendChild(s),s});if(!r.length){const n=document.createElement("p");n.textContent="Icon engine unavailable \u2014 type an icon name into the field instead.",i.appendChild(n)}window.I?.scan?.(i),e.addEventListener("input",()=>{const n=e.value.trim().toLowerCase();l.forEach(s=>{s.style.display=!n||s.dataset.iconName.includes(n)?"":"none"})}),e.focus()}async function R(){const a=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!a)return{error:"auth"};const o=i=>fetch("/api/media",{headers:{Authorization:"Bearer "+i}});let t;try{if(t=await o(a),t.status===401&&S.get("auth_refresh_token")){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(i.ok){const{token:r}=await i.json();S.set("auth_token",r),t=await o(r)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(i=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(i.name||i.url||""))}}function _(a){const{body:o,close:t}=L("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),R().then(({files:i,error:r})=>{if(r){e.textContent=r==="auth"?"Sign in with media access to browse the library \u2014 or paste an image URL into the field.":"Could not load the media library \u2014 paste an image URL into the field instead.";return}if(!i.length){e.textContent="No images in the media library yet.";return}e.remove();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",i.forEach(n=>{const s=document.createElement("button");s.type="button",s.title=n.name||n.url,s.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const u=document.createElement("img");u.src=n.url,u.alt=n.name||"",u.loading="lazy",u.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const d=document.createElement("span");d.textContent=n.name||n.url,d.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",s.appendChild(u),s.appendChild(d),s.addEventListener("click",()=>{t(),a(n.url)}),l.appendChild(s)}),o.appendChild(l)})}function T(a,o){a.value=o,a.dispatchEvent(new Event("input",{bubbles:!0})),a.dispatchEvent(new Event("change",{bubbles:!0}))}function q(a){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",a.parentNode.insertBefore(o,a),o.appendChild(a),a.style.flex="1",a.style.minWidth="0",o}function F(a){const o=document.createElement("button");return o.type="button",o.textContent=a,o.style.cssText=k,o}function B(a){if(!window.I||typeof I.list!="function")return;const o=q(a),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const r=a.value.trim();if(!r)return;const l=document.createElement("span");l.setAttribute("data-icon",r),l.setAttribute("data-icon-size","16"),t.appendChild(l),window.I?.scan?.(t)};a.addEventListener("input",e),e();const i=F("Browse");i.addEventListener("click",()=>A(r=>{T(a,r),e()})),o.appendChild(t),o.appendChild(i)}function z(a){const o=q(a),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const r=a.value.trim();t.style.display=r?"":"none",r&&(t.src=r)};a.addEventListener("input",e),e();const i=F("Browse");i.addEventListener("click",()=>_(r=>{T(a,r),e()})),o.appendChild(t),o.appendChild(i)}export function enhancePickerFields(a,o){const t=typeof a=="string"?document.querySelector(a):a;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const i=t.querySelector('[name="'+e.name+'"]');!i||i.dataset.pickerEnhanced||(i.dataset.pickerEnhanced="1",e.type==="icon"?B(i):z(i))})}function g(a){const o=document.createElement("div");o.className="fb-form-honeypot",o.setAttribute("aria-hidden","true");const t=document.createElement("input");t.name="website",t.type="text",t.tabIndex=-1,t.autocomplete="url",t.placeholder="https://",o.appendChild(t);const e=document.createElement("input");e.name="_t",e.type="hidden",e.value=Date.now(),o.appendChild(e),a.appendChild(o)}function O(a,o){const t=a.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let i=0;o.forEach(function(r){if(r.type==="spacer"){const l=document.createElement("div");l.className="fb-spacer";const n=e[i];if(n)t.insertBefore(l,n);else{const s=t.querySelector('[type="submit"]');s?t.insertBefore(l,s):t.appendChild(l)}}else r.type!=="page-break"&&i++})}function b(a,o,t,e,i){const r=i||e,l=r.querySelector('[name="website"]')?.value||"",n=r.querySelector('[name="_t"]')?.value||"",s=r?Array.from(r.querySelectorAll('input[type="file"]')):[],u=s.some(m=>m.files&&m.files.length>0);let d,c;if(u){const m=new FormData;for(const[h,p]of Object.entries(o||{}))p!=null&&(s.some(f=>f.name===h)||m.append(h,typeof p=="object"?JSON.stringify(p):String(p)));for(const h of s)for(const p of h.files)m.append(h.name,p,p.name);m.append("_hp",l),m.append("_t",n),d=m,c={}}else{const m=Object.assign({},o,{_hp:l,_t:n});d=JSON.stringify(m),c={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+a,{method:"POST",headers:c,body:d}).then(m=>m.json().then(h=>({ok:m.ok,body:h}))).then(m=>{m.ok&&m.body.ok?(e.textContent="",y(e,m.body.message||t.successMessage||"Thank you.","success")):y(e,m.body.error||"Something went wrong.","error")}).catch(()=>{y(e,"Unable to submit. Please check your connection.","error")})}function P(a,o,t,e,i){const r=document.createElement("form");r.noValidate=!0,o.forEach(function(n){const s=document.createElement("div");s.className="form-group",s.style.marginBottom="1.25rem";const u=document.createElement("label");if(u.className="form-label",u.textContent=n.label||n.name,n.required){const c=document.createElement("span");c.textContent=" *",c.style.color="var(--dm-danger)",u.appendChild(c)}let d;n.type==="textarea"?(d=document.createElement("textarea"),d.rows=n.formConfig?.rows||4,d.className="form-input"):n.type==="select"?(d=document.createElement("select"),d.className="form-input",(n.options||[]).forEach(function(c){const m=document.createElement("option");m.value=typeof c=="string"?c:c.value??"",m.textContent=typeof c=="string"?c:c.label||m.value,d.appendChild(m)})):(d=document.createElement("input"),d.type=n.type==="icon"||n.type==="image"?"text":n.type||"text",d.className="form-input",n.placeholder&&(d.placeholder=n.placeholder),n.type==="file"&&(n.file?.accept&&(d.accept=n.file.accept),n.multiple&&(d.multiple=!0))),d.name=n.name,d.required=n.required||!1,s.appendChild(u),s.appendChild(d),r.appendChild(s)}),t.honeypot&&g(r);const l=document.createElement("button");l.type="submit",l.className="btn btn-primary",l.textContent=t.submitText||"Submit",r.appendChild(l),r.addEventListener("submit",function(n){n.preventDefault();const s={};if(o.forEach(function(u){const d=r.querySelector('[name="'+u.name+'"]');d&&(s[u.name]=d.value)}),window.FormLogicEngine&&i){const u=window.FormLogicEngine,d=[],c=[];if(o.forEach(function(m){if(u.evaluateFieldVisibility(m,s)==="hidden"){delete s[m.name];return}const p=u.evaluateFieldRequirement(m,s),f=s[m.name];p&&(!f||!String(f).trim())&&d.push(m.label||m.name);const v=u.validateField(m,f||"",s);v.length&&c.push(v[0].message)}),d.length||c.length){const m=[];d.length&&m.push("Required: "+d.join(", ")),c.length&&m.push(c.join("; ")),y(a,m.join(". "),"error");return}}a.classList.add("fb-form-loading"),l.disabled=!0,b(e,s,t,a,r).finally(function(){a.classList.remove("fb-form-loading"),l.disabled=!1})}),a.appendChild(r),enhancePickerFields(a,o),window.FormLogicEngine&&i&&o.some(n=>n.logic)&&new window.FormLogicEngine.FormLogicRuntime(i,a).init()}function D(a){const o=a.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],i=t.settings||{},r=document.createElement("div");r.className="fb-form-wrapper",a.appendChild(r);const l=e.some(n=>n.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const n=i.columns||1;if(l&&Domma.forms.wizard){const u=N(e,t.title).map(function(c){return{title:c.title,description:c.description,fields:w(c.fieldGroup,n)}}),d=Domma.forms.wizard(r,{schema:{steps:u},onSubmit:function(c){return b(o,c,i,r,null)}});Promise.resolve(d).then(function(){if(C(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(c=>c.logic)){const c=new window.FormLogicEngine.FormLogicRuntime(t,r);c.init(),E(r,c)}if(i.honeypot){const c=r.querySelector("form");c&&g(c)}})}else if(Domma.forms.render){const s=w(e,n),u=j(e),d=Domma.forms.render(r,s,u,{submitText:i.submitText||"Submit",layout:i.layout||"stacked",columns:n,onSubmit:function(c){return b(o,c,i,r,null)}});Promise.resolve(d).then(function(){if(C(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&e.some(c=>c.logic)){const c=new window.FormLogicEngine.FormLogicRuntime(t,r);c.init(),E(r,c)}if(e.some(c=>c.type==="spacer")&&O(r,e),i.honeypot){const c=r.querySelector("form");c&&g(c)}})}}else P(r,e.filter(n=>n.type!=="page-break"&&n.type!=="spacer"),i,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",a.appendChild(e),console.warn("[forms]",t.message)})}
|