diff --git a/packages/components/src/components/Table/Table.stories.tsx b/packages/components/src/components/Table/Table.stories.tsx
index d5098601..ad6149f6 100644
--- a/packages/components/src/components/Table/Table.stories.tsx
+++ b/packages/components/src/components/Table/Table.stories.tsx
@@ -1,6 +1,10 @@
import { useState, useMemo } from 'react';
-import { IconArrowDownS16, IconArrowUpS16 } from '@koobiq/react-icons';
+import {
+ IconArrowDownS16,
+ IconArrowUpS16,
+ IconArrowUpArrowDown16,
+} from '@koobiq/react-icons';
import type { Meta, StoryObj } from '@storybook/react';
import type {
@@ -727,9 +731,16 @@ export const RenderSortIcon: Story = {
aria-label="Fast animals"
{...(sortDescriptor && { sortDescriptor })}
onSortChange={handleSortChange}
- renderSortIcon={({ direction }) =>
- direction === 'ascending' ? :
- }
+ renderSortIcon={({ direction }) => {
+ if (!direction)
+ return ;
+
+ return direction === 'ascending' ? (
+
+ ) : (
+
+ );
+ }}
selectionMode="multiple"
{...args}
>
diff --git a/packages/components/src/components/Table/Table.test.tsx b/packages/components/src/components/Table/Table.test.tsx
index 2de809ab..bec68562 100644
--- a/packages/components/src/components/Table/Table.test.tsx
+++ b/packages/components/src/components/Table/Table.test.tsx
@@ -203,4 +203,62 @@ describe('Table', () => {
expect(onNavigate).toBeCalled();
});
+
+ it('should pass unsorted state to renderSortIcon for sortable column', () => {
+ const renderSortIcon = vi.fn(() => );
+
+ render(
+
+
+
+ Name
+
+
+
+ {(item) => (
+
+ {item.name}
+
+ )}
+
+
+ );
+
+ expect(renderSortIcon).toBeCalledWith({
+ direction: undefined,
+ isActive: false,
+ });
+
+ expect(screen.getByTestId('sort-icon')).toBeInTheDocument();
+ });
+
+ it('should pass active sort direction to renderSortIcon', () => {
+ const renderSortIcon = vi.fn(() => );
+
+ render(
+
+
+
+ Name
+
+
+
+ {(item) => (
+
+ {item.name}
+
+ )}
+
+
+ );
+
+ expect(renderSortIcon).toBeCalledWith({
+ direction: 'ascending',
+ isActive: true,
+ });
+ });
});
diff --git a/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.module.css b/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.module.css
index d61424db..30be4205 100644
--- a/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.module.css
+++ b/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.module.css
@@ -97,6 +97,10 @@
.sortIcon {
display: flex;
visibility: hidden;
+ opacity: 1;
+ align-items: center;
+ justify-content: center;
+ inline-size: var(--kbq-size-l);
&.active {
visibility: visible;
diff --git a/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.tsx b/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.tsx
index a1ba5822..1f2b2683 100644
--- a/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.tsx
+++ b/packages/components/src/components/Table/components/TableColumnHeader/TableColumnHeader.tsx
@@ -2,7 +2,7 @@
import { useRef } from 'react';
-import { useFocusRing, mergeProps, clsx } from '@koobiq/react-core';
+import { useFocusRing, mergeProps, clsx, useHover } from '@koobiq/react-core';
import { IconChevronUpS16, IconChevronDownS16 } from '@koobiq/react-icons';
import type {
TableState,
@@ -58,18 +58,32 @@ export function TableColumnHeader({
}: ColumnProps = column.props;
const { isFocusVisible, focusProps } = useFocusRing();
+ const { isHovered, hoverProps } = useHover({ isDisabled: !allowsSorting });
const isActive = state.sortDescriptor?.column === column.key;
const direction = isActive ? state.sortDescriptor?.direction : undefined;
- const defaultIcon =
- direction === 'ascending' ? : ;
+ const defaultIcon = () => {
+ if (direction === 'ascending') {
+ return ;
+ }
- const iconToRender = renderSortIcon?.({ direction, isActive }) ?? defaultIcon;
+ if (direction === 'descending') {
+ return ;
+ }
+
+ return null;
+ };
+
+ const iconToRender =
+ renderSortIcon?.({ direction, isActive }) ?? defaultIcon();
const columnSortIcon = allowsSorting && (
-
+
{iconToRender}
);
@@ -91,7 +105,7 @@ export function TableColumnHeader({
data-valign={valign || undefined}
data-allows-sorting={allowsSorting || undefined}
data-allows-resizing={isResizable || undefined}
- {...mergeProps(columnHeaderProps, focusProps)}
+ {...mergeProps(columnHeaderProps, hoverProps, focusProps)}
style={{
...styleProp,
inlineSize: layoutState?.getColumnWidth(column.key),