diff --git a/packages/pxweb2-ui/src/lib/components/Table/Table.module.scss b/packages/pxweb2-ui/src/lib/components/Table/Table.module.scss
index 0a6caeb66..0287a5d46 100644
--- a/packages/pxweb2-ui/src/lib/components/Table/Table.module.scss
+++ b/packages/pxweb2-ui/src/lib/components/Table/Table.module.scss
@@ -17,11 +17,7 @@
tbody tr {
&:hover {
- background: var(--px-color-surface-subtle) !important;
-
- th {
- background: var(--px-color-surface-subtle) !important;
- }
+ background: var(--px-color-surface-subtle);
}
}
@@ -124,6 +120,7 @@
}
th.stub-9 {
border-left: none;
+
@media screen and (min-width: fixed.$breakpoints-small-min-width) {
padding-left: 156px;
}
@@ -140,7 +137,6 @@
text-align: right;
border-top: 1px solid var(--px-color-border-default);
border-left: 1px solid var(--px-color-border-default);
-
@media screen and (min-width: fixed.$breakpoints-small-min-width) {
padding: 8px 12px;
}
@@ -254,3 +250,6 @@
border: none;
}
}
+.table td.colHover {
+ background: var(--px-color-surface-subtle);
+}
diff --git a/packages/pxweb2-ui/src/lib/components/Table/Table.spec.tsx b/packages/pxweb2-ui/src/lib/components/Table/Table.spec.tsx
index 9aa13c68c..277f45588 100644
--- a/packages/pxweb2-ui/src/lib/components/Table/Table.spec.tsx
+++ b/packages/pxweb2-ui/src/lib/components/Table/Table.spec.tsx
@@ -1,6 +1,5 @@
-import { render } from '@testing-library/react';
+import { render, fireEvent } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
-
import Table from './Table';
import { pxTable } from './testData';
@@ -45,4 +44,25 @@ describe('Table', () => {
});
expect(found).toBe(false);
});
+
+ it('highlights column on header hover', () => {
+ const { container } = render(
);
+ console.log(container.innerHTML); // Debug: check for data-col and stub classes
+
+ // Find a leaf header cell
+ const leafHeader = container.querySelector(
+ 'thead tr:last-child th[data-col]',
+ );
+ expect(leafHeader).toBeTruthy();
+
+ // Simulate mouseover
+ fireEvent.mouseOver(leafHeader!);
+
+ // Find highlighted data cells
+ const col = leafHeader!.getAttribute('data-col');
+ const highlightedCells = container.querySelectorAll(
+ `td[data-col="${col}"][class*="colHover"]`,
+ );
+ expect(highlightedCells.length).toBeGreaterThan(0);
+ });
});
diff --git a/packages/pxweb2-ui/src/lib/components/Table/Table.tsx b/packages/pxweb2-ui/src/lib/components/Table/Table.tsx
index 37a77140c..af2335840 100644
--- a/packages/pxweb2-ui/src/lib/components/Table/Table.tsx
+++ b/packages/pxweb2-ui/src/lib/components/Table/Table.tsx
@@ -1,4 +1,4 @@
-import { memo, useMemo } from 'react';
+import { memo, useMemo, useRef, useEffect } from 'react';
import cl from 'clsx';
import classes from './Table.module.scss';
@@ -115,8 +115,67 @@ export const Table = memo(function Table({
headingDataCellCodes[i] = dataCellCodes;
}
+ const tableRef = useRef(null);
+
+ useEffect(() => {
+ const table = tableRef.current;
+ if (!table) {
+ return;
+ }
+
+ let currentCol: string | null = null;
+
+ function clear() {
+ for (const cell of Array.from(
+ table!.querySelectorAll('.' + classes.colHover),
+ )) {
+ cell.classList.remove(classes.colHover);
+ }
+ currentCol = null;
+ }
+
+ function handleOver(e: MouseEvent) {
+ // Only highlight if hovering a data cell (td[data-col]) or a leaf header cell (th[data-col] in last header row)
+ const td = (e.target as HTMLElement).closest('td[data-col]');
+ const th = (e.target as HTMLElement).closest(
+ 'thead tr:last-child th[data-col]',
+ );
+ // If hovering stub or emptyTableData, clear highlight
+ if (
+ (e.target as HTMLElement).closest('.stub') ||
+ (e.target as HTMLElement).closest('.emptyTableData') ||
+ (!td && !th)
+ ) {
+ clear();
+ return;
+ }
+ // Determine column
+ const cell = td || th;
+ const col = (cell as HTMLElement).dataset.col;
+ if (!col || col === currentCol) {
+ return;
+ }
+ clear();
+ // Highlight only data cells in the same column
+ for (const cell of Array.from(
+ table!.querySelectorAll(`td[data-col="${col}"]`),
+ )) {
+ cell.classList.add(classes.colHover);
+ }
+ currentCol = col;
+ }
+
+ table.addEventListener('mouseover', handleOver);
+ table.addEventListener('mouseleave', clear);
+ return () => {
+ table.removeEventListener('mouseover', handleOver);
+ table.removeEventListener('mouseleave', clear);
+ };
+ }, []);
+
return (
@@ -224,6 +283,12 @@ export function createHeading(
idxRepetitionCurrentHeadingLevel === 1 &&
table.stub.length === 0,
})}
+ // Only add data-col for leaf header row
+ data-col={
+ idxHeadingLevel === table.heading.length - 1
+ ? String(columnIndex + tableMeta.columnOffset)
+ : undefined
+ }
>
{variable.values[i].label}
,
@@ -608,7 +673,11 @@ function fillEmpty(
// Loop through all data columns in the table
for (let i = 0; i < maxCols; i++) {
- tableRow.push(| {emptyText} | );
+ tableRow.push(
+
+ {emptyText}
+ | ,
+ );
}
}
@@ -632,7 +701,6 @@ function fillData(
const maxCols = tableMeta.columns - tableMeta.columnOffset;
// Loop through all data columns in the table
-
for (let i = 0; i < maxCols; i++) {
// Merge the metadata structure for the dimensions of the stub and header cells
const dataCellCodes = stubDataCellCodes.concat(headingDataCellCodes[i]);
@@ -654,7 +722,11 @@ function fillData(
const dataValue = getPxTableData(table.data.cube, dimensions);
tableRow.push(
-
+ |
{dataValue?.formattedValue}
| ,
);