44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import { ArrowDown, ArrowUp, ChevronsUpDown } from 'lucide-react'
|
|
import { cn } from '@/shared/lib/cn'
|
|
import type { SortState } from '@/shared/lib/table-sort'
|
|
|
|
/** Заголовок-кнопка столбца со стрелкой сортировки. */
|
|
export function SortHeader({
|
|
label,
|
|
sortKey,
|
|
sort,
|
|
onToggle,
|
|
className,
|
|
}: {
|
|
label: string
|
|
sortKey: string
|
|
sort: SortState
|
|
onToggle: (key: string) => void
|
|
className?: string
|
|
}) {
|
|
const active = sort.key === sortKey
|
|
const direction = sort.desc ? 'descending' : 'ascending'
|
|
let Icon = ChevronsUpDown
|
|
if (active) Icon = sort.desc ? ArrowDown : ArrowUp
|
|
return (
|
|
// aria-sort — атрибут заголовка столбца, а не кнопки внутри него: у роли button его нет,
|
|
// и скринридер там его просто не прочтёт.
|
|
<th
|
|
className={cn('px-4 py-2 font-medium', className)}
|
|
aria-sort={active ? direction : 'none'}
|
|
>
|
|
<button
|
|
type="button"
|
|
onClick={() => onToggle(sortKey)}
|
|
className={cn(
|
|
'inline-flex items-center gap-1 hover:text-foreground',
|
|
active && 'text-foreground',
|
|
)}
|
|
>
|
|
{label}
|
|
<Icon className={cn('h-3.5 w-3.5', !active && 'opacity-40')} />
|
|
</button>
|
|
</th>
|
|
)
|
|
}
|