From b7d65f715a332d48f2c7dd7f9824448d7b76fdca Mon Sep 17 00:00:00 2001
From: Charles McDonald <59840481+cm9361@users.noreply.github.com>
Date: Mon, 8 Apr 2024 07:51:23 -0500
Subject: [PATCH] Cell auto focus property (#2123)
---
packages/terra-data-grid/CHANGELOG.md | 3 +
packages/terra-data-grid/src/DataGrid.jsx | 13 +++-
.../terra-data-grid/src/FlowsheetDataGrid.jsx | 7 ++
.../terra-data-grid/src/WorklistDataGrid.jsx | 7 ++
packages/terra-framework-docs/CHANGELOG.md | 3 +
.../WorklistDataGridAutoFocusableCell.doc.mdx | 19 +++++
.../WorklistDataGridAutoFocusableCell.jsx | 69 +++++++++++++++++++
.../data-grid/DataGridFocusableCell.test.jsx | 1 +
packages/terra-table/CHANGELOG.md | 3 +
.../terra-table/src/subcomponents/Cell.jsx | 5 ++
10 files changed, 127 insertions(+), 3 deletions(-)
create mode 100644 packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.doc.mdx
create mode 100644 packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.jsx
diff --git a/packages/terra-data-grid/CHANGELOG.md b/packages/terra-data-grid/CHANGELOG.md
index a9d29e18918..b4ece33f3b2 100644
--- a/packages/terra-data-grid/CHANGELOG.md
+++ b/packages/terra-data-grid/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* Added
+ * 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)
* Changed
diff --git a/packages/terra-data-grid/src/DataGrid.jsx b/packages/terra-data-grid/src/DataGrid.jsx
index 256a5f01a0e..2fe9f548a7d 100644
--- a/packages/terra-data-grid/src/DataGrid.jsx
+++ b/packages/terra-data-grid/src/DataGrid.jsx
@@ -149,6 +149,11 @@ const propTypes = {
* With this property the height of the cell will grow to fit the cell content.
*/
rowMinimumHeight: PropTypes.string,
+
+ /**
+ * Determines if focus is moved to the interactive element of a cell when a single button or hyperlink element is the only interactive element.
+ */
+ isAutoFocusEnabled: PropTypes.bool,
};
const defaultProps = {
@@ -186,6 +191,7 @@ const DataGrid = forwardRef((props, ref) => {
rows,
sections,
rowMinimumHeight,
+ isAutoFocusEnabled,
} = props;
const displayedColumns = (hasSelectableRows ? [WorklistDataGridUtils.ROW_SELECTION_COLUMN] : []).concat(pinnedColumns).concat(overflowColumns);
@@ -228,7 +234,8 @@ const DataGrid = forwardRef((props, ref) => {
setCellAriaLiveMessage,
tableRef: grid,
tableContainerRef,
- }), [grid, tableContainerRef]);
+ isAutoFocusEnabled,
+ }), [grid, isAutoFocusEnabled, tableContainerRef]);
// -------------------------------------
// functions
@@ -282,7 +289,7 @@ const DataGrid = forwardRef((props, ref) => {
// Set focus to a single header button or hyperlink if they are the only content in cell
const cellButtonOrHyperlink = focusedCell.querySelector('a, button');
- if ((isHeaderRow && !focusedCell.hasAttribute('tabindex')) || cellButtonOrHyperlink) {
+ if ((isHeaderRow && !focusedCell.hasAttribute('tabindex')) || (isAutoFocusEnabled && cellButtonOrHyperlink)) {
focusedCell = focusedCell.querySelector('a, button, [role="button"]');
focusedCell?.focus();
return;
@@ -297,7 +304,7 @@ const DataGrid = forwardRef((props, ref) => {
}
focusedCell?.focus();
- }, [displayedColumns, isSection, isRowSelectionCell, hasColumnHeaderActions]);
+ }, [displayedColumns, 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
diff --git a/packages/terra-data-grid/src/FlowsheetDataGrid.jsx b/packages/terra-data-grid/src/FlowsheetDataGrid.jsx
index f97ac20b410..6b8456f8b89 100644
--- a/packages/terra-data-grid/src/FlowsheetDataGrid.jsx
+++ b/packages/terra-data-grid/src/FlowsheetDataGrid.jsx
@@ -109,6 +109,11 @@ const propTypes = {
* Boolean to show/hide column headers. By default, it is set to `true` and column headers are visible.
*/
hasVisibleColumnHeaders: PropTypes.bool,
+
+ /**
+ * Determines if focus is moved to the interactive element of a cell when a single button or hyperlink element is the only interactive element.
+ */
+ isAutoFocusEnabled: PropTypes.bool,
};
const defaultProps = {
@@ -138,6 +143,7 @@ function FlowsheetDataGrid(props) {
intl,
hasVisibleColumnHeaders,
rowMinimumHeight,
+ isAutoFocusEnabled,
} = props;
const anchorCell = useRef(null);
@@ -424,6 +430,7 @@ function FlowsheetDataGrid(props) {
hasVisibleColumnHeaders={hasVisibleColumnHeaders}
ref={dataGridFuncRef}
rowMinimumHeight={rowMinimumHeight}
+ isAutoFocusEnabled={isAutoFocusEnabled}
/>
diff --git a/packages/terra-data-grid/src/WorklistDataGrid.jsx b/packages/terra-data-grid/src/WorklistDataGrid.jsx
index 3fb53bb74d1..33350f79894 100644
--- a/packages/terra-data-grid/src/WorklistDataGrid.jsx
+++ b/packages/terra-data-grid/src/WorklistDataGrid.jsx
@@ -124,6 +124,11 @@ const propTypes = {
* rendered to allow for row selection to occur.
*/
hasSelectableRows: PropTypes.bool,
+
+ /**
+ * Determines if focus is moved to the interactive element of a cell when a single button or hyperlink element is the only interactive element.
+ */
+ isAutoFocusEnabled: PropTypes.bool,
};
const defaultProps = {
@@ -158,6 +163,7 @@ function WorklistDataGrid(props) {
onEnableRowSelection,
hasSelectableRows,
rowHeaderIndex,
+ isAutoFocusEnabled,
} = props;
const inShiftUpDownMode = useRef(false);
@@ -388,6 +394,7 @@ function WorklistDataGrid(props) {
onClearSelection={handleClearSelection}
onRangeSelection={onRangeSelection}
hasSelectableRows={hasSelectableRows}
+ isAutoFocusEnabled={isAutoFocusEnabled}
ref={dataGridFuncRef}
/>
diff --git a/packages/terra-framework-docs/CHANGELOG.md b/packages/terra-framework-docs/CHANGELOG.md
index 9c3f2e89f37..e8882335bed 100644
--- a/packages/terra-framework-docs/CHANGELOG.md
+++ b/packages/terra-framework-docs/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* Added
+ * Added examples and tests for `isAutoFocusEnabled` prop for `terra-data-grid`.
+
* Changed
* Updated `date-time-picker` KeyboardShortcuts doc for +/- Keys for DateTime input.
diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.doc.mdx b/packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.doc.mdx
new file mode 100644
index 00000000000..e0ab882ae66
--- /dev/null
+++ b/packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.doc.mdx
@@ -0,0 +1,19 @@
+import WorklistDataGridAutoFocusableCell from './WorklistDataGridAutoFocusableCell?dev-site-example';
+
+# Auto Focusable Cell Navigation
+
+### Description
+
+The content of a cell in the [Worklist Data Grid](/components/cerner-terra-framework-docs/data-grid/worklist-data-grid/about) may be empty, text, numerical, or any combination of widgets.
+When the only interactable element in the cell is a button or hyperlink element and the isAutoFocusable property is set to true, navigation to the cell will focus the button or hyperlink element directly.
+
+
+#### Keyboard Interactions
+
+|Key Interaction|Description|
+|-|-|
+|*Enter*|Moves focus to the button or hyperlink element when the table cell has focus.|
+|*Escape*|Moves focus to the parent table cell element.|
+
+
+
diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.jsx b/packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.jsx
new file mode 100644
index 00000000000..19116fc8544
--- /dev/null
+++ b/packages/terra-framework-docs/src/terra-dev-site/doc/data-grid/WorklistDataGrid.1/Examples.3/WorklistDataGridAutoFocusableCell.jsx
@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import { WorklistDataGrid } from 'terra-data-grid';
+import NotificationDialog from 'terra-notification-dialog';
+
+const WorklistDataGridAutoFocusableCell = () => {
+ const rowHeaderIndex = 0;
+
+ const [isOpen, setIsOpen] = useState(false);
+
+ const handleCloseModal = () => {
+ setIsOpen(false);
+ };
+
+ const handleButtonOpenModal = () => {
+ setIsOpen(true);
+ };
+
+ const buttonCell = ;
+ // eslint-disable-next-line react/forbid-dom-props
+ const anchorCell = Visit Oracle;
+
+ const gridDataJSON = {
+ cols: [
+ { id: 'Column-0', displayName: 'Patient' },
+ { id: 'Column-1', displayName: 'Action A' },
+ { id: 'Column-2', displayName: 'Action B' },
+ ],
+ rows: [
+ {
+ id: '1',
+ cells: [
+ { content: 'Fleck, Arthur' },
+ { content: buttonCell },
+ { content: anchorCell },
+ ],
+ },
+ ],
+ };
+
+ const { cols, rows } = gridDataJSON;
+
+ return (
+ <>
+ {isOpen && (
+
+ )}
+
+ >
+ );
+};
+
+export default WorklistDataGridAutoFocusableCell;
diff --git a/packages/terra-framework-docs/src/terra-dev-site/test/data-grid/data-grid/DataGridFocusableCell.test.jsx b/packages/terra-framework-docs/src/terra-dev-site/test/data-grid/data-grid/DataGridFocusableCell.test.jsx
index 7e3ed97dccf..226ecbf8bd9 100644
--- a/packages/terra-framework-docs/src/terra-dev-site/test/data-grid/data-grid/DataGridFocusableCell.test.jsx
+++ b/packages/terra-framework-docs/src/terra-dev-site/test/data-grid/data-grid/DataGridFocusableCell.test.jsx
@@ -110,6 +110,7 @@ const DataGridFocusableCell = () => {
rows={rows}
rowHeaderIndex={rowHeaderIndex}
ariaLabel="Data Grid"
+ isAutoFocusEnabled
/>
diff --git a/packages/terra-table/CHANGELOG.md b/packages/terra-table/CHANGELOG.md
index a2e6518aa53..81965911f32 100644
--- a/packages/terra-table/CHANGELOG.md
+++ b/packages/terra-table/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* Changed
+ * Updated the cell component auto focus logic to be configured by the grid context.
+
## 5.18.0 - (April 4, 2024)
* Added
diff --git a/packages/terra-table/src/subcomponents/Cell.jsx b/packages/terra-table/src/subcomponents/Cell.jsx
index ab8f8559af0..62d3f0b1d80 100644
--- a/packages/terra-table/src/subcomponents/Cell.jsx
+++ b/packages/terra-table/src/subcomponents/Cell.jsx
@@ -203,6 +203,10 @@ function Cell(props) {
* @returns The auto focusable button or anchor element. If there is no auto focusable element, null is returned.
*/
const getAutoFocusableElement = () => {
+ if (!gridContext.isAutoFocusEnabled) {
+ return null;
+ }
+
const focusableElements = getFocusableElements(cellRef.current);
if (focusableElements.length > 1) {
return null;
@@ -241,6 +245,7 @@ function Cell(props) {
setIsInteractable(hasFocusableElements());
}
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [gridContext, intl, isGridContext]);
const handleMouseDown = (event) => {