Files
Primora/apps/frontend/src/components/Input.tsx
T
Tomas DvorakandDevin 420502eec1 feat: ship phase 1 surface area (v0.2.0)
- primora CLI + @primora/mcp server over generated client
- auth users admin panel, mobile bottom nav
- release workflow: GHCR images, compiled binaries, npm tarballs
- fix gzip Content-Length truncation, nginx upstream re-resolution

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-16 14:04:43 +02:00

120 lines
3.3 KiB
TypeScript

import { type JSX, For, Show, splitProps } from "solid-js";
interface InputProps extends JSX.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
size?: "sm" | "md" | "lg";
}
const sizeClasses = {
sm: "input-sm",
md: "",
lg: "input-lg",
};
export function Input(props: InputProps) {
const [local, rest] = splitProps(props, ["label", "error", "size", "class"]);
const size = () => local.size ?? "md";
return (
<div class="w-full">
<Show when={local.label}>
<label class="label">{local.label}</label>
</Show>
<input
class={`input ${sizeClasses[size()]} ${local.error ? "border-error focus:border-error focus:ring-error/20" : ""} ${local.class ?? ""}`}
{...rest}
/>
<Show when={local.error}>
<p class="mt-1 text-xs text-error">{local.error}</p>
</Show>
</div>
);
}
interface TextareaProps extends JSX.TextareaHTMLAttributes<HTMLTextAreaElement> {
label?: string;
error?: string;
}
export function Textarea(props: TextareaProps) {
const [local, rest] = splitProps(props, ["label", "error", "class"]);
return (
<div class="w-full">
<Show when={local.label}>
<label class="label">{local.label}</label>
</Show>
<textarea
class={`textarea ${local.error ? "border-error focus:border-error focus:ring-error/20" : ""} ${local.class ?? ""}`}
{...rest}
/>
<Show when={local.error}>
<p class="mt-1 text-xs text-error">{local.error}</p>
</Show>
</div>
);
}
interface SelectProps extends JSX.SelectHTMLAttributes<HTMLSelectElement> {
label?: string;
error?: string;
options?: { value: string; label: string; disabled?: boolean }[];
}
export function Select(props: SelectProps) {
const [local, rest] = splitProps(props, ["label", "error", "options", "children", "class"]);
return (
<div class="w-full">
<Show when={local.label}>
<label class="label">{local.label}</label>
</Show>
<select
class={`select ${local.error ? "border-error focus:border-error focus:ring-error/20" : ""} ${local.class ?? ""}`}
{...rest}
>
<Show when={local.options}>
<For each={local.options}>
{(option) => (
<option value={option.value} disabled={option.disabled}>
{option.label}
</option>
)}
</For>
</Show>
{local.children}
</select>
<Show when={local.error}>
<p class="mt-1 text-xs text-error">{local.error}</p>
</Show>
</div>
);
}
interface FileInputProps extends JSX.InputHTMLAttributes<HTMLInputElement> {
label?: string;
error?: string;
}
export function FileInput(props: FileInputProps) {
const [local, rest] = splitProps(props, ["label", "error", "class"]);
return (
<div class="w-full">
<Show when={local.label}>
<label class="label">{local.label}</label>
</Show>
<input
type="file"
class={`input cursor-pointer file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:text-sm file:font-medium file:bg-surface-2 file:text-text-2 hover:file:bg-surface-3 ${local.error ? "border-error" : ""} ${local.class ?? ""}`}
{...rest}
/>
<Show when={local.error}>
<p class="mt-1 text-xs text-error">{local.error}</p>
</Show>
</div>
);
}