input.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { Input as TaroInput, InputProps as TaroInputProps, View, Text } from '@tarojs/components'
  2. import { cn } from '@/utils/cn'
  3. import { cva, type VariantProps } from 'class-variance-authority'
  4. import { forwardRef } from 'react'
  5. const inputVariants = cva(
  6. 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
  7. {
  8. variants: {
  9. variant: {
  10. default: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500',
  11. outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
  12. filled: 'border-none bg-gray-50 hover:bg-gray-100',
  13. },
  14. size: {
  15. default: 'h-10 px-3 py-2',
  16. sm: 'h-9 px-2 text-sm',
  17. lg: 'h-11 px-4 text-lg',
  18. icon: 'h-10 w-10',
  19. },
  20. },
  21. defaultVariants: {
  22. variant: 'default',
  23. size: 'default',
  24. },
  25. }
  26. )
  27. export interface InputProps extends Omit<TaroInputProps, 'className' | 'onChange'>, VariantProps<typeof inputVariants> {
  28. className?: string
  29. leftIcon?: string
  30. rightIcon?: string
  31. error?: boolean
  32. errorMessage?: string
  33. onLeftIconClick?: () => void
  34. onRightIconClick?: () => void
  35. onChange?: (value: string, event: any) => void
  36. }
  37. const Input = forwardRef<any, InputProps>(
  38. ({ className, variant, size, leftIcon, rightIcon, error, errorMessage, onLeftIconClick, onRightIconClick, onChange, ...props }, ref) => {
  39. const handleInput = (event: any) => {
  40. const value = event.detail.value
  41. onChange?.(value, event)
  42. // 同时调用原始的onInput(如果提供了)
  43. if (props.onInput) {
  44. props.onInput(event)
  45. }
  46. }
  47. return (
  48. <View className="w-full">
  49. <View className="relative">
  50. {leftIcon && (
  51. <View
  52. className={cn(
  53. "absolute left-3 top-1/2 -translate-y-1/2",
  54. onLeftIconClick ? "cursor-pointer" : "pointer-events-none"
  55. )}
  56. onClick={onLeftIconClick}
  57. >
  58. <View className={cn('w-5 h-5 text-gray-400', leftIcon)} />
  59. </View>
  60. )}
  61. <TaroInput
  62. ref={ref}
  63. className={cn(
  64. inputVariants({ variant, size, className }),
  65. error && 'border-red-500 focus:border-red-500 focus:ring-red-500',
  66. leftIcon && 'pl-10',
  67. rightIcon && 'pr-10',
  68. )}
  69. onInput={handleInput}
  70. {...props}
  71. />
  72. {rightIcon && (
  73. <View
  74. className={cn(
  75. "absolute right-3 top-1/2 -translate-y-1/2",
  76. onRightIconClick ? "cursor-pointer" : "pointer-events-none"
  77. )}
  78. onClick={onRightIconClick}
  79. >
  80. <View className={cn('w-5 h-5 text-gray-400', rightIcon)} />
  81. </View>
  82. )}
  83. </View>
  84. {error && errorMessage && (
  85. <Text className="mt-1 text-sm text-red-600">{errorMessage}</Text>
  86. )}
  87. </View>
  88. )
  89. }
  90. )
  91. Input.displayName = 'Input'
  92. export { Input, inputVariants }