diff --git a/CHANGELOG.md b/CHANGELOG.md index 8978feb20ec..4959b77e78d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Bug fixes** - Fixed inconsistent width of `EuiRange` and `EuiDualRange` with custom tick values ([#4781](https://github.com/elastic/eui/pull/4781)) +- Fixes browser freezing when `EuiDataGrid` is used together with `EuiFlyout` and the user clicks a cell ([4813](https://github.com/elastic/eui/pull/4813)) ## [`34.0.0`](https://github.com/elastic/eui/tree/v34.0.0) diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx index 36571f64abb..13fcbd5f825 100644 --- a/src/components/datagrid/data_grid.test.tsx +++ b/src/components/datagrid/data_grid.test.tsx @@ -2300,7 +2300,7 @@ describe('EuiDataGrid', () => { ).toEqual('6, C'); }); - it('does not break arrow key focus control behavior when also using a mouse', () => { + it('does not break arrow key focus control behavior when also using a mouse', async () => { const component = mount( { findTestSubject(component, 'dataGridRowCell').at(3).simulate('focus'); + // wait for a tick to give focus logic time to run + await act(async () => { + await new Promise((r) => setTimeout(r, 0)); + }); + component.update(); + focusableCell = getFocusableCell(component); expect(focusableCell.length).toEqual(1); expect( diff --git a/src/components/datagrid/data_grid_cell.tsx b/src/components/datagrid/data_grid_cell.tsx index 9ad88f45ab4..a936eb495e7 100644 --- a/src/components/datagrid/data_grid_cell.tsx +++ b/src/components/datagrid/data_grid_cell.tsx @@ -152,6 +152,7 @@ export class EuiDataGridCell extends Component< disableCellTabIndex: false, }; unsubscribeCell?: Function = () => {}; + focusTimeout: number | undefined; style = null; setCellRef = (ref: HTMLDivElement | null) => { @@ -227,6 +228,7 @@ export class EuiDataGridCell extends Component< }; componentWillUnmount() { + window.clearTimeout(this.focusTimeout); if (this.unsubscribeCell) { this.unsubscribeCell(); } @@ -286,13 +288,16 @@ export class EuiDataGridCell extends Component< // event up, which can trigger the focus() call below, causing focus lock fighting if (this.cellRef.current === e.target) { const { colIndex, visibleRowIndex, isExpandable } = this.props; - this.context.setFocusedCell([colIndex, visibleRowIndex]); + // focus in next tick to give potential focus capturing mechanisms time to release their traps + this.focusTimeout = window.setTimeout(() => { + this.context.setFocusedCell([colIndex, visibleRowIndex]); - const interactables = this.getInteractables(); - if (interactables.length === 1 && isExpandable === false) { - interactables[0].focus(); - this.setState({ disableCellTabIndex: true }); - } + const interactables = this.getInteractables(); + if (interactables.length === 1 && isExpandable === false) { + interactables[0].focus(); + this.setState({ disableCellTabIndex: true }); + } + }, 0); } }; diff --git a/src/components/popover/popover.tsx b/src/components/popover/popover.tsx index c741b09523c..fe890e49e40 100644 --- a/src/components/popover/popover.tsx +++ b/src/components/popover/popover.tsx @@ -472,6 +472,9 @@ export class EuiPopover extends Component { onOpenPopover = () => { clearTimeout(this.closingTransitionTimeout); + if (this.closingTransitionAnimationFrame) { + cancelAnimationFrame(this.closingTransitionAnimationFrame); + } // We need to set this state a beat after the render takes place, so that the CSS // transition can take effect. this.closingTransitionAnimationFrame = window.requestAnimationFrame(() => { @@ -498,6 +501,7 @@ export class EuiPopover extends Component { { durationMatch: 0, delayMatch: 0 } ); + clearTimeout(this.respositionTimeout); this.respositionTimeout = window.setTimeout(() => { this.setState({ isOpenStable: true }, () => { this.positionPopoverFixed();