Phase 2
Base app architecture:
Route groups for customer, staff and owner.
* Reusable design system with around 20 UI components.
* Complete Prisma schema.
* Authentication with email/password and Google.
* Role and permission model.
* Protected routes.
* Clean separation between features, services, components and shared utilities.
This commit is contained in:
201 files changed
+31984
No files matched your search
@@ -0,0 +1,57 @@
|
||||
import { forwardRef, useId } from "react";
|
||||
import type { TextareaHTMLAttributes } from "react";
|
||||
import { cn } from "@/lib/utils/cn";
|
||||
|
||||
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
||||
label?: string;
|
||||
error?: string;
|
||||
hint?: string;
|
||||
}
|
||||
|
||||
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, label, error, hint, id, required, rows = 4, ...props }, ref) => {
|
||||
const generatedId = useId();
|
||||
const textareaId = id ?? generatedId;
|
||||
const hintId = hint ? `${textareaId}-hint` : undefined;
|
||||
const errorId = error ? `${textareaId}-error` : undefined;
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
{label && (
|
||||
<label
|
||||
htmlFor={textareaId}
|
||||
className="mb-2 ml-1 block text-[10px] font-bold uppercase tracking-widest text-muted"
|
||||
>
|
||||
{label}
|
||||
{required && <span aria-hidden="true"> *</span>}
|
||||
</label>
|
||||
)}
|
||||
<textarea
|
||||
ref={ref}
|
||||
id={textareaId}
|
||||
rows={rows}
|
||||
required={required}
|
||||
aria-invalid={!!error || undefined}
|
||||
aria-describedby={cn(hintId, errorId) || undefined}
|
||||
className={cn(
|
||||
"w-full resize-none rounded-xl border border-line bg-white p-4 text-sm outline-none transition-all placeholder:text-muted focus:ring-2 focus:ring-ink",
|
||||
error && "border-red-300 focus:ring-red-400",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
{hint && !error && (
|
||||
<p id={hintId} className="mt-1.5 ml-1 text-xs text-muted">
|
||||
{hint}
|
||||
</p>
|
||||
)}
|
||||
{error && (
|
||||
<p id={errorId} role="alert" className="mt-1.5 ml-1 text-xs font-medium text-red-500">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
Textarea.displayName = "Textarea";
|
||||
Reference in new issue
Block a user