UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

1 lines 11.8 kB
{"version":3,"sources":["../src/components/TextArea/TextArea.tsx"],"sourcesContent":["import {\n TextareaHTMLAttributes,\n ReactNode,\n forwardRef,\n useState,\n useId,\n useEffect,\n useRef,\n useImperativeHandle,\n ChangeEvent,\n FocusEvent,\n} from 'react';\nimport { WarningCircleIcon } from '@phosphor-icons/react/dist/csr/WarningCircle';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\n\n/**\n * TextArea size variants\n */\ntype TextAreaSize = 'small' | 'medium' | 'large' | 'extraLarge';\n\n/**\n * TextArea visual state\n */\ntype TextAreaState = 'default' | 'hovered' | 'focused' | 'invalid' | 'disabled';\n\n/**\n * Size configurations with exact pixel specifications\n */\nconst SIZE_CLASSES = {\n small: {\n textarea: 'h-24 text-sm', // 96px height, 14px font\n textSize: 'sm' as const,\n },\n medium: {\n textarea: 'h-24 text-base', // 96px height, 16px font\n textSize: 'md' as const,\n },\n large: {\n textarea: 'h-24 text-lg', // 96px height, 18px font\n textSize: 'lg' as const,\n },\n extraLarge: {\n textarea: 'h-24 text-xl', // 96px height, 20px font\n textSize: 'xl' as const,\n },\n} as const;\n\n/**\n * Base textarea styling classes using design system colors\n */\nconst BASE_TEXTAREA_CLASSES =\n 'w-full box-border p-3 bg-background border border-solid rounded-[4px] resize-none focus:outline-none font-roboto font-normal leading-[150%] placeholder:text-text-600 transition-all duration-200';\n\n/**\n * State-based styling classes using design system colors from styles.css\n */\nconst STATE_CLASSES = {\n default: {\n base: 'border-border-300 bg-background text-text-600',\n hover: 'hover:border-border-400',\n focus: 'focus:border-border-500',\n },\n hovered: {\n base: 'border-border-400 bg-background text-text-600',\n hover: '',\n focus: 'focus:border-border-500',\n },\n focused: {\n base: 'border-2 border-primary-950 bg-background text-text-900',\n hover: '',\n focus: '',\n },\n invalid: {\n base: 'border-2 border-red-700 bg-white text-gray-800',\n hover: 'hover:border-red-700',\n focus: 'focus:border-red-700',\n },\n disabled: {\n base: 'border-border-300 bg-background text-text-600 cursor-not-allowed opacity-40',\n hover: '',\n focus: '',\n },\n} as const;\n\n/**\n * TextArea component props interface\n */\nexport type TextAreaProps = {\n /** Label text to display above the textarea */\n label?: ReactNode;\n /** Size variant of the textarea */\n size?: TextAreaSize;\n /** Visual state of the textarea */\n state?: TextAreaState;\n /** Error message to display */\n errorMessage?: string;\n /** Helper text to display */\n helperMessage?: string;\n /** Additional CSS classes */\n className?: string;\n /** Label CSS classes */\n labelClassName?: string;\n /** Show character count when maxLength is provided */\n showCharacterCount?: boolean;\n /** Enable auto-resize based on content */\n autoResize?: boolean;\n /** Minimum height when autoResize is enabled (default: 96px) */\n minHeight?: number;\n} & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>;\n\n/**\n * TextArea component for Analytica Ensino platforms\n *\n * A textarea component with essential states, sizes and themes.\n * Uses exact design specifications with 288px width, 96px height, and specific\n * color values. Includes Text component integration for consistent typography.\n *\n * @example\n * ```tsx\n * // Basic textarea\n * <TextArea label=\"Description\" placeholder=\"Enter description...\" />\n *\n * // Small size\n * <TextArea size=\"small\" label=\"Comment\" />\n *\n * // Invalid state\n * <TextArea state=\"invalid\" label=\"Required field\" errorMessage=\"This field is required\" />\n *\n * // Disabled state\n * <TextArea disabled label=\"Read-only field\" />\n *\n * // Auto-resize textarea\n * <TextArea autoResize minHeight={200} placeholder=\"Grows with content...\" />\n * ```\n */\nconst TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(\n (\n {\n label,\n size = 'medium',\n state = 'default',\n errorMessage,\n helperMessage,\n className = '',\n labelClassName = '',\n disabled,\n id,\n onChange,\n placeholder,\n required,\n showCharacterCount = false,\n maxLength,\n value,\n autoResize = false,\n minHeight = 96,\n ...props\n },\n ref\n ) => {\n // Generate unique ID if not provided\n const generatedId = useId();\n const inputId = id ?? `textarea-${generatedId}`;\n\n // Internal ref for auto-resize\n const internalRef = useRef<HTMLTextAreaElement>(null);\n\n // Expose ref to parent\n useImperativeHandle(ref, () => internalRef.current as HTMLTextAreaElement);\n\n // Internal state for focus tracking\n const [isFocused, setIsFocused] = useState(false);\n\n // Calculate current character count\n const currentLength = typeof value === 'string' ? value.length : 0;\n const isNearLimit = maxLength && currentLength >= maxLength * 0.8;\n\n // Auto-resize effect\n useEffect(() => {\n if (autoResize && internalRef.current) {\n const textarea = internalRef.current;\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.max(textarea.scrollHeight, minHeight)}px`;\n }\n }, [autoResize, minHeight, value]);\n\n // Handle change events\n const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {\n onChange?.(event);\n };\n\n // Handle focus events\n const handleFocus = (event: FocusEvent<HTMLTextAreaElement>) => {\n setIsFocused(true);\n props.onFocus?.(event);\n };\n\n // Handle blur events\n const handleBlur = (event: FocusEvent<HTMLTextAreaElement>) => {\n setIsFocused(false);\n props.onBlur?.(event);\n };\n\n // Determine current state based on props and focus\n let currentState = disabled ? 'disabled' : state;\n\n // Override state based on focus\n if (\n isFocused &&\n currentState !== 'invalid' &&\n currentState !== 'disabled'\n ) {\n currentState = 'focused';\n }\n\n // Get size classes\n const sizeClasses = SIZE_CLASSES[size];\n\n // Get styling classes\n const stateClasses = STATE_CLASSES[currentState];\n\n // Get height classes based on autoResize\n const heightClasses = autoResize\n ? 'h-auto overflow-hidden'\n : sizeClasses.textarea;\n\n // Get font size from size classes (extract only the text size)\n const fontSizeClass =\n sizeClasses.textarea.split(' ').find((c) => c.startsWith('text-')) ??\n 'text-base';\n\n // Get final textarea classes\n const textareaClasses = cn(\n BASE_TEXTAREA_CLASSES,\n autoResize ? fontSizeClass : sizeClasses.textarea,\n heightClasses,\n stateClasses.base,\n stateClasses.hover,\n stateClasses.focus,\n className\n );\n\n return (\n <div className={`flex flex-col`}>\n {/* Label */}\n {label && (\n <Text\n as=\"label\"\n htmlFor={inputId}\n size={sizeClasses.textSize}\n weight=\"medium\"\n color=\"text-text-950\"\n className={cn('mb-1.5', labelClassName)}\n >\n {label}{' '}\n {required && <span className=\"text-indicator-error\">*</span>}\n </Text>\n )}\n\n {/* Textarea */}\n <textarea\n ref={internalRef}\n id={inputId}\n disabled={disabled}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n className={textareaClasses}\n placeholder={placeholder}\n required={required}\n maxLength={maxLength}\n value={value}\n {...props}\n />\n\n {/* Error message */}\n {errorMessage && (\n <p className=\"flex gap-1 items-center text-sm text-indicator-error mt-1.5\">\n <WarningCircleIcon size={16} /> {errorMessage}\n </p>\n )}\n\n {/* Helper text or Character count */}\n {!errorMessage && showCharacterCount && maxLength && (\n <Text\n size=\"sm\"\n weight=\"normal\"\n className={`mt-1.5 ${isNearLimit ? 'text-indicator-warning' : 'text-text-500'}`}\n >\n {currentLength}/{maxLength} caracteres\n </Text>\n )}\n {!errorMessage &&\n helperMessage &&\n !(showCharacterCount && maxLength) && (\n <Text size=\"sm\" weight=\"normal\" className=\"mt-1.5 text-text-500\">\n {helperMessage}\n </Text>\n )}\n </div>\n );\n }\n);\n\nTextArea.displayName = 'TextArea';\n\nexport default TextArea;\n"],"mappings":"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","names":[]}