From acc305ff21cf40a5959c99e9d57bfdcf45d6dcb7 Mon Sep 17 00:00:00 2001 From: Rodribm10 Date: Mon, 13 Apr 2026 23:10:00 -0300 Subject: [PATCH] feat: migra FormField e SelectField com paleta premium + componente Button base com variantes premium --- src/components/FormField.tsx | 43 +++++++++++++++++++++ src/components/SelectField.tsx | 69 ++++++++++++++++++++++++++++++++++ src/components/ui/button.tsx | 48 +++++++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 src/components/FormField.tsx create mode 100644 src/components/SelectField.tsx create mode 100644 src/components/ui/button.tsx diff --git a/src/components/FormField.tsx b/src/components/FormField.tsx new file mode 100644 index 0000000..f7a91fb --- /dev/null +++ b/src/components/FormField.tsx @@ -0,0 +1,43 @@ +import { forwardRef, type InputHTMLAttributes } from 'react' +import { cn } from '@/lib/utils' + +interface FormFieldProps extends InputHTMLAttributes { + label: string + error?: string + required?: boolean +} + +export const FormField = forwardRef( + ({ label, error, required, className, id, ...props }, ref) => { + const inputId = id ?? `field-${label.toLowerCase().replace(/\s+/g, '-')}` + + return ( +
+ + + {error && {error}} +
+ ) + } +) + +FormField.displayName = 'FormField' diff --git a/src/components/SelectField.tsx b/src/components/SelectField.tsx new file mode 100644 index 0000000..4def228 --- /dev/null +++ b/src/components/SelectField.tsx @@ -0,0 +1,69 @@ +import { forwardRef, type SelectHTMLAttributes } from 'react' +import { ChevronDown } from 'lucide-react' +import { cn } from '@/lib/utils' + +interface Option { + value: string + label: string +} + +interface SelectFieldProps extends Omit, 'children'> { + label: string + options: Option[] + placeholder?: string + error?: string + required?: boolean +} + +export const SelectField = forwardRef( + ( + { label, options, placeholder = 'Selecione...', error, required, className, id, ...props }, + ref + ) => { + const selectId = id ?? `select-${label.toLowerCase().replace(/\s+/g, '-')}` + + return ( +
+ +
+ + +
+ {error && {error}} +
+ ) + } +) + +SelectField.displayName = 'SelectField' diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..2ac683a --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,48 @@ +import { forwardRef, type ButtonHTMLAttributes } from 'react' +import { Slot } from '@radix-ui/react-slot' +import { cva, type VariantProps } from 'class-variance-authority' +import { cn } from '@/lib/utils' + +const buttonVariants = cva( + 'inline-flex items-center justify-center gap-2 rounded-lg font-sans font-semibold transition-all duration-200 disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-champagne/60', + { + variants: { + variant: { + primary: + 'bg-gradient-to-r from-champagne to-rose-gold text-obsidian hover:glow-champagne hover:scale-[1.02]', + secondary: + 'border border-champagne/30 bg-midnight/60 text-ivory hover:border-champagne hover:glow-champagne', + ghost: 'text-champagne hover:bg-champagne/10', + destructive: 'bg-ruby text-ivory hover:bg-ruby/90', + }, + size: { + sm: 'h-9 px-4 text-sm', + md: 'h-11 px-6 text-base', + lg: 'h-14 px-8 text-lg', + }, + }, + defaultVariants: { + variant: 'primary', + size: 'md', + }, + } +) + +interface ButtonProps + extends ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +export const Button = forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button' + return ( + + ) + } +) + +Button.displayName = 'Button' + +export { buttonVariants }