Skip to content

Commit

Permalink
feat(Modal): Convert Modal component to typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-phillips-18 committed May 13, 2019
1 parent c92e603 commit 2fce11a
Show file tree
Hide file tree
Showing 43 changed files with 899 additions and 818 deletions.
18 changes: 0 additions & 18 deletions packages/patternfly-4/react-core/src/components/Modal/Modal.d.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Modal from './Modal';
import React from 'react';
import * as React from 'react';
import { shallow } from 'enzyme';
import { KEY_CODES } from '../../helpers/constants';
import { css } from '../../../../react-styles/dist/js';
Expand All @@ -24,15 +24,17 @@ test('Modal creates a container element once for div', () => {

test('modal closes with escape', () => {
shallow(<Modal {...props} isOpen />);
const [event, handler] = document.addEventListener.mock.calls[0];
const mock: any = (document.addEventListener as any).mock;
const [event, handler] = mock.calls[0];
expect(event).toBe('keydown');
handler({ keyCode: KEY_CODES.ESCAPE_KEY });
expect(props.onClose).toBeCalled();
});

test('modal does not call onClose for esc key if it is not open', () => {
shallow(<Modal {...props} />);
const [event, handler] = document.addEventListener.mock.calls[0];
const mock: any = (document.addEventListener as any).mock;
const [event, handler] = mock.calls[0];
expect(event).toBe('keydown');
handler({ keyCode: KEY_CODES.ESCAPE_KEY });
expect(props.onClose).not.toBeCalled();
Expand All @@ -41,7 +43,7 @@ test('modal does not call onClose for esc key if it is not open', () => {
test('Each modal is given a new id', () => {
const first = shallow(<Modal {...props} />);
const second = shallow(<Modal {...props} />);
expect(first.instance().id).not.toBe(second.instance().id);
expect((first.instance() as any).id).not.toBe((second.instance() as any).id);
});

test('modal removes body backdropOpen class when removed', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,76 +1,80 @@
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import ModalContent from './ModalContent';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { canUseDOM } from 'exenv';
import { KEY_CODES } from '../../helpers/constants';

import { css } from '@patternfly/react-styles';
import styles from '@patternfly/patternfly/components/Backdrop/backdrop.css';

const propTypes = {
import { KEY_CODES } from '../../helpers/constants';
import ModalContent from './ModalContent';

export interface ModalProps extends React.HTMLProps<HTMLDivElement> {
/** content rendered inside the Modal. */
children: PropTypes.node.isRequired,
children: React.ReactNode;
/** additional classes added to the Modal */
className: PropTypes.string,
className?: string;
/** Flag to show the modal */
isOpen: PropTypes.bool,
isOpen?: boolean;
/** Content of the Modal Header */
title: PropTypes.string.isRequired,
/** Flag to show the title */
hideTitle: PropTypes.bool,
title: string;
/** Flag to hide the title */
hideTitle?: boolean;
/** id to use for Modal Box description */
ariaDescribedById: PropTypes.string,
ariaDescribedById?: string;
/** Action buttons to put in the Modal Footer */
actions: PropTypes.any,
actions?: any,
/** A callback for when the close button is clicked */
onClose: PropTypes.func,
onClose?(): void;
/** Default width of the Modal. */
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
width?: number | string;
/** Creates a large version of the Modal */
isLarge: PropTypes.bool,
isLarge?: boolean;
/** Creates a small version of the Modal */
isSmall: PropTypes.bool,
/** Additional props are passed and spread in the Modal body container <div> */
'': PropTypes.any
};

const defaultProps = {
width: null,
className: '',
isOpen: false,
hideTitle: false,
ariaDescribedById: '',
actions: [],
onClose: () => undefined,
isLarge: false,
isSmall: false
};

let currentId = 0;

class Modal extends React.Component {
static propTypes = propTypes;
static defaultProps = defaultProps;

id = `pf-modal-${currentId++}`;

handleEscKeyClick = event => {
isSmall?: boolean;
}

export class Modal extends React.Component<ModalProps> {
static currentId = 0;
id = '';
container?: HTMLDivElement = undefined;

static defaultProps = {
width: undefined as any,
className: '',
isOpen: false,
hideTitle: false,
ariaDescribedById: '',
actions: [] as any[],
isLarge: false,
isSmall: false
};

constructor(props: ModalProps) {
super(props);
const newId = Modal.currentId++;
this.id = `pf-modal-${newId}`;
}


handleEscKeyClick = (event: KeyboardEvent): void => {
if (event.keyCode === KEY_CODES.ESCAPE_KEY && this.props.isOpen) {
this.props.onClose();
this.props.onClose!();
}
};

toggleSiblingsFromScreenReaders = hide => {
toggleSiblingsFromScreenReaders = (hide: boolean) => {
const bodyChildren = document.body.children;
for (const child of bodyChildren) {
for (const child of Array.from(bodyChildren)) {
if (child !== this.container) {
hide ? child.setAttribute('aria-hidden', hide) : child.removeAttribute('aria-hidden');
hide ? child.setAttribute('aria-hidden', '' + hide) : child.removeAttribute('aria-hidden');
}
}
};

componentDidMount() {
document.body.appendChild(this.container);
if (this.container) {
document.body.appendChild(this.container);
}
document.addEventListener('keydown', this.handleEscKeyClick, false);
if (this.props.isOpen) {
document.body.classList.add(css(styles.backdropOpen));
Expand All @@ -90,7 +94,9 @@ class Modal extends React.Component {
}

componentWillUnmount() {
document.body.removeChild(this.container);
if (this.container) {
document.body.removeChild(this.container);
}
document.removeEventListener('keydown', this.handleEscKeyClick, false);
document.body.classList.remove(css(styles.backdropOpen));
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import ModalBox from './ModalBox';
import React from 'react';
import * as React from 'react';
import { shallow } from 'enzyme';

test('ModalBox Test', () => {
const view = shallow(
<ModalBox titleId="titleId" ariaDescribedById="bodyId">
<ModalBox title="Test Modal Box" id="boxId">
This is a ModalBox
</ModalBox>
);
Expand All @@ -13,16 +13,16 @@ test('ModalBox Test', () => {

test('ModalBox Test isLarge', () => {
const view = shallow(
<ModalBox titleId="titleId" ariaDescribedById="bodyId" isLarge>
<ModalBox title="Test Modal Box" id="boxId" isLarge>
This is a ModalBox
</ModalBox>
);
expect(view).toMatchSnapshot();
});

test('ModalBox Test isOpen', () => {
test('ModalBox Test isSmall', () => {
const view = shallow(
<ModalBox titleId="titleId" ariaDescribedById="bodyId" isLarge isOpen>
<ModalBox title="Test Modal Box" id="boxId" isSmall>
This is a ModalBox
</ModalBox>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import React from 'react';
import * as React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly/components/ModalBox/modal-box.css';

const propTypes = {
export interface ModalBoxProps extends React.HTMLProps<HTMLDivElement> {
/** content rendered inside the ModalBox. */
children: PropTypes.node.isRequired,
children: React.ReactNode;
/** additional classes added to the ModalBox */
className: PropTypes.string,
className?: string;
/** Creates a large version of the ModalBox */
isLarge: PropTypes.bool,
isLarge?: boolean;
/** Creates a small version of the ModalBox. */
isSmall: PropTypes.bool,
/** string to use for Modal Box label */
title: PropTypes.string.isRequired,
isSmall?: boolean;
/** string to use for Modal Box aria-label */
title: string;
/** id to use for Modal Box description */
id: PropTypes.string.isRequired,
/** Additional props are spread to the container <div> */
'': PropTypes.any
};
id: string;
}

const defaultProps = {
className: '',
isLarge: false,
isSmall: false
};

const ModalBox = ({ children, className, isLarge, isSmall, title, id, ...props }) => (
export const ModalBox: React.FunctionComponent<ModalBoxProps> = ({
children,
className = '',
isLarge = false,
isSmall = false,
title,
id,
...props
}) => (
<div
{...props}
role="dialog"
Expand All @@ -38,7 +37,5 @@ const ModalBox = ({ children, className, isLarge, isSmall, title, id, ...props }
{children}
</div>
);
ModalBox.propTypes = propTypes;
ModalBox.defaultProps = defaultProps;

export default ModalBox;

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import ModalBoxBody from './ModalBoxBody';
import React from 'react';
import * as React from 'react';
import { shallow } from 'enzyme';

test('ModalBoxBody Test', () => {
const view = shallow(<ModalBoxBody id="id">This is a ModalBox header</ModalBoxBody>);
const view = shallow(<ModalBoxBody id="id" className="test-box-class">This is a ModalBox header</ModalBoxBody>);
expect(view).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as React from 'react';
import { css } from '@patternfly/react-styles';
import styles from '@patternfly/patternfly/components/ModalBox/modal-box.css';

export interface ModalBoxBodyProps extends React.HTMLProps<HTMLDivElement> {
/** content rendered inside the ModalBoxBody */
children?: React.ReactNode;
/** additional classes added to the ModalBoxBody */
className?: string;
}

export const ModalBoxBody: React.FunctionComponent<ModalBoxBodyProps> = ({
children = null,
className = '',
...props
}) => (
<div {...props} className={css(styles.modalBoxBody, className)}>
{children}
</div>
);

export default ModalBoxBody;

This file was deleted.

Loading

0 comments on commit 2fce11a

Please sign in to comment.