From f441310a981ba8fa5602d2cd933875e6df9853f2 Mon Sep 17 00:00:00 2001 From: Valentine Nuikin <zwerg44@gmail.com> Date: Thu, 23 Jan 2020 01:41:28 +0300 Subject: [PATCH] [table] fix: column resize calculation on header double click (#3732) --- packages/table/src/common/utils.ts | 32 +++++++++---------- .../table/src/headers/columnHeaderCell.tsx | 3 +- packages/table/src/headers/header.tsx | 5 ++- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/packages/table/src/common/utils.ts b/packages/table/src/common/utils.ts index e37f4fda60..05de754853 100644 --- a/packages/table/src/common/utils.ts +++ b/packages/table/src/common/utils.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -const CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT = "bp-table-text-no-measure"; +// used to exclude icons from column header measure +export const CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT = "bp-table-text-no-measure"; +// supposed width of the icons placeholder +const EXCLUDED_ICON_PLACEHOLDER_WIDTH = 16; /** * Since Firefox doesn't provide a computed "font" property, we manually @@ -350,23 +353,20 @@ export const Utils = { * exclude an element's text from the computation. */ function measureTextContentWithExclusions(context: CanvasRenderingContext2D, element: Element): TextMetrics { - // We only expect one or zero excluded elements in this subtree - // We don't have a need for more than one, so we avoid that complexity altogether. - const elementToExclude = element.querySelector(`.${CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT}`); - let removedElementParent: Element | undefined; - let removedElementNextSibling: Node | undefined; - - if (elementToExclude != null) { - removedElementParent = elementToExclude.parentElement; - removedElementNextSibling = elementToExclude.nextSibling; - removedElementParent.removeChild(elementToExclude); + const elementsToExclude = element.querySelectorAll(`.${CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT}`); + let excludedElementsWidth = 0; + if (elementsToExclude && elementsToExclude.length) { + elementsToExclude.forEach((e) => { + const excludedMetrics = context.measureText(e.textContent); + excludedElementsWidth += excludedMetrics.width - EXCLUDED_ICON_PLACEHOLDER_WIDTH; + }); } const metrics = context.measureText(element.textContent); + const metricsWithExclusions = { + ...metrics, + width: metrics.width - excludedElementsWidth, + }; - if (elementToExclude != null) { - removedElementParent.insertBefore(elementToExclude, removedElementNextSibling); - } - - return metrics; + return metricsWithExclusions; } diff --git a/packages/table/src/headers/columnHeaderCell.tsx b/packages/table/src/headers/columnHeaderCell.tsx index 568911a529..97be63b318 100644 --- a/packages/table/src/headers/columnHeaderCell.tsx +++ b/packages/table/src/headers/columnHeaderCell.tsx @@ -31,6 +31,7 @@ import { import * as Classes from "../common/classes"; import { columnInteractionBarContextTypes, IColumnInteractionBarContextTypes } from "../common/context"; import { LoadableContent } from "../common/loadableContent"; +import { CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT } from "../common/utils"; import { HeaderCell, IHeaderCellProps } from "./headerCell"; export interface IColumnNameProps { @@ -196,7 +197,7 @@ export class ColumnHeaderCell extends AbstractPureComponent2<IColumnHeaderCellPr return undefined; } - const classes = classNames(Classes.TABLE_TH_MENU_CONTAINER, { + const classes = classNames(Classes.TABLE_TH_MENU_CONTAINER, CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT, { [Classes.TABLE_TH_MENU_OPEN]: this.state.isActive, }); diff --git a/packages/table/src/headers/header.tsx b/packages/table/src/headers/header.tsx index 86d69c6877..101622bf92 100644 --- a/packages/table/src/headers/header.tsx +++ b/packages/table/src/headers/header.tsx @@ -21,6 +21,7 @@ import * as React from "react"; import { Grid } from "../common"; import { IFocusedCellCoordinates } from "../common/cell"; import * as Classes from "../common/classes"; +import { CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT } from "../common/utils"; import { DragEvents } from "../interactions/dragEvents"; import { IClientCoordinates, ICoordinateData } from "../interactions/draggable"; import { DragReorderable, IReorderableProps } from "../interactions/reorderable"; @@ -384,7 +385,9 @@ export class Header extends React.Component<IInternalHeaderProps, IHeaderState> : this.wrapInDragReorderable( index, <div className={Classes.TABLE_REORDER_HANDLE_TARGET}> - <div className={Classes.TABLE_REORDER_HANDLE}> + <div + className={classNames(Classes.TABLE_REORDER_HANDLE, CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT)} + > <Icon icon="drag-handle-vertical" /> </div> </div>,