import Block from '../../Primitives/Block/Block' import PrimitiveTextarea from '../../Primitives/PrimitiveTextArea' import InputLabelsV2 from '../utils/InputLabels/InputLabelsV2' import InputFooterV2 from '../utils/InputFooter/InputFooterV2' import type { TextAreaV2Props } from './TextAreaV2.types' import type { TextAreaV2TokensType } from './TextAreaV2.tokens' import { useResponsiveTokens } from '../../../hooks/useResponsiveTokens' import { useState, useId, forwardRef, useMemo } from 'react' import { useBreakpoints } from '../../../hooks/useBreakPoints' import { BREAKPOINTS } from '../../../breakpoints/breakPoints' import { filterBlockedProps } from '../../../utils/prop-helpers' import FloatingLabelsV2 from '../utils/FloatingLabelsV2/FloatingLabelsV2' import { InputSizeV2, type AnyRef } from '../inputV2.types' import { FOCUS_RING_STYLES, TRANSITION } from '../TextInputV2/utils' import { generateAccessibilityIds, setExternalRef } from '../utils/utils' import { addPxToValue, toPixels } from '../../../global-utils/GlobalUtils' import { getTextAreaAriaDescribedBy, getTextAreaInputPadding, getTextAreaInteractionKeys, getTextAreaLabelState, getTextAreaV2MinHeightFromRows, omitTextAreaV2PrivateProps, } from './utils' const TextAreaV2 = forwardRef( (props, ref) => { const { value, placeholder, disabled, autoFocus, onChange, onFocus, onBlur, rows = 3, label, sublabel, hintText, helpIconText, required = false, error = { show: false, message: '' }, resize = 'none', name = 'text-area', size = InputSizeV2.MD, id: providedId, ...rest } = props const { onKeyDown: restOnKeyDown, ...restWithoutKeyDown } = rest const filteredRest = filterBlockedProps( omitTextAreaV2PrivateProps( restWithoutKeyDown as Record ) as typeof restWithoutKeyDown ) const textAreaTokens = useResponsiveTokens('TEXT_AREA_V2') const ic = textAreaTokens.inputContainer const [isFocused, setIsFocused] = useState(false) const { breakPointLabel } = useBreakpoints(BREAKPOINTS) const isSmallScreen = breakPointLabel === 'sm' const generatedId = useId() const textareaId = providedId || generatedId const { errorId, hintId } = generateAccessibilityIds(textareaId) const ariaDescribedBy = useMemo( () => getTextAreaAriaDescribedBy(hintText, error, hintId, errorId), [hintText, error, hintId, errorId] ) const labelState = useMemo( () => getTextAreaLabelState(disabled, error.show, isFocused), [disabled, error.show, isFocused] ) const inputFocusedOrWithValue = isFocused || value.length > 0 const inputPadding = useMemo( () => getTextAreaInputPadding({ inputContainer: ic, size, isSmallScreen, inputFocusedOrWithValue, hasLabel: Boolean(label), }), [ic, size, isSmallScreen, inputFocusedOrWithValue, label] ) const { borderDefault, borderHover, borderFocus, bgDefault, bgHover, textColorKey, } = useMemo( () => getTextAreaInteractionKeys(error.show, disabled), [error.show, disabled] ) const textareaMinHeight = useMemo( () => getTextAreaV2MinHeightFromRows(rows, ic.lineHeight[size], { paddingTop: inputPadding.paddingTop, paddingBottom: inputPadding.paddingBottom, }), [ rows, ic.lineHeight, size, inputPadding.paddingTop, inputPadding.paddingBottom, ] ) const setTextAreaRef = (node: HTMLTextAreaElement | null) => { setExternalRef(ref as AnyRef, node) } return ( {!isSmallScreen && ( )} {label && isSmallScreen && ( )} { e.stopPropagation() setIsFocused(true) onFocus?.(e) }} onBlur={(e) => { e.stopPropagation() setIsFocused(false) onBlur?.(e) }} onKeyDown={(e) => { e.stopPropagation() restOnKeyDown?.(e) }} rows={rows} minHeight={textareaMinHeight} style={{ lineHeight: addPxToValue( toPixels(ic.lineHeight[size]) ), }} required={required} borderRadius={ic.borderRadius} resize={resize} paddingTop={inputPadding.paddingTop} paddingBottom={inputPadding.paddingBottom} paddingLeft={inputPadding.paddingLeft} paddingRight={inputPadding.paddingRight} border={ic.border[borderDefault]} fontSize={ic.fontSize} fontWeight={ic.fontWeight} backgroundColor={ic.backgroundColor[bgDefault]} transition={TRANSITION} placeholderStyles={{ transition: ic.placeholder.transition, color: ic.placeholder.color[labelState], fontWeight: ic.placeholder.fontWeight[size], }} _hover={{ border: ic.border[borderHover], backgroundColor: ic.backgroundColor[bgHover], }} color={ic.color[textColorKey]} _focus={{ border: ic.border[borderFocus], boxShadow: FOCUS_RING_STYLES.boxShadow, }} disabled={disabled} _disabled={{ backgroundColor: ic.backgroundColor.disabled, border: ic.border.disabled, cursor: 'not-allowed', }} aria-required={required ? 'true' : undefined} aria-invalid={error.show ? 'true' : 'false'} aria-describedby={ariaDescribedBy} /> ) } ) TextAreaV2.displayName = 'TextAreaV2' export default TextAreaV2