input-number-with-slider.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. 'use client'
  2. import type { FC } from 'react'
  3. import React, { useCallback } from 'react'
  4. import Slider from '@/app/components/base/slider'
  5. type Props = {
  6. value: number
  7. defaultValue?: number
  8. min?: number
  9. max?: number
  10. readonly?: boolean
  11. onChange: (value: number) => void
  12. }
  13. const InputNumberWithSlider: FC<Props> = ({
  14. value,
  15. defaultValue = 0,
  16. min,
  17. max,
  18. readonly,
  19. onChange,
  20. }) => {
  21. const handleBlur = useCallback(() => {
  22. if (value === undefined || value === null) {
  23. onChange(defaultValue)
  24. return
  25. }
  26. if (max !== undefined && value > max) {
  27. onChange(max)
  28. return
  29. }
  30. if (min !== undefined && value < min)
  31. onChange(min)
  32. }, [defaultValue, max, min, onChange, value])
  33. const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
  34. onChange(Number.parseFloat(e.target.value))
  35. }, [onChange])
  36. return (
  37. <div className='flex justify-between items-center h-8 space-x-2'>
  38. <input
  39. value={value}
  40. className='shrink-0 block pl-3 w-12 h-8 appearance-none outline-none rounded-lg bg-components-input-bg-normal text-[13px] text-components-input-text-filled'
  41. type='number'
  42. min={min}
  43. max={max}
  44. step={1}
  45. onChange={handleChange}
  46. onBlur={handleBlur}
  47. disabled={readonly}
  48. />
  49. <Slider
  50. className='grow'
  51. value={value}
  52. min={min}
  53. max={max}
  54. step={1}
  55. onChange={onChange}
  56. disabled={readonly}
  57. />
  58. </div>
  59. )
  60. }
  61. export default React.memo(InputNumberWithSlider)