| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- import * as React from "react"
- import { cname } from "../utils"
- import { SearchIcon } from "../../bs-icons/search"
- import { generateUUID } from "../utils"
- import { MinusCircledIcon } from "@radix-ui/react-icons"
- import { EyeOpenIcon, EyeNoneIcon } from "@radix-ui/react-icons"
- import { useState } from "react"
- import sousuo from "../../../assets/npc/sousuo.png"
- export interface InputProps
- extends React.InputHTMLAttributes<HTMLInputElement> { }
- const Input = React.forwardRef<HTMLInputElement, InputProps>(
- ({ className, type, ...props }, ref) => {
- return (
- <input
- type={type}
- className={cname(
- "flex h-9 w-full rounded-md border-input bg-[#FAFBFC] px-3 py-1 text-sm text-[#111] shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-[#666] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 ",
- className
- )}
- ref={ref}
- {...props}
- />
- )
- }
- )
- Input.displayName = "Input"
- const SearchInput = React.forwardRef<HTMLInputElement, InputProps & { inputClassName?: string, iconClassName?: string }>(
- ({ className, inputClassName, iconClassName, ...props }, ref) => {
- return <div className={cname("relative", className)}>
- {/* <SearchIcon className={cname("h-5 w-5 absolute left-2 top-2 text-[#666666]", iconClassName)} /> */}
- <div className="absolute w-[40px] h-[100%] flex items-center">
- <img src={sousuo} alt="" className="w-[14px] absolute left-[14px]" />
- </div>
- <Input type="text" ref={ref} className={cname("w-[244px] h-[34px] pl-[40px] npcInput2", inputClassName)} {...props}></Input>
- </div>
- }
- )
- SearchInput.displayName = "SearchInput"
- const PasswordInput = React.forwardRef<HTMLInputElement, InputProps & { inputClassName?: string, iconClassName?: string }>(
- ({ className, inputClassName, iconClassName, ...props }, ref) => {
- const [type, setType] = useState('password')
- const handleShowPwd = () => {
- type === 'password' ? setType('text') : setType('password')
- }
- return <div className={cname("relative flex place-items-center", className)}>
- <Input type={type} ref={ref} autocomplete="new-password" className={cname("pr-8 bg-[#1a1a1a] text-[#fff] ", inputClassName)} {...props}></Input>
- {
- type === 'password'
- ? <EyeNoneIcon onClick={handleShowPwd} className={cname("absolute right-2 text-[#fff] dark:text-[#fff] cursor-pointer", iconClassName)}/>
- : <EyeOpenIcon onClick={handleShowPwd} className={cname("absolute right-2 text-[#fff] dark:text-[#fff] cursor-pointer", iconClassName)}/>
- }
- </div>
- }
- )
- PasswordInput.displayName = 'PasswordInput'
- /**
- * 多行文本
- */
- export interface TextareaProps
- extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { }
- const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
- ({ className, ...props }, ref) => {
- return (
- <textarea
- className={cname(
- "flex min-h-[80px] w-full rounded-md border border-input bg-[#FAFBFC] px-3 py-2 text-sm text-[#111] shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
- className
- )}
- ref={ref}
- {...props}
- />
- )
- }
- )
- Textarea.displayName = "Textarea"
- /**
- * input list
- */
- const InputList = React.forwardRef<HTMLDivElement, InputProps & {
- rules: any[],
- value?: string[],
- inputClassName?: string,
- defaultValue?: string[],
- onChange?: (values: string[]) => void
- }>(
- ({ rules, className, inputClassName, value = [], defaultValue = [], ...props }, ref) => {
- // 初始化 inputs 状态,为每个值分配唯一 ID
- const [inputs, setInputs] = React.useState(() =>
- value.map(val => ({ id: generateUUID(8), value: val }))
- );
- React.useEffect(() => {
- // 仅为新增的值分配新的 ID
- const updatedInputs = value.map((val, index) => {
- return inputs[index] && inputs[index].value === val
- ? inputs[index] // 如果当前输入项与外部值相同,则保持不变
- : { id: generateUUID(8), value: val }; // 否则,创建新的输入项
- });
- setInputs(updatedInputs);
- }, [value]); // 依赖项中包含 value,确保外部 value 更新时同步更新
- const handleChange = (newValue, id, index) => {
- let newInputs = inputs.map(input =>
- input.id === id ? { ...input, value: newValue } : input
- );
- // push
- if (index === newInputs.length - 1) {
- newInputs = ([...newInputs, { id: generateUUID(8), value: '' }]);
- }
- setInputs(newInputs);
- props.onChange(newInputs.map(input => input.value));
- };
- // delete input
- const handleRemoveInput = (id) => {
- const newInputs = inputs.filter(input => input.id !== id);
- setInputs(newInputs);
- props.onChange(newInputs.map(input => input.value));
- };
- return <div className={cname('', className)}>
- {
- inputs.map((item, index) => (
- <div className="relative mt-2">
- <Input
- key={item.id}
- defaultValue={item.value}
- className={cname('pr-8 npcInput2', inputClassName)}
- placeholder={props.placeholder || ''}
- onChange={(e) => handleChange(e.target.value, item.id, index)}
- onInput={(e) => {
- rules.some(rule => {
- if (rule.maxLength && e.target.value.length > rule.maxLength) {
- e.target.nextSibling.textContent = rule.message;
- e.target.nextSibling.style.display = '';
- return true;
- }
- e.target.nextSibling.style.display = 'none';
- })
- }}
- // onFocus={(e) => {
- // if (e.target.value && index === inputs.length - 1) {
- // setInputs([...inputs, { id: generateUUID(8), value: '' }]);
- // }
- // }}
- ></Input>
- <p className="text-sm text-red-500" style={{ display: 'none' }}></p>
- {index !== inputs.length - 1 && <MinusCircledIcon onClick={(e) => {
- e.target.previousSibling.style.display = 'none';
- handleRemoveInput(item.id)
- }} className="absolute top-2.5 right-2 text-gray-500 hover:text-gray-700 cursor-pointer" />}
- </div>
- ))
- }
- </div>
- }
- )
- export { Input, SearchInput, PasswordInput, Textarea, InputList }
|