47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
// packages/core/src/components/data-table/data-table-header-cell.tsx
|
|
import type { JSX } from "solid-js";
|
|
import { Show } from "solid-js";
|
|
import { useInternalDataTableContext } from "./data-table-context";
|
|
|
|
export interface DataTableHeaderCellProps {
|
|
columnId: string;
|
|
header: string;
|
|
sortable?: boolean;
|
|
}
|
|
|
|
/** Maps the current sort state to an aria-sort attribute value. */
|
|
function toAriaSort(direction: string): JSX.AriaAttributes["aria-sort"] {
|
|
if (direction === "asc") return "ascending";
|
|
if (direction === "desc") return "descending";
|
|
return "none";
|
|
}
|
|
|
|
/**
|
|
* Renders a single `<th>` column header.
|
|
* When the column is sortable, clicking toggles sort asc → desc → none
|
|
* and the appropriate aria-sort attribute and visual indicator are applied.
|
|
*/
|
|
export function DataTableHeaderCell(props: DataTableHeaderCellProps): JSX.Element {
|
|
const ctx = useInternalDataTableContext();
|
|
|
|
const isActive = () => ctx.sortColumnId() === props.columnId;
|
|
const direction = () => (isActive() ? ctx.sortDirection() : "none");
|
|
|
|
function handleClick(): void {
|
|
if (props.sortable) ctx.toggleSort(props.columnId);
|
|
}
|
|
|
|
return (
|
|
<th
|
|
aria-sort={props.sortable ? toAriaSort(direction()) : undefined}
|
|
onClick={handleClick}
|
|
style={{ cursor: props.sortable ? "pointer" : undefined }}
|
|
data-sort-direction={isActive() ? direction() : undefined}
|
|
>
|
|
{props.header}
|
|
<Show when={props.sortable && isActive() && direction() === "asc"}> ▲</Show>
|
|
<Show when={props.sortable && isActive() && direction() === "desc"}> ▼</Show>
|
|
</th>
|
|
);
|
|
}
|