@opensite/ui 1.8.2 → 1.8.4

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 (171) hide show
  1. package/dist/about-story-gallery.cjs +3 -30
  2. package/dist/about-story-gallery.d.cts +1 -1
  3. package/dist/about-story-gallery.d.ts +1 -1
  4. package/dist/about-story-gallery.js +3 -30
  5. package/dist/components.d.cts +1 -1
  6. package/dist/components.d.ts +1 -1
  7. package/dist/contact-callback.cjs +526 -273
  8. package/dist/contact-callback.d.cts +39 -59
  9. package/dist/contact-callback.d.ts +39 -59
  10. package/dist/contact-callback.js +528 -274
  11. package/dist/contact-card.cjs +459 -183
  12. package/dist/contact-card.d.cts +26 -49
  13. package/dist/contact-card.d.ts +26 -49
  14. package/dist/contact-card.js +461 -183
  15. package/dist/contact-careers.cjs +614 -510
  16. package/dist/contact-careers.d.cts +32 -55
  17. package/dist/contact-careers.d.ts +32 -55
  18. package/dist/contact-careers.js +616 -510
  19. package/dist/contact-catering.cjs +507 -501
  20. package/dist/contact-catering.d.cts +27 -61
  21. package/dist/contact-catering.d.ts +27 -61
  22. package/dist/contact-catering.js +509 -500
  23. package/dist/contact-consultation.cjs +484 -253
  24. package/dist/contact-consultation.d.cts +29 -56
  25. package/dist/contact-consultation.d.ts +29 -56
  26. package/dist/contact-consultation.js +486 -253
  27. package/dist/contact-dark.cjs +296 -296
  28. package/dist/contact-dark.d.cts +1 -1
  29. package/dist/contact-dark.d.ts +1 -1
  30. package/dist/contact-dark.js +297 -296
  31. package/dist/contact-demo.d.cts +1 -1
  32. package/dist/contact-demo.d.ts +1 -1
  33. package/dist/contact-emergency.d.cts +1 -1
  34. package/dist/contact-emergency.d.ts +1 -1
  35. package/dist/contact-event.d.cts +1 -1
  36. package/dist/contact-event.d.ts +1 -1
  37. package/dist/contact-faq.cjs +247 -250
  38. package/dist/contact-faq.d.cts +1 -1
  39. package/dist/contact-faq.d.ts +1 -1
  40. package/dist/contact-faq.js +248 -250
  41. package/dist/contact-feedback.d.cts +1 -1
  42. package/dist/contact-feedback.d.ts +1 -1
  43. package/dist/contact-fitness.d.cts +1 -1
  44. package/dist/contact-fitness.d.ts +1 -1
  45. package/dist/contact-guest.d.cts +1 -1
  46. package/dist/contact-guest.d.ts +1 -1
  47. package/dist/contact-image.d.cts +1 -1
  48. package/dist/contact-image.d.ts +1 -1
  49. package/dist/contact-insurance.d.cts +1 -1
  50. package/dist/contact-insurance.d.ts +1 -1
  51. package/dist/contact-interview.d.cts +1 -1
  52. package/dist/contact-interview.d.ts +1 -1
  53. package/dist/contact-locations.d.cts +1 -1
  54. package/dist/contact-locations.d.ts +1 -1
  55. package/dist/contact-maintenance.d.cts +1 -1
  56. package/dist/contact-maintenance.d.ts +1 -1
  57. package/dist/contact-map.d.cts +1 -1
  58. package/dist/contact-map.d.ts +1 -1
  59. package/dist/contact-minimal.d.cts +1 -1
  60. package/dist/contact-minimal.d.ts +1 -1
  61. package/dist/contact-moving.d.cts +1 -1
  62. package/dist/contact-moving.d.ts +1 -1
  63. package/dist/contact-multistep.d.cts +1 -1
  64. package/dist/contact-multistep.d.ts +1 -1
  65. package/dist/contact-partnership.d.cts +1 -1
  66. package/dist/contact-partnership.d.ts +1 -1
  67. package/dist/contact-photography.cjs +247 -250
  68. package/dist/contact-photography.d.cts +1 -1
  69. package/dist/contact-photography.d.ts +1 -1
  70. package/dist/contact-photography.js +248 -250
  71. package/dist/contact-press.d.cts +1 -1
  72. package/dist/contact-press.d.ts +1 -1
  73. package/dist/contact-quote.d.cts +1 -1
  74. package/dist/contact-quote.d.ts +1 -1
  75. package/dist/contact-referral.d.cts +1 -1
  76. package/dist/contact-referral.d.ts +1 -1
  77. package/dist/contact-report.d.cts +1 -1
  78. package/dist/contact-report.d.ts +1 -1
  79. package/dist/contact-reservation.d.cts +1 -1
  80. package/dist/contact-reservation.d.ts +1 -1
  81. package/dist/contact-retreat.d.cts +1 -1
  82. package/dist/contact-retreat.d.ts +1 -1
  83. package/dist/contact-rsvp.d.cts +1 -1
  84. package/dist/contact-rsvp.d.ts +1 -1
  85. package/dist/contact-sales.d.cts +1 -1
  86. package/dist/contact-sales.d.ts +1 -1
  87. package/dist/contact-schedule.d.cts +1 -1
  88. package/dist/contact-schedule.d.ts +1 -1
  89. package/dist/contact-sponsorship.d.cts +1 -1
  90. package/dist/contact-sponsorship.d.ts +1 -1
  91. package/dist/contact-support.d.cts +1 -1
  92. package/dist/contact-support.d.ts +1 -1
  93. package/dist/contact-tenant.d.cts +1 -1
  94. package/dist/contact-tenant.d.ts +1 -1
  95. package/dist/contact-vendor.d.cts +1 -1
  96. package/dist/contact-vendor.d.ts +1 -1
  97. package/dist/contact-volunteer.d.cts +1 -1
  98. package/dist/contact-volunteer.d.ts +1 -1
  99. package/dist/contact-warranty.d.cts +1 -1
  100. package/dist/contact-warranty.d.ts +1 -1
  101. package/dist/contact-wedding.d.cts +1 -1
  102. package/dist/contact-wedding.d.ts +1 -1
  103. package/dist/cta-app-download-newsletter.d.cts +1 -1
  104. package/dist/cta-app-download-newsletter.d.ts +1 -1
  105. package/dist/cta-newsletter-features.d.cts +1 -1
  106. package/dist/cta-newsletter-features.d.ts +1 -1
  107. package/dist/footer-accordion-social.d.cts +1 -1
  108. package/dist/footer-accordion-social.d.ts +1 -1
  109. package/dist/footer-newsletter-contact.d.cts +1 -1
  110. package/dist/footer-newsletter-contact.d.ts +1 -1
  111. package/dist/footer-newsletter-minimal.d.cts +1 -1
  112. package/dist/footer-newsletter-minimal.d.ts +1 -1
  113. package/dist/footer-split-image-accordion.d.cts +1 -1
  114. package/dist/footer-split-image-accordion.d.ts +1 -1
  115. package/dist/{forms-nGgHUTBw.d.cts → forms-CStlFhnh.d.cts} +41 -0
  116. package/dist/{forms-nGgHUTBw.d.ts → forms-CStlFhnh.d.ts} +41 -0
  117. package/dist/hero-conversation-intelligence.cjs +1 -2
  118. package/dist/hero-conversation-intelligence.d.cts +1 -5
  119. package/dist/hero-conversation-intelligence.d.ts +1 -5
  120. package/dist/hero-conversation-intelligence.js +1 -2
  121. package/dist/hero-conversion-video-play.cjs +2 -2
  122. package/dist/hero-conversion-video-play.js +2 -2
  123. package/dist/hero-design-system-3d.cjs +162 -82
  124. package/dist/hero-design-system-3d.js +162 -82
  125. package/dist/hero-ecommerce-product-showcase.cjs +103 -81
  126. package/dist/hero-ecommerce-product-showcase.d.cts +5 -1
  127. package/dist/hero-ecommerce-product-showcase.d.ts +5 -1
  128. package/dist/hero-ecommerce-product-showcase.js +103 -81
  129. package/dist/hero-floating-images.cjs +1 -1
  130. package/dist/hero-floating-images.js +1 -1
  131. package/dist/hero-hiring-animated-text.cjs +4 -4
  132. package/dist/hero-hiring-animated-text.js +4 -4
  133. package/dist/hero-minimal-centered-dark.cjs +111 -82
  134. package/dist/hero-minimal-centered-dark.d.cts +1 -1
  135. package/dist/hero-minimal-centered-dark.d.ts +1 -1
  136. package/dist/hero-minimal-centered-dark.js +111 -82
  137. package/dist/hero-mobile-app-download.cjs +1 -1
  138. package/dist/hero-mobile-app-download.js +1 -1
  139. package/dist/hero-overlay-cta-grid.cjs +1 -1
  140. package/dist/hero-overlay-cta-grid.js +1 -1
  141. package/dist/hero-spiral-pattern-cards.cjs +1 -1
  142. package/dist/hero-spiral-pattern-cards.js +1 -1
  143. package/dist/hero-startup-launch-cta.cjs +1 -1
  144. package/dist/hero-startup-launch-cta.js +1 -1
  145. package/dist/hero-stats-social-proof.cjs +106 -90
  146. package/dist/hero-stats-social-proof.js +106 -90
  147. package/dist/hero-testimonial-image-grid.cjs +1 -1
  148. package/dist/hero-testimonial-image-grid.js +1 -1
  149. package/dist/hero-therapy-testimonial-grid.cjs +1 -1
  150. package/dist/hero-therapy-testimonial-grid.js +1 -1
  151. package/dist/hero-ui-library-showcase.cjs +63 -15
  152. package/dist/hero-ui-library-showcase.d.cts +5 -1
  153. package/dist/hero-ui-library-showcase.d.ts +5 -1
  154. package/dist/hero-ui-library-showcase.js +63 -15
  155. package/dist/index.cjs +44 -6
  156. package/dist/index.d.cts +3 -2
  157. package/dist/index.d.ts +3 -2
  158. package/dist/index.js +44 -6
  159. package/dist/link-page-newsletter-social.d.cts +1 -1
  160. package/dist/link-page-newsletter-social.d.ts +1 -1
  161. package/dist/offer-modal-membership-image.d.cts +1 -1
  162. package/dist/offer-modal-membership-image.d.ts +1 -1
  163. package/dist/offer-modal-newsletter-discount.d.cts +1 -1
  164. package/dist/offer-modal-newsletter-discount.d.ts +1 -1
  165. package/dist/offer-modal-sheet-newsletter.d.cts +1 -1
  166. package/dist/offer-modal-sheet-newsletter.d.ts +1 -1
  167. package/dist/registry.cjs +14465 -14767
  168. package/dist/registry.js +12664 -12966
  169. package/dist/resource-list-hero-filter.d.cts +1 -1
  170. package/dist/resource-list-hero-filter.d.ts +1 -1
  171. package/package.json +3 -3
@@ -6,8 +6,7 @@ import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import { cva } from 'class-variance-authority';
8
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
- import { TextInput, TextArea, Select, Radio, Checkbox, CheckboxGroup, DatePicker, DateRangePicker, TimePicker, FileInput, RichTextEditor } from '@page-speed/forms/inputs';
10
- import * as LabelPrimitive from '@radix-ui/react-label';
9
+ import { TextInput, TextArea, Select, MultiSelect, Radio, Checkbox, CheckboxGroup, DatePicker, DateRangePicker, TimePicker, FileInput, RichTextEditor } from '@page-speed/forms/inputs';
11
10
  import { serializeForRails, deserializeErrors } from '@page-speed/forms/integration';
12
11
 
13
12
  // components/blocks/contact/contact-dark.tsx
@@ -357,6 +356,7 @@ var Pressable = React.forwardRef(
357
356
  rel,
358
357
  linkType,
359
358
  isInternal,
359
+ isExternal,
360
360
  handleClick
361
361
  } = navigation;
362
362
  const shouldRenderLink = normalizedHref && linkType !== "none";
@@ -550,22 +550,6 @@ function Card({ className, ...props }) {
550
550
  }
551
551
  );
552
552
  }
553
- function Label({
554
- className,
555
- ...props
556
- }) {
557
- return /* @__PURE__ */ jsx(
558
- LabelPrimitive.Root,
559
- {
560
- "data-slot": "label",
561
- className: cn(
562
- "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
563
- className
564
- ),
565
- ...props
566
- }
567
- );
568
- }
569
553
  function DynamicFormField({
570
554
  field,
571
555
  className,
@@ -574,190 +558,199 @@ function DynamicFormField({
574
558
  onFileRemove,
575
559
  isUploading = false
576
560
  }) {
577
- const fieldId = `field-${field.name}`;
578
- return /* @__PURE__ */ jsx(Field, { name: field.name, children: ({ field: formField, meta }) => /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), children: [
579
- field.type !== "checkbox" && /* @__PURE__ */ jsxs(Label, { htmlFor: fieldId, children: [
580
- field.label,
581
- field.required && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" })
582
- ] }),
583
- (field.type === "text" || field.type === "email" || field.type === "tel" || field.type === "search" || field.type === "password" || field.type === "url") && /* @__PURE__ */ jsx(
584
- TextInput,
585
- {
586
- ...formField,
587
- id: fieldId,
588
- type: field.type,
589
- placeholder: field.placeholder,
590
- error: meta.touched && !!meta.error,
591
- disabled: field.disabled,
592
- "aria-label": field.label
593
- }
594
- ),
595
- field.type === "number" && /* @__PURE__ */ jsx(
596
- TextInput,
597
- {
598
- ...formField,
599
- id: fieldId,
600
- type: "text",
601
- placeholder: field.placeholder,
602
- error: meta.touched && !!meta.error,
603
- disabled: field.disabled,
604
- "aria-label": field.label
605
- }
606
- ),
607
- field.type === "textarea" && /* @__PURE__ */ jsx(
608
- TextArea,
609
- {
610
- ...formField,
611
- id: fieldId,
612
- placeholder: field.placeholder,
613
- rows: field.rows || 4,
614
- error: meta.touched && !!meta.error,
615
- disabled: field.disabled,
616
- "aria-label": field.label
617
- }
618
- ),
619
- field.type === "select" && field.options && /* @__PURE__ */ jsx(
620
- Select,
621
- {
622
- ...formField,
623
- id: fieldId,
624
- options: field.options,
625
- placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
626
- error: meta.touched && !!meta.error,
627
- disabled: field.disabled,
628
- "aria-label": field.label
629
- }
630
- ),
631
- field.type === "multi-select" && field.options && /* @__PURE__ */ jsx(
632
- Select,
633
- {
634
- ...formField,
635
- id: fieldId,
636
- options: field.options,
637
- placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
638
- error: meta.touched && !!meta.error,
639
- disabled: field.disabled,
640
- "aria-label": field.label,
641
- multiple: true
642
- }
643
- ),
644
- field.type === "radio" && field.options && /* @__PURE__ */ jsx(
645
- Radio,
646
- {
647
- ...formField,
648
- id: fieldId,
649
- options: field.options,
650
- disabled: field.disabled,
651
- layout: field.layout || "stacked",
652
- error: meta.touched && !!meta.error,
653
- "aria-label": field.label
654
- }
655
- ),
656
- field.type === "checkbox" && /* @__PURE__ */ jsxs("div", { className: "flex items-start space-x-2", children: [
657
- /* @__PURE__ */ jsx(
658
- Checkbox,
659
- {
660
- ...formField,
661
- id: fieldId,
662
- value: formField.value === true || formField.value === "true",
663
- onChange: (checked) => formField.onChange(checked),
664
- disabled: field.disabled,
665
- error: meta.touched && !!meta.error,
666
- "aria-label": field.label
667
- }
668
- ),
669
- /* @__PURE__ */ jsxs(
670
- Label,
671
- {
672
- htmlFor: fieldId,
673
- className: "font-normal cursor-pointer leading-relaxed",
674
- children: [
675
- field.label,
676
- field.required && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" })
677
- ]
678
- }
679
- )
680
- ] }),
681
- field.type === "checkbox-group" && field.options && /* @__PURE__ */ jsx(
682
- CheckboxGroup,
683
- {
684
- ...formField,
685
- id: fieldId,
686
- options: field.options,
687
- disabled: field.disabled,
688
- layout: field.layout || "stacked",
689
- error: meta.touched && !!meta.error,
690
- "aria-label": field.label
691
- }
692
- ),
693
- (field.type === "date-picker" || field.type === "date") && /* @__PURE__ */ jsx(
694
- DatePicker,
695
- {
696
- ...formField,
697
- id: fieldId,
698
- placeholder: field.placeholder,
699
- error: meta.touched && !!meta.error,
700
- disabled: field.disabled,
701
- "aria-label": field.label
702
- }
703
- ),
704
- field.type === "date-range" && /* @__PURE__ */ jsx(
705
- DateRangePicker,
706
- {
707
- ...formField,
708
- id: fieldId,
709
- error: meta.touched && !!meta.error,
710
- disabled: field.disabled,
711
- "aria-label": field.label
712
- }
713
- ),
714
- field.type === "time" && /* @__PURE__ */ jsx(
715
- TimePicker,
716
- {
717
- ...formField,
718
- id: fieldId,
719
- placeholder: field.placeholder,
720
- error: meta.touched && !!meta.error,
721
- disabled: field.disabled,
722
- "aria-label": field.label
723
- }
724
- ),
725
- field.type === "file" && /* @__PURE__ */ jsx(
726
- FileInput,
727
- {
728
- ...formField,
729
- id: fieldId,
730
- accept: field.accept,
731
- maxSize: field.maxSize || 5 * 1024 * 1024,
732
- maxFiles: field.maxFiles || 1,
733
- multiple: field.multiple || false,
734
- placeholder: field.placeholder || "Choose file(s)...",
735
- error: meta.touched && !!meta.error,
736
- disabled: field.disabled || isUploading,
737
- showProgress: true,
738
- uploadProgress,
739
- onChange: (files) => {
740
- formField.onChange(files);
741
- if (files.length > 0 && onFileUpload) {
742
- onFileUpload(files);
561
+ const fieldId = field.name;
562
+ const usesGroupLegend = field.type === "radio" || field.type === "checkbox-group";
563
+ const usesInlineCheckboxLabel = field.type === "checkbox";
564
+ const shouldRenderFieldLabel = !usesGroupLegend && !usesInlineCheckboxLabel;
565
+ const checkboxLabel = /* @__PURE__ */ jsxs(Fragment, { children: [
566
+ field.label,
567
+ field.required ? /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" }) : null
568
+ ] });
569
+ return /* @__PURE__ */ jsx(
570
+ Field,
571
+ {
572
+ name: field.name,
573
+ label: shouldRenderFieldLabel ? field.label : void 0,
574
+ description: shouldRenderFieldLabel ? field.description : void 0,
575
+ required: field.required,
576
+ className: cn("space-y-2", className),
577
+ children: ({ field: formField, meta }) => /* @__PURE__ */ jsxs("div", { children: [
578
+ (field.type === "text" || field.type === "email" || field.type === "tel" || field.type === "search" || field.type === "password" || field.type === "url") && /* @__PURE__ */ jsx(
579
+ TextInput,
580
+ {
581
+ ...formField,
582
+ id: fieldId,
583
+ type: field.type,
584
+ placeholder: field.placeholder,
585
+ error: meta.touched && !!meta.error,
586
+ disabled: field.disabled,
587
+ "aria-label": field.label
743
588
  }
744
- },
745
- onFileRemove,
746
- "aria-label": field.label
747
- }
748
- ),
749
- field.type === "rich-text" && /* @__PURE__ */ jsx(
750
- RichTextEditor,
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
- )
760
- ] }) });
589
+ ),
590
+ field.type === "number" && /* @__PURE__ */ jsx(
591
+ TextInput,
592
+ {
593
+ ...formField,
594
+ id: fieldId,
595
+ type: "text",
596
+ placeholder: field.placeholder,
597
+ error: meta.touched && !!meta.error,
598
+ disabled: field.disabled,
599
+ "aria-label": field.label
600
+ }
601
+ ),
602
+ field.type === "textarea" && /* @__PURE__ */ jsx(
603
+ TextArea,
604
+ {
605
+ ...formField,
606
+ id: fieldId,
607
+ placeholder: field.placeholder,
608
+ rows: field.rows || 4,
609
+ error: meta.touched && !!meta.error,
610
+ disabled: field.disabled,
611
+ "aria-label": field.label
612
+ }
613
+ ),
614
+ field.type === "select" && field.options && /* @__PURE__ */ jsx(
615
+ Select,
616
+ {
617
+ ...formField,
618
+ id: fieldId,
619
+ options: field.options,
620
+ placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
621
+ error: meta.touched && !!meta.error,
622
+ disabled: field.disabled,
623
+ "aria-label": field.label
624
+ }
625
+ ),
626
+ field.type === "multi-select" && field.options && /* @__PURE__ */ jsx(
627
+ MultiSelect,
628
+ {
629
+ ...formField,
630
+ id: fieldId,
631
+ options: field.options,
632
+ placeholder: field.placeholder || `Select ${field.label.toLowerCase()}`,
633
+ error: meta.touched && !!meta.error,
634
+ disabled: field.disabled,
635
+ "aria-label": field.label
636
+ }
637
+ ),
638
+ field.type === "radio" && field.options && /* @__PURE__ */ jsx(
639
+ Radio,
640
+ {
641
+ ...formField,
642
+ id: fieldId,
643
+ options: field.options,
644
+ label: field.label,
645
+ description: field.description,
646
+ required: field.required,
647
+ disabled: field.disabled,
648
+ layout: field.layout || "stacked",
649
+ error: meta.touched && !!meta.error,
650
+ "aria-label": field.label
651
+ }
652
+ ),
653
+ field.type === "checkbox" && /* @__PURE__ */ jsx(
654
+ Checkbox,
655
+ {
656
+ ...formField,
657
+ id: fieldId,
658
+ value: formField.value === true || formField.value === "true",
659
+ onChange: (checked) => formField.onChange(checked),
660
+ label: checkboxLabel,
661
+ description: field.description,
662
+ disabled: field.disabled,
663
+ required: field.required,
664
+ error: meta.touched && !!meta.error,
665
+ "aria-label": field.label
666
+ }
667
+ ),
668
+ field.type === "checkbox-group" && field.options && /* @__PURE__ */ jsx(
669
+ CheckboxGroup,
670
+ {
671
+ ...formField,
672
+ id: fieldId,
673
+ options: field.options,
674
+ label: field.label,
675
+ description: field.description,
676
+ required: field.required,
677
+ disabled: field.disabled,
678
+ layout: field.layout || "stacked",
679
+ error: meta.touched && !!meta.error,
680
+ "aria-label": field.label
681
+ }
682
+ ),
683
+ (field.type === "date-picker" || field.type === "date") && /* @__PURE__ */ jsx(
684
+ DatePicker,
685
+ {
686
+ ...formField,
687
+ id: fieldId,
688
+ placeholder: field.placeholder,
689
+ error: meta.touched && !!meta.error,
690
+ disabled: field.disabled,
691
+ "aria-label": field.label
692
+ }
693
+ ),
694
+ field.type === "date-range" && /* @__PURE__ */ jsx(
695
+ DateRangePicker,
696
+ {
697
+ ...formField,
698
+ id: fieldId,
699
+ placeholder: field.placeholder,
700
+ error: meta.touched && !!meta.error,
701
+ disabled: field.disabled,
702
+ "aria-label": field.label
703
+ }
704
+ ),
705
+ field.type === "time" && /* @__PURE__ */ jsx(
706
+ TimePicker,
707
+ {
708
+ ...formField,
709
+ id: fieldId,
710
+ placeholder: field.placeholder,
711
+ error: meta.touched && !!meta.error,
712
+ disabled: field.disabled,
713
+ "aria-label": field.label
714
+ }
715
+ ),
716
+ field.type === "file" && /* @__PURE__ */ jsx(
717
+ FileInput,
718
+ {
719
+ ...formField,
720
+ id: fieldId,
721
+ accept: field.accept,
722
+ maxSize: field.maxSize || 5 * 1024 * 1024,
723
+ maxFiles: field.maxFiles || 1,
724
+ multiple: field.multiple || false,
725
+ placeholder: field.placeholder || "Choose file(s)...",
726
+ error: meta.touched && !!meta.error,
727
+ disabled: field.disabled || isUploading,
728
+ showProgress: true,
729
+ uploadProgress,
730
+ onChange: (files) => {
731
+ formField.onChange(files);
732
+ if (files.length > 0 && onFileUpload) {
733
+ onFileUpload(files);
734
+ }
735
+ },
736
+ onFileRemove,
737
+ "aria-label": field.label
738
+ }
739
+ ),
740
+ field.type === "rich-text" && /* @__PURE__ */ jsx(
741
+ RichTextEditor,
742
+ {
743
+ ...formField,
744
+ id: fieldId,
745
+ placeholder: field.placeholder,
746
+ error: meta.touched && !!meta.error,
747
+ disabled: field.disabled,
748
+ "aria-label": field.label
749
+ }
750
+ )
751
+ ] })
752
+ }
753
+ );
761
754
  }
762
755
 
763
756
  // lib/form-field-types.ts
@@ -889,8 +882,36 @@ function useContactForm(options) {
889
882
  resetOnSuccess = true,
890
883
  uploadTokens = []
891
884
  } = options;
892
- const [isSubmitted, setIsSubmitted] = useState(false);
893
885
  const [submissionError, setSubmissionError] = useState(null);
886
+ const submissionConfig = formConfig?.submissionConfig;
887
+ const redirectUrl = submissionConfig?.redirectUrl;
888
+ const redirectNavigation = useNavigation({ href: redirectUrl });
889
+ const resetSubmissionState = useCallback(() => {
890
+ setSubmissionError(null);
891
+ }, []);
892
+ const performRedirect = useCallback(() => {
893
+ if (!redirectUrl || typeof window === "undefined") {
894
+ return;
895
+ }
896
+ const navigate = () => {
897
+ if (redirectNavigation.shouldUseRouter && redirectNavigation.normalizedHref) {
898
+ const handler = window.__opensiteNavigationHandler;
899
+ if (typeof handler === "function") {
900
+ try {
901
+ const handled = handler(redirectNavigation.normalizedHref, void 0);
902
+ if (handled !== false) {
903
+ return;
904
+ }
905
+ } catch (error) {
906
+ console.error("Internal redirect handler failed:", error);
907
+ }
908
+ }
909
+ }
910
+ const destination = redirectNavigation.normalizedHref || redirectUrl;
911
+ window.location.assign(destination);
912
+ };
913
+ window.setTimeout(navigate, 150);
914
+ }, [redirectNavigation, redirectUrl]);
894
915
  const form = useForm({
895
916
  initialValues: useMemo(
896
917
  () => generateInitialValues(formFields),
@@ -901,7 +922,7 @@ function useContactForm(options) {
901
922
  [formFields]
902
923
  ),
903
924
  onSubmit: async (values, helpers) => {
904
- setSubmissionError(null);
925
+ resetSubmissionState();
905
926
  const shouldAutoSubmit = Boolean(formConfig?.endpoint);
906
927
  if (!shouldAutoSubmit && !onSubmit) {
907
928
  return;
@@ -921,12 +942,21 @@ function useContactForm(options) {
921
942
  await onSubmit(submissionValues);
922
943
  }
923
944
  if (shouldAutoSubmit || onSubmit) {
924
- setIsSubmitted(true);
945
+ try {
946
+ await submissionConfig?.handleFormSubmission?.({
947
+ formData: submissionValues,
948
+ responseData: result
949
+ });
950
+ } catch (callbackError) {
951
+ console.error("handleFormSubmission callback failed:", callbackError);
952
+ }
925
953
  if (resetOnSuccess) {
926
954
  helpers.resetForm();
927
955
  }
928
956
  onSuccess?.(result);
929
- setTimeout(() => setIsSubmitted(false), 1e4);
957
+ if (submissionConfig?.behavior === "redirect" && submissionConfig.redirectUrl) {
958
+ performRedirect();
959
+ }
930
960
  }
931
961
  } catch (error) {
932
962
  if (error instanceof PageSpeedFormSubmissionError && error.formErrors) {
@@ -941,9 +971,10 @@ function useContactForm(options) {
941
971
  const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
942
972
  return {
943
973
  form,
944
- isSubmitted,
974
+ isSubmitted: form.status === "success",
945
975
  submissionError,
946
- formMethod
976
+ formMethod,
977
+ resetSubmissionState
947
978
  };
948
979
  }
949
980
 
@@ -1438,38 +1469,6 @@ var Section = React__default.forwardRef(
1438
1469
  }
1439
1470
  );
1440
1471
  Section.displayName = "Section";
1441
- var FormFeedback = ({
1442
- isSubmitted,
1443
- successMessageClassName,
1444
- successMessage,
1445
- submissionError,
1446
- errorMessageClassName
1447
- }) => {
1448
- if (!isSubmitted && !submissionError) return null;
1449
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1450
- isSubmitted && !submissionError && /* @__PURE__ */ jsx(
1451
- "div",
1452
- {
1453
- className: cn(
1454
- "mb-6 p-4 bg-primary/10 border border-primary rounded-md",
1455
- successMessageClassName
1456
- ),
1457
- children: typeof successMessage === "string" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-primary-foreground/90 text-center", children: successMessage }) : successMessage
1458
- }
1459
- ),
1460
- submissionError && /* @__PURE__ */ jsx(
1461
- "div",
1462
- {
1463
- className: cn(
1464
- "mb-6 p-4 bg-destructive/10 border border-destructive rounded-md",
1465
- errorMessageClassName
1466
- ),
1467
- children: typeof submissionError === "string" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive text-center", children: submissionError }) : submissionError
1468
- }
1469
- )
1470
- ] });
1471
- };
1472
- var form_feedback_default = FormFeedback;
1473
1472
  var DEFAULT_FORM_FIELDS = [
1474
1473
  {
1475
1474
  name: "firstName",
@@ -1551,7 +1550,7 @@ function ContactDark({
1551
1550
  removeFile,
1552
1551
  resetUpload
1553
1552
  } = useFileUpload({ onError });
1554
- const { form, isSubmitted, submissionError, formMethod } = useContactForm({
1553
+ const { form, submissionError, formMethod, resetSubmissionState } = useContactForm({
1555
1554
  formFields,
1556
1555
  formConfig,
1557
1556
  onSubmit,
@@ -1624,9 +1623,14 @@ function ContactDark({
1624
1623
  Pressable,
1625
1624
  {
1626
1625
  href: social.href,
1627
- className: "flex h-9 w-9 items-center justify-center rounded-full border border-primary-foreground/20 text-primary-foreground/70 transition-colors hover:border-primary-foreground/40 hover:text-primary-foreground",
1626
+ className: cn(
1627
+ "flex h-9 w-9 items-center justify-center",
1628
+ "rounded-xl border-2 transition-shadow duration-1000",
1629
+ "bg-primary text-primary-foreground border-primary-foreground",
1630
+ "shadow-sm hover:shadow-xl"
1631
+ ),
1628
1632
  "aria-label": social.label,
1629
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: social.icon, size: 16 })
1633
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: social.icon, size: 18 })
1630
1634
  },
1631
1635
  key
1632
1636
  ));
@@ -1673,60 +1677,57 @@ function ContactDark({
1673
1677
  cardClassName
1674
1678
  ),
1675
1679
  children: [
1676
- /* @__PURE__ */ jsxs("div", { className: cn("p-6 lg:p-12", formPanelClassName), children: [
1677
- /* @__PURE__ */ jsx(
1678
- form_feedback_default,
1679
- {
1680
- isSubmitted,
1681
- successMessageClassName,
1682
- successMessage,
1683
- submissionError,
1684
- errorMessageClassName
1685
- }
1686
- ),
1687
- /* @__PURE__ */ jsxs(
1688
- Form,
1689
- {
1690
- form,
1691
- action: formConfig?.endpoint,
1692
- method: formMethod,
1693
- className: cn("space-y-6", formClassName),
1694
- children: [
1695
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-12 gap-6", children: formFields.map((field) => /* @__PURE__ */ jsx(
1696
- "div",
1697
- {
1698
- className: getColumnSpanClass(field.columnSpan),
1699
- children: /* @__PURE__ */ jsx(
1700
- DynamicFormField,
1701
- {
1702
- field,
1703
- uploadProgress,
1704
- onFileUpload: uploadFiles,
1705
- onFileRemove: removeFile,
1706
- isUploading
1707
- }
1708
- )
1709
- },
1710
- field.name
1711
- )) }),
1712
- actionsSlot || actions && actions.length > 0 ? actionsContent : /* @__PURE__ */ jsxs(
1713
- Pressable,
1714
- {
1715
- componentType: "button",
1716
- type: "submit",
1717
- className: cn("w-full", submitClassName),
1718
- asButton: true,
1719
- disabled: form.isSubmitting,
1720
- children: [
1721
- buttonIcon,
1722
- buttonText
1723
- ]
1724
- }
1725
- )
1726
- ]
1727
- }
1728
- )
1729
- ] }),
1680
+ /* @__PURE__ */ jsx("div", { className: cn("p-6 lg:p-12", formPanelClassName), children: /* @__PURE__ */ jsxs(
1681
+ Form,
1682
+ {
1683
+ form,
1684
+ action: formConfig?.endpoint,
1685
+ method: formMethod,
1686
+ submissionError,
1687
+ successMessage,
1688
+ successMessageClassName,
1689
+ errorMessageClassName,
1690
+ submissionConfig: formConfig?.submissionConfig,
1691
+ onNewSubmission: () => {
1692
+ resetUpload();
1693
+ resetSubmissionState();
1694
+ },
1695
+ className: cn("space-y-6", formClassName),
1696
+ children: [
1697
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-12 gap-6", children: formFields.map((field) => /* @__PURE__ */ jsx(
1698
+ "div",
1699
+ {
1700
+ className: getColumnSpanClass(field.columnSpan),
1701
+ children: /* @__PURE__ */ jsx(
1702
+ DynamicFormField,
1703
+ {
1704
+ field,
1705
+ uploadProgress,
1706
+ onFileUpload: uploadFiles,
1707
+ onFileRemove: removeFile,
1708
+ isUploading
1709
+ }
1710
+ )
1711
+ },
1712
+ field.name
1713
+ )) }),
1714
+ actionsSlot || actions && actions.length > 0 ? actionsContent : /* @__PURE__ */ jsxs(
1715
+ Pressable,
1716
+ {
1717
+ componentType: "button",
1718
+ type: "submit",
1719
+ className: cn("w-full", submitClassName),
1720
+ asButton: true,
1721
+ disabled: form.isSubmitting,
1722
+ children: [
1723
+ buttonIcon,
1724
+ buttonText
1725
+ ]
1726
+ }
1727
+ )
1728
+ ]
1729
+ }
1730
+ ) }),
1730
1731
  /* @__PURE__ */ jsxs(
1731
1732
  "div",
1732
1733
  {