Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions packages/react-core/src/components/Truncate/Truncate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react';
import styles from '@patternfly/react-styles/css/components/Truncate/truncate';
import { css } from '@patternfly/react-styles';
import { Tooltip } from '../Tooltip';

export enum TruncatePosition {
start = 'start',
end = 'end',
middle = 'middle'
}

const truncateStyles = {
start: styles.truncateEnd,
end: styles.truncateStart
};

const minWidthCharacters: number = 12;

interface TruncateProps extends React.HTMLProps<HTMLSpanElement> {
/** Class to add to outer span */
className?: string;
/** Text to truncate */
content: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wondering if we considered just using children for content instead. I don't have much of a preference, but curious about your thoughts.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that if we know that the content will always be a string, there is no need to have it as children and just use a prop content. But this was one thing that I knew that someone will be commenting, so totally up for debate :D

Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if at some point we'd want content to be bold or italicized. In that case, I think we'd want to just use ReactNode. If there's potential for that, I think it's worth a debate, or at least the changing of the type, otherwise if we know it will always be a string, what you have is fine with me.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a good question for @mattnolting
Will the css that controls the truncation still work if someone wants to put an icon or link somewhere in the string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The text can be bold or italicized, you can just add those tags around. But with the icon it won't work. So I think that it is best we keep it as string.

/** The number of characters displayed in the second half of the truncation */
trailingNumChars?: number;
/** Where the text will be truncated */
position?: 'start' | 'middle' | 'end';
/** Tooltip position */
tooltipPosition?: 'auto' | 'top' | 'bottom' | 'left' | 'right';
}

const sliceContent = (str: string, slice: number) => [str.slice(0, str.length - slice), str.slice(-slice)];

export const Truncate: React.FunctionComponent<TruncateProps> = ({
className,
position = 'end',
tooltipPosition = 'top',
trailingNumChars = 7,
content,
...props
}: TruncateProps) => (
<Tooltip position={tooltipPosition} content={content}>
<span className={css(styles.truncate, className)} {...props}>
{(position === TruncatePosition.end || position === TruncatePosition.start) && (
<span className={truncateStyles[position]}>
{content}
{position === TruncatePosition.start && <React.Fragment>&lrm;</React.Fragment>}
</span>
)}
{position === TruncatePosition.middle &&
content.slice(0, content.length - trailingNumChars).length > minWidthCharacters && (
<React.Fragment>
<span className={styles.truncateStart}>{sliceContent(content, trailingNumChars)[0]}</span>
<span className={styles.truncateEnd}>{sliceContent(content, trailingNumChars)[1]}</span>
</React.Fragment>
)}
{position === TruncatePosition.middle &&
content.slice(0, content.length - trailingNumChars).length <= minWidthCharacters &&
content}
</span>
</Tooltip>
);
Truncate.displayName = 'Truncate';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { shallow } from 'enzyme';
import { Truncate } from '../Truncate';

test('renders default truncation', () => {
const view = shallow(<Truncate content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'} />);
expect(view).toMatchSnapshot();
});

test('renders start truncation', () => {
const view = shallow(<Truncate content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'} position={'start'} />);
expect(view).toMatchSnapshot();
});

test('renders middle truncation', () => {
const view = shallow(<Truncate content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'} position={'middle'} />);
expect(view).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders default truncation 1`] = `
<Tooltip
content="Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan."
position="top"
>
<span
className="pf-c-truncate"
>
<span
className="pf-c-truncate__start"
>
Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.
</span>
</span>
</Tooltip>
`;

exports[`renders middle truncation 1`] = `
<Tooltip
content="Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan."
position="top"
>
<span
className="pf-c-truncate"
>
<span
className="pf-c-truncate__start"
>
Vestibulum interdum risus et enim faucibus, sit amet molestie est ac
</span>
<span
className="pf-c-truncate__end"
>
cumsan.
</span>
</span>
</Tooltip>
`;

exports[`renders start truncation 1`] = `
<Tooltip
content="Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan."
position="top"
>
<span
className="pf-c-truncate"
>
<span
className="pf-c-truncate__end"
>
Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.
</span>
</span>
</Tooltip>
`;
59 changes: 59 additions & 0 deletions packages/react-core/src/components/Truncate/examples/Truncate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
id: Truncate
section: components
propComponents: [Truncate]
beta: true
---

import './TruncateExamples.css';

## Examples

### Default
```js
import React from 'react';
import { Truncate } from '@patternfly/react-core';
<div className="pf-c-truncate--example">
<Truncate
content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'}
/>
</div>
```

### Middle

```js
import React from 'react';
import { Truncate } from '@patternfly/react-core';
<div className="pf-c-truncate--example">
<Truncate
content={'redhat_logo_black_and_white_reversed_simple_with_fedora_container.zip'}
trailingNumChars={10}
position={'middle'}
/>
</div>
```

### Start
```js
import React from 'react';
import { Truncate } from '@patternfly/react-core';
<div className="pf-c-truncate--example">
<Truncate
content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'}
position={'start'}
/>
</div>
```

### Default with tooltip at the bottom
```js
import React from 'react';
import { Truncate } from '@patternfly/react-core';
<div className="pf-c-truncate--example">
<Truncate
content={'Vestibulum interdum risus et enim faucibus, sit amet molestie est accumsan.'}
tooltipPosition={'bottom'}
/>
</div>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.pf-c-truncate--example {
width: 320px;
resize: horizontal;
overflow: auto;
min-width: 161px;
max-width: 100%;
padding: var(--pf-global--spacer--md);
border: var(--pf-global--BorderWidth--sm) solid var(--pf-global--BorderColor--100);
}
1 change: 1 addition & 0 deletions packages/react-core/src/components/Truncate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Truncate';
1 change: 1 addition & 0 deletions packages/react-core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ export * from './Wizard';
export * from './DragDrop';
export * from './TextInputGroup';
export * from './Panel';
export * from './Truncate';