Skip to content

Commit 5079a24

Browse files
Directly apply width to table column and add hover events to table header for S2 (#6719)
* Directly apply width to table column so we dont assume a specific virtualized DOM structure * Add support for hover events on TableHeader used in S2 so we can tell the resize nubbins to all render when the header is hovered --------- Co-authored-by: Robert Snow <[email protected]>
1 parent 4b27a0c commit 5079a24

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

packages/react-aria-components/src/Table.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,15 @@ export function useTableOptions(): TableOptionsContextValue {
522522
return useContext(TableOptionsContext)!;
523523
}
524524

525-
export interface TableHeaderProps<T> extends StyleProps {
525+
export interface TableHeaderRenderProps {
526+
/**
527+
* Whether the table header is currently hovered with a mouse.
528+
* @selector [data-hovered]
529+
*/
530+
isHovered: boolean
531+
}
532+
533+
export interface TableHeaderProps<T> extends StyleRenderProps<TableHeaderRenderProps>, HoverEvents {
526534
/** A list of table columns. */
527535
columns?: T[],
528536
/** A list of `Column(s)` or a function. If the latter, a list of columns must be provided using the `columns` prop. */
@@ -552,13 +560,27 @@ export const TableHeader = /*#__PURE__*/ createBranchComponent(
552560

553561
let THead = useElementType('thead');
554562
let {rowGroupProps} = useTableRowGroup();
563+
let {hoverProps, isHovered} = useHover({
564+
onHoverStart: props.onHoverStart,
565+
onHoverChange: props.onHoverChange,
566+
onHoverEnd: props.onHoverEnd
567+
});
568+
569+
let renderProps = useRenderProps({
570+
className: props.className,
571+
style: props.style,
572+
defaultClassName: 'react-aria-TableHeader',
573+
values: {
574+
isHovered
575+
}
576+
});
577+
555578
return (
556579
<THead
557-
{...filterDOMProps(props as any)}
558-
{...rowGroupProps}
580+
{...mergeProps(filterDOMProps(props as any), rowGroupProps, hoverProps)}
581+
{...renderProps}
559582
ref={ref}
560-
className={props.className ?? 'react-aria-TableHeader'}
561-
style={props.style}>
583+
data-hovered={isHovered || undefined}>
562584
{headerRows}
563585
</THead>
564586
);
@@ -711,7 +733,7 @@ export const Column = /*#__PURE__*/ createLeafComponent('column', (props: Column
711733

712734
let style = renderProps.style;
713735
if (layoutState) {
714-
style = {...style, width: isVirtualized ? undefined : layoutState.getColumnWidth(column.key)};
736+
style = {...style, width: layoutState.getColumnWidth(column.key)};
715737
}
716738

717739
let TH = useElementType('th');

packages/react-aria-components/test/Table.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,34 @@ describe('Table', () => {
410410
expect(onHoverEnd).not.toHaveBeenCalled();
411411
});
412412

413+
it('should support hover events on the TableHeader', async () => {
414+
let onHoverStart = jest.fn();
415+
let onHoverChange = jest.fn();
416+
let onHoverEnd = jest.fn();
417+
let {getAllByRole} = renderTable({
418+
tableHeaderProps: {className: ({isHovered}) => isHovered ? 'hover' : '', onHoverStart, onHoverChange, onHoverEnd}
419+
});
420+
let headerRow = getAllByRole('rowgroup')[0];
421+
422+
expect(headerRow).not.toHaveAttribute('data-hovered');
423+
expect(headerRow).not.toHaveClass('hover');
424+
expect(onHoverStart).not.toHaveBeenCalled();
425+
expect(onHoverChange).not.toHaveBeenCalled();
426+
expect(onHoverEnd).not.toHaveBeenCalled();
427+
428+
await user.hover(headerRow);
429+
expect(headerRow).toHaveAttribute('data-hovered');
430+
expect(headerRow).toHaveClass('hover');
431+
expect(onHoverStart).toHaveBeenCalledTimes(1);
432+
expect(onHoverChange).toHaveBeenCalledTimes(1);
433+
434+
await user.unhover(headerRow);
435+
expect(headerRow).not.toHaveAttribute('data-hovered');
436+
expect(headerRow).not.toHaveClass('hover');
437+
expect(onHoverEnd).toHaveBeenCalledTimes(1);
438+
expect(onHoverChange).toHaveBeenCalledTimes(2);
439+
});
440+
413441
it('should support focus ring', async () => {
414442
let {getAllByRole} = renderTable({
415443
rowProps: {className: ({isFocusVisible}) => isFocusVisible ? 'focus' : ''},

starters/tailwind/src/Table.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function TableHeader<T extends object>(props: TableHeaderProps<T>) {
7474
let { selectionBehavior, selectionMode, allowsDragging } = useTableOptions();
7575

7676
return (
77-
<AriaTableHeader {...props} className={twMerge('sticky top-0 z-10 bg-gray-100/60 dark:bg-zinc-700/60 backdrop-blur-md supports-[-moz-appearance:none]:bg-gray-100 dark:supports-[-moz-appearance:none]:bg-zinc-700 forced-colors:bg-[Canvas] rounded-t-lg border-b dark:border-b-zinc-700', props.className)}>
77+
<AriaTableHeader {...props} className={composeTailwindRenderProps(props.className, 'sticky top-0 z-10 bg-gray-100/60 dark:bg-zinc-700/60 backdrop-blur-md supports-[-moz-appearance:none]:bg-gray-100 dark:supports-[-moz-appearance:none]:bg-zinc-700 forced-colors:bg-[Canvas] rounded-t-lg border-b dark:border-b-zinc-700')}>
7878
{/* Add extra columns for drag and drop and selection. */}
7979
{allowsDragging && <Column />}
8080
{selectionBehavior === 'toggle' && (

0 commit comments

Comments
 (0)