Add MinMaxDisplay and MinMaxInput components for enhanced min/max value input and display functionality. Implement formatting and precision handling for better user experience in data entry and visualization.

This commit is contained in:
Tom Butcher 2026-07-20 02:05:32 +01:00
parent aa1446b502
commit bde1d5b896
2 changed files with 131 additions and 0 deletions

View File

@ -0,0 +1,66 @@
import { Flex, Typography, Tag, Space } from 'antd'
import PropTypes from 'prop-types'
const { Text } = Typography
const getPrecision = (step) => {
if (step == null) return null
const stepStr = String(step)
const dotIndex = stepStr.indexOf('.')
return dotIndex === -1 ? 0 : stepStr.length - dotIndex - 1
}
const formatValue = (value, step) => {
if (value == null || value === '') return null
const parsed = parseFloat(value)
if (Number.isNaN(parsed)) return null
const precision = getPrecision(step)
return precision == null ? parsed.toString() : parsed.toFixed(precision)
}
const MinMaxDisplay = ({ value, prefix = '', suffix = '', step }) => {
const min = formatValue(value?.min, step)
const max = formatValue(value?.max, step)
return (
<Flex gap={'middle'} align='center' style={{ height: '100%' }}>
<Flex wrap>
<Text style={{ marginRight: 4 }}>
{min != null ? (
prefix + min + suffix
) : (
<Text type='secondary'>n/a</Text>
)}
</Text>
<Space>
<Tag>Min</Tag>
</Space>
</Flex>
<Flex wrap>
<Text style={{ marginRight: 4 }}>
{max != null ? (
prefix + max + suffix
) : (
<Text type='secondary'>n/a</Text>
)}
</Text>
<Space>
<Tag>Max</Tag>
</Space>
</Flex>
</Flex>
)
}
MinMaxDisplay.propTypes = {
value: PropTypes.shape({
min: PropTypes.number,
max: PropTypes.number
}),
prefix: PropTypes.string,
suffix: PropTypes.string,
step: PropTypes.number
}
export default MinMaxDisplay

View File

@ -0,0 +1,65 @@
import { Flex, InputNumber, Typography } from 'antd'
import PropTypes from 'prop-types'
const { Text } = Typography
const MinMaxInput = ({
value = {},
onChange,
prefix = '',
suffix = '',
min,
max,
step,
disabled = false
}) => {
const handleChange = (field, val) => {
if (!onChange) return
onChange({ ...value, [field]: val })
}
return (
<Flex gap={'middle'} align='center' style={{ width: '100%' }}>
<InputNumber
addonBefore={<Text type='secondary'>Min:</Text>}
value={value?.min}
onChange={(val) => handleChange('min', val)}
prefix={prefix}
suffix={suffix}
min={min}
max={max}
step={step}
disabled={disabled}
style={{ minWidth: 120, flex: 1 }}
/>
<InputNumber
addonBefore={<Text type='secondary'>Max:</Text>}
value={value?.max}
onChange={(val) => handleChange('max', val)}
prefix={prefix}
suffix={suffix}
min={min}
max={max}
step={step}
disabled={disabled}
style={{ minWidth: 120, flex: 1 }}
/>
</Flex>
)
}
MinMaxInput.propTypes = {
value: PropTypes.shape({
min: PropTypes.number,
max: PropTypes.number
}),
onChange: PropTypes.func,
prefix: PropTypes.string,
suffix: PropTypes.string,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
disabled: PropTypes.bool
}
export default MinMaxInput