@duffcloudservices/site-forms 0.5.0 → 0.7.1

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,8 +1,8 @@
1
- import { ref as A, watch as Q, computed as f, reactive as Se, defineComponent as C, createElementBlock as p, openBlock as m, normalizeClass as ke, renderSlot as V, createCommentVNode as I, createTextVNode as X, toDisplayString as w, createBlock as j, withCtx as D, createElementVNode as v, Fragment as U, renderList as W, onBeforeUnmount as qe, onMounted as Pe, unref as y, resolveDynamicComponent as Le } from "vue";
2
- import Ie from "ajv";
3
- import Te from "ajv-formats";
4
- import fe from "js-yaml";
5
- const oe = "dcs.sound", pe = {
1
+ import { ref as E, watch as ee, computed as m, reactive as Ee, defineComponent as M, createElementBlock as f, openBlock as c, normalizeClass as Oe, renderSlot as V, createCommentVNode as T, createTextVNode as W, toDisplayString as w, createBlock as _, withCtx as j, createElementVNode as v, Fragment as K, renderList as G, onBeforeUnmount as Re, onMounted as pe, unref as g, resolveDynamicComponent as De } from "vue";
2
+ import je from "ajv";
3
+ import _e from "ajv-formats";
4
+ import $e from "js-yaml";
5
+ const ce = "dcs.sound", xe = {
6
6
  enabled: !1,
7
7
  userSet: !1,
8
8
  prmOverride: !1,
@@ -16,173 +16,173 @@ const oe = "dcs.sound", pe = {
16
16
  },
17
17
  hintShown: !1
18
18
  };
19
- function Ve(e) {
20
- const t = typeof e == "number" && Number.isFinite(e) ? e : pe.volume;
19
+ function Be(e) {
20
+ const t = typeof e == "number" && Number.isFinite(e) ? e : xe.volume;
21
21
  return Math.min(0.8, Math.max(0, t));
22
22
  }
23
- function ae(e) {
24
- const t = pe, r = e?.categories ?? {};
23
+ function me(e) {
24
+ const t = xe, n = e?.categories ?? {};
25
25
  return {
26
26
  enabled: typeof e?.enabled == "boolean" ? e.enabled : t.enabled,
27
27
  userSet: typeof e?.userSet == "boolean" ? e.userSet : t.userSet,
28
28
  prmOverride: typeof e?.prmOverride == "boolean" ? e.prmOverride : t.prmOverride,
29
- volume: Ve(e?.volume),
29
+ volume: Be(e?.volume),
30
30
  categories: {
31
- interaction: r.interaction ?? t.categories.interaction,
32
- overlay: r.overlay ?? t.categories.overlay,
33
- navigation: r.navigation ?? t.categories.navigation,
34
- notification: r.notification ?? t.categories.notification,
35
- hero: r.hero ?? t.categories.hero
31
+ interaction: n.interaction ?? t.categories.interaction,
32
+ overlay: n.overlay ?? t.categories.overlay,
33
+ navigation: n.navigation ?? t.categories.navigation,
34
+ notification: n.notification ?? t.categories.notification,
35
+ hero: n.hero ?? t.categories.hero
36
36
  },
37
37
  hintShown: typeof e?.hintShown == "boolean" ? e.hintShown : t.hintShown
38
38
  };
39
39
  }
40
- function Ce() {
40
+ function Ne() {
41
41
  if (typeof window > "u" || !window.localStorage)
42
42
  return null;
43
43
  try {
44
- const e = window.localStorage.getItem(oe);
45
- return e ? ae(JSON.parse(e)) : null;
44
+ const e = window.localStorage.getItem(ce);
45
+ return e ? me(JSON.parse(e)) : null;
46
46
  } catch {
47
47
  return null;
48
48
  }
49
49
  }
50
- const he = Ce(), k = A(he ?? ae(null));
51
- let ye = he !== null;
52
- function Ae(e) {
50
+ const ke = Ne(), I = E(ke ?? me(null));
51
+ let Pe = ke !== null;
52
+ function ze(e) {
53
53
  if (!(typeof window > "u" || !window.localStorage))
54
54
  try {
55
- window.localStorage.setItem(oe, JSON.stringify(e)), ye = !0;
55
+ window.localStorage.setItem(ce, JSON.stringify(e)), Pe = !0;
56
56
  } catch {
57
57
  }
58
58
  }
59
- Q(k, (e) => Ae(e), { deep: !0 });
59
+ ee(I, (e) => ze(e), { deep: !0 });
60
60
  typeof window < "u" && window.addEventListener && window.addEventListener("storage", (e) => {
61
- if (e.key === oe && e.newValue)
61
+ if (e.key === ce && e.newValue)
62
62
  try {
63
- k.value = ae(JSON.parse(e.newValue)), ye = !0;
63
+ I.value = me(JSON.parse(e.newValue)), Pe = !0;
64
64
  } catch {
65
65
  }
66
66
  });
67
- const Z = 0.02, ge = 1e-4;
68
- function $(e, t, r, i) {
69
- const { freq: o, type: a = "sine", dur: u = 0.15, gain: s = 0.2, attack: d = 0.01, glideTo: c } = r, n = e.createOscillator(), h = e.createGain();
70
- n.type = a, n.frequency.setValueAtTime(o, i), c && n.frequency.exponentialRampToValueAtTime(c, i + u), h.gain.setValueAtTime(ge, i), h.gain.exponentialRampToValueAtTime(s, i + d), h.gain.exponentialRampToValueAtTime(1e-3, i + u), n.connect(h).connect(t), n.start(i), n.stop(i + u + Z), n.onended = () => {
67
+ const te = 0.02, qe = 1e-4;
68
+ function k(e, t, n, i) {
69
+ const { freq: o, type: a = "sine", dur: d = 0.15, gain: s = 0.2, attack: l = 0.01, glideTo: u } = n, r = e.createOscillator(), b = e.createGain();
70
+ r.type = a, r.frequency.setValueAtTime(o, i), u && r.frequency.exponentialRampToValueAtTime(u, i + d), b.gain.setValueAtTime(qe, i), b.gain.exponentialRampToValueAtTime(s, i + l), b.gain.exponentialRampToValueAtTime(1e-3, i + d), r.connect(b).connect(t), r.start(i), r.stop(i + d + te), r.onended = () => {
71
71
  try {
72
- n.disconnect(), h.disconnect();
72
+ r.disconnect(), b.disconnect();
73
73
  } catch {
74
74
  }
75
75
  };
76
76
  }
77
- function Me(e, t, r, i) {
78
- const { freq: o, ratio: a = 2, index: u = 120, dur: s = 0.4, gain: d = 0.2 } = r, c = e.createOscillator(), n = e.createOscillator(), h = e.createGain(), x = e.createGain();
79
- c.type = "sine", n.type = "sine", c.frequency.setValueAtTime(o, i), n.frequency.setValueAtTime(o * a, i), h.gain.setValueAtTime(u, i), h.gain.exponentialRampToValueAtTime(1, i + s), x.gain.setValueAtTime(ge, i), x.gain.exponentialRampToValueAtTime(d, i + 0.012), x.gain.exponentialRampToValueAtTime(1e-3, i + s), n.connect(h).connect(c.frequency), c.connect(x).connect(t), n.start(i), c.start(i), n.stop(i + s + Z), c.stop(i + s + Z), c.onended = () => {
77
+ function Ke(e, t, n, i) {
78
+ const { freq: o, ratio: a = 2, index: d = 120, dur: s = 0.4, gain: l = 0.2 } = n, u = e.createOscillator(), r = e.createOscillator(), b = e.createGain(), F = e.createGain();
79
+ u.type = "sine", r.type = "sine", u.frequency.setValueAtTime(o, i), r.frequency.setValueAtTime(o * a, i), b.gain.setValueAtTime(d, i), b.gain.exponentialRampToValueAtTime(1, i + s), F.gain.setValueAtTime(qe, i), F.gain.exponentialRampToValueAtTime(l, i + 0.012), F.gain.exponentialRampToValueAtTime(1e-3, i + s), r.connect(b).connect(u.frequency), u.connect(F).connect(t), r.start(i), u.start(i), r.stop(i + s + te), u.stop(i + s + te), u.onended = () => {
80
80
  try {
81
- c.disconnect(), n.disconnect(), h.disconnect(), x.disconnect();
81
+ u.disconnect(), r.disconnect(), b.disconnect(), F.disconnect();
82
82
  } catch {
83
83
  }
84
84
  };
85
85
  }
86
- function G(e, t, r, i) {
87
- const { dur: o = 0.08, gain: a = 0.2, cutoff: u = 2e3, q: s = 1, sweepTo: d } = r, c = Math.max(1, Math.floor(e.sampleRate * o)), n = e.createBuffer(1, c, e.sampleRate), h = n.getChannelData(0);
88
- for (let q = 0; q < c; q++)
89
- h[q] = Math.random() * 2 - 1;
90
- const x = e.createBufferSource();
91
- x.buffer = n;
86
+ function Q(e, t, n, i) {
87
+ const { dur: o = 0.08, gain: a = 0.2, cutoff: d = 2e3, q: s = 1, sweepTo: l } = n, u = Math.max(1, Math.floor(e.sampleRate * o)), r = e.createBuffer(1, u, e.sampleRate), b = r.getChannelData(0);
88
+ for (let P = 0; P < u; P++)
89
+ b[P] = Math.random() * 2 - 1;
90
+ const F = e.createBufferSource();
91
+ F.buffer = r;
92
92
  const L = e.createBiquadFilter();
93
- L.type = "bandpass", L.frequency.setValueAtTime(u, i), L.Q.value = Math.min(s, 10), d && L.frequency.exponentialRampToValueAtTime(d, i + o);
93
+ L.type = "bandpass", L.frequency.setValueAtTime(d, i), L.Q.value = Math.min(s, 10), l && L.frequency.exponentialRampToValueAtTime(l, i + o);
94
94
  const S = e.createGain();
95
- S.gain.setValueAtTime(a, i), S.gain.exponentialRampToValueAtTime(1e-3, i + o), x.connect(L).connect(S).connect(t), x.start(i), x.stop(i + o + Z), x.onended = () => {
95
+ S.gain.setValueAtTime(a, i), S.gain.exponentialRampToValueAtTime(1e-3, i + o), F.connect(L).connect(S).connect(t), F.start(i), F.stop(i + o + te), F.onended = () => {
96
96
  try {
97
- x.disconnect(), L.disconnect(), S.disconnect();
97
+ F.disconnect(), L.disconnect(), S.disconnect();
98
98
  } catch {
99
99
  }
100
100
  };
101
101
  }
102
- const K = 523.25, le = 587.33, _ = 659.25, J = 783.99, De = 1046.5, je = 392, ee = 440, Oe = 293.66, be = {
102
+ const U = 523.25, he = 587.33, z = 659.25, X = 783.99, Ue = 1046.5, He = 392, oe = 440, We = 293.66, Ie = {
103
103
  // ── interaction ────────────────────────────────────────────────────────
104
104
  "interaction.tap": {
105
105
  category: "interaction",
106
106
  gain: 0.25,
107
107
  duration: 0.06,
108
- render: (e, t, r, i) => G(e, t, { dur: 0.05, gain: i, cutoff: 1800, q: 1 }, r)
108
+ render: (e, t, n, i) => Q(e, t, { dur: 0.05, gain: i, cutoff: 1800, q: 1 }, n)
109
109
  },
110
110
  "interaction.subtle": {
111
111
  category: "interaction",
112
112
  gain: 0.12,
113
113
  duration: 0.04,
114
- render: (e, t, r, i) => G(e, t, { dur: 0.035, gain: i, cutoff: 2400, q: 0.7 }, r)
114
+ render: (e, t, n, i) => Q(e, t, { dur: 0.035, gain: i, cutoff: 2400, q: 0.7 }, n)
115
115
  },
116
116
  "interaction.toggle": {
117
117
  category: "interaction",
118
118
  gain: 0.2,
119
119
  duration: 0.07,
120
- render: (e, t, r, i) => $(e, t, { freq: _, type: "triangle", dur: 0.07, gain: i, attack: 5e-3 }, r)
120
+ render: (e, t, n, i) => k(e, t, { freq: z, type: "triangle", dur: 0.07, gain: i, attack: 5e-3 }, n)
121
121
  },
122
122
  "interaction.confirm": {
123
123
  category: "interaction",
124
124
  gain: 0.3,
125
125
  duration: 0.09,
126
- render: (e, t, r, i) => $(e, t, { freq: K, type: "sine", dur: 0.09, gain: i, attack: 8e-3 }, r)
126
+ render: (e, t, n, i) => k(e, t, { freq: U, type: "sine", dur: 0.09, gain: i, attack: 8e-3 }, n)
127
127
  },
128
128
  // ── overlay ────────────────────────────────────────────────────────────
129
129
  "overlay.open": {
130
130
  category: "overlay",
131
131
  gain: 0.18,
132
132
  duration: 0.18,
133
- render: (e, t, r, i) => G(e, t, { dur: 0.18, gain: i, cutoff: 700, q: 0.8, sweepTo: 2200 }, r)
133
+ render: (e, t, n, i) => Q(e, t, { dur: 0.18, gain: i, cutoff: 700, q: 0.8, sweepTo: 2200 }, n)
134
134
  },
135
135
  "overlay.close": {
136
136
  category: "overlay",
137
137
  gain: 0.18,
138
138
  duration: 0.18,
139
- render: (e, t, r, i) => G(e, t, { dur: 0.18, gain: i, cutoff: 2200, q: 0.8, sweepTo: 600 }, r)
139
+ render: (e, t, n, i) => Q(e, t, { dur: 0.18, gain: i, cutoff: 2200, q: 0.8, sweepTo: 600 }, n)
140
140
  },
141
141
  "overlay.expand": {
142
142
  category: "overlay",
143
143
  gain: 0.16,
144
144
  duration: 0.16,
145
- render: (e, t, r, i) => $(e, t, { freq: K, type: "sine", dur: 0.16, gain: i, glideTo: _ }, r)
145
+ render: (e, t, n, i) => k(e, t, { freq: U, type: "sine", dur: 0.16, gain: i, glideTo: z }, n)
146
146
  },
147
147
  "overlay.collapse": {
148
148
  category: "overlay",
149
149
  gain: 0.16,
150
150
  duration: 0.16,
151
- render: (e, t, r, i) => $(e, t, { freq: _, type: "sine", dur: 0.16, gain: i, glideTo: K }, r)
151
+ render: (e, t, n, i) => k(e, t, { freq: z, type: "sine", dur: 0.16, gain: i, glideTo: U }, n)
152
152
  },
153
153
  // ── navigation ─────────────────────────────────────────────────────────
154
154
  "navigation.forward": {
155
155
  category: "navigation",
156
156
  gain: 0.2,
157
157
  duration: 0.14,
158
- render: (e, t, r, i) => $(e, t, { freq: le, type: "sine", dur: 0.13, gain: i, glideTo: J }, r)
158
+ render: (e, t, n, i) => k(e, t, { freq: he, type: "sine", dur: 0.13, gain: i, glideTo: X }, n)
159
159
  },
160
160
  "navigation.backward": {
161
161
  category: "navigation",
162
162
  gain: 0.2,
163
163
  duration: 0.14,
164
- render: (e, t, r, i) => $(e, t, { freq: J, type: "sine", dur: 0.13, gain: i, glideTo: le }, r)
164
+ render: (e, t, n, i) => k(e, t, { freq: X, type: "sine", dur: 0.13, gain: i, glideTo: he }, n)
165
165
  },
166
166
  "navigation.tab": {
167
167
  category: "navigation",
168
168
  gain: 0.18,
169
169
  duration: 0.1,
170
- render: (e, t, r, i) => $(e, t, { freq: ee, type: "triangle", dur: 0.09, gain: i, attack: 5e-3 }, r)
170
+ render: (e, t, n, i) => k(e, t, { freq: oe, type: "triangle", dur: 0.09, gain: i, attack: 5e-3 }, n)
171
171
  },
172
172
  // ── notification ─────────────────────────────────────────────────────────
173
173
  "notification.info": {
174
174
  category: "notification",
175
175
  gain: 0.15,
176
176
  duration: 0.4,
177
- render: (e, t, r, i) => Me(e, t, { freq: _, ratio: 2, index: 90, dur: 0.42, gain: i }, r)
177
+ render: (e, t, n, i) => Ke(e, t, { freq: z, ratio: 2, index: 90, dur: 0.42, gain: i }, n)
178
178
  },
179
179
  "notification.success": {
180
180
  // Ascending major third (C5 → E5) — unmistakably "up" vs the error contour.
181
181
  category: "notification",
182
182
  gain: 0.2,
183
183
  duration: 0.34,
184
- render: (e, t, r, i) => {
185
- $(e, t, { freq: K, type: "sine", dur: 0.14, gain: i, attack: 8e-3 }, r), $(e, t, { freq: _, type: "sine", dur: 0.2, gain: i, attack: 8e-3 }, r + 0.11);
184
+ render: (e, t, n, i) => {
185
+ k(e, t, { freq: U, type: "sine", dur: 0.14, gain: i, attack: 8e-3 }, n), k(e, t, { freq: z, type: "sine", dur: 0.2, gain: i, attack: 8e-3 }, n + 0.11);
186
186
  }
187
187
  },
188
188
  "notification.warning": {
@@ -190,8 +190,8 @@ const K = 523.25, le = 587.33, _ = 659.25, J = 783.99, De = 1046.5, je = 392, ee
190
190
  category: "notification",
191
191
  gain: 0.24,
192
192
  duration: 0.3,
193
- render: (e, t, r, i) => {
194
- $(e, t, { freq: ee, type: "triangle", dur: 0.1, gain: i, attack: 6e-3 }, r), $(e, t, { freq: ee, type: "triangle", dur: 0.1, gain: i, attack: 6e-3 }, r + 0.16);
193
+ render: (e, t, n, i) => {
194
+ k(e, t, { freq: oe, type: "triangle", dur: 0.1, gain: i, attack: 6e-3 }, n), k(e, t, { freq: oe, type: "triangle", dur: 0.1, gain: i, attack: 6e-3 }, n + 0.16);
195
195
  }
196
196
  },
197
197
  "notification.error": {
@@ -199,8 +199,8 @@ const K = 523.25, le = 587.33, _ = 659.25, J = 783.99, De = 1046.5, je = 392, ee
199
199
  category: "notification",
200
200
  gain: 0.28,
201
201
  duration: 0.42,
202
- render: (e, t, r, i) => {
203
- $(e, t, { freq: je, type: "triangle", dur: 0.16, gain: i, attack: 8e-3 }, r), $(e, t, { freq: Oe, type: "triangle", dur: 0.26, gain: i, attack: 8e-3 }, r + 0.13);
202
+ render: (e, t, n, i) => {
203
+ k(e, t, { freq: He, type: "triangle", dur: 0.16, gain: i, attack: 8e-3 }, n), k(e, t, { freq: We, type: "triangle", dur: 0.26, gain: i, attack: 8e-3 }, n + 0.13);
204
204
  }
205
205
  },
206
206
  // ── hero (disabled by default even when sound is on) ──────────────────────
@@ -208,22 +208,22 @@ const K = 523.25, le = 587.33, _ = 659.25, J = 783.99, De = 1046.5, je = 392, ee
208
208
  category: "hero",
209
209
  gain: 0.4,
210
210
  duration: 0.9,
211
- render: (e, t, r, i) => {
212
- $(e, t, { freq: K, type: "sine", dur: 0.2, gain: i, attack: 0.01 }, r), $(e, t, { freq: _, type: "sine", dur: 0.2, gain: i, attack: 0.01 }, r + 0.16), $(e, t, { freq: J, type: "sine", dur: 0.4, gain: i, attack: 0.01 }, r + 0.32);
211
+ render: (e, t, n, i) => {
212
+ k(e, t, { freq: U, type: "sine", dur: 0.2, gain: i, attack: 0.01 }, n), k(e, t, { freq: z, type: "sine", dur: 0.2, gain: i, attack: 0.01 }, n + 0.16), k(e, t, { freq: X, type: "sine", dur: 0.4, gain: i, attack: 0.01 }, n + 0.32);
213
213
  }
214
214
  },
215
215
  "hero.milestone": {
216
216
  category: "hero",
217
217
  gain: 0.5,
218
218
  duration: 1.3,
219
- render: (e, t, r, i) => {
220
- $(e, t, { freq: K, type: "sine", dur: 0.22, gain: i, attack: 0.01 }, r), $(e, t, { freq: _, type: "sine", dur: 0.22, gain: i, attack: 0.01 }, r + 0.18), $(e, t, { freq: J, type: "sine", dur: 0.22, gain: i, attack: 0.01 }, r + 0.36), $(e, t, { freq: De, type: "sine", dur: 0.55, gain: i, attack: 0.01 }, r + 0.54);
219
+ render: (e, t, n, i) => {
220
+ k(e, t, { freq: U, type: "sine", dur: 0.22, gain: i, attack: 0.01 }, n), k(e, t, { freq: z, type: "sine", dur: 0.22, gain: i, attack: 0.01 }, n + 0.18), k(e, t, { freq: X, type: "sine", dur: 0.22, gain: i, attack: 0.01 }, n + 0.36), k(e, t, { freq: Ue, type: "sine", dur: 0.55, gain: i, attack: 0.01 }, n + 0.54);
221
221
  }
222
222
  }
223
- }, Re = 120;
224
- let R = null, N = null, de = !1, ve = !1;
225
- const Fe = /* @__PURE__ */ new Map(), ie = /* @__PURE__ */ new Set();
226
- function Ee() {
223
+ }, Ge = 120;
224
+ let B = null, H = null, ye = !1, Le = !1;
225
+ const Te = /* @__PURE__ */ new Map(), se = /* @__PURE__ */ new Set();
226
+ function Je() {
227
227
  if (typeof window > "u")
228
228
  return !0;
229
229
  try {
@@ -238,132 +238,132 @@ function Ee() {
238
238
  return !0;
239
239
  }
240
240
  }
241
- function we() {
241
+ function Ce() {
242
242
  return typeof window > "u" || !window.matchMedia ? !1 : window.matchMedia("(prefers-reduced-motion: reduce)").matches;
243
243
  }
244
- function xe() {
244
+ function Ae() {
245
245
  if (typeof window > "u")
246
246
  return null;
247
- if (R)
248
- return R;
247
+ if (B)
248
+ return B;
249
249
  const e = window.AudioContext ?? window.webkitAudioContext;
250
250
  if (!e)
251
251
  return null;
252
252
  try {
253
- R = new e(), N = R.createGain(), N.gain.value = 1, N.connect(R.destination);
253
+ B = new e(), H = B.createGain(), H.gain.value = 1, H.connect(B.destination);
254
254
  } catch {
255
- R = null, N = null;
255
+ B = null, H = null;
256
256
  }
257
- return R;
257
+ return B;
258
258
  }
259
- function Be() {
260
- if (de || typeof window > "u")
259
+ function Ye() {
260
+ if (ye || typeof window > "u")
261
261
  return;
262
- de = !0;
262
+ ye = !0;
263
263
  const e = ["pointerdown", "keydown", "touchstart"], t = () => {
264
- ve = !0;
265
- const r = xe();
266
- r && r.state === "suspended" && r.resume().catch(() => {
267
- }), r && r.state !== "suspended" && e.forEach((i) => window.removeEventListener(i, t));
264
+ Le = !0;
265
+ const n = Ae();
266
+ n && n.state === "suspended" && n.resume().catch(() => {
267
+ }), n && n.state !== "suspended" && e.forEach((i) => window.removeEventListener(i, t));
268
268
  };
269
- e.forEach((r) => window.addEventListener(r, t, { passive: !0 }));
269
+ e.forEach((n) => window.addEventListener(n, t, { passive: !0 }));
270
270
  }
271
- function _e(e) {
272
- return ie.add(e), () => ie.delete(e);
271
+ function Qe(e) {
272
+ return se.add(e), () => se.delete(e);
273
273
  }
274
- function ze(e, t) {
274
+ function Xe(e, t) {
275
275
  if (typeof document > "u")
276
276
  return !1;
277
- const r = be[e];
278
- if (!r || Ee())
277
+ const n = Ie[e];
278
+ if (!n || Je())
279
279
  return !1;
280
- const i = k.value;
281
- if (!i.enabled || we() && !i.prmOverride)
280
+ const i = I.value;
281
+ if (!i.enabled || Ce() && !i.prmOverride)
282
282
  return !1;
283
- const o = r.category;
283
+ const o = n.category;
284
284
  if (!i.categories[o] || document.hidden && o !== "notification")
285
285
  return !1;
286
286
  if (!t?.force) {
287
- const a = Fe.get(e) ?? 0;
288
- if (performance.now() - a < Re)
287
+ const a = Te.get(e) ?? 0;
288
+ if (performance.now() - a < Ge)
289
289
  return !1;
290
290
  }
291
291
  return !0;
292
292
  }
293
- function Ke(e, t) {
294
- if (!ze(e, t) || !R && !ve)
293
+ function Ze(e, t) {
294
+ if (!Xe(e, t) || !B && !Le)
295
295
  return !1;
296
- const r = xe();
297
- if (!r || !N)
296
+ const n = Ae();
297
+ if (!n || !H)
298
298
  return !1;
299
- if (r.state === "suspended")
300
- return r.resume().catch(() => {
299
+ if (n.state === "suspended")
300
+ return n.resume().catch(() => {
301
301
  }), !1;
302
- const i = be[e];
303
- Fe.set(e, performance.now());
304
- const o = r.currentTime, a = Math.min(0.8, i.gain * k.value.volume);
302
+ const i = Ie[e];
303
+ Te.set(e, performance.now());
304
+ const o = n.currentTime, a = Math.min(0.8, i.gain * I.value.volume);
305
305
  try {
306
- i.render(r, N, o, a);
306
+ i.render(n, H, o, a);
307
307
  } catch {
308
308
  return !1;
309
309
  }
310
- return ie.forEach((u) => {
310
+ return se.forEach((d) => {
311
311
  try {
312
- u();
312
+ d();
313
313
  } catch {
314
314
  }
315
315
  }), !0;
316
316
  }
317
- const re = A(!1);
317
+ const le = E(!1);
318
318
  if (typeof window < "u" && typeof window.matchMedia == "function")
319
319
  try {
320
320
  const e = window.matchMedia("(prefers-reduced-motion: reduce)");
321
- re.value = e.matches, e.addEventListener?.("change", (t) => {
322
- re.value = t.matches;
321
+ le.value = e.matches, e.addEventListener?.("change", (t) => {
322
+ le.value = t.matches;
323
323
  });
324
324
  } catch {
325
325
  }
326
- function te(e) {
327
- k.value.enabled = e, k.value.userSet = !0, e ? we() && (k.value.prmOverride = !0) : k.value.prmOverride = !1;
326
+ function ae(e) {
327
+ I.value.enabled = e, I.value.userSet = !0, e ? Ce() && (I.value.prmOverride = !0) : I.value.prmOverride = !1;
328
328
  }
329
- function Ne() {
330
- Be();
331
- const e = f({
332
- get: () => k.value.enabled,
333
- set: (o) => te(o)
334
- }), t = f({
335
- get: () => k.value.volume,
329
+ function et() {
330
+ Ye();
331
+ const e = m({
332
+ get: () => I.value.enabled,
333
+ set: (o) => ae(o)
334
+ }), t = m({
335
+ get: () => I.value.volume,
336
336
  set: (o) => {
337
- k.value.volume = Math.min(0.8, Math.max(0, o));
337
+ I.value.volume = Math.min(0.8, Math.max(0, o));
338
338
  }
339
- }), r = f(() => k.value.hintShown), i = f(
340
- () => re.value && !k.value.prmOverride
339
+ }), n = m(() => I.value.hintShown), i = m(
340
+ () => le.value && !I.value.prmOverride
341
341
  );
342
342
  return {
343
- play: Ke,
343
+ play: Ze,
344
344
  enabled: e,
345
345
  volume: t,
346
- hintShown: r,
346
+ hintShown: n,
347
347
  mutedByReducedMotion: i,
348
- toggleMute: () => te(!k.value.enabled),
349
- setEnabled: (o) => te(o),
348
+ toggleMute: () => ae(!I.value.enabled),
349
+ setEnabled: (o) => ae(o),
350
350
  setVolume: (o) => {
351
- k.value.volume = Math.min(0.8, Math.max(0, o));
351
+ I.value.volume = Math.min(0.8, Math.max(0, o));
352
352
  },
353
- isCategoryEnabled: (o) => k.value.categories[o],
353
+ isCategoryEnabled: (o) => I.value.categories[o],
354
354
  setCategory: (o, a) => {
355
- k.value.categories[o] = a, k.value.userSet = !0;
355
+ I.value.categories[o] = a, I.value.userSet = !0;
356
356
  },
357
357
  markHintShown: () => {
358
- k.value.hintShown = !0;
358
+ I.value.hintShown = !0;
359
359
  },
360
- onDidPlay: _e
360
+ onDidPlay: Qe
361
361
  };
362
362
  }
363
- function ne(e, t) {
363
+ function de(e, t) {
364
364
  return e.visibleIf ? t[e.visibleIf.fieldId] === e.visibleIf.equals : !0;
365
365
  }
366
- function Ue(e, t, r) {
366
+ function tt(e, t, n) {
367
367
  if (e.type === "section-heading" || e.type === "html-block" || e.type === "hidden")
368
368
  return;
369
369
  const i = typeof t == "string" ? t.trim() : t, o = t == null || i === "" || Array.isArray(t) && t.length === 0;
@@ -392,270 +392,399 @@ function Ue(e, t, r) {
392
392
  return `${e.label} must be at most ${a.max}`;
393
393
  }
394
394
  if (e.type === "file") {
395
- const u = Ge(t), s = r?.maxFiles, d = r?.maxFileSizeBytes, c = a.accept && a.accept.length > 0 ? a.accept : r?.accept;
396
- if (s != null && u.length > s)
395
+ const d = rt(t), s = n?.maxFiles, l = n?.maxFileSizeBytes, u = a.accept && a.accept.length > 0 ? a.accept : n?.accept;
396
+ if (s != null && d.length > s)
397
397
  return `${e.label} accepts up to ${s} file${s === 1 ? "" : "s"}`;
398
- if (d != null) {
399
- const n = u.find((h) => h.size > d);
400
- if (n)
401
- return `${n.name} exceeds the ${Ye(d)} limit`;
398
+ if (l != null) {
399
+ const r = d.find((b) => b.size > l);
400
+ if (r)
401
+ return `${r.name} exceeds the ${at(l)} limit`;
402
402
  }
403
- if (c && c.length > 0) {
404
- const n = u.find((h) => !Je(h, c));
405
- if (n)
406
- return `${n.name} must be one of: ${c.join(", ")}`;
403
+ if (u && u.length > 0) {
404
+ const r = d.find((b) => !ot(b, u));
405
+ if (r)
406
+ return `${r.name} must be one of: ${u.join(", ")}`;
407
407
  }
408
408
  }
409
409
  }
410
- function We(e, t, r) {
411
- const i = {}, o = r ? new Set(r) : null;
410
+ function it(e, t, n) {
411
+ const i = {}, o = n ? new Set(n) : null;
412
412
  for (const a of e.fields) {
413
- if (o && !o.has(a.id) || !ne(a, t)) continue;
414
- const u = Ue(a, t[a.id], e.attachmentPolicy);
415
- u && (i[a.id] = u);
413
+ if (o && !o.has(a.id) || !de(a, t)) continue;
414
+ const d = tt(a, t[a.id], e.attachmentPolicy);
415
+ d && (i[a.id] = d);
416
416
  }
417
417
  return i;
418
418
  }
419
- function He(e) {
419
+ function nt(e) {
420
420
  return Object.values(e).some((t) => !!t);
421
421
  }
422
- function Ge(e) {
422
+ function rt(e) {
423
423
  return typeof File > "u" ? [] : e instanceof File ? [e] : Array.isArray(e) ? e.filter((t) => t instanceof File) : [];
424
424
  }
425
- function Je(e, t) {
426
- const r = e.name.toLowerCase(), i = e.type.toLowerCase();
425
+ function ot(e, t) {
426
+ const n = e.name.toLowerCase(), i = e.type.toLowerCase();
427
427
  return t.some((o) => {
428
428
  const a = o.trim().toLowerCase();
429
- return a === "" ? !1 : a.startsWith(".") ? r.endsWith(a) : a.endsWith("/*") ? i.startsWith(a.slice(0, -1)) : i === a;
429
+ return a === "" ? !1 : a.startsWith(".") ? n.endsWith(a) : a.endsWith("/*") ? i.startsWith(a.slice(0, -1)) : i === a;
430
430
  });
431
431
  }
432
- function Ye(e) {
432
+ function at(e) {
433
433
  return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${Math.round(e / 1024)} KB` : `${Math.round(e / (1024 * 1024))} MB`;
434
434
  }
435
- function ue(e) {
435
+ function ge(e) {
436
436
  const t = {};
437
- for (const r of e.fields)
438
- 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] = "";
437
+ for (const n of e.fields)
438
+ n.defaultValue !== void 0 ? t[n.id] = n.defaultValue : n.type === "checkbox" ? t[n.id] = !1 : n.type === "multiselect" || n.type === "checkbox-group" ? t[n.id] = [] : t[n.id] = "";
439
439
  return t;
440
440
  }
441
- function Qe(e) {
442
- const { definition: t } = e, r = Se(ue(t)), i = A({}), o = A({}), a = A(!1), u = A(!1), s = A(null), d = A(0), c = f(() => t.fields), n = f(
441
+ function st(e) {
442
+ const { definition: t } = e, n = Ee(ge(t)), i = E({}), o = E({}), a = E(!1), d = E(!1), s = E(null), l = E(0), u = m(() => t.fields), r = m(
443
443
  () => t.steps && t.steps.length > 0 ? t.steps : null
444
- ), h = f(() => {
445
- const b = n.value;
446
- return b ? b[d.value] ?? null : null;
447
- }), x = f(() => {
448
- const b = h.value;
449
- if (!b) return t.fields;
450
- const T = new Set(b.fieldIds);
451
- return t.fields.filter((H) => T.has(H.id));
452
- }), L = f(() => d.value === 0), S = f(() => {
453
- const b = n.value;
454
- return !b || d.value >= b.length - 1;
455
- }), q = f(
456
- () => x.value.filter((b) => ne(b, r))
444
+ ), b = m(() => {
445
+ const y = r.value;
446
+ return y ? y[l.value] ?? null : null;
447
+ }), F = m(() => {
448
+ const y = b.value;
449
+ if (!y) return t.fields;
450
+ const x = new Set(y.fieldIds);
451
+ return t.fields.filter((Y) => x.has(Y.id));
452
+ }), L = m(() => l.value === 0), S = m(() => {
453
+ const y = r.value;
454
+ return !y || l.value >= y.length - 1;
455
+ }), P = m(
456
+ () => F.value.filter((y) => de(y, n))
457
457
  );
458
- function M(b, T) {
459
- r[b] = T, i.value[b] && (i.value = { ...i.value, [b]: void 0 });
458
+ function O(y, x) {
459
+ n[y] = x, i.value[y] && (i.value = { ...i.value, [y]: void 0 });
460
460
  }
461
- function z(b) {
462
- o.value = { ...o.value, [b]: !0 };
461
+ function R(y) {
462
+ o.value = { ...o.value, [y]: !0 };
463
463
  }
464
- function B(b) {
465
- const T = We(t, r, b);
466
- if (b) {
467
- const H = { ...i.value };
468
- for (const se of b)
469
- H[se] = T[se];
470
- i.value = H;
464
+ function D(y) {
465
+ const x = it(t, n, y);
466
+ if (y) {
467
+ const Y = { ...i.value };
468
+ for (const fe of y)
469
+ Y[fe] = x[fe];
470
+ i.value = Y;
471
471
  } else
472
- i.value = T;
473
- return !He(i.value);
472
+ i.value = x;
473
+ return !nt(i.value);
474
474
  }
475
- function l() {
476
- const b = h.value?.fieldIds;
477
- return B(b);
475
+ function p() {
476
+ const y = b.value?.fieldIds;
477
+ return D(y);
478
478
  }
479
- function F() {
480
- return B();
479
+ function $() {
480
+ return D();
481
481
  }
482
- function g() {
483
- return !n.value || !l() ? !1 : d.value < n.value.length - 1 ? (d.value++, !0) : !1;
482
+ function q() {
483
+ return !r.value || !p() ? !1 : l.value < r.value.length - 1 ? (l.value++, !0) : !1;
484
484
  }
485
- function P() {
486
- d.value > 0 && d.value--;
485
+ function h() {
486
+ l.value > 0 && l.value--;
487
487
  }
488
- function O() {
489
- const b = ue(t);
490
- for (const T of Object.keys(r))
491
- delete r[T];
492
- Object.assign(r, b), i.value = {}, o.value = {}, a.value = !1, u.value = !1, s.value = null, d.value = 0;
488
+ function C() {
489
+ const y = ge(t);
490
+ for (const x of Object.keys(n))
491
+ delete n[x];
492
+ Object.assign(n, y), i.value = {}, o.value = {}, a.value = !1, d.value = !1, s.value = null, l.value = 0;
493
493
  }
494
- function $e() {
495
- const b = {};
496
- for (const T of t.fields)
497
- T.type === "section-heading" || T.type === "html-block" || ne(T, r) && (b[T.id] = r[T.id]);
498
- return b;
494
+ function A() {
495
+ const y = {};
496
+ for (const x of t.fields)
497
+ x.type === "section-heading" || x.type === "html-block" || de(x, n) && (y[x.id] = n[x.id]);
498
+ return y;
499
499
  }
500
500
  return {
501
- values: r,
501
+ values: n,
502
502
  errors: i,
503
503
  touched: o,
504
504
  submitting: a,
505
- submitted: u,
505
+ submitted: d,
506
506
  submitError: s,
507
- fields: c,
508
- steps: n,
509
- currentStepIndex: d,
510
- currentStep: h,
511
- currentStepFields: x,
507
+ fields: u,
508
+ steps: r,
509
+ currentStepIndex: l,
510
+ currentStep: b,
511
+ currentStepFields: F,
512
512
  isFirstStep: L,
513
513
  isLastStep: S,
514
- visibleFields: q,
515
- setValue: M,
516
- touch: z,
517
- validateCurrentScope: l,
518
- validateAll: F,
519
- next: g,
520
- prev: P,
521
- reset: O,
522
- collectSubmissionValues: $e
514
+ visibleFields: P,
515
+ setValue: O,
516
+ touch: R,
517
+ validateCurrentScope: p,
518
+ validateAll: $,
519
+ next: q,
520
+ prev: h,
521
+ reset: C,
522
+ collectSubmissionValues: A
523
523
  };
524
524
  }
525
- async function Xe(e) {
526
- const { apiBase: t, siteSlug: r, payload: i } = e, o = e.retries ?? 1, a = e.fetchImpl ?? fetch, u = t.replace(/\/$/, ""), s = `forms/${encodeURIComponent(i.formId)}/submissions`, d = r.trim(), c = d ? `${u}/sites/${encodeURIComponent(d)}/${s}` : `${u}/${s}`, n = Object.values(i.values).some(et);
527
- let h, x;
525
+ async function lt(e, t = Ve) {
526
+ if (typeof e.text != "function")
527
+ try {
528
+ return await e.json();
529
+ } catch {
530
+ return null;
531
+ }
532
+ const n = ft(e);
533
+ let i;
534
+ try {
535
+ i = (await e.text()).trim();
536
+ } catch (o) {
537
+ throw ht(t, e.status, o);
538
+ }
539
+ if (i === "")
540
+ throw yt(t, e.status);
541
+ if (n && !n.includes("json"))
542
+ throw be(t, e.status, n, i);
543
+ try {
544
+ return JSON.parse(i);
545
+ } catch {
546
+ throw be(t, e.status, n, i);
547
+ }
548
+ }
549
+ async function dt(e, t, n = {}) {
550
+ const i = n.label ?? Ve, o = await lt(e, i);
551
+ if (t(o)) return o;
552
+ throw gt(i, e.status, n.receiptName ?? "submission", o);
553
+ }
554
+ const ut = ["submitted", "accepted", "queued"];
555
+ function ct(e) {
556
+ return J(e) && ne(e.id) && Me(e.status, ut) && pt(e.submittedAt);
557
+ }
558
+ const mt = ["submitted", "processing", "responded"];
559
+ function Wi(e) {
560
+ return J(e) && ne(e.id) && Me(e.status, mt);
561
+ }
562
+ function Gi(e) {
563
+ return J(e) && ne(e.id);
564
+ }
565
+ function Ji(e) {
566
+ return J(e) && e.success === !0;
567
+ }
568
+ function Yi(e) {
569
+ return J(e) && e.success === !0;
570
+ }
571
+ const Ve = "[@duffcloudservices/site-forms]", ie = "We could not confirm your message was received. Please try again, or contact us directly.";
572
+ function ft(e) {
573
+ return typeof e.headers?.get != "function" ? "" : (e.headers.get("content-type") ?? "").toLowerCase();
574
+ }
575
+ function J(e) {
576
+ return typeof e == "object" && e !== null && !Array.isArray(e);
577
+ }
578
+ function ne(e) {
579
+ return typeof e == "string" && e.trim().length > 0;
580
+ }
581
+ function Me(e, t) {
582
+ return typeof e == "string" && t.includes(e);
583
+ }
584
+ function pt(e) {
585
+ return ne(e) && Number.isFinite(Date.parse(e));
586
+ }
587
+ function re(e, t) {
588
+ const n = new Error(e);
589
+ return n.receiptRejected = t, n;
590
+ }
591
+ function ht(e, t, n) {
592
+ const i = n instanceof Error ? n.message : String(n);
593
+ return console.error(
594
+ `${e} Submission could not be confirmed: the server answered ${t} but the response body could not be read (${i}). The submission may or may not have been stored, so it is reported as a failure rather than risk telling the visitor it was sent.`
595
+ ), re(ie, !1);
596
+ }
597
+ function yt(e, t) {
598
+ return console.error(
599
+ `${e} Submission NOT confirmed: the server answered ${t} with an empty body. EVERY DCS submission endpoint returns a JSON receipt — including on 204, which is why the old 204 exemption was removed (C-310) — so an empty body means the request was answered by something other than the DCS API (a misrouted POST).`
600
+ ), re(ie, !1);
601
+ }
602
+ function be(e, t, n, i) {
603
+ const o = n.includes("html") || /^\s*<(?:!doctype|html)/i.test(i);
604
+ return console.error(
605
+ `${e} Submission NOT stored: the server answered ${t} with a ${n || "bodyless/unknown"} body instead of JSON` + (o ? " — this is an HTML page, so the POST did not reach the DCS API (check the resolved api-base and the host routing for /api/v1/*)." : ".") + ` First 200 bytes: ${i.slice(0, 200)}`
606
+ ), re(ie, !1);
607
+ }
608
+ function gt(e, t, n, i) {
609
+ return console.error(
610
+ `${e} Submission NOT confirmed: the server answered ${t} with JSON that is not a valid ${n} receipt. A 2xx and parseable JSON prove only that SOMETHING answered; only the endpoint's receipt proves a row was stored. Received: ${bt(i).slice(0, 200)}`
611
+ ), re(ie, !0);
612
+ }
613
+ function bt(e) {
614
+ try {
615
+ return JSON.stringify(e) ?? String(e);
616
+ } catch {
617
+ return String(e);
618
+ }
619
+ }
620
+ async function vt(e) {
621
+ const { apiBase: t, siteSlug: n, payload: i } = e, o = e.retries ?? 1, a = e.fetchImpl ?? fetch, d = t.replace(/\/$/, ""), s = `forms/${encodeURIComponent(i.formId)}/submissions`, l = n.trim(), u = l ? `${d}/sites/${encodeURIComponent(l)}/${s}` : `${d}/${s}`, r = Object.values(i.values).some(Ft);
622
+ let b, F;
528
623
  for (let L = 0; L <= o; L++)
529
624
  try {
530
- const S = n ? { method: "POST", body: Ze(i) } : {
625
+ const S = r ? { method: "POST", redirect: ve, body: wt(i) } : {
531
626
  method: "POST",
627
+ redirect: ve,
532
628
  headers: { "Content-Type": "application/json" },
533
629
  body: JSON.stringify(i)
534
- }, q = await a(c, S);
535
- if (x = q.status, q.ok) {
536
- const M = await tt(q);
537
- return { payload: i, response: M };
630
+ }, P = await a(u, S);
631
+ if (F = P.status, P.ok) {
632
+ let O;
633
+ try {
634
+ O = await dt(P, ct, {
635
+ receiptName: "managed-form submission"
636
+ });
637
+ } catch (R) {
638
+ const D = !!R?.receiptRejected;
639
+ throw {
640
+ payload: i,
641
+ status: P.status,
642
+ error: R,
643
+ // `nonJsonResponse` keeps its original literal meaning (the body was
644
+ // not JSON at all); a JSON body that failed the receipt predicate is
645
+ // reported through the additive `unconfirmedReceipt` flag instead.
646
+ nonJsonResponse: !D,
647
+ unconfirmedReceipt: D
648
+ };
649
+ }
650
+ return { payload: i, response: O };
538
651
  }
539
- if (q.status < 500) {
540
- const M = await it(q);
652
+ if (P.status < 500) {
653
+ const O = await St(P);
541
654
  throw {
542
655
  payload: i,
543
- status: q.status,
544
- error: new Error(`Submission failed (${q.status}): ${M}`)
656
+ status: P.status,
657
+ error: new Error(`Submission failed (${P.status}): ${O}`)
545
658
  };
546
659
  }
547
- h = new Error(`Server error ${q.status}`);
660
+ b = new Error(`Server error ${P.status}`);
548
661
  } catch (S) {
549
662
  if (S && typeof S == "object" && "payload" in S && "error" in S)
550
663
  throw S;
551
- h = S;
664
+ b = S;
552
665
  }
553
666
  throw {
554
667
  payload: i,
555
- status: x,
556
- error: h ?? new Error("Submission failed")
668
+ status: F,
669
+ error: b ?? new Error("Submission failed")
557
670
  };
558
671
  }
559
- function Ze(e) {
672
+ function wt(e) {
560
673
  const t = new FormData();
561
674
  t.append("formId", e.formId), e.captchaToken && t.append("captchaToken", e.captchaToken);
562
- for (const [r, i] of Object.entries(e.values))
675
+ for (const [n, i] of Object.entries(e.values))
563
676
  if (i != null)
564
677
  if (typeof File < "u" && i instanceof File)
565
- t.append(`values[${r}]`, i);
678
+ t.append(`values[${n}]`, i);
566
679
  else if (Array.isArray(i) && i.some((o) => typeof File < "u" && o instanceof File))
567
680
  for (const o of i)
568
- typeof File < "u" && o instanceof File && t.append(`values[${r}][]`, o);
681
+ typeof File < "u" && o instanceof File && t.append(`values[${n}][]`, o);
569
682
  else if (Array.isArray(i))
570
- for (const o of i) t.append(`values[${r}][]`, String(o));
683
+ for (const o of i) t.append(`values[${n}][]`, String(o));
571
684
  else
572
- t.append(`values[${r}]`, String(i));
685
+ t.append(`values[${n}]`, String(i));
573
686
  return t;
574
687
  }
575
- function et(e) {
688
+ function Ft(e) {
576
689
  return typeof File > "u" ? !1 : e instanceof File ? !0 : Array.isArray(e) && e.some((t) => t instanceof File);
577
690
  }
578
- async function tt(e) {
579
- try {
580
- return await e.json();
581
- } catch {
582
- return null;
583
- }
584
- }
585
- async function it(e) {
691
+ const ve = "error";
692
+ async function St(e) {
586
693
  try {
587
694
  return await e.text();
588
695
  } catch {
589
696
  return "";
590
697
  }
591
698
  }
592
- const rt = "http://json-schema.org/draft-07/schema#", nt = "https://duffcloudservices.com/schemas/form-definition.schema.json", ot = "PortalFormDefinition", at = "object", st = "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", lt = ["formId", "submission", "fields"], dt = { 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." } }, ut = /* @__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"}}}}}'), ct = {
593
- $schema: rt,
594
- $id: nt,
595
- title: ot,
596
- type: at,
597
- description: st,
598
- required: lt,
599
- properties: dt,
600
- definitions: ut
699
+ const ue = /* @__PURE__ */ new Map();
700
+ function Qi() {
701
+ ue.clear();
702
+ }
703
+ async function $t(e) {
704
+ const t = (e.apiBase ?? "").replace(/\/$/, ""), n = (e.siteSlug ?? "").trim(), i = n ? `${t}/sites/${encodeURIComponent(n)}/forms/compliance` : `${t}/forms/compliance`, o = `${t}|${n}`, a = ue.get(o);
705
+ if (a) return a;
706
+ const d = e.fetchImpl ?? (typeof fetch == "function" ? fetch : void 0);
707
+ if (!d) return !1;
708
+ const s = (async () => {
709
+ try {
710
+ const l = await d(i, { method: "GET" });
711
+ return l.ok ? (await l.json())?.siteHandlesPhi === !0 : !1;
712
+ } catch {
713
+ return !1;
714
+ }
715
+ })();
716
+ return ue.set(o, s), s;
717
+ }
718
+ const we = {
719
+ lead: "Please don't include personal health details.",
720
+ detail: "A general description of what you need is enough — we'll go over anything specific with you directly."
721
+ }, xt = "http://json-schema.org/draft-07/schema#", kt = "https://duffcloudservices.com/schemas/form-definition.schema.json", Pt = "PortalFormDefinition", qt = "object", It = "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", Lt = ["formId", "submission", "fields"], Tt = { 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." } }, Ct = /* @__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"}}}}}'), At = {
722
+ $schema: xt,
723
+ $id: kt,
724
+ title: Pt,
725
+ type: qt,
726
+ description: It,
727
+ required: Lt,
728
+ properties: Tt,
729
+ definitions: Ct
601
730
  };
602
- let Y = null;
603
- function mt() {
604
- if (Y) return Y;
605
- const e = new Ie({
731
+ let Z = null;
732
+ function Vt() {
733
+ if (Z) return Z;
734
+ const e = new je({
606
735
  allErrors: !0,
607
736
  strict: !1,
608
737
  discriminator: !1
609
738
  });
610
- return Te(e), Y = e.compile(ct), Y;
739
+ return _e(e), Z = e.compile(At), Z;
611
740
  }
612
- function ft(e) {
613
- const t = mt(), r = t(e);
614
- return { valid: r, errors: r ? [] : t.errors ?? [] };
741
+ function Mt(e) {
742
+ const t = Vt(), n = t(e);
743
+ return { valid: n, errors: n ? [] : t.errors ?? [] };
615
744
  }
616
- function pt(e, t, r) {
617
- const i = ft(t);
618
- return !i.valid && r && console.warn(
745
+ function Et(e, t, n) {
746
+ const i = Mt(t);
747
+ return !i.valid && n && console.warn(
619
748
  `[@duffcloudservices/site-forms] Form "${e}" failed schema validation:`,
620
749
  i.errors
621
750
  ), i;
622
751
  }
623
- function ht(e) {
752
+ function Ot(e) {
624
753
  const t = {};
625
- for (const [r, i] of Object.entries(e)) {
626
- const o = yt(r), a = gt(i);
754
+ for (const [n, i] of Object.entries(e)) {
755
+ const o = Rt(n), a = Dt(i);
627
756
  a && (t[a.formId ?? o] = a);
628
757
  }
629
758
  return t;
630
759
  }
631
- function yt(e) {
760
+ function Rt(e) {
632
761
  return (e.split("/").pop() ?? e).replace(/\.ya?ml$/i, "");
633
762
  }
634
- function gt(e) {
763
+ function Dt(e) {
635
764
  if (!e) return null;
636
765
  if (typeof e == "string")
637
- return fe.load(e);
766
+ return $e.load(e);
638
767
  if (typeof e == "object") {
639
768
  const t = e.default;
640
769
  return t && typeof t == "object" ? t : e;
641
770
  }
642
771
  return null;
643
772
  }
644
- function ki(e) {
645
- return fe.load(e);
773
+ function Xi(e) {
774
+ return $e.load(e);
646
775
  }
647
- const bt = ["data-form-field-key"], vt = ["for"], Ft = {
776
+ const jt = ["data-form-field-key"], _t = ["for"], Bt = {
648
777
  key: 0,
649
778
  "aria-hidden": "true",
650
779
  class: "dcs-form-field__required"
651
- }, wt = {
780
+ }, Nt = {
652
781
  key: 0,
653
782
  class: "dcs-form-field__help"
654
- }, xt = {
783
+ }, zt = {
655
784
  key: 0,
656
785
  class: "dcs-form-field__error",
657
786
  role: "alert"
658
- }, E = /* @__PURE__ */ C({
787
+ }, N = /* @__PURE__ */ M({
659
788
  __name: "DcsFormFieldWrapper",
660
789
  props: {
661
790
  field: {},
@@ -663,30 +792,30 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
663
792
  inputId: {}
664
793
  },
665
794
  setup(e) {
666
- return (t, r) => (m(), p("div", {
667
- class: ke(["dcs-form-field", [`dcs-form-field--${e.field.type}`, `dcs-form-field--width-${e.field.width ?? "full"}`]]),
795
+ return (t, n) => (c(), f("div", {
796
+ class: Oe(["dcs-form-field", [`dcs-form-field--${e.field.type}`, `dcs-form-field--width-${e.field.width ?? "full"}`]]),
668
797
  "data-form-field-key": e.field.id
669
798
  }, [
670
799
  V(t.$slots, "label", {}, () => [
671
- e.field.type !== "checkbox" && e.field.type !== "hidden" && e.field.type !== "section-heading" && e.field.type !== "html-block" ? (m(), p("label", {
800
+ e.field.type !== "checkbox" && e.field.type !== "hidden" && e.field.type !== "section-heading" && e.field.type !== "html-block" ? (c(), f("label", {
672
801
  key: 0,
673
802
  for: e.inputId ?? `field-${e.field.id}`,
674
803
  class: "dcs-form-field__label"
675
804
  }, [
676
- X(w(e.field.label) + " ", 1),
677
- e.field.required ? (m(), p("span", Ft, "*")) : I("", !0)
678
- ], 8, vt)) : I("", !0)
805
+ W(w(e.field.label) + " ", 1),
806
+ e.field.required ? (c(), f("span", Bt, "*")) : T("", !0)
807
+ ], 8, _t)) : T("", !0)
679
808
  ]),
680
809
  V(t.$slots, "default"),
681
810
  V(t.$slots, "help", {}, () => [
682
- e.field.helpText ? (m(), p("p", wt, w(e.field.helpText), 1)) : I("", !0)
811
+ e.field.helpText ? (c(), f("p", Nt, w(e.field.helpText), 1)) : T("", !0)
683
812
  ]),
684
813
  V(t.$slots, "error", {}, () => [
685
- e.error ? (m(), p("p", xt, w(e.error), 1)) : I("", !0)
814
+ e.error ? (c(), f("p", zt, w(e.error), 1)) : T("", !0)
686
815
  ])
687
- ], 10, bt));
816
+ ], 10, jt));
688
817
  }
689
- }), $t = ["id", "type", "name", "value", "placeholder", "required", "aria-invalid", "aria-describedby"], ce = /* @__PURE__ */ C({
818
+ }), Kt = ["id", "type", "name", "value", "placeholder", "required", "aria-invalid", "aria-describedby"], Fe = /* @__PURE__ */ M({
690
819
  __name: "DcsFormText",
691
820
  props: {
692
821
  field: {},
@@ -695,8 +824,8 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
695
824
  },
696
825
  emits: ["update:modelValue", "blur"],
697
826
  setup(e, { emit: t }) {
698
- const r = e, i = t, o = f(() => `field-${r.field.id}`), a = f(() => {
699
- switch (r.field.type) {
827
+ const n = e, i = t, o = m(() => `field-${n.field.id}`), a = m(() => {
828
+ switch (n.field.type) {
700
829
  case "email":
701
830
  return "email";
702
831
  case "tel":
@@ -705,16 +834,16 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
705
834
  return "text";
706
835
  }
707
836
  });
708
- return (u, s) => (m(), j(E, {
837
+ return (d, s) => (c(), _(N, {
709
838
  field: e.field,
710
839
  error: e.error,
711
840
  "input-id": o.value
712
841
  }, {
713
- default: D(() => [
714
- V(u.$slots, "input", {
842
+ default: j(() => [
843
+ V(d.$slots, "input", {
715
844
  id: o.value,
716
845
  value: e.modelValue,
717
- onInput: (d) => i("update:modelValue", d.target.value),
846
+ onInput: (l) => i("update:modelValue", l.target.value),
718
847
  onBlur: () => i("blur")
719
848
  }, () => [
720
849
  v("input", {
@@ -727,15 +856,15 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
727
856
  required: e.field.required,
728
857
  "aria-invalid": !!e.error,
729
858
  "aria-describedby": e.error ? `${o.value}-error` : void 0,
730
- onInput: s[0] || (s[0] = (d) => i("update:modelValue", d.target.value)),
731
- onBlur: s[1] || (s[1] = (d) => i("blur"))
732
- }, null, 40, $t)
859
+ onInput: s[0] || (s[0] = (l) => i("update:modelValue", l.target.value)),
860
+ onBlur: s[1] || (s[1] = (l) => i("blur"))
861
+ }, null, 40, Kt)
733
862
  ])
734
863
  ]),
735
864
  _: 3
736
865
  }, 8, ["field", "error", "input-id"]));
737
866
  }
738
- }), St = ["id", "name", "placeholder", "required", "aria-invalid", "value"], kt = /* @__PURE__ */ C({
867
+ }), Ut = ["id", "name", "placeholder", "required", "aria-invalid", "value"], Ht = /* @__PURE__ */ M({
739
868
  __name: "DcsFormTextarea",
740
869
  props: {
741
870
  field: {},
@@ -744,13 +873,13 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
744
873
  },
745
874
  emits: ["update:modelValue", "blur"],
746
875
  setup(e, { emit: t }) {
747
- const r = e, i = t, o = f(() => `field-${r.field.id}`);
748
- return (a, u) => (m(), j(E, {
876
+ const n = e, i = t, o = m(() => `field-${n.field.id}`);
877
+ return (a, d) => (c(), _(N, {
749
878
  field: e.field,
750
879
  error: e.error,
751
880
  "input-id": o.value
752
881
  }, {
753
- default: D(() => [
882
+ default: j(() => [
754
883
  V(a.$slots, "input", {
755
884
  id: o.value,
756
885
  value: e.modelValue,
@@ -766,19 +895,19 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
766
895
  "aria-invalid": !!e.error,
767
896
  rows: "5",
768
897
  value: e.modelValue ?? "",
769
- onInput: u[0] || (u[0] = (s) => i("update:modelValue", s.target.value)),
770
- onBlur: u[1] || (u[1] = (s) => i("blur"))
771
- }, null, 40, St)
898
+ onInput: d[0] || (d[0] = (s) => i("update:modelValue", s.target.value)),
899
+ onBlur: d[1] || (d[1] = (s) => i("blur"))
900
+ }, null, 40, Ut)
772
901
  ])
773
902
  ]),
774
903
  _: 3
775
904
  }, 8, ["field", "error", "input-id"]));
776
905
  }
777
- }), qt = ["id", "name", "required", "multiple", "aria-invalid", "value"], Pt = {
906
+ }), Wt = ["id", "name", "required", "multiple", "aria-invalid", "value"], Gt = {
778
907
  key: 0,
779
908
  value: "",
780
909
  disabled: ""
781
- }, Lt = ["value"], It = /* @__PURE__ */ C({
910
+ }, Jt = ["value"], Yt = /* @__PURE__ */ M({
782
911
  __name: "DcsFormSelect",
783
912
  props: {
784
913
  field: {},
@@ -787,26 +916,26 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
787
916
  },
788
917
  emits: ["update:modelValue", "blur"],
789
918
  setup(e, { emit: t }) {
790
- const r = e, i = t, o = f(() => `field-${r.field.id}`), a = f(() => r.field.type === "multiselect"), u = f(() => r.field.options ?? []);
791
- function s(d) {
792
- const c = d.target;
919
+ const n = e, i = t, o = m(() => `field-${n.field.id}`), a = m(() => n.field.type === "multiselect"), d = m(() => n.field.options ?? []);
920
+ function s(l) {
921
+ const u = l.target;
793
922
  if (a.value) {
794
- const n = [];
795
- for (const h of Array.from(c.selectedOptions)) n.push(h.value);
796
- i("update:modelValue", n);
923
+ const r = [];
924
+ for (const b of Array.from(u.selectedOptions)) r.push(b.value);
925
+ i("update:modelValue", r);
797
926
  } else
798
- i("update:modelValue", c.value);
927
+ i("update:modelValue", u.value);
799
928
  }
800
- return (d, c) => (m(), j(E, {
929
+ return (l, u) => (c(), _(N, {
801
930
  field: e.field,
802
931
  error: e.error,
803
932
  "input-id": o.value
804
933
  }, {
805
- default: D(() => [
806
- V(d.$slots, "input", {
934
+ default: j(() => [
935
+ V(l.$slots, "input", {
807
936
  id: o.value,
808
937
  value: e.modelValue,
809
- options: u.value,
938
+ options: d.value,
810
939
  onChange: s
811
940
  }, () => [
812
941
  v("select", {
@@ -818,20 +947,20 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
818
947
  "aria-invalid": !!e.error,
819
948
  value: e.modelValue ?? (a.value ? [] : ""),
820
949
  onChange: s,
821
- onBlur: c[0] || (c[0] = (n) => i("blur"))
950
+ onBlur: u[0] || (u[0] = (r) => i("blur"))
822
951
  }, [
823
- a.value ? I("", !0) : (m(), p("option", Pt, w(e.field.placeholder ?? "Select…"), 1)),
824
- (m(!0), p(U, null, W(u.value, (n) => (m(), p("option", {
825
- key: n.value,
826
- value: n.value
827
- }, w(n.label), 9, Lt))), 128))
828
- ], 40, qt)
952
+ a.value ? T("", !0) : (c(), f("option", Gt, w(e.field.placeholder ?? "Select…"), 1)),
953
+ (c(!0), f(K, null, G(d.value, (r) => (c(), f("option", {
954
+ key: r.value,
955
+ value: r.value
956
+ }, w(r.label), 9, Jt))), 128))
957
+ ], 40, Wt)
829
958
  ])
830
959
  ]),
831
960
  _: 3
832
961
  }, 8, ["field", "error", "input-id"]));
833
962
  }
834
- }), Tt = ["aria-required", "aria-invalid"], Vt = { class: "sr-only" }, Ct = ["name", "value", "checked", "onChange"], At = /* @__PURE__ */ C({
963
+ }), Qt = ["aria-required", "aria-invalid"], Xt = { class: "sr-only" }, Zt = ["name", "value", "checked", "onChange"], ei = /* @__PURE__ */ M({
835
964
  __name: "DcsFormRadio",
836
965
  props: {
837
966
  field: {},
@@ -840,39 +969,39 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
840
969
  },
841
970
  emits: ["update:modelValue"],
842
971
  setup(e, { emit: t }) {
843
- const r = e, i = t, o = f(() => `field-${r.field.id}`), a = f(() => r.field.options ?? []);
844
- return (u, s) => (m(), j(E, {
972
+ const n = e, i = t, o = m(() => `field-${n.field.id}`), a = m(() => n.field.options ?? []);
973
+ return (d, s) => (c(), _(N, {
845
974
  field: e.field,
846
975
  error: e.error,
847
976
  "input-id": o.value
848
977
  }, {
849
- default: D(() => [
978
+ default: j(() => [
850
979
  v("fieldset", {
851
980
  class: "dcs-form-radio-group",
852
981
  role: "radiogroup",
853
982
  "aria-required": e.field.required,
854
983
  "aria-invalid": !!e.error
855
984
  }, [
856
- v("legend", Vt, w(e.field.label), 1),
857
- (m(!0), p(U, null, W(a.value, (d) => (m(), p("label", {
858
- key: d.value,
985
+ v("legend", Xt, w(e.field.label), 1),
986
+ (c(!0), f(K, null, G(a.value, (l) => (c(), f("label", {
987
+ key: l.value,
859
988
  class: "dcs-form-radio"
860
989
  }, [
861
990
  v("input", {
862
991
  type: "radio",
863
992
  name: e.field.id,
864
- value: d.value,
865
- checked: e.modelValue === d.value,
866
- onChange: (c) => i("update:modelValue", d.value)
867
- }, null, 40, Ct),
868
- v("span", null, w(d.label), 1)
993
+ value: l.value,
994
+ checked: e.modelValue === l.value,
995
+ onChange: (u) => i("update:modelValue", l.value)
996
+ }, null, 40, Zt),
997
+ v("span", null, w(l.label), 1)
869
998
  ]))), 128))
870
- ], 8, Tt)
999
+ ], 8, Qt)
871
1000
  ]),
872
1001
  _: 1
873
1002
  }, 8, ["field", "error", "input-id"]));
874
1003
  }
875
- }), Mt = ["aria-required", "aria-invalid"], Dt = { class: "sr-only" }, jt = ["name", "value", "checked", "onChange"], Ot = /* @__PURE__ */ C({
1004
+ }), ti = ["aria-required", "aria-invalid"], ii = { class: "sr-only" }, ni = ["name", "value", "checked", "onChange"], ri = /* @__PURE__ */ M({
876
1005
  __name: "DcsFormCheckboxGroup",
877
1006
  props: {
878
1007
  field: {},
@@ -881,45 +1010,45 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
881
1010
  },
882
1011
  emits: ["update:modelValue"],
883
1012
  setup(e, { emit: t }) {
884
- const r = e, i = t, o = f(() => `field-${r.field.id}`), a = f(() => r.field.options ?? []), u = f(() => r.modelValue ?? []);
885
- function s(d, c) {
886
- const n = new Set(u.value);
887
- c ? n.add(d) : n.delete(d), i("update:modelValue", Array.from(n));
1013
+ const n = e, i = t, o = m(() => `field-${n.field.id}`), a = m(() => n.field.options ?? []), d = m(() => n.modelValue ?? []);
1014
+ function s(l, u) {
1015
+ const r = new Set(d.value);
1016
+ u ? r.add(l) : r.delete(l), i("update:modelValue", Array.from(r));
888
1017
  }
889
- return (d, c) => (m(), j(E, {
1018
+ return (l, u) => (c(), _(N, {
890
1019
  field: e.field,
891
1020
  error: e.error,
892
1021
  "input-id": o.value
893
1022
  }, {
894
- default: D(() => [
1023
+ default: j(() => [
895
1024
  v("fieldset", {
896
1025
  class: "dcs-form-checkbox-group",
897
1026
  "aria-required": e.field.required,
898
1027
  "aria-invalid": !!e.error
899
1028
  }, [
900
- v("legend", Dt, w(e.field.label), 1),
901
- (m(!0), p(U, null, W(a.value, (n) => (m(), p("label", {
902
- key: n.value,
1029
+ v("legend", ii, w(e.field.label), 1),
1030
+ (c(!0), f(K, null, G(a.value, (r) => (c(), f("label", {
1031
+ key: r.value,
903
1032
  class: "dcs-form-checkbox"
904
1033
  }, [
905
1034
  v("input", {
906
1035
  type: "checkbox",
907
1036
  name: `${e.field.id}[]`,
908
- value: n.value,
909
- checked: u.value.includes(n.value),
910
- onChange: (h) => s(n.value, h.target.checked)
911
- }, null, 40, jt),
912
- v("span", null, w(n.label), 1)
1037
+ value: r.value,
1038
+ checked: d.value.includes(r.value),
1039
+ onChange: (b) => s(r.value, b.target.checked)
1040
+ }, null, 40, ni),
1041
+ v("span", null, w(r.label), 1)
913
1042
  ]))), 128))
914
- ], 8, Mt)
1043
+ ], 8, ti)
915
1044
  ]),
916
1045
  _: 1
917
1046
  }, 8, ["field", "error", "input-id"]));
918
1047
  }
919
- }), Rt = { class: "sr-only" }, Et = ["for"], Bt = ["id", "name", "checked", "required", "aria-invalid"], _t = {
1048
+ }), oi = { class: "sr-only" }, ai = ["for"], si = ["id", "name", "checked", "required", "aria-invalid"], li = {
920
1049
  key: 0,
921
1050
  "aria-hidden": "true"
922
- }, zt = /* @__PURE__ */ C({
1051
+ }, di = /* @__PURE__ */ M({
923
1052
  __name: "DcsFormCheckbox",
924
1053
  props: {
925
1054
  field: {},
@@ -928,16 +1057,16 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
928
1057
  },
929
1058
  emits: ["update:modelValue"],
930
1059
  setup(e, { emit: t }) {
931
- const r = e, i = t, o = f(() => `field-${r.field.id}`);
932
- return (a, u) => (m(), j(E, {
1060
+ const n = e, i = t, o = m(() => `field-${n.field.id}`);
1061
+ return (a, d) => (c(), _(N, {
933
1062
  field: e.field,
934
1063
  error: e.error,
935
1064
  "input-id": o.value
936
1065
  }, {
937
- label: D(() => [
938
- v("span", Rt, w(e.field.label), 1)
1066
+ label: j(() => [
1067
+ v("span", oi, w(e.field.label), 1)
939
1068
  ]),
940
- default: D(() => [
1069
+ default: j(() => [
941
1070
  v("label", {
942
1071
  class: "dcs-form-checkbox-single",
943
1072
  for: o.value
@@ -949,18 +1078,18 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
949
1078
  checked: !!e.modelValue,
950
1079
  required: e.field.required,
951
1080
  "aria-invalid": !!e.error,
952
- onChange: u[0] || (u[0] = (s) => i("update:modelValue", s.target.checked))
953
- }, null, 40, Bt),
1081
+ onChange: d[0] || (d[0] = (s) => i("update:modelValue", s.target.checked))
1082
+ }, null, 40, si),
954
1083
  v("span", null, [
955
- X(w(e.field.label), 1),
956
- e.field.required ? (m(), p("span", _t, " *")) : I("", !0)
1084
+ W(w(e.field.label), 1),
1085
+ e.field.required ? (c(), f("span", li, " *")) : T("", !0)
957
1086
  ])
958
- ], 8, Et)
1087
+ ], 8, ai)
959
1088
  ]),
960
1089
  _: 1
961
1090
  }, 8, ["field", "error", "input-id"]));
962
1091
  }
963
- }), Kt = ["id", "name", "required", "aria-invalid", "value"], Nt = /* @__PURE__ */ C({
1092
+ }), ui = ["id", "name", "required", "aria-invalid", "value"], ci = /* @__PURE__ */ M({
964
1093
  __name: "DcsFormDate",
965
1094
  props: {
966
1095
  field: {},
@@ -969,13 +1098,13 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
969
1098
  },
970
1099
  emits: ["update:modelValue", "blur"],
971
1100
  setup(e, { emit: t }) {
972
- const r = e, i = t, o = f(() => `field-${r.field.id}`);
973
- return (a, u) => (m(), j(E, {
1101
+ const n = e, i = t, o = m(() => `field-${n.field.id}`);
1102
+ return (a, d) => (c(), _(N, {
974
1103
  field: e.field,
975
1104
  error: e.error,
976
1105
  "input-id": o.value
977
1106
  }, {
978
- default: D(() => [
1107
+ default: j(() => [
979
1108
  v("input", {
980
1109
  id: o.value,
981
1110
  class: "dcs-form-input dcs-form-date",
@@ -984,25 +1113,25 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
984
1113
  required: e.field.required,
985
1114
  "aria-invalid": !!e.error,
986
1115
  value: e.modelValue ?? "",
987
- onInput: u[0] || (u[0] = (s) => i("update:modelValue", s.target.value)),
988
- onBlur: u[1] || (u[1] = (s) => i("blur"))
989
- }, null, 40, Kt)
1116
+ onInput: d[0] || (d[0] = (s) => i("update:modelValue", s.target.value)),
1117
+ onBlur: d[1] || (d[1] = (s) => i("blur"))
1118
+ }, null, 40, ui)
990
1119
  ]),
991
1120
  _: 1
992
1121
  }, 8, ["field", "error", "input-id"]));
993
1122
  }
994
- }), Ut = ["id", "name", "multiple", "required", "aria-invalid", "accept"], Wt = {
1123
+ }), mi = ["id", "name", "multiple", "required", "aria-invalid", "accept"], fi = {
995
1124
  key: 0,
996
1125
  class: "dcs-form-file__status"
997
- }, Ht = {
1126
+ }, pi = {
998
1127
  key: 1,
999
1128
  class: "dcs-form-file-preview-grid",
1000
1129
  "aria-live": "polite"
1001
- }, Gt = ["src", "alt"], Jt = {
1130
+ }, hi = ["src", "alt"], yi = {
1002
1131
  key: 1,
1003
1132
  class: "dcs-form-file-preview__placeholder",
1004
1133
  "aria-hidden": "true"
1005
- }, Yt = { class: "dcs-form-file-preview__meta" }, Qt = { class: "dcs-form-file-preview__name" }, Xt = { class: "dcs-form-file-preview__size" }, Zt = ["aria-label", "onClick"], ei = /* @__PURE__ */ C({
1134
+ }, gi = { class: "dcs-form-file-preview__meta" }, bi = { class: "dcs-form-file-preview__name" }, vi = { class: "dcs-form-file-preview__size" }, wi = ["aria-label", "onClick"], Fi = /* @__PURE__ */ M({
1006
1135
  __name: "DcsFormFile",
1007
1136
  props: {
1008
1137
  field: {},
@@ -1012,57 +1141,57 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1012
1141
  },
1013
1142
  emits: ["update:modelValue"],
1014
1143
  setup(e, { emit: t }) {
1015
- const r = e, i = t, o = f(() => `field-${r.field.id}`), a = A(null), u = f(() => (r.field.validation?.accept ?? r.attachmentPolicy?.accept ?? []).join(",")), s = f(() => Math.max(1, Math.floor(r.attachmentPolicy?.maxFiles ?? 1))), d = f(() => s.value > 1), c = f(() => h(r.modelValue)), n = A([]);
1016
- function h(l) {
1017
- return Array.isArray(l) ? l.filter(Boolean) : l ? [l] : [];
1144
+ const n = e, i = t, o = m(() => `field-${n.field.id}`), a = E(null), d = m(() => (n.field.validation?.accept ?? n.attachmentPolicy?.accept ?? []).join(",")), s = m(() => Math.max(1, Math.floor(n.attachmentPolicy?.maxFiles ?? 1))), l = m(() => s.value > 1), u = m(() => b(n.modelValue)), r = E([]);
1145
+ function b(p) {
1146
+ return Array.isArray(p) ? p.filter(Boolean) : p ? [p] : [];
1018
1147
  }
1019
- function x(l) {
1020
- const F = l.slice(0, s.value);
1021
- i("update:modelValue", d.value ? F : F[0]);
1148
+ function F(p) {
1149
+ const $ = p.slice(0, s.value);
1150
+ i("update:modelValue", l.value ? $ : $[0]);
1022
1151
  }
1023
- function L(l) {
1024
- return [l.name, l.type, l.size, l.lastModified].join(":");
1152
+ function L(p) {
1153
+ return [p.name, p.type, p.size, p.lastModified].join(":");
1025
1154
  }
1026
- function S(l) {
1027
- const F = /* @__PURE__ */ new Set(), g = [];
1028
- for (const P of l) {
1029
- const O = L(P);
1030
- F.has(O) || (F.add(O), g.push(P));
1155
+ function S(p) {
1156
+ const $ = /* @__PURE__ */ new Set(), q = [];
1157
+ for (const h of p) {
1158
+ const C = L(h);
1159
+ $.has(C) || ($.add(C), q.push(h));
1031
1160
  }
1032
- return g;
1161
+ return q;
1033
1162
  }
1034
- function q(l) {
1035
- const F = l.target, g = Array.from(F.files ?? []).filter((P) => P.size > 0);
1036
- g.length !== 0 && (x(d.value ? S([...c.value, ...g]) : g), F.value = "");
1163
+ function P(p) {
1164
+ const $ = p.target, q = Array.from($.files ?? []).filter((h) => h.size > 0);
1165
+ q.length !== 0 && (F(l.value ? S([...u.value, ...q]) : q), $.value = "");
1037
1166
  }
1038
- function M(l) {
1039
- const F = c.value.filter((g, P) => P !== l);
1040
- x(F), F.length === 0 && a.value && (a.value.value = "");
1167
+ function O(p) {
1168
+ const $ = u.value.filter((q, h) => h !== p);
1169
+ F($), $.length === 0 && a.value && (a.value.value = "");
1041
1170
  }
1042
- function z(l) {
1043
- return l < 1024 ? `${l} B` : l < 1024 * 1024 ? `${(l / 1024).toFixed(1)} KB` : `${(l / (1024 * 1024)).toFixed(1)} MB`;
1171
+ function R(p) {
1172
+ return p < 1024 ? `${p} B` : p < 1024 * 1024 ? `${(p / 1024).toFixed(1)} KB` : `${(p / (1024 * 1024)).toFixed(1)} MB`;
1044
1173
  }
1045
- function B() {
1046
- for (const l of n.value)
1047
- URL.revokeObjectURL(l.url);
1048
- n.value = [];
1174
+ function D() {
1175
+ for (const p of r.value)
1176
+ URL.revokeObjectURL(p.url);
1177
+ r.value = [];
1049
1178
  }
1050
- return Q(
1051
- c,
1052
- (l) => {
1053
- B(), n.value = l.map((F) => ({
1054
- file: F,
1055
- url: URL.createObjectURL(F),
1056
- canPreview: F.type.toLowerCase().startsWith("image/")
1179
+ return ee(
1180
+ u,
1181
+ (p) => {
1182
+ D(), r.value = p.map(($) => ({
1183
+ file: $,
1184
+ url: URL.createObjectURL($),
1185
+ canPreview: $.type.toLowerCase().startsWith("image/")
1057
1186
  }));
1058
1187
  },
1059
1188
  { immediate: !0 }
1060
- ), qe(B), (l, F) => (m(), j(E, {
1189
+ ), Re(D), (p, $) => (c(), _(N, {
1061
1190
  field: e.field,
1062
1191
  error: e.error,
1063
1192
  "input-id": o.value
1064
1193
  }, {
1065
- default: D(() => [
1194
+ default: j(() => [
1066
1195
  v("input", {
1067
1196
  ref_key: "inputEl",
1068
1197
  ref: a,
@@ -1070,94 +1199,99 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1070
1199
  class: "dcs-form-input dcs-form-file",
1071
1200
  type: "file",
1072
1201
  name: e.field.id,
1073
- multiple: d.value,
1202
+ multiple: l.value,
1074
1203
  required: e.field.required,
1075
1204
  "aria-invalid": !!e.error,
1076
- accept: u.value || void 0,
1077
- onChange: q
1078
- }, null, 40, Ut),
1079
- d.value ? (m(), p("p", Wt, w(c.value.length) + " of " + w(s.value) + " files selected ", 1)) : I("", !0),
1080
- n.value.length > 0 ? (m(), p("div", Ht, [
1081
- (m(!0), p(U, null, W(n.value, (g, P) => (m(), p("div", {
1082
- key: L(g.file),
1205
+ accept: d.value || void 0,
1206
+ onChange: P
1207
+ }, null, 40, mi),
1208
+ l.value ? (c(), f("p", fi, w(u.value.length) + " of " + w(s.value) + " files selected ", 1)) : T("", !0),
1209
+ r.value.length > 0 ? (c(), f("div", pi, [
1210
+ (c(!0), f(K, null, G(r.value, (q, h) => (c(), f("div", {
1211
+ key: L(q.file),
1083
1212
  class: "dcs-form-file-preview"
1084
1213
  }, [
1085
- g.canPreview ? (m(), p("img", {
1214
+ q.canPreview ? (c(), f("img", {
1086
1215
  key: 0,
1087
1216
  class: "dcs-form-file-preview__image",
1088
- src: g.url,
1089
- alt: `${g.file.name} preview`
1090
- }, null, 8, Gt)) : (m(), p("div", Jt, " File ")),
1091
- v("div", Yt, [
1092
- v("span", Qt, w(g.file.name), 1),
1093
- v("span", Xt, w(z(g.file.size)), 1)
1217
+ src: q.url,
1218
+ alt: `${q.file.name} preview`
1219
+ }, null, 8, hi)) : (c(), f("div", yi, " File ")),
1220
+ v("div", gi, [
1221
+ v("span", bi, w(q.file.name), 1),
1222
+ v("span", vi, w(R(q.file.size)), 1)
1094
1223
  ]),
1095
1224
  v("button", {
1096
1225
  type: "button",
1097
1226
  class: "dcs-form-file-preview__remove",
1098
- "aria-label": `Remove ${g.file.name}`,
1099
- onClick: (O) => M(P)
1100
- }, " Remove ", 8, Zt)
1227
+ "aria-label": `Remove ${q.file.name}`,
1228
+ onClick: (C) => O(h)
1229
+ }, " Remove ", 8, wi)
1101
1230
  ]))), 128))
1102
- ])) : I("", !0)
1231
+ ])) : T("", !0)
1103
1232
  ]),
1104
1233
  _: 1
1105
1234
  }, 8, ["field", "error", "input-id"]));
1106
1235
  }
1107
- }), ti = ["name", "value", "data-form-field-key"], ii = /* @__PURE__ */ C({
1236
+ }), Si = ["name", "value", "data-form-field-key"], $i = /* @__PURE__ */ M({
1108
1237
  __name: "DcsFormHidden",
1109
1238
  props: {
1110
1239
  field: {},
1111
1240
  modelValue: {}
1112
1241
  },
1113
1242
  setup(e) {
1114
- return (t, r) => (m(), p("input", {
1243
+ return (t, n) => (c(), f("input", {
1115
1244
  type: "hidden",
1116
1245
  name: e.field.id,
1117
1246
  value: e.modelValue ?? e.field.defaultValue ?? "",
1118
1247
  "data-form-field-key": e.field.id
1119
- }, null, 8, ti));
1248
+ }, null, 8, Si));
1120
1249
  }
1121
- }), ri = ["data-form-field-key"], ni = { class: "dcs-form-section__heading" }, oi = {
1250
+ }), xi = ["data-form-field-key"], ki = { class: "dcs-form-section__heading" }, Pi = {
1122
1251
  key: 0,
1123
1252
  class: "dcs-form-section__help"
1124
- }, ai = /* @__PURE__ */ C({
1253
+ }, qi = /* @__PURE__ */ M({
1125
1254
  __name: "DcsFormSection",
1126
1255
  props: {
1127
1256
  field: {}
1128
1257
  },
1129
1258
  setup(e) {
1130
- return (t, r) => (m(), p("div", {
1259
+ return (t, n) => (c(), f("div", {
1131
1260
  class: "dcs-form-section",
1132
1261
  "data-form-field-key": e.field.id
1133
1262
  }, [
1134
1263
  V(t.$slots, "default", {}, () => [
1135
- v("h3", ni, w(e.field.label), 1),
1136
- e.field.helpText ? (m(), p("p", oi, w(e.field.helpText), 1)) : I("", !0)
1264
+ v("h3", ki, w(e.field.label), 1),
1265
+ e.field.helpText ? (c(), f("p", Pi, w(e.field.helpText), 1)) : T("", !0)
1137
1266
  ])
1138
- ], 8, ri));
1267
+ ], 8, xi));
1139
1268
  }
1140
- }), si = ["data-form-field-key", "innerHTML"], li = /* @__PURE__ */ C({
1269
+ }), Ii = ["data-form-field-key", "innerHTML"], Li = /* @__PURE__ */ M({
1141
1270
  __name: "DcsFormHtmlBlock",
1142
1271
  props: {
1143
1272
  field: {}
1144
1273
  },
1145
1274
  setup(e) {
1146
- return (t, r) => (m(), p("div", {
1275
+ return (t, n) => (c(), f("div", {
1147
1276
  class: "dcs-form-html-block",
1148
1277
  "data-form-field-key": e.field.id,
1149
1278
  innerHTML: e.field.html ?? ""
1150
- }, null, 8, si));
1279
+ }, null, 8, Ii));
1151
1280
  }
1152
- }), me = {}, di = ["data-form-key"], ui = ["data-form-key"], ci = ["data-form-key"], mi = {
1281
+ }), Se = {}, Ti = ["data-form-key"], Ci = ["data-form-key"], Ai = ["data-form-key"], Vi = {
1153
1282
  key: 0,
1154
1283
  class: "dcs-form__progress",
1155
1284
  "aria-live": "polite"
1156
- }, fi = { class: "dcs-form__fields" }, pi = {
1285
+ }, Mi = { class: "dcs-form__fields" }, Ei = {
1286
+ key: 0,
1287
+ class: "dcs-form__phi-guidance",
1288
+ "data-form-phi-guidance": "",
1289
+ role: "note"
1290
+ }, Oi = {
1157
1291
  key: 1,
1158
1292
  class: "dcs-form__submit-error",
1159
1293
  role: "alert"
1160
- }, hi = { class: "dcs-form__actions" }, yi = ["disabled"], qi = /* @__PURE__ */ C({
1294
+ }, Ri = { class: "dcs-form__actions" }, Di = ["disabled"], Zi = /* @__PURE__ */ M({
1161
1295
  __name: "DcsForm",
1162
1296
  props: {
1163
1297
  formId: {},
@@ -1168,194 +1302,215 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1168
1302
  formsModules: {}
1169
1303
  },
1170
1304
  emits: ["submit-success", "submit-error", "validation-error"],
1171
- setup(e, { expose: t, emit: r }) {
1172
- const i = e, o = r, a = /* @__PURE__ */ Object.assign({}), u = f(
1173
- () => ht(i.formsModules ?? a)
1174
- ), s = f(() => i.definitionOverride ? i.definitionOverride : u.value[i.formId] ?? null), d = !1;
1175
- Q(
1305
+ setup(e, { expose: t, emit: n }) {
1306
+ const i = e, o = n, a = /* @__PURE__ */ Object.assign({}), d = m(
1307
+ () => Ot(i.formsModules ?? a)
1308
+ ), s = m(() => i.definitionOverride ? i.definitionOverride : d.value[i.formId] ?? null), l = !1;
1309
+ ee(
1176
1310
  s,
1177
- (l) => {
1178
- l && pt(i.formId, l, d);
1311
+ (h) => {
1312
+ h && Et(i.formId, h, l);
1179
1313
  },
1180
1314
  { immediate: !0 }
1181
1315
  );
1182
- const c = f(
1316
+ const u = m(
1183
1317
  () => s.value ?? {
1184
1318
  formId: i.formId,
1185
1319
  submission: { kind: "lead" },
1186
1320
  fields: []
1187
1321
  }
1188
- ), n = Qe({ definition: c.value }), { play: h } = Ne();
1189
- Q(
1190
- () => c.value,
1191
- () => n.reset()
1322
+ ), r = st({ definition: u.value }), { play: b } = et();
1323
+ ee(
1324
+ () => u.value,
1325
+ () => r.reset()
1192
1326
  );
1193
- const x = f(() => {
1194
- const l = i.apiBase ?? me?.VITE_DCS_PUBLIC_API ?? "";
1195
- return l || L();
1327
+ const F = m(() => {
1328
+ const h = i.apiBase ?? Se?.VITE_DCS_PUBLIC_API ?? "";
1329
+ return h || L();
1196
1330
  });
1197
1331
  function L() {
1198
1332
  if (typeof window > "u") return "";
1199
- const l = window.location.hostname.toLowerCase();
1200
- return l === "localhost" || l === "127.0.0.1" || l === "::1" ? "/api/v1" : "https://api.duffcloudservices.com/api/v1";
1333
+ const h = window.location.hostname.toLowerCase();
1334
+ return h === "localhost" || h === "127.0.0.1" || h === "::1" ? "/api/v1" : "https://api.duffcloudservices.com/api/v1";
1201
1335
  }
1202
- const S = f(
1203
- () => i.siteSlug ?? me?.VITE_DCS_SITE_SLUG ?? ""
1204
- ), q = f(
1205
- () => c.value.submitLabel ?? "Send"
1336
+ const S = m(
1337
+ () => i.siteSlug ?? Se?.VITE_DCS_SITE_SLUG ?? ""
1338
+ ), P = m(
1339
+ () => u.value.submitLabel ?? "Send"
1206
1340
  );
1207
- function M(l) {
1208
- switch (l.type) {
1341
+ function O(h) {
1342
+ switch (h.type) {
1209
1343
  case "text":
1210
1344
  case "email":
1211
1345
  case "tel":
1212
- return ce;
1346
+ return Fe;
1213
1347
  case "textarea":
1214
- return kt;
1348
+ return Ht;
1215
1349
  case "select":
1216
1350
  case "multiselect":
1217
- return It;
1351
+ return Yt;
1218
1352
  case "radio":
1219
- return At;
1353
+ return ei;
1220
1354
  case "checkbox-group":
1221
- return Ot;
1355
+ return ri;
1222
1356
  case "checkbox":
1223
- return zt;
1357
+ return di;
1224
1358
  case "date":
1225
- return Nt;
1359
+ return ci;
1226
1360
  case "file":
1227
- return ei;
1361
+ return Fi;
1228
1362
  case "hidden":
1229
- return ii;
1363
+ return $i;
1230
1364
  case "section-heading":
1231
- return ai;
1365
+ return qi;
1232
1366
  case "html-block":
1233
- return li;
1367
+ return Li;
1234
1368
  default:
1235
- return ce;
1369
+ return Fe;
1236
1370
  }
1237
1371
  }
1238
- const z = A(null);
1372
+ const R = E(!1), D = m(
1373
+ () => R.value && !!s.value
1374
+ ), p = m(() => {
1375
+ const h = r.visibleFields.value.findIndex(
1376
+ (C) => C.type === "textarea" || C.role === "message" || C.role === "summary"
1377
+ );
1378
+ return h >= 0 ? h : 0;
1379
+ });
1380
+ pe(async () => {
1381
+ R.value = await $t({
1382
+ apiBase: F.value,
1383
+ siteSlug: S.value
1384
+ });
1385
+ });
1386
+ const $ = E(null);
1239
1387
  t({
1240
- values: n.values,
1241
- errors: n.errors,
1242
- validateAll: n.validateAll,
1243
- collectSubmissionValues: n.collectSubmissionValues,
1244
- reset: n.reset
1388
+ values: r.values,
1389
+ errors: r.errors,
1390
+ validateAll: r.validateAll,
1391
+ collectSubmissionValues: r.collectSubmissionValues,
1392
+ reset: r.reset
1245
1393
  });
1246
- async function B(l) {
1247
- if (l.preventDefault(), !s.value) return;
1248
- if (!n.validateAll()) {
1249
- o("validation-error", n.errors.value);
1394
+ async function q(h) {
1395
+ if (h.preventDefault(), !s.value) return;
1396
+ if (!r.validateAll()) {
1397
+ o("validation-error", r.errors.value);
1250
1398
  return;
1251
1399
  }
1252
- n.submitting.value = !0, n.submitError.value = null;
1253
- const g = {
1400
+ r.submitting.value = !0, r.submitError.value = null;
1401
+ const A = {
1254
1402
  formId: i.formId,
1255
- values: n.collectSubmissionValues(),
1403
+ values: r.collectSubmissionValues(),
1256
1404
  captchaToken: i.captchaToken
1257
1405
  };
1258
1406
  try {
1259
- const P = await Xe({
1260
- apiBase: x.value,
1407
+ const y = await vt({
1408
+ apiBase: F.value,
1261
1409
  siteSlug: S.value,
1262
- payload: g
1410
+ payload: A
1263
1411
  });
1264
- n.submitted.value = !0, h("notification.success"), o("submit-success", P);
1265
- } catch (P) {
1266
- const O = P;
1267
- n.submitError.value = O.error?.message ?? "Submission failed", o("submit-error", O);
1412
+ r.submitted.value = !0, b("notification.success"), o("submit-success", y);
1413
+ } catch (y) {
1414
+ const x = y;
1415
+ r.submitError.value = x.error?.message ?? "Submission failed", o("submit-error", x);
1268
1416
  } finally {
1269
- n.submitting.value = !1;
1417
+ r.submitting.value = !1;
1270
1418
  }
1271
1419
  }
1272
- return Pe(() => {
1420
+ return pe(() => {
1273
1421
  s.value || console.warn(
1274
1422
  `[@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.`
1275
1423
  );
1276
- }), (l, F) => s.value ? y(n).submitted.value ? (m(), p("div", {
1424
+ }), (h, C) => s.value ? g(r).submitted.value ? (c(), f("div", {
1277
1425
  key: 1,
1278
1426
  class: "dcs-form dcs-form--success",
1279
1427
  "data-form-key": e.formId
1280
1428
  }, [
1281
- V(l.$slots, "success", { definition: s.value }, () => [
1429
+ V(h.$slots, "success", { definition: s.value }, () => [
1282
1430
  v("p", null, w(s.value.successMessage ?? "Thanks — we received your message."), 1)
1283
1431
  ])
1284
- ], 8, ui)) : (m(), p("form", {
1432
+ ], 8, Ci)) : (c(), f("form", {
1285
1433
  key: 2,
1286
1434
  ref_key: "formEl",
1287
- ref: z,
1435
+ ref: $,
1288
1436
  class: "dcs-form",
1289
1437
  "data-form-key": e.formId,
1290
1438
  novalidate: "",
1291
- onSubmit: B
1439
+ onSubmit: q
1292
1440
  }, [
1293
- V(l.$slots, "header", { definition: s.value }),
1294
- y(n).steps.value ? (m(), p("div", mi, [
1295
- V(l.$slots, "progress", {
1296
- current: y(n).currentStepIndex.value,
1297
- total: y(n).steps.value.length,
1298
- step: y(n).currentStep.value
1441
+ V(h.$slots, "header", { definition: s.value }),
1442
+ g(r).steps.value ? (c(), f("div", Vi, [
1443
+ V(h.$slots, "progress", {
1444
+ current: g(r).currentStepIndex.value,
1445
+ total: g(r).steps.value.length,
1446
+ step: g(r).currentStep.value
1299
1447
  }, () => [
1300
1448
  v("p", null, [
1301
- X(" Step " + w(y(n).currentStepIndex.value + 1) + " of " + w(y(n).steps.value.length) + " ", 1),
1302
- y(n).currentStep.value ? (m(), p(U, { key: 0 }, [
1303
- X(" — " + w(y(n).currentStep.value.title), 1)
1304
- ], 64)) : I("", !0)
1449
+ W(" Step " + w(g(r).currentStepIndex.value + 1) + " of " + w(g(r).steps.value.length) + " ", 1),
1450
+ g(r).currentStep.value ? (c(), f(K, { key: 0 }, [
1451
+ W(" — " + w(g(r).currentStep.value.title), 1)
1452
+ ], 64)) : T("", !0)
1305
1453
  ])
1306
1454
  ])
1307
- ])) : I("", !0),
1308
- v("div", fi, [
1309
- (m(!0), p(U, null, W(y(n).visibleFields.value, (g) => (m(), j(Le(M(g)), {
1310
- key: g.id,
1311
- field: g,
1312
- "attachment-policy": c.value.attachmentPolicy,
1313
- "model-value": y(n).values[g.id],
1314
- error: y(n).errors.value[g.id],
1315
- "onUpdate:modelValue": (P) => y(n).setValue(g.id, P),
1316
- onBlur: (P) => y(n).touch(g.id)
1317
- }, null, 40, ["field", "attachment-policy", "model-value", "error", "onUpdate:modelValue", "onBlur"]))), 128))
1455
+ ])) : T("", !0),
1456
+ v("div", Mi, [
1457
+ (c(!0), f(K, null, G(g(r).visibleFields.value, (A, y) => (c(), f(K, {
1458
+ key: A.id
1459
+ }, [
1460
+ D.value && y === p.value ? (c(), f("p", Ei, [
1461
+ v("strong", null, w(g(we).lead), 1),
1462
+ W(" " + w(g(we).detail), 1)
1463
+ ])) : T("", !0),
1464
+ (c(), _(De(O(A)), {
1465
+ field: A,
1466
+ "attachment-policy": u.value.attachmentPolicy,
1467
+ "model-value": g(r).values[A.id],
1468
+ error: g(r).errors.value[A.id],
1469
+ "onUpdate:modelValue": (x) => g(r).setValue(A.id, x),
1470
+ onBlur: (x) => g(r).touch(A.id)
1471
+ }, null, 40, ["field", "attachment-policy", "model-value", "error", "onUpdate:modelValue", "onBlur"]))
1472
+ ], 64))), 128))
1318
1473
  ]),
1319
- y(n).submitError.value ? (m(), p("div", pi, w(y(n).submitError.value), 1)) : I("", !0),
1320
- v("div", hi, [
1321
- V(l.$slots, "actions", {
1322
- isFirstStep: y(n).isFirstStep.value,
1323
- isLastStep: y(n).isLastStep.value,
1324
- submitting: y(n).submitting.value,
1325
- prev: y(n).prev,
1326
- next: y(n).next
1474
+ g(r).submitError.value ? (c(), f("div", Oi, w(g(r).submitError.value), 1)) : T("", !0),
1475
+ v("div", Ri, [
1476
+ V(h.$slots, "actions", {
1477
+ isFirstStep: g(r).isFirstStep.value,
1478
+ isLastStep: g(r).isLastStep.value,
1479
+ submitting: g(r).submitting.value,
1480
+ prev: g(r).prev,
1481
+ next: g(r).next
1327
1482
  }, () => [
1328
- y(n).steps.value && !y(n).isFirstStep.value ? (m(), p("button", {
1483
+ g(r).steps.value && !g(r).isFirstStep.value ? (c(), f("button", {
1329
1484
  key: 0,
1330
1485
  type: "button",
1331
1486
  class: "dcs-form__btn dcs-form__btn--prev",
1332
- onClick: F[0] || (F[0] = (g) => y(n).prev())
1333
- }, " Previous ")) : I("", !0),
1334
- y(n).steps.value && !y(n).isLastStep.value ? (m(), p("button", {
1487
+ onClick: C[0] || (C[0] = (A) => g(r).prev())
1488
+ }, " Previous ")) : T("", !0),
1489
+ g(r).steps.value && !g(r).isLastStep.value ? (c(), f("button", {
1335
1490
  key: 1,
1336
1491
  type: "button",
1337
1492
  class: "dcs-form__btn dcs-form__btn--next",
1338
- onClick: F[1] || (F[1] = (g) => y(n).next())
1339
- }, " Next ")) : I("", !0),
1340
- !y(n).steps.value || y(n).isLastStep.value ? (m(), p("button", {
1493
+ onClick: C[1] || (C[1] = (A) => g(r).next())
1494
+ }, " Next ")) : T("", !0),
1495
+ !g(r).steps.value || g(r).isLastStep.value ? (c(), f("button", {
1341
1496
  key: 2,
1342
1497
  type: "submit",
1343
1498
  class: "dcs-form__btn dcs-form__btn--submit",
1344
- disabled: y(n).submitting.value
1345
- }, w(y(n).submitting.value ? "Sending…" : q.value), 9, yi)) : I("", !0)
1499
+ disabled: g(r).submitting.value
1500
+ }, w(g(r).submitting.value ? "Sending…" : P.value), 9, Di)) : T("", !0)
1346
1501
  ])
1347
1502
  ])
1348
- ], 40, ci)) : (m(), p("div", {
1503
+ ], 40, Ai)) : (c(), f("div", {
1349
1504
  key: 0,
1350
1505
  class: "dcs-form dcs-form--missing",
1351
1506
  "data-form-key": e.formId
1352
1507
  }, [
1353
- V(l.$slots, "missing", { formId: e.formId }, () => [
1508
+ V(h.$slots, "missing", { formId: e.formId }, () => [
1354
1509
  v("p", null, "Form “" + w(e.formId) + "” is not configured.", 1)
1355
1510
  ])
1356
- ], 8, di));
1511
+ ], 8, Ti));
1357
1512
  }
1358
- }), Pi = {
1513
+ }), en = {
1359
1514
  contact: {
1360
1515
  label: "Contact",
1361
1516
  description: "Canonical contact form with standard contact fields."
@@ -1372,7 +1527,7 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1372
1527
  label: "Custom / free-form",
1373
1528
  description: "Flexible starter that stays fully editable for questionnaires and bespoke intake."
1374
1529
  }
1375
- }, gi = () => [
1530
+ }, ji = () => [
1376
1531
  { id: "name", type: "text", role: "contact-name", label: "Full name", required: !0, width: "full" },
1377
1532
  { id: "email", type: "email", role: "contact-email", label: "Email", required: !0, width: "half" },
1378
1533
  { id: "phone", type: "tel", role: "contact-phone", label: "Phone", width: "half" },
@@ -1386,7 +1541,7 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1386
1541
  width: "full",
1387
1542
  validation: { minLength: 10, maxLength: 2e3 }
1388
1543
  }
1389
- ], bi = () => [
1544
+ ], _i = () => [
1390
1545
  { id: "name", type: "text", role: "contact-name", label: "Full name", required: !0, width: "full" },
1391
1546
  { id: "email", type: "email", role: "contact-email", label: "Email", required: !0, width: "half" },
1392
1547
  { id: "phone", type: "tel", role: "contact-phone", label: "Phone", required: !0, width: "half" },
@@ -1410,7 +1565,7 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1410
1565
  width: "full",
1411
1566
  validation: { accept: ["image/*"] }
1412
1567
  }
1413
- ], vi = () => [
1568
+ ], Bi = () => [
1414
1569
  { id: "name", type: "text", role: "contact-name", label: "Full name", required: !0, width: "full" },
1415
1570
  { id: "email", type: "email", role: "contact-email", label: "Email", required: !0, width: "half" },
1416
1571
  { id: "phone", type: "tel", role: "contact-phone", label: "Phone", width: "half" },
@@ -1438,7 +1593,7 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1438
1593
  ]
1439
1594
  }
1440
1595
  }
1441
- ], Fi = () => [
1596
+ ], Ni = () => [
1442
1597
  { id: "name", type: "text", label: "Full name", required: !0, width: "full" },
1443
1598
  { id: "email", type: "email", label: "Email", required: !0, width: "half" },
1444
1599
  { id: "phone", type: "tel", label: "Phone", width: "half" },
@@ -1451,7 +1606,7 @@ const bt = ["data-form-field-key"], vt = ["for"], Ft = {
1451
1606
  validation: { minLength: 10, maxLength: 2e3 }
1452
1607
  }
1453
1608
  ];
1454
- function Li(e, t = {}) {
1609
+ function tn(e, t = {}) {
1455
1610
  switch (e ?? "custom") {
1456
1611
  case "contact":
1457
1612
  return {
@@ -1463,7 +1618,7 @@ function Li(e, t = {}) {
1463
1618
  kind: "lead",
1464
1619
  ...t.leadCategory ? { category: t.leadCategory } : {}
1465
1620
  },
1466
- fields: gi()
1621
+ fields: ji()
1467
1622
  };
1468
1623
  case "revenue-contractor":
1469
1624
  return {
@@ -1481,7 +1636,7 @@ function Li(e, t = {}) {
1481
1636
  maxFiles: 5,
1482
1637
  accept: ["image/*"]
1483
1638
  },
1484
- fields: bi()
1639
+ fields: _i()
1485
1640
  };
1486
1641
  case "resume-submission":
1487
1642
  return {
@@ -1503,7 +1658,7 @@ function Li(e, t = {}) {
1503
1658
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
1504
1659
  ]
1505
1660
  },
1506
- fields: vi()
1661
+ fields: Bi()
1507
1662
  };
1508
1663
  default:
1509
1664
  return {
@@ -1515,35 +1670,45 @@ function Li(e, t = {}) {
1515
1670
  kind: "lead",
1516
1671
  ...t.leadCategory ? { category: t.leadCategory } : {}
1517
1672
  },
1518
- fields: Fi()
1673
+ fields: Ni()
1519
1674
  };
1520
1675
  }
1521
1676
  }
1522
1677
  export {
1523
- qi as DcsForm,
1524
- zt as DcsFormCheckbox,
1525
- Ot as DcsFormCheckboxGroup,
1526
- Nt as DcsFormDate,
1527
- E as DcsFormFieldWrapper,
1528
- ei as DcsFormFile,
1529
- ii as DcsFormHidden,
1530
- li as DcsFormHtmlBlock,
1531
- At as DcsFormRadio,
1532
- ai as DcsFormSection,
1533
- It as DcsFormSelect,
1534
- ce as DcsFormText,
1535
- kt as DcsFormTextarea,
1536
- Pi as STANDARD_FORM_PRESET_META,
1537
- Li as buildStandardFormDefinition,
1538
- He as hasErrors,
1539
- ne as isFieldVisible,
1540
- ht as loadFormDefinitions,
1541
- ki as parseFormYaml,
1542
- Xe as submitFormValues,
1543
- Qe as useDcsForm,
1544
- Ue as validateField,
1545
- We as validateForm,
1546
- ft as validateFormDefinition,
1547
- pt as warnIfInvalid
1678
+ Zi as DcsForm,
1679
+ di as DcsFormCheckbox,
1680
+ ri as DcsFormCheckboxGroup,
1681
+ ci as DcsFormDate,
1682
+ N as DcsFormFieldWrapper,
1683
+ Fi as DcsFormFile,
1684
+ $i as DcsFormHidden,
1685
+ Li as DcsFormHtmlBlock,
1686
+ ei as DcsFormRadio,
1687
+ qi as DcsFormSection,
1688
+ Yt as DcsFormSelect,
1689
+ Fe as DcsFormText,
1690
+ Ht as DcsFormTextarea,
1691
+ we as PHI_GUIDANCE_COPY,
1692
+ en as STANDARD_FORM_PRESET_META,
1693
+ tn as buildStandardFormDefinition,
1694
+ $t as fetchSiteHandlesPhi,
1695
+ nt as hasErrors,
1696
+ Yi as isBookingCancellationReceipt,
1697
+ Gi as isEstimateReceipt,
1698
+ de as isFieldVisible,
1699
+ ct as isManagedFormReceipt,
1700
+ Ji as isPasswordlessVerifyReceipt,
1701
+ Wi as isSiteContactReceipt,
1702
+ Ot as loadFormDefinitions,
1703
+ Xi as parseFormYaml,
1704
+ dt as readExpectedJson,
1705
+ lt as readOkBody,
1706
+ Qi as resetSitePhiPostureCache,
1707
+ vt as submitFormValues,
1708
+ st as useDcsForm,
1709
+ tt as validateField,
1710
+ it as validateForm,
1711
+ Mt as validateFormDefinition,
1712
+ Et as warnIfInvalid
1548
1713
  };
1549
1714
  //# sourceMappingURL=index.js.map