first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
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-xs font-medium text-muted',
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="opacity-0">{column.header()}</div>
) : (
column.header()
)}
<AnimatePresence>
{allowSorting && (
<m.span
variants={sortVariants}
animate={sortVisible ? 'visible' : 'hidden'}
initial={false}
transition={{type: 'tween'}}
key="sort-icon"
className="-mt-2 ml-6 inline-block"
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>
);
}