@forms.expert/sdk 0.2.13 → 0.4.0

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.
@@ -49,6 +49,8 @@ interface FormField {
49
49
  operator: 'eq' | 'neq' | 'contains' | 'gt' | 'lt';
50
50
  value: unknown;
51
51
  };
52
+ row?: number;
53
+ width?: '1/4' | '1/3' | '1/2' | '2/3' | '3/4' | 'full';
52
54
  }
53
55
  /**
54
56
  * Secondary button configuration
@@ -66,6 +68,8 @@ interface SecondaryButton {
66
68
  color?: string;
67
69
  textColor?: string;
68
70
  fontSize?: number;
71
+ icon?: string;
72
+ iconPosition?: 'left' | 'right';
69
73
  }
70
74
  /**
71
75
  * Form styling configuration
@@ -100,6 +104,8 @@ interface FormStyling {
100
104
  buttonGradient?: string;
101
105
  buttonFullWidth?: boolean;
102
106
  buttonFontSize?: number;
107
+ buttonIcon?: string;
108
+ buttonIconPosition?: 'left' | 'right';
103
109
  fieldSpacing?: 'compact' | 'normal' | 'relaxed' | 'spacious';
104
110
  formPadding?: 'none' | 'compact' | 'normal' | 'relaxed' | 'spacious';
105
111
  labelSpacing?: 'compact' | 'normal' | 'relaxed';
@@ -116,6 +122,8 @@ interface FormStyling {
116
122
  backgroundOverlay?: number;
117
123
  transparentBackground?: boolean;
118
124
  secondaryButton?: SecondaryButton;
125
+ inputBackgroundColor?: string;
126
+ placeholderColor?: string;
119
127
  }
120
128
  /**
121
129
  * Form schema
@@ -49,6 +49,8 @@ interface FormField {
49
49
  operator: 'eq' | 'neq' | 'contains' | 'gt' | 'lt';
50
50
  value: unknown;
51
51
  };
52
+ row?: number;
53
+ width?: '1/4' | '1/3' | '1/2' | '2/3' | '3/4' | 'full';
52
54
  }
53
55
  /**
54
56
  * Secondary button configuration
@@ -66,6 +68,8 @@ interface SecondaryButton {
66
68
  color?: string;
67
69
  textColor?: string;
68
70
  fontSize?: number;
71
+ icon?: string;
72
+ iconPosition?: 'left' | 'right';
69
73
  }
70
74
  /**
71
75
  * Form styling configuration
@@ -100,6 +104,8 @@ interface FormStyling {
100
104
  buttonGradient?: string;
101
105
  buttonFullWidth?: boolean;
102
106
  buttonFontSize?: number;
107
+ buttonIcon?: string;
108
+ buttonIconPosition?: 'left' | 'right';
103
109
  fieldSpacing?: 'compact' | 'normal' | 'relaxed' | 'spacious';
104
110
  formPadding?: 'none' | 'compact' | 'normal' | 'relaxed' | 'spacious';
105
111
  labelSpacing?: 'compact' | 'normal' | 'relaxed';
@@ -116,6 +122,8 @@ interface FormStyling {
116
122
  backgroundOverlay?: number;
117
123
  transparentBackground?: boolean;
118
124
  secondaryButton?: SecondaryButton;
125
+ inputBackgroundColor?: string;
126
+ placeholderColor?: string;
119
127
  }
120
128
  /**
121
129
  * Form schema
@@ -571,6 +571,49 @@ function getFieldBorderRadius(radius) {
571
571
  return "0.375rem";
572
572
  }
573
573
  }
574
+ function getWidthPercent(width) {
575
+ switch (width) {
576
+ case "1/4":
577
+ return "25%";
578
+ case "1/3":
579
+ return "33.333%";
580
+ case "1/2":
581
+ return "50%";
582
+ case "2/3":
583
+ return "66.666%";
584
+ case "3/4":
585
+ return "75%";
586
+ case "full":
587
+ return "100%";
588
+ default:
589
+ return void 0;
590
+ }
591
+ }
592
+ function groupFieldsIntoRows(fields) {
593
+ const result = [];
594
+ let i = 0;
595
+ while (i < fields.length) {
596
+ const field = fields[i];
597
+ if (field.row != null) {
598
+ const rowFields = [field];
599
+ let j = i + 1;
600
+ while (j < fields.length && fields[j].row === field.row) {
601
+ rowFields.push(fields[j]);
602
+ j++;
603
+ }
604
+ if (rowFields.length > 1) {
605
+ result.push({ type: "row", fields: rowFields });
606
+ } else {
607
+ result.push({ type: "single", field });
608
+ }
609
+ i = j;
610
+ } else {
611
+ result.push({ type: "single", field });
612
+ i++;
613
+ }
614
+ }
615
+ return result;
616
+ }
574
617
  function getButtonRadius(radius) {
575
618
  switch (radius) {
576
619
  case "none":
@@ -1007,7 +1050,7 @@ function FormsExpertForm({
1007
1050
  children: [
1008
1051
  googleFontUrl && /* @__PURE__ */ jsx2("link", { rel: "stylesheet", href: googleFontUrl }),
1009
1052
  /* @__PURE__ */ jsx2("style", { dangerouslySetInnerHTML: { __html: `
1010
- form[data-fe-scope="${formScopeId}"] input::placeholder, form[data-fe-scope="${formScopeId}"] textarea::placeholder { font-size: ${phFontSize}; }
1053
+ form[data-fe-scope="${formScopeId}"] input::placeholder, form[data-fe-scope="${formScopeId}"] textarea::placeholder { font-size: ${phFontSize};${styling.placeholderColor ? ` color: ${styling.placeholderColor};` : ""} }
1011
1054
  form[data-fe-scope="${formScopeId}"] button[type="submit"]:hover:not(:disabled) { filter: brightness(0.9); }
1012
1055
  form[data-fe-scope="${formScopeId}"] button[type="submit"]:active:not(:disabled) { filter: brightness(0.85); transform: scale(0.98); }
1013
1056
  form[data-fe-scope="${formScopeId}"] a[href]:hover { filter: brightness(0.9); }
@@ -1045,21 +1088,39 @@ function FormsExpertForm({
1045
1088
  marginBottom: "0.5rem",
1046
1089
  color: styling.textColor
1047
1090
  }, children: form.config.hostedConfig?.pageTitle || form.config.name }),
1048
- fields.map((field) => /* @__PURE__ */ jsx2(
1049
- FormFieldInput,
1050
- {
1051
- field,
1052
- value: form.values[field.name],
1053
- error: form.errors[field.name],
1054
- onChange: handleChange,
1055
- onValueChange: (name, val) => form.setValue(name, val),
1056
- styling,
1057
- fieldSpacing,
1058
- labelSpacing,
1059
- phFontSize
1060
- },
1061
- field.name
1062
- )),
1091
+ groupFieldsIntoRows(fields).map((group, idx) => {
1092
+ if (group.type === "single") {
1093
+ return /* @__PURE__ */ jsx2(
1094
+ FormFieldInput,
1095
+ {
1096
+ field: group.field,
1097
+ value: form.values[group.field.name],
1098
+ error: form.errors[group.field.name],
1099
+ onChange: handleChange,
1100
+ onValueChange: (name, val) => form.setValue(name, val),
1101
+ styling,
1102
+ fieldSpacing,
1103
+ labelSpacing,
1104
+ phFontSize
1105
+ },
1106
+ group.field.name
1107
+ );
1108
+ }
1109
+ return /* @__PURE__ */ jsx2("div", { style: { display: "flex", gap: "0.75rem", flexWrap: "wrap", marginBottom: fieldSpacing }, children: group.fields.map((f) => /* @__PURE__ */ jsx2("div", { style: { flex: getWidthPercent(f.width) ? `0 0 calc(${getWidthPercent(f.width)} - 0.75rem)` : "1 1 0", minWidth: "120px" }, children: /* @__PURE__ */ jsx2(
1110
+ FormFieldInput,
1111
+ {
1112
+ field: f,
1113
+ value: form.values[f.name],
1114
+ error: form.errors[f.name],
1115
+ onChange: handleChange,
1116
+ onValueChange: (name, val) => form.setValue(name, val),
1117
+ styling,
1118
+ fieldSpacing: "0",
1119
+ labelSpacing,
1120
+ phFontSize
1121
+ }
1122
+ ) }, f.name)) }, `row-${idx}`);
1123
+ }),
1063
1124
  form.honeypotEnabled && /* @__PURE__ */ jsx2("div", { style: { position: "absolute", left: "-9999px", opacity: 0, height: 0, overflow: "hidden" }, "aria-hidden": "true", children: /* @__PURE__ */ jsx2("input", { type: "text", name: "_hp", tabIndex: -1, autoComplete: "off" }) }),
1064
1125
  form.requiresCaptcha && form.captchaProvider !== "recaptcha" && /* @__PURE__ */ jsx2("div", { ref: captchaContainerRef, style: { marginTop: "1rem" } }),
1065
1126
  (() => {
@@ -1101,8 +1162,12 @@ function FormsExpertForm({
1101
1162
  } : void 0;
1102
1163
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1103
1164
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: btnAlign, marginTop: "1rem", gap: "0.5rem", flexWrap: "wrap" }, children: [
1104
- sec?.enabled && secStyle && sec.position === "left" && /* @__PURE__ */ jsx2("a", { href: sec.href || "#", target: sec.openInNewTab ? "_blank" : void 0, rel: sec.openInNewTab ? "noopener noreferrer" : void 0, style: secStyle, children: sec.text || "Learn More" }),
1105
- /* @__PURE__ */ jsx2(
1165
+ sec?.enabled && secStyle && sec.position === "left" && /* @__PURE__ */ jsxs("a", { href: sec.href || "#", target: sec.openInNewTab ? "_blank" : void 0, rel: sec.openInNewTab ? "noopener noreferrer" : void 0, style: { ...secStyle, display: "inline-flex", alignItems: "center", gap: "0.5rem" }, children: [
1166
+ sec.icon && sec.iconPosition !== "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: sec.icon } }),
1167
+ /* @__PURE__ */ jsx2("span", { children: sec.text || "Learn More" }),
1168
+ sec.icon && sec.iconPosition === "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: sec.icon } })
1169
+ ] }),
1170
+ /* @__PURE__ */ jsxs(
1106
1171
  "button",
1107
1172
  {
1108
1173
  type: "submit",
@@ -1126,19 +1191,35 @@ function FormsExpertForm({
1126
1191
  minWidth: 0,
1127
1192
  whiteSpace: "nowrap",
1128
1193
  overflow: "hidden",
1129
- textOverflow: "ellipsis"
1194
+ textOverflow: "ellipsis",
1195
+ display: "inline-flex",
1196
+ alignItems: "center",
1197
+ justifyContent: "center",
1198
+ gap: "0.5rem"
1130
1199
  },
1131
- children: form.isLoading ? "Submitting..." : resolvedButtonText
1200
+ children: [
1201
+ !form.isLoading && styling.buttonIcon && styling.buttonIconPosition !== "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: styling.buttonIcon } }),
1202
+ /* @__PURE__ */ jsx2("span", { children: form.isLoading ? "Submitting..." : resolvedButtonText }),
1203
+ !form.isLoading && styling.buttonIcon && styling.buttonIconPosition === "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: styling.buttonIcon } })
1204
+ ]
1132
1205
  }
1133
1206
  ),
1134
- sec?.enabled && secStyle && sec.position !== "left" && sec.position !== "below" && /* @__PURE__ */ jsx2("a", { href: sec.href || "#", target: sec.openInNewTab ? "_blank" : void 0, rel: sec.openInNewTab ? "noopener noreferrer" : void 0, style: { ...secStyle, marginLeft: "auto" }, children: sec.text || "Learn More" })
1207
+ sec?.enabled && secStyle && sec.position !== "left" && sec.position !== "below" && /* @__PURE__ */ jsxs("a", { href: sec.href || "#", target: sec.openInNewTab ? "_blank" : void 0, rel: sec.openInNewTab ? "noopener noreferrer" : void 0, style: { ...secStyle, display: "inline-flex", alignItems: "center", gap: "0.5rem", marginLeft: "auto" }, children: [
1208
+ sec.icon && sec.iconPosition !== "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: sec.icon } }),
1209
+ /* @__PURE__ */ jsx2("span", { children: sec.text || "Learn More" }),
1210
+ sec.icon && sec.iconPosition === "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: sec.icon } })
1211
+ ] })
1135
1212
  ] }),
1136
1213
  sec?.enabled && secStyle && sec.position === "below" && /* @__PURE__ */ jsx2("div", { style: {
1137
1214
  display: "flex",
1138
1215
  justifyContent: sec.align === "center" ? "center" : sec.align === "right" ? "flex-end" : sec.align === "left" ? "flex-start" : btnAlign,
1139
1216
  marginTop: sec.marginTop != null ? `${sec.marginTop}px` : "0.5rem",
1140
1217
  marginBottom: sec.marginBottom != null ? `${sec.marginBottom}px` : void 0
1141
- }, children: /* @__PURE__ */ jsx2("a", { href: sec.href || "#", target: sec.openInNewTab ? "_blank" : void 0, rel: sec.openInNewTab ? "noopener noreferrer" : void 0, style: { ...secStyle, marginTop: 0, marginBottom: 0 }, children: sec.text || "Learn More" }) })
1218
+ }, children: /* @__PURE__ */ jsxs("a", { href: sec.href || "#", target: sec.openInNewTab ? "_blank" : void 0, rel: sec.openInNewTab ? "noopener noreferrer" : void 0, style: { ...secStyle, display: "inline-flex", alignItems: "center", gap: "0.5rem", marginTop: 0, marginBottom: 0 }, children: [
1219
+ sec.icon && sec.iconPosition !== "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: sec.icon } }),
1220
+ /* @__PURE__ */ jsx2("span", { children: sec.text || "Learn More" }),
1221
+ sec.icon && sec.iconPosition === "right" && /* @__PURE__ */ jsx2("span", { style: { display: "inline-flex", flexShrink: 0 }, dangerouslySetInnerHTML: { __html: sec.icon } })
1222
+ ] }) })
1142
1223
  ] });
1143
1224
  })(),
1144
1225
  showBranding && /* @__PURE__ */ jsx2(
@@ -1206,7 +1287,7 @@ function FormFieldInput({
1206
1287
  borderRadius: isBottomBorder ? 0 : fieldRadius,
1207
1288
  fontSize,
1208
1289
  fontFamily: "inherit",
1209
- backgroundColor: styling.theme === "dark" ? "#374151" : "#ffffff",
1290
+ backgroundColor: styling.inputBackgroundColor || (styling.theme === "dark" ? "#374151" : "#ffffff"),
1210
1291
  color: styling.textColor
1211
1292
  };
1212
1293
  const getOpts = () => {