@expressivecss/expressive 0.7.0-rc.0 → 0.8.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +1311 -1
  2. package/README.md +14 -11
  3. package/dist/css/expressive.css +4215 -1668
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/js/expressive.cjs +1231 -1253
  8. package/dist/js/expressive.cjs.map +4 -4
  9. package/dist/js/expressive.js +1231 -1253
  10. package/dist/js/expressive.js.map +4 -4
  11. package/dist/js/expressive.min.js +12 -12
  12. package/dist/js/expressive.min.js.map +4 -4
  13. package/dist/js/expressive.mjs +1231 -1253
  14. package/dist/js/expressive.mjs.map +4 -4
  15. package/dist/types/behaviors/bottomSheets.d.ts +19 -11
  16. package/dist/types/behaviors/sheetDrag.d.ts +40 -0
  17. package/dist/types/behaviors/sideSheets.d.ts +2 -9
  18. package/dist/types/components/autocomplete.d.ts +15 -3
  19. package/dist/types/components/buttons.d.ts +5 -1
  20. package/dist/types/components/carousel.d.ts +87 -53
  21. package/dist/types/components/chips.d.ts +21 -1
  22. package/dist/types/components/expandingCard.d.ts +31 -0
  23. package/dist/types/components/index.d.ts +21 -20
  24. package/dist/types/components/lightbox.d.ts +1 -0
  25. package/dist/types/components/menu.d.ts +7 -1
  26. package/dist/types/components/{sidenav.d.ts → navigationDrawer.d.ts} +16 -16
  27. package/dist/types/components/registry.d.ts +8 -8
  28. package/dist/types/components/slider.d.ts +26 -85
  29. package/dist/types/components/snackbar.d.ts +20 -5
  30. package/dist/types/components/tabs.d.ts +12 -0
  31. package/dist/types/components/timepicker.d.ts +12 -9
  32. package/dist/types/core/utils.d.ts +64 -53
  33. package/dist/types/index.d.ts +8 -9
  34. package/package.json +15 -1
  35. package/src/sass/README.md +61 -11
  36. package/src/sass/abstracts/_breakpoints.scss +17 -19
  37. package/src/sass/abstracts/_mixins.scss +103 -21
  38. package/src/sass/abstracts/_variables.scss +50 -5
  39. package/src/sass/base/_global.scss +6 -24
  40. package/src/sass/base/_grid.scss +15 -12
  41. package/src/sass/base/_normalize.scss +34 -38
  42. package/src/sass/base/_typography.scss +4 -18
  43. package/src/sass/components/_badges.scss +2 -3
  44. package/src/sass/components/_banners.scss +298 -0
  45. package/src/sass/components/_bottom-app-bar.scss +180 -0
  46. package/src/sass/components/_bottom-sheet.scss +12 -4
  47. package/src/sass/components/_button-groups.scss +186 -0
  48. package/src/sass/components/_buttons.scss +245 -92
  49. package/src/sass/components/_cards.scss +494 -73
  50. package/src/sass/components/_carousel.scss +562 -68
  51. package/src/sass/components/_chips.scss +64 -5
  52. package/src/sass/components/_datepicker.scss +24 -24
  53. package/src/sass/components/_dialog.scss +17 -11
  54. package/src/sass/components/_drag-handle.scss +130 -0
  55. package/src/sass/components/_expanding-card.scss +260 -0
  56. package/src/sass/components/_fab-menu.scss +232 -0
  57. package/src/sass/components/_floating-sheet.scss +86 -0
  58. package/src/sass/components/_icon-buttons.scss +194 -0
  59. package/src/sass/components/_icons-material-design.scss +16 -4
  60. package/src/sass/components/_index.scss +22 -6
  61. package/src/sass/components/_list.scss +16 -13
  62. package/src/sass/components/_loading-indicator.scss +106 -0
  63. package/src/sass/components/_menu.scss +335 -61
  64. package/src/sass/components/_navbar.scss +71 -24
  65. package/src/sass/components/_navigation-bar.scss +13 -10
  66. package/src/sass/components/{_sidenav.scss → _navigation-drawer.scss} +123 -33
  67. package/src/sass/components/_navigation-rail.scss +22 -22
  68. package/src/sass/components/_page-footer.scss +19 -16
  69. package/src/sass/components/_pagination.scss +24 -6
  70. package/src/sass/components/_panes.scss +52 -11
  71. package/src/sass/components/{_preloader.scss → _progress.scss} +11 -3
  72. package/src/sass/components/_scrim.scss +37 -0
  73. package/src/sass/components/_search.scss +259 -0
  74. package/src/sass/components/_segmented-buttons.scss +188 -0
  75. package/src/sass/components/_side-sheet.scss +2 -2
  76. package/src/sass/components/_snackbar.scss +20 -15
  77. package/src/sass/components/_split-button.scss +196 -0
  78. package/src/sass/components/_tabs.scss +7 -8
  79. package/src/sass/components/_timepicker.scss +67 -58
  80. package/src/sass/components/_toolbar.scss +206 -80
  81. package/src/sass/components/forms/_checkboxes.scss +49 -12
  82. package/src/sass/components/forms/_fieldset.scss +4 -4
  83. package/src/sass/components/forms/_file-input.scss +8 -1
  84. package/src/sass/components/forms/_index.scss +1 -1
  85. package/src/sass/components/forms/_input-fields.scss +50 -44
  86. package/src/sass/components/forms/_radio-buttons.scss +42 -10
  87. package/src/sass/components/forms/_select.scss +0 -1
  88. package/src/sass/components/forms/{_range.scss → _slider.scss} +8 -9
  89. package/src/sass/components/forms/_switches.scss +6 -7
  90. package/src/sass/tokens/_index.scss +4 -1
  91. package/src/sass/tokens/_reference.scss +70 -61
  92. package/src/sass/tokens/_state.scss +24 -0
  93. package/src/sass/tokens/_theme.scss +6 -3
  94. package/src/sass/tokens/_vibrant.scss +76 -0
  95. package/src/sass/utilities/_colors.scss +14 -1
  96. package/src/sass/utilities/_helpers.scss +5 -5
  97. package/src/sass/utilities/_visibility.scss +48 -26
  98. package/dist/types/behaviors/waves.d.ts +0 -15
  99. package/dist/types/components/parallax.d.ts +0 -16
  100. package/dist/types/components/range.d.ts +0 -43
  101. package/dist/types/core/bounding.d.ts +0 -6
  102. package/dist/types/core/edges.d.ts +0 -6
  103. package/src/sass/components/_parallax.scss +0 -104
  104. package/src/sass/components/_pulse.scss +0 -37
  105. package/src/sass/components/_slider.scss +0 -129
@@ -1,45 +1,5 @@
1
1
  // src/ts/core/utils.ts
2
2
  var _Utils = class _Utils {
3
- /**
4
- * Detects when a key is pressed.
5
- * @param e Event instance.
6
- */
7
- static docHandleKeydown(e) {
8
- _Utils.keyDown = true;
9
- if (_Utils._navigationKeys.has(e.key)) {
10
- _Utils.tabPressed = true;
11
- }
12
- }
13
- /**
14
- * Detects when a key is released.
15
- * @param e Event instance.
16
- */
17
- static docHandleKeyup(e) {
18
- _Utils.keyDown = false;
19
- if (_Utils._navigationKeys.has(e.key)) {
20
- _Utils.tabPressed = false;
21
- }
22
- }
23
- /**
24
- * Detects when document is focused.
25
- * @param e Event instance.
26
- */
27
- /* eslint-disabled as of required event type condition check */
28
- /* eslint-disable-next-line */
29
- static docHandleFocus(e) {
30
- if (_Utils.keyDown) {
31
- document.body.classList.add("keyboard-focused");
32
- }
33
- }
34
- /**
35
- * Detects when document is not focused.
36
- * @param e Event instance.
37
- */
38
- /* eslint-disabled as of required event type condition check */
39
- /* eslint-disable-next-line */
40
- static docHandleBlur(e) {
41
- document.body.classList.remove("keyboard-focused");
42
- }
43
3
  /**
44
4
  * Run `callback` once the document is parsed.
45
5
  *
@@ -57,13 +17,46 @@ var _Utils = class _Utils {
57
17
  }
58
18
  }
59
19
  /**
60
- * Generates a unique string identifier.
20
+ * Generates a unique string identifier. Every caller prefixes the result and
21
+ * uses it as an element id, and a UUID is valid in that position.
22
+ *
23
+ * `randomUUID` is exposed only in secure contexts, and a dev server on a
24
+ * plain-HTTP LAN address - the usual way a page is opened on a phone - is
25
+ * not one. Without the fallback every component that stamps an id would
26
+ * throw there. The ids only have to be unique within one document, so the
27
+ * fallback does not need to be cryptographic.
61
28
  */
62
29
  static guid() {
63
- const s4 = () => {
64
- return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
65
- };
66
- return s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4();
30
+ return globalThis.crypto?.randomUUID?.() ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
31
+ }
32
+ /**
33
+ * Where an element created at runtime has to be appended to stay in the same
34
+ * tree as `el`. A stylesheet adopted into a shadow root cannot match a node
35
+ * in the document, so a portal that lands on `document.body` is unstyled
36
+ * whenever its origin lives in a shadow root (adr/0002).
37
+ *
38
+ * Light-DOM elements still get `document.body`, which is what escapes an
39
+ * ancestor's `overflow: hidden` and stacking context. Inside a shadow root
40
+ * both hazards come back: the host's own ancestors still form the containing
41
+ * block, so a transformed ancestor re-anchors `position: fixed` and a
42
+ * positioned one re-anchors `position: absolute`.
43
+ */
44
+ static portalRoot(el) {
45
+ const root = el.getRootNode();
46
+ return root.host ? root : document.body;
47
+ }
48
+ /**
49
+ * `getElementById` against the tree `el` lives in. The mirror of
50
+ * `portalRoot`: an id in a shadow root is invisible to
51
+ * `document.getElementById`, so a trigger and its target inside the same
52
+ * root could not find each other at all.
53
+ *
54
+ * Falls back to the document for a detached `el`, whose root is a plain
55
+ * element with no lookup of its own.
56
+ */
57
+ static getElementById(el, id) {
58
+ const root = el.getRootNode();
59
+ return root.getElementById ? root.getElementById(id) : document.getElementById(id);
67
60
  }
68
61
  /**
69
62
  * Checks for exceeded edges
@@ -160,43 +153,50 @@ var _Utils = class _Utils {
160
153
  * Retrieves document scroll postion from top.
161
154
  */
162
155
  static getDocumentScrollTop() {
163
- return window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0;
156
+ return window.scrollY;
164
157
  }
165
158
  /**
166
159
  * Retrieves document scroll postion from left.
167
160
  */
168
161
  static getDocumentScrollLeft() {
169
- return window.scrollX || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
162
+ return window.scrollX;
170
163
  }
171
164
  /**
172
- * Fires the given function after a certain ammount of time.
173
- * @param func Function to be fired.
174
- * @param wait Wait time.
175
- * @param options Additional options.
165
+ * Trailing-edge throttle: run `func` now, then at most once per `wait` ms
166
+ * with the most recent arguments.
167
+ *
168
+ * This used to carry its underscore ancestor's whole configuration - leading
169
+ * and trailing switches, a result passthrough - and both call sites are
170
+ * resize handlers passing nothing but a function and a delay.
171
+ *
172
+ * Assign the return value once. `x = Utils.throttle(fn, 200)` is right;
173
+ * wrapping it in an arrow builds a fresh closure per event and never calls
174
+ * it, which is how resize handling was dead in three components.
176
175
  */
177
- static throttle(func, wait, options = {}) {
178
- let lastArgs = null, result, timeout = null, previous = 0;
179
- const later = () => {
180
- previous = options?.leading === false ? 0 : Date.now();
181
- timeout = null;
182
- result = func(...lastArgs ?? []);
183
- lastArgs = null;
184
- };
176
+ static throttle(func, wait) {
177
+ let timeout = null;
178
+ let lastArgs = null;
179
+ let previous = 0;
185
180
  return (...args) => {
186
181
  const now = Date.now();
187
- if (!previous && options?.leading === false) previous = now;
188
182
  const remaining = wait - (now - previous);
189
- lastArgs = args;
190
183
  if (remaining <= 0) {
191
184
  clearTimeout(timeout);
192
185
  timeout = null;
193
186
  previous = now;
194
187
  lastArgs = null;
195
- result = func(...args);
196
- } else if (!timeout && options?.trailing !== false) {
197
- timeout = setTimeout(later, remaining);
188
+ func(...args);
189
+ } else if (!timeout) {
190
+ lastArgs = args;
191
+ timeout = setTimeout(() => {
192
+ previous = Date.now();
193
+ timeout = null;
194
+ func(...lastArgs ?? []);
195
+ lastArgs = null;
196
+ }, remaining);
197
+ } else {
198
+ lastArgs = args;
198
199
  }
199
- return result;
200
200
  };
201
201
  }
202
202
  /**
@@ -213,7 +213,7 @@ var _Utils = class _Utils {
213
213
  * Renders a button with optional callback function
214
214
  */
215
215
  static createButton(container, text, className = [], visibility = true, callback = null) {
216
- className = className.concat(["waves-effect", "text"]);
216
+ className = className.concat(["text"]);
217
217
  const button = document.createElement("button");
218
218
  button.className = className.join(" ");
219
219
  button.style.visibility = visibility ? "visible" : "hidden";
@@ -223,7 +223,7 @@ var _Utils = class _Utils {
223
223
  if (typeof callback === "function") {
224
224
  button.addEventListener("click", callback);
225
225
  button.addEventListener("keypress", (e) => {
226
- if (_Utils.keys.ENTER.includes(e.key)) callback(e);
226
+ if (e.key === _Utils.keys.ENTER) callback(e);
227
227
  });
228
228
  }
229
229
  container.append(button);
@@ -302,36 +302,22 @@ var _Utils = class _Utils {
302
302
  };
303
303
  }
304
304
  };
305
- /** Specifies wether tab is pressed or not. */
306
- _Utils.tabPressed = false;
307
- /** Specifies wether there is a key pressed. */
308
- _Utils.keyDown = false;
309
305
  /**
310
- * Key maps.
306
+ * Key maps. One `KeyboardEvent.key` value each: the second entries these used
307
+ * to carry (`Esc`, `Up`, `Del`, ...) were IE and Edge Legacy spellings, and
308
+ * the support baseline excludes both.
311
309
  */
312
310
  _Utils.keys = {
313
- TAB: ["Tab"],
314
- ENTER: ["Enter"],
315
- ESC: ["Escape", "Esc"],
316
- BACKSPACE: ["Backspace"],
317
- ARROW_UP: ["ArrowUp", "Up"],
318
- ARROW_DOWN: ["ArrowDown", "Down"],
319
- ARROW_LEFT: ["ArrowLeft", "Left"],
320
- ARROW_RIGHT: ["ArrowRight", "Right"],
321
- DELETE: ["Delete", "Del"]
311
+ TAB: "Tab",
312
+ ENTER: "Enter",
313
+ ESC: "Escape",
314
+ BACKSPACE: "Backspace",
315
+ ARROW_UP: "ArrowUp",
316
+ ARROW_DOWN: "ArrowDown",
317
+ ARROW_LEFT: "ArrowLeft",
318
+ ARROW_RIGHT: "ArrowRight",
319
+ DELETE: "Delete"
322
320
  };
323
- /**
324
- * Keys that count as keyboard navigation, precomputed.
325
- *
326
- * These handlers run at capture phase on the document for every keystroke on
327
- * the page, and used to rebuild three arrays and spread them into a fourth
328
- * on each one.
329
- */
330
- _Utils._navigationKeys = /* @__PURE__ */ new Set([
331
- ..._Utils.keys.TAB,
332
- ..._Utils.keys.ARROW_DOWN,
333
- ..._Utils.keys.ARROW_UP
334
- ]);
335
321
  var Utils = _Utils;
336
322
 
337
323
  // src/ts/core/component.ts
@@ -415,13 +401,14 @@ var Cards = class _Cards extends Component {
415
401
  this._handleRevealEvent();
416
402
  };
417
403
  this._handleKeypressEvent = (e) => {
418
- if (Utils.keys.ENTER.includes(e.key)) {
404
+ if (e.key === Utils.keys.ENTER || e.key === " ") {
405
+ e.preventDefault();
419
406
  this._handleRevealEvent();
420
407
  }
421
408
  };
422
409
  this._handleRevealEvent = () => {
423
- this._activators.forEach((el) => el.tabIndex = -1);
424
- this.open();
410
+ if (this.isOpen) this.close();
411
+ else this.open();
425
412
  };
426
413
  this._setupRevealCloseEventHandlers = () => {
427
414
  this.cardRevealClose.addEventListener("click", this.close);
@@ -432,7 +419,7 @@ var Cards = class _Cards extends Component {
432
419
  this.cardRevealClose.removeEventListener("keypress", this._handleKeypressCloseEvent);
433
420
  };
434
421
  this._handleKeypressCloseEvent = (e) => {
435
- if (Utils.keys.ENTER.includes(e.key)) {
422
+ if (e.key === Utils.keys.ENTER) {
436
423
  this.close();
437
424
  }
438
425
  };
@@ -443,6 +430,7 @@ var Cards = class _Cards extends Component {
443
430
  if (this.isOpen || !this.cardReveal) return;
444
431
  this.isOpen = true;
445
432
  this.cardReveal.ariaExpanded = "true";
433
+ this._activators.forEach((el) => el.ariaExpanded = "true");
446
434
  if (this.cardRevealClose) this.cardRevealClose.tabIndex = 0;
447
435
  if (typeof this.options.onOpen === "function") {
448
436
  this.options.onOpen.call(this);
@@ -456,7 +444,7 @@ var Cards = class _Cards extends Component {
456
444
  if (!this.isOpen || !this.cardReveal) return;
457
445
  this.isOpen = false;
458
446
  this.cardReveal.ariaExpanded = "false";
459
- this._activators.forEach((el) => el.tabIndex = 0);
447
+ this._activators.forEach((el) => el.ariaExpanded = "false");
460
448
  if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
461
449
  if (typeof this.options.onClose === "function") {
462
450
  this.options.onClose.call(this);
@@ -471,9 +459,18 @@ var Cards = class _Cards extends Component {
471
459
  this._activators = [];
472
460
  this.cardReveal = this.el.querySelector(":scope > aside");
473
461
  if (this.cardReveal) {
474
- this._activators = Array.from(this.el.querySelectorAll(".activator"));
462
+ this._activators = Array.from(
463
+ this.el.querySelectorAll(".activator")
464
+ ).filter(
465
+ (activator) => !this.cardReveal.contains(activator)
466
+ );
475
467
  this._activators.forEach((el2) => {
476
- if (el2) el2.tabIndex = 0;
468
+ if (!el2) return;
469
+ el2.tabIndex = 0;
470
+ el2.ariaExpanded = "false";
471
+ if (!el2.matches("a[href], button, input, select, textarea")) {
472
+ el2.setAttribute("role", "button");
473
+ }
477
474
  });
478
475
  this.cardRevealClose = this.cardReveal.querySelector(
479
476
  ":scope > :is(h1, h2, h3, h4, h5, h6)"
@@ -516,8 +513,171 @@ var Cards = class _Cards extends Component {
516
513
  }
517
514
  };
518
515
 
519
- // src/ts/components/menu.ts
516
+ // src/ts/components/expandingCard.ts
520
517
  var _defaults2 = {
518
+ onOpen: null,
519
+ onClose: null
520
+ };
521
+ var MOTION_DURATION = 500;
522
+ var EXPANDING_CARD_SELECTOR = "article.expanding-card:has(> dialog.expanding-card-dialog)";
523
+ var ExpandingCard = class _ExpandingCard extends Component {
524
+ constructor(el, options) {
525
+ super(el, options, _ExpandingCard);
526
+ this.isOpen = false;
527
+ this.closeTimer = null;
528
+ this._setupEventHandlers = () => {
529
+ this.trigger?.addEventListener("click", this.open);
530
+ this.trigger?.addEventListener("keypress", this._handleTriggerKeypress);
531
+ this.closeButton?.addEventListener("click", this.close);
532
+ this.dialog?.addEventListener("cancel", this._handleCancel);
533
+ this.dialog?.addEventListener("close", this._handleNativeClose);
534
+ };
535
+ this._removeEventHandlers = () => {
536
+ this.trigger?.removeEventListener("click", this.open);
537
+ this.trigger?.removeEventListener("keypress", this._handleTriggerKeypress);
538
+ this.closeButton?.removeEventListener("click", this.close);
539
+ this.dialog?.removeEventListener("cancel", this._handleCancel);
540
+ this.dialog?.removeEventListener("close", this._handleNativeClose);
541
+ };
542
+ this._handleTriggerKeypress = (event) => {
543
+ if (event.key === Utils.keys.ENTER || event.key === " ") {
544
+ event.preventDefault();
545
+ this.open();
546
+ }
547
+ };
548
+ this._handleCancel = (event) => {
549
+ event.preventDefault();
550
+ this.close();
551
+ };
552
+ this._handleNativeClose = () => {
553
+ if (!this.isOpen) return;
554
+ this.isOpen = false;
555
+ this.trigger.ariaExpanded = "false";
556
+ this.dialog.ariaExpanded = "false";
557
+ this.dialog.classList.remove("expanded");
558
+ };
559
+ this._setTransitionOrigin = () => {
560
+ if (!this.dialog) return;
561
+ const card = this.el.getBoundingClientRect();
562
+ const media = this.el.querySelector(
563
+ ":scope > figure, :scope > img"
564
+ );
565
+ const mediaRect = media?.getBoundingClientRect();
566
+ this.dialog.style.setProperty(
567
+ "--md-comp-expanding-card-from-top",
568
+ `${Math.max(0, card.top)}px`
569
+ );
570
+ this.dialog.style.setProperty(
571
+ "--md-comp-expanding-card-from-right",
572
+ `${Math.max(0, window.innerWidth - card.right)}px`
573
+ );
574
+ this.dialog.style.setProperty(
575
+ "--md-comp-expanding-card-from-bottom",
576
+ `${Math.max(0, window.innerHeight - card.bottom)}px`
577
+ );
578
+ this.dialog.style.setProperty(
579
+ "--md-comp-expanding-card-from-left",
580
+ `${Math.max(0, card.left)}px`
581
+ );
582
+ this.dialog.style.setProperty(
583
+ "--md-comp-expanding-card-from-media-height",
584
+ `${Math.max(0, mediaRect?.height ?? 0)}px`
585
+ );
586
+ };
587
+ this.open = () => {
588
+ if (this.isOpen || !this.dialog || !this.trigger) return;
589
+ if (this.closeTimer !== null) {
590
+ window.clearTimeout(this.closeTimer);
591
+ this.closeTimer = null;
592
+ }
593
+ this._setTransitionOrigin();
594
+ this.isOpen = true;
595
+ this.trigger.ariaExpanded = "true";
596
+ this.dialog.ariaExpanded = "true";
597
+ this.dialog.showModal();
598
+ void this.dialog.offsetWidth;
599
+ this.dialog.classList.add("expanded");
600
+ this.closeButton?.focus();
601
+ if (typeof this.options.onOpen === "function") {
602
+ this.options.onOpen.call(this, this.el);
603
+ }
604
+ };
605
+ this.close = () => {
606
+ if (!this.isOpen || !this.dialog || !this.trigger) return;
607
+ this._setTransitionOrigin();
608
+ this.isOpen = false;
609
+ this.trigger.ariaExpanded = "false";
610
+ this.dialog.ariaExpanded = "false";
611
+ this.dialog.classList.remove("expanded");
612
+ if (typeof this.options.onClose === "function") {
613
+ this.options.onClose.call(this, this.el);
614
+ }
615
+ const finish = () => {
616
+ this.closeTimer = null;
617
+ if (this.dialog.open) this.dialog.close();
618
+ this.trigger.focus();
619
+ };
620
+ const reducedMotion = window.matchMedia(
621
+ "(prefers-reduced-motion: reduce)"
622
+ ).matches;
623
+ if (reducedMotion) finish();
624
+ else this.closeTimer = window.setTimeout(finish, MOTION_DURATION);
625
+ };
626
+ this.el["Expressive_ExpandingCard"] = this;
627
+ this.options = {
628
+ ..._ExpandingCard.defaults,
629
+ ...options
630
+ };
631
+ this.dialog = this.el.querySelector(
632
+ ":scope > dialog.expanding-card-dialog"
633
+ );
634
+ this.trigger = this.el.querySelector(
635
+ ":scope > .expanding-card-trigger, :scope > figure > .expanding-card-trigger"
636
+ );
637
+ this.closeButton = this.dialog?.querySelector(".expanding-card-close") ?? null;
638
+ if (this.trigger && this.dialog) {
639
+ this.trigger.ariaExpanded = "false";
640
+ if (this.dialog.id)
641
+ this.trigger.setAttribute("aria-controls", this.dialog.id);
642
+ if (!this.trigger.matches("a[href], button, input, select, textarea")) {
643
+ this.trigger.tabIndex = 0;
644
+ this.trigger.setAttribute("role", "button");
645
+ }
646
+ this.dialog.ariaExpanded = "false";
647
+ this._setupEventHandlers();
648
+ }
649
+ }
650
+ static get defaults() {
651
+ return _defaults2;
652
+ }
653
+ static init(els, options) {
654
+ return super.init(els, options, _ExpandingCard);
655
+ }
656
+ static getInstance(el) {
657
+ return el["Expressive_ExpandingCard"];
658
+ }
659
+ destroy() {
660
+ this._removeEventHandlers();
661
+ if (this.closeTimer !== null) window.clearTimeout(this.closeTimer);
662
+ this.dialog?.classList.remove("expanded");
663
+ if (this.dialog?.open) this.dialog.close();
664
+ this.el["Expressive_ExpandingCard"] = void 0;
665
+ }
666
+ static Init() {
667
+ Utils.onDocumentReady(() => {
668
+ document.querySelectorAll(EXPANDING_CARD_SELECTOR).forEach((el) => {
669
+ if (el && el["Expressive_ExpandingCard"] == void 0) {
670
+ this.init(el);
671
+ }
672
+ });
673
+ });
674
+ }
675
+ };
676
+
677
+ // src/ts/components/menu.ts
678
+ var MIN_SURFACE_WIDTH = 112;
679
+ var MAX_SURFACE_WIDTH = 280;
680
+ var _defaults3 = {
521
681
  alignment: "left",
522
682
  autoFocus: true,
523
683
  constrainWidth: true,
@@ -533,6 +693,7 @@ var _defaults2 = {
533
693
  onCloseEnd: null,
534
694
  onItemClick: null
535
695
  };
696
+ var SPACE = " ";
536
697
  var _Menu = class _Menu extends Component {
537
698
  constructor(el, options) {
538
699
  super(el, options, _Menu);
@@ -578,8 +739,8 @@ var _Menu = class _Menu extends Component {
578
739
  this.isTouchMoving = false;
579
740
  };
580
741
  this._handleTriggerKeydown = (e) => {
581
- const arrowDownOrEnter = Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ENTER.includes(e.key);
582
- if (arrowDownOrEnter && !this.isOpen) {
742
+ const opensMenu = e.key === SPACE || e.key === Utils.keys.ENTER || e.key === Utils.keys.ARROW_DOWN || e.key === Utils.keys.ARROW_UP;
743
+ if (opensMenu && !this.isOpen) {
583
744
  e.preventDefault();
584
745
  this.open();
585
746
  }
@@ -593,13 +754,18 @@ var _Menu = class _Menu extends Component {
593
754
  this._handleMenuClick = (e) => {
594
755
  const target = e.target;
595
756
  const li = target.closest("li");
757
+ if (li?.matches('.disabled, [aria-disabled="true"]')) {
758
+ e.preventDefault();
759
+ e.stopPropagation();
760
+ return;
761
+ }
596
762
  if (li && this._isSubmenuTriggerClick(target)) {
597
763
  e.preventDefault();
598
764
  e.stopPropagation();
599
765
  this._toggleSubmenu(li);
600
766
  return;
601
767
  }
602
- if (typeof this.options.onItemClick === "function") {
768
+ if (li && typeof this.options.onItemClick === "function") {
603
769
  this.options.onItemClick.call(this, li);
604
770
  }
605
771
  };
@@ -612,11 +778,11 @@ var _Menu = class _Menu extends Component {
612
778
  }
613
779
  };
614
780
  this._handleMenuKeydown = (e) => {
615
- const arrowUpOrDown = Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key);
616
- if (Utils.keys.TAB.includes(e.key)) {
781
+ const arrowUpOrDown = e.key === Utils.keys.ARROW_DOWN || e.key === Utils.keys.ARROW_UP;
782
+ if (e.key === Utils.keys.TAB) {
617
783
  e.preventDefault();
618
784
  this.close();
619
- } else if (Utils.keys.ARROW_RIGHT.includes(e.key) && this.isOpen) {
785
+ } else if (e.key === Utils.keys.ARROW_RIGHT && this.isOpen) {
620
786
  const li = this._focusedRow(e);
621
787
  if (li?.querySelector(":scope > menu")) {
622
788
  e.preventDefault();
@@ -626,7 +792,7 @@ var _Menu = class _Menu extends Component {
626
792
  const first = li.querySelector(":scope > menu > li");
627
793
  first?.focus();
628
794
  }
629
- } else if (Utils.keys.ARROW_LEFT.includes(e.key) && this.isOpen) {
795
+ } else if (e.key === Utils.keys.ARROW_LEFT && this.isOpen) {
630
796
  const submenu = this._containingSubmenu(e);
631
797
  if (submenu) {
632
798
  e.preventDefault();
@@ -637,7 +803,7 @@ var _Menu = class _Menu extends Component {
637
803
  }
638
804
  } else if (arrowUpOrDown && this.isOpen) {
639
805
  e.preventDefault();
640
- const direction = Utils.keys.ARROW_DOWN.includes(e.key) ? 1 : -1;
806
+ const direction = e.key === Utils.keys.ARROW_DOWN ? 1 : -1;
641
807
  const list = this._containingSubmenu(e) ?? this.menuEl;
642
808
  let newFocusedIndex = this.focusedIndex;
643
809
  let hasFoundNewIndex = false;
@@ -649,17 +815,17 @@ var _Menu = class _Menu extends Component {
649
815
  }
650
816
  } while (newFocusedIndex < list.children.length && newFocusedIndex >= 0);
651
817
  if (hasFoundNewIndex) {
652
- if (this.focusedIndex >= 0)
653
- list.children[this.focusedIndex]?.classList.remove("active");
818
+ if (this.focusedIndex >= 0) list.children[this.focusedIndex]?.classList.remove("active");
654
819
  this.focusedIndex = newFocusedIndex;
655
820
  const item = list.children[this.focusedIndex];
656
821
  item.classList.add("active");
657
822
  item.focus({ preventScroll: true });
658
823
  }
659
- } else if (Utils.keys.ENTER.includes(e.key) && this.isOpen) {
824
+ } else if ((e.key === Utils.keys.ENTER || e.key === SPACE) && this.isOpen) {
660
825
  const li = this._focusedRow(e);
826
+ e.preventDefault();
827
+ if (li?.matches('.disabled, [aria-disabled="true"]')) return;
661
828
  if (li?.querySelector(":scope > menu")) {
662
- e.preventDefault();
663
829
  this._toggleSubmenu(li);
664
830
  return;
665
831
  }
@@ -670,7 +836,7 @@ var _Menu = class _Menu extends Component {
670
836
  } else if (focusedElement instanceof HTMLElement) {
671
837
  focusedElement.click();
672
838
  }
673
- } else if (Utils.keys.ESC.includes(e.key) && this.isOpen) {
839
+ } else if (e.key === Utils.keys.ESC && this.isOpen) {
674
840
  e.preventDefault();
675
841
  const openSub = this.menuEl.querySelector("li.open");
676
842
  if (openSub) {
@@ -684,11 +850,12 @@ var _Menu = class _Menu extends Component {
684
850
  const keyText = e.key.toLowerCase();
685
851
  const isLetter = /[a-zA-Z0-9-_]/.test(keyText);
686
852
  const specialKeys = [
687
- ...Utils.keys.ARROW_DOWN,
688
- ...Utils.keys.ARROW_UP,
689
- ...Utils.keys.ENTER,
690
- ...Utils.keys.ESC,
691
- ...Utils.keys.TAB
853
+ Utils.keys.ARROW_DOWN,
854
+ Utils.keys.ARROW_UP,
855
+ Utils.keys.ENTER,
856
+ Utils.keys.ESC,
857
+ Utils.keys.TAB,
858
+ SPACE
692
859
  ];
693
860
  if (isLetter && !specialKeys.includes(e.key)) {
694
861
  this.filterQuery.push(keyText);
@@ -759,7 +926,7 @@ var _Menu = class _Menu extends Component {
759
926
  this.el["Expressive_Menu"] = this;
760
927
  _Menu._menus.push(this);
761
928
  this.id = Utils.getIdFromTrigger(el);
762
- this.menuEl = document.getElementById(this.id);
929
+ this.menuEl = Utils.getElementById(el, this.id);
763
930
  this.options = {
764
931
  ..._Menu.defaults,
765
932
  ...options
@@ -770,13 +937,17 @@ var _Menu = class _Menu extends Component {
770
937
  this.focusedIndex = -1;
771
938
  this.filterQuery = [];
772
939
  this.el.ariaExpanded = "false";
940
+ if (!this.el.hasAttribute("aria-haspopup")) this.el.setAttribute("aria-haspopup", "menu");
941
+ if (this.id && !this.el.hasAttribute("aria-controls"))
942
+ this.el.setAttribute("aria-controls", this.id);
773
943
  this._moveMenuToElement();
944
+ this._setupAccessibility();
774
945
  this._makeMenuFocusable();
775
946
  this._setupSubmenus();
776
947
  this._setupEventHandlers();
777
948
  }
778
949
  static get defaults() {
779
- return _defaults2;
950
+ return _defaults3;
780
951
  }
781
952
  /**
782
953
  * Initializes instances of Menu.
@@ -826,7 +997,9 @@ var _Menu = class _Menu extends Component {
826
997
  }
827
998
  _setupTemporaryEventHandlers() {
828
999
  document.body.addEventListener("click", this._handleDocumentClick);
829
- document.body.addEventListener("touchmove", this._handleDocumentTouchmove, { passive: true });
1000
+ document.body.addEventListener("touchmove", this._handleDocumentTouchmove, {
1001
+ passive: true
1002
+ });
830
1003
  this.menuEl?.addEventListener("keydown", this._handleMenuKeydown);
831
1004
  window.addEventListener("resize", this._handleWindowResize);
832
1005
  }
@@ -836,6 +1009,33 @@ var _Menu = class _Menu extends Component {
836
1009
  this.menuEl?.removeEventListener("keydown", this._handleMenuKeydown);
837
1010
  window.removeEventListener("resize", this._handleWindowResize);
838
1011
  }
1012
+ _setupAccessibility() {
1013
+ if (!this.menuEl) return;
1014
+ if (!this.menuEl.hasAttribute("role")) this.menuEl.setAttribute("role", "menu");
1015
+ const menus = [this.menuEl, ...this.menuEl.querySelectorAll("menu")];
1016
+ menus.forEach((menu) => {
1017
+ if (!menu.hasAttribute("role")) menu.setAttribute("role", "menu");
1018
+ if (menu.getAttribute("role") !== "menu") return;
1019
+ menu.querySelectorAll(":scope > li").forEach((li) => {
1020
+ if (li.classList.contains("divider")) {
1021
+ if (!li.hasAttribute("role")) li.setAttribute("role", "separator");
1022
+ return;
1023
+ }
1024
+ if (li.classList.contains("gap")) {
1025
+ li.setAttribute("aria-hidden", "true");
1026
+ return;
1027
+ }
1028
+ if (li.classList.contains("label") || li.classList.contains("optgroup")) {
1029
+ if (!li.hasAttribute("role")) li.setAttribute("role", "presentation");
1030
+ return;
1031
+ }
1032
+ if (!li.hasAttribute("role")) li.setAttribute("role", "menuitem");
1033
+ if (li.classList.contains("disabled") && !li.hasAttribute("aria-disabled")) {
1034
+ li.setAttribute("aria-disabled", "true");
1035
+ }
1036
+ });
1037
+ });
1038
+ }
839
1039
  _isSubmenuTriggerClick(target) {
840
1040
  if (!this.menuEl) return false;
841
1041
  const li = target.closest("li");
@@ -922,7 +1122,7 @@ var _Menu = class _Menu extends Component {
922
1122
  _makeMenuFocusable() {
923
1123
  if (!this.menuEl) return;
924
1124
  this.menuEl.popover = "";
925
- this.menuEl.tabIndex = 0;
1125
+ this.menuEl.tabIndex = -1;
926
1126
  this.menuEl.querySelectorAll(":scope li, :scope > hr").forEach((el) => {
927
1127
  if (el instanceof HTMLHRElement || el.classList.contains("divider") || el.classList.contains("gap") || el.classList.contains("label") || el.classList.contains("optgroup")) {
928
1128
  el.setAttribute("tabindex", "-1");
@@ -931,6 +1131,15 @@ var _Menu = class _Menu extends Component {
931
1131
  if (!el.getAttribute("tabindex")) el.setAttribute("tabindex", "0");
932
1132
  });
933
1133
  }
1134
+ _focusInitialItem() {
1135
+ if (!this.menuEl || !this.options.autoFocus) return;
1136
+ const first = Array.from(this.menuEl.children).find(
1137
+ (child) => child instanceof HTMLElement && child.tabIndex !== -1
1138
+ );
1139
+ if (!first) return;
1140
+ this.focusedIndex = Array.from(this.menuEl.children).indexOf(first);
1141
+ first.focus({ preventScroll: true });
1142
+ }
934
1143
  _focusFocusedItem() {
935
1144
  if (this.focusedIndex >= 0 && this.focusedIndex < this.menuEl.children.length && this.options.autoFocus) {
936
1145
  this.menuEl.children[this.focusedIndex].focus({
@@ -1025,7 +1234,7 @@ var _Menu = class _Menu extends Component {
1025
1234
  this.menuEl.style.transform = "scale(1)";
1026
1235
  }, 1);
1027
1236
  setTimeout(() => {
1028
- if (this.options.autoFocus) this.menuEl.focus();
1237
+ this._focusInitialItem();
1029
1238
  if (typeof this.options.onOpenEnd === "function") this.options.onOpenEnd.call(this, this.el);
1030
1239
  }, duration);
1031
1240
  }
@@ -1042,11 +1251,11 @@ var _Menu = class _Menu extends Component {
1042
1251
  }
1043
1252
  _getClosestAncestor(el, condition) {
1044
1253
  let ancestor = el.parentNode;
1045
- while (ancestor !== null && ancestor !== document) {
1046
- if (condition(ancestor)) {
1254
+ while (ancestor !== null && ancestor !== void 0 && ancestor !== document) {
1255
+ if (ancestor.nodeType === Node.ELEMENT_NODE && condition(ancestor)) {
1047
1256
  return ancestor;
1048
1257
  }
1049
- ancestor = ancestor.parentElement;
1258
+ ancestor = ancestor.parentNode ?? ancestor.host;
1050
1259
  }
1051
1260
  return null;
1052
1261
  }
@@ -1058,12 +1267,14 @@ var _Menu = class _Menu extends Component {
1058
1267
  }
1059
1268
  );
1060
1269
  if (!closestOverflowParent) {
1061
- closestOverflowParent = !!this.menuEl.offsetParent ? this.menuEl.offsetParent : this.menuEl.parentNode;
1270
+ const parent = !!this.menuEl.offsetParent ? this.menuEl.offsetParent : this.menuEl.parentNode;
1271
+ closestOverflowParent = parent.host ?? parent;
1062
1272
  }
1063
1273
  if (getComputedStyle(closestOverflowParent).position === "static")
1064
1274
  closestOverflowParent.style.position = "relative";
1065
1275
  const natural = this.menuEl.getBoundingClientRect().width;
1066
- const idealWidth = this.options.constrainWidth ? this.el.getBoundingClientRect().width : Math.min(280, Math.max(112, natural));
1276
+ const triggerWidth = this.el.getBoundingClientRect().width;
1277
+ const idealWidth = this.options.constrainWidth && triggerWidth >= MIN_SURFACE_WIDTH ? triggerWidth : Math.min(MAX_SURFACE_WIDTH, Math.max(MIN_SURFACE_WIDTH, natural));
1067
1278
  this.menuEl.style.width = idealWidth + "px";
1068
1279
  const positionInfo = this._getMenuPosition(closestOverflowParent);
1069
1280
  this.menuEl.style.left = positionInfo.x + "px";
@@ -1077,7 +1288,7 @@ _Menu._menus = [];
1077
1288
  var Menu = _Menu;
1078
1289
 
1079
1290
  // src/ts/components/autocomplete.ts
1080
- var _defaults3 = {
1291
+ var _defaults4 = {
1081
1292
  data: [],
1082
1293
  // Autocomplete data set
1083
1294
  onAutocomplete: null,
@@ -1107,7 +1318,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1107
1318
  constructor(el, options) {
1108
1319
  super(el, options, _Autocomplete);
1109
1320
  this._handleInputBlur = () => {
1110
- if (!this._mousedown) {
1321
+ if (!this._pointerDown) {
1111
1322
  this.close();
1112
1323
  this._resetAutocomplete();
1113
1324
  }
@@ -1116,9 +1327,9 @@ var _Autocomplete = class _Autocomplete extends Component {
1116
1327
  if (e.type === "keyup") _Autocomplete._keydown = false;
1117
1328
  this.count = 0;
1118
1329
  const actualValue = this.el.value.toLocaleLowerCase();
1119
- if (Utils.keys.ENTER.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key) || Utils.keys.ARROW_DOWN.includes(e.key))
1330
+ if (e.key === Utils.keys.ENTER || e.key === Utils.keys.ARROW_UP || e.key === Utils.keys.ARROW_DOWN)
1120
1331
  return;
1121
- if (this.oldVal !== actualValue && Utils.tabPressed) {
1332
+ if (this.oldVal !== actualValue && this.el.matches(":focus-visible")) {
1122
1333
  this.open();
1123
1334
  }
1124
1335
  this._inputChangeDetection(actualValue);
@@ -1142,7 +1353,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1142
1353
  this._handleInputKeydown = (e) => {
1143
1354
  _Autocomplete._keydown = true;
1144
1355
  const numItems = this.container.querySelectorAll("li").length;
1145
- if (Utils.keys.ENTER.includes(e.key) && this.activeIndex >= 0) {
1356
+ if (e.key === Utils.keys.ENTER && this.activeIndex >= 0) {
1146
1357
  const liElement = this.container.querySelectorAll("li")[this.activeIndex];
1147
1358
  if (liElement) {
1148
1359
  this.selectOption(liElement.getAttribute("data-id"));
@@ -1150,15 +1361,14 @@ var _Autocomplete = class _Autocomplete extends Component {
1150
1361
  }
1151
1362
  return;
1152
1363
  }
1153
- if (Utils.keys.ARROW_UP.includes(e.key) || Utils.keys.ARROW_DOWN.includes(e.key)) {
1364
+ if (e.key === Utils.keys.ARROW_UP || e.key === Utils.keys.ARROW_DOWN) {
1154
1365
  e.preventDefault();
1155
- if (Utils.keys.ARROW_UP.includes(e.key) && this.activeIndex > 0) this.activeIndex--;
1156
- if (Utils.keys.ARROW_DOWN.includes(e.key) && this.activeIndex < numItems - 1)
1366
+ if (e.key === Utils.keys.ARROW_UP && this.activeIndex > 0) this.activeIndex--;
1367
+ if (e.key === Utils.keys.ARROW_DOWN && this.activeIndex < numItems - 1)
1157
1368
  this.activeIndex++;
1158
- this.$active?.classList.remove("active");
1369
+ this._setActive(null);
1159
1370
  if (this.activeIndex >= 0) {
1160
- this.$active = this.container.querySelectorAll("li")[this.activeIndex];
1161
- this.$active?.classList.add("active");
1371
+ this._setActive(this.container.querySelectorAll("li")[this.activeIndex]);
1162
1372
  this.container.children[this.activeIndex].scrollIntoView({
1163
1373
  behavior: "smooth",
1164
1374
  block: "nearest",
@@ -1170,11 +1380,17 @@ var _Autocomplete = class _Autocomplete extends Component {
1170
1380
  this._handleInputClick = () => {
1171
1381
  this.open();
1172
1382
  };
1173
- this._handleContainerMousedownAndTouchstart = () => {
1174
- this._mousedown = true;
1383
+ // The flag says "a press is in flight inside the option list", so that a blur
1384
+ // caused by that press does not close the list out from under it. Without the
1385
+ // cancel half, a cancelled gesture left the flag set and the next blur could
1386
+ // not close the list at all.
1387
+ this._handleContainerPointerDown = (e) => {
1388
+ if (!e.isPrimary) return;
1389
+ if (e.pointerType === "mouse" && e.button !== 0) return;
1390
+ this._pointerDown = true;
1175
1391
  };
1176
- this._handleContainerMouseupAndTouchend = () => {
1177
- this._mousedown = false;
1392
+ this._handleContainerPointerUp = () => {
1393
+ this._pointerDown = false;
1178
1394
  };
1179
1395
  /**
1180
1396
  * Show autocomplete.
@@ -1187,7 +1403,9 @@ var _Autocomplete = class _Autocomplete extends Component {
1187
1403
  this._renderMenu();
1188
1404
  }
1189
1405
  if (!this.menu.isOpen) {
1190
- setTimeout(() => {
1406
+ if (this._openTimer !== void 0) clearTimeout(this._openTimer);
1407
+ this._openTimer = setTimeout(() => {
1408
+ this._openTimer = void 0;
1191
1409
  this.menu.open();
1192
1410
  }, 0);
1193
1411
  } else this.menu.recalculateDimensions();
@@ -1210,12 +1428,32 @@ var _Autocomplete = class _Autocomplete extends Component {
1210
1428
  this.selectedValues = this.selectedValues || this.options.selected.map((value) => ({ id: value })) || [];
1211
1429
  this.menuItems = this.options.data || [];
1212
1430
  this.$active = null;
1213
- this._mousedown = false;
1431
+ this._pointerDown = false;
1214
1432
  this._setupMenu();
1215
1433
  this._setupEventHandlers();
1216
1434
  }
1435
+ /**
1436
+ * The active entry, for both the eye and the screen reader. The class alone
1437
+ * was invisible to assistive technology; aria-activedescendant on the input
1438
+ * is what reports the move.
1439
+ *
1440
+ * Deliberately does not touch aria-selected. Active and selected are two
1441
+ * different things - in a multi-select the checkboxes track real choices,
1442
+ * and folding the highlight into aria-selected would announce a committed
1443
+ * choice as unselected the moment the user arrowed past it.
1444
+ */
1445
+ _setActive(item) {
1446
+ this.$active?.classList.remove("active");
1447
+ this.$active = item;
1448
+ if (item) {
1449
+ item.classList.add("active");
1450
+ this.el.setAttribute("aria-activedescendant", item.id);
1451
+ } else {
1452
+ this.el.removeAttribute("aria-activedescendant");
1453
+ }
1454
+ }
1217
1455
  static get defaults() {
1218
- return _defaults3;
1456
+ return _defaults4;
1219
1457
  }
1220
1458
  /**
1221
1459
  * Initializes instances of Autocomplete.
@@ -1241,6 +1479,10 @@ var _Autocomplete = class _Autocomplete extends Component {
1241
1479
  return _Autocomplete._loadingTemplate.cloneNode(true);
1242
1480
  }
1243
1481
  destroy() {
1482
+ if (this._openTimer !== void 0) {
1483
+ clearTimeout(this._openTimer);
1484
+ this._openTimer = void 0;
1485
+ }
1244
1486
  this._removeEventHandlers();
1245
1487
  this._removeMenu();
1246
1488
  this.el["Expressive_Autocomplete"] = void 0;
@@ -1251,12 +1493,9 @@ var _Autocomplete = class _Autocomplete extends Component {
1251
1493
  this.el.addEventListener("focus", this._handleInputFocus);
1252
1494
  this.el.addEventListener("keydown", this._handleInputKeydown);
1253
1495
  this.el.addEventListener("click", this._handleInputClick);
1254
- this.container.addEventListener("mousedown", this._handleContainerMousedownAndTouchstart);
1255
- this.container.addEventListener("mouseup", this._handleContainerMouseupAndTouchend);
1256
- if (typeof window.ontouchstart !== "undefined") {
1257
- this.container.addEventListener("touchstart", this._handleContainerMousedownAndTouchstart);
1258
- this.container.addEventListener("touchend", this._handleContainerMouseupAndTouchend);
1259
- }
1496
+ this.container.addEventListener("pointerdown", this._handleContainerPointerDown);
1497
+ this.container.addEventListener("pointerup", this._handleContainerPointerUp);
1498
+ this.container.addEventListener("pointercancel", this._handleContainerPointerUp);
1260
1499
  }
1261
1500
  _removeEventHandlers() {
1262
1501
  this.el.removeEventListener("blur", this._handleInputBlur);
@@ -1264,12 +1503,9 @@ var _Autocomplete = class _Autocomplete extends Component {
1264
1503
  this.el.removeEventListener("focus", this._handleInputFocus);
1265
1504
  this.el.removeEventListener("keydown", this._handleInputKeydown);
1266
1505
  this.el.removeEventListener("click", this._handleInputClick);
1267
- this.container.removeEventListener("mousedown", this._handleContainerMousedownAndTouchstart);
1268
- this.container.removeEventListener("mouseup", this._handleContainerMouseupAndTouchend);
1269
- if (typeof window.ontouchstart !== "undefined") {
1270
- this.container.removeEventListener("touchstart", this._handleContainerMousedownAndTouchstart);
1271
- this.container.removeEventListener("touchend", this._handleContainerMouseupAndTouchend);
1272
- }
1506
+ this.container.removeEventListener("pointerdown", this._handleContainerPointerDown);
1507
+ this.container.removeEventListener("pointerup", this._handleContainerPointerUp);
1508
+ this.container.removeEventListener("pointercancel", this._handleContainerPointerUp);
1273
1509
  }
1274
1510
  _setupMenu() {
1275
1511
  this.container = document.createElement("menu");
@@ -1277,6 +1513,10 @@ var _Autocomplete = class _Autocomplete extends Component {
1277
1513
  this.container.id = `autocomplete-options-${Utils.guid()}`;
1278
1514
  this.container.classList.add("autocomplete-content");
1279
1515
  this.container.ariaExpanded = "true";
1516
+ this.container.setAttribute("role", "listbox");
1517
+ this.el.setAttribute("role", "combobox");
1518
+ this.el.setAttribute("aria-autocomplete", "list");
1519
+ this.el.setAttribute("aria-controls", this.container.id);
1280
1520
  this.el.setAttribute("data-target", this.container.id);
1281
1521
  this.menuItems.forEach((menuItem) => {
1282
1522
  const itemElement = this._createMenuItem(menuItem);
@@ -1315,14 +1555,14 @@ var _Autocomplete = class _Autocomplete extends Component {
1315
1555
  }
1316
1556
  _resetCurrentElementPosition() {
1317
1557
  this.activeIndex = -1;
1318
- this.$active?.classList.remove("active");
1558
+ this._setActive(null);
1319
1559
  }
1320
1560
  _resetAutocomplete() {
1321
1561
  this.container.replaceChildren();
1322
1562
  this._resetCurrentElementPosition();
1323
1563
  this.oldVal = null;
1324
1564
  this.isOpen = false;
1325
- this._mousedown = false;
1565
+ this._pointerDown = false;
1326
1566
  }
1327
1567
  _highlightPartialText(input, label) {
1328
1568
  const start = label.toLocaleLowerCase().indexOf("" + input.toLocaleLowerCase());
@@ -1334,6 +1574,10 @@ var _Autocomplete = class _Autocomplete extends Component {
1334
1574
  }
1335
1575
  _createMenuItem(entry) {
1336
1576
  const item = document.createElement("li");
1577
+ item.id = `autocomplete-option-${Utils.guid()}`;
1578
+ item.setAttribute("role", "option");
1579
+ const isSelected = this.selectedValues.some((sel) => sel.id === entry.id);
1580
+ item.setAttribute("aria-selected", isSelected ? "true" : "false");
1337
1581
  item.setAttribute("data-id", entry.id);
1338
1582
  item.setAttribute(
1339
1583
  "style",
@@ -1346,7 +1590,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1346
1590
  selection.style.textAlign = "center";
1347
1591
  const checkbox = document.createElement("input");
1348
1592
  checkbox.type = "checkbox";
1349
- checkbox.checked = this.selectedValues.some((sel) => sel.id === entry.id);
1593
+ checkbox.checked = isSelected;
1350
1594
  const spacer = document.createElement("span");
1351
1595
  spacer.style.paddingLeft = "21px";
1352
1596
  selection.append(checkbox, spacer);
@@ -1492,7 +1736,7 @@ _Autocomplete._loadingTemplate = null;
1492
1736
  var Autocomplete = _Autocomplete;
1493
1737
 
1494
1738
  // src/ts/components/chips.ts
1495
- var _defaults4 = {
1739
+ var _defaults5 = {
1496
1740
  data: [],
1497
1741
  placeholder: "",
1498
1742
  secondaryPlaceholder: "",
@@ -1501,6 +1745,7 @@ var _defaults4 = {
1501
1745
  autocompleteOnly: false,
1502
1746
  limit: Infinity,
1503
1747
  allowUserInput: false,
1748
+ i18n: { remove: "Remove" },
1504
1749
  onChipAdd: null,
1505
1750
  onChipSelect: null,
1506
1751
  onChipDelete: null
@@ -1510,7 +1755,7 @@ var _Chips = class _Chips extends Component {
1510
1755
  super(el, options, _Chips);
1511
1756
  this._handleChipClick = (e) => {
1512
1757
  const _chip = e.target.closest(".chip");
1513
- const clickedClose = e.target.classList.contains("close");
1758
+ const clickedClose = !!e.target.closest(".close");
1514
1759
  if (_chip) {
1515
1760
  const index = this._chips.indexOf(_chip);
1516
1761
  if (index < 0) return;
@@ -1532,7 +1777,7 @@ var _Chips = class _Chips extends Component {
1532
1777
  };
1533
1778
  this._handleInputKeydown = (e) => {
1534
1779
  _Chips._keydown = true;
1535
- if (Utils.keys.ENTER.includes(e.key)) {
1780
+ if (e.key === Utils.keys.ENTER) {
1536
1781
  if (this.hasAutocomplete && this.autocomplete && this.autocomplete.isOpen) {
1537
1782
  return;
1538
1783
  }
@@ -1541,7 +1786,7 @@ var _Chips = class _Chips extends Component {
1541
1786
  this.addChip({ id: this._input.value });
1542
1787
  }
1543
1788
  this._input.value = "";
1544
- } else if ((Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.ARROW_LEFT.includes(e.key)) && this._input.value === "" && this.chipsData.length) {
1789
+ } else if ((e.key === Utils.keys.BACKSPACE || e.key === Utils.keys.ARROW_LEFT) && this._input.value === "" && this.chipsData.length) {
1545
1790
  e.preventDefault();
1546
1791
  this.selectChip(this.chipsData.length - 1);
1547
1792
  }
@@ -1551,6 +1796,7 @@ var _Chips = class _Chips extends Component {
1551
1796
  ..._Chips.defaults,
1552
1797
  ...options
1553
1798
  };
1799
+ if (options?.i18n) this.options.i18n = { ..._Chips.defaults.i18n, ...options.i18n };
1554
1800
  this.el.classList.add("chips");
1555
1801
  this.chipsData = [];
1556
1802
  this._chips = [];
@@ -1566,8 +1812,22 @@ var _Chips = class _Chips extends Component {
1566
1812
  }
1567
1813
  this._setupLabel();
1568
1814
  }
1815
+ /**
1816
+ * Selection is drawn by a class now, not by `:focus`, so it does not clear
1817
+ * itself when focus moves - every path that changes the selection has to go
1818
+ * through here or the class and the field drift apart.
1819
+ *
1820
+ * Deliberately no `aria-selected`: the chip is not an option in a listbox,
1821
+ * and putting the attribute on an element with no such role is the same
1822
+ * defect the semantics standard exists to remove.
1823
+ */
1824
+ _setSelected(chip) {
1825
+ this._selectedChip?.classList.remove("selected");
1826
+ this._selectedChip = chip;
1827
+ chip?.classList.add("selected");
1828
+ }
1569
1829
  static get defaults() {
1570
- return _defaults4;
1830
+ return _defaults5;
1571
1831
  }
1572
1832
  /**
1573
1833
  * Initializes instances of Chips.
@@ -1617,28 +1877,30 @@ var _Chips = class _Chips extends Component {
1617
1877
  if (tag === "INPUT" || tag === "TEXTAREA" || !chipsKeydown) return;
1618
1878
  const currChips = chips["Expressive_Chips"];
1619
1879
  if (!currChips) return;
1620
- if (Utils.keys.BACKSPACE.includes(e.key) || Utils.keys.DELETE.includes(e.key)) {
1880
+ if (e.key === Utils.keys.BACKSPACE || e.key === Utils.keys.DELETE) {
1621
1881
  e.preventDefault();
1622
1882
  let selectIndex = currChips.chipsData.length;
1623
1883
  if (currChips._selectedChip) {
1624
1884
  const index = currChips._chips.indexOf(currChips._selectedChip);
1625
1885
  currChips.deleteChip(index);
1626
- currChips._selectedChip = null;
1886
+ currChips._setSelected(null);
1627
1887
  selectIndex = Math.max(index - 1, 0);
1628
1888
  }
1629
1889
  if (currChips.chipsData.length) currChips.selectChip(selectIndex);
1630
1890
  else currChips._input.focus();
1631
- } else if (Utils.keys.ARROW_LEFT.includes(e.key)) {
1891
+ } else if (e.key === Utils.keys.ARROW_LEFT) {
1632
1892
  if (currChips._selectedChip) {
1633
1893
  const selectIndex = currChips._chips.indexOf(currChips._selectedChip) - 1;
1634
1894
  if (selectIndex < 0) return;
1635
1895
  currChips.selectChip(selectIndex);
1636
1896
  }
1637
- } else if (Utils.keys.ARROW_RIGHT.includes(e.key)) {
1897
+ } else if (e.key === Utils.keys.ARROW_RIGHT) {
1638
1898
  if (currChips._selectedChip) {
1639
1899
  const selectIndex = currChips._chips.indexOf(currChips._selectedChip) + 1;
1640
- if (selectIndex >= currChips.chipsData.length) currChips._input.focus();
1641
- else currChips.selectChip(selectIndex);
1900
+ if (selectIndex >= currChips.chipsData.length) {
1901
+ currChips._setSelected(null);
1902
+ currChips._input.focus();
1903
+ } else currChips.selectChip(selectIndex);
1642
1904
  }
1643
1905
  }
1644
1906
  }
@@ -1649,25 +1911,31 @@ var _Chips = class _Chips extends Component {
1649
1911
  if (!_Chips._keydown && document.hidden) {
1650
1912
  const chips = e.target.closest(".chips");
1651
1913
  const currChips = chips?.["Expressive_Chips"];
1652
- if (currChips) currChips._selectedChip = null;
1914
+ if (currChips) currChips._setSelected(null);
1653
1915
  }
1654
1916
  }
1655
1917
  _renderChip(chip) {
1656
1918
  if (!chip.id) return;
1657
- const renderedChip = document.createElement("div");
1919
+ const label = chip.text || chip.id;
1920
+ const renderedChip = document.createElement("span");
1658
1921
  renderedChip.classList.add("chip");
1659
- renderedChip.innerText = chip.text || chip.id;
1922
+ renderedChip.innerText = label;
1660
1923
  if (chip.image) {
1661
1924
  const img = document.createElement("img");
1662
1925
  img.setAttribute("src", chip.image);
1663
1926
  renderedChip.insertBefore(img, renderedChip.firstChild);
1664
1927
  }
1665
1928
  if (this.options.allowUserInput) {
1666
- renderedChip.setAttribute("tabindex", "0");
1667
- const closeIcon = document.createElement("i");
1668
- closeIcon.classList.add(this.options.closeIconClass, "close");
1929
+ const closeButton = document.createElement("button");
1930
+ closeButton.type = "button";
1931
+ closeButton.classList.add("close");
1932
+ closeButton.setAttribute("aria-label", `${this.options.i18n.remove} ${label}`);
1933
+ const closeIcon = document.createElement("span");
1934
+ closeIcon.classList.add(this.options.closeIconClass);
1935
+ closeIcon.setAttribute("aria-hidden", "true");
1669
1936
  closeIcon.innerText = "close";
1670
- renderedChip.appendChild(closeIcon);
1937
+ closeButton.appendChild(closeIcon);
1938
+ renderedChip.appendChild(closeButton);
1671
1939
  }
1672
1940
  return renderedChip;
1673
1941
  }
@@ -1742,6 +2010,7 @@ var _Chips = class _Chips extends Component {
1742
2010
  deleteChip(chipIndex) {
1743
2011
  const chip = this._chips[chipIndex];
1744
2012
  if (!chip) return;
2013
+ if (this._selectedChip === chip) this._setSelected(null);
1745
2014
  chip.remove();
1746
2015
  this._chips.splice(chipIndex, 1);
1747
2016
  this.chipsData.splice(chipIndex, 1);
@@ -1757,8 +2026,8 @@ var _Chips = class _Chips extends Component {
1757
2026
  selectChip(chipIndex) {
1758
2027
  const chip = this._chips[chipIndex];
1759
2028
  if (!chip) return;
1760
- this._selectedChip = chip;
1761
- chip.focus();
2029
+ this._setSelected(chip);
2030
+ chip.querySelector(".close")?.focus();
1762
2031
  if (typeof this.options.onChipSelect === "function") {
1763
2032
  this.options.onChipSelect(this.el, chip);
1764
2033
  }
@@ -1769,7 +2038,7 @@ var _Chips = class _Chips extends Component {
1769
2038
  chips.forEach((el) => {
1770
2039
  el.addEventListener("click", (e) => {
1771
2040
  if (el["Expressive_Chips"]) return;
1772
- if (e.target.classList.contains("close")) {
2041
+ if (e.target.closest(".close")) {
1773
2042
  const chip = e.target.closest(".chip");
1774
2043
  if (chip) chip.remove();
1775
2044
  }
@@ -1781,97 +2050,93 @@ var _Chips = class _Chips extends Component {
1781
2050
  _Chips._keydown = false;
1782
2051
  var Chips = _Chips;
1783
2052
 
1784
- // src/ts/components/range.ts
1785
- var _defaults5 = {};
1786
- var Range = class _Range extends Component {
2053
+ // src/ts/components/slider.ts
2054
+ var _defaults6 = {};
2055
+ var Slider = class _Slider extends Component {
1787
2056
  constructor(el, options) {
1788
- super(el, options, _Range);
2057
+ super(el, options, _Slider);
1789
2058
  this._handleRangeChange = () => {
1790
2059
  this._clampDual();
1791
2060
  this._sync();
1792
2061
  this.thumb.classList.add("active");
1793
2062
  };
1794
- this._handleRangeMousedownTouchstart = (e) => {
1795
- this._mousedown = true;
2063
+ this._handleRangePointerDown = (e) => {
2064
+ if (!e.isPrimary) return;
2065
+ if (e.pointerType === "mouse" && e.button !== 0) return;
2066
+ this._pointerDown = true;
1796
2067
  this.el.classList.add("active");
1797
2068
  this._clampDual();
1798
2069
  this._sync();
1799
- if (e.type !== "input") {
1800
- this.thumb.classList.add("active");
1801
- }
2070
+ this.thumb.classList.add("active");
1802
2071
  };
1803
- this._handleRangeInputMousemoveTouchmove = () => {
1804
- if (this._mousedown) {
2072
+ this._handleRangeInputOrMove = () => {
2073
+ if (this._pointerDown) {
1805
2074
  this._clampDual();
1806
2075
  this._sync();
1807
2076
  this.thumb.classList.add("active");
1808
2077
  }
1809
2078
  };
1810
- this._handleRangeMouseupTouchend = () => {
1811
- this._mousedown = false;
2079
+ this._handleRangePointerUp = (e) => {
2080
+ if (!e.isPrimary) return;
2081
+ this._pointerDown = false;
1812
2082
  this.el.classList.remove("active");
1813
2083
  };
1814
- this._handleRangeBlurMouseoutTouchleave = () => {
1815
- if (!this._mousedown) {
2084
+ this._handleRangeRelease = () => {
2085
+ if (!this._pointerDown) {
1816
2086
  this.thumb.classList.remove("active");
1817
2087
  }
1818
2088
  };
1819
- this.el["Expressive_Range"] = this;
2089
+ this.el["Expressive_Slider"] = this;
1820
2090
  this.options = {
1821
- ..._Range.defaults,
2091
+ ..._Slider.defaults,
1822
2092
  ...options
1823
2093
  };
1824
- this._mousedown = false;
2094
+ this._pointerDown = false;
1825
2095
  this._setupThumb();
1826
2096
  this._sync();
1827
2097
  this._setupEventHandlers();
1828
2098
  }
1829
2099
  static get defaults() {
1830
- return _defaults5;
2100
+ return _defaults6;
1831
2101
  }
1832
2102
  /**
1833
- * Initializes instances of Range.
2103
+ * Initializes instances of Slider.
1834
2104
  * @param els HTML elements.
1835
2105
  * @param options Component options.
1836
2106
  */
1837
2107
  static init(els, options = {}) {
1838
- return super.init(els, options, _Range);
2108
+ return super.init(els, options, _Slider);
1839
2109
  }
1840
2110
  static getInstance(el) {
1841
- return el["Expressive_Range"];
2111
+ return el["Expressive_Slider"];
1842
2112
  }
1843
2113
  destroy() {
1844
2114
  this._removeEventHandlers();
1845
2115
  this._removeThumb();
1846
- this.el["Expressive_Range"] = void 0;
2116
+ this.el["Expressive_Slider"] = void 0;
1847
2117
  }
2118
+ // Eleven listeners used to cover four stages, because each one was written
2119
+ // twice - once for mouse, once for touch. One of the touch spellings,
2120
+ // `touchleave`, was never implemented by any browser at all.
1848
2121
  _setupEventHandlers() {
1849
2122
  this.el.addEventListener("change", this._handleRangeChange);
1850
- this.el.addEventListener("mousedown", this._handleRangeMousedownTouchstart);
1851
- this.el.addEventListener("touchstart", this._handleRangeMousedownTouchstart);
1852
- this.el.addEventListener("input", this._handleRangeInputMousemoveTouchmove);
1853
- this.el.addEventListener("mousemove", this._handleRangeInputMousemoveTouchmove);
1854
- this.el.addEventListener("touchmove", this._handleRangeInputMousemoveTouchmove, {
1855
- passive: true
1856
- });
1857
- this.el.addEventListener("mouseup", this._handleRangeMouseupTouchend);
1858
- this.el.addEventListener("touchend", this._handleRangeMouseupTouchend);
1859
- this.el.addEventListener("blur", this._handleRangeBlurMouseoutTouchleave);
1860
- this.el.addEventListener("mouseout", this._handleRangeBlurMouseoutTouchleave);
1861
- this.el.addEventListener("touchleave", this._handleRangeBlurMouseoutTouchleave);
2123
+ this.el.addEventListener("pointerdown", this._handleRangePointerDown);
2124
+ this.el.addEventListener("input", this._handleRangeInputOrMove);
2125
+ this.el.addEventListener("pointermove", this._handleRangeInputOrMove, { passive: true });
2126
+ this.el.addEventListener("pointerup", this._handleRangePointerUp);
2127
+ this.el.addEventListener("pointercancel", this._handleRangePointerUp);
2128
+ this.el.addEventListener("blur", this._handleRangeRelease);
2129
+ this.el.addEventListener("mouseout", this._handleRangeRelease);
1862
2130
  }
1863
2131
  _removeEventHandlers() {
1864
2132
  this.el.removeEventListener("change", this._handleRangeChange);
1865
- this.el.removeEventListener("mousedown", this._handleRangeMousedownTouchstart);
1866
- this.el.removeEventListener("touchstart", this._handleRangeMousedownTouchstart);
1867
- this.el.removeEventListener("input", this._handleRangeInputMousemoveTouchmove);
1868
- this.el.removeEventListener("mousemove", this._handleRangeInputMousemoveTouchmove);
1869
- this.el.removeEventListener("touchmove", this._handleRangeInputMousemoveTouchmove);
1870
- this.el.removeEventListener("mouseup", this._handleRangeMouseupTouchend);
1871
- this.el.removeEventListener("touchend", this._handleRangeMouseupTouchend);
1872
- this.el.removeEventListener("blur", this._handleRangeBlurMouseoutTouchleave);
1873
- this.el.removeEventListener("mouseout", this._handleRangeBlurMouseoutTouchleave);
1874
- this.el.removeEventListener("touchleave", this._handleRangeBlurMouseoutTouchleave);
2133
+ this.el.removeEventListener("pointerdown", this._handleRangePointerDown);
2134
+ this.el.removeEventListener("input", this._handleRangeInputOrMove);
2135
+ this.el.removeEventListener("pointermove", this._handleRangeInputOrMove);
2136
+ this.el.removeEventListener("pointerup", this._handleRangePointerUp);
2137
+ this.el.removeEventListener("pointercancel", this._handleRangePointerUp);
2138
+ this.el.removeEventListener("blur", this._handleRangeRelease);
2139
+ this.el.removeEventListener("mouseout", this._handleRangeRelease);
1875
2140
  }
1876
2141
  _setupThumb() {
1877
2142
  this.thumb = document.createElement("span");
@@ -1888,7 +2153,7 @@ var Range = class _Range extends Component {
1888
2153
  return !!this.el.closest(".vertical");
1889
2154
  }
1890
2155
  _host() {
1891
- return this.el.closest(".range, .range-field, label");
2156
+ return this.el.closest(".slider, .range, .range-field, label");
1892
2157
  }
1893
2158
  _clampDual() {
1894
2159
  const host = this._host();
@@ -1943,7 +2208,7 @@ var Range = class _Range extends Component {
1943
2208
  */
1944
2209
  static Init() {
1945
2210
  Utils.onDocumentReady(() => {
1946
- _Range.init(document.querySelectorAll("input[type=range]"), {});
2211
+ _Slider.init(document.querySelectorAll("input[type=range]"), {});
1947
2212
  });
1948
2213
  }
1949
2214
  };
@@ -2016,169 +2281,144 @@ var _Dialogs = class _Dialogs {
2016
2281
  _Dialogs._down = null;
2017
2282
  var Dialogs = _Dialogs;
2018
2283
 
2019
- // src/ts/behaviors/bottomSheets.ts
2020
- var _BottomSheets = class _BottomSheets {
2021
- static Init() {
2022
- Utils.onDocumentReady(() => {
2023
- document.addEventListener("pointerdown", _BottomSheets._onDown, { passive: true });
2024
- document.addEventListener("pointermove", _BottomSheets._onMove, { passive: true });
2025
- document.addEventListener("pointerup", _BottomSheets._onUp, { passive: true });
2026
- document.addEventListener("pointercancel", _BottomSheets._onCancel, { passive: true });
2027
- });
2028
- }
2029
- static _onDown(event) {
2284
+ // src/ts/behaviors/sheetDrag.ts
2285
+ var DISMISS_DISTANCE = 96;
2286
+ var DISMISS_VELOCITY = 0.5;
2287
+ var DRAG_SLOP = 4;
2288
+ function installSheetDrag(config) {
2289
+ const coord = (event) => config.axis === "x" ? event.clientX : event.clientY;
2290
+ let drag = null;
2291
+ const sheetFor = (target) => {
2292
+ if (!(target instanceof Element)) return null;
2293
+ const dialog = target.closest(config.selector);
2294
+ return dialog instanceof HTMLDialogElement ? dialog : null;
2295
+ };
2296
+ const reset = (dialog) => {
2297
+ dialog.style.transition = "";
2298
+ dialog.style.setProperty(config.property, "0px");
2299
+ };
2300
+ const onDown = (event) => {
2301
+ config.onPress?.();
2030
2302
  if (!event.isPrimary) return;
2031
2303
  if (event.pointerType === "mouse" && event.button !== 0) return;
2032
- const dialog = _BottomSheets._sheet(event.target);
2304
+ const dialog = sheetFor(event.target);
2033
2305
  if (!dialog?.open) {
2034
- _BottomSheets._drag = null;
2306
+ drag = null;
2035
2307
  return;
2036
2308
  }
2037
- if (!_BottomSheets._inHandle(event, dialog)) {
2038
- _BottomSheets._drag = null;
2309
+ if (!config.inHandle(event, dialog)) {
2310
+ drag = null;
2039
2311
  return;
2040
2312
  }
2041
2313
  dialog.style.transition = "none";
2042
- _BottomSheets._drag = {
2314
+ drag = {
2043
2315
  dialog,
2044
2316
  pointerId: event.pointerId,
2045
- startY: event.clientY,
2046
- lastY: event.clientY,
2317
+ direction: config.direction(dialog),
2318
+ start: coord(event),
2319
+ last: coord(event),
2047
2320
  lastT: Date.now(),
2048
2321
  shift: 0
2049
2322
  };
2050
- }
2051
- static _onMove(event) {
2052
- const drag = _BottomSheets._drag;
2323
+ };
2324
+ const onMove = (event) => {
2053
2325
  if (!drag || drag.pointerId !== event.pointerId) return;
2054
- const shift = Math.max(0, event.clientY - drag.startY);
2055
- drag.shift = shift;
2056
- drag.lastY = event.clientY;
2326
+ const delta = coord(event) - drag.start;
2327
+ drag.shift = drag.direction === 1 ? Math.max(0, delta) : Math.min(0, delta);
2328
+ drag.last = coord(event);
2057
2329
  drag.lastT = Date.now();
2058
- drag.dialog.style.setProperty("--md-comp-bottom-sheet-shift", `${shift}px`);
2059
- }
2060
- static _onUp(event) {
2061
- const drag = _BottomSheets._drag;
2062
- _BottomSheets._drag = null;
2063
- if (!drag || drag.pointerId !== event.pointerId) return;
2064
- const dialog = drag.dialog;
2065
- dialog.style.transition = "";
2066
- const dt = Math.max(1, Date.now() - drag.lastT);
2067
- const velocity = (event.clientY - drag.lastY) / dt;
2068
- const dismiss = drag.shift > 96 || velocity > 0.5;
2069
- if (dismiss && dialog.open) {
2070
- dialog.close();
2071
- }
2072
- dialog.style.setProperty("--md-comp-bottom-sheet-shift", "0px");
2073
- }
2074
- static _onCancel() {
2075
- const drag = _BottomSheets._drag;
2076
- _BottomSheets._drag = null;
2077
- if (!drag) return;
2078
- drag.dialog.style.transition = "";
2079
- drag.dialog.style.setProperty("--md-comp-bottom-sheet-shift", "0px");
2080
- }
2081
- static _sheet(target) {
2082
- if (!(target instanceof Element)) return null;
2083
- const dialog = target.closest("dialog.bottom-sheet, dialog.bottom");
2084
- return dialog instanceof HTMLDialogElement ? dialog : null;
2330
+ drag.dialog.style.setProperty(config.property, `${drag.shift}px`);
2331
+ };
2332
+ const onUp = (event) => {
2333
+ const held = drag;
2334
+ if (!held || held.pointerId !== event.pointerId) return;
2335
+ drag = null;
2336
+ held.dialog.style.transition = "";
2337
+ const dt = Math.max(1, Date.now() - held.lastT);
2338
+ const velocity = (coord(event) - held.last) / dt;
2339
+ config.onRelease?.(Math.abs(held.shift) > DRAG_SLOP);
2340
+ const dismiss = held.direction === 1 ? held.shift > DISMISS_DISTANCE || velocity > DISMISS_VELOCITY : held.shift < -DISMISS_DISTANCE || velocity < -DISMISS_VELOCITY;
2341
+ if (dismiss && held.dialog.open) held.dialog.close();
2342
+ held.dialog.style.setProperty(config.property, "0px");
2343
+ };
2344
+ const onCancel = () => {
2345
+ config.onRelease?.(false);
2346
+ const held = drag;
2347
+ drag = null;
2348
+ if (held) reset(held.dialog);
2349
+ };
2350
+ Utils.onDocumentReady(() => {
2351
+ document.addEventListener("pointerdown", onDown, { passive: true });
2352
+ document.addEventListener("pointermove", onMove, { passive: true });
2353
+ document.addEventListener("pointerup", onUp, { passive: true });
2354
+ document.addEventListener("pointercancel", onCancel, { passive: true });
2355
+ });
2356
+ }
2357
+
2358
+ // src/ts/behaviors/bottomSheets.ts
2359
+ var SHEET_SELECTOR = "dialog.bottom-sheet, dialog.bottom";
2360
+ var _BottomSheets = class _BottomSheets {
2361
+ static Init() {
2362
+ installSheetDrag({
2363
+ selector: SHEET_SELECTOR,
2364
+ axis: "y",
2365
+ property: "--md-comp-bottom-sheet-shift",
2366
+ direction: () => 1,
2367
+ inHandle: (event, dialog) => {
2368
+ const target = event.target;
2369
+ if (target instanceof Element && target.closest(".handle")) return true;
2370
+ const rect = dialog.getBoundingClientRect();
2371
+ return event.clientY >= rect.top && event.clientY <= rect.top + 48;
2372
+ },
2373
+ onPress: () => {
2374
+ _BottomSheets._dragged = false;
2375
+ },
2376
+ onRelease: (dragged) => {
2377
+ _BottomSheets._dragged = dragged;
2378
+ }
2379
+ });
2380
+ Utils.onDocumentReady(() => {
2381
+ document.addEventListener("click", _BottomSheets._onClick);
2382
+ });
2085
2383
  }
2086
- static _inHandle(event, dialog) {
2384
+ static _onClick(event) {
2087
2385
  const target = event.target;
2088
- if (target instanceof Element && target.closest(".handle")) return true;
2089
- const rect = dialog.getBoundingClientRect();
2090
- return event.clientY >= rect.top && event.clientY <= rect.top + 48;
2386
+ if (!(target instanceof Element)) return;
2387
+ const handle = target.closest(".handle, .drag-handle");
2388
+ if (!(handle instanceof HTMLButtonElement)) return;
2389
+ if (event.detail !== 0 && _BottomSheets._dragged) return;
2390
+ const dialog = handle.closest(SHEET_SELECTOR);
2391
+ if (dialog instanceof HTMLDialogElement && dialog.open) dialog.close();
2091
2392
  }
2092
2393
  };
2093
- _BottomSheets._drag = null;
2394
+ /**
2395
+ * Whether the last pointer sequence moved. A drag ends with a `click` on the
2396
+ * element it started on, so without this the tail of a drag that snapped back
2397
+ * would dismiss the sheet the drag had just declined to dismiss.
2398
+ */
2399
+ _BottomSheets._dragged = false;
2094
2400
  var BottomSheets = _BottomSheets;
2095
2401
 
2096
2402
  // src/ts/behaviors/sideSheets.ts
2097
- var _SideSheets = class _SideSheets {
2403
+ var startDocked = (dialog) => dialog.classList.contains("left") || dialog.classList.contains("left-sheet") || dialog.classList.contains("start");
2404
+ var SideSheets = class {
2098
2405
  static Init() {
2099
- Utils.onDocumentReady(() => {
2100
- document.addEventListener("pointerdown", _SideSheets._onDown, { passive: true });
2101
- document.addEventListener("pointermove", _SideSheets._onMove, { passive: true });
2102
- document.addEventListener("pointerup", _SideSheets._onUp, { passive: true });
2103
- document.addEventListener("pointercancel", _SideSheets._onCancel, { passive: true });
2406
+ installSheetDrag({
2407
+ selector: "dialog.side-sheet, dialog.right, dialog.right-sheet, dialog.left, dialog.left-sheet",
2408
+ axis: "x",
2409
+ property: "--md-comp-side-sheet-shift",
2410
+ // A start-docked sheet leaves toward the start edge, so its dismissal
2411
+ // direction is the negative one.
2412
+ direction: (dialog) => startDocked(dialog) ? -1 : 1,
2413
+ inHandle: (event, dialog) => {
2414
+ const target = event.target;
2415
+ if (target instanceof Element && target.closest("header")) return true;
2416
+ const rect = dialog.getBoundingClientRect();
2417
+ return startDocked(dialog) ? event.clientX >= rect.right - 24 && event.clientX <= rect.right : event.clientX >= rect.left && event.clientX <= rect.left + 24;
2418
+ }
2104
2419
  });
2105
2420
  }
2106
- static _onDown(event) {
2107
- if (!event.isPrimary) return;
2108
- if (event.pointerType === "mouse" && event.button !== 0) return;
2109
- const dialog = _SideSheets._sheet(event.target);
2110
- if (!dialog?.open) {
2111
- _SideSheets._drag = null;
2112
- return;
2113
- }
2114
- if (!_SideSheets._inHandle(event, dialog)) {
2115
- _SideSheets._drag = null;
2116
- return;
2117
- }
2118
- dialog.style.transition = "none";
2119
- _SideSheets._drag = {
2120
- dialog,
2121
- pointerId: event.pointerId,
2122
- startX: event.clientX,
2123
- lastX: event.clientX,
2124
- lastT: Date.now(),
2125
- shift: 0,
2126
- startDocked: _SideSheets._startDocked(dialog)
2127
- };
2128
- }
2129
- static _onMove(event) {
2130
- const drag = _SideSheets._drag;
2131
- if (!drag || drag.pointerId !== event.pointerId) return;
2132
- const delta = event.clientX - drag.startX;
2133
- const shift = drag.startDocked ? Math.min(0, delta) : Math.max(0, delta);
2134
- drag.shift = shift;
2135
- drag.lastX = event.clientX;
2136
- drag.lastT = Date.now();
2137
- drag.dialog.style.setProperty("--md-comp-side-sheet-shift", `${shift}px`);
2138
- }
2139
- static _onUp(event) {
2140
- const drag = _SideSheets._drag;
2141
- _SideSheets._drag = null;
2142
- if (!drag || drag.pointerId !== event.pointerId) return;
2143
- const dialog = drag.dialog;
2144
- dialog.style.transition = "";
2145
- const dt = Math.max(1, Date.now() - drag.lastT);
2146
- const velocity = (event.clientX - drag.lastX) / dt;
2147
- const dismiss = drag.startDocked ? drag.shift < -96 || velocity < -0.5 : drag.shift > 96 || velocity > 0.5;
2148
- if (dismiss && dialog.open) {
2149
- dialog.close();
2150
- }
2151
- dialog.style.setProperty("--md-comp-side-sheet-shift", "0px");
2152
- }
2153
- static _onCancel() {
2154
- const drag = _SideSheets._drag;
2155
- _SideSheets._drag = null;
2156
- if (!drag) return;
2157
- drag.dialog.style.transition = "";
2158
- drag.dialog.style.setProperty("--md-comp-side-sheet-shift", "0px");
2159
- }
2160
- static _sheet(target) {
2161
- if (!(target instanceof Element)) return null;
2162
- const dialog = target.closest(
2163
- "dialog.side-sheet, dialog.right, dialog.right-sheet, dialog.left, dialog.left-sheet"
2164
- );
2165
- return dialog instanceof HTMLDialogElement ? dialog : null;
2166
- }
2167
- static _startDocked(dialog) {
2168
- return dialog.classList.contains("left") || dialog.classList.contains("left-sheet") || dialog.classList.contains("start");
2169
- }
2170
- static _inHandle(event, dialog) {
2171
- const target = event.target;
2172
- if (target instanceof Element && target.closest("header")) return true;
2173
- const rect = dialog.getBoundingClientRect();
2174
- if (_SideSheets._startDocked(dialog)) {
2175
- return event.clientX >= rect.right - 24 && event.clientX <= rect.right;
2176
- }
2177
- return event.clientX >= rect.left && event.clientX <= rect.left + 24;
2178
- }
2179
2421
  };
2180
- _SideSheets._drag = null;
2181
- var SideSheets = _SideSheets;
2182
2422
 
2183
2423
  // src/ts/behaviors/forms.ts
2184
2424
  var Forms = class _Forms {
@@ -2234,7 +2474,7 @@ var Forms = class _Forms {
2234
2474
  document.addEventListener("keyup", (e) => {
2235
2475
  const target = e.target;
2236
2476
  if (target instanceof HTMLInputElement && ["radio", "checkbox"].includes(target.type)) {
2237
- if (Utils.keys.TAB.includes(e.key)) {
2477
+ if (e.key === Utils.keys.TAB) {
2238
2478
  target.classList.add("tabbed");
2239
2479
  target.addEventListener("blur", () => target.classList.remove("tabbed"), {
2240
2480
  once: true
@@ -2272,61 +2512,8 @@ var Forms = class _Forms {
2272
2512
  }
2273
2513
  };
2274
2514
 
2275
- // src/ts/behaviors/waves.ts
2276
- var Waves = class _Waves {
2277
- static _offset(el) {
2278
- const box = el.getBoundingClientRect();
2279
- const docElem = document.documentElement;
2280
- return {
2281
- top: box.top + window.pageYOffset - docElem.clientTop,
2282
- left: box.left + window.pageXOffset - docElem.clientLeft
2283
- };
2284
- }
2285
- // https://phoenix-dx.com/css-techniques-for-material-ripple-effect/
2286
- static renderWaveEffect(targetElement, position = null, color = null) {
2287
- const isCentered = position === null;
2288
- const duration = 500;
2289
- let animationFrame, animationStart;
2290
- const animationStep = function(timestamp) {
2291
- if (!animationStart) {
2292
- animationStart = timestamp;
2293
- }
2294
- const frame = timestamp - animationStart;
2295
- if (frame < duration) {
2296
- const easing = frame / duration * (2 - frame / duration);
2297
- const circle = isCentered ? "circle at 50% 50%" : `circle at ${position.x}px ${position.y}px`;
2298
- const waveColor = `rgba(${color?.r || 0}, ${color?.g || 0}, ${color?.b || 0}, ${0.3 * (1 - easing)})`;
2299
- const stop = 90 * easing + "%";
2300
- targetElement.style.backgroundImage = "radial-gradient(" + circle + ", " + waveColor + " " + stop + ", transparent " + stop + ")";
2301
- animationFrame = window.requestAnimationFrame(animationStep);
2302
- } else {
2303
- targetElement.style.backgroundImage = "none";
2304
- window.cancelAnimationFrame(animationFrame);
2305
- }
2306
- };
2307
- animationFrame = window.requestAnimationFrame(animationStep);
2308
- }
2309
- static Init() {
2310
- Utils.onDocumentReady(() => {
2311
- document.body.addEventListener("click", (e) => {
2312
- const trigger = e.target;
2313
- const el = trigger.closest(".waves-effect");
2314
- if (el && el.contains(trigger)) {
2315
- const isCircular = el.classList.contains("waves-circle");
2316
- const offset = _Waves._offset(el);
2317
- const x = e.pageX - offset.left;
2318
- const y = e.pageY - offset.top;
2319
- let color = null;
2320
- if (el.classList.contains("waves-light")) color = { r: 255, g: 255, b: 255 };
2321
- _Waves.renderWaveEffect(el, isCircular ? null : { x, y }, color);
2322
- }
2323
- });
2324
- });
2325
- }
2326
- };
2327
-
2328
2515
  // src/ts/components/buttons.ts
2329
- var _defaults6 = {
2516
+ var _defaults7 = {
2330
2517
  direction: "top",
2331
2518
  hoverEnabled: true,
2332
2519
  toolbarEnabled: false
@@ -2361,13 +2548,13 @@ var FloatingActionButton = class _FloatingActionButton extends Component {
2361
2548
  this._toggle();
2362
2549
  };
2363
2550
  this._handleAnchorKeydown = (e) => {
2364
- if (Utils.keys.ENTER.includes(e.key) || e.key === " ") {
2551
+ if (e.key === Utils.keys.ENTER || e.key === " ") {
2365
2552
  e.preventDefault();
2366
2553
  this._toggle();
2367
2554
  }
2368
2555
  };
2369
2556
  this._handleDocumentKeydown = (e) => {
2370
- if (Utils.keys.ESC.includes(e.key)) this.close();
2557
+ if (e.key === Utils.keys.ESC) this.close();
2371
2558
  };
2372
2559
  this._handleDocumentClick = (e) => {
2373
2560
  const target = e.target;
@@ -2387,22 +2574,19 @@ var FloatingActionButton = class _FloatingActionButton extends Component {
2387
2574
  };
2388
2575
  this.isOpen = false;
2389
2576
  this._anchor = this.el.querySelector(":scope > a, :scope > button");
2390
- this._menu = this.el.querySelector("ul, menu");
2391
2577
  this.el.classList.add(`direction-${this.options.direction}`);
2392
2578
  if (clickToToggle) this.el.classList.add("click-to-toggle");
2393
2579
  if (toolbar) this.el.classList.add("toolbar");
2394
2580
  if (this._anchor) {
2395
- this._anchor.setAttribute("aria-haspopup", "menu");
2396
2581
  this._anchor.setAttribute("aria-expanded", "false");
2397
2582
  if (this._anchor instanceof HTMLAnchorElement && !this._anchor.hasAttribute("href") && this._anchor.tabIndex < 0) {
2398
2583
  this._anchor.tabIndex = 0;
2399
2584
  }
2400
2585
  }
2401
- if (this._menu) this._menu.setAttribute("role", "menu");
2402
2586
  this._setupEventHandlers();
2403
2587
  }
2404
2588
  static get defaults() {
2405
- return _defaults6;
2589
+ return _defaults7;
2406
2590
  }
2407
2591
  static init(els, options = {}) {
2408
2592
  return super.init(els, options, _FloatingActionButton);
@@ -2440,16 +2624,21 @@ var FloatingActionButton = class _FloatingActionButton extends Component {
2440
2624
  };
2441
2625
 
2442
2626
  // src/ts/components/carousel.ts
2443
- var _defaults7 = {
2627
+ var _defaults8 = {
2444
2628
  duration: 200,
2445
- dist: -100,
2446
- shift: 0,
2447
- padding: 0,
2448
- numVisible: 5,
2449
2629
  fullWidth: false,
2450
2630
  indicators: false,
2451
2631
  noWrap: false,
2452
- onCycleTo: null
2632
+ interval: 0,
2633
+ height: null,
2634
+ onCycleTo: null,
2635
+ i18n: {
2636
+ carousel: "Carousel",
2637
+ item: "Item",
2638
+ of: "of",
2639
+ indicators: "Slides",
2640
+ slide: "Slide"
2641
+ }
2453
2642
  };
2454
2643
  var _Carousel = class _Carousel extends Component {
2455
2644
  constructor(el, options) {
@@ -2460,101 +2649,112 @@ var _Carousel = class _Carousel extends Component {
2460
2649
  this._ignoreScroll = false;
2461
2650
  this._trackRaf = null;
2462
2651
  this._started = false;
2652
+ this._vertical = false;
2653
+ this._resizeObserver = null;
2654
+ this._usesWindowResize = false;
2655
+ this._dragPointerId = null;
2656
+ this._dragStartX = 0;
2657
+ this._dragStartY = 0;
2658
+ this._dragStartScroll = 0;
2659
+ this._suppressClick = false;
2660
+ this._suppressClickTimeout = null;
2661
+ this._generatedContainerRole = false;
2662
+ this._generatedContainerLabel = false;
2663
+ this._generatedContainerDescription = false;
2664
+ this._generatedWideLayout = false;
2665
+ this._generatedFixedHeight = false;
2666
+ this._authoredInlineHeight = null;
2667
+ this._autoAdvanceTimer = null;
2668
+ this._autoAdvances = false;
2669
+ this._autoPaused = false;
2670
+ this._hovered = false;
2671
+ this._focused = false;
2672
+ this._generatedItemTabIndexes = /* @__PURE__ */ new Set();
2673
+ this._generatedItemLabels = /* @__PURE__ */ new Set();
2674
+ this._generatedItemDescriptions = /* @__PURE__ */ new Set();
2675
+ this._generatedItemSizes = /* @__PURE__ */ new Set();
2676
+ this._authoredItemSizes = /* @__PURE__ */ new Set();
2677
+ this._itemA11yOriginal = /* @__PURE__ */ new Map();
2463
2678
  this._handleThrottledResize = Utils.throttle(() => this._handleResize(), 200);
2464
- this._handleCarouselTap = (e) => {
2465
- if (e.pointerType === "mouse" && e.button !== 0) return;
2466
- if (e.target instanceof HTMLElement && e.target.tagName === "IMG") {
2467
- e.preventDefault();
2679
+ this._handleAutoAdvanceState = (e) => {
2680
+ if (e.type === "mouseenter") this._hovered = true;
2681
+ else if (e.type === "mouseleave") this._hovered = false;
2682
+ else if (e.type === "focusin") this._focused = true;
2683
+ else if (e.type === "focusout") this._focused = false;
2684
+ this._syncAutoAdvance();
2685
+ };
2686
+ this._tick = () => {
2687
+ this._autoAdvanceTimer = null;
2688
+ this._advance();
2689
+ this._syncAutoAdvance();
2690
+ };
2691
+ this._advance = () => {
2692
+ const next = this.center + 1;
2693
+ if (next < this.count) {
2694
+ this.set(next);
2695
+ return;
2696
+ }
2697
+ if (this.options.noWrap) {
2698
+ this._autoAdvances = false;
2699
+ this._syncAutoAdvance();
2700
+ return;
2468
2701
  }
2702
+ this.set(0);
2703
+ };
2704
+ this._handleTrackPointerDown = (e) => {
2705
+ if (e.pointerType !== "mouse" || e.button !== 0) return;
2469
2706
  this.pressed = true;
2470
2707
  this.dragged = false;
2471
- this.verticalDragged = false;
2472
- this.reference = e.clientX;
2473
- this.referenceY = e.clientY;
2474
- this.velocity = this.amplitude = 0;
2475
- this.frame = this.offset;
2476
- this.timestamp = Date.now();
2708
+ this._suppressClick = false;
2709
+ this._dragPointerId = e.pointerId;
2710
+ this._dragStartX = e.clientX;
2711
+ this._dragStartY = e.clientY;
2712
+ this._dragStartScroll = this._vertical ? this._scroller.scrollTop : this._scroller.scrollLeft;
2477
2713
  try {
2478
- this.el.setPointerCapture(e.pointerId);
2714
+ this._scroller.setPointerCapture(e.pointerId);
2479
2715
  } catch {
2480
2716
  }
2481
- if (this._trackRaf !== null) cancelAnimationFrame(this._trackRaf);
2482
- const loop = () => {
2483
- this._track();
2484
- if (this.pressed) this._trackRaf = requestAnimationFrame(loop);
2485
- else this._trackRaf = null;
2486
- };
2487
- this._trackRaf = requestAnimationFrame(loop);
2488
- };
2489
- this._handleCarouselDrag = (e) => {
2490
- if (!this.pressed) return;
2491
- const delta = this.reference - e.clientX;
2492
- const deltaY = Math.abs(this.referenceY - e.clientY);
2493
- if (deltaY < 30 && !this.verticalDragged) {
2494
- if (delta > 2 || delta < -2) {
2495
- this.dragged = true;
2496
- this.reference = e.clientX;
2497
- this._scroll(this.offset + delta);
2498
- }
2499
- } else if (this.dragged) {
2500
- e.preventDefault();
2501
- } else {
2502
- this.verticalDragged = true;
2717
+ };
2718
+ this._handleTrackPointerMove = (e) => {
2719
+ if (!this.pressed || e.pointerId !== this._dragPointerId) return;
2720
+ const deltaX = e.clientX - this._dragStartX;
2721
+ const deltaY = e.clientY - this._dragStartY;
2722
+ const primaryDelta = this._vertical ? deltaY : deltaX;
2723
+ const crossDelta = this._vertical ? deltaX : deltaY;
2724
+ if (!this.dragged) {
2725
+ if (Math.abs(primaryDelta) < 6 || Math.abs(primaryDelta) <= Math.abs(crossDelta)) return;
2726
+ this.dragged = true;
2727
+ this.el.classList.add("dragging");
2503
2728
  }
2504
- if (this.dragged) e.preventDefault();
2729
+ if (this._vertical) this._scroller.scrollTop = this._dragStartScroll - deltaY;
2730
+ else this._scroller.scrollLeft = this._dragStartScroll - deltaX;
2731
+ e.preventDefault();
2505
2732
  };
2506
- this._handleCarouselRelease = (e) => {
2507
- if (!this.pressed) return;
2733
+ this._handleTrackPointerUp = (e) => {
2734
+ if (!this.pressed || e.pointerId !== this._dragPointerId) return;
2508
2735
  this.pressed = false;
2509
- if (this._trackRaf !== null) {
2510
- cancelAnimationFrame(this._trackRaf);
2511
- this._trackRaf = null;
2512
- }
2736
+ this._dragPointerId = null;
2737
+ this.el.classList.remove("dragging");
2513
2738
  try {
2514
- this.el.releasePointerCapture(e.pointerId);
2739
+ this._scroller.releasePointerCapture(e.pointerId);
2515
2740
  } catch {
2516
2741
  }
2517
- this.target = this.offset;
2518
- if (this.velocity > 10 || this.velocity < -10) {
2519
- this.amplitude = 0.9 * this.velocity;
2520
- this.target = this.offset + this.amplitude;
2521
- }
2522
- this.target = Math.round(this.target / this.dim) * this.dim;
2523
- if (this.noWrap) {
2524
- if (this.target >= this.dim * (this.count - 1)) {
2525
- this.target = this.dim * (this.count - 1);
2526
- } else if (this.target < 0) {
2527
- this.target = 0;
2528
- }
2529
- }
2530
- this.amplitude = this.target - this.offset;
2531
- this.timestamp = Date.now();
2532
- requestAnimationFrame(this._autoScroll);
2533
- if (this.dragged) e.preventDefault();
2742
+ if (!this.dragged) return;
2743
+ this._suppressClick = true;
2744
+ window.clearTimeout(this._suppressClickTimeout);
2745
+ this._suppressClickTimeout = setTimeout(() => {
2746
+ this._suppressClick = false;
2747
+ }, 0);
2748
+ this._syncActive(this._nearestIndex(), true);
2749
+ };
2750
+ this._handleTrackClick = (e) => {
2751
+ if (!this._suppressClick) return;
2752
+ this._suppressClick = false;
2753
+ e.preventDefault();
2754
+ e.stopImmediatePropagation();
2534
2755
  };
2535
- this._handleCarouselClick = (e) => {
2536
- if (this.dragged) {
2537
- e.preventDefault();
2538
- e.stopPropagation();
2539
- return;
2540
- }
2541
- const clickedElem = e.target.closest(".carousel-item");
2542
- if (!clickedElem || !this.el.contains(clickedElem)) return;
2543
- const clickedIndex = this.images.indexOf(clickedElem);
2544
- const diff = this._wrap(this.center) - clickedIndex;
2545
- if (diff !== 0) {
2546
- e.preventDefault();
2547
- e.stopPropagation();
2548
- }
2549
- if (clickedIndex < 0) {
2550
- if (e.clientX - e.target.getBoundingClientRect().left > this.el.clientWidth / 2) {
2551
- this.next();
2552
- } else {
2553
- this.prev();
2554
- }
2555
- } else {
2556
- this._cycleTo(clickedIndex);
2557
- }
2756
+ this._handleTrackDragStart = (e) => {
2757
+ if (e.target.closest("img, picture, video")) e.preventDefault();
2558
2758
  };
2559
2759
  this._handleIndicatorClick = (e) => {
2560
2760
  e.stopPropagation();
@@ -2567,112 +2767,107 @@ var _Carousel = class _Carousel extends Component {
2567
2767
  this._handleKeydown = (e) => {
2568
2768
  const target = e.target;
2569
2769
  if (target.closest('input, textarea, select, [contenteditable="true"]')) return;
2570
- if (Utils.keys.ARROW_RIGHT.includes(e.key)) {
2770
+ const forward = this._vertical ? e.key === "ArrowDown" : e.key === Utils.keys.ARROW_RIGHT;
2771
+ const backward = this._vertical ? e.key === "ArrowUp" : e.key === Utils.keys.ARROW_LEFT;
2772
+ if (e.key === "Home") {
2773
+ e.preventDefault();
2774
+ this.set(0);
2775
+ this._focusItem(0);
2776
+ } else if (e.key === "End") {
2777
+ e.preventDefault();
2778
+ this.set(this.count - 1);
2779
+ this._focusItem(this.count - 1);
2780
+ } else if (forward) {
2571
2781
  e.preventDefault();
2572
2782
  this.next();
2573
- } else if (Utils.keys.ARROW_LEFT.includes(e.key)) {
2783
+ this._focusItem(this.center);
2784
+ } else if (backward) {
2574
2785
  e.preventDefault();
2575
2786
  this.prev();
2787
+ this._focusItem(this.center);
2576
2788
  }
2577
2789
  };
2578
- this._handleFlatScroll = () => {
2579
- if (this._ignoreScroll) return;
2580
- const index = this._nearestIndex();
2581
- if (index !== this.center) this._syncActive(index, this.dragged);
2790
+ this._handleTrackScroll = () => {
2791
+ if (!this.el.classList.contains("scrolling")) this.el.classList.add("scrolling");
2792
+ window.clearTimeout(this.scrollingTimeout);
2793
+ this.scrollingTimeout = setTimeout(() => this.el.classList.remove("scrolling"), 120);
2794
+ if (this._trackRaf !== null) return;
2795
+ this._trackRaf = requestAnimationFrame(() => {
2796
+ this._trackRaf = null;
2797
+ this._updateParallax();
2798
+ if (this._ignoreScroll) return;
2799
+ const index = this._nearestIndex();
2800
+ if (index !== this.center) this._syncActive(index, this.dragged);
2801
+ });
2582
2802
  };
2583
2803
  this._handleResize = () => {
2584
2804
  if (!this.images.length) return;
2585
- if (this._flat) {
2586
- this._scrollToIndex(this.center, false);
2587
- return;
2588
- }
2589
- if (this.options.fullWidth) {
2590
- const firstItem = this.images[0];
2591
- if (!firstItem) return;
2592
- this.itemWidth = firstItem.clientWidth;
2593
- this.dim = this.itemWidth * 2 + this.options.padding;
2594
- this.offset = this.center * 2 * this.itemWidth;
2595
- this.target = this.offset;
2596
- } else {
2597
- this._scroll();
2598
- }
2599
- };
2600
- this._track = () => {
2601
- const now = Date.now();
2602
- const elapsed = now - this.timestamp;
2603
- const delta = this.offset - this.frame;
2604
- const v = 1e3 * delta / (1 + elapsed);
2605
- this.timestamp = now;
2606
- this.frame = this.offset;
2607
- this.velocity = 0.8 * v + 0.2 * this.velocity;
2608
- };
2609
- this._autoScroll = () => {
2610
- if (!this.amplitude) return;
2611
- const elapsed = Date.now() - this.timestamp;
2612
- const delta = this.amplitude * Math.exp(-elapsed / this.options.duration);
2613
- if (delta > 2 || delta < -2) {
2614
- this._scroll(this.target - delta);
2615
- requestAnimationFrame(this._autoScroll);
2616
- } else {
2617
- this._scroll(this.target);
2618
- }
2805
+ this._syncAdaptiveMode();
2806
+ this._syncLayoutRoles(this.center);
2807
+ this._scrollToIndex(this.center, false);
2808
+ this._updateParallax();
2619
2809
  };
2620
2810
  this.el["Expressive_Carousel"] = this;
2621
2811
  this.options = {
2622
2812
  ..._Carousel.defaults,
2623
2813
  ...options
2624
2814
  };
2625
- this._flat = this.options.fullWidth || this.el.classList.contains("flat");
2626
- if (this._flat) {
2815
+ if (options?.i18n) {
2816
+ this.options.i18n = { ..._Carousel.defaults.i18n, ...options.i18n };
2817
+ }
2818
+ if (this.options.fullWidth || this.el.classList.contains("flat")) {
2627
2819
  this.el.classList.add("flat");
2628
2820
  this.options.fullWidth = true;
2629
- this.options.dist = 0;
2630
- }
2631
- if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
2632
- this.options.duration = 1;
2633
- if (!this._flat) this.options.dist = 0;
2634
2821
  }
2822
+ this._vertical = this.el.classList.contains("full-screen");
2823
+ const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
2824
+ if (reducedMotion) this.options.duration = 1;
2635
2825
  this.pressed = false;
2636
2826
  this.dragged = false;
2637
- this.offset = this.target = 0;
2638
2827
  this.images = this._collectItems();
2639
2828
  if (!this.images.length) {
2640
2829
  console.error("Carousel: no .carousel-item elements to show");
2641
2830
  return;
2642
2831
  }
2832
+ this.images.forEach((item) => {
2833
+ this._itemA11yOriginal.set(item, {
2834
+ ariaHidden: item.getAttribute("aria-hidden"),
2835
+ tabIndex: item.getAttribute("tabindex")
2836
+ });
2837
+ if (item.hasAttribute("data-carousel-size")) this._authoredItemSizes.add(item);
2838
+ });
2643
2839
  this.hasMultipleSlides = this.images.length > 1;
2644
2840
  this.showIndicators = this.options.indicators && this.hasMultipleSlides;
2645
- this.noWrap = this.options.noWrap || !this.hasMultipleSlides || this._flat;
2646
2841
  this.count = this.images.length;
2647
- this.options.numVisible = Math.min(this.count, this.options.numVisible);
2842
+ this._autoAdvances = this.options.interval > 0 && this.hasMultipleSlides && !reducedMotion;
2648
2843
  this.images.forEach((item) => item.classList.add("carousel-item"));
2649
- if (this._flat) this._wrapTrack();
2650
- const firstItem = this.images[0];
2651
- this.itemWidth = firstItem.clientWidth || this.el.clientWidth || 1;
2652
- this.itemHeight = firstItem.clientHeight || this.el.clientHeight || 1;
2653
- this.dim = this.itemWidth * 2 + this.options.padding || 1;
2844
+ if (this.options.height !== null) {
2845
+ this._generatedFixedHeight = !this.el.classList.contains("fixed-height");
2846
+ this._authoredInlineHeight = this.el.style.getPropertyValue("--carousel-height") || null;
2847
+ this.el.classList.add("fixed-height");
2848
+ this.el.style.setProperty("--carousel-height", `${this.options.height}px`);
2849
+ }
2850
+ this._wrapTrack();
2851
+ this._syncAdaptiveMode();
2654
2852
  if (this.showIndicators) this._setupIndicators();
2655
- this.el.tabIndex = this.el.tabIndex >= 0 ? this.el.tabIndex : 0;
2656
- this.el.setAttribute("aria-roledescription", "carousel");
2853
+ this._setupAccessibility();
2657
2854
  this._setupEventHandlers();
2658
2855
  this._started = true;
2659
- if (this._flat) {
2660
- const start = Math.max(
2661
- 0,
2662
- this.images.findIndex((el2) => el2.classList.contains("active"))
2663
- );
2664
- this.center = start;
2665
- this._syncActive(start, false);
2666
- this._scrollToIndex(start, false);
2667
- } else {
2668
- this._scroll(this.offset);
2669
- }
2856
+ const start = Math.max(
2857
+ 0,
2858
+ this.images.findIndex((el2) => el2.classList.contains("active"))
2859
+ );
2860
+ this.center = start;
2861
+ this._syncActive(start, false);
2862
+ this._updateParallax();
2863
+ this._scrollToIndex(start, false);
2864
+ this._syncAutoAdvance();
2670
2865
  }
2671
2866
  get _scroller() {
2672
2867
  return this._trackEl ?? this.el;
2673
2868
  }
2674
2869
  static get defaults() {
2675
- return _defaults7;
2870
+ return _defaults8;
2676
2871
  }
2677
2872
  static init(els, options = {}) {
2678
2873
  return super.init(els, options, _Carousel);
@@ -2697,6 +2892,39 @@ var _Carousel = class _Carousel extends Component {
2697
2892
  return el.tagName !== "NAV";
2698
2893
  });
2699
2894
  }
2895
+ _setupAccessibility() {
2896
+ if (!this.el.hasAttribute("role")) {
2897
+ this.el.setAttribute("role", "region");
2898
+ this._generatedContainerRole = true;
2899
+ }
2900
+ if (!this.el.hasAttribute("aria-label") && !this.el.hasAttribute("aria-labelledby")) {
2901
+ this.el.setAttribute("aria-label", this.options.i18n.carousel);
2902
+ this._generatedContainerLabel = true;
2903
+ }
2904
+ if (!this.el.hasAttribute("aria-roledescription")) {
2905
+ this.el.setAttribute("aria-roledescription", "carousel");
2906
+ this._generatedContainerDescription = true;
2907
+ }
2908
+ const naturallyFocusable = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
2909
+ this.images.forEach((item, index) => {
2910
+ if (!item.hasAttribute("aria-roledescription")) {
2911
+ item.setAttribute("aria-roledescription", "slide");
2912
+ this._generatedItemDescriptions.add(item);
2913
+ }
2914
+ if (!item.hasAttribute("aria-label") && !item.hasAttribute("aria-labelledby")) {
2915
+ const mediaName = item.querySelector("img[alt]")?.getAttribute("alt")?.trim();
2916
+ const textName = item.textContent?.replace(/\s+/g, " ").trim();
2917
+ const name = mediaName || textName;
2918
+ const position = `${this.options.i18n.item} ${index + 1} ${this.options.i18n.of} ${this.count}`;
2919
+ item.setAttribute("aria-label", name ? `${name}, ${position}` : position);
2920
+ this._generatedItemLabels.add(item);
2921
+ }
2922
+ if (!item.matches(naturallyFocusable) && !item.querySelector(naturallyFocusable)) {
2923
+ item.tabIndex = 0;
2924
+ this._generatedItemTabIndexes.add(item);
2925
+ }
2926
+ });
2927
+ }
2700
2928
  _setupIndicators() {
2701
2929
  const existing = Array.from(this.el.children).find(
2702
2930
  (el) => el instanceof HTMLElement && el.classList.contains("indicators")
@@ -2704,7 +2932,7 @@ var _Carousel = class _Carousel extends Component {
2704
2932
  this._indicators = existing ?? document.createElement("nav");
2705
2933
  this._ownIndicators = !existing;
2706
2934
  this._indicators.classList.add("indicators");
2707
- this._indicators.setAttribute("aria-label", "Slides");
2935
+ this._indicators.setAttribute("aria-label", this.options.i18n.indicators);
2708
2936
  this._indicators.replaceChildren();
2709
2937
  this.images.forEach((_, i) => {
2710
2938
  const button = document.createElement("button");
@@ -2714,158 +2942,124 @@ var _Carousel = class _Carousel extends Component {
2714
2942
  button.classList.add("active");
2715
2943
  button.setAttribute("aria-current", "true");
2716
2944
  }
2717
- button.setAttribute("aria-label", `Slide ${i + 1}`);
2945
+ button.setAttribute("aria-label", `${this.options.i18n.slide} ${i + 1}`);
2718
2946
  this._indicators.appendChild(button);
2719
2947
  });
2720
2948
  if (this._ownIndicators) this.el.appendChild(this._indicators);
2721
- if (this._flat) {
2722
- this.el.querySelector(".carousel-fixed-item")?.classList.add("with-indicators");
2723
- }
2949
+ this.el.querySelector(".carousel-fixed-item")?.classList.add("with-indicators");
2724
2950
  }
2725
2951
  _setupEventHandlers() {
2726
2952
  this.el.addEventListener("keydown", this._handleKeydown);
2953
+ if (this._autoAdvances) {
2954
+ this.el.addEventListener("mouseenter", this._handleAutoAdvanceState);
2955
+ this.el.addEventListener("mouseleave", this._handleAutoAdvanceState);
2956
+ this.el.addEventListener("focusin", this._handleAutoAdvanceState);
2957
+ this.el.addEventListener("focusout", this._handleAutoAdvanceState);
2958
+ document.addEventListener("visibilitychange", this._handleAutoAdvanceState);
2959
+ }
2727
2960
  if (this.showIndicators && this._indicators) {
2728
2961
  this._indicators.addEventListener("click", this._handleIndicatorClick);
2729
2962
  }
2730
- _Carousel._live.add(this);
2731
- if (!_Carousel._resizeListening) {
2732
- window.addEventListener("resize", _Carousel._onResize, { passive: true });
2733
- _Carousel._resizeListening = true;
2963
+ if (typeof ResizeObserver !== "undefined") {
2964
+ this._resizeObserver = new ResizeObserver(() => this._handleThrottledResize());
2965
+ this._resizeObserver.observe(this.el);
2734
2966
  }
2735
- if (this._flat) {
2736
- this._scroller.addEventListener("scroll", this._handleFlatScroll, { passive: true });
2737
- return;
2967
+ this._usesWindowResize = !this._resizeObserver || this.el.classList.contains("full-screen");
2968
+ if (this._usesWindowResize) {
2969
+ _Carousel._live.add(this);
2970
+ if (!_Carousel._resizeListening) {
2971
+ window.addEventListener("resize", _Carousel._onResize, {
2972
+ passive: true
2973
+ });
2974
+ _Carousel._resizeListening = true;
2975
+ }
2738
2976
  }
2739
- this.el.addEventListener("pointerdown", this._handleCarouselTap);
2740
- this.el.addEventListener("pointermove", this._handleCarouselDrag);
2741
- this.el.addEventListener("pointerup", this._handleCarouselRelease);
2742
- this.el.addEventListener("pointercancel", this._handleCarouselRelease);
2743
- this.el.addEventListener("click", this._handleCarouselClick);
2977
+ this._scroller.addEventListener("scroll", this._handleTrackScroll, {
2978
+ passive: true
2979
+ });
2980
+ this._scroller.addEventListener("pointerdown", this._handleTrackPointerDown);
2981
+ this._scroller.addEventListener("pointermove", this._handleTrackPointerMove);
2982
+ this._scroller.addEventListener("pointerup", this._handleTrackPointerUp);
2983
+ this._scroller.addEventListener("pointercancel", this._handleTrackPointerUp);
2984
+ this._scroller.addEventListener("click", this._handleTrackClick, true);
2985
+ this._scroller.addEventListener("dragstart", this._handleTrackDragStart);
2744
2986
  }
2745
2987
  _removeEventHandlers() {
2746
2988
  this.el.removeEventListener("keydown", this._handleKeydown);
2989
+ this.el.removeEventListener("mouseenter", this._handleAutoAdvanceState);
2990
+ this.el.removeEventListener("mouseleave", this._handleAutoAdvanceState);
2991
+ this.el.removeEventListener("focusin", this._handleAutoAdvanceState);
2992
+ this.el.removeEventListener("focusout", this._handleAutoAdvanceState);
2993
+ document.removeEventListener("visibilitychange", this._handleAutoAdvanceState);
2747
2994
  if (this._indicators) {
2748
2995
  this._indicators.removeEventListener("click", this._handleIndicatorClick);
2749
2996
  }
2750
- this._scroller.removeEventListener("scroll", this._handleFlatScroll);
2751
- this.el.removeEventListener("pointerdown", this._handleCarouselTap);
2752
- this.el.removeEventListener("pointermove", this._handleCarouselDrag);
2753
- this.el.removeEventListener("pointerup", this._handleCarouselRelease);
2754
- this.el.removeEventListener("pointercancel", this._handleCarouselRelease);
2755
- this.el.removeEventListener("click", this._handleCarouselClick);
2756
- _Carousel._live.delete(this);
2757
- if (_Carousel._live.size === 0 && _Carousel._resizeListening) {
2758
- window.removeEventListener("resize", _Carousel._onResize);
2759
- _Carousel._resizeListening = false;
2997
+ this._scroller.removeEventListener("scroll", this._handleTrackScroll);
2998
+ this._scroller.removeEventListener("pointerdown", this._handleTrackPointerDown);
2999
+ this._scroller.removeEventListener("pointermove", this._handleTrackPointerMove);
3000
+ this._scroller.removeEventListener("pointerup", this._handleTrackPointerUp);
3001
+ this._scroller.removeEventListener("pointercancel", this._handleTrackPointerUp);
3002
+ this._scroller.removeEventListener("click", this._handleTrackClick, true);
3003
+ this._scroller.removeEventListener("dragstart", this._handleTrackDragStart);
3004
+ this._resizeObserver?.disconnect();
3005
+ this._resizeObserver = null;
3006
+ if (this._usesWindowResize) {
3007
+ _Carousel._live.delete(this);
3008
+ if (_Carousel._live.size === 0 && _Carousel._resizeListening) {
3009
+ window.removeEventListener("resize", _Carousel._onResize);
3010
+ _Carousel._resizeListening = false;
3011
+ }
2760
3012
  }
2761
3013
  }
2762
3014
  _teardown() {
2763
3015
  this._removeEventHandlers();
3016
+ this._autoAdvances = false;
3017
+ this._syncAutoAdvance();
2764
3018
  if (this._trackRaf !== null) cancelAnimationFrame(this._trackRaf);
2765
3019
  window.clearTimeout(this.scrollingTimeout);
3020
+ window.clearTimeout(this._suppressClickTimeout);
2766
3021
  if (this._ownIndicators) this._indicators?.remove();
2767
3022
  this._unwrapTrack();
2768
3023
  this.images.forEach((el) => {
2769
- el.style.transform = "";
2770
- el.style.zIndex = "";
2771
- el.style.opacity = "";
2772
- el.style.visibility = "";
3024
+ el.style.removeProperty("--md-comp-carousel-item-parallax");
3025
+ if (this._generatedItemLabels.has(el)) el.removeAttribute("aria-label");
3026
+ if (this._generatedItemDescriptions.has(el)) el.removeAttribute("aria-roledescription");
3027
+ if (this._generatedItemSizes.has(el)) el.removeAttribute("data-carousel-size");
3028
+ const original = this._itemA11yOriginal.get(el);
3029
+ if (original?.ariaHidden === null) el.removeAttribute("aria-hidden");
3030
+ else if (original) el.setAttribute("aria-hidden", original.ariaHidden);
3031
+ if (original?.tabIndex === null) el.removeAttribute("tabindex");
3032
+ else if (original) el.setAttribute("tabindex", original.tabIndex);
2773
3033
  });
2774
- }
2775
- _xpos(e) {
2776
- if ("clientX" in e) return e.clientX;
2777
- return 0;
2778
- }
2779
- _ypos(e) {
2780
- if ("clientY" in e) return e.clientY;
2781
- return 0;
2782
- }
2783
- _wrap(x) {
2784
- return x >= this.count ? x % this.count : x < 0 ? this._wrap(this.count + x % this.count) : x;
2785
- }
2786
- _scroll(x = 0) {
2787
- if (!this.el.classList.contains("scrolling")) {
2788
- this.el.classList.add("scrolling");
2789
- }
2790
- window.clearTimeout(this.scrollingTimeout);
2791
- this.scrollingTimeout = setTimeout(() => {
2792
- this.el.classList.remove("scrolling");
2793
- }, this.options.duration);
2794
- this.offset = typeof x === "number" ? x : this.offset;
2795
- this.center = Math.floor((this.offset + this.dim / 2) / this.dim);
2796
- const half = this.count >> 1;
2797
- const delta = this.offset - this.center * this.dim;
2798
- const dir = delta < 0 ? 1 : -1;
2799
- const tween = -dir * delta * 2 / this.dim;
2800
- const lastCenter = this.center;
2801
- const numVisibleOffset = 1 / this.options.numVisible;
2802
- let alignment;
2803
- let centerTweenedOpacity;
2804
- if (this.options.fullWidth) {
2805
- alignment = "translateX(0)";
2806
- centerTweenedOpacity = 1;
2807
- } else {
2808
- alignment = "translateX(" + (this.el.clientWidth - this.itemWidth) / 2 + "px) ";
2809
- alignment += "translateY(" + (this.el.clientHeight - this.itemHeight) / 2 + "px)";
2810
- centerTweenedOpacity = 1 - numVisibleOffset * tween;
2811
- }
2812
- this._paintIndicators(this.center);
2813
- if (!this.noWrap || this.center >= 0 && this.center < this.count) {
2814
- const el = this.images[this._wrap(this.center)];
2815
- if (el && !el.classList.contains("active")) {
2816
- this.el.querySelector(".carousel-item.active")?.classList.remove("active");
2817
- el.classList.add("active");
2818
- }
2819
- }
2820
- for (let i = 1; i <= half; ++i) {
2821
- let zTranslation;
2822
- let tweenedOpacity;
2823
- if (this.options.fullWidth) {
2824
- zTranslation = this.options.dist;
2825
- tweenedOpacity = i === half && delta < 0 ? 1 - tween : 1;
2826
- } else {
2827
- zTranslation = this.options.dist * (i * 2 + tween * dir);
2828
- tweenedOpacity = 1 - numVisibleOffset * (i * 2 + tween * dir);
2829
- }
2830
- if (!this.noWrap || this.center + i < this.count) {
2831
- const el = this.images[this._wrap(this.center + i)];
2832
- const transformString = `${alignment} translateX(${this.options.shift + (this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`;
2833
- this._updateItemStyle(el, tweenedOpacity, -i, transformString);
2834
- }
2835
- if (this.options.fullWidth) {
2836
- zTranslation = this.options.dist;
2837
- tweenedOpacity = i === half && delta > 0 ? 1 - tween : 1;
2838
- } else {
2839
- zTranslation = this.options.dist * (i * 2 - tween * dir);
2840
- tweenedOpacity = 1 - numVisibleOffset * (i * 2 - tween * dir);
2841
- }
2842
- if (!this.noWrap || this.center - i >= 0) {
2843
- const el = this.images[this._wrap(this.center - i)];
2844
- const transformString = `${alignment} translateX(${-this.options.shift + (-this.dim * i - delta) / 2}px) translateZ(${zTranslation}px)`;
2845
- this._updateItemStyle(el, tweenedOpacity, -i, transformString);
2846
- }
2847
- }
2848
- if (!this.noWrap || this.center >= 0 && this.center < this.count) {
2849
- const el = this.images[this._wrap(this.center)];
2850
- const transformString = `${alignment} translateX(${-delta / 2}px) translateX(${dir * this.options.shift * tween}px) translateZ(${this.options.dist * tween}px)`;
2851
- this._updateItemStyle(el, centerTweenedOpacity, 0, transformString);
2852
- }
2853
- const currItem = this.images[this._wrap(this.center)];
2854
- this._syncA11y(this._wrap(this.center));
2855
- if (lastCenter !== this.center && typeof this.options.onCycleTo === "function") {
2856
- this.options.onCycleTo.call(this, currItem, this.dragged);
2857
- }
2858
- if (typeof this.oneTimeCallback === "function") {
2859
- this.oneTimeCallback.call(this, currItem, this.dragged);
2860
- this.oneTimeCallback = null;
3034
+ if (this._generatedContainerRole) this.el.removeAttribute("role");
3035
+ if (this._generatedContainerLabel) this.el.removeAttribute("aria-label");
3036
+ if (this._generatedContainerDescription) this.el.removeAttribute("aria-roledescription");
3037
+ if (this._generatedFixedHeight) this.el.classList.remove("fixed-height");
3038
+ if (this.options.height !== null) {
3039
+ if (this._authoredInlineHeight === null) this.el.style.removeProperty("--carousel-height");
3040
+ else this.el.style.setProperty("--carousel-height", this._authoredInlineHeight);
3041
+ }
3042
+ if (this._generatedWideLayout) {
3043
+ this.el.classList.remove(
3044
+ "multi-wide",
3045
+ "multi-large",
3046
+ "multi-extra-large",
3047
+ "full-screen-horizontal"
3048
+ );
2861
3049
  }
2862
3050
  }
2863
- _updateItemStyle(el, opacity, zIndex, transform) {
2864
- if (!el) return;
2865
- el.style.transform = transform;
2866
- el.style.zIndex = zIndex.toString();
2867
- el.style.opacity = opacity.toString();
2868
- el.style.visibility = "visible";
3051
+ /** Start or stop the timer to match the current pause state. */
3052
+ _syncAutoAdvance() {
3053
+ const run = this._autoAdvances && !this._autoPaused && !this._hovered && !this._focused && !document.hidden;
3054
+ if (run && this._autoAdvanceTimer === null) {
3055
+ this._autoAdvanceTimer = setTimeout(
3056
+ this._tick,
3057
+ this.options.duration + this.options.interval
3058
+ );
3059
+ } else if (!run && this._autoAdvanceTimer !== null) {
3060
+ clearTimeout(this._autoAdvanceTimer);
3061
+ this._autoAdvanceTimer = null;
3062
+ }
2869
3063
  }
2870
3064
  _paintIndicators(center) {
2871
3065
  if (!this.showIndicators || !this._indicators) return;
@@ -2877,18 +3071,12 @@ var _Carousel = class _Carousel extends Component {
2877
3071
  else el.removeAttribute("aria-current");
2878
3072
  });
2879
3073
  }
2880
- _syncA11y(index) {
2881
- this.images.forEach((el, i) => {
2882
- if (i === index) el.removeAttribute("aria-hidden");
2883
- else el.setAttribute("aria-hidden", "true");
2884
- });
2885
- }
2886
3074
  _syncActive(index, dragged) {
2887
3075
  const prev = this.center;
2888
3076
  this.center = index;
2889
3077
  this.images.forEach((el, i) => el.classList.toggle("active", i === index));
2890
3078
  this._paintIndicators(index);
2891
- this._syncA11y(index);
3079
+ this._syncLayoutRoles(index);
2892
3080
  const curr = this.images[index];
2893
3081
  if (prev !== index && typeof this.options.onCycleTo === "function") {
2894
3082
  this.options.onCycleTo.call(this, curr, dragged);
@@ -2898,6 +3086,81 @@ var _Carousel = class _Carousel extends Component {
2898
3086
  this.oneTimeCallback = null;
2899
3087
  }
2900
3088
  }
3089
+ _syncLayoutRoles(index) {
3090
+ const setSize = (item, size) => {
3091
+ if (this._authoredItemSizes.has(item)) return;
3092
+ item.setAttribute("data-carousel-size", size);
3093
+ this._generatedItemSizes.add(item);
3094
+ };
3095
+ this.images.forEach((item) => setSize(item, "large"));
3096
+ if (this.el.classList.contains("flat") || this.el.classList.contains("uncontained") || this.el.classList.contains("full-screen") && this._vertical) {
3097
+ return;
3098
+ }
3099
+ if (this.el.classList.contains("hero") || this.el.classList.contains("full-screen-horizontal")) {
3100
+ const next = this.images[index + 1];
3101
+ if (next) setSize(next, "small");
3102
+ if (this.el.classList.contains("center-aligned")) {
3103
+ const previous = this.images[index - 1];
3104
+ if (previous) setSize(previous, "small");
3105
+ }
3106
+ return;
3107
+ }
3108
+ const width = this.el.clientWidth;
3109
+ const desiredLargeCount = width >= 1600 ? 4 : width >= 1200 ? 3 : width >= 600 ? 2 : 1;
3110
+ const largeCount = Math.min(desiredLargeCount, Math.max(1, this.count - 2));
3111
+ this.el.classList.remove("multi-wide", "multi-large", "multi-extra-large");
3112
+ if (largeCount === 2) this.el.classList.add("multi-wide");
3113
+ else if (largeCount === 3) this.el.classList.add("multi-large");
3114
+ else if (largeCount >= 4) this.el.classList.add("multi-extra-large");
3115
+ this._generatedWideLayout = this._generatedWideLayout || largeCount > 1;
3116
+ for (let offset = 1; offset < largeCount; offset += 1) {
3117
+ const item = this.images[index + offset];
3118
+ if (item) setSize(item, "large");
3119
+ }
3120
+ const medium = this.images[index + largeCount];
3121
+ const small = this.images[index + largeCount + 1];
3122
+ if (medium) setSize(medium, "medium");
3123
+ if (small) setSize(small, "small");
3124
+ }
3125
+ _syncAdaptiveMode() {
3126
+ if (!this.el.classList.contains("full-screen")) return;
3127
+ const landscape = window.matchMedia("(orientation: landscape)").matches;
3128
+ const horizontal = this.el.clientWidth >= 840 || landscape;
3129
+ const wasVertical = this._vertical;
3130
+ this._vertical = !horizontal;
3131
+ this.el.classList.toggle("full-screen-horizontal", horizontal);
3132
+ this._generatedWideLayout = this._generatedWideLayout || horizontal;
3133
+ if (this._started && wasVertical !== this._vertical) {
3134
+ this._scroller.scrollTo({ left: 0, top: 0, behavior: "auto" });
3135
+ }
3136
+ }
3137
+ _focusItem(index) {
3138
+ const item = this.images[index];
3139
+ if (!item) return;
3140
+ const focusable = item.matches(
3141
+ 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
3142
+ ) ? item : item.querySelector(
3143
+ 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
3144
+ );
3145
+ (focusable ?? item).focus({ preventScroll: true });
3146
+ }
3147
+ _updateParallax() {
3148
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
3149
+ this.images.forEach(
3150
+ (item) => item.style.setProperty("--md-comp-carousel-item-parallax", "0px")
3151
+ );
3152
+ return;
3153
+ }
3154
+ const scrollerRect = this._scroller.getBoundingClientRect();
3155
+ const viewportCenter = this._vertical ? scrollerRect.top + scrollerRect.height / 2 : scrollerRect.left + scrollerRect.width / 2;
3156
+ const viewportSize = Math.max(1, this._vertical ? scrollerRect.height : scrollerRect.width);
3157
+ this.images.forEach((item) => {
3158
+ const rect = item.getBoundingClientRect();
3159
+ const itemCenter = this._vertical ? rect.top + rect.height / 2 : rect.left + rect.width / 2;
3160
+ const progress = Math.max(-1, Math.min(1, (itemCenter - viewportCenter) / viewportSize));
3161
+ item.style.setProperty("--md-comp-carousel-item-parallax", `${progress * -24}px`);
3162
+ });
3163
+ }
2901
3164
  _wrapTrack() {
2902
3165
  const track = document.createElement("div");
2903
3166
  track.className = "carousel-track";
@@ -2912,11 +3175,16 @@ var _Carousel = class _Carousel extends Component {
2912
3175
  this._trackEl = null;
2913
3176
  }
2914
3177
  _nearestIndex() {
2915
- const left = this._scroller.scrollLeft;
3178
+ const centered = this.el.classList.contains("center-aligned");
3179
+ const position = this._vertical ? this._scroller.scrollTop : this._scroller.scrollLeft;
3180
+ const viewportCenter = position + (this._vertical ? this._scroller.clientHeight : this._scroller.clientWidth) / 2;
2916
3181
  let best = 0;
2917
3182
  let bestDist = Infinity;
2918
3183
  this.images.forEach((el, i) => {
2919
- const dist = Math.abs(el.offsetLeft - left);
3184
+ const start = this._vertical ? el.offsetTop : el.offsetLeft;
3185
+ const size = this._vertical ? el.offsetHeight : el.offsetWidth;
3186
+ const target = centered ? start + size / 2 : start;
3187
+ const dist = Math.abs(target - (centered ? viewportCenter : position));
2920
3188
  if (dist < bestDist) {
2921
3189
  bestDist = dist;
2922
3190
  best = i;
@@ -2927,13 +3195,24 @@ var _Carousel = class _Carousel extends Component {
2927
3195
  _scrollToIndex(n, smooth = true) {
2928
3196
  const el = this.images[n];
2929
3197
  if (!el) return;
2930
- const left = el.offsetLeft;
2931
- if (Math.abs(this._scroller.scrollLeft - left) < 1) {
3198
+ const centered = this.el.classList.contains("center-aligned");
3199
+ const style = getComputedStyle(this._scroller);
3200
+ const inlinePadding = Number.parseFloat(style.paddingInlineStart) || 0;
3201
+ const blockPadding = Number.parseFloat(style.paddingBlockStart) || 0;
3202
+ const left = centered ? el.offsetLeft - (this._scroller.clientWidth - el.offsetWidth) / 2 : el.offsetLeft - inlinePadding;
3203
+ const top = el.offsetTop - blockPadding;
3204
+ const current = this._vertical ? this._scroller.scrollTop : this._scroller.scrollLeft;
3205
+ const target = this._vertical ? top : left;
3206
+ if (Math.abs(current - target) < 1) {
2932
3207
  this._syncActive(n, false);
2933
3208
  return;
2934
3209
  }
2935
3210
  this._ignoreScroll = true;
2936
- this._scroller.scrollTo({ left, behavior: smooth ? "smooth" : "auto" });
3211
+ this._scroller.scrollTo({
3212
+ left: this._vertical ? 0 : left,
3213
+ top: this._vertical ? top : 0,
3214
+ behavior: smooth ? "smooth" : "auto"
3215
+ });
2937
3216
  const done = () => {
2938
3217
  this._ignoreScroll = false;
2939
3218
  };
@@ -2941,63 +3220,38 @@ var _Carousel = class _Carousel extends Component {
2941
3220
  window.setTimeout(done, this.options.duration + 350);
2942
3221
  }
2943
3222
  _cycleTo(n, callback = null) {
2944
- if (this._flat) {
2945
- if (typeof callback === "function") this.oneTimeCallback = callback;
2946
- this._syncActive(n, false);
2947
- this._scrollToIndex(n);
2948
- return;
2949
- }
2950
- let diff = this.center % this.count - n;
2951
- if (!this.noWrap) {
2952
- if (diff < 0) {
2953
- if (Math.abs(diff + this.count) < Math.abs(diff)) {
2954
- diff += this.count;
2955
- }
2956
- } else if (diff > 0) {
2957
- if (Math.abs(diff - this.count) < diff) {
2958
- diff -= this.count;
2959
- }
2960
- }
2961
- }
2962
- this.target = this.dim * Math.round(this.offset / this.dim);
2963
- if (diff < 0) {
2964
- this.target += this.dim * Math.abs(diff);
2965
- } else if (diff > 0) {
2966
- this.target -= this.dim * diff;
2967
- }
2968
- if (typeof callback === "function") {
2969
- this.oneTimeCallback = callback;
2970
- }
2971
- if (this.offset !== this.target) {
2972
- this.amplitude = this.target - this.offset;
2973
- this.timestamp = Date.now();
2974
- requestAnimationFrame(this._autoScroll);
2975
- }
3223
+ if (typeof callback === "function") this.oneTimeCallback = callback;
3224
+ this._syncActive(n, false);
3225
+ this._scrollToIndex(n);
3226
+ }
3227
+ /**
3228
+ * Stop auto-advance until start() is called. Without an `interval` there is
3229
+ * nothing to stop and this does nothing.
3230
+ */
3231
+ pause() {
3232
+ this._autoPaused = true;
3233
+ this._syncAutoAdvance();
3234
+ }
3235
+ /** Resume auto-advance after pause(). */
3236
+ start() {
3237
+ this._autoPaused = false;
3238
+ this._syncAutoAdvance();
2976
3239
  }
2977
3240
  next(n = 1) {
2978
3241
  if (n === void 0 || isNaN(n)) n = 1;
2979
- let index = this.center + n;
2980
- if (index >= this.count || index < 0) {
2981
- if (this.noWrap) return;
2982
- index = this._wrap(index);
2983
- }
3242
+ const index = this.center + n;
3243
+ if (index >= this.count || index < 0) return;
2984
3244
  this._cycleTo(index);
2985
3245
  }
2986
3246
  prev(n = 1) {
2987
3247
  if (n === void 0 || isNaN(n)) n = 1;
2988
- let index = this.center - n;
2989
- if (index >= this.count || index < 0) {
2990
- if (this.noWrap) return;
2991
- index = this._wrap(index);
2992
- }
3248
+ const index = this.center - n;
3249
+ if (index >= this.count || index < 0) return;
2993
3250
  this._cycleTo(index);
2994
3251
  }
2995
3252
  set(n, callback) {
2996
3253
  if (n === void 0 || isNaN(n)) n = 0;
2997
- if (n > this.count || n < 0) {
2998
- if (this.noWrap) return;
2999
- n = this._wrap(n);
3000
- }
3254
+ if (n >= this.count || n < 0) return;
3001
3255
  this._cycleTo(n, callback);
3002
3256
  }
3003
3257
  };
@@ -3009,7 +3263,7 @@ _Carousel._onResize = Utils.throttle(() => {
3009
3263
  var Carousel = _Carousel;
3010
3264
 
3011
3265
  // src/ts/components/characterCounter.ts
3012
- var _defaults8 = Object.freeze({});
3266
+ var _defaults9 = Object.freeze({});
3013
3267
  var CharacterCounter = class _CharacterCounter extends Component {
3014
3268
  constructor(el, options) {
3015
3269
  super(el, {}, _CharacterCounter);
@@ -3034,7 +3288,7 @@ var CharacterCounter = class _CharacterCounter extends Component {
3034
3288
  this._setupEventHandlers();
3035
3289
  }
3036
3290
  static get defaults() {
3037
- return _defaults8;
3291
+ return _defaults9;
3038
3292
  }
3039
3293
  /**
3040
3294
  * Initializes instances of CharacterCounter.
@@ -3063,6 +3317,8 @@ var CharacterCounter = class _CharacterCounter extends Component {
3063
3317
  _setupCounter() {
3064
3318
  this.counterEl = document.createElement("span");
3065
3319
  this.counterEl.classList.add("character-counter");
3320
+ this.counterEl.setAttribute("aria-live", "polite");
3321
+ this.counterEl.setAttribute("aria-atomic", "true");
3066
3322
  this.counterEl.style.float = "right";
3067
3323
  this.counterEl.style.fontSize = "12px";
3068
3324
  this.counterEl.style.height = "1";
@@ -3084,7 +3340,7 @@ var CharacterCounter = class _CharacterCounter extends Component {
3084
3340
  };
3085
3341
 
3086
3342
  // src/ts/components/select.ts
3087
- var _defaults9 = {
3343
+ var _defaults10 = {
3088
3344
  classes: "",
3089
3345
  menuOptions: {}
3090
3346
  };
@@ -3133,7 +3389,7 @@ var FormSelect = class _FormSelect extends Component {
3133
3389
  this._setupEventHandlers();
3134
3390
  }
3135
3391
  static get defaults() {
3136
- return _defaults9;
3392
+ return _defaults10;
3137
3393
  }
3138
3394
  /**
3139
3395
  * Initializes instances of FormSelect.
@@ -3304,10 +3560,8 @@ var FormSelect = class _FormSelect extends Component {
3304
3560
  menuOptions.onOpenEnd = () => {
3305
3561
  const selectedOption = this.menuEl.querySelector(".selected");
3306
3562
  if (selectedOption) {
3307
- Utils.keyDown = true;
3308
3563
  this.menu.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption);
3309
3564
  this.menu._focusFocusedItem();
3310
- Utils.keyDown = false;
3311
3565
  if (this.menu.isScrollable) {
3312
3566
  let scrollOffset = selectedOption.getBoundingClientRect().top - this.menuEl.getBoundingClientRect().top;
3313
3567
  scrollOffset -= this.menuEl.clientHeight / 2;
@@ -3507,7 +3761,7 @@ var FormSelect = class _FormSelect extends Component {
3507
3761
  };
3508
3762
 
3509
3763
  // src/ts/plugins/dockedDisplayPlugin.ts
3510
- var _defaults10 = {
3764
+ var _defaults11 = {
3511
3765
  margin: 5,
3512
3766
  transition: 10,
3513
3767
  duration: 250,
@@ -3556,7 +3810,7 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
3556
3810
  };
3557
3811
  this.el = el;
3558
3812
  this.options = {
3559
- ..._defaults10,
3813
+ ..._defaults11,
3560
3814
  ...options
3561
3815
  };
3562
3816
  this.container = document.createElement("div");
@@ -3577,7 +3831,7 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
3577
3831
  };
3578
3832
 
3579
3833
  // src/ts/components/datepicker.ts
3580
- var _defaults11 = {
3834
+ var _defaults12 = {
3581
3835
  // the default output format for the input field value
3582
3836
  format: "mmm dd, yyyy",
3583
3837
  // Used to create date object from current input string
@@ -3702,7 +3956,7 @@ var _Datepicker = class _Datepicker extends Component {
3702
3956
  if (this.options.onInputInteraction) this.options.onInputInteraction.call(this);
3703
3957
  };
3704
3958
  this._handleInputKeydown = (e) => {
3705
- if (Utils.keys.ENTER.includes(e.key)) {
3959
+ if (e.key === Utils.keys.ENTER) {
3706
3960
  e.preventDefault();
3707
3961
  this._batchDraws(() => {
3708
3962
  this.setDateFromInput(e.target);
@@ -3842,7 +4096,7 @@ var _Datepicker = class _Datepicker extends Component {
3842
4096
  }
3843
4097
  }
3844
4098
  static get defaults() {
3845
- return _defaults11;
4099
+ return _defaults12;
3846
4100
  }
3847
4101
  /**
3848
4102
  * Initializes instances of Datepicker.
@@ -4425,11 +4679,11 @@ var _Datepicker = class _Datepicker extends Component {
4425
4679
  const monthSelect = this.calendarEl.querySelector(".orig-select-month");
4426
4680
  FormSelect.init(yearSelect, {
4427
4681
  classes: "select-year",
4428
- menuOptions: { container: document.body, constrainWidth: false }
4682
+ menuOptions: { container: Utils.portalRoot(this.el), constrainWidth: false }
4429
4683
  });
4430
4684
  FormSelect.init(monthSelect, {
4431
4685
  classes: "select-month",
4432
- menuOptions: { container: document.body, constrainWidth: false }
4686
+ menuOptions: { container: Utils.portalRoot(this.el), constrainWidth: false }
4433
4687
  });
4434
4688
  yearSelect.addEventListener("change", this._handleYearChange);
4435
4689
  monthSelect.addEventListener("change", this._handleMonthChange);
@@ -4560,7 +4814,7 @@ _Datepicker._template = `
4560
4814
  var Datepicker = _Datepicker;
4561
4815
 
4562
4816
  // src/ts/components/lightbox.ts
4563
- var _defaults12 = {
4817
+ var _defaults13 = {
4564
4818
  inDuration: 275,
4565
4819
  outDuration: 200,
4566
4820
  onOpenStart: null,
@@ -4575,7 +4829,7 @@ var Lightbox = class _Lightbox extends Component {
4575
4829
  this._handleLightboxToggle();
4576
4830
  };
4577
4831
  this._handleLightboxKeypress = (e) => {
4578
- if (Utils.keys.ENTER.includes(e.key)) {
4832
+ if (e.key === Utils.keys.ENTER) {
4579
4833
  this._handleLightboxToggle();
4580
4834
  }
4581
4835
  };
@@ -4590,7 +4844,7 @@ var Lightbox = class _Lightbox extends Component {
4590
4844
  if (this.overlayActive) this.close();
4591
4845
  };
4592
4846
  this._handleWindowEscape = (e) => {
4593
- if (Utils.keys.ESC.includes(e.key) && this.doneAnimating && this.overlayActive) this.close();
4847
+ if (e.key === Utils.keys.ESC && this.doneAnimating && this.overlayActive) this.close();
4594
4848
  };
4595
4849
  /**
4596
4850
  * Open lightbox.
@@ -4679,7 +4933,7 @@ var Lightbox = class _Lightbox extends Component {
4679
4933
  this._setupEventHandlers();
4680
4934
  }
4681
4935
  static get defaults() {
4682
- return _defaults12;
4936
+ return _defaults13;
4683
4937
  }
4684
4938
  /**
4685
4939
  * Initializes instances of Lightbox.
@@ -4709,13 +4963,13 @@ var Lightbox = class _Lightbox extends Component {
4709
4963
  _makeAncestorsOverflowVisible() {
4710
4964
  this._changedAncestorList = [];
4711
4965
  let ancestor = this.placeholder.parentNode;
4712
- while (ancestor !== null && ancestor !== document) {
4966
+ while (ancestor !== null && ancestor !== void 0 && ancestor !== document) {
4713
4967
  const curr = ancestor;
4714
- if (curr.style.overflow !== "visible") {
4968
+ if (curr.style && curr.style.overflow !== "visible") {
4969
+ this._changedAncestorList.push([curr, curr.style.overflow]);
4715
4970
  curr.style.overflow = "visible";
4716
- this._changedAncestorList.push(curr);
4717
4971
  }
4718
- ancestor = ancestor.parentNode;
4972
+ ancestor = ancestor.parentNode ?? ancestor.host;
4719
4973
  }
4720
4974
  }
4721
4975
  _offset(el) {
@@ -4779,7 +5033,7 @@ var Lightbox = class _Lightbox extends Component {
4779
5033
  if (this.originInlineStyles) this.el.setAttribute("style", this.originInlineStyles);
4780
5034
  this.el.classList.remove("active");
4781
5035
  this.doneAnimating = true;
4782
- this._changedAncestorList.forEach((anchestor) => anchestor.style.overflow = "");
5036
+ this._changedAncestorList.forEach(([ancestor, overflow]) => ancestor.style.overflow = overflow);
4783
5037
  if (typeof this.options.onCloseEnd === "function")
4784
5038
  this.options.onCloseEnd.call(this, this.el);
4785
5039
  }, duration);
@@ -4789,7 +5043,7 @@ var Lightbox = class _Lightbox extends Component {
4789
5043
  this._photoCaption = document.createElement("div");
4790
5044
  this._photoCaption.classList.add("lightbox-caption");
4791
5045
  this._photoCaption.innerText = this.caption;
4792
- document.body.append(this._photoCaption);
5046
+ Utils.portalRoot(this.el).append(this._photoCaption);
4793
5047
  this._photoCaption.style.display = "inline";
4794
5048
  this._photoCaption.style.transition = "none";
4795
5049
  this._photoCaption.style.opacity = "0";
@@ -4843,34 +5097,6 @@ var Lightbox = class _Lightbox extends Component {
4843
5097
  }
4844
5098
  };
4845
5099
 
4846
- // src/ts/components/parallax.ts
4847
- var _defaults13 = {};
4848
- var Parallax = class _Parallax extends Component {
4849
- constructor(el, options) {
4850
- super(el, options, _Parallax);
4851
- this.el["Expressive_Parallax"] = this;
4852
- this.options = {
4853
- ..._Parallax.defaults,
4854
- ...options
4855
- };
4856
- if (!this.el.querySelector("img, video")) {
4857
- console.error("Parallax: no <img> or <video> to move inside the .parallax element");
4858
- }
4859
- }
4860
- static get defaults() {
4861
- return _defaults13;
4862
- }
4863
- static init(els, options = {}) {
4864
- return super.init(els, options, _Parallax);
4865
- }
4866
- static getInstance(el) {
4867
- return el["Expressive_Parallax"];
4868
- }
4869
- destroy() {
4870
- this.el["Expressive_Parallax"] = void 0;
4871
- }
4872
- };
4873
-
4874
5100
  // src/ts/components/scrollspy.ts
4875
5101
  var _defaultGetActiveElement = (id) => `a[href="#${id}"]`;
4876
5102
  var _defaults14 = {
@@ -5017,7 +5243,7 @@ _ScrollSpy._onIntersect = (entries) => {
5017
5243
  };
5018
5244
  var ScrollSpy = _ScrollSpy;
5019
5245
 
5020
- // src/ts/components/sidenav.ts
5246
+ // src/ts/components/navigationDrawer.ts
5021
5247
  var _defaults15 = {
5022
5248
  edge: "left",
5023
5249
  draggable: true,
@@ -5027,17 +5253,17 @@ var _defaults15 = {
5027
5253
  onCloseStart: null,
5028
5254
  onCloseEnd: null
5029
5255
  };
5030
- var LARGE_UP = "(width >= 993px)";
5031
- var _Sidenav = class _Sidenav extends Component {
5256
+ var EXPANDED_UP = "(width >= 840px)";
5257
+ var _NavigationDrawer = class _NavigationDrawer extends Component {
5032
5258
  constructor(el, options) {
5033
- super(el, options, _Sidenav);
5259
+ super(el, options, _NavigationDrawer);
5034
5260
  /**
5035
5261
  * Opens the overlay drawer. No-op while the sidenav is docked
5036
- * (sidenav-fixed at the large breakpoint).
5262
+ * (navigation-drawer-fixed at the Expanded breakpoint).
5037
5263
  */
5038
5264
  this.open = () => {
5039
5265
  if (this._isCurrentlyFixed() || this.isOpen || !this._dialog) return;
5040
- _Sidenav._sidenavs.forEach((other) => {
5266
+ _NavigationDrawer._sidenavs.forEach((other) => {
5041
5267
  if (other !== this && other.isOpen) other.close();
5042
5268
  });
5043
5269
  if (typeof this.options.onOpenStart === "function") {
@@ -5089,7 +5315,7 @@ var _Sidenav = class _Sidenav extends Component {
5089
5315
  this._handleCloseTriggerClick = (e) => {
5090
5316
  const target = e.target;
5091
5317
  if (!(target instanceof Element)) return;
5092
- const closeTrigger = target.closest(".sidenav-close");
5318
+ const closeTrigger = target.closest(".sidenav-close, .navigation-drawer-close");
5093
5319
  if (closeTrigger && !this._isCurrentlyFixed()) {
5094
5320
  this.close();
5095
5321
  }
@@ -5133,14 +5359,14 @@ var _Sidenav = class _Sidenav extends Component {
5133
5359
  this.isDragged = false;
5134
5360
  this._verticallyScrolling = false;
5135
5361
  };
5136
- this.el["Expressive_Sidenav"] = this;
5362
+ this.el["Expressive_NavigationDrawer"] = this;
5137
5363
  this.options = {
5138
- ..._Sidenav.defaults,
5364
+ ..._NavigationDrawer.defaults,
5139
5365
  ...options
5140
5366
  };
5141
5367
  this.id = this.el.id;
5142
5368
  this.isOpen = false;
5143
- this.isFixed = this.el.classList.contains("sidenav-fixed");
5369
+ this.isFixed = this.el.classList.contains("navigation-drawer-fixed") || this.el.classList.contains("sidenav-fixed");
5144
5370
  this.isDragged = false;
5145
5371
  this.dragTarget = null;
5146
5372
  this._dialog = null;
@@ -5152,27 +5378,27 @@ var _Sidenav = class _Sidenav extends Component {
5152
5378
  this._width = 0;
5153
5379
  this._initialScrollTop = 0;
5154
5380
  this._verticallyScrolling = false;
5155
- this._mql = window.matchMedia(LARGE_UP);
5381
+ this._mql = window.matchMedia(EXPANDED_UP);
5156
5382
  this._setupDialog();
5157
5383
  this._createDragTarget();
5158
5384
  this._setupClasses();
5159
5385
  this._setupEventHandlers();
5160
5386
  this._syncTriggers();
5161
- _Sidenav._sidenavs.push(this);
5387
+ _NavigationDrawer._sidenavs.push(this);
5162
5388
  }
5163
5389
  static get defaults() {
5164
5390
  return _defaults15;
5165
5391
  }
5166
5392
  /**
5167
- * Initializes instances of Sidenav.
5393
+ * Initializes instances of NavigationDrawer.
5168
5394
  * @param els HTML elements.
5169
5395
  * @param options Component options.
5170
5396
  */
5171
5397
  static init(els, options = {}) {
5172
- return super.init(els, options, _Sidenav);
5398
+ return super.init(els, options, _NavigationDrawer);
5173
5399
  }
5174
5400
  static getInstance(el) {
5175
- return el["Expressive_Sidenav"];
5401
+ return el["Expressive_NavigationDrawer"];
5176
5402
  }
5177
5403
  destroy() {
5178
5404
  this._removeEventHandlers();
@@ -5185,10 +5411,10 @@ var _Sidenav = class _Sidenav extends Component {
5185
5411
  this._clearShift();
5186
5412
  this._unwrapDialog();
5187
5413
  this._removeDragTarget();
5188
- this.el["Expressive_Sidenav"] = void 0;
5189
- const index = _Sidenav._sidenavs.indexOf(this);
5414
+ this.el["Expressive_NavigationDrawer"] = void 0;
5415
+ const index = _NavigationDrawer._sidenavs.indexOf(this);
5190
5416
  if (index >= 0) {
5191
- _Sidenav._sidenavs.splice(index, 1);
5417
+ _NavigationDrawer._sidenavs.splice(index, 1);
5192
5418
  }
5193
5419
  }
5194
5420
  _beginClose() {
@@ -5219,6 +5445,11 @@ var _Sidenav = class _Sidenav extends Component {
5219
5445
  }
5220
5446
  const dialog = document.createElement("dialog");
5221
5447
  dialog.classList.add("sidenav-overlay");
5448
+ const named = this.el.closest("[aria-label], [aria-labelledby]") ?? this.el;
5449
+ const label = named.getAttribute("aria-label");
5450
+ const labelledBy = named.getAttribute("aria-labelledby");
5451
+ if (label) dialog.setAttribute("aria-label", label);
5452
+ else if (labelledBy) dialog.setAttribute("aria-labelledby", labelledBy);
5222
5453
  this.el.replaceWith(dialog);
5223
5454
  dialog.appendChild(this.el);
5224
5455
  this._dialog = dialog;
@@ -5236,7 +5467,7 @@ var _Sidenav = class _Sidenav extends Component {
5236
5467
  dragTarget.classList.add("drag-target");
5237
5468
  dragTarget.style.width = this.options.dragTargetWidth;
5238
5469
  if (this.isFixed) dragTarget.dataset.fixed = "";
5239
- document.body.appendChild(dragTarget);
5470
+ Utils.portalRoot(this.el).appendChild(dragTarget);
5240
5471
  this.dragTarget = dragTarget;
5241
5472
  }
5242
5473
  _removeDragTarget() {
@@ -5251,8 +5482,8 @@ var _Sidenav = class _Sidenav extends Component {
5251
5482
  }
5252
5483
  }
5253
5484
  _setupEventHandlers() {
5254
- if (_Sidenav._sidenavs.length === 0) {
5255
- document.body.addEventListener("click", _Sidenav._handleTriggerClick);
5485
+ if (_NavigationDrawer._sidenavs.length === 0) {
5486
+ document.body.addEventListener("click", _NavigationDrawer._handleTriggerClick);
5256
5487
  }
5257
5488
  const passive = { passive: true };
5258
5489
  this.dragTarget?.addEventListener("touchmove", this._handleDragTargetDrag, passive);
@@ -5264,8 +5495,8 @@ var _Sidenav = class _Sidenav extends Component {
5264
5495
  this._mql.addEventListener("change", this._onBreakpointChange);
5265
5496
  }
5266
5497
  _removeEventHandlers() {
5267
- if (_Sidenav._sidenavs.length === 1) {
5268
- document.body.removeEventListener("click", _Sidenav._handleTriggerClick);
5498
+ if (_NavigationDrawer._sidenavs.length === 1) {
5499
+ document.body.removeEventListener("click", _NavigationDrawer._handleTriggerClick);
5269
5500
  }
5270
5501
  this.dragTarget?.removeEventListener("touchmove", this._handleDragTargetDrag);
5271
5502
  this.dragTarget?.removeEventListener("touchend", this._handleDragTargetRelease);
@@ -5278,10 +5509,10 @@ var _Sidenav = class _Sidenav extends Component {
5278
5509
  static _handleTriggerClick(e) {
5279
5510
  const target = e.target;
5280
5511
  if (!(target instanceof Element)) return;
5281
- const trigger = target.closest(".sidenav-trigger");
5512
+ const trigger = target.closest(".sidenav-trigger, .navigation-drawer-trigger");
5282
5513
  if (!trigger || !(trigger instanceof HTMLElement)) return;
5283
5514
  const sidenavId = Utils.getIdFromTrigger(trigger);
5284
- const sidenavInstance = document.getElementById(sidenavId)?.["Expressive_Sidenav"];
5515
+ const sidenavInstance = Utils.getElementById(trigger, sidenavId)?.["Expressive_NavigationDrawer"];
5285
5516
  if (sidenavInstance) {
5286
5517
  sidenavInstance.open();
5287
5518
  e.preventDefault();
@@ -5335,7 +5566,7 @@ var _Sidenav = class _Sidenav extends Component {
5335
5566
  }
5336
5567
  _syncTriggers() {
5337
5568
  if (!this.id) return;
5338
- document.querySelectorAll(".sidenav-trigger").forEach((trigger) => {
5569
+ document.querySelectorAll(".sidenav-trigger, .navigation-drawer-trigger").forEach((trigger) => {
5339
5570
  if (!(trigger instanceof HTMLElement)) return;
5340
5571
  if (Utils.getIdFromTrigger(trigger) !== this.id) return;
5341
5572
  trigger.setAttribute("aria-expanded", this.isOpen ? "true" : "false");
@@ -5343,8 +5574,8 @@ var _Sidenav = class _Sidenav extends Component {
5343
5574
  });
5344
5575
  }
5345
5576
  };
5346
- _Sidenav._sidenavs = [];
5347
- var Sidenav = _Sidenav;
5577
+ _NavigationDrawer._sidenavs = [];
5578
+ var NavigationDrawer = _NavigationDrawer;
5348
5579
 
5349
5580
  // src/ts/components/navigationRail.ts
5350
5581
  var _defaults16 = {
@@ -5353,7 +5584,7 @@ var _defaults16 = {
5353
5584
  onCloseStart: null,
5354
5585
  onCloseEnd: null
5355
5586
  };
5356
- var COMPACT = "(width < 601px)";
5587
+ var COMPACT = "(width < 600px)";
5357
5588
  var NavigationRail = class _NavigationRail extends Component {
5358
5589
  constructor(el, options) {
5359
5590
  super(el, options, _NavigationRail);
@@ -5452,309 +5683,8 @@ var NavigationRail = class _NavigationRail extends Component {
5452
5683
  }
5453
5684
  };
5454
5685
 
5455
- // src/ts/components/slider.ts
5456
- var _defaults17 = {
5457
- indicators: true,
5458
- height: 400,
5459
- duration: 500,
5460
- interval: 6e3,
5461
- pauseOnFocus: true,
5462
- pauseOnHover: true,
5463
- indicatorLabelFunc: null
5464
- // Function which will generate a label for the indicators (ARIA)
5465
- };
5466
- var Slider = class _Slider extends Component {
5467
- constructor(el, options) {
5468
- super(el, options, _Slider);
5469
- // Nobody is watching a backgrounded tab. Browsers clamp the timer rather
5470
- // than stopping it, so without this the slider keeps cycling slides - and
5471
- // running their transitions - out of sight.
5472
- this._handleVisibilityChange = () => {
5473
- if (document.hidden) {
5474
- if (this.interval != null) this._pause(true);
5475
- } else if (this.eventPause && !(this.options.pauseOnHover && this._hovered) && !(this.options.pauseOnFocus && this._focused)) {
5476
- this.start();
5477
- }
5478
- };
5479
- this._handleIndicatorClick = (e) => {
5480
- const el = e.target.parentElement;
5481
- const currIndex = [...el.parentNode.children].indexOf(el);
5482
- this._focusCurrent = true;
5483
- this.set(currIndex);
5484
- };
5485
- this._handleAutoPauseHover = () => {
5486
- this._hovered = true;
5487
- if (this.interval != null) {
5488
- this._pause(true);
5489
- }
5490
- };
5491
- this._handleAutoPauseFocus = () => {
5492
- this._focused = true;
5493
- if (this.interval != null) {
5494
- this._pause(true);
5495
- }
5496
- };
5497
- this._handleAutoStartHover = () => {
5498
- this._hovered = false;
5499
- if (!(this.options.pauseOnFocus && this._focused) && this.eventPause) {
5500
- this.start();
5501
- }
5502
- };
5503
- this._handleAutoStartFocus = () => {
5504
- this._focused = false;
5505
- if (!(this.options.pauseOnHover && this._hovered) && this.eventPause) {
5506
- this.start();
5507
- }
5508
- };
5509
- this._handleInterval = () => {
5510
- const activeElem = this._slider.querySelector(".active");
5511
- let newActiveIndex = [...activeElem.parentNode.children].indexOf(activeElem);
5512
- if (this._slides.length === newActiveIndex + 1)
5513
- newActiveIndex = 0;
5514
- else newActiveIndex += 1;
5515
- this.set(newActiveIndex);
5516
- };
5517
- /**
5518
- * Pause slider autoslide.
5519
- */
5520
- this.pause = () => {
5521
- this._pause(false);
5522
- };
5523
- /**
5524
- * Start slider autoslide.
5525
- */
5526
- this.start = () => {
5527
- clearInterval(this.interval);
5528
- this.interval = setInterval(
5529
- this._handleInterval,
5530
- this.options.duration + this.options.interval
5531
- );
5532
- this.eventPause = false;
5533
- };
5534
- /**
5535
- * Move to next slider.
5536
- */
5537
- this.next = () => {
5538
- let newIndex = this.activeIndex + 1;
5539
- if (newIndex >= this._slides.length) newIndex = 0;
5540
- else if (newIndex < 0) newIndex = this._slides.length - 1;
5541
- this.set(newIndex);
5542
- };
5543
- /**
5544
- * Move to prev slider.
5545
- */
5546
- this.prev = () => {
5547
- let newIndex = this.activeIndex - 1;
5548
- if (newIndex >= this._slides.length) newIndex = 0;
5549
- else if (newIndex < 0) newIndex = this._slides.length - 1;
5550
- this.set(newIndex);
5551
- };
5552
- this.el["Expressive_Slider"] = this;
5553
- this.options = {
5554
- ..._Slider.defaults,
5555
- ...options
5556
- };
5557
- this.interval = null;
5558
- this.eventPause = false;
5559
- this._hovered = false;
5560
- this._focused = false;
5561
- this._focusCurrent = false;
5562
- this._slider = this.el.querySelector(".slides");
5563
- this._slides = Array.from(this._slider.querySelectorAll("li"));
5564
- this.activeIndex = this._slides.findIndex((li) => li.classList.contains("active"));
5565
- if (this.activeIndex !== -1) {
5566
- this._activeSlide = this._slides[this.activeIndex];
5567
- }
5568
- this._setSliderHeight();
5569
- if (this._slider.hasAttribute("id")) this._sliderId = this._slider.getAttribute("id");
5570
- else {
5571
- this._sliderId = "slider-" + Utils.guid();
5572
- this._slider.setAttribute("id", this._sliderId);
5573
- }
5574
- const placeholderBase64 = "data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
5575
- this._slides.forEach((slide) => {
5576
- const img = slide.querySelector("img");
5577
- if (img) {
5578
- if (img.src !== placeholderBase64) {
5579
- img.style.backgroundImage = "url(" + img.src + ")";
5580
- img.src = placeholderBase64;
5581
- }
5582
- }
5583
- if (!slide.hasAttribute("tabindex")) slide.setAttribute("tabindex", "-1");
5584
- slide.style.visibility = "hidden";
5585
- });
5586
- this._setupIndicators();
5587
- if (this._activeSlide) {
5588
- this._activeSlide.style.display = "block";
5589
- this._activeSlide.style.visibility = "visible";
5590
- } else {
5591
- this.activeIndex = 0;
5592
- this._slides[0].classList.add("active");
5593
- this._slides[0].style.visibility = "visible";
5594
- this._activeSlide = this._slides[0];
5595
- this._animateSlide(this._slides[0], true);
5596
- if (this.options.indicators) {
5597
- this._indicators[this.activeIndex].children[0].classList.add("active");
5598
- }
5599
- }
5600
- this._setupEventHandlers();
5601
- this.start();
5602
- }
5603
- static get defaults() {
5604
- return _defaults17;
5605
- }
5606
- /**
5607
- * Initializes instances of Slider.
5608
- * @param els HTML elements.
5609
- * @param options Component options.
5610
- */
5611
- static init(els, options = {}) {
5612
- return super.init(els, options, _Slider);
5613
- }
5614
- static getInstance(el) {
5615
- return el["Expressive_Slider"];
5616
- }
5617
- destroy() {
5618
- this.pause();
5619
- this._removeIndicators();
5620
- this._removeEventHandlers();
5621
- this.el["Expressive_Slider"] = void 0;
5622
- }
5623
- _setupEventHandlers() {
5624
- if (this.options.pauseOnFocus) {
5625
- this.el.addEventListener("focusin", this._handleAutoPauseFocus);
5626
- this.el.addEventListener("focusout", this._handleAutoStartFocus);
5627
- }
5628
- if (this.options.pauseOnHover) {
5629
- this.el.addEventListener("mouseenter", this._handleAutoPauseHover);
5630
- this.el.addEventListener("mouseleave", this._handleAutoStartHover);
5631
- }
5632
- if (this.options.indicators) {
5633
- this._indicators.forEach((el) => {
5634
- el.addEventListener("click", this._handleIndicatorClick);
5635
- });
5636
- }
5637
- document.addEventListener("visibilitychange", this._handleVisibilityChange);
5638
- }
5639
- _removeEventHandlers() {
5640
- if (this.options.pauseOnFocus) {
5641
- this.el.removeEventListener("focusin", this._handleAutoPauseFocus);
5642
- this.el.removeEventListener("focusout", this._handleAutoStartFocus);
5643
- }
5644
- if (this.options.pauseOnHover) {
5645
- this.el.removeEventListener("mouseenter", this._handleAutoPauseHover);
5646
- this.el.removeEventListener("mouseleave", this._handleAutoStartHover);
5647
- }
5648
- if (this.options.indicators) {
5649
- this._indicators.forEach((el) => {
5650
- el.removeEventListener("click", this._handleIndicatorClick);
5651
- });
5652
- }
5653
- document.removeEventListener("visibilitychange", this._handleVisibilityChange);
5654
- }
5655
- _animateSlide(slide, isDirectionIn) {
5656
- let dx = 0, dy = 0;
5657
- slide.style.opacity = isDirectionIn ? "0" : "1";
5658
- setTimeout(() => {
5659
- slide.style.transition = `opacity ${this.options.duration}ms ease`;
5660
- slide.style.opacity = isDirectionIn ? "1" : "0";
5661
- }, 1);
5662
- const caption = slide.querySelector(".caption");
5663
- if (!caption) return;
5664
- if (caption.classList.contains("center-align")) dy = -100;
5665
- else if (caption.classList.contains("right-align")) dx = 100;
5666
- else if (caption.classList.contains("left-align")) dx = -100;
5667
- caption.style.opacity = isDirectionIn ? "0" : "1";
5668
- caption.style.transform = isDirectionIn ? `translate(${dx}px, ${dy}px)` : `translate(0, 0)`;
5669
- setTimeout(() => {
5670
- caption.style.transition = `opacity ${this.options.duration}ms ease, transform ${this.options.duration}ms ease`;
5671
- caption.style.opacity = isDirectionIn ? "1" : "0";
5672
- caption.style.transform = isDirectionIn ? `translate(0, 0)` : `translate(${dx}px, ${dy}px)`;
5673
- }, this.options.duration);
5674
- }
5675
- _setSliderHeight() {
5676
- if (!this.el.classList.contains("fullscreen")) {
5677
- if (this.options.indicators) {
5678
- this.el.style.height = this.options.height + 40 + "px";
5679
- } else {
5680
- this.el.style.height = this.options.height + "px";
5681
- }
5682
- this._slider.style.height = this.options.height + "px";
5683
- }
5684
- }
5685
- _setupIndicators() {
5686
- if (this.options.indicators) {
5687
- const ul = document.createElement("ul");
5688
- ul.classList.add("indicators");
5689
- const arrLi = [];
5690
- this._slides.forEach((el, i) => {
5691
- const label = this.options.indicatorLabelFunc ? this.options.indicatorLabelFunc.call(this, i + 1, i === 0) : `${i + 1}`;
5692
- const li = document.createElement("li");
5693
- li.classList.add("indicator-item");
5694
- const button = document.createElement("button");
5695
- button.type = "button";
5696
- button.classList.add("indicator-item-btn");
5697
- button.setAttribute("aria-label", label);
5698
- button.setAttribute("aria-controls", this._sliderId);
5699
- li.appendChild(button);
5700
- arrLi.push(li);
5701
- ul.append(li);
5702
- });
5703
- this.el.append(ul);
5704
- this._indicators = arrLi;
5705
- }
5706
- }
5707
- _removeIndicators() {
5708
- this.el.querySelector("ul.indicators").remove();
5709
- }
5710
- set(index) {
5711
- if (index >= this._slides.length) index = 0;
5712
- else if (index < 0) index = this._slides.length - 1;
5713
- if (this.activeIndex === index) return;
5714
- this._activeSlide = this._slides[this.activeIndex];
5715
- const _caption = this._activeSlide.querySelector(".caption");
5716
- this._activeSlide.classList.remove("active");
5717
- this._slides.forEach((slide) => slide.style.visibility = "visible");
5718
- this._activeSlide.style.opacity = "0";
5719
- setTimeout(() => {
5720
- this._slides.forEach((slide) => {
5721
- if (slide.classList.contains("active")) return;
5722
- slide.style.opacity = "0";
5723
- slide.style.transform = "translate(0, 0)";
5724
- slide.style.visibility = "hidden";
5725
- });
5726
- }, this.options.duration);
5727
- if (_caption) _caption.style.opacity = "0";
5728
- if (this.options.indicators) {
5729
- const activeIndicator = this._indicators[this.activeIndex].children[0];
5730
- const nextIndicator = this._indicators[index].children[0];
5731
- activeIndicator.classList.remove("active");
5732
- nextIndicator.classList.add("active");
5733
- if (typeof this.options.indicatorLabelFunc === "function") {
5734
- activeIndicator.ariaLabel = this.options.indicatorLabelFunc.call(
5735
- this,
5736
- this.activeIndex,
5737
- false
5738
- );
5739
- nextIndicator.ariaLabel = this.options.indicatorLabelFunc.call(this, index, true);
5740
- }
5741
- }
5742
- this._animateSlide(this._slides[index], true);
5743
- this._slides[index].classList.add("active");
5744
- this.activeIndex = index;
5745
- if (this.interval != null) {
5746
- this.start();
5747
- }
5748
- }
5749
- _pause(fromEvent) {
5750
- clearInterval(this.interval);
5751
- this.eventPause = fromEvent;
5752
- this.interval = null;
5753
- }
5754
- };
5755
-
5756
5686
  // src/ts/components/tabs.ts
5757
- var _defaults18 = {
5687
+ var _defaults17 = {
5758
5688
  duration: 300,
5759
5689
  onShow: null,
5760
5690
  swipeable: false,
@@ -5783,12 +5713,10 @@ var Tabs = class _Tabs extends Component {
5783
5713
  return;
5784
5714
  }
5785
5715
  if (tabLink.hasAttribute("target")) return;
5786
- this._activeTabLink.classList.remove("active");
5787
5716
  const _oldContent = this._content;
5788
- this._activeTabLink = tabLink;
5789
5717
  if (tabLink.hash) this._content = document.querySelector(tabLink.hash);
5790
5718
  this._tabLinks = this._queryTabLinks();
5791
- this._activeTabLink.classList.add("active");
5719
+ this._setActiveTabLink(tabLink);
5792
5720
  const prevIndex = this._index;
5793
5721
  this._index = Math.max(Array.from(this._tabLinks).indexOf(tabLink), 0);
5794
5722
  if (this.options.swipeable) {
@@ -5832,7 +5760,7 @@ var Tabs = class _Tabs extends Component {
5832
5760
  this._setupEventHandlers();
5833
5761
  }
5834
5762
  static get defaults() {
5835
- return _defaults18;
5763
+ return _defaults17;
5836
5764
  }
5837
5765
  /**
5838
5766
  * Initializes instances of Tabs.
@@ -5883,6 +5811,26 @@ var Tabs = class _Tabs extends Component {
5883
5811
  this._indicator.style.left = this._calcLeftPos(this._activeTabLink) + "px";
5884
5812
  this._indicator.style.right = this._calcRightPos(this._activeTabLink) + "px";
5885
5813
  }
5814
+ /**
5815
+ * Which tab is current, for the eye and for assistive technology.
5816
+ *
5817
+ * The class alone is a colour. `aria-current` is the part a screen reader
5818
+ * reads, and because tabs are navigation rather than a tablist (rule 2 -
5819
+ * there is no keyboard model here to back a tablist), "current" is exactly
5820
+ * the right word for it. Its *value* changes as the user clicks, which makes
5821
+ * maintaining it the component's job, not the author's - see CONTEXT.md on
5822
+ * static semantics versus dynamic state. Writing it once in the markup and
5823
+ * never moving it left the old tab announcing itself as current.
5824
+ */
5825
+ _setActiveTabLink(tabLink) {
5826
+ Array.from(this._tabLinks).forEach((a) => {
5827
+ a.classList.remove("active");
5828
+ a.removeAttribute("aria-current");
5829
+ });
5830
+ this._activeTabLink = tabLink;
5831
+ tabLink.classList.add("active");
5832
+ tabLink.setAttribute("aria-current", "page");
5833
+ }
5886
5834
  _setupActiveTabLink() {
5887
5835
  this._activeTabLink = Array.from(this._tabLinks).find(
5888
5836
  (a) => a.getAttribute("href") === location.hash
@@ -5894,8 +5842,7 @@ var Tabs = class _Tabs extends Component {
5894
5842
  }
5895
5843
  this._activeTabLink = activeTabLink;
5896
5844
  }
5897
- Array.from(this._tabLinks).forEach((a) => a.classList.remove("active"));
5898
- this._activeTabLink.classList.add("active");
5845
+ this._setActiveTabLink(this._activeTabLink);
5899
5846
  this._index = Math.max(Array.from(this._tabLinks).indexOf(this._activeTabLink), 0);
5900
5847
  if (this._activeTabLink && this._activeTabLink.hash) {
5901
5848
  this._content = document.querySelector(this._activeTabLink.hash);
@@ -6000,7 +5947,7 @@ var Tabs = class _Tabs extends Component {
6000
5947
  };
6001
5948
 
6002
5949
  // src/ts/components/timepicker.ts
6003
- var _defaults19 = {
5950
+ var _defaults18 = {
6004
5951
  dialRadius: 135,
6005
5952
  outerRadius: 105,
6006
5953
  innerRadius: 70,
@@ -6034,6 +5981,8 @@ var _defaults19 = {
6034
5981
  var _Timepicker = class _Timepicker extends Component {
6035
5982
  constructor(el, options) {
6036
5983
  super(el, options, _Timepicker);
5984
+ /** Which pointer is dragging the clock hand; a second finger is ignored. */
5985
+ this._dragPointerId = null;
6037
5986
  /** Whether the dial (ticks + SVG + AM/PM buttons) has been built yet. */
6038
5987
  this._clockBuilt = false;
6039
5988
  this._handleInputClick = () => {
@@ -6043,7 +5992,7 @@ var _Timepicker = class _Timepicker extends Component {
6043
5992
  if (this.displayPlugin) this.displayPlugin.show();
6044
5993
  };
6045
5994
  this._handleInputKeydown = (e) => {
6046
- if (Utils.keys.ENTER.includes(e.key)) {
5995
+ if (e.key === Utils.keys.ENTER) {
6047
5996
  e.preventDefault();
6048
5997
  this._ensureClockBuilt();
6049
5998
  this.inputHours.focus();
@@ -6052,12 +6001,14 @@ var _Timepicker = class _Timepicker extends Component {
6052
6001
  }
6053
6002
  };
6054
6003
  this._handleTimeInputEnterKey = (e) => {
6055
- if (Utils.keys.ENTER.includes(e.key)) {
6004
+ if (e.key === Utils.keys.ENTER) {
6056
6005
  e.preventDefault();
6057
6006
  this._inputFromTextField();
6058
6007
  }
6059
6008
  };
6060
6009
  this._handleClockClickStart = (e) => {
6010
+ if (!e.isPrimary) return;
6011
+ if (e.pointerType === "mouse" && e.button !== 0) return;
6061
6012
  e.preventDefault();
6062
6013
  this._ensureClockBuilt();
6063
6014
  const clockPlateBR = this.plate.getBoundingClientRect();
@@ -6065,30 +6016,30 @@ var _Timepicker = class _Timepicker extends Component {
6065
6016
  this.x0 = offset.x + this.options.dialRadius;
6066
6017
  this.y0 = offset.y + this.options.dialRadius;
6067
6018
  this.moved = false;
6068
- const clickPos = _Timepicker._Pos(e);
6069
- this.dx = clickPos.x - this.x0;
6070
- this.dy = clickPos.y - this.y0;
6019
+ this._dragPointerId = e.pointerId;
6020
+ this.dx = e.clientX - this.x0;
6021
+ this.dy = e.clientY - this.y0;
6071
6022
  this.setHand(this.dx, this.dy, false);
6072
- document.addEventListener("mousemove", this._handleDocumentClickMove);
6073
- document.addEventListener("touchmove", this._handleDocumentClickMove);
6074
- document.addEventListener("mouseup", this._handleDocumentClickEnd);
6075
- document.addEventListener("touchend", this._handleDocumentClickEnd);
6023
+ document.addEventListener("pointermove", this._handleDocumentClickMove);
6024
+ document.addEventListener("pointerup", this._handleDocumentClickEnd);
6025
+ document.addEventListener("pointercancel", this._handleDocumentClickCancel);
6076
6026
  };
6077
6027
  this._handleDocumentClickMove = (e) => {
6028
+ if (e.pointerId !== this._dragPointerId) return;
6078
6029
  e.preventDefault();
6079
- const clickPos = _Timepicker._Pos(e);
6080
- const x = clickPos.x - this.x0;
6081
- const y = clickPos.y - this.y0;
6030
+ const x = e.clientX - this.x0;
6031
+ const y = e.clientY - this.y0;
6082
6032
  this.moved = true;
6083
6033
  this.setHand(x, y, false);
6084
6034
  };
6085
6035
  this._handleDocumentClickEnd = (e) => {
6036
+ if (e.pointerId !== this._dragPointerId) return;
6037
+ this._dragPointerId = null;
6086
6038
  e.preventDefault();
6087
- document.removeEventListener("mouseup", this._handleDocumentClickEnd);
6088
- document.removeEventListener("touchend", this._handleDocumentClickEnd);
6089
- const clickPos = _Timepicker._Pos(e);
6090
- const x = clickPos.x - this.x0;
6091
- const y = clickPos.y - this.y0;
6039
+ document.removeEventListener("pointerup", this._handleDocumentClickEnd);
6040
+ document.removeEventListener("pointercancel", this._handleDocumentClickCancel);
6041
+ const x = e.clientX - this.x0;
6042
+ const y = e.clientY - this.y0;
6092
6043
  if (this.moved && x === this.dx && y === this.dy) {
6093
6044
  this.setHand(x, y);
6094
6045
  }
@@ -6103,14 +6054,27 @@ var _Timepicker = class _Timepicker extends Component {
6103
6054
  if (typeof this.options.onSelect === "function") {
6104
6055
  this.options.onSelect.call(this, this.hours, this.minutes);
6105
6056
  }
6106
- document.removeEventListener("mousemove", this._handleDocumentClickMove);
6107
- document.removeEventListener("touchmove", this._handleDocumentClickMove);
6057
+ document.removeEventListener("pointermove", this._handleDocumentClickMove);
6058
+ };
6059
+ /**
6060
+ * A cancelled pointer is not a completed selection. The browser or the OS
6061
+ * took the gesture over, so this only lets go of the drag - it must not run
6062
+ * the pointer-up path, which advances hours to minutes, fires `onSelect`,
6063
+ * and under `autoSubmit` closes the picker on a time the user never chose.
6064
+ */
6065
+ this._handleDocumentClickCancel = (e) => {
6066
+ if (e.pointerId !== this._dragPointerId) return;
6067
+ this._dragPointerId = null;
6068
+ this.moved = false;
6069
+ document.removeEventListener("pointermove", this._handleDocumentClickMove);
6070
+ document.removeEventListener("pointerup", this._handleDocumentClickEnd);
6071
+ document.removeEventListener("pointercancel", this._handleDocumentClickCancel);
6108
6072
  };
6109
6073
  this._handleAmPmClick = (e) => {
6110
6074
  this._handleAmPmInteraction(e.target);
6111
6075
  };
6112
6076
  this._handleAmPmKeypress = (e) => {
6113
- if (Utils.keys.ENTER.includes(e.key)) {
6077
+ if (e.key === Utils.keys.ENTER) {
6114
6078
  this._handleAmPmInteraction(e.target);
6115
6079
  }
6116
6080
  };
@@ -6125,8 +6089,6 @@ var _Timepicker = class _Timepicker extends Component {
6125
6089
  */
6126
6090
  this.showView = (view, delay = null) => {
6127
6091
  this._ensureClockBuilt();
6128
- if (view === "minutes" && getComputedStyle(this.hoursView).visibility === "visible") {
6129
- }
6130
6092
  const isHours = view === "hours", nextView = isHours ? this.hoursView : this.minutesView, hideView = isHours ? this.minutesView : this.hoursView;
6131
6093
  this.currentView = view;
6132
6094
  hideView.classList.add("timepicker-dial-out");
@@ -6198,7 +6160,7 @@ var _Timepicker = class _Timepicker extends Component {
6198
6160
  }
6199
6161
  }
6200
6162
  static get defaults() {
6201
- return _defaults19;
6163
+ return _defaults18;
6202
6164
  }
6203
6165
  /**
6204
6166
  * Initializes instances of Timepicker.
@@ -6215,15 +6177,6 @@ var _Timepicker = class _Timepicker extends Component {
6215
6177
  const svgNS = "http://www.w3.org/2000/svg";
6216
6178
  return document.createElementNS(svgNS, name);
6217
6179
  }
6218
- static _Pos(e) {
6219
- if (e.type.startsWith("touch") && e.targetTouches.length >= 1) {
6220
- return {
6221
- x: e.targetTouches[0].clientX,
6222
- y: e.targetTouches[0].clientY
6223
- };
6224
- }
6225
- return { x: e.clientX, y: e.clientY };
6226
- }
6227
6180
  static getInstance(el) {
6228
6181
  return el["Expressive_Timepicker"];
6229
6182
  }
@@ -6236,8 +6189,7 @@ var _Timepicker = class _Timepicker extends Component {
6236
6189
  _setupEventHandlers() {
6237
6190
  this.el.addEventListener("click", this._handleInputClick);
6238
6191
  this.el.addEventListener("keydown", this._handleInputKeydown);
6239
- this.plate.addEventListener("mousedown", this._handleClockClickStart);
6240
- this.plate.addEventListener("touchstart", this._handleClockClickStart);
6192
+ this.plate.addEventListener("pointerdown", this._handleClockClickStart);
6241
6193
  this.digitalClock.addEventListener("keyup", this._inputFromTextField);
6242
6194
  this.inputHours.addEventListener("focus", () => this.showView("hours"));
6243
6195
  this.inputHours.addEventListener("focusout", () => this.formatHours());
@@ -6247,10 +6199,9 @@ var _Timepicker = class _Timepicker extends Component {
6247
6199
  _removeEventHandlers() {
6248
6200
  this.el.removeEventListener("click", this._handleInputClick);
6249
6201
  this.el.removeEventListener("keydown", this._handleInputKeydown);
6250
- document.removeEventListener("mousemove", this._handleDocumentClickMove);
6251
- document.removeEventListener("touchmove", this._handleDocumentClickMove);
6252
- document.removeEventListener("mouseup", this._handleDocumentClickEnd);
6253
- document.removeEventListener("touchend", this._handleDocumentClickEnd);
6202
+ document.removeEventListener("pointermove", this._handleDocumentClickMove);
6203
+ document.removeEventListener("pointerup", this._handleDocumentClickEnd);
6204
+ document.removeEventListener("pointercancel", this._handleDocumentClickCancel);
6254
6205
  }
6255
6206
  _insertHTMLIntoDOM() {
6256
6207
  const template = document.createElement("template");
@@ -6279,15 +6230,6 @@ var _Timepicker = class _Timepicker extends Component {
6279
6230
  this.footer = this.containerEl.querySelector(".timepicker-footer");
6280
6231
  this.amOrPm = "PM";
6281
6232
  }
6282
- /*private _createButton(text: string, visibility: string): HTMLButtonElement {
6283
- const button = document.createElement('button');
6284
- button.classList.add('waves-effect', 'text');
6285
- button.style.visibility = visibility;
6286
- button.type = 'button';
6287
- button.tabIndex = -1;
6288
- button.innerText = text;
6289
- return button;
6290
- }*/
6291
6233
  _pickerSetup() {
6292
6234
  Utils.createButton(
6293
6235
  this.footer,
@@ -6568,7 +6510,7 @@ _Timepicker._template = `<div class="timepicker-container">
6568
6510
  var Timepicker = _Timepicker;
6569
6511
 
6570
6512
  // src/ts/components/snackbar.ts
6571
- var _defaults20 = {
6513
+ var _defaults19 = {
6572
6514
  text: "",
6573
6515
  action: "",
6574
6516
  onAction: null,
@@ -6578,7 +6520,8 @@ var _defaults20 = {
6578
6520
  outDuration: 375,
6579
6521
  classes: "",
6580
6522
  completeCallback: null,
6581
- activationPercent: 0.8
6523
+ activationPercent: 0.8,
6524
+ root: null
6582
6525
  };
6583
6526
  var _Snackbar = class _Snackbar {
6584
6527
  constructor(options = {}) {
@@ -6601,8 +6544,10 @@ var _Snackbar = class _Snackbar {
6601
6544
  }
6602
6545
  _Snackbar._snackbars.length = 0;
6603
6546
  }
6604
- if (!_Snackbar._container || !_Snackbar._container.isConnected) {
6605
- _Snackbar._createContainer();
6547
+ const root = Utils.portalRoot(this.options.root ?? document.body);
6548
+ if (!_Snackbar._container || !_Snackbar._container.isConnected || _Snackbar._container.parentNode !== root) {
6549
+ if (_Snackbar._container) _Snackbar._removeContainer();
6550
+ _Snackbar._createContainer(root);
6606
6551
  }
6607
6552
  _Snackbar._snackbars.push(this);
6608
6553
  const snackbarElement = this._createSnackbar();
@@ -6612,30 +6557,31 @@ var _Snackbar = class _Snackbar {
6612
6557
  this._setTimer();
6613
6558
  }
6614
6559
  static get defaults() {
6615
- return _defaults20;
6560
+ return _defaults19;
6616
6561
  }
6617
6562
  static getInstance(el) {
6618
6563
  return el["Expressive_Snackbar"];
6619
6564
  }
6620
- static _createContainer() {
6565
+ static _createContainer(root = document.body) {
6621
6566
  const container = document.createElement("div");
6622
6567
  container.setAttribute("id", "snackbar-container");
6623
- container.addEventListener("touchstart", _Snackbar._onDragStart);
6624
- container.addEventListener("touchmove", _Snackbar._onDragMove);
6625
- container.addEventListener("touchend", _Snackbar._onDragEnd);
6626
- container.addEventListener("mousedown", _Snackbar._onDragStart);
6627
- document.addEventListener("mousemove", _Snackbar._onDragMove);
6628
- document.addEventListener("mouseup", _Snackbar._onDragEnd);
6629
- document.body.appendChild(container);
6568
+ container.addEventListener("pointerdown", _Snackbar._onDragStart);
6569
+ document.addEventListener("pointermove", _Snackbar._onDragMove);
6570
+ document.addEventListener("pointerup", _Snackbar._onDragEnd);
6571
+ document.addEventListener("pointercancel", _Snackbar._onDragCancel);
6572
+ root.appendChild(container);
6630
6573
  _Snackbar._container = container;
6631
6574
  }
6632
6575
  static _removeContainer() {
6633
- document.removeEventListener("mousemove", _Snackbar._onDragMove);
6634
- document.removeEventListener("mouseup", _Snackbar._onDragEnd);
6576
+ document.removeEventListener("pointermove", _Snackbar._onDragMove);
6577
+ document.removeEventListener("pointerup", _Snackbar._onDragEnd);
6578
+ document.removeEventListener("pointercancel", _Snackbar._onDragCancel);
6635
6579
  _Snackbar._container.remove();
6636
6580
  _Snackbar._container = null;
6637
6581
  }
6638
6582
  static _onDragStart(e) {
6583
+ if (!e.isPrimary) return;
6584
+ if (e.pointerType === "mouse" && e.button !== 0) return;
6639
6585
  const target = e.target;
6640
6586
  if (target && !target.closest("button, a") && target.closest(".snackbar")) {
6641
6587
  const snackbarElem = target.closest(".snackbar");
@@ -6646,17 +6592,19 @@ var _Snackbar = class _Snackbar {
6646
6592
  _Snackbar._draggedSnackbar = snackbar;
6647
6593
  snackbar.el.classList.add("panning");
6648
6594
  snackbar.el.style.transition = "";
6649
- snackbar.startingXPos = _Snackbar._xPos(e);
6595
+ _Snackbar._dragPointerId = e.pointerId;
6596
+ snackbar.startingXPos = e.clientX;
6650
6597
  snackbar.time = Date.now();
6651
- snackbar.xPos = _Snackbar._xPos(e);
6598
+ snackbar.xPos = e.clientX;
6652
6599
  }
6653
6600
  }
6654
6601
  static _onDragMove(e) {
6602
+ if (_Snackbar._dragPointerId !== e.pointerId) return;
6655
6603
  if (!!_Snackbar._draggedSnackbar) {
6656
6604
  e.preventDefault();
6657
6605
  const snackbar = _Snackbar._draggedSnackbar;
6658
- snackbar.deltaX = Math.abs(snackbar.xPos - _Snackbar._xPos(e));
6659
- snackbar.xPos = _Snackbar._xPos(e);
6606
+ snackbar.deltaX = Math.abs(snackbar.xPos - e.clientX);
6607
+ snackbar.xPos = e.clientX;
6660
6608
  snackbar.velocityX = snackbar.deltaX / (Date.now() - snackbar.time);
6661
6609
  snackbar.time = Date.now();
6662
6610
  const totalDeltaX = snackbar.xPos - snackbar.startingXPos;
@@ -6665,7 +6613,9 @@ var _Snackbar = class _Snackbar {
6665
6613
  snackbar.el.style.opacity = (1 - Math.abs(totalDeltaX / activationDistance)).toString();
6666
6614
  }
6667
6615
  }
6668
- static _onDragEnd() {
6616
+ static _onDragEnd(e) {
6617
+ if (_Snackbar._dragPointerId !== e.pointerId) return;
6618
+ _Snackbar._dragPointerId = null;
6669
6619
  if (!!_Snackbar._draggedSnackbar) {
6670
6620
  const snackbar = _Snackbar._draggedSnackbar;
6671
6621
  snackbar.panning = false;
@@ -6685,11 +6635,23 @@ var _Snackbar = class _Snackbar {
6685
6635
  _Snackbar._draggedSnackbar = null;
6686
6636
  }
6687
6637
  }
6688
- static _xPos(e) {
6689
- if (e.type.startsWith("touch") && e.targetTouches.length >= 1) {
6690
- return e.targetTouches[0].clientX;
6691
- }
6692
- return e.clientX;
6638
+ /**
6639
+ * A cancelled pointer is not a short swipe. Snap back and resume the timer
6640
+ * without consulting the distance travelled - the browser took the gesture
6641
+ * over, so the movement so far says nothing about what the user wanted.
6642
+ */
6643
+ static _onDragCancel(e) {
6644
+ if (_Snackbar._dragPointerId !== e.pointerId) return;
6645
+ _Snackbar._dragPointerId = null;
6646
+ const snackbar = _Snackbar._draggedSnackbar;
6647
+ if (!snackbar) return;
6648
+ snackbar.panning = false;
6649
+ snackbar.el.classList.remove("panning");
6650
+ snackbar.el.style.transition = "transform .2s, opacity .2s";
6651
+ snackbar.el.style.transform = "";
6652
+ snackbar.el.style.opacity = "";
6653
+ snackbar._resumeTimer();
6654
+ _Snackbar._draggedSnackbar = null;
6693
6655
  }
6694
6656
  /**
6695
6657
  * dismiss all snackbars.
@@ -6700,7 +6662,7 @@ var _Snackbar = class _Snackbar {
6700
6662
  }
6701
6663
  }
6702
6664
  _createSnackbar() {
6703
- let snackbar = this.options.snackbarId ? document.getElementById(this.options.snackbarId) : document.createElement("div");
6665
+ let snackbar = this.options.snackbarId ? Utils.getElementById(this.options.root ?? document.body, this.options.snackbarId) : document.createElement("div");
6704
6666
  if (snackbar instanceof HTMLTemplateElement) {
6705
6667
  const node = snackbar.content.cloneNode(true);
6706
6668
  snackbar = node.firstElementChild;
@@ -6822,13 +6784,15 @@ var _Snackbar = class _Snackbar {
6822
6784
  }, this.options.outDuration);
6823
6785
  }
6824
6786
  };
6787
+ /** Which pointer owns the drag in flight; a second finger is ignored. */
6788
+ _Snackbar._dragPointerId = null;
6825
6789
  _Snackbar._snackbars = [];
6826
6790
  _Snackbar._container = null;
6827
6791
  _Snackbar._draggedSnackbar = null;
6828
6792
  var Snackbar = _Snackbar;
6829
6793
 
6830
6794
  // src/ts/components/tooltip.ts
6831
- var _defaults21 = {
6795
+ var _defaults20 = {
6832
6796
  exitDelay: 200,
6833
6797
  enterDelay: 0,
6834
6798
  text: "",
@@ -6873,8 +6837,10 @@ var Tooltip = class _Tooltip extends Component {
6873
6837
  this.isFocused = false;
6874
6838
  this.close();
6875
6839
  };
6840
+ // Focus opens the tooltip only when it arrived by keyboard: a pointer press
6841
+ // on the trigger also focuses it, and _handleMouseEnter already covers that.
6876
6842
  this._handleFocus = () => {
6877
- if (Utils.tabPressed) {
6843
+ if (this.el.matches(":focus-visible")) {
6878
6844
  this.isFocused = true;
6879
6845
  this.open(false);
6880
6846
  }
@@ -6896,7 +6862,7 @@ var Tooltip = class _Tooltip extends Component {
6896
6862
  this._setupEventHandlers();
6897
6863
  }
6898
6864
  static get defaults() {
6899
- return _defaults21;
6865
+ return _defaults20;
6900
6866
  }
6901
6867
  /**
6902
6868
  * Initializes instances of Tooltip.
@@ -6923,7 +6889,7 @@ var Tooltip = class _Tooltip extends Component {
6923
6889
  this.tooltipEl.id = `tooltip-${Utils.guid()}`;
6924
6890
  this.tooltipEl.setAttribute("role", "tooltip");
6925
6891
  this.el.setAttribute("aria-describedby", this.tooltipEl.id);
6926
- const tooltipContentEl = this.options.tooltipId ? document.getElementById(this.options.tooltipId) : document.createElement("div");
6892
+ const tooltipContentEl = this.options.tooltipId ? Utils.getElementById(this.el, this.options.tooltipId) : document.createElement("div");
6927
6893
  if (this.options.tooltipId) {
6928
6894
  this.tooltipEl.classList.add("rich");
6929
6895
  }
@@ -6931,7 +6897,7 @@ var Tooltip = class _Tooltip extends Component {
6931
6897
  tooltipContentEl.classList.add("tooltip-content");
6932
6898
  this._setTooltipContent(tooltipContentEl);
6933
6899
  this.tooltipEl.appendChild(tooltipContentEl);
6934
- document.body.appendChild(this.tooltipEl);
6900
+ Utils.portalRoot(this.el).appendChild(this.tooltipEl);
6935
6901
  }
6936
6902
  _setTooltipContent(tooltipContentEl) {
6937
6903
  if (this.options.tooltipId) return;
@@ -7070,26 +7036,44 @@ var Tooltip = class _Tooltip extends Component {
7070
7036
 
7071
7037
  // src/ts/components/registry.ts
7072
7038
  var AUTO_INIT_COMPONENTS = {
7073
- Autocomplete: { component: Autocomplete, selector: ".autocomplete" },
7039
+ Autocomplete: {
7040
+ component: Autocomplete,
7041
+ selector: ".autocomplete"
7042
+ },
7074
7043
  // Shared with Cards.Init() - see CARDS_SELECTOR. This entry used to read
7075
7044
  // '.cards', which no card markup uses.
7076
7045
  Cards: { component: Cards, selector: CARDS_SELECTOR },
7046
+ ExpandingCard: {
7047
+ component: ExpandingCard,
7048
+ selector: EXPANDING_CARD_SELECTOR
7049
+ },
7077
7050
  Carousel: { component: Carousel, selector: ".carousel" },
7078
7051
  Chips: { component: Chips, selector: ".chips" },
7079
- Datepicker: { component: Datepicker, selector: ".datepicker" },
7052
+ Datepicker: {
7053
+ component: Datepicker,
7054
+ selector: ".datepicker, .date-picker"
7055
+ },
7080
7056
  Menu: { component: Menu, selector: ".menu-trigger" },
7081
7057
  Lightbox: { component: Lightbox, selector: ".lightboxed" },
7082
- Parallax: { component: Parallax, selector: ".parallax" },
7083
7058
  ScrollSpy: { component: ScrollSpy, selector: ".scrollspy" },
7084
7059
  FormSelect: { component: FormSelect, selector: "select" },
7085
- Sidenav: { component: Sidenav, selector: ".sidenav" },
7086
- NavigationRail: { component: NavigationRail, selector: ".navigation-rail" },
7060
+ NavigationDrawer: {
7061
+ component: NavigationDrawer,
7062
+ selector: ".sidenav, .navigation-drawer"
7063
+ },
7064
+ NavigationRail: {
7065
+ component: NavigationRail,
7066
+ selector: ".navigation-rail"
7067
+ },
7087
7068
  Tabs: { component: Tabs, selector: ".tabs" },
7088
- Timepicker: { component: Timepicker, selector: ".timepicker" },
7069
+ Timepicker: {
7070
+ component: Timepicker,
7071
+ selector: ".timepicker, .time-picker"
7072
+ },
7089
7073
  Tooltip: { component: Tooltip, selector: ".tooltipped" },
7090
7074
  FloatingActionButton: {
7091
7075
  component: FloatingActionButton,
7092
- selector: ".fixed-action-btn"
7076
+ selector: ".fab, .fixed-action-btn, .fab-menu"
7093
7077
  }
7094
7078
  };
7095
7079
  function AutoInit(context = document.body, options) {
@@ -7101,18 +7085,12 @@ function AutoInit(context = document.body, options) {
7101
7085
  }
7102
7086
 
7103
7087
  // src/ts/index.ts
7104
- var version = "0.7.0-rc.0";
7105
- if (typeof document !== "undefined") {
7106
- document.addEventListener("keydown", Utils.docHandleKeydown, true);
7107
- document.addEventListener("keyup", Utils.docHandleKeyup, true);
7108
- document.addEventListener("focus", Utils.docHandleFocus, true);
7109
- document.addEventListener("blur", Utils.docHandleBlur, true);
7110
- }
7088
+ var version = "0.8.0";
7111
7089
  Forms.Init();
7112
7090
  Chips.Init();
7113
- Waves.Init();
7114
- Range.Init();
7091
+ Slider.Init();
7115
7092
  Cards.Init();
7093
+ ExpandingCard.Init();
7116
7094
  Dialogs.Init();
7117
7095
  BottomSheets.Init();
7118
7096
  SideSheets.Init();
@@ -7126,23 +7104,23 @@ export {
7126
7104
  Chips,
7127
7105
  Datepicker,
7128
7106
  Dialogs,
7107
+ ExpandingCard,
7129
7108
  FloatingActionButton,
7130
7109
  FormSelect,
7131
7110
  Forms,
7132
7111
  Lightbox,
7133
7112
  Menu,
7113
+ NavigationDrawer,
7134
7114
  NavigationRail,
7135
- Parallax,
7136
- Range,
7115
+ Slider as Range,
7137
7116
  ScrollSpy,
7138
7117
  SideSheets,
7139
- Sidenav,
7118
+ NavigationDrawer as Sidenav,
7140
7119
  Slider,
7141
7120
  Snackbar,
7142
7121
  Tabs,
7143
7122
  Timepicker,
7144
7123
  Tooltip,
7145
- Waves,
7146
7124
  version
7147
7125
  };
7148
7126
  //# sourceMappingURL=expressive.mjs.map