Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
**Bug fixes**

- Fixed bug in `EuiBasicTable` not fully expanding tall rows (height > 1000px) ([#3855](https://github.com/elastic/eui/pull/3855))
- Fixed bug in `EuiDataGrid` which sometimes prevented header cells from being focusabled ([#3943](https://github.com/elastic/eui/pull/3943))

## [`28.2.0`](https://github.com/elastic/eui/tree/v28.2.0)

Expand Down
71 changes: 40 additions & 31 deletions src/components/datagrid/data_grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -626,43 +626,41 @@ export const EuiDataGrid: FunctionComponent<EuiDataGridProps> = props => {
headerIsInteractive
);

const handleHeaderChange = useCallback<MutationCallback>(
const handleHeaderChange = useCallback<(headerRow: HTMLElement) => void>(
headerRow => {
const tabbables = tabbable(headerRow);
const managed = headerRow.querySelectorAll('[data-euigrid-tab-managed]');
const hasInteractives = tabbables.length > 0 || managed.length > 0;
if (hasInteractives !== headerIsInteractive) {
setHeaderIsInteractive(hasInteractives);

// if the focus is on the header, and the header is no longer interactive
// move the focus down to the first row
if (hasInteractives === false && focusedCell && focusedCell[1] === -1) {
setFocusedCell([focusedCell[0], 0]);
}
}
},
[headerIsInteractive, setHeaderIsInteractive, focusedCell, setFocusedCell]
);
const handleHeaderMutation = useCallback<MutationCallback>(
records => {
const [{ target }] = records;

// find the wrapping header div
let headerRow = target.parentElement;
while (
headerRow &&
(headerRow.getAttribute('data-test-subj') || '').indexOf(
'dataGridHeader'
) === -1
(headerRow.getAttribute('data-test-subj') || '')
.split(/\s+/)
.indexOf('dataGridHeader') === -1
) {
headerRow = headerRow.parentElement;
}

if (headerRow) {
const tabbables = tabbable(headerRow);
const managed = headerRow.querySelectorAll(
'[data-euigrid-tab-managed]'
);
const hasInteractives = tabbables.length > 0 || managed.length > 0;
if (hasInteractives !== headerIsInteractive) {
setHeaderIsInteractive(hasInteractives);

// if the focus is on the header, and the header is no longer interactive
// move the focus down to the first row
if (
hasInteractives === false &&
focusedCell &&
focusedCell[1] === -1
) {
setFocusedCell([focusedCell[0], 0]);
}
}
}
if (headerRow) handleHeaderChange(headerRow);
},
[headerIsInteractive, setHeaderIsInteractive, focusedCell, setFocusedCell]
[handleHeaderChange]
);

const handleGridKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -773,17 +771,28 @@ export const EuiDataGrid: FunctionComponent<EuiDataGridProps> = props => {
orderedVisibleColumns
);

const contentRef = useRef<HTMLDivElement>(null);
const [contentRef, setContentRef] = useState<HTMLDivElement | null>(null);

useEffect(() => {
if (contentRef) {
const headerElement = contentRef.querySelector(
'[data-test-subj~=dataGridHeader]'
);
if (headerElement) {
handleHeaderChange(headerElement as HTMLElement);
}
}
}, [contentRef, handleHeaderChange]);

// Because of a weird Chrome bug with position:sticky css items and focus, we force scrolling to the top
// if the item is in the first row. This prevents the cell from ever being under the sticky header.
useEffect(() => {
if (focusedCell !== undefined && focusedCell[1] === 0) {
if (contentRef.current != null) {
contentRef.current.scrollTop = 0;
if (contentRef != null) {
contentRef.scrollTop = 0;
}
}
}, [focusedCell]);
}, [focusedCell, contentRef]);

const classes = classNames(
'euiDataGrid',
Expand Down Expand Up @@ -999,7 +1008,7 @@ export const EuiDataGrid: FunctionComponent<EuiDataGridProps> = props => {
/>
) : null}
<div
ref={contentRef}
ref={setContentRef}
data-test-subj="dataGridWrapper"
className="euiDataGrid__content"
role="grid"
Expand All @@ -1011,7 +1020,7 @@ export const EuiDataGrid: FunctionComponent<EuiDataGridProps> = props => {
subtree: true,
childList: true,
}}
onMutation={handleHeaderChange}>
onMutation={handleHeaderMutation}>
{ref => (
<EuiDataGridHeaderRow
ref={ref}
Expand Down