diff --git a/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js b/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
index e978a551224..adf9825c347 100644
--- a/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
+++ b/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
@@ -1,7 +1,13 @@
import React from 'react';
import { GuideSectionTypes } from '../../../components';
-import { EuiCode, EuiSpacer, EuiCallOut } from '../../../../../src/components';
+import {
+ EuiCode,
+ EuiSpacer,
+ EuiCallOut,
+ EuiTitle,
+ EuiLink,
+} from '../../../../../src/components';
import { EuiDataGridRefProps } from '!!prop-loader!../../../../../src/components/datagrid/data_grid_types';
@@ -81,8 +87,6 @@ export const DataGridAdvancedExample = {
-
-
When using setFocusedCell or{' '}
openCellPopover, keep in mind:
@@ -104,11 +108,74 @@ export const DataGridAdvancedExample = {
+
+
+
+ react-window methods
+
+
+ EuiDataGrid also exposes several underlying
+ methods from{' '}
+
+ react-window's VariableSizeGrid imperative
+ API
+ {' '}
+ via its ref:
+
+
+ -
+
+
+ scrollTo({'{ scrollLeft: number, scrollTop: number }'})
+ {' '}
+ - scrolls the grid to the specified horizontal and vertical
+ pixel offsets.
+
+
+ -
+
+
+ scrollToItem(
+ {
+ '{ align: string = "auto", columnIndex?: number, rowIndex?: number }'
+ }
+ )
+ {' '}
+ - scrolls the grid to the specified row and columns indices
+
+
+
+
+
+ Unlike EUI's ref APIs, rowIndex here
+ refers to the visible rowIndex{' '}
+ when passed to a method of a native{' '}
+ react-window API.
+
+
+ For example:{' '}
+
+ {'scrollToItem({ rowIndex: 50, columnIndex: 0 })'}
+ {' '}
+ will always scroll to 51st visible row on the currently visible
+ page, regardless of the content in the cell. In contrast,{' '}
+
+ {'setFocusedCell({ rowIndex: 50, colIndex: 0 })'}
+ {' '}
+ will scroll to the 51st row in your data, which may not be the
+ 51st visible row in the grid if it is paginated or sorted.
+
+
+
The below example shows how to use the internal APIs for a data grid
- that opens a modal via cell actions.
+ that opens a modal via cell actions, that scroll to specific cells,
+ and that can be put into full-screen mode.
>
),
diff --git a/src-docs/src/views/datagrid/advanced/ref.tsx b/src-docs/src/views/datagrid/advanced/ref.tsx
index c755105a28f..880e493a1d1 100644
--- a/src-docs/src/views/datagrid/advanced/ref.tsx
+++ b/src-docs/src/views/datagrid/advanced/ref.tsx
@@ -31,7 +31,7 @@ for (let i = 1; i < 100; i++) {
}
export default () => {
- const dataGridRef = useRef(null);
+ const dataGridRef = useRef(null);
// Modal
const [isModalVisible, setIsModalVisible] = useState(false);
@@ -161,6 +161,20 @@ export default () => {
Set cell focus
+
+
+ dataGridRef.current!.scrollToItem?.({
+ rowIndex: rowIndexAction,
+ columnIndex: colIndexAction,
+ align: 'center',
+ })
+ }
+ >
+ Scroll to cell
+
+
(
*/
useImperativeGridRef({
ref,
+ gridRef,
setIsFullScreen,
focusContext,
cellPopoverContext,
diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts
index 9d98ac0f039..556c07faae3 100644
--- a/src/components/datagrid/data_grid_types.ts
+++ b/src/components/datagrid/data_grid_types.ts
@@ -15,6 +15,7 @@ import {
ReactElement,
AriaAttributes,
MutableRefObject,
+ Component,
} from 'react';
import {
VariableSizeGridProps,
@@ -28,6 +29,8 @@ import { RowHeightUtils } from './utils/row_heights';
import { IconType } from '../icon';
import { EuiTokenProps } from '../token';
+export type ImperativeGridApi = Omit;
+
export interface EuiDataGridToolbarProps {
gridWidth: number;
minSizeForControls?: number;
@@ -358,6 +361,14 @@ export interface EuiDataGridRefProps {
* Closes any currently open popovers in the data grid.
*/
closeCellPopover: () => void;
+ /**
+ * Scrolls to a specified top and left offset.
+ */
+ scrollTo?: ImperativeGridApi['scrollTo'];
+ /**
+ * Scrolls to a specified rowIndex.
+ */
+ scrollToItem?: ImperativeGridApi['scrollToItem'];
}
export interface EuiDataGridColumnResizerProps {
diff --git a/src/components/datagrid/utils/ref.spec.tsx b/src/components/datagrid/utils/ref.spec.tsx
index af33ad4a9d0..e371976a4c1 100644
--- a/src/components/datagrid/utils/ref.spec.tsx
+++ b/src/components/datagrid/utils/ref.spec.tsx
@@ -10,18 +10,19 @@
import React, { useState, createRef, forwardRef } from 'react';
import { EuiDataGrid } from '../';
-import { EuiDataGridRefProps } from '../data_grid_types';
+import type {
+ EuiDataGridRefProps,
+ EuiDataGridSorting,
+} from '../data_grid_types';
// We need to set up a test component here for sorting/pagination state to work
// The underlying imperative ref should still be forwarded and work as normal
const GridTest = forwardRef((_, ref) => {
// Pagination
- const [pageIndex, setPageIndex] = useState(0);
- const onChangePage = (pageIndex) => setPageIndex(pageIndex);
+ const [pageIndex, onChangePage] = useState(0);
// Sorting
- const [sortingColumns, setSortingColumns] = useState([]);
- const onSort = (sortingColumns) => setSortingColumns(sortingColumns);
+ const [sortingColumns, onSort] = useState([]);
return (
{
});
});
});
+
+ describe('scrollTo', () => {
+ it('scrolls the grid to a specified position', () => {
+ cy.get('.euiDataGrid__virtualized').should('have.prop', 'scrollTop', 0);
+ cy.then(() => {
+ ref.current.scrollTo({ scrollTop: 500, scrollLeft: 0 });
+ });
+ cy.get('.euiDataGrid__virtualized').should('have.prop', 'scrollTop', 500);
+ });
+ });
+
+ describe('scrollToItem', () => {
+ it('scrolls to a specific cell position, rendering the cell', () => {
+ cy.get('[data-gridcell-row-index="15"]').should('not.exist');
+ cy.then(() => {
+ ref.current.scrollToItem({ rowIndex: 15, columnIndex: 5 });
+ });
+ cy.get('[data-gridcell-row-index="15"]').should('exist');
+ });
+ });
});
diff --git a/src/components/datagrid/utils/ref.ts b/src/components/datagrid/utils/ref.ts
index 5c4d6a0085e..f3e2409651c 100644
--- a/src/components/datagrid/utils/ref.ts
+++ b/src/components/datagrid/utils/ref.ts
@@ -6,7 +6,8 @@
* Side Public License, v 1.
*/
-import { useImperativeHandle, useCallback, Ref } from 'react';
+import { useImperativeHandle, useCallback, Ref, RefObject } from 'react';
+import type { VariableSizeGrid } from 'react-window';
import {
EuiDataGridRefProps,
EuiDataGridProps,
@@ -17,6 +18,7 @@ import {
interface Dependencies {
ref: Ref;
+ gridRef: RefObject;
setIsFullScreen: EuiDataGridRefProps['setIsFullScreen'];
focusContext: DataGridFocusContextShape;
cellPopoverContext: DataGridCellPopoverContextShape;
@@ -28,6 +30,7 @@ interface Dependencies {
export const useImperativeGridRef = ({
ref,
+ gridRef,
setIsFullScreen,
focusContext,
cellPopoverContext,
@@ -75,16 +78,35 @@ export const useImperativeGridRef = ({
[_openCellPopover, checkCellExists, findVisibleRowIndex]
);
+ const scrollTo = useCallback(
+ (...args) => gridRef.current?.scrollTo(...args),
+ [gridRef]
+ );
+
+ const scrollToItem = useCallback(
+ (...args) => gridRef.current?.scrollToItem(...args),
+ [gridRef]
+ );
+
// Set the ref APIs
useImperativeHandle(
ref,
- () => ({
+ (): EuiDataGridRefProps => ({
setIsFullScreen,
setFocusedCell,
openCellPopover,
closeCellPopover,
+ scrollTo,
+ scrollToItem,
}),
- [setIsFullScreen, setFocusedCell, openCellPopover, closeCellPopover]
+ [
+ setIsFullScreen,
+ setFocusedCell,
+ openCellPopover,
+ closeCellPopover,
+ scrollTo,
+ scrollToItem,
+ ]
);
};
diff --git a/upcoming_changelogs/6042.md b/upcoming_changelogs/6042.md
new file mode 100644
index 00000000000..3b7bc806aa5
--- /dev/null
+++ b/upcoming_changelogs/6042.md
@@ -0,0 +1 @@
+- `EuiDataGrid`'s imperative API now exposes the `scrollTo` and `scrollToItem` APIs of `react-window`.