vrembem 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,60 +1,105 @@
1
- const setInert = (state, selector) => {
2
- if (selector) {
3
- const els = document.querySelectorAll(selector);
4
- els.forEach(el => {
5
- if (state) {
6
- el.inert = true;
7
- el.setAttribute('aria-hidden', true);
8
- } else {
9
- el.inert = null;
10
- el.removeAttribute('aria-hidden');
1
+ function _extends() {
2
+ _extends = Object.assign || function (target) {
3
+ for (var i = 1; i < arguments.length; i++) {
4
+ var source = arguments[i];
5
+
6
+ for (var key in source) {
7
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
8
+ target[key] = source[key];
9
+ }
11
10
  }
11
+ }
12
+
13
+ return target;
14
+ };
15
+
16
+ return _extends.apply(this, arguments);
17
+ }
18
+
19
+ var id = 0;
20
+
21
+ function _classPrivateFieldLooseKey(name) {
22
+ return "__private_" + id++ + "_" + name;
23
+ }
24
+
25
+ function _classPrivateFieldLooseBase(receiver, privateKey) {
26
+ if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
27
+ throw new TypeError("attempted to use private field on non-instance");
28
+ }
29
+
30
+ return receiver;
31
+ }
32
+
33
+ var _handler = /*#__PURE__*/_classPrivateFieldLooseKey("handler");
34
+
35
+ class Breakpoint {
36
+ constructor(value, handler) {
37
+ Object.defineProperty(this, _handler, {
38
+ writable: true,
39
+ value: void 0
12
40
  });
41
+ this.value = value;
42
+ _classPrivateFieldLooseBase(this, _handler)[_handler] = handler;
43
+ this.mql = null;
13
44
  }
14
- };
15
- const setOverflowHidden = (state, selector) => {
16
- if (selector) {
17
- const els = document.querySelectorAll(selector);
18
- els.forEach(el => {
19
- if (state) {
20
- el.style.overflow = 'hidden';
45
+
46
+ get handler() {
47
+ return _classPrivateFieldLooseBase(this, _handler)[_handler];
48
+ } // Unmount existing handler before setting a new one.
49
+
50
+
51
+ set handler(func) {
52
+ if (this.mql) {
53
+ // Conditionally use removeListener() for IE11 support.
54
+ if (typeof this.mql.removeEventListener === 'function') {
55
+ this.mql.removeEventListener('change', _classPrivateFieldLooseBase(this, _handler)[_handler]);
21
56
  } else {
22
- el.style.removeProperty('overflow');
57
+ this.mql.removeListener(_classPrivateFieldLooseBase(this, _handler)[_handler]);
23
58
  }
24
- });
59
+ }
60
+
61
+ _classPrivateFieldLooseBase(this, _handler)[_handler] = func;
25
62
  }
26
- };
27
- const setTabindex = selector => {
28
- if (selector) {
29
- const els = document.querySelectorAll(selector);
30
- els.forEach(el => {
31
- el.setAttribute('tabindex', '-1');
32
- });
63
+
64
+ mount(value, handler) {
65
+ // Update passed params.
66
+ if (value) this.value = value;
67
+ if (handler) _classPrivateFieldLooseBase(this, _handler)[_handler] = handler; // Guard if no breakpoint was set.
68
+
69
+ if (!this.value) return this; // Setup and store the MediaQueryList instance.
70
+
71
+ this.mql = window.matchMedia(`(min-width: ${this.value})`); // Conditionally use addListener() for IE11 support.
72
+
73
+ if (typeof this.mql.addEventListener === 'function') {
74
+ this.mql.addEventListener('change', _classPrivateFieldLooseBase(this, _handler)[_handler]);
75
+ } else {
76
+ this.mql.addListener(_classPrivateFieldLooseBase(this, _handler)[_handler]);
77
+ } // Run the handler.
78
+
79
+
80
+ _classPrivateFieldLooseBase(this, _handler)[_handler](this.mql);
81
+
82
+ return this;
33
83
  }
34
- };
35
84
 
36
- /**
37
- * Adds a class or classes to a Node or NodeList.
38
- * @param {Node || NodeList} el - Element(s) to add class(es) to.
39
- * @param {String || Array} cl - Class(es) to add.
40
- */
41
- const addClass = (el, ...cl) => {
42
- el = el.forEach ? el : [el];
43
- el.forEach(el => {
44
- el.classList.add(...cl);
45
- });
46
- };
85
+ unmount() {
86
+ // Guard if no MediaQueryList instance exists.
87
+ if (!this.mql) return this; // Conditionally use removeListener() for IE11 support.
47
88
 
48
- /**
49
- * Takes a hyphen cased string and converts it to camel case.
50
- * @param {String } str - the string to convert to camel case.
51
- * @returns {Boolean} - returns a camel cased string.
52
- */
53
- const camelCase = str => {
54
- return str.replace(/-([a-z])/g, function (g) {
55
- return g[1].toUpperCase();
56
- });
57
- };
89
+ if (typeof this.mql.removeEventListener === 'function') {
90
+ this.mql.removeEventListener('change', _classPrivateFieldLooseBase(this, _handler)[_handler]);
91
+ } else {
92
+ this.mql.removeListener(_classPrivateFieldLooseBase(this, _handler)[_handler]);
93
+ } // Set value, handler and MediaQueryList to null.
94
+
95
+
96
+ this.value = null;
97
+ _classPrivateFieldLooseBase(this, _handler)[_handler] = null;
98
+ this.mql = null;
99
+ return this;
100
+ }
101
+
102
+ }
58
103
 
59
104
  class Collection {
60
105
  constructor() {
@@ -108,154 +153,168 @@ class Collection {
108
153
 
109
154
  var focusableSelectors = ['a[href]:not([tabindex^="-"])', 'area[href]:not([tabindex^="-"])', 'input:not([type="hidden"]):not([type="radio"]):not([disabled]):not([tabindex^="-"])', 'input[type="radio"]:not([disabled]):not([tabindex^="-"])', 'select:not([disabled]):not([tabindex^="-"])', 'textarea:not([disabled]):not([tabindex^="-"])', 'button:not([disabled]):not([tabindex^="-"])', 'iframe:not([tabindex^="-"])', 'audio[controls]:not([tabindex^="-"])', 'video[controls]:not([tabindex^="-"])', '[contenteditable]:not([tabindex^="-"])', '[tabindex]:not([tabindex^="-"])'];
110
155
 
111
- const focusTarget = (target, settings) => {
112
- const innerFocus = target.querySelector(settings.selectorFocus);
156
+ var _focusable = /*#__PURE__*/_classPrivateFieldLooseKey("focusable");
157
+
158
+ var _handleFocusTrap = /*#__PURE__*/_classPrivateFieldLooseKey("handleFocusTrap");
159
+
160
+ var _handleFocusLock = /*#__PURE__*/_classPrivateFieldLooseKey("handleFocusLock");
113
161
 
114
- if (innerFocus) {
115
- innerFocus.focus();
116
- } else {
117
- const innerElement = target.querySelector('[tabindex="-1"]');
118
- if (innerElement) innerElement.focus();
119
- }
120
- };
121
- const focusTrigger = obj => {
122
- if (!obj || !obj.memory || !obj.memory.trigger) return;
123
- obj.memory.trigger.focus();
124
- obj.memory.trigger = null;
125
- };
126
162
  class FocusTrap {
127
- constructor() {
128
- this.target = null;
129
- this.__handlerFocusTrap = this.handlerFocusTrap.bind(this);
163
+ constructor(el = null, selectorFocus = '[data-focus]') {
164
+ Object.defineProperty(this, _focusable, {
165
+ writable: true,
166
+ value: void 0
167
+ });
168
+ Object.defineProperty(this, _handleFocusTrap, {
169
+ writable: true,
170
+ value: void 0
171
+ });
172
+ Object.defineProperty(this, _handleFocusLock, {
173
+ writable: true,
174
+ value: void 0
175
+ });
176
+ this.el = el;
177
+ this.selectorFocus = selectorFocus;
178
+ _classPrivateFieldLooseBase(this, _handleFocusTrap)[_handleFocusTrap] = handleFocusTrap.bind(this);
179
+ _classPrivateFieldLooseBase(this, _handleFocusLock)[_handleFocusLock] = handleFocusLock.bind(this);
130
180
  }
131
181
 
132
- init(target) {
133
- this.destroy();
134
- this.target = target;
135
- this.inner = this.target.querySelector('[tabindex="-1"]');
136
- this.focusable = this.getFocusable();
182
+ get focusable() {
183
+ return _classPrivateFieldLooseBase(this, _focusable)[_focusable];
184
+ }
137
185
 
138
- if (this.focusable.length) {
139
- this.focusableFirst = this.focusable[0];
140
- this.focusableLast = this.focusable[this.focusable.length - 1];
141
- this.target.addEventListener('keydown', this.__handlerFocusTrap);
186
+ set focusable(value) {
187
+ // Update the focusable value.
188
+ _classPrivateFieldLooseBase(this, _focusable)[_focusable] = value; // Apply event listeners based on new focusable array length.
189
+
190
+ if (_classPrivateFieldLooseBase(this, _focusable)[_focusable].length) {
191
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleFocusLock)[_handleFocusLock]);
192
+ document.addEventListener('keydown', _classPrivateFieldLooseBase(this, _handleFocusTrap)[_handleFocusTrap]);
142
193
  } else {
143
- this.target.addEventListener('keydown', this.handlerFocusLock);
194
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleFocusTrap)[_handleFocusTrap]);
195
+ document.addEventListener('keydown', _classPrivateFieldLooseBase(this, _handleFocusLock)[_handleFocusLock]);
144
196
  }
145
197
  }
146
198
 
147
- destroy() {
148
- if (!this.target) return;
149
- this.inner = null;
150
- this.focusable = null;
151
- this.focusableFirst = null;
152
- this.focusableLast = null;
153
- this.target.removeEventListener('keydown', this.__handlerFocusTrap);
154
- this.target.removeEventListener('keydown', this.handlerFocusLock);
155
- this.target = null;
156
- }
157
-
158
- refresh() {
159
- // Check if a target has been set
160
- if (!this.target) return; // Remove existing events
161
-
162
- this.target.removeEventListener('keydown', this.__handlerFocusTrap);
163
- this.target.removeEventListener('keydown', this.handlerFocusLock); // Get the focusable elements
164
-
165
- this.focusable = this.getFocusable(); // Setup the focus handlers based on focusable length
166
-
167
- if (this.focusable.length) {
168
- // If there are focusable elements, setup focus trap
169
- this.focusableFirst = this.focusable[0];
170
- this.focusableLast = this.focusable[this.focusable.length - 1];
171
- this.target.addEventListener('keydown', this.__handlerFocusTrap);
172
- } else {
173
- // If there are no focusable elements, setup focus lock
174
- this.focusableFirst = null;
175
- this.focusableLast = null;
176
- this.target.addEventListener('keydown', this.handlerFocusLock);
177
- }
199
+ get focusableFirst() {
200
+ return this.focusable[0];
178
201
  }
179
202
 
180
- handlerFocusTrap(event) {
181
- const isTab = event.key === 'Tab' || event.keyCode === 9;
182
- if (!isTab) return;
203
+ get focusableLast() {
204
+ return this.focusable[this.focusable.length - 1];
205
+ }
183
206
 
184
- if (event.shiftKey) {
185
- if (document.activeElement === this.focusableFirst || document.activeElement === this.inner) {
186
- this.focusableLast.focus();
187
- event.preventDefault();
188
- }
189
- } else {
190
- if (document.activeElement === this.focusableLast || document.activeElement === this.inner) {
191
- this.focusableFirst.focus();
192
- event.preventDefault();
193
- }
194
- }
207
+ mount(el, selectorFocus) {
208
+ // Update passed params.
209
+ if (el) this.el = el;
210
+ if (selectorFocus) this.selectorFocus = selectorFocus; // Get the focusable elements.
211
+
212
+ this.focusable = this.getFocusable(); // Set the focus on the element.
213
+
214
+ this.focus();
215
+ }
216
+
217
+ unmount() {
218
+ // Set element to null.
219
+ this.el = null; // Apply empty array to focusable.
220
+
221
+ this.focusable = []; // Remove event listeners
222
+
223
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleFocusTrap)[_handleFocusTrap]);
224
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleFocusLock)[_handleFocusLock]);
195
225
  }
196
226
 
197
- handlerFocusLock(event) {
198
- const isTab = event.key === 'Tab' || event.keyCode === 9;
199
- if (isTab) event.preventDefault();
227
+ focus(el = this.el, selectorFocus = this.selectorFocus) {
228
+ // Query for the focus selector, otherwise return this element.
229
+ const result = el.querySelector(selectorFocus) || el; // Give the returned element focus.
230
+
231
+ result.focus();
200
232
  }
201
233
 
202
- getFocusable() {
203
- const focusable = [];
234
+ getFocusable(el = this.el) {
235
+ // Initialize the focusable array.
236
+ const focusable = []; // Store the initial focus and scroll position.
237
+
204
238
  const initFocus = document.activeElement;
205
- const initScrollTop = this.inner ? this.inner.scrollTop : 0;
206
- this.target.querySelectorAll(focusableSelectors.join(',')).forEach(el => {
207
- el.focus();
239
+ const initScrollTop = el.scrollTop; // Query for all the focusable elements.
208
240
 
209
- if (el === document.activeElement) {
241
+ const els = el.querySelectorAll(focusableSelectors.join(',')); // Loop through all focusable elements.
242
+
243
+ els.forEach(el => {
244
+ // Set them to focus and check
245
+ el.focus(); // Test that the element took focus.
246
+
247
+ if (document.activeElement === el) {
248
+ // Add element to the focusable array.
210
249
  focusable.push(el);
211
250
  }
212
- });
213
- if (this.inner) this.inner.scrollTop = initScrollTop;
214
- initFocus.focus();
251
+ }); // Restore the initial scroll position and focus.
252
+
253
+ el.scrollTop = initScrollTop;
254
+ initFocus.focus(); // Return the focusable array.
255
+
215
256
  return focusable;
216
257
  }
217
258
 
218
259
  }
219
260
 
220
- /**
221
- * Checks an element or NodeList whether they contain a class or classes.
222
- * Ref: https://davidwalsh.name/nodelist-array
223
- * @param {Node} el - Element(s) to check class(es) on.
224
- * @param {String || Array} c - Class(es) to check.
225
- * @returns {Boolean} - Returns true if class exists, otherwise false.
226
- */
227
- const hasClass = (el, ...cl) => {
228
- el = el.forEach ? el : [el];
229
- el = [].slice.call(el);
230
- return cl.some(cl => {
231
- return el.some(el => {
232
- if (el.classList.contains(cl)) return true;
233
- });
234
- });
235
- };
261
+ function handleFocusTrap(event) {
262
+ // Check if the click was a tab and return if not.
263
+ const isTab = event.key === 'Tab' || event.keyCode === 9;
264
+ if (!isTab) return; // If the shift key is pressed.
236
265
 
237
- /**
238
- * Takes a camel cased string and converts it to hyphen case.
239
- * @param {String } str - the string to convert to hyphen case.
240
- * @returns {Boolean} - returns a hyphen cased string.
241
- */
242
- const hyphenCase = str => {
243
- return str.replace(/([a-z][A-Z])/g, function (g) {
244
- return g[0] + '-' + g[1].toLowerCase();
245
- });
246
- };
266
+ if (event.shiftKey) {
267
+ // If the active element is either the root el or first focusable.
268
+ if (document.activeElement === this.focusableFirst || document.activeElement === this.el) {
269
+ // Prevent default and focus the last focusable element instead.
270
+ event.preventDefault();
271
+ this.focusableLast.focus();
272
+ }
273
+ } else {
274
+ // If the active element is either the root el or last focusable.
275
+ if (document.activeElement === this.focusableLast || document.activeElement === this.el) {
276
+ // Prevent default and focus the first focusable element instead.
277
+ event.preventDefault();
278
+ this.focusableFirst.focus();
279
+ }
280
+ }
281
+ }
247
282
 
248
- /**
249
- * Remove a class or classes from an element or NodeList.
250
- * @param {Node || NodeList} el - Element(s) to remove class(es) from.
251
- * @param {String || Array} cl - Class(es) to remove.
252
- */
253
- const removeClass = (el, ...cl) => {
254
- el = el.forEach ? el : [el];
255
- el.forEach(el => {
256
- el.classList.remove(...cl);
283
+ function handleFocusLock(event) {
284
+ // Ignore the tab key by preventing default.
285
+ const isTab = event.key === 'Tab' || event.keyCode === 9;
286
+ if (isTab) event.preventDefault();
287
+ }
288
+
289
+ function getConfig$1(el, dataConfig) {
290
+ const string = el.getAttribute(`data-${dataConfig}`) || '';
291
+ const json = string.replace(/'/g, '"');
292
+ return json ? JSON.parse(json) : {};
293
+ }
294
+
295
+ function localStore(key, enable = true) {
296
+ function getStore() {
297
+ const value = localStorage.getItem(key);
298
+ return value ? JSON.parse(value) : {};
299
+ }
300
+
301
+ function setStore(obj) {
302
+ localStorage.setItem(key, JSON.stringify(obj));
303
+ }
304
+
305
+ return new Proxy(getStore(), {
306
+ set: (target, property, value) => {
307
+ target[property] = value;
308
+ if (enable) setStore(target);
309
+ return true;
310
+ },
311
+ deleteProperty: (target, property) => {
312
+ delete target[property];
313
+ if (enable) setStore(target);
314
+ return true;
315
+ }
257
316
  });
258
- };
317
+ }
259
318
 
260
319
  /**
261
320
  * Teleports an element in the DOM based on a reference and teleport method.
@@ -299,20 +358,6 @@ function teleport(what, where, how) {
299
358
  return returnRef;
300
359
  }
301
360
 
302
- /**
303
- * Toggle a class or classes on an element or NodeList.
304
- * @param {Node || NodeList} el - Element(s) to toggle class(es) on.
305
- * @param {String || Array} cl - Class(es) to toggle.
306
- */
307
- const toggleClass = (el, ...cl) => {
308
- el = el.forEach ? el : [el];
309
- el.forEach(el => {
310
- cl.forEach(cl => {
311
- el.classList.toggle(cl);
312
- });
313
- });
314
- };
315
-
316
361
  const openTransition = (el, settings) => {
317
362
  return new Promise(resolve => {
318
363
  if (settings.transition) {
@@ -350,44 +395,54 @@ const closeTransition = (el, settings) => {
350
395
  });
351
396
  };
352
397
 
398
+ function setOverflowHidden(state, selector) {
399
+ if (selector) {
400
+ const els = document.querySelectorAll(selector);
401
+ els.forEach(el => {
402
+ if (state) {
403
+ el.style.overflow = 'hidden';
404
+ } else {
405
+ el.style.removeProperty('overflow');
406
+ }
407
+ });
408
+ }
409
+ }
410
+
411
+ function setInert(state, selector) {
412
+ if (selector) {
413
+ const els = document.querySelectorAll(selector);
414
+ els.forEach(el => {
415
+ if (state) {
416
+ el.inert = true;
417
+ el.setAttribute('aria-hidden', true);
418
+ } else {
419
+ el.inert = null;
420
+ el.removeAttribute('aria-hidden');
421
+ }
422
+ });
423
+ }
424
+ }
425
+
426
+ function updateGlobalState(param, config) {
427
+ // Set inert state based on if a modal is active.
428
+ setInert(!!param, config.selectorInert); // Set overflow state based on if a modal is active.
429
+
430
+ setOverflowHidden(!!param, config.selectorOverflow);
431
+ }
432
+
353
433
  var index = {
354
434
  __proto__: null,
355
- setInert: setInert,
356
- setOverflowHidden: setOverflowHidden,
357
- setTabindex: setTabindex,
358
- addClass: addClass,
359
- camelCase: camelCase,
435
+ Breakpoint: Breakpoint,
360
436
  Collection: Collection,
361
- focusTarget: focusTarget,
362
- focusTrigger: focusTrigger,
363
437
  FocusTrap: FocusTrap,
364
- hasClass: hasClass,
365
- hyphenCase: hyphenCase,
366
- removeClass: removeClass,
438
+ getConfig: getConfig$1,
439
+ localStore: localStore,
367
440
  teleport: teleport,
368
- toggleClass: toggleClass,
369
441
  openTransition: openTransition,
370
- closeTransition: closeTransition
442
+ closeTransition: closeTransition,
443
+ updateGlobalState: updateGlobalState
371
444
  };
372
445
 
373
- function _extends() {
374
- _extends = Object.assign || function (target) {
375
- for (var i = 1; i < arguments.length; i++) {
376
- var source = arguments[i];
377
-
378
- for (var key in source) {
379
- if (Object.prototype.hasOwnProperty.call(source, key)) {
380
- target[key] = source[key];
381
- }
382
- }
383
- }
384
-
385
- return target;
386
- };
387
-
388
- return _extends.apply(this, arguments);
389
- }
390
-
391
446
  var defaults$3 = {
392
447
  autoInit: false,
393
448
  stateAttr: 'aria-checked',
@@ -452,16 +507,17 @@ class Checkbox {
452
507
  var defaults$2 = {
453
508
  autoInit: false,
454
509
  // Data attributes
455
- dataDrawer: 'drawer',
456
- dataDialog: 'drawer-dialog',
457
- dataToggle: 'drawer-toggle',
458
510
  dataOpen: 'drawer-open',
459
511
  dataClose: 'drawer-close',
512
+ dataToggle: 'drawer-toggle',
460
513
  dataBreakpoint: 'drawer-breakpoint',
514
+ dataConfig: 'drawer-config',
461
515
  // Selectors
516
+ selectorDrawer: '.drawer',
517
+ selectorDialog: '.drawer__dialog',
462
518
  selectorFocus: '[data-focus]',
463
519
  selectorInert: null,
464
- selectorOverflow: null,
520
+ selectorOverflow: 'body',
465
521
  // State classes
466
522
  stateOpened: 'is-opened',
467
523
  stateOpening: 'is-opening',
@@ -473,440 +529,593 @@ var defaults$2 = {
473
529
  breakpoints: null,
474
530
  customEventPrefix: 'drawer:',
475
531
  eventListeners: true,
476
- stateSave: true,
477
- stateKey: 'DrawerState',
532
+ store: true,
533
+ storeKey: 'VB:DrawerState',
478
534
  setTabindex: true,
479
535
  transition: true
480
536
  };
481
537
 
482
- class Breakpoint {
483
- constructor(parent) {
484
- this.mediaQueryLists = [];
485
- this.parent = parent;
486
- this.prefix = this.getVariablePrefix();
487
- this.__check = this.check.bind(this);
488
- }
489
-
490
- init() {
491
- const drawers = document.querySelectorAll(`[data-${this.parent.settings.dataBreakpoint}]`);
492
- drawers.forEach(drawer => {
493
- // Setup mediaQueryList object
494
- const id = drawer.getAttribute(`data-${this.parent.settings.dataDrawer}`);
495
- const key = drawer.getAttribute(`data-${this.parent.settings.dataBreakpoint}`);
496
- const bp = this.getBreakpoint(key);
497
- const mql = window.matchMedia('(min-width:' + bp + ')'); // Run match check
498
-
499
- this.match(mql, drawer); // Conditionally use addListner() for IE11 support
500
-
501
- if (typeof mql.addEventListener === 'function') {
502
- mql.addEventListener('change', this.__check);
503
- } else {
504
- mql.addListener(this.__check);
505
- } // Push to mediaQueryLists array along with drawer ID
538
+ function handleClick$2(event) {
539
+ // If an open, close or toggle button was clicked, handle the click event.
540
+ const trigger = event.target.closest(`
541
+ [data-${this.settings.dataOpen}],
542
+ [data-${this.settings.dataToggle}],
543
+ [data-${this.settings.dataClose}]
544
+ `);
545
+
546
+ if (trigger) {
547
+ // Prevent the default behavior of the trigger.
548
+ event.preventDefault(); // If it's a toggle trigger...
549
+
550
+ if (trigger.matches(`[data-${this.settings.dataToggle}]`)) {
551
+ const selectors = trigger.getAttribute(`data-${this.settings.dataToggle}`).trim().split(' ');
552
+ selectors.forEach(selector => {
553
+ // Get the entry from collection using the attribute value.
554
+ const entry = this.get(selector); // Store the trigger on the entry.
555
+
556
+ entry.trigger = trigger; // Toggle the drawer
557
+
558
+ entry.toggle();
559
+ });
560
+ } // If it's a open trigger...
561
+
562
+
563
+ if (trigger.matches(`[data-${this.settings.dataOpen}]`)) {
564
+ const selectors = trigger.getAttribute(`data-${this.settings.dataOpen}`).trim().split(' ');
565
+ selectors.forEach(selector => {
566
+ // Get the entry from collection using the attribute value.
567
+ const entry = this.get(selector); // Store the trigger on the entry.
568
+
569
+ entry.trigger = trigger; // Open the drawer.
570
+
571
+ entry.open();
572
+ });
573
+ } // If it's a close trigger...
574
+
575
+
576
+ if (trigger.matches(`[data-${this.settings.dataClose}]`)) {
577
+ const selectors = trigger.getAttribute(`data-${this.settings.dataClose}`).trim().split(' ');
578
+ selectors.forEach(selector => {
579
+ if (selector) {
580
+ // Get the entry from collection using the attribute value.
581
+ const entry = this.get(selector); // Store the trigger on the entry.
582
+
583
+ entry.trigger = trigger; // Close the drawer.
584
+
585
+ entry.close();
586
+ } else {
587
+ // If no value is set on close trigger, get the parent drawer.
588
+ const parent = event.target.closest(this.settings.selectorDrawer); // If a parent drawer was found, close it.
589
+
590
+ if (parent) this.close(parent);
591
+ }
592
+ });
593
+ }
594
+
595
+ return;
596
+ } // If the modal drawer screen was clicked...
597
+
598
+
599
+ if (event.target.matches(this.settings.selectorDrawer)) {
600
+ // Close the modal drawer.
601
+ this.close(event.target.id);
602
+ }
603
+ }
604
+ function handleKeydown$2(event) {
605
+ if (event.key === 'Escape') {
606
+ const modal = this.activeModal;
607
+ if (modal) this.close(modal);
608
+ }
609
+ }
610
+
611
+ async function deregister$2(obj, close = true) {
612
+ // Return collection if nothing was passed.
613
+ if (!obj) return this.collection; // Check if entry has been registered in the collection.
614
+
615
+ const index = this.collection.findIndex(entry => {
616
+ return entry.id === obj.id;
617
+ });
618
+
619
+ if (index >= 0) {
620
+ // Get the collection entry.
621
+ const entry = this.collection[index]; // If entry is in the opened state.
622
+
623
+ if (close && entry.state === 'opened') {
624
+ // Close the drawer.
625
+ await entry.close(false);
626
+ } // Remove entry from local store.
627
+
628
+
629
+ delete this.store[entry.id]; // Unmount the MatchMedia functionality.
630
+
631
+ entry.unmountBreakpoint(); // Delete properties from collection entry.
632
+
633
+ Object.getOwnPropertyNames(entry).forEach(prop => {
634
+ delete entry[prop];
635
+ }); // Remove entry from collection.
636
+
637
+ this.collection.splice(index, 1);
638
+ } // Return the modified collection.
639
+
640
+
641
+ return this.collection;
642
+ }
643
+
644
+ function getBreakpoint(drawer) {
645
+ const prefix = getVariablePrefix();
646
+ const bp = drawer.getAttribute(`data-${this.settings.dataBreakpoint}`);
647
+
648
+ if (this.settings.breakpoints && this.settings.breakpoints[bp]) {
649
+ return this.settings.breakpoints[bp];
650
+ } else if (getComputedStyle(document.body).getPropertyValue(prefix + bp)) {
651
+ return getComputedStyle(document.body).getPropertyValue(prefix + bp);
652
+ } else {
653
+ return bp;
654
+ }
655
+ }
656
+
657
+ function getVariablePrefix() {
658
+ let prefix = '--';
659
+ prefix += getComputedStyle(document.body).getPropertyValue('--vrembem-variable-prefix');
660
+ prefix += 'breakpoint-';
661
+ return prefix;
662
+ }
663
+
664
+ function getDrawer(query) {
665
+ // Get the entry from collection.
666
+ const entry = typeof query === 'string' ? this.get(query) : this.get(query.id); // Return entry if it was resolved, otherwise throw error.
667
+
668
+ if (entry) {
669
+ return entry;
670
+ } else {
671
+ throw new Error(`Drawer not found in collection with id of "${query.id || query}".`);
672
+ }
673
+ }
674
+
675
+ function getDrawerID(obj) {
676
+ // If it's a string, return the string.
677
+ if (typeof obj === 'string') {
678
+ return obj;
679
+ } // If it's an HTML element.
680
+ else if (typeof obj.hasAttribute === 'function') {
681
+ // If it's a drawer open trigger, return data value.
682
+ if (obj.hasAttribute(`data-${this.settings.dataOpen}`)) {
683
+ return obj.getAttribute(`data-${this.settings.dataOpen}`);
684
+ } // If it's a drawer close trigger, return data value or false.
685
+ else if (obj.hasAttribute(`data-${this.settings.dataClose}`)) {
686
+ return obj.getAttribute(`data-${this.settings.dataClose}`) || false;
687
+ } // If it's a drawer toggle trigger, return data value.
688
+ else if (obj.hasAttribute(`data-${this.settings.dataToggle}`)) {
689
+ return obj.getAttribute(`data-${this.settings.dataToggle}`);
690
+ } // If it's a drawer element, return the id.
691
+ else if (obj.closest(this.settings.selectorDrawer)) {
692
+ obj = obj.closest(this.settings.selectorDrawer);
693
+ return obj.id || false;
694
+ } // Return false if no id was found.
695
+ else return false;
696
+ } // If it has an id property, return its value.
697
+ else if (obj.id) {
698
+ return obj.id;
699
+ } // Return false if no id was found.
700
+ else return false;
701
+ }
506
702
 
703
+ function getDrawerElements(query) {
704
+ const id = getDrawerID.call(this, query);
507
705
 
508
- this.mediaQueryLists.push({
509
- 'mql': mql,
510
- 'drawer': id
511
- });
512
- });
513
- }
706
+ if (id) {
707
+ const drawer = document.querySelector(`#${id}`);
708
+ const dialog = drawer ? drawer.querySelector(this.settings.selectorDialog) : null;
514
709
 
515
- destroy() {
516
- if (this.mediaQueryLists && this.mediaQueryLists.length) {
517
- this.mediaQueryLists.forEach(item => {
518
- item.mql.removeListener(this.__check);
519
- });
710
+ if (!drawer && !dialog) {
711
+ return {
712
+ error: new Error(`No drawer elements found using the ID: "${id}".`)
713
+ };
714
+ } else if (!dialog) {
715
+ return {
716
+ error: new Error('Drawer is missing dialog element.')
717
+ };
718
+ } else {
719
+ return {
720
+ drawer,
721
+ dialog
722
+ };
520
723
  }
521
-
522
- this.mediaQueryLists = null;
724
+ } else {
725
+ return {
726
+ error: new Error('Could not resolve the drawer ID.')
727
+ };
523
728
  }
729
+ }
524
730
 
525
- check(event = null) {
526
- if (this.mediaQueryLists && this.mediaQueryLists.length) {
527
- this.mediaQueryLists.forEach(item => {
528
- // If an event is passed, filter out drawers that don't match the query
529
- // If event is null, run all drawers through match
530
- let filter = event ? event.media == item.mql.media : true;
531
- if (!filter) return;
532
- const drawer = document.querySelector(`[data-${this.parent.settings.dataDrawer}="${item.drawer}"]`);
533
- if (drawer) this.match(item.mql, drawer);
534
- });
535
- document.dispatchEvent(new CustomEvent(this.parent.settings.customEventPrefix + 'breakpoint', {
536
- bubbles: true
537
- }));
731
+ async function initialState(entry) {
732
+ // Setup initial state using the following priority:
733
+ // 1. If a store state is available, restore from local store.
734
+ // 2. If opened state class is set, set state to opened.
735
+ // 3. Else, initialize default state.
736
+ if (this.store[entry.id]) {
737
+ // Restore drawers to saved inline state.
738
+ if (this.store[entry.id] === 'opened') {
739
+ await entry.open(false, false);
740
+ } else {
741
+ await entry.close(false, false);
538
742
  }
743
+ } else if (entry.el.classList.contains(this.settings.stateOpened)) {
744
+ // Update drawer state.
745
+ entry.state = 'opened';
746
+ } else {
747
+ // Remove transition state classes.
748
+ entry.el.classList.remove(this.settings.stateOpening);
749
+ entry.el.classList.remove(this.settings.stateClosing); // Add closed state class.
750
+
751
+ entry.el.classList.add(this.settings.stateClosed);
539
752
  }
753
+ }
540
754
 
541
- match(mql, drawer) {
542
- if (mql.matches) {
543
- this.parent.switchToDefault(drawer);
755
+ function updateFocusState$1(entry) {
756
+ // Check if there's an active modal
757
+ if (entry.state === 'opened') {
758
+ // Mount the focus trap on the opened drawer.
759
+ if (entry.mode === 'modal') {
760
+ this.focusTrap.mount(entry.dialog, this.settings.selectorFocus);
544
761
  } else {
545
- this.parent.switchToModal(drawer);
762
+ this.focusTrap.focus(entry.dialog, this.settings.selectorFocus);
763
+ }
764
+ } else {
765
+ // Set focus to root trigger and unmount the focus trap.
766
+ if (entry.trigger) {
767
+ entry.trigger.focus();
768
+ entry.trigger = null;
546
769
  }
770
+
771
+ this.focusTrap.unmount();
547
772
  }
773
+ }
548
774
 
549
- getBreakpoint(key) {
550
- let breakpoint = key;
775
+ async function open$2(query, transition, focus = true) {
776
+ // Get the drawer from collection.
777
+ const drawer = getDrawer.call(this, query); // Get the modal configuration.
551
778
 
552
- if (this.parent.settings.breakpoints && this.parent.settings.breakpoints[key]) {
553
- breakpoint = this.parent.settings.breakpoints[key];
554
- } else if (getComputedStyle(document.body).getPropertyValue(this.prefix + key)) {
555
- breakpoint = getComputedStyle(document.body).getPropertyValue(this.prefix + key);
556
- }
779
+ const config = _extends({}, this.settings, drawer.settings); // Add transition parameter to configuration.
557
780
 
558
- return breakpoint;
559
- }
560
781
 
561
- getVariablePrefix() {
562
- let prefix = '--';
563
- prefix += getComputedStyle(document.body).getPropertyValue('--vrembem-variable-prefix');
564
- prefix += 'breakpoint-';
565
- return prefix;
566
- }
782
+ if (transition !== undefined) config.transition = transition; // If drawer is closed.
567
783
 
568
- }
784
+ if (drawer.state === 'closed') {
785
+ // Update drawer state.
786
+ drawer.state = 'opening'; // Run the open transition.
569
787
 
570
- function getDrawer(drawerKey) {
571
- if (typeof drawerKey !== 'string') return drawerKey;
572
- return document.querySelector(`[data-${this.settings.dataDrawer}="${drawerKey}"]`);
573
- }
574
- function drawerNotFound(key) {
575
- return Promise.reject(new Error(`Did not find drawer with key: "${key}"`));
788
+ await openTransition(drawer.el, config); // Update the global state if mode is modal.
789
+
790
+ if (drawer.mode === 'modal') updateGlobalState(true, config); // Update drawer state.
791
+
792
+ drawer.state = 'opened';
793
+ } // Set focus to the drawer element if the focus param is true.
794
+
795
+
796
+ if (focus) {
797
+ updateFocusState$1.call(this, drawer);
798
+ } // Dispatch custom opened event.
799
+
800
+
801
+ drawer.el.dispatchEvent(new CustomEvent(config.customEventPrefix + 'opened', {
802
+ detail: this,
803
+ bubbles: true
804
+ })); // Return the drawer.
805
+
806
+ return drawer;
576
807
  }
577
808
 
578
- async function close$2(drawerKey) {
579
- const drawer = this.getDrawer(drawerKey);
580
- if (!drawer) return drawerNotFound(drawerKey);
809
+ async function close$2(query, transition, focus = true) {
810
+ // Get the drawer from collection.
811
+ const drawer = getDrawer.call(this, query); // Get the modal configuration.
581
812
 
582
- if (hasClass(drawer, this.settings.stateOpened)) {
583
- this.working = true;
813
+ const config = _extends({}, this.settings, drawer.settings); // Add transition parameter to configuration.
584
814
 
585
- if (hasClass(drawer, this.settings.classModal)) {
586
- setInert(false, this.settings.selectorInert);
587
- setOverflowHidden(false, this.settings.selectorOverflow);
588
- }
589
815
 
590
- await closeTransition(drawer, this.settings);
591
- this.stateSave(drawer);
592
- focusTrigger(this);
593
- this.focusTrap.destroy();
594
- drawer.dispatchEvent(new CustomEvent(this.settings.customEventPrefix + 'closed', {
816
+ if (transition !== undefined) config.transition = transition; // If drawer is opened.
817
+
818
+ if (drawer.state === 'opened') {
819
+ // Update drawer state.
820
+ drawer.state = 'closing'; // Remove focus from active element.
821
+
822
+ document.activeElement.blur(); // Run the close transition.
823
+
824
+ await closeTransition(drawer.el, config); // Update the global state if mode is modal.
825
+
826
+ if (drawer.mode === 'modal') updateGlobalState(false, config); // Set focus to the trigger element if the focus param is true.
827
+
828
+ if (focus) {
829
+ updateFocusState$1.call(this, drawer);
830
+ } // Update drawer state.
831
+
832
+
833
+ drawer.state = 'closed'; // Dispatch custom closed event.
834
+
835
+ drawer.el.dispatchEvent(new CustomEvent(config.customEventPrefix + 'closed', {
595
836
  detail: this,
596
837
  bubbles: true
597
838
  }));
598
- this.working = false;
599
- return drawer;
839
+ } // Return the drawer.
840
+
841
+
842
+ return drawer;
843
+ }
844
+
845
+ async function toggle(query, transition, focus) {
846
+ // Get the drawer from collection.
847
+ const drawer = getDrawer.call(this, query); // Open or close the drawer based on its current state.
848
+
849
+ if (drawer.state === 'closed') {
850
+ return open$2.call(this, drawer, transition, focus);
600
851
  } else {
601
- return drawer;
852
+ return close$2.call(this, drawer, transition, focus);
602
853
  }
603
854
  }
604
855
 
605
- function handlerClick$1(event) {
606
- // Working catch
607
- if (this.working) return; // Toggle data trigger
856
+ function switchMode(entry) {
857
+ switch (entry.mode) {
858
+ case 'inline':
859
+ return toInline.call(this, entry);
608
860
 
609
- let trigger = event.target.closest(`[data-${this.settings.dataToggle}]`);
861
+ case 'modal':
862
+ return toModal.call(this, entry);
610
863
 
611
- if (trigger) {
612
- const selector = trigger.getAttribute(`data-${this.settings.dataToggle}`);
613
- this.memory.trigger = trigger;
614
- this.toggle(selector);
615
- event.preventDefault();
616
- return;
617
- } // Open data trigger
864
+ default:
865
+ throw new Error(`"${entry.mode}" is not a valid drawer mode.`);
866
+ }
867
+ }
618
868
 
869
+ async function toInline(entry) {
870
+ // Remove the modal class.
871
+ entry.el.classList.remove(entry.getSetting('classModal')); // Remove the aria-modal attribute.
619
872
 
620
- trigger = event.target.closest(`[data-${this.settings.dataOpen}]`);
873
+ entry.dialog.removeAttribute('aria-modal'); // Update the global state.
621
874
 
622
- if (trigger) {
623
- const selector = trigger.getAttribute(`data-${this.settings.dataOpen}`);
624
- this.memory.trigger = trigger;
625
- this.open(selector);
626
- event.preventDefault();
627
- return;
628
- } // Close data trigger
875
+ updateGlobalState(false, _extends({}, this.settings, entry.settings)); // Remove any focus traps.
629
876
 
877
+ this.focusTrap.unmount(); // Setup initial state.
630
878
 
631
- trigger = event.target.closest(`[data-${this.settings.dataClose}]`);
879
+ await initialState.call(this, entry); // Dispatch custom switch event.
632
880
 
633
- if (trigger) {
634
- const selector = trigger.getAttribute(`data-${this.settings.dataClose}`);
881
+ entry.el.dispatchEvent(new CustomEvent(entry.getSetting('customEventPrefix') + 'switchMode', {
882
+ detail: this,
883
+ bubbles: true
884
+ })); // Return the entry.
635
885
 
636
- if (selector) {
637
- this.memory.trigger = trigger;
638
- this.close(selector);
639
- } else {
640
- const target = event.target.closest(`[data-${this.settings.dataDrawer}]`);
641
- if (target) this.close(target);
642
- }
886
+ return entry;
887
+ }
643
888
 
644
- event.preventDefault();
645
- return;
646
- } // Screen modal trigger
889
+ async function toModal(entry) {
890
+ // Get the drawer configuration.
891
+ // Add the modal class.
892
+ entry.el.classList.add(entry.getSetting('classModal')); // Set aria-modal attribute to true.
647
893
 
894
+ entry.dialog.setAttribute('aria-modal', 'true'); // If there isn't a stored state but also has the opened state class...
648
895
 
649
- if (event.target.hasAttribute(`data-${this.settings.dataDrawer}`)) {
650
- this.close(event.target);
651
- return;
652
- }
653
- }
654
- function handlerKeydown$1(event) {
655
- // Working catch
656
- if (this.working) return;
896
+ if (!this.store[entry.id] && entry.el.classList.contains(entry.getSetting('stateOpened'))) {
897
+ // Save the opened state in local store.
898
+ this.store[entry.id] = 'opened';
899
+ } // Modal drawer defaults to closed state.
657
900
 
658
- if (event.key === 'Escape') {
659
- const target = document.querySelector(`.${this.settings.classModal}.${this.settings.stateOpened}`);
660
901
 
661
- if (target) {
662
- this.close(target);
663
- }
664
- }
902
+ await close$2.call(this, entry, false, false); // Dispatch custom switch event.
903
+
904
+ entry.el.dispatchEvent(new CustomEvent(entry.getSetting('customEventPrefix') + 'switchMode', {
905
+ detail: this,
906
+ bubbles: true
907
+ })); // Return the entry.
908
+
909
+ return entry;
665
910
  }
666
911
 
667
- async function open$2(drawerKey) {
668
- const drawer = this.getDrawer(drawerKey);
669
- if (!drawer) return drawerNotFound(drawerKey);
912
+ async function register$2(el, dialog) {
913
+ // Deregister entry incase it has already been registered.
914
+ await deregister$2.call(this, el, false); // Save root this for use inside methods API.
670
915
 
671
- if (!hasClass(drawer, this.settings.stateOpened)) {
672
- this.working = true;
673
- const isModal = hasClass(drawer, this.settings.classModal);
916
+ const root = this; // Create an instance of the Breakpoint class.
674
917
 
675
- if (isModal) {
676
- setOverflowHidden(true, this.settings.selectorOverflow);
677
- }
918
+ const breakpoint = new Breakpoint(); // Setup methods API.
678
919
 
679
- await openTransition(drawer, this.settings);
680
- this.stateSave(drawer);
920
+ const methods = {
921
+ open(transition, focus) {
922
+ return open$2.call(root, this, transition, focus);
923
+ },
681
924
 
682
- if (isModal) {
683
- this.focusTrap.init(drawer);
684
- setInert(true, this.settings.selectorInert);
685
- }
925
+ close(transition, focus) {
926
+ return close$2.call(root, this, transition, focus);
927
+ },
686
928
 
687
- focusTarget(drawer, this.settings);
688
- drawer.dispatchEvent(new CustomEvent(this.settings.customEventPrefix + 'opened', {
689
- detail: this,
690
- bubbles: true
691
- }));
692
- this.working = false;
693
- return drawer;
694
- } else {
695
- focusTarget(drawer, this.settings);
696
- return drawer;
697
- }
698
- }
929
+ toggle(transition, focus) {
930
+ return toggle.call(root, this, transition, focus);
931
+ },
932
+
933
+ deregister() {
934
+ return deregister$2.call(root, this);
935
+ },
699
936
 
700
- function stateSet(settings) {
701
- // If save state is disabled
702
- if (!settings.stateSave) return stateClear(settings); // If there isn't an existing state to set
937
+ mountBreakpoint() {
938
+ const value = this.breakpoint;
939
+ const handler = this.handleBreakpoint.bind(this);
940
+ breakpoint.mount(value, handler);
941
+ return this;
942
+ },
703
943
 
704
- const storageCheck = localStorage.getItem(settings.stateKey);
944
+ unmountBreakpoint() {
945
+ breakpoint.unmount();
946
+ return this;
947
+ },
705
948
 
706
- if (!storageCheck || storageCheck && Object.keys(JSON.parse(storageCheck)).length === 0) {
707
- return stateSave(null, settings);
708
- } // Set the existing state
949
+ handleBreakpoint(event) {
950
+ this.mode = event.matches ? 'inline' : 'modal';
951
+ return this;
952
+ },
709
953
 
954
+ getSetting(key) {
955
+ return key in this.settings ? this.settings[key] : root.settings[key];
956
+ }
710
957
 
711
- const state = JSON.parse(localStorage.getItem(settings.stateKey));
712
- Object.keys(state).forEach(key => {
713
- const item = document.querySelector(`[data-${settings.dataDrawer}="${key}"]`);
714
- if (!item) return;
715
- state[key] == settings.stateOpened ? addClass(item, settings.stateOpened) : removeClass(item, settings.stateOpened);
716
- });
717
- return state;
718
- }
719
- function stateSave(target, settings) {
720
- // If save state is disabled
721
- if (!settings.stateSave) return stateClear(settings); // Get the currently saved object if it exists
958
+ }; // Setup the drawer object.
722
959
 
723
- const state = localStorage.getItem(settings.stateKey) ? JSON.parse(localStorage.getItem(settings.stateKey)) : {}; // Are we saving a single target or the entire suite?
960
+ const entry = _extends({
961
+ id: el.id,
962
+ el: el,
963
+ dialog: dialog,
964
+ trigger: null,
965
+ settings: getConfig$1(el, this.settings.dataConfig),
724
966
 
725
- const drawers = target ? [target] : document.querySelectorAll(`[data-${settings.dataDrawer}]`); // Loop through drawers and save their states
967
+ get breakpoint() {
968
+ return getBreakpoint.call(root, el);
969
+ },
726
970
 
727
- drawers.forEach(el => {
728
- if (hasClass(el, settings.classModal)) return;
729
- const drawerKey = el.getAttribute(`data-${settings.dataDrawer}`);
730
- state[drawerKey] = hasClass(el, settings.stateOpened) ? settings.stateOpened : settings.stateClosed;
731
- }); // Save to localStorage and return the state
971
+ get state() {
972
+ return __state;
973
+ },
732
974
 
733
- localStorage.setItem(settings.stateKey, JSON.stringify(state));
734
- return state;
735
- }
736
- function stateClear(settings) {
737
- if (localStorage.getItem(settings.stateKey)) {
738
- localStorage.removeItem(settings.stateKey);
739
- }
975
+ set state(value) {
976
+ __state = value; // Save 'opened' and 'closed' states to store if mode is inline.
740
977
 
741
- return {};
742
- }
978
+ if (value === 'opened' || value === 'closed') {
979
+ if (this.mode === 'inline') root.store[this.id] = this.state;
980
+ }
981
+ },
743
982
 
744
- async function switchToModal(drawerKey) {
745
- // Initial guards
746
- const drawer = this.getDrawer(drawerKey);
747
- if (!drawer) return drawerNotFound(drawerKey);
748
- if (hasClass(drawer, this.settings.classModal)) return; // Enable modal state
983
+ get mode() {
984
+ return __mode;
985
+ },
749
986
 
750
- addClass(drawer, this.settings.classModal);
751
- addClass(drawer, this.settings.stateClosed);
752
- removeClass(drawer, this.settings.stateOpened); // Dispatch custom event
987
+ set mode(value) {
988
+ __mode = value;
989
+ switchMode.call(root, this);
990
+ }
753
991
 
754
- drawer.dispatchEvent(new CustomEvent(this.settings.customEventPrefix + 'toModal', {
755
- bubbles: true
756
- }));
757
- return drawer;
758
- }
759
- async function switchToDefault(drawerKey) {
760
- // Initial guards
761
- const drawer = this.getDrawer(drawerKey);
762
- if (!drawer) return drawerNotFound(drawerKey);
763
- if (!hasClass(drawer, this.settings.classModal)) return; // Tear down modal state
992
+ }, methods); // Create the state var with the initial state.
764
993
 
765
- setInert(false, this.settings.selectorInert);
766
- setOverflowHidden(false, this.settings.selectorOverflow);
767
- removeClass(drawer, this.settings.classModal);
768
- this.focusTrap.destroy(); // Restore drawers saved state
769
994
 
770
- drawerKey = drawer.getAttribute(`data-${this.settings.dataDrawer}`);
771
- const drawerState = this.state[drawerKey];
995
+ let __state = el.classList.contains(entry.getSetting('stateOpened')) ? 'opened' : 'closed'; // Create the mode var with the initial mode.
772
996
 
773
- if (drawerState == this.settings.stateOpened) {
774
- addClass(drawer, this.settings.stateOpened);
775
- removeClass(drawer, this.settings.stateClosed);
776
- } // Dispatch custom event
777
997
 
998
+ let __mode = el.classList.contains(entry.getSetting('classModal')) ? 'modal' : 'inline'; // Setup mode specific attributes.
999
+
1000
+
1001
+ if (entry.mode === 'modal') {
1002
+ // Set aria-modal attribute to true.
1003
+ entry.dialog.setAttribute('aria-modal', 'true');
1004
+ } else {
1005
+ // Remove the aria-modal attribute.
1006
+ entry.dialog.removeAttribute('aria-modal');
1007
+ } // Set tabindex="-1" so dialog is focusable via JS or click.
1008
+
1009
+
1010
+ if (entry.getSetting('setTabindex')) {
1011
+ entry.dialog.setAttribute('tabindex', '-1');
1012
+ } // Add entry to collection.
778
1013
 
779
- drawer.dispatchEvent(new CustomEvent(this.settings.customEventPrefix + 'toDefault', {
780
- bubbles: true
781
- }));
782
- return drawer;
783
- }
784
1014
 
785
- async function toggle(drawerKey) {
786
- const drawer = this.getDrawer(drawerKey);
787
- if (!drawer) return drawerNotFound(drawerKey);
788
- const isClosed = !hasClass(drawer, this.settings.stateOpened);
1015
+ this.collection.push(entry); // If the entry has a breakpoint...
789
1016
 
790
- if (isClosed) {
791
- return this.open(drawer);
1017
+ if (entry.breakpoint) {
1018
+ // Mount media query breakpoint functionality.
1019
+ entry.mountBreakpoint();
792
1020
  } else {
793
- return this.close(drawer);
794
- }
1021
+ // Else, Setup initial state.
1022
+ await initialState.call(this, entry);
1023
+ } // Return the registered entry.
1024
+
1025
+
1026
+ return entry;
795
1027
  }
796
1028
 
797
- class Drawer {
1029
+ var _handleClick$1 = /*#__PURE__*/_classPrivateFieldLooseKey("handleClick");
1030
+
1031
+ var _handleKeydown$2 = /*#__PURE__*/_classPrivateFieldLooseKey("handleKeydown");
1032
+
1033
+ class Drawer extends Collection {
798
1034
  constructor(options) {
1035
+ super();
1036
+ Object.defineProperty(this, _handleClick$1, {
1037
+ writable: true,
1038
+ value: void 0
1039
+ });
1040
+ Object.defineProperty(this, _handleKeydown$2, {
1041
+ writable: true,
1042
+ value: void 0
1043
+ });
799
1044
  this.defaults = defaults$2;
800
1045
  this.settings = _extends({}, this.defaults, options);
801
- this.working = false;
802
- this.memory = {};
803
- this.state = {};
804
- this.focusTrap = new FocusTrap();
805
- this.breakpoint = new Breakpoint(this);
806
- this.__handlerClick = handlerClick$1.bind(this);
807
- this.__handlerKeydown = handlerKeydown$1.bind(this);
1046
+ this.focusTrap = new FocusTrap(); // Setup local store for inline drawer state management.
1047
+
1048
+ this.store = localStore(this.settings.storeKey, this.settings.store);
1049
+ _classPrivateFieldLooseBase(this, _handleClick$1)[_handleClick$1] = handleClick$2.bind(this);
1050
+ _classPrivateFieldLooseBase(this, _handleKeydown$2)[_handleKeydown$2] = handleKeydown$2.bind(this);
808
1051
  if (this.settings.autoInit) this.init();
809
1052
  }
810
1053
 
811
- init(options = null) {
812
- if (options) this.settings = _extends({}, this.settings, options);
813
- this.stateSet();
1054
+ get activeModal() {
1055
+ return this.collection.find(entry => {
1056
+ return entry.state === 'opened' && entry.mode === 'modal';
1057
+ });
1058
+ }
814
1059
 
815
- if (this.settings.setTabindex) {
816
- this.setTabindex();
817
- }
1060
+ async init(options = null) {
1061
+ // Update settings with passed options.
1062
+ if (options) this.settings = _extends({}, this.settings, options); // Get all the modals.
818
1063
 
819
- this.breakpoint.init();
1064
+ const drawers = document.querySelectorAll(this.settings.selectorDrawer); // Register the collections array with modal instances.
1065
+
1066
+ await this.registerCollection(drawers); // If eventListeners are enabled, init event listeners.
820
1067
 
821
1068
  if (this.settings.eventListeners) {
822
1069
  this.initEventListeners();
823
1070
  }
1071
+
1072
+ return this;
824
1073
  }
825
1074
 
826
- destroy() {
827
- this.breakpoint.destroy();
828
- this.memory = {};
829
- this.state = {};
830
- localStorage.removeItem(this.settings.stateKey);
1075
+ async destroy() {
1076
+ // Remove all entries from the collection.
1077
+ await this.deregisterCollection(); // If eventListeners are enabled, init event listeners.
831
1078
 
832
1079
  if (this.settings.eventListeners) {
833
1080
  this.destroyEventListeners();
834
1081
  }
835
- }
836
- /**
837
- * Event listeners
838
- */
839
1082
 
1083
+ return this;
1084
+ }
840
1085
 
841
1086
  initEventListeners() {
842
- document.addEventListener('click', this.__handlerClick, false);
843
- document.addEventListener('touchend', this.__handlerClick, false);
844
- document.addEventListener('keydown', this.__handlerKeydown, false);
1087
+ document.addEventListener('click', _classPrivateFieldLooseBase(this, _handleClick$1)[_handleClick$1], false);
1088
+ document.addEventListener('touchend', _classPrivateFieldLooseBase(this, _handleClick$1)[_handleClick$1], false);
1089
+ document.addEventListener('keydown', _classPrivateFieldLooseBase(this, _handleKeydown$2)[_handleKeydown$2], false);
845
1090
  }
846
1091
 
847
1092
  destroyEventListeners() {
848
- document.removeEventListener('click', this.__handlerClick, false);
849
- document.removeEventListener('touchend', this.__handlerClick, false);
850
- document.removeEventListener('keydown', this.__handlerKeydown, false);
851
- }
852
- /**
853
- * Helpers
854
- */
855
-
856
-
857
- getDrawer(drawerKey) {
858
- return getDrawer.call(this, drawerKey);
859
- }
860
-
861
- setTabindex() {
862
- return setTabindex(`
863
- [data-${this.settings.dataDrawer}]
864
- [data-${this.settings.dataDialog}]
865
- `);
866
- }
867
- /**
868
- * Save state functionality
869
- */
870
-
871
-
872
- stateSet() {
873
- this.state = stateSet(this.settings);
874
- }
875
-
876
- stateSave(target = null) {
877
- this.state = stateSave(target, this.settings);
1093
+ document.removeEventListener('click', _classPrivateFieldLooseBase(this, _handleClick$1)[_handleClick$1], false);
1094
+ document.removeEventListener('touchend', _classPrivateFieldLooseBase(this, _handleClick$1)[_handleClick$1], false);
1095
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleKeydown$2)[_handleKeydown$2], false);
878
1096
  }
879
1097
 
880
- stateClear() {
881
- this.state = stateClear(this.settings);
882
- }
883
- /**
884
- * SwitchTo functionality
885
- */
886
-
887
-
888
- switchToDefault(drawerKey) {
889
- return switchToDefault.call(this, drawerKey);
1098
+ register(query) {
1099
+ const els = getDrawerElements.call(this, query);
1100
+ if (els.error) return Promise.reject(els.error);
1101
+ return register$2.call(this, els.drawer, els.dialog);
890
1102
  }
891
1103
 
892
- switchToModal(drawerKey) {
893
- return switchToModal.call(this, drawerKey);
1104
+ deregister(query) {
1105
+ const entry = this.get(getDrawerID.call(this, query));
1106
+ return deregister$2.call(this, entry);
894
1107
  }
895
- /**
896
- * Change state functionality
897
- */
898
1108
 
899
-
900
- toggle(drawerKey) {
901
- return toggle.call(this, drawerKey);
1109
+ open(id, transition, focus) {
1110
+ return open$2.call(this, id, transition, focus);
902
1111
  }
903
1112
 
904
- open(drawerKey) {
905
- return open$2.call(this, drawerKey);
1113
+ close(id, transition, focus) {
1114
+ return close$2.call(this, id, transition, focus);
906
1115
  }
907
1116
 
908
- close(drawerKey) {
909
- return close$2.call(this, drawerKey);
1117
+ toggle(id, transition, focus) {
1118
+ return toggle.call(this, id, transition, focus);
910
1119
  }
911
1120
 
912
1121
  }
@@ -939,38 +1148,6 @@ var defaults$1 = {
939
1148
  transition: true
940
1149
  };
941
1150
 
942
- function updateGlobalState() {
943
- // Set inert state based on if a modal is active.
944
- setInert(!!this.active, this.settings.selectorInert); // Set overflow state based on if a modal is active.
945
-
946
- setOverflowHidden(!!this.active, this.settings.selectorOverflow); // Update the z-index of the stack.
947
-
948
- updateStackIndex(this.stack);
949
- }
950
- function updateFocusState() {
951
- // Check if there's an active modal
952
- if (this.active) {
953
- // Set focus and init focus trap on active modal.
954
- focusTarget(this.active.target, this.settings);
955
- this.focusTrap.init(this.active.target);
956
- } else {
957
- // Set focus to root trigger and destroy focus trap.
958
- focusTrigger(this);
959
- this.focusTrap.destroy();
960
- }
961
- }
962
- function updateStackIndex(stack) {
963
- stack.forEach((entry, index) => {
964
- entry.target.style.zIndex = null;
965
- const value = getComputedStyle(entry.target)['z-index'];
966
- entry.target.style.zIndex = parseInt(value) + index + 1;
967
- });
968
- }
969
- function getConfig$1(el) {
970
- const string = el.getAttribute(`data-${this.settings.dataConfig}`) || '';
971
- const json = string.replace(/'/g, '"');
972
- return json ? JSON.parse(json) : {};
973
- }
974
1151
  function getModal(query) {
975
1152
  // Get the entry from collection.
976
1153
  const entry = typeof query === 'string' ? this.get(query) : this.get(query.id); // Return entry if it was resolved, otherwise throw error.
@@ -978,9 +1155,10 @@ function getModal(query) {
978
1155
  if (entry) {
979
1156
  return entry;
980
1157
  } else {
981
- throw new Error(`Modal not found in collection with id of "${query}".`);
1158
+ throw new Error(`Modal not found in collection with id of "${query.id || query}".`);
982
1159
  }
983
1160
  }
1161
+
984
1162
  function getModalID(obj) {
985
1163
  // If it's a string, return the string.
986
1164
  if (typeof obj === 'string') {
@@ -996,7 +1174,7 @@ function getModalID(obj) {
996
1174
  } // If it's a modal replace trigger, return data value.
997
1175
  else if (obj.hasAttribute(`data-${this.settings.dataReplace}`)) {
998
1176
  return obj.getAttribute(`data-${this.settings.dataReplace}`);
999
- } // If it's a modal target, return the id.
1177
+ } // If it's a modal element, return the id.
1000
1178
  else if (obj.closest(this.settings.selectorModal)) {
1001
1179
  obj = obj.closest(this.settings.selectorModal);
1002
1180
  return obj.id || false;
@@ -1008,14 +1186,15 @@ function getModalID(obj) {
1008
1186
  } // Return false if no id was found.
1009
1187
  else return false;
1010
1188
  }
1189
+
1011
1190
  function getModalElements(query) {
1012
1191
  const id = getModalID.call(this, query);
1013
1192
 
1014
1193
  if (id) {
1015
- const target = document.querySelector(`#${id}`);
1016
- const dialog = target ? target.querySelector(this.settings.selectorDialog) : null;
1194
+ const modal = document.querySelector(`#${id}`);
1195
+ const dialog = modal ? modal.querySelector(this.settings.selectorDialog) : null;
1017
1196
 
1018
- if (!target && !dialog) {
1197
+ if (!modal && !dialog) {
1019
1198
  return {
1020
1199
  error: new Error(`No modal elements found using the ID: "${id}".`)
1021
1200
  };
@@ -1025,7 +1204,7 @@ function getModalElements(query) {
1025
1204
  };
1026
1205
  } else {
1027
1206
  return {
1028
- target,
1207
+ modal,
1029
1208
  dialog
1030
1209
  };
1031
1210
  }
@@ -1036,7 +1215,31 @@ function getModalElements(query) {
1036
1215
  }
1037
1216
  }
1038
1217
 
1039
- async function handleClick(event) {
1218
+ function updateFocusState() {
1219
+ // Check if there's an active modal
1220
+ if (this.active) {
1221
+ // Mount the focus trap on the active modal.
1222
+ this.focusTrap.mount(this.active.dialog, this.settings.selectorFocus);
1223
+ } else {
1224
+ // Set focus to root trigger and unmount the focus trap.
1225
+ if (this.trigger) {
1226
+ this.trigger.focus();
1227
+ this.trigger = null;
1228
+ }
1229
+
1230
+ this.focusTrap.unmount();
1231
+ }
1232
+ }
1233
+
1234
+ function updateStackIndex(stack) {
1235
+ stack.forEach((entry, index) => {
1236
+ entry.el.style.zIndex = null;
1237
+ const value = getComputedStyle(entry.el)['z-index'];
1238
+ entry.el.style.zIndex = parseInt(value) + index + 1;
1239
+ });
1240
+ }
1241
+
1242
+ async function handleClick$1(event) {
1040
1243
  // If an open or replace button was clicked, open or replace the modal.
1041
1244
  let trigger = event.target.closest(`[data-${this.settings.dataOpen}], [data-${this.settings.dataReplace}]`);
1042
1245
 
@@ -1044,7 +1247,7 @@ async function handleClick(event) {
1044
1247
  event.preventDefault(); // Save the trigger if it's not coming from inside a modal.
1045
1248
 
1046
1249
  const fromModal = event.target.closest(this.settings.selectorModal);
1047
- if (!fromModal) this.memory.trigger = trigger; // Get the modal.
1250
+ if (!fromModal) this.trigger = trigger; // Get the modal.
1048
1251
 
1049
1252
  const modal = this.get(getModalID.call(this, trigger)); // Depending on the button type, either open or replace the modal.
1050
1253
 
@@ -1067,7 +1270,7 @@ async function handleClick(event) {
1067
1270
  return this.close(getModalID.call(this, event.target));
1068
1271
  }
1069
1272
  }
1070
- function handleKeydown(event) {
1273
+ function handleKeydown$1(event) {
1071
1274
  // If escape key was pressed.
1072
1275
  if (event.key === 'Escape') {
1073
1276
  // If a modal is opened and not required, close the modal.
@@ -1119,7 +1322,7 @@ async function deregister$1(obj, close = true) {
1119
1322
  return this.collection;
1120
1323
  }
1121
1324
 
1122
- async function open$1(query, transition, bulk = false) {
1325
+ async function open$1(query, transition, focus = true) {
1123
1326
  // Get the modal from collection.
1124
1327
  const modal = getModal.call(this, query); // Get the modal configuration.
1125
1328
 
@@ -1144,24 +1347,24 @@ async function open$1(query, transition, bulk = false) {
1144
1347
  // Update modal state.
1145
1348
  modal.state = 'opening'; // Apply z-index styles based on stack length.
1146
1349
 
1147
- modal.target.style.zIndex = null;
1148
- const value = getComputedStyle(modal.target)['z-index'];
1149
- modal.target.style.zIndex = parseInt(value) + this.stack.length + 1; // Store modal in stack array.
1350
+ modal.el.style.zIndex = null;
1351
+ const value = getComputedStyle(modal.el)['z-index'];
1352
+ modal.el.style.zIndex = parseInt(value) + this.stack.length + 1; // Store modal in stack array.
1150
1353
 
1151
1354
  this.stack.push(modal); // Run the open transition.
1152
1355
 
1153
- await openTransition(modal.target, config); // Update modal state.
1356
+ await openTransition(modal.el, config); // Update modal state.
1154
1357
 
1155
1358
  modal.state = 'opened';
1156
- } // Update the focus state if this is not a bulk action.
1359
+ } // Update focus if the focus param is true.
1157
1360
 
1158
1361
 
1159
- if (!bulk) {
1362
+ if (focus) {
1160
1363
  updateFocusState.call(this);
1161
1364
  } // Dispatch custom opened event.
1162
1365
 
1163
1366
 
1164
- modal.target.dispatchEvent(new CustomEvent(config.customEventPrefix + 'opened', {
1367
+ modal.el.dispatchEvent(new CustomEvent(config.customEventPrefix + 'opened', {
1165
1368
  detail: this,
1166
1369
  bubbles: true
1167
1370
  })); // Return the modal.
@@ -1169,7 +1372,7 @@ async function open$1(query, transition, bulk = false) {
1169
1372
  return modal;
1170
1373
  }
1171
1374
 
1172
- async function close$1(query, transition, bulk = false) {
1375
+ async function close$1(query, transition, focus = true) {
1173
1376
  // Get the modal from collection, or top modal in stack if no query is provided.
1174
1377
  const modal = query ? getModal.call(this, query) : this.active; // If a modal exists and its state is opened.
1175
1378
 
@@ -1184,24 +1387,24 @@ async function close$1(query, transition, bulk = false) {
1184
1387
 
1185
1388
  document.activeElement.blur(); // Run the close transition.
1186
1389
 
1187
- await closeTransition(modal.target, config); // Remove z-index styles.
1390
+ await closeTransition(modal.el, config); // Remove z-index styles.
1188
1391
 
1189
- modal.target.style.zIndex = null; // Get index of modal in stack array.
1392
+ modal.el.style.zIndex = null; // Get index of modal in stack array.
1190
1393
 
1191
1394
  const index = this.stack.findIndex(entry => {
1192
1395
  return entry.id === modal.id;
1193
1396
  }); // Remove modal from stack array.
1194
1397
 
1195
- this.stack.splice(index, 1); // Update the focus state if this is not a bulk action.
1398
+ this.stack.splice(index, 1); // Update focus if the focus param is true.
1196
1399
 
1197
- if (!bulk) {
1400
+ if (focus) {
1198
1401
  updateFocusState.call(this);
1199
1402
  } // Update modal state.
1200
1403
 
1201
1404
 
1202
1405
  modal.state = 'closed'; // Dispatch custom closed event.
1203
1406
 
1204
- modal.target.dispatchEvent(new CustomEvent(config.customEventPrefix + 'closed', {
1407
+ modal.el.dispatchEvent(new CustomEvent(config.customEventPrefix + 'closed', {
1205
1408
  detail: this,
1206
1409
  bubbles: true
1207
1410
  }));
@@ -1217,7 +1420,7 @@ async function closeAll$1(exclude, transition) {
1217
1420
  if (exclude && exclude === modal.id) {
1218
1421
  Promise.resolve();
1219
1422
  } else {
1220
- result.push(await close$1.call(this, modal, transition, true));
1423
+ result.push(await close$1.call(this, modal, transition, false));
1221
1424
  }
1222
1425
 
1223
1426
  modal.trigger = null;
@@ -1225,7 +1428,7 @@ async function closeAll$1(exclude, transition) {
1225
1428
  return result;
1226
1429
  }
1227
1430
 
1228
- async function replace(query, transition) {
1431
+ async function replace(query, transition, focus = true) {
1229
1432
  // Get the modal from collection.
1230
1433
  const modal = getModal.call(this, query); // Setup results for return.
1231
1434
 
@@ -1237,13 +1440,16 @@ async function replace(query, transition) {
1237
1440
  resultClosed = await closeAll$1.call(this, modal.id, transition);
1238
1441
  } else {
1239
1442
  // If modal is closed, close all and open replacement at the same time.
1240
- resultOpened = open$1.call(this, modal, transition, true);
1443
+ resultOpened = open$1.call(this, modal, transition, false);
1241
1444
  resultClosed = closeAll$1.call(this, false, transition);
1242
1445
  await Promise.all([resultOpened, resultClosed]);
1243
- } // Update the focus state.
1446
+ } // Update focus if the focus param is true.
1447
+
1244
1448
 
1449
+ if (focus) {
1450
+ updateFocusState.call(this);
1451
+ } // Return the modals there were opened and closed.
1245
1452
 
1246
- updateFocusState.call(this); // Return the modals there were opened and closed.
1247
1453
 
1248
1454
  return {
1249
1455
  opened: resultOpened,
@@ -1251,23 +1457,23 @@ async function replace(query, transition) {
1251
1457
  };
1252
1458
  }
1253
1459
 
1254
- async function register$1(target, dialog) {
1460
+ async function register$1(el, dialog) {
1255
1461
  // Deregister entry incase it has already been registered.
1256
- await deregister$1.call(this, target, false); // Save root this for use inside methods API.
1462
+ await deregister$1.call(this, el, false); // Save root this for use inside methods API.
1257
1463
 
1258
1464
  const root = this; // Setup methods API.
1259
1465
 
1260
1466
  const methods = {
1261
- open(transition) {
1262
- return open$1.call(root, this, transition);
1467
+ open(transition, focus) {
1468
+ return open$1.call(root, this, transition, focus);
1263
1469
  },
1264
1470
 
1265
- close(transition) {
1266
- return close$1.call(root, this, transition);
1471
+ close(transition, focus) {
1472
+ return close$1.call(root, this, transition, focus);
1267
1473
  },
1268
1474
 
1269
- replace(transition) {
1270
- return replace.call(root, this, transition);
1475
+ replace(transition, focus) {
1476
+ return replace.call(root, this, transition, focus);
1271
1477
  },
1272
1478
 
1273
1479
  deregister() {
@@ -1276,20 +1482,20 @@ async function register$1(target, dialog) {
1276
1482
 
1277
1483
  teleport(ref = this.getSetting('teleport'), method = this.getSetting('teleportMethod')) {
1278
1484
  if (!this.returnRef) {
1279
- this.returnRef = teleport(this.target, ref, method);
1280
- return this.target;
1485
+ this.returnRef = teleport(this.el, ref, method);
1486
+ return this.el;
1281
1487
  } else {
1282
- console.error('Element has already been teleported:', this.target);
1488
+ console.error('Element has already been teleported:', this.el);
1283
1489
  return false;
1284
1490
  }
1285
1491
  },
1286
1492
 
1287
1493
  teleportReturn() {
1288
1494
  if (this.returnRef) {
1289
- this.returnRef = teleport(this.target, this.returnRef);
1290
- return this.target;
1495
+ this.returnRef = teleport(this.el, this.returnRef);
1496
+ return this.el;
1291
1497
  } else {
1292
- console.error('No return reference found:', this.target);
1498
+ console.error('No return reference found:', this.el);
1293
1499
  return false;
1294
1500
  }
1295
1501
  },
@@ -1301,12 +1507,12 @@ async function register$1(target, dialog) {
1301
1507
  }; // Setup the modal object.
1302
1508
 
1303
1509
  const entry = _extends({
1304
- id: target.id,
1510
+ id: el.id,
1305
1511
  state: 'closed',
1306
- settings: getConfig$1.call(this, target),
1307
- target: target,
1512
+ el: el,
1308
1513
  dialog: dialog,
1309
- returnRef: null
1514
+ returnRef: null,
1515
+ settings: getConfig$1(el, this.settings.dataConfig)
1310
1516
  }, methods); // Set aria-modal attribute to true.
1311
1517
 
1312
1518
 
@@ -1329,42 +1535,55 @@ async function register$1(target, dialog) {
1329
1535
 
1330
1536
  this.collection.push(entry); // Setup initial state.
1331
1537
 
1332
- if (entry.target.classList.contains(this.settings.stateOpened)) {
1333
- // Open modal with transitions disabled.
1334
- entry.open(false);
1538
+ if (entry.el.classList.contains(this.settings.stateOpened)) {
1539
+ // Open entry with transitions disabled.
1540
+ await entry.open(false);
1335
1541
  } else {
1336
1542
  // Remove transition state classes.
1337
- entry.target.classList.remove(this.settings.stateOpening);
1338
- entry.target.classList.remove(this.settings.stateClosing); // Add closed state class.
1543
+ entry.el.classList.remove(this.settings.stateOpening);
1544
+ entry.el.classList.remove(this.settings.stateClosing); // Add closed state class.
1339
1545
 
1340
- entry.target.classList.add(this.settings.stateClosed);
1546
+ entry.el.classList.add(this.settings.stateClosed);
1341
1547
  } // Return the registered entry.
1342
1548
 
1343
1549
 
1344
1550
  return entry;
1345
1551
  }
1346
1552
 
1553
+ var _handleClick = /*#__PURE__*/_classPrivateFieldLooseKey("handleClick");
1554
+
1555
+ var _handleKeydown$1 = /*#__PURE__*/_classPrivateFieldLooseKey("handleKeydown");
1556
+
1347
1557
  class Modal extends Collection {
1348
1558
  constructor(options) {
1349
1559
  super();
1560
+ Object.defineProperty(this, _handleClick, {
1561
+ writable: true,
1562
+ value: void 0
1563
+ });
1564
+ Object.defineProperty(this, _handleKeydown$1, {
1565
+ writable: true,
1566
+ value: void 0
1567
+ });
1350
1568
  this.defaults = defaults$1;
1351
1569
  this.settings = _extends({}, this.defaults, options);
1352
- this.memory = {};
1570
+ this.trigger = null;
1353
1571
  this.focusTrap = new FocusTrap(); // Setup a proxy for stack array.
1354
1572
 
1355
1573
  this.stack = new Proxy([], {
1356
1574
  set: (target, property, value) => {
1357
- target[property] = value; // Update global state whenever the length property of stack changes.
1575
+ target[property] = value; // Update global state if stack length changed.
1358
1576
 
1359
1577
  if (property === 'length') {
1360
- updateGlobalState.call(this);
1578
+ updateGlobalState(this.active, this.settings);
1579
+ updateStackIndex(this.stack);
1361
1580
  }
1362
1581
 
1363
1582
  return true;
1364
1583
  }
1365
1584
  });
1366
- this.__handleClick = handleClick.bind(this);
1367
- this.__handleKeydown = handleKeydown.bind(this);
1585
+ _classPrivateFieldLooseBase(this, _handleClick)[_handleClick] = handleClick$1.bind(this);
1586
+ _classPrivateFieldLooseBase(this, _handleKeydown$1)[_handleKeydown$1] = handleKeydown$1.bind(this);
1368
1587
  if (this.settings.autoInit) this.init();
1369
1588
  }
1370
1589
 
@@ -1383,35 +1602,39 @@ class Modal extends Collection {
1383
1602
  if (this.settings.eventListeners) {
1384
1603
  this.initEventListeners();
1385
1604
  }
1605
+
1606
+ return this;
1386
1607
  }
1387
1608
 
1388
1609
  async destroy() {
1389
- // Clear any stored memory.
1390
- this.memory = {}; // Remove all entries from the collection.
1610
+ // Clear stored trigger.
1611
+ this.trigger = null; // Remove all entries from the collection.
1391
1612
 
1392
1613
  await this.deregisterCollection(); // If eventListeners are enabled, destroy event listeners.
1393
1614
 
1394
1615
  if (this.settings.eventListeners) {
1395
1616
  this.destroyEventListeners();
1396
1617
  }
1618
+
1619
+ return this;
1397
1620
  }
1398
1621
 
1399
1622
  initEventListeners() {
1400
- document.addEventListener('click', this.__handleClick, false);
1401
- document.addEventListener('touchend', this.__handleClick, false);
1402
- document.addEventListener('keydown', this.__handleKeydown, false);
1623
+ document.addEventListener('click', _classPrivateFieldLooseBase(this, _handleClick)[_handleClick], false);
1624
+ document.addEventListener('touchend', _classPrivateFieldLooseBase(this, _handleClick)[_handleClick], false);
1625
+ document.addEventListener('keydown', _classPrivateFieldLooseBase(this, _handleKeydown$1)[_handleKeydown$1], false);
1403
1626
  }
1404
1627
 
1405
1628
  destroyEventListeners() {
1406
- document.removeEventListener('click', this.__handleClick, false);
1407
- document.removeEventListener('touchend', this.__handleClick, false);
1408
- document.removeEventListener('keydown', this.__handleKeydown, false);
1629
+ document.removeEventListener('click', _classPrivateFieldLooseBase(this, _handleClick)[_handleClick], false);
1630
+ document.removeEventListener('touchend', _classPrivateFieldLooseBase(this, _handleClick)[_handleClick], false);
1631
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleKeydown$1)[_handleKeydown$1], false);
1409
1632
  }
1410
1633
 
1411
1634
  register(query) {
1412
1635
  const els = getModalElements.call(this, query);
1413
1636
  if (els.error) return Promise.reject(els.error);
1414
- return register$1.call(this, els.target, els.dialog);
1637
+ return register$1.call(this, els.modal, els.dialog);
1415
1638
  }
1416
1639
 
1417
1640
  deregister(query) {
@@ -1419,21 +1642,25 @@ class Modal extends Collection {
1419
1642
  return deregister$1.call(this, modal);
1420
1643
  }
1421
1644
 
1422
- open(id, transition) {
1423
- return open$1.call(this, id, transition);
1645
+ open(id, transition, focus) {
1646
+ return open$1.call(this, id, transition, focus);
1424
1647
  }
1425
1648
 
1426
- close(id, transition) {
1427
- return close$1.call(this, id, transition);
1649
+ close(id, transition, focus) {
1650
+ return close$1.call(this, id, transition, focus);
1428
1651
  }
1429
1652
 
1430
- replace(id, transition) {
1431
- return replace.call(this, id, transition);
1653
+ replace(id, transition, focus) {
1654
+ return replace.call(this, id, transition, focus);
1432
1655
  }
1433
1656
 
1434
- async closeAll(exclude = false, transition) {
1435
- const result = await closeAll$1.call(this, exclude, transition);
1436
- updateFocusState.call(this);
1657
+ async closeAll(exclude = false, transition, focus = true) {
1658
+ const result = await closeAll$1.call(this, exclude, transition); // Update focus if the focus param is true.
1659
+
1660
+ if (focus) {
1661
+ updateFocusState.call(this);
1662
+ }
1663
+
1437
1664
  return result;
1438
1665
  }
1439
1666
 
@@ -1479,6 +1706,7 @@ function getConfig(el, settings) {
1479
1706
 
1480
1707
  return config;
1481
1708
  }
1709
+
1482
1710
  function getPadding(value) {
1483
1711
  let padding; // Split the value by spaces if it's a string.
1484
1712
 
@@ -1528,6 +1756,7 @@ function getPadding(value) {
1528
1756
 
1529
1757
  return padding;
1530
1758
  }
1759
+
1531
1760
  function getModifiers(options) {
1532
1761
  return [{
1533
1762
  name: 'offset',
@@ -1552,6 +1781,7 @@ function getModifiers(options) {
1552
1781
  }
1553
1782
  }];
1554
1783
  }
1784
+
1555
1785
  function getPopover(query) {
1556
1786
  // Get the entry from collection.
1557
1787
  const entry = typeof query === 'string' ? this.get(query) : this.get(query.id); // Return entry if it was resolved, otherwise throw error.
@@ -1562,13 +1792,14 @@ function getPopover(query) {
1562
1792
  throw new Error(`Popover not found in collection with id of "${query}".`);
1563
1793
  }
1564
1794
  }
1795
+
1565
1796
  function getPopoverID(obj) {
1566
1797
  // If it's a string, return the string.
1567
1798
  if (typeof obj === 'string') {
1568
1799
  return obj;
1569
1800
  } // If it's an HTML element.
1570
1801
  else if (typeof obj.hasAttribute === 'function') {
1571
- // If it's a popover target, return the id.
1802
+ // If it's a popover element, return the id.
1572
1803
  if (obj.closest(this.settings.selectorPopover)) {
1573
1804
  obj = obj.closest(this.settings.selectorPopover);
1574
1805
  return obj.id;
@@ -1586,14 +1817,15 @@ function getPopoverID(obj) {
1586
1817
  } // Return false if no id was found.
1587
1818
  else return false;
1588
1819
  }
1820
+
1589
1821
  function getPopoverElements(query) {
1590
1822
  const id = getPopoverID.call(this, query);
1591
1823
 
1592
1824
  if (id) {
1825
+ const popover = document.querySelector(`#${id}`);
1593
1826
  const trigger = document.querySelector(`[aria-controls="${id}"]`) || document.querySelector(`[aria-describedby="${id}"]`);
1594
- const target = document.querySelector(`#${id}`);
1595
1827
 
1596
- if (!trigger && !target) {
1828
+ if (!trigger && !popover) {
1597
1829
  return {
1598
1830
  error: new Error(`No popover elements found using the ID: "${id}".`)
1599
1831
  };
@@ -1601,14 +1833,14 @@ function getPopoverElements(query) {
1601
1833
  return {
1602
1834
  error: new Error('No popover trigger associated with the provided popover.')
1603
1835
  };
1604
- } else if (!target) {
1836
+ } else if (!popover) {
1605
1837
  return {
1606
1838
  error: new Error('No popover associated with the provided popover trigger.')
1607
1839
  };
1608
1840
  } else {
1609
1841
  return {
1610
- trigger,
1611
- target
1842
+ popover,
1843
+ trigger
1612
1844
  };
1613
1845
  }
1614
1846
  } else {
@@ -1624,7 +1856,7 @@ async function close(query) {
1624
1856
 
1625
1857
  if (popover && popover.state === 'opened') {
1626
1858
  // Update state class.
1627
- popover.target.classList.remove(this.settings.stateActive); // Update accessibility attribute(s).
1859
+ popover.el.classList.remove(this.settings.stateActive); // Update accessibility attribute(s).
1628
1860
 
1629
1861
  if (popover.trigger.hasAttribute('aria-controls')) {
1630
1862
  popover.trigger.setAttribute('aria-expanded', 'false');
@@ -1638,10 +1870,10 @@ async function close(query) {
1638
1870
  }]
1639
1871
  }); // Update popover state.
1640
1872
 
1641
- popover.state = 'closed'; // Clear memory if popover trigger matches the one saved in memory.
1873
+ popover.state = 'closed'; // Clear root trigger if popover trigger matches.
1642
1874
 
1643
- if (popover.trigger === this.memory.trigger) {
1644
- this.memory.trigger = null;
1875
+ if (popover.trigger === this.trigger) {
1876
+ this.trigger = null;
1645
1877
  }
1646
1878
  } // Return the popover.
1647
1879
 
@@ -1662,10 +1894,10 @@ function closeCheck(popover) {
1662
1894
  if (popover.state != 'opened') return; // Needed to correctly check which element is currently being focused.
1663
1895
 
1664
1896
  setTimeout(() => {
1665
- // Check if trigger or target are being hovered.
1666
- const isHovered = popover.target.closest(':hover') === popover.target || popover.trigger.closest(':hover') === popover.trigger; // Check if trigger or target are being focused.
1897
+ // Check if trigger or element are being hovered.
1898
+ const isHovered = popover.el.closest(':hover') === popover.el || popover.trigger.closest(':hover') === popover.trigger; // Check if trigger or element are being focused.
1667
1899
 
1668
- const isFocused = document.activeElement.closest(`#${popover.id}, [aria-controls="${popover.id}"]`); // Close if the trigger and target are not currently hovered or focused.
1900
+ const isFocused = document.activeElement.closest(`#${popover.id}, [aria-controls="${popover.id}"]`); // Close if the trigger and element are not currently hovered or focused.
1669
1901
 
1670
1902
  if (!isHovered && !isFocused) {
1671
1903
  popover.close();
@@ -1676,20 +1908,20 @@ function closeCheck(popover) {
1676
1908
  }, 1);
1677
1909
  }
1678
1910
 
1679
- function handlerClick(popover) {
1911
+ function handleClick(popover) {
1680
1912
  if (popover.state === 'opened') {
1681
1913
  popover.close();
1682
1914
  } else {
1683
- this.memory.trigger = popover.trigger;
1915
+ this.trigger = popover.trigger;
1684
1916
  popover.open();
1685
- documentClick.call(this, popover);
1917
+ handleDocumentClick.call(this, popover);
1686
1918
  }
1687
1919
  }
1688
- function handlerKeydown(event) {
1920
+ function handleKeydown(event) {
1689
1921
  switch (event.key) {
1690
1922
  case 'Escape':
1691
- if (this.memory.trigger) {
1692
- this.memory.trigger.focus();
1923
+ if (this.trigger) {
1924
+ this.trigger.focus();
1693
1925
  }
1694
1926
 
1695
1927
  closeAll.call(this);
@@ -1705,7 +1937,7 @@ function handlerKeydown(event) {
1705
1937
  return;
1706
1938
  }
1707
1939
  }
1708
- function documentClick(popover) {
1940
+ function handleDocumentClick(popover) {
1709
1941
  const root = this;
1710
1942
  document.addEventListener('click', function _f(event) {
1711
1943
  // Check if a popover was clicked.
@@ -1713,14 +1945,14 @@ function documentClick(popover) {
1713
1945
 
1714
1946
  if (!result) {
1715
1947
  // If it doesn't match and popover is open, close it and remove event listener.
1716
- if (popover.target && popover.target.classList.contains(root.settings.stateActive)) {
1948
+ if (popover.el && popover.el.classList.contains(root.settings.stateActive)) {
1717
1949
  popover.close();
1718
1950
  }
1719
1951
 
1720
1952
  this.removeEventListener('click', _f);
1721
1953
  } else {
1722
1954
  // If it does match and popover isn't currently active, remove event listener.
1723
- if (popover.target && !popover.target.classList.contains(root.settings.stateActive)) {
1955
+ if (popover.el && !popover.el.classList.contains(root.settings.stateActive)) {
1724
1956
  this.removeEventListener('click', _f);
1725
1957
  }
1726
1958
  }
@@ -3569,14 +3801,14 @@ async function open(query) {
3569
3801
  // Get the popover from collection.
3570
3802
  const popover = getPopover.call(this, query); // Update state class.
3571
3803
 
3572
- popover.target.classList.add(this.settings.stateActive); // Update accessibility attribute(s).
3804
+ popover.el.classList.add(this.settings.stateActive); // Update accessibility attribute(s).
3573
3805
 
3574
3806
  if (popover.trigger.hasAttribute('aria-controls')) {
3575
3807
  popover.trigger.setAttribute('aria-expanded', 'true');
3576
3808
  } // Update popover config.
3577
3809
 
3578
3810
 
3579
- popover.config = getConfig(popover.target, this.settings); // Enable popper event listeners and set placement/modifiers.
3811
+ popover.config = getConfig(popover.el, this.settings); // Enable popper event listeners and set placement/modifiers.
3580
3812
 
3581
3813
  popover.popper.setOptions({
3582
3814
  placement: popover.config['placement'],
@@ -3593,9 +3825,9 @@ async function open(query) {
3593
3825
  return popover;
3594
3826
  }
3595
3827
 
3596
- async function register(trigger, target) {
3828
+ async function register(el, trigger) {
3597
3829
  // Deregister entry incase it has already been registered.
3598
- deregister.call(this, target); // Save root this for use inside methods API.
3830
+ deregister.call(this, el); // Save root this for use inside methods API.
3599
3831
 
3600
3832
  const root = this; // Setup methods API.
3601
3833
 
@@ -3615,12 +3847,12 @@ async function register(trigger, target) {
3615
3847
  }; // Setup the popover object.
3616
3848
 
3617
3849
  const entry = _extends({
3618
- id: target.id,
3850
+ id: el.id,
3619
3851
  state: 'closed',
3852
+ el: el,
3620
3853
  trigger: trigger,
3621
- target: target,
3622
- popper: createPopper(trigger, target),
3623
- config: getConfig(target, this.settings)
3854
+ popper: createPopper(trigger, el),
3855
+ config: getConfig(el, this.settings)
3624
3856
  }, methods); // Set aria-expanded to false if trigger has aria-controls attribute.
3625
3857
 
3626
3858
 
@@ -3633,9 +3865,9 @@ async function register(trigger, target) {
3633
3865
 
3634
3866
  this.collection.push(entry); // Set initial state.
3635
3867
 
3636
- if (entry.target.classList.contains(this.settings.stateActive)) {
3868
+ if (entry.el.classList.contains(this.settings.stateActive)) {
3637
3869
  await entry.open();
3638
- documentClick.call(this, entry);
3870
+ handleDocumentClick.call(this, entry);
3639
3871
  } // Return the registered entry.
3640
3872
 
3641
3873
 
@@ -3654,7 +3886,7 @@ function registerEventListeners(entry) {
3654
3886
  type: ['mouseenter', 'focus'],
3655
3887
  listener: open.bind(this, entry)
3656
3888
  }, {
3657
- el: ['trigger', 'target'],
3889
+ el: ['el', 'trigger'],
3658
3890
  type: ['mouseleave', 'focusout'],
3659
3891
  listener: closeCheck.bind(this, entry)
3660
3892
  }]; // Loop through listeners and apply to the appropriate elements.
@@ -3672,7 +3904,7 @@ function registerEventListeners(entry) {
3672
3904
  entry.__eventListeners = [{
3673
3905
  el: ['trigger'],
3674
3906
  type: ['click'],
3675
- listener: handlerClick.bind(this, entry)
3907
+ listener: handleClick.bind(this, entry)
3676
3908
  }]; // Loop through listeners and apply to the appropriate elements.
3677
3909
 
3678
3910
  entry.__eventListeners.forEach(evObj => {
@@ -3689,13 +3921,19 @@ function registerEventListeners(entry) {
3689
3921
  return entry;
3690
3922
  }
3691
3923
 
3924
+ var _handleKeydown = /*#__PURE__*/_classPrivateFieldLooseKey("handleKeydown");
3925
+
3692
3926
  class Popover extends Collection {
3693
3927
  constructor(options) {
3694
3928
  super();
3929
+ Object.defineProperty(this, _handleKeydown, {
3930
+ writable: true,
3931
+ value: void 0
3932
+ });
3695
3933
  this.defaults = defaults;
3696
3934
  this.settings = _extends({}, this.defaults, options);
3697
- this.memory = {};
3698
- this.__handlerKeydown = handlerKeydown.bind(this);
3935
+ this.trigger = null;
3936
+ _classPrivateFieldLooseBase(this, _handleKeydown)[_handleKeydown] = handleKeydown.bind(this);
3699
3937
  if (this.settings.autoInit) this.init();
3700
3938
  }
3701
3939
 
@@ -3712,11 +3950,13 @@ class Popover extends Collection {
3712
3950
  // already adds event listeners to popovers.
3713
3951
  this.initEventListeners(false);
3714
3952
  }
3953
+
3954
+ return this;
3715
3955
  }
3716
3956
 
3717
3957
  async destroy() {
3718
- // Clear any stored memory.
3719
- this.memory = {}; // Remove all entries from the collection.
3958
+ // Clear stored trigger.
3959
+ this.trigger = null; // Remove all entries from the collection.
3720
3960
 
3721
3961
  await this.deregisterCollection(); // If eventListeners are enabled, destroy event listeners.
3722
3962
 
@@ -3725,6 +3965,8 @@ class Popover extends Collection {
3725
3965
  // already removes event listeners from popovers.
3726
3966
  this.destroyEventListeners(false);
3727
3967
  }
3968
+
3969
+ return this;
3728
3970
  }
3729
3971
 
3730
3972
  initEventListeners(processCollection = true) {
@@ -3736,7 +3978,7 @@ class Popover extends Collection {
3736
3978
  } // Add keydown global event listener.
3737
3979
 
3738
3980
 
3739
- document.addEventListener('keydown', this.__handlerKeydown, false);
3981
+ document.addEventListener('keydown', _classPrivateFieldLooseBase(this, _handleKeydown)[_handleKeydown], false);
3740
3982
  }
3741
3983
 
3742
3984
  destroyEventListeners(processCollection = true) {
@@ -3748,13 +3990,13 @@ class Popover extends Collection {
3748
3990
  } // Remove keydown global event listener.
3749
3991
 
3750
3992
 
3751
- document.removeEventListener('keydown', this.__handlerKeydown, false);
3993
+ document.removeEventListener('keydown', _classPrivateFieldLooseBase(this, _handleKeydown)[_handleKeydown], false);
3752
3994
  }
3753
3995
 
3754
3996
  register(query) {
3755
3997
  const els = getPopoverElements.call(this, query);
3756
3998
  if (els.error) return Promise.reject(els.error);
3757
- return register.call(this, els.trigger, els.target);
3999
+ return register.call(this, els.popover, els.trigger);
3758
4000
  }
3759
4001
 
3760
4002
  deregister(query) {