Skip to content

Commit

Permalink
[Dashboard] [Collapsable Panels] Interact with real panel element (el…
Browse files Browse the repository at this point in the history
…astic#196756)

Closes elastic#190647

## Summary

This PR swaps the interaction of `kbn-grid-layout` so that you are now
dragging/resizing the **actual element** rather than the preview - i.e.
the preview now shows the **real** / grid aligned location (i.e. where
the panel will land once the interaction stops), while the element shows
the non-grid-aligned location.

**Dragging**

| Before | After |
|--------|--------|
| ![Oct-18-2024
09-10-52](https://github.com/user-attachments/assets/f117124d-3200-4c7b-a5f7-6a4bc767ebff)
| ![Oct-18-2024
09-07-25](https://github.com/user-attachments/assets/483d481a-a752-4455-b9bd-2d89ec273454)
|


**Resizing**

| Before | After |
|--------|--------|
| ![Oct-18-2024
09-11-21](https://github.com/user-attachments/assets/64e4314d-b641-4b0c-a4a9-93e3f0d21cbc)
| ![Oct-18-2024
09-07-55](https://github.com/user-attachments/assets/755be726-38bc-475b-a85d-7696262c4b4f)
|

This serves as more than just a visual update - because we are dragging
the real element, the mouse stays "locked" to the drag and/or resize
handler, which means we have introduced the possibility for an `onDrop`
event. This is necessary in order to keep the current "unsaved changes"
behaviour on Dashboard, where changes are triggered only once the panel
is actually **dropped** and not when other panels move as a consequence
of a drag event.

To make this possible, I also removed the `GridOverlay` component - it
was creating a transparent `div` **over the entire grid** on
interaction, which meant that focus was lost as soon as the interaction
started. If we want to restore the "scroll up" and "scroll down" buttons
(which we were unsure about, anyway), we would need to rethink this
(i.e. just render two fixed-position buttons without any overlay).

### Checklist

- [x] This was checked for [cross-browser
compatibility](https://www.elastic.co/support/matrix#matrix_browsers)


### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels)
- [ ] This will appear in the **Release Notes** and follow the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
  • Loading branch information
Heenawter authored Oct 22, 2024
1 parent 87bda29 commit cb56679
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 257 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-grid-layout/grid/grid_height_smoother.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const GridHeightSmoother = ({
gridLayoutStateManager.interactionEvent$,
]).subscribe(([dimensions, interactionEvent]) => {
if (!smoothHeightRef.current) return;
if (!interactionEvent) {
if (!interactionEvent || interactionEvent.type === 'drop') {
smoothHeightRef.current.style.height = `${dimensions.height}px`;
return;
}
Expand Down
15 changes: 6 additions & 9 deletions packages/kbn-grid-layout/grid/grid_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
import React from 'react';

import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';

import { GridHeightSmoother } from './grid_height_smoother';
import { GridOverlay } from './grid_overlay';
import { GridRow } from './grid_row';
import { GridLayoutData, GridSettings } from './types';
import { useGridLayoutEvents } from './use_grid_layout_events';
Expand Down Expand Up @@ -49,17 +50,17 @@ export const GridLayout = ({
key={rowData.title}
rowIndex={rowIndex}
runtimeSettings={runtimeSettings}
activePanelId={interactionEvent?.id}
renderPanelContents={renderPanelContents}
targetRowIndex={interactionEvent?.targetRowIndex}
gridLayoutStateManager={gridLayoutStateManager}
toggleIsCollapsed={() => {
const currentLayout = gridLayoutStateManager.gridLayout$.value;
currentLayout[rowIndex].isCollapsed = !currentLayout[rowIndex].isCollapsed;
gridLayoutStateManager.gridLayout$.next(currentLayout);
}}
setInteractionEvent={(nextInteractionEvent) => {
if (!nextInteractionEvent) {
gridLayoutStateManager.hideDragPreview();
if (nextInteractionEvent?.type === 'drop') {
gridLayoutStateManager.activePanel$.next(undefined);
}
gridLayoutStateManager.interactionEvent$.next(nextInteractionEvent);
}}
Expand All @@ -69,10 +70,6 @@ export const GridLayout = ({
})}
</div>
</GridHeightSmoother>
<GridOverlay
interactionEvent={interactionEvent}
gridLayoutStateManager={gridLayoutStateManager}
/>
</>
);
};
135 changes: 0 additions & 135 deletions packages/kbn-grid-layout/grid/grid_overlay.tsx

This file was deleted.

77 changes: 31 additions & 46 deletions packages/kbn-grid-layout/grid/grid_panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,38 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React, { forwardRef } from 'react';

import {
EuiIcon,
EuiPanel,
euiFullHeight,
transparentize,
useEuiOverflowScroll,
useEuiTheme,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { euiThemeVars } from '@kbn/ui-theme';
import React, { useCallback, useRef } from 'react';

import { GridPanelData, PanelInteractionEvent } from './types';

export const GridPanel = ({
activePanelId,
panelData,
renderPanelContents,
setInteractionEvent,
}: {
panelData: GridPanelData;
activePanelId: string | undefined;
renderPanelContents: (panelId: string) => React.ReactNode;
setInteractionEvent: (interactionData?: Omit<PanelInteractionEvent, 'targetRowIndex'>) => void;
}) => {
const panelRef = useRef<HTMLDivElement>(null);
export const GridPanel = forwardRef<
HTMLDivElement,
{
panelData: GridPanelData;
activePanelId: string | undefined;
renderPanelContents: (panelId: string) => React.ReactNode;
interactionStart: (
type: PanelInteractionEvent['type'],
e: React.MouseEvent<HTMLDivElement, MouseEvent>
) => void;
}
>(({ activePanelId, panelData, renderPanelContents, interactionStart }, panelRef) => {
const { euiTheme } = useEuiTheme();
const thisPanelActive = activePanelId === panelData.id;

const interactionStart = useCallback(
(type: 'drag' | 'resize', e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (!panelRef.current) return;
e.preventDefault();
e.stopPropagation();
const panelRect = panelRef.current.getBoundingClientRect();
setInteractionEvent({
type,
id: panelData.id,
panelDiv: panelRef.current,
mouseOffsets: {
top: e.clientY - panelRect.top,
left: e.clientX - panelRect.left,
right: e.clientX - panelRect.right,
bottom: e.clientY - panelRect.bottom,
},
});
},
[panelData.id, setInteractionEvent]
);

return (
<div
ref={panelRef}
css={css`
grid-column-start: ${panelData.column + 1};
grid-column-end: ${panelData.column + 1 + panelData.width};
grid-row-start: ${panelData.row + 1};
grid-row-end: ${panelData.row + 1 + panelData.height};
`}
>
<div ref={panelRef}>
<EuiPanel
hasShadow={false}
hasBorder={true}
Expand Down Expand Up @@ -97,18 +72,28 @@ export const GridPanel = ({
height: ${euiThemeVars.euiSizeL};
z-index: ${euiThemeVars.euiZLevel3};
margin-left: ${euiThemeVars.euiSizeS};
border: 1px solid ${euiThemeVars.euiBorderColor};
background-color: ${euiThemeVars.euiColorEmptyShade};
border: 1px solid ${euiTheme.border.color};
background-color: ${euiTheme.colors.emptyShade};
border-radius: ${euiThemeVars.euiBorderRadius} ${euiThemeVars.euiBorderRadius} 0 0;
&:hover {
cursor: grab;
opacity: 1 !important;
}
&:active {
cursor: grabbing;
opacity: 1 !important;
}
`}
onMouseDown={(e) => interactionStart('drag', e)}
onMouseUp={(e) => interactionStart('drop', e)}
>
<EuiIcon type="grabOmnidirectional" />
</div>
{/* Resize handle */}
<div
className="resizeHandle"
onMouseDown={(e) => interactionStart('resize', e)}
onMouseUp={(e) => interactionStart('drop', e)}
css={css`
right: 0;
bottom: 0;
Expand Down Expand Up @@ -139,4 +124,4 @@ export const GridPanel = ({
</EuiPanel>
</div>
);
};
});
Loading

0 comments on commit cb56679

Please sign in to comment.