Skip to content
This repository was archived by the owner on Dec 28, 2019. It is now read-only.
Open
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
87 changes: 64 additions & 23 deletions elements/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Card } from '../card/Card';

interface ModalProps {
isOpen?: boolean,
closeTitle: string,
onModalClose?: Function,
}
export class Modal extends Component {
Expand All @@ -14,62 +15,102 @@ export class Modal extends Component {
return {
isOpen: prop.boolean({
attribute: true
})
}),
closeTitle: prop.string()
}
}

isOpen = false;
private closeTitle = "close";
private modalElement: HTMLDivElement;
private lastActiveElement: HTMLElement;

private handleEsc(evt:KeyboardEvent){
if ( evt.which === 27 ) {
this.handleModalClose()
}
}
private handleModalClose(){
this.isOpen = !this.isOpen;
this.isOpen = false;
emit(this,'modalClose')
}
private focusModal() {
this.modalElement.focus();
}

private handleDocumentFocus(event: FocusEvent) {
if (this.modalElement && !this.modalElement.contains(event.target as Node)) {
event.stopImmediatePropagation();
this.focusModal();
}
}

private preventModalBlur() {
document.addEventListener("focus", this.handleDocumentFocus.bind(this), true);
}
private allowModalBlur() {
document.removeEventListener("focus", this.handleDocumentFocus.bind(this), true);
}

connectedCallback(){
super.connectedCallback();
this.handleEsc = this.handleEsc.bind(this);
this.handleModalClose = this.handleModalClose.bind(this);
this.focusModal = this.focusModal.bind(this);
}
renderCallback() {
const {isOpen} = this;
const {isOpen, closeTitle} = this;
return [
<style>{styles}</style>,
isOpen && <div class="c-overlay c-overlay--fullpage"/>,
isOpen &&
<div class="c-overlay c-overlay--fullpage"
tabIndex={-1}
onFocus={this.focusModal} />,
isOpen &&
<div ref={(_ref: HTMLDivElement)=>this.modalElement=_ref}
tabIndex={0}
tabIndex={-1}
class="o-modal"
role="dialog"
aria-labelledby="modal-heading"
aria-describedby="modal-body"
onKeydown={this.handleEsc}
>
<Card>
<Button
slot="dismiss"
onClick={this.handleModalClose}>
x
</Button>
<div slot="title">
<slot name="title"></slot>
</div>
<div slot="body">
<slot></slot>
</div>
<div slot="footer">
<slot name="footer"></slot>
</div>
</Card>
<Card>
<Button
slot="dismiss"
aria-label={closeTitle}
onClick={this.handleModalClose}>
x
</Button>
<div slot="heading" id="modal-heading">
<slot name="title"></slot>
</div>
<div slot="body" id="modal-body">
<slot></slot>
</div>
<div slot="footer">
<slot name="footer"></slot>
</div>
</Card>
</div>
]
}

renderedCallback() {
if ( this.isOpen ) {
this.modalElement.focus();
this.lastActiveElement = document.activeElement as HTMLElement;

this.focusModal();

this.preventModalBlur();
} else {
this.allowModalBlur();

if (this.lastActiveElement) {
this.lastActiveElement.focus();
}
}
}
}

customElements.define( Modal.is, Modal )
customElements.define( Modal.is, Modal )
4 changes: 2 additions & 2 deletions elements/modal/demo/Demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ export class Demo extends Component {
return [
<style>{styles}</style>,
<Button type="info" onClick={this.toggleModal}>Open Modal</Button>,
<Modal isOpen={isModalOpen} onModalClose={this.toggleModal}>
<span slot="title">Modal heading</span>
<Modal isOpen={isModalOpen} onModalClose={this.toggleModal} closeTitle="Close NOW">
<span slot="title">Modal <em>heading</em></span>
<span>
This is the modal body
<input type="text"/>
Expand Down