@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,4 +1,8 @@
1
- import * as React from 'react';
1
+ import { useForm, Field } from './chunk-24RPM43T.js';
2
+ import { TextInput, TextArea, Select, MultiSelect, Radio, Checkbox, CheckboxGroup, DatePicker, DateRangePicker, TimePicker, FileInput } from './chunk-5NT5T5XY.js';
3
+ import { cn } from './chunk-232KNGJI.js';
4
+ import * as React2 from 'react';
5
+ import { useState, useCallback, useMemo } from 'react';
2
6
 
3
7
  // src/integration/ContactFormSerializer.ts
4
8
  var STANDARD_FIELDS = [
@@ -139,7 +143,7 @@ function deserializeErrors(railsErrors) {
139
143
  }
140
144
  return formErrors;
141
145
  }
142
- var BlockErrorBoundary = class extends React.Component {
146
+ var BlockErrorBoundary = class extends React2.Component {
143
147
  constructor(props) {
144
148
  super(props);
145
149
  this.state = { error: null };
@@ -159,16 +163,16 @@ var BlockErrorBoundary = class extends React.Component {
159
163
  if (this.props.fallback) {
160
164
  return this.props.fallback(this.state.error, this.props.block);
161
165
  }
162
- return /* @__PURE__ */ React.createElement(
166
+ return /* @__PURE__ */ React2.createElement(
163
167
  "div",
164
168
  {
165
169
  className: "block-error border border-destructive bg-destructive p-4 rounded text-destructive-foreground",
166
170
  "data-block-id": this.props.block._id,
167
171
  "data-block-type": this.props.block._type
168
172
  },
169
- /* @__PURE__ */ React.createElement("p", { className: "font-semibold" }, "Block Render Error"),
170
- /* @__PURE__ */ React.createElement("p", { className: "text-sm" }, "Block: ", this.props.block._name || this.props.block._id, " (", this.props.block._type, ")"),
171
- /* @__PURE__ */ React.createElement("p", { className: "text-sm mt-1" }, this.state.error.message)
173
+ /* @__PURE__ */ React2.createElement("p", { className: "font-semibold" }, "Block Render Error"),
174
+ /* @__PURE__ */ React2.createElement("p", { className: "text-sm" }, "Block: ", this.props.block._name || this.props.block._id, " (", this.props.block._type, ")"),
175
+ /* @__PURE__ */ React2.createElement("p", { className: "text-sm mt-1" }, this.state.error.message)
172
176
  );
173
177
  }
174
178
  return this.props.children;
@@ -199,9 +203,9 @@ function createBlockAdapter(Component2, options = {}) {
199
203
  ...dataAttrs
200
204
  };
201
205
  const renderedChildren = renderChildren ? renderChildren(block._id) : children;
202
- const element = /* @__PURE__ */ React.createElement(Component2, { ...componentProps }, renderedChildren);
206
+ const element = /* @__PURE__ */ React2.createElement(Component2, { ...componentProps }, renderedChildren);
203
207
  if (withErrorBoundary) {
204
- return /* @__PURE__ */ React.createElement(BlockErrorBoundary, { block, fallback: errorFallback }, element);
208
+ return /* @__PURE__ */ React2.createElement(BlockErrorBoundary, { block, fallback: errorFallback }, element);
205
209
  }
206
210
  return element;
207
211
  };
@@ -226,6 +230,559 @@ function createBlockAdapters(components, options = {}) {
226
230
  return adapted;
227
231
  }
228
232
 
229
- export { createBlockAdapter, createBlockAdapters, deserializeErrors, serializeForRails, standardInputTransformer };
233
+ // src/integration/form-submit.ts
234
+ var PageSpeedFormSubmissionError = class extends Error {
235
+ constructor(message, options = {}) {
236
+ super(message);
237
+ this.name = "PageSpeedFormSubmissionError";
238
+ this.formErrors = options.formErrors;
239
+ this.status = options.status;
240
+ }
241
+ };
242
+ var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
243
+ function isValidEmail(value) {
244
+ return EMAIL_REGEX.test(value);
245
+ }
246
+ function buildUrlWithParams(endpoint, values) {
247
+ const base = typeof window === "undefined" ? "http://localhost" : window.location.origin;
248
+ const url = new URL(endpoint, base);
249
+ Object.entries(values).forEach(([key, value]) => {
250
+ if (value === void 0 || value === null) return;
251
+ if (Array.isArray(value)) {
252
+ value.forEach((item) => {
253
+ if (item !== void 0 && item !== null) {
254
+ url.searchParams.append(key, String(item));
255
+ }
256
+ });
257
+ return;
258
+ }
259
+ url.searchParams.set(key, String(value));
260
+ });
261
+ return url.toString();
262
+ }
263
+ function normalizeMethod(method) {
264
+ return (method || "post").toUpperCase();
265
+ }
266
+ function resolveFormat(config) {
267
+ if (config?.format) return config.format;
268
+ return config?.apiKey ? "rails" : "json";
269
+ }
270
+ function mergeValues(values, config) {
271
+ return {
272
+ ...config?.values ?? {},
273
+ ...values
274
+ };
275
+ }
276
+ async function submitPageSpeedForm(values, config) {
277
+ if (!config?.endpoint) {
278
+ return null;
279
+ }
280
+ const payload = mergeValues(values, config);
281
+ const method = normalizeMethod(config.method);
282
+ const format = resolveFormat(config);
283
+ const headers = { ...config.headers ?? {} };
284
+ if (format === "rails") {
285
+ if (!config.apiKey) {
286
+ throw new PageSpeedFormSubmissionError(
287
+ "Missing apiKey for Rails form submission."
288
+ );
289
+ }
290
+ const railsConfig = {
291
+ apiKey: config.apiKey,
292
+ contactCategoryToken: config.contactCategoryToken,
293
+ locationId: config.locationId,
294
+ websiteId: config.websiteId,
295
+ websiteFormAssignmentId: config.websiteFormAssignmentId,
296
+ visitorIpAddress: config.visitorIpAddress
297
+ };
298
+ const serialized = serializeForRails(payload, railsConfig);
299
+ if (serialized.contact.contact_form_upload_tokens) {
300
+ serialized.contact.contact_form_upload_tokens = serialized.contact.contact_form_upload_tokens.map((token) => token.replace(/^upload_/, ""));
301
+ }
302
+ headers["Content-Type"] ?? (headers["Content-Type"] = "application/json");
303
+ const response2 = await fetch(config.endpoint, {
304
+ method,
305
+ headers,
306
+ body: JSON.stringify(serialized)
307
+ });
308
+ const data2 = await response2.json().catch(() => null);
309
+ if (!response2.ok || data2 && data2.errors) {
310
+ const errorResponse = {
311
+ errors: data2?.errors ?? { base: ["Form submission failed"] },
312
+ status: data2?.status ?? response2.status
313
+ };
314
+ const formErrors = deserializeErrors(errorResponse);
315
+ throw new PageSpeedFormSubmissionError("Form submission failed.", {
316
+ formErrors,
317
+ status: errorResponse.status
318
+ });
319
+ }
320
+ return data2;
321
+ }
322
+ if (method === "GET") {
323
+ const url = buildUrlWithParams(config.endpoint, payload);
324
+ const response2 = await fetch(url, { method, headers });
325
+ const data2 = await response2.json().catch(() => null);
326
+ if (!response2.ok) {
327
+ throw new PageSpeedFormSubmissionError(
328
+ data2?.message || "Form submission failed.",
329
+ { status: response2.status }
330
+ );
331
+ }
332
+ return data2;
333
+ }
334
+ headers["Content-Type"] ?? (headers["Content-Type"] = "application/json");
335
+ const response = await fetch(config.endpoint, {
336
+ method,
337
+ headers,
338
+ body: JSON.stringify(payload)
339
+ });
340
+ const data = await response.json().catch(() => null);
341
+ if (!response.ok) {
342
+ throw new PageSpeedFormSubmissionError(
343
+ data?.message || "Form submission failed.",
344
+ { status: response.status }
345
+ );
346
+ }
347
+ return data;
348
+ }
349
+
350
+ // src/integration/form-field-types.ts
351
+ function generateInitialValues(fields) {
352
+ return fields.reduce(
353
+ (acc, field) => {
354
+ if (field.type === "checkbox") {
355
+ acc[field.name] = false;
356
+ } else if (field.type === "checkbox-group" || field.type === "multi-select") {
357
+ acc[field.name] = [];
358
+ } else if (field.type === "file") {
359
+ acc[field.name] = [];
360
+ } else if (field.type === "date-range") {
361
+ acc[field.name] = { start: null, end: null };
362
+ } else {
363
+ acc[field.name] = "";
364
+ }
365
+ return acc;
366
+ },
367
+ {}
368
+ );
369
+ }
370
+ function generateValidationSchema(fields) {
371
+ return fields.reduce(
372
+ (acc, field) => {
373
+ acc[field.name] = (value, allValues) => {
374
+ if (field.required) {
375
+ if (!value || typeof value === "string" && !value.trim()) {
376
+ return `${field.label} is required`;
377
+ }
378
+ }
379
+ if (field.type === "email" && value) {
380
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
381
+ return "Please enter a valid email address";
382
+ }
383
+ }
384
+ if (field.type === "url" && value) {
385
+ try {
386
+ new URL(value);
387
+ } catch {
388
+ return "Please enter a valid URL";
389
+ }
390
+ }
391
+ if (field.validator) {
392
+ return field.validator(value, allValues);
393
+ }
394
+ return void 0;
395
+ };
396
+ return acc;
397
+ },
398
+ {}
399
+ );
400
+ }
401
+ var columnSpanClasses = {
402
+ 1: "col-span-12 md:col-span-1",
403
+ 2: "col-span-12 md:col-span-2",
404
+ 3: "col-span-12 md:col-span-3",
405
+ 4: "col-span-12 md:col-span-4",
406
+ 5: "col-span-12 md:col-span-5",
407
+ 6: "col-span-12 md:col-span-6",
408
+ 7: "col-span-12 md:col-span-7",
409
+ 8: "col-span-12 md:col-span-8",
410
+ 9: "col-span-12 md:col-span-9",
411
+ 10: "col-span-12 md:col-span-10",
412
+ 11: "col-span-12 md:col-span-11",
413
+ 12: "col-span-12"
414
+ };
415
+ function getColumnSpanClass(span) {
416
+ if (!span || span === 12) return "col-span-12";
417
+ const clamped = Math.max(1, Math.min(span, 12));
418
+ return columnSpanClasses[clamped] || "col-span-12";
419
+ }
420
+ var DEFAULT_UPLOAD_ENDPOINT = "https://api.dashtrack.com/contacts/_/contact_form_uploads";
421
+ function useFileUpload(options) {
422
+ const [uploadTokens, setUploadTokens] = useState([]);
423
+ const [uploadProgress, setUploadProgress] = useState({});
424
+ const [isUploading, setIsUploading] = useState(false);
425
+ const endpoint = options?.endpoint || DEFAULT_UPLOAD_ENDPOINT;
426
+ const uploadFiles = useCallback(
427
+ async (files) => {
428
+ if (files.length === 0) return;
429
+ setIsUploading(true);
430
+ try {
431
+ const tokens = [];
432
+ for (const file of files) {
433
+ const formData = new FormData();
434
+ formData.append("contact_form_upload[file_upload]", file);
435
+ formData.append("contact_form_upload[title]", file.name);
436
+ formData.append("contact_form_upload[file_name]", file.name);
437
+ formData.append("contact_form_upload[file_size]", String(file.size));
438
+ const response = await fetch(endpoint, {
439
+ method: "POST",
440
+ body: formData
441
+ });
442
+ if (!response.ok) {
443
+ throw new Error(`Upload failed: ${response.statusText}`);
444
+ }
445
+ const data = await response.json();
446
+ if (data.contact_form_upload?.token) {
447
+ tokens.push(`upload_${data.contact_form_upload.token}`);
448
+ }
449
+ setUploadProgress((prev) => ({
450
+ ...prev,
451
+ [file.name]: 100
452
+ }));
453
+ }
454
+ setUploadTokens(tokens);
455
+ } catch (error) {
456
+ options?.onError?.(error);
457
+ } finally {
458
+ setIsUploading(false);
459
+ }
460
+ },
461
+ [endpoint, options]
462
+ );
463
+ const removeFile = useCallback((file, index) => {
464
+ setUploadTokens((prev) => prev.filter((_, i) => i !== index));
465
+ setUploadProgress((prev) => {
466
+ const next = { ...prev };
467
+ delete next[file.name];
468
+ return next;
469
+ });
470
+ }, []);
471
+ const resetUpload = useCallback(() => {
472
+ setUploadTokens([]);
473
+ setUploadProgress({});
474
+ }, []);
475
+ return {
476
+ uploadTokens,
477
+ uploadProgress,
478
+ isUploading,
479
+ uploadFiles,
480
+ removeFile,
481
+ resetUpload
482
+ };
483
+ }
484
+ function resolveRedirect(redirectUrl) {
485
+ const trimmed = redirectUrl.trim();
486
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
487
+ return { destination: trimmed, internalHref: trimmed };
488
+ }
489
+ if (typeof window === "undefined") {
490
+ return { destination: trimmed };
491
+ }
492
+ try {
493
+ const url = new URL(trimmed, window.location.href);
494
+ if (url.origin === window.location.origin) {
495
+ return {
496
+ destination: url.toString(),
497
+ internalHref: `${url.pathname}${url.search}${url.hash}`
498
+ };
499
+ }
500
+ return { destination: url.toString() };
501
+ } catch {
502
+ return { destination: trimmed };
503
+ }
504
+ }
505
+ function useContactForm(options) {
506
+ const {
507
+ formFields,
508
+ formConfig,
509
+ onSubmit,
510
+ onSuccess,
511
+ onError,
512
+ resetOnSuccess = true,
513
+ uploadTokens = [],
514
+ navigate
515
+ } = options;
516
+ const [submissionError, setSubmissionError] = useState(null);
517
+ const submissionConfig = formConfig?.submissionConfig;
518
+ const redirectUrl = submissionConfig?.redirectUrl;
519
+ const resetSubmissionState = useCallback(() => {
520
+ setSubmissionError(null);
521
+ }, []);
522
+ const performRedirect = useCallback(() => {
523
+ if (!redirectUrl || typeof window === "undefined") {
524
+ return;
525
+ }
526
+ const { destination, internalHref } = resolveRedirect(redirectUrl);
527
+ const attemptInternalNavigation = () => {
528
+ if (!internalHref) return false;
529
+ if (navigate) {
530
+ return navigate(internalHref) !== false;
531
+ }
532
+ const handler = window.__opensiteNavigationHandler;
533
+ if (typeof handler === "function") {
534
+ try {
535
+ return handler(internalHref, void 0) !== false;
536
+ } catch {
537
+ return false;
538
+ }
539
+ }
540
+ return false;
541
+ };
542
+ window.setTimeout(() => {
543
+ if (attemptInternalNavigation()) return;
544
+ window.location.assign(destination);
545
+ }, 150);
546
+ }, [navigate, redirectUrl]);
547
+ const form = useForm({
548
+ initialValues: useMemo(
549
+ () => generateInitialValues(formFields),
550
+ [formFields]
551
+ ),
552
+ validationSchema: useMemo(
553
+ () => generateValidationSchema(formFields),
554
+ [formFields]
555
+ ),
556
+ onSubmit: async (values, helpers) => {
557
+ resetSubmissionState();
558
+ const shouldAutoSubmit = Boolean(formConfig?.endpoint);
559
+ if (!shouldAutoSubmit && !onSubmit) {
560
+ return;
561
+ }
562
+ try {
563
+ let result;
564
+ const submissionValues = {
565
+ ...values,
566
+ ...uploadTokens.length > 0 && {
567
+ contact_form_upload_tokens: uploadTokens
568
+ }
569
+ };
570
+ if (shouldAutoSubmit) {
571
+ result = await submitPageSpeedForm(submissionValues, formConfig);
572
+ }
573
+ if (onSubmit) {
574
+ await onSubmit(submissionValues);
575
+ }
576
+ if (shouldAutoSubmit || onSubmit) {
577
+ try {
578
+ await submissionConfig?.handleFormSubmission?.({
579
+ formData: submissionValues,
580
+ responseData: result
581
+ });
582
+ } catch {
583
+ }
584
+ if (resetOnSuccess) {
585
+ helpers.resetForm();
586
+ }
587
+ onSuccess?.(result);
588
+ if (submissionConfig?.behavior === "redirect" && submissionConfig.redirectUrl) {
589
+ performRedirect();
590
+ }
591
+ }
592
+ } catch (error) {
593
+ if (error instanceof PageSpeedFormSubmissionError && error.formErrors) {
594
+ helpers.setErrors(error.formErrors);
595
+ }
596
+ const errorMessage = error instanceof Error ? error.message : "Form submission failed";
597
+ setSubmissionError(errorMessage);
598
+ onError?.(error);
599
+ }
600
+ }
601
+ });
602
+ const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
603
+ return {
604
+ form,
605
+ isSubmitted: form.status === "success",
606
+ submissionError,
607
+ formMethod,
608
+ resetSubmissionState
609
+ };
610
+ }
611
+ function DynamicFormField({
612
+ field,
613
+ className,
614
+ uploadProgress = {},
615
+ onFileUpload,
616
+ onFileRemove,
617
+ isUploading = false
618
+ }) {
619
+ const fieldId = field.name;
620
+ const usesGroupLegend = field.type === "radio" || field.type === "checkbox-group";
621
+ const usesInlineCheckboxLabel = field.type === "checkbox";
622
+ const shouldRenderFieldLabel = !usesGroupLegend && !usesInlineCheckboxLabel;
623
+ return /* @__PURE__ */ React2.createElement(
624
+ Field,
625
+ {
626
+ name: field.name,
627
+ label: shouldRenderFieldLabel ? field.label : void 0,
628
+ description: shouldRenderFieldLabel ? field.description : void 0,
629
+ required: field.required,
630
+ className: cn("space-y-2", className)
631
+ },
632
+ ({ field: formField, meta }) => /* @__PURE__ */ React2.createElement("div", null, (field.type === "text" || field.type === "email" || field.type === "tel" || field.type === "search" || field.type === "password" || field.type === "url") && /* @__PURE__ */ React2.createElement(
633
+ TextInput,
634
+ {
635
+ ...formField,
636
+ id: fieldId,
637
+ type: field.type,
638
+ placeholder: field.placeholder,
639
+ error: meta.touched && !!meta.error,
640
+ disabled: field.disabled,
641
+ "aria-label": field.label
642
+ }
643
+ ), field.type === "number" && /* @__PURE__ */ React2.createElement(
644
+ TextInput,
645
+ {
646
+ ...formField,
647
+ id: fieldId,
648
+ type: "text",
649
+ placeholder: field.placeholder,
650
+ error: meta.touched && !!meta.error,
651
+ disabled: field.disabled,
652
+ "aria-label": field.label
653
+ }
654
+ ), field.type === "textarea" && /* @__PURE__ */ React2.createElement(
655
+ TextArea,
656
+ {
657
+ ...formField,
658
+ id: fieldId,
659
+ placeholder: field.placeholder,
660
+ rows: field.rows || 4,
661
+ error: meta.touched && !!meta.error,
662
+ disabled: field.disabled,
663
+ "aria-label": field.label
664
+ }
665
+ ), field.type === "select" && field.options && /* @__PURE__ */ React2.createElement(
666
+ Select,
667
+ {
668
+ ...formField,
669
+ id: fieldId,
670
+ options: field.options,
671
+ placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
672
+ error: meta.touched && !!meta.error,
673
+ disabled: field.disabled,
674
+ "aria-label": field.label
675
+ }
676
+ ), field.type === "multi-select" && field.options && /* @__PURE__ */ React2.createElement(
677
+ MultiSelect,
678
+ {
679
+ ...formField,
680
+ id: fieldId,
681
+ options: field.options,
682
+ placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
683
+ error: meta.touched && !!meta.error,
684
+ disabled: field.disabled,
685
+ "aria-label": field.label
686
+ }
687
+ ), field.type === "radio" && field.options && /* @__PURE__ */ React2.createElement(
688
+ Radio,
689
+ {
690
+ ...formField,
691
+ id: fieldId,
692
+ options: field.options,
693
+ label: field.label,
694
+ description: field.description,
695
+ required: field.required,
696
+ disabled: field.disabled,
697
+ layout: field.layout || "stacked",
698
+ error: meta.touched && !!meta.error,
699
+ "aria-label": field.label
700
+ }
701
+ ), field.type === "checkbox" && /* @__PURE__ */ React2.createElement(
702
+ Checkbox,
703
+ {
704
+ ...formField,
705
+ id: fieldId,
706
+ value: formField.value === true || formField.value === "true",
707
+ onChange: (checked) => formField.onChange(checked),
708
+ label: field.label,
709
+ description: field.description,
710
+ disabled: field.disabled,
711
+ required: field.required,
712
+ error: meta.touched && !!meta.error,
713
+ "aria-label": field.label
714
+ }
715
+ ), field.type === "checkbox-group" && field.options && /* @__PURE__ */ React2.createElement(
716
+ CheckboxGroup,
717
+ {
718
+ ...formField,
719
+ id: fieldId,
720
+ options: field.options,
721
+ label: field.label,
722
+ description: field.description,
723
+ required: field.required,
724
+ disabled: field.disabled,
725
+ layout: field.layout || "stacked",
726
+ error: meta.touched && !!meta.error,
727
+ "aria-label": field.label
728
+ }
729
+ ), (field.type === "date-picker" || field.type === "date") && /* @__PURE__ */ React2.createElement(
730
+ DatePicker,
731
+ {
732
+ ...formField,
733
+ id: fieldId,
734
+ placeholder: field.placeholder,
735
+ error: meta.touched && !!meta.error,
736
+ disabled: field.disabled,
737
+ "aria-label": field.label
738
+ }
739
+ ), field.type === "date-range" && /* @__PURE__ */ React2.createElement(
740
+ DateRangePicker,
741
+ {
742
+ ...formField,
743
+ id: fieldId,
744
+ placeholder: field.placeholder,
745
+ error: meta.touched && !!meta.error,
746
+ disabled: field.disabled,
747
+ "aria-label": field.label
748
+ }
749
+ ), field.type === "time" && /* @__PURE__ */ React2.createElement(
750
+ TimePicker,
751
+ {
752
+ ...formField,
753
+ id: fieldId,
754
+ placeholder: field.placeholder,
755
+ error: meta.touched && !!meta.error,
756
+ disabled: field.disabled,
757
+ "aria-label": field.label
758
+ }
759
+ ), field.type === "file" && /* @__PURE__ */ React2.createElement(
760
+ FileInput,
761
+ {
762
+ ...formField,
763
+ id: fieldId,
764
+ accept: field.accept,
765
+ maxSize: field.maxSize || 5 * 1024 * 1024,
766
+ maxFiles: field.maxFiles || 1,
767
+ multiple: field.multiple || false,
768
+ placeholder: field.placeholder || "Choose file(s)...",
769
+ error: meta.touched && !!meta.error,
770
+ disabled: field.disabled || isUploading,
771
+ showProgress: true,
772
+ uploadProgress,
773
+ onChange: (files) => {
774
+ formField.onChange(files);
775
+ if (files.length > 0 && onFileUpload) {
776
+ onFileUpload(files);
777
+ }
778
+ },
779
+ onFileRemove,
780
+ "aria-label": field.label
781
+ }
782
+ ))
783
+ );
784
+ }
785
+
786
+ export { DynamicFormField, PageSpeedFormSubmissionError, createBlockAdapter, createBlockAdapters, deserializeErrors, generateInitialValues, generateValidationSchema, getColumnSpanClass, isValidEmail, serializeForRails, standardInputTransformer, submitPageSpeedForm, useContactForm, useFileUpload };
230
787
  //# sourceMappingURL=integration.js.map
231
788
  //# sourceMappingURL=integration.js.map