@nextlyhq/plugin-form-builder 0.0.2-alpha.58 → 0.0.2-alpha.60

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.
@@ -872,6 +872,9 @@ function SubmissionsView({ collectionSlug }) {
872
872
  // src/admin/FormBuilderView.tsx
873
873
  import {
874
874
  Button as Button8,
875
+ FieldShell as FieldShell2,
876
+ FormActions,
877
+ FormLayout,
875
878
  Input as Input6,
876
879
  toast,
877
880
  Tabs as Tabs4,
@@ -1339,6 +1342,7 @@ function AddFieldDialog({
1339
1342
  // src/admin/components/builder/FieldEditor.tsx
1340
1343
  import {
1341
1344
  FieldOptionsEditor,
1345
+ ValidationNumberField,
1342
1346
  withOptionIds
1343
1347
  } from "@nextlyhq/plugin-sdk/admin";
1344
1348
  import {
@@ -2010,102 +2014,46 @@ function ValidationTab({
2010
2014
  )
2011
2015
  ] }),
2012
2016
  (field.type === "text" || field.type === "textarea") && /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-2 gap-4", children: [
2013
- /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
2014
- /* @__PURE__ */ jsx6(
2015
- FormLabelWithTooltip2,
2016
- {
2017
- label: "Min Length",
2018
- htmlFor: "min-len",
2019
- description: "Minimum characters required."
2020
- }
2021
- ),
2022
- /* @__PURE__ */ jsx6(
2023
- Input2,
2024
- {
2025
- id: "min-len",
2026
- type: "number",
2027
- min: 0,
2028
- value: field.validation?.minLength ?? "",
2029
- onChange: (e) => updateValidation(
2030
- "minLength",
2031
- e.target.value ? parseInt(e.target.value) : void 0
2032
- ),
2033
- className: "bg-transparent"
2034
- }
2035
- )
2036
- ] }),
2037
- /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
2038
- /* @__PURE__ */ jsx6(
2039
- FormLabelWithTooltip2,
2040
- {
2041
- label: "Max Length",
2042
- htmlFor: "max-len",
2043
- description: "Maximum characters allowed."
2044
- }
2045
- ),
2046
- /* @__PURE__ */ jsx6(
2047
- Input2,
2048
- {
2049
- id: "max-len",
2050
- type: "number",
2051
- min: 0,
2052
- value: field.validation?.maxLength ?? "",
2053
- onChange: (e) => updateValidation(
2054
- "maxLength",
2055
- e.target.value ? parseInt(e.target.value) : void 0
2056
- ),
2057
- className: "bg-transparent"
2058
- }
2059
- )
2060
- ] })
2017
+ /* @__PURE__ */ jsx6(
2018
+ ValidationNumberField,
2019
+ {
2020
+ label: "Min Length",
2021
+ description: "Minimum characters required.",
2022
+ counts: true,
2023
+ value: field.validation?.minLength,
2024
+ onChange: (n) => updateValidation("minLength", n)
2025
+ }
2026
+ ),
2027
+ /* @__PURE__ */ jsx6(
2028
+ ValidationNumberField,
2029
+ {
2030
+ label: "Max Length",
2031
+ description: "Maximum characters allowed.",
2032
+ counts: true,
2033
+ value: field.validation?.maxLength,
2034
+ onChange: (n) => updateValidation("maxLength", n)
2035
+ }
2036
+ )
2061
2037
  ] }),
2062
2038
  field.type === "number" && /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-2 gap-4", children: [
2063
- /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
2064
- /* @__PURE__ */ jsx6(
2065
- FormLabelWithTooltip2,
2066
- {
2067
- label: "Min Value",
2068
- htmlFor: "min-val",
2069
- description: "Minimum numerical value."
2070
- }
2071
- ),
2072
- /* @__PURE__ */ jsx6(
2073
- Input2,
2074
- {
2075
- id: "min-val",
2076
- type: "number",
2077
- value: field.validation?.min ?? "",
2078
- onChange: (e) => updateValidation(
2079
- "min",
2080
- e.target.value ? parseFloat(e.target.value) : void 0
2081
- ),
2082
- className: "bg-transparent"
2083
- }
2084
- )
2085
- ] }),
2086
- /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
2087
- /* @__PURE__ */ jsx6(
2088
- FormLabelWithTooltip2,
2089
- {
2090
- label: "Max Value",
2091
- htmlFor: "max-val",
2092
- description: "Maximum numerical value."
2093
- }
2094
- ),
2095
- /* @__PURE__ */ jsx6(
2096
- Input2,
2097
- {
2098
- id: "max-val",
2099
- type: "number",
2100
- value: field.validation?.max ?? "",
2101
- onChange: (e) => updateValidation(
2102
- "max",
2103
- e.target.value ? parseFloat(e.target.value) : void 0
2104
- ),
2105
- className: "bg-transparent"
2106
- }
2107
- )
2108
- ] })
2039
+ /* @__PURE__ */ jsx6(
2040
+ ValidationNumberField,
2041
+ {
2042
+ label: "Min Value",
2043
+ description: "Minimum numerical value.",
2044
+ value: field.validation?.min,
2045
+ onChange: (n) => updateValidation("min", n)
2046
+ }
2047
+ ),
2048
+ /* @__PURE__ */ jsx6(
2049
+ ValidationNumberField,
2050
+ {
2051
+ label: "Max Value",
2052
+ description: "Maximum numerical value.",
2053
+ value: field.validation?.max,
2054
+ onChange: (n) => updateValidation("max", n)
2055
+ }
2056
+ )
2109
2057
  ] }),
2110
2058
  (field.type === "text" || field.type === "email" || field.type === "phone" || field.type === "url") && /* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
2111
2059
  /* @__PURE__ */ jsx6(
@@ -2543,6 +2491,8 @@ import {
2543
2491
  DropdownMenuItem as DropdownMenuItem3,
2544
2492
  DropdownMenuSeparator as DropdownMenuSeparator2,
2545
2493
  DropdownMenuTrigger as DropdownMenuTrigger3,
2494
+ FieldShell,
2495
+ Grid,
2546
2496
  Input as Input3,
2547
2497
  Label as Label2,
2548
2498
  Select as Select5,
@@ -2938,235 +2888,269 @@ function NotificationSheet({
2938
2888
  /* @__PURE__ */ jsx8(SheetDescription2, { children: "Sent when someone submits this form." })
2939
2889
  ] }),
2940
2890
  /* @__PURE__ */ jsxs7("div", { className: "flex-1 overflow-y-auto p-4 space-y-6", children: [
2941
- /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
2942
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-name", children: "Name" }),
2943
- /* @__PURE__ */ jsx8(
2944
- Input3,
2891
+ /* @__PURE__ */ jsx8(FieldShell, { label: "Name", htmlFor: "notification-name", width: "half", children: /* @__PURE__ */ jsx8(
2892
+ Input3,
2893
+ {
2894
+ type: "text",
2895
+ value: form.name,
2896
+ onChange: (e) => update("name", e.target.value),
2897
+ placeholder: "e.g. Admin notification"
2898
+ }
2899
+ ) }),
2900
+ /* @__PURE__ */ jsxs7(Grid, { cols: 2, responsive: true, children: [
2901
+ /* @__PURE__ */ jsx8(FieldShell, { label: "Email provider", htmlFor: "notification-provider", children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
2902
+ Select5,
2945
2903
  {
2946
- id: "notification-name",
2947
- type: "text",
2948
- value: form.name,
2949
- onChange: (e) => update("name", e.target.value),
2950
- placeholder: "e.g. Admin notification"
2904
+ value: form.providerId ?? "__default",
2905
+ onValueChange: (value) => update(
2906
+ "providerId",
2907
+ value === "__default" ? void 0 : value
2908
+ ),
2909
+ children: [
2910
+ /* @__PURE__ */ jsx8(
2911
+ SelectTrigger5,
2912
+ {
2913
+ id,
2914
+ "aria-describedby": describedBy,
2915
+ "aria-invalid": invalid,
2916
+ className: "w-full bg-transparent border-input dark:bg-muted/50",
2917
+ children: /* @__PURE__ */ jsx8(SelectValue5, {})
2918
+ }
2919
+ ),
2920
+ /* @__PURE__ */ jsxs7(SelectContent5, { children: [
2921
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "__default", children: defaultProviderLabel }),
2922
+ providers.map((p) => /* @__PURE__ */ jsxs7(SelectItem5, { value: p.id, children: [
2923
+ p.name,
2924
+ p.isDefault ? " (Default)" : ""
2925
+ ] }, p.id))
2926
+ ] })
2927
+ ]
2951
2928
  }
2952
- )
2953
- ] }),
2954
- /* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
2929
+ ) }),
2955
2930
  /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
2956
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-provider", children: "Email provider" }),
2957
- /* @__PURE__ */ jsxs7(
2931
+ /* @__PURE__ */ jsx8(
2932
+ FieldShell,
2933
+ {
2934
+ label: "Email template",
2935
+ htmlFor: "notification-template",
2936
+ children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
2937
+ Select5,
2938
+ {
2939
+ value: form.templateSlug ?? "__none",
2940
+ onValueChange: (value) => update(
2941
+ "templateSlug",
2942
+ value === "__none" ? void 0 : value
2943
+ ),
2944
+ children: [
2945
+ /* @__PURE__ */ jsx8(
2946
+ SelectTrigger5,
2947
+ {
2948
+ id,
2949
+ "aria-describedby": describedBy,
2950
+ "aria-invalid": invalid,
2951
+ className: "w-full bg-transparent border-input dark:bg-muted/50",
2952
+ children: /* @__PURE__ */ jsx8(SelectValue5, {})
2953
+ }
2954
+ ),
2955
+ /* @__PURE__ */ jsxs7(SelectContent5, { children: [
2956
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a template" }),
2957
+ templates.filter((t) => t.isActive && t.kind !== "layout").map((t) => /* @__PURE__ */ jsx8(SelectItem5, { value: t.slug, children: t.name }, t.id))
2958
+ ] })
2959
+ ]
2960
+ }
2961
+ )
2962
+ }
2963
+ ),
2964
+ !form.templateSlug && /* @__PURE__ */ jsxs7("p", { className: "flex items-center gap-1 text-xs text-destructive", children: [
2965
+ /* @__PURE__ */ jsx8(TriangleAlert2, { className: "h-3 w-3", "aria-hidden": "true" }),
2966
+ "Required \u2014 a notification without a template is never sent."
2967
+ ] })
2968
+ ] })
2969
+ ] }),
2970
+ /* @__PURE__ */ jsx8(
2971
+ FieldShell,
2972
+ {
2973
+ label: "Sender email",
2974
+ htmlFor: "notification-sender",
2975
+ width: "half",
2976
+ description: addressErrors.senderEmail ? void 0 : senderHelp,
2977
+ error: addressErrors.senderEmail,
2978
+ children: /* @__PURE__ */ jsx8(
2979
+ Input3,
2980
+ {
2981
+ type: "email",
2982
+ value: form.senderEmail ?? "",
2983
+ onChange: (e) => update("senderEmail", e.target.value || void 0),
2984
+ placeholder: senderPlaceholder
2985
+ }
2986
+ )
2987
+ }
2988
+ ),
2989
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-4 pt-4 border-t border-border", children: [
2990
+ /* @__PURE__ */ jsxs7(Grid, { cols: 2, responsive: true, children: [
2991
+ /* @__PURE__ */ jsx8(FieldShell, { label: "Send to", htmlFor: "notification-recipient-type", children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
2958
2992
  Select5,
2959
2993
  {
2960
- value: form.providerId ?? "__default",
2961
- onValueChange: (value) => update(
2962
- "providerId",
2963
- value === "__default" ? void 0 : value
2964
- ),
2994
+ value: form.recipientType,
2995
+ onValueChange: (value) => {
2996
+ setForm((prev) => ({
2997
+ ...prev,
2998
+ recipientType: value,
2999
+ to: ""
3000
+ }));
3001
+ },
2965
3002
  children: [
2966
3003
  /* @__PURE__ */ jsx8(
2967
3004
  SelectTrigger5,
2968
3005
  {
2969
- id: "notification-provider",
3006
+ id,
3007
+ "aria-describedby": describedBy,
3008
+ "aria-invalid": invalid,
2970
3009
  className: "w-full bg-transparent border-input dark:bg-muted/50",
2971
3010
  children: /* @__PURE__ */ jsx8(SelectValue5, {})
2972
3011
  }
2973
3012
  ),
2974
3013
  /* @__PURE__ */ jsxs7(SelectContent5, { children: [
2975
- /* @__PURE__ */ jsx8(SelectItem5, { value: "__default", children: defaultProviderLabel }),
2976
- providers.map((p) => /* @__PURE__ */ jsxs7(SelectItem5, { value: p.id, children: [
2977
- p.name,
2978
- p.isDefault ? " (Default)" : ""
2979
- ] }, p.id))
3014
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "static", children: "A specific address" }),
3015
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "field", children: "The visitor (email field)" })
2980
3016
  ] })
2981
3017
  ]
2982
3018
  }
3019
+ ) }),
3020
+ form.recipientType === "field" ? /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3021
+ /* @__PURE__ */ jsx8(
3022
+ FieldShell,
3023
+ {
3024
+ label: "Visitor email field",
3025
+ htmlFor: "notification-to",
3026
+ children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
3027
+ Select5,
3028
+ {
3029
+ value: toRef ?? "__none",
3030
+ onValueChange: (value) => update(
3031
+ "to",
3032
+ value === "__none" ? "" : toFieldRef(value)
3033
+ ),
3034
+ children: [
3035
+ /* @__PURE__ */ jsx8(
3036
+ SelectTrigger5,
3037
+ {
3038
+ id,
3039
+ "aria-describedby": describedBy,
3040
+ "aria-invalid": invalid,
3041
+ className: "w-full bg-transparent border-input dark:bg-muted/50",
3042
+ children: /* @__PURE__ */ jsx8(SelectValue5, {})
3043
+ }
3044
+ ),
3045
+ /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3046
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a field" }),
3047
+ toFieldOptions.map((f) => /* @__PURE__ */ jsx8(SelectItem5, { value: f.name, children: f.label }, f.name))
3048
+ ] })
3049
+ ]
3050
+ }
3051
+ )
3052
+ }
3053
+ ),
3054
+ toFieldOptions.length === 0 && /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: "Add an email field to the form first." })
3055
+ ] }) : /* @__PURE__ */ jsx8(
3056
+ FieldShell,
3057
+ {
3058
+ label: "Recipient address",
3059
+ htmlFor: "notification-to",
3060
+ width: "half",
3061
+ error: addressErrors.to,
3062
+ children: /* @__PURE__ */ jsx8(
3063
+ Input3,
3064
+ {
3065
+ type: "email",
3066
+ value: form.to,
3067
+ onChange: (e) => update("to", e.target.value),
3068
+ placeholder: defaults?.defaultToEmail || "admin@example.com"
3069
+ }
3070
+ )
3071
+ }
2983
3072
  )
2984
3073
  ] }),
2985
- /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
2986
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-template", children: "Email template" }),
2987
- /* @__PURE__ */ jsxs7(
3074
+ /* @__PURE__ */ jsxs7(Grid, { cols: 2, responsive: true, children: [
3075
+ /* @__PURE__ */ jsx8(FieldShell, { label: "Reply-To", htmlFor: "notification-replyto-mode", children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
2988
3076
  Select5,
2989
3077
  {
2990
- value: form.templateSlug ?? "__none",
2991
- onValueChange: (value) => update("templateSlug", value === "__none" ? void 0 : value),
3078
+ value: replyToMode,
3079
+ onValueChange: (value) => {
3080
+ const mode = value;
3081
+ setReplyToMode(mode);
3082
+ update("replyTo", void 0);
3083
+ },
2992
3084
  children: [
2993
3085
  /* @__PURE__ */ jsx8(
2994
3086
  SelectTrigger5,
2995
3087
  {
2996
- id: "notification-template",
3088
+ id,
3089
+ "aria-describedby": describedBy,
3090
+ "aria-invalid": invalid,
2997
3091
  className: "w-full bg-transparent border-input dark:bg-muted/50",
2998
3092
  children: /* @__PURE__ */ jsx8(SelectValue5, {})
2999
3093
  }
3000
3094
  ),
3001
3095
  /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3002
- /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a template" }),
3003
- templates.filter((t) => t.isActive && t.kind !== "layout").map((t) => /* @__PURE__ */ jsx8(SelectItem5, { value: t.slug, children: t.name }, t.id))
3096
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "none", children: "None" }),
3097
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "field", children: "The visitor (email field)" }),
3098
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "custom", children: "A custom address" })
3004
3099
  ] })
3005
3100
  ]
3006
3101
  }
3007
- ),
3008
- !form.templateSlug && /* @__PURE__ */ jsxs7("p", { className: "flex items-center gap-1 text-xs text-destructive", children: [
3009
- /* @__PURE__ */ jsx8(TriangleAlert2, { className: "h-3 w-3", "aria-hidden": "true" }),
3010
- "Required \u2014 a notification without a template is never sent."
3011
- ] })
3012
- ] })
3013
- ] }),
3014
- /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3015
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-sender", children: "Sender email" }),
3016
- /* @__PURE__ */ jsx8(
3017
- Input3,
3018
- {
3019
- id: "notification-sender",
3020
- type: "email",
3021
- value: form.senderEmail ?? "",
3022
- onChange: (e) => update("senderEmail", e.target.value || void 0),
3023
- placeholder: senderPlaceholder,
3024
- "aria-invalid": addressErrors.senderEmail ? true : void 0
3025
- }
3026
- ),
3027
- addressErrors.senderEmail ? /* @__PURE__ */ jsx8("p", { className: "text-xs text-destructive", children: addressErrors.senderEmail }) : /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: senderHelp })
3028
- ] }),
3029
- /* @__PURE__ */ jsxs7("div", { className: "space-y-4 pt-4 border-t border-border", children: [
3030
- /* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
3031
- /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3032
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-recipient-type", children: "Send to" }),
3033
- /* @__PURE__ */ jsxs7(
3034
- Select5,
3035
- {
3036
- value: form.recipientType,
3037
- onValueChange: (value) => {
3038
- setForm((prev) => ({
3039
- ...prev,
3040
- recipientType: value,
3041
- to: ""
3042
- }));
3043
- },
3044
- children: [
3045
- /* @__PURE__ */ jsx8(
3046
- SelectTrigger5,
3047
- {
3048
- id: "notification-recipient-type",
3049
- className: "w-full bg-transparent border-input dark:bg-muted/50",
3050
- children: /* @__PURE__ */ jsx8(SelectValue5, {})
3051
- }
3052
- ),
3053
- /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3054
- /* @__PURE__ */ jsx8(SelectItem5, { value: "static", children: "A specific address" }),
3055
- /* @__PURE__ */ jsx8(SelectItem5, { value: "field", children: "The visitor (email field)" })
3056
- ] })
3057
- ]
3058
- }
3059
- )
3060
- ] }),
3061
- /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3062
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-to", children: form.recipientType === "field" ? "Visitor email field" : "Recipient address" }),
3063
- form.recipientType === "field" ? /* @__PURE__ */ jsxs7(
3064
- Select5,
3065
- {
3066
- value: toRef ?? "__none",
3067
- onValueChange: (value) => update("to", value === "__none" ? "" : toFieldRef(value)),
3068
- children: [
3069
- /* @__PURE__ */ jsx8(
3070
- SelectTrigger5,
3071
- {
3072
- id: "notification-to",
3073
- className: "w-full bg-transparent border-input dark:bg-muted/50",
3074
- children: /* @__PURE__ */ jsx8(SelectValue5, {})
3075
- }
3076
- ),
3077
- /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3078
- /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a field" }),
3079
- toFieldOptions.map((f) => /* @__PURE__ */ jsx8(SelectItem5, { value: f.name, children: f.label }, f.name))
3080
- ] })
3081
- ]
3082
- }
3083
- ) : /* @__PURE__ */ jsx8(
3084
- Input3,
3085
- {
3086
- id: "notification-to",
3087
- type: "email",
3088
- value: form.to,
3089
- onChange: (e) => update("to", e.target.value),
3090
- placeholder: defaults?.defaultToEmail || "admin@example.com",
3091
- "aria-invalid": addressErrors.to ? true : void 0
3092
- }
3093
- ),
3094
- addressErrors.to && /* @__PURE__ */ jsx8("p", { className: "text-xs text-destructive", children: addressErrors.to }),
3095
- form.recipientType === "field" && toFieldOptions.length === 0 && /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground", children: "Add an email field to the form first." })
3096
- ] })
3097
- ] }),
3098
- /* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-4", children: [
3099
- /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3100
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-replyto-mode", children: "Reply-To" }),
3101
- /* @__PURE__ */ jsxs7(
3102
- Select5,
3103
- {
3104
- value: replyToMode,
3105
- onValueChange: (value) => {
3106
- const mode = value;
3107
- setReplyToMode(mode);
3108
- update("replyTo", void 0);
3109
- },
3110
- children: [
3111
- /* @__PURE__ */ jsx8(
3112
- SelectTrigger5,
3113
- {
3114
- id: "notification-replyto-mode",
3115
- className: "w-full bg-transparent border-input dark:bg-muted/50",
3116
- children: /* @__PURE__ */ jsx8(SelectValue5, {})
3117
- }
3118
- ),
3119
- /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3120
- /* @__PURE__ */ jsx8(SelectItem5, { value: "none", children: "None" }),
3121
- /* @__PURE__ */ jsx8(SelectItem5, { value: "field", children: "The visitor (email field)" }),
3122
- /* @__PURE__ */ jsx8(SelectItem5, { value: "custom", children: "A custom address" })
3123
- ] })
3124
- ]
3125
- }
3126
- )
3127
- ] }),
3128
- replyToMode === "field" && /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3129
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-replyto", children: "Visitor email field" }),
3130
- /* @__PURE__ */ jsxs7(
3131
- Select5,
3132
- {
3133
- value: replyToRef ?? "__none",
3134
- onValueChange: (value) => update(
3135
- "replyTo",
3136
- value === "__none" ? void 0 : toFieldRef(value)
3137
- ),
3138
- children: [
3139
- /* @__PURE__ */ jsx8(
3140
- SelectTrigger5,
3141
- {
3142
- id: "notification-replyto",
3143
- className: "w-full bg-transparent border-input dark:bg-muted/50",
3144
- children: /* @__PURE__ */ jsx8(SelectValue5, {})
3145
- }
3102
+ ) }),
3103
+ replyToMode === "field" && /* @__PURE__ */ jsx8(
3104
+ FieldShell,
3105
+ {
3106
+ label: "Visitor email field",
3107
+ htmlFor: "notification-replyto",
3108
+ children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
3109
+ Select5,
3110
+ {
3111
+ value: replyToRef ?? "__none",
3112
+ onValueChange: (value) => update(
3113
+ "replyTo",
3114
+ value === "__none" ? void 0 : toFieldRef(value)
3146
3115
  ),
3147
- /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3148
- /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a field" }),
3149
- replyToFieldOptions.map((f) => /* @__PURE__ */ jsx8(SelectItem5, { value: f.name, children: f.label }, f.name))
3150
- ] })
3151
- ]
3152
- }
3153
- )
3154
- ] }),
3155
- replyToMode === "custom" && /* @__PURE__ */ jsxs7("div", { className: "space-y-1.5", children: [
3156
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-replyto", children: "Reply-To address" }),
3157
- /* @__PURE__ */ jsx8(
3158
- Input3,
3159
- {
3160
- id: "notification-replyto",
3161
- type: "email",
3162
- value: form.replyTo ?? "",
3163
- onChange: (e) => update("replyTo", e.target.value || void 0),
3164
- placeholder: "replies@example.com",
3165
- "aria-invalid": addressErrors.replyTo ? true : void 0
3166
- }
3167
- ),
3168
- addressErrors.replyTo && /* @__PURE__ */ jsx8("p", { className: "text-xs text-destructive", children: addressErrors.replyTo })
3169
- ] })
3116
+ children: [
3117
+ /* @__PURE__ */ jsx8(
3118
+ SelectTrigger5,
3119
+ {
3120
+ id,
3121
+ "aria-describedby": describedBy,
3122
+ "aria-invalid": invalid,
3123
+ className: "w-full bg-transparent border-input dark:bg-muted/50",
3124
+ children: /* @__PURE__ */ jsx8(SelectValue5, {})
3125
+ }
3126
+ ),
3127
+ /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3128
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a field" }),
3129
+ replyToFieldOptions.map((f) => /* @__PURE__ */ jsx8(SelectItem5, { value: f.name, children: f.label }, f.name))
3130
+ ] })
3131
+ ]
3132
+ }
3133
+ )
3134
+ }
3135
+ ),
3136
+ replyToMode === "custom" && /* @__PURE__ */ jsx8(
3137
+ FieldShell,
3138
+ {
3139
+ label: "Reply-To address",
3140
+ htmlFor: "notification-replyto",
3141
+ width: "half",
3142
+ error: addressErrors.replyTo,
3143
+ children: /* @__PURE__ */ jsx8(
3144
+ Input3,
3145
+ {
3146
+ type: "email",
3147
+ value: form.replyTo ?? "",
3148
+ onChange: (e) => update("replyTo", e.target.value || void 0),
3149
+ placeholder: "replies@example.com"
3150
+ }
3151
+ )
3152
+ }
3153
+ )
3170
3154
  ] }),
3171
3155
  replyToMode === "field" && /* @__PURE__ */ jsx8("p", { className: "text-xs text-muted-foreground -mt-2", children: "Replying to this email answers the person who submitted the form." }),
3172
3156
  /* @__PURE__ */ jsx8(
@@ -3216,74 +3200,92 @@ function NotificationSheet({
3216
3200
  )
3217
3201
  ] }),
3218
3202
  condition && /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-end gap-2 border border-border bg-muted/40 p-3", children: [
3219
- /* @__PURE__ */ jsxs7("div", { className: "min-w-36 flex-1 space-y-1.5", children: [
3220
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-condition-field", children: "Field" }),
3221
- /* @__PURE__ */ jsxs7(
3222
- Select5,
3223
- {
3224
- value: condition.field || "__none",
3225
- onValueChange: (value) => update("condition", {
3226
- ...condition,
3227
- field: value === "__none" ? "" : value
3228
- }),
3229
- children: [
3230
- /* @__PURE__ */ jsx8(
3231
- SelectTrigger5,
3232
- {
3233
- id: "notification-condition-field",
3234
- className: "w-full bg-transparent border-input dark:bg-muted/50",
3235
- children: /* @__PURE__ */ jsx8(SelectValue5, {})
3236
- }
3237
- ),
3238
- /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3239
- /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a field" }),
3240
- fields.map((f) => /* @__PURE__ */ jsx8(SelectItem5, { value: f.name, children: f.label }, f.name))
3241
- ] })
3242
- ]
3243
- }
3244
- )
3245
- ] }),
3246
- /* @__PURE__ */ jsxs7("div", { className: "min-w-36 flex-1 space-y-1.5", children: [
3247
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-condition-comparison", children: "Comparison" }),
3248
- /* @__PURE__ */ jsxs7(
3249
- Select5,
3250
- {
3251
- value: condition.comparison,
3252
- onValueChange: (value) => update("condition", {
3253
- ...condition,
3254
- comparison: value
3255
- }),
3256
- children: [
3257
- /* @__PURE__ */ jsx8(
3258
- SelectTrigger5,
3259
- {
3260
- id: "notification-condition-comparison",
3261
- className: "w-full bg-transparent border-input dark:bg-muted/50",
3262
- children: /* @__PURE__ */ jsx8(SelectValue5, {})
3263
- }
3264
- ),
3265
- /* @__PURE__ */ jsx8(SelectContent5, { children: Object.entries(COMPARISON_LABELS).map(
3266
- ([value, label]) => /* @__PURE__ */ jsx8(SelectItem5, { value, children: label }, value)
3267
- ) })
3268
- ]
3269
- }
3270
- )
3271
- ] }),
3272
- !VALUELESS_COMPARISONS.has(condition.comparison) && /* @__PURE__ */ jsxs7("div", { className: "min-w-36 flex-1 space-y-1.5", children: [
3273
- /* @__PURE__ */ jsx8(Label2, { htmlFor: "notification-condition-value", children: "Value" }),
3274
- /* @__PURE__ */ jsx8(
3275
- Input3,
3276
- {
3277
- id: "notification-condition-value",
3278
- type: "text",
3279
- value: typeof condition.value === "string" || typeof condition.value === "number" ? String(condition.value) : "",
3280
- onChange: (e) => update("condition", {
3281
- ...condition,
3282
- value: e.target.value
3283
- })
3284
- }
3285
- )
3286
- ] }),
3203
+ /* @__PURE__ */ jsx8(
3204
+ FieldShell,
3205
+ {
3206
+ label: "Field",
3207
+ htmlFor: "notification-condition-field",
3208
+ className: "min-w-36 flex-1",
3209
+ children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
3210
+ Select5,
3211
+ {
3212
+ value: condition.field || "__none",
3213
+ onValueChange: (value) => update("condition", {
3214
+ ...condition,
3215
+ field: value === "__none" ? "" : value
3216
+ }),
3217
+ children: [
3218
+ /* @__PURE__ */ jsx8(
3219
+ SelectTrigger5,
3220
+ {
3221
+ id,
3222
+ "aria-describedby": describedBy,
3223
+ "aria-invalid": invalid,
3224
+ className: "w-full bg-transparent border-input dark:bg-muted/50",
3225
+ children: /* @__PURE__ */ jsx8(SelectValue5, {})
3226
+ }
3227
+ ),
3228
+ /* @__PURE__ */ jsxs7(SelectContent5, { children: [
3229
+ /* @__PURE__ */ jsx8(SelectItem5, { value: "__none", children: "Select a field" }),
3230
+ fields.map((f) => /* @__PURE__ */ jsx8(SelectItem5, { value: f.name, children: f.label }, f.name))
3231
+ ] })
3232
+ ]
3233
+ }
3234
+ )
3235
+ }
3236
+ ),
3237
+ /* @__PURE__ */ jsx8(
3238
+ FieldShell,
3239
+ {
3240
+ label: "Comparison",
3241
+ htmlFor: "notification-condition-comparison",
3242
+ className: "min-w-36 flex-1",
3243
+ children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs7(
3244
+ Select5,
3245
+ {
3246
+ value: condition.comparison,
3247
+ onValueChange: (value) => update("condition", {
3248
+ ...condition,
3249
+ comparison: value
3250
+ }),
3251
+ children: [
3252
+ /* @__PURE__ */ jsx8(
3253
+ SelectTrigger5,
3254
+ {
3255
+ id,
3256
+ "aria-describedby": describedBy,
3257
+ "aria-invalid": invalid,
3258
+ className: "w-full bg-transparent border-input dark:bg-muted/50",
3259
+ children: /* @__PURE__ */ jsx8(SelectValue5, {})
3260
+ }
3261
+ ),
3262
+ /* @__PURE__ */ jsx8(SelectContent5, { children: Object.entries(COMPARISON_LABELS).map(
3263
+ ([value, label]) => /* @__PURE__ */ jsx8(SelectItem5, { value, children: label }, value)
3264
+ ) })
3265
+ ]
3266
+ }
3267
+ )
3268
+ }
3269
+ ),
3270
+ !VALUELESS_COMPARISONS.has(condition.comparison) && /* @__PURE__ */ jsx8(
3271
+ FieldShell,
3272
+ {
3273
+ label: "Value",
3274
+ htmlFor: "notification-condition-value",
3275
+ className: "min-w-36 flex-1",
3276
+ children: /* @__PURE__ */ jsx8(
3277
+ Input3,
3278
+ {
3279
+ type: "text",
3280
+ value: typeof condition.value === "string" || typeof condition.value === "number" ? String(condition.value) : "",
3281
+ onChange: (e) => update("condition", {
3282
+ ...condition,
3283
+ value: e.target.value
3284
+ })
3285
+ }
3286
+ )
3287
+ }
3288
+ ),
3287
3289
  /* @__PURE__ */ jsx8(
3288
3290
  Button6,
3289
3291
  {
@@ -3382,52 +3384,55 @@ function FormNotificationsTab({ defaults }) {
3382
3384
  [providers]
3383
3385
  );
3384
3386
  const initialNotification = sheetState.editing ?? createNotification();
3385
- return /* @__PURE__ */ jsxs7("div", { className: "max-w-200", children: [
3386
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between mb-8 pb-4 border-b border-border", children: [
3387
- /* @__PURE__ */ jsxs7("div", { children: [
3388
- /* @__PURE__ */ jsx8("h3", { className: "text-xl font-semibold text-foreground", children: "Notifications" }),
3389
- /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground mt-1", children: "Emails sent when someone submits this form." })
3387
+ return (
3388
+ // The measure belongs to `FormLayout` now, not to this tab.
3389
+ /* @__PURE__ */ jsxs7("div", { children: [
3390
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between mb-8 pb-4 border-b border-border", children: [
3391
+ /* @__PURE__ */ jsxs7("div", { children: [
3392
+ /* @__PURE__ */ jsx8("h3", { className: "text-xl font-semibold text-foreground", children: "Notifications" }),
3393
+ /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground mt-1", children: "Emails sent when someone submits this form." })
3394
+ ] }),
3395
+ /* @__PURE__ */ jsxs7(Button6, { type: "button", onClick: openAddSheet, children: [
3396
+ /* @__PURE__ */ jsx8(Plus2, { className: "h-4 w-4", "aria-hidden": "true" }),
3397
+ "Add notification"
3398
+ ] })
3390
3399
  ] }),
3391
- /* @__PURE__ */ jsxs7(Button6, { type: "button", onClick: openAddSheet, children: [
3392
- /* @__PURE__ */ jsx8(Plus2, { className: "h-4 w-4", "aria-hidden": "true" }),
3393
- "Add notification"
3394
- ] })
3395
- ] }),
3396
- notifications.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center p-12 mt-6 border-2 border-dashed border-border rounded-none bg-muted", children: [
3397
- /* @__PURE__ */ jsx8("div", { className: "flex items-center justify-center w-12 h-12 rounded-none border border-border bg-background mb-4 text-primary", children: /* @__PURE__ */ jsx8(Mail, { className: "h-6 w-6", "aria-hidden": "true" }) }),
3398
- /* @__PURE__ */ jsx8("p", { className: "text-base font-medium text-foreground mb-1", children: "No notifications yet" }),
3399
- /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground mb-6 text-center max-w-sm", children: "Add a notification to email someone when this form is submitted." }),
3400
- /* @__PURE__ */ jsxs7(Button6, { type: "button", onClick: openAddSheet, children: [
3401
- /* @__PURE__ */ jsx8(Plus2, { className: "h-4 w-4", "aria-hidden": "true" }),
3402
- "Add notification"
3403
- ] })
3404
- ] }) : /* @__PURE__ */ jsx8("div", { className: "space-y-2", children: notifications.map((notification) => /* @__PURE__ */ jsx8(
3405
- NotificationCard,
3406
- {
3407
- notification,
3408
- providerName: getProviderName(notification.providerId),
3409
- fields: fieldList,
3410
- onEdit: () => openEditSheet(notification),
3411
- onDuplicate: () => duplicateNotification(notification.id),
3412
- onDelete: () => deleteNotification(notification.id),
3413
- onToggleEnabled: (enabled) => updateNotification(notification.id, { enabled })
3414
- },
3415
- notification.id
3416
- )) }),
3417
- sheetState.open && /* @__PURE__ */ jsx8(
3418
- NotificationSheet,
3419
- {
3420
- initial: initialNotification,
3421
- isEditing: !!sheetState.editing,
3422
- providers,
3423
- templates,
3424
- fields: fieldList,
3425
- defaults,
3426
- onSave: handleSave,
3427
- onClose: closeSheet
3428
- }
3429
- )
3430
- ] });
3400
+ notifications.length === 0 ? /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center justify-center p-12 mt-6 border-2 border-dashed border-border rounded-none bg-muted", children: [
3401
+ /* @__PURE__ */ jsx8("div", { className: "flex items-center justify-center w-12 h-12 rounded-none border border-border bg-background mb-4 text-primary", children: /* @__PURE__ */ jsx8(Mail, { className: "h-6 w-6", "aria-hidden": "true" }) }),
3402
+ /* @__PURE__ */ jsx8("p", { className: "text-base font-medium text-foreground mb-1", children: "No notifications yet" }),
3403
+ /* @__PURE__ */ jsx8("p", { className: "text-sm text-muted-foreground mb-6 text-center max-w-sm", children: "Add a notification to email someone when this form is submitted." }),
3404
+ /* @__PURE__ */ jsxs7(Button6, { type: "button", onClick: openAddSheet, children: [
3405
+ /* @__PURE__ */ jsx8(Plus2, { className: "h-4 w-4", "aria-hidden": "true" }),
3406
+ "Add notification"
3407
+ ] })
3408
+ ] }) : /* @__PURE__ */ jsx8("div", { className: "space-y-2", children: notifications.map((notification) => /* @__PURE__ */ jsx8(
3409
+ NotificationCard,
3410
+ {
3411
+ notification,
3412
+ providerName: getProviderName(notification.providerId),
3413
+ fields: fieldList,
3414
+ onEdit: () => openEditSheet(notification),
3415
+ onDuplicate: () => duplicateNotification(notification.id),
3416
+ onDelete: () => deleteNotification(notification.id),
3417
+ onToggleEnabled: (enabled) => updateNotification(notification.id, { enabled })
3418
+ },
3419
+ notification.id
3420
+ )) }),
3421
+ sheetState.open && /* @__PURE__ */ jsx8(
3422
+ NotificationSheet,
3423
+ {
3424
+ initial: initialNotification,
3425
+ isEditing: !!sheetState.editing,
3426
+ providers,
3427
+ templates,
3428
+ fields: fieldList,
3429
+ defaults,
3430
+ onSave: handleSave,
3431
+ onClose: closeSheet
3432
+ }
3433
+ )
3434
+ ] })
3435
+ );
3431
3436
  }
3432
3437
 
3433
3438
  // src/admin/components/builder/FormPreview.tsx
@@ -3750,7 +3755,7 @@ function SettingRow({
3750
3755
  children
3751
3756
  }) {
3752
3757
  return /* @__PURE__ */ jsxs9("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-6 py-2", children: [
3753
- /* @__PURE__ */ jsxs9("div", { className: "space-y-1 max-w-xl", children: [
3758
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-1", children: [
3754
3759
  /* @__PURE__ */ jsx10(
3755
3760
  Label4,
3756
3761
  {
@@ -3799,172 +3804,175 @@ function InheritToggle({
3799
3804
  }
3800
3805
  function FormSettingsTab({ spamDefaults }) {
3801
3806
  const { settings, updateSettings } = useFormBuilder();
3802
- return /* @__PURE__ */ jsxs9("div", { className: "w-full max-w-3xl flex flex-col gap-10", children: [
3803
- /* @__PURE__ */ jsxs9("section", { children: [
3804
- /* @__PURE__ */ jsx10(SectionHeading, { children: "Submission" }),
3805
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1 pt-2", children: [
3806
- /* @__PURE__ */ jsx10(
3807
- SettingRow,
3808
- {
3809
- label: "Submit button text",
3810
- description: "Label on the form's primary action button",
3811
- htmlFor: "settings-submit-text",
3812
- children: /* @__PURE__ */ jsx10(
3813
- Input5,
3814
- {
3815
- id: "settings-submit-text",
3816
- type: "text",
3817
- className: "w-56",
3818
- value: settings.submitButtonText ?? "",
3819
- onChange: (e) => updateSettings({ submitButtonText: e.target.value })
3820
- }
3821
- )
3822
- }
3823
- ),
3824
- /* @__PURE__ */ jsx10(
3825
- SettingRow,
3826
- {
3827
- label: "Allow multiple submissions",
3828
- description: "When off, the same visitor (by IP) can submit this form only once. Best-effort: IP-based, so shared networks count as one visitor.",
3829
- htmlFor: "settings-multiple",
3830
- children: /* @__PURE__ */ jsx10(
3831
- Switch3,
3832
- {
3833
- id: "settings-multiple",
3834
- checked: settings.allowMultipleSubmissions ?? true,
3835
- onCheckedChange: (checked) => updateSettings({ allowMultipleSubmissions: checked })
3836
- }
3837
- )
3838
- }
3839
- )
3840
- ] })
3841
- ] }),
3842
- /* @__PURE__ */ jsxs9("section", { children: [
3843
- /* @__PURE__ */ jsx10(SectionHeading, { children: "After submission" }),
3844
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-4 pt-4", children: [
3845
- settings.confirmationType === "relationship" && /* @__PURE__ */ jsx10("p", { className: "border border-border bg-muted/40 p-3 text-sm text-muted-foreground", children: "This form redirects to a linked page (configured via the API). Picking an option below replaces that behavior." }),
3846
- /* @__PURE__ */ jsxs9(
3847
- RadioGroup2,
3848
- {
3849
- value: settings.confirmationType ?? "message",
3850
- onValueChange: (value) => updateSettings({
3851
- confirmationType: value
3852
- }),
3853
- className: "flex flex-col gap-3",
3854
- children: [
3855
- /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-3", children: [
3856
- /* @__PURE__ */ jsx10(
3857
- RadioGroupItem2,
3858
- {
3859
- value: "message",
3860
- id: "settings-confirm-message",
3861
- className: "mt-0.5"
3862
- }
3863
- ),
3864
- /* @__PURE__ */ jsxs9("div", { className: "w-full space-y-2", children: [
3865
- /* @__PURE__ */ jsx10(Label4, { htmlFor: "settings-confirm-message", children: "Show a message" }),
3866
- (settings.confirmationType ?? "message") === "message" && /* @__PURE__ */ jsx10(
3867
- Textarea3,
3807
+ return (
3808
+ // The measure belongs to `FormLayout` now, not to this tab.
3809
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-10", children: [
3810
+ /* @__PURE__ */ jsxs9("section", { children: [
3811
+ /* @__PURE__ */ jsx10(SectionHeading, { children: "Submission" }),
3812
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1 pt-2", children: [
3813
+ /* @__PURE__ */ jsx10(
3814
+ SettingRow,
3815
+ {
3816
+ label: "Submit button text",
3817
+ description: "Label on the form's primary action button",
3818
+ htmlFor: "settings-submit-text",
3819
+ children: /* @__PURE__ */ jsx10(
3820
+ Input5,
3821
+ {
3822
+ id: "settings-submit-text",
3823
+ type: "text",
3824
+ className: "w-56",
3825
+ value: settings.submitButtonText ?? "",
3826
+ onChange: (e) => updateSettings({ submitButtonText: e.target.value })
3827
+ }
3828
+ )
3829
+ }
3830
+ ),
3831
+ /* @__PURE__ */ jsx10(
3832
+ SettingRow,
3833
+ {
3834
+ label: "Allow multiple submissions",
3835
+ description: "When off, the same visitor (by IP) can submit this form only once. Best-effort: IP-based, so shared networks count as one visitor.",
3836
+ htmlFor: "settings-multiple",
3837
+ children: /* @__PURE__ */ jsx10(
3838
+ Switch3,
3839
+ {
3840
+ id: "settings-multiple",
3841
+ checked: settings.allowMultipleSubmissions ?? true,
3842
+ onCheckedChange: (checked) => updateSettings({ allowMultipleSubmissions: checked })
3843
+ }
3844
+ )
3845
+ }
3846
+ )
3847
+ ] })
3848
+ ] }),
3849
+ /* @__PURE__ */ jsxs9("section", { children: [
3850
+ /* @__PURE__ */ jsx10(SectionHeading, { children: "After submission" }),
3851
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-4 pt-4", children: [
3852
+ settings.confirmationType === "relationship" && /* @__PURE__ */ jsx10("p", { className: "border border-border bg-muted/40 p-3 text-sm text-muted-foreground", children: "This form redirects to a linked page (configured via the API). Picking an option below replaces that behavior." }),
3853
+ /* @__PURE__ */ jsxs9(
3854
+ RadioGroup2,
3855
+ {
3856
+ value: settings.confirmationType ?? "message",
3857
+ onValueChange: (value) => updateSettings({
3858
+ confirmationType: value
3859
+ }),
3860
+ className: "flex flex-col gap-3",
3861
+ children: [
3862
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-3", children: [
3863
+ /* @__PURE__ */ jsx10(
3864
+ RadioGroupItem2,
3868
3865
  {
3869
- "aria-label": "Success message",
3870
- value: settings.successMessage ?? "",
3871
- onChange: (e) => updateSettings({ successMessage: e.target.value }),
3872
- rows: 3,
3873
- placeholder: "Thank you for your submission!"
3866
+ value: "message",
3867
+ id: "settings-confirm-message",
3868
+ className: "mt-0.5"
3874
3869
  }
3875
- )
3876
- ] })
3877
- ] }),
3878
- /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-3", children: [
3879
- /* @__PURE__ */ jsx10(
3880
- RadioGroupItem2,
3881
- {
3882
- value: "redirect",
3883
- id: "settings-confirm-redirect",
3884
- className: "mt-0.5"
3885
- }
3886
- ),
3887
- /* @__PURE__ */ jsxs9("div", { className: "w-full space-y-2", children: [
3888
- /* @__PURE__ */ jsx10(Label4, { htmlFor: "settings-confirm-redirect", children: "Redirect to a URL" }),
3889
- settings.confirmationType === "redirect" && /* @__PURE__ */ jsx10(
3890
- Input5,
3870
+ ),
3871
+ /* @__PURE__ */ jsxs9("div", { className: "w-full space-y-2", children: [
3872
+ /* @__PURE__ */ jsx10(Label4, { htmlFor: "settings-confirm-message", children: "Show a message" }),
3873
+ (settings.confirmationType ?? "message") === "message" && /* @__PURE__ */ jsx10(
3874
+ Textarea3,
3875
+ {
3876
+ "aria-label": "Success message",
3877
+ value: settings.successMessage ?? "",
3878
+ onChange: (e) => updateSettings({ successMessage: e.target.value }),
3879
+ rows: 3,
3880
+ placeholder: "Thank you for your submission!"
3881
+ }
3882
+ )
3883
+ ] })
3884
+ ] }),
3885
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-start gap-3", children: [
3886
+ /* @__PURE__ */ jsx10(
3887
+ RadioGroupItem2,
3891
3888
  {
3892
- "aria-label": "Redirect URL",
3893
- type: "url",
3894
- value: settings.redirectUrl ?? "",
3895
- onChange: (e) => updateSettings({
3896
- redirectUrl: e.target.value || void 0
3897
- }),
3898
- placeholder: "https://example.com/thanks"
3889
+ value: "redirect",
3890
+ id: "settings-confirm-redirect",
3891
+ className: "mt-0.5"
3899
3892
  }
3900
- )
3893
+ ),
3894
+ /* @__PURE__ */ jsxs9("div", { className: "w-full space-y-2", children: [
3895
+ /* @__PURE__ */ jsx10(Label4, { htmlFor: "settings-confirm-redirect", children: "Redirect to a URL" }),
3896
+ settings.confirmationType === "redirect" && /* @__PURE__ */ jsx10(
3897
+ Input5,
3898
+ {
3899
+ "aria-label": "Redirect URL",
3900
+ type: "url",
3901
+ value: settings.redirectUrl ?? "",
3902
+ onChange: (e) => updateSettings({
3903
+ redirectUrl: e.target.value || void 0
3904
+ }),
3905
+ placeholder: "https://example.com/thanks"
3906
+ }
3907
+ )
3908
+ ] })
3901
3909
  ] })
3902
- ] })
3903
- ]
3904
- }
3905
- )
3906
- ] })
3907
- ] }),
3908
- /* @__PURE__ */ jsxs9("section", { children: [
3909
- /* @__PURE__ */ jsx10(SectionHeading, { children: "Spam protection" }),
3910
- /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1 pt-2", children: [
3911
- /* @__PURE__ */ jsx10(
3912
- SettingRow,
3913
- {
3914
- label: "Honeypot",
3915
- description: "Invisible trap field for bots. Inherits the plugin default unless overridden here.",
3916
- htmlFor: "settings-honeypot",
3917
- children: /* @__PURE__ */ jsx10(
3918
- InheritToggle,
3919
- {
3920
- id: "settings-honeypot",
3921
- value: settings.honeypotEnabled,
3922
- inherited: spamDefaults?.honeypot,
3923
- onChange: (honeypotEnabled) => updateSettings({ honeypotEnabled })
3924
- }
3925
- )
3926
- }
3927
- ),
3928
- /* @__PURE__ */ jsx10(
3929
- SettingRow,
3930
- {
3931
- label: "reCAPTCHA",
3932
- description: "Challenge-based bot check. Inherits the plugin default unless overridden here.",
3933
- htmlFor: "settings-captcha",
3934
- children: /* @__PURE__ */ jsx10(
3935
- InheritToggle,
3936
- {
3937
- id: "settings-captcha",
3938
- value: settings.captchaEnabled,
3939
- inherited: spamDefaults?.recaptchaEnabled,
3940
- onChange: (captchaEnabled) => updateSettings({ captchaEnabled })
3941
- }
3942
- )
3943
- }
3944
- ),
3945
- settings.captchaEnabled === true && /* @__PURE__ */ jsx10(
3946
- SettingRow,
3947
- {
3948
- label: "reCAPTCHA site key",
3949
- description: "The client-facing site key for this form",
3950
- htmlFor: "settings-captcha-key",
3951
- children: /* @__PURE__ */ jsx10(
3952
- Input5,
3953
- {
3954
- id: "settings-captcha-key",
3955
- type: "text",
3956
- className: "w-72 font-mono",
3957
- value: settings.captchaSiteKey ?? "",
3958
- onChange: (e) => updateSettings({
3959
- captchaSiteKey: e.target.value || void 0
3960
- })
3961
- }
3962
- )
3963
- }
3964
- )
3910
+ ]
3911
+ }
3912
+ )
3913
+ ] })
3914
+ ] }),
3915
+ /* @__PURE__ */ jsxs9("section", { children: [
3916
+ /* @__PURE__ */ jsx10(SectionHeading, { children: "Spam protection" }),
3917
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-1 pt-2", children: [
3918
+ /* @__PURE__ */ jsx10(
3919
+ SettingRow,
3920
+ {
3921
+ label: "Honeypot",
3922
+ description: "Invisible trap field for bots. Inherits the plugin default unless overridden here.",
3923
+ htmlFor: "settings-honeypot",
3924
+ children: /* @__PURE__ */ jsx10(
3925
+ InheritToggle,
3926
+ {
3927
+ id: "settings-honeypot",
3928
+ value: settings.honeypotEnabled,
3929
+ inherited: spamDefaults?.honeypot,
3930
+ onChange: (honeypotEnabled) => updateSettings({ honeypotEnabled })
3931
+ }
3932
+ )
3933
+ }
3934
+ ),
3935
+ /* @__PURE__ */ jsx10(
3936
+ SettingRow,
3937
+ {
3938
+ label: "reCAPTCHA",
3939
+ description: "Challenge-based bot check. Inherits the plugin default unless overridden here.",
3940
+ htmlFor: "settings-captcha",
3941
+ children: /* @__PURE__ */ jsx10(
3942
+ InheritToggle,
3943
+ {
3944
+ id: "settings-captcha",
3945
+ value: settings.captchaEnabled,
3946
+ inherited: spamDefaults?.recaptchaEnabled,
3947
+ onChange: (captchaEnabled) => updateSettings({ captchaEnabled })
3948
+ }
3949
+ )
3950
+ }
3951
+ ),
3952
+ settings.captchaEnabled === true && /* @__PURE__ */ jsx10(
3953
+ SettingRow,
3954
+ {
3955
+ label: "reCAPTCHA site key",
3956
+ description: "The client-facing site key for this form",
3957
+ htmlFor: "settings-captcha-key",
3958
+ children: /* @__PURE__ */ jsx10(
3959
+ Input5,
3960
+ {
3961
+ id: "settings-captcha-key",
3962
+ type: "text",
3963
+ className: "w-72 font-mono",
3964
+ value: settings.captchaSiteKey ?? "",
3965
+ onChange: (e) => updateSettings({
3966
+ captchaSiteKey: e.target.value || void 0
3967
+ })
3968
+ }
3969
+ )
3970
+ }
3971
+ )
3972
+ ] })
3965
3973
  ] })
3966
3974
  ] })
3967
- ] });
3975
+ );
3968
3976
  }
3969
3977
 
3970
3978
  // src/admin/FormBuilderView.tsx
@@ -4157,88 +4165,22 @@ function FormBuilderViewInner({
4157
4165
  count: notifications.length > 0 ? notifications.length : null
4158
4166
  }
4159
4167
  ];
4160
- return /* @__PURE__ */ jsxs10(Fragment4, { children: [
4161
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4 mb-6 px-1", children: [
4162
- /* @__PURE__ */ jsxs10("div", { children: [
4163
- /* @__PURE__ */ jsx11("h1", { className: "text-2xl font-semibold text-foreground tracking-tight", children: isCreating ? "Create Form" : "Edit Form" }),
4164
- /* @__PURE__ */ jsx11("p", { className: "text-sm text-muted-foreground mt-1", children: isCreating ? "Design a new form with drag-and-drop fields." : "Modify your form fields and settings." })
4165
- ] }),
4166
- /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 shrink-0", children: [
4167
- isDirty && // Full-strength warning border so the unsaved-changes badge boundary is perceivable over its tinted fill.
4168
- /* @__PURE__ */ jsx11("span", { className: "text-xs font-medium bg-warning-100 text-warning-700 dark:bg-warning-900 dark:text-warning-100 border border-warning px-2.5 py-1 rounded-none whitespace-nowrap", children: "Unsaved changes" }),
4169
- /* @__PURE__ */ jsx11(
4170
- Button8,
4171
- {
4172
- type: "button",
4173
- variant: "outline",
4174
- size: "sm",
4175
- onClick: handleCancel,
4176
- disabled: isSaving,
4177
- children: "Cancel"
4178
- }
4179
- ),
4168
+ return /* @__PURE__ */ jsxs10(FormLayout, { children: [
4169
+ /* @__PURE__ */ jsxs10("div", { className: "mb-6", children: [
4170
+ /* @__PURE__ */ jsx11("h1", { className: "text-2xl font-semibold text-foreground tracking-tight", children: isCreating ? "Create Form" : "Edit Form" }),
4171
+ /* @__PURE__ */ jsx11("p", { className: "text-sm text-muted-foreground mt-1", children: isCreating ? "Design a new form with drag-and-drop fields." : "Modify your form fields and settings." })
4172
+ ] }),
4173
+ /* @__PURE__ */ jsxs10("div", { className: "border-b border-border space-y-4 pb-4 mb-6", children: [
4174
+ /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-4", children: [
4180
4175
  /* @__PURE__ */ jsx11(
4181
- Button8,
4176
+ FieldShell2,
4182
4177
  {
4183
- type: "button",
4184
- size: "sm",
4185
- onClick: () => {
4186
- void handleSave();
4187
- },
4188
- disabled: isSaving,
4189
- className: "flex items-center gap-1.5",
4190
- children: isSaving ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
4191
- /* @__PURE__ */ jsxs10(
4192
- "svg",
4193
- {
4194
- className: "animate-spin h-3.5 w-3.5",
4195
- viewBox: "0 0 24 24",
4196
- fill: "none",
4197
- children: [
4198
- /* @__PURE__ */ jsx11(
4199
- "circle",
4200
- {
4201
- className: "opacity-25",
4202
- cx: "12",
4203
- cy: "12",
4204
- r: "10",
4205
- stroke: "currentColor",
4206
- strokeWidth: "4"
4207
- }
4208
- ),
4209
- /* @__PURE__ */ jsx11(
4210
- "path",
4211
- {
4212
- className: "opacity-75",
4213
- fill: "currentColor",
4214
- d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
4215
- }
4216
- )
4217
- ]
4218
- }
4219
- ),
4220
- "Saving\u2026"
4221
- ] }) : isCreating ? "Create" : "Save Changes"
4222
- }
4223
- )
4224
- ] })
4225
- ] }),
4226
- /* @__PURE__ */ jsx11("div", { className: "flex border border-border bg-background overflow-hidden", children: /* @__PURE__ */ jsx11("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxs10("div", { className: "w-full px-8 pt-8 pb-12 space-y-6", children: [
4227
- /* @__PURE__ */ jsxs10("div", { className: "bg-background -mx-8 px-8 border-b border-border space-y-4", children: [
4228
- /* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap gap-4", children: [
4229
- /* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-[200px] max-w-sm space-y-1.5", children: [
4230
- /* @__PURE__ */ jsx11(
4231
- "label",
4232
- {
4233
- htmlFor: "form-name",
4234
- className: "text-sm font-medium text-foreground",
4235
- children: "Form Name"
4236
- }
4237
- ),
4238
- /* @__PURE__ */ jsx11(
4178
+ label: "Form Name",
4179
+ htmlFor: "form-name",
4180
+ className: "flex-1 min-w-[200px]",
4181
+ children: /* @__PURE__ */ jsx11(
4239
4182
  Input6,
4240
4183
  {
4241
- id: "form-name",
4242
4184
  type: "text",
4243
4185
  value: formData.name || "",
4244
4186
  onChange: (e) => handleNameChange(e.target.value),
@@ -4246,20 +4188,17 @@ function FormBuilderViewInner({
4246
4188
  className: "bg-transparent"
4247
4189
  }
4248
4190
  )
4249
- ] }),
4250
- /* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-[160px] max-w-xs space-y-1.5", children: [
4251
- /* @__PURE__ */ jsx11(
4252
- "label",
4253
- {
4254
- htmlFor: "form-slug",
4255
- className: "text-sm font-medium text-foreground",
4256
- children: "Slug"
4257
- }
4258
- ),
4259
- /* @__PURE__ */ jsx11(
4191
+ }
4192
+ ),
4193
+ /* @__PURE__ */ jsx11(
4194
+ FieldShell2,
4195
+ {
4196
+ label: "Slug",
4197
+ htmlFor: "form-slug",
4198
+ className: "flex-1 min-w-[160px]",
4199
+ children: /* @__PURE__ */ jsx11(
4260
4200
  Input6,
4261
4201
  {
4262
- id: "form-slug",
4263
4202
  type: "text",
4264
4203
  value: formData.slug || "",
4265
4204
  onChange: (e) => updateFormData({ slug: e.target.value }),
@@ -4267,75 +4206,131 @@ function FormBuilderViewInner({
4267
4206
  className: "bg-transparent placeholder:text-muted-foreground"
4268
4207
  }
4269
4208
  )
4270
- ] }),
4271
- /* @__PURE__ */ jsxs10("div", { className: "w-36 space-y-1.5", children: [
4272
- /* @__PURE__ */ jsx11(
4273
- "label",
4274
- {
4275
- htmlFor: "form-status",
4276
- className: "text-sm font-medium text-foreground",
4277
- children: "Status"
4278
- }
4279
- ),
4280
- /* @__PURE__ */ jsxs10(
4281
- Select8,
4282
- {
4283
- value: formData.status || "draft",
4284
- onValueChange: (value) => updateFormData({
4285
- status: value
4286
- }),
4287
- children: [
4288
- /* @__PURE__ */ jsx11(SelectTrigger8, { id: "form-status", className: "bg-transparent", children: /* @__PURE__ */ jsx11(SelectValue8, { placeholder: "Status" }) }),
4289
- /* @__PURE__ */ jsxs10(SelectContent8, { children: [
4290
- /* @__PURE__ */ jsx11(SelectItem8, { value: "draft", children: "Draft" }),
4291
- /* @__PURE__ */ jsx11(SelectItem8, { value: "published", children: "Published" }),
4292
- /* @__PURE__ */ jsx11(SelectItem8, { value: "closed", children: "Closed" })
4293
- ] })
4294
- ]
4295
- }
4296
- )
4297
- ] })
4298
- ] }),
4299
- /* @__PURE__ */ jsx11(
4300
- Tabs4,
4209
+ }
4210
+ ),
4211
+ /* @__PURE__ */ jsx11("div", { className: "w-36", children: /* @__PURE__ */ jsx11(FieldShell2, { label: "Status", htmlFor: "form-status", children: ({ id, describedBy, invalid }) => /* @__PURE__ */ jsxs10(
4212
+ Select8,
4301
4213
  {
4302
- value: activeTab,
4303
- onValueChange: (v) => setActiveTab(v),
4304
- children: /* @__PURE__ */ jsx11(TabsList4, { className: "bg-transparent justify-start gap-0 -mb-px max-w-full overflow-x-auto", children: mainTabs.map((tab) => /* @__PURE__ */ jsxs10(
4305
- TabsTrigger4,
4214
+ value: formData.status || "draft",
4215
+ onValueChange: (value) => updateFormData({
4216
+ status: value
4217
+ }),
4218
+ children: [
4219
+ /* @__PURE__ */ jsx11(
4220
+ SelectTrigger8,
4221
+ {
4222
+ id,
4223
+ "aria-describedby": describedBy,
4224
+ "aria-invalid": invalid,
4225
+ className: "bg-transparent",
4226
+ children: /* @__PURE__ */ jsx11(SelectValue8, { placeholder: "Status" })
4227
+ }
4228
+ ),
4229
+ /* @__PURE__ */ jsxs10(SelectContent8, { children: [
4230
+ /* @__PURE__ */ jsx11(SelectItem8, { value: "draft", children: "Draft" }),
4231
+ /* @__PURE__ */ jsx11(SelectItem8, { value: "published", children: "Published" }),
4232
+ /* @__PURE__ */ jsx11(SelectItem8, { value: "closed", children: "Closed" })
4233
+ ] })
4234
+ ]
4235
+ }
4236
+ ) }) })
4237
+ ] }),
4238
+ /* @__PURE__ */ jsx11(
4239
+ Tabs4,
4240
+ {
4241
+ value: activeTab,
4242
+ onValueChange: (v) => setActiveTab(v),
4243
+ children: /* @__PURE__ */ jsx11(TabsList4, { className: "bg-transparent justify-start gap-0 max-w-full overflow-x-auto", children: mainTabs.map((tab) => /* @__PURE__ */ jsxs10(
4244
+ TabsTrigger4,
4245
+ {
4246
+ value: tab.value,
4247
+ className: "shrink-0 whitespace-nowrap",
4248
+ children: [
4249
+ tab.label,
4250
+ tab.count !== null && /* @__PURE__ */ jsx11(
4251
+ "span",
4252
+ {
4253
+ className: `inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 text-[10px] font-semibold rounded-sm ml-2 transition-colors ${activeTab === tab.value ? "bg-primary/5 text-primary" : "bg-primary/5 text-muted-foreground"}`,
4254
+ children: tab.count
4255
+ }
4256
+ )
4257
+ ]
4258
+ },
4259
+ tab.value
4260
+ )) })
4261
+ }
4262
+ )
4263
+ ] }),
4264
+ activeTab === "builder" && /* @__PURE__ */ jsx11(
4265
+ FieldCards,
4266
+ {
4267
+ enabledTypes,
4268
+ disabledFieldTypes,
4269
+ onAddField: handleAddField
4270
+ }
4271
+ ),
4272
+ activeTab === "preview" && /* @__PURE__ */ jsx11(FormPreview, { fields, formData }),
4273
+ activeTab === "settings" && /* @__PURE__ */ jsx11(FormSettingsTab, { spamDefaults }),
4274
+ activeTab === "notifications" && /* @__PURE__ */ jsx11(FormNotificationsTab, { defaults: notificationDefaults }),
4275
+ saveError && // Full-strength destructive border so the error box boundary is perceivable over its tinted fill.
4276
+ /* @__PURE__ */ jsx11("div", { className: "mt-6 p-3 text-sm text-destructive bg-destructive/10 border border-destructive rounded-none", children: saveError }),
4277
+ /* @__PURE__ */ jsxs10(FormActions, { dirty: isDirty, children: [
4278
+ /* @__PURE__ */ jsx11(
4279
+ Button8,
4280
+ {
4281
+ type: "button",
4282
+ variant: "outline",
4283
+ size: "sm",
4284
+ onClick: handleCancel,
4285
+ disabled: isSaving,
4286
+ children: "Cancel"
4287
+ }
4288
+ ),
4289
+ /* @__PURE__ */ jsx11(
4290
+ Button8,
4291
+ {
4292
+ type: "button",
4293
+ size: "sm",
4294
+ onClick: () => {
4295
+ void handleSave();
4296
+ },
4297
+ disabled: isSaving,
4298
+ className: "flex items-center gap-1.5",
4299
+ children: isSaving ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
4300
+ /* @__PURE__ */ jsxs10(
4301
+ "svg",
4306
4302
  {
4307
- value: tab.value,
4308
- className: "shrink-0 whitespace-nowrap",
4303
+ className: "animate-spin h-3.5 w-3.5",
4304
+ viewBox: "0 0 24 24",
4305
+ fill: "none",
4309
4306
  children: [
4310
- tab.label,
4311
- tab.count !== null && /* @__PURE__ */ jsx11(
4312
- "span",
4307
+ /* @__PURE__ */ jsx11(
4308
+ "circle",
4309
+ {
4310
+ className: "opacity-25",
4311
+ cx: "12",
4312
+ cy: "12",
4313
+ r: "10",
4314
+ stroke: "currentColor",
4315
+ strokeWidth: "4"
4316
+ }
4317
+ ),
4318
+ /* @__PURE__ */ jsx11(
4319
+ "path",
4313
4320
  {
4314
- className: `inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 text-[10px] font-semibold rounded-sm ml-2 transition-colors ${activeTab === tab.value ? "bg-primary/5 text-primary" : "bg-primary/5 text-muted-foreground"}`,
4315
- children: tab.count
4321
+ className: "opacity-75",
4322
+ fill: "currentColor",
4323
+ d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
4316
4324
  }
4317
4325
  )
4318
4326
  ]
4319
- },
4320
- tab.value
4321
- )) })
4322
- }
4323
- )
4324
- ] }),
4325
- activeTab === "builder" && /* @__PURE__ */ jsx11(
4326
- FieldCards,
4327
- {
4328
- enabledTypes,
4329
- disabledFieldTypes,
4330
- onAddField: handleAddField
4327
+ }
4328
+ ),
4329
+ "Saving\u2026"
4330
+ ] }) : isCreating ? "Create" : "Save Changes"
4331
4331
  }
4332
- ),
4333
- activeTab === "preview" && /* @__PURE__ */ jsx11(FormPreview, { fields, formData }),
4334
- activeTab === "settings" && /* @__PURE__ */ jsx11("div", { className: "w-full", children: /* @__PURE__ */ jsx11(FormSettingsTab, { spamDefaults }) }),
4335
- activeTab === "notifications" && /* @__PURE__ */ jsx11("div", { className: "w-full", children: /* @__PURE__ */ jsx11(FormNotificationsTab, { defaults: notificationDefaults }) }),
4336
- saveError && // Full-strength destructive border so the error box boundary is perceivable over its tinted fill.
4337
- /* @__PURE__ */ jsx11("div", { className: "p-3 text-sm text-destructive bg-destructive/10 border border-destructive rounded-none", children: saveError })
4338
- ] }) }) })
4332
+ )
4333
+ ] })
4339
4334
  ] });
4340
4335
  }
4341
4336
  function FormBuilderView({