Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add modal using react modal #6375

Closed
wants to merge 16 commits into from
Closed
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
1 change: 1 addition & 0 deletions components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export { default as KeyboardShortcuts } from './keyboard-shortcuts';
export { default as MenuGroup } from './menu-group';
export { default as MenuItem } from './menu-item';
export { default as MenuItemsChoice } from './menu-items-choice';
export { default as Modal } from './modal';
export { default as ScrollLock } from './scroll-lock';
export { NavigableMenu, TabbableContainer } from './navigable-container';
export { default as Notice } from './notice';
Expand Down
161 changes: 161 additions & 0 deletions components/modal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
RangeControl
=======

The modal uses `react-modal` to create an accessible modal over an application.

## Usage

Render a screen overlay with a modal on top.
```js
// When the app element is set it puts an aria-hidden="true" to the provided node.
Modal.setAppElement( document.getElementById( 'wpwrap' ).parentNode )
```
```jsx
import { Modal } from '@wordpress/components';
import { Component } from '@wordpress/element';

class ModalWrapper extends Component {
constructor( props ) {
super( props );

this.state = {
isOpen: true,
};

this.onClose = this.onClose.bind( this );
}
onClose() {
this.setState( {
isOpen: false,
} );
}
render() {
const { children } = this.props;
return <Modal { ...this.props } isOpen={ this.state.isOpen } onRequestClose={ this.onClose } >
{ children }
</Modal>;
}
}

export default ModalWrapper;

```

Responsibility for properly opening and closing the modal is placed in the implementor.

## Props

The set of props accepted by the component will be specified below.
Props not included in this set will be applied to the input elements.

Many props supported by react-modal have been included here.

### isOpen

Determines whether the modal should be open when started.

- Type: `bool`
- Required: No
- Default: false

### render

Determines whether the modal should be rendered or not.

- Type: `bool`
- Required: No
- Default: true

### style.content

If this property is added, it will add inline styles to the modal content `div`.

- Type: `Object`
- Required: No

### className

If this property is added, it will an additional class name to the modal content `div`.

- Type: `String`
- Required: No

### overlayClassName

Sets the class of the overlay around the modal.

- Type: `String`
- Required: No
- Default: 'components-modal__frame'

### ContentClassName

Sets the class of the content block in the modal.

- Type: `String`
- Required: No
- Default: 'components-modal__content'

### aria.labelledby

If this property is added, it will be added to the modal content `div` as `aria-labelledby`.
You are encouraged to use this when the modal is visually labelled.

- Type: `String`
- Required: No
- Default: 'modalID'

### icon

This property sets the icon in the header of the modal

- Type: `Element`
- Required: No
- Default: null

### title

This property sets the title in the header of the modal.

- Type: `String`
- Required: No
- Default: 'Plugin screen'

### bodyOpenClassName

Sets the classname of the open body

- Type: `String`
- Required: No
- Default: 'modal-body--open'

### portalClassName

Sets the classname of the open body

- Type: `String`
- Required: No
- Default: 'WordPress-modal'

### shouldCloseOnEsc

If this property is added, it will determine whether the modal requests to close when the escape key is pressed.

- Type: `bool`
- Required: No
- Default: true

### shouldCloseOnOverlayClick

If this property is added, it will determine whether the modal requests to close when a mouse click occurs outside of the modal content.

- Type: `bool`
- Required: No
- Default: true

### onRequestClose

This function is called to indicate that the modal should be closed.

- Type: `function`
- Required: Yes
99 changes: 99 additions & 0 deletions components/modal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* WordPress dependencies
*/
import { Component } from '@wordpress/element';

/**
* Internal dependencies
*/
import './style.scss';

/**
* External dependencies
*/
import ReactModal from 'react-modal';
import ModalHeader from './modal-header';

class Modal extends Component {
constructor( props ) {
super( props );

this.state = {
height: window.innerHeight - 32,
};

this.updateWindowHeight = this.updateWindowHeight.bind( this );
}

componentDidMount() {
window.addEventListener( 'resize', this.updateWindowHeight );
}

componentWillUnmount() {
window.removeEventListener( 'resize', this.updateWindowHeight );
}

updateWindowHeight() {
this.setState( {
height: window.innerHeight - 32,
} );
}

render() {
ReactModal.setAppElement( document.getElementById( 'wpwrap' ) );

const {
isOpen,
render,
style,
className,
overlayClassName,
contentClassName,
ariaLabelledBy,
icon,
title,
bodyOpenClassName,
portalClassName,
shouldCloseOnEsc,
shouldCloseOnOverlayClick,
onRequestClose,
children } = this.props;

return <ReactModal
style={ style }
isOpen={ isOpen }
render={ render }
className={ className }
overlayClassName={ overlayClassName }
bodyOpenClassName={ bodyOpenClassName }
portalClassName={ portalClassName }
aria-labelledby={ ariaLabelledBy }
shouldCloseOnEsc={ shouldCloseOnEsc }
shouldCloseOnOverlayClick={ shouldCloseOnOverlayClick }
onRequestClose={ onRequestClose }>
<ModalHeader icon={ icon } title={ title } onClose={ onRequestClose } />
<div className={ contentClassName } aria-labelledby="modalID">
{ children }
</div>
</ReactModal>;
}
}

Modal.defaultProps = {
isOpen: false,
render: true,
style: {},
className: 'components-modal__frame',
overlayClassName: 'components-modal__screen-overlay',
contentClassName: 'components-modal__content',
ariaLabelledBy: 'modalID',
icon: null,
title: 'Plugin screen',
onRequestClose: null,
bodyOpenClassName: 'modal-body--open',
portalClassName: 'WordPress-modal',
shouldCloseOnEsc: true,
shouldCloseOnOverlayClick: true,
};

export default Modal;
29 changes: 29 additions & 0 deletions components/modal/modal-header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import IconButton from '../icon-button';
import './style.scss';
import { __ } from '@wordpress/i18n';

const ModalHeader = ( { icon, title, onClose, closeLabel } ) => {
const label = closeLabel ? closeLabel : __( 'Close window' );

return (
<div
className={ 'components-modal__header' }
>
<div>
<span aria-hidden="true">
{ icon }
</span>
<h1 id="modalID" >
{ title }
</h1>
</div>
<IconButton
onClick={ onClose }
icon="no-alt"
label={ label }
/>
</div>
);
};

export default ModalHeader;
Loading