mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-26 11:48:27 -05:00
refactor: extract styling field components into separate files
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { ColorPicker } from "@/modules/ui/components/color-picker";
|
||||
import { FormControl, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
|
||||
|
||||
interface ColorFieldProps {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
containerClass?: string;
|
||||
}
|
||||
|
||||
export const ColorField = ({ form, name, label, containerClass }: ColorFieldProps) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<ColorPicker
|
||||
color={field.value}
|
||||
onChange={(color) => field.onChange(color)}
|
||||
containerClass={containerClass || "w-full"}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,74 @@
|
||||
"use client";
|
||||
|
||||
import { FormControl, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
|
||||
interface DimensionInputProps {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export const DimensionInput = ({ form, name, label, placeholder }: DimensionInputProps) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => {
|
||||
const value = field.value;
|
||||
let unit = "px";
|
||||
if (typeof value === "string") {
|
||||
if (value.endsWith("%")) unit = "%";
|
||||
else if (value.endsWith("rem")) unit = "rem";
|
||||
else if (value.endsWith("em")) unit = "em";
|
||||
}
|
||||
const numericValue = typeof value === "string" ? Number.parseFloat(value) : value;
|
||||
|
||||
return (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<div className="flex rounded-md shadow-xs">
|
||||
<Input
|
||||
type="number"
|
||||
{...field}
|
||||
value={numericValue ?? ""}
|
||||
onChange={(e) => {
|
||||
const valStr = e.target.value;
|
||||
if (valStr === "") {
|
||||
field.onChange(null);
|
||||
return;
|
||||
}
|
||||
const newVal = Number.parseFloat(valStr);
|
||||
if (Number.isNaN(newVal)) {
|
||||
return;
|
||||
}
|
||||
field.onChange(unit === "px" ? newVal : `${newVal}${unit}`);
|
||||
}}
|
||||
className="flex-1 rounded-r-none border-r-0 text-xs focus-visible:ring-0"
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
<select
|
||||
value={unit}
|
||||
onChange={(e) => {
|
||||
const newUnit = e.target.value;
|
||||
const currentVal = numericValue ?? 0;
|
||||
if (newUnit === "px") {
|
||||
field.onChange(currentVal);
|
||||
} else {
|
||||
field.onChange(`${currentVal}${newUnit}`);
|
||||
}
|
||||
}}
|
||||
className="ring-offset-background placeholder:text-muted-foreground focus:border-brand-dark h-10 items-center justify-between rounded-r-md border border-slate-300 bg-white pr-8 pl-3 text-xs font-medium focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50">
|
||||
<option value="px">px</option>
|
||||
<option value="%">%</option>
|
||||
<option value="rem">rem</option>
|
||||
<option value="em">em</option>
|
||||
</select>
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,39 @@
|
||||
"use client";
|
||||
|
||||
import { FormControl, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
|
||||
interface NumberFieldProps {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
step?: number;
|
||||
max?: number;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
export const NumberField = ({ form, name, label, step = 1, max, placeholder }: NumberFieldProps) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
const val = e.target.valueAsNumber;
|
||||
field.onChange(Number.isNaN(val) ? null : val);
|
||||
}}
|
||||
step={step}
|
||||
max={max}
|
||||
className="text-xs"
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { FormControl, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
|
||||
interface TextFieldProps {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const TextField = ({ form, name, label }: TextFieldProps) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" {...field} className="text-xs" />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
@@ -3,21 +3,20 @@
|
||||
import { useAutoAnimate } from "@formkit/auto-animate/react";
|
||||
import { ChevronDown, ChevronRight } from "lucide-react";
|
||||
import React from "react";
|
||||
import { ColorPicker } from "@/modules/ui/components/color-picker";
|
||||
import { FormControl, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
|
||||
export const StylingSection = ({
|
||||
title,
|
||||
open,
|
||||
setOpen,
|
||||
children,
|
||||
}: {
|
||||
export { ColorField } from "./components/color-field";
|
||||
export { DimensionInput } from "./components/dimension-input";
|
||||
export { NumberField } from "./components/number-field";
|
||||
export { TextField } from "./components/text-field";
|
||||
|
||||
interface StylingSectionProps {
|
||||
title: string;
|
||||
open: boolean;
|
||||
setOpen: (o: boolean) => void;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
}
|
||||
|
||||
export const StylingSection = ({ title, open, setOpen, children }: StylingSectionProps) => {
|
||||
const [parent] = useAutoAnimate();
|
||||
|
||||
return (
|
||||
@@ -33,160 +32,3 @@ export const StylingSection = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ColorField = ({
|
||||
form,
|
||||
name,
|
||||
label,
|
||||
containerClass,
|
||||
}: {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
containerClass?: string;
|
||||
}) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<ColorPicker
|
||||
color={field.value}
|
||||
onChange={(color) => field.onChange(color)}
|
||||
containerClass={containerClass || "w-full"}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
export const NumberField = ({
|
||||
form,
|
||||
name,
|
||||
label,
|
||||
step = 1,
|
||||
max,
|
||||
placeholder,
|
||||
}: {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
step?: number;
|
||||
max?: number;
|
||||
placeholder?: string;
|
||||
}) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
const val = e.target.valueAsNumber;
|
||||
field.onChange(Number.isNaN(val) ? null : val);
|
||||
}}
|
||||
step={step}
|
||||
max={max}
|
||||
className="text-xs"
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
export const DimensionInput = ({
|
||||
form,
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
}: {
|
||||
form: any;
|
||||
name: string;
|
||||
label: string;
|
||||
placeholder?: string;
|
||||
}) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => {
|
||||
const value = field.value;
|
||||
let unit = "px";
|
||||
if (typeof value === "string") {
|
||||
if (value.endsWith("%")) unit = "%";
|
||||
else if (value.endsWith("rem")) unit = "rem";
|
||||
else if (value.endsWith("em")) unit = "em";
|
||||
}
|
||||
const numericValue = typeof value === "string" ? Number.parseFloat(value) : value;
|
||||
|
||||
return (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<div className="flex rounded-md shadow-xs">
|
||||
<Input
|
||||
type="number"
|
||||
{...field}
|
||||
value={numericValue ?? ""}
|
||||
onChange={(e) => {
|
||||
const valStr = e.target.value;
|
||||
if (valStr === "") {
|
||||
field.onChange(null);
|
||||
return;
|
||||
}
|
||||
const newVal = Number.parseFloat(valStr);
|
||||
if (Number.isNaN(newVal)) {
|
||||
return;
|
||||
}
|
||||
field.onChange(unit === "px" ? newVal : `${newVal}${unit}`);
|
||||
}}
|
||||
className="flex-1 rounded-r-none border-r-0 text-xs focus-visible:ring-0"
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
<select
|
||||
value={unit}
|
||||
onChange={(e) => {
|
||||
const newUnit = e.target.value;
|
||||
const currentVal = numericValue ?? 0;
|
||||
if (newUnit === "px") {
|
||||
field.onChange(currentVal);
|
||||
} else {
|
||||
field.onChange(`${currentVal}${newUnit}`);
|
||||
}
|
||||
}}
|
||||
className="ring-offset-background placeholder:text-muted-foreground focus:border-brand-dark h-10 items-center justify-between rounded-r-md border border-slate-300 bg-white pr-8 pl-3 text-xs font-medium focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 focus:outline-hidden disabled:cursor-not-allowed disabled:opacity-50">
|
||||
<option value="px">px</option>
|
||||
<option value="%">%</option>
|
||||
<option value="rem">rem</option>
|
||||
<option value="em">em</option>
|
||||
</select>
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const TextField = ({ form, name, label }: { form: any; name: string; label: string }) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel className="text-xs">{label}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" {...field} className="text-xs" />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user