@duffcloudservices/site-forms 0.1.2 → 0.1.3

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/dist/index.js CHANGED
@@ -1,197 +1,197 @@
1
- import { reactive as X, ref as C, computed as p, defineComponent as I, createElementBlock as f, openBlock as l, normalizeClass as Z, renderSlot as S, createCommentVNode as k, createTextVNode as A, toDisplayString as b, createBlock as w, withCtx as V, createElementVNode as v, Fragment as T, renderList as B, watch as H, onMounted as ee, unref as u, resolveDynamicComponent as te } from "vue";
1
+ import { reactive as X, ref as j, computed as f, defineComponent as S, createElementBlock as h, openBlock as d, normalizeClass as Z, renderSlot as k, createCommentVNode as w, createTextVNode as E, toDisplayString as b, createBlock as L, withCtx as I, createElementVNode as y, Fragment as D, renderList as R, watch as N, onMounted as ee, unref as c, resolveDynamicComponent as te } from "vue";
2
2
  import ie from "ajv";
3
3
  import re from "ajv-formats";
4
- import K from "js-yaml";
5
- function R(e, t) {
4
+ import J from "js-yaml";
5
+ function z(e, t) {
6
6
  return e.visibleIf ? t[e.visibleIf.fieldId] === e.visibleIf.equals : !0;
7
7
  }
8
8
  function ne(e, t) {
9
9
  if (e.type === "section-heading" || e.type === "html-block" || e.type === "hidden")
10
10
  return;
11
- const r = t == null || t === "" || Array.isArray(t) && t.length === 0;
11
+ const i = typeof t == "string" ? t.trim() : t, r = t == null || i === "" || Array.isArray(t) && t.length === 0;
12
12
  if (e.required && r)
13
13
  return `${e.label} is required`;
14
14
  if (r) return;
15
- if (e.type === "email" && typeof t == "string" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t))
15
+ if (e.type === "email" && typeof i == "string" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(i))
16
16
  return `${e.label} must be a valid email address`;
17
- const i = e.validation;
18
- if (i) {
19
- if (typeof t == "string") {
20
- if (i.minLength != null && t.length < i.minLength)
21
- return `${e.label} must be at least ${i.minLength} characters`;
22
- if (i.maxLength != null && t.length > i.maxLength)
23
- return `${e.label} must be at most ${i.maxLength} characters`;
24
- if (i.regex)
17
+ const n = e.validation;
18
+ if (n) {
19
+ if (typeof i == "string") {
20
+ if (n.minLength != null && i.length < n.minLength)
21
+ return `${e.label} must be at least ${n.minLength} characters`;
22
+ if (n.maxLength != null && i.length > n.maxLength)
23
+ return `${e.label} must be at most ${n.maxLength} characters`;
24
+ if (n.regex)
25
25
  try {
26
- if (!new RegExp(i.regex).test(t))
26
+ if (!new RegExp(n.regex).test(i))
27
27
  return `${e.label} is invalid`;
28
28
  } catch {
29
29
  }
30
30
  }
31
31
  if (typeof t == "number") {
32
- if (i.min != null && t < i.min)
33
- return `${e.label} must be at least ${i.min}`;
34
- if (i.max != null && t > i.max)
35
- return `${e.label} must be at most ${i.max}`;
32
+ if (n.min != null && t < n.min)
33
+ return `${e.label} must be at least ${n.min}`;
34
+ if (n.max != null && t > n.max)
35
+ return `${e.label} must be at most ${n.max}`;
36
36
  }
37
- if (e.type === "file" && i.accept && i.accept.length > 0) {
38
- const o = t;
39
- if (o && typeof File < "u" && o instanceof File && !i.accept.some((s) => s.startsWith(".") ? o.name.toLowerCase().endsWith(s.toLowerCase()) : o.type === s))
40
- return `${e.label} must be one of: ${i.accept.join(", ")}`;
37
+ if (e.type === "file" && n.accept && n.accept.length > 0) {
38
+ const l = t;
39
+ if (l && typeof File < "u" && l instanceof File && !n.accept.some((u) => u.startsWith(".") ? l.name.toLowerCase().endsWith(u.toLowerCase()) : l.type === u))
40
+ return `${e.label} must be one of: ${n.accept.join(", ")}`;
41
41
  }
42
42
  }
43
43
  }
44
- function oe(e, t, r) {
45
- const i = {}, o = r ? new Set(r) : null;
46
- for (const d of e.fields) {
47
- if (o && !o.has(d.id) || !R(d, t)) continue;
48
- const s = ne(d, t[d.id]);
49
- s && (i[d.id] = s);
50
- }
51
- return i;
44
+ function oe(e, t, i) {
45
+ const r = {}, n = i ? new Set(i) : null;
46
+ for (const l of e.fields) {
47
+ if (n && !n.has(l.id) || !z(l, t)) continue;
48
+ const s = ne(l, t[l.id]);
49
+ s && (r[l.id] = s);
50
+ }
51
+ return r;
52
52
  }
53
53
  function se(e) {
54
54
  return Object.values(e).some((t) => !!t);
55
55
  }
56
- function _(e) {
56
+ function W(e) {
57
57
  const t = {};
58
- for (const r of e.fields)
59
- r.defaultValue !== void 0 ? t[r.id] = r.defaultValue : r.type === "checkbox" ? t[r.id] = !1 : r.type === "multiselect" || r.type === "checkbox-group" ? t[r.id] = [] : t[r.id] = "";
58
+ for (const i of e.fields)
59
+ i.defaultValue !== void 0 ? t[i.id] = i.defaultValue : i.type === "checkbox" ? t[i.id] = !1 : i.type === "multiselect" || i.type === "checkbox-group" ? t[i.id] = [] : t[i.id] = "";
60
60
  return t;
61
61
  }
62
62
  function ae(e) {
63
- const { definition: t } = e, r = X(_(t)), i = C({}), o = C({}), d = C(!1), s = C(!1), c = C(null), a = C(0), n = p(() => t.fields), m = p(
63
+ const { definition: t } = e, i = X(W(t)), r = j({}), n = j({}), l = j(!1), s = j(!1), u = j(null), a = j(0), o = f(() => t.fields), m = f(
64
64
  () => t.steps && t.steps.length > 0 ? t.steps : null
65
- ), g = p(() => {
66
- const h = m.value;
67
- return h ? h[a.value] ?? null : null;
68
- }), x = p(() => {
69
- const h = g.value;
70
- if (!h) return t.fields;
71
- const F = new Set(h.fieldIds);
72
- return t.fields.filter((E) => F.has(E.id));
73
- }), P = p(() => a.value === 0), O = p(() => {
74
- const h = m.value;
75
- return !h || a.value >= h.length - 1;
76
- }), z = p(
77
- () => x.value.filter((h) => R(h, r))
65
+ ), g = f(() => {
66
+ const p = m.value;
67
+ return p ? p[a.value] ?? null : null;
68
+ }), $ = f(() => {
69
+ const p = g.value;
70
+ if (!p) return t.fields;
71
+ const x = new Set(p.fieldIds);
72
+ return t.fields.filter((A) => x.has(A.id));
73
+ }), C = f(() => a.value === 0), T = f(() => {
74
+ const p = m.value;
75
+ return !p || a.value >= p.length - 1;
76
+ }), K = f(
77
+ () => $.value.filter((p) => z(p, i))
78
78
  );
79
- function y(h, F) {
80
- r[h] = F, i.value[h] && (i.value = { ...i.value, [h]: void 0 });
81
- }
82
- function D(h) {
83
- o.value = { ...o.value, [h]: !0 };
84
- }
85
- function $(h) {
86
- const F = oe(t, r, h);
87
- if (h) {
88
- const E = { ...i.value };
89
- for (const W of h)
90
- E[W] = F[W];
91
- i.value = E;
79
+ function v(p, x) {
80
+ i[p] = x, r.value[p] && (r.value = { ...r.value, [p]: void 0 });
81
+ }
82
+ function V(p) {
83
+ n.value = { ...n.value, [p]: !0 };
84
+ }
85
+ function F(p) {
86
+ const x = oe(t, i, p);
87
+ if (p) {
88
+ const A = { ...r.value };
89
+ for (const B of p)
90
+ A[B] = x[B];
91
+ r.value = A;
92
92
  } else
93
- i.value = F;
94
- return !se(i.value);
93
+ r.value = x;
94
+ return !se(r.value);
95
95
  }
96
- function L() {
97
- const h = g.value?.fieldIds;
98
- return $(h);
96
+ function P() {
97
+ const p = g.value?.fieldIds;
98
+ return F(p);
99
99
  }
100
- function j() {
101
- return $();
100
+ function M() {
101
+ return F();
102
102
  }
103
- function J() {
104
- return !m.value || !L() ? !1 : a.value < m.value.length - 1 ? (a.value++, !0) : !1;
103
+ function _() {
104
+ return !m.value || !P() ? !1 : a.value < m.value.length - 1 ? (a.value++, !0) : !1;
105
105
  }
106
106
  function G() {
107
107
  a.value > 0 && a.value--;
108
108
  }
109
109
  function Y() {
110
- const h = _(t);
111
- for (const F of Object.keys(r))
112
- delete r[F];
113
- Object.assign(r, h), i.value = {}, o.value = {}, d.value = !1, s.value = !1, c.value = null, a.value = 0;
110
+ const p = W(t);
111
+ for (const x of Object.keys(i))
112
+ delete i[x];
113
+ Object.assign(i, p), r.value = {}, n.value = {}, l.value = !1, s.value = !1, u.value = null, a.value = 0;
114
114
  }
115
115
  function Q() {
116
- const h = {};
117
- for (const F of t.fields)
118
- F.type === "section-heading" || F.type === "html-block" || R(F, r) && (h[F.id] = r[F.id]);
119
- return h;
116
+ const p = {};
117
+ for (const x of t.fields)
118
+ x.type === "section-heading" || x.type === "html-block" || z(x, i) && (p[x.id] = i[x.id]);
119
+ return p;
120
120
  }
121
121
  return {
122
- values: r,
123
- errors: i,
124
- touched: o,
125
- submitting: d,
122
+ values: i,
123
+ errors: r,
124
+ touched: n,
125
+ submitting: l,
126
126
  submitted: s,
127
- submitError: c,
128
- fields: n,
127
+ submitError: u,
128
+ fields: o,
129
129
  steps: m,
130
130
  currentStepIndex: a,
131
131
  currentStep: g,
132
- currentStepFields: x,
133
- isFirstStep: P,
134
- isLastStep: O,
135
- visibleFields: z,
136
- setValue: y,
137
- touch: D,
138
- validateCurrentScope: L,
139
- validateAll: j,
140
- next: J,
132
+ currentStepFields: $,
133
+ isFirstStep: C,
134
+ isLastStep: T,
135
+ visibleFields: K,
136
+ setValue: v,
137
+ touch: V,
138
+ validateCurrentScope: P,
139
+ validateAll: M,
140
+ next: _,
141
141
  prev: G,
142
142
  reset: Y,
143
143
  collectSubmissionValues: Q
144
144
  };
145
145
  }
146
146
  async function le(e) {
147
- const { apiBase: t, siteSlug: r, payload: i } = e, o = e.retries ?? 1, d = e.fetchImpl ?? fetch, s = `${t.replace(/\/$/, "")}/public/sites/${encodeURIComponent(
148
- r
149
- )}/form-submissions`, c = Object.values(i.values).some(
147
+ const { apiBase: t, siteSlug: i, payload: r } = e, n = e.retries ?? 1, l = e.fetchImpl ?? fetch, s = `${t.replace(/\/$/, "")}/sites/${encodeURIComponent(
148
+ i
149
+ )}/forms/${encodeURIComponent(r.formId)}/submissions`, u = Object.values(r.values).some(
150
150
  (m) => typeof File < "u" && m instanceof File
151
151
  );
152
- let a, n;
153
- for (let m = 0; m <= o; m++)
152
+ let a, o;
153
+ for (let m = 0; m <= n; m++)
154
154
  try {
155
- const g = c ? { method: "POST", body: de(i) } : {
155
+ const g = u ? { method: "POST", body: de(r) } : {
156
156
  method: "POST",
157
157
  headers: { "Content-Type": "application/json" },
158
- body: JSON.stringify(i)
159
- }, x = await d(s, g);
160
- if (n = x.status, x.ok) {
161
- const P = await ue(x);
162
- return { payload: i, response: P };
158
+ body: JSON.stringify(r)
159
+ }, $ = await l(s, g);
160
+ if (o = $.status, $.ok) {
161
+ const C = await ue($);
162
+ return { payload: r, response: C };
163
163
  }
164
- if (x.status < 500) {
165
- const P = await ce(x);
164
+ if ($.status < 500) {
165
+ const C = await ce($);
166
166
  throw {
167
- payload: i,
168
- status: x.status,
169
- error: new Error(`Submission failed (${x.status}): ${P}`)
167
+ payload: r,
168
+ status: $.status,
169
+ error: new Error(`Submission failed (${$.status}): ${C}`)
170
170
  };
171
171
  }
172
- a = new Error(`Server error ${x.status}`);
172
+ a = new Error(`Server error ${$.status}`);
173
173
  } catch (g) {
174
174
  if (g && typeof g == "object" && "payload" in g && "error" in g)
175
175
  throw g;
176
176
  a = g;
177
177
  }
178
178
  throw {
179
- payload: i,
180
- status: n,
179
+ payload: r,
180
+ status: o,
181
181
  error: a ?? new Error("Submission failed")
182
182
  };
183
183
  }
184
184
  function de(e) {
185
185
  const t = new FormData();
186
186
  t.append("formId", e.formId), e.captchaToken && t.append("captchaToken", e.captchaToken);
187
- for (const [r, i] of Object.entries(e.values))
188
- if (i != null)
189
- if (i instanceof File)
190
- t.append(`values[${r}]`, i);
191
- else if (Array.isArray(i))
192
- for (const o of i) t.append(`values[${r}][]`, String(o));
187
+ for (const [i, r] of Object.entries(e.values))
188
+ if (r != null)
189
+ if (r instanceof File)
190
+ t.append(`values[${i}]`, r);
191
+ else if (Array.isArray(r))
192
+ for (const n of r) t.append(`values[${i}][]`, String(n));
193
193
  else
194
- t.append(`values[${r}]`, String(i));
194
+ t.append(`values[${i}]`, String(r));
195
195
  return t;
196
196
  }
197
197
  async function ue(e) {
@@ -208,73 +208,73 @@ async function ce(e) {
208
208
  return "";
209
209
  }
210
210
  }
211
- const me = "http://json-schema.org/draft-07/schema#", fe = "https://duffcloudservices.com/schemas/form-definition.schema.json", pe = "PortalFormDefinition", he = "object", ve = "Portable form definition. This schema is the source of truth for\nboth the portal CRUD APIs and the `.dcs/forms/<formId>.yaml`\nfiles consumed by customer-site builds via `<DcsForm/>`.\n", be = ["formId", "title", "submission", "fields"], ge = { formId: { type: "string", description: "Kebab-case identifier, unique per site.", pattern: "^[a-z0-9][a-z0-9-]*$", minLength: 1, maxLength: 80, example: "contact" }, title: { type: "string", description: "Human-readable form title shown in the portal and rendered as the form heading.", minLength: 1, maxLength: 200, example: "Contact Us" }, description: { type: "string", description: "Optional descriptive text rendered above the fields.", maxLength: 2e3 }, submitLabel: { type: "string", description: 'Label for the submit button. Defaults to "Send" client-side.', maxLength: 80, example: "Send message" }, successMessage: { type: "string", description: "Confirmation message shown after a successful submission.", maxLength: 2e3, example: "Thanks — we'll be in touch shortly." }, submission: { $ref: "#/definitions/PortalFormSubmissionConfig" }, steps: { type: "array", description: "Optional multi-step grouping. When omitted, fields render as a single page.", items: { $ref: "#/definitions/PortalFormStep" } }, fields: { type: "array", description: "Flat list of all fields in the form. When `steps` is present,\nevery field referenced from a step's `fieldIds` must exist here.\n", items: { $ref: "#/definitions/PortalFormField" } }, version: { type: "integer", minimum: 1, description: "Monotonically increasing version, bumped on each save." }, createdAt: { type: "string", format: "date-time", description: "Form creation timestamp." }, updatedAt: { type: "string", format: "date-time", description: "Last modification timestamp." } }, ye = /* @__PURE__ */ JSON.parse('{"PortalFormFieldType":{"type":"string","description":"Field type controlling input rendering and validation. Includes\\nlayout-only types (`section-heading`, `html-block`) that render\\ndecorative content rather than capturing values, and `hidden`\\nfor prefilled values not displayed to the user.\\n","enum":["text","email","tel","textarea","select","multiselect","radio","checkbox","checkbox-group","date","file","hidden","section-heading","html-block"]},"PortalFormFieldWidth":{"type":"string","description":"Layout hint for the field within its row.","enum":["full","half","third"]},"PortalFormFieldOption":{"type":"object","description":"A single option for select / radio / checkbox-group fields.","required":["value","label"],"properties":{"value":{"type":"string","description":"Submitted value for this option."},"label":{"type":"string","description":"Human-readable label shown to the user."}}},"PortalFormFieldValidation":{"type":"object","description":"Optional validation rules applied to a field\'s value.","properties":{"regex":{"type":"string","description":"ECMAScript-compatible pattern the value must match."},"minLength":{"type":"integer","minimum":0,"description":"Minimum string length (text-like fields only)."},"maxLength":{"type":"integer","minimum":0,"description":"Maximum string length (text-like fields only)."},"min":{"type":"number","description":"Minimum numeric / date value."},"max":{"type":"number","description":"Maximum numeric / date value."},"accept":{"type":"array","description":"Accepted MIME types or file extensions for `file` fields.","items":{"type":"string"}}}},"PortalFormFieldVisibleIf":{"type":"object","description":"Single-predicate visibility rule. The field is shown only when\\nthe referenced sibling field\'s value equals `equals`. Future\\nrevisions may extend this with AND / OR composition; clients\\nshould treat unknown extra properties as opaque.\\n","required":["fieldId","equals"],"properties":{"fieldId":{"type":"string","description":"ID of the sibling field whose value gates visibility."},"equals":{"description":"Value (string, number, or boolean) the sibling field must equal.","oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"PortalFormField":{"type":"object","description":"A single field within a form definition.","required":["id","type","label"],"properties":{"id":{"type":"string","description":"Kebab-case identifier, unique within the form.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"type":{"$ref":"#/definitions/PortalFormFieldType"},"label":{"type":"string","description":"Human-readable label rendered above the input.","minLength":1,"maxLength":200},"helpText":{"type":"string","description":"Optional helper / description text shown beneath the label.","maxLength":500},"placeholder":{"type":"string","description":"Optional placeholder shown inside empty inputs.","maxLength":200},"defaultValue":{"description":"Optional default value (string, number, boolean, or array of strings).","oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"required":{"type":"boolean","default":false,"description":"Whether the field must be supplied to submit the form."},"width":{"allOf":[{"$ref":"#/definitions/PortalFormFieldWidth"}],"default":"full"},"options":{"type":"array","description":"Options for `select`, `multiselect`, `radio`, `checkbox-group` fields.","items":{"$ref":"#/definitions/PortalFormFieldOption"}},"validation":{"$ref":"#/definitions/PortalFormFieldValidation"},"visibleIf":{"$ref":"#/definitions/PortalFormFieldVisibleIf"},"phi":{"type":"boolean","default":false,"description":"Marks the field as collecting Protected Health Information.\\nWhen true the value must never appear in notification emails\\nor logs and the owning site must be in the Medical category\\n(see `compliance.instructions.md`).\\n"},"html":{"type":"string","description":"Sanitized HTML body for `html-block` fields. Ignored for\\nother field types.\\n","maxLength":10000}}},"PortalFormStep":{"type":"object","description":"Optional grouping for multi-step (wizard-style) forms such as\\nthe KT Braun estate-planning questionnaires. When `steps` is\\nomitted on a form, all fields render as a single page.\\n","required":["id","title","fieldIds"],"properties":{"id":{"type":"string","description":"Kebab-case step identifier, unique within the form.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"title":{"type":"string","description":"Step title shown in the wizard header.","minLength":1,"maxLength":200},"description":{"type":"string","description":"Optional descriptive text shown below the step title.","maxLength":1000},"fieldIds":{"type":"array","description":"Ordered list of field IDs that belong to this step.","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}}}},"PortalFormSubmissionLeadConfig":{"type":"object","required":["kind"],"description":"Routes submissions into the existing PortalLeads pipeline.","properties":{"kind":{"type":"string","enum":["lead"]},"category":{"type":"string","description":"Service category id used to route the lead."}}},"PortalFormSubmissionEmailConfig":{"type":"object","required":["kind","to"],"description":"Routes submissions as a notification email to the listed recipients.","properties":{"kind":{"type":"string","enum":["email"]},"to":{"type":"array","minItems":1,"items":{"type":"string","format":"email"},"description":"Recipient email addresses."},"subjectTemplate":{"type":"string","description":"Optional subject-line template. Use `{title}` to interpolate\\nthe form\'s title; values are intentionally not interpolated\\ninto the subject line for compliance reasons.\\n","maxLength":200}}},"PortalFormSubmissionWebhookConfig":{"type":"object","required":["kind","url"],"description":"Posts the submission JSON to a third-party webhook.","properties":{"kind":{"type":"string","enum":["webhook"]},"url":{"type":"string","format":"uri","description":"HTTPS endpoint receiving the signed POST."},"signingSecretRef":{"type":"string","description":"Name of the Key Vault secret used to HMAC-sign the request.\\nThe secret value is never returned in API responses.\\n"}}},"PortalFormSubmissionConfig":{"description":"Discriminated union of submission destinations. Exactly one of\\n`lead`, `email`, or `webhook` shapes is used based on `kind`.\\n","oneOf":[{"$ref":"#/definitions/PortalFormSubmissionLeadConfig"},{"$ref":"#/definitions/PortalFormSubmissionEmailConfig"},{"$ref":"#/definitions/PortalFormSubmissionWebhookConfig"}],"discriminator":{"propertyName":"kind","mapping":{"lead":"#/definitions/PortalFormSubmissionLeadConfig","email":"#/definitions/PortalFormSubmissionEmailConfig","webhook":"#/definitions/PortalFormSubmissionWebhookConfig"}}},"PortalFormSummary":{"type":"object","description":"List-row projection of a form definition.","required":["formId","title","fieldCount"],"properties":{"formId":{"type":"string","description":"Kebab-case identifier.","pattern":"^[a-z0-9][a-z0-9-]*$","example":"contact"},"title":{"type":"string","description":"Human-readable title.","example":"Contact Us"},"description":{"type":"string","description":"Optional descriptive text."},"fieldCount":{"type":"integer","minimum":0,"description":"Number of input-bearing fields in the form.","example":4},"attachedPageSlugs":{"type":"array","description":"Slugs of pages that currently reference this form via `formId`.","items":{"type":"string"}},"submissionKind":{"type":"string","enum":["lead","email","webhook"],"description":"Submission destination kind."},"lastUpdated":{"type":"string","format":"date-time","description":"Last modification timestamp."}}},"PortalCreateFormRequest":{"type":"object","description":"Payload for creating a new form definition.","required":["formId","title","submission","fields"],"properties":{"formId":{"type":"string","description":"Kebab-case identifier, unique per site.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"submitLabel":{"type":"string","maxLength":80},"successMessage":{"type":"string","maxLength":2000},"submission":{"$ref":"#/definitions/PortalFormSubmissionConfig"},"steps":{"type":"array","items":{"$ref":"#/definitions/PortalFormStep"}},"fields":{"type":"array","items":{"$ref":"#/definitions/PortalFormField"}}}},"PortalUpdateFormRequest":{"type":"object","description":"Payload for updating an existing form definition. The `formId`\\nis taken from the URL; supplying it in the body is optional and,\\nif present, must match the path.\\n","properties":{"formId":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80,"description":"Optional echo of the path formId; must match if provided."},"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"submitLabel":{"type":"string","maxLength":80},"successMessage":{"type":"string","maxLength":2000},"submission":{"$ref":"#/definitions/PortalFormSubmissionConfig"},"steps":{"type":"array","items":{"$ref":"#/definitions/PortalFormStep"}},"fields":{"type":"array","items":{"$ref":"#/definitions/PortalFormField"}},"expectedVersion":{"type":"integer","minimum":1,"description":"Optional optimistic-concurrency token. When supplied, the\\nupdate is rejected with 409 if the stored form\'s `version`\\nno longer matches.\\n"}}},"PortalDuplicateFormRequest":{"type":"object","description":"Payload for cloning an existing form under a new formId.","required":["formId"],"properties":{"formId":{"type":"string","description":"Target kebab-case formId for the cloned form.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"title":{"type":"string","description":"Optional title override; defaults to `<source title> (copy)`.","minLength":1,"maxLength":200}}},"PortalFormResponse":{"type":"object","description":"Full form definition response.","required":["form"],"properties":{"form":{"$ref":"#/definitions/PortalFormDefinition"},"attachedPageSlugs":{"type":"array","description":"Slugs of pages that currently reference this form via `formId`.","items":{"type":"string"}}}},"PortalFormListResponse":{"type":"object","required":["forms","totalCount"],"properties":{"forms":{"type":"array","items":{"$ref":"#/definitions/PortalFormSummary"}},"totalCount":{"type":"integer","minimum":0,"description":"Total number of forms matching the query.","example":3}}}}'), $e = {
211
+ const me = "http://json-schema.org/draft-07/schema#", fe = "https://duffcloudservices.com/schemas/form-definition.schema.json", pe = "PortalFormDefinition", he = "object", ye = "Portable form definition. This schema is the source of truth for\nboth the portal CRUD APIs and the `.dcs/forms/<formId>.yaml`\nfiles consumed by customer-site builds via `<DcsForm/>`.\n", be = ["formId", "submission", "fields"], ge = { formId: { type: "string", description: "Kebab-case identifier, unique per site.", pattern: "^[a-z0-9][a-z0-9-]*$", minLength: 1, maxLength: 80, example: "contact" }, formKind: { $ref: "#/definitions/PortalFormKind" }, submitLabel: { type: "string", description: 'Label for the submit button. Defaults to "Send" client-side.', maxLength: 80, example: "Send message" }, successMessage: { type: "string", description: "Confirmation message shown after a successful submission.", maxLength: 2e3, example: "Thanks — we'll be in touch shortly." }, submission: { $ref: "#/definitions/PortalFormSubmissionConfig" }, attachmentPolicy: { $ref: "#/definitions/PortalFormAttachmentPolicy" }, steps: { type: "array", description: "Optional multi-step grouping. When omitted, fields render as a single page.", items: { $ref: "#/definitions/PortalFormStep" } }, fields: { type: "array", description: "Flat list of all fields in the form. When `steps` is present,\nevery field referenced from a step's `fieldIds` must exist here.\n", items: { $ref: "#/definitions/PortalFormField" } }, version: { type: "integer", minimum: 1, description: "Monotonically increasing version, bumped on each save." }, createdAt: { type: "string", format: "date-time", description: "Form creation timestamp." }, updatedAt: { type: "string", format: "date-time", description: "Last modification timestamp." } }, ve = /* @__PURE__ */ JSON.parse('{"PortalFormKind":{"type":"string","description":"High-level form kind used by the visual page editor and submission\\npipeline. `freeform` preserves fully editable questionnaires; the\\nstandard values provide predictable field roles and routing for common\\nsite forms.\\n","enum":["freeform","contact","revenue-contractor","resume-submission"],"default":"freeform"},"PortalFormFieldRole":{"type":"string","description":"Semantic role for a field inside a standard form. Free-form forms may\\nomit roles or use `custom`; standard forms use roles so submissions can\\nbe surfaced consistently as contact messages, notifications, revenue\\ncontractor inquiries, or resume submissions without locking the editor\\nout of label/help-text changes.\\n","enum":["contact-name","contact-email","contact-phone","contact-company","subject","message","summary","image-attachments","resume","consent","custom"]},"PortalFormAttachmentPolicy":{"type":"object","description":"Attachment expectations for standard forms. For\\n`revenue-contractor`, image attachments are expected so contractors can\\ninclude project photos. For `resume-submission`, the resume field\\nshould accept document uploads. Free-form questionnaires can omit this.\\n","properties":{"expected":{"type":"boolean","default":false,"description":"Whether the standard flow should prompt for attachments."},"required":{"type":"boolean","default":false,"description":"Whether at least one attachment is required."},"maxFiles":{"type":"integer","minimum":1,"maximum":20,"description":"Maximum number of files accepted.","example":5},"maxFileSizeBytes":{"type":"integer","minimum":1,"description":"Maximum size per file in bytes.","example":10485760},"accept":{"type":"array","description":"Accepted MIME types or extensions (for example `image/*`).","items":{"type":"string"}}}},"PublicSiteFormContact":{"type":"object","description":"Normalized contact identity supplied with a public form submission.","properties":{"name":{"type":"string","maxLength":160},"email":{"type":"string","format":"email","maxLength":255},"phone":{"type":"string","maxLength":32},"company":{"type":"string","maxLength":160}}},"PublicSiteFormAttachment":{"type":"object","description":"Metadata for an attachment associated with a public form submission.","required":["fileName"],"properties":{"fileName":{"type":"string","maxLength":255},"contentType":{"type":"string","maxLength":120},"sizeBytes":{"type":"integer","minimum":0},"storageUrl":{"type":"string","format":"uri","description":"Internal or pre-uploaded storage URL when the binary was uploaded separately."}}},"PublicSiteFormSubmissionRequest":{"type":"object","description":"JSON request for public managed-form submissions.","required":["values"],"properties":{"formKind":{"$ref":"#/definitions/PortalFormKind"},"pageSlug":{"type":"string","description":"Optional visual-editor page slug where the form was rendered."},"contact":{"$ref":"#/definitions/PublicSiteFormContact"},"subject":{"type":"string","maxLength":200,"description":"Contact subject or inquiry title."},"summary":{"type":"string","maxLength":4000,"description":"Project, request, or applicant summary for standard flows."},"message":{"type":"string","maxLength":4000,"description":"Free-text message supplied by the submitter."},"values":{"type":"object","additionalProperties":true,"description":"Field id to submitted value map for the attached PortalFormDefinition."},"attachments":{"type":"array","description":"Attachment metadata for JSON submissions.","items":{"$ref":"#/definitions/PublicSiteFormAttachment"}},"source":{"type":"string","maxLength":120,"description":"Capture source such as `site-contact-page` or `visual-page-editor`."},"consent":{"type":"boolean","description":"Whether the submitter consented to follow-up."}}},"PublicSiteFormMultipartSubmissionRequest":{"type":"object","description":"Multipart request for public managed-form submissions with binary uploads.","properties":{"formKind":{"$ref":"#/definitions/PortalFormKind"},"pageSlug":{"type":"string"},"values":{"type":"string","description":"JSON-encoded field id to submitted value map."},"name":{"type":"string","maxLength":160},"email":{"type":"string","format":"email","maxLength":255},"phone":{"type":"string","maxLength":32},"company":{"type":"string","maxLength":160},"subject":{"type":"string","maxLength":200},"summary":{"type":"string","maxLength":4000},"message":{"type":"string","maxLength":4000},"attachments":{"type":"array","description":"Image or supporting files for standard form submissions.","items":{"type":"string","format":"binary"}},"resume":{"type":"string","format":"binary","description":"Resume document for `resume-submission` standard forms."},"source":{"type":"string","maxLength":120},"consent":{"type":"boolean"}}},"PublicSiteFormSubmissionResponse":{"type":"object","required":["id","status","submittedAt"],"properties":{"id":{"type":"string","description":"Unique submission identifier."},"status":{"type":"string","enum":["submitted","accepted","queued"]},"submittedAt":{"type":"string","format":"date-time"},"message":{"type":"string","description":"Friendly acknowledgement shown to the submitter."},"contactMessageId":{"type":"string","nullable":true,"description":"Future portal contact-message identifier when surfaced in the portal."},"notificationQueued":{"type":"boolean","description":"Whether a portal notification/contact-message handoff was queued."}}},"PortalFormFieldType":{"type":"string","description":"Field type controlling input rendering and validation. Includes\\nlayout-only types (`section-heading`, `html-block`) that render\\ndecorative content rather than capturing values, and `hidden`\\nfor prefilled values not displayed to the user.\\n","enum":["text","email","tel","textarea","select","multiselect","radio","checkbox","checkbox-group","date","file","hidden","section-heading","html-block"]},"PortalFormFieldWidth":{"type":"string","description":"Layout hint for the field within its row.","enum":["full","half","third"]},"PortalFormFieldOption":{"type":"object","description":"A single option for select / radio / checkbox-group fields.","required":["value","label"],"properties":{"value":{"type":"string","description":"Submitted value for this option."},"label":{"type":"string","description":"Human-readable label shown to the user."}}},"PortalFormFieldValidation":{"type":"object","description":"Optional validation rules applied to a field\'s value.","properties":{"regex":{"type":"string","description":"ECMAScript-compatible pattern the value must match."},"minLength":{"type":"integer","minimum":0,"description":"Minimum string length (text-like fields only)."},"maxLength":{"type":"integer","minimum":0,"description":"Maximum string length (text-like fields only)."},"min":{"type":"number","description":"Minimum numeric / date value."},"max":{"type":"number","description":"Maximum numeric / date value."},"accept":{"type":"array","description":"Accepted MIME types or file extensions for `file` fields.","items":{"type":"string"}}}},"PortalFormFieldVisibleIf":{"type":"object","description":"Single-predicate visibility rule. The field is shown only when\\nthe referenced sibling field\'s value equals `equals`. Future\\nrevisions may extend this with AND / OR composition; clients\\nshould treat unknown extra properties as opaque.\\n","required":["fieldId","equals"],"properties":{"fieldId":{"type":"string","description":"ID of the sibling field whose value gates visibility."},"equals":{"description":"Value (string, number, or boolean) the sibling field must equal.","oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]}}},"PortalFormField":{"type":"object","description":"A single field within a form definition.","required":["id","type","label"],"properties":{"id":{"type":"string","description":"Kebab-case identifier, unique within the form.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"type":{"$ref":"#/definitions/PortalFormFieldType"},"role":{"$ref":"#/definitions/PortalFormFieldRole"},"label":{"type":"string","description":"Human-readable label rendered above the input.","minLength":1,"maxLength":200},"helpText":{"type":"string","description":"Optional helper / description text shown beneath the label.","maxLength":500},"placeholder":{"type":"string","description":"Optional placeholder shown inside empty inputs.","maxLength":200},"defaultValue":{"description":"Optional default value (string, number, boolean, or array of strings).","oneOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string"}}]},"required":{"type":"boolean","default":false,"description":"Whether the field must be supplied to submit the form."},"width":{"allOf":[{"$ref":"#/definitions/PortalFormFieldWidth"}],"default":"full"},"options":{"type":"array","description":"Options for `select`, `multiselect`, `radio`, `checkbox-group` fields.","items":{"$ref":"#/definitions/PortalFormFieldOption"}},"validation":{"$ref":"#/definitions/PortalFormFieldValidation"},"visibleIf":{"$ref":"#/definitions/PortalFormFieldVisibleIf"},"phi":{"type":"boolean","default":false,"description":"Marks the field as collecting Protected Health Information.\\nWhen true the value must never appear in notification emails\\nor logs and the owning site must be in the Medical category\\n(see `compliance.instructions.md`).\\n"},"html":{"type":"string","description":"Sanitized HTML body for `html-block` fields. Ignored for\\nother field types.\\n","maxLength":10000}}},"PortalFormStep":{"type":"object","description":"Optional grouping for multi-step (wizard-style) forms such as\\nthe KT Braun estate-planning questionnaires. When `steps` is\\nomitted on a form, all fields render as a single page.\\n","required":["id","title","fieldIds"],"properties":{"id":{"type":"string","description":"Kebab-case step identifier, unique within the form.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"title":{"type":"string","description":"Step title shown in the wizard header.","minLength":1,"maxLength":200},"description":{"type":"string","description":"Optional descriptive text shown below the step title.","maxLength":1000},"fieldIds":{"type":"array","description":"Ordered list of field IDs that belong to this step.","items":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$"}}}},"PortalFormSubmissionLeadConfig":{"type":"object","required":["kind"],"description":"Routes submissions into the existing PortalLeads pipeline.","properties":{"kind":{"type":"string","enum":["lead"]},"category":{"type":"string","description":"Service category id used to route the lead."}}},"PortalFormSubmissionEmailConfig":{"type":"object","required":["kind","to"],"description":"Routes submissions as a notification email to the listed recipients.","properties":{"kind":{"type":"string","enum":["email"]},"to":{"type":"array","minItems":1,"items":{"type":"string","format":"email"},"description":"Recipient email addresses."},"subjectTemplate":{"type":"string","description":"Optional subject-line template. Submitted values are intentionally\\nnot interpolated into the subject line for compliance reasons.\\n","maxLength":200}}},"PortalFormSubmissionWebhookConfig":{"type":"object","required":["kind","url"],"description":"Posts the submission JSON to a third-party webhook.","properties":{"kind":{"type":"string","enum":["webhook"]},"url":{"type":"string","format":"uri","description":"HTTPS endpoint receiving the signed POST."},"signingSecretRef":{"type":"string","description":"Name of the Key Vault secret used to HMAC-sign the request.\\nThe secret value is never returned in API responses.\\n"}}},"PortalFormSubmissionConfig":{"description":"Discriminated union of submission destinations. Exactly one of\\n`lead`, `email`, or `webhook` shapes is used based on `kind`.\\n","oneOf":[{"$ref":"#/definitions/PortalFormSubmissionLeadConfig"},{"$ref":"#/definitions/PortalFormSubmissionEmailConfig"},{"$ref":"#/definitions/PortalFormSubmissionWebhookConfig"}],"discriminator":{"propertyName":"kind","mapping":{"lead":"#/definitions/PortalFormSubmissionLeadConfig","email":"#/definitions/PortalFormSubmissionEmailConfig","webhook":"#/definitions/PortalFormSubmissionWebhookConfig"}}},"PortalFormSummary":{"type":"object","description":"List-row projection of a form definition.","required":["formId","fieldCount"],"properties":{"formId":{"type":"string","description":"Kebab-case identifier.","pattern":"^[a-z0-9][a-z0-9-]*$","example":"contact"},"formKind":{"$ref":"#/definitions/PortalFormKind"},"fieldCount":{"type":"integer","minimum":0,"description":"Number of input-bearing fields in the form.","example":4},"attachedPageSlugs":{"type":"array","description":"Slugs of pages that currently reference this form via `formId`.","items":{"type":"string"}},"submissionKind":{"type":"string","enum":["lead","email","webhook"],"description":"Submission destination kind."},"lastUpdated":{"type":"string","format":"date-time","description":"Last modification timestamp."}}},"PortalCreateFormRequest":{"type":"object","description":"Payload for creating a new form definition.","required":["formId","submission","fields"],"properties":{"formId":{"type":"string","description":"Kebab-case identifier, unique per site.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80},"formKind":{"$ref":"#/definitions/PortalFormKind"},"submitLabel":{"type":"string","maxLength":80},"successMessage":{"type":"string","maxLength":2000},"submission":{"$ref":"#/definitions/PortalFormSubmissionConfig"},"attachmentPolicy":{"$ref":"#/definitions/PortalFormAttachmentPolicy"},"steps":{"type":"array","items":{"$ref":"#/definitions/PortalFormStep"}},"fields":{"type":"array","items":{"$ref":"#/definitions/PortalFormField"}}}},"PortalUpdateFormRequest":{"type":"object","description":"Payload for updating an existing form definition. The `formId`\\nis taken from the URL; supplying it in the body is optional and,\\nif present, must match the path.\\n","properties":{"formId":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80,"description":"Optional echo of the path formId; must match if provided."},"formKind":{"$ref":"#/definitions/PortalFormKind"},"submitLabel":{"type":"string","maxLength":80},"successMessage":{"type":"string","maxLength":2000},"submission":{"$ref":"#/definitions/PortalFormSubmissionConfig"},"attachmentPolicy":{"$ref":"#/definitions/PortalFormAttachmentPolicy"},"steps":{"type":"array","items":{"$ref":"#/definitions/PortalFormStep"}},"fields":{"type":"array","items":{"$ref":"#/definitions/PortalFormField"}},"expectedVersion":{"type":"integer","minimum":1,"description":"Optional optimistic-concurrency token. When supplied, the\\nupdate is rejected with 409 if the stored form\'s `version`\\nno longer matches.\\n"}}},"PortalDuplicateFormRequest":{"type":"object","description":"Payload for cloning an existing form under a new formId.","required":["formId"],"properties":{"formId":{"type":"string","description":"Target kebab-case formId for the cloned form.","pattern":"^[a-z0-9][a-z0-9-]*$","minLength":1,"maxLength":80}}},"PortalFormResponse":{"type":"object","description":"Full form definition response.","required":["form"],"properties":{"form":{"$ref":"#/definitions/PortalFormDefinition"},"attachedPageSlugs":{"type":"array","description":"Slugs of pages that currently reference this form via `formId`.","items":{"type":"string"}}}},"PortalFormListResponse":{"type":"object","required":["forms","totalCount"],"properties":{"forms":{"type":"array","items":{"$ref":"#/definitions/PortalFormSummary"}},"totalCount":{"type":"integer","minimum":0,"description":"Total number of forms matching the query.","example":3}}},"PortalFormSubmission":{"type":"object","description":"A single recorded submission against a managed form. PHI fields are\\nreplaced with `[REDACTED]` for Medical-category sites, in which case\\n`redactedForPhi` is true.\\n","required":["id","formId","siteSlug","submittedAt","source","values","redactedForPhi"],"properties":{"id":{"type":"string","description":"Unique submission row key (reverse-chronological)."},"formId":{"type":"string"},"siteSlug":{"type":"string"},"formKind":{"$ref":"#/definitions/PortalFormKind"},"submittedAt":{"type":"string","format":"date-time"},"source":{"type":"string","description":"Capture channel (e.g. `web`, `import`)."},"values":{"type":"object","additionalProperties":true,"description":"Field id → submitted value map. PHI values are redacted."},"attachments":{"type":"array","description":"Attachment metadata captured with the submission.","items":{"$ref":"#/definitions/PublicSiteFormAttachment"}},"leadId":{"type":"string","nullable":true,"description":"Cross-reference to the lead row created by the legacy capture flow."},"contactMessageId":{"type":"string","nullable":true,"description":"Future portal contact-message identifier when surfaced in the portal."},"redactedForPhi":{"type":"boolean","description":"True when one or more values were replaced with the PHI placeholder."},"remoteIp":{"type":"string","nullable":true},"userAgent":{"type":"string","nullable":true}}},"PortalFormSubmissionSummary":{"type":"object","description":"List-view representation of a submission.","required":["id","formId","submittedAt","redactedForPhi","summary"],"properties":{"id":{"type":"string"},"formId":{"type":"string"},"formKind":{"$ref":"#/definitions/PortalFormKind"},"submittedAt":{"type":"string","format":"date-time"},"redactedForPhi":{"type":"boolean"},"summary":{"type":"string","description":"Short single-line preview suitable for the portal list view."}}},"PortalFormSubmissionListResponse":{"type":"object","required":["submissions"],"properties":{"submissions":{"type":"array","items":{"$ref":"#/definitions/PortalFormSubmissionSummary"}}}}}'), Fe = {
212
212
  $schema: me,
213
213
  $id: fe,
214
214
  title: pe,
215
215
  type: he,
216
- description: ve,
216
+ description: ye,
217
217
  required: be,
218
218
  properties: ge,
219
- definitions: ye
219
+ definitions: ve
220
220
  };
221
- let M = null;
222
- function Fe() {
223
- if (M) return M;
221
+ let O = null;
222
+ function xe() {
223
+ if (O) return O;
224
224
  const e = new ie({
225
225
  allErrors: !0,
226
226
  strict: !1,
227
227
  discriminator: !1
228
228
  });
229
- return re(e), M = e.compile($e), M;
229
+ return re(e), O = e.compile(Fe), O;
230
230
  }
231
- function ke(e) {
232
- const t = Fe(), r = t(e);
233
- return { valid: r, errors: r ? [] : t.errors ?? [] };
231
+ function $e(e) {
232
+ const t = xe(), i = t(e);
233
+ return { valid: i, errors: i ? [] : t.errors ?? [] };
234
234
  }
235
- function xe(e, t, r) {
236
- const i = ke(t);
237
- return !i.valid && r && console.warn(
235
+ function we(e, t, i) {
236
+ const r = $e(t);
237
+ return !r.valid && i && console.warn(
238
238
  `[@duffcloudservices/site-forms] Form "${e}" failed schema validation:`,
239
- i.errors
240
- ), i;
239
+ r.errors
240
+ ), r;
241
241
  }
242
- function Se(e) {
242
+ function ke(e) {
243
243
  const t = {};
244
- for (const [r, i] of Object.entries(e)) {
245
- const o = Ie(r), d = Le(i);
246
- d && (t[d.formId ?? o] = d);
244
+ for (const [i, r] of Object.entries(e)) {
245
+ const n = Se(i), l = Pe(r);
246
+ l && (t[l.formId ?? n] = l);
247
247
  }
248
248
  return t;
249
249
  }
250
- function Ie(e) {
250
+ function Se(e) {
251
251
  return (e.split("/").pop() ?? e).replace(/\.ya?ml$/i, "");
252
252
  }
253
- function Le(e) {
253
+ function Pe(e) {
254
254
  if (!e) return null;
255
255
  if (typeof e == "string")
256
- return K.load(e);
256
+ return J.load(e);
257
257
  if (typeof e == "object") {
258
258
  const t = e.default;
259
259
  return t && typeof t == "object" ? t : e;
260
260
  }
261
261
  return null;
262
262
  }
263
- function It(e) {
264
- return K.load(e);
263
+ function Pt(e) {
264
+ return J.load(e);
265
265
  }
266
- const Ve = ["data-form-field-key"], we = ["for"], qe = {
266
+ const Ie = ["data-form-field-key"], Le = ["for"], qe = {
267
267
  key: 0,
268
268
  "aria-hidden": "true",
269
269
  class: "dcs-form-field__required"
270
- }, Pe = {
270
+ }, Ce = {
271
271
  key: 0,
272
272
  class: "dcs-form-field__help"
273
- }, De = {
273
+ }, Ve = {
274
274
  key: 0,
275
275
  class: "dcs-form-field__error",
276
276
  role: "alert"
277
- }, q = /* @__PURE__ */ I({
277
+ }, q = /* @__PURE__ */ S({
278
278
  __name: "DcsFormFieldWrapper",
279
279
  props: {
280
280
  field: {},
@@ -282,30 +282,30 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
282
282
  inputId: {}
283
283
  },
284
284
  setup(e) {
285
- return (t, r) => (l(), f("div", {
285
+ return (t, i) => (d(), h("div", {
286
286
  class: Z(["dcs-form-field", [`dcs-form-field--${e.field.type}`, `dcs-form-field--width-${e.field.width ?? "full"}`]]),
287
287
  "data-form-field-key": e.field.id
288
288
  }, [
289
- S(t.$slots, "label", {}, () => [
290
- e.field.type !== "checkbox" && e.field.type !== "hidden" && e.field.type !== "section-heading" && e.field.type !== "html-block" ? (l(), f("label", {
289
+ k(t.$slots, "label", {}, () => [
290
+ e.field.type !== "checkbox" && e.field.type !== "hidden" && e.field.type !== "section-heading" && e.field.type !== "html-block" ? (d(), h("label", {
291
291
  key: 0,
292
292
  for: e.inputId ?? `field-${e.field.id}`,
293
293
  class: "dcs-form-field__label"
294
294
  }, [
295
- A(b(e.field.label) + " ", 1),
296
- e.field.required ? (l(), f("span", qe, "*")) : k("", !0)
297
- ], 8, we)) : k("", !0)
295
+ E(b(e.field.label) + " ", 1),
296
+ e.field.required ? (d(), h("span", qe, "*")) : w("", !0)
297
+ ], 8, Le)) : w("", !0)
298
298
  ]),
299
- S(t.$slots, "default"),
300
- S(t.$slots, "help", {}, () => [
301
- e.field.helpText ? (l(), f("p", Pe, b(e.field.helpText), 1)) : k("", !0)
299
+ k(t.$slots, "default"),
300
+ k(t.$slots, "help", {}, () => [
301
+ e.field.helpText ? (d(), h("p", Ce, b(e.field.helpText), 1)) : w("", !0)
302
302
  ]),
303
- S(t.$slots, "error", {}, () => [
304
- e.error ? (l(), f("p", De, b(e.error), 1)) : k("", !0)
303
+ k(t.$slots, "error", {}, () => [
304
+ e.error ? (d(), h("p", Ve, b(e.error), 1)) : w("", !0)
305
305
  ])
306
- ], 10, Ve));
306
+ ], 10, Ie));
307
307
  }
308
- }), Ce = ["id", "type", "name", "value", "placeholder", "required", "aria-invalid", "aria-describedby"], N = /* @__PURE__ */ I({
308
+ }), je = ["id", "type", "name", "value", "placeholder", "required", "aria-invalid", "aria-describedby"], H = /* @__PURE__ */ S({
309
309
  __name: "DcsFormText",
310
310
  props: {
311
311
  field: {},
@@ -314,8 +314,8 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
314
314
  },
315
315
  emits: ["update:modelValue", "blur"],
316
316
  setup(e, { emit: t }) {
317
- const r = e, i = t, o = p(() => `field-${r.field.id}`), d = p(() => {
318
- switch (r.field.type) {
317
+ const i = e, r = t, n = f(() => `field-${i.field.id}`), l = f(() => {
318
+ switch (i.field.type) {
319
319
  case "email":
320
320
  return "email";
321
321
  case "tel":
@@ -324,37 +324,37 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
324
324
  return "text";
325
325
  }
326
326
  });
327
- return (s, c) => (l(), w(q, {
327
+ return (s, u) => (d(), L(q, {
328
328
  field: e.field,
329
329
  error: e.error,
330
- "input-id": o.value
330
+ "input-id": n.value
331
331
  }, {
332
- default: V(() => [
333
- S(s.$slots, "input", {
334
- id: o.value,
332
+ default: I(() => [
333
+ k(s.$slots, "input", {
334
+ id: n.value,
335
335
  value: e.modelValue,
336
- onInput: (a) => i("update:modelValue", a.target.value),
337
- onBlur: () => i("blur")
336
+ onInput: (a) => r("update:modelValue", a.target.value),
337
+ onBlur: () => r("blur")
338
338
  }, () => [
339
- v("input", {
340
- id: o.value,
339
+ y("input", {
340
+ id: n.value,
341
341
  class: "dcs-form-input",
342
- type: d.value,
342
+ type: l.value,
343
343
  name: e.field.id,
344
344
  value: e.modelValue ?? "",
345
345
  placeholder: e.field.placeholder,
346
346
  required: e.field.required,
347
347
  "aria-invalid": !!e.error,
348
- "aria-describedby": e.error ? `${o.value}-error` : void 0,
349
- onInput: c[0] || (c[0] = (a) => i("update:modelValue", a.target.value)),
350
- onBlur: c[1] || (c[1] = (a) => i("blur"))
351
- }, null, 40, Ce)
348
+ "aria-describedby": e.error ? `${n.value}-error` : void 0,
349
+ onInput: u[0] || (u[0] = (a) => r("update:modelValue", a.target.value)),
350
+ onBlur: u[1] || (u[1] = (a) => r("blur"))
351
+ }, null, 40, je)
352
352
  ])
353
353
  ]),
354
354
  _: 3
355
355
  }, 8, ["field", "error", "input-id"]));
356
356
  }
357
- }), Te = ["id", "name", "placeholder", "required", "aria-invalid", "value"], Oe = /* @__PURE__ */ I({
357
+ }), De = ["id", "name", "placeholder", "required", "aria-invalid", "value"], Te = /* @__PURE__ */ S({
358
358
  __name: "DcsFormTextarea",
359
359
  props: {
360
360
  field: {},
@@ -363,21 +363,21 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
363
363
  },
364
364
  emits: ["update:modelValue", "blur"],
365
365
  setup(e, { emit: t }) {
366
- const r = e, i = t, o = p(() => `field-${r.field.id}`);
367
- return (d, s) => (l(), w(q, {
366
+ const i = e, r = t, n = f(() => `field-${i.field.id}`);
367
+ return (l, s) => (d(), L(q, {
368
368
  field: e.field,
369
369
  error: e.error,
370
- "input-id": o.value
370
+ "input-id": n.value
371
371
  }, {
372
- default: V(() => [
373
- S(d.$slots, "input", {
374
- id: o.value,
372
+ default: I(() => [
373
+ k(l.$slots, "input", {
374
+ id: n.value,
375
375
  value: e.modelValue,
376
- onInput: (c) => i("update:modelValue", c.target.value),
377
- onBlur: () => i("blur")
376
+ onInput: (u) => r("update:modelValue", u.target.value),
377
+ onBlur: () => r("blur")
378
378
  }, () => [
379
- v("textarea", {
380
- id: o.value,
379
+ y("textarea", {
380
+ id: n.value,
381
381
  class: "dcs-form-input dcs-form-textarea",
382
382
  name: e.field.id,
383
383
  placeholder: e.field.placeholder,
@@ -385,19 +385,19 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
385
385
  "aria-invalid": !!e.error,
386
386
  rows: "5",
387
387
  value: e.modelValue ?? "",
388
- onInput: s[0] || (s[0] = (c) => i("update:modelValue", c.target.value)),
389
- onBlur: s[1] || (s[1] = (c) => i("blur"))
390
- }, null, 40, Te)
388
+ onInput: s[0] || (s[0] = (u) => r("update:modelValue", u.target.value)),
389
+ onBlur: s[1] || (s[1] = (u) => r("blur"))
390
+ }, null, 40, De)
391
391
  ])
392
392
  ]),
393
393
  _: 3
394
394
  }, 8, ["field", "error", "input-id"]));
395
395
  }
396
- }), je = ["id", "name", "required", "multiple", "aria-invalid", "value"], Ee = {
396
+ }), Me = ["id", "name", "required", "multiple", "aria-invalid", "value"], Ae = {
397
397
  key: 0,
398
398
  value: "",
399
399
  disabled: ""
400
- }, Me = ["value"], Ae = /* @__PURE__ */ I({
400
+ }, Oe = ["value"], Ee = /* @__PURE__ */ S({
401
401
  __name: "DcsFormSelect",
402
402
  props: {
403
403
  field: {},
@@ -406,51 +406,51 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
406
406
  },
407
407
  emits: ["update:modelValue", "blur"],
408
408
  setup(e, { emit: t }) {
409
- const r = e, i = t, o = p(() => `field-${r.field.id}`), d = p(() => r.field.type === "multiselect"), s = p(() => r.field.options ?? []);
410
- function c(a) {
411
- const n = a.target;
412
- if (d.value) {
409
+ const i = e, r = t, n = f(() => `field-${i.field.id}`), l = f(() => i.field.type === "multiselect"), s = f(() => i.field.options ?? []);
410
+ function u(a) {
411
+ const o = a.target;
412
+ if (l.value) {
413
413
  const m = [];
414
- for (const g of Array.from(n.selectedOptions)) m.push(g.value);
415
- i("update:modelValue", m);
414
+ for (const g of Array.from(o.selectedOptions)) m.push(g.value);
415
+ r("update:modelValue", m);
416
416
  } else
417
- i("update:modelValue", n.value);
417
+ r("update:modelValue", o.value);
418
418
  }
419
- return (a, n) => (l(), w(q, {
419
+ return (a, o) => (d(), L(q, {
420
420
  field: e.field,
421
421
  error: e.error,
422
- "input-id": o.value
422
+ "input-id": n.value
423
423
  }, {
424
- default: V(() => [
425
- S(a.$slots, "input", {
426
- id: o.value,
424
+ default: I(() => [
425
+ k(a.$slots, "input", {
426
+ id: n.value,
427
427
  value: e.modelValue,
428
428
  options: s.value,
429
- onChange: c
429
+ onChange: u
430
430
  }, () => [
431
- v("select", {
432
- id: o.value,
431
+ y("select", {
432
+ id: n.value,
433
433
  class: "dcs-form-input dcs-form-select",
434
434
  name: e.field.id,
435
435
  required: e.field.required,
436
- multiple: d.value,
436
+ multiple: l.value,
437
437
  "aria-invalid": !!e.error,
438
- value: e.modelValue ?? (d.value ? [] : ""),
439
- onChange: c,
440
- onBlur: n[0] || (n[0] = (m) => i("blur"))
438
+ value: e.modelValue ?? (l.value ? [] : ""),
439
+ onChange: u,
440
+ onBlur: o[0] || (o[0] = (m) => r("blur"))
441
441
  }, [
442
- d.value ? k("", !0) : (l(), f("option", Ee, b(e.field.placeholder ?? "Select…"), 1)),
443
- (l(!0), f(T, null, B(s.value, (m) => (l(), f("option", {
442
+ l.value ? w("", !0) : (d(), h("option", Ae, b(e.field.placeholder ?? "Select…"), 1)),
443
+ (d(!0), h(D, null, R(s.value, (m) => (d(), h("option", {
444
444
  key: m.value,
445
445
  value: m.value
446
- }, b(m.label), 9, Me))), 128))
447
- ], 40, je)
446
+ }, b(m.label), 9, Oe))), 128))
447
+ ], 40, Me)
448
448
  ])
449
449
  ]),
450
450
  _: 3
451
451
  }, 8, ["field", "error", "input-id"]));
452
452
  }
453
- }), Be = ["aria-required", "aria-invalid"], ze = { class: "sr-only" }, Re = ["name", "value", "checked", "onChange"], We = /* @__PURE__ */ I({
453
+ }), Re = ["aria-required", "aria-invalid"], Ke = { class: "sr-only" }, ze = ["name", "value", "checked", "onChange"], Be = /* @__PURE__ */ S({
454
454
  __name: "DcsFormRadio",
455
455
  props: {
456
456
  field: {},
@@ -459,39 +459,39 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
459
459
  },
460
460
  emits: ["update:modelValue"],
461
461
  setup(e, { emit: t }) {
462
- const r = e, i = t, o = p(() => `field-${r.field.id}`), d = p(() => r.field.options ?? []);
463
- return (s, c) => (l(), w(q, {
462
+ const i = e, r = t, n = f(() => `field-${i.field.id}`), l = f(() => i.field.options ?? []);
463
+ return (s, u) => (d(), L(q, {
464
464
  field: e.field,
465
465
  error: e.error,
466
- "input-id": o.value
466
+ "input-id": n.value
467
467
  }, {
468
- default: V(() => [
469
- v("fieldset", {
468
+ default: I(() => [
469
+ y("fieldset", {
470
470
  class: "dcs-form-radio-group",
471
471
  role: "radiogroup",
472
472
  "aria-required": e.field.required,
473
473
  "aria-invalid": !!e.error
474
474
  }, [
475
- v("legend", ze, b(e.field.label), 1),
476
- (l(!0), f(T, null, B(d.value, (a) => (l(), f("label", {
475
+ y("legend", Ke, b(e.field.label), 1),
476
+ (d(!0), h(D, null, R(l.value, (a) => (d(), h("label", {
477
477
  key: a.value,
478
478
  class: "dcs-form-radio"
479
479
  }, [
480
- v("input", {
480
+ y("input", {
481
481
  type: "radio",
482
482
  name: e.field.id,
483
483
  value: a.value,
484
484
  checked: e.modelValue === a.value,
485
- onChange: (n) => i("update:modelValue", a.value)
486
- }, null, 40, Re),
487
- v("span", null, b(a.label), 1)
485
+ onChange: (o) => r("update:modelValue", a.value)
486
+ }, null, 40, ze),
487
+ y("span", null, b(a.label), 1)
488
488
  ]))), 128))
489
- ], 8, Be)
489
+ ], 8, Re)
490
490
  ]),
491
491
  _: 1
492
492
  }, 8, ["field", "error", "input-id"]));
493
493
  }
494
- }), He = ["aria-required", "aria-invalid"], _e = { class: "sr-only" }, Ne = ["name", "value", "checked", "onChange"], Ue = /* @__PURE__ */ I({
494
+ }), Ne = ["aria-required", "aria-invalid"], We = { class: "sr-only" }, He = ["name", "value", "checked", "onChange"], Ue = /* @__PURE__ */ S({
495
495
  __name: "DcsFormCheckboxGroup",
496
496
  props: {
497
497
  field: {},
@@ -500,45 +500,45 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
500
500
  },
501
501
  emits: ["update:modelValue"],
502
502
  setup(e, { emit: t }) {
503
- const r = e, i = t, o = p(() => `field-${r.field.id}`), d = p(() => r.field.options ?? []), s = p(() => r.modelValue ?? []);
504
- function c(a, n) {
503
+ const i = e, r = t, n = f(() => `field-${i.field.id}`), l = f(() => i.field.options ?? []), s = f(() => i.modelValue ?? []);
504
+ function u(a, o) {
505
505
  const m = new Set(s.value);
506
- n ? m.add(a) : m.delete(a), i("update:modelValue", Array.from(m));
506
+ o ? m.add(a) : m.delete(a), r("update:modelValue", Array.from(m));
507
507
  }
508
- return (a, n) => (l(), w(q, {
508
+ return (a, o) => (d(), L(q, {
509
509
  field: e.field,
510
510
  error: e.error,
511
- "input-id": o.value
511
+ "input-id": n.value
512
512
  }, {
513
- default: V(() => [
514
- v("fieldset", {
513
+ default: I(() => [
514
+ y("fieldset", {
515
515
  class: "dcs-form-checkbox-group",
516
516
  "aria-required": e.field.required,
517
517
  "aria-invalid": !!e.error
518
518
  }, [
519
- v("legend", _e, b(e.field.label), 1),
520
- (l(!0), f(T, null, B(d.value, (m) => (l(), f("label", {
519
+ y("legend", We, b(e.field.label), 1),
520
+ (d(!0), h(D, null, R(l.value, (m) => (d(), h("label", {
521
521
  key: m.value,
522
522
  class: "dcs-form-checkbox"
523
523
  }, [
524
- v("input", {
524
+ y("input", {
525
525
  type: "checkbox",
526
526
  name: `${e.field.id}[]`,
527
527
  value: m.value,
528
528
  checked: s.value.includes(m.value),
529
- onChange: (g) => c(m.value, g.target.checked)
530
- }, null, 40, Ne),
531
- v("span", null, b(m.label), 1)
529
+ onChange: (g) => u(m.value, g.target.checked)
530
+ }, null, 40, He),
531
+ y("span", null, b(m.label), 1)
532
532
  ]))), 128))
533
- ], 8, He)
533
+ ], 8, Ne)
534
534
  ]),
535
535
  _: 1
536
536
  }, 8, ["field", "error", "input-id"]));
537
537
  }
538
- }), Ke = { class: "sr-only" }, Je = ["for"], Ge = ["id", "name", "checked", "required", "aria-invalid"], Ye = {
538
+ }), Je = { class: "sr-only" }, _e = ["for"], Ge = ["id", "name", "checked", "required", "aria-invalid"], Ye = {
539
539
  key: 0,
540
540
  "aria-hidden": "true"
541
- }, Qe = /* @__PURE__ */ I({
541
+ }, Qe = /* @__PURE__ */ S({
542
542
  __name: "DcsFormCheckbox",
543
543
  props: {
544
544
  field: {},
@@ -547,39 +547,39 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
547
547
  },
548
548
  emits: ["update:modelValue"],
549
549
  setup(e, { emit: t }) {
550
- const r = e, i = t, o = p(() => `field-${r.field.id}`);
551
- return (d, s) => (l(), w(q, {
550
+ const i = e, r = t, n = f(() => `field-${i.field.id}`);
551
+ return (l, s) => (d(), L(q, {
552
552
  field: e.field,
553
553
  error: e.error,
554
- "input-id": o.value
554
+ "input-id": n.value
555
555
  }, {
556
- label: V(() => [
557
- v("span", Ke, b(e.field.label), 1)
556
+ label: I(() => [
557
+ y("span", Je, b(e.field.label), 1)
558
558
  ]),
559
- default: V(() => [
560
- v("label", {
559
+ default: I(() => [
560
+ y("label", {
561
561
  class: "dcs-form-checkbox-single",
562
- for: o.value
562
+ for: n.value
563
563
  }, [
564
- v("input", {
565
- id: o.value,
564
+ y("input", {
565
+ id: n.value,
566
566
  type: "checkbox",
567
567
  name: e.field.id,
568
568
  checked: !!e.modelValue,
569
569
  required: e.field.required,
570
570
  "aria-invalid": !!e.error,
571
- onChange: s[0] || (s[0] = (c) => i("update:modelValue", c.target.checked))
571
+ onChange: s[0] || (s[0] = (u) => r("update:modelValue", u.target.checked))
572
572
  }, null, 40, Ge),
573
- v("span", null, [
574
- A(b(e.field.label), 1),
575
- e.field.required ? (l(), f("span", Ye, " *")) : k("", !0)
573
+ y("span", null, [
574
+ E(b(e.field.label), 1),
575
+ e.field.required ? (d(), h("span", Ye, " *")) : w("", !0)
576
576
  ])
577
- ], 8, Je)
577
+ ], 8, _e)
578
578
  ]),
579
579
  _: 1
580
580
  }, 8, ["field", "error", "input-id"]));
581
581
  }
582
- }), Xe = ["id", "name", "required", "aria-invalid", "value"], Ze = /* @__PURE__ */ I({
582
+ }), Xe = ["id", "name", "required", "aria-invalid", "value"], Ze = /* @__PURE__ */ S({
583
583
  __name: "DcsFormDate",
584
584
  props: {
585
585
  field: {},
@@ -588,29 +588,29 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
588
588
  },
589
589
  emits: ["update:modelValue", "blur"],
590
590
  setup(e, { emit: t }) {
591
- const r = e, i = t, o = p(() => `field-${r.field.id}`);
592
- return (d, s) => (l(), w(q, {
591
+ const i = e, r = t, n = f(() => `field-${i.field.id}`);
592
+ return (l, s) => (d(), L(q, {
593
593
  field: e.field,
594
594
  error: e.error,
595
- "input-id": o.value
595
+ "input-id": n.value
596
596
  }, {
597
- default: V(() => [
598
- v("input", {
599
- id: o.value,
597
+ default: I(() => [
598
+ y("input", {
599
+ id: n.value,
600
600
  class: "dcs-form-input dcs-form-date",
601
601
  type: "date",
602
602
  name: e.field.id,
603
603
  required: e.field.required,
604
604
  "aria-invalid": !!e.error,
605
605
  value: e.modelValue ?? "",
606
- onInput: s[0] || (s[0] = (c) => i("update:modelValue", c.target.value)),
607
- onBlur: s[1] || (s[1] = (c) => i("blur"))
606
+ onInput: s[0] || (s[0] = (u) => r("update:modelValue", u.target.value)),
607
+ onBlur: s[1] || (s[1] = (u) => r("blur"))
608
608
  }, null, 40, Xe)
609
609
  ]),
610
610
  _: 1
611
611
  }, 8, ["field", "error", "input-id"]));
612
612
  }
613
- }), et = ["id", "name", "required", "aria-invalid", "accept"], tt = /* @__PURE__ */ I({
613
+ }), et = ["id", "name", "required", "aria-invalid", "accept"], tt = /* @__PURE__ */ S({
614
614
  __name: "DcsFormFile",
615
615
  props: {
616
616
  field: {},
@@ -619,39 +619,39 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
619
619
  },
620
620
  emits: ["update:modelValue"],
621
621
  setup(e, { emit: t }) {
622
- const r = e, i = t, o = p(() => `field-${r.field.id}`), d = p(() => (r.field.validation?.accept ?? []).join(","));
623
- function s(c) {
624
- const a = c.target;
625
- i("update:modelValue", a.files?.[0]);
622
+ const i = e, r = t, n = f(() => `field-${i.field.id}`), l = f(() => (i.field.validation?.accept ?? []).join(","));
623
+ function s(u) {
624
+ const a = u.target;
625
+ r("update:modelValue", a.files?.[0]);
626
626
  }
627
- return (c, a) => (l(), w(q, {
627
+ return (u, a) => (d(), L(q, {
628
628
  field: e.field,
629
629
  error: e.error,
630
- "input-id": o.value
630
+ "input-id": n.value
631
631
  }, {
632
- default: V(() => [
633
- v("input", {
634
- id: o.value,
632
+ default: I(() => [
633
+ y("input", {
634
+ id: n.value,
635
635
  class: "dcs-form-input dcs-form-file",
636
636
  type: "file",
637
637
  name: e.field.id,
638
638
  required: e.field.required,
639
639
  "aria-invalid": !!e.error,
640
- accept: d.value || void 0,
640
+ accept: l.value || void 0,
641
641
  onChange: s
642
642
  }, null, 40, et)
643
643
  ]),
644
644
  _: 1
645
645
  }, 8, ["field", "error", "input-id"]));
646
646
  }
647
- }), it = ["name", "value", "data-form-field-key"], rt = /* @__PURE__ */ I({
647
+ }), it = ["name", "value", "data-form-field-key"], rt = /* @__PURE__ */ S({
648
648
  __name: "DcsFormHidden",
649
649
  props: {
650
650
  field: {},
651
651
  modelValue: {}
652
652
  },
653
653
  setup(e) {
654
- return (t, r) => (l(), f("input", {
654
+ return (t, i) => (d(), h("input", {
655
655
  type: "hidden",
656
656
  name: e.field.id,
657
657
  value: e.modelValue ?? e.field.defaultValue ?? "",
@@ -661,46 +661,43 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
661
661
  }), nt = ["data-form-field-key"], ot = { class: "dcs-form-section__heading" }, st = {
662
662
  key: 0,
663
663
  class: "dcs-form-section__help"
664
- }, at = /* @__PURE__ */ I({
664
+ }, at = /* @__PURE__ */ S({
665
665
  __name: "DcsFormSection",
666
666
  props: {
667
667
  field: {}
668
668
  },
669
669
  setup(e) {
670
- return (t, r) => (l(), f("div", {
670
+ return (t, i) => (d(), h("div", {
671
671
  class: "dcs-form-section",
672
672
  "data-form-field-key": e.field.id
673
673
  }, [
674
- S(t.$slots, "default", {}, () => [
675
- v("h3", ot, b(e.field.label), 1),
676
- e.field.helpText ? (l(), f("p", st, b(e.field.helpText), 1)) : k("", !0)
674
+ k(t.$slots, "default", {}, () => [
675
+ y("h3", ot, b(e.field.label), 1),
676
+ e.field.helpText ? (d(), h("p", st, b(e.field.helpText), 1)) : w("", !0)
677
677
  ])
678
678
  ], 8, nt));
679
679
  }
680
- }), lt = ["data-form-field-key", "innerHTML"], dt = /* @__PURE__ */ I({
680
+ }), lt = ["data-form-field-key", "innerHTML"], dt = /* @__PURE__ */ S({
681
681
  __name: "DcsFormHtmlBlock",
682
682
  props: {
683
683
  field: {}
684
684
  },
685
685
  setup(e) {
686
- return (t, r) => (l(), f("div", {
686
+ return (t, i) => (d(), h("div", {
687
687
  class: "dcs-form-html-block",
688
688
  "data-form-field-key": e.field.id,
689
689
  innerHTML: e.field.html ?? ""
690
690
  }, null, 8, lt));
691
691
  }
692
- }), U = {}, ut = ["data-form-key"], ct = ["data-form-key"], mt = ["data-form-key"], ft = { class: "dcs-form__header" }, pt = { class: "dcs-form__title" }, ht = {
693
- key: 0,
694
- class: "dcs-form__description"
695
- }, vt = {
692
+ }), U = {}, ut = ["data-form-key"], ct = ["data-form-key"], mt = ["data-form-key"], ft = {
696
693
  key: 0,
697
694
  class: "dcs-form__progress",
698
695
  "aria-live": "polite"
699
- }, bt = { class: "dcs-form__fields" }, gt = {
696
+ }, pt = { class: "dcs-form__fields" }, ht = {
700
697
  key: 1,
701
698
  class: "dcs-form__submit-error",
702
699
  role: "alert"
703
- }, yt = { class: "dcs-form__actions" }, $t = ["disabled"], Lt = /* @__PURE__ */ I({
700
+ }, yt = { class: "dcs-form__actions" }, bt = ["disabled"], It = /* @__PURE__ */ S({
704
701
  __name: "DcsForm",
705
702
  props: {
706
703
  formId: {},
@@ -712,48 +709,47 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
712
709
  },
713
710
  emits: ["submit-success", "submit-error", "validation-error"],
714
711
  setup(e, { emit: t }) {
715
- const r = e, i = t, o = /* @__PURE__ */ Object.assign({}), d = p(
716
- () => Se(r.formsModules ?? o)
717
- ), s = p(() => r.definitionOverride ? r.definitionOverride : d.value[r.formId] ?? null), c = !1;
718
- H(
712
+ const i = e, r = t, n = /* @__PURE__ */ Object.assign({}), l = f(
713
+ () => ke(i.formsModules ?? n)
714
+ ), s = f(() => i.definitionOverride ? i.definitionOverride : l.value[i.formId] ?? null), u = !1;
715
+ N(
719
716
  s,
720
- (y) => {
721
- y && xe(r.formId, y, c);
717
+ (v) => {
718
+ v && we(i.formId, v, u);
722
719
  },
723
720
  { immediate: !0 }
724
721
  );
725
- const a = p(
722
+ const a = f(
726
723
  () => s.value ?? {
727
- formId: r.formId,
728
- title: "",
724
+ formId: i.formId,
729
725
  submission: { kind: "lead" },
730
726
  fields: []
731
727
  }
732
- ), n = ae({ definition: a.value });
733
- H(
728
+ ), o = ae({ definition: a.value });
729
+ N(
734
730
  () => a.value,
735
- () => n.reset()
731
+ () => o.reset()
736
732
  );
737
- const m = p(
738
- () => r.apiBase ?? U?.VITE_DCS_PUBLIC_API ?? ""
739
- ), g = p(
740
- () => r.siteSlug ?? U?.VITE_DCS_SITE_SLUG ?? ""
741
- ), x = p(
733
+ const m = f(
734
+ () => i.apiBase ?? U?.VITE_DCS_PUBLIC_API ?? ""
735
+ ), g = f(
736
+ () => i.siteSlug ?? U?.VITE_DCS_SITE_SLUG ?? ""
737
+ ), $ = f(
742
738
  () => a.value.submitLabel ?? "Send"
743
739
  );
744
- function P(y) {
745
- switch (y.type) {
740
+ function C(v) {
741
+ switch (v.type) {
746
742
  case "text":
747
743
  case "email":
748
744
  case "tel":
749
- return N;
745
+ return H;
750
746
  case "textarea":
751
- return Oe;
747
+ return Te;
752
748
  case "select":
753
749
  case "multiselect":
754
- return Ae;
750
+ return Ee;
755
751
  case "radio":
756
- return We;
752
+ return Be;
757
753
  case "checkbox-group":
758
754
  return Ue;
759
755
  case "checkbox":
@@ -769,129 +765,287 @@ const Ve = ["data-form-field-key"], we = ["for"], qe = {
769
765
  case "html-block":
770
766
  return dt;
771
767
  default:
772
- return N;
768
+ return H;
773
769
  }
774
770
  }
775
- const O = C(null);
776
- async function z(y) {
777
- if (y.preventDefault(), !s.value) return;
778
- if (!n.validateAll()) {
779
- i("validation-error", n.errors.value);
771
+ const T = j(null);
772
+ async function K(v) {
773
+ if (v.preventDefault(), !s.value) return;
774
+ if (!o.validateAll()) {
775
+ r("validation-error", o.errors.value);
780
776
  return;
781
777
  }
782
- n.submitting.value = !0, n.submitError.value = null;
783
- const $ = {
784
- formId: r.formId,
785
- values: n.collectSubmissionValues(),
786
- captchaToken: r.captchaToken
778
+ o.submitting.value = !0, o.submitError.value = null;
779
+ const F = {
780
+ formId: i.formId,
781
+ values: o.collectSubmissionValues(),
782
+ captchaToken: i.captchaToken
787
783
  };
788
784
  try {
789
- const L = await le({
785
+ const P = await le({
790
786
  apiBase: m.value,
791
787
  siteSlug: g.value,
792
- payload: $
788
+ payload: F
793
789
  });
794
- n.submitted.value = !0, i("submit-success", L);
795
- } catch (L) {
796
- const j = L;
797
- n.submitError.value = j.error?.message ?? "Submission failed", i("submit-error", j);
790
+ o.submitted.value = !0, r("submit-success", P);
791
+ } catch (P) {
792
+ const M = P;
793
+ o.submitError.value = M.error?.message ?? "Submission failed", r("submit-error", M);
798
794
  } finally {
799
- n.submitting.value = !1;
795
+ o.submitting.value = !1;
800
796
  }
801
797
  }
802
798
  return ee(() => {
803
799
  s.value || console.warn(
804
- `[@duffcloudservices/site-forms] No form definition found for "${r.formId}". Expected a YAML at .dcs/forms/${r.formId}.yaml. In customer-site repos the YAML lives above the Vite root, so the internal auto-glob will not find it — pass formsModules explicitly: <DcsForm form-id="${r.formId}" :forms-modules="dcsFormsModules" />. See @duffcloudservices/site-forms README "Vite setup" section.`
800
+ `[@duffcloudservices/site-forms] No form definition found for "${i.formId}". Expected a YAML at .dcs/forms/${i.formId}.yaml. In customer-site repos the YAML lives above the Vite root, so the internal auto-glob will not find it — pass formsModules explicitly: <DcsForm form-id="${i.formId}" :forms-modules="dcsFormsModules" />. See @duffcloudservices/site-forms README "Vite setup" section.`
805
801
  );
806
- }), (y, D) => s.value ? u(n).submitted.value ? (l(), f("div", {
802
+ }), (v, V) => s.value ? c(o).submitted.value ? (d(), h("div", {
807
803
  key: 1,
808
804
  class: "dcs-form dcs-form--success",
809
805
  "data-form-key": e.formId
810
806
  }, [
811
- S(y.$slots, "success", { definition: s.value }, () => [
812
- v("p", null, b(s.value.successMessage ?? "Thanks — we received your message."), 1)
807
+ k(v.$slots, "success", { definition: s.value }, () => [
808
+ y("p", null, b(s.value.successMessage ?? "Thanks — we received your message."), 1)
813
809
  ])
814
- ], 8, ct)) : (l(), f("form", {
810
+ ], 8, ct)) : (d(), h("form", {
815
811
  key: 2,
816
812
  ref_key: "formEl",
817
- ref: O,
813
+ ref: T,
818
814
  class: "dcs-form",
819
815
  "data-form-key": e.formId,
820
816
  novalidate: "",
821
- onSubmit: z
817
+ onSubmit: K
822
818
  }, [
823
- S(y.$slots, "header", { definition: s.value }, () => [
824
- v("header", ft, [
825
- v("h2", pt, b(s.value.title), 1),
826
- s.value.description ? (l(), f("p", ht, b(s.value.description), 1)) : k("", !0)
827
- ])
828
- ]),
829
- u(n).steps.value ? (l(), f("div", vt, [
830
- S(y.$slots, "progress", {
831
- current: u(n).currentStepIndex.value,
832
- total: u(n).steps.value.length,
833
- step: u(n).currentStep.value
819
+ k(v.$slots, "header", { definition: s.value }),
820
+ c(o).steps.value ? (d(), h("div", ft, [
821
+ k(v.$slots, "progress", {
822
+ current: c(o).currentStepIndex.value,
823
+ total: c(o).steps.value.length,
824
+ step: c(o).currentStep.value
834
825
  }, () => [
835
- v("p", null, [
836
- A(" Step " + b(u(n).currentStepIndex.value + 1) + " of " + b(u(n).steps.value.length) + " ", 1),
837
- u(n).currentStep.value ? (l(), f(T, { key: 0 }, [
838
- A(" — " + b(u(n).currentStep.value.title), 1)
839
- ], 64)) : k("", !0)
826
+ y("p", null, [
827
+ E(" Step " + b(c(o).currentStepIndex.value + 1) + " of " + b(c(o).steps.value.length) + " ", 1),
828
+ c(o).currentStep.value ? (d(), h(D, { key: 0 }, [
829
+ E(" — " + b(c(o).currentStep.value.title), 1)
830
+ ], 64)) : w("", !0)
840
831
  ])
841
832
  ])
842
- ])) : k("", !0),
843
- v("div", bt, [
844
- (l(!0), f(T, null, B(u(n).visibleFields.value, ($) => (l(), w(te(P($)), {
845
- key: $.id,
846
- field: $,
847
- "model-value": u(n).values[$.id],
848
- error: u(n).errors.value[$.id],
849
- "onUpdate:modelValue": (L) => u(n).setValue($.id, L),
850
- onBlur: (L) => u(n).touch($.id)
833
+ ])) : w("", !0),
834
+ y("div", pt, [
835
+ (d(!0), h(D, null, R(c(o).visibleFields.value, (F) => (d(), L(te(C(F)), {
836
+ key: F.id,
837
+ field: F,
838
+ "model-value": c(o).values[F.id],
839
+ error: c(o).errors.value[F.id],
840
+ "onUpdate:modelValue": (P) => c(o).setValue(F.id, P),
841
+ onBlur: (P) => c(o).touch(F.id)
851
842
  }, null, 40, ["field", "model-value", "error", "onUpdate:modelValue", "onBlur"]))), 128))
852
843
  ]),
853
- u(n).submitError.value ? (l(), f("div", gt, b(u(n).submitError.value), 1)) : k("", !0),
854
- v("div", yt, [
855
- S(y.$slots, "actions", {
856
- isFirstStep: u(n).isFirstStep.value,
857
- isLastStep: u(n).isLastStep.value,
858
- submitting: u(n).submitting.value,
859
- prev: u(n).prev,
860
- next: u(n).next
844
+ c(o).submitError.value ? (d(), h("div", ht, b(c(o).submitError.value), 1)) : w("", !0),
845
+ y("div", yt, [
846
+ k(v.$slots, "actions", {
847
+ isFirstStep: c(o).isFirstStep.value,
848
+ isLastStep: c(o).isLastStep.value,
849
+ submitting: c(o).submitting.value,
850
+ prev: c(o).prev,
851
+ next: c(o).next
861
852
  }, () => [
862
- u(n).steps.value && !u(n).isFirstStep.value ? (l(), f("button", {
853
+ c(o).steps.value && !c(o).isFirstStep.value ? (d(), h("button", {
863
854
  key: 0,
864
855
  type: "button",
865
856
  class: "dcs-form__btn dcs-form__btn--prev",
866
- onClick: D[0] || (D[0] = ($) => u(n).prev())
867
- }, " Previous ")) : k("", !0),
868
- u(n).steps.value && !u(n).isLastStep.value ? (l(), f("button", {
857
+ onClick: V[0] || (V[0] = (F) => c(o).prev())
858
+ }, " Previous ")) : w("", !0),
859
+ c(o).steps.value && !c(o).isLastStep.value ? (d(), h("button", {
869
860
  key: 1,
870
861
  type: "button",
871
862
  class: "dcs-form__btn dcs-form__btn--next",
872
- onClick: D[1] || (D[1] = ($) => u(n).next())
873
- }, " Next ")) : k("", !0),
874
- !u(n).steps.value || u(n).isLastStep.value ? (l(), f("button", {
863
+ onClick: V[1] || (V[1] = (F) => c(o).next())
864
+ }, " Next ")) : w("", !0),
865
+ !c(o).steps.value || c(o).isLastStep.value ? (d(), h("button", {
875
866
  key: 2,
876
867
  type: "submit",
877
868
  class: "dcs-form__btn dcs-form__btn--submit",
878
- disabled: u(n).submitting.value
879
- }, b(u(n).submitting.value ? "Sending…" : x.value), 9, $t)) : k("", !0)
869
+ disabled: c(o).submitting.value
870
+ }, b(c(o).submitting.value ? "Sending…" : $.value), 9, bt)) : w("", !0)
880
871
  ])
881
872
  ])
882
- ], 40, mt)) : (l(), f("div", {
873
+ ], 40, mt)) : (d(), h("div", {
883
874
  key: 0,
884
875
  class: "dcs-form dcs-form--missing",
885
876
  "data-form-key": e.formId
886
877
  }, [
887
- S(y.$slots, "missing", { formId: e.formId }, () => [
888
- v("p", null, "Form “" + b(e.formId) + "” is not configured.", 1)
878
+ k(v.$slots, "missing", { formId: e.formId }, () => [
879
+ y("p", null, "Form “" + b(e.formId) + "” is not configured.", 1)
889
880
  ])
890
881
  ], 8, ut));
891
882
  }
892
- });
883
+ }), Lt = {
884
+ contact: {
885
+ label: "Contact",
886
+ description: "Canonical contact form with standard contact fields."
887
+ },
888
+ "revenue-contractor": {
889
+ label: "Revenue contractor",
890
+ description: "Contact fields plus a required project summary and optional image upload."
891
+ },
892
+ "resume-submission": {
893
+ label: "Resume submission",
894
+ description: "Candidate contact fields plus a required resume upload."
895
+ },
896
+ custom: {
897
+ label: "Custom / free-form",
898
+ description: "Flexible starter that stays fully editable for questionnaires and bespoke intake."
899
+ }
900
+ }, gt = () => [
901
+ { id: "name", type: "text", role: "contact-name", label: "Full name", required: !0, width: "full" },
902
+ { id: "email", type: "email", role: "contact-email", label: "Email", required: !0, width: "half" },
903
+ { id: "phone", type: "tel", role: "contact-phone", label: "Phone", width: "half" },
904
+ { id: "company", type: "text", role: "contact-company", label: "Company", width: "full" },
905
+ {
906
+ id: "message",
907
+ type: "textarea",
908
+ role: "message",
909
+ label: "How can we help?",
910
+ required: !0,
911
+ width: "full",
912
+ validation: { minLength: 10, maxLength: 2e3 }
913
+ }
914
+ ], vt = () => [
915
+ { id: "name", type: "text", role: "contact-name", label: "Full name", required: !0, width: "full" },
916
+ { id: "email", type: "email", role: "contact-email", label: "Email", required: !0, width: "half" },
917
+ { id: "phone", type: "tel", role: "contact-phone", label: "Phone", required: !0, width: "half" },
918
+ { id: "company", type: "text", role: "contact-company", label: "Company", width: "full" },
919
+ {
920
+ id: "message",
921
+ type: "textarea",
922
+ role: "summary",
923
+ label: "Project summary",
924
+ helpText: "Tell us what you want built, repaired, or updated.",
925
+ required: !0,
926
+ width: "full",
927
+ validation: { minLength: 20, maxLength: 4e3 }
928
+ },
929
+ {
930
+ id: "project-image",
931
+ type: "file",
932
+ role: "image-attachments",
933
+ label: "Reference image",
934
+ helpText: "Optional. Upload one photo or inspiration image to help us understand the request.",
935
+ width: "full",
936
+ validation: { accept: ["image/*"] }
937
+ }
938
+ ], Ft = () => [
939
+ { id: "name", type: "text", role: "contact-name", label: "Full name", required: !0, width: "full" },
940
+ { id: "email", type: "email", role: "contact-email", label: "Email", required: !0, width: "half" },
941
+ { id: "phone", type: "tel", role: "contact-phone", label: "Phone", width: "half" },
942
+ { id: "position", type: "text", label: "Role you are applying for", width: "full" },
943
+ {
944
+ id: "message",
945
+ type: "textarea",
946
+ role: "message",
947
+ label: "Anything else we should know?",
948
+ width: "full",
949
+ validation: { maxLength: 2e3 }
950
+ },
951
+ {
952
+ id: "resume",
953
+ type: "file",
954
+ role: "resume",
955
+ label: "Resume",
956
+ required: !0,
957
+ width: "full",
958
+ validation: {
959
+ accept: [
960
+ "application/pdf",
961
+ "application/msword",
962
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
963
+ ]
964
+ }
965
+ }
966
+ ], xt = () => [
967
+ { id: "name", type: "text", label: "Full name", required: !0, width: "full" },
968
+ { id: "email", type: "email", label: "Email", required: !0, width: "half" },
969
+ { id: "phone", type: "tel", label: "Phone", width: "half" },
970
+ {
971
+ id: "message",
972
+ type: "textarea",
973
+ label: "Message",
974
+ required: !0,
975
+ width: "full",
976
+ validation: { minLength: 10, maxLength: 2e3 }
977
+ }
978
+ ];
979
+ function qt(e, t = {}) {
980
+ switch (e ?? "custom") {
981
+ case "contact":
982
+ return {
983
+ formId: t.formId ?? "contact",
984
+ formKind: "contact",
985
+ submitLabel: t.submitLabel ?? "Send",
986
+ successMessage: t.successMessage ?? "Thanks — we’ll be in touch shortly.",
987
+ submission: {
988
+ kind: "lead",
989
+ ...t.leadCategory ? { category: t.leadCategory } : {}
990
+ },
991
+ fields: gt()
992
+ };
993
+ case "revenue-contractor":
994
+ return {
995
+ formId: t.formId ?? "contact",
996
+ formKind: "revenue-contractor",
997
+ submitLabel: t.submitLabel ?? "Request estimate",
998
+ successMessage: t.successMessage ?? "Thanks — we’ll review your project and follow up soon.",
999
+ submission: {
1000
+ kind: "lead",
1001
+ ...t.leadCategory ? { category: t.leadCategory } : {}
1002
+ },
1003
+ attachmentPolicy: {
1004
+ expected: !0,
1005
+ required: !1,
1006
+ maxFiles: 5,
1007
+ accept: ["image/*"]
1008
+ },
1009
+ fields: vt()
1010
+ };
1011
+ case "resume-submission":
1012
+ return {
1013
+ formId: t.formId ?? "resume",
1014
+ formKind: "resume-submission",
1015
+ submitLabel: t.submitLabel ?? "Submit resume",
1016
+ successMessage: t.successMessage ?? "Thanks — your application was received.",
1017
+ submission: {
1018
+ kind: "lead",
1019
+ ...t.leadCategory ? { category: t.leadCategory } : {}
1020
+ },
1021
+ attachmentPolicy: {
1022
+ expected: !0,
1023
+ required: !0,
1024
+ maxFiles: 1,
1025
+ accept: [
1026
+ "application/pdf",
1027
+ "application/msword",
1028
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
1029
+ ]
1030
+ },
1031
+ fields: Ft()
1032
+ };
1033
+ default:
1034
+ return {
1035
+ formId: t.formId ?? "custom-form",
1036
+ formKind: "freeform",
1037
+ submitLabel: t.submitLabel ?? "Send",
1038
+ successMessage: t.successMessage ?? "Thanks — we received your submission.",
1039
+ submission: {
1040
+ kind: "lead",
1041
+ ...t.leadCategory ? { category: t.leadCategory } : {}
1042
+ },
1043
+ fields: xt()
1044
+ };
1045
+ }
1046
+ }
893
1047
  export {
894
- Lt as DcsForm,
1048
+ It as DcsForm,
895
1049
  Qe as DcsFormCheckbox,
896
1050
  Ue as DcsFormCheckboxGroup,
897
1051
  Ze as DcsFormDate,
@@ -899,20 +1053,22 @@ export {
899
1053
  tt as DcsFormFile,
900
1054
  rt as DcsFormHidden,
901
1055
  dt as DcsFormHtmlBlock,
902
- We as DcsFormRadio,
1056
+ Be as DcsFormRadio,
903
1057
  at as DcsFormSection,
904
- Ae as DcsFormSelect,
905
- N as DcsFormText,
906
- Oe as DcsFormTextarea,
1058
+ Ee as DcsFormSelect,
1059
+ H as DcsFormText,
1060
+ Te as DcsFormTextarea,
1061
+ Lt as STANDARD_FORM_PRESET_META,
1062
+ qt as buildStandardFormDefinition,
907
1063
  se as hasErrors,
908
- R as isFieldVisible,
909
- Se as loadFormDefinitions,
910
- It as parseFormYaml,
1064
+ z as isFieldVisible,
1065
+ ke as loadFormDefinitions,
1066
+ Pt as parseFormYaml,
911
1067
  le as submitFormValues,
912
1068
  ae as useDcsForm,
913
1069
  ne as validateField,
914
1070
  oe as validateForm,
915
- ke as validateFormDefinition,
916
- xe as warnIfInvalid
1071
+ $e as validateFormDefinition,
1072
+ we as warnIfInvalid
917
1073
  };
918
1074
  //# sourceMappingURL=index.js.map