123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- import type { FC } from 'react'
- import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react'
- import Input, { type InputProps } from '../input'
- import classNames from '@/utils/classnames'
- export type InputNumberProps = {
- unit?: string
- value?: number
- onChange: (value?: number) => void
- amount?: number
- size?: 'sm' | 'md'
- max?: number
- min?: number
- defaultValue?: number
- } & Omit<InputProps, 'value' | 'onChange' | 'size' | 'min' | 'max' | 'defaultValue'>
- export const InputNumber: FC<InputNumberProps> = (props) => {
- const { unit, className, onChange, amount = 1, value, size = 'md', max, min, defaultValue, ...rest } = props
- const isValidValue = (v: number) => {
- if (max && v > max)
- return false
- if (min && v < min)
- return false
- return true
- }
- const inc = () => {
- if (value === undefined) {
- onChange(defaultValue)
- return
- }
- const newValue = value + amount
- if (!isValidValue(newValue))
- return
- onChange(newValue)
- }
- const dec = () => {
- if (value === undefined) {
- onChange(defaultValue)
- return
- }
- const newValue = value - amount
- if (!isValidValue(newValue))
- return
- onChange(newValue)
- }
- return <div className='flex'>
- <Input {...rest}
- // disable default controller
- type='text'
- className={classNames('rounded-r-none', className)}
- value={value}
- max={max}
- min={min}
- onChange={(e) => {
- if (e.target.value === '')
- onChange(undefined)
- const parsed = Number(e.target.value)
- if (Number.isNaN(parsed))
- return
- if (!isValidValue(parsed))
- return
- onChange(parsed)
- }}
- unit={unit}
- />
- <div className='flex flex-col bg-components-input-bg-normal rounded-r-md border-l border-divider-subtle text-text-tertiary focus:shadow-xs'>
- <button onClick={inc} className={classNames(
- size === 'sm' ? 'pt-1' : 'pt-1.5',
- 'px-1.5 hover:bg-components-input-bg-hover',
- )}>
- <RiArrowUpSLine className='size-3' />
- </button>
- <button onClick={dec} className={classNames(
- size === 'sm' ? 'pb-1' : 'pb-1.5',
- 'px-1.5 hover:bg-components-input-bg-hover',
- )}>
- <RiArrowDownSLine className='size-3' />
- </button>
- </div>
- </div>
- }
|