diff --git a/src/components/Table/Table.stories.tsx b/src/components/Table/Table.stories.tsx index c6e3a6b6..69b9f27b 100644 --- a/src/components/Table/Table.stories.tsx +++ b/src/components/Table/Table.stories.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Meta, StoryObj } from "@storybook/react-vite"; @@ -94,3 +94,44 @@ export const Selectable: StoryObj = { ); }, }; + +export const Sortable: StoryObj = { + args: { + headers, + rows, + }, + render: ({ rows, headers, ...props }) => { + const [sort, setSort] = useState<[number, "asc" | "desc"]>([0, "asc"]); + + const sortedHeaders = useMemo( + () => + headers.map((header, headerIndex) => ({ + ...header, + isSortable: true, + sortDir: sort[0] === headerIndex ? sort[1] : undefined, + })), + [headers, sort] + ); + + const sortedRows = useMemo( + () => + [...rows].sort((a, b) => { + const [cellIdx, sortDir] = sort; + const cellA = a.items[cellIdx]?.label?.toString() || ""; + const cellB = b.items[cellIdx]?.label?.toString() || ""; + const result = cellA.localeCompare(cellB, "en", { numeric: true }); + return sortDir === "asc" ? result : -result; + }), + [rows, sort] + ); + + return ( + void setSort([idx, dir])} + /> + ); + }, +}; diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 962d583b..f1639957 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -34,11 +34,13 @@ const StyledHeader = styled.th<{ $size: TableSize }>` text-align: left; `; -const HeaderContentWrapper = styled.div` +const HeaderContentWrapper = styled.div<{ $interactive: boolean }>` display: flex; align-items: center; justify-content: start; gap: inherit; + + ${({ $interactive }) => $interactive && "cursor: pointer;"} `; const SortIcon = styled(Icon)<{ $sortDir: SortDir }>` @@ -57,6 +59,9 @@ const TableHeader = ({ ...delegated }: Omit & { onSort?: () => void; size: TableSize }) => { const isSorted = typeof sortDir === "string"; + const isInteractive = Boolean( + typeof onClick === "function" || (isSortable && typeof onSort === "function") + ); const onHeaderClick = (e: MouseEvent): void => { if (typeof onClick === "function") { onClick(e); @@ -70,7 +75,10 @@ const TableHeader = ({ $size={size} {...delegated} > - + {isSorted && isSortable && sortPosition == "start" && (