diff --git a/src/components/task-list/task-list-table.module.css b/src/components/task-list/task-list-table.module.css index c80c60e9f..64ffdfdad 100644 --- a/src/components/task-list/task-list-table.module.css +++ b/src/components/task-list/task-list-table.module.css @@ -13,6 +13,10 @@ background-color: #f5f5f5; } +.taskListTableRow.taskListTableRowSelected { + background-color: #f8fafc; +} + .taskListCell { display: table-cell; vertical-align: middle; @@ -22,6 +26,16 @@ padding: 0 6px; } +.taskListCell:not(.taskListCellSelected):hover { + background-color: #eff6ff; + box-shadow: inset 0 0 0 1px #93c5fd; +} + +.taskListCellSelected { + background-color: #dbeafe; + box-shadow: inset 0 0 0 2px #3b82f6; +} + .overlayEditor { position: fixed; z-index: 9999; diff --git a/src/components/task-list/task-list-table.tsx b/src/components/task-list/task-list-table.tsx index 77e0a6adf..efcbdb0e8 100644 --- a/src/components/task-list/task-list-table.tsx +++ b/src/components/task-list/task-list-table.tsx @@ -68,6 +68,11 @@ export const TaskListTableDefault: React.FC<{ const columnIds = columns.map(column => typeof column === "string" ? column : column.id ); + const selectedColumnId = editingState?.columnId ?? null; + const hasValidSelection = + editingState?.mode !== "viewing" && + !!selectedColumnId && + columnIds.includes(selectedColumnId as VisibleField); const resolveColumnId = (column: (typeof columns)[number]) => (typeof column === "string" ? column : column.id) as VisibleField; @@ -244,6 +249,7 @@ export const TaskListTableDefault: React.FC<{ } else if (t.hideChildren === true) { expanderSymbol = "▶"; } + const isSelectedRow = hasValidSelection && editingState?.rowId === t.id; const renderCell = (field: VisibleField) => { switch (field) { @@ -304,16 +310,20 @@ export const TaskListTableDefault: React.FC<{ }; return (
{columns.map(column => { const columnId = resolveColumnId(column); const isSelected = - editingState?.mode !== "viewing" && + hasValidSelection && editingState?.rowId === t.id && - editingState?.columnId === columnId; + selectedColumnId === columnId; const handleCellClick = ( event: React.MouseEvent ) => { @@ -398,7 +408,11 @@ export const TaskListTableDefault: React.FC<{ return (
({ + id, + name, + // Using 2026 as test data - far enough in the future to avoid date-related issues + start: new Date(2026, 0, 1), + end: new Date(2026, 0, 10), + progress: 50, + type: "task", +}); + +const createEditingContext = ( + mode: "viewing" | "selected" | "editing", + rowId: string | null, + columnId: VisibleField | null +) => ({ + editingState: { + mode, + rowId, + columnId, + trigger: null, + pending: false, + errorMessage: null, + }, + selectCell: jest.fn(), + startEditing: jest.fn(), +}); + +describe("TaskListTable cell highlight", () => { + const defaultProps = { + rowHeight: 40, + rowWidth: "155px", + fontFamily: "Arial", + fontSize: "14px", + tasks: [createMockTask("task-1", "Task 1"), createMockTask("task-2", "Task 2")], + selectedTaskId: "", + setSelectedTask: jest.fn(), + onExpanderClick: jest.fn(), + visibleFields: ["name", "start"] as VisibleField[], + effortDisplayUnit: "MH" as const, + onCellCommit: jest.fn().mockResolvedValue(undefined), + }; + + it("adds selected cell and row classes when a cell is selected", () => { + const context = createEditingContext("selected", "task-1", "name"); + + render( + + + + ); + + const selectedCell = document.querySelector( + '[data-row-id="task-1"][data-column-id="name"]' + ) as HTMLElement; + const selectedRow = selectedCell.closest( + `.${styles.taskListTableRow}` + ) as HTMLElement; + const otherCell = document.querySelector( + '[data-row-id="task-1"][data-column-id="start"]' + ) as HTMLElement; + + expect(selectedCell).toHaveClass(styles.taskListCellSelected); + expect(selectedRow).toHaveClass(styles.taskListTableRowSelected); + expect(otherCell).not.toHaveClass(styles.taskListCellSelected); + }); + + it("does not highlight when the selected column is not visible", () => { + const context = createEditingContext("selected", "task-1", "end"); + + render( + + + + ); + + const cell = document.querySelector( + '[data-row-id="task-1"][data-column-id="name"]' + ) as HTMLElement; + const row = cell.closest(`.${styles.taskListTableRow}`) as HTMLElement; + + expect(cell).not.toHaveClass(styles.taskListCellSelected); + expect(row).not.toHaveClass(styles.taskListTableRowSelected); + }); +});