From 29f9f121dbb41779d896376cb11ec2b9705d78a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20St=C3=BCrmer?=
Date: Tue, 5 Jul 2022 18:32:21 +0000
Subject: [PATCH 1/7] Expose scrollTo and scrollToItem on imperative ref
---
src/components/datagrid/data_grid.tsx | 1 +
src/components/datagrid/data_grid_types.ts | 11 +++++++++
src/components/datagrid/utils/ref.ts | 28 +++++++++++++++++++---
3 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx
index b62786d82bd..bf858177a02 100644
--- a/src/components/datagrid/data_grid.tsx
+++ b/src/components/datagrid/data_grid.tsx
@@ -287,6 +287,7 @@ export const EuiDataGrid = forwardRef(
*/
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.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,
+ ]
);
};
From da364e5653d5e5759c539c9347733518dab79b99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20St=C3=BCrmer?=
Date: Wed, 6 Jul 2022 15:24:50 +0000
Subject: [PATCH 2/7] Add documentation for `scrollTo` and `scrollToItem`
---
.../advanced/datagrid_advanced_example.js | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
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..e7ee17661de 100644
--- a/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
+++ b/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
@@ -79,6 +79,27 @@ export const DataGridAdvancedExample = {
open cell popover.
+
+
+
+ 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
+
+
From f9894dbf311d59d82e87a79313ccbadbe48ba519 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20St=C3=BCrmer?=
Date: Mon, 11 Jul 2022 17:50:19 +0000
Subject: [PATCH 3/7] Add tests for `scrollTo` and `scrollToItem`
---
src/components/datagrid/utils/ref.spec.tsx | 31 ++++++++++++++++++----
1 file changed, 26 insertions(+), 5 deletions(-)
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');
+ });
+ });
});
From 39f655eb376e744c3af1c087bfed2cf8419f5c2a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20St=C3=BCrmer?=
Date: Mon, 11 Jul 2022 17:52:10 +0000
Subject: [PATCH 4/7] Add changelog entry
---
upcoming_changelogs/6042.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 upcoming_changelogs/6042.md
diff --git a/upcoming_changelogs/6042.md b/upcoming_changelogs/6042.md
new file mode 100644
index 00000000000..0fb6d06d91b
--- /dev/null
+++ b/upcoming_changelogs/6042.md
@@ -0,0 +1 @@
+- The `EuiDataGrid`'s imperative API now exposes the `scrollTo` and `scrollToItem` APIs of `react-window`.
From c56d7056aee672a9423fd238fbb2e551b553939f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20St=C3=BCrmer?=
Date: Tue, 12 Jul 2022 11:05:46 +0200
Subject: [PATCH 5/7] Update upcoming_changelogs/6042.md
Co-authored-by: Constance
---
upcoming_changelogs/6042.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/upcoming_changelogs/6042.md b/upcoming_changelogs/6042.md
index 0fb6d06d91b..3b7bc806aa5 100644
--- a/upcoming_changelogs/6042.md
+++ b/upcoming_changelogs/6042.md
@@ -1 +1 @@
-- The `EuiDataGrid`'s imperative API now exposes the `scrollTo` and `scrollToItem` APIs of `react-window`.
+- `EuiDataGrid`'s imperative API now exposes the `scrollTo` and `scrollToItem` APIs of `react-window`.
From 530a33ce5bc76e9b5cbda8d859e347b7f713bc9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Felix=20St=C3=BCrmer?=
Date: Tue, 12 Jul 2022 10:47:28 +0000
Subject: [PATCH 6/7] Move react-window API docs into separate section
---
.../advanced/datagrid_advanced_example.js | 95 ++++++++++++++-----
src-docs/src/views/datagrid/advanced/ref.tsx | 16 +++-
2 files changed, 84 insertions(+), 27 deletions(-)
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 e7ee17661de..3c39965f2ac 100644
--- a/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
+++ b/src-docs/src/views/datagrid/advanced/datagrid_advanced_example.js
@@ -1,4 +1,5 @@
import React from 'react';
+import { Link } from 'react-router-dom';
import { GuideSectionTypes } from '../../../components';
import { EuiCode, EuiSpacer, EuiCallOut } from '../../../../../src/components';
@@ -30,12 +31,6 @@ export const DataGridAdvancedExample = {
sections: [
{
title: 'Ref methods',
- source: [
- {
- type: GuideSectionTypes.TSX,
- code: dataGridRefSource,
- },
- ],
text: (
<>
@@ -79,6 +74,53 @@ export const DataGridAdvancedExample = {
open cell popover.
+
+
+
+
+
+ When using setFocusedCell or{' '}
+ openCellPopover , keep in mind:
+
+
+ colIndex is affected by the user reordering
+ or hiding columns.
+
+
+ If the passed cell indices are outside the data grid's
+ total row count or visible column count, an error will be
+ thrown.
+
+
+ If the data grid is paginated or sorted, the grid will handle
+ automatically finding specified row index's correct
+ location for you.
+
+
+
+ >
+ ),
+ },
+ {
+ title: 'react-window methods',
+ source: [
+ {
+ type: GuideSectionTypes.TSX,
+ code: dataGridRefSource,
+ },
+ ],
+ text: (
+ <>
+
+ EuiDataGrid also exposes several underlying
+ methods from{' '}
+
+ react-window's VariableSizeGrid imperative
+ API
+ {' '}
+ via its ref :
+
+
@@ -93,7 +135,7 @@ export const DataGridAdvancedExample = {
scrollToItem(
{
- '{align: string = "auto", columnIndex?: number, rowIndex?: number }'
+ '{ align: string = "auto", columnIndex?: number, rowIndex?: number }'
}
)
{' '}
@@ -105,31 +147,32 @@ export const DataGridAdvancedExample = {
- When using setFocusedCell or{' '}
- openCellPopover , keep in mind:
-
-
- colIndex is affected by the user reordering
- or hiding columns.
-
-
- If the passed cell indices are outside the data grid's
- total row count or visible column count, an error will be
- thrown.
-
-
- If the data grid is paginated or sorted, the grid will handle
- automatically finding specified row index's correct
- location for you.
-
-
+
+ Unlike in other EUI APIs, rowIndex refers to
+ the visible rowIndex when passed to a method of
+ the 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 what content is 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
+
+
Date: Tue, 12 Jul 2022 13:07:37 -0700
Subject: [PATCH 7/7] [PR feedback] Docs tweaks
- combine sections and use EuiTitle tag for react-window methods
- Fix link to react-window docs
- minor grammar tweaks
---
.../advanced/datagrid_advanced_example.js | 57 ++++++++++---------
1 file changed, 30 insertions(+), 27 deletions(-)
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 3c39965f2ac..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,8 +1,13 @@
import React from 'react';
-import { Link } from 'react-router-dom';
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';
@@ -31,6 +36,12 @@ export const DataGridAdvancedExample = {
sections: [
{
title: 'Ref methods',
+ source: [
+ {
+ type: GuideSectionTypes.TSX,
+ code: dataGridRefSource,
+ },
+ ],
text: (
<>
@@ -76,8 +87,6 @@ export const DataGridAdvancedExample = {
-
-
When using setFocusedCell or{' '}
openCellPopover , keep in mind:
@@ -98,26 +107,22 @@ export const DataGridAdvancedExample = {
- >
- ),
- },
- {
- title: 'react-window methods',
- source: [
- {
- type: GuideSectionTypes.TSX,
- code: dataGridRefSource,
- },
- ],
- text: (
- <>
+
+
+
+
+ react-window methods
+
EuiDataGrid also exposes several underlying
methods from{' '}
-
+
react-window's VariableSizeGrid imperative
API
- {' '}
+ {' '}
via its ref :
@@ -143,14 +148,12 @@ export const DataGridAdvancedExample = {
-
-
-
-
+
- Unlike in other EUI APIs, rowIndex refers to
- the visible rowIndex when passed to a method of
- the native react-window API.
+ 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:{' '}
@@ -158,7 +161,7 @@ export const DataGridAdvancedExample = {
{'scrollToItem({ rowIndex: 50, columnIndex: 0 })'}
{' '}
will always scroll to 51st visible row on the currently visible
- page, regardless of what content is in the cell. In contrast,{' '}
+ page, regardless of the content in the cell. In contrast,{' '}
{'setFocusedCell({ rowIndex: 50, colIndex: 0 })'}
{' '}