Initial commit for new panel
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import { ChevronUpIcon } from "@/assets/icons";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useId, useState } from "react";
|
||||
import {
|
||||
type FieldErrors,
|
||||
type FieldValues,
|
||||
type Path,
|
||||
type UseFormRegister,
|
||||
type UseFormRegisterReturn,
|
||||
} from "react-hook-form";
|
||||
|
||||
type PropsType<T extends FieldValues> = {
|
||||
name: Path<T>;
|
||||
label: string;
|
||||
items: { value: string; label: string }[];
|
||||
prefixIcon?: React.ReactNode;
|
||||
className?: string;
|
||||
register?: UseFormRegister<T>;
|
||||
errors?: FieldErrors<T>;
|
||||
required?: boolean;
|
||||
} & (
|
||||
| { placeholder?: string; defaultValue: string }
|
||||
| { placeholder: string; defaultValue?: string }
|
||||
) &
|
||||
Partial<UseFormRegisterReturn>;
|
||||
|
||||
export function Select<T extends FieldValues>({
|
||||
items,
|
||||
label,
|
||||
defaultValue,
|
||||
placeholder,
|
||||
prefixIcon,
|
||||
className,
|
||||
name,
|
||||
register,
|
||||
errors,
|
||||
required,
|
||||
onChange,
|
||||
onBlur,
|
||||
ref,
|
||||
...props
|
||||
}: PropsType<T>) {
|
||||
const id = useId();
|
||||
|
||||
const [isOptionSelected, setIsOptionSelected] = useState(!!defaultValue);
|
||||
const error = errors && errors[name];
|
||||
|
||||
return (
|
||||
<div className={cn("space-y-3", className)}>
|
||||
<label
|
||||
htmlFor={id}
|
||||
className="block text-body-sm font-medium text-dark dark:text-white"
|
||||
>
|
||||
{label}
|
||||
{required && <span className="text-red ml-1 select-none">*</span>}
|
||||
</label>
|
||||
|
||||
<div className="relative">
|
||||
{prefixIcon && (
|
||||
<div className="absolute left-4 top-1/2 -translate-y-1/2">
|
||||
{prefixIcon}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<select
|
||||
id={id}
|
||||
name={name}
|
||||
ref={ref}
|
||||
defaultValue={defaultValue || ""}
|
||||
onChange={(e) => {
|
||||
setIsOptionSelected(!!e.target.value);
|
||||
onChange?.(e);
|
||||
}}
|
||||
onBlur={onBlur}
|
||||
className={cn(
|
||||
"w-full appearance-none rounded-lg border border-stroke bg-transparent px-5.5 py-3 outline-none transition focus:border-primary active:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary [&>option]:text-dark-5 dark:[&>option]:text-dark-6",
|
||||
isOptionSelected && "text-dark dark:text-white",
|
||||
error && "border-red focus:border-red dark:border-red",
|
||||
prefixIcon && "pl-11.5",
|
||||
)}
|
||||
>
|
||||
{placeholder && (
|
||||
<option value="" disabled hidden>
|
||||
{placeholder}
|
||||
</option>
|
||||
)}
|
||||
|
||||
{items.map((item) => (
|
||||
<option key={item.value} value={item.value}>
|
||||
{item.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<ChevronUpIcon className="pointer-events-none absolute right-4 top-1/2 -translate-y-1/2 rotate-180" />
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<p className="text-red mt-1.5 text-sm">{error.message as string}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user