Skip to content

Commit

Permalink
DH-11923: Fix column tooltip when above the table (deephaven#306)
Browse files Browse the repository at this point in the history
Co-authored-by: Mike Bender <mikebender@deephaven.io>
  • Loading branch information
dsmmcken and mofojed authored Nov 24, 2021
1 parent bea1907 commit 1a9f7fb
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 17 deletions.
4 changes: 4 additions & 0 deletions packages/code-studio/src/styleguide/MockIrisGridTreeModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class MockIrisGridTreeModel extends IrisGridModel {

set pendingDataMap(value) {}

getColumnIndexByName(name) {
return Number(name);
}

textForCell(column, row) {
return (
this.editedData[column]?.[row] ?? this.model.textForCell(column, row)
Expand Down
11 changes: 7 additions & 4 deletions packages/components/src/popper/Popper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames';
import { CSSTransition } from 'react-transition-group';
import PopperJs, { PopperOptions } from 'popper.js';
import PopperJs, { PopperOptions, ReferenceObject } from 'popper.js';
import PropTypes from 'prop-types';
import ThemeExport from '../ThemeExport';
import './Popper.scss';
Expand All @@ -33,6 +33,7 @@ interface PopperProps {
isShown: boolean;
closeOnBlur: boolean;
interactive: boolean;
referenceObject: ReferenceObject;
}

interface PopperState {
Expand All @@ -51,6 +52,7 @@ class Popper extends Component<PopperProps, PopperState> {
isShown: PropTypes.bool,
closeOnBlur: PropTypes.bool,
interactive: PropTypes.bool,
referenceObject: PropTypes.shape({}),
};

static defaultProps = {
Expand All @@ -66,6 +68,7 @@ class Popper extends Component<PopperProps, PopperState> {
isShown: false,
interactive: false,
closeOnBlur: false,
referenceObject: null,
};

constructor(props: PopperProps) {
Expand Down Expand Up @@ -136,7 +139,7 @@ class Popper extends Component<PopperProps, PopperState> {

initPopper(): void {
let { popper } = this.state;
const { closeOnBlur } = this.props;
const { closeOnBlur, referenceObject } = this.props;

if (popper) {
return;
Expand All @@ -158,7 +161,7 @@ class Popper extends Component<PopperProps, PopperState> {
parent = this.container.current;
}

popper = new PopperJs(parent, this.element, options);
popper = new PopperJs(referenceObject || parent, this.element, options);
popper.scheduleUpdate();

// delayed due to scheduleUpdate
Expand Down Expand Up @@ -293,4 +296,4 @@ class Popper extends Component<PopperProps, PopperState> {
}

export default Popper;
export type { PopperOptions };
export type { PopperOptions, ReferenceObject };
13 changes: 11 additions & 2 deletions packages/components/src/popper/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import classNames from 'classnames';
import Log from '@deephaven/log';
import Popper, { PopperOptions } from './Popper';
import Popper, { PopperOptions, ReferenceObject } from './Popper';

const log = Log.module('Tooltip');

Expand All @@ -12,6 +12,7 @@ interface TooltipProps {
reshowTimeout: number;
children: React.ReactNode;
popperClassName: string;
referenceObject: ReferenceObject;
}

interface TooltipState {
Expand Down Expand Up @@ -47,6 +48,7 @@ class Tooltip extends Component<TooltipProps, TooltipState> {
popperClassName: '',
reshowTimeout: Tooltip.defaultReshowTimeout,
timeout: Tooltip.defaultTimeout,
referenceObject: null,
};

static handleHidden(): void {
Expand Down Expand Up @@ -280,7 +282,13 @@ class Tooltip extends Component<TooltipProps, TooltipState> {
}

render(): JSX.Element {
const { interactive, children, options, popperClassName } = this.props;
const {
interactive,
children,
options,
referenceObject,
popperClassName,
} = this.props;
const { isShown } = this.state;
return (
<div ref={this.container} style={{ display: 'none' }}>
Expand All @@ -290,6 +298,7 @@ class Tooltip extends Component<TooltipProps, TooltipState> {
ref={this.popper}
onExited={this.handleExited}
interactive={interactive}
referenceObject={referenceObject}
>
<div className="tooltip-content"> {isShown && children}</div>
</Popper>
Expand Down
1 change: 1 addition & 0 deletions packages/iris-grid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@fortawesome/react-fontawesome": "^0.1.12",
"classnames": "^2.3.1",
"deep-equal": "^2.0.4",
"lodash.clamp": "^4.0.3",
"lodash.debounce": "^4.0.8",
"lodash.throttle": "^4.1.1",
"memoize-one": "^5.1.1",
Expand Down
65 changes: 62 additions & 3 deletions packages/iris-grid/src/IrisGrid.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import dh, { PropTypes as APIPropTypes } from '@deephaven/jsapi-shim';
import { Pending, PromiseUtils, ValidationError } from '@deephaven/utils';
import throttle from 'lodash.throttle';
import debounce from 'lodash.debounce';
import clamp from 'lodash.clamp';
import PendingDataBottomBar from './PendingDataBottomBar';
import IrisGridCopyHandler from './IrisGridCopyHandler';
import FilterInputField from './FilterInputField';
Expand Down Expand Up @@ -2421,23 +2422,80 @@ export class IrisGrid extends Component {
}

let columnTooltip = null;
if (shownColumnTooltip != null && metrics) {
if (shownColumnTooltip != null && metrics && this.gridWrapper) {
const {
columnHeaderHeight,
visibleColumnXs,
visibleColumnWidths,
width,
} = metrics;
const columnX = visibleColumnXs.get(shownColumnTooltip);
const columnWidth = visibleColumnWidths.get(shownColumnTooltip);

/**
* Create a wrapper dom element, the size of the column header.
* The wrapper acts as tooltip parent, the tooltip component
* will trigger hide on mouseleave of wrapper or tooltip.
* The wrapper should be bound to within the grid dimensions,
* so popper only remains triggered while mouse is inside the panel.
*/
const boundedLeft = Math.max(0, columnX);
let boundedWidth = columnWidth;
if (columnX + columnWidth > width) {
// column is extending past right edge
boundedWidth = width - columnX;
} else if (columnX < 0) {
// column is extending past left edge
boundedWidth = columnWidth - Math.abs(columnX);
}

const wrapperStyle = {
position: 'absolute',
top: 0,
left: columnX,
width: columnWidth,
left: boundedLeft,
width: boundedWidth,
height: columnHeaderHeight,
pointerEvents: 'none',
};

/**
* Because the popper parent wrapper center is no longer the same as
* the column label center, we create a popper virtual ref, to handle
* positioning and keep the popper centered on the label. Creates a
* 1px x headerHeight virtual object, placed centered on the column
* label, clamped to 0 + margin to width - margin. We add a margin,
* otherwise the arrow wants to escape the boundary.
*/
const gridRect = this.gridWrapper.getBoundingClientRect();
const popperMargin = 20;
const virtualReference = {
clientWidth: 1,
clientHeight: columnHeaderHeight,
getBoundingClientRect() {
return {
top: gridRect.top,
left:
gridRect.left +
clamp(
columnX + columnWidth / 2,
popperMargin,
width - popperMargin
),
bottom: gridRect.top + columnHeaderHeight,
right:
gridRect.left +
clamp(
columnX + columnWidth / 2,
popperMargin,
width - popperMargin
) +
1,
width: 1,
height: columnHeaderHeight,
};
},
};

const popperOptions = {
placement: 'bottom',
modifiers: {
Expand All @@ -2459,6 +2517,7 @@ export class IrisGrid extends Component {
interactive
options={popperOptions}
ref={this.handleTooltipRef}
referenceObject={virtualReference}
>
<ColumnStatistics
model={model}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class IrisGridColumnTooltipMouseHandler extends GridMouseHandler {
return false;
}

onWheel() {
this.destroyColumnTooltip();
}

onMove(gridPoint) {
const { y, column, row } = gridPoint;
const { shownColumnTooltip } = this.irisGrid.state;
Expand All @@ -58,14 +62,6 @@ class IrisGridColumnTooltipMouseHandler extends GridMouseHandler {

return false;
}

onLeave(gridPoint) {
const { y } = gridPoint;
if (y < 0) {
this.destroyColumnTooltip();
}
return false;
}
}

export default IrisGridColumnTooltipMouseHandler;

0 comments on commit 1a9f7fb

Please sign in to comment.