vrembem 4.0.0-next.30 → 4.0.0-next.31

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.
package/dev/index.js CHANGED
@@ -5,9 +5,73 @@ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot
5
5
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
6
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
7
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
- var _handler, _focusable, _handleFocusTrap, _handleFocusLock, _mode, _state, _breakpoint, _handleClick, _handleKeydown, _handleClick2, _handleKeydown2, _eventListeners, _isHovered, _handleKeydown3;
8
+ var _mode, _handleClick, _handleKeydown, _handleClick2, _handleKeydown2, _eventListeners, _isHovered, _handleKeydown3;
9
+ const notInert = ":not([inert])";
10
+ const notNegTabIndex = ':not([tabindex^="-"])';
11
+ const notDisabled = ":not(:disabled)";
12
+ const focusableSelectors = [
13
+ `a[href]${notInert}${notNegTabIndex}`,
14
+ `area[href]${notInert}${notNegTabIndex}`,
15
+ `input:not([type="hidden"]):not([type="radio"])${notInert}${notNegTabIndex}${notDisabled}`,
16
+ `input[type="radio"]${notInert}${notNegTabIndex}${notDisabled}`,
17
+ `select${notInert}${notNegTabIndex}${notDisabled}`,
18
+ `textarea${notInert}${notNegTabIndex}${notDisabled}`,
19
+ `button${notInert}${notNegTabIndex}${notDisabled}`,
20
+ `details${notInert} > summary:first-of-type${notNegTabIndex}`,
21
+ `iframe${notInert}${notNegTabIndex}`,
22
+ `audio[controls]${notInert}${notNegTabIndex}`,
23
+ `video[controls]${notInert}${notNegTabIndex}`,
24
+ `[contenteditable]${notInert}${notNegTabIndex}`,
25
+ `[tabindex]${notInert}${notNegTabIndex}`
26
+ ];
27
+ function getDataConfig(el, dataConfig = "config") {
28
+ const string = el.getAttribute(`data-${dataConfig}`) || "";
29
+ const json = string.replace(/'/g, '"');
30
+ return json ? JSON.parse(json) : {};
31
+ }
32
+ function getElement(query) {
33
+ if (typeof query === "string") {
34
+ return document.getElementById(query);
35
+ } else if (query instanceof HTMLElement) {
36
+ return query;
37
+ } else {
38
+ return null;
39
+ }
40
+ }
41
+ async function maybeRunMethod(obj, name, ...args) {
42
+ if (name in obj && typeof obj[name] === "function") {
43
+ await obj[name](...args);
44
+ }
45
+ }
46
+ function teleportElement(what, where, how) {
47
+ if (typeof where === "string") {
48
+ const whereEl = document.querySelector(where);
49
+ if (!whereEl) {
50
+ throw new Error(`No teleport reference found for selector: ${where}`);
51
+ }
52
+ where = whereEl;
53
+ } else if (!(where instanceof HTMLElement)) {
54
+ throw new Error(`Not a valid teleport reference: '${where}'`);
55
+ }
56
+ if (typeof where[how] != "function")
57
+ throw new Error(`Not a valid teleport method: '${how}'`);
58
+ let returnRef = document.createComment(
59
+ "teleported #" + what.id
60
+ );
61
+ what.before(returnRef);
62
+ where[how](what);
63
+ return () => {
64
+ if (returnRef) {
65
+ returnRef.after(what);
66
+ returnRef.remove();
67
+ returnRef = null;
68
+ }
69
+ };
70
+ }
9
71
  function toCamel(value) {
10
- return value.split("-").map((word, index2) => index2 === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)).join("");
72
+ return value.split("-").map(
73
+ (word, index2) => index2 === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)
74
+ ).join("");
11
75
  }
12
76
  function toKebab(value) {
13
77
  return value.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
@@ -23,16 +87,24 @@ function toMilliseconds(value) {
23
87
  }
24
88
  throw new Error(`Could not convert value to milliseconds: ${value}`);
25
89
  }
26
- function getPrefix() {
27
- return getComputedStyle(document.body).getPropertyValue("--vb-prefix").trim();
90
+ function transition(el, init, interim, final, duration = 0) {
91
+ return new Promise((resolve) => {
92
+ el.classList.remove(init);
93
+ el.classList.add(interim);
94
+ setTimeout(() => {
95
+ el.classList.add(final);
96
+ el.classList.remove(interim);
97
+ resolve(el);
98
+ }, toMilliseconds(duration));
99
+ });
28
100
  }
29
- function cssVar(property, options) {
101
+ function cssVar(property, options = {}) {
30
102
  const settings = {
31
103
  fallback: null,
32
104
  element: document.body,
33
105
  ...options
34
106
  };
35
- if (property.slice(0, 2) !== "--") {
107
+ if (!property.startsWith("--")) {
36
108
  const prefixValue = getPrefix();
37
109
  if (prefixValue) {
38
110
  property = `${prefixValue}${property}`;
@@ -50,10 +122,15 @@ function cssVar(property, options) {
50
122
  }
51
123
  }
52
124
  }
53
- function getConfig(el, dataConfig = "config") {
54
- const string = el.getAttribute(`data-${dataConfig}`) || "";
55
- const json = string.replace(/'/g, '"');
56
- return json ? JSON.parse(json) : {};
125
+ async function dispatchLifecycleHook(name, parent2, entry) {
126
+ await maybeRunMethod(parent2, name, entry);
127
+ if (entry) {
128
+ await maybeRunMethod(entry, name);
129
+ }
130
+ for (const plugin of parent2.plugins) {
131
+ await maybeRunMethod(plugin, name, { plugin, parent: parent2, entry });
132
+ }
133
+ await parent2.emit(name, entry);
57
134
  }
58
135
  function getCustomProps(entry) {
59
136
  const styles = getComputedStyle(entry.el);
@@ -61,7 +138,7 @@ function getCustomProps(entry) {
61
138
  const keys = entry.getSetting("customProps");
62
139
  for (let i = 0; i < keys.length; i++) {
63
140
  const prefix = getPrefix();
64
- const module = entry.context.module.toLowerCase();
141
+ const module = entry.parent.module.toLowerCase();
65
142
  const key = toKebab(keys[i]);
66
143
  const value = styles.getPropertyValue(`--${prefix}${module}-${key}`).trim();
67
144
  if (value) {
@@ -70,14 +147,8 @@ function getCustomProps(entry) {
70
147
  }
71
148
  return result;
72
149
  }
73
- function getElement(query) {
74
- if (typeof query === "string") {
75
- return document.getElementById(query);
76
- } else if (query instanceof HTMLElement) {
77
- return query;
78
- } else {
79
- return null;
80
- }
150
+ function getPrefix() {
151
+ return getComputedStyle(document.body).getPropertyValue("--vb-prefix").trim();
81
152
  }
82
153
  function maybeReturnSetting(prop, key, type = "camel") {
83
154
  key = type === "camel" ? toCamel(key) : toKebab(key);
@@ -86,7 +157,7 @@ function maybeReturnSetting(prop, key, type = "camel") {
86
157
  function getSetting(key, options = {}) {
87
158
  const {
88
159
  fallback,
89
- props = ["dataConfig", "customProps", "settings", "context.settings"]
160
+ props = ["dataConfig", "customProps", "settings", "parent.settings"]
90
161
  } = options;
91
162
  for (const prop of props) {
92
163
  const type = prop !== "customProps" ? "camel" : "kebab";
@@ -98,23 +169,7 @@ function getSetting(key, options = {}) {
98
169
  if (fallback !== void 0) {
99
170
  return fallback;
100
171
  }
101
- throw new Error(`${this.context.module} setting does not exist: ${key}`);
102
- }
103
- async function lifecycleHook(name, ...args) {
104
- if (name in this && typeof this[name] === "function") {
105
- await this[name](...args);
106
- }
107
- }
108
- function transition(el, init, interim, final, duration = 0) {
109
- return new Promise((resolve) => {
110
- el.classList.remove(init);
111
- el.classList.add(interim);
112
- setTimeout(() => {
113
- el.classList.add(final);
114
- el.classList.remove(interim);
115
- resolve(el);
116
- }, toMilliseconds(duration));
117
- });
172
+ throw new Error(`${this.parent.module} setting does not exist: ${key}`);
118
173
  }
119
174
  function setOverflowHidden(state, selector) {
120
175
  if (selector) {
@@ -134,9 +189,9 @@ function setInert(state, selector) {
134
189
  els.forEach((el) => {
135
190
  if (state) {
136
191
  el.inert = true;
137
- el.setAttribute("aria-hidden", true);
192
+ el.setAttribute("aria-hidden", "true");
138
193
  } else {
139
- el.inert = null;
194
+ el.inert = false;
140
195
  el.removeAttribute("aria-hidden");
141
196
  }
142
197
  });
@@ -146,308 +201,725 @@ function setGlobalState(state, selectorInert, selectorOverflow) {
146
201
  setInert(!!state, selectorInert);
147
202
  setOverflowHidden(!!state, selectorOverflow);
148
203
  }
149
- class Breakpoint {
150
- constructor(value, handler) {
151
- __privateAdd(this, _handler);
152
- this.value = value;
153
- __privateSet(this, _handler, handler);
154
- this.mql = null;
155
- }
156
- get handler() {
157
- return __privateGet(this, _handler);
158
- }
159
- // Unmount existing handler before setting a new one.
160
- set handler(func) {
161
- if (this.mql) {
162
- this.mql.removeEventListener("change", __privateGet(this, _handler));
163
- }
164
- __privateSet(this, _handler, func);
165
- }
166
- mount(value, handler) {
167
- if (value) this.value = value;
168
- if (handler) __privateSet(this, _handler, handler);
169
- if (!this.value) return this;
170
- this.mql = window.matchMedia(`(min-width: ${this.value})`);
171
- this.mql.addEventListener("change", __privateGet(this, _handler));
172
- __privateGet(this, _handler).call(this, this.mql);
173
- return this;
204
+ const eventEmitter = {
205
+ on(event, listener, ...args) {
206
+ if (!this.events[event]) {
207
+ this.events[event] = [];
208
+ }
209
+ const listenerExists = this.events[event].some(
210
+ (entry) => entry.listener === listener
211
+ );
212
+ if (!listenerExists) {
213
+ this.events[event].push({ listener, args });
214
+ }
215
+ },
216
+ off(event, listenerRef) {
217
+ if (!this.events[event]) return;
218
+ this.events[event] = this.events[event].filter(
219
+ (entry) => entry.listener !== listenerRef
220
+ );
221
+ },
222
+ async emit(event, data) {
223
+ event = event.startsWith("on") ? event.slice(2, 3).toLowerCase() + event.slice(3) : event;
224
+ if (!this.events[event]) return;
225
+ for (const { listener, args } of this.events[event]) {
226
+ await listener(data, ...args);
227
+ }
174
228
  }
175
- unmount() {
176
- if (!this.mql) return this;
177
- this.mql.removeEventListener("change", __privateGet(this, _handler));
178
- this.value = null;
179
- __privateSet(this, _handler, null);
180
- this.mql = null;
181
- return this;
229
+ };
230
+ class FocusableArray extends Array {
231
+ constructor(el = null) {
232
+ super();
233
+ this.el = el;
234
+ if (this.el) this.set();
235
+ }
236
+ get first() {
237
+ return this[0];
238
+ }
239
+ get last() {
240
+ return this[this.length - 1];
241
+ }
242
+ set(el = this.el) {
243
+ this.length = 0;
244
+ this.push(...el.querySelectorAll(focusableSelectors.join(",")));
245
+ }
246
+ clear() {
247
+ this.length = 0;
182
248
  }
183
249
  }
184
- _handler = new WeakMap();
185
- class Collection {
186
- constructor(options = {}) {
187
- this.module = this.constructor.name;
188
- this.collection = [];
189
- this.settings = Object.assign({
190
- dataConfig: "config",
191
- customProps: [],
192
- teleport: null,
193
- teleportMethod: "append"
194
- }, options);
250
+ class FocusTrap {
251
+ constructor(el = null) {
252
+ this.el = el;
253
+ this.focusable = new FocusableArray();
254
+ this.handleFocusTrap = handleFocusTrap.bind(this);
195
255
  }
196
- get(value, key = "id") {
197
- return this.collection.find((entry) => entry[key] === value);
256
+ on(el = this.el) {
257
+ this.focusable.set(el);
258
+ this.focusable.length ? document.addEventListener("keydown", this.handleFocusTrap) : document.addEventListener("keydown", handleFocusLock);
198
259
  }
199
- applySettings(obj) {
200
- return Object.assign(this.settings, obj);
260
+ off() {
261
+ this.focusable.clear();
262
+ document.removeEventListener("keydown", this.handleFocusTrap);
263
+ document.removeEventListener("keydown", handleFocusLock);
201
264
  }
202
- async createEntry(query, config) {
203
- return new CollectionEntry(this, query, config);
265
+ }
266
+ function handleFocusLock(event) {
267
+ if (event.key === "Tab" || event.keyCode === 9) event.preventDefault();
268
+ }
269
+ function handleFocusTrap(event) {
270
+ if (event.key !== "Tab" && event.keyCode !== 9) return;
271
+ const { activeElement } = document;
272
+ const { el, focusable } = this;
273
+ const isShiftTab = event.shiftKey;
274
+ const isFirstOrRoot = activeElement === focusable.first || activeElement === el;
275
+ const isLastOrRoot = activeElement === focusable.last || activeElement === el;
276
+ if (isShiftTab && isFirstOrRoot || !isShiftTab && isLastOrRoot) {
277
+ event.preventDefault();
278
+ (isShiftTab ? focusable.last : focusable.first).focus();
204
279
  }
205
- async register(query, config = {}) {
206
- await this.deregister((query == null ? void 0 : query.id) || query, true);
207
- const entry = await this.createEntry(query, config);
208
- await entry.mount();
209
- await lifecycleHook.call(this, "beforeRegister", entry);
210
- await lifecycleHook.call(entry, "beforeRegister");
211
- this.collection.push(entry);
212
- await lifecycleHook.call(entry, "afterRegister");
213
- await lifecycleHook.call(this, "afterRegister", entry);
214
- return entry;
280
+ }
281
+ function localStore(key, enable = true) {
282
+ const local = localStorage.getItem(key);
283
+ const store = local ? JSON.parse(local) : {};
284
+ return {
285
+ get(prop, fallback = void 0) {
286
+ if (!prop) return store;
287
+ return prop in store ? store[prop] : fallback;
288
+ },
289
+ set(prop, value) {
290
+ if (value) {
291
+ store[prop] = value;
292
+ } else {
293
+ delete store[prop];
294
+ }
295
+ if (enable) localStorage.setItem(key, JSON.stringify(store));
296
+ return store;
297
+ }
298
+ };
299
+ }
300
+ class PluginsArray extends Array {
301
+ constructor(presets2 = {}) {
302
+ super();
303
+ this.presets = presets2;
304
+ }
305
+ applySettings(plugin) {
306
+ var _a;
307
+ const defaults2 = (plugin == null ? void 0 : plugin.defaults) || {};
308
+ const preset = ((_a = this.presets) == null ? void 0 : _a[plugin.name]) || {};
309
+ const options = (plugin == null ? void 0 : plugin.options) || {};
310
+ plugin.settings = { ...defaults2, ...preset, ...options };
311
+ }
312
+ validate(plugin) {
313
+ if (!("name" in plugin) || typeof plugin.name !== "string") {
314
+ console.error("Plugin requires a name!");
315
+ return false;
316
+ }
317
+ return true;
215
318
  }
216
- async deregister(id, reReg = false) {
217
- const index2 = this.collection.findIndex((entry) => entry.id === id);
218
- if (~index2) {
219
- const entry = this.collection[index2];
220
- await entry.unmount(reReg);
221
- await lifecycleHook.call(this, "beforeDeregister", entry);
222
- await lifecycleHook.call(entry, "beforeDeregister", reReg);
223
- Object.getOwnPropertyNames(entry).forEach((prop) => {
224
- if (prop != "beforeDeregister" && prop != "afterDeregister") {
225
- delete entry[prop];
319
+ get(name) {
320
+ return this.find((plugin) => plugin.name === name);
321
+ }
322
+ add(plugin) {
323
+ if (Array.isArray(plugin)) {
324
+ plugin.forEach((plugin2) => this.add(plugin2));
325
+ } else {
326
+ this.applySettings(plugin);
327
+ if (this.validate(plugin)) {
328
+ const index2 = this.findIndex((item) => item.name === plugin.name);
329
+ if (~index2) {
330
+ this[index2] = plugin;
331
+ } else {
332
+ this.push(plugin);
226
333
  }
334
+ }
335
+ }
336
+ }
337
+ remove(name) {
338
+ const index2 = this.findIndex((plugin) => plugin.name === name);
339
+ if (~index2) {
340
+ this.splice(index2, 1);
341
+ }
342
+ }
343
+ }
344
+ class StackArray extends Array {
345
+ constructor(settings = {}) {
346
+ super();
347
+ this.settings = settings;
348
+ }
349
+ get copy() {
350
+ return [...this];
351
+ }
352
+ get top() {
353
+ const result = this[this.length - 1];
354
+ return result ? result : null;
355
+ }
356
+ updateIndex() {
357
+ this.forEach((entry, index2) => {
358
+ entry.el.style.zIndex = null;
359
+ const value = getComputedStyle(entry.el)["z-index"];
360
+ entry.el.style.zIndex = parseInt(value) + index2 + 1;
361
+ });
362
+ }
363
+ onChange() {
364
+ this.updateIndex();
365
+ if (typeof this.settings.onChange === "function") {
366
+ this.settings.onChange();
367
+ }
368
+ }
369
+ add(entry) {
370
+ this.push(entry);
371
+ this.onChange();
372
+ }
373
+ remove(entry) {
374
+ const index2 = this.findIndex((item) => item.id === entry.id);
375
+ if (~index2) {
376
+ entry.el.style.zIndex = null;
377
+ this.splice(index2, 1);
378
+ this.onChange();
379
+ }
380
+ }
381
+ moveToTop(entry) {
382
+ const index2 = this.findIndex((item) => item.id === entry.id);
383
+ if (~index2) {
384
+ this.splice(index2, 1);
385
+ this.add(entry);
386
+ }
387
+ }
388
+ }
389
+ const defaults$8 = {
390
+ condition: true
391
+ };
392
+ const colors = {
393
+ primary: "hsl(152deg 60% 50%)",
394
+ secondary: "hsl(214deg 50% 50%)",
395
+ neutral: "hsl(214deg 20% 50%)",
396
+ important: "hsl(0deg 80% 50%)"
397
+ };
398
+ function debug(options = {}) {
399
+ const props = {
400
+ name: "debug",
401
+ defaults: defaults$8,
402
+ options
403
+ };
404
+ function log(name, args = [], colorKeys = ["primary", "secondary"]) {
405
+ const colorStyles = colorKeys.map((key) => `color: ${colors[key]}`);
406
+ console.log(`%c📡 DEBUG: %c${name}`, ...colorStyles, ...args);
407
+ }
408
+ function getValue(obj, ...args) {
409
+ return typeof obj === "function" ? obj(...args) : obj;
410
+ }
411
+ const refs = {
412
+ beforeMountRef: log.bind(null, "Event > beforeMount()"),
413
+ afterMountRef: log.bind(null, "Event > afterMount()"),
414
+ beforeUnmountRef: log.bind(
415
+ null,
416
+ "Event > beforeUnmount()",
417
+ [],
418
+ ["important", "neutral"]
419
+ ),
420
+ afterUnmountRef: log.bind(
421
+ null,
422
+ "Event > afterUnmount()",
423
+ [],
424
+ ["important", "neutral"]
425
+ ),
426
+ createEntryRef: (entry, { parent: parent2, plugin }) => {
427
+ if (getValue(plugin.settings.condition, entry)) {
428
+ const count = parent2.collection.length;
429
+ log(`Event > createEntry() > [${count}] #${entry.id}`);
430
+ }
431
+ },
432
+ registerEntryRef: (entry, { parent: parent2, plugin }) => {
433
+ if (getValue(plugin.settings.condition, entry)) {
434
+ const count = parent2.collection.length;
435
+ log(`Event > registerEntry() > [${count}] #${entry.id}`);
436
+ }
437
+ },
438
+ destroyEntryRef: (entry, { parent: parent2, plugin }) => {
439
+ if (getValue(plugin.settings.condition, entry)) {
440
+ const count = parent2.collection.length;
441
+ log(
442
+ `Event > destroyEntry() > [${count}] #${entry.id}`,
443
+ [],
444
+ ["important", "neutral"]
445
+ );
446
+ }
447
+ },
448
+ deregisterEntryRef: (entry, { parent: parent2, plugin }) => {
449
+ if (getValue(plugin.settings.condition, entry)) {
450
+ const count = parent2.collection.length;
451
+ log(
452
+ `Event > deregisterEntry() > [${count}] #${entry.id}`,
453
+ [],
454
+ ["important", "neutral"]
455
+ );
456
+ }
457
+ }
458
+ };
459
+ const methods = {
460
+ // Plugin setup/teardown methods
461
+ setup({ parent: parent2 }) {
462
+ log("Plugin > setup()", arguments, ["secondary", "neutral"]);
463
+ parent2.on("beforeMount", refs.beforeMountRef);
464
+ parent2.on("createEntry", refs.createEntryRef, { parent: parent2, plugin: this });
465
+ parent2.on("registerEntry", refs.registerEntryRef, {
466
+ parent: parent2,
467
+ plugin: this
227
468
  });
228
- this.collection.splice(index2, 1);
229
- await lifecycleHook.call(entry, "afterDeregister", reReg);
230
- await lifecycleHook.call(this, "afterDeregister", entry);
469
+ parent2.on("afterMount", refs.afterMountRef);
470
+ parent2.on("beforeUnmount", refs.beforeUnmountRef);
471
+ parent2.on("destroyEntry", refs.destroyEntryRef, { parent: parent2, plugin: this });
472
+ parent2.on("deregisterEntry", refs.deregisterEntryRef, {
473
+ parent: parent2,
474
+ plugin: this
475
+ });
476
+ parent2.on("afterUnmount", refs.afterUnmountRef);
477
+ },
478
+ teardown({ parent: parent2 }) {
479
+ log("Plugin > teardown()", arguments, ["secondary", "neutral"]);
480
+ parent2.off("beforeMount", refs.beforeMountRef);
481
+ parent2.off("createEntry", refs.createEntryRef);
482
+ parent2.off("registerEntry", refs.registerEntryRef);
483
+ parent2.off("afterMount", refs.afterMountRef);
484
+ parent2.off("beforeUnmount", refs.beforeUnmountRef);
485
+ parent2.off("destroyEntry", refs.destroyEntryRef);
486
+ parent2.off("deregisterEntry", refs.deregisterEntryRef);
487
+ parent2.off("afterUnmount", refs.afterUnmountRef);
488
+ },
489
+ // Mount lifecycle hooks
490
+ beforeMount() {
491
+ log("Hook > beforeMount()", arguments);
492
+ },
493
+ onCreateEntry({ parent: parent2, entry }) {
494
+ if (getValue(this.settings.condition, entry)) {
495
+ const count = parent2.collection.length;
496
+ log(`Hook > onCreateEntry() > [${count}] #${entry.id}`, arguments);
497
+ }
498
+ },
499
+ onRegisterEntry({ parent: parent2, entry }) {
500
+ if (getValue(this.settings.condition, entry)) {
501
+ const count = parent2.collection.length - 1;
502
+ log(`Hook > onRegisterEntry() > [${count}] #${entry.id}`, arguments);
503
+ }
504
+ },
505
+ afterMount() {
506
+ log("Hook > afterMount()", arguments);
507
+ },
508
+ // Unmount lifecycle hooks
509
+ beforeUnmount() {
510
+ log("Hook > beforeUnmount()", arguments, ["important", "neutral"]);
511
+ },
512
+ onDestroyEntry({ parent: parent2, entry }) {
513
+ if (getValue(this.settings.condition, entry)) {
514
+ const count = parent2.collection.length - 1;
515
+ log(`Hook > onDestroyEntry() > [${count}] #${entry.id}`, arguments, [
516
+ "important",
517
+ "neutral"
518
+ ]);
519
+ }
520
+ },
521
+ onDeregisterEntry({ parent: parent2, entry }) {
522
+ if (getValue(this.settings.condition, entry)) {
523
+ const count = parent2.collection.length;
524
+ log(`Hook > onDeregisterEntry() > [${count}] #${entry.id}`, arguments, [
525
+ "important",
526
+ "neutral"
527
+ ]);
528
+ }
529
+ },
530
+ afterUnmount() {
531
+ log("Hook > afterUnmount()", arguments, ["important", "neutral"]);
532
+ }
533
+ };
534
+ return { ...props, ...methods };
535
+ }
536
+ const defaults$7 = {
537
+ condition: true
538
+ };
539
+ function focusTrap(options = {}) {
540
+ const props = {
541
+ name: "focusTrap",
542
+ defaults: defaults$7,
543
+ options
544
+ };
545
+ const methods = {
546
+ setup({ parent: parent2 }) {
547
+ parent2.on("opened", enableFocusTrap, this);
548
+ parent2.on("closed", disableFocusTrap, this);
549
+ },
550
+ teardown({ parent: parent2 }) {
551
+ parent2.off("opened", enableFocusTrap);
552
+ parent2.off("closed", disableFocusTrap);
553
+ },
554
+ onCreateEntry({ entry }) {
555
+ entry.focusTrap = new FocusTrap();
231
556
  }
232
- return this.collection;
557
+ };
558
+ function getValue(obj, ...args) {
559
+ return typeof obj === "function" ? obj(...args) : obj;
560
+ }
561
+ function enableFocusTrap(entry, plugin) {
562
+ var _a;
563
+ const contextObj = { plugin, parent: entry.parent, entry };
564
+ if (getValue(plugin.settings.condition, contextObj)) {
565
+ (_a = entry.focusTrap) == null ? void 0 : _a.on(entry.dialog);
566
+ }
567
+ }
568
+ function disableFocusTrap(entry, plugin) {
569
+ var _a;
570
+ const contextObj = { plugin, parent: entry.parent, entry };
571
+ if (getValue(plugin.settings.condition, contextObj)) {
572
+ (_a = entry.focusTrap) == null ? void 0 : _a.off();
573
+ }
574
+ }
575
+ return { ...props, ...methods };
576
+ }
577
+ const defaults$6 = {
578
+ // The data attributes to get the breakpoint values from.
579
+ dataBreakpoint: "breakpoint",
580
+ // The data attributes to get the media query value from.
581
+ dataMediaQuery: "media-query",
582
+ // The string token to replace in the media query string.
583
+ token: "{{BP}}",
584
+ // Sets a global breakpoint. Can be overridden by setting a data attribute
585
+ // value. Notice: setting this option will enable a media query breakpoint on
586
+ // all entries.
587
+ breakpoint: null,
588
+ // The default media query string to use. Can be overridden by setting a data
589
+ // attribute value.
590
+ mediaQuery: "(min-width: {{BP}})",
591
+ // Maps entry ID or breakpoint key to breakpoint values. This is referenced
592
+ // when getting an entries breakpoint value.
593
+ breakpoints: {},
594
+ // Maps entry ID's to a media query strings. Media query may contain a token.
595
+ // This is referenced when getting an entries media query string.
596
+ mediaQueries: {},
597
+ // The function to run when the MediaQueryList triggers a "change" event.
598
+ // This is run once on initial mount.
599
+ onChange: () => {
233
600
  }
234
- async mount(options = {}) {
235
- this.applySettings(options);
236
- await lifecycleHook.call(this, "beforeMount");
237
- const els = document.querySelectorAll(this.settings.selector);
238
- for (const el of els) {
239
- await this.register(el);
601
+ };
602
+ function mediaQuery(options = {}) {
603
+ const props = {
604
+ name: "mediaQuery",
605
+ defaults: defaults$6,
606
+ options
607
+ };
608
+ const methods = {
609
+ onCreateEntry({ entry }) {
610
+ setupMediaQueryList.call(this, entry);
611
+ },
612
+ onDestroyEntry({ entry }) {
613
+ removeMediaQueryList(entry);
240
614
  }
241
- await lifecycleHook.call(this, "afterMount");
242
- return this;
615
+ };
616
+ function getMediaQuery(entry) {
617
+ const value = entry.el.getAttribute(`data-${this.settings.dataMediaQuery}`);
618
+ if (!value && entry.id in this.settings.mediaQueries) {
619
+ return this.settings.mediaQueries[entry.id];
620
+ }
621
+ return value;
243
622
  }
244
- async unmount() {
245
- await lifecycleHook.call(this, "beforeUnmount");
246
- while (this.collection.length > 0) {
247
- await this.deregister(this.collection[0].id);
623
+ function getBreakpointValue(entry) {
624
+ let value = entry.el.getAttribute(`data-${this.settings.dataBreakpoint}`);
625
+ if (!value && entry.id in this.settings.breakpoints) {
626
+ value = this.settings.breakpoints[entry.id];
248
627
  }
249
- await lifecycleHook.call(this, "afterUnmount");
250
- return this;
628
+ if (value && value in this.settings.breakpoints) {
629
+ value = this.settings.breakpoints[value];
630
+ }
631
+ if (value) {
632
+ const customProp = getComputedStyle(document.body).getPropertyValue(`--${getPrefix()}breakpoint-${value}`).trim();
633
+ value = customProp || value;
634
+ }
635
+ return value || this.settings.breakpoint;
636
+ }
637
+ function setupMediaQueryList(entry) {
638
+ let mq = getMediaQuery.call(this, entry);
639
+ const bp = getBreakpointValue.call(this, entry);
640
+ if (!bp && !mq) return;
641
+ if (bp && !mq) {
642
+ mq = this.settings.mediaQuery;
643
+ }
644
+ const mqs = mq.replace(new RegExp(`${this.settings.token}`, "g"), bp);
645
+ entry.mql = window.matchMedia(mqs);
646
+ entry.mql.onchange = (event) => {
647
+ this.settings.onChange(event, entry);
648
+ };
649
+ this.settings.onChange(entry.mql, entry);
650
+ }
651
+ function removeMediaQueryList(entry) {
652
+ if (!entry.mql) return;
653
+ entry.mql.onchange = null;
654
+ entry.mql = null;
655
+ }
656
+ return { ...props, ...methods };
657
+ }
658
+ const defaults$5 = {
659
+ // The property on entry objects to watch.
660
+ prop: "state",
661
+ // The default value or a function to compute the initial value.
662
+ value: null,
663
+ // The local storage key prefix.
664
+ keyPrefix: "VB:",
665
+ // The local storage key to use. If not provided, module name and prop value
666
+ // will be used e.g., "VB:ModalState".
667
+ key: null,
668
+ // Condition to determine whether or not to store the value in local storage.
669
+ condition: false,
670
+ // The function to run whenever the value changes.
671
+ onChange() {
672
+ }
673
+ };
674
+ function propStore(options = {}) {
675
+ const props = {
676
+ name: "propStore",
677
+ defaults: defaults$5,
678
+ options,
679
+ store: null
680
+ };
681
+ const methods = {
682
+ setup({ parent: parent2 }) {
683
+ this.store = localStore(getKey.call(this, parent2.module));
684
+ },
685
+ async onCreateEntry({ entry }) {
686
+ await setupPropStore.call(this, entry);
687
+ },
688
+ onDestroyEntry({ entry }) {
689
+ removePropStore.call(this, entry);
690
+ }
691
+ };
692
+ async function setupPropStore(entry) {
693
+ let _value = entry[this.settings.prop] || null;
694
+ const contextObj = { plugin: this, parent: entry.parent, entry };
695
+ Object.defineProperty(entry, this.settings.prop, {
696
+ configurable: true,
697
+ get() {
698
+ return _value;
699
+ },
700
+ set: async (newValue) => {
701
+ if (_value === newValue) return;
702
+ const oldValue = _value;
703
+ _value = newValue;
704
+ const condition = getValue(
705
+ this.settings.condition,
706
+ contextObj,
707
+ newValue,
708
+ oldValue
709
+ );
710
+ if (condition) {
711
+ this.store.set(entry.id, newValue);
712
+ }
713
+ await this.settings.onChange(contextObj, newValue, oldValue);
714
+ }
715
+ });
716
+ Object.defineProperty(entry, "store", {
717
+ configurable: true,
718
+ get: () => {
719
+ return this.store.get(entry.id);
720
+ },
721
+ set: (value) => {
722
+ entry[this.settings.prop] = value;
723
+ }
724
+ });
725
+ entry[this.settings.prop] = await getValue(this.settings.value, contextObj) || entry[this.settings.prop];
726
+ }
727
+ function getValue(obj, ...args) {
728
+ return typeof obj === "function" ? obj(...args) : obj;
729
+ }
730
+ async function removePropStore(entry) {
731
+ const currentValue = entry[this.settings.prop];
732
+ delete entry[this.settings.prop];
733
+ entry[this.settings.prop] = currentValue;
734
+ this.store.set(entry.id, null);
735
+ }
736
+ function getKey(moduleName) {
737
+ const prop = this.settings.prop.charAt(0).toUpperCase() + this.settings.prop.slice(1);
738
+ const key = this.settings.key || moduleName + prop;
739
+ return this.settings.keyPrefix + key;
740
+ }
741
+ return { ...props, ...methods };
742
+ }
743
+ const defaults$4 = {
744
+ where: null,
745
+ how: "append"
746
+ };
747
+ function teleport(options = {}) {
748
+ const props = {
749
+ name: "teleport",
750
+ defaults: defaults$4,
751
+ options
752
+ };
753
+ const methods = {
754
+ onCreateEntry({ plugin, entry }) {
755
+ teleport2(plugin, entry);
756
+ },
757
+ onDestroyEntry({ plugin, entry }) {
758
+ teleportReturn(plugin, entry);
759
+ }
760
+ };
761
+ function teleport2(plugin, entry) {
762
+ entry.teleport = () => {
763
+ if (typeof entry.teleportReturn === "function") {
764
+ entry.teleportReturn();
765
+ }
766
+ entry.teleportReturn = teleportElement(
767
+ entry.el,
768
+ entry.getSetting("teleport", { fallback: plugin.settings.where }),
769
+ entry.getSetting("teleportMethod", { fallback: plugin.settings.how })
770
+ );
771
+ };
772
+ entry.teleport();
773
+ entry.parent.emit("teleport", { plugin, parent, entry });
251
774
  }
775
+ function teleportReturn(plugin, entry) {
776
+ if (typeof entry.teleportReturn === "function") {
777
+ entry.teleportReturn();
778
+ }
779
+ entry.parent.emit("teleportReturn", { plugin, parent, entry });
780
+ }
781
+ return { ...props, ...methods };
252
782
  }
783
+ const defaults$3 = {
784
+ dataConfig: "config",
785
+ customProps: []
786
+ };
253
787
  class CollectionEntry {
254
- constructor(context, query, options = {}) {
255
- this.context = context;
788
+ constructor(parent2, query, options = {}) {
789
+ this.parent = parent2;
256
790
  this.id = (query == null ? void 0 : query.id) || query;
257
791
  this.el = getElement(query);
258
- this.settings = Object.assign({}, options);
792
+ this.settings = { ...options };
259
793
  this.dataConfig = {};
260
794
  this.customProps = {};
261
- this.returnRef = null;
262
795
  }
263
- applySettings(obj) {
264
- return Object.assign(this.settings, obj);
796
+ applySettings(options) {
797
+ return Object.assign(this.settings, options);
265
798
  }
266
- getDataConfig() {
267
- return Object.assign(this.dataConfig, getConfig(this.el, this.getSetting("dataConfig")));
799
+ getSetting(key, options) {
800
+ return getSetting.call(this, key, options);
268
801
  }
269
- getCustomProps() {
270
- return Object.assign(this.customProps, getCustomProps(this));
802
+ buildDataConfig() {
803
+ return Object.assign(
804
+ this.dataConfig,
805
+ getDataConfig(this.el, this.getSetting("dataConfig"))
806
+ );
271
807
  }
272
- getSetting(key, options = {}) {
273
- return getSetting.call(this, key, options);
808
+ buildCustomProps() {
809
+ return Object.assign(this.customProps, getCustomProps(this));
274
810
  }
275
- async mount(options = {}) {
811
+ async init(options = {}) {
276
812
  if (this.el === null) {
277
- throw new Error(`${this.context.module} element was not found with ID: "${this.id}"`);
813
+ throw new Error(
814
+ `${this.parent.module} element was not found with ID: "${this.id}"`
815
+ );
278
816
  }
279
817
  this.applySettings(options);
280
- this.getDataConfig();
281
- this.getCustomProps();
282
- await lifecycleHook.call(this, "beforeMount");
283
- if (this.getSetting("teleport")) {
284
- this.teleport();
818
+ this.buildDataConfig();
819
+ this.buildCustomProps();
820
+ }
821
+ async destroy() {
822
+ Object.getOwnPropertyNames(this).forEach((prop) => {
823
+ if (prop !== "id") {
824
+ delete this[prop];
825
+ }
826
+ });
827
+ }
828
+ }
829
+ class Collection {
830
+ constructor(options = {}) {
831
+ this.module = this.constructor.name;
832
+ this.collection = [];
833
+ this.entryClass = CollectionEntry;
834
+ this.settings = { ...defaults$3, ...options };
835
+ this.plugins = new PluginsArray(this.settings.presets);
836
+ this.events = {};
837
+ Object.assign(this, eventEmitter);
838
+ }
839
+ get(value, key = "id") {
840
+ return this.collection.find((entry) => entry[key] === value);
841
+ }
842
+ applySettings(options) {
843
+ return Object.assign(this.settings, options);
844
+ }
845
+ async createEntry(query, config) {
846
+ const entry = new this.entryClass(this, query, config);
847
+ await maybeRunMethod(entry, "init");
848
+ await dispatchLifecycleHook("onCreateEntry", this, entry);
849
+ return entry;
850
+ }
851
+ async destroyEntry(entry) {
852
+ await dispatchLifecycleHook("onDestroyEntry", this, entry);
853
+ await maybeRunMethod(entry, "destroy");
854
+ return entry;
855
+ }
856
+ async register(query, config = {}) {
857
+ const element = getElement(query);
858
+ if (element === null) {
859
+ throw new Error(
860
+ `${this.module} element was not found with ID: "${(query == null ? void 0 : query.id) || query}"`
861
+ );
862
+ }
863
+ const index2 = this.collection.findIndex((item) => item.id === element.id);
864
+ if (~index2) {
865
+ const entry = this.collection[index2];
866
+ entry.el = element;
867
+ if (typeof entry.init === "function") {
868
+ await entry.init(config);
869
+ }
870
+ return entry;
871
+ } else {
872
+ const entry = await this.createEntry(element, config);
873
+ this.collection.push(entry);
874
+ await dispatchLifecycleHook("onRegisterEntry", this, entry);
875
+ return entry;
285
876
  }
286
- await lifecycleHook.call(this, "afterMount");
287
877
  }
288
- async unmount(reMount = false) {
289
- await lifecycleHook.call(this, "beforeUnmount", reMount);
290
- if (this.getSetting("teleport")) {
291
- this.teleportReturn();
878
+ async deregister(id) {
879
+ const index2 = this.collection.findIndex((entry) => entry.id === id);
880
+ if (~index2) {
881
+ const entry = await this.destroyEntry(this.collection[index2]);
882
+ await dispatchLifecycleHook(
883
+ "onDeregisterEntry",
884
+ this,
885
+ this.collection[index2]
886
+ );
887
+ this.collection.splice(index2, 1);
888
+ return entry;
292
889
  }
293
- await lifecycleHook.call(this, "afterUnmount", reMount);
890
+ return null;
294
891
  }
295
- teleport(ref = this.getSetting("teleport"), method = this.getSetting("teleportMethod")) {
296
- if (!this.returnRef) {
297
- this.returnRef = teleport(this.el, ref, method);
298
- return this.el;
299
- } else {
300
- console.error("Element has already been teleported:", this.el);
301
- return false;
892
+ async mount(options = {}) {
893
+ var _a;
894
+ this.applySettings(options);
895
+ for (const plugin of ((_a = this.settings) == null ? void 0 : _a.plugins) || []) {
896
+ this.plugins.add(plugin);
302
897
  }
303
- }
304
- teleportReturn() {
305
- if (this.returnRef) {
306
- this.returnRef = teleport(this.el, this.returnRef);
307
- return this.el;
308
- } else {
309
- console.error("No return reference found:", this.el);
310
- return false;
898
+ for (const plugin of this.plugins) {
899
+ await maybeRunMethod(plugin, "setup", { plugin, parent: this });
311
900
  }
901
+ await dispatchLifecycleHook("beforeMount", this);
902
+ const els = document.querySelectorAll(this.settings.selector);
903
+ for (const el of els) {
904
+ await this.register(el);
905
+ }
906
+ await dispatchLifecycleHook("afterMount", this);
907
+ return this;
312
908
  }
313
- }
314
- class FocusTrap {
315
- constructor(el = null, selectorFocus = "[data-focus]") {
316
- __privateAdd(this, _focusable);
317
- __privateAdd(this, _handleFocusTrap);
318
- __privateAdd(this, _handleFocusLock);
319
- this.el = el;
320
- this.selectorFocus = selectorFocus;
321
- __privateSet(this, _handleFocusTrap, handleFocusTrap.bind(this));
322
- __privateSet(this, _handleFocusLock, handleFocusLock.bind(this));
323
- }
324
- get focusable() {
325
- return __privateGet(this, _focusable);
326
- }
327
- set focusable(value) {
328
- __privateSet(this, _focusable, value);
329
- if (__privateGet(this, _focusable).length) {
330
- document.removeEventListener("keydown", __privateGet(this, _handleFocusLock));
331
- document.addEventListener("keydown", __privateGet(this, _handleFocusTrap));
332
- } else {
333
- document.removeEventListener("keydown", __privateGet(this, _handleFocusTrap));
334
- document.addEventListener("keydown", __privateGet(this, _handleFocusLock));
335
- }
336
- }
337
- get focusableFirst() {
338
- return this.focusable[0];
339
- }
340
- get focusableLast() {
341
- return this.focusable[this.focusable.length - 1];
342
- }
343
- mount(el, selectorFocus) {
344
- if (el) this.el = el;
345
- if (selectorFocus) this.selectorFocus = selectorFocus;
346
- this.focusable = this.getFocusable();
347
- this.focus();
348
- }
349
- unmount() {
350
- this.el = null;
351
- this.focusable = [];
352
- document.removeEventListener("keydown", __privateGet(this, _handleFocusTrap));
353
- document.removeEventListener("keydown", __privateGet(this, _handleFocusLock));
354
- }
355
- focus(el = this.el, selectorFocus = this.selectorFocus) {
356
- const result = el.querySelector(selectorFocus) || el;
357
- result.focus();
358
- }
359
- getFocusable(el = this.el) {
360
- const focusable = [];
361
- const initFocus = document.activeElement;
362
- const initScrollTop = el.scrollTop;
363
- const selector = focusableSelectors.join(",");
364
- const els = el.querySelectorAll(selector);
365
- els.forEach((el2) => {
366
- el2.focus();
367
- if (document.activeElement === el2) {
368
- focusable.push(el2);
369
- }
370
- });
371
- el.scrollTop = initScrollTop;
372
- initFocus.focus();
373
- return focusable;
374
- }
375
- }
376
- _focusable = new WeakMap();
377
- _handleFocusTrap = new WeakMap();
378
- _handleFocusLock = new WeakMap();
379
- const notInert = ":not([inert])";
380
- const notNegTabIndex = ':not([tabindex^="-"])';
381
- const notDisabled = ":not(:disabled)";
382
- const focusableSelectors = [
383
- `a[href]${notInert}${notNegTabIndex}`,
384
- `area[href]${notInert}${notNegTabIndex}`,
385
- `input:not([type="hidden"]):not([type="radio"])${notInert}${notNegTabIndex}${notDisabled}`,
386
- `input[type="radio"]${notInert}${notNegTabIndex}${notDisabled}`,
387
- `select${notInert}${notNegTabIndex}${notDisabled}`,
388
- `textarea${notInert}${notNegTabIndex}${notDisabled}`,
389
- `button${notInert}${notNegTabIndex}${notDisabled}`,
390
- `details${notInert} > summary:first-of-type${notNegTabIndex}`,
391
- `iframe${notInert}${notNegTabIndex}`,
392
- `audio[controls]${notInert}${notNegTabIndex}`,
393
- `video[controls]${notInert}${notNegTabIndex}`,
394
- `[contenteditable]${notInert}${notNegTabIndex}`,
395
- `[tabindex]${notInert}${notNegTabIndex}`
396
- ];
397
- function handleFocusTrap(event) {
398
- const isTab = event.key === "Tab" || event.keyCode === 9;
399
- if (!isTab) return;
400
- if (event.shiftKey) {
401
- if (document.activeElement === this.focusableFirst || document.activeElement === this.el) {
402
- event.preventDefault();
403
- this.focusableLast.focus();
909
+ async unmount() {
910
+ await dispatchLifecycleHook("beforeUnmount", this);
911
+ while (this.collection.length > 0) {
912
+ await this.deregister(this.collection[0].id);
404
913
  }
405
- } else {
406
- if (document.activeElement === this.focusableLast || document.activeElement === this.el) {
407
- event.preventDefault();
408
- this.focusableFirst.focus();
914
+ await dispatchLifecycleHook("afterUnmount", this);
915
+ for (const plugin of this.plugins) {
916
+ await maybeRunMethod(plugin, "teardown", { plugin, parent: this });
409
917
  }
410
- }
411
- }
412
- function handleFocusLock(event) {
413
- const isTab = event.key === "Tab" || event.keyCode === 9;
414
- if (isTab) event.preventDefault();
415
- }
416
- function localStore(key, enable = true) {
417
- const local = localStorage.getItem(key);
418
- const store = local ? JSON.parse(local) : {};
419
- return {
420
- get(prop) {
421
- return prop ? store[prop] : store;
422
- },
423
- set(prop, value) {
424
- if (value) {
425
- store[prop] = value;
426
- } else {
427
- delete store[prop];
428
- }
429
- if (enable) localStorage.setItem(key, JSON.stringify(store));
430
- return store;
918
+ for (const plugin of [...this.plugins]) {
919
+ this.plugins.remove(plugin.name);
431
920
  }
432
- };
433
- }
434
- function teleport(what, where, how) {
435
- const isComment = where.nodeType === Node.COMMENT_NODE;
436
- const isElement2 = where.nodeType === Node.ELEMENT_NODE;
437
- where = isComment || isElement2 ? where : document.querySelector(where);
438
- if (isComment) how = "after";
439
- if (!where) throw new Error(`Not a valid teleport reference: '${where}'`);
440
- if (typeof where[how] != "function") throw new Error(`Not a valid teleport method: '${how}'`);
441
- let returnRef = null;
442
- if (!isComment) {
443
- returnRef = document.createComment("teleported #" + what.id);
444
- what.before(returnRef);
445
- }
446
- where[how](what);
447
- if (isComment) {
448
- where.remove();
921
+ return this;
449
922
  }
450
- return returnRef;
451
923
  }
452
924
  function themeStore(options) {
453
925
  const settings = {
@@ -473,9 +945,9 @@ function themeStore(options) {
473
945
  }
474
946
  const profile = localStore(settings.storeKey);
475
947
  const api = {
476
- // Store our settings in the API.
948
+ // Store our settings in the API
477
949
  settings,
478
- // Actions.
950
+ // Actions
479
951
  add(value) {
480
952
  settings.themes.push(value);
481
953
  },
@@ -486,7 +958,7 @@ function themeStore(options) {
486
958
  callback(name) {
487
959
  callbacks[name].call(this);
488
960
  },
489
- // Getters.
961
+ // Getters
490
962
  get class() {
491
963
  return `${settings.prefix}${this.theme}`;
492
964
  },
@@ -496,7 +968,7 @@ function themeStore(options) {
496
968
  get themes() {
497
969
  return settings.themes;
498
970
  },
499
- // Setup the theme get and set methods.
971
+ // Setup the theme get and set methods
500
972
  get theme() {
501
973
  return profile.get("theme") || "root";
502
974
  },
@@ -518,32 +990,61 @@ function themeStore(options) {
518
990
  }
519
991
  const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
520
992
  __proto__: null,
521
- Breakpoint,
522
993
  Collection,
523
994
  CollectionEntry,
524
995
  FocusTrap,
996
+ FocusableArray,
997
+ PluginsArray,
998
+ StackArray,
525
999
  cssVar,
526
- getConfig,
1000
+ debug,
1001
+ dispatchLifecycleHook,
1002
+ eventEmitter,
1003
+ focusTrap,
1004
+ focusableSelectors,
527
1005
  getCustomProps,
1006
+ getDataConfig,
528
1007
  getElement,
529
1008
  getPrefix,
530
1009
  getSetting,
531
- lifecycleHook,
532
1010
  localStore,
1011
+ maybeRunMethod,
1012
+ mediaQuery,
1013
+ propStore,
533
1014
  setGlobalState,
534
1015
  teleport,
1016
+ teleportElement,
535
1017
  themeStore,
536
1018
  toCamel,
537
1019
  toKebab,
538
1020
  toMilliseconds,
539
1021
  transition
540
1022
  }, Symbol.toStringTag, { value: "Module" }));
1023
+ const presets = {
1024
+ focusTrap: {
1025
+ condition: ({ entry }) => {
1026
+ return entry.state === "closed" || entry.state === "opened" && entry.mode === "modal";
1027
+ }
1028
+ },
1029
+ mediaQuery: {
1030
+ onChange(event, entry) {
1031
+ entry.mode = event.matches ? "inline" : "modal";
1032
+ }
1033
+ },
1034
+ propStore: {
1035
+ prop: "inlineState",
1036
+ value: ({ entry }) => entry.store,
1037
+ condition: ({ entry }) => ["opened", "closed", "indeterminate"].includes(entry.state),
1038
+ onChange: ({ entry }) => entry.applyState()
1039
+ }
1040
+ };
541
1041
  const defaults$2 = {
1042
+ // Plugin presets
1043
+ presets,
542
1044
  // Data attributes
543
1045
  dataOpen: "drawer-open",
544
1046
  dataClose: "drawer-close",
545
1047
  dataToggle: "drawer-toggle",
546
- dataBreakpoint: "drawer-breakpoint",
547
1048
  // Selectors
548
1049
  selector: ".drawer",
549
1050
  selectorDialog: ".drawer__dialog",
@@ -559,90 +1060,13 @@ const defaults$2 = {
559
1060
  // Classes
560
1061
  classModal: "drawer_modal",
561
1062
  // Feature toggles
562
- customProps: [
563
- "transition-duration"
564
- ],
1063
+ customProps: ["transition-duration"],
565
1064
  breakpoints: null,
566
1065
  customEventPrefix: "drawer:",
567
- store: true,
568
- storeKey: "VB:DrawerState",
569
1066
  setTabindex: true,
570
- teleport: null,
571
- teleportMethod: "prepend",
572
1067
  transition: true,
573
1068
  transitionDuration: 300
574
1069
  };
575
- function applyInitialState(entry) {
576
- if (entry.store === "opened") {
577
- entry.open(false, false);
578
- } else if (entry.store === "closed") {
579
- entry.close(false, false);
580
- } else if (entry.store === "indeterminate") {
581
- entry.state = "indeterminate";
582
- } else {
583
- if (entry.el.classList.contains(entry.getSetting("stateOpened"))) {
584
- entry.open(false, false);
585
- } else if (entry.el.classList.contains(entry.getSetting("stateClosed"))) {
586
- entry.close(false, false);
587
- } else {
588
- entry.state = "indeterminate";
589
- }
590
- }
591
- }
592
- async function applyInlineState(entry) {
593
- if (entry.store === "opened") {
594
- await entry.open(false, false);
595
- } else if (entry.store === "closed") {
596
- await entry.close(false, false);
597
- } else if (entry.store === "indeterminate") {
598
- if (entry.state != "indeterminate") {
599
- entry.state = "indeterminate";
600
- }
601
- } else {
602
- if (entry.state != entry.inlineState) {
603
- entry.state = entry.inlineState;
604
- }
605
- if (entry.inlineState === "opened") {
606
- await entry.open(false, false);
607
- } else if (entry.inlineState === "closed") {
608
- await entry.close(false, false);
609
- }
610
- }
611
- }
612
- function getBreakpoint(drawer) {
613
- const prefix = getPrefix();
614
- const bp = drawer.getAttribute(`data-${this.settings.dataBreakpoint}`);
615
- if (this.settings.breakpoints && this.settings.breakpoints[bp]) {
616
- return this.settings.breakpoints[bp];
617
- } else if (getComputedStyle(document.body).getPropertyValue(`--${prefix}breakpoint-${bp}`).trim()) {
618
- return getComputedStyle(document.body).getPropertyValue(`--${prefix}breakpoint-${bp}`).trim();
619
- } else {
620
- return bp;
621
- }
622
- }
623
- function getDrawer(query) {
624
- const entry = typeof query === "string" ? this.get(query) : query;
625
- if (entry) {
626
- return entry;
627
- } else {
628
- throw new Error(`Drawer not found in collection with id of "${query.id || query}".`);
629
- }
630
- }
631
- function updateFocusState$1(entry) {
632
- if (entry.state === "opened") {
633
- if (entry.mode === "modal") {
634
- this.focusTrap.mount(entry.dialog, this.settings.selectorFocus);
635
- } else {
636
- this.focusTrap.focus(entry.dialog, this.settings.selectorFocus);
637
- }
638
- } else {
639
- if (entry.trigger) {
640
- entry.trigger.focus();
641
- entry.trigger = null;
642
- }
643
- this.focusTrap.unmount();
644
- }
645
- }
646
1070
  function switchMode(entry) {
647
1071
  switch (entry.mode) {
648
1072
  case "inline":
@@ -656,61 +1080,57 @@ function switchMode(entry) {
656
1080
  async function toInline(entry) {
657
1081
  entry.el.classList.remove(entry.getSetting("classModal"));
658
1082
  entry.dialog.removeAttribute("aria-modal");
659
- setGlobalState(false, entry.getSetting("selectorInert"), entry.getSetting("selectorOverflow"));
660
- this.focusTrap.unmount();
661
- await applyInlineState(entry);
662
- entry.el.dispatchEvent(new CustomEvent(entry.getSetting("customEventPrefix") + "switchMode", {
663
- detail: this,
664
- bubbles: true
665
- }));
1083
+ setGlobalState(
1084
+ false,
1085
+ entry.getSetting("selectorInert"),
1086
+ entry.getSetting("selectorOverflow")
1087
+ );
1088
+ entry.applyState();
1089
+ entry.el.dispatchEvent(
1090
+ new CustomEvent(entry.getSetting("customEventPrefix") + "switchMode", {
1091
+ detail: this,
1092
+ bubbles: true
1093
+ })
1094
+ );
1095
+ await entry.parent.emit("switchMode", entry);
666
1096
  return entry;
667
1097
  }
668
1098
  async function toModal(entry) {
669
1099
  entry.el.classList.add(entry.getSetting("classModal"));
670
1100
  entry.dialog.setAttribute("aria-modal", "true");
671
1101
  await entry.close(false, false);
672
- entry.el.dispatchEvent(new CustomEvent(entry.getSetting("customEventPrefix") + "switchMode", {
673
- detail: this,
674
- bubbles: true
675
- }));
1102
+ entry.el.dispatchEvent(
1103
+ new CustomEvent(entry.getSetting("customEventPrefix") + "switchMode", {
1104
+ detail: this,
1105
+ bubbles: true
1106
+ })
1107
+ );
1108
+ await entry.parent.emit("switchMode", entry);
676
1109
  return entry;
677
1110
  }
678
1111
  class DrawerEntry extends CollectionEntry {
679
- constructor(context, query, options = {}) {
680
- super(context, query, options);
1112
+ constructor(parent2, query, options = {}) {
1113
+ super(parent2, query, options);
681
1114
  __privateAdd(this, _mode);
682
- __privateAdd(this, _state);
683
- __privateAdd(this, _breakpoint);
684
1115
  this.dialog = null;
685
1116
  this.trigger = null;
686
- __privateSet(this, _breakpoint, new Breakpoint());
1117
+ this.state = null;
1118
+ this.inlineState = null;
687
1119
  __privateSet(this, _mode, "indeterminate");
688
- __privateSet(this, _state, "indeterminate");
689
- this.inlineState = "indeterminate";
690
- }
691
- get breakpoint() {
692
- return getBreakpoint.call(this.context, this.el);
693
- }
694
- get store() {
695
- return this.context.store.get(this.id);
696
1120
  }
697
1121
  get mode() {
698
1122
  return __privateGet(this, _mode);
699
1123
  }
700
1124
  set mode(value) {
1125
+ if (__privateGet(this, _mode) === value) return;
701
1126
  __privateSet(this, _mode, value);
702
- switchMode.call(this.context, this);
1127
+ switchMode.call(this.parent, this);
703
1128
  }
704
- get state() {
705
- return __privateGet(this, _state);
706
- }
707
- set state(value) {
708
- __privateSet(this, _state, value);
709
- if (this.mode === "inline" && value != "opening" && value != "closing") {
1129
+ setState(value) {
1130
+ this.state = value;
1131
+ const ignoreStates = ["opening", "closing"];
1132
+ if (this.mode === "inline" && !ignoreStates.includes(value)) {
710
1133
  this.inlineState = value;
711
- if (this.getSetting("store")) {
712
- this.context.store.set(this.id, value);
713
- }
714
1134
  }
715
1135
  if (value === "indeterminate") {
716
1136
  this.el.classList.remove(this.getSetting("stateOpened"));
@@ -719,56 +1139,63 @@ class DrawerEntry extends CollectionEntry {
719
1139
  this.el.classList.remove(this.getSetting("stateClosing"));
720
1140
  }
721
1141
  }
1142
+ async applyState() {
1143
+ if (this.mode === "modal") return;
1144
+ if (this.inlineState === "opened") {
1145
+ return await this.open(false, false);
1146
+ }
1147
+ if (this.inlineState === "closed") {
1148
+ return await this.close(false, false);
1149
+ }
1150
+ if (this.state === null) {
1151
+ if (this.el.classList.contains(this.getSetting("stateOpened"))) {
1152
+ return await this.open(false, false);
1153
+ }
1154
+ if (this.el.classList.contains(this.getSetting("stateClosed"))) {
1155
+ return await this.close(false, false);
1156
+ }
1157
+ }
1158
+ return this.setState("indeterminate");
1159
+ }
722
1160
  async open(transition2, focus) {
723
- return this.context.open(this, transition2, focus);
1161
+ return this.parent.open(this, transition2, focus);
724
1162
  }
725
1163
  async close(transition2, focus) {
726
- return this.context.close(this, transition2, focus);
1164
+ return this.parent.close(this, transition2, focus);
727
1165
  }
728
1166
  async toggle(transition2, focus) {
729
- return this.context.toggle(this, transition2, focus);
1167
+ return this.parent.toggle(this, transition2, focus);
730
1168
  }
731
1169
  async deregister() {
732
- return this.context.deregister(this.id);
733
- }
734
- mountBreakpoint() {
735
- const value = this.breakpoint;
736
- const handler = this.handleBreakpoint.bind(this);
737
- __privateGet(this, _breakpoint).mount(value, handler);
738
- }
739
- unmountBreakpoint() {
740
- __privateGet(this, _breakpoint).unmount();
741
- }
742
- handleBreakpoint(event) {
743
- const bpMode = event.matches ? "inline" : "modal";
744
- if (this.mode != bpMode) {
745
- this.mode = bpMode;
746
- }
1170
+ return this.parent.deregister(this.id);
747
1171
  }
748
- async beforeMount() {
1172
+ async onCreateEntry() {
749
1173
  const dialog = this.el.querySelector(this.getSetting("selectorDialog"));
750
1174
  this.dialog = dialog ? dialog : this.el;
751
1175
  if (this.getSetting("setTabindex")) {
752
1176
  this.dialog.setAttribute("tabindex", "-1");
753
1177
  }
754
- applyInitialState(this);
1178
+ await this.applyState();
755
1179
  this.inlineState = this.state;
756
1180
  this.mode = this.el.classList.contains(this.getSetting("classModal")) ? "modal" : "inline";
757
- if (this.breakpoint) {
758
- this.mountBreakpoint();
759
- }
760
1181
  }
761
- async beforeUnmount(close2 = true) {
762
- if (close2 && this.state === "opened") {
1182
+ async onDestroyEntry() {
1183
+ if (this.mode === "modal" && this.state === "opened") {
763
1184
  await this.close(false);
764
1185
  }
765
- this.context.store.set(this.id);
766
- this.unmountBreakpoint();
767
1186
  }
768
1187
  }
769
1188
  _mode = new WeakMap();
770
- _state = new WeakMap();
771
- _breakpoint = new WeakMap();
1189
+ function getDrawer(query) {
1190
+ const entry = typeof query === "string" ? this.get(query) : query;
1191
+ if (entry) {
1192
+ return entry;
1193
+ } else {
1194
+ throw new Error(
1195
+ `Drawer not found in collection with id of "${query.id || query}".`
1196
+ );
1197
+ }
1198
+ }
772
1199
  async function handleClick$2(event) {
773
1200
  const trigger = event.target.closest(`
774
1201
  [data-${this.settings.dataOpen}],
@@ -801,8 +1228,8 @@ async function handleClick$2(event) {
801
1228
  entry.trigger = trigger;
802
1229
  return entry.close();
803
1230
  } else {
804
- const parent = event.target.closest(this.settings.selector);
805
- if (parent) return this.close(parent.id);
1231
+ const parent2 = event.target.closest(this.settings.selector);
1232
+ if (parent2) return this.close(parent2.id);
806
1233
  }
807
1234
  });
808
1235
  }
@@ -817,10 +1244,20 @@ function handleKeydown$2(event) {
817
1244
  if (this.activeModal) return this.close(this.activeModal.id);
818
1245
  }
819
1246
  }
1247
+ function updateFocusState$1(entry) {
1248
+ if (entry.state === "opened") {
1249
+ (entry.dialog.querySelector(this.settings.selectorFocus) || entry.dialog).focus();
1250
+ } else {
1251
+ if (entry.trigger) {
1252
+ entry.trigger.focus();
1253
+ entry.trigger = null;
1254
+ }
1255
+ }
1256
+ }
820
1257
  async function open$2(query, transitionOverride, focus = true) {
821
1258
  const entry = getDrawer.call(this, query);
822
- if (entry.state === "closed" || entry.state === "indeterminate") {
823
- entry.state = "opening";
1259
+ if (entry.state === "closed" || entry.state === "indeterminate" || entry.state === null) {
1260
+ entry.setState("opening");
824
1261
  if (transitionOverride != void 0 ? transitionOverride : entry.getSetting("transition")) {
825
1262
  await transition(
826
1263
  entry.el,
@@ -833,22 +1270,30 @@ async function open$2(query, transitionOverride, focus = true) {
833
1270
  entry.el.classList.add(entry.getSetting("stateOpened"));
834
1271
  entry.el.classList.remove(entry.getSetting("stateClosed"));
835
1272
  }
836
- entry.state = "opened";
837
- if (entry.mode === "modal") setGlobalState(true, entry.getSetting("selectorInert"), entry.getSetting("selectorOverflow"));
1273
+ entry.setState("opened");
1274
+ if (entry.mode === "modal")
1275
+ setGlobalState(
1276
+ true,
1277
+ entry.getSetting("selectorInert"),
1278
+ entry.getSetting("selectorOverflow")
1279
+ );
838
1280
  if (focus) {
839
1281
  updateFocusState$1.call(this, entry);
840
1282
  }
841
- entry.el.dispatchEvent(new CustomEvent(entry.getSetting("customEventPrefix") + "opened", {
842
- detail: this,
843
- bubbles: true
844
- }));
1283
+ entry.el.dispatchEvent(
1284
+ new CustomEvent(entry.getSetting("customEventPrefix") + "opened", {
1285
+ detail: this,
1286
+ bubbles: true
1287
+ })
1288
+ );
1289
+ await entry.parent.emit("opened", entry);
845
1290
  }
846
1291
  return entry;
847
1292
  }
848
1293
  async function close$2(query, transitionOverride, focus = true) {
849
1294
  const entry = getDrawer.call(this, query);
850
- if (entry.state === "opened" || entry.state === "indeterminate") {
851
- entry.state = "closing";
1295
+ if (entry.state === "opened" || entry.state === "indeterminate" || entry.state === null) {
1296
+ entry.setState("closing");
852
1297
  document.activeElement.blur();
853
1298
  if (transitionOverride != void 0 ? transitionOverride : entry.getSetting("transition")) {
854
1299
  await transition(
@@ -862,15 +1307,23 @@ async function close$2(query, transitionOverride, focus = true) {
862
1307
  entry.el.classList.add(entry.getSetting("stateClosed"));
863
1308
  entry.el.classList.remove(entry.getSetting("stateOpened"));
864
1309
  }
865
- entry.state = "closed";
866
- if (entry.mode === "modal") setGlobalState(false, entry.getSetting("selectorInert"), entry.getSetting("selectorOverflow"));
1310
+ entry.setState("closed");
1311
+ if (entry.mode === "modal")
1312
+ setGlobalState(
1313
+ false,
1314
+ entry.getSetting("selectorInert"),
1315
+ entry.getSetting("selectorOverflow")
1316
+ );
867
1317
  if (focus) {
868
1318
  updateFocusState$1.call(this, entry);
869
1319
  }
870
- entry.el.dispatchEvent(new CustomEvent(entry.getSetting("customEventPrefix") + "closed", {
871
- detail: this,
872
- bubbles: true
873
- }));
1320
+ entry.el.dispatchEvent(
1321
+ new CustomEvent(entry.getSetting("customEventPrefix") + "closed", {
1322
+ detail: this,
1323
+ bubbles: true
1324
+ })
1325
+ );
1326
+ await entry.parent.emit("closed", entry);
874
1327
  }
875
1328
  return entry;
876
1329
  }
@@ -887,19 +1340,16 @@ class Drawer extends Collection {
887
1340
  super({ ...defaults$2, ...options });
888
1341
  __privateAdd(this, _handleClick);
889
1342
  __privateAdd(this, _handleKeydown);
890
- this.focusTrap = new FocusTrap();
1343
+ this.module = "Drawer";
1344
+ this.entryClass = DrawerEntry;
891
1345
  __privateSet(this, _handleClick, handleClick$2.bind(this));
892
1346
  __privateSet(this, _handleKeydown, handleKeydown$2.bind(this));
893
- this.store = localStore(this.settings.storeKey, this.settings.store);
894
1347
  }
895
1348
  get activeModal() {
896
1349
  return this.collection.find((entry) => {
897
1350
  return entry.state === "opened" && entry.mode === "modal";
898
1351
  });
899
1352
  }
900
- async createEntry(query, config) {
901
- return new DrawerEntry(this, query, config);
902
- }
903
1353
  async open(id, transition2, focus) {
904
1354
  return open$2.call(this, id, transition2, focus);
905
1355
  }
@@ -942,19 +1392,15 @@ const defaults$1 = {
942
1392
  stateClosing: "is-closing",
943
1393
  stateClosed: "is-closed",
944
1394
  // Feature settings
945
- customProps: [
946
- "transition-duration"
947
- ],
1395
+ customProps: ["transition-duration"],
948
1396
  customEventPrefix: "modal:",
949
1397
  setTabindex: true,
950
- teleport: null,
951
- teleportMethod: "append",
952
1398
  transition: true,
953
1399
  transitionDuration: 300
954
1400
  };
955
1401
  class ModalEntry extends CollectionEntry {
956
- constructor(context, query, options = {}) {
957
- super(context, query, options);
1402
+ constructor(parent2, query, options = {}) {
1403
+ super(parent2, query, options);
958
1404
  this.state = "closed";
959
1405
  this.dialog = null;
960
1406
  }
@@ -962,18 +1408,18 @@ class ModalEntry extends CollectionEntry {
962
1408
  return this.dialog.matches(this.getSetting("selectorRequired"));
963
1409
  }
964
1410
  async open(transition2, focus) {
965
- return this.context.open(this, transition2, focus);
1411
+ return this.parent.open(this, transition2, focus);
966
1412
  }
967
1413
  async close(transition2, focus) {
968
- return this.context.close(this, transition2, focus);
1414
+ return this.parent.close(this, transition2, focus);
969
1415
  }
970
1416
  async replace(transition2, focus) {
971
- return this.context.replace(this, transition2, focus);
1417
+ return this.parent.replace(this, transition2, focus);
972
1418
  }
973
1419
  async deregister() {
974
- return this.context.deregister(this.id);
1420
+ return this.parent.deregister(this.id);
975
1421
  }
976
- async beforeMount() {
1422
+ async onCreateEntry() {
977
1423
  const dialog = this.el.querySelector(this.getSetting("selectorDialog"));
978
1424
  this.dialog = dialog ? dialog : this.el;
979
1425
  this.dialog.setAttribute("aria-modal", "true");
@@ -984,7 +1430,7 @@ class ModalEntry extends CollectionEntry {
984
1430
  this.dialog.setAttribute("tabindex", "-1");
985
1431
  }
986
1432
  }
987
- async afterRegister() {
1433
+ async onRegisterEntry() {
988
1434
  if (this.el.classList.contains(this.getSetting("stateOpened"))) {
989
1435
  await this.open(false);
990
1436
  } else {
@@ -993,11 +1439,9 @@ class ModalEntry extends CollectionEntry {
993
1439
  this.el.classList.add(this.getSetting("stateClosed"));
994
1440
  }
995
1441
  }
996
- async beforeUnmount(reMount = false) {
997
- if (!reMount && this.state === "opened") {
1442
+ async onDestroyEntry() {
1443
+ if (this.state === "opened") {
998
1444
  await this.close(false);
999
- } else {
1000
- this.context.stack.remove(this);
1001
1445
  }
1002
1446
  }
1003
1447
  }
@@ -1006,18 +1450,9 @@ function getModal(query) {
1006
1450
  if (entry) {
1007
1451
  return entry;
1008
1452
  } else {
1009
- throw new Error(`Modal not found in collection with id of "${query.id || query}".`);
1010
- }
1011
- }
1012
- function updateFocusState() {
1013
- if (this.active) {
1014
- this.focusTrap.mount(this.active.dialog, this.settings.selectorFocus);
1015
- } else {
1016
- if (this.trigger) {
1017
- this.trigger.focus();
1018
- this.trigger = null;
1019
- }
1020
- this.focusTrap.unmount();
1453
+ throw new Error(
1454
+ `Modal not found in collection with id of "${query.id || query}".`
1455
+ );
1021
1456
  }
1022
1457
  }
1023
1458
  async function handleClick$1(event) {
@@ -1058,6 +1493,16 @@ function handleKeydown$1(event) {
1058
1493
  }
1059
1494
  }
1060
1495
  }
1496
+ function updateFocusState() {
1497
+ if (this.active) {
1498
+ (this.active.dialog.querySelector(this.settings.selectorFocus) || this.active.dialog).focus();
1499
+ } else {
1500
+ if (this.trigger) {
1501
+ this.trigger.focus();
1502
+ this.trigger = null;
1503
+ }
1504
+ }
1505
+ }
1061
1506
  async function open$1(query, transitionOverride = void 0, focus = true) {
1062
1507
  const entry = getModal.call(this, query);
1063
1508
  this.stack.moveToTop(entry);
@@ -1081,10 +1526,13 @@ async function open$1(query, transitionOverride = void 0, focus = true) {
1081
1526
  if (focus) {
1082
1527
  updateFocusState.call(this);
1083
1528
  }
1084
- entry.el.dispatchEvent(new CustomEvent(entry.getSetting("customEventPrefix") + "opened", {
1085
- detail: this,
1086
- bubbles: true
1087
- }));
1529
+ entry.el.dispatchEvent(
1530
+ new CustomEvent(entry.getSetting("customEventPrefix") + "opened", {
1531
+ detail: entry,
1532
+ bubbles: true
1533
+ })
1534
+ );
1535
+ await entry.parent.emit("opened", entry);
1088
1536
  return entry;
1089
1537
  }
1090
1538
  async function close$1(query, transitionOverride, focus = true) {
@@ -1109,23 +1557,25 @@ async function close$1(query, transitionOverride, focus = true) {
1109
1557
  if (focus) {
1110
1558
  updateFocusState.call(this);
1111
1559
  }
1112
- entry.el.dispatchEvent(new CustomEvent(entry.getSetting("customEventPrefix") + "closed", {
1113
- detail: this,
1114
- bubbles: true
1115
- }));
1560
+ entry.el.dispatchEvent(
1561
+ new CustomEvent(entry.getSetting("customEventPrefix") + "closed", {
1562
+ detail: entry,
1563
+ bubbles: true
1564
+ })
1565
+ );
1566
+ await entry.parent.emit("closed", entry);
1116
1567
  }
1117
1568
  return entry;
1118
1569
  }
1119
1570
  async function closeAll$1(exclude, transition2) {
1120
1571
  const result = [];
1121
- await Promise.all(this.stack.value.map(async (modal) => {
1122
- if (exclude && exclude === modal.id) {
1123
- Promise.resolve();
1124
- } else {
1125
- result.push(await close$1.call(this, modal, transition2, false));
1126
- }
1127
- modal.trigger = null;
1128
- }));
1572
+ await Promise.all(
1573
+ this.stack.copy.map(async (entry) => {
1574
+ if (exclude && exclude === entry.id) return;
1575
+ result.push(await close$1.call(this, entry, transition2, false));
1576
+ entry.trigger = null;
1577
+ })
1578
+ );
1129
1579
  return result;
1130
1580
  }
1131
1581
  async function replace(query, transition2, focus = true) {
@@ -1144,72 +1594,29 @@ async function replace(query, transition2, focus = true) {
1144
1594
  }
1145
1595
  return { opened: resultOpened, closed: resultClosed };
1146
1596
  }
1147
- function stack(settings) {
1148
- const stackArray = [];
1149
- return {
1150
- get value() {
1151
- return [...stackArray];
1152
- },
1153
- get top() {
1154
- const result = stackArray[stackArray.length - 1];
1155
- return result ? result : null;
1156
- },
1157
- updateIndex() {
1158
- stackArray.forEach((entry, index2) => {
1159
- entry.el.style.zIndex = null;
1160
- const value = getComputedStyle(entry.el)["z-index"];
1161
- entry.el.style.zIndex = parseInt(value) + index2 + 1;
1162
- });
1163
- },
1164
- setGlobalState() {
1165
- setGlobalState(this.top, settings.selectorInert, settings.selectorOverflow);
1166
- this.updateIndex();
1167
- },
1168
- add(entry) {
1169
- entry.el.style.zIndex = null;
1170
- const value = getComputedStyle(entry.el)["z-index"];
1171
- entry.el.style.zIndex = parseInt(value) + stackArray.length + 1;
1172
- stackArray.push(entry);
1173
- this.setGlobalState();
1174
- },
1175
- remove(entry) {
1176
- const index2 = stackArray.findIndex((item) => {
1177
- return item.id === entry.id;
1178
- });
1179
- if (index2 >= 0) {
1180
- entry.el.style.zIndex = null;
1181
- stackArray.splice(index2, 1);
1182
- this.setGlobalState();
1183
- }
1184
- },
1185
- moveToTop(entry) {
1186
- const index2 = stackArray.findIndex((item) => {
1187
- return item.id === entry.id;
1188
- });
1189
- if (index2 >= 0) {
1190
- stackArray.splice(index2, 1);
1191
- this.add(entry);
1192
- }
1193
- }
1194
- };
1195
- }
1196
1597
  class Modal extends Collection {
1197
1598
  constructor(options) {
1198
1599
  super({ ...defaults$1, ...options });
1199
1600
  __privateAdd(this, _handleClick2);
1200
1601
  __privateAdd(this, _handleKeydown2);
1602
+ this.module = "Modal";
1603
+ this.entryClass = ModalEntry;
1201
1604
  this.trigger = null;
1202
- this.focusTrap = new FocusTrap();
1203
1605
  __privateSet(this, _handleClick2, handleClick$1.bind(this));
1204
1606
  __privateSet(this, _handleKeydown2, handleKeydown$1.bind(this));
1205
- this.stack = stack(this.settings);
1607
+ this.stack = new StackArray({
1608
+ onChange: () => {
1609
+ setGlobalState(
1610
+ this.stack.top,
1611
+ this.settings.selectorInert,
1612
+ this.settings.selectorOverflow
1613
+ );
1614
+ }
1615
+ });
1206
1616
  }
1207
1617
  get active() {
1208
1618
  return this.stack.top;
1209
1619
  }
1210
- async createEntry(query, config) {
1211
- return new ModalEntry(this, query, config);
1212
- }
1213
1620
  async open(id, transition2, focus) {
1214
1621
  return open$1.call(this, id, transition2, focus);
1215
1622
  }
@@ -1257,16 +1664,14 @@ const defaults = {
1257
1664
  "arrow-padding",
1258
1665
  "toggle-delay"
1259
1666
  ],
1667
+ customEventPrefix: "popover:",
1260
1668
  placement: "bottom",
1261
1669
  event: "click",
1262
1670
  offset: 0,
1263
1671
  flipPadding: 0,
1264
1672
  shiftPadding: 0,
1265
1673
  arrowPadding: 0,
1266
- toggleDelay: 0,
1267
- // Feature settings
1268
- teleport: null,
1269
- teleportMethod: "append"
1674
+ toggleDelay: 0
1270
1675
  };
1271
1676
  function applyPositionStyle(el, x, y) {
1272
1677
  Object.assign(el.style, {
@@ -1370,16 +1775,25 @@ async function close(query) {
1370
1775
  if (popover.trigger === this.trigger) {
1371
1776
  this.trigger = null;
1372
1777
  }
1778
+ popover.el.dispatchEvent(
1779
+ new CustomEvent(popover.getSetting("customEventPrefix") + "closed", {
1780
+ detail: this,
1781
+ bubbles: true
1782
+ })
1783
+ );
1784
+ await popover.parent.emit("closed", popover);
1373
1785
  }
1374
1786
  return popover;
1375
1787
  }
1376
1788
  async function closeAll() {
1377
1789
  const result = [];
1378
- await Promise.all(this.collection.map(async (popover) => {
1379
- if (popover.state === "opened") {
1380
- result.push(await close.call(this, popover));
1381
- }
1382
- }));
1790
+ await Promise.all(
1791
+ this.collection.map(async (popover) => {
1792
+ if (popover.state === "opened") {
1793
+ result.push(await close.call(this, popover));
1794
+ }
1795
+ })
1796
+ );
1383
1797
  return result;
1384
1798
  }
1385
1799
  function closeCheck(popover) {
@@ -1389,7 +1803,6 @@ function closeCheck(popover) {
1389
1803
  let isFocused = document.activeElement.closest(
1390
1804
  `#${popover.id}, [aria-controls="${popover.id}"], [aria-describedby="${popover.id}"]`
1391
1805
  );
1392
- isFocused = isFocused ? isFocused.matches(":focus-visible") : false;
1393
1806
  if (!isHovered && !isFocused) {
1394
1807
  popover.close();
1395
1808
  }
@@ -1435,9 +1848,12 @@ function handleMouseLeave(popover, event) {
1435
1848
  if (popover.toggleDelayId) {
1436
1849
  clearTimeout(popover.toggleDelayId);
1437
1850
  }
1438
- popover.toggleDelayId = setTimeout(() => {
1439
- closeCheck.call(this, popover);
1440
- }, getDelay(popover, 1));
1851
+ popover.toggleDelayId = setTimeout(
1852
+ () => {
1853
+ closeCheck.call(this, popover);
1854
+ },
1855
+ getDelay(popover, 1)
1856
+ );
1441
1857
  }, 1);
1442
1858
  }
1443
1859
  function handleKeydown(event) {
@@ -1476,8 +1892,8 @@ function handleDocumentClick(popover) {
1476
1892
  });
1477
1893
  }
1478
1894
  class PopoverEntry extends CollectionEntry {
1479
- constructor(context, query, options = {}) {
1480
- super(context, query, options);
1895
+ constructor(parent2, query, options = {}) {
1896
+ super(parent2, query, options);
1481
1897
  __privateAdd(this, _eventListeners);
1482
1898
  __privateAdd(this, _isHovered);
1483
1899
  this.state = "closed";
@@ -1510,31 +1926,35 @@ class PopoverEntry extends CollectionEntry {
1510
1926
  }
1511
1927
  }
1512
1928
  async open() {
1513
- return this.context.open(this);
1929
+ return this.parent.open(this);
1514
1930
  }
1515
1931
  async close() {
1516
- return this.context.close(this);
1932
+ return this.parent.close(this);
1517
1933
  }
1518
1934
  async deregister() {
1519
- return this.context.deregister(this.id);
1935
+ return this.parent.deregister(this.id);
1520
1936
  }
1521
1937
  registerEventListeners() {
1522
1938
  if (!__privateGet(this, _eventListeners)) {
1523
1939
  const eventType = this.getSetting("event");
1524
1940
  if (eventType === "hover") {
1525
- __privateSet(this, _eventListeners, [{
1526
- el: ["el", "trigger"],
1527
- type: ["mouseenter", "focus"],
1528
- listener: handleMouseEnter.bind(this.context, this)
1529
- }, {
1530
- el: ["el", "trigger"],
1531
- type: ["mouseleave", "focusout"],
1532
- listener: handleMouseLeave.bind(this.context, this)
1533
- }, {
1534
- el: ["trigger"],
1535
- type: ["click"],
1536
- listener: handleTooltipClick.bind(this.context, this)
1537
- }]);
1941
+ __privateSet(this, _eventListeners, [
1942
+ {
1943
+ el: ["el", "trigger"],
1944
+ type: ["mouseenter", "focus"],
1945
+ listener: handleMouseEnter.bind(this.parent, this)
1946
+ },
1947
+ {
1948
+ el: ["el", "trigger"],
1949
+ type: ["mouseleave", "focusout"],
1950
+ listener: handleMouseLeave.bind(this.parent, this)
1951
+ },
1952
+ {
1953
+ el: ["trigger"],
1954
+ type: ["click"],
1955
+ listener: handleTooltipClick.bind(this.parent, this)
1956
+ }
1957
+ ]);
1538
1958
  __privateGet(this, _eventListeners).forEach((evObj) => {
1539
1959
  evObj.el.forEach((el) => {
1540
1960
  evObj.type.forEach((type) => {
@@ -1543,11 +1963,13 @@ class PopoverEntry extends CollectionEntry {
1543
1963
  });
1544
1964
  });
1545
1965
  } else {
1546
- __privateSet(this, _eventListeners, [{
1547
- el: ["trigger"],
1548
- type: ["click"],
1549
- listener: handleClick.bind(this.context, this)
1550
- }]);
1966
+ __privateSet(this, _eventListeners, [
1967
+ {
1968
+ el: ["trigger"],
1969
+ type: ["click"],
1970
+ listener: handleClick.bind(this.parent, this)
1971
+ }
1972
+ ]);
1551
1973
  __privateGet(this, _eventListeners).forEach((evObj) => {
1552
1974
  evObj.el.forEach((el) => {
1553
1975
  evObj.type.forEach((type) => {
@@ -1570,7 +1992,7 @@ class PopoverEntry extends CollectionEntry {
1570
1992
  __privateSet(this, _eventListeners, null);
1571
1993
  }
1572
1994
  }
1573
- async beforeMount() {
1995
+ async onCreateEntry() {
1574
1996
  this.trigger = document.querySelector(
1575
1997
  `[aria-controls="${this.id}"], [aria-describedby="${this.id}"]`
1576
1998
  );
@@ -1582,14 +2004,14 @@ class PopoverEntry extends CollectionEntry {
1582
2004
  }
1583
2005
  this.registerEventListeners();
1584
2006
  }
1585
- async afterRegister() {
2007
+ async onRegisterEntry() {
1586
2008
  if (this.el.classList.contains(this.getSetting("stateActive"))) {
1587
2009
  await this.open();
1588
2010
  } else {
1589
2011
  this.el.inert = true;
1590
2012
  }
1591
2013
  }
1592
- async beforeUnmount() {
2014
+ async onDestroyEntry() {
1593
2015
  if (this.state === "opened") {
1594
2016
  await this.close();
1595
2017
  }
@@ -2041,15 +2463,20 @@ const flip$1 = function(options) {
2041
2463
  const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1;
2042
2464
  const nextPlacement = placements[nextIndex];
2043
2465
  if (nextPlacement) {
2044
- return {
2045
- data: {
2046
- index: nextIndex,
2047
- overflows: overflowsData
2048
- },
2049
- reset: {
2050
- placement: nextPlacement
2051
- }
2052
- };
2466
+ var _overflowsData$;
2467
+ const ignoreCrossAxisOverflow = checkCrossAxis === "alignment" ? initialSideAxis !== getSideAxis(nextPlacement) : false;
2468
+ const hasInitialMainAxisOverflow = ((_overflowsData$ = overflowsData[0]) == null ? void 0 : _overflowsData$.overflows[0]) > 0;
2469
+ if (!ignoreCrossAxisOverflow || hasInitialMainAxisOverflow) {
2470
+ return {
2471
+ data: {
2472
+ index: nextIndex,
2473
+ overflows: overflowsData
2474
+ },
2475
+ reset: {
2476
+ placement: nextPlacement
2477
+ }
2478
+ };
2479
+ }
2053
2480
  }
2054
2481
  let resetPlacement = (_overflowsData$filter = overflowsData.filter((d) => d.overflows[0] <= 0).sort((a, b) => a.overflows[1] - b.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement;
2055
2482
  if (!resetPlacement) {
@@ -2356,7 +2783,7 @@ function isTopLayer(element) {
2356
2783
  function isContainingBlock(elementOrCss) {
2357
2784
  const webkit = isWebKit();
2358
2785
  const css = isElement(elementOrCss) ? getComputedStyle$1(elementOrCss) : elementOrCss;
2359
- return css.transform !== "none" || css.perspective !== "none" || (css.containerType ? css.containerType !== "normal" : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== "none" : false) || !webkit && (css.filter ? css.filter !== "none" : false) || ["transform", "perspective", "filter"].some((value) => (css.willChange || "").includes(value)) || ["paint", "layout", "strict", "content"].some((value) => (css.contain || "").includes(value));
2786
+ return ["transform", "translate", "scale", "rotate", "perspective"].some((value) => css[value] ? css[value] !== "none" : false) || (css.containerType ? css.containerType !== "normal" : false) || !webkit && (css.backdropFilter ? css.backdropFilter !== "none" : false) || !webkit && (css.filter ? css.filter !== "none" : false) || ["transform", "translate", "scale", "rotate", "perspective", "filter"].some((value) => (css.willChange || "").includes(value)) || ["paint", "layout", "strict", "content"].some((value) => (css.contain || "").includes(value));
2360
2787
  }
2361
2788
  function getContainingBlock(element) {
2362
2789
  let currentNode = getParentNode(element);
@@ -2552,6 +2979,28 @@ function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetPar
2552
2979
  y
2553
2980
  });
2554
2981
  }
2982
+ function getWindowScrollBarX(element, rect) {
2983
+ const leftScroll = getNodeScroll(element).scrollLeft;
2984
+ if (!rect) {
2985
+ return getBoundingClientRect(getDocumentElement(element)).left + leftScroll;
2986
+ }
2987
+ return rect.left + leftScroll;
2988
+ }
2989
+ function getHTMLOffset(documentElement, scroll, ignoreScrollbarX) {
2990
+ if (ignoreScrollbarX === void 0) {
2991
+ ignoreScrollbarX = false;
2992
+ }
2993
+ const htmlRect = documentElement.getBoundingClientRect();
2994
+ const x = htmlRect.left + scroll.scrollLeft - (ignoreScrollbarX ? 0 : (
2995
+ // RTL <body> scrollbar.
2996
+ getWindowScrollBarX(documentElement, htmlRect)
2997
+ ));
2998
+ const y = htmlRect.top + scroll.scrollTop;
2999
+ return {
3000
+ x,
3001
+ y
3002
+ };
3003
+ }
2555
3004
  function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
2556
3005
  let {
2557
3006
  elements,
@@ -2583,23 +3032,17 @@ function convertOffsetParentRelativeRectToViewportRelativeRect(_ref) {
2583
3032
  offsets.y = offsetRect.y + offsetParent.clientTop;
2584
3033
  }
2585
3034
  }
3035
+ const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll, true) : createCoords(0);
2586
3036
  return {
2587
3037
  width: rect.width * scale.x,
2588
3038
  height: rect.height * scale.y,
2589
- x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x,
2590
- y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y
3039
+ x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x,
3040
+ y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y
2591
3041
  };
2592
3042
  }
2593
3043
  function getClientRects(element) {
2594
3044
  return Array.from(element.getClientRects());
2595
3045
  }
2596
- function getWindowScrollBarX(element, rect) {
2597
- const leftScroll = getNodeScroll(element).scrollLeft;
2598
- if (!rect) {
2599
- return getBoundingClientRect(getDocumentElement(element)).left + leftScroll;
2600
- }
2601
- return rect.left + leftScroll;
2602
- }
2603
3046
  function getDocumentRect(element) {
2604
3047
  const html = getDocumentElement(element);
2605
3048
  const scroll = getNodeScroll(element);
@@ -2669,9 +3112,10 @@ function getClientRectFromClippingAncestor(element, clippingAncestor, strategy)
2669
3112
  } else {
2670
3113
  const visualOffsets = getVisualOffsets(element);
2671
3114
  rect = {
2672
- ...clippingAncestor,
2673
3115
  x: clippingAncestor.x - visualOffsets.x,
2674
- y: clippingAncestor.y - visualOffsets.y
3116
+ y: clippingAncestor.y - visualOffsets.y,
3117
+ width: clippingAncestor.width,
3118
+ height: clippingAncestor.height
2675
3119
  };
2676
3120
  }
2677
3121
  return rectToClientRect(rect);
@@ -2754,6 +3198,9 @@ function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
2754
3198
  scrollTop: 0
2755
3199
  };
2756
3200
  const offsets = createCoords(0);
3201
+ function setLeftRTLScrollbarOffset() {
3202
+ offsets.x = getWindowScrollBarX(documentElement);
3203
+ }
2757
3204
  if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
2758
3205
  if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) {
2759
3206
  scroll = getNodeScroll(offsetParent);
@@ -2763,19 +3210,15 @@ function getRectRelativeToOffsetParent(element, offsetParent, strategy) {
2763
3210
  offsets.x = offsetRect.x + offsetParent.clientLeft;
2764
3211
  offsets.y = offsetRect.y + offsetParent.clientTop;
2765
3212
  } else if (documentElement) {
2766
- offsets.x = getWindowScrollBarX(documentElement);
3213
+ setLeftRTLScrollbarOffset();
2767
3214
  }
2768
3215
  }
2769
- let htmlX = 0;
2770
- let htmlY = 0;
2771
- if (documentElement && !isOffsetParentAnElement && !isFixed) {
2772
- const htmlRect = documentElement.getBoundingClientRect();
2773
- htmlY = htmlRect.top + scroll.scrollTop;
2774
- htmlX = htmlRect.left + scroll.scrollLeft - // RTL <body> scrollbar.
2775
- getWindowScrollBarX(documentElement, htmlRect);
3216
+ if (isFixed && !isOffsetParentAnElement && documentElement) {
3217
+ setLeftRTLScrollbarOffset();
2776
3218
  }
2777
- const x = rect.left + scroll.scrollLeft - offsets.x - htmlX;
2778
- const y = rect.top + scroll.scrollTop - offsets.y - htmlY;
3219
+ const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0);
3220
+ const x = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x;
3221
+ const y = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y;
2779
3222
  return {
2780
3223
  x,
2781
3224
  y,
@@ -2852,6 +3295,9 @@ const platform = {
2852
3295
  isElement,
2853
3296
  isRTL
2854
3297
  };
3298
+ function rectsAreEqual(a, b) {
3299
+ return a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
3300
+ }
2855
3301
  function observeMove(element, onMove) {
2856
3302
  let io = null;
2857
3303
  let timeoutId;
@@ -2870,12 +3316,13 @@ function observeMove(element, onMove) {
2870
3316
  threshold = 1;
2871
3317
  }
2872
3318
  cleanup();
3319
+ const elementRectForRootMargin = element.getBoundingClientRect();
2873
3320
  const {
2874
3321
  left,
2875
3322
  top,
2876
3323
  width,
2877
3324
  height
2878
- } = element.getBoundingClientRect();
3325
+ } = elementRectForRootMargin;
2879
3326
  if (!skip) {
2880
3327
  onMove();
2881
3328
  }
@@ -2906,6 +3353,9 @@ function observeMove(element, onMove) {
2906
3353
  refresh(false, ratio);
2907
3354
  }
2908
3355
  }
3356
+ if (ratio === 1 && !rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) {
3357
+ refresh();
3358
+ }
2909
3359
  isFirstUpdate = false;
2910
3360
  }
2911
3361
  try {
@@ -2914,7 +3364,7 @@ function observeMove(element, onMove) {
2914
3364
  // Handle <iframe>s
2915
3365
  root: root.ownerDocument
2916
3366
  });
2917
- } catch (e) {
3367
+ } catch (_e) {
2918
3368
  io = new IntersectionObserver(handleObserve, options);
2919
3369
  }
2920
3370
  io.observe(element);
@@ -2969,7 +3419,7 @@ function autoUpdate(reference, floating, update, options) {
2969
3419
  }
2970
3420
  function frameLoop() {
2971
3421
  const nextRefRect = getBoundingClientRect(reference);
2972
- if (prevRefRect && (nextRefRect.x !== prevRefRect.x || nextRefRect.y !== prevRefRect.y || nextRefRect.width !== prevRefRect.width || nextRefRect.height !== prevRefRect.height)) {
3422
+ if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) {
2973
3423
  update();
2974
3424
  }
2975
3425
  prevRefRect = nextRefRect;
@@ -3017,7 +3467,7 @@ async function open(query) {
3017
3467
  if (!popover.isTooltip) {
3018
3468
  popover.trigger.setAttribute("aria-expanded", "true");
3019
3469
  }
3020
- popover.getCustomProps();
3470
+ popover.buildCustomProps();
3021
3471
  const middlewareOptions = getMiddlewareOptions(popover);
3022
3472
  const arrowEl = popover.el.querySelector(middlewareOptions.arrow.element);
3023
3473
  middlewareOptions.arrow.element = arrowEl ? arrowEl : void 0;
@@ -3046,12 +3496,21 @@ async function open(query) {
3046
3496
  if (popover.getSetting("event") === "click") {
3047
3497
  handleDocumentClick.call(this, popover);
3048
3498
  }
3499
+ popover.el.dispatchEvent(
3500
+ new CustomEvent(popover.getSetting("customEventPrefix") + "opened", {
3501
+ detail: this,
3502
+ bubbles: true
3503
+ })
3504
+ );
3505
+ await popover.parent.emit("opened", popover);
3049
3506
  return popover;
3050
3507
  }
3051
3508
  class Popover extends Collection {
3052
3509
  constructor(options = {}) {
3053
3510
  super({ ...defaults, ...options });
3054
3511
  __privateAdd(this, _handleKeydown3);
3512
+ this.module = "Popover";
3513
+ this.entryClass = PopoverEntry;
3055
3514
  this.trigger = null;
3056
3515
  __privateSet(this, _handleKeydown3, handleKeydown.bind(this));
3057
3516
  }
@@ -3063,9 +3522,6 @@ class Popover extends Collection {
3063
3522
  return popover.state == "opened" && popover.getSetting("event") == "hover";
3064
3523
  });
3065
3524
  }
3066
- async createEntry(query, config) {
3067
- return new PopoverEntry(this, query, config);
3068
- }
3069
3525
  async open(id) {
3070
3526
  return open.call(this, id);
3071
3527
  }