@opensite/ui 1.7.5 → 1.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contact-dark.cjs +503 -124
- package/dist/contact-dark.d.cts +28 -9
- package/dist/contact-dark.d.ts +28 -9
- package/dist/contact-dark.js +505 -126
- package/dist/contact-faq.cjs +482 -104
- package/dist/contact-faq.d.cts +27 -17
- package/dist/contact-faq.d.ts +27 -17
- package/dist/contact-faq.js +484 -106
- package/dist/contact-photography.cjs +485 -116
- package/dist/contact-photography.d.cts +22 -9
- package/dist/contact-photography.d.ts +22 -9
- package/dist/contact-photography.js +487 -118
- package/dist/form-field-types-BYdJNOsW.d.cts +92 -0
- package/dist/form-field-types-BYdJNOsW.d.ts +92 -0
- package/dist/registry.cjs +2397 -2037
- package/dist/registry.js +1141 -781
- package/package.json +6 -1
package/dist/contact-dark.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default from 'react';
|
|
4
|
-
import {
|
|
5
|
-
import { TextInput, TextArea } from '@page-speed/forms/inputs';
|
|
3
|
+
import React__default, { useState, useCallback, useMemo } from 'react';
|
|
4
|
+
import { Form, useForm, Field } from '@page-speed/forms';
|
|
6
5
|
import { clsx } from 'clsx';
|
|
7
6
|
import { twMerge } from 'tailwind-merge';
|
|
8
7
|
import { cva } from 'class-variance-authority';
|
|
9
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
10
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
11
11
|
import { serializeForRails, deserializeErrors } from '@page-speed/forms/integration';
|
|
12
12
|
|
|
@@ -566,6 +566,389 @@ function Label({
|
|
|
566
566
|
}
|
|
567
567
|
);
|
|
568
568
|
}
|
|
569
|
+
function DynamicFormField({
|
|
570
|
+
field,
|
|
571
|
+
className,
|
|
572
|
+
uploadProgress = {},
|
|
573
|
+
onFileUpload,
|
|
574
|
+
onFileRemove,
|
|
575
|
+
isUploading = false
|
|
576
|
+
}) {
|
|
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);
|
|
743
|
+
}
|
|
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
|
+
meta.touched && meta.error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: meta.error })
|
|
761
|
+
] }) });
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// lib/form-field-types.ts
|
|
765
|
+
function generateInitialValues(fields) {
|
|
766
|
+
return fields.reduce(
|
|
767
|
+
(acc, field) => {
|
|
768
|
+
if (field.type === "checkbox") {
|
|
769
|
+
acc[field.name] = false;
|
|
770
|
+
} else if (field.type === "checkbox-group" || field.type === "multi-select") {
|
|
771
|
+
acc[field.name] = [];
|
|
772
|
+
} else if (field.type === "file") {
|
|
773
|
+
acc[field.name] = [];
|
|
774
|
+
} else if (field.type === "date-range") {
|
|
775
|
+
acc[field.name] = { start: null, end: null };
|
|
776
|
+
} else {
|
|
777
|
+
acc[field.name] = "";
|
|
778
|
+
}
|
|
779
|
+
return acc;
|
|
780
|
+
},
|
|
781
|
+
{}
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
function generateValidationSchema(fields) {
|
|
785
|
+
return fields.reduce(
|
|
786
|
+
(acc, field) => {
|
|
787
|
+
acc[field.name] = (value, allValues) => {
|
|
788
|
+
if (field.required) {
|
|
789
|
+
if (!value || typeof value === "string" && !value.trim()) {
|
|
790
|
+
return `${field.label} is required`;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (field.type === "email" && value) {
|
|
794
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
|
|
795
|
+
return "Please enter a valid email address";
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (field.type === "url" && value) {
|
|
799
|
+
try {
|
|
800
|
+
new URL(value);
|
|
801
|
+
} catch {
|
|
802
|
+
return "Please enter a valid URL";
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (field.validator) {
|
|
806
|
+
return field.validator(value, allValues);
|
|
807
|
+
}
|
|
808
|
+
return void 0;
|
|
809
|
+
};
|
|
810
|
+
return acc;
|
|
811
|
+
},
|
|
812
|
+
{}
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
function getColumnSpanClass(span) {
|
|
816
|
+
if (!span || span === 12) return "col-span-12";
|
|
817
|
+
return `col-span-12 sm:col-span-${Math.min(span, 12)}`;
|
|
818
|
+
}
|
|
819
|
+
function useFileUpload(options) {
|
|
820
|
+
const [uploadTokens, setUploadTokens] = useState([]);
|
|
821
|
+
const [uploadProgress, setUploadProgress] = useState({});
|
|
822
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
823
|
+
const endpoint = options?.endpoint || "https://api.dashtrack.com/contacts/_/contact_form_uploads";
|
|
824
|
+
const uploadFiles = useCallback(
|
|
825
|
+
async (files) => {
|
|
826
|
+
if (files.length === 0) return;
|
|
827
|
+
setIsUploading(true);
|
|
828
|
+
try {
|
|
829
|
+
const tokens = [];
|
|
830
|
+
for (const file of files) {
|
|
831
|
+
const formData = new FormData();
|
|
832
|
+
formData.append("contact_form_upload[file_upload]", file);
|
|
833
|
+
formData.append("contact_form_upload[title]", file.name);
|
|
834
|
+
formData.append("contact_form_upload[file_name]", file.name);
|
|
835
|
+
formData.append("contact_form_upload[file_size]", String(file.size));
|
|
836
|
+
const response = await fetch(endpoint, {
|
|
837
|
+
method: "POST",
|
|
838
|
+
body: formData
|
|
839
|
+
});
|
|
840
|
+
if (!response.ok) {
|
|
841
|
+
throw new Error(`Upload failed: ${response.statusText}`);
|
|
842
|
+
}
|
|
843
|
+
const data = await response.json();
|
|
844
|
+
if (data.contact_form_upload?.token) {
|
|
845
|
+
tokens.push(`upload_${data.contact_form_upload.token}`);
|
|
846
|
+
}
|
|
847
|
+
setUploadProgress((prev) => ({
|
|
848
|
+
...prev,
|
|
849
|
+
[file.name]: 100
|
|
850
|
+
}));
|
|
851
|
+
}
|
|
852
|
+
setUploadTokens(tokens);
|
|
853
|
+
} catch (error) {
|
|
854
|
+
console.error("File upload error:", error);
|
|
855
|
+
options?.onError?.(error);
|
|
856
|
+
} finally {
|
|
857
|
+
setIsUploading(false);
|
|
858
|
+
}
|
|
859
|
+
},
|
|
860
|
+
[endpoint, options]
|
|
861
|
+
);
|
|
862
|
+
const removeFile = useCallback((file, index) => {
|
|
863
|
+
setUploadTokens((prev) => prev.filter((_, i) => i !== index));
|
|
864
|
+
setUploadProgress((prev) => {
|
|
865
|
+
const newProgress = { ...prev };
|
|
866
|
+
delete newProgress[file.name];
|
|
867
|
+
return newProgress;
|
|
868
|
+
});
|
|
869
|
+
}, []);
|
|
870
|
+
const resetUpload = useCallback(() => {
|
|
871
|
+
setUploadTokens([]);
|
|
872
|
+
setUploadProgress({});
|
|
873
|
+
}, []);
|
|
874
|
+
return {
|
|
875
|
+
uploadTokens,
|
|
876
|
+
uploadProgress,
|
|
877
|
+
isUploading,
|
|
878
|
+
uploadFiles,
|
|
879
|
+
removeFile,
|
|
880
|
+
resetUpload
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
function useContactForm(options) {
|
|
884
|
+
const {
|
|
885
|
+
formFields,
|
|
886
|
+
formConfig,
|
|
887
|
+
onSubmit,
|
|
888
|
+
onSuccess,
|
|
889
|
+
onError,
|
|
890
|
+
resetOnSuccess = true,
|
|
891
|
+
uploadTokens = []
|
|
892
|
+
} = options;
|
|
893
|
+
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
894
|
+
const [submissionError, setSubmissionError] = useState(null);
|
|
895
|
+
const form = useForm({
|
|
896
|
+
initialValues: useMemo(
|
|
897
|
+
() => generateInitialValues(formFields),
|
|
898
|
+
[formFields]
|
|
899
|
+
),
|
|
900
|
+
validationSchema: useMemo(
|
|
901
|
+
() => generateValidationSchema(formFields),
|
|
902
|
+
[formFields]
|
|
903
|
+
),
|
|
904
|
+
onSubmit: async (values, helpers) => {
|
|
905
|
+
setSubmissionError(null);
|
|
906
|
+
const shouldAutoSubmit = Boolean(formConfig?.endpoint);
|
|
907
|
+
if (!shouldAutoSubmit && !onSubmit) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
try {
|
|
911
|
+
let result;
|
|
912
|
+
const submissionValues = {
|
|
913
|
+
...values,
|
|
914
|
+
...uploadTokens.length > 0 && {
|
|
915
|
+
contact_form_upload_tokens: uploadTokens
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
if (shouldAutoSubmit) {
|
|
919
|
+
result = await submitPageSpeedForm(submissionValues, formConfig);
|
|
920
|
+
}
|
|
921
|
+
if (onSubmit) {
|
|
922
|
+
await onSubmit(submissionValues);
|
|
923
|
+
}
|
|
924
|
+
if (shouldAutoSubmit || onSubmit) {
|
|
925
|
+
setIsSubmitted(true);
|
|
926
|
+
if (resetOnSuccess) {
|
|
927
|
+
helpers.resetForm();
|
|
928
|
+
}
|
|
929
|
+
onSuccess?.(result);
|
|
930
|
+
setTimeout(() => setIsSubmitted(false), 5e3);
|
|
931
|
+
}
|
|
932
|
+
} catch (error) {
|
|
933
|
+
if (error instanceof PageSpeedFormSubmissionError && error.formErrors) {
|
|
934
|
+
helpers.setErrors(error.formErrors);
|
|
935
|
+
}
|
|
936
|
+
const errorMessage = error instanceof Error ? error.message : "Form submission failed";
|
|
937
|
+
setSubmissionError(errorMessage);
|
|
938
|
+
onError?.(error);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
|
|
943
|
+
return {
|
|
944
|
+
form,
|
|
945
|
+
isSubmitted,
|
|
946
|
+
submissionError,
|
|
947
|
+
formMethod
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// lib/forms.ts
|
|
569
952
|
var PageSpeedFormSubmissionError = class extends Error {
|
|
570
953
|
constructor(message, options = {}) {
|
|
571
954
|
super(message);
|
|
@@ -1056,12 +1439,47 @@ var Section = React__default.forwardRef(
|
|
|
1056
1439
|
}
|
|
1057
1440
|
);
|
|
1058
1441
|
Section.displayName = "Section";
|
|
1442
|
+
var DEFAULT_FORM_FIELDS = [
|
|
1443
|
+
{
|
|
1444
|
+
name: "firstName",
|
|
1445
|
+
type: "text",
|
|
1446
|
+
label: "First Name",
|
|
1447
|
+
placeholder: "First name",
|
|
1448
|
+
required: true,
|
|
1449
|
+
columnSpan: 6
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
name: "lastName",
|
|
1453
|
+
type: "text",
|
|
1454
|
+
label: "Last Name",
|
|
1455
|
+
placeholder: "Last name",
|
|
1456
|
+
required: true,
|
|
1457
|
+
columnSpan: 6
|
|
1458
|
+
},
|
|
1459
|
+
{
|
|
1460
|
+
name: "email",
|
|
1461
|
+
type: "email",
|
|
1462
|
+
label: "Email Address",
|
|
1463
|
+
placeholder: "your@email.com",
|
|
1464
|
+
required: true,
|
|
1465
|
+
columnSpan: 12
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
name: "message",
|
|
1469
|
+
type: "textarea",
|
|
1470
|
+
label: "Message",
|
|
1471
|
+
placeholder: "Your message...",
|
|
1472
|
+
required: true,
|
|
1473
|
+
rows: 4,
|
|
1474
|
+
columnSpan: 12
|
|
1475
|
+
}
|
|
1476
|
+
];
|
|
1059
1477
|
function ContactDark({
|
|
1060
1478
|
heading,
|
|
1061
1479
|
description,
|
|
1062
1480
|
contactHeading = "Contact Information",
|
|
1063
1481
|
contactDescription = "Fill up the form and our team will get back to you within 24 hours.",
|
|
1064
|
-
buttonText,
|
|
1482
|
+
buttonText = "Submit",
|
|
1065
1483
|
buttonIcon,
|
|
1066
1484
|
actions,
|
|
1067
1485
|
actionsSlot,
|
|
@@ -1069,6 +1487,9 @@ function ContactDark({
|
|
|
1069
1487
|
contactOptionsSlot,
|
|
1070
1488
|
socialLinks,
|
|
1071
1489
|
socialLinksSlot,
|
|
1490
|
+
formFields = DEFAULT_FORM_FIELDS,
|
|
1491
|
+
successMessage = "Thank you! Your message has been sent successfully.",
|
|
1492
|
+
errorMessage = "There was an error sending your message. Please try again.",
|
|
1072
1493
|
className,
|
|
1073
1494
|
headerClassName,
|
|
1074
1495
|
headingClassName,
|
|
@@ -1080,6 +1501,8 @@ function ContactDark({
|
|
|
1080
1501
|
infoPanelClassName,
|
|
1081
1502
|
contactOptionsClassName,
|
|
1082
1503
|
socialLinksClassName,
|
|
1504
|
+
successMessageClassName,
|
|
1505
|
+
errorMessageClassName,
|
|
1083
1506
|
background,
|
|
1084
1507
|
spacing = "py-8 md:py-32",
|
|
1085
1508
|
containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
|
|
@@ -1090,53 +1513,26 @@ function ContactDark({
|
|
|
1090
1513
|
onSuccess,
|
|
1091
1514
|
onError
|
|
1092
1515
|
}) {
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
},
|
|
1109
|
-
message: (value) => !value ? "Message is required" : void 0
|
|
1516
|
+
const {
|
|
1517
|
+
uploadTokens,
|
|
1518
|
+
uploadProgress,
|
|
1519
|
+
isUploading,
|
|
1520
|
+
uploadFiles,
|
|
1521
|
+
removeFile,
|
|
1522
|
+
resetUpload
|
|
1523
|
+
} = useFileUpload({ onError });
|
|
1524
|
+
const { form, isSubmitted, submissionError, formMethod } = useContactForm({
|
|
1525
|
+
formFields,
|
|
1526
|
+
formConfig,
|
|
1527
|
+
onSubmit,
|
|
1528
|
+
onSuccess: (data) => {
|
|
1529
|
+
resetUpload();
|
|
1530
|
+
onSuccess?.(data);
|
|
1110
1531
|
},
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
return;
|
|
1115
|
-
}
|
|
1116
|
-
try {
|
|
1117
|
-
let result;
|
|
1118
|
-
if (shouldAutoSubmit) {
|
|
1119
|
-
result = await submitPageSpeedForm(values, formConfig);
|
|
1120
|
-
}
|
|
1121
|
-
if (onSubmit) {
|
|
1122
|
-
await onSubmit(values);
|
|
1123
|
-
}
|
|
1124
|
-
if (shouldAutoSubmit || onSubmit) {
|
|
1125
|
-
if (formConfig?.resetOnSuccess !== false) {
|
|
1126
|
-
helpers.resetForm();
|
|
1127
|
-
}
|
|
1128
|
-
onSuccess?.(result);
|
|
1129
|
-
}
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
if (error instanceof PageSpeedFormSubmissionError && error.formErrors) {
|
|
1132
|
-
helpers.setErrors(error.formErrors);
|
|
1133
|
-
}
|
|
1134
|
-
onError?.(error);
|
|
1135
|
-
throw error;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1532
|
+
onError,
|
|
1533
|
+
resetOnSuccess: formConfig?.resetOnSuccess !== false,
|
|
1534
|
+
uploadTokens
|
|
1138
1535
|
});
|
|
1139
|
-
const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
|
|
1140
1536
|
const actionsContent = React.useMemo(() => {
|
|
1141
1537
|
if (actionsSlot) return actionsSlot;
|
|
1142
1538
|
if (actions && actions.length > 0) {
|
|
@@ -1247,87 +1643,70 @@ function ContactDark({
|
|
|
1247
1643
|
cardClassName
|
|
1248
1644
|
),
|
|
1249
1645
|
children: [
|
|
1250
|
-
/* @__PURE__ */
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
/* @__PURE__ */
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
"aria-label": "Last Name"
|
|
1282
|
-
}
|
|
1283
|
-
)
|
|
1284
|
-
] }) })
|
|
1285
|
-
] }),
|
|
1286
|
-
/* @__PURE__ */ jsx(Field, { name: "email", children: ({ field, meta }) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1287
|
-
/* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "Email Address" }),
|
|
1288
|
-
/* @__PURE__ */ jsx(
|
|
1289
|
-
TextInput,
|
|
1646
|
+
/* @__PURE__ */ jsxs("div", { className: cn("p-6 lg:p-12", formPanelClassName), children: [
|
|
1647
|
+
isSubmitted && /* @__PURE__ */ jsx(
|
|
1648
|
+
"div",
|
|
1649
|
+
{
|
|
1650
|
+
className: cn(
|
|
1651
|
+
"mb-6 p-4 bg-primary/10 border border-primary rounded-md",
|
|
1652
|
+
successMessageClassName
|
|
1653
|
+
),
|
|
1654
|
+
children: typeof successMessage === "string" ? /* @__PURE__ */ jsx("p", { className: "text-sm text-primary-foreground/90 text-center", children: successMessage }) : successMessage
|
|
1655
|
+
}
|
|
1656
|
+
),
|
|
1657
|
+
submissionError && /* @__PURE__ */ jsx(
|
|
1658
|
+
"div",
|
|
1659
|
+
{
|
|
1660
|
+
className: cn(
|
|
1661
|
+
"mb-6 p-4 bg-destructive/10 border border-destructive rounded-md",
|
|
1662
|
+
errorMessageClassName
|
|
1663
|
+
),
|
|
1664
|
+
children: /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive text-center", children: submissionError })
|
|
1665
|
+
}
|
|
1666
|
+
),
|
|
1667
|
+
/* @__PURE__ */ jsxs(
|
|
1668
|
+
Form,
|
|
1669
|
+
{
|
|
1670
|
+
form,
|
|
1671
|
+
action: formConfig?.endpoint,
|
|
1672
|
+
method: formMethod,
|
|
1673
|
+
className: cn("space-y-6", formClassName),
|
|
1674
|
+
children: [
|
|
1675
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-12 gap-4", children: formFields.map((field) => /* @__PURE__ */ jsx(
|
|
1676
|
+
"div",
|
|
1290
1677
|
{
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1678
|
+
className: getColumnSpanClass(field.columnSpan),
|
|
1679
|
+
children: /* @__PURE__ */ jsx(
|
|
1680
|
+
DynamicFormField,
|
|
1681
|
+
{
|
|
1682
|
+
field,
|
|
1683
|
+
uploadProgress,
|
|
1684
|
+
onFileUpload: uploadFiles,
|
|
1685
|
+
onFileRemove: removeFile,
|
|
1686
|
+
isUploading
|
|
1687
|
+
}
|
|
1688
|
+
)
|
|
1689
|
+
},
|
|
1690
|
+
field.name
|
|
1691
|
+
)) }),
|
|
1692
|
+
actionsSlot || actions && actions.length > 0 ? actionsContent : /* @__PURE__ */ jsxs(
|
|
1693
|
+
Pressable,
|
|
1304
1694
|
{
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1695
|
+
componentType: "button",
|
|
1696
|
+
type: "submit",
|
|
1697
|
+
className: cn("w-full", submitClassName),
|
|
1698
|
+
asButton: true,
|
|
1699
|
+
disabled: form.isSubmitting,
|
|
1700
|
+
children: [
|
|
1701
|
+
buttonIcon,
|
|
1702
|
+
buttonText
|
|
1703
|
+
]
|
|
1311
1704
|
}
|
|
1312
1705
|
)
|
|
1313
|
-
]
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
componentType: "button",
|
|
1318
|
-
type: "submit",
|
|
1319
|
-
className: cn("w-full", submitClassName),
|
|
1320
|
-
asButton: true,
|
|
1321
|
-
disabled: form.isSubmitting,
|
|
1322
|
-
children: [
|
|
1323
|
-
buttonIcon,
|
|
1324
|
-
buttonText
|
|
1325
|
-
]
|
|
1326
|
-
}
|
|
1327
|
-
)
|
|
1328
|
-
]
|
|
1329
|
-
}
|
|
1330
|
-
) }),
|
|
1706
|
+
]
|
|
1707
|
+
}
|
|
1708
|
+
)
|
|
1709
|
+
] }),
|
|
1331
1710
|
/* @__PURE__ */ jsxs(
|
|
1332
1711
|
"div",
|
|
1333
1712
|
{
|