UNPKG

ember-promise-modals

Version:

The better way to handle modals in your Ember.js apps.

140 lines (130 loc) 4.28 kB
import Component, { setComponentTemplate } from '@ember/component'; import { set } from '@ember/object'; import { readOnly } from '@ember/object/computed'; import { guidFor } from '@ember/object/internals'; import { inject } from '@ember/service'; import { createFocusTrap } from 'focus-trap'; import { precompileTemplate } from '@ember/template-compilation'; var TEMPLATE = precompileTemplate("{{!-- template-lint-disable no-action --}}\n<div id={{this.modalElementId}} class=\"epm-modal {{this.optionsClassName}} {{this.animatingClass}}\">\n {{#let (component (ensure-safe-component @modal._componentClass) data=@modal._data close=(action \"close\")) as |ModalComponent|}}\n <ModalComponent />\n {{/let}}\n</div>"); var epmModal = setComponentTemplate(TEMPLATE, Component.extend({ tagName: '', outAnimationClass: 'epm-out', animatingClass: '', modals: inject(), optionsClassName: readOnly('modal._options.className'), modalElementId: null, focusTrapOptions: null, _animationEnd: null, init() { this._super(...arguments); set(this, 'modalElementId', guidFor(this)); this.modal._componentInstance = this; let { focusTrapOptions: globalFocusTrapOptions } = this.modals; let { focusTrapOptions: localFocusTrapOptions } = this.modal._options; if (localFocusTrapOptions !== null) { this.focusTrapOptions = localFocusTrapOptions || globalFocusTrapOptions; } }, didInsertElement() { this._super(...arguments); this._addFocusTrap(); this._addAnimationListeners(); // animating in starts when the element is added to the DOM. Inform the service about it. this.modals._onModalAnimationStart(); }, willDestroyElement() { this.destroyModal(); this._super(...arguments); }, _getElement() { return document.getElementById(this.modalElementId); }, _addFocusTrap() { let element = this._getElement(); if (!this.focusTrapOptions) { return; } let options = { ...this.focusTrapOptions, fallbackFocus: element, onDeactivate: (...args) => { this.focusTrapOptions.onDeactivate?.(...args); if (this.isDestroyed || this.isDestroying) { return; } this.closeModal(); } }; this.focusTrap = createFocusTrap(element, options); this.focusTrap.activate(); }, _removeFocusTrap(onDeactivate = this.focusTrapOptions?.onDeactivate) { if (!this.focusTrap) { return; } this.focusTrap.deactivate({ onDeactivate }); }, _addAnimationListeners() { this._animationEnd = ({ target, animationName }) => { // ignore animations bubbling up if (target !== this._getElement()) { return; } // An animation has ended, inform the modals service this.modals._onModalAnimationEnd(); let isOutAnimation = animationName.substring(animationName.length - 4) === '-out'; if (isOutAnimation) { this.modal._remove(); } }; let element = this._getElement(); if (element) { element.addEventListener('animationend', this._animationEnd); } }, _removeAnimationListeners() { if (!this._animationEnd) { return; } let element = this._getElement(); if (element) { element.removeEventListener('animationend', this._animationEnd); } this._animationEnd = null; }, destroyModal() { // Remove the focus trap without triggering the optional onDeactivate() hook this._removeFocusTrap(null); // Remove the animation listeners this._removeAnimationListeners(); // make sure that we remove the modal, also resolving the test waiter this.modal._remove(); }, closeModal(result) { if (this.animatingClass !== '') { return; } this.modals._onModalAnimationStart(); // This triggers the out animation, which in turn will remove the modal after it completes set(this, 'animatingClass', this.outAnimationClass); this.modal._resolve(result); }, actions: { close(result) { this.closeModal(result); // Remove the focus trap, triggering the onDeactivate() hook this._removeFocusTrap(); } } })); export { epmModal as default }; //# sourceMappingURL=epm-modal.js.map