@uptrademedia/site-kit 1.2.4 → 1.2.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.
@@ -172,8 +172,9 @@ function getDeviceType() {
172
172
  }
173
173
 
174
174
  // src/forms/recaptcha.ts
175
- function getSiteKey() {
175
+ function getSiteKey(explicitSiteKey) {
176
176
  if (typeof window === "undefined") return void 0;
177
+ if (explicitSiteKey) return explicitSiteKey;
177
178
  const win = window;
178
179
  return win.__SITE_KIT_RECAPTCHA_SITE_KEY__ ?? process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY;
179
180
  }
@@ -205,8 +206,8 @@ function loadScript(siteKey) {
205
206
  document.head.appendChild(script);
206
207
  });
207
208
  }
208
- async function getRecaptchaToken() {
209
- const siteKey = getSiteKey();
209
+ async function getRecaptchaToken(explicitSiteKey) {
210
+ const siteKey = getSiteKey(explicitSiteKey);
210
211
  if (!siteKey || typeof window === "undefined") return null;
211
212
  try {
212
213
  const grecaptcha = await loadScript(siteKey);
@@ -281,6 +282,10 @@ function useForm(formIdOrSlug, options = {}) {
281
282
  }
282
283
  const data = await response.json();
283
284
  if (!data) throw new Error("Form not found");
285
+ if (typeof window !== "undefined" && data.recaptcha_site_key) {
286
+ ;
287
+ window.__SITE_KIT_RECAPTCHA_SITE_KEY__ = data.recaptcha_site_key;
288
+ }
284
289
  if (data.steps) {
285
290
  data.steps.sort((a, b) => (a.step_number || 0) - (b.step_number || 0));
286
291
  }
@@ -441,11 +446,18 @@ function useForm(formIdOrSlug, options = {}) {
441
446
  if (!apiKey) {
442
447
  throw new Error("API key is required. Set NEXT_PUBLIC_UPTRADE_API_KEY in your .env");
443
448
  }
444
- const recaptchaToken = await getRecaptchaToken();
449
+ const honeypotFieldName = form.honeypot_field || "website";
450
+ const recaptchaToken = form.recaptcha_enabled ? await getRecaptchaToken(form.recaptcha_site_key) : null;
451
+ if (form.recaptcha_enabled && !recaptchaToken) {
452
+ throw new Error("reCAPTCHA is required but could not be initialized.");
453
+ }
445
454
  const utm = getUTMParams();
446
455
  const submission = {
447
456
  formId: form.id,
448
- data: values,
457
+ data: {
458
+ ...values,
459
+ ...form.honeypot_enabled ? { [honeypotFieldName]: "" } : {}
460
+ },
449
461
  metadata: {
450
462
  pageUrl: typeof window !== "undefined" ? window.location.href : null,
451
463
  referrer: typeof document !== "undefined" ? document.referrer || null : null,
@@ -539,6 +551,7 @@ function normalizeOptions(options) {
539
551
  return [];
540
552
  }
541
553
  function FormField({ field: field2, value, error, onChange, classPrefix = "uptrade-form" }) {
554
+ const inputId = `uptrade-${field2.id || field2.slug}`;
542
555
  const options = normalizeOptions(field2.options);
543
556
  const baseInputStyle = {
544
557
  width: "100%",
@@ -578,13 +591,14 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
578
591
  const hideLabel = !!field2.hide_label;
579
592
  const effectivePlaceholder = hideLabel ? field2.label : field2.placeholder;
580
593
  return /* @__PURE__ */ jsxs("div", { className: `${classPrefix}__field ${classPrefix}__field--${field2.field_type}`, children: [
581
- /* @__PURE__ */ jsxs("label", { className: `${classPrefix}__label`, style: { ...labelStyle, ...hideLabel ? { position: "absolute", width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clip: "rect(0,0,0,0)", whiteSpace: "nowrap", border: 0 } : {} }, children: [
594
+ /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: `${classPrefix}__label`, style: { ...labelStyle, ...hideLabel ? { position: "absolute", width: 1, height: 1, padding: 0, margin: -1, overflow: "hidden", clip: "rect(0,0,0,0)", whiteSpace: "nowrap", border: 0 } : {} }, children: [
582
595
  field2.label,
583
596
  field2.is_required && /* @__PURE__ */ jsx("span", { style: { color: "var(--uptrade-error-color, #ef4444)" }, children: " *" })
584
597
  ] }),
585
598
  ["text", "email", "phone", "tel", "number"].includes(field2.field_type) && /* @__PURE__ */ jsx(
586
599
  "input",
587
600
  {
601
+ id: inputId,
588
602
  className: `${classPrefix}__input`,
589
603
  type: field2.field_type === "phone" || field2.field_type === "tel" ? "tel" : field2.field_type,
590
604
  name: field2.slug,
@@ -598,6 +612,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
598
612
  field2.field_type === "textarea" && /* @__PURE__ */ jsx(
599
613
  "textarea",
600
614
  {
615
+ id: inputId,
601
616
  className: `${classPrefix}__textarea`,
602
617
  name: field2.slug,
603
618
  value: String(value || ""),
@@ -611,6 +626,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
611
626
  field2.field_type === "select" && /* @__PURE__ */ jsxs(
612
627
  "select",
613
628
  {
629
+ id: inputId,
614
630
  className: `${classPrefix}__select`,
615
631
  name: field2.slug,
616
632
  value: String(value || ""),
@@ -626,6 +642,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
626
642
  field2.field_type === "multi-select" && /* @__PURE__ */ jsx(
627
643
  "select",
628
644
  {
645
+ id: inputId,
629
646
  className: `${classPrefix}__select ${classPrefix}__select--multi`,
630
647
  name: field2.slug,
631
648
  value: Array.isArray(value) ? value : [],
@@ -688,6 +705,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
688
705
  field2.field_type === "date" && /* @__PURE__ */ jsx(
689
706
  "input",
690
707
  {
708
+ id: inputId,
691
709
  className: `${classPrefix}__input ${classPrefix}__input--date`,
692
710
  type: "date",
693
711
  name: field2.slug,
@@ -700,6 +718,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
700
718
  field2.field_type === "time" && /* @__PURE__ */ jsx(
701
719
  "input",
702
720
  {
721
+ id: inputId,
703
722
  className: `${classPrefix}__input ${classPrefix}__input--time`,
704
723
  type: "time",
705
724
  name: field2.slug,
@@ -712,6 +731,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
712
731
  field2.field_type === "datetime" && /* @__PURE__ */ jsx(
713
732
  "input",
714
733
  {
734
+ id: inputId,
715
735
  className: `${classPrefix}__input ${classPrefix}__input--datetime`,
716
736
  type: "datetime-local",
717
737
  name: field2.slug,
@@ -724,6 +744,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
724
744
  field2.field_type === "file" && /* @__PURE__ */ jsx(
725
745
  "input",
726
746
  {
747
+ id: inputId,
727
748
  className: `${classPrefix}__input ${classPrefix}__input--file`,
728
749
  type: "file",
729
750
  name: field2.slug,
@@ -758,6 +779,7 @@ function FormField({ field: field2, value, error, onChange, classPrefix = "uptra
758
779
  /* @__PURE__ */ jsx(
759
780
  "input",
760
781
  {
782
+ id: inputId,
761
783
  type: "range",
762
784
  name: field2.slug,
763
785
  value: Number(value || 50),
@@ -785,6 +807,8 @@ function FormClient({
785
807
  const [step, setStep] = useState(1);
786
808
  const [isSubmitting, setIsSubmitting] = useState(false);
787
809
  const [isComplete, setIsComplete] = useState(false);
810
+ const [honeypotValue, setHoneypotValue] = useState("");
811
+ const honeypotFieldName = config.honeypot_field || "website";
788
812
  const { trackStepChange, trackComplete } = useFormTracking({
789
813
  formId: config.id,
790
814
  totalSteps: config.total_steps
@@ -908,12 +932,18 @@ function FormClient({
908
932
  if (!apiKey) {
909
933
  throw new Error("API key is required. Set NEXT_PUBLIC_UPTRADE_API_KEY in your .env");
910
934
  }
911
- const recaptchaToken = await getRecaptchaToken();
935
+ const recaptchaToken = config.recaptcha_enabled ? await getRecaptchaToken(config.recaptcha_site_key) : null;
936
+ if (config.recaptcha_enabled && !recaptchaToken) {
937
+ throw new Error("reCAPTCHA is required but could not be initialized.");
938
+ }
912
939
  const utm = getUTMParams2();
913
940
  const submission = {
914
941
  form_id: config.id,
915
942
  project_id: config.project_id,
916
- data: values,
943
+ data: {
944
+ ...values,
945
+ ...config.honeypot_enabled ? { [honeypotFieldName]: honeypotValue } : {}
946
+ },
917
947
  routing_type: config.form_type,
918
948
  status: "new",
919
949
  metadata: {
@@ -952,7 +982,7 @@ function FormClient({
952
982
  } finally {
953
983
  setIsSubmitting(false);
954
984
  }
955
- }, [config, values, validateStep, trackComplete, onSuccess, onError]);
985
+ }, [config, honeypotFieldName, honeypotValue, values, validateStep, trackComplete, onSuccess, onError]);
956
986
  const progress = useMemo(() => {
957
987
  return Math.round(step / config.total_steps * 100);
958
988
  }, [step, config.total_steps]);
@@ -1040,7 +1070,7 @@ function FormClient({
1040
1070
  "input",
1041
1071
  {
1042
1072
  type: "text",
1043
- name: "website",
1073
+ name: honeypotFieldName,
1044
1074
  tabIndex: -1,
1045
1075
  autoComplete: "off",
1046
1076
  style: {
@@ -1049,7 +1079,9 @@ function FormClient({
1049
1079
  opacity: 0,
1050
1080
  pointerEvents: "none"
1051
1081
  },
1082
+ value: honeypotValue,
1052
1083
  onChange: (e) => {
1084
+ setHoneypotValue(e.target.value);
1053
1085
  if (e.target.value) {
1054
1086
  console.warn("[Forms] Honeypot triggered");
1055
1087
  }