Skip to content

Commit

Permalink
feat(Truncate): Added the truncate component.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlabaj committed Sep 21, 2023
1 parent 521a280 commit 9a3355c
Show file tree
Hide file tree
Showing 13 changed files with 3,361 additions and 49 deletions.
2,466 changes: 2,423 additions & 43 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
"lint:md:fix": "eslint packages --ext md --no-eslintrc --config .eslintrc-md.json --cache --fix",
"lint": "npm run lint:js && npm run lint:md",
"lint:fix": "npm run lint:js:fix && npm run lint:md:fix",
"serve:a11y": "npm run serve:a11y -w @patternfly/react-component-groups",
"test": "TZ=EST jest packages",
"test:a11y": "npm run test:a11y -w @patternfly/react-component-groups",
"serve:a11y": "npm run serve:a11y -w @patternfly/react-component-groups"
"test:a11y": "npm run test:a11y -w @patternfly/react-component-groups"
},
"devDependencies": {
"@babel/core": "^7.19.6",
Expand Down
15 changes: 11 additions & 4 deletions packages/module/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"scripts": {
"build": "npm run build:index && npm run build:js && npm run build:esm && npm run build:fed:packages",
"build:watch": "npm run build:js && npm run build:esm -- --watch && npm run build:fed:packages -- --watch",
"build": "npm run build:index && npm run build:js && npm run build:esm && npm run build:fed:packages && npm run build:css && npm run transform:css",
"build:css": "node ../../scripts/build-styles.js",
"build:watch": "npm run build:js && npm run build:esm -- --watch && npm run build:fed:packages -- --watch && npm run build:css -- --watch",
"build:esm": "tsc --build --verbose ./tsconfig.json",
"build:fed:packages": "node generate-fed-package-json.js",
"build:js": "tsc -p tsconfig.cjs.json",
Expand All @@ -16,8 +17,9 @@
"docs:build": "pf-docs-framework build all --output public",
"docs:serve": "pf-docs-framework serve public --port 5001",
"docs:screenshots": "pf-docs-framework screenshots --urlPrefix http://localhost:5001",
"serve:a11y": "serve coverage",
"test:a11y": "patternfly-a11y --config patternfly-a11y.config",
"serve:a11y": "serve coverage"
"transform:css": "node ../../scripts/transform-scss.js"
},
"repository": "git+https://github.com/patternfly/react-component-groups.git",
"author": "Red Hat",
Expand All @@ -33,7 +35,8 @@
"dependencies": {
"@patternfly/react-core": "^5.0.0",
"@patternfly/react-icons": "^5.0.0",
"react-jss": "^10.9.2"
"react-jss": "^10.9.2",
"sanitize-html": "^2.3.3"
},
"peerDependencies": {
"react": "^17 || ^18",
Expand All @@ -45,16 +48,20 @@
"@patternfly/patternfly": "^5.0.0",
"@patternfly/react-table": "^5.0.0",
"@patternfly/react-code-editor": "^5.0.0",
"@redhat-cloud-services/frontend-components-utilities": "^4.0.2",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react-router-dom": "^5.3.3",
"classnames": "^2.2.5",
"copyfiles": "^2.4.1",
"node-sass-package-importer": "^5.3.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"rimraf": "^2.6.2",
"sass": "^1.55.0",
"style-to-object": "^0.3.0",
"typescript": "^4.9.5"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
section: extensions
subsection: Component groups
id: Truncate
source: react
propComponents: ['Truncate']
---

import Truncate from "@patternfly/react-component-groups/dist/dynamic/Truncate";

## Component usage

### Truncate component

```js file="./TruncateExample.tsx"

```
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import Truncate from "@patternfly/react-component-groups/dist/dynamic/Truncate";


export const BasicExample: React.FunctionComponent = () => <Truncate text="This is a long string that will be truncated" length={10} />;

79 changes: 79 additions & 0 deletions packages/module/src/Truncate/Truncate.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';
import { render } from '@testing-library/react';
import Truncate from './Truncate';

const text = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore
et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.`;

describe('Truncate component', () => {

Check failure on line 11 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'describe' is not defined
describe('should render correctly', () => {

Check failure on line 12 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'describe' is not defined
[true, false].forEach((isInline) => {

Check failure on line 13 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

A space is required after '['

Check failure on line 13 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

A space is required before ']'
describe(isInline ? 'inline' : 'block', () => {

Check failure on line 14 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'describe' is not defined
it('without length specified', () => {

Check failure on line 15 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'it' is not defined
const wrapper = render(<Truncate text={text} inline={isInline} />);
expect(toJson(wrapper)).toMatchSnapshot();

Check failure on line 17 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'expect' is not defined

Check failure on line 17 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'toJson' is not defined
});

it('with short length', () => {

Check failure on line 20 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'it' is not defined
const wrapper = render(<Truncate text={text} length={2} />);
expect(toJson(wrapper)).toMatchSnapshot();

Check failure on line 22 in packages/module/src/Truncate/Truncate.test.js

View workflow job for this annotation

GitHub Actions / call-build-lint-test-workflow / lint

'expect' is not defined
});

it('clicking on expand toggles to collapse', () => {
const wrapper = render(<Truncate text={text} inline={isInline} expandText="Custom expand" collapseText="Custom collapse" />);
wrapper.find('.ins-c-expand-button').first().simulate('click');
expect(toJson(wrapper)).toMatchSnapshot();
});

it('custom expande button', () => {
const wrapper = render(<Truncate text={text} inline={isInline} expandText="Custom expand" collapseText="Custom collapse" />);
expect(toJson(wrapper)).toMatchSnapshot();
});

it('custom button titles', () => {
const wrapper = render(<Truncate text={text} inline={isInline} expandText="Custom expand" collapseText="Custom collapse" />);
wrapper.find('.ins-c-expand-button').first().simulate('click');
expect(toJson(wrapper)).toMatchSnapshot();
});

it('clicking on expand toggles to collapse', () => {
const wrapper = render(<Truncate text={text} inline={isInline} expandText="Custom expand" collapseText="Custom collapse" />);
wrapper.find('.ins-c-expand-button').first().simulate('click');
expect(toJson(wrapper)).toMatchSnapshot();
});

it('custom expande button', () => {
const wrapper = render(<Truncate text={text} inline={isInline} expandText="Custom expand" collapseText="Custom collapse" />);
expect(toJson(wrapper)).toMatchSnapshot();
});

it('custom button titles', () => {
const wrapper = render(<Truncate text={text} inline={isInline} expandText="Custom expand" collapseText="Custom collapse" />);
wrapper.find('.ins-c-expand-button').first().simulate('click');
expect(toJson(wrapper)).toMatchSnapshot();
});

it('when text length is less than user specified length', () => {
const wrapper = render(<Truncate text={text} inline={isInline} length={1000} />);
expect(toJson(wrapper)).toMatchSnapshot();
});

it('hovering over toggles to collapse', () => {
const wrapper = render(<Truncate length={50} inline={isInline} text={text} expandOnMouseOver hideExpandText />);
const eventElement = isInline ? wrapper.find('.ins-c-truncate').first() : wrapper.find('.ins-c-truncate').first().children().first();

expect(toJson(wrapper)).toMatchSnapshot();

eventElement.simulate('mouseenter');
expect(toJson(wrapper)).toMatchSnapshot();

eventElement.simulate('mouseleave');
expect(toJson(wrapper)).toMatchSnapshot();
});
});
});
});
});
88 changes: 88 additions & 0 deletions packages/module/src/Truncate/Truncate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { useState } from 'react';
import classNames from 'classnames';
import { Button, Stack, StackItem } from '@patternfly/react-core';
import sanitizeHtml from 'sanitize-html';

import './truncate.scss';

const dangerousHtml = (html: string) => ({ __html: sanitizeHtml(html) });

export interface TruncateProps {
/** Additional classes added to the Truncate */
className?: string;
/** Text to display inside the Truncate component */
text?: string;
/** A set length for the truncate component. */
length?: number;
/** Indicates if the component is expanded to show the entire text */
expandText?: React.ReactNode;
collapseText?: React.ReactNode;
/** Indicates if the text should be kept inline */
inline?: boolean;
spaceBetween?: boolean;
hideExpandText?: boolean;
/** If set to true the text will be expanded when moused over */
expandOnMouseOver?: boolean;
}

const Truncate: React.FunctionComponent<TruncateProps> = ({
text = '',
length = 150,
expandText = 'Read more',
hideExpandText = false,
expandOnMouseOver = false,
collapseText = 'Collapse',
className,
inline,
spaceBetween,
}: TruncateProps) => {
const truncateClasses = classNames('ins-c-truncate', className, { [`is-inline`]: inline }, { [`is-block`]: !inline });
const trimmedText = text.substring(0, length);
const textOverflow = text.length > length;
const [showText, setShowText] = useState(false);
const toggleText = (event: React.MouseEvent<HTMLButtonElement>) => {
event && event.preventDefault();
setShowText(!showText);
};

const expandButton = (
<Button className="ins-c-expand-button" variant="link" onClick={toggleText}>
{expandText}
</Button>
);
const collapseButton = (
<Button className="ins-c-collapse-button" variant="link" onClick={toggleText}>
{collapseText}
</Button>
);
const textWithOverflow = showText === false ? `${trimmedText}${textOverflow ? '...' : ''}` : text;
const html = dangerousHtml(textWithOverflow);
const mouseOverHandler = expandOnMouseOver && {
onMouseEnter: () => setShowText(true),
onMouseLeave: () => setShowText(false),
};

return inline ? (
<React.Fragment>
<span className={truncateClasses} widget-type="InsightsTruncateInline" dangerouslySetInnerHTML={html} {...mouseOverHandler} />
{!hideExpandText && textOverflow && (showText === false ? expandButton : collapseButton)}
</React.Fragment>
) : (
<Stack className={truncateClasses}>
<StackItem {...mouseOverHandler}>
<span widget-type="InsightsTruncateBlock" dangerouslySetInnerHTML={html} />
</StackItem>
{!hideExpandText && textOverflow && (
<StackItem
className={classNames({
'pf-u-mt-sm': spaceBetween,
})}
>
{showText === false ? expandButton : collapseButton}
</StackItem>
)}
</Stack>
);
};

export default Truncate;
Loading

0 comments on commit 9a3355c

Please sign in to comment.