import { useImperativeHandle, forwardRef, useEffect, useState, useRef } from "react"; import { TextInput as NativeTextInput, TouchableOpacity, Keyboard, View } from "react-native"; import type ITextAreaInputProps from "./type"; import { type TextAreaInputInstance, type ITextAreaInputRef, type TextAreaInputType } from "./type"; import stylesheet, { getTextAreaInputType, useStyles } from "./stylesheet"; import { NCoreUIKitLocalize, NCoreUIKitTheme } from "../../core/hooks"; import { type RefForwardingComponent } from "../../types"; import type ITextProps from "../text/type"; import { BadgeQuestionMark as BadgeQuestionMarkIcon, BadgeAlert as BadgeAlertIcon, BadgeCheck as BadgeCheckIcon, BadgeInfo as BadgeInfoIcon, CircleX as CircleXIcon, BadgeX as BadgeXIcon, type LucideIcon } from "lucide-react-native"; import Text from "../text"; const TextInputTypeIcon: Record, LucideIcon> = { "question": BadgeQuestionMarkIcon, "success": BadgeCheckIcon, "warning": BadgeAlertIcon, "info": BadgeInfoIcon, "danger": BadgeXIcon }; const TextAreaInput: RefForwardingComponent = ({ isAutoKeyboardDismissOnBlur = true, rightIcon: RightIconComponentProp, hintTextIcon: HintTextIconProp, spreadBehaviour = "baseline", isShowLengthLimiter = true, isShowHintTextIcon = false, isUpdateOnRealtime = false, icon: IconComponentProp, hintTextContainerStyle, isCleanEnabled = false, contentContainerStyle, subTitle = "Optional", onFocus: onFocusProp, isRequired = false, isDisabled = false, onBlur: onBlurProp, type = "default", rightIconOnPress, maxHeight = 350, customLocalize, rightIconStyle, isShowSubTitle, cleanIconStyle, onChangeText, initialValue, customTheme, placeholder, iconOnPress, isOptional, validation, inputStyle, maxLength, iconStyle, hintText, style, title, ...props }, ref) => { const { inlineSpaces, typography, radiuses, borders, spaces, colors } = NCoreUIKitTheme.useContext(customTheme); const { localize } = NCoreUIKitLocalize.useContext(customLocalize); const currentType = getTextAreaInputType({ type }); const inputRef = useRef(null); const styleType = type === "default" ? "neutral" : type === "question" ? "neutral" : type === "danger" ? "error" : type; const [ value, setValue ] = useState(initialValue ? initialValue : ""); const [ isFocused, setIsFocused ] = useState(false); const { lengthLimiterContainer: lengthLimiterContainerDynamicStyle, titleContainer: titleContainerDynamicStyle, inputContainer: inputContainerDynamicStyle, hintTextIcon: hintTextIconDynamicStyle, cleanButton: cleanButtonDynamicStyle, rightIcon: rightIconDynamicStyle, container: containerDynamicStyle, hintText: hintTextDynamicStyle, required: requiredDynamicStyle, subTitle: subTitleDynamicStyle, content: contentDynamicStyle, overlay: overlayDynamicStyle, title: titleDynamicStyle, input: inputDynamicStyle, icon: iconDynamicStyle } = useStyles({ icon: IconComponentProp ? true : false, spreadBehaviour, inlineSpaces, currentType, isDisabled, typography, isFocused, maxHeight, radiuses, borders, spaces, colors, title, type }); useEffect(() => { if(initialValue) { inputRef.current?.setNativeProps({ text: initialValue }); } }, []); useImperativeHandle( ref, () => ({ updateValue, cleanText, focus, blur }), [] ); const titleProps: ITextProps = { color: currentType.titleColor, variant: "bodyLargeSize" }; const iconProps: NCoreUIKit.IconCallbackProps = { size: Number(typography.labelLargeSize.fontSize) + 6, color: currentType.iconColor }; if(isDisabled) { iconProps.color = "disabled"; } const blur = () => { inputRef.current?.blur(); }; const focus = () => { inputRef.current?.focus(); }; const cleanText = () => { setValue(""); inputRef.current?.clear(); if(onChangeText) { onChangeText(""); } }; const updateValue = (text: string) => { setValue(text); inputRef.current?.setNativeProps({ text: text }); }; const onFocus = () => { setIsFocused(true); if(onFocusProp) onFocusProp(); }; const onBlur = () => { setIsFocused(false); inputRef.current?.blur(); if(isAutoKeyboardDismissOnBlur) { Keyboard.dismiss(); } if(onBlurProp) onBlurProp(); }; const renderCleanButton = () => { if(isDisabled) { return null; } if(!isCleanEnabled || !value.length) { return null; } return { if(inputRef.current) inputRef.current?.clear(); if(onChangeText) { onChangeText(""); } setValue(""); }} > ; }; const renderIcon = () => { if (!IconComponentProp) { return null; } return ; }; const renderRightIcon = () => { if (!RightIconComponentProp) { return null; } if(isCleanEnabled && value.length > 0) { return null; } return ; }; const renderHintIcon = () => { if(!isShowHintTextIcon) { return null; } if(HintTextIconProp) { return ; } const CurrentHintIcon = TextInputTypeIcon[type === "default" ? "question" : type]; let hintIconColor = colors.content.icon[currentType.hintTextIconColor]; if(isDisabled) { hintIconColor = colors.system.state.content.disabled[styleType]; } return ; }; const renderHintText = () => { if (!hintText) { return null; } return {renderHintIcon()} {hintText} ; }; const renderRequired = () => { if(!isRequired) { return null; } return *; }; const renderSubtitle = () => { if(!isShowSubTitle && !isOptional) { return null; } return ( {isOptional ? localize("is-optional") : subTitle} ) ; }; const renderTitle = () => { if (!title) { return null; } return {renderRequired()} {title} {renderSubtitle()} ; }; const renderLengthLimiter = () => { if(!isShowLengthLimiter || !maxLength) { return null; } return {value.length} / {maxLength} ; }; const renderInput = () => { return { const text = t.nativeEvent.text; if(!isUpdateOnRealtime) { if (validation) { if (validation(text)) { setValue(text); if(onChangeText) onChangeText(text); } } else { setValue(text); if(onChangeText) onChangeText(text); } } }} onChangeText={(text) => { if(isUpdateOnRealtime) { if (validation) { if (validation(text)) { setValue(text); if(onChangeText) onChangeText(text); } } else { setValue(text); if(onChangeText) onChangeText(text); } } }} style={[ inputStyle, stylesheet.input, inputDynamicStyle ]} /> {renderLengthLimiter()} ; }; const renderOverlay = () => { return ; }; return { if(!isDisabled) inputRef.current?.focus(); }} > {renderTitle()} {renderOverlay()} {renderIcon()} {renderInput()} {renderCleanButton()} {renderRightIcon()} {renderHintText()} ; }; export default forwardRef(TextAreaInput);