[Collapsable panels] Refactor forward refs (#208360)

## Summary

This PR fixes a few very small issues:
1. Removes this warning via setting explicity `touchstart` passive. 
I read that `touchstart` is passive by default, but apparently it varies
between browsers.
<img width="1053" alt="Screenshot 2025-01-27 at 14 04 26"
src="https://github.com/user-attachments/assets/0d641575-df6c-429c-a731-e9f41dc9ec65"
/>

2. Removes the `containerRef` that we stopped using, but didn't remove
the variable.

3. Sets the refs for `rowRefs` and `panelRefs` inside the component
instead of passing `forwardRefs` and passing it on parent components.
Unless I am missing something, there's no reason for adding this
complexity. Plus `forwardRef` is deprecated in React 19 so it's good to
remove now :)
  
4. Adds `max-height: 100vh` for expanded version of gridHeightSmoother.
We need that, since setting it to 100% right now will not always work
properly if parent won't set up its height. The problem is very visible
in our example app with Lens datatable, (uses EuiDataGrid underneath).
When we maximize the datatable panel, it will grow forever and cause a
lot of console errors about Resize Observers.
This commit is contained in:
Marta Bondyra 2025-01-28 00:28:30 +01:00 committed by GitHub
parent 3e0fd1f82e
commit 00d822d88a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 309 additions and 306 deletions

View file

@ -60,6 +60,7 @@ export const GridHeightSmoother = ({
&:has(.kbnGridPanel--expanded) {
min-height: 100% !important;
max-height: 100vh; // fallback in case if the parent doesn't set the height correctly
position: relative;
transition: none;
}

View file

@ -145,9 +145,6 @@ export const GridLayout = ({
rowIndex={rowIndex}
renderPanelContents={renderPanelContents}
gridLayoutStateManager={gridLayoutStateManager}
ref={(element: HTMLDivElement | null) =>
(gridLayoutStateManager.rowRefs.current[rowIndex] = element)
}
/>
);
});

View file

@ -41,7 +41,7 @@ export const DragHandle = React.forwardRef<
for (const handle of dragHandles) {
if (handle === null) return;
handle.addEventListener('mousedown', startInteraction, { passive: true });
handle.addEventListener('touchstart', startInteraction);
handle.addEventListener('touchstart', startInteraction, { passive: true });
handle.style.touchAction = 'none';
}
removeEventListenersRef.current = () => {

View file

@ -7,7 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import React, { forwardRef, useEffect, useMemo, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { combineLatest, skip } from 'rxjs';
import { useEuiTheme } from '@elastic/eui';
@ -27,8 +27,12 @@ export interface GridPanelProps {
gridLayoutStateManager: GridLayoutStateManager;
}
export const GridPanel = forwardRef<HTMLDivElement, GridPanelProps>(
({ panelId, rowIndex, renderPanelContents, gridLayoutStateManager }, panelRef) => {
export const GridPanel = ({
panelId,
rowIndex,
renderPanelContents,
gridLayoutStateManager,
}: GridPanelProps) => {
const [dragHandleApi, setDragHandleApi] = useState<DragHandleApi | null>(null);
const { euiTheme } = useEuiTheme();
@ -161,7 +165,16 @@ export const GridPanel = forwardRef<HTMLDivElement, GridPanelProps>(
}, [panelId, renderPanelContents, dragHandleApi]);
return (
<div ref={panelRef} css={initialStyles} className="kbnGridPanel">
<div
ref={(element) => {
if (!gridLayoutStateManager.panelRefs.current[rowIndex]) {
gridLayoutStateManager.panelRefs.current[rowIndex] = {};
}
gridLayoutStateManager.panelRefs.current[rowIndex][panelId] = element;
}}
css={initialStyles}
className="kbnGridPanel"
>
<DragHandle
ref={setDragHandleApi}
gridLayoutStateManager={gridLayoutStateManager}
@ -176,5 +189,4 @@ export const GridPanel = forwardRef<HTMLDivElement, GridPanelProps>(
/>
</div>
);
}
);
};

View file

@ -8,7 +8,7 @@
*/
import { cloneDeep } from 'lodash';
import React, { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
import React, { useEffect, useMemo, useState } from 'react';
import { map, pairwise, skip, combineLatest } from 'rxjs';
import { css } from '@emotion/react';
@ -27,8 +27,11 @@ export interface GridRowProps {
gridLayoutStateManager: GridLayoutStateManager;
}
export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
({ rowIndex, renderPanelContents, gridLayoutStateManager }, gridRef) => {
export const GridRow = ({
rowIndex,
renderPanelContents,
gridLayoutStateManager,
}: GridRowProps) => {
const currentRow = gridLayoutStateManager.gridLayout$.value[rowIndex];
const [panelIds, setPanelIds] = useState<string[]>(Object.keys(currentRow.panels));
@ -38,8 +41,6 @@ export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
const [rowTitle, setRowTitle] = useState<string>(currentRow.title);
const [isCollapsed, setIsCollapsed] = useState<boolean>(currentRow.isCollapsed);
const rowContainer = useRef<HTMLDivElement | null>(null);
/** Set initial styles based on state at mount to prevent styles from "blipping" */
const initialStyles = useMemo(() => {
const { columnCount } = gridLayoutStateManager.runtimeSettings$.getValue();
@ -114,14 +115,12 @@ export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
* the order of rendered panels need to be aligned with how they are displayed in the grid for accessibility
* reasons (screen readers and focus management).
*/
const gridLayoutSubscription = gridLayoutStateManager.gridLayout$.subscribe(
(gridLayout) => {
const gridLayoutSubscription = gridLayoutStateManager.gridLayout$.subscribe((gridLayout) => {
const newPanelIdsInOrder = getKeysInOrder(gridLayout[rowIndex].panels);
if (panelIdsInOrder.join() !== newPanelIdsInOrder.join()) {
setPanelIdsInOrder(newPanelIdsInOrder);
}
}
);
});
return () => {
interactionStyleSubscription.unsubscribe();
@ -147,12 +146,6 @@ export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
rowIndex={rowIndex}
gridLayoutStateManager={gridLayoutStateManager}
renderPanelContents={renderPanelContents}
ref={(element) => {
if (!gridLayoutStateManager.panelRefs.current[rowIndex]) {
gridLayoutStateManager.panelRefs.current[rowIndex] = {};
}
gridLayoutStateManager.panelRefs.current[rowIndex][panelId] = element;
}}
/>
),
}),
@ -162,7 +155,6 @@ export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
return (
<div
ref={rowContainer}
css={css`
height: 100%;
`}
@ -182,7 +174,9 @@ export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
{!isCollapsed && (
<div
className={'kbnGridRow'}
ref={gridRef}
ref={(element: HTMLDivElement | null) =>
(gridLayoutStateManager.rowRefs.current[rowIndex] = element)
}
css={css`
height: 100%;
display: grid;
@ -199,5 +193,4 @@ export const GridRow = forwardRef<HTMLDivElement, GridRowProps>(
)}
</div>
);
}
);
};