@forms.expert/sdk 0.1.3 → 0.1.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.
@@ -576,6 +576,22 @@ function getBorderRadius(radius) {
576
576
  return "0.375rem";
577
577
  }
578
578
  }
579
+ function getButtonRadius(radius) {
580
+ switch (radius) {
581
+ case "none":
582
+ return "0";
583
+ case "small":
584
+ return "4px";
585
+ case "medium":
586
+ return "8px";
587
+ case "large":
588
+ return "12px";
589
+ case "full":
590
+ return "9999px";
591
+ default:
592
+ return "8px";
593
+ }
594
+ }
579
595
  function getFontSize(size) {
580
596
  switch (size) {
581
597
  case "sm":
@@ -588,6 +604,94 @@ function getFontSize(size) {
588
604
  return "1rem";
589
605
  }
590
606
  }
607
+ function getPlaceholderFontSize(size) {
608
+ switch (size) {
609
+ case "small":
610
+ return "0.75rem";
611
+ case "large":
612
+ return "1rem";
613
+ default:
614
+ return "0.875rem";
615
+ }
616
+ }
617
+ function getFieldSpacing(spacing) {
618
+ switch (spacing) {
619
+ case "compact":
620
+ return "0.5rem";
621
+ case "relaxed":
622
+ return "1.5rem";
623
+ case "spacious":
624
+ return "2rem";
625
+ default:
626
+ return "1rem";
627
+ }
628
+ }
629
+ function getFormPadding(padding) {
630
+ switch (padding) {
631
+ case "compact":
632
+ return "1rem";
633
+ case "relaxed":
634
+ return "2.5rem";
635
+ case "spacious":
636
+ return "3.5rem";
637
+ default:
638
+ return "1.5rem";
639
+ }
640
+ }
641
+ function getLabelSpacing(spacing) {
642
+ switch (spacing) {
643
+ case "compact":
644
+ return "0.125rem";
645
+ case "relaxed":
646
+ return "0.75rem";
647
+ default:
648
+ return "0.25rem";
649
+ }
650
+ }
651
+ function getFormMaxWidth(width) {
652
+ switch (width) {
653
+ case "narrow":
654
+ return "28rem";
655
+ case "wide":
656
+ return "48rem";
657
+ case "full":
658
+ return "100%";
659
+ default:
660
+ return "36rem";
661
+ }
662
+ }
663
+ function getButtonAlign(align) {
664
+ switch (align) {
665
+ case "left":
666
+ return "flex-start";
667
+ case "right":
668
+ return "flex-end";
669
+ default:
670
+ return "center";
671
+ }
672
+ }
673
+ function getHeadingSize(size) {
674
+ switch (size) {
675
+ case "small":
676
+ return "1.125rem";
677
+ case "large":
678
+ return "1.875rem";
679
+ case "extra-large":
680
+ return "2.25rem";
681
+ default:
682
+ return "1.5rem";
683
+ }
684
+ }
685
+ function getParagraphSize(size) {
686
+ switch (size) {
687
+ case "small":
688
+ return "0.875rem";
689
+ case "large":
690
+ return "1.125rem";
691
+ default:
692
+ return "1rem";
693
+ }
694
+ }
591
695
  function FormsExpertForm({
592
696
  config,
593
697
  slug,
@@ -693,7 +797,17 @@ function FormsExpertForm({
693
797
  };
694
798
  const styling = form.config?.schema?.styling || defaultStyling;
695
799
  const radius = getBorderRadius(styling.borderRadius);
800
+ const btnRadius = getButtonRadius(styling.buttonRadius);
696
801
  const fontSize = getFontSize(styling.fontSize);
802
+ const phFontSize = getPlaceholderFontSize(styling.placeholderFontSize);
803
+ const fieldSpacing = getFieldSpacing(styling.fieldSpacing);
804
+ const formPadding = getFormPadding(styling.formPadding);
805
+ const labelSpacing = getLabelSpacing(styling.labelSpacing);
806
+ const formMaxWidth = getFormMaxWidth(styling.formWidth);
807
+ const btnColor = styling.buttonColor || styling.primaryColor;
808
+ const fontFamily = styling.fontFamily || "system-ui, -apple-system, sans-serif";
809
+ const btnAlign = getButtonAlign(styling.buttonAlign);
810
+ const resolvedButtonText = styling.buttonText || submitText;
697
811
  const handleSubmit = async (e) => {
698
812
  e.preventDefault();
699
813
  const result = await form.submit(captchaToken || void 0);
@@ -742,19 +856,26 @@ function FormsExpertForm({
742
856
  );
743
857
  }
744
858
  if (form.isSubmitted) {
745
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
859
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
746
860
  "div",
747
861
  {
748
862
  className,
749
863
  style: {
750
- padding: "2rem",
864
+ display: "flex",
865
+ alignItems: "center",
866
+ justifyContent: "center",
867
+ minHeight: "100%",
868
+ padding: formPadding,
751
869
  textAlign: "center",
752
- backgroundColor: styling.backgroundColor,
870
+ backgroundColor: styling.transparentBackground ? "transparent" : styling.backgroundColor,
753
871
  color: styling.textColor,
754
872
  borderRadius: radius,
873
+ maxWidth: formMaxWidth,
874
+ margin: "0 auto",
875
+ fontFamily,
755
876
  ...style
756
877
  },
757
- children: [
878
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
758
879
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
759
880
  "svg",
760
881
  {
@@ -762,7 +883,7 @@ function FormsExpertForm({
762
883
  width: "3rem",
763
884
  height: "3rem",
764
885
  margin: "0 auto 1rem",
765
- color: "#22c55e"
886
+ color: styling.successColor || "#22c55e"
766
887
  },
767
888
  fill: "none",
768
889
  stroke: "currentColor",
@@ -786,39 +907,69 @@ function FormsExpertForm({
786
907
  onClick: form.reset,
787
908
  style: {
788
909
  marginTop: "1rem",
789
- padding: "0.5rem 1rem",
790
- backgroundColor: "transparent",
910
+ background: "none",
911
+ border: "none",
791
912
  color: styling.primaryColor,
792
- border: `1px solid ${styling.primaryColor}`,
793
- borderRadius: radius,
794
- cursor: "pointer"
913
+ textDecoration: "underline",
914
+ cursor: "pointer",
915
+ fontSize: "0.875rem"
795
916
  },
796
- children: "Submit another response"
917
+ children: "Submit again"
797
918
  }
798
919
  )
799
- ]
920
+ ] })
800
921
  }
801
922
  );
802
923
  }
803
924
  const fields = form.config.schema?.fields || [];
804
925
  const showBranding = form.config.branding?.enabled !== false;
805
- const brandingText = form.config.branding?.text || "Powered by Mira";
806
- const brandingUrl = form.config.branding?.url || "https://mira.io";
807
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
926
+ const brandingText = form.config.branding?.text || "Powered by forms.expert";
927
+ const brandingUrl = form.config.branding?.url || "https://forms.expert";
928
+ const wrapperStyle = {
929
+ ...styling.backgroundImageUrl ? {
930
+ backgroundImage: `url(${styling.backgroundImageUrl})`,
931
+ backgroundSize: "cover",
932
+ backgroundPosition: "center"
933
+ } : {},
934
+ position: "relative"
935
+ };
936
+ const formEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
808
937
  "form",
809
938
  {
810
939
  onSubmit: handleSubmit,
811
940
  className,
812
941
  style: {
813
- fontFamily: "system-ui, -apple-system, sans-serif",
942
+ fontFamily,
814
943
  fontSize,
815
- backgroundColor: styling.backgroundColor,
944
+ backgroundColor: styling.transparentBackground ? "transparent" : styling.backgroundColor,
816
945
  color: styling.textColor,
817
- padding: "1.5rem",
946
+ padding: formPadding,
818
947
  borderRadius: radius,
948
+ maxWidth: formMaxWidth,
949
+ width: "100%",
950
+ margin: "0 auto",
951
+ position: "relative",
819
952
  ...style
820
953
  },
821
954
  children: [
955
+ styling.logoUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
956
+ textAlign: styling.logoPosition === "top-left" ? "left" : styling.logoPosition === "top-right" ? "right" : "center",
957
+ marginBottom: "1rem"
958
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: styling.logoUrl, alt: "", style: { maxHeight: "48px" } }) }),
959
+ styling.coverImageUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
960
+ "img",
961
+ {
962
+ src: styling.coverImageUrl,
963
+ alt: "",
964
+ style: {
965
+ width: "100%",
966
+ maxHeight: "200px",
967
+ objectFit: "cover",
968
+ borderRadius: `${radius} ${radius} 0 0`,
969
+ marginBottom: "1rem"
970
+ }
971
+ }
972
+ ),
822
973
  fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
823
974
  FormFieldInput,
824
975
  {
@@ -826,34 +977,37 @@ function FormsExpertForm({
826
977
  value: form.values[field.name],
827
978
  error: form.errors[field.name],
828
979
  onChange: handleChange,
829
- styling
980
+ onValueChange: (name, val) => form.setValue(name, val),
981
+ styling,
982
+ fieldSpacing,
983
+ labelSpacing,
984
+ phFontSize
830
985
  },
831
986
  field.name
832
987
  )),
833
988
  form.honeypotEnabled && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { position: "absolute", left: "-9999px", opacity: 0, height: 0, overflow: "hidden" }, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "text", name: "_hp", tabIndex: -1, autoComplete: "off" }) }),
834
989
  form.requiresCaptcha && form.captchaProvider !== "recaptcha" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: captchaContainerRef, style: { marginTop: "1rem" } }),
835
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
990
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", justifyContent: btnAlign, marginTop: "1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
836
991
  "button",
837
992
  {
838
993
  type: "submit",
839
994
  disabled: form.isLoading,
840
995
  style: {
841
- width: "100%",
996
+ ...styling.buttonAlign ? {} : { width: "100%" },
842
997
  padding: "0.625rem 1.25rem",
843
- marginTop: "1rem",
844
998
  fontWeight: 500,
845
999
  fontSize,
846
1000
  fontFamily: "inherit",
847
- borderRadius: radius,
1001
+ borderRadius: btnRadius,
848
1002
  cursor: form.isLoading ? "not-allowed" : "pointer",
849
1003
  opacity: form.isLoading ? 0.5 : 1,
850
- backgroundColor: styling.buttonStyle === "filled" ? styling.primaryColor : "transparent",
851
- color: styling.buttonStyle === "filled" ? "white" : styling.primaryColor,
852
- border: styling.buttonStyle === "filled" ? "none" : `2px solid ${styling.primaryColor}`
1004
+ backgroundColor: styling.buttonStyle === "filled" ? btnColor : "transparent",
1005
+ color: styling.buttonStyle === "filled" ? "white" : btnColor,
1006
+ border: styling.buttonStyle === "filled" ? "none" : `2px solid ${btnColor}`
853
1007
  },
854
- children: form.isLoading ? "Submitting..." : submitText
1008
+ children: form.isLoading ? "Submitting..." : resolvedButtonText
855
1009
  }
856
- ),
1010
+ ) }),
857
1011
  showBranding && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
858
1012
  "div",
859
1013
  {
@@ -882,16 +1036,33 @@ function FormsExpertForm({
882
1036
  ]
883
1037
  }
884
1038
  );
1039
+ if (styling.backgroundImageUrl) {
1040
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: wrapperStyle, children: [
1041
+ styling.backgroundOverlay ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: {
1042
+ position: "absolute",
1043
+ inset: 0,
1044
+ backgroundColor: `rgba(0,0,0,${styling.backgroundOverlay})`,
1045
+ pointerEvents: "none"
1046
+ } }) : null,
1047
+ formEl
1048
+ ] });
1049
+ }
1050
+ return formEl;
885
1051
  }
886
1052
  function FormFieldInput({
887
1053
  field,
888
1054
  value,
889
1055
  error,
890
1056
  onChange,
891
- styling
1057
+ onValueChange,
1058
+ styling,
1059
+ fieldSpacing,
1060
+ labelSpacing,
1061
+ phFontSize
892
1062
  }) {
893
1063
  const radius = getBorderRadius(styling.borderRadius);
894
1064
  const fontSize = getFontSize(styling.fontSize);
1065
+ const isInline = styling.labelPosition === "left" || styling.fieldLayout === "inline";
895
1066
  const inputStyle = {
896
1067
  width: "100%",
897
1068
  padding: "0.5rem 0.75rem",
@@ -902,8 +1073,25 @@ function FormFieldInput({
902
1073
  backgroundColor: styling.theme === "dark" ? "#374151" : "#ffffff",
903
1074
  color: styling.textColor
904
1075
  };
905
- if (field.type === "checkbox") {
906
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", marginBottom: "1rem" }, children: [
1076
+ const getOpts = () => {
1077
+ if (!field.options) return [];
1078
+ return field.options.map((o) => typeof o === "string" ? { value: o, label: o } : o);
1079
+ };
1080
+ if (field.type === "heading") {
1081
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: { marginBottom: fieldSpacing, fontSize: getHeadingSize(styling.headingSize), fontWeight: 600 }, children: field.content || field.label });
1082
+ }
1083
+ if (field.type === "divider") {
1084
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("hr", { style: { marginBottom: fieldSpacing, border: "none", borderTop: `1px solid ${styling.theme === "dark" ? "#4b5563" : "#d1d5db"}` } });
1085
+ }
1086
+ if (field.type === "paragraph") {
1087
+ const pSize = field.paragraphFontSize ? `${field.paragraphFontSize}px` : getParagraphSize(styling.paragraphSize);
1088
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { marginBottom: fieldSpacing, fontSize: pSize, color: styling.theme === "dark" ? "#9ca3af" : "#6b7280" }, children: field.content || field.label });
1089
+ }
1090
+ if (field.type === "hidden") {
1091
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "hidden", name: field.name, value: String(value || field.defaultValue || "") });
1092
+ }
1093
+ if (field.type === "checkbox" || field.type === "toggle" || field.type === "consent") {
1094
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", marginBottom: fieldSpacing }, children: [
907
1095
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
908
1096
  "input",
909
1097
  {
@@ -917,91 +1105,312 @@ function FormFieldInput({
917
1105
  }
918
1106
  ),
919
1107
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { htmlFor: field.name, children: [
920
- field.label || field.name,
921
- field.required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
1108
+ field.type === "consent" && field.consentText ? field.consentUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
1109
+ field.consentText,
1110
+ " ",
1111
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: field.consentUrl, target: "_blank", rel: "noopener noreferrer", style: { color: styling.primaryColor }, children: "(link)" })
1112
+ ] }) : field.consentText : field.label || field.name,
1113
+ field.required && !styling.hideRequiredAsterisk && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
922
1114
  ] }),
923
- error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ef4444", fontSize: "0.875rem", marginLeft: "0.5rem" }, children: error })
1115
+ error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: styling.errorColor || "#ef4444", fontSize: "0.875rem", marginLeft: "0.5rem" }, children: error })
1116
+ ] });
1117
+ }
1118
+ const labelEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1119
+ "label",
1120
+ {
1121
+ htmlFor: field.name,
1122
+ style: {
1123
+ display: "block",
1124
+ fontWeight: 500,
1125
+ ...isInline ? { width: "33%", flexShrink: 0, paddingTop: "0.5rem", marginBottom: 0 } : { marginBottom: labelSpacing }
1126
+ },
1127
+ children: [
1128
+ field.label || field.name,
1129
+ field.required && !styling.hideRequiredAsterisk && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
1130
+ ]
1131
+ }
1132
+ );
1133
+ const errorEl = error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: styling.errorColor || "#ef4444", fontSize: "0.875rem", marginTop: "0.25rem" }, children: error }) : null;
1134
+ let fieldEl;
1135
+ if (field.type === "textarea" || field.type === "richText") {
1136
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1137
+ "textarea",
1138
+ {
1139
+ id: field.name,
1140
+ name: field.name,
1141
+ value: String(value || ""),
1142
+ onChange,
1143
+ placeholder: field.placeholder,
1144
+ required: field.required,
1145
+ style: { ...inputStyle, minHeight: "100px", resize: "vertical" }
1146
+ }
1147
+ );
1148
+ } else if (field.type === "select" || field.type === "dropdown") {
1149
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { id: field.name, name: field.name, value: String(value || ""), onChange, required: field.required, style: inputStyle, children: [
1150
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "Select an option..." }),
1151
+ getOpts().map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: opt.value, children: opt.label }, opt.value))
1152
+ ] });
1153
+ } else if (field.type === "radio") {
1154
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: getOpts().map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: { display: "flex", alignItems: "center", gap: "0.5rem", cursor: "pointer" }, children: [
1155
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1156
+ "input",
1157
+ {
1158
+ type: "radio",
1159
+ name: field.name,
1160
+ value: opt.value,
1161
+ checked: value === opt.value,
1162
+ onChange: () => onValueChange(field.name, opt.value),
1163
+ style: { accentColor: styling.primaryColor }
1164
+ }
1165
+ ),
1166
+ opt.label
1167
+ ] }, opt.value)) });
1168
+ } else if (field.type === "multiselect") {
1169
+ const selected = Array.isArray(value) ? value : [];
1170
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: getOpts().map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: { display: "flex", alignItems: "center", gap: "0.5rem", cursor: "pointer" }, children: [
1171
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1172
+ "input",
1173
+ {
1174
+ type: "checkbox",
1175
+ checked: selected.includes(opt.value),
1176
+ onChange: () => {
1177
+ const next = selected.includes(opt.value) ? selected.filter((v) => v !== opt.value) : [...selected, opt.value];
1178
+ onValueChange(field.name, next);
1179
+ },
1180
+ style: { accentColor: styling.primaryColor }
1181
+ }
1182
+ ),
1183
+ opt.label
1184
+ ] }, opt.value)) });
1185
+ } else if (field.type === "rating") {
1186
+ const max = field.ratingMax || 5;
1187
+ const current = Number(value) || 0;
1188
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: "0.25rem" }, children: Array.from({ length: max }, (_, i) => i + 1).map((n) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1189
+ "button",
1190
+ {
1191
+ type: "button",
1192
+ onClick: () => onValueChange(field.name, n),
1193
+ style: {
1194
+ width: "2rem",
1195
+ height: "2rem",
1196
+ cursor: "pointer",
1197
+ border: "none",
1198
+ background: "none",
1199
+ padding: 0,
1200
+ fontSize: "1.5rem",
1201
+ color: n <= current ? "#f59e0b" : styling.theme === "dark" ? "#4b5563" : "#d1d5db",
1202
+ transition: "color 0.15s"
1203
+ },
1204
+ children: "\u2605"
1205
+ },
1206
+ n
1207
+ )) });
1208
+ } else if (field.type === "scale" || field.type === "opinionScale") {
1209
+ const min = field.min ?? 1;
1210
+ const max = field.max ?? 10;
1211
+ const current = value;
1212
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1213
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: "0.25rem", flexWrap: "wrap" }, children: Array.from({ length: max - min + 1 }, (_, i) => min + i).map((n) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1214
+ "button",
1215
+ {
1216
+ type: "button",
1217
+ onClick: () => onValueChange(field.name, n),
1218
+ style: {
1219
+ minWidth: "2.25rem",
1220
+ height: "2.25rem",
1221
+ borderRadius: radius,
1222
+ cursor: "pointer",
1223
+ border: `1px solid ${styling.theme === "dark" ? "#4b5563" : "#d1d5db"}`,
1224
+ background: current === n ? styling.primaryColor : styling.theme === "dark" ? "#374151" : "#ffffff",
1225
+ color: current === n ? "white" : styling.textColor,
1226
+ fontSize: "0.875rem",
1227
+ transition: "all 0.15s"
1228
+ },
1229
+ children: n
1230
+ },
1231
+ n
1232
+ )) }),
1233
+ (field.lowLabel || field.highLabel) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", fontSize: "0.75rem", color: styling.theme === "dark" ? "#9ca3af" : "#6b7280", marginTop: "0.25rem" }, children: [
1234
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: field.lowLabel }),
1235
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: field.highLabel })
1236
+ ] })
1237
+ ] });
1238
+ } else if (field.type === "slider") {
1239
+ const min = field.min ?? 0;
1240
+ const max = field.max ?? 100;
1241
+ const step = field.step ?? 1;
1242
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
1243
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1244
+ "input",
1245
+ {
1246
+ type: "range",
1247
+ id: field.name,
1248
+ name: field.name,
1249
+ min,
1250
+ max,
1251
+ step,
1252
+ value: Number(value) || min,
1253
+ onChange: (e) => onValueChange(field.name, Number(e.target.value)),
1254
+ style: { width: "100%", accentColor: styling.primaryColor }
1255
+ }
1256
+ ),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { textAlign: "center", fontSize: "0.875rem", marginTop: "0.25rem" }, children: String(value ?? min) })
1258
+ ] });
1259
+ } else if (field.type === "imageChoice") {
1260
+ const selected = value;
1261
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem" }, children: getOpts().map((opt) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1262
+ "button",
1263
+ {
1264
+ type: "button",
1265
+ onClick: () => onValueChange(field.name, opt.value),
1266
+ style: {
1267
+ border: `2px solid ${selected === opt.value ? styling.primaryColor : styling.theme === "dark" ? "#4b5563" : "#d1d5db"}`,
1268
+ borderRadius: radius,
1269
+ padding: "0.5rem",
1270
+ cursor: "pointer",
1271
+ textAlign: "center",
1272
+ background: "none",
1273
+ transition: "border-color 0.15s"
1274
+ },
1275
+ children: [
1276
+ opt.imageUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src: opt.imageUrl, alt: opt.label, style: { maxWidth: "80px", maxHeight: "80px", objectFit: "cover", borderRadius: radius } }),
1277
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: "0.875rem", marginTop: "0.25rem" }, children: opt.label })
1278
+ ]
1279
+ },
1280
+ opt.value
1281
+ )) });
1282
+ } else if (field.type === "file") {
1283
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1284
+ "input",
1285
+ {
1286
+ type: "file",
1287
+ id: field.name,
1288
+ name: field.name,
1289
+ onChange,
1290
+ required: field.required,
1291
+ accept: field.allowedMimeTypes?.join(","),
1292
+ multiple: field.multiple,
1293
+ style: inputStyle
1294
+ }
1295
+ );
1296
+ } else if (field.type === "name") {
1297
+ const nameVal = value || {};
1298
+ const nameFields = field.nameFields || ["first", "last"];
1299
+ const labels = { prefix: "Prefix", first: "First Name", middle: "Middle", last: "Last Name", suffix: "Suffix" };
1300
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: "0.5rem", flexWrap: "wrap" }, children: nameFields.map((nf) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1301
+ "input",
1302
+ {
1303
+ placeholder: labels[nf] || nf,
1304
+ value: nameVal[nf] || "",
1305
+ onChange: (e) => onValueChange(field.name, { ...nameVal, [nf]: e.target.value }),
1306
+ style: { ...inputStyle, flex: 1, minWidth: "120px" }
1307
+ },
1308
+ nf
1309
+ )) });
1310
+ } else if (field.type === "address") {
1311
+ const addr = value || {};
1312
+ const addrFields = field.addressFields || ["street", "city", "state", "zip", "country"];
1313
+ const labels = { street: "Street", street2: "Street 2", city: "City", state: "State", zip: "ZIP", country: "Country" };
1314
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: "0.5rem" }, children: addrFields.map((af) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1315
+ "input",
1316
+ {
1317
+ placeholder: labels[af] || af,
1318
+ value: addr[af] || "",
1319
+ onChange: (e) => onValueChange(field.name, { ...addr, [af]: e.target.value }),
1320
+ style: inputStyle
1321
+ },
1322
+ af
1323
+ )) });
1324
+ } else if (field.type === "currency") {
1325
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "0.25rem" }, children: [
1326
+ field.currencySymbol && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: field.currencySymbol }),
1327
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1328
+ "input",
1329
+ {
1330
+ type: "number",
1331
+ id: field.name,
1332
+ name: field.name,
1333
+ value: String(value || ""),
1334
+ onChange,
1335
+ step: 0.01,
1336
+ min: field.min,
1337
+ max: field.max,
1338
+ required: field.required,
1339
+ style: inputStyle
1340
+ }
1341
+ )
1342
+ ] });
1343
+ } else if (field.type === "colorPicker") {
1344
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "0.5rem", alignItems: "center" }, children: [
1345
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1346
+ "input",
1347
+ {
1348
+ type: "color",
1349
+ id: field.name,
1350
+ value: String(value || "#000000"),
1351
+ onChange: (e) => onValueChange(field.name, e.target.value),
1352
+ style: { width: "3rem", height: "2.25rem", border: "none", cursor: "pointer", padding: 0 }
1353
+ }
1354
+ ),
1355
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1356
+ "input",
1357
+ {
1358
+ type: "text",
1359
+ value: String(value || ""),
1360
+ onChange: (e) => onValueChange(field.name, e.target.value),
1361
+ placeholder: "#000000",
1362
+ style: { ...inputStyle, flex: 1 }
1363
+ }
1364
+ )
924
1365
  ] });
1366
+ } else if (field.type === "dateRange") {
1367
+ const range = value || {};
1368
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "0.5rem", alignItems: "center" }, children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "date", value: range.start || "", onChange: (e) => onValueChange(field.name, { ...range, start: e.target.value }), style: { ...inputStyle, flex: 1 } }),
1370
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "to" }),
1371
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "date", value: range.end || "", onChange: (e) => onValueChange(field.name, { ...range, end: e.target.value }), style: { ...inputStyle, flex: 1 } })
1372
+ ] });
1373
+ } else {
1374
+ const typeMap = {
1375
+ phone: "tel",
1376
+ url: "url",
1377
+ datetime: "datetime-local",
1378
+ time: "time",
1379
+ date: "date",
1380
+ number: "number",
1381
+ email: "email",
1382
+ password: "password"
1383
+ };
1384
+ fieldEl = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1385
+ "input",
1386
+ {
1387
+ type: typeMap[field.type] || "text",
1388
+ id: field.name,
1389
+ name: field.name,
1390
+ value: String(value || ""),
1391
+ onChange,
1392
+ placeholder: field.placeholder,
1393
+ required: field.required,
1394
+ min: field.min,
1395
+ max: field.max,
1396
+ step: field.step,
1397
+ maxLength: field.maxLength,
1398
+ style: inputStyle
1399
+ }
1400
+ );
925
1401
  }
926
1402
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
927
1403
  "div",
928
1404
  {
929
1405
  style: {
930
- marginBottom: "1rem",
931
- ...styling.labelPosition === "left" ? { display: "flex", alignItems: "flex-start", gap: "1rem" } : {}
1406
+ marginBottom: fieldSpacing,
1407
+ ...isInline ? { display: "flex", alignItems: "flex-start", gap: "1rem" } : {}
932
1408
  },
933
1409
  children: [
934
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
935
- "label",
936
- {
937
- htmlFor: field.name,
938
- style: {
939
- display: "block",
940
- fontWeight: 500,
941
- ...styling.labelPosition === "left" ? { width: "33%", flexShrink: 0, paddingTop: "0.5rem" } : { marginBottom: "0.25rem" }
942
- },
943
- children: [
944
- field.label || field.name,
945
- field.required && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ef4444", marginLeft: "0.25rem" }, children: "*" })
946
- ]
947
- }
948
- ),
949
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styling.labelPosition === "left" ? { flex: 1 } : {}, children: [
950
- field.type === "textarea" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
951
- "textarea",
952
- {
953
- id: field.name,
954
- name: field.name,
955
- value: String(value || ""),
956
- onChange,
957
- placeholder: field.placeholder,
958
- required: field.required,
959
- style: { ...inputStyle, minHeight: "100px", resize: "vertical" }
960
- }
961
- ) : field.type === "select" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
962
- "select",
963
- {
964
- id: field.name,
965
- name: field.name,
966
- value: String(value || ""),
967
- onChange,
968
- required: field.required,
969
- style: inputStyle,
970
- children: [
971
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "Select an option..." }),
972
- field.options?.map((opt) => {
973
- const val = typeof opt === "string" ? opt : opt.value;
974
- const label = typeof opt === "string" ? opt : opt.label;
975
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: val, children: label }, val);
976
- })
977
- ]
978
- }
979
- ) : field.type === "file" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
980
- "input",
981
- {
982
- type: "file",
983
- id: field.name,
984
- name: field.name,
985
- onChange,
986
- required: field.required,
987
- accept: field.allowedMimeTypes?.join(","),
988
- multiple: field.multiple,
989
- style: inputStyle
990
- }
991
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
992
- "input",
993
- {
994
- type: field.type,
995
- id: field.name,
996
- name: field.name,
997
- value: String(value || ""),
998
- onChange,
999
- placeholder: field.placeholder,
1000
- required: field.required,
1001
- style: inputStyle
1002
- }
1003
- ),
1004
- error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#ef4444", fontSize: "0.875rem", marginTop: "0.25rem" }, children: error })
1410
+ labelEl,
1411
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: isInline ? { flex: 1 } : {}, children: [
1412
+ fieldEl,
1413
+ errorEl
1005
1414
  ] })
1006
1415
  ]
1007
1416
  }