@page-speed/forms 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +29 -0
  2. package/dist/chunk-232KNGJI.js +207 -0
  3. package/dist/chunk-232KNGJI.js.map +1 -0
  4. package/dist/chunk-24RPM43T.js +373 -0
  5. package/dist/chunk-24RPM43T.js.map +1 -0
  6. package/dist/chunk-27JUYRDE.cjs +173 -0
  7. package/dist/chunk-27JUYRDE.cjs.map +1 -0
  8. package/dist/chunk-5NT5T5XY.js +4136 -0
  9. package/dist/chunk-5NT5T5XY.js.map +1 -0
  10. package/dist/chunk-AVAKC6R7.cjs +236 -0
  11. package/dist/chunk-AVAKC6R7.cjs.map +1 -0
  12. package/dist/chunk-DKLLPKZN.cjs +238 -0
  13. package/dist/chunk-DKLLPKZN.cjs.map +1 -0
  14. package/dist/chunk-EX6CRLKG.cjs +397 -0
  15. package/dist/chunk-EX6CRLKG.cjs.map +1 -0
  16. package/dist/chunk-H6NNFV64.js +127 -0
  17. package/dist/chunk-H6NNFV64.js.map +1 -0
  18. package/dist/chunk-JBEWTBFH.js +217 -0
  19. package/dist/chunk-JBEWTBFH.js.map +1 -0
  20. package/dist/chunk-JBEZLX3H.cjs +138 -0
  21. package/dist/chunk-JBEZLX3H.cjs.map +1 -0
  22. package/dist/chunk-VLGZG2VP.js +150 -0
  23. package/dist/chunk-VLGZG2VP.js.map +1 -0
  24. package/dist/chunk-ZYFTT6DB.cjs +4169 -0
  25. package/dist/chunk-ZYFTT6DB.cjs.map +1 -0
  26. package/dist/core.cjs +23 -722
  27. package/dist/core.cjs.map +1 -1
  28. package/dist/core.d.cts +3 -3
  29. package/dist/core.d.ts +3 -3
  30. package/dist/core.js +3 -705
  31. package/dist/core.js.map +1 -1
  32. package/dist/index.cjs +43 -727
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +3 -705
  37. package/dist/index.js.map +1 -1
  38. package/dist/inputs.cjs +44 -4359
  39. package/dist/inputs.cjs.map +1 -1
  40. package/dist/inputs.d.cts +1 -1
  41. package/dist/inputs.d.ts +1 -1
  42. package/dist/inputs.js +2 -4337
  43. package/dist/inputs.js.map +1 -1
  44. package/dist/integration.cjs +574 -9
  45. package/dist/integration.cjs.map +1 -1
  46. package/dist/integration.d.cts +298 -1
  47. package/dist/integration.d.ts +298 -1
  48. package/dist/integration.js +566 -9
  49. package/dist/integration.js.map +1 -1
  50. package/dist/{types-DuX3q6A4.d.cts → types-CnOCn7b3.d.cts} +51 -1
  51. package/dist/{types-DuX3q6A4.d.ts → types-CnOCn7b3.d.ts} +51 -1
  52. package/dist/validation-rules.cjs +75 -231
  53. package/dist/validation-rules.cjs.map +1 -1
  54. package/dist/validation-rules.d.cts +1 -1
  55. package/dist/validation-rules.d.ts +1 -1
  56. package/dist/validation-rules.js +1 -215
  57. package/dist/validation-rules.js.map +1 -1
  58. package/dist/validation-utils.cjs +43 -133
  59. package/dist/validation-utils.cjs.map +1 -1
  60. package/dist/validation-utils.d.cts +1 -1
  61. package/dist/validation-utils.d.ts +1 -1
  62. package/dist/validation-utils.js +1 -125
  63. package/dist/validation-utils.js.map +1 -1
  64. package/dist/validation-valibot.d.cts +1 -1
  65. package/dist/validation-valibot.d.ts +1 -1
  66. package/dist/validation.cjs +115 -364
  67. package/dist/validation.cjs.map +1 -1
  68. package/dist/validation.d.cts +1 -1
  69. package/dist/validation.d.ts +1 -1
  70. package/dist/validation.js +2 -339
  71. package/dist/validation.js.map +1 -1
  72. package/package.json +1 -1
@@ -1,6 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var React = require('react');
3
+ var chunkEX6CRLKG_cjs = require('./chunk-EX6CRLKG.cjs');
4
+ var chunkZYFTT6DB_cjs = require('./chunk-ZYFTT6DB.cjs');
5
+ var chunkDKLLPKZN_cjs = require('./chunk-DKLLPKZN.cjs');
6
+ var React2 = require('react');
4
7
 
5
8
  function _interopNamespace(e) {
6
9
  if (e && e.__esModule) return e;
@@ -20,7 +23,7 @@ function _interopNamespace(e) {
20
23
  return Object.freeze(n);
21
24
  }
22
25
 
23
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
26
+ var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
24
27
 
25
28
  // src/integration/ContactFormSerializer.ts
26
29
  var STANDARD_FIELDS = [
@@ -161,7 +164,7 @@ function deserializeErrors(railsErrors) {
161
164
  }
162
165
  return formErrors;
163
166
  }
164
- var BlockErrorBoundary = class extends React__namespace.Component {
167
+ var BlockErrorBoundary = class extends React2__namespace.Component {
165
168
  constructor(props) {
166
169
  super(props);
167
170
  this.state = { error: null };
@@ -181,16 +184,16 @@ var BlockErrorBoundary = class extends React__namespace.Component {
181
184
  if (this.props.fallback) {
182
185
  return this.props.fallback(this.state.error, this.props.block);
183
186
  }
184
- return /* @__PURE__ */ React__namespace.createElement(
187
+ return /* @__PURE__ */ React2__namespace.createElement(
185
188
  "div",
186
189
  {
187
190
  className: "block-error border border-destructive bg-destructive p-4 rounded text-destructive-foreground",
188
191
  "data-block-id": this.props.block._id,
189
192
  "data-block-type": this.props.block._type
190
193
  },
191
- /* @__PURE__ */ React__namespace.createElement("p", { className: "font-semibold" }, "Block Render Error"),
192
- /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm" }, "Block: ", this.props.block._name || this.props.block._id, " (", this.props.block._type, ")"),
193
- /* @__PURE__ */ React__namespace.createElement("p", { className: "text-sm mt-1" }, this.state.error.message)
194
+ /* @__PURE__ */ React2__namespace.createElement("p", { className: "font-semibold" }, "Block Render Error"),
195
+ /* @__PURE__ */ React2__namespace.createElement("p", { className: "text-sm" }, "Block: ", this.props.block._name || this.props.block._id, " (", this.props.block._type, ")"),
196
+ /* @__PURE__ */ React2__namespace.createElement("p", { className: "text-sm mt-1" }, this.state.error.message)
194
197
  );
195
198
  }
196
199
  return this.props.children;
@@ -221,9 +224,9 @@ function createBlockAdapter(Component2, options = {}) {
221
224
  ...dataAttrs
222
225
  };
223
226
  const renderedChildren = renderChildren ? renderChildren(block._id) : children;
224
- const element = /* @__PURE__ */ React__namespace.createElement(Component2, { ...componentProps }, renderedChildren);
227
+ const element = /* @__PURE__ */ React2__namespace.createElement(Component2, { ...componentProps }, renderedChildren);
225
228
  if (withErrorBoundary) {
226
- return /* @__PURE__ */ React__namespace.createElement(BlockErrorBoundary, { block, fallback: errorFallback }, element);
229
+ return /* @__PURE__ */ React2__namespace.createElement(BlockErrorBoundary, { block, fallback: errorFallback }, element);
227
230
  }
228
231
  return element;
229
232
  };
@@ -248,10 +251,572 @@ function createBlockAdapters(components, options = {}) {
248
251
  return adapted;
249
252
  }
250
253
 
254
+ // src/integration/form-submit.ts
255
+ var PageSpeedFormSubmissionError = class extends Error {
256
+ constructor(message, options = {}) {
257
+ super(message);
258
+ this.name = "PageSpeedFormSubmissionError";
259
+ this.formErrors = options.formErrors;
260
+ this.status = options.status;
261
+ }
262
+ };
263
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
264
+ function isValidEmail(value) {
265
+ return EMAIL_REGEX.test(value);
266
+ }
267
+ function buildUrlWithParams(endpoint, values) {
268
+ const base = typeof window === "undefined" ? "http://localhost" : window.location.origin;
269
+ const url = new URL(endpoint, base);
270
+ Object.entries(values).forEach(([key, value]) => {
271
+ if (value === void 0 || value === null) return;
272
+ if (Array.isArray(value)) {
273
+ value.forEach((item) => {
274
+ if (item !== void 0 && item !== null) {
275
+ url.searchParams.append(key, String(item));
276
+ }
277
+ });
278
+ return;
279
+ }
280
+ url.searchParams.set(key, String(value));
281
+ });
282
+ return url.toString();
283
+ }
284
+ function normalizeMethod(method) {
285
+ return (method || "post").toUpperCase();
286
+ }
287
+ function resolveFormat(config) {
288
+ if (config?.format) return config.format;
289
+ return config?.apiKey ? "rails" : "json";
290
+ }
291
+ function mergeValues(values, config) {
292
+ return {
293
+ ...config?.values ?? {},
294
+ ...values
295
+ };
296
+ }
297
+ async function submitPageSpeedForm(values, config) {
298
+ if (!config?.endpoint) {
299
+ return null;
300
+ }
301
+ const payload = mergeValues(values, config);
302
+ const method = normalizeMethod(config.method);
303
+ const format = resolveFormat(config);
304
+ const headers = { ...config.headers ?? {} };
305
+ if (format === "rails") {
306
+ if (!config.apiKey) {
307
+ throw new PageSpeedFormSubmissionError(
308
+ "Missing apiKey for Rails form submission."
309
+ );
310
+ }
311
+ const railsConfig = {
312
+ apiKey: config.apiKey,
313
+ contactCategoryToken: config.contactCategoryToken,
314
+ locationId: config.locationId,
315
+ websiteId: config.websiteId,
316
+ websiteFormAssignmentId: config.websiteFormAssignmentId,
317
+ visitorIpAddress: config.visitorIpAddress
318
+ };
319
+ const serialized = serializeForRails(payload, railsConfig);
320
+ if (serialized.contact.contact_form_upload_tokens) {
321
+ serialized.contact.contact_form_upload_tokens = serialized.contact.contact_form_upload_tokens.map((token) => token.replace(/^upload_/, ""));
322
+ }
323
+ headers["Content-Type"] ?? (headers["Content-Type"] = "application/json");
324
+ const response2 = await fetch(config.endpoint, {
325
+ method,
326
+ headers,
327
+ body: JSON.stringify(serialized)
328
+ });
329
+ const data2 = await response2.json().catch(() => null);
330
+ if (!response2.ok || data2 && data2.errors) {
331
+ const errorResponse = {
332
+ errors: data2?.errors ?? { base: ["Form submission failed"] },
333
+ status: data2?.status ?? response2.status
334
+ };
335
+ const formErrors = deserializeErrors(errorResponse);
336
+ throw new PageSpeedFormSubmissionError("Form submission failed.", {
337
+ formErrors,
338
+ status: errorResponse.status
339
+ });
340
+ }
341
+ return data2;
342
+ }
343
+ if (method === "GET") {
344
+ const url = buildUrlWithParams(config.endpoint, payload);
345
+ const response2 = await fetch(url, { method, headers });
346
+ const data2 = await response2.json().catch(() => null);
347
+ if (!response2.ok) {
348
+ throw new PageSpeedFormSubmissionError(
349
+ data2?.message || "Form submission failed.",
350
+ { status: response2.status }
351
+ );
352
+ }
353
+ return data2;
354
+ }
355
+ headers["Content-Type"] ?? (headers["Content-Type"] = "application/json");
356
+ const response = await fetch(config.endpoint, {
357
+ method,
358
+ headers,
359
+ body: JSON.stringify(payload)
360
+ });
361
+ const data = await response.json().catch(() => null);
362
+ if (!response.ok) {
363
+ throw new PageSpeedFormSubmissionError(
364
+ data?.message || "Form submission failed.",
365
+ { status: response.status }
366
+ );
367
+ }
368
+ return data;
369
+ }
370
+
371
+ // src/integration/form-field-types.ts
372
+ function generateInitialValues(fields) {
373
+ return fields.reduce(
374
+ (acc, field) => {
375
+ if (field.type === "checkbox") {
376
+ acc[field.name] = false;
377
+ } else if (field.type === "checkbox-group" || field.type === "multi-select") {
378
+ acc[field.name] = [];
379
+ } else if (field.type === "file") {
380
+ acc[field.name] = [];
381
+ } else if (field.type === "date-range") {
382
+ acc[field.name] = { start: null, end: null };
383
+ } else {
384
+ acc[field.name] = "";
385
+ }
386
+ return acc;
387
+ },
388
+ {}
389
+ );
390
+ }
391
+ function generateValidationSchema(fields) {
392
+ return fields.reduce(
393
+ (acc, field) => {
394
+ acc[field.name] = (value, allValues) => {
395
+ if (field.required) {
396
+ if (!value || typeof value === "string" && !value.trim()) {
397
+ return `${field.label} is required`;
398
+ }
399
+ }
400
+ if (field.type === "email" && value) {
401
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
402
+ return "Please enter a valid email address";
403
+ }
404
+ }
405
+ if (field.type === "url" && value) {
406
+ try {
407
+ new URL(value);
408
+ } catch {
409
+ return "Please enter a valid URL";
410
+ }
411
+ }
412
+ if (field.validator) {
413
+ return field.validator(value, allValues);
414
+ }
415
+ return void 0;
416
+ };
417
+ return acc;
418
+ },
419
+ {}
420
+ );
421
+ }
422
+ var columnSpanClasses = {
423
+ 1: "col-span-12 md:col-span-1",
424
+ 2: "col-span-12 md:col-span-2",
425
+ 3: "col-span-12 md:col-span-3",
426
+ 4: "col-span-12 md:col-span-4",
427
+ 5: "col-span-12 md:col-span-5",
428
+ 6: "col-span-12 md:col-span-6",
429
+ 7: "col-span-12 md:col-span-7",
430
+ 8: "col-span-12 md:col-span-8",
431
+ 9: "col-span-12 md:col-span-9",
432
+ 10: "col-span-12 md:col-span-10",
433
+ 11: "col-span-12 md:col-span-11",
434
+ 12: "col-span-12"
435
+ };
436
+ function getColumnSpanClass(span) {
437
+ if (!span || span === 12) return "col-span-12";
438
+ const clamped = Math.max(1, Math.min(span, 12));
439
+ return columnSpanClasses[clamped] || "col-span-12";
440
+ }
441
+ var DEFAULT_UPLOAD_ENDPOINT = "https://api.dashtrack.com/contacts/_/contact_form_uploads";
442
+ function useFileUpload(options) {
443
+ const [uploadTokens, setUploadTokens] = React2.useState([]);
444
+ const [uploadProgress, setUploadProgress] = React2.useState({});
445
+ const [isUploading, setIsUploading] = React2.useState(false);
446
+ const endpoint = options?.endpoint || DEFAULT_UPLOAD_ENDPOINT;
447
+ const uploadFiles = React2.useCallback(
448
+ async (files) => {
449
+ if (files.length === 0) return;
450
+ setIsUploading(true);
451
+ try {
452
+ const tokens = [];
453
+ for (const file of files) {
454
+ const formData = new FormData();
455
+ formData.append("contact_form_upload[file_upload]", file);
456
+ formData.append("contact_form_upload[title]", file.name);
457
+ formData.append("contact_form_upload[file_name]", file.name);
458
+ formData.append("contact_form_upload[file_size]", String(file.size));
459
+ const response = await fetch(endpoint, {
460
+ method: "POST",
461
+ body: formData
462
+ });
463
+ if (!response.ok) {
464
+ throw new Error(`Upload failed: ${response.statusText}`);
465
+ }
466
+ const data = await response.json();
467
+ if (data.contact_form_upload?.token) {
468
+ tokens.push(`upload_${data.contact_form_upload.token}`);
469
+ }
470
+ setUploadProgress((prev) => ({
471
+ ...prev,
472
+ [file.name]: 100
473
+ }));
474
+ }
475
+ setUploadTokens(tokens);
476
+ } catch (error) {
477
+ options?.onError?.(error);
478
+ } finally {
479
+ setIsUploading(false);
480
+ }
481
+ },
482
+ [endpoint, options]
483
+ );
484
+ const removeFile = React2.useCallback((file, index) => {
485
+ setUploadTokens((prev) => prev.filter((_, i) => i !== index));
486
+ setUploadProgress((prev) => {
487
+ const next = { ...prev };
488
+ delete next[file.name];
489
+ return next;
490
+ });
491
+ }, []);
492
+ const resetUpload = React2.useCallback(() => {
493
+ setUploadTokens([]);
494
+ setUploadProgress({});
495
+ }, []);
496
+ return {
497
+ uploadTokens,
498
+ uploadProgress,
499
+ isUploading,
500
+ uploadFiles,
501
+ removeFile,
502
+ resetUpload
503
+ };
504
+ }
505
+ function resolveRedirect(redirectUrl) {
506
+ const trimmed = redirectUrl.trim();
507
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
508
+ return { destination: trimmed, internalHref: trimmed };
509
+ }
510
+ if (typeof window === "undefined") {
511
+ return { destination: trimmed };
512
+ }
513
+ try {
514
+ const url = new URL(trimmed, window.location.href);
515
+ if (url.origin === window.location.origin) {
516
+ return {
517
+ destination: url.toString(),
518
+ internalHref: `${url.pathname}${url.search}${url.hash}`
519
+ };
520
+ }
521
+ return { destination: url.toString() };
522
+ } catch {
523
+ return { destination: trimmed };
524
+ }
525
+ }
526
+ function useContactForm(options) {
527
+ const {
528
+ formFields,
529
+ formConfig,
530
+ onSubmit,
531
+ onSuccess,
532
+ onError,
533
+ resetOnSuccess = true,
534
+ uploadTokens = [],
535
+ navigate
536
+ } = options;
537
+ const [submissionError, setSubmissionError] = React2.useState(null);
538
+ const submissionConfig = formConfig?.submissionConfig;
539
+ const redirectUrl = submissionConfig?.redirectUrl;
540
+ const resetSubmissionState = React2.useCallback(() => {
541
+ setSubmissionError(null);
542
+ }, []);
543
+ const performRedirect = React2.useCallback(() => {
544
+ if (!redirectUrl || typeof window === "undefined") {
545
+ return;
546
+ }
547
+ const { destination, internalHref } = resolveRedirect(redirectUrl);
548
+ const attemptInternalNavigation = () => {
549
+ if (!internalHref) return false;
550
+ if (navigate) {
551
+ return navigate(internalHref) !== false;
552
+ }
553
+ const handler = window.__opensiteNavigationHandler;
554
+ if (typeof handler === "function") {
555
+ try {
556
+ return handler(internalHref, void 0) !== false;
557
+ } catch {
558
+ return false;
559
+ }
560
+ }
561
+ return false;
562
+ };
563
+ window.setTimeout(() => {
564
+ if (attemptInternalNavigation()) return;
565
+ window.location.assign(destination);
566
+ }, 150);
567
+ }, [navigate, redirectUrl]);
568
+ const form = chunkEX6CRLKG_cjs.useForm({
569
+ initialValues: React2.useMemo(
570
+ () => generateInitialValues(formFields),
571
+ [formFields]
572
+ ),
573
+ validationSchema: React2.useMemo(
574
+ () => generateValidationSchema(formFields),
575
+ [formFields]
576
+ ),
577
+ onSubmit: async (values, helpers) => {
578
+ resetSubmissionState();
579
+ const shouldAutoSubmit = Boolean(formConfig?.endpoint);
580
+ if (!shouldAutoSubmit && !onSubmit) {
581
+ return;
582
+ }
583
+ try {
584
+ let result;
585
+ const submissionValues = {
586
+ ...values,
587
+ ...uploadTokens.length > 0 && {
588
+ contact_form_upload_tokens: uploadTokens
589
+ }
590
+ };
591
+ if (shouldAutoSubmit) {
592
+ result = await submitPageSpeedForm(submissionValues, formConfig);
593
+ }
594
+ if (onSubmit) {
595
+ await onSubmit(submissionValues);
596
+ }
597
+ if (shouldAutoSubmit || onSubmit) {
598
+ try {
599
+ await submissionConfig?.handleFormSubmission?.({
600
+ formData: submissionValues,
601
+ responseData: result
602
+ });
603
+ } catch {
604
+ }
605
+ if (resetOnSuccess) {
606
+ helpers.resetForm();
607
+ }
608
+ onSuccess?.(result);
609
+ if (submissionConfig?.behavior === "redirect" && submissionConfig.redirectUrl) {
610
+ performRedirect();
611
+ }
612
+ }
613
+ } catch (error) {
614
+ if (error instanceof PageSpeedFormSubmissionError && error.formErrors) {
615
+ helpers.setErrors(error.formErrors);
616
+ }
617
+ const errorMessage = error instanceof Error ? error.message : "Form submission failed";
618
+ setSubmissionError(errorMessage);
619
+ onError?.(error);
620
+ }
621
+ }
622
+ });
623
+ const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
624
+ return {
625
+ form,
626
+ isSubmitted: form.status === "success",
627
+ submissionError,
628
+ formMethod,
629
+ resetSubmissionState
630
+ };
631
+ }
632
+ function DynamicFormField({
633
+ field,
634
+ className,
635
+ uploadProgress = {},
636
+ onFileUpload,
637
+ onFileRemove,
638
+ isUploading = false
639
+ }) {
640
+ const fieldId = field.name;
641
+ const usesGroupLegend = field.type === "radio" || field.type === "checkbox-group";
642
+ const usesInlineCheckboxLabel = field.type === "checkbox";
643
+ const shouldRenderFieldLabel = !usesGroupLegend && !usesInlineCheckboxLabel;
644
+ return /* @__PURE__ */ React2__namespace.createElement(
645
+ chunkEX6CRLKG_cjs.Field,
646
+ {
647
+ name: field.name,
648
+ label: shouldRenderFieldLabel ? field.label : void 0,
649
+ description: shouldRenderFieldLabel ? field.description : void 0,
650
+ required: field.required,
651
+ className: chunkDKLLPKZN_cjs.cn("space-y-2", className)
652
+ },
653
+ ({ field: formField, meta }) => /* @__PURE__ */ React2__namespace.createElement("div", null, (field.type === "text" || field.type === "email" || field.type === "tel" || field.type === "search" || field.type === "password" || field.type === "url") && /* @__PURE__ */ React2__namespace.createElement(
654
+ chunkZYFTT6DB_cjs.TextInput,
655
+ {
656
+ ...formField,
657
+ id: fieldId,
658
+ type: field.type,
659
+ placeholder: field.placeholder,
660
+ error: meta.touched && !!meta.error,
661
+ disabled: field.disabled,
662
+ "aria-label": field.label
663
+ }
664
+ ), field.type === "number" && /* @__PURE__ */ React2__namespace.createElement(
665
+ chunkZYFTT6DB_cjs.TextInput,
666
+ {
667
+ ...formField,
668
+ id: fieldId,
669
+ type: "text",
670
+ placeholder: field.placeholder,
671
+ error: meta.touched && !!meta.error,
672
+ disabled: field.disabled,
673
+ "aria-label": field.label
674
+ }
675
+ ), field.type === "textarea" && /* @__PURE__ */ React2__namespace.createElement(
676
+ chunkZYFTT6DB_cjs.TextArea,
677
+ {
678
+ ...formField,
679
+ id: fieldId,
680
+ placeholder: field.placeholder,
681
+ rows: field.rows || 4,
682
+ error: meta.touched && !!meta.error,
683
+ disabled: field.disabled,
684
+ "aria-label": field.label
685
+ }
686
+ ), field.type === "select" && field.options && /* @__PURE__ */ React2__namespace.createElement(
687
+ chunkZYFTT6DB_cjs.Select,
688
+ {
689
+ ...formField,
690
+ id: fieldId,
691
+ options: field.options,
692
+ placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
693
+ error: meta.touched && !!meta.error,
694
+ disabled: field.disabled,
695
+ "aria-label": field.label
696
+ }
697
+ ), field.type === "multi-select" && field.options && /* @__PURE__ */ React2__namespace.createElement(
698
+ chunkZYFTT6DB_cjs.MultiSelect,
699
+ {
700
+ ...formField,
701
+ id: fieldId,
702
+ options: field.options,
703
+ placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
704
+ error: meta.touched && !!meta.error,
705
+ disabled: field.disabled,
706
+ "aria-label": field.label
707
+ }
708
+ ), field.type === "radio" && field.options && /* @__PURE__ */ React2__namespace.createElement(
709
+ chunkZYFTT6DB_cjs.Radio,
710
+ {
711
+ ...formField,
712
+ id: fieldId,
713
+ options: field.options,
714
+ label: field.label,
715
+ description: field.description,
716
+ required: field.required,
717
+ disabled: field.disabled,
718
+ layout: field.layout || "stacked",
719
+ error: meta.touched && !!meta.error,
720
+ "aria-label": field.label
721
+ }
722
+ ), field.type === "checkbox" && /* @__PURE__ */ React2__namespace.createElement(
723
+ chunkZYFTT6DB_cjs.Checkbox,
724
+ {
725
+ ...formField,
726
+ id: fieldId,
727
+ value: formField.value === true || formField.value === "true",
728
+ onChange: (checked) => formField.onChange(checked),
729
+ label: field.label,
730
+ description: field.description,
731
+ disabled: field.disabled,
732
+ required: field.required,
733
+ error: meta.touched && !!meta.error,
734
+ "aria-label": field.label
735
+ }
736
+ ), field.type === "checkbox-group" && field.options && /* @__PURE__ */ React2__namespace.createElement(
737
+ chunkZYFTT6DB_cjs.CheckboxGroup,
738
+ {
739
+ ...formField,
740
+ id: fieldId,
741
+ options: field.options,
742
+ label: field.label,
743
+ description: field.description,
744
+ required: field.required,
745
+ disabled: field.disabled,
746
+ layout: field.layout || "stacked",
747
+ error: meta.touched && !!meta.error,
748
+ "aria-label": field.label
749
+ }
750
+ ), (field.type === "date-picker" || field.type === "date") && /* @__PURE__ */ React2__namespace.createElement(
751
+ chunkZYFTT6DB_cjs.DatePicker,
752
+ {
753
+ ...formField,
754
+ id: fieldId,
755
+ placeholder: field.placeholder,
756
+ error: meta.touched && !!meta.error,
757
+ disabled: field.disabled,
758
+ "aria-label": field.label
759
+ }
760
+ ), field.type === "date-range" && /* @__PURE__ */ React2__namespace.createElement(
761
+ chunkZYFTT6DB_cjs.DateRangePicker,
762
+ {
763
+ ...formField,
764
+ id: fieldId,
765
+ placeholder: field.placeholder,
766
+ error: meta.touched && !!meta.error,
767
+ disabled: field.disabled,
768
+ "aria-label": field.label
769
+ }
770
+ ), field.type === "time" && /* @__PURE__ */ React2__namespace.createElement(
771
+ chunkZYFTT6DB_cjs.TimePicker,
772
+ {
773
+ ...formField,
774
+ id: fieldId,
775
+ placeholder: field.placeholder,
776
+ error: meta.touched && !!meta.error,
777
+ disabled: field.disabled,
778
+ "aria-label": field.label
779
+ }
780
+ ), field.type === "file" && /* @__PURE__ */ React2__namespace.createElement(
781
+ chunkZYFTT6DB_cjs.FileInput,
782
+ {
783
+ ...formField,
784
+ id: fieldId,
785
+ accept: field.accept,
786
+ maxSize: field.maxSize || 5 * 1024 * 1024,
787
+ maxFiles: field.maxFiles || 1,
788
+ multiple: field.multiple || false,
789
+ placeholder: field.placeholder || "Choose file(s)...",
790
+ error: meta.touched && !!meta.error,
791
+ disabled: field.disabled || isUploading,
792
+ showProgress: true,
793
+ uploadProgress,
794
+ onChange: (files) => {
795
+ formField.onChange(files);
796
+ if (files.length > 0 && onFileUpload) {
797
+ onFileUpload(files);
798
+ }
799
+ },
800
+ onFileRemove,
801
+ "aria-label": field.label
802
+ }
803
+ ))
804
+ );
805
+ }
806
+
807
+ exports.DynamicFormField = DynamicFormField;
808
+ exports.PageSpeedFormSubmissionError = PageSpeedFormSubmissionError;
251
809
  exports.createBlockAdapter = createBlockAdapter;
252
810
  exports.createBlockAdapters = createBlockAdapters;
253
811
  exports.deserializeErrors = deserializeErrors;
812
+ exports.generateInitialValues = generateInitialValues;
813
+ exports.generateValidationSchema = generateValidationSchema;
814
+ exports.getColumnSpanClass = getColumnSpanClass;
815
+ exports.isValidEmail = isValidEmail;
254
816
  exports.serializeForRails = serializeForRails;
255
817
  exports.standardInputTransformer = standardInputTransformer;
818
+ exports.submitPageSpeedForm = submitPageSpeedForm;
819
+ exports.useContactForm = useContactForm;
820
+ exports.useFileUpload = useFileUpload;
256
821
  //# sourceMappingURL=integration.cjs.map
257
822
  //# sourceMappingURL=integration.cjs.map