Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

Commit

Permalink
[terra-clinical-header] Add support for hyperlink header title (#923)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Tran <[email protected]>
  • Loading branch information
trandrew1023 and Andrew Tran authored Oct 9, 2023
1 parent 212b64d commit cd3392a
Show file tree
Hide file tree
Showing 29 changed files with 280 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Please review [Terra's Internationalization documentation](https://engineering.c
Contributing
</h2>

Please read through our [contributing guidelines](CONTRIBUTING.md). Included are directions for issue reporting and pull requests.
Please read through our [contributing guidelines](./CONTRIBUTING.md). Included are directions for issue reporting and pull requests.

<h2 id="local-development">
Local Development
Expand Down
3 changes: 3 additions & 0 deletions packages/terra-clinical-header/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Added
* Added `onTextClick` and support for hyperlink button header titles.

## 3.28.0 - (August 14, 2023)

* Changed
Expand Down
2 changes: 2 additions & 0 deletions packages/terra-clinical-header/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"classnames": "^2.2.5",
"prop-types": "^15.5.8",
"terra-button": "^3.0.0",
"terra-enzyme-intl": "^3.4.0",
"terra-hyperlink": "^2.63.0",
"terra-theme-context": "^1.0.0"
},
"scripts": {
Expand Down
30 changes: 26 additions & 4 deletions packages/terra-clinical-header/src/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import classNamesBind from 'classnames/bind';

import Hyperlink from 'terra-hyperlink';
import ThemeContext from 'terra-theme-context';

import styles from './Header.module.scss';
Expand Down Expand Up @@ -59,6 +61,12 @@ const propTypes = {
* A Boolean indicating if element is a subheader.
*/
isSubheader: PropTypes.bool,

/**
* Callback function triggered via hyperlink button title.
* Sets the header title to be a hyperlink.
*/
onClick: PropTypes.func,
};

const defaultProps = {
Expand All @@ -70,7 +78,16 @@ const defaultProps = {
};

const Header = ({
children, title, startContent, endContent, text, level, id, isSubheader, ...customProps
children,
title,
startContent,
endContent,
text,
level,
id,
isSubheader,
onClick,
...customProps
}) => {
const theme = useContext(ThemeContext);
if (title) {
Expand All @@ -85,12 +102,17 @@ const Header = ({
}

let titleElement;
if (title || text) {
const HeaderElement = (level) ? `h${level}` : 'h1';
const titleContent = title || text;
if (titleContent) {
const HeaderElement = level ? `h${level}` : 'h1';
titleElement = (
<div className={cx('title-container')}>
<HeaderElement id={id} className={cx('title')}>
{title || text}
{onClick ? (
<Hyperlink onClick={onClick} text={titleContent} />
) : (
titleContent
)}
</HeaderElement>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions packages/terra-clinical-header/src/Header.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@
width: 100%;
word-wrap: break-word; /* For IE 10 and IE 11 */
}

/* stylelint-disable selector-max-compound-selectors */
.flex-end + .flex-fill {
.title {
padding-left: var(--terra-clinical-header-end-content-plus-title-padding-left, 0.35714rem);
}
}

.flex-fill + .flex-end {
.title {
padding-right: var(--terra-clinical-header-title-plus-end-content-padding-right, 0.35714rem);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ContentHeader from '../example/ContentHeader?dev-site-example';
import HeaderLongText from '../example/HeaderLongText?dev-site-example';
import HeaderLongTextWithContent from '../example/HeaderLongTextWithContent?dev-site-example';
import Subheader from '../example/Subheader?dev-site-example';
import HyperlinkTitleHeader from '../example/HyperlinkTitleHeader?dev-site-example';

<Badge />

Expand All @@ -19,7 +20,7 @@ A Header component that allows elements to be placed on the left and right ends
- Install with [npmjs](https://www.npmjs.com):
- `npm install terra-clinical-header`

## Usage
## Usage

``` jsx
import Header from 'terra-clinical-header';
Expand All @@ -30,12 +31,13 @@ import Header from 'terra-clinical-header';
* [Responsive Support](https://engineering.cerner.com/terra-ui/about/terra-ui/component-standards#responsive-support)
* [Mobile Support](https://engineering.cerner.com/terra-ui/about/terra-ui/component-standards#mobile-support)

## Example
## Example
<TitleHeader title='Header With Title Only' />
<HyperlinkTitleHeader title='Header With Hyperlink Title' />
<ContentHeader title='Header With Content' />
<HeaderLongText title='Header With Long Title' />
<HeaderLongTextWithContent title='Header With Long Title, Children, And Content' />
<Subheader title='Subheader With Content' />

## Header Props Table
## Header Props Table
<HeaderPropsTable />
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import Header from 'terra-clinical-header';

const HyperlinkTitleHeader = () => (
// eslint-disable-next-line no-console
<Header onClick={() => { console.log('Hyperlink title clicked'); }} text="John Smith" level={3} />
);

export default HyperlinkTitleHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

import Header from '../../../Header';

const HyperlinkTitleHeader = () => (
<Header onClick={() => {}} text="John Smith" />
);

export default HyperlinkTitleHeader;
95 changes: 82 additions & 13 deletions packages/terra-clinical-header/tests/jest/Header.test.jsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,137 @@
import React from 'react';
import { shallowWithIntl } from 'terra-enzyme-intl';

import Header from '../../src/Header';

const mockFunc = jest.fn();
afterEach(() => {
// restore the spy created with spyOn
jest.restoreAllMocks();
});

it('should render a default component', () => {
const header = render(<Header />);
const header = shallow(<Header />);
expect(header).toMatchSnapshot();
});

it('should render a header with title', () => {
const header = shallow(<Header text="title" />);

const headerTitle = header.find('h1');
expect(headerTitle.text()).toEqual('title');
expect(header).toMatchSnapshot();
});

it('should render a header with title and heading level', () => {
const header = render(<Header id="test-id" level={1} text="title" />);
it('should render a header with id', () => {
const header = shallow(<Header id="test-id" text="title" />);

const headerTitle = header.find('h1');
expect(headerTitle.prop('id')).toEqual('test-id');
expect(headerTitle.text()).toEqual('title');
expect(header).toMatchSnapshot();
});

it('should render a header with heading level', () => {
const header = shallow(<Header level={2} text="title" />);

const headerTitle = header.find('h2');
expect(headerTitle.text()).toEqual('title');
expect(header).toMatchSnapshot();
});

it('should render a header with content on the left', () => {
const header = render(<Header level={1} startContent={<div>start content</div>} />);
const startContent = <div id="start-id">start content</div>;
const flexFill = <div className="flex-fill" />;
const flexEnd = <div className="flex-end">{startContent}</div>;
const header = shallow(<Header startContent={startContent} />);

// ensure flex-fill title container is after start content
expect(header.find('.flex-header').props().children[0]).toEqual(flexEnd);
expect(header.find('.flex-header').props().children[1]).toEqual(flexFill);
expect(header).toMatchSnapshot();
});

it('should render a header with content on the right', () => {
const header = render(<Header level={1} endContent={<div>end content</div>} />);
const endContent = <div id="end-id">end content</div>;
const flexFill = <div className="flex-fill" />;
const flexEnd = <div className="flex-end">{endContent}</div>;
const header = shallow(<Header endContent={endContent} />);

// ensure flex-fill title container is before end content
expect(header.find('.flex-header').props().children[1]).toEqual(flexFill);
expect(header.find('.flex-header').props().children[3]).toEqual(flexEnd);
expect(header).toMatchSnapshot();
});

it('should render a header with all content', () => {
const header = render((
const startContent = <div id="start-id">start content</div>;
const endContent = <div id="end-id">end content</div>;
const flexFill = (
<div className="flex-fill">
<div className="title-container">
<h1 className="title">Title</h1>
</div>
</div>
);
const flexEndStart = <div className="flex-end">{startContent}</div>;
const flexEndEnd = <div className="flex-end">{endContent}</div>;
const header = shallow((
<Header
startContent={<div>start content</div>}
startContent={startContent}
text="Title"
endContent={<div>end content</div>}
level={1}
endContent={endContent}
/>
));

const headerTitle = header.find('h1');
expect(headerTitle.text()).toEqual('Title');
expect(header.find('.flex-header').props().children[0]).toEqual(flexEndStart);
expect(header.find('.flex-header').props().children[1]).toEqual(flexFill);
expect(header.find('.flex-header').props().children[3]).toEqual(flexEndEnd);
expect(header).toMatchSnapshot();
});

it('should render a subheader with title and heading level', () => {
const consoleSpy = jest.spyOn(global.console, 'warn');
const subheader = render(<Header level={1} title="title" isSubheader />);
const subheader = shallow(<Header title="title" isSubheader />);
const titleWarningMessage = 'The `title` prop has been renamed to `text`. Please update all references of `title` prop to `text`.';

expect(subheader.prop('className')).toEqual('flex-header subheader');
expect(subheader.find('h1').text()).toEqual('title');
expect(consoleSpy).toHaveBeenCalledWith(titleWarningMessage);
expect(subheader).toMatchSnapshot();
});

it('should render a subheader with all content', () => {
const subheader = render((
const subheader = shallow((
<Header
startContent={<div>start content</div>}
text="Title"
endContent={<div>end content</div>}
isSubheader
level={1}
/>
));
expect(subheader).toMatchSnapshot();
});

it('should render a header with default heading level when level not set', () => {
const consoleSpy = jest.spyOn(global.console, 'warn');
const header = render(<Header text="This title should render with a default level" />);
const title = 'This title should render with a default level';
const header = shallow(<Header text={title} />);
const levelWarningMessage = 'Default heading level may not appropriate has it would fail to convey context of heading in a site / application where it is used. Heading level should be set explicitly depending on the position of header in site / application to allow screen readers to identify headers consistently.';

expect(header.find('h1').text()).toEqual(title);
expect(consoleSpy).toHaveBeenCalledWith(levelWarningMessage);
expect(header).toMatchSnapshot();
});

it('should render a header with hyperlink title', () => {
const header = shallowWithIntl(<Header onClick={mockFunc} text="Title" />);

expect(header.find('h1').length).toEqual(1);
const hyperlinkButton = header.find('InjectIntl(Hyperlink)');
expect(hyperlinkButton.prop('onClick')).toEqual(mockFunc);
expect(hyperlinkButton.prop('text')).toEqual('Title');
expect(header).toMatchSnapshot();
});

Loading

0 comments on commit cd3392a

Please sign in to comment.