diff --git a/sass/components/_modal.scss b/sass/components/_modal.scss
index c16e7fc2ef..5d3b5bedb2 100644
--- a/sass/components/_modal.scss
+++ b/sass/components/_modal.scss
@@ -60,11 +60,9 @@ dialog::backdrop {
// Modal Bottom Sheet Style
.modal.bottom-sheet {
- top: auto;
- bottom: -100%;
- margin: 0;
- width: 100%;
+ margin-bottom: 0;
max-height: 45%;
- border-radius: 0;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
will-change: bottom, opacity;
}
diff --git a/spec/tests/modal/modalSpec.js b/spec/tests/modal/modalSpec.js
index c374e0a172..10ac243a6d 100644
--- a/spec/tests/modal/modalSpec.js
+++ b/spec/tests/modal/modalSpec.js
@@ -1,113 +1,59 @@
/* eslint-disable no-undef */
describe('Modal:', () => {
- let trigger1, modal1;
+ const fixture = `Modal
+
- const fixture = `
-Modal
-
-
-
-
-
+
-
-
-
-
Modal
-
-
-
-
-
-
Modal
-
-
-
-
-
Modal Header
-
A bunch of text
-
-
-
+
`;
+
beforeEach(() => {
XloadHtml(fixture);
- trigger1 = document.querySelector('.btn[href="#modal1"]');
- triggerIcon1 = document.querySelector('.btn[data-target="modal1"] i');
- trigger2 = document.querySelector('.btn[href="#modal2"]');
- trigger3 = document.querySelector('.btn[href="#modal3"]');
- modal1 = document.querySelector('#modal1');
- modal2 = document.querySelector('#modal2');
- modal3 = document.querySelector('#modal3');
});
afterEach(() => XunloadFixtures());
describe('Modals', () => {
it('Should open and close correctly', (done) => {
- M.Modal.init(modal1, { inDuration: 0, outDuration: 0 });
+ const modal1 = document.querySelector('.modal');
+ const trigger = document.querySelector('.trigger');
expect(modal1).toBeHidden('Modal should be hidden');
- click(trigger1);
+ click(trigger);
setTimeout(() => {
expect(modal1).toBeVisible('Modal should be shown');
- expect(modal1).toHaveClass('open', 'Modal should have class open');
- // Check overlay is attached
- let overlay = M.Modal.getInstance(modal1)._overlay;
- let overlayInDOM = document.contains(overlay);
- expect(overlayInDOM).toEqual(true, 'Overlay should be attached on open');
- click(overlay);
- setTimeout(() => {
- expect(modal1).toNotHaveClass('open', 'Modal should have class open removed');
- let overlayInDOM = document.contains(overlay);
- expect(overlayInDOM).toEqual(false, 'Overlay should be removed on close');
- done();
- }, 10);
+ done();
}, 10);
});
it('Should open and close correctly with children elements in trigger', (done) => {
- M.Modal.init(modal1, { inDuration: 0, outDuration: 0 });
+ const modal1 = document.querySelector('.modal');
+ const triggerIcon1 = document.querySelector('button i');
expect(modal1).toBeHidden('Modal should be hidden');
click(triggerIcon1);
setTimeout(() => {
expect(modal1).toBeVisible('Modal should be shown');
- expect(modal1).toHaveClass('open', 'Modal should have class open');
- // Check overlay is attached
- let overlay = M.Modal.getInstance(modal1)._overlay;
- let overlayInDOM = document.contains(overlay);
- expect(overlayInDOM).toEqual(true, 'Overlay should be attached on open');
- click(overlay);
- setTimeout(() => {
- expect(modal1).toNotHaveClass('open', 'Modal should have class open removed');
- let overlayInDOM = document.contains(overlay);
- expect(overlayInDOM).toEqual(false, 'Overlay should be removed on close');
- done();
- }, 10);
+ done();
}, 10);
});
+ // Modals should not be dismissible, use a Popover then
+
+ /*
it('Should have a dismissible option', (done) => {
- M.Modal.init(modal1, {
- dismissible: false,
- inDuration: 0,
- outDuration: 0
- });
+ // M.Modal.init(modal1, {
+ // dismissible: false,
+ // inDuration: 0,
+ // outDuration: 0
+ // });
click(trigger1);
setTimeout(() => {
expect(modal1).toBeVisible('Modal should be shown');
@@ -123,33 +69,20 @@ describe('Modal:', () => {
}, 10);
}, 10);
});
+ */
it('Should have callbacks', (done) => {
- let readyTest = false;
- let completeTest = false;
- M.Modal.init(modal1, {
- inDuration: 0,
- outDuration: 0,
- onOpenStart: () => {
- readyTest = true;
- },
- onCloseStart: () => {
- completeTest = true;
- }
+ let hasBeenClosed = false;
+ document.querySelector('.modal').addEventListener('close', () => {
+ hasBeenClosed = true;
});
- expect(readyTest).toEqual(false, 'callback not yet fired');
- expect(completeTest).toEqual(false, 'callback not yet fired');
+ const trigger1 = document.querySelector('.trigger');
click(trigger1);
+ expect(hasBeenClosed).toEqual(false, 'callback not yet fired');
+ click(document.querySelector('.modal-footer a'));
setTimeout(() => {
- expect(readyTest).toEqual(true, 'callback fired');
- expect(completeTest).toEqual(false, 'callback not yet fired');
- let overlay = M.Modal.getInstance(modal1)._overlay;
- click(overlay);
- setTimeout(() => {
- expect(readyTest).toEqual(true, 'callback fired');
- expect(completeTest).toEqual(true, 'callback fired');
- done();
- }, 10);
+ expect(hasBeenClosed).toEqual(true, 'callback fired');
+ done();
}, 10);
});
});
diff --git a/src/modal.ts b/src/modal.ts
index 3d4b6dda67..1793846085 100644
--- a/src/modal.ts
+++ b/src/modal.ts
@@ -1,4 +1,3 @@
-import { Utils } from './utils';
import { Component, BaseOptions, InitElements, MElement } from './component';
export interface ModalOptions extends BaseOptions {
@@ -74,9 +73,8 @@ const _defaults = {
};
export class Modal extends Component
{
- static _modalsOpen: number;
- static _count: number;
-
+ //static _modalsOpen: number;
+ //static _count: number;
/**
* ID of the modal element.
*/
@@ -86,9 +84,9 @@ export class Modal extends Component {
*/
isOpen: boolean;
- private _openingTrigger: any;
- private _overlay: HTMLDivElement;
- private _nthModalOpened: number;
+ //private _openingTrigger: any;
+ //private _overlay: HTMLDivElement;
+ //private _nthModalOpened: number;
constructor(el: HTMLElement, options: Partial) {
super(el, options, Modal);
@@ -100,13 +98,13 @@ export class Modal extends Component {
};
this.isOpen = false;
- this.id = this.el.id;
- this._openingTrigger = undefined;
- this._overlay = document.createElement('div');
- this._overlay.classList.add('modal-overlay');
+ //this.id = this.el.id;
+ //this._openingTrigger = undefined;
+ //this._overlay = document.createElement('div');
+ //this._overlay.classList.add('modal-overlay');
this.el.tabIndex = 0;
- this._nthModalOpened = 0;
- Modal._count++;
+ //this._nthModalOpened = 0;
+ //Modal._count++;
this._setupEventHandlers();
}
@@ -146,173 +144,95 @@ export class Modal extends Component {
}
destroy() {
- Modal._count--;
+ //Modal._count--;
this._removeEventHandlers();
- this.el.removeAttribute('style');
- this._overlay.remove();
+ //this.el.removeAttribute('style');
+ //this._overlay.remove();
(this.el as any).M_Modal = undefined;
}
_setupEventHandlers() {
- if (Modal._count === 1) {
- document.body.addEventListener('click', this._handleTriggerClick);
- }
- this._overlay.addEventListener('click', this._handleOverlayClick);
- this.el.addEventListener('click', this._handleModalCloseClick);
+ // if (Modal._count === 1) {
+ // document.body.addEventListener('click', this._handleTriggerClick);
+ // }
+ //this._overlay.addEventListener('click', this._handleOverlayClick);
+ //this.el.addEventListener('click', this._handleModalCloseClick);
}
_removeEventHandlers() {
- if (Modal._count === 0) {
- document.body.removeEventListener('click', this._handleTriggerClick);
- }
- this._overlay.removeEventListener('click', this._handleOverlayClick);
- this.el.removeEventListener('click', this._handleModalCloseClick);
+ //if (Modal._count === 0) {
+ // document.body.removeEventListener('click', this._handleTriggerClick);
+ //}
+ //this._overlay.removeEventListener('click', this._handleOverlayClick);
+ //this.el.removeEventListener('click', this._handleModalCloseClick);
}
// todo: modal-trigger has no function anymore, remove and use native html5 dialog
_handleTriggerClick = (e: MouseEvent) => {
- const trigger = (e.target as HTMLElement).closest('.modal-trigger');
- if (!trigger) return;
- const modalId = Utils.getIdFromTrigger(trigger as HTMLElement);
- const modalInstance = (document.getElementById(modalId) as any).M_Modal;
- if (modalInstance) modalInstance.open(trigger);
- e.preventDefault();
+ // const trigger = (e.target as HTMLElement).closest('.modal-trigger');
+ // if (!trigger) return;
+ // const modalId = Utils.getIdFromTrigger(trigger as HTMLElement);
+ // const modalInstance = (document.getElementById(modalId) as any).M_Modal;
+ // if (modalInstance) modalInstance.open(trigger);
+ // e.preventDefault();
};
_handleOverlayClick = () => {
- if (this.options.dismissible) this.close();
+ //if (this.options.dismissible) this.close();
};
// todo: modal-close is also obsolete
_handleModalCloseClick = (e: MouseEvent) => {
- const closeTrigger = (e.target as HTMLElement).closest('.modal-close');
- if (closeTrigger) this.close();
+ // const closeTrigger = (e.target as HTMLElement).closest('.modal-close');
+ // if (closeTrigger) this.close();
};
_handleKeydown = (e: KeyboardEvent) => {
- if (Utils.keys.ESC.includes(e.key) && this.options.dismissible) this.close();
+ //if (Utils.keys.ESC.includes(e.key) && this.options.dismissible) this.close();
};
_handleFocus = (e: FocusEvent) => {
// Only trap focus if this modal is the last model opened (prevents loops in nested modals).
- if (!this.el.contains(e.target as HTMLElement) && this._nthModalOpened === Modal._modalsOpen) {
- this.el.focus();
- }
+ // if (!this.el.contains(e.target as HTMLElement) && this._nthModalOpened === Modal._modalsOpen) {
+ // this.el.focus();
+ // }
};
- _animateIn() {
- // Set initial styles
- this._overlay.style.display = 'block';
- this._overlay.style.opacity = '0';
- this.el.style.display = 'block';
- this.el.style.opacity = '0';
-
- const duration = this.options.inDuration;
- const isBottomSheet = this.el.classList.contains('bottom-sheet');
-
- if (!isBottomSheet) {
- this.el.style.top = this.options.startingTop;
- this.el.style.transform = 'scaleX(0.9) scaleY(0.9)';
- }
- // Overlay
- this._overlay.style.transition = `opacity ${duration}ms ease-out`; // v1: easeOutQuad
- // Modal
- this.el.style.transition = `
- top ${duration}ms ease-out,
- bottom ${duration}ms ease-out,
- opacity ${duration}ms ease-out,
- transform ${duration}ms ease-out
- `;
-
- setTimeout(() => {
- this._overlay.style.opacity = this.options.opacity.toString();
- this.el.style.opacity = '1';
- if (isBottomSheet) {
- this.el.style.bottom = '0';
- } else {
- this.el.style.top = this.options.endingTop;
- this.el.style.transform = 'scaleX(1) scaleY(1)';
- }
- setTimeout(() => {
- if (typeof this.options.onOpenEnd === 'function') {
- this.options.onOpenEnd.call(this, this.el, this._openingTrigger);
- }
- }, duration);
- }, 1);
- }
-
- _animateOut() {
- const duration = this.options.outDuration;
- const isBottomSheet = this.el.classList.contains('bottom-sheet');
- if (!isBottomSheet) {
- this.el.style.top = this.options.endingTop;
- }
-
- // Overlay
- this._overlay.style.transition = `opacity ${duration}ms ease-out`; // v1: easeOutQuart
-
- // Modal // easeOutCubic
- this.el.style.transition = `
- top ${duration}ms ease-out,
- bottom ${duration}ms ease-out,
- opacity ${duration}ms ease-out,
- transform ${duration}ms ease-out
- `;
-
- setTimeout(() => {
- this._overlay.style.opacity = '0';
- this.el.style.opacity = '0';
- if (isBottomSheet) {
- this.el.style.bottom = '-100%';
- } else {
- this.el.style.top = this.options.startingTop;
- this.el.style.transform = 'scaleX(0.9) scaleY(0.9)';
- }
- setTimeout(() => {
- this.el.style.display = 'none';
- this._overlay.remove();
- if (typeof this.options.onCloseEnd === 'function') {
- this.options.onCloseEnd.call(this, this.el);
- }
- }, duration);
- }, 1);
- }
-
/**
* Open modal.
*/
open = (trigger?: HTMLElement): Modal => {
if (this.isOpen) return;
- this.isOpen = true;
- Modal._modalsOpen++;
- this._nthModalOpened = Modal._modalsOpen;
- // Set Z-Index based on number of currently open modals
- this._overlay.style.zIndex = (1000 + Modal._modalsOpen * 2).toString();
- this.el.style.zIndex = (1000 + Modal._modalsOpen * 2 + 1).toString();
- // Set opening trigger, undefined indicates modal was opened by javascript
- this._openingTrigger = !!trigger ? trigger : undefined;
- // onOpenStart callback
- if (typeof this.options.onOpenStart === 'function') {
- this.options.onOpenStart.call(this, this.el, this._openingTrigger);
- }
- if (this.options.preventScrolling) {
- const hasVerticalScrollBar =
- document.documentElement.scrollHeight > document.documentElement.clientHeight;
- if (hasVerticalScrollBar) {
- const scrollTop = document.documentElement.scrollTop;
- document.documentElement.style.top = '-' + scrollTop + 'px';
- document.documentElement.classList.add('noscroll');
- }
- }
- this.el.classList.add('open');
- this.el.insertAdjacentElement('afterend', this._overlay);
- if (this.options.dismissible) {
- document.addEventListener('keydown', this._handleKeydown);
- document.addEventListener('focus', this._handleFocus, true);
- }
- this._animateIn();
- // Focus modal
- this.el.focus();
+ // this.isOpen = true;
+ // Modal._modalsOpen++;
+ // this._nthModalOpened = Modal._modalsOpen;
+ // // Set Z-Index based on number of currently open modals
+ // this._overlay.style.zIndex = (1000 + Modal._modalsOpen * 2).toString();
+ // this.el.style.zIndex = (1000 + Modal._modalsOpen * 2 + 1).toString();
+ // // Set opening trigger, undefined indicates modal was opened by javascript
+ // this._openingTrigger = !!trigger ? trigger : undefined;
+ // // onOpenStart callback
+ // if (typeof this.options.onOpenStart === 'function') {
+ // this.options.onOpenStart.call(this, this.el, this._openingTrigger);
+ // }
+ // if (this.options.preventScrolling) {
+ // const hasVerticalScrollBar =
+ // document.documentElement.scrollHeight > document.documentElement.clientHeight;
+ // if (hasVerticalScrollBar) {
+ // const scrollTop = document.documentElement.scrollTop;
+ // document.documentElement.style.top = '-' + scrollTop + 'px';
+ // document.documentElement.classList.add('noscroll');
+ // }
+ // }
+ // this.el.classList.add('open');
+ // this.el.insertAdjacentElement('afterend', this._overlay);
+ // if (this.options.dismissible) {
+ // document.addEventListener('keydown', this._handleKeydown);
+ // document.addEventListener('focus', this._handleFocus, true);
+ // }
+ // this._animateIn();
+ // // Focus modal
+ // this.el.focus();
return this;
};
@@ -321,32 +241,32 @@ export class Modal extends Component {
*/
close = () => {
if (!this.isOpen) return;
- this.isOpen = false;
- Modal._modalsOpen--;
- this._nthModalOpened = 0;
- // Call onCloseStart callback
- if (typeof this.options.onCloseStart === 'function') {
- this.options.onCloseStart.call(this, this.el);
- }
- this.el.classList.remove('open');
- // Enable body scrolling only if there are no more modals open.
- if (Modal._modalsOpen === 0) {
- const scrollTop = -parseInt(document.documentElement.style.top);
- document.documentElement.style.removeProperty('top');
- document.documentElement.classList.remove('noscroll');
- document.documentElement.scrollTop = scrollTop;
- }
- if (this.options.dismissible) {
- document.removeEventListener('keydown', this._handleKeydown);
- document.removeEventListener('focus', this._handleFocus, true);
- }
- this._animateOut();
+ // this.isOpen = false;
+ // Modal._modalsOpen--;
+ // this._nthModalOpened = 0;
+ // // Call onCloseStart callback
+ // if (typeof this.options.onCloseStart === 'function') {
+ // this.options.onCloseStart.call(this, this.el);
+ // }
+ // this.el.classList.remove('open');
+ // // Enable body scrolling only if there are no more modals open.
+ // if (Modal._modalsOpen === 0) {
+ // const scrollTop = -parseInt(document.documentElement.style.top);
+ // document.documentElement.style.removeProperty('top');
+ // document.documentElement.classList.remove('noscroll');
+ // document.documentElement.scrollTop = scrollTop;
+ // }
+ // if (this.options.dismissible) {
+ // document.removeEventListener('keydown', this._handleKeydown);
+ // document.removeEventListener('focus', this._handleFocus, true);
+ // }
+ // this._animateOut();
return this;
};
// Experimental!
// also note: https://stackoverflow.com/a/35385518/8830502
- static create(children: string = ''): string {
+ static createHtml(children: string = ''): string {
return ``;
}
+ static createElement() {}
static {
- Modal._modalsOpen = 0;
- Modal._count = 0;
+ //Modal._modalsOpen = 0;
+ //Modal._count = 0;
}
}