1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Incorporate existing component to handle cell resizing

Signed-off-by: Alex Culliere <alozhkin@mirantis.com>
This commit is contained in:
Alex Culliere 2021-03-18 18:34:36 +02:00
parent 051d79fcde
commit 2292f2624c
2 changed files with 10 additions and 98 deletions

View File

@ -1,7 +0,0 @@
/**
* Ergonomic rate for throttling mouse events
* when resizing, in miliseconds.
* Represents optimal balance between user-facing latency
* and rendering performance
*/
export const ERGONOMIC_RESIZE_THROTTLE_RATE = 10;

View File

@ -1,12 +1,11 @@
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import { throttle } from "lodash";
import "./table-cell.scss"; import "./table-cell.scss";
import type { TableSortBy, TableSortParams } from "./table"; import type { TableSortBy, TableSortParams } from "./table";
import { autobind, cssNames, displayBooleans, prevDefault } from "../../utils"; import { autobind, cssNames, displayBooleans, prevDefault } from "../../utils";
import { Icon } from "../icon"; import { Icon } from "../icon";
import { Checkbox } from "../checkbox"; import { Checkbox } from "../checkbox";
import { ERGONOMIC_RESIZE_THROTTLE_RATE } from "./constants"; import { ResizingAnchor, ResizeDirection, ResizeSide, ResizeGrowthDirection } from "../resizing-anchor";
export type TableCellElem = React.ReactElement<TableCellProps>; export type TableCellElem = React.ReactElement<TableCellProps>;
@ -45,77 +44,6 @@ export class TableCell extends React.Component<TableCellProps> {
private resizeHandlerState?: ResizeHandlerState; private resizeHandlerState?: ResizeHandlerState;
private cellContainer: React.RefObject<HTMLDivElement> = React.createRef(); private cellContainer: React.RefObject<HTMLDivElement> = React.createRef();
/**
* Stores an instance of `<TableCell>` that is currently responsible for handling resize-related events
*/
private static currentEventHandlingInstance?: TableCell;
/**
* Appends static event proxies to document `mousemove` and `mouseup` events for resizing,
* sets a particulate instance of `<TableCell>` to handle these events
* @param handlingInstance instance of `<TableCell>` responsible for handling events
*/
private static addMouseEventListeners(handlingInstance: TableCell) {
TableCell.currentEventHandlingInstance = handlingInstance;
document.addEventListener("mousemove", TableCell.mouseMoveEventProxy);
document.addEventListener("mouseup", TableCell.mouseUpEventProxy);
}
/**
* Detaches static proxies from document `mousemove` and `mouseup`,
* cleans up the reference to current event handling instance
*/
private static removeMouseEventListeners() {
document.removeEventListener("mousemove", TableCell.mouseMoveEventProxy);
document.removeEventListener("mouseup", TableCell.mouseUpEventProxy);
delete TableCell.currentEventHandlingInstance;
}
/**
* Proxy for document-level `mousemove` events.
*
* Forwards the event to a member function
* of a current event handling instance of `<TableCell>`.
*
* Static to prevent it from leaking events.
*/
private static mouseMoveEventProxy(event: MouseEvent) {
TableCell.currentEventHandlingInstance.mouseMoveHandler(event);
}
/**
* Proxy for document-level `mouseup` events.
*
* Forwards the event to a member function
* of a current event handling instance of `<TableCell>`.
*
* Static to prevent it from leaking events.
*/
private static mouseUpEventProxy() {
TableCell.currentEventHandlingInstance.mouseUpHandler();
}
private mouseMoveHandler = throttle((event: MouseEvent) => {
if (!this.resizeHandlerState) {
return;
}
const diffPosX = event.pageX - this.resizeHandlerState.mousePosX;
const currentWidth = this.cellContainer.current.offsetWidth;
this.props?.onResize(currentWidth + diffPosX);
this.resizeHandlerState.mousePosX = event.pageX;
}, ERGONOMIC_RESIZE_THROTTLE_RATE);
private mouseUpHandler() {
TableCell.removeMouseEventListeners();
this.props?.onResizeComplete();
delete this.resizeHandlerState;
}
@autobind() @autobind()
onClick(evt: React.MouseEvent<HTMLDivElement>) { onClick(evt: React.MouseEvent<HTMLDivElement>) {
if (this.props.onClick) { if (this.props.onClick) {
@ -127,10 +55,6 @@ export class TableCell extends React.Component<TableCellProps> {
} }
} }
componentWillUnmount() {
TableCell.removeMouseEventListeners();
}
get isSortable() { get isSortable() {
const { _sorting, sortBy } = this.props; const { _sorting, sortBy } = this.props;
@ -188,16 +112,6 @@ export class TableCell extends React.Component<TableCellProps> {
const cellStyle: React.CSSProperties = size !== undefined ? const cellStyle: React.CSSProperties = size !== undefined ?
{ minWidth: `${size}px` } : { minWidth: `${size}px` } :
{}; {};
const resizeHandlers: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> = {
onMouseDown: event => {
this.resizeHandlerState = {
mousePosX: event.pageX
};
TableCell.addMouseEventListeners(this);
},
// prevent click events from triggering
onClick: prevDefault(() => {})
};
return ( return (
<div ref={this.cellContainer} style={cellStyle} {...cellProps} className={classNames} onClick={this.onClick}> <div ref={this.cellContainer} style={cellStyle} {...cellProps} className={classNames} onClick={this.onClick}>
@ -206,11 +120,16 @@ export class TableCell extends React.Component<TableCellProps> {
{_nowrap ? <div className="content">{content}</div> : content} {_nowrap ? <div className="content">{content}</div> : content}
{this.renderSortIcon()} {this.renderSortIcon()}
</div> </div>
{resizable && ( {resizable && (
<span {...resizeHandlers} className="resize-anchor"> <ResizingAnchor
<Icon material="unfold_more" /> onStart={() => prevDefault(() => {})}
</span> onDrag={newSize => this.props.onResize(newSize)}
onEnd={() => this.props.onResizeComplete()}
getCurrentExtent={() => size}
direction={ResizeDirection.HORIZONTAL}
placement={ResizeSide.TRAILING}
growthDirection={ResizeGrowthDirection.LEFT_TO_RIGHT}
/>
)} )}
</div> </div>
); );