From 1f535e39b94698d6fb339f49f33610766c1db252 Mon Sep 17 00:00:00 2001 From: Bill Dwyer Date: Tue, 29 Nov 2016 13:41:23 -0800 Subject: [PATCH] Adjust Truncated Popover Behavior Previously, the `TruncatedFormat` cell would display a popover target with the "..." icon when its text content was longer than the `truncationLength` prop. Cells that weren't truncated this way used a CSS "text-overflow: ellipsis" rule, which lead to the odd sight of a mixture of "..." in the cells. This change alters the default behavior to always show the large "..." icon even if the cell's text content isn't truncated. Therefore the look of the cells will be much more consistent. Also, the `JSONFormat` cell will turn off the "..." popover target for nully values. --- .../table/src/cell/formats/jsonFormat.tsx | 19 ++++++-- .../src/cell/formats/truncatedFormat.tsx | 46 +++++++++++++++++-- packages/table/src/index.ts | 1 + packages/table/test/formatsTests.tsx | 24 +++++++--- 4 files changed, 77 insertions(+), 13 deletions(-) diff --git a/packages/table/src/cell/formats/jsonFormat.tsx b/packages/table/src/cell/formats/jsonFormat.tsx index 388853119a..c4872d0776 100644 --- a/packages/table/src/cell/formats/jsonFormat.tsx +++ b/packages/table/src/cell/formats/jsonFormat.tsx @@ -8,7 +8,7 @@ import * as classNames from "classnames"; import * as PureRender from "pure-render-decorator"; import * as React from "react"; -import { ITruncatedFormatProps, TruncatedFormat } from "./truncatedFormat"; +import { ITruncatedFormatProps, TruncatedFormat, TruncatedPopover } from "./truncatedFormat"; /* istanbul ignore next */ export interface IJSONFormatProps extends ITruncatedFormatProps { @@ -38,15 +38,28 @@ export class JSONFormat extends React.Component { public render() { const { children, omitQuotesOnStrings, stringify } = this.props; + + const isNully = children === undefined || children === null; + const showPopover = isNully ? TruncatedPopover.NEVER : TruncatedPopover.ALWAYS; const className = classNames(this.props.className, { - "bp-table-null": children === undefined || children === null, + "bp-table-null": isNully, }); + let displayValue = ""; if (omitQuotesOnStrings && typeof children === "string") { displayValue = children; } else { displayValue = stringify(children); } - return {displayValue}; + + return ( + + {displayValue} + + ); } } diff --git a/packages/table/src/cell/formats/truncatedFormat.tsx b/packages/table/src/cell/formats/truncatedFormat.tsx index 36cc84bd7a..b9dd575811 100644 --- a/packages/table/src/cell/formats/truncatedFormat.tsx +++ b/packages/table/src/cell/formats/truncatedFormat.tsx @@ -10,6 +10,12 @@ import * as classNames from "classnames"; import * as PureRender from "pure-render-decorator"; import * as React from "react"; +export enum TruncatedPopover { + ALWAYS, + NEVER, + WHEN_TRUNCATED, +} + export interface ITruncatedFormatProps extends IProps { children?: string; @@ -20,6 +26,16 @@ export interface ITruncatedFormatProps extends IProps { */ preformatted?: boolean; + /** + * Configures when the popover is shown with the `TruncatedPopover` enum. + * + * The enum values are: + * - `ALWAYS` - show the popover (default). + * - `NEVER` - don't show the popover. + * - `WHEN_TRUNCATED` - show the popover only when the text is truncated. + */ + showPopover?: TruncatedPopover; + /** * Number of characters that are displayed before being truncated and appended with * the `truncationSuffix` prop. A value of 0 will disable truncation. @@ -32,12 +48,14 @@ export interface ITruncatedFormatProps extends IProps { * @default "..." */ truncationSuffix?: string; + } @PureRender export class TruncatedFormat extends React.Component { public static defaultProps: ITruncatedFormatProps = { preformatted: true, + showPopover: TruncatedPopover.ALWAYS, truncateLength: 80, truncationSuffix: "...", }; @@ -45,14 +63,19 @@ export class TruncatedFormat extends React.Component public render() { const { children, preformatted, truncateLength, truncationSuffix } = this.props; const content = "" + children; - if (truncateLength > 0 && content.length > truncateLength) { + + let cellContent = content; + if (truncateLength > 0 && cellContent.length > truncateLength) { + cellContent = cellContent.substring(0, truncateLength) + truncationSuffix; + } + + if (this.shouldShowPopover(content)) { const popoverClasses = classNames( "bp-table-truncated-popover", preformatted ? "bp-table-popover-whitespace-pre" : "bp-table-popover-whitespace-normal", ); const popoverContent =
{children}
; const className = classNames(this.props.className, "bp-table-truncated-format"); - const truncated = content.substring(0, truncateLength) + truncationSuffix; const constraints = [{ attachment: "together", pin: true, @@ -60,7 +83,7 @@ export class TruncatedFormat extends React.Component }]; return (
-
{truncated}
+
{cellContent}
); } else { const className = classNames(this.props.className, "bp-table-truncated-text"); - return
{content}
; + return
{cellContent}
; + } + } + + private shouldShowPopover(content: string) { + const { showPopover, truncateLength } = this.props; + + switch (showPopover) { + case TruncatedPopover.ALWAYS: + return true; + case TruncatedPopover.NEVER: + return false; + case TruncatedPopover.WHEN_TRUNCATED: + return (truncateLength > 0 && content.length > truncateLength); + default: + return false; } } } diff --git a/packages/table/src/index.ts b/packages/table/src/index.ts index 45c8320ded..a75803d3b9 100644 --- a/packages/table/src/index.ts +++ b/packages/table/src/index.ts @@ -24,6 +24,7 @@ export { } from "./cell/formats/jsonFormat"; export { + TruncatedPopover, TruncatedFormat, ITruncatedFormatProps, } from "./cell/formats/truncatedFormat"; diff --git a/packages/table/test/formatsTests.tsx b/packages/table/test/formatsTests.tsx index 7b03a7f04d..02dc0de375 100644 --- a/packages/table/test/formatsTests.tsx +++ b/packages/table/test/formatsTests.tsx @@ -8,7 +8,7 @@ import { expect } from "chai"; import * as React from "react"; import { JSONFormat } from "../src/cell/formats/jsonFormat"; -import { TruncatedFormat } from "../src/cell/formats/truncatedFormat"; +import { TruncatedFormat, TruncatedPopover } from "../src/cell/formats/truncatedFormat"; import { ReactHarness } from "./harness"; describe("Formats", () => { @@ -42,12 +42,20 @@ describe("Formats", () => { const comp = harness.mount({str}); expect(comp.find(".bp-table-truncated-value").text()).to.have.lengthOf(83); + expect(comp.find(".bp-table-truncated-popover-target").element).to.exist; }); - it("doesn't truncate if text is short enough", () => { + it("shows popover by default even if text is short", () => { const str = `quote from Unweaving the Rainbow by Richard Dawkins`; const comp = harness.mount({str}); - expect(comp.find(".bp-table-truncated-text").text()).to.have.lengthOf(str.length); + expect(comp.find(".bp-table-truncated-popover-target").element).to.exist; + }); + + it("doesn't show popover if text is short enough, when configured", () => { + const str = `quote from Unweaving the Rainbow by Richard Dawkins`; + /* tslint:disable-next-line:max-line-length */ + const comp = harness.mount({str}); + expect(comp.find(".bp-table-truncated-popover-target").element).to.not.exist; }); it("doesn't truncate if truncation length is 0", () => { @@ -89,7 +97,7 @@ describe("Formats", () => { Be all my sins remembered. `; const comp = harness.mount({str}); - expect(comp.find(".bp-table-truncated-text").text()).to.have.lengthOf(str.length); + expect(comp.find(".bp-table-truncated-value").text()).to.have.lengthOf(str.length); }); }); @@ -101,17 +109,21 @@ describe("Formats", () => { }; const str = JSON.stringify(obj, null, 2); const comp = harness.mount({obj}); - expect(comp.find(".bp-table-truncated-text").text()).to.equal(str); + expect(comp.find(".bp-table-truncated-popover-target").element).to.exist; + expect(comp.find(".bp-table-truncated-value").text()).to.equal(str); }); it("omits quotes on strings and null-likes", () => { let comp = harness.mount({"a string"}); - expect(comp.find(".bp-table-truncated-text").text()).to.equal("a string"); + expect(comp.find(".bp-table-truncated-popover-target").element).to.exist; + expect(comp.find(".bp-table-truncated-value").text()).to.equal("a string"); comp = harness.mount({null}); + expect(comp.find(".bp-table-truncated-popover-target").element).to.not.exist; expect(comp.find(".bp-table-truncated-text").text()).to.equal("null"); comp = harness.mount({undefined}); + expect(comp.find(".bp-table-truncated-popover-target").element).to.not.exist; expect(comp.find(".bp-table-truncated-text").text()).to.equal("undefined"); }); });