Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

[terra-table] [terra-data-grid] Add column span functionality to FlowsheetDataGrid and Table #2096

Merged
merged 53 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
630224c
Add column span functionality to FlowsheetDataGrid and Table
Mar 20, 2024
e97f173
Disable column highlighting for columns with columnspan greater than 1
Mar 20, 2024
98f046a
Cover an edge case for columnSpan defined as 1
Mar 20, 2024
f28d1bc
Add changelogs, Fix lint errors
Mar 20, 2024
756cbf5
Add WDIO tests, code cleanup
Mar 21, 2024
fe9b4ce
Fix lint errors
Mar 21, 2024
a223d2b
Update snapshots, code cleanup
Mar 21, 2024
c38a2a2
Update data grid changelog
Mar 21, 2024
9c5546b
Update docs
Mar 21, 2024
3ed8202
Merge branch 'main' into fdg-column-span
nikhitasharma Mar 21, 2024
6720132
Fix lint
Mar 21, 2024
c620ad7
Update Actions column header to support column span
Mar 21, 2024
6fd4f66
Update packages/terra-framework-docs/src/terra-dev-site/doc/data-grid…
nikhitasharma Mar 21, 2024
67929c5
Keyboard navigation, multi select and pinned columns css updates
Apr 5, 2024
cb3d7e1
Merge branch 'fdg-column-span' of https://github.com/cerner/terra-fra…
Apr 5, 2024
087ab29
Update docs
Apr 5, 2024
5de78ec
Resolve lint errors
Apr 5, 2024
80f29ed
Support pinned column with columnspans, fix scroll issues, update sna…
Apr 8, 2024
5cf6bf1
Merge branch 'main' of https://github.com/cerner/terra-framework into…
Apr 8, 2024
f791a65
Update snapshots
Apr 8, 2024
744c0c1
Fix jest tests
Apr 8, 2024
31e55a1
Resolve lint errors
Apr 8, 2024
3c86491
Resolve review comments
Apr 9, 2024
3edd3cc
Resolve comments, fix lint errors
Apr 9, 2024
266e7d0
Add example for Column Span with Header Actions
Apr 10, 2024
426e523
Merge remote-tracking branch 'origin' into fdg-column-span
cm9361 Apr 11, 2024
61ce095
Resolve column header selection via keyboard navigation
cm9361 Apr 11, 2024
71e1d4d
Resolve Home and End key navigation issue
Apr 11, 2024
6a79a4f
Fix navigation with column header action rows.
cm9361 Apr 11, 2024
aabecaa
Merge branch 'fdg-column-span' of https://github.com/cerner/terra-fra…
cm9361 Apr 11, 2024
b7cf09c
Remove redundant code, Update home and end key logic
Apr 11, 2024
6be0629
Merge branch 'fdg-column-span' of https://github.com/cerner/terra-fra…
Apr 11, 2024
c602d3c
Update focus logic when tabbing in and out of DataGrid
Apr 11, 2024
9da0845
Resolve review comments
Apr 12, 2024
6882e7d
Update snapshots
Apr 12, 2024
0f2522d
Resolve review comments
Apr 15, 2024
8915402
Reorganize column span code to Table level
Apr 15, 2024
a893464
Flowsheet level ref updates, code cleanup
Apr 15, 2024
d6218c8
Merge branch 'main' of https://github.com/cerner/terra-framework into…
Apr 15, 2024
e149624
Resolve lint errors
Apr 15, 2024
2f3b688
Fix navigation between sections, add resizable columns table example …
Apr 16, 2024
9ee2636
Resolve lint errors
Apr 16, 2024
b3eeed3
Add new tests, examples, update snapshots
Apr 16, 2024
a162cdc
Resolve lint errors
Apr 16, 2024
ea931f3
Fix changelog entries
Apr 16, 2024
a49419c
Update snapshots
Apr 16, 2024
e25f2a4
Update table column span snapshots
Apr 16, 2024
6e49847
Add columnSpanIndex info to callbacks
Apr 16, 2024
f2a16e9
Fix Column Span Actions examples and tests
Apr 16, 2024
5a7fc6e
Resolve lint error
Apr 16, 2024
6f09b55
Update jest snapshot
Apr 16, 2024
8f731e0
Resolve lint error
Apr 16, 2024
e3bb148
Update Column Span actions wdio snapshots
Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/terra-data-grid/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

* Added
* Added column span functionality to FlowsheetDataGrid.
* Added `isAutoFocusEnabled` prop to allow auto focus of interactable elements when the only interactable element is a button or hyperlink.

## 1.25.0 - (April 4, 2024)
Expand Down
42 changes: 30 additions & 12 deletions packages/terra-data-grid/src/DataGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,25 @@ const DataGrid = forwardRef((props, ref) => {
} = props;

const displayedColumns = (hasSelectableRows ? [WorklistDataGridUtils.ROW_SELECTION_COLUMN] : []).concat(pinnedColumns).concat(overflowColumns);
// Create new displayedColumns object to account for column spans
const displayedColumnsWithColumnSpan = useMemo(() => {
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
let i = 0;
const newDisplayedColumns = [];
displayedColumns.forEach((column) => {
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
if (column.columnSpan > 1) {
newDisplayedColumns[i] = { ...column, columnSpanIndex: 0 };
i += 1;
for (let counter = column.columnSpan; counter > 1; counter -= 1) {
newDisplayedColumns[i] = { id: `${column.id}`, columnSpanIndex: `${column.columnSpan - counter + 1}` };
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
i += 1;
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
newDisplayedColumns[i] = column;
i += 1;
}
});
return newDisplayedColumns;
}, [displayedColumns]);
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved

// By default, all grid-based components have selectable cells.
const dataGridRows = useMemo(() => (rows.map((row) => ({
Expand Down Expand Up @@ -241,8 +260,8 @@ const DataGrid = forwardRef((props, ref) => {
// functions

const isRowSelectionCell = useCallback((columnIndex) => (
hasSelectableRows && columnIndex < displayedColumns.length && displayedColumns[columnIndex].id === WorklistDataGridUtils.ROW_SELECTION_COLUMN.id
), [displayedColumns, hasSelectableRows]);
hasSelectableRows && columnIndex < displayedColumnsWithColumnSpan.length && displayedColumnsWithColumnSpan[columnIndex].id === WorklistDataGridUtils.ROW_SELECTION_COLUMN.id
), [displayedColumnsWithColumnSpan, hasSelectableRows]);

const isSection = useCallback((rowIndex) => (
grid.current.rows[rowIndex].hasAttribute('data-section-id')
Expand All @@ -253,10 +272,10 @@ const DataGrid = forwardRef((props, ref) => {
setFocusedRow(newRowIndex);
setFocusedCol(newColIndex);

if (newColIndex < displayedColumns.length) {
if (newColIndex < displayedColumnsWithColumnSpan.length) {
focusedCellRef.current = {
rowId: grid.current.rows[newRowIndex].getAttribute('data-row-id'),
columnId: displayedColumns[newColIndex].id,
columnId: displayedColumnsWithColumnSpan[newColIndex].id,
};
}

Expand Down Expand Up @@ -304,7 +323,7 @@ const DataGrid = forwardRef((props, ref) => {
}

focusedCell?.focus();
}, [displayedColumns, isSection, hasColumnHeaderActions, isAutoFocusEnabled, isRowSelectionCell]);
}, [displayedColumnsWithColumnSpan, isSection, hasColumnHeaderActions, isAutoFocusEnabled, isRowSelectionCell]);

// The focus is handled by the DataGrid. However, there are times
// when the other components may want to change the currently focus
Expand All @@ -327,7 +346,7 @@ const DataGrid = forwardRef((props, ref) => {
if (!isSection(toCell.row)) {
// Obtain coordinate rectangles for grid container, column header, and new cell selection
const gridContainerRect = tableContainerRef.current.getBoundingClientRect();
const columnHeaderRect = grid.current.rows[0].cells[toCell.col].getBoundingClientRect();
const columnHeaderRect = grid.current.rows[0].getBoundingClientRect();
const nextCellRect = grid.current.rows[toCell.row].cells[toCell.col].getBoundingClientRect();

// Calculate horizontal scroll offset for right boundary
Expand Down Expand Up @@ -358,7 +377,6 @@ const DataGrid = forwardRef((props, ref) => {
tableContainerRef.current.scrollBy(0, scrollOffsetY);
}
}

setFocusedRowCol(toCell.row, toCell.col, true);
};

Expand Down Expand Up @@ -479,7 +497,7 @@ const DataGrid = forwardRef((props, ref) => {
if (event.metaKey) {
// Mac: Cmd + Right
// Win: End
nextCol = displayedColumns.length - 1;
nextCol = displayedColumnsWithColumnSpan.length - 1;

if (event.ctrlKey) {
// Mac: Ctrl + Cmd + Right
Expand All @@ -498,7 +516,7 @@ const DataGrid = forwardRef((props, ref) => {
}
break;
case KeyCode.KEY_END:
nextCol = displayedColumns.length - 1; // Col are zero based.
nextCol = displayedColumnsWithColumnSpan.length - 1; // Col are zero based.
if (event.ctrlKey) {
// Though rows are zero based, the header is the first row so the rowsLength will
// always be one more than then actual number of data rows.
Expand Down Expand Up @@ -528,7 +546,7 @@ const DataGrid = forwardRef((props, ref) => {
onCellRangeSelect(cellCoordinates.row, cellCoordinates.col, event.keyCode);
}

if (nextRow >= gridRowCount || nextCol >= displayedColumns.length) {
if (nextRow >= gridRowCount || nextCol >= displayedColumnsWithColumnSpan.length) {
event.preventDefault(); // prevent the page from moving with the arrow keys.
return;
}
Expand Down Expand Up @@ -578,9 +596,9 @@ const DataGrid = forwardRef((props, ref) => {

// Check for last focused column ID. If found set the index. Otherwise set it to the last focused column or last index.
if (focusedCellRef.current.columnId) {
newColumnIndex = displayedColumns.findIndex(column => column.id === focusedCellRef.current.columnId);
newColumnIndex = displayedColumnsWithColumnSpan.findIndex(column => column.id === focusedCellRef.current.columnId);
newColumnIndex = newColumnIndex === -1
? Math.min(focusedCol, displayedColumns.length - 1)
? Math.min(focusedCol, displayedColumnsWithColumnSpan.length - 1)
: newColumnIndex;
}

Expand Down
72 changes: 54 additions & 18 deletions packages/terra-data-grid/src/FlowsheetDataGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,38 @@ function FlowsheetDataGrid(props) {
isResizable: false,
})), [columns]);

const displayedColumnsWithColumnSpan = useMemo(() => {
let i = 0;
const newDisplayedColumns = [];
columns.forEach((column) => {
if (column.columnSpan > 1) {
newDisplayedColumns[i] = {
...column,
columnSpanIndex: 0,
isSelectable: false,
isSelected: false,
isResizable: false,
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
};
i += 1;
for (let counter = column.columnSpan; counter > 1; counter -= 1) {
newDisplayedColumns[i] = {
id: `${column.id}`, columnSpanIndex: `${column.columnSpan - counter + 1}`, isSelectable: false, isResizable: false, isSelected: false,
};
i += 1;
}
} else {
newDisplayedColumns[i] = {
...column,
isSelectable: false,
isSelected: false,
isResizable: false,
};
i += 1;
}
});
return newDisplayedColumns;
}, [columns]);
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved

const pinnedColumns = flowsheetColumns.length ? [flowsheetColumns[0]] : [];
const overflowColumns = flowsheetColumns.length > 1 ? flowsheetColumns.slice(1) : [];

Expand Down Expand Up @@ -238,7 +270,7 @@ function FlowsheetDataGrid(props) {
rowsToSearch.forEach((row) => {
row.cells.forEach((cell, cellIndex) => {
if (cell.isSelected) {
newSelectedCells.push({ rowId: row.id, columnId: columns[cellIndex].id });
newSelectedCells.push({ rowId: row.id, columnId: displayedColumnsWithColumnSpan[cellIndex].id });
}
});
});
Expand All @@ -253,25 +285,23 @@ function FlowsheetDataGrid(props) {
} else if (selectedCells.current.length) {
setCellSelectionAriaLiveMessage(intl.formatMessage({ id: 'Terra.flowsheetDataGrid.cells-selected' }, { cellCount: selectedCells.current.length }));
}
}, [intl, rowsToSearch, columns, setCellSelectionAriaLiveMessage]);
}, [intl, rowsToSearch, displayedColumnsWithColumnSpan, setCellSelectionAriaLiveMessage]);

const selectCellRange = useCallback((rowId, columnId, sectionId) => {
const selectCellRange = useCallback((rowId, columnId, columnIndex, sectionId) => {
if (anchorCell.current === null) {
return;
}

const anchorRowIndex = rowsToSearch.findIndex(row => row.id === anchorCell.current.rowId);
const anchorColumnIndex = columns.findIndex(col => col.id === anchorCell.current.columnId);

const anchorColumnIndex = anchorCell.current.columnIndex;
const rowIndex = rowsToSearch.findIndex(row => row.id === rowId);
const columnIndex = columns.findIndex(col => col.id === columnId);
// const columnIndex = displayedColumnsWithColumnSpan.findIndex(col => col.id === columnId);

// Determine the boundaries of selected region.
let rowIndexTopBound = Math.min(anchorRowIndex, rowIndex);
let rowIndexBottomBound = Math.max(anchorRowIndex, rowIndex);
const columnIndexLeftBound = Math.min(anchorColumnIndex, columnIndex);
const columnIndexRightBound = Math.max(anchorColumnIndex, columnIndex);

if (flowsheetSections) {
const selectedSection = flowsheetSections.find(section => section.id === sectionId);
const sectionTopBound = rowsToSearch.findIndex(row => row.sectionId === sectionId);
Expand All @@ -285,15 +315,17 @@ function FlowsheetDataGrid(props) {
for (let rowIdx = rowIndexTopBound; rowIdx <= rowIndexBottomBound; rowIdx += 1) {
const rowIdToSelect = rowsToSearch[rowIdx].id;
for (let colIdx = columnIndexLeftBound; colIdx <= columnIndexRightBound; colIdx += 1) {
const columnIdToSelect = columns[colIdx].id;
cellsToSelect.push({ rowId: rowIdToSelect, columnId: columnIdToSelect, sectionId });
const columnIdToSelect = displayedColumnsWithColumnSpan[colIdx].id;
cellsToSelect.push({
rowId: rowIdToSelect, columnId: columnIdToSelect, columnIndex: colIdx, sectionId,
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
});
}
}

if (onCellRangeSelect) {
onCellRangeSelect(cellsToSelect);
}
}, [rowsToSearch, flowsheetSections, columns, onCellRangeSelect]);
}, [rowsToSearch, flowsheetSections, displayedColumnsWithColumnSpan, onCellRangeSelect]);

const handleCellSelection = useCallback((selectionDetails, event) => {
// Call onRowSelect for row header column
Expand All @@ -302,12 +334,15 @@ function FlowsheetDataGrid(props) {
onRowSelect({ rowId: selectionDetails.rowId, sectionId: selectionDetails.sectionId, isMetaPressed: selectionDetails.isMetaPressed });
}
} else if (selectionDetails.isShiftPressed && anchorCell.current !== null) {
selectCellRange(selectionDetails.rowId, selectionDetails.columnId, selectionDetails.sectionId);
selectCellRange(selectionDetails.rowId, selectionDetails.columnId, selectionDetails.columnIndex, selectionDetails.sectionId);
} else if (onCellSelect) {
anchorCell.current = { rowId: selectionDetails.rowId, columnId: selectionDetails.columnId, sectionId: selectionDetails.sectionId };
anchorCell.current = {
rowId: selectionDetails.rowId, columnId: selectionDetails.columnId, columnIndex: selectionDetails.columnIndex, sectionId: selectionDetails.sectionId,
};
onCellSelect({
rowId: selectionDetails.rowId,
columnId: selectionDetails.columnId,
columnIndex: selectionDetails.columnIndex,
sectionId: selectionDetails.sectionId,
isMetaPressed: selectionDetails.isMetaPressed,
}, event);
Expand Down Expand Up @@ -339,7 +374,8 @@ function FlowsheetDataGrid(props) {
if (anchorCell.current === null && !gridRef.rows[rowIndex].hasAttribute('data-section-id')) {
anchorCell.current = {
rowId: gridRef.rows[rowIndex].getAttribute('data-row-id'),
columnId: columns[columnIndex].id,
columnId: displayedColumnsWithColumnSpan[columnIndex].id,
columnIndex,
nikhitasharma marked this conversation as resolved.
Show resolved Hide resolved
sectionId: anchorSectionId,
};
}
Expand Down Expand Up @@ -374,11 +410,11 @@ function FlowsheetDataGrid(props) {

if (nextColumnIndex <= 0) {
nextColumnIndex = 1;
} else if (nextColumnIndex >= columns.length) {
nextColumnIndex = columns.length - 1;
} else if (nextColumnIndex >= displayedColumnsWithColumnSpan.length) {
nextColumnIndex = displayedColumnsWithColumnSpan.length - 1;
}

const nextColumnId = columns[nextColumnIndex].id;
const nextColumnId = displayedColumnsWithColumnSpan[nextColumnIndex].id;
const nextRowId = gridRef.rows[nextRowIndex].getAttribute('data-row-id');

if (!gridRef.rows[nextRowIndex].hasAttribute('data-section-id')) {
Expand All @@ -391,9 +427,9 @@ function FlowsheetDataGrid(props) {
break;
}
}
selectCellRange(nextRowId, nextColumnId, nextSectionId);
selectCellRange(nextRowId, nextColumnId, nextColumnIndex, nextSectionId);
}
}, [flowsheetSections, columns, selectCellRange]);
}, [flowsheetSections, displayedColumnsWithColumnSpan, selectCellRange]);

const handleKeyUp = (event) => {
const key = event.keyCode;
Expand Down
Loading
Loading