/** @format */ import React, { useRef, useState } from 'react'; import { Animated, StyleSheet, TouchableWithoutFeedback, View, Text, } from 'react-native'; import style from './styles/tag.style'; import { RNTagProps, TagFunc } from '../Tag/interface'; import { InputFocusEvent, InputInstance } from './interface'; import { useThemeStyle } from '../Theme'; import Tag from '../Tag'; import Input from './Input'; export interface TagInputProps { accessibilityLabel: string; value?: string[]; placeholder?: string; onChange?: (value: string[] | undefined) => void; tagProps?: RNTagProps; status?: 'error'; onBlur?: (e: InputFocusEvent) => void; suffix?: React.ReactNode; disabled?: boolean; } const BaseTagInput = (props: TagInputProps) => { const { onChange, value = [], suffix, status, placeholder, accessibilityLabel, tagProps = {}, disabled, } = props; const styles = useThemeStyle(style); const [focus, setFocus] = useState(false); const inputRef = useRef(null); const [fadeAnim] = useState(new Animated.Value(1)); const [initialText, setInitialText] = useState(); const [showNumberHolder, setShowNumberHolder] = useState(''); // 显示数量 const [inputWidth, setInputWidth] = useState(4); const addTag = () => { if (!initialText) return; const isExist = value?.find((tagValue) => tagValue === initialText.trim()); if (isExist) { return setInitialText(''); } const newTags = value ? [...value, initialText.trim()] : [initialText.trim()]; setInitialText(''); setInputWidth(0); setShowNumberHolder(``); onChange?.(newTags); }; const deleteTag = (tagValue: string) => { const newTags = value.filter((tag) => tag !== tagValue); setShowNumberHolder(``); onChange?.(newTags); }; const handleOnKeyPress = (e: { nativeEvent: { key: string } }) => { if ( e.nativeEvent?.key === 'Backspace' && !initialText && value?.length > 0 ) { const newTags = value.slice(0, -1); Animated.timing(fadeAnim, { toValue: 0, duration: 500, useNativeDriver: false, }).start(() => { setShowNumberHolder(``); onChange?.(newTags); }); } }; const handleOnBlur = () => { setFocus(false); addTag(); }; const handleFocus = () => { setFocus(true); }; const onTextLayout = (event: any) => { // 当隐藏文本布局完成时,获取实际宽度 const { width } = event.nativeEvent.layout; const currentWidth = width > 3 ? width + 25 : 0; const actualWidth = Math.min(80, currentWidth); // 加上padding setInputWidth(actualWidth); }; const onChangeText = (text: string) => { setInitialText(text); }; const handleTagPress = () => { inputRef.current?.focus?.(); }; return ( {value?.map((tagText) => ( deleteTag(tagText)} style={StyleSheet.flatten([disabled && styles.disabled])} tagFunc={TagFunc.weaken} {...tagProps} > {tagText} ))} 0 ? showNumberHolder : placeholder} value={initialText} style={[styles.input, { minWidth: inputWidth }]} onChangeText={onChangeText} onSubmitEditing={addTag} blurOnSubmit={false} onKeyPress={handleOnKeyPress} onBlur={handleOnBlur} onFocus={handleFocus} borderNone disabled={disabled} /> {suffix} {/* 隐藏的Text组件用于测量文本宽度 */} {initialText} ); }; export default BaseTagInput;