Skip to content

Commit

Permalink
[WNMGDS-384] Allow custom heading level (#638)
Browse files Browse the repository at this point in the history
* Add headingLevel and make it more consistent across components

* Rename title to heading in Dialog

* Rename title to heading in HelpDrawer

* Rename title to heading in StepList

* Fix tests

* Fix lint errors

* PR feedback
  • Loading branch information
bernardwang authored Mar 4, 2020
1 parent b1dd82e commit 084d80f
Show file tree
Hide file tree
Showing 22 changed files with 160 additions and 83 deletions.
12 changes: 9 additions & 3 deletions packages/core/src/components/Alert/Alert.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ export class Alert extends React.PureComponent {
}

heading() {
const Heading = `h${this.props.headingLevel}` || `h3`;
if (this.props.heading) {
return (
<h3 className="ds-c-alert__heading" id={this.headingId}>
<Heading className="ds-c-alert__heading" id={this.headingId}>
{this.props.heading}
</h3>
</Heading>
);
}
}
Expand Down Expand Up @@ -51,7 +52,8 @@ export class Alert extends React.PureComponent {
}
}
Alert.defaultProps = {
role: 'region'
role: 'region',
headingLevel: '3'
};
Alert.propTypes = {
/**
Expand All @@ -66,6 +68,10 @@ Alert.propTypes = {
* Optional id used to link the `aria-labelledby` attribute to the heading. If not provided, a unique id will be automatically generated and used.
*/
headingId: PropTypes.string,
/**
* Heading type to override default `<h3>`.
*/
headingLevel: PropTypes.oneOf(['1', '2', '3', '4', '5']),
/**
* Boolean to hide the `Alert` icon
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/components/Dialog/Dialog.example.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Example extends React.PureComponent {
<Dialog
onExit={() => this.hideModal()}
getApplicationNode={() => document.getElementById('App')}
title="Dialog title"
heading="Dialog heading"
actions={[
<button className="ds-c-button ds-c-button--primary" key="primary">
Dialog action
Expand Down
22 changes: 18 additions & 4 deletions packages/core/src/components/Dialog/Dialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@ export const Dialog = function(props) {
closeText,
escapeExitDisabled,
headerClassName,
heading,
onExit,
size,
title,
...modalProps
} = props;

if (process.env.NODE_ENV !== 'production') {
if (props.title) {
console.warn(
`[Deprecated]: Please remove the 'title' prop in <Button>, use 'heading' instead. This prop has been renamed and will be removed in a future release.`
);
}
}

const dialogClassNames = classNames(
'ds-c-dialog',
'ds-base',
Expand All @@ -44,9 +53,10 @@ export const Dialog = function(props) {
>
<div role="document">
<header className={headerClassNames} role="banner">
{title && (
{// TODO: make heading required after removing title
(title || heading) && (
<h1 className="ds-h2" id="dialog-title">
{title}
{heading}
</h1>
)}
<Button
Expand Down Expand Up @@ -144,10 +154,14 @@ Dialog.propTypes = {
*/
getApplicationNode: PropTypes.func,
/**
* Additional classes to be added to the header, which wraps the title and
* Additional classes to be added to the header, which wraps the heading and
* close button.
*/
headerClassName: PropTypes.string,
/**
* The Dialog's heading, to be rendered in the header alongside the close button.
*/
heading: PropTypes.node,
/**
* A method to handle the state change of exiting (or deactivating)
* the modal. It will be invoked when the user presses Escape, or clicks outside
Expand All @@ -156,7 +170,7 @@ Dialog.propTypes = {
onExit: PropTypes.func,
size: PropTypes.oneOf(['narrow', 'wide', 'full']),
/**
* The Dialog's title, to be rendered in the header alongside the close button.
* @hide-prop [Deprecated] This prop has been renamed to `heading`.
*/
title: PropTypes.node,
/**
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/components/Dialog/Dialog.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Dialog', function() {
// https://github.com/reactjs/react-modal/issues/553
expect(
mount(
<Dialog getApplicationNode={jest.fn()} onExit={jest.fn()} title="Foo">
<Dialog getApplicationNode={jest.fn()} onExit={jest.fn()} heading="Foo">
Bar
</Dialog>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Example extends React.PureComponent {
<Dialog
onExit={() => this.hideModal()}
getApplicationNode={() => document.getElementById('App')}
title="You are leaving URL"
heading="You are leaving URL"
actions={[
<Button
className="ds-c-button ds-c-button--primary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ exports[`Dialog renders react-aria-modal 1`] = `
],
}
}
heading="Foo"
onExit={[MockFunction]}
title="Foo"
underlayClickExits={false}
>
<Displaced
Expand Down
20 changes: 10 additions & 10 deletions packages/core/src/components/Dialog/dialog-size.example.html
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
<div data-demo="This div is for demo purposes only" style="min-height: 300px;">
<button
data-type="ds-c-dialog--narrow"
data-title="Narrow dialog"
data-heading="Narrow dialog"
class="dialog-open-btn ds-c-button ds-c-button--success ds-c-button--big ds-u-display--block"
>
Click to show narrow dialog
</button>
<button
data-type="ds-c-dialog--wide"
data-title="Wide dialog"
data-heading="Wide dialog"
class="dialog-open-btn ds-c-button ds-c-button--success ds-c-button--big ds-u-display--block ds-u-margin-top--2"
>
Click to show wide dialog
</button>
<button
data-type="ds-c-dialog--full"
data-title="Full page dialog"
data-heading="Full page dialog"
class="dialog-open-btn ds-c-button ds-c-button--success ds-c-button--big ds-u-display--block ds-u-margin-top--2"
>
Click to show full page dialog
</button>
<div
id="dialog-wrap"
class="ds-c-dialog-wrap ds-u-display--none"
aria-labelledby="dialog-title"
aria-labelledby="dialog-heading"
role="dialog"
>
<div id="dialog" class="ds-c-dialog" role="document">
<header class="ds-c-dialog__header" role="banner">
<h1 class="ds-h2" id="dialog-title">Dialog title</h1>
<h1 class="ds-h2" id="dialog-heading">Dialog heading</h1>
<button
class="dialog-close-btn ds-c-button ds-c-button--transparent ds-c-dialog__close"
aria-label="Close modal dialog"
Expand All @@ -51,18 +51,18 @@ <h1 class="ds-h2" id="dialog-title">Dialog title</h1>
</div>
</div>
<!--
const dialog = document.getElementById('dialog');
const dialogTitle = document.getElementById('dialog-title');
const dialog = document.getElementById('dialog');
const dialogHeading = document.getElementById('dialog-heading');
const dialogWrap = document.getElementById('dialog-wrap');
document.querySelectorAll('.dialog-open-btn').forEach((btn) => {
document.querySelectorAll('.dialog-open-btn').forEach(btn => {
btn.addEventListener('click', () => {
dialog.classList.add(btn.dataset.type);
dialogTitle.textContent = btn.dataset.title;
dialogHeading.textContent = btn.dataset.heading;
dialogWrap.classList.remove('ds-u-display--none');
});
});
document.querySelectorAll('.dialog-close-btn').forEach((btn) => {
document.querySelectorAll('.dialog-close-btn').forEach(btn => {
btn.addEventListener('click', () => {
dialog.className = 'ds-c-dialog';
dialogWrap.classList.add('ds-u-display--none');
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/Dialog/dialog.example.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div data-demo="This div is for demo purposes only" style="min-height: 300px;">
<div class="ds-c-dialog-wrap" aria-labelledby="dialog-title" role="dialog">
<div class="ds-c-dialog-wrap" aria-labelledby="dialog-heading" role="dialog">
<div class="ds-c-dialog {{modifier}}" role="document">
<header class="ds-c-dialog__header" role="banner">
<h1 class="ds-h2" id="dialog-title">Dialog title</h1>
<h1 class="ds-h2" id="dialog-heading">Dialog heading</h1>
<button
class="ds-c-button ds-c-button--transparent ds-c-dialog__close"
aria-label="Close modal dialog"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class HelpDrawerExample extends React.PureComponent {
<HelpDrawer
footerTitle="Footer Title"
footerBody={<p className="ds-text ds-u-margin--0">Footer content</p>}
title="Help Drawer Title"
heading="Help Drawer Heading"
onCloseClick={() => this.handleDrawerClose()}
>
<strong>An Explanation</strong>
Expand Down
50 changes: 40 additions & 10 deletions packages/core/src/components/HelpDrawer/HelpDrawer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,24 @@ import React from 'react';
export class HelpDrawer extends React.PureComponent {
constructor(props) {
super(props);
this.titleRef = null;
this.headingRef = null;

if (process.env.NODE_ENV !== 'production') {
if (props.title) {
console.warn(
`[Deprecated]: Please remove the 'title' prop in <Button>, use 'heading' instead. This prop has been renamed and will be removed in a future release.`
);
}
if (!props.title && !props.heading) {
console.warn(
`The 'heading' prop in <Button>, use 'heading' instead. This prop has been renamed and will be removed in a future release.`
);
}
}
}

componentDidMount() {
if (this.titleRef) this.titleRef.focus();
if (this.headingRef) this.headingRef.focus();
}

render() {
Expand All @@ -19,9 +32,12 @@ export class HelpDrawer extends React.PureComponent {
title,
children,
onCloseClick,
heading,
footerBody,
footerTitle
} = this.props;
const Heading = `h${this.props.headingLevel}` || `h3`;

/* eslint-disable jsx-a11y/no-noninteractive-tabindex, react/no-danger */
return (
<div className="ds-c-help-drawer">
Expand All @@ -31,13 +47,14 @@ export class HelpDrawer extends React.PureComponent {
* so things display as expected when the body content overflows
*/}
<div className="ds-u-fill--gray-lightest ds-u-padding--2 ds-u-display--flex ds-u-align-items--start">
<h3
ref={el => (this.titleRef = el)}
<Heading
ref={el => (this.headingRef = el)}
tabIndex="0"
className="ds-u-text--lead ds-u-margin-y--0 ds-u-margin-right--2"
>
{title}
</h3>
{// TODO: make heading required after removing title
title || heading}
</Heading>
<Button
aria-label={ariaLabel}
className="ds-u-margin-left--auto ds-c-help-drawer__close-button"
Expand All @@ -64,18 +81,31 @@ export class HelpDrawer extends React.PureComponent {

HelpDrawer.defaultProps = {
ariaLabel: 'Close help drawer',
closeButtonText: 'Close'
closeButtonText: 'Close',
headingLevel: '3'
};
HelpDrawer.propTypes = {
/** Helps give more context to screen readers on the button that closes the Help Drawer */
/**
* Helps give more context to screen readers on the button that closes the Help Drawer
*/
ariaLabel: PropTypes.string,
closeButtonText: PropTypes.string,
children: PropTypes.node.isRequired,
footerBody: PropTypes.node,
footerTitle: PropTypes.string,
/**
* Text for the HelpDrawer title. Required because the `heading` will be focused on mount.
*/
heading: PropTypes.string,
/**
* Heading type to override default `<h3>`
*/
headingLevel: PropTypes.oneOf(['1', '2', '3', '4', '5']),
onCloseClick: PropTypes.func.isRequired,
/** Required because the title is what gets focused on mount */
title: PropTypes.string.isRequired
/**
* @hide-prop [Deprecated] This prop has been renamed to `heading`.
*/
title: PropTypes.string
};

export default HelpDrawer;
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
class="ds-u-fill--gray-lightest ds-u-padding--2 ds-u-display--flex ds-u-align-items--start"
>
<h3 tabindex="0" class="ds-u-text--lead ds-u-margin-y--0 ds-u-margin-right--2">
Help Drawer Title
Help Drawer Heading
</h3>
<button
class="ds-c-button ds-c-button--secondary ds-c-button--small ds-u-margin-left--auto"
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/components/Review/Review.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import classNames from 'classnames';

export class Review extends React.PureComponent {
heading() {
const Heading = this.props.headingLevel ? `h${this.props.headingLevel}` : `h3`;
const Heading = `h${this.props.headingLevel}` || `h3`;
if (this.props.heading) {
return (
<Heading className="ds-c-review__heading ds-text ds-u-margin-bottom--0 ds-u-font-weight--bold ds-u-display--inline-block">
Expand Down Expand Up @@ -47,7 +47,8 @@ export class Review extends React.PureComponent {
}

Review.defaultProps = {
editText: 'Edit'
editText: 'Edit',
headingLevel: '3'
};

Review.propTypes = {
Expand All @@ -74,7 +75,7 @@ Review.propTypes = {
/**
* Heading type to override default `<h3>`.
*/
headingLevel: PropTypes.number,
headingLevel: PropTypes.oneOf(['1', '2', '3', '4', '5']),
/**
* An optional function that is executed on edit link click. The event and
* props.editHref value are passed to this function.
Expand Down
Loading

0 comments on commit 084d80f

Please sign in to comment.