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"); }); });