Viewing File: /home/markqprx/iniasli.pro/client/ui/tables/header-cell.tsx
import {useContext, useState} from 'react';
import clsx from 'clsx';
import {AnimatePresence, m} from 'framer-motion';
import {TableContext} from './table-context';
import {SortDescriptor} from './types/sort-descriptor';
import {ArrowDownwardIcon} from '../../icons/material/ArrowDownward';
import {useTableCellStyle} from '@common/ui/tables/style/use-table-cell-style';
interface HeaderCellProps {
index: number;
}
export function HeaderCell({index}: HeaderCellProps) {
const {columns, sortDescriptor, onSortChange, enableSorting} =
useContext(TableContext);
const column = columns[index];
const style = useTableCellStyle({
index: index,
isHeader: true,
});
const [isHovered, setIsHovered] = useState(false);
const sortingKey = column.sortingKey || column.key;
const allowSorting = column.allowsSorting && enableSorting;
const {orderBy, orderDir} = sortDescriptor || {};
const sortActive = allowSorting && orderBy === sortingKey;
let ariaSort: 'ascending' | 'descending' | 'none' | undefined;
if (sortActive && orderDir === 'asc') {
ariaSort = 'ascending';
} else if (sortActive && orderDir === 'desc') {
ariaSort = 'descending';
} else if (allowSorting) {
ariaSort = 'none';
}
const toggleSorting = () => {
if (!allowSorting) return;
let newSort: SortDescriptor;
// if this col was sorted desc, go to asc
if (sortActive && orderDir === 'desc') {
newSort = {orderDir: 'asc', orderBy: sortingKey};
// if this col was sorted asc, clear sort
} else if (sortActive && orderDir === 'asc') {
newSort = {orderBy: undefined, orderDir: undefined};
// if sort was on another col, or no sort was applied yet, start from desc
} else {
newSort = {orderDir: 'desc', orderBy: sortingKey};
}
onSortChange?.(newSort);
};
const sortVisible = sortActive || isHovered;
const sortVariants = {
visible: {opacity: 1, y: 0},
hidden: {opacity: 0, y: '-25%'},
};
return (
<div
role="columnheader"
tabIndex={-1}
aria-colindex={index + 1}
aria-sort={ariaSort}
className={clsx(
style,
'text-muted font-medium text-xs',
allowSorting && 'cursor-pointer'
)}
onMouseEnter={() => {
setIsHovered(true);
}}
onMouseLeave={() => {
setIsHovered(false);
}}
onKeyDown={e => {
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
toggleSorting();
}
}}
onClick={toggleSorting}
>
{column.hideHeader ? (
<div className="sr-only">{column.header()}</div>
) : (
column.header()
)}
<AnimatePresence>
{allowSorting && (
<m.span
variants={sortVariants}
animate={sortVisible ? 'visible' : 'hidden'}
initial={false}
transition={{type: 'tween'}}
key="sort-icon"
className="inline-block ml-6 -mt-2"
data-testid="table-sort-button"
aria-hidden={!sortVisible}
>
<ArrowDownwardIcon
size="xs"
className={clsx(
'text-muted',
orderDir === 'asc' &&
orderBy === sortingKey &&
'rotate-180 transition-transform'
)}
/>
</m.span>
)}
</AnimatePresence>
</div>
);
}
Back to Directory
File Manager