Files
protoc-frontend/src/component/BasicElements/SelectElement.tsx
2025-07-25 09:19:36 +03:00

144 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Button } from '@/component/ui/button'
import { Input } from '@/component/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/component/ui/select'
import { ElementDefinition } from '@/entitiy/element/model/interface'
import { ElementOption } from '@/type/template'
import { ChevronDown, Plus, Trash2 } from 'lucide-react'
interface SelectConfig {
placeholder?: string
required?: boolean
options: ElementOption[]
targetCells: any[]
}
export const selectDefinition: ElementDefinition<SelectConfig, string> = {
type: 'select',
label: 'Выпадающий список',
icon: <ChevronDown className="h-4 w-4" />,
version: 1,
defaultConfig: {
placeholder: '',
required: false,
options: [],
targetCells: [],
},
mapToCells: config => config.targetCells || [],
mapToCellValues: (config, value) => {
const cells = config.targetCells || []
return cells.map(target => ({ target, value: value || '' }))
},
Editor: ({ config, onChange }) => {
const handleAddOption = () => {
onChange({
...config,
options: [...config.options, { value: '', label: '' }],
})
}
const handleUpdateOption = (
index: number,
field: 'value' | 'label',
value: string
) => {
onChange({
...config,
options: config.options.map((option, i) =>
i === index ? { ...option, [field]: value } : option
),
})
}
const handleRemoveOption = (index: number) => {
onChange({
...config,
options: config.options.filter((_, i) => i !== index),
})
}
return (
<div className="space-y-4">
<div className="space-y-2">
<div className="flex items-center justify-between">
<label className="text-sm font-medium">Варианты</label>
<Button variant="outline" size="sm" onClick={handleAddOption}>
<Plus className="mr-1 h-4 w-4" />
Добавить
</Button>
</div>
<div className="max-h-32 space-y-2 overflow-y-auto">
{config.options.map((option, index) => (
<div key={index} className="flex gap-2">
<Input
placeholder="Значение"
value={option.value}
onChange={e =>
handleUpdateOption(index, 'value', e.target.value)
}
/>
<Input
placeholder="Подпись"
value={option.label}
onChange={e =>
handleUpdateOption(index, 'label', e.target.value)
}
/>
<Button
variant="outline"
size="icon"
onClick={() => handleRemoveOption(index)}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
))}
</div>
</div>
</div>
)
},
Preview: ({ config }) => (
<Select>
<SelectTrigger className="w-full min-w-32">
<SelectValue placeholder={config.placeholder || 'Выберите значение'} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{config.options
.filter(option => option.value.trim() !== '')
.map((option, index) => (
<SelectItem key={index} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
),
Render: ({ config, value, onChange }) => (
<Select value={value} onValueChange={onChange}>
<SelectTrigger className="w-full min-w-32">
<SelectValue placeholder={config.placeholder || 'Выберите значение'} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{config.options
.filter(option => option.value.trim() !== '')
.map((option, index) => (
<SelectItem key={index} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
),
}