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) => {