Skip to content

Commit

Permalink
Adjust Truncated Popover Behavior
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
themadcreator committed Nov 29, 2016
1 parent 8c576e7 commit 1f535e3
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 13 deletions.
19 changes: 16 additions & 3 deletions packages/table/src/cell/formats/jsonFormat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -38,15 +38,28 @@ export class JSONFormat extends React.Component<IJSONFormatProps, {}> {

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 <TruncatedFormat {...this.props} className={className}>{displayValue}</TruncatedFormat>;

return (
<TruncatedFormat
{...this.props}
className={className}
showPopover={showPopover}
>
{displayValue}
</TruncatedFormat>
);
}
}
46 changes: 42 additions & 4 deletions packages/table/src/cell/formats/truncatedFormat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand All @@ -32,35 +48,42 @@ export interface ITruncatedFormatProps extends IProps {
* @default "..."
*/
truncationSuffix?: string;

}

@PureRender
export class TruncatedFormat extends React.Component<ITruncatedFormatProps, {}> {
public static defaultProps: ITruncatedFormatProps = {
preformatted: true,
showPopover: TruncatedPopover.ALWAYS,
truncateLength: 80,
truncationSuffix: "...",
};

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 = <div className={popoverClasses}>{children}</div>;
const className = classNames(this.props.className, "bp-table-truncated-format");
const truncated = content.substring(0, truncateLength) + truncationSuffix;
const constraints = [{
attachment: "together",
pin: true,
to: "window",
}];
return (
<div className={className}>
<div className="bp-table-truncated-value">{truncated}</div>
<div className="bp-table-truncated-value">{cellContent}</div>
<Popover
className="bp-table-truncated-popover-target"
constraints={constraints}
Expand All @@ -74,7 +97,22 @@ export class TruncatedFormat extends React.Component<ITruncatedFormatProps, {}>
);
} else {
const className = classNames(this.props.className, "bp-table-truncated-text");
return <div className={className}>{content}</div>;
return <div className={className}>{cellContent}</div>;
}
}

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;
}
}
}
1 change: 1 addition & 0 deletions packages/table/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export {
} from "./cell/formats/jsonFormat";

export {
TruncatedPopover,
TruncatedFormat,
ITruncatedFormatProps,
} from "./cell/formats/truncatedFormat";
Expand Down
24 changes: 18 additions & 6 deletions packages/table/test/formatsTests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down Expand Up @@ -42,12 +42,20 @@ describe("Formats", () => {

const comp = harness.mount(<TruncatedFormat>{str}</TruncatedFormat>);
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(<TruncatedFormat>{str}</TruncatedFormat>);
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(<TruncatedFormat showPopover={TruncatedPopover.WHEN_TRUNCATED}>{str}</TruncatedFormat>);
expect(comp.find(".bp-table-truncated-popover-target").element).to.not.exist;
});

it("doesn't truncate if truncation length is 0", () => {
Expand Down Expand Up @@ -89,7 +97,7 @@ describe("Formats", () => {
Be all my sins remembered.
`;
const comp = harness.mount(<TruncatedFormat truncateLength={0}>{str}</TruncatedFormat>);
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);
});
});

Expand All @@ -101,17 +109,21 @@ describe("Formats", () => {
};
const str = JSON.stringify(obj, null, 2);
const comp = harness.mount(<JSONFormat>{obj}</JSONFormat>);
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(<JSONFormat>{"a string"}</JSONFormat>);
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(<JSONFormat>{null}</JSONFormat>);
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(<JSONFormat>{undefined}</JSONFormat>);
expect(comp.find(".bp-table-truncated-popover-target").element).to.not.exist;
expect(comp.find(".bp-table-truncated-text").text()).to.equal("undefined");
});
});
Expand Down

1 comment on commit 1f535e3

@blueprint-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjust Truncated Popover Behavior

Preview: docs | table Coverage: core | datetime

Please sign in to comment.