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

Cell auto focus property #2123

Merged
merged 4 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions packages/terra-data-grid/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions packages/terra-data-grid/src/DataGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would enableAutofocus make sense as a simpler name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to follow the naming pattern of some of the other props. However, I can make this change if it is the desired update.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the is___ pattern is preferred. Would a name like isAutofocusable or similar work? (Not sure if that's sufficiently descriptive of the prop's usage though)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're keeping to the is__ pattern, then I think both these names are similar enough that either works.

};

const defaultProps = {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -228,7 +234,8 @@ const DataGrid = forwardRef((props, ref) => {
setCellAriaLiveMessage,
tableRef: grid,
tableContainerRef,
}), [grid, tableContainerRef]);
isAutoFocusEnabled,
}), [grid, isAutoFocusEnabled, tableContainerRef]);

// -------------------------------------
// functions
Expand Down Expand Up @@ -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)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will action buttons on header cells still be autofocused, regardless of the prop?

Copy link
Contributor Author

@cm9361 cm9361 Apr 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first half of the condition is for the header row and all unit tests pass. I will manually confirm though.

Yes, the button in the row header is still being selected.

focusedCell = focusedCell.querySelector('a, button, [role="button"]');
focusedCell?.focus();
return;
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions packages/terra-data-grid/src/FlowsheetDataGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -138,6 +143,7 @@ function FlowsheetDataGrid(props) {
intl,
hasVisibleColumnHeaders,
rowMinimumHeight,
isAutoFocusEnabled,
} = props;

const anchorCell = useRef(null);
Expand Down Expand Up @@ -424,6 +430,7 @@ function FlowsheetDataGrid(props) {
hasVisibleColumnHeaders={hasVisibleColumnHeaders}
ref={dataGridFuncRef}
rowMinimumHeight={rowMinimumHeight}
isAutoFocusEnabled={isAutoFocusEnabled}
/>
<VisuallyHiddenText aria-live="polite" text={cellSelectionAriaLiveMessage} />
</div>
Expand Down
7 changes: 7 additions & 0 deletions packages/terra-data-grid/src/WorklistDataGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -158,6 +163,7 @@ function WorklistDataGrid(props) {
onEnableRowSelection,
hasSelectableRows,
rowHeaderIndex,
isAutoFocusEnabled,
} = props;

const inShiftUpDownMode = useRef(false);
Expand Down Expand Up @@ -388,6 +394,7 @@ function WorklistDataGrid(props) {
onClearSelection={handleClearSelection}
onRangeSelection={onRangeSelection}
hasSelectableRows={hasSelectableRows}
isAutoFocusEnabled={isAutoFocusEnabled}
ref={dataGridFuncRef}
/>
</div>
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-framework-docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Original file line number Diff line number Diff line change
@@ -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.|


<WorklistDataGridAutoFocusableCell />
Original file line number Diff line number Diff line change
@@ -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 = <button type="button" aria-label="Alert" onClick={handleButtonOpenModal}>Alert</button>;
// eslint-disable-next-line react/forbid-dom-props
const anchorCell = <a href="https://www.oracle.com/" aria-label="Visit Oracle">Visit Oracle</a>;

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 && (
<NotificationDialog
variant="hazard-low"
dialogTitle="Button from Focusable Cell"
startMessage="Button Selected"
acceptAction={{
text: 'OK',
onClick: handleCloseModal,
}}
/>
)}
<WorklistDataGrid
id="default-terra-worklist-data-grid-focusable-cell"
overflowColumns={cols}
defaultColumnWidth={170}
rows={rows}
rowHeaderIndex={rowHeaderIndex}
rowHeight="50px"
ariaLabel="Worklist Data Grid"
isAutoFocusEnabled
/>
Copy link
Contributor

@adoroshk adoroshk Apr 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this example is missing isAutoFocusEnabled prop

</>
);
};

export default WorklistDataGridAutoFocusableCell;
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ const DataGridFocusableCell = () => {
rows={rows}
rowHeaderIndex={rowHeaderIndex}
ariaLabel="Data Grid"
isAutoFocusEnabled
/>
</div>
<button id="next-focus-button" type="button" aria-label="Next Element">Test Next</button>
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-table/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions packages/terra-table/src/subcomponents/Cell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -241,6 +245,7 @@ function Cell(props) {
setIsInteractable(hasFocusableElements());
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [gridContext, intl, isGridContext]);

const handleMouseDown = (event) => {
Expand Down
Loading