fix: выбранные позиции справочника отображаются горизонтально рядом с полем
This commit is contained in:
@@ -142,102 +142,100 @@ export default function TableFieldMultiSelect({
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover open={isOpen} onOpenChange={setIsOpen} modal={false}>
|
||||
<PopoverAnchor asChild>
|
||||
<div className="relative w-full">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
className="h-8"
|
||||
placeholder={placeholder || 'Выберите значения...'}
|
||||
value={isOpen ? searchTerm : (selectedLabels.length > 0 ? `${selectedLabels.length} выбрано` : placeholder || 'Выберите значения...')}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value);
|
||||
setIsOpen(true);
|
||||
}}
|
||||
onFocus={() => {
|
||||
setSearchTerm('');
|
||||
setIsOpen(true);
|
||||
}}
|
||||
data-testid={`select-table-multi-${fieldCode}`}
|
||||
/>
|
||||
</div>
|
||||
</PopoverAnchor>
|
||||
<PopoverContent
|
||||
className="p-0"
|
||||
style={{ width: 'var(--radix-popper-anchor-width)' }}
|
||||
onOpenAutoFocus={(e) => e.preventDefault()}
|
||||
onInteractOutside={(e) => {
|
||||
if (inputRef.current && inputRef.current.contains(e.target as Node)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="max-h-60 overflow-auto"
|
||||
onWheel={(e) => {
|
||||
const el = e.currentTarget;
|
||||
const isUp = e.deltaY < 0;
|
||||
const isDown = e.deltaY > 0;
|
||||
const atTop = el.scrollTop <= 0;
|
||||
const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
|
||||
if ((isUp && atTop) || (isDown && atBottom)) return;
|
||||
e.preventDefault();
|
||||
el.scrollTop += e.deltaY;
|
||||
<div className="flex flex-wrap items-center gap-1 w-full">
|
||||
<Popover open={isOpen} onOpenChange={setIsOpen} modal={false}>
|
||||
<PopoverAnchor asChild>
|
||||
<div className="relative flex-1 min-w-[120px]">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
className="h-8"
|
||||
placeholder={placeholder || 'Выберите значения...'}
|
||||
value={isOpen ? searchTerm : (selectedLabels.length > 0 ? `${selectedLabels.length} выбрано` : placeholder || 'Выберите значения...')}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value);
|
||||
setIsOpen(true);
|
||||
}}
|
||||
onFocus={() => {
|
||||
setSearchTerm('');
|
||||
setIsOpen(true);
|
||||
}}
|
||||
data-testid={`select-table-multi-${fieldCode}`}
|
||||
/>
|
||||
</div>
|
||||
</PopoverAnchor>
|
||||
<PopoverContent
|
||||
className="p-0"
|
||||
style={{ width: 'var(--radix-popper-anchor-width)' }}
|
||||
onOpenAutoFocus={(e) => e.preventDefault()}
|
||||
onInteractOutside={(e) => {
|
||||
if (inputRef.current && inputRef.current.contains(e.target as Node)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
>
|
||||
{hasTree ? (
|
||||
<DirectoryTreeMultiSelect
|
||||
nodes={nodes}
|
||||
selected={selectedSet}
|
||||
onToggle={toggle}
|
||||
searchTerm={searchTerm}
|
||||
/>
|
||||
) : (
|
||||
<ul className="py-1">
|
||||
{filtered.map((row) => {
|
||||
const rowId = row.id.toString();
|
||||
const label = row.values[displayColumnIndex!] || row.values[0] || rowId;
|
||||
return (
|
||||
<li
|
||||
key={row.id}
|
||||
className="flex items-center gap-2 px-3 py-2 hover:bg-accent cursor-pointer text-sm"
|
||||
title={label}
|
||||
onMouseDown={(e) => { e.preventDefault(); toggle(rowId); }}
|
||||
>
|
||||
<Checkbox checked={selectedSet.has(rowId)} />
|
||||
<Table className="w-3 h-3 text-muted-foreground flex-shrink-0" />
|
||||
<span className="flex-1">{label}</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
{filtered.length === 0 && (
|
||||
<li className="px-3 py-2 text-sm text-muted-foreground">Нет совпадений</li>
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
{selectedLabels.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 mt-1.5">
|
||||
{selectedLabels.map((label, idx) => {
|
||||
const rowId = selectedValues[idx];
|
||||
return (
|
||||
<div key={rowId} className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-muted text-xs">
|
||||
<span className="truncate max-w-[150px]">{label}</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-4 w-4"
|
||||
onClick={() => toggle(rowId)}
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</Popover>
|
||||
<div
|
||||
className="max-h-60 overflow-auto"
|
||||
onWheel={(e) => {
|
||||
const el = e.currentTarget;
|
||||
const isUp = e.deltaY < 0;
|
||||
const isDown = e.deltaY > 0;
|
||||
const atTop = el.scrollTop <= 0;
|
||||
const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
|
||||
if ((isUp && atTop) || (isDown && atBottom)) return;
|
||||
e.preventDefault();
|
||||
el.scrollTop += e.deltaY;
|
||||
}}
|
||||
>
|
||||
{hasTree ? (
|
||||
<DirectoryTreeMultiSelect
|
||||
nodes={nodes}
|
||||
selected={selectedSet}
|
||||
onToggle={toggle}
|
||||
searchTerm={searchTerm}
|
||||
/>
|
||||
) : (
|
||||
<ul className="py-1">
|
||||
{filtered.map((row) => {
|
||||
const rowId = row.id.toString();
|
||||
const label = row.values[displayColumnIndex!] || row.values[0] || rowId;
|
||||
return (
|
||||
<li
|
||||
key={row.id}
|
||||
className="flex items-center gap-2 px-3 py-2 hover:bg-accent cursor-pointer text-sm"
|
||||
title={label}
|
||||
onMouseDown={(e) => { e.preventDefault(); toggle(rowId); }}
|
||||
>
|
||||
<Checkbox checked={selectedSet.has(rowId)} />
|
||||
<Table className="w-3 h-3 text-muted-foreground flex-shrink-0" />
|
||||
<span className="flex-1">{label}</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
{filtered.length === 0 && (
|
||||
<li className="px-3 py-2 text-sm text-muted-foreground">Нет совпадений</li>
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
{selectedLabels.map((label, idx) => {
|
||||
const rowId = selectedValues[idx];
|
||||
return (
|
||||
<div key={rowId} className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-muted text-xs shrink-0">
|
||||
<span className="truncate max-w-[150px]">{label}</span>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-4 w-4"
|
||||
onClick={() => toggle(rowId)}
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user