index.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import type { CSSProperties } from 'react'
  2. import React from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react'
  5. import { type VariantProps, cva } from 'class-variance-authority'
  6. import cn from '@/utils/classnames'
  7. export const inputVariants = cva(
  8. '',
  9. {
  10. variants: {
  11. size: {
  12. regular: 'px-3 radius-md system-sm-regular',
  13. large: 'px-4 radius-lg system-md-regular',
  14. },
  15. },
  16. defaultVariants: {
  17. size: 'regular',
  18. },
  19. },
  20. )
  21. export type InputProps = {
  22. showLeftIcon?: boolean
  23. showClearIcon?: boolean
  24. onClear?: () => void
  25. onEnter?: () => void
  26. disabled?: boolean
  27. destructive?: boolean
  28. wrapperClassName?: string
  29. styleCss?: CSSProperties
  30. unit?: string
  31. } & React.InputHTMLAttributes<HTMLInputElement> & VariantProps<typeof inputVariants>
  32. const Input = ({
  33. size,
  34. disabled,
  35. destructive,
  36. showLeftIcon,
  37. showClearIcon,
  38. onClear,
  39. wrapperClassName,
  40. className,
  41. styleCss,
  42. value,
  43. placeholder,
  44. onChange,
  45. onEnter,
  46. unit,
  47. ...props
  48. }: InputProps) => {
  49. const { t } = useTranslation()
  50. const onKeyUp = (e: any) => {
  51. if (e.key === 'Enter') {
  52. e.preventDefault()
  53. onEnter?.()
  54. }
  55. }
  56. return (
  57. <div className={cn('relative w-full', wrapperClassName)}>
  58. {showLeftIcon && <RiSearchLine className={cn('absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-components-input-text-placeholder')} />}
  59. <input
  60. style={styleCss}
  61. className={cn(
  62. 'w-full appearance-none border border-transparent bg-components-input-bg-normal py-[7px] text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
  63. inputVariants({ size }),
  64. showLeftIcon && 'pl-[26px]',
  65. showLeftIcon && size === 'large' && 'pl-7',
  66. showClearIcon && value && 'pr-[26px]',
  67. showClearIcon && value && size === 'large' && 'pr-7',
  68. destructive && 'pr-[26px]',
  69. destructive && size === 'large' && 'pr-7',
  70. disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled',
  71. destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive',
  72. className,
  73. )}
  74. placeholder={placeholder ?? (showLeftIcon
  75. ? (t('common.operation.search') || '')
  76. : (t('common.placeholder.input') || ''))}
  77. value={value}
  78. onChange={onChange}
  79. disabled={disabled}
  80. {...props}
  81. onKeyUp={onKeyUp}
  82. />
  83. {showClearIcon && value && !disabled && !destructive && (
  84. <div className={cn('group absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer p-[1px]')} onClick={onClear}>
  85. <RiCloseCircleFill className='h-3.5 w-3.5 cursor-pointer text-text-quaternary group-hover:text-text-tertiary' />
  86. </div>
  87. )}
  88. {destructive && (
  89. <RiErrorWarningLine className='absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-text-destructive-secondary' />
  90. )}
  91. {
  92. unit && (
  93. <div className='system-sm-regular absolute right-2 top-1/2 -translate-y-1/2 text-text-tertiary'>
  94. {unit}
  95. </div>
  96. )
  97. }
  98. </div>
  99. )
  100. }
  101. export default Input