import { cva, type VariantProps } from 'class-variance-authority'; import { DISABLED_CURSOR, TRANSITION_COLORS } from '../../styles/constants'; export const textareaRootVariants = cva( [ // Multiline shell: stretch the field to full width and let the shell grow with it // (no fixed height, no overflow-hidden so a web resize handle is never clipped). 'w-full flex-row items-stretch', 'bg-surface-primary', 'border-solid border-stroke-primary', 'web:border-default native:border-[length:var(--border-width-default)]', 'rounded-[var(--border-radius-default)]', TRANSITION_COLORS, 'data-[disabled=true]:bg-surface-secondary', 'data-[disabled=true]:opacity-[var(--opacity-disabled)]', DISABLED_CURSOR, 'data-[readonly=true]:cursor-default', 'data-[readonly=true]:bg-surface-secondary', 'web:data-[hover=true]:data-[focus=false]:data-[invalid=false]:border-stroke-hover', // Web: inset ring avoids a border-width change so the shell never shifts on focus. // Recolor the border to match the ring so the two read as a single focus outline // instead of a gray border + colored ring. 'web:data-[focus=true]:ring-inset', 'web:data-[focus=true]:ring-[length:var(--border-width-focused)]', 'web:data-[focus=true]:data-[invalid=false]:ring-stroke-action', 'web:data-[focus=true]:data-[invalid=false]:border-stroke-action', 'web:data-[focus=true]:data-[invalid=true]:ring-stroke-danger', 'web:data-[focus=true]:data-[invalid=true]:border-stroke-danger', // Native: thicker border on focus; size variants subtract a hairline of padding // so layout doesn't shift by 1px. 'native:data-[focus=true]:border-[length:var(--border-width-focused)]', 'native:data-[field-state=focused]:border-stroke-action', 'native:data-[field-state=focused-invalid]:border-stroke-danger', 'data-[invalid=true]:border-stroke-danger', ], { variants: { variant: { outline: [], }, size: { default: [ 'px-4 py-3 gap-4', 'native:data-[focus=true]:px-[calc(var(--spacing-4)-var(--spacing-px))]', 'native:data-[focus=true]:py-[calc(var(--spacing-3)-var(--spacing-px))]', ], small: [ 'px-3 py-2 gap-1.5', 'native:data-[focus=true]:px-[calc(var(--spacing-3)-var(--spacing-px))]', 'native:data-[focus=true]:py-[calc(var(--spacing-2)-var(--spacing-px))]', ], }, }, defaultVariants: { variant: 'outline', size: 'default', }, }, ); export const textareaFieldVariants = cva( [ // `min-w-0` lets the field shrink below its intrinsic content width so the shell // never overflows (mirrors the Input field rationale). 'flex-1 min-w-0 bg-transparent p-0', 'text-content-primary', 'placeholder:text-content-tertiary', 'web:outline-none', 'tracking-normal', ], { variants: { size: { default: 'text-[0.875rem]', small: 'text-[0.75rem]', }, }, defaultVariants: { size: 'default', }, }, ); export const textareaFieldPlaceholderVariants = cva(['accent-content-tertiary']); export type TextareaVariantProps = VariantProps;