Add ArrayDisplay and ArrayInput components for enhanced array handling. ArrayDisplay provides a visual representation of array items with optional prefix and suffix, while ArrayInput allows dynamic addition and removal of items, supporting both text and numeric inputs for improved user interaction.

This commit is contained in:
Tom Butcher 2026-07-20 02:05:51 +01:00
parent 8cb2bea2d3
commit 0c6fe5cbac
2 changed files with 113 additions and 0 deletions

View File

@ -0,0 +1,30 @@
import PropTypes from 'prop-types'
import { Flex, Tag, Typography } from 'antd'
const { Text } = Typography
const ArrayDisplay = ({ value, prefix, suffix }) => {
if (!Array.isArray(value) || value.length === 0) {
return <Text type='secondary'>n/a</Text>
}
return (
<Flex gap='small' wrap>
{value.map((item, index) => (
<Tag key={`${item}-${index}`}>
{prefix}
{item}
{suffix}
</Tag>
))}
</Flex>
)
}
ArrayDisplay.propTypes = {
value: PropTypes.array,
prefix: PropTypes.node,
suffix: PropTypes.node
}
export default ArrayDisplay

View File

@ -0,0 +1,83 @@
import PropTypes from 'prop-types'
import { Button, Flex, Input, InputNumber } from 'antd'
const ArrayInput = ({
value = [],
onChange,
disabled = false,
numeric = false,
min,
max,
step,
placeholder
}) => {
const values = Array.isArray(value) ? value : []
const updateValue = (index, nextValue) => {
const nextValues = [...values]
nextValues[index] = nextValue
onChange?.(nextValues)
}
const removeValue = (index) => {
onChange?.(values.filter((_, valueIndex) => valueIndex !== index))
}
return (
<Flex vertical gap='small' style={{ width: '100%' }}>
{values.map((item, index) => (
<Flex key={index} gap='small' style={{ width: '100%' }}>
{numeric ? (
<InputNumber
value={item}
onChange={(nextValue) => updateValue(index, nextValue)}
min={min}
max={max}
step={step}
placeholder={placeholder}
disabled={disabled}
style={{ flex: 1 }}
/>
) : (
<Input
value={item}
onChange={(event) => updateValue(index, event.target.value)}
placeholder={placeholder}
disabled={disabled}
style={{ flex: 1 }}
/>
)}
<Button
onClick={() => removeValue(index)}
disabled={disabled}
danger
aria-label={`Remove ${placeholder || 'item'}`}
>
Remove
</Button>
</Flex>
))}
<Button
onClick={() => onChange?.([...values, numeric ? null : ''])}
disabled={disabled}
type='dashed'
block
>
Add {placeholder || 'item'}
</Button>
</Flex>
)
}
ArrayInput.propTypes = {
value: PropTypes.array,
onChange: PropTypes.func,
disabled: PropTypes.bool,
numeric: PropTypes.bool,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
placeholder: PropTypes.string
}
export default ArrayInput