147 lines
4.8 KiB
TypeScript
147 lines
4.8 KiB
TypeScript
import type { ValidComponent } from "solid-js";
|
|
import { mergeProps, splitProps } from "solid-js";
|
|
|
|
import type { PolymorphicProps } from "@kobalte/core";
|
|
import * as TextFieldPrimitive from "@kobalte/core/text-field";
|
|
import { cva } from "class-variance-authority";
|
|
|
|
import { cn } from "~/lib/utils";
|
|
|
|
type TextFieldRootProps<T extends ValidComponent = "div"> = TextFieldPrimitive.TextFieldRootProps<T> & {
|
|
class?: string | undefined;
|
|
};
|
|
|
|
const TextField = <T extends ValidComponent = "div">(props: PolymorphicProps<T, TextFieldRootProps<T>>) => {
|
|
const [local, others] = splitProps(props as TextFieldRootProps, ["class"]);
|
|
return (
|
|
<TextFieldPrimitive.Root
|
|
class={cn("flex flex-col gap-1", local.class)}
|
|
{...others}
|
|
/>
|
|
);
|
|
};
|
|
|
|
type TextFieldInputProps<T extends ValidComponent = "input"> = TextFieldPrimitive.TextFieldInputProps<T> & {
|
|
class?: string | undefined;
|
|
type?:
|
|
| "button"
|
|
| "checkbox"
|
|
| "color"
|
|
| "date"
|
|
| "datetime-local"
|
|
| "email"
|
|
| "file"
|
|
| "hidden"
|
|
| "image"
|
|
| "month"
|
|
| "number"
|
|
| "password"
|
|
| "radio"
|
|
| "range"
|
|
| "reset"
|
|
| "search"
|
|
| "submit"
|
|
| "tel"
|
|
| "text"
|
|
| "time"
|
|
| "url"
|
|
| "week";
|
|
};
|
|
|
|
const TextFieldInput = <T extends ValidComponent = "input">(rawProps: PolymorphicProps<T, TextFieldInputProps<T>>) => {
|
|
const props = mergeProps<TextFieldInputProps<T>[]>({ type: "text" }, rawProps);
|
|
const [local, others] = splitProps(props as TextFieldInputProps, ["type", "class"]);
|
|
return (
|
|
<TextFieldPrimitive.Input
|
|
type={local.type}
|
|
class={cn(
|
|
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[invalid]:border-error-foreground data-[invalid]:text-error-foreground",
|
|
local.class,
|
|
)}
|
|
{...others}
|
|
/>
|
|
);
|
|
};
|
|
|
|
type TextFieldTextAreaProps<T extends ValidComponent = "textarea"> = TextFieldPrimitive.TextFieldTextAreaProps<T> & {
|
|
class?: string | undefined;
|
|
};
|
|
|
|
const TextFieldTextArea = <T extends ValidComponent = "textarea">(
|
|
props: PolymorphicProps<T, TextFieldTextAreaProps<T>>,
|
|
) => {
|
|
const [local, others] = splitProps(props as TextFieldTextAreaProps, ["class"]);
|
|
return (
|
|
<TextFieldPrimitive.TextArea
|
|
class={cn(
|
|
"flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
local.class,
|
|
)}
|
|
{...others}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const labelVariants = cva(
|
|
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
{
|
|
variants: {
|
|
variant: {
|
|
label: "data-[invalid]:text-destructive",
|
|
description: "font-normal text-muted-foreground",
|
|
error: "text-xs text-destructive",
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: "label",
|
|
},
|
|
},
|
|
);
|
|
|
|
type TextFieldLabelProps<T extends ValidComponent = "label"> = TextFieldPrimitive.TextFieldLabelProps<T> & {
|
|
class?: string | undefined;
|
|
};
|
|
|
|
const TextFieldLabel = <T extends ValidComponent = "label">(props: PolymorphicProps<T, TextFieldLabelProps<T>>) => {
|
|
const [local, others] = splitProps(props as TextFieldLabelProps, ["class"]);
|
|
return (
|
|
<TextFieldPrimitive.Label
|
|
class={cn(labelVariants(), local.class)}
|
|
{...others}
|
|
/>
|
|
);
|
|
};
|
|
|
|
type TextFieldDescriptionProps<T extends ValidComponent = "div"> = TextFieldPrimitive.TextFieldDescriptionProps<T> & {
|
|
class?: string | undefined;
|
|
};
|
|
|
|
const TextFieldDescription = <T extends ValidComponent = "div">(
|
|
props: PolymorphicProps<T, TextFieldDescriptionProps<T>>,
|
|
) => {
|
|
const [local, others] = splitProps(props as TextFieldDescriptionProps, ["class"]);
|
|
return (
|
|
<TextFieldPrimitive.Description
|
|
class={cn(labelVariants({ variant: "description" }), local.class)}
|
|
{...others}
|
|
/>
|
|
);
|
|
};
|
|
|
|
type TextFieldErrorMessageProps<T extends ValidComponent = "div"> = TextFieldPrimitive.TextFieldErrorMessageProps<T> & {
|
|
class?: string | undefined;
|
|
};
|
|
|
|
const TextFieldErrorMessage = <T extends ValidComponent = "div">(
|
|
props: PolymorphicProps<T, TextFieldErrorMessageProps<T>>,
|
|
) => {
|
|
const [local, others] = splitProps(props as TextFieldErrorMessageProps, ["class"]);
|
|
return (
|
|
<TextFieldPrimitive.ErrorMessage
|
|
class={cn(labelVariants({ variant: "error" }), local.class)}
|
|
{...others}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export { TextField, TextFieldDescription, TextFieldErrorMessage, TextFieldInput, TextFieldLabel, TextFieldTextArea };
|