@flamingo-stack/openframe-frontend-core 0.0.664 → 0.0.665-2372.7061.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.
@@ -1 +1 @@
1
- {"version":3,"file":"booking-form.d.ts","sourceRoot":"","sources":["../../../src/components/meeting-scheduler/booking-form.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAGvD,OAAO,EAEL,KAAK,uBAAuB,EAM5B,KAAK,mBAAmB,EAKzB,MAAM,sCAAsC,CAAC;AAsB9C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yFAAyF;IACzF,IAAI,EAAE,uBAAuB,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,gFAAgF;IAChF,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,+EAA+E;AAC/E,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,UAAU,CAAC;AAEvD,MAAM,MAAM,eAAe,GAAG,gBAAgB,EAAE,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAiBD;6CAC6C;AAC7C,QAAA,MAAM,UAAU;;;;;CAKN,CAAC;AAOX,0GAA0G;AAC1G,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAYtD;iFACiF;AACjF,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,EAAE,OAAO,MAAM,KAAG,gBAIvD,CAAC;AAqJF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,mBAAmB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;qEACiE;IACjE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,uFAAuF;IACvF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,mFAAmF;IACnF,kBAAkB,EAAE;QAAE,GAAG,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,UAAU,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CACnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,YAAY,EACZ,SAAS,EACT,WAAW,EACX,UAAU,EACV,QAAQ,EACR,SAAiB,EACjB,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,kBAAkB,EAClB,UAAU,GACX,EAAE,gBAAgB,+BAoTlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,OAAO,EACP,UAAU,GACX,EAAE;IACD,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B;;qDAEiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,+BA2BA"}
1
+ {"version":3,"file":"booking-form.d.ts","sourceRoot":"","sources":["../../../src/components/meeting-scheduler/booking-form.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAGvD,OAAO,EAEL,KAAK,uBAAuB,EAQ5B,KAAK,mBAAmB,EAKzB,MAAM,sCAAsC,CAAC;AAsB9C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yFAAyF;IACzF,IAAI,EAAE,uBAAuB,GAAG,CAAC,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAChE,gFAAgF;IAChF,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAED,+EAA+E;AAC/E,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,UAAU,CAAC;AAEvD,MAAM,MAAM,eAAe,GAAG,gBAAgB,EAAE,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAiBD;6CAC6C;AAC7C,QAAA,MAAM,UAAU;;;;;CAKN,CAAC;AAOX,0GAA0G;AAC1G,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AAYtD;iFACiF;AACjF,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,EAAE,OAAO,MAAM,KAAG,gBAIvD,CAAC;AA+MF,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,mBAAmB,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;qEACiE;IACjE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,uFAAuF;IACvF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,mFAAmF;IACnF,kBAAkB,EAAE;QAAE,GAAG,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,UAAU,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CACnD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,YAAY,EACZ,SAAS,EACT,WAAW,EACX,UAAU,EACV,QAAQ,EACR,SAAiB,EACjB,aAAa,EACb,WAAW,EACX,UAAU,EACV,SAAS,EACT,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,kBAAkB,EAClB,UAAU,GACX,EAAE,gBAAgB,+BAuTlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,OAAO,EACP,UAAU,GACX,EAAE;IACD,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B;;qDAEiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,+BA2BA"}
@@ -101,6 +101,18 @@ var optionValidator = (field, base) => base.refine((v) => !v || (_nullishCoalesc
101
101
  message: `Please choose a valid option for ${field.label}`
102
102
  });
103
103
  var DECIMAL_LITERAL_RE = /^-?\d+(\.\d+)?$/;
104
+ var MULTI_VALUE_SEPARATOR = ";";
105
+ var splitMultiValue = (value) => typeof value === "string" && value ? value.split(MULTI_VALUE_SEPARATOR) : [];
106
+ var PHONE_RE = /^\+?[\d\s().\-/]+(?:\s*(?:x|ext\.?)\s*\d+)?$/i;
107
+ var PHONE_MIN_DIGITS = 5;
108
+ var PHONE_MAX_DIGITS = 20;
109
+ var phoneDigits = (v) => v.replace(/\D/g, "").length;
110
+ var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
111
+ var isRealIsoDate = (v) => {
112
+ if (!ISO_DATE_RE.test(v)) return false;
113
+ const d = /* @__PURE__ */ new Date(`${v}T00:00:00Z`);
114
+ return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === v;
115
+ };
104
116
  var FORM_FIELD_TYPES = {
105
117
  text: {
106
118
  kind: "string",
@@ -121,16 +133,85 @@ var FORM_FIELD_TYPES = {
121
133
  // accepts (`1e3`, `007`) to this before it is validated or sent.
122
134
  validator: (field, base) => base.max(32, { message: `${field.label} is too long` }).regex(DECIMAL_LITERAL_RE, { message: `${field.label} must be a number` })
123
135
  },
136
+ phone: {
137
+ kind: "string",
138
+ hasOptions: false,
139
+ validator: (field, base) => base.max(40, { message: `${field.label} is too long` }).refine(
140
+ (v) => !v || PHONE_RE.test(v) && phoneDigits(v) >= PHONE_MIN_DIGITS && phoneDigits(v) <= PHONE_MAX_DIGITS,
141
+ { message: `Please enter a valid phone number for ${field.label}` }
142
+ ),
143
+ placeholder: (field) => `Enter ${field.label}`
144
+ },
145
+ date: {
146
+ kind: "string",
147
+ hasOptions: false,
148
+ validator: (field, base) => base.refine((v) => !v || isRealIsoDate(v), { message: `${field.label} must be a date` })
149
+ },
124
150
  select: { kind: "string", hasOptions: true, validator: optionValidator },
125
151
  radio: { kind: "string", hasOptions: true, validator: optionValidator },
152
+ multiselect: {
153
+ kind: "string",
154
+ hasOptions: true,
155
+ validator: (field, base) => base.refine((v) => splitMultiValue(v).every((part) => (_nullishCoalesce(field.options, () => ( []))).includes(part)), {
156
+ message: `Please choose valid options for ${field.label}`
157
+ })
158
+ },
126
159
  checkbox: { kind: "boolean", hasOptions: false, validator: () => _zod.z.boolean() }
127
160
  };
128
161
  var SUPPORTED_FORM_FIELD_TYPES = Object.keys(FORM_FIELD_TYPES);
129
- var FORM_FIELD_TYPES_WITH_OPTIONS = SUPPORTED_FORM_FIELD_TYPES.filter(
130
- (type) => FORM_FIELD_TYPES[type].hasOptions
131
- );
132
- function isSupportedFormField(field) {
133
- return Object.prototype.hasOwnProperty.call(FORM_FIELD_TYPES, field.type);
162
+ var FIELD_TYPE_CONTROLS = {
163
+ text: "text",
164
+ textarea: "textarea",
165
+ number: "number",
166
+ select: "select",
167
+ radio: "radio",
168
+ booleancheckbox: "checkbox",
169
+ phonenumber: "phone",
170
+ date: "date",
171
+ html: "display",
172
+ file: "unanswerable"
173
+ };
174
+ var DATA_TYPE_CONTROLS = {
175
+ string: "text",
176
+ number: "number",
177
+ enumeration: "select",
178
+ bool: "checkbox",
179
+ date: "date",
180
+ datetime: "date",
181
+ phone_number: "phone"
182
+ };
183
+ var hasDeclaredOptions = (field) => (_nullishCoalesce(_optionalChain([field, 'access', _2 => _2.options, 'optionalAccess', _3 => _3.length]), () => ( 0))) > 0;
184
+ function resolveFormFieldControl(field) {
185
+ const fieldType = (_nullishCoalesce(field.type, () => ( ""))).toLowerCase();
186
+ const withOptions = hasDeclaredOptions(field);
187
+ const usable = (r) => {
188
+ if (!r || r === "display" || r === "unanswerable") return r;
189
+ return FORM_FIELD_TYPES[r].hasOptions && !withOptions ? "text" : r;
190
+ };
191
+ if (fieldType === "checkbox") return withOptions ? "multiselect" : "checkbox";
192
+ if (fieldType.startsWith("calculation")) return "display";
193
+ const asControl = Object.prototype.hasOwnProperty.call(FORM_FIELD_TYPES, fieldType) ? fieldType : void 0;
194
+ return _nullishCoalesce(_nullishCoalesce(usable(_nullishCoalesce(FIELD_TYPE_CONTROLS[fieldType], () => ( asControl))), () => ( usable(DATA_TYPE_CONTROLS[(_nullishCoalesce(field.dataType, () => ( ""))).toLowerCase()]))), () => ( (withOptions ? "select" : "text")));
195
+ }
196
+ function normalizeFormField(field) {
197
+ const control = resolveFormFieldControl(field);
198
+ if (control === "display" || control === "unanswerable") return null;
199
+ const normalized = {
200
+ ...field,
201
+ type: control,
202
+ hubspotType: _nullishCoalesce(field.hubspotType, () => ( field.type))
203
+ };
204
+ if (!FORM_FIELD_TYPES[control].hasOptions) {
205
+ delete normalized.options;
206
+ delete normalized.optionLabels;
207
+ }
208
+ return normalized;
209
+ }
210
+ function normalizeFormFields(fields) {
211
+ return fields.flatMap((f) => _nullishCoalesce(normalizeFormField(f), () => ( [])));
212
+ }
213
+ function blocksNativeBooking(field) {
214
+ return field.required && resolveFormFieldControl(field) === "unanswerable";
134
215
  }
135
216
  var BUILT_IN_BOOKING_FIELDS = [
136
217
  {
@@ -188,8 +269,8 @@ function isValidBcp47Locale(locale) {
188
269
  }
189
270
  function buildBookingSchema(formFields, legalConsent, slot) {
190
271
  const answers = {};
191
- for (const field of formFields) {
192
- if (!isSupportedFormField(field)) continue;
272
+ const drawn = normalizeFormFields(formFields);
273
+ for (const field of drawn) {
193
274
  const spec = FORM_FIELD_TYPES[field.type];
194
275
  let validator;
195
276
  if (spec.kind === "boolean") {
@@ -201,8 +282,8 @@ function buildBookingSchema(formFields, legalConsent, slot) {
201
282
  }
202
283
  answers[field.name] = validator;
203
284
  }
204
- const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _2 => _2.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
205
- const hasRequiredAnswers = formFields.some((f) => isSupportedFormField(f) && f.required);
285
+ const requiredConsentIds = (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _4 => _4.communicationConsentCheckboxes]), () => ( []))).filter((c) => c.required).map((c) => c.communicationTypeId);
286
+ const hasRequiredAnswers = drawn.some((f) => f.required);
206
287
  const answersObject = _zod.z.object(answers);
207
288
  return _zod.z.object({
208
289
  meetingId: _zod.z.string().min(1),
@@ -254,7 +335,7 @@ var BOOKING_IN_FLIGHT_MESSAGE = "Already submitting";
254
335
  function useMeetingBooking(options) {
255
336
  const { meetingId, apiBaseUrl = "", initialAvailability } = options;
256
337
  const queryClient = _reactquery.useQueryClient.call(void 0, );
257
- const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _3 => _3.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
338
+ const seededOffset = _optionalChain([initialAvailability, 'optionalAccess', _5 => _5.meetingId]) === meetingId ? initialAvailability.monthOffset : void 0;
258
339
  const [monthOffset, setMonthOffsetState] = _react.useState.call(void 0, _nullishCoalesce(seededOffset, () => ( 0)));
259
340
  const setMonthOffset = _react.useCallback.call(void 0, (offset) => {
260
341
  setMonthOffsetState(Math.max(0, Math.min(_chunk6FD7ZEBYcjs.MAX_MONTH_OFFSET, offset)));
@@ -265,7 +346,7 @@ function useMeetingBooking(options) {
265
346
  prevMeetingIdRef.current = meetingId;
266
347
  setMonthOffsetState(0);
267
348
  }, [meetingId]);
268
- const seed = _optionalChain([initialAvailability, 'optionalAccess', _4 => _4.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
349
+ const seed = _optionalChain([initialAvailability, 'optionalAccess', _6 => _6.meetingId]) === meetingId && initialAvailability.monthOffset === monthOffset ? initialAvailability : void 0;
269
350
  const availabilityQuery = _reactquery.useQuery.call(void 0, {
270
351
  queryKey: meetingAvailabilityKey(apiBaseUrl, meetingId, monthOffset),
271
352
  queryFn: async ({ signal }) => {
@@ -361,7 +442,9 @@ var evenSpan = (count, index) => {
361
442
  return Math.min(GRID_COLUMNS, Math.max(1, index < extra ? base + 1 : base));
362
443
  };
363
444
  var slotColumnClass = (row, slot, index) => _chunkX7CEWD6Vcjs.cn.call(void 0, row.length === 2 ? "col-span-1" : "col-span-2", SPAN_CLASS[_nullishCoalesce(slot.span, () => ( evenSpan(row.length, index)))]);
364
- var placeholderFor = (field) => _nullishCoalesce(field.placeholder, () => ( _optionalChain([fieldTypeSpec, 'call', _5 => _5(field.type), 'access', _6 => _6.placeholder, 'optionalCall', _7 => _7(field)])));
445
+ var placeholderFor = (field) => _nullishCoalesce(field.placeholder, () => ( _optionalChain([fieldTypeSpec, 'call', _7 => _7(field.type), 'access', _8 => _8.placeholder, 'optionalCall', _9 => _9(field)])));
446
+ var optionLabel = (field, value) => _nullishCoalesce(_optionalChain([field, 'access', _10 => _10.optionLabels, 'optionalAccess', _11 => _11[value]]), () => ( value));
447
+ var trimmed = (v) => String(_nullishCoalesce(v, () => ( ""))).trim();
365
448
  var canonicalNumber = (v) => {
366
449
  const s = String(_nullishCoalesce(v, () => ( ""))).trim();
367
450
  if (s === "" || DECIMAL_LITERAL_RE.test(s)) return s;
@@ -405,6 +488,32 @@ var FIELD_CONTROLS = {
405
488
  ...register(registerName, { setValueAs: canonicalNumber })
406
489
  }
407
490
  ),
491
+ phone: ({ field, id, registerName, error, register }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
492
+ _chunkQVSVRG7Icjs.Input,
493
+ {
494
+ id,
495
+ type: "tel",
496
+ inputMode: "tel",
497
+ autoComplete: "tel",
498
+ required: field.required,
499
+ "aria-invalid": Boolean(error),
500
+ placeholder: placeholderFor(field),
501
+ ...register(registerName, { setValueAs: trimmed })
502
+ }
503
+ ),
504
+ date: ({ field, id, registerName, error, register }) => (
505
+ // The native picker emits exactly the wire shape (`YYYY-MM-DD`).
506
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
507
+ _chunkQVSVRG7Icjs.Input,
508
+ {
509
+ id,
510
+ type: "date",
511
+ required: field.required,
512
+ "aria-invalid": Boolean(error),
513
+ ...register(registerName)
514
+ }
515
+ )
516
+ ),
408
517
  select: ({ field, id, registerName, error, control }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
409
518
  _reacthookform.Controller,
410
519
  {
@@ -412,7 +521,7 @@ var FIELD_CONTROLS = {
412
521
  name: registerName,
413
522
  render: ({ field: rhf }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk6FD7ZEBYcjs.Select, { value: _nullishCoalesce(rhf.value, () => ( "")), onValueChange: rhf.onChange, children: [
414
523
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.SelectTrigger, { id, "aria-required": field.required || void 0, "aria-invalid": Boolean(error), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.SelectValue, { placeholder: "Select\u2026" }) }),
415
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.SelectItem, { value: opt, children: opt }, opt)) })
524
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.SelectContent, { children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.SelectItem, { value: opt, children: optionLabel(field, opt) }, opt)) })
416
525
  ] })
417
526
  }
418
527
  ),
@@ -430,12 +539,42 @@ var FIELD_CONTROLS = {
430
539
  "aria-invalid": Boolean(error),
431
540
  children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
432
541
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6FD7ZEBYcjs.RadioGroupItem, { id: `${id}-${opt}`, value: opt }),
433
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGSD62VAYcjs.Label, { htmlFor: `${id}-${opt}`, children: opt })
542
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGSD62VAYcjs.Label, { htmlFor: `${id}-${opt}`, children: optionLabel(field, opt) })
434
543
  ] }, opt))
435
544
  }
436
545
  )
437
546
  }
438
547
  ),
548
+ multiselect: ({ field, id, registerName, error, control }) => (
549
+ // HubSpot's "multiple checkboxes": the answer is its `;`-joined value list,
550
+ // held in that wire shape so the validator and the POST see one string.
551
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
552
+ _reacthookform.Controller,
553
+ {
554
+ control,
555
+ name: registerName,
556
+ render: ({ field: rhf }) => {
557
+ const selected = splitMultiValue(rhf.value);
558
+ const toggle = (opt, on) => {
559
+ const next = (_nullishCoalesce(field.options, () => ( []))).filter((o) => o === opt ? on : selected.includes(o));
560
+ rhf.onChange(next.join(MULTI_VALUE_SEPARATOR));
561
+ };
562
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { id, role: "group", className: "flex flex-col gap-[var(--spacing-system-xs)]", children: (_nullishCoalesce(field.options, () => ( []))).map((opt) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex items-center gap-[var(--spacing-system-xs)]", children: [
563
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
564
+ _chunkQVSVRG7Icjs.Checkbox,
565
+ {
566
+ id: `${id}-${opt}`,
567
+ checked: selected.includes(opt),
568
+ onCheckedChange: (v) => toggle(opt, v === true),
569
+ "aria-invalid": Boolean(error)
570
+ }
571
+ ),
572
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGSD62VAYcjs.Label, { htmlFor: `${id}-${opt}`, children: optionLabel(field, opt) })
573
+ ] }, opt)) });
574
+ }
575
+ }
576
+ )
577
+ ),
439
578
  checkbox: ({ field, id, registerName, error, control }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
440
579
  _reacthookform.Controller,
441
580
  {
@@ -478,13 +617,13 @@ function BookingForm({
478
617
  getSignals
479
618
  }) {
480
619
  const { formFields, legalConsent } = availability;
481
- const supportedFields = _react.useMemo.call(void 0, () => formFields.filter(isSupportedFormField), [formFields]);
620
+ const supportedFields = _react.useMemo.call(void 0, () => normalizeFormFields(formFields), [formFields]);
482
621
  const schema = _react.useMemo.call(void 0,
483
622
  () => makeDeferredBookingSchema(supportedFields, legalConsent),
484
623
  [supportedFields, legalConsent]
485
624
  );
486
625
  const consentDefaults = _react.useMemo.call(void 0,
487
- () => (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _8 => _8.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
626
+ () => (_nullishCoalesce(_optionalChain([legalConsent, 'optionalAccess', _12 => _12.communicationConsentCheckboxes]), () => ( []))).map((c) => ({
488
627
  communicationTypeId: c.communicationTypeId,
489
628
  consented: false
490
629
  })),
@@ -515,8 +654,8 @@ function BookingForm({
515
654
  ..._nullishCoalesce(initialValues, () => ( {}))
516
655
  }
517
656
  });
518
- const priorConsents = _optionalChain([initialValues, 'optionalAccess', _9 => _9.legalConsentResponses]);
519
- const [consented, setConsented] = _react.useState.call(void 0, _optionalChain([initialValues, 'optionalAccess', _10 => _10[HOST_CONSENT_KEY]]) === true);
657
+ const priorConsents = _optionalChain([initialValues, 'optionalAccess', _13 => _13.legalConsentResponses]);
658
+ const [consented, setConsented] = _react.useState.call(void 0, _optionalChain([initialValues, 'optionalAccess', _14 => _14[HOST_CONSENT_KEY]]) === true);
520
659
  const [consentError, setConsentError] = _react.useState.call(void 0, null);
521
660
  const consentMissing = Boolean(consent) && !consented;
522
661
  _react.useEffect.call(void 0, () => {
@@ -525,7 +664,7 @@ function BookingForm({
525
664
  "legalConsentResponses",
526
665
  consentDefaults.map((next) => ({
527
666
  ...next,
528
- consented: _nullishCoalesce(_optionalChain([current, 'access', _11 => _11.find, 'call', _12 => _12((r) => r.communicationTypeId === next.communicationTypeId), 'optionalAccess', _13 => _13.consented]), () => ( false))
667
+ consented: _nullishCoalesce(_optionalChain([current, 'access', _15 => _15.find, 'call', _16 => _16((r) => r.communicationTypeId === next.communicationTypeId), 'optionalAccess', _17 => _17.consented]), () => ( false))
529
668
  })),
530
669
  { shouldDirty: false }
531
670
  );
@@ -547,12 +686,12 @@ function BookingForm({
547
686
  });
548
687
  });
549
688
  const submit = (event) => {
550
- if (consentMissing) setConsentError(_nullishCoalesce(_optionalChain([consent, 'optionalAccess', _14 => _14.errorMessage]), () => ( "Please agree to continue.")));
689
+ if (consentMissing) setConsentError(_nullishCoalesce(_optionalChain([consent, 'optionalAccess', _18 => _18.errorMessage]), () => ( "Please agree to continue.")));
551
690
  return submitValid(event);
552
691
  };
553
692
  const fieldError = (name) => {
554
- const err = _optionalChain([errors, 'access', _15 => _15.formFields, 'optionalAccess', _16 => _16[name]]);
555
- return _optionalChain([err, 'optionalAccess', _17 => _17.message]);
693
+ const err = _optionalChain([errors, 'access', _19 => _19.formFields, 'optionalAccess', _20 => _20[name]]);
694
+ return _optionalChain([err, 'optionalAccess', _21 => _21.message]);
556
695
  };
557
696
  const renderField = (field, where) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQVSVRG7Icjs.FieldWrapper, { label: field.label, htmlFor: where.id, required: field.required, error: where.error, children: FIELD_CONTROLS[field.type]({
558
697
  field,
@@ -565,7 +704,7 @@ function BookingForm({
565
704
  const builtInFields = Object.fromEntries(
566
705
  BUILT_IN_BOOKING_FIELDS.map((field) => [
567
706
  field.name,
568
- renderField(field, { id: builtInId(field.name), registerName: field.name, error: _optionalChain([errors, 'access', _18 => _18[field.name], 'optionalAccess', _19 => _19.message]) })
707
+ renderField(field, { id: builtInId(field.name), registerName: field.name, error: _optionalChain([errors, 'access', _22 => _22[field.name], 'optionalAccess', _23 => _23.message]) })
569
708
  ])
570
709
  );
571
710
  const renderDeclaredField = (field) => renderField(field, {
@@ -626,7 +765,7 @@ function BookingForm({
626
765
  // box doesn't shove the submit button down the card. With no error the
627
766
  // wrapper is `display:contents` and the panel below is the flex item,
628
767
  // exactly as it was.
629
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQVSVRG7Icjs.FieldWrapper, { error: _optionalChain([errors, 'access', _20 => _20.legalConsentResponses, 'optionalAccess', _21 => _21.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
768
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkQVSVRG7Icjs.FieldWrapper, { error: _optionalChain([errors, 'access', _24 => _24.legalConsentResponses, 'optionalAccess', _25 => _25.message]), children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-[var(--spacing-system-xs)]", children: [
630
769
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.processingConsentText }),
631
770
  legalConsent.communicationConsentText && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-ods-text-secondary text-h6", children: legalConsent.communicationConsentText }),
632
771
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -645,7 +784,7 @@ function BookingForm({
645
784
  _chunk6FD7ZEBYcjs.CheckboxBlock,
646
785
  {
647
786
  id: `ms-consent-${box.communicationTypeId}`,
648
- checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _22 => _22.consented]), () => ( false)),
787
+ checked: _nullishCoalesce(_optionalChain([current, 'optionalAccess', _26 => _26.consented]), () => ( false)),
649
788
  onCheckedChange: (v) => rhf.onChange(
650
789
  responses.map(
651
790
  (r) => r.communicationTypeId === box.communicationTypeId ? { ...r, consented: v } : r
@@ -740,7 +879,7 @@ function zoneLabel(tz) {
740
879
  timeZone: tz,
741
880
  timeZoneName: "shortOffset"
742
881
  }).formatToParts(/* @__PURE__ */ new Date());
743
- const offset = _nullishCoalesce(_optionalChain([parts, 'access', _23 => _23.find, 'call', _24 => _24((p) => p.type === "timeZoneName"), 'optionalAccess', _25 => _25.value]), () => ( ""));
882
+ const offset = _nullishCoalesce(_optionalChain([parts, 'access', _27 => _27.find, 'call', _28 => _28((p) => p.type === "timeZoneName"), 'optionalAccess', _29 => _29.value]), () => ( ""));
744
883
  return offset ? `${tz.replace(/_/g, " ")} (${offset})` : tz.replace(/_/g, " ");
745
884
  } catch (e4) {
746
885
  return tz.replace(/_/g, " ");
@@ -867,7 +1006,7 @@ function SchedulerContextPanel({
867
1006
  value: timezone,
868
1007
  disabled,
869
1008
  onChange: (tz) => {
870
- if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _26 => _26(tz)]);
1009
+ if (tz) _optionalChain([onTimezoneChange, 'optionalCall', _30 => _30(tz)]);
871
1010
  },
872
1011
  options: zoneOptions,
873
1012
  placeholder: "Search timezone\u2026",
@@ -951,7 +1090,7 @@ function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDa
951
1090
  const startMonth = new Date(now.getFullYear(), now.getMonth(), 1);
952
1091
  const endMonth = new Date(now.getFullYear(), now.getMonth() + _chunk6FD7ZEBYcjs.MAX_MONTH_OFFSET + 1, 0);
953
1092
  const visibleMonth = new Date(now.getFullYear(), now.getMonth() + monthOffset, 1);
954
- const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _27 => _27.has, 'call', _28 => _28(calendarDayKey(day))]), [slotsByDay]);
1093
+ const dayHasNoSlots = _react.useCallback.call(void 0, (day) => !_optionalChain([slotsByDay, 'optionalAccess', _31 => _31.has, 'call', _32 => _32(calendarDayKey(day))]), [slotsByDay]);
955
1094
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex min-h-0 flex-1 flex-col", "aria-busy": slotsByDay === null, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
956
1095
  _chunk6FD7ZEBYcjs.DatePickerCalendar,
957
1096
  {
@@ -969,7 +1108,7 @@ function DayCalendar({ monthOffset, onMonthOffsetChange, selectedDay, onSelectDa
969
1108
  const day = value;
970
1109
  if (!day) return;
971
1110
  const key = calendarDayKey(day);
972
- if (_optionalChain([slotsByDay, 'optionalAccess', _29 => _29.has, 'call', _30 => _30(key)])) onSelectDay(key);
1111
+ if (_optionalChain([slotsByDay, 'optionalAccess', _33 => _33.has, 'call', _34 => _34(key)])) onSelectDay(key);
973
1112
  },
974
1113
  disabledDays: slotsByDay === null ? DISABLE_EVERY_DAY : dayHasNoSlots
975
1114
  }
@@ -1193,7 +1332,7 @@ function MeetingSchedulerDirectory({
1193
1332
  };
1194
1333
  }, [initialData, includeAll, apiBaseUrl]);
1195
1334
  const rows = _react.useMemo.call(void 0, () => {
1196
- const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _31 => _31.purposes]), () => ( []));
1335
+ const purposes = _nullishCoalesce(_optionalChain([data, 'optionalAccess', _35 => _35.purposes]), () => ( []));
1197
1336
  return purposes.flatMap((p) => p.links.map((link) => ({ link, audienceLabel: p.label })));
1198
1337
  }, [data]);
1199
1338
  const totalPages = _chunkVTYP25OWcjs.pageCount.call(void 0, rows.length, pageSize);
@@ -1293,7 +1432,7 @@ function SchedulerDegradedCard({
1293
1432
  ] });
1294
1433
  }
1295
1434
  function isNativelyBookable(availability) {
1296
- if (!availability.formFields.every(isSupportedFormField)) return false;
1435
+ if (availability.formFields.some(blocksNativeBooking)) return false;
1297
1436
  const consent = availability.legalConsent;
1298
1437
  if (consent) {
1299
1438
  if (typeof consent.processingConsentText !== "string") return false;
@@ -1349,7 +1488,7 @@ function HubSpotMeetingScheduler({
1349
1488
  onStageChangeRef.current = onStageChange;
1350
1489
  });
1351
1490
  _react.useEffect.call(void 0, () => {
1352
- _optionalChain([onStageChangeRef, 'access', _32 => _32.current, 'optionalCall', _33 => _33(stage)]);
1491
+ _optionalChain([onStageChangeRef, 'access', _36 => _36.current, 'optionalCall', _37 => _37(stage)]);
1353
1492
  }, [stage]);
1354
1493
  const [stash, setStash] = _react.useState.call(void 0, null);
1355
1494
  const inFlightRef = _react.useRef.call(void 0, false);
@@ -1380,8 +1519,8 @@ function HubSpotMeetingScheduler({
1380
1519
  _react.useEffect.call(void 0, () => {
1381
1520
  autoAdvanceCount.current = 0;
1382
1521
  }, [meetingId]);
1383
- const durations = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _34 => _34.durationsMs]), () => ( [])), [_optionalChain([availability, 'optionalAccess', _35 => _35.durationsMs])]);
1384
- const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _36 => _36.hosts]))), () => ( []));
1522
+ const durations = _react.useMemo.call(void 0, () => _nullishCoalesce(_optionalChain([availability, 'optionalAccess', _38 => _38.durationsMs]), () => ( [])), [_optionalChain([availability, 'optionalAccess', _39 => _39.durationsMs])]);
1523
+ const shownHosts = _nullishCoalesce(_nullishCoalesce(hosts, () => ( _optionalChain([availability, 'optionalAccess', _40 => _40.hosts]))), () => ( []));
1385
1524
  const durationMs = _nullishCoalesce(_nullishCoalesce(pickedDurationMs, () => ( durations[0])), () => ( null));
1386
1525
  const slots = _react.useMemo.call(void 0, () => {
1387
1526
  if (!availability || durationMs == null) return [];
@@ -1440,7 +1579,7 @@ function HubSpotMeetingScheduler({
1440
1579
  if (result.ok && result.confirmation) {
1441
1580
  setConfirmation(result.confirmation);
1442
1581
  setStep("confirmed");
1443
- _optionalChain([onBooked, 'optionalCall', _37 => _37(result.confirmation)]);
1582
+ _optionalChain([onBooked, 'optionalCall', _41 => _41(result.confirmation)]);
1444
1583
  return;
1445
1584
  }
1446
1585
  const code = _nullishCoalesce(result.code, () => ( "TEMPORARILY_UNAVAILABLE"));
@@ -1488,8 +1627,8 @@ function HubSpotMeetingScheduler({
1488
1627
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: stepPanelClass, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1489
1628
  BookingFormSkeleton,
1490
1629
  {
1491
- fieldRows: _optionalChain([detailsFormProps, 'optionalAccess', _38 => _38.fieldRows]),
1492
- consent: Boolean(_optionalChain([detailsFormProps, 'optionalAccess', _39 => _39.consent])),
1630
+ fieldRows: _optionalChain([detailsFormProps, 'optionalAccess', _42 => _42.fieldRows]),
1631
+ consent: Boolean(_optionalChain([detailsFormProps, 'optionalAccess', _43 => _43.consent])),
1493
1632
  footerNote: preset.footerNote
1494
1633
  }
1495
1634
  ) })
@@ -1550,7 +1689,7 @@ function HubSpotMeetingScheduler({
1550
1689
  deferSlot: detailsFirst,
1551
1690
  submitLabel: preset.submitLabel,
1552
1691
  footerNote: preset.footerNote,
1553
- initialValues: detailsFirst ? _optionalChain([stash, 'optionalAccess', _40 => _40.payload]) : void 0,
1692
+ initialValues: detailsFirst ? _optionalChain([stash, 'optionalAccess', _44 => _44.payload]) : void 0,
1554
1693
  isSubmitting,
1555
1694
  onSubmit: detailsFirst ? stashDetails : handleSubmit,
1556
1695
  honeypotInputProps,