UNPKG

11.4 kBJavaScriptView Raw
1function _typeof(obj) {
2 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
3 _typeof = function _typeof(obj) {
4 return typeof obj;
5 };
6 } else {
7 _typeof = function _typeof(obj) {
8 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
9 };
10 }
11
12 return _typeof(obj);
13}
14
15function _classCallCheck(instance, Constructor) {
16 if (!(instance instanceof Constructor)) {
17 throw new TypeError("Cannot call a class as a function");
18 }
19}
20
21function _defineProperties(target, props) {
22 for (var i = 0; i < props.length; i++) {
23 var descriptor = props[i];
24 descriptor.enumerable = descriptor.enumerable || false;
25 descriptor.configurable = true;
26 if ("value" in descriptor) descriptor.writable = true;
27 Object.defineProperty(target, descriptor.key, descriptor);
28 }
29}
30
31function _createClass(Constructor, protoProps, staticProps) {
32 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
33 if (staticProps) _defineProperties(Constructor, staticProps);
34 return Constructor;
35}
36
37function _possibleConstructorReturn(self, call) {
38 if (call && (_typeof(call) === "object" || typeof call === "function")) {
39 return call;
40 }
41
42 return _assertThisInitialized(self);
43}
44
45function _assertThisInitialized(self) {
46 if (self === void 0) {
47 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
48 }
49
50 return self;
51}
52
53function _getPrototypeOf(o) {
54 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
55 return o.__proto__ || Object.getPrototypeOf(o);
56 };
57 return _getPrototypeOf(o);
58}
59
60function _inherits(subClass, superClass) {
61 if (typeof superClass !== "function" && superClass !== null) {
62 throw new TypeError("Super expression must either be null or a function");
63 }
64
65 subClass.prototype = Object.create(superClass && superClass.prototype, {
66 constructor: {
67 value: subClass,
68 writable: true,
69 configurable: true
70 }
71 });
72 if (superClass) _setPrototypeOf(subClass, superClass);
73}
74
75function _setPrototypeOf(o, p) {
76 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
77 o.__proto__ = p;
78 return o;
79 };
80
81 return _setPrototypeOf(o, p);
82}
83/**
84 * Copyright IBM Corp. 2016, 2018
85 *
86 * This source code is licensed under the Apache-2.0 license found in the
87 * LICENSE file in the root directory of this source tree.
88 */
89
90
91import settings from '../../globals/js/settings';
92import mixin from '../../globals/js/misc/mixin';
93import createComponent from '../../globals/js/mixins/create-component';
94import initComponentByLauncher from '../../globals/js/mixins/init-component-by-launcher';
95import eventedShowHideState from '../../globals/js/mixins/evented-show-hide-state';
96import handles from '../../globals/js/mixins/handles';
97import eventMatches from '../../globals/js/misc/event-matches';
98import on from '../../globals/js/misc/on';
99
100var Modal =
101/*#__PURE__*/
102function (_mixin) {
103 _inherits(Modal, _mixin);
104 /**
105 * Modal dialog.
106 * @extends CreateComponent
107 * @extends InitComponentByLauncher
108 * @extends EventedShowHideState
109 * @extends Handles
110 * @param {HTMLElement} element The element working as a modal dialog.
111 * @param {Object} [options] The component options.
112 * @param {string} [options.classVisible] The CSS class for the visible state.
113 * @param {string} [options.eventBeforeShown]
114 * The name of the custom event fired before this modal is shown.
115 * Cancellation of this event stops showing the modal.
116 * @param {string} [options.eventAfterShown]
117 * The name of the custom event telling that modal is sure shown
118 * without being canceled by the event handler named by `eventBeforeShown` option (`modal-beingshown`).
119 * @param {string} [options.eventBeforeHidden]
120 * The name of the custom event fired before this modal is hidden.
121 * Cancellation of this event stops hiding the modal.
122 * @param {string} [options.eventAfterHidden]
123 * The name of the custom event telling that modal is sure hidden
124 * without being canceled by the event handler named by `eventBeforeHidden` option (`modal-beinghidden`).
125 */
126
127
128 function Modal(element, options) {
129 var _this;
130
131 _classCallCheck(this, Modal);
132
133 _this = _possibleConstructorReturn(this, _getPrototypeOf(Modal).call(this, element, options));
134 _this._handleFocusinListener = void 0;
135 _this._handleKeydownListener = void 0;
136
137 _this._handleFocusin = function (evt) {
138 if (_this.element.classList.contains(_this.options.classVisible) && !_this.element.contains(evt.target) && _this.options.selectorsFloatingMenus.every(function (selector) {
139 return !eventMatches(evt, selector);
140 })) {
141 _this.element.focus();
142 }
143 };
144
145 _this._hookCloseActions();
146
147 return _this;
148 }
149 /**
150 * The handle for `focusin` event listener.
151 * Used for "focus-wrap" feature.
152 * @type {Handle}
153 * @private
154 */
155
156
157 _createClass(Modal, [{
158 key: "createdByLauncher",
159
160 /**
161 * A method that runs when `.init()` is called from `initComponentByLauncher`.
162 * @param {Event} evt The event fired on the launcher button.
163 */
164 value: function createdByLauncher(evt) {
165 this.show(evt);
166 }
167 /**
168 * Determines whether or not to emit events and callback function when `.changeState()` is called from `eventedState`.
169 * @param {string} state The new state.
170 * @returns {boolean} `true` if the given `state` is different from current state.
171 */
172
173 }, {
174 key: "shouldStateBeChanged",
175 value: function shouldStateBeChanged(state) {
176 if (state === 'shown') {
177 return !this.element.classList.contains(this.options.classVisible);
178 }
179
180 return this.element.classList.contains(this.options.classVisible);
181 }
182 /**
183 * Changes the shown/hidden state.
184 * @private
185 * @param {string} state The new state.
186 * @param {Object} detail The detail data to be included in the event that will be fired.
187 * @param {Function} callback Callback called when change in state completes.
188 */
189
190 }, {
191 key: "_changeState",
192 value: function _changeState(state, detail, callback) {
193 var _this2 = this;
194
195 var handleTransitionEnd;
196
197 var transitionEnd = function transitionEnd() {
198 if (handleTransitionEnd) {
199 handleTransitionEnd = _this2.unmanage(handleTransitionEnd).release();
200 }
201
202 if (state === 'shown' && _this2.element.offsetWidth > 0 && _this2.element.offsetHeight > 0) {
203 (_this2.element.querySelector(_this2.options.selectorPrimaryFocus) || _this2.element).focus();
204 }
205
206 callback();
207 };
208
209 if (this._handleFocusinListener) {
210 this._handleFocusinListener = this.unmanage(this._handleFocusinListener).release();
211 }
212
213 if (state === 'shown') {
214 var hasFocusin = 'onfocusin' in this.element.ownerDocument.defaultView;
215 var focusinEventName = hasFocusin ? 'focusin' : 'focus';
216 this._handleFocusinListener = this.manage(on(this.element.ownerDocument, focusinEventName, this._handleFocusin, !hasFocusin));
217 }
218
219 if (state === 'hidden') {
220 this.element.classList.toggle(this.options.classVisible, false);
221 } else if (state === 'shown') {
222 this.element.classList.toggle(this.options.classVisible, true);
223 }
224
225 handleTransitionEnd = this.manage(on(this.element, 'transitionend', transitionEnd));
226 }
227 }, {
228 key: "_hookCloseActions",
229 value: function _hookCloseActions() {
230 var _this3 = this;
231
232 this.manage(on(this.element, 'click', function (evt) {
233 var closeButton = eventMatches(evt, _this3.options.selectorModalClose);
234
235 if (closeButton) {
236 evt.delegateTarget = closeButton; // eslint-disable-line no-param-reassign
237 }
238
239 if (closeButton || evt.target === _this3.element) {
240 _this3.hide(evt);
241 }
242 }));
243
244 if (this._handleKeydownListener) {
245 this._handleKeydownListener = this.unmanage(this._handleKeydownListener).release();
246 }
247
248 this._handleKeydownListener = this.manage(on(this.element.ownerDocument.body, 'keydown', function (evt) {
249 if (evt.which === 27) {
250 evt.stopPropagation();
251
252 _this3.hide(evt);
253 }
254 }));
255 }
256 /**
257 * Handles `focusin` (or `focus` depending on browser support of `focusin`) event to do wrap-focus behavior.
258 * @param {Event} evt The event.
259 * @private
260 */
261
262 }], [{
263 key: "options",
264
265 /**
266 * The component options.
267 * If `options` is specified in the constructor, {@linkcode Modal.create .create()}, or {@linkcode Modal.init .init()},
268 * properties in this object are overriden for the instance being create and how {@linkcode Modal.init .init()} works.
269 * @member Modal.options
270 * @type {Object}
271 * @property {string} selectorInit The CSS class to find modal dialogs.
272 * @property {string} [selectorModalClose] The selector to find elements that close the modal.
273 * @property {string} [selectorPrimaryFocus] The CSS selector to determine the element to put focus when modal gets open.
274 * @property {string} attribInitTarget The attribute name in the launcher buttons to find target modal dialogs.
275 * @property {string[]} [selectorsFloatingMenu]
276 * The CSS selectors of floating menus.
277 * Used for detecting if focus-wrap behavior should be disabled temporarily.
278 * @property {string} [classVisible] The CSS class for the visible state.
279 * @property {string} [classNoScroll] The CSS class for hiding scroll bar in body element while modal is shown.
280 * @property {string} [eventBeforeShown]
281 * The name of the custom event fired before this modal is shown.
282 * Cancellation of this event stops showing the modal.
283 * @property {string} [eventAfterShown]
284 * The name of the custom event telling that modal is sure shown
285 * without being canceled by the event handler named by `eventBeforeShown` option (`modal-beingshown`).
286 * @property {string} [eventBeforeHidden]
287 * The name of the custom event fired before this modal is hidden.
288 * Cancellation of this event stops hiding the modal.
289 * @property {string} [eventAfterHidden]
290 * The name of the custom event telling that modal is sure hidden
291 * without being canceled by the event handler named by `eventBeforeHidden` option (`modal-beinghidden`).
292 */
293 get: function get() {
294 var prefix = settings.prefix;
295 return {
296 selectorInit: '[data-modal]',
297 selectorModalClose: '[data-modal-close]',
298 selectorPrimaryFocus: '[data-modal-primary-focus]',
299 selectorsFloatingMenus: [".".concat(prefix, "--overflow-menu-options"), ".".concat(prefix, "--tooltip"), '.flatpickr-calendar'],
300 classVisible: 'is-visible',
301 attribInitTarget: 'data-modal-target',
302 initEventNames: ['click'],
303 eventBeforeShown: 'modal-beingshown',
304 eventAfterShown: 'modal-shown',
305 eventBeforeHidden: 'modal-beinghidden',
306 eventAfterHidden: 'modal-hidden'
307 };
308 }
309 }]);
310
311 Modal.components = new WeakMap();
312 return Modal;
313}(mixin(createComponent, initComponentByLauncher, eventedShowHideState, handles));
314
315export default Modal;
\No newline at end of file