@expressivecss/expressive 0.3.0 → 0.5.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 (96) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +4 -9
  3. package/dist/css/expressive.css +3183 -2150
  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 +1254 -1567
  8. package/dist/js/expressive.cjs.map +4 -4
  9. package/dist/js/expressive.js +1254 -1567
  10. package/dist/js/expressive.js.map +4 -4
  11. package/dist/js/expressive.min.js +12 -22
  12. package/dist/js/expressive.min.js.map +4 -4
  13. package/dist/js/expressive.mjs +1254 -1568
  14. package/dist/js/expressive.mjs.map +4 -4
  15. package/dist/types/behaviors/bottomSheets.d.ts +18 -0
  16. package/dist/types/behaviors/sideSheets.d.ts +18 -0
  17. package/dist/types/components/autocomplete.d.ts +13 -20
  18. package/dist/types/components/buttons.d.ts +2 -2
  19. package/dist/types/components/cards.d.ts +3 -6
  20. package/dist/types/components/carousel.d.ts +3 -3
  21. package/dist/types/components/characterCounter.d.ts +3 -5
  22. package/dist/types/components/chips.d.ts +2 -2
  23. package/dist/types/components/datepicker.d.ts +2 -8
  24. package/dist/types/components/index.d.ts +3 -6
  25. package/dist/types/components/lightbox.d.ts +2 -2
  26. package/dist/types/components/{dropdown.d.ts → menu.d.ts} +48 -38
  27. package/dist/types/components/navigationRail.d.ts +53 -0
  28. package/dist/types/components/parallax.d.ts +2 -8
  29. package/dist/types/components/range.d.ts +5 -2
  30. package/dist/types/components/registry.d.ts +7 -19
  31. package/dist/types/components/scrollspy.d.ts +26 -50
  32. package/dist/types/components/select.d.ts +28 -14
  33. package/dist/types/components/sidenav.d.ts +40 -55
  34. package/dist/types/components/slider.d.ts +2 -2
  35. package/dist/types/components/{toasts.d.ts → snackbar.d.ts} +28 -25
  36. package/dist/types/components/tabs.d.ts +2 -2
  37. package/dist/types/components/timepicker.d.ts +2 -4
  38. package/dist/types/components/tooltip.d.ts +2 -2
  39. package/dist/types/core/component.d.ts +4 -4
  40. package/dist/types/index.d.ts +3 -1
  41. package/package.json +4 -3
  42. package/src/sass/README.md +13 -15
  43. package/src/sass/abstracts/_breakpoints.scss +14 -19
  44. package/src/sass/abstracts/_mixins.scss +3 -3
  45. package/src/sass/abstracts/_variables.scss +27 -23
  46. package/src/sass/base/_global.scss +1 -1
  47. package/src/sass/base/_grid.scss +64 -133
  48. package/src/sass/base/_index.scss +1 -1
  49. package/src/sass/components/_badges.scss +76 -61
  50. package/src/sass/components/_bottom-sheet.scss +137 -0
  51. package/src/sass/components/_buttons.scss +22 -54
  52. package/src/sass/components/_cards.scss +54 -127
  53. package/src/sass/components/_carousel.scss +4 -6
  54. package/src/sass/components/_chips.scss +6 -5
  55. package/src/sass/components/_datepicker.scss +1 -15
  56. package/src/sass/components/_dialog.scss +268 -0
  57. package/src/sass/components/_index.scss +9 -7
  58. package/src/sass/components/_list.scss +253 -0
  59. package/src/sass/components/_menu.scss +341 -0
  60. package/src/sass/components/_navbar.scss +68 -117
  61. package/src/sass/components/_navigation-bar.scss +165 -0
  62. package/src/sass/components/_navigation-rail.scss +308 -0
  63. package/src/sass/components/_page-footer.scss +138 -15
  64. package/src/sass/components/_parallax.scss +7 -28
  65. package/src/sass/components/_preloader.scss +145 -300
  66. package/src/sass/components/_scrollspy.scss +18 -0
  67. package/src/sass/components/_side-sheet.scss +193 -0
  68. package/src/sass/components/_sidenav.scss +281 -146
  69. package/src/sass/components/{_toast.scss → _snackbar.scss} +43 -43
  70. package/src/sass/components/_table_of_contents.scss +30 -14
  71. package/src/sass/components/_tabs.scss +43 -50
  72. package/src/sass/components/_toolbar.scss +93 -27
  73. package/src/sass/components/_tooltip.scss +5 -10
  74. package/src/sass/components/_transitions.scss +0 -5
  75. package/src/sass/components/forms/_fieldset.scss +1 -1
  76. package/src/sass/components/forms/_index.scss +0 -5
  77. package/src/sass/components/forms/_input-fields.scss +52 -55
  78. package/src/sass/components/forms/_range.scss +423 -98
  79. package/src/sass/components/forms/_select.scss +177 -60
  80. package/src/sass/components/forms/_switches.scss +21 -8
  81. package/src/sass/tokens/_reference.scss +37 -13
  82. package/src/sass/tokens/_theme.scss +5 -13
  83. package/src/sass/utilities/_colors.scss +16 -74
  84. package/src/sass/utilities/_helpers.scss +1 -3
  85. package/src/sass/utilities/_typescale.scss +0 -5
  86. package/src/sass/utilities/_visibility.scss +10 -2
  87. package/dist/types/components/collapsible.d.ts +0 -96
  88. package/dist/types/components/modal.d.ts +0 -45
  89. package/dist/types/components/pushpin.d.ts +0 -51
  90. package/dist/types/components/tapTarget.d.ts +0 -57
  91. package/src/sass/components/_collapsible.scss +0 -181
  92. package/src/sass/components/_collection.scss +0 -198
  93. package/src/sass/components/_dropdown.scss +0 -129
  94. package/src/sass/components/_modal.scss +0 -208
  95. package/src/sass/components/_pushpin.scss +0 -11
  96. package/src/sass/components/_tapTarget.scss +0 -191
@@ -2,9 +2,6 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __typeError = (msg) => {
6
- throw TypeError(msg);
7
- };
8
5
  var __export = (target, all) => {
9
6
  for (var name in all)
10
7
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -18,38 +15,34 @@ var __copyProps = (to, from, except, desc) => {
18
15
  return to;
19
16
  };
20
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
22
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
23
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
24
18
 
25
19
  // src/ts/index.ts
26
20
  var index_exports = {};
27
21
  __export(index_exports, {
28
22
  AutoInit: () => AutoInit,
29
23
  Autocomplete: () => Autocomplete,
24
+ BottomSheets: () => BottomSheets,
30
25
  Cards: () => Cards,
31
26
  Carousel: () => Carousel,
32
27
  CharacterCounter: () => CharacterCounter,
33
28
  Chips: () => Chips,
34
- Collapsible: () => Collapsible,
35
29
  Datepicker: () => Datepicker,
36
30
  Dialogs: () => Dialogs,
37
- Dropdown: () => Dropdown,
38
31
  FloatingActionButton: () => FloatingActionButton,
39
32
  FormSelect: () => FormSelect,
40
33
  Forms: () => Forms,
41
34
  Lightbox: () => Lightbox,
42
- Modal: () => Modal,
35
+ Menu: () => Menu,
36
+ NavigationRail: () => NavigationRail,
43
37
  Parallax: () => Parallax,
44
- Pushpin: () => Pushpin,
45
38
  Range: () => Range,
46
39
  ScrollSpy: () => ScrollSpy,
40
+ SideSheets: () => SideSheets,
47
41
  Sidenav: () => Sidenav,
48
42
  Slider: () => Slider,
43
+ Snackbar: () => Snackbar,
49
44
  Tabs: () => Tabs,
50
- TapTarget: () => TapTarget,
51
45
  Timepicker: () => Timepicker,
52
- Toast: () => Toast,
53
46
  Tooltip: () => Tooltip,
54
47
  Waves: () => Waves,
55
48
  version: () => version
@@ -271,7 +264,7 @@ var _Utils = class _Utils {
271
264
  * Renders a button with optional callback function
272
265
  */
273
266
  static createButton(container, text, className = [], visibility = true, callback = null) {
274
- className = className.concat(["btn", "waves-effect", "text"]);
267
+ className = className.concat(["waves-effect", "text"]);
275
268
  const button = document.createElement("button");
276
269
  button.className = className.join(" ");
277
270
  button.style.visibility = visibility ? "visible" : "hidden";
@@ -450,11 +443,9 @@ var Component = class {
450
443
  // src/ts/components/cards.ts
451
444
  var _defaults = {
452
445
  onOpen: null,
453
- onClose: null,
454
- inDuration: 225,
455
- outDuration: 300
446
+ onClose: null
456
447
  };
457
- var CARDS_SELECTOR = ".card, article:has(> aside), article:has(.card-reveal)";
448
+ var CARDS_SELECTOR = "article:has(> aside)";
458
449
  var Cards = class _Cards extends Component {
459
450
  constructor(el, options) {
460
451
  super(el, options, _Cards);
@@ -500,16 +491,10 @@ var Cards = class _Cards extends Component {
500
491
  * Show card reveal.
501
492
  */
502
493
  this.open = () => {
503
- if (this.isOpen) return;
494
+ if (this.isOpen || !this.cardReveal) return;
504
495
  this.isOpen = true;
505
- this.el.style.overflow = "hidden";
506
- this.cardReveal.style.display = "block";
507
496
  this.cardReveal.ariaExpanded = "true";
508
497
  if (this.cardRevealClose) this.cardRevealClose.tabIndex = 0;
509
- setTimeout(() => {
510
- this.cardReveal.style.transition = `transform ${this.options.outDuration}ms ease`;
511
- this.cardReveal.style.transform = "translateY(-100%)";
512
- }, 1);
513
498
  if (typeof this.options.onOpen === "function") {
514
499
  this.options.onOpen.call(this);
515
500
  }
@@ -519,17 +504,11 @@ var Cards = class _Cards extends Component {
519
504
  * Hide card reveal.
520
505
  */
521
506
  this.close = () => {
522
- if (!this.isOpen) return;
507
+ if (!this.isOpen || !this.cardReveal) return;
523
508
  this.isOpen = false;
524
- this.cardReveal.style.transition = `transform ${this.options.inDuration}ms ease`;
525
- this.cardReveal.style.transform = "translateY(0)";
526
- setTimeout(() => {
527
- this.cardReveal.style.display = "none";
528
- this.cardReveal.ariaExpanded = "false";
529
- this._activators.forEach((el) => el.tabIndex = 0);
530
- if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
531
- this.el.style.overflow = this.initialOverflow;
532
- }, this.options.inDuration);
509
+ this.cardReveal.ariaExpanded = "false";
510
+ this._activators.forEach((el) => el.tabIndex = 0);
511
+ if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
533
512
  if (typeof this.options.onClose === "function") {
534
513
  this.options.onClose.call(this);
535
514
  }
@@ -541,15 +520,14 @@ var Cards = class _Cards extends Component {
541
520
  ...options
542
521
  };
543
522
  this._activators = [];
544
- this.cardReveal = this.el.querySelector(":scope > aside, .card-reveal");
523
+ this.cardReveal = this.el.querySelector(":scope > aside");
545
524
  if (this.cardReveal) {
546
- this.initialOverflow = getComputedStyle(this.el).overflow;
547
525
  this._activators = Array.from(this.el.querySelectorAll(".activator"));
548
526
  this._activators.forEach((el2) => {
549
527
  if (el2) el2.tabIndex = 0;
550
528
  });
551
529
  this.cardRevealClose = this.cardReveal.querySelector(
552
- ".card-title, :scope > :is(h1, h2, h3, h4, h5, h6)"
530
+ ":scope > :is(h1, h2, h3, h4, h5, h6)"
553
531
  );
554
532
  if (this.cardRevealClose) this.cardRevealClose.tabIndex = -1;
555
533
  this.cardReveal.ariaExpanded = "false";
@@ -589,13 +567,13 @@ var Cards = class _Cards extends Component {
589
567
  }
590
568
  };
591
569
 
592
- // src/ts/components/dropdown.ts
570
+ // src/ts/components/menu.ts
593
571
  var _defaults2 = {
594
572
  alignment: "left",
595
573
  autoFocus: true,
596
574
  constrainWidth: true,
597
575
  container: null,
598
- coverTrigger: true,
576
+ coverTrigger: false,
599
577
  closeOnClick: true,
600
578
  hover: false,
601
579
  inDuration: 150,
@@ -606,9 +584,9 @@ var _defaults2 = {
606
584
  onCloseEnd: null,
607
585
  onItemClick: null
608
586
  };
609
- var _Dropdown = class _Dropdown extends Component {
587
+ var _Menu = class _Menu extends Component {
610
588
  constructor(el, options) {
611
- super(el, options, _Dropdown);
589
+ super(el, options, _Menu);
612
590
  this._handleClick = (e) => {
613
591
  e.preventDefault();
614
592
  if (this.isOpen) {
@@ -626,21 +604,22 @@ var _Dropdown = class _Dropdown extends Component {
626
604
  this.close();
627
605
  return;
628
606
  }
629
- const leaveToDropdownContent = !!toEl.closest(".dropdown-content, menu");
630
- let leaveToActiveDropdownTrigger = false;
631
- const closestTrigger = toEl.closest(".dropdown-trigger");
632
- if (closestTrigger && !!closestTrigger["Expressive_Dropdown"] && closestTrigger["Expressive_Dropdown"].isOpen) {
633
- leaveToActiveDropdownTrigger = true;
607
+ const leaveToMenuContent = !!(this.menuEl && toEl && this.menuEl.contains(toEl));
608
+ let leaveToActiveMenuTrigger = false;
609
+ const closestTrigger = toEl.closest(".menu-trigger");
610
+ if (closestTrigger && !!closestTrigger["Expressive_Menu"] && closestTrigger["Expressive_Menu"].isOpen) {
611
+ leaveToActiveMenuTrigger = true;
634
612
  }
635
- if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) {
613
+ if (!leaveToActiveMenuTrigger && !leaveToMenuContent) {
636
614
  this.close();
637
615
  }
638
616
  };
639
617
  this._handleDocumentClick = (e) => {
640
618
  const target = e.target;
641
- if (this.options.closeOnClick && target.closest(".dropdown-content, menu") && !this.isTouchMoving) {
619
+ if (this._isSubmenuTriggerClick(target)) return;
620
+ if (this.options.closeOnClick && this.menuEl?.contains(target) && !this.isTouchMoving) {
642
621
  this.close();
643
- } else if (!target.closest(".dropdown-content, menu")) {
622
+ } else if (!this.menuEl?.contains(target)) {
644
623
  setTimeout(() => {
645
624
  if (this.isOpen) {
646
625
  this.close();
@@ -658,52 +637,100 @@ var _Dropdown = class _Dropdown extends Component {
658
637
  };
659
638
  this._handleDocumentTouchmove = (e) => {
660
639
  const target = e.target;
661
- if (target.closest(".dropdown-content, menu")) {
640
+ if (this.menuEl?.contains(target)) {
662
641
  this.isTouchMoving = true;
663
642
  }
664
643
  };
665
- this._handleDropdownClick = (e) => {
644
+ this._handleMenuClick = (e) => {
645
+ const target = e.target;
646
+ const li = target.closest("li");
647
+ if (li && this._isSubmenuTriggerClick(target)) {
648
+ e.preventDefault();
649
+ e.stopPropagation();
650
+ this._toggleSubmenu(li);
651
+ return;
652
+ }
666
653
  if (typeof this.options.onItemClick === "function") {
667
- const itemEl = e.target.closest("li");
668
- this.options.onItemClick.call(this, itemEl);
654
+ this.options.onItemClick.call(this, li);
655
+ }
656
+ };
657
+ this._handleSubmenuAlign = (e) => {
658
+ const target = e.target;
659
+ if (!(target instanceof Element)) return;
660
+ const li = target.closest("li");
661
+ if (li?.querySelector(":scope > menu") && this.menuEl?.contains(li)) {
662
+ this._alignSubmenu(li);
669
663
  }
670
664
  };
671
- this._handleDropdownKeydown = (e) => {
665
+ this._handleMenuKeydown = (e) => {
672
666
  const arrowUpOrDown = Utils.keys.ARROW_DOWN.includes(e.key) || Utils.keys.ARROW_UP.includes(e.key);
673
667
  if (Utils.keys.TAB.includes(e.key)) {
674
668
  e.preventDefault();
675
669
  this.close();
670
+ } else if (Utils.keys.ARROW_RIGHT.includes(e.key) && this.isOpen) {
671
+ const li = this._focusedRow(e);
672
+ if (li?.querySelector(":scope > menu")) {
673
+ e.preventDefault();
674
+ li.classList.add("open");
675
+ this._alignSubmenu(li);
676
+ this._syncSubmenuAria(li, true);
677
+ const first = li.querySelector(":scope > menu > li");
678
+ first?.focus();
679
+ }
680
+ } else if (Utils.keys.ARROW_LEFT.includes(e.key) && this.isOpen) {
681
+ const submenu = this._containingSubmenu(e);
682
+ if (submenu) {
683
+ e.preventDefault();
684
+ const parentLi = submenu.parentElement;
685
+ parentLi.classList.remove("open", "submenu-start");
686
+ this._syncSubmenuAria(parentLi, false);
687
+ parentLi.focus();
688
+ }
676
689
  } else if (arrowUpOrDown && this.isOpen) {
677
690
  e.preventDefault();
678
691
  const direction = Utils.keys.ARROW_DOWN.includes(e.key) ? 1 : -1;
692
+ const list = this._containingSubmenu(e) ?? this.menuEl;
679
693
  let newFocusedIndex = this.focusedIndex;
680
694
  let hasFoundNewIndex = false;
681
695
  do {
682
696
  newFocusedIndex = newFocusedIndex + direction;
683
- if (!!this.dropdownEl.children[newFocusedIndex] && this.dropdownEl.children[newFocusedIndex].tabIndex !== -1) {
697
+ if (!!list.children[newFocusedIndex] && list.children[newFocusedIndex].tabIndex !== -1) {
684
698
  hasFoundNewIndex = true;
685
699
  break;
686
700
  }
687
- } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0);
701
+ } while (newFocusedIndex < list.children.length && newFocusedIndex >= 0);
688
702
  if (hasFoundNewIndex) {
689
703
  if (this.focusedIndex >= 0)
690
- this.dropdownEl.children[this.focusedIndex].classList.remove("active");
704
+ list.children[this.focusedIndex]?.classList.remove("active");
691
705
  this.focusedIndex = newFocusedIndex;
692
- this._focusFocusedItem();
706
+ const item = list.children[this.focusedIndex];
707
+ item.classList.add("active");
708
+ item.focus({ preventScroll: true });
693
709
  }
694
710
  } else if (Utils.keys.ENTER.includes(e.key) && this.isOpen) {
695
- const focusedElement = this.dropdownEl.children[this.focusedIndex];
711
+ const li = this._focusedRow(e);
712
+ if (li?.querySelector(":scope > menu")) {
713
+ e.preventDefault();
714
+ this._toggleSubmenu(li);
715
+ return;
716
+ }
717
+ const focusedElement = li ?? this.menuEl.children[this.focusedIndex];
696
718
  const activatableElement = focusedElement?.querySelector("a, button");
697
719
  if (!!activatableElement) {
698
720
  activatableElement.click();
699
- } else if (!!focusedElement) {
700
- if (focusedElement instanceof HTMLElement) {
701
- focusedElement.click();
702
- }
721
+ } else if (focusedElement instanceof HTMLElement) {
722
+ focusedElement.click();
703
723
  }
704
724
  } else if (Utils.keys.ESC.includes(e.key) && this.isOpen) {
705
725
  e.preventDefault();
706
- this.close();
726
+ const openSub = this.menuEl.querySelector("li.open");
727
+ if (openSub) {
728
+ openSub.classList.remove("open", "submenu-start");
729
+ this._syncSubmenuAria(openSub, false);
730
+ openSub.focus();
731
+ } else {
732
+ this.close();
733
+ }
707
734
  }
708
735
  const keyText = e.key.toLowerCase();
709
736
  const isLetter = /[a-zA-Z0-9-_]/.test(keyText);
@@ -717,7 +744,8 @@ var _Dropdown = class _Dropdown extends Component {
717
744
  if (isLetter && !specialKeys.includes(e.key)) {
718
745
  this.filterQuery.push(keyText);
719
746
  const string = this.filterQuery.join("");
720
- const newOptionEl = Array.from(this.dropdownEl.querySelectorAll("li")).find(
747
+ const list = this._containingSubmenu(e) ?? this.menuEl;
748
+ const newOptionEl = Array.from(list.querySelectorAll(":scope > li")).find(
721
749
  (el) => el.textContent.trim().toLowerCase().indexOf(string) === 0
722
750
  );
723
751
  if (newOptionEl) {
@@ -737,7 +765,7 @@ var _Dropdown = class _Dropdown extends Component {
737
765
  this.filterQuery = [];
738
766
  };
739
767
  /**
740
- * Open dropdown.
768
+ * Open menu.
741
769
  */
742
770
  this.open = () => {
743
771
  if (this.isOpen) return;
@@ -745,20 +773,21 @@ var _Dropdown = class _Dropdown extends Component {
745
773
  if (typeof this.options.onOpenStart === "function") {
746
774
  this.options.onOpenStart.call(this, this.el);
747
775
  }
748
- this._resetDropdownStyles();
749
- this.dropdownEl.style.display = "block";
750
- this._placeDropdown();
776
+ this._resetMenuStyles();
777
+ this.menuEl.style.display = "block";
778
+ this._placeMenu();
751
779
  this._animateIn();
752
780
  setTimeout(() => this._setupTemporaryEventHandlers(), 0);
753
781
  this.el.ariaExpanded = "true";
754
782
  };
755
783
  /**
756
- * Close dropdown.
784
+ * Close menu.
757
785
  */
758
786
  this.close = () => {
759
787
  if (!this.isOpen) return;
760
788
  this.isOpen = false;
761
789
  this.focusedIndex = -1;
790
+ this._closeSubmenus();
762
791
  if (typeof this.options.onCloseStart === "function") {
763
792
  this.options.onCloseStart.call(this, this.el);
764
793
  }
@@ -770,21 +799,20 @@ var _Dropdown = class _Dropdown extends Component {
770
799
  this.el.ariaExpanded = "false";
771
800
  };
772
801
  /**
773
- * While dropdown is open, you can recalculate its dimensions if its contents have changed.
802
+ * While menu is open, you can recalculate its dimensions if its contents have changed.
774
803
  */
775
804
  this.recalculateDimensions = () => {
776
805
  if (this.isOpen) {
777
- this._resetDropdownPositioningStyles();
778
- this._placeDropdown();
806
+ this._resetMenuPositioningStyles();
807
+ this._placeMenu();
779
808
  }
780
809
  };
781
- this.el["Expressive_Dropdown"] = this;
782
- _Dropdown._dropdowns.push(this);
810
+ this.el["Expressive_Menu"] = this;
811
+ _Menu._menus.push(this);
783
812
  this.id = Utils.getIdFromTrigger(el);
784
- this.dropdownEl = document.getElementById(this.id);
785
- this.dropdownEl?.classList.add("dropdown-content");
813
+ this.menuEl = document.getElementById(this.id);
786
814
  this.options = {
787
- ..._Dropdown.defaults,
815
+ ..._Menu.defaults,
788
816
  ...options
789
817
  };
790
818
  this.isOpen = false;
@@ -793,51 +821,56 @@ var _Dropdown = class _Dropdown extends Component {
793
821
  this.focusedIndex = -1;
794
822
  this.filterQuery = [];
795
823
  this.el.ariaExpanded = "false";
796
- this._moveDropdownToElement();
797
- this._makeDropdownFocusable();
824
+ this._moveMenuToElement();
825
+ this._makeMenuFocusable();
826
+ this._setupSubmenus();
798
827
  this._setupEventHandlers();
799
828
  }
800
829
  static get defaults() {
801
830
  return _defaults2;
802
831
  }
803
832
  /**
804
- * Initializes instances of Dropdown.
833
+ * Initializes instances of Menu.
805
834
  * @param els HTML elements.
806
835
  * @param options Component options.
807
836
  */
808
837
  static init(els, options = {}) {
809
- return super.init(els, options, _Dropdown);
838
+ return super.init(els, options, _Menu);
810
839
  }
811
840
  static getInstance(el) {
812
- return el["Expressive_Dropdown"];
841
+ return el["Expressive_Menu"];
813
842
  }
814
843
  destroy() {
815
844
  clearTimeout(this.filterTimeout);
816
- this._resetDropdownStyles();
845
+ this._resetMenuStyles();
817
846
  this._removeEventHandlers();
818
847
  this._removeTemporaryEventHandlers();
819
- const index = _Dropdown._dropdowns.indexOf(this);
820
- if (index >= 0) _Dropdown._dropdowns.splice(index, 1);
821
- this.el["Expressive_Dropdown"] = void 0;
848
+ const index = _Menu._menus.indexOf(this);
849
+ if (index >= 0) _Menu._menus.splice(index, 1);
850
+ this.el["Expressive_Menu"] = void 0;
822
851
  }
823
852
  _setupEventHandlers() {
824
853
  this.el.addEventListener("keydown", this._handleTriggerKeydown);
825
- this.dropdownEl?.addEventListener("click", this._handleDropdownClick);
854
+ this.menuEl?.addEventListener("click", this._handleMenuClick);
855
+ if (this.menuEl?.querySelector(":scope > li > menu")) {
856
+ this.menuEl.addEventListener("mouseover", this._handleSubmenuAlign);
857
+ }
826
858
  if (this.options.hover) {
827
859
  this.el.addEventListener("mouseenter", this._handleMouseEnter);
828
860
  this.el.addEventListener("mouseleave", this._handleMouseLeave);
829
- this.dropdownEl.addEventListener("mouseleave", this._handleMouseLeave);
861
+ this.menuEl.addEventListener("mouseleave", this._handleMouseLeave);
830
862
  } else {
831
863
  this.el.addEventListener("click", this._handleClick);
832
864
  }
833
865
  }
834
866
  _removeEventHandlers() {
835
867
  this.el.removeEventListener("keydown", this._handleTriggerKeydown);
836
- this.dropdownEl?.removeEventListener("click", this._handleDropdownClick);
868
+ this.menuEl?.removeEventListener("click", this._handleMenuClick);
869
+ this.menuEl?.removeEventListener("mouseover", this._handleSubmenuAlign);
837
870
  if (this.options.hover) {
838
871
  this.el.removeEventListener("mouseenter", this._handleMouseEnter);
839
872
  this.el.removeEventListener("mouseleave", this._handleMouseLeave);
840
- this.dropdownEl?.removeEventListener("mouseleave", this._handleMouseLeave);
873
+ this.menuEl?.removeEventListener("mouseleave", this._handleMouseLeave);
841
874
  } else {
842
875
  this.el.removeEventListener("click", this._handleClick);
843
876
  }
@@ -845,45 +878,104 @@ var _Dropdown = class _Dropdown extends Component {
845
878
  _setupTemporaryEventHandlers() {
846
879
  document.body.addEventListener("click", this._handleDocumentClick);
847
880
  document.body.addEventListener("touchmove", this._handleDocumentTouchmove, { passive: true });
848
- this.dropdownEl?.addEventListener("keydown", this._handleDropdownKeydown);
881
+ this.menuEl?.addEventListener("keydown", this._handleMenuKeydown);
849
882
  window.addEventListener("resize", this._handleWindowResize);
850
883
  }
851
884
  _removeTemporaryEventHandlers() {
852
885
  document.body.removeEventListener("click", this._handleDocumentClick);
853
886
  document.body.removeEventListener("touchmove", this._handleDocumentTouchmove);
854
- this.dropdownEl?.removeEventListener("keydown", this._handleDropdownKeydown);
887
+ this.menuEl?.removeEventListener("keydown", this._handleMenuKeydown);
855
888
  window.removeEventListener("resize", this._handleWindowResize);
856
889
  }
857
- _resetDropdownStyles() {
858
- this.dropdownEl.style.display = "";
859
- this._resetDropdownPositioningStyles();
860
- this.dropdownEl.style.transform = "";
861
- this.dropdownEl.style.opacity = "";
890
+ _isSubmenuTriggerClick(target) {
891
+ if (!this.menuEl) return false;
892
+ const li = target.closest("li");
893
+ if (!li || !this.menuEl.contains(li)) return false;
894
+ const submenu = li.querySelector(":scope > menu");
895
+ if (!submenu) return false;
896
+ return !submenu.contains(target);
897
+ }
898
+ _setupSubmenus() {
899
+ this.menuEl?.querySelectorAll("li").forEach((li) => {
900
+ if (!li.querySelector(":scope > menu")) return;
901
+ const trigger = li.querySelector(":scope > a, :scope > button, :scope > span") ?? li;
902
+ trigger.setAttribute("aria-haspopup", "menu");
903
+ trigger.setAttribute("aria-expanded", "false");
904
+ });
905
+ }
906
+ _toggleSubmenu(li) {
907
+ const open = !li.classList.contains("open");
908
+ li.parentElement?.querySelectorAll(":scope > li.open").forEach((other) => {
909
+ if (other !== li) {
910
+ other.classList.remove("open", "submenu-start");
911
+ this._syncSubmenuAria(other, false);
912
+ }
913
+ });
914
+ li.classList.toggle("open", open);
915
+ if (open) this._alignSubmenu(li);
916
+ this._syncSubmenuAria(li, open);
917
+ }
918
+ _syncSubmenuAria(li, open) {
919
+ const trigger = li.querySelector(":scope > a, :scope > button, :scope > span") ?? li;
920
+ trigger.setAttribute("aria-expanded", open ? "true" : "false");
921
+ }
922
+ _alignSubmenu(li) {
923
+ const menu = li.querySelector(":scope > menu");
924
+ if (!menu) return;
925
+ li.classList.remove("submenu-start");
926
+ const rect = menu.getBoundingClientRect();
927
+ if (rect.right > window.innerWidth - 8) li.classList.add("submenu-start");
928
+ }
929
+ _closeSubmenus() {
930
+ this.menuEl?.querySelectorAll("li.open").forEach((li) => {
931
+ li.classList.remove("open", "submenu-start");
932
+ this._syncSubmenuAria(li, false);
933
+ });
934
+ }
935
+ _containingSubmenu(e) {
936
+ const target = e.target;
937
+ if (!(target instanceof Element)) return null;
938
+ const submenu = target.closest("li > menu");
939
+ if (submenu instanceof HTMLElement && this.menuEl?.contains(submenu)) return submenu;
940
+ return null;
941
+ }
942
+ _focusedRow(e) {
943
+ const target = e.target;
944
+ if (!(target instanceof Element)) return null;
945
+ const li = target.closest("li");
946
+ if (li instanceof HTMLElement && this.menuEl?.contains(li)) return li;
947
+ return null;
862
948
  }
863
- _resetDropdownPositioningStyles() {
864
- this.dropdownEl.style.width = "";
865
- this.dropdownEl.style.height = "";
866
- this.dropdownEl.style.left = "";
867
- this.dropdownEl.style.top = "";
868
- this.dropdownEl.style.transformOrigin = "";
949
+ _resetMenuStyles() {
950
+ this.menuEl.style.display = "";
951
+ this._resetMenuPositioningStyles();
952
+ this.menuEl.style.transform = "";
953
+ this.menuEl.style.opacity = "";
869
954
  }
870
- _moveDropdownToElement(containerEl = null) {
955
+ _resetMenuPositioningStyles() {
956
+ this.menuEl.style.width = "";
957
+ this.menuEl.style.height = "";
958
+ this.menuEl.style.left = "";
959
+ this.menuEl.style.top = "";
960
+ this.menuEl.style.transformOrigin = "";
961
+ }
962
+ _moveMenuToElement(containerEl = null) {
871
963
  if (this.options.container) {
872
- this.options.container.append(this.dropdownEl);
964
+ this.options.container.append(this.menuEl);
873
965
  return;
874
966
  }
875
967
  if (containerEl) {
876
- if (!containerEl.contains(this.dropdownEl)) containerEl.append(this.dropdownEl);
968
+ if (!containerEl.contains(this.menuEl)) containerEl.append(this.menuEl);
877
969
  return;
878
970
  }
879
- this.el.after(this.dropdownEl);
971
+ this.el.after(this.menuEl);
880
972
  }
881
- _makeDropdownFocusable() {
882
- if (!this.dropdownEl) return;
883
- this.dropdownEl.popover = "";
884
- this.dropdownEl.tabIndex = 0;
885
- Array.from(this.dropdownEl.children).forEach((el) => {
886
- if (el instanceof HTMLHRElement || el.classList.contains("divider")) {
973
+ _makeMenuFocusable() {
974
+ if (!this.menuEl) return;
975
+ this.menuEl.popover = "";
976
+ this.menuEl.tabIndex = 0;
977
+ this.menuEl.querySelectorAll(":scope li, :scope > hr").forEach((el) => {
978
+ if (el instanceof HTMLHRElement || el.classList.contains("divider") || el.classList.contains("gap") || el.classList.contains("label") || el.classList.contains("optgroup")) {
887
979
  el.setAttribute("tabindex", "-1");
888
980
  return;
889
981
  }
@@ -891,25 +983,25 @@ var _Dropdown = class _Dropdown extends Component {
891
983
  });
892
984
  }
893
985
  _focusFocusedItem() {
894
- if (this.focusedIndex >= 0 && this.focusedIndex < this.dropdownEl.children.length && this.options.autoFocus) {
895
- this.dropdownEl.children[this.focusedIndex].focus({
986
+ if (this.focusedIndex >= 0 && this.focusedIndex < this.menuEl.children.length && this.options.autoFocus) {
987
+ this.menuEl.children[this.focusedIndex].focus({
896
988
  preventScroll: true
897
989
  });
898
- this.dropdownEl.children[this.focusedIndex].scrollIntoView({
990
+ this.menuEl.children[this.focusedIndex].scrollIntoView({
899
991
  behavior: "smooth",
900
992
  block: "nearest",
901
993
  inline: "nearest"
902
994
  });
903
995
  }
904
996
  }
905
- _getDropdownPosition(closestOverflowParent) {
997
+ _getMenuPosition(closestOverflowParent) {
906
998
  const triggerBRect = this.el.getBoundingClientRect();
907
- const dropdownBRect = this.dropdownEl.getBoundingClientRect();
908
- let idealHeight = dropdownBRect.height;
909
- let idealWidth = dropdownBRect.width;
910
- let idealXPos = triggerBRect.left - dropdownBRect.left;
911
- let idealYPos = triggerBRect.top - dropdownBRect.top;
912
- const dropdownBounds = {
999
+ const menuBRect = this.menuEl.getBoundingClientRect();
1000
+ let idealHeight = menuBRect.height;
1001
+ let idealWidth = menuBRect.width;
1002
+ let idealXPos = triggerBRect.left - menuBRect.left;
1003
+ let idealYPos = triggerBRect.top - menuBRect.top;
1004
+ const menuBounds = {
913
1005
  left: idealXPos,
914
1006
  top: idealYPos,
915
1007
  height: idealHeight,
@@ -918,7 +1010,7 @@ var _Dropdown = class _Dropdown extends Component {
918
1010
  const alignments = Utils.checkPossibleAlignments(
919
1011
  this.el,
920
1012
  closestOverflowParent,
921
- dropdownBounds,
1013
+ menuBounds,
922
1014
  this.options.coverTrigger ? 0 : triggerBRect.height
923
1015
  );
924
1016
  let verticalAlignment = "top";
@@ -959,10 +1051,10 @@ var _Dropdown = class _Dropdown extends Component {
959
1051
  }
960
1052
  }
961
1053
  if (verticalAlignment === "bottom") {
962
- idealYPos = idealYPos - dropdownBRect.height + (this.options.coverTrigger ? triggerBRect.height : 0);
1054
+ idealYPos = idealYPos - menuBRect.height + (this.options.coverTrigger ? triggerBRect.height : 0);
963
1055
  }
964
1056
  if (horizontalAlignment === "right") {
965
- idealXPos = idealXPos - dropdownBRect.width + triggerBRect.width;
1057
+ idealXPos = idealXPos - menuBRect.width + triggerBRect.width;
966
1058
  }
967
1059
  return {
968
1060
  x: idealXPos,
@@ -975,26 +1067,26 @@ var _Dropdown = class _Dropdown extends Component {
975
1067
  }
976
1068
  _animateIn() {
977
1069
  const duration = this.options.inDuration;
978
- this.dropdownEl.style.transition = "none";
979
- this.dropdownEl.style.opacity = "0";
980
- this.dropdownEl.style.transform = "scale(0.3, 0.3)";
1070
+ this.menuEl.style.transition = "none";
1071
+ this.menuEl.style.opacity = "0";
1072
+ this.menuEl.style.transform = "scale(0.85)";
981
1073
  setTimeout(() => {
982
- this.dropdownEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
983
- this.dropdownEl.style.opacity = "1";
984
- this.dropdownEl.style.transform = "scale(1, 1)";
1074
+ this.menuEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
1075
+ this.menuEl.style.opacity = "1";
1076
+ this.menuEl.style.transform = "scale(1)";
985
1077
  }, 1);
986
1078
  setTimeout(() => {
987
- if (this.options.autoFocus) this.dropdownEl.focus();
1079
+ if (this.options.autoFocus) this.menuEl.focus();
988
1080
  if (typeof this.options.onOpenEnd === "function") this.options.onOpenEnd.call(this, this.el);
989
1081
  }, duration);
990
1082
  }
991
1083
  _animateOut() {
992
1084
  const duration = this.options.outDuration;
993
- this.dropdownEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
994
- this.dropdownEl.style.opacity = "0";
995
- this.dropdownEl.style.transform = "scale(0.3, 0.3)";
1085
+ this.menuEl.style.transition = `opacity ${duration}ms ease, transform ${duration}ms ease`;
1086
+ this.menuEl.style.opacity = "0";
1087
+ this.menuEl.style.transform = "scale(0.85)";
996
1088
  setTimeout(() => {
997
- this._resetDropdownStyles();
1089
+ this._resetMenuStyles();
998
1090
  if (typeof this.options.onCloseEnd === "function")
999
1091
  this.options.onCloseEnd.call(this, this.el);
1000
1092
  }, duration);
@@ -1009,30 +1101,31 @@ var _Dropdown = class _Dropdown extends Component {
1009
1101
  }
1010
1102
  return null;
1011
1103
  }
1012
- _placeDropdown() {
1104
+ _placeMenu() {
1013
1105
  let closestOverflowParent = this._getClosestAncestor(
1014
- this.dropdownEl,
1106
+ this.menuEl,
1015
1107
  (ancestor) => {
1016
1108
  return !["HTML", "BODY"].includes(ancestor.tagName) && getComputedStyle(ancestor).overflow !== "visible";
1017
1109
  }
1018
1110
  );
1019
1111
  if (!closestOverflowParent) {
1020
- closestOverflowParent = !!this.dropdownEl.offsetParent ? this.dropdownEl.offsetParent : this.dropdownEl.parentNode;
1112
+ closestOverflowParent = !!this.menuEl.offsetParent ? this.menuEl.offsetParent : this.menuEl.parentNode;
1021
1113
  }
1022
1114
  if (getComputedStyle(closestOverflowParent).position === "static")
1023
1115
  closestOverflowParent.style.position = "relative";
1024
- const idealWidth = this.options.constrainWidth ? this.el.getBoundingClientRect().width : this.dropdownEl.getBoundingClientRect().width;
1025
- this.dropdownEl.style.width = idealWidth + "px";
1026
- const positionInfo = this._getDropdownPosition(closestOverflowParent);
1027
- this.dropdownEl.style.left = positionInfo.x + "px";
1028
- this.dropdownEl.style.top = positionInfo.y + "px";
1029
- this.dropdownEl.style.height = positionInfo.height + "px";
1030
- this.dropdownEl.style.width = positionInfo.width + "px";
1031
- this.dropdownEl.style.transformOrigin = `${positionInfo.horizontalAlignment === "left" ? "0" : "100%"} ${positionInfo.verticalAlignment === "top" ? "0" : "100%"}`;
1116
+ const natural = this.menuEl.getBoundingClientRect().width;
1117
+ const idealWidth = this.options.constrainWidth ? this.el.getBoundingClientRect().width : Math.min(280, Math.max(112, natural));
1118
+ this.menuEl.style.width = idealWidth + "px";
1119
+ const positionInfo = this._getMenuPosition(closestOverflowParent);
1120
+ this.menuEl.style.left = positionInfo.x + "px";
1121
+ this.menuEl.style.top = positionInfo.y + "px";
1122
+ this.menuEl.style.height = positionInfo.height + "px";
1123
+ this.menuEl.style.width = positionInfo.width + "px";
1124
+ this.menuEl.style.transformOrigin = `${positionInfo.horizontalAlignment === "left" ? "0" : "100%"} ${positionInfo.verticalAlignment === "top" ? "0" : "100%"}`;
1032
1125
  }
1033
1126
  };
1034
- _Dropdown._dropdowns = [];
1035
- var Dropdown = _Dropdown;
1127
+ _Menu._menus = [];
1128
+ var Menu = _Menu;
1036
1129
 
1037
1130
  // src/ts/components/autocomplete.ts
1038
1131
  var _defaults3 = {
@@ -1040,8 +1133,8 @@ var _defaults3 = {
1040
1133
  // Autocomplete data set
1041
1134
  onAutocomplete: null,
1042
1135
  // Callback for when autocompleted
1043
- dropdownOptions: {
1044
- // Default dropdown options
1136
+ menuOptions: {
1137
+ // Default menu options
1045
1138
  autoFocus: false,
1046
1139
  closeOnClick: false,
1047
1140
  coverTrigger: false
@@ -1057,7 +1150,7 @@ var _defaults3 = {
1057
1150
  )
1058
1151
  );
1059
1152
  },
1060
- maxDropDownHeight: "300px",
1153
+ maxMenuHeight: "300px",
1061
1154
  allowUnsafeHTML: false,
1062
1155
  selected: []
1063
1156
  };
@@ -1142,19 +1235,19 @@ var _Autocomplete = class _Autocomplete extends Component {
1142
1235
  this._resetAutocomplete();
1143
1236
  if (inputText.length >= this.options.minLength) {
1144
1237
  this.isOpen = true;
1145
- this._renderDropdown();
1238
+ this._renderMenu();
1146
1239
  }
1147
- if (!this.dropdown.isOpen) {
1240
+ if (!this.menu.isOpen) {
1148
1241
  setTimeout(() => {
1149
- this.dropdown.open();
1242
+ this.menu.open();
1150
1243
  }, 0);
1151
- } else this.dropdown.recalculateDimensions();
1244
+ } else this.menu.recalculateDimensions();
1152
1245
  };
1153
1246
  /**
1154
1247
  * Hide autocomplete.
1155
1248
  */
1156
1249
  this.close = () => {
1157
- this.dropdown.close();
1250
+ this.menu.close();
1158
1251
  };
1159
1252
  this.el["Expressive_Autocomplete"] = this;
1160
1253
  this.options = {
@@ -1169,7 +1262,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1169
1262
  this.menuItems = this.options.data || [];
1170
1263
  this.$active = null;
1171
1264
  this._mousedown = false;
1172
- this._setupDropdown();
1265
+ this._setupMenu();
1173
1266
  this._setupEventHandlers();
1174
1267
  }
1175
1268
  static get defaults() {
@@ -1200,7 +1293,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1200
1293
  }
1201
1294
  destroy() {
1202
1295
  this._removeEventHandlers();
1203
- this._removeDropdown();
1296
+ this._removeMenu();
1204
1297
  this.el["Expressive_Autocomplete"] = void 0;
1205
1298
  }
1206
1299
  _setupEventHandlers() {
@@ -1229,34 +1322,33 @@ var _Autocomplete = class _Autocomplete extends Component {
1229
1322
  this.container.removeEventListener("touchend", this._handleContainerMouseupAndTouchend);
1230
1323
  }
1231
1324
  }
1232
- _setupDropdown() {
1233
- this.container = document.createElement("ul");
1234
- this.container.style.maxHeight = this.options.maxDropDownHeight;
1325
+ _setupMenu() {
1326
+ this.container = document.createElement("menu");
1327
+ this.container.style.maxHeight = this.options.maxMenuHeight;
1235
1328
  this.container.id = `autocomplete-options-${Utils.guid()}`;
1236
- this.container.classList.add("autocomplete-content", "dropdown-content");
1329
+ this.container.classList.add("autocomplete-content");
1237
1330
  this.container.ariaExpanded = "true";
1238
1331
  this.el.setAttribute("data-target", this.container.id);
1239
1332
  this.menuItems.forEach((menuItem) => {
1240
- const itemElement = this._createDropdownItem(menuItem);
1333
+ const itemElement = this._createMenuItem(menuItem);
1241
1334
  this.container.append(itemElement);
1242
1335
  });
1243
1336
  this.el.parentElement.appendChild(this.container);
1244
- const dropdownOptions = {
1245
- ..._Autocomplete.defaults.dropdownOptions,
1246
- ...this.options.dropdownOptions
1337
+ const menuOptions = {
1338
+ ..._Autocomplete.defaults.menuOptions,
1339
+ ...this.options.menuOptions
1247
1340
  };
1248
- const userOnItemClick = dropdownOptions.onItemClick;
1249
- dropdownOptions.onItemClick = (li) => {
1341
+ const userOnItemClick = menuOptions.onItemClick;
1342
+ menuOptions.onItemClick = (li) => {
1250
1343
  if (!li) return;
1251
1344
  const entryID = li.getAttribute("data-id");
1252
1345
  this.selectOption(entryID);
1253
- if (userOnItemClick && typeof userOnItemClick === "function")
1254
- userOnItemClick.call(this.dropdown, this.el);
1346
+ if (typeof userOnItemClick === "function") userOnItemClick.call(this.menu, li);
1255
1347
  };
1256
- this.dropdown = Dropdown.init(this.el, dropdownOptions);
1348
+ this.menu = Menu.init(this.el, menuOptions);
1257
1349
  const label = this.el.parentElement.querySelector("label");
1258
1350
  if (label) this.el.after(label);
1259
- this.el.removeEventListener("click", this.dropdown._handleClick);
1351
+ this.el.removeEventListener("click", this.menu._handleClick);
1260
1352
  if (!this.options.isMultiSelect && !(this.options.selected.length === 0)) {
1261
1353
  const selectedValue = this.menuItems.filter((value) => value.id === this.selectedValues[0].id);
1262
1354
  this.el.value = selectedValue[0].text;
@@ -1268,7 +1360,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1268
1360
  this.el.parentElement.appendChild(div);
1269
1361
  this._updateSelectedInfo();
1270
1362
  }
1271
- _removeDropdown() {
1363
+ _removeMenu() {
1272
1364
  this.container.ariaExpanded = "false";
1273
1365
  this.container.parentNode.removeChild(this.container);
1274
1366
  }
@@ -1291,7 +1383,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1291
1383
  }
1292
1384
  return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
1293
1385
  }
1294
- _createDropdownItem(entry) {
1386
+ _createMenuItem(entry) {
1295
1387
  const item = document.createElement("li");
1296
1388
  item.setAttribute("data-id", entry.id);
1297
1389
  item.setAttribute(
@@ -1358,13 +1450,13 @@ var _Autocomplete = class _Autocomplete extends Component {
1358
1450
  item.style.gridTemplateColumns = getGridConfig();
1359
1451
  return item;
1360
1452
  }
1361
- _renderDropdown() {
1453
+ _renderMenu() {
1362
1454
  this._resetAutocomplete();
1363
1455
  if (this.menuItems.length === 0) {
1364
1456
  this.menuItems = this.selectedValues;
1365
1457
  }
1366
1458
  for (let i = 0; i < this.menuItems.length; i++) {
1367
- const item = this._createDropdownItem(this.menuItems[i]);
1459
+ const item = this._createMenuItem(this.menuItems[i]);
1368
1460
  this.container.append(item);
1369
1461
  }
1370
1462
  }
@@ -1395,7 +1487,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1395
1487
  * Updates the visible or selectable items shown in the menu.
1396
1488
  * @param menuItems Items to be available.
1397
1489
  * @param selected Selected item ids
1398
- * @param open Option to conditionally open dropdown
1490
+ * @param open Option to conditionally open menu
1399
1491
  */
1400
1492
  setMenuItems(menuItems, selected = null, open = true) {
1401
1493
  this.menuItems = menuItems;
@@ -1406,7 +1498,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1406
1498
  );
1407
1499
  }
1408
1500
  if (this.options.isMultiSelect) {
1409
- this._renderDropdown();
1501
+ this._renderMenu();
1410
1502
  } else {
1411
1503
  this._refreshInputText();
1412
1504
  }
@@ -1414,19 +1506,6 @@ var _Autocomplete = class _Autocomplete extends Component {
1414
1506
  this._updateSelectedInfo();
1415
1507
  this._triggerChanged();
1416
1508
  }
1417
- /**
1418
- * Sets selected values.
1419
- * @deprecated @see https://github.com/materializecss/materialize/issues/552
1420
- * @param entries
1421
- */
1422
- setValues(entries) {
1423
- this.selectedValues = entries;
1424
- this._updateSelectedInfo();
1425
- if (!this.options.isMultiSelect) {
1426
- this._refreshInputText();
1427
- }
1428
- this._triggerChanged();
1429
- }
1430
1509
  /**
1431
1510
  * Select a specific autocomplete option via id-property.
1432
1511
  * @param id The id of a data-entry.
@@ -1441,7 +1520,7 @@ var _Autocomplete = class _Autocomplete extends Component {
1441
1520
  else this.selectedValues = this.selectedValues.filter(
1442
1521
  (selectedEntry) => selectedEntry.id !== entry.id
1443
1522
  );
1444
- this._renderDropdown();
1523
+ this._renderMenu();
1445
1524
  this.el.focus();
1446
1525
  } else {
1447
1526
  this.selectedValues = [entry];
@@ -1452,14 +1531,6 @@ var _Autocomplete = class _Autocomplete extends Component {
1452
1531
  this._updateSelectedInfo();
1453
1532
  this._triggerChanged();
1454
1533
  }
1455
- selectOptions(ids) {
1456
- const entries = this.menuItems.filter(
1457
- (item) => !(ids.indexOf(item.id) === -1)
1458
- );
1459
- if (!entries) return;
1460
- this.selectedValues = entries;
1461
- this._renderDropdown();
1462
- }
1463
1534
  };
1464
1535
  /**
1465
1536
  * The three-dot loading indicator, parsed once and cloned thereafter.
@@ -1539,7 +1610,7 @@ var _Chips = class _Chips extends Component {
1539
1610
  this._renderChips();
1540
1611
  }
1541
1612
  if (this.options.allowUserInput) {
1542
- this.el.classList.add("input-field");
1613
+ this.el.classList.add("field");
1543
1614
  this._setupInput();
1544
1615
  this._setupEventHandlers();
1545
1616
  this.el.append(this._input);
@@ -1767,12 +1838,14 @@ var Range = class _Range extends Component {
1767
1838
  constructor(el, options) {
1768
1839
  super(el, options, _Range);
1769
1840
  this._handleRangeChange = () => {
1841
+ this._clampDual();
1770
1842
  this._sync();
1771
1843
  this.thumb.classList.add("active");
1772
1844
  };
1773
1845
  this._handleRangeMousedownTouchstart = (e) => {
1774
1846
  this._mousedown = true;
1775
1847
  this.el.classList.add("active");
1848
+ this._clampDual();
1776
1849
  this._sync();
1777
1850
  if (e.type !== "input") {
1778
1851
  this.thumb.classList.add("active");
@@ -1780,6 +1853,7 @@ var Range = class _Range extends Component {
1780
1853
  };
1781
1854
  this._handleRangeInputMousemoveTouchmove = () => {
1782
1855
  if (this._mousedown) {
1856
+ this._clampDual();
1783
1857
  this._sync();
1784
1858
  this.thumb.classList.add("active");
1785
1859
  }
@@ -1864,16 +1938,48 @@ var Range = class _Range extends Component {
1864
1938
  _isVertical() {
1865
1939
  return !!this.el.closest(".vertical");
1866
1940
  }
1941
+ _host() {
1942
+ return this.el.closest(".range, .range-field, label");
1943
+ }
1944
+ _clampDual() {
1945
+ const host = this._host();
1946
+ const peers = host?.querySelectorAll('input[type="range"]');
1947
+ if (!peers || peers.length !== 2) return;
1948
+ const start = peers[0];
1949
+ const end = peers[1];
1950
+ if (this.el === start && +start.value > +end.value) start.value = end.value;
1951
+ if (this.el === end && +end.value < +start.value) end.value = start.value;
1952
+ }
1953
+ _fraction(el) {
1954
+ const max = parseFloat(el.max) || 100;
1955
+ const min = parseFloat(el.min) || 0;
1956
+ const val = parseFloat(el.value) || 0;
1957
+ return max === min ? 0 : (val - min) / (max - min);
1958
+ }
1867
1959
  _sync() {
1868
- const max = parseFloat(this.el.getAttribute("max")) || 100;
1869
- const min = parseFloat(this.el.getAttribute("min")) || 0;
1870
- const val = parseFloat(this.el.value) || 0;
1871
- const percent = max === min ? 0 : (val - min) / (max - min);
1960
+ const percent = this._fraction(this.el);
1961
+ const fraction = `${percent * 100}%`;
1872
1962
  const left = this.el.offsetLeft;
1873
1963
  const top = this.el.offsetTop;
1874
1964
  const width = this.el.offsetWidth;
1875
1965
  const height = this.el.offsetHeight;
1876
- this.el.style.setProperty("--md-comp-slider-active-fraction", `${percent * 100}%`);
1966
+ this.el.style.setProperty("--md-comp-slider-active-fraction", fraction);
1967
+ const host = this._host();
1968
+ const peers = host?.querySelectorAll('input[type="range"]');
1969
+ if (host && peers && peers.length === 2) {
1970
+ const nums = Array.from(peers).map((el) => this._fraction(el));
1971
+ host.style.setProperty("--md-comp-slider-start-fraction", `${Math.min(...nums) * 100}%`);
1972
+ host.style.setProperty("--md-comp-slider-end-fraction", `${Math.max(...nums) * 100}%`);
1973
+ }
1974
+ if (host?.classList.contains("stops")) {
1975
+ const max = parseFloat(this.el.max) || 100;
1976
+ const min = parseFloat(this.el.min) || 0;
1977
+ const step = parseFloat(this.el.step);
1978
+ if (step > 0 && Number.isFinite(step)) {
1979
+ const n = Math.round((max - min) / step) + 1;
1980
+ host.style.setProperty("--md-comp-slider-stop-count", String(Math.max(2, n)));
1981
+ }
1982
+ }
1877
1983
  this.value.textContent = this.el.value;
1878
1984
  if (this._isVertical()) {
1879
1985
  this.thumb.style.left = `${left + width / 2}px`;
@@ -1961,6 +2067,170 @@ var _Dialogs = class _Dialogs {
1961
2067
  _Dialogs._down = null;
1962
2068
  var Dialogs = _Dialogs;
1963
2069
 
2070
+ // src/ts/behaviors/bottomSheets.ts
2071
+ var _BottomSheets = class _BottomSheets {
2072
+ static Init() {
2073
+ Utils.onDocumentReady(() => {
2074
+ document.addEventListener("pointerdown", _BottomSheets._onDown, { passive: true });
2075
+ document.addEventListener("pointermove", _BottomSheets._onMove, { passive: true });
2076
+ document.addEventListener("pointerup", _BottomSheets._onUp, { passive: true });
2077
+ document.addEventListener("pointercancel", _BottomSheets._onCancel, { passive: true });
2078
+ });
2079
+ }
2080
+ static _onDown(event) {
2081
+ if (!event.isPrimary) return;
2082
+ if (event.pointerType === "mouse" && event.button !== 0) return;
2083
+ const dialog = _BottomSheets._sheet(event.target);
2084
+ if (!dialog?.open) {
2085
+ _BottomSheets._drag = null;
2086
+ return;
2087
+ }
2088
+ if (!_BottomSheets._inHandle(event, dialog)) {
2089
+ _BottomSheets._drag = null;
2090
+ return;
2091
+ }
2092
+ dialog.style.transition = "none";
2093
+ _BottomSheets._drag = {
2094
+ dialog,
2095
+ pointerId: event.pointerId,
2096
+ startY: event.clientY,
2097
+ lastY: event.clientY,
2098
+ lastT: Date.now(),
2099
+ shift: 0
2100
+ };
2101
+ }
2102
+ static _onMove(event) {
2103
+ const drag = _BottomSheets._drag;
2104
+ if (!drag || drag.pointerId !== event.pointerId) return;
2105
+ const shift = Math.max(0, event.clientY - drag.startY);
2106
+ drag.shift = shift;
2107
+ drag.lastY = event.clientY;
2108
+ drag.lastT = Date.now();
2109
+ drag.dialog.style.setProperty("--md-comp-bottom-sheet-shift", `${shift}px`);
2110
+ }
2111
+ static _onUp(event) {
2112
+ const drag = _BottomSheets._drag;
2113
+ _BottomSheets._drag = null;
2114
+ if (!drag || drag.pointerId !== event.pointerId) return;
2115
+ const dialog = drag.dialog;
2116
+ dialog.style.transition = "";
2117
+ const dt = Math.max(1, Date.now() - drag.lastT);
2118
+ const velocity = (event.clientY - drag.lastY) / dt;
2119
+ const dismiss = drag.shift > 96 || velocity > 0.5;
2120
+ if (dismiss && dialog.open) {
2121
+ dialog.close();
2122
+ }
2123
+ dialog.style.setProperty("--md-comp-bottom-sheet-shift", "0px");
2124
+ }
2125
+ static _onCancel() {
2126
+ const drag = _BottomSheets._drag;
2127
+ _BottomSheets._drag = null;
2128
+ if (!drag) return;
2129
+ drag.dialog.style.transition = "";
2130
+ drag.dialog.style.setProperty("--md-comp-bottom-sheet-shift", "0px");
2131
+ }
2132
+ static _sheet(target) {
2133
+ if (!(target instanceof Element)) return null;
2134
+ const dialog = target.closest("dialog.bottom-sheet, dialog.bottom");
2135
+ return dialog instanceof HTMLDialogElement ? dialog : null;
2136
+ }
2137
+ static _inHandle(event, dialog) {
2138
+ const target = event.target;
2139
+ if (target instanceof Element && target.closest(".handle")) return true;
2140
+ const rect = dialog.getBoundingClientRect();
2141
+ return event.clientY >= rect.top && event.clientY <= rect.top + 48;
2142
+ }
2143
+ };
2144
+ _BottomSheets._drag = null;
2145
+ var BottomSheets = _BottomSheets;
2146
+
2147
+ // src/ts/behaviors/sideSheets.ts
2148
+ var _SideSheets = class _SideSheets {
2149
+ static Init() {
2150
+ Utils.onDocumentReady(() => {
2151
+ document.addEventListener("pointerdown", _SideSheets._onDown, { passive: true });
2152
+ document.addEventListener("pointermove", _SideSheets._onMove, { passive: true });
2153
+ document.addEventListener("pointerup", _SideSheets._onUp, { passive: true });
2154
+ document.addEventListener("pointercancel", _SideSheets._onCancel, { passive: true });
2155
+ });
2156
+ }
2157
+ static _onDown(event) {
2158
+ if (!event.isPrimary) return;
2159
+ if (event.pointerType === "mouse" && event.button !== 0) return;
2160
+ const dialog = _SideSheets._sheet(event.target);
2161
+ if (!dialog?.open) {
2162
+ _SideSheets._drag = null;
2163
+ return;
2164
+ }
2165
+ if (!_SideSheets._inHandle(event, dialog)) {
2166
+ _SideSheets._drag = null;
2167
+ return;
2168
+ }
2169
+ dialog.style.transition = "none";
2170
+ _SideSheets._drag = {
2171
+ dialog,
2172
+ pointerId: event.pointerId,
2173
+ startX: event.clientX,
2174
+ lastX: event.clientX,
2175
+ lastT: Date.now(),
2176
+ shift: 0,
2177
+ startDocked: _SideSheets._startDocked(dialog)
2178
+ };
2179
+ }
2180
+ static _onMove(event) {
2181
+ const drag = _SideSheets._drag;
2182
+ if (!drag || drag.pointerId !== event.pointerId) return;
2183
+ const delta = event.clientX - drag.startX;
2184
+ const shift = drag.startDocked ? Math.min(0, delta) : Math.max(0, delta);
2185
+ drag.shift = shift;
2186
+ drag.lastX = event.clientX;
2187
+ drag.lastT = Date.now();
2188
+ drag.dialog.style.setProperty("--md-comp-side-sheet-shift", `${shift}px`);
2189
+ }
2190
+ static _onUp(event) {
2191
+ const drag = _SideSheets._drag;
2192
+ _SideSheets._drag = null;
2193
+ if (!drag || drag.pointerId !== event.pointerId) return;
2194
+ const dialog = drag.dialog;
2195
+ dialog.style.transition = "";
2196
+ const dt = Math.max(1, Date.now() - drag.lastT);
2197
+ const velocity = (event.clientX - drag.lastX) / dt;
2198
+ const dismiss = drag.startDocked ? drag.shift < -96 || velocity < -0.5 : drag.shift > 96 || velocity > 0.5;
2199
+ if (dismiss && dialog.open) {
2200
+ dialog.close();
2201
+ }
2202
+ dialog.style.setProperty("--md-comp-side-sheet-shift", "0px");
2203
+ }
2204
+ static _onCancel() {
2205
+ const drag = _SideSheets._drag;
2206
+ _SideSheets._drag = null;
2207
+ if (!drag) return;
2208
+ drag.dialog.style.transition = "";
2209
+ drag.dialog.style.setProperty("--md-comp-side-sheet-shift", "0px");
2210
+ }
2211
+ static _sheet(target) {
2212
+ if (!(target instanceof Element)) return null;
2213
+ const dialog = target.closest(
2214
+ "dialog.side-sheet, dialog.right, dialog.right-sheet, dialog.left, dialog.left-sheet"
2215
+ );
2216
+ return dialog instanceof HTMLDialogElement ? dialog : null;
2217
+ }
2218
+ static _startDocked(dialog) {
2219
+ return dialog.classList.contains("left") || dialog.classList.contains("left-sheet") || dialog.classList.contains("start");
2220
+ }
2221
+ static _inHandle(event, dialog) {
2222
+ const target = event.target;
2223
+ if (target instanceof Element && target.closest("header")) return true;
2224
+ const rect = dialog.getBoundingClientRect();
2225
+ if (_SideSheets._startDocked(dialog)) {
2226
+ return event.clientX >= rect.right - 24 && event.clientX <= rect.right;
2227
+ }
2228
+ return event.clientX >= rect.left && event.clientX <= rect.left + 24;
2229
+ }
2230
+ };
2231
+ _SideSheets._drag = null;
2232
+ var SideSheets = _SideSheets;
2233
+
1964
2234
  // src/ts/behaviors/forms.ts
1965
2235
  var Forms = class _Forms {
1966
2236
  /**
@@ -2403,7 +2673,7 @@ var _Carousel = class _Carousel extends Component {
2403
2673
  ..._Carousel.defaults,
2404
2674
  ...options
2405
2675
  };
2406
- this._flat = this.options.fullWidth || this.el.classList.contains("flat") || this.el.classList.contains("carousel-slider");
2676
+ this._flat = this.options.fullWidth || this.el.classList.contains("flat");
2407
2677
  if (this._flat) {
2408
2678
  this.el.classList.add("flat");
2409
2679
  this.options.fullWidth = true;
@@ -2864,236 +3134,10 @@ var CharacterCounter = class _CharacterCounter extends Component {
2864
3134
  }
2865
3135
  };
2866
3136
 
2867
- // src/ts/components/collapsible.ts
2868
- var _defaults9 = {
2869
- accordion: true,
2870
- onOpenStart: null,
2871
- onOpenEnd: null,
2872
- onCloseStart: null,
2873
- onCloseEnd: null,
2874
- inDuration: 300,
2875
- outDuration: 300
2876
- };
2877
- var Collapsible = class _Collapsible extends Component {
2878
- constructor(el, options) {
2879
- super(el, options, _Collapsible);
2880
- this._items = [];
2881
- this._endTimers = [];
2882
- this._wrappedBodies = [];
2883
- /**
2884
- * Open collapsible section.
2885
- * @param index 0-based index of the section to open.
2886
- */
2887
- this.open = (index) => {
2888
- const item = this._items[index];
2889
- if (!item || this._isOpen(item)) return;
2890
- if (this.options.accordion) {
2891
- this._items.forEach((other, i) => {
2892
- if (i !== index && this._isOpen(other)) this.close(i);
2893
- });
2894
- }
2895
- this._setOpen(item, true);
2896
- };
2897
- /**
2898
- * Close collapsible section.
2899
- * @param index 0-based index of the section to close.
2900
- */
2901
- this.close = (index) => {
2902
- const item = this._items[index];
2903
- if (!item || !this._isOpen(item)) return;
2904
- this._setOpen(item, false);
2905
- };
2906
- this._handleClick = (e) => {
2907
- const header = e.target.closest(".collapsible-header");
2908
- if (!header || header.closest(".collapsible") !== this.el) return;
2909
- if (header.closest("details")) return;
2910
- const item = header.closest("li");
2911
- if (!item) return;
2912
- const index = this._items.indexOf(item);
2913
- if (index < 0) return;
2914
- if (this._isOpen(item)) this.close(index);
2915
- else this.open(index);
2916
- };
2917
- this._handleKeydown = (e) => {
2918
- if (!Utils.keys.ENTER.includes(e.key) && e.key !== " ") return;
2919
- const header = e.target.closest(".collapsible-header");
2920
- if (!header || header.closest(".collapsible") !== this.el) return;
2921
- if (header.closest("details")) return;
2922
- if (header.matches("a, button")) return;
2923
- e.preventDefault();
2924
- const item = header.closest("li");
2925
- if (!item) return;
2926
- const index = this._items.indexOf(item);
2927
- if (index < 0) return;
2928
- if (this._isOpen(item)) this.close(index);
2929
- else this.open(index);
2930
- };
2931
- this._handleToggle = (e) => {
2932
- const item = e.target;
2933
- if (!(item instanceof HTMLDetailsElement)) return;
2934
- if (!this._items.includes(item)) return;
2935
- this._notify(item, item.open);
2936
- };
2937
- this.el["Expressive_Collapsible"] = this;
2938
- const accordion = options.accordion !== void 0 ? options.accordion : !el.classList.contains("expandable");
2939
- this.options = {
2940
- ..._Collapsible.defaults,
2941
- ...options,
2942
- accordion
2943
- };
2944
- this._groupName = el.id ? `collapsible-${el.id}` : `collapsible-${Utils.guid()}`;
2945
- this._items = this._collectItems();
2946
- this._wrapDetailsBodies();
2947
- this._setupItems();
2948
- this._setupEventHandlers();
2949
- }
2950
- static get defaults() {
2951
- return _defaults9;
2952
- }
2953
- /**
2954
- * Initializes instances of Collapsible.
2955
- * @param els HTML elements.
2956
- * @param options Component options.
2957
- */
2958
- static init(els, options = {}) {
2959
- return super.init(els, options, _Collapsible);
2960
- }
2961
- static getInstance(el) {
2962
- return el["Expressive_Collapsible"];
2963
- }
2964
- destroy() {
2965
- this._removeEventHandlers();
2966
- this._endTimers.forEach((id) => clearTimeout(id));
2967
- this._endTimers = [];
2968
- this._unwrapDetailsBodies();
2969
- this.el["Expressive_Collapsible"] = void 0;
2970
- }
2971
- _collectItems() {
2972
- const details = Array.from(this.el.querySelectorAll(":scope > details"));
2973
- if (details.length) return details;
2974
- return Array.from(this.el.children).filter((c) => c.tagName === "LI");
2975
- }
2976
- _setupItems() {
2977
- if (this.options.accordion) {
2978
- this._items.forEach((item) => {
2979
- if (item instanceof HTMLDetailsElement && !item.getAttribute("name")) {
2980
- item.setAttribute("name", this._groupName);
2981
- }
2982
- });
2983
- }
2984
- const opened = this._items.filter((item) => this._isOpen(item));
2985
- if (this.options.accordion && opened.length > 1) {
2986
- opened.slice(1).forEach((item) => {
2987
- if (item instanceof HTMLDetailsElement) item.open = false;
2988
- else item.classList.remove("active");
2989
- });
2990
- }
2991
- this._items.forEach((item) => this._syncAria(item));
2992
- }
2993
- _isOpen(item) {
2994
- if (item instanceof HTMLDetailsElement) return item.open;
2995
- return item.classList.contains("active");
2996
- }
2997
- _setOpen(item, open) {
2998
- if (item instanceof HTMLDetailsElement) {
2999
- item.open = open;
3000
- return;
3001
- }
3002
- item.classList.toggle("active", open);
3003
- this._syncAria(item);
3004
- this._notify(item, open);
3005
- }
3006
- _headerOf(item) {
3007
- if (item instanceof HTMLDetailsElement) {
3008
- return item.querySelector(":scope > summary");
3009
- }
3010
- return item.querySelector(":scope > .collapsible-header");
3011
- }
3012
- _wrapDetailsBodies() {
3013
- this._items.forEach((item) => {
3014
- if (!(item instanceof HTMLDetailsElement)) return;
3015
- if (item.querySelector(":scope > .collapsible-body")) return;
3016
- const body = document.createElement("div");
3017
- body.className = "collapsible-body";
3018
- Array.from(item.childNodes).forEach((node) => {
3019
- if (node instanceof HTMLElement && node.tagName === "SUMMARY") return;
3020
- body.appendChild(node);
3021
- });
3022
- item.appendChild(body);
3023
- this._wrappedBodies.push(body);
3024
- });
3025
- }
3026
- _unwrapDetailsBodies() {
3027
- this._wrappedBodies.forEach((body) => {
3028
- const parent = body.parentNode;
3029
- if (!parent) return;
3030
- while (body.firstChild) parent.insertBefore(body.firstChild, body);
3031
- body.remove();
3032
- });
3033
- this._wrappedBodies = [];
3034
- }
3035
- _bodyOf(item) {
3036
- return item.querySelector(":scope > .collapsible-body");
3037
- }
3038
- _syncAria(item) {
3039
- if (item instanceof HTMLDetailsElement) return;
3040
- const header = this._headerOf(item);
3041
- const body = this._bodyOf(item);
3042
- if (!header) return;
3043
- header.setAttribute("aria-expanded", String(this._isOpen(item)));
3044
- if (body) {
3045
- if (!body.id) body.id = `collapsible-body-${Utils.guid()}`;
3046
- header.setAttribute("aria-controls", body.id);
3047
- }
3048
- if (!header.matches("a, button, summary")) {
3049
- header.setAttribute("role", "button");
3050
- if (header.tabIndex < 0) header.tabIndex = 0;
3051
- }
3052
- }
3053
- _setupEventHandlers() {
3054
- this.el.addEventListener("click", this._handleClick);
3055
- this.el.addEventListener("keydown", this._handleKeydown);
3056
- this.el.addEventListener("toggle", this._handleToggle, true);
3057
- }
3058
- _removeEventHandlers() {
3059
- this.el.removeEventListener("click", this._handleClick);
3060
- this.el.removeEventListener("keydown", this._handleKeydown);
3061
- this.el.removeEventListener("toggle", this._handleToggle, true);
3062
- }
3063
- _notify(item, opening) {
3064
- const start = opening ? this.options.onOpenStart : this.options.onCloseStart;
3065
- if (typeof start === "function") start.call(this, item);
3066
- const end = opening ? this.options.onOpenEnd : this.options.onCloseEnd;
3067
- if (typeof end !== "function") return;
3068
- const target = this._bodyOf(item) ?? item;
3069
- let done = false;
3070
- const finish = () => {
3071
- if (done) return;
3072
- done = true;
3073
- target.removeEventListener("transitionend", onEnd);
3074
- end.call(this, item);
3075
- };
3076
- const onEnd = (ev) => {
3077
- if (ev.target !== target) return;
3078
- finish();
3079
- };
3080
- target.addEventListener("transitionend", onEnd);
3081
- this._endTimers.push(window.setTimeout(finish, this._durationMs() + 50));
3082
- }
3083
- _durationMs() {
3084
- const raw = getComputedStyle(this.el).getPropertyValue("--md-comp-collapsible-duration").trim();
3085
- if (!raw) return 500;
3086
- if (raw.endsWith("ms")) return parseFloat(raw);
3087
- if (raw.endsWith("s")) return parseFloat(raw) * 1e3;
3088
- const n = parseFloat(raw);
3089
- return Number.isFinite(n) ? n : 500;
3090
- }
3091
- };
3092
-
3093
3137
  // src/ts/components/select.ts
3094
- var _defaults10 = {
3138
+ var _defaults9 = {
3095
3139
  classes: "",
3096
- dropdownOptions: {}
3140
+ menuOptions: {}
3097
3141
  };
3098
3142
  var FormSelect = class _FormSelect extends Component {
3099
3143
  constructor(el, options) {
@@ -3112,8 +3156,14 @@ var FormSelect = class _FormSelect extends Component {
3112
3156
  this._selectOptionElement(virtualOption);
3113
3157
  e.stopPropagation();
3114
3158
  };
3159
+ this._handleOptionFocus = (e) => {
3160
+ const target = e.target;
3161
+ if (!(target instanceof Element)) return;
3162
+ const li = target.closest('li[role="option"]');
3163
+ if (li?.id) this.input.setAttribute("aria-activedescendant", li.id);
3164
+ };
3115
3165
  this._handleInputClick = () => {
3116
- if (this.dropdown && this.dropdown.isOpen) {
3166
+ if (this.menu && this.menu.isOpen) {
3117
3167
  this._setValueToInput();
3118
3168
  this._setSelectedStates();
3119
3169
  }
@@ -3128,11 +3178,13 @@ var FormSelect = class _FormSelect extends Component {
3128
3178
  this.nativeTabIndex = this.el.tabIndex ?? -1;
3129
3179
  this.el.tabIndex = -1;
3130
3180
  this._values = [];
3131
- this._setupDropdown();
3181
+ this._createdWrapper = false;
3182
+ this._originalLabelFor = null;
3183
+ this._setupMenu();
3132
3184
  this._setupEventHandlers();
3133
3185
  }
3134
3186
  static get defaults() {
3135
- return _defaults10;
3187
+ return _defaults9;
3136
3188
  }
3137
3189
  /**
3138
3190
  * Initializes instances of FormSelect.
@@ -3147,36 +3199,48 @@ var FormSelect = class _FormSelect extends Component {
3147
3199
  }
3148
3200
  destroy() {
3149
3201
  this._removeEventHandlers();
3150
- this.dropdown?.destroy();
3151
- this._removeDropdown();
3202
+ this.menu?.destroy();
3203
+ this._removeMenu();
3204
+ this.el.tabIndex = this.nativeTabIndex;
3152
3205
  this.el["Expressive_FormSelect"] = void 0;
3153
3206
  }
3154
3207
  /**
3155
- * Re-read the native `<select>` and update the generated dropdown to match.
3208
+ * Re-read the native `<select>` and update the generated menu to match.
3156
3209
  *
3157
3210
  * Assigning `select.value` from script fires no `change` event, so nothing
3158
3211
  * else syncs the visible input text or the `.selected` state on the virtual
3159
- * options. Call this after mutating the underlying select programmatically.
3212
+ * options. Adding or removing `<option>`s also requires this — the menu is
3213
+ * rebuilt from the native list, the field and Menu instance stay put.
3160
3214
  */
3161
3215
  refresh() {
3216
+ if (!this.menuEl) return;
3217
+ this._rebuildOptions();
3162
3218
  this._setValueToInput();
3163
3219
  this._setSelectedStates();
3164
3220
  }
3165
3221
  _setupEventHandlers() {
3166
- this.dropdownOptions.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3167
- el.addEventListener("click", this._handleOptionClick);
3168
- el.addEventListener("keydown", this._handleOptionKeydown);
3169
- });
3222
+ this._setupOptionHandlers();
3170
3223
  this.el.addEventListener("change", this._handleSelectChange);
3171
3224
  this.input.addEventListener("click", this._handleInputClick);
3225
+ this.menuEl.addEventListener("focusin", this._handleOptionFocus);
3172
3226
  }
3173
3227
  _removeEventHandlers() {
3174
- this.dropdownOptions.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3228
+ this._removeOptionHandlers();
3229
+ this.el.removeEventListener("change", this._handleSelectChange);
3230
+ this.input?.removeEventListener("click", this._handleInputClick);
3231
+ this.menuEl?.removeEventListener("focusin", this._handleOptionFocus);
3232
+ }
3233
+ _setupOptionHandlers() {
3234
+ this.menuEl.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3235
+ el.addEventListener("click", this._handleOptionClick);
3236
+ el.addEventListener("keydown", this._handleOptionKeydown);
3237
+ });
3238
+ }
3239
+ _removeOptionHandlers() {
3240
+ this.menuEl?.querySelectorAll("li:not(.optgroup)").forEach((el) => {
3175
3241
  el.removeEventListener("click", this._handleOptionClick);
3176
3242
  el.removeEventListener("keydown", this._handleOptionKeydown);
3177
3243
  });
3178
- this.el.removeEventListener("change", this._handleSelectChange);
3179
- this.input.removeEventListener("click", this._handleInputClick);
3180
3244
  }
3181
3245
  _arraysEqual(a, b) {
3182
3246
  if (a === b) return true;
@@ -3188,6 +3252,7 @@ var FormSelect = class _FormSelect extends Component {
3188
3252
  _selectOptionElement(virtualOption) {
3189
3253
  if (!virtualOption.classList.contains("disabled") && !virtualOption.classList.contains("optgroup")) {
3190
3254
  const value = this._values.find((value2) => value2.optionEl === virtualOption);
3255
+ if (!value) return;
3191
3256
  const previousSelectedValues = this.getSelectedValues();
3192
3257
  if (this.isMultiple) {
3193
3258
  this._toggleEntryFromArray(value);
@@ -3203,73 +3268,57 @@ var FormSelect = class _FormSelect extends Component {
3203
3268
  new Event("change", { bubbles: true, cancelable: true, composed: true })
3204
3269
  );
3205
3270
  }
3206
- if (!this.isMultiple) this.dropdown.close();
3271
+ if (!this.isMultiple) this.menu?.close();
3207
3272
  }
3208
- _setupDropdown() {
3273
+ _setupMenu() {
3209
3274
  this.labelEl = this.el.labels?.[0] ?? null;
3210
- this.wrapper = document.createElement("div");
3211
- this.wrapper.classList.add("select-wrapper", "input-field");
3275
+ this._setupWrapper();
3276
+ this._hideNativeSelect();
3277
+ if (this.el.disabled) this.wrapper.classList.add("disabled");
3278
+ this.menuEl = document.createElement("menu");
3279
+ this.menuEl.id = `select-options-${Utils.guid()}`;
3280
+ this.menuEl.setAttribute("popover", "auto");
3281
+ this.menuEl.setAttribute("role", "listbox");
3282
+ this.menuEl.ariaMultiSelectable = this.isMultiple.toString();
3283
+ if (this.isMultiple) this.menuEl.classList.add("multiple-select-menu");
3284
+ this._buildOptions();
3285
+ this.wrapper.append(this.menuEl);
3286
+ this._buildInput();
3287
+ this._buildCaret();
3288
+ this._initMenu();
3289
+ this._setSelectedStates();
3290
+ if (this.labelEl) this.input.after(this.labelEl);
3291
+ }
3292
+ _setupWrapper() {
3293
+ const parent = this.el.parentElement;
3294
+ const reuse = parent && parent.matches(".field") && !parent.querySelector(":scope > .hide-select") && !parent.querySelector(":scope > input, :scope > textarea");
3295
+ if (reuse) {
3296
+ this.wrapper = parent;
3297
+ this._createdWrapper = false;
3298
+ } else {
3299
+ this.wrapper = document.createElement("div");
3300
+ this.wrapper.classList.add("field");
3301
+ this._createdWrapper = true;
3302
+ this.el.before(this.wrapper);
3303
+ }
3212
3304
  if (this.options.classes.length > 0) {
3213
3305
  this.wrapper.classList.add(...this.options.classes.split(" ").filter(Boolean));
3214
3306
  }
3215
- this.el.before(this.wrapper);
3307
+ }
3308
+ _hideNativeSelect() {
3216
3309
  const hiddenDiv = document.createElement("div");
3217
3310
  hiddenDiv.classList.add("hide-select");
3218
- this.wrapper.append(hiddenDiv);
3311
+ this.el.before(hiddenDiv);
3219
3312
  hiddenDiv.appendChild(this.el);
3220
- if (this.el.disabled) this.wrapper.classList.add("disabled");
3221
- this.selectOptions = Array.from(this.el.children).filter((el) => ["OPTION", "OPTGROUP"].includes(el.tagName));
3222
- this.dropdownOptions = document.createElement("ul");
3223
- this.dropdownOptions.id = `select-options-${Utils.guid()}`;
3224
- this.dropdownOptions.setAttribute("popover", "auto");
3225
- this.dropdownOptions.classList.add("dropdown-content", "select-dropdown");
3226
- this.dropdownOptions.setAttribute("role", "listbox");
3227
- this.dropdownOptions.ariaMultiSelectable = this.isMultiple.toString();
3228
- if (this.isMultiple) this.dropdownOptions.classList.add("multiple-select-dropdown");
3229
- if (this.selectOptions.length > 0) {
3230
- this.selectOptions.forEach((realOption) => {
3231
- if (realOption.tagName === "OPTION") {
3232
- const virtualOption = this._createAndAppendOptionWithIcon(
3233
- realOption,
3234
- this.isMultiple ? "multiple" : void 0
3235
- );
3236
- this._addOptionToValues(realOption, virtualOption);
3237
- } else if (realOption.tagName === "OPTGROUP") {
3238
- const groupId = "opt-group-" + Utils.guid();
3239
- const groupParent = document.createElement("li");
3240
- groupParent.classList.add("optgroup");
3241
- groupParent.tabIndex = -1;
3242
- groupParent.setAttribute("role", "group");
3243
- groupParent.setAttribute("aria-labelledby", groupId);
3244
- const groupLabel = document.createElement("span");
3245
- groupLabel.id = groupId;
3246
- groupLabel.setAttribute("role", "presentation");
3247
- groupLabel.textContent = realOption.getAttribute("label") ?? "";
3248
- groupParent.replaceChildren(groupLabel);
3249
- this.dropdownOptions.append(groupParent);
3250
- const groupChildren = [];
3251
- const selectOptions = Array.from(realOption.children).filter((el) => el.tagName === "OPTION");
3252
- selectOptions.forEach((realOption2) => {
3253
- const virtualOption = this._createAndAppendOptionWithIcon(
3254
- realOption2,
3255
- "optgroup-option"
3256
- );
3257
- const childId = "opt-child-" + Utils.guid();
3258
- virtualOption.id = childId;
3259
- groupChildren.push(childId);
3260
- this._addOptionToValues(realOption2, virtualOption);
3261
- });
3262
- groupParent.setAttribute("aria-owns", groupChildren.join(" "));
3263
- }
3264
- });
3265
- }
3266
- this.wrapper.append(this.dropdownOptions);
3313
+ this.wrapper.append(hiddenDiv);
3314
+ }
3315
+ _buildInput() {
3267
3316
  this.input = document.createElement("input");
3268
- this.input.id = "m_select-input-" + Utils.guid();
3269
- this.input.classList.add("select-dropdown", "dropdown-trigger");
3317
+ this.input.id = "select-input-" + Utils.guid();
3318
+ this.input.classList.add("menu-trigger");
3270
3319
  this.input.type = "text";
3271
3320
  this.input.readOnly = true;
3272
- this.input.setAttribute("data-target", this.dropdownOptions.id);
3321
+ this.input.setAttribute("data-target", this.menuEl.id);
3273
3322
  this.input.ariaReadOnly = "true";
3274
3323
  this.input.ariaRequired = this.el.hasAttribute("required").toString();
3275
3324
  if (this.el.disabled) this.input.disabled = true;
@@ -3280,71 +3329,131 @@ var FormSelect = class _FormSelect extends Component {
3280
3329
  if (attr.name.startsWith("aria-")) this.input.setAttribute(attr.name, attr.value);
3281
3330
  }
3282
3331
  this.input.setAttribute("role", "combobox");
3332
+ this.input.setAttribute("aria-haspopup", "listbox");
3283
3333
  this.input.ariaExpanded = "false";
3284
- this.input.setAttribute("aria-owns", this.dropdownOptions.id);
3285
- this.input.setAttribute("aria-controls", this.dropdownOptions.id);
3334
+ this.input.setAttribute("aria-controls", this.menuEl.id);
3286
3335
  this.input.placeholder = " ";
3336
+ if (this.labelEl) {
3337
+ this._originalLabelFor = this.labelEl.htmlFor;
3338
+ this.labelEl.htmlFor = this.input.id;
3339
+ }
3287
3340
  this.wrapper.prepend(this.input);
3288
3341
  this._setValueToInput();
3289
- const dropdownIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
3290
- dropdownIcon.classList.add("caret");
3291
- dropdownIcon.setAttribute("height", "24");
3292
- dropdownIcon.setAttribute("width", "24");
3293
- dropdownIcon.setAttribute("viewBox", "0 0 24 24");
3294
- dropdownIcon.ariaHidden = "true";
3295
- dropdownIcon.innerHTML = `<path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/>`;
3296
- this.wrapper.prepend(dropdownIcon);
3297
- if (!this.el.disabled) {
3298
- const dropdownOptions = { ...this.options.dropdownOptions };
3299
- dropdownOptions.coverTrigger = false;
3300
- const userOnOpenEnd = dropdownOptions.onOpenEnd;
3301
- const userOnCloseEnd = dropdownOptions.onCloseEnd;
3302
- dropdownOptions.onOpenEnd = () => {
3303
- const selectedOption = this.dropdownOptions.querySelector(".selected");
3304
- if (selectedOption) {
3305
- Utils.keyDown = true;
3306
- this.dropdown.focusedIndex = [...selectedOption.parentNode.children].indexOf(
3307
- selectedOption
3308
- );
3309
- this.dropdown._focusFocusedItem();
3310
- Utils.keyDown = false;
3311
- if (this.dropdown.isScrollable) {
3312
- let scrollOffset = selectedOption.getBoundingClientRect().top - this.dropdownOptions.getBoundingClientRect().top;
3313
- scrollOffset -= this.dropdownOptions.clientHeight / 2;
3314
- this.dropdownOptions.scrollTop = scrollOffset;
3315
- }
3342
+ }
3343
+ _buildCaret() {
3344
+ const caret = document.createElement("span");
3345
+ caret.classList.add("caret");
3346
+ caret.setAttribute("aria-hidden", "true");
3347
+ this.wrapper.prepend(caret);
3348
+ }
3349
+ _initMenu() {
3350
+ if (this.el.disabled) return;
3351
+ const menuOptions = { ...this.options.menuOptions };
3352
+ menuOptions.coverTrigger = false;
3353
+ const userOnOpenEnd = menuOptions.onOpenEnd;
3354
+ const userOnCloseEnd = menuOptions.onCloseEnd;
3355
+ menuOptions.onOpenEnd = () => {
3356
+ const selectedOption = this.menuEl.querySelector(".selected");
3357
+ if (selectedOption) {
3358
+ Utils.keyDown = true;
3359
+ this.menu.focusedIndex = [...selectedOption.parentNode.children].indexOf(selectedOption);
3360
+ this.menu._focusFocusedItem();
3361
+ Utils.keyDown = false;
3362
+ if (this.menu.isScrollable) {
3363
+ let scrollOffset = selectedOption.getBoundingClientRect().top - this.menuEl.getBoundingClientRect().top;
3364
+ scrollOffset -= this.menuEl.clientHeight / 2;
3365
+ this.menuEl.scrollTop = scrollOffset;
3316
3366
  }
3317
- this.input.ariaExpanded = "true";
3318
- if (userOnOpenEnd && typeof userOnOpenEnd === "function")
3319
- userOnOpenEnd.call(this.dropdown, this.el);
3320
- };
3321
- dropdownOptions.onCloseEnd = () => {
3322
- this.input.ariaExpanded = "false";
3323
- if (userOnCloseEnd && typeof userOnCloseEnd === "function")
3324
- userOnCloseEnd.call(this.dropdown, this.el);
3325
- };
3326
- dropdownOptions.closeOnClick = false;
3327
- this.dropdown = Dropdown.init(this.input, dropdownOptions);
3328
- }
3329
- this._setSelectedStates();
3330
- if (this.labelEl) this.input.after(this.labelEl);
3367
+ if (selectedOption.id) this.input.setAttribute("aria-activedescendant", selectedOption.id);
3368
+ }
3369
+ this.input.ariaExpanded = "true";
3370
+ if (userOnOpenEnd && typeof userOnOpenEnd === "function")
3371
+ userOnOpenEnd.call(this.menu, this.el);
3372
+ };
3373
+ menuOptions.onCloseEnd = () => {
3374
+ this.input.ariaExpanded = "false";
3375
+ this.input.removeAttribute("aria-activedescendant");
3376
+ if (userOnCloseEnd && typeof userOnCloseEnd === "function")
3377
+ userOnCloseEnd.call(this.menu, this.el);
3378
+ };
3379
+ menuOptions.closeOnClick = false;
3380
+ this.menu = Menu.init(this.input, menuOptions);
3381
+ }
3382
+ _nativeOptions() {
3383
+ return Array.from(this.el.children).filter((el) => ["OPTION", "OPTGROUP"].includes(el.tagName));
3384
+ }
3385
+ _buildOptions() {
3386
+ this.selectOptions = this._nativeOptions();
3387
+ this._values = [];
3388
+ this.selectOptions.forEach((realOption) => {
3389
+ if (realOption.tagName === "OPTION") {
3390
+ const virtualOption = this._createAndAppendOptionWithIcon(
3391
+ realOption,
3392
+ this.isMultiple ? "multiple" : void 0
3393
+ );
3394
+ this._addOptionToValues(realOption, virtualOption);
3395
+ } else if (realOption.tagName === "OPTGROUP") {
3396
+ const groupId = "opt-group-" + Utils.guid();
3397
+ const groupParent = document.createElement("li");
3398
+ groupParent.classList.add("optgroup");
3399
+ groupParent.tabIndex = -1;
3400
+ groupParent.setAttribute("role", "group");
3401
+ groupParent.setAttribute("aria-labelledby", groupId);
3402
+ const groupLabel = document.createElement("span");
3403
+ groupLabel.id = groupId;
3404
+ groupLabel.setAttribute("role", "presentation");
3405
+ groupLabel.textContent = realOption.getAttribute("label") ?? "";
3406
+ groupParent.replaceChildren(groupLabel);
3407
+ this.menuEl.append(groupParent);
3408
+ const groupChildren = [];
3409
+ const selectOptions = Array.from(realOption.children).filter((el) => el.tagName === "OPTION");
3410
+ selectOptions.forEach((child) => {
3411
+ const virtualOption = this._createAndAppendOptionWithIcon(child, "optgroup-option");
3412
+ groupChildren.push(virtualOption.id);
3413
+ this._addOptionToValues(child, virtualOption);
3414
+ });
3415
+ groupParent.setAttribute("aria-owns", groupChildren.join(" "));
3416
+ }
3417
+ });
3418
+ }
3419
+ _rebuildOptions() {
3420
+ this._removeOptionHandlers();
3421
+ this.menuEl.replaceChildren();
3422
+ this._buildOptions();
3423
+ this._setupOptionHandlers();
3424
+ this.menu?._makeMenuFocusable();
3331
3425
  }
3332
3426
  _addOptionToValues(realOption, virtualOption) {
3333
3427
  this._values.push({ el: realOption, optionEl: virtualOption });
3334
3428
  }
3335
- _removeDropdown() {
3336
- this.wrapper.querySelector(".caret").remove();
3337
- this.input.remove();
3338
- this.dropdownOptions.remove();
3339
- this.wrapper.before(this.el);
3340
- this.wrapper.remove();
3429
+ _removeMenu() {
3430
+ this.wrapper?.querySelector(":scope > .caret")?.remove();
3431
+ this.input?.remove();
3432
+ this.menuEl?.remove();
3433
+ const hide = this.el.parentElement;
3434
+ if (hide?.classList.contains("hide-select")) hide.replaceWith(this.el);
3435
+ if (this.labelEl && this._originalLabelFor !== null) {
3436
+ this.labelEl.htmlFor = this._originalLabelFor;
3437
+ }
3438
+ if (!this.wrapper) return;
3439
+ if (this._createdWrapper) {
3440
+ this.wrapper.replaceWith(this.el);
3441
+ } else {
3442
+ this.wrapper.classList.remove("disabled");
3443
+ if (this.options.classes.length > 0) {
3444
+ this.wrapper.classList.remove(...this.options.classes.split(" ").filter(Boolean));
3445
+ }
3446
+ }
3341
3447
  }
3342
3448
  _createAndAppendOptionWithIcon(realOption, type) {
3343
3449
  const li = document.createElement("li");
3450
+ li.id = "select-option-" + Utils.guid();
3344
3451
  li.setAttribute("role", "option");
3452
+ li.tabIndex = 0;
3345
3453
  if (realOption.disabled) {
3346
3454
  li.classList.add("disabled");
3347
3455
  li.ariaDisabled = "true";
3456
+ li.tabIndex = -1;
3348
3457
  }
3349
3458
  if (type === "optgroup-option") li.classList.add(type);
3350
3459
  const optionText = realOption.textContent;
@@ -3353,6 +3462,7 @@ var FormSelect = class _FormSelect extends Component {
3353
3462
  const label = document.createElement("label");
3354
3463
  const checkbox = document.createElement("input");
3355
3464
  checkbox.type = "checkbox";
3465
+ checkbox.tabIndex = -1;
3356
3466
  const labelText = document.createElement("span");
3357
3467
  labelText.textContent = optionText;
3358
3468
  label.append(checkbox, labelText);
@@ -3370,7 +3480,7 @@ var FormSelect = class _FormSelect extends Component {
3370
3480
  img.ariaHidden = "true";
3371
3481
  li.prepend(img);
3372
3482
  }
3373
- this.dropdownOptions.append(li);
3483
+ this.menuEl.append(li);
3374
3484
  return li;
3375
3485
  }
3376
3486
  _selectValue(value) {
@@ -3416,7 +3526,7 @@ var FormSelect = class _FormSelect extends Component {
3416
3526
  if (texts.length === 0) {
3417
3527
  const firstDisabledOption = this.el.querySelector("option:disabled");
3418
3528
  if (firstDisabledOption && firstDisabledOption.value === "") {
3419
- this.input.value = firstDisabledOption.innerText;
3529
+ this.input.value = firstDisabledOption.textContent;
3420
3530
  return;
3421
3531
  }
3422
3532
  }
@@ -3428,7 +3538,7 @@ var FormSelect = class _FormSelect extends Component {
3428
3538
  const cb = value.optionEl.querySelector('input[type="checkbox"]');
3429
3539
  if (cb) cb.checked = optionIsSelected;
3430
3540
  if (optionIsSelected) {
3431
- this._activateOption(this.dropdownOptions, value.optionEl);
3541
+ this._activateOption(this.menuEl, value.optionEl);
3432
3542
  } else {
3433
3543
  value.optionEl.classList.remove("selected");
3434
3544
  value.optionEl.ariaSelected = "false";
@@ -3438,7 +3548,7 @@ var FormSelect = class _FormSelect extends Component {
3438
3548
  _activateOption(ul, li) {
3439
3549
  if (!li) return;
3440
3550
  if (!this.isMultiple)
3441
- ul.querySelectorAll("li.selected").forEach((li2) => li2.classList.remove("selected"));
3551
+ ul.querySelectorAll("li.selected").forEach((row) => row.classList.remove("selected"));
3442
3552
  li.classList.add("selected");
3443
3553
  li.ariaSelected = "true";
3444
3554
  }
@@ -3448,7 +3558,7 @@ var FormSelect = class _FormSelect extends Component {
3448
3558
  };
3449
3559
 
3450
3560
  // src/ts/plugins/dockedDisplayPlugin.ts
3451
- var _defaults11 = {
3561
+ var _defaults10 = {
3452
3562
  margin: 5,
3453
3563
  transition: 10,
3454
3564
  duration: 250,
@@ -3497,7 +3607,7 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
3497
3607
  };
3498
3608
  this.el = el;
3499
3609
  this.options = {
3500
- ..._defaults11,
3610
+ ..._defaults10,
3501
3611
  ...options
3502
3612
  };
3503
3613
  this.container = document.createElement("div");
@@ -3518,7 +3628,7 @@ var DockedDisplayPlugin = class _DockedDisplayPlugin {
3518
3628
  };
3519
3629
 
3520
3630
  // src/ts/components/datepicker.ts
3521
- var _defaults12 = {
3631
+ var _defaults11 = {
3522
3632
  // the default output format for the input field value
3523
3633
  format: "mmm dd, yyyy",
3524
3634
  // Used to create date object from current input string
@@ -3724,7 +3834,6 @@ var _Datepicker = class _Datepicker extends Component {
3724
3834
  }
3725
3835
  }
3726
3836
  };
3727
- // Set input value to the selected date and close Datepicker
3728
3837
  this._finishSelection = () => {
3729
3838
  this.setInputValues();
3730
3839
  };
@@ -3784,7 +3893,7 @@ var _Datepicker = class _Datepicker extends Component {
3784
3893
  }
3785
3894
  }
3786
3895
  static get defaults() {
3787
- return _defaults12;
3896
+ return _defaults11;
3788
3897
  }
3789
3898
  /**
3790
3899
  * Initializes instances of Datepicker.
@@ -4280,7 +4389,7 @@ var _Datepicker = class _Datepicker extends Component {
4280
4389
  if (opts.yearRangeReverse) arr.reverse();
4281
4390
  const yearHtml = `<select class="datepicker-select orig-select-year" tabindex="-1">${arr.join("")}</select>`;
4282
4391
  const leftArrow = '<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"/><path d="M0-.5h24v24H0z" fill="none"/></svg>';
4283
- html += `<button class="month-prev${prev ? "" : " is-disabled"} btn" type="button">${leftArrow}</button>`;
4392
+ html += `<button class="month-prev${prev ? "" : " is-disabled"}" type="button">${leftArrow}</button>`;
4284
4393
  html += '<div class="selects-container">';
4285
4394
  if (opts.showMonthAfterYear) {
4286
4395
  html += yearHtml + monthHtml;
@@ -4289,7 +4398,7 @@ var _Datepicker = class _Datepicker extends Component {
4289
4398
  }
4290
4399
  html += "</div>";
4291
4400
  const rightArrow = '<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"/><path d="M0-.25h24v24H0z" fill="none"/></svg>';
4292
- html += `<button class="month-next${next ? "" : " is-disabled"} btn" type="button">${rightArrow}</button>`;
4401
+ html += `<button class="month-next${next ? "" : " is-disabled"}" type="button">${rightArrow}</button>`;
4293
4402
  return html += "</div>";
4294
4403
  }
4295
4404
  /**
@@ -4367,11 +4476,11 @@ var _Datepicker = class _Datepicker extends Component {
4367
4476
  const monthSelect = this.calendarEl.querySelector(".orig-select-month");
4368
4477
  FormSelect.init(yearSelect, {
4369
4478
  classes: "select-year",
4370
- dropdownOptions: { container: document.body, constrainWidth: false }
4479
+ menuOptions: { container: document.body, constrainWidth: false }
4371
4480
  });
4372
4481
  FormSelect.init(monthSelect, {
4373
4482
  classes: "select-month",
4374
- dropdownOptions: { container: document.body, constrainWidth: false }
4483
+ menuOptions: { container: document.body, constrainWidth: false }
4375
4484
  });
4376
4485
  yearSelect.addEventListener("change", this._handleYearChange);
4377
4486
  monthSelect.addEventListener("change", this._handleMonthChange);
@@ -4487,17 +4596,6 @@ var _Datepicker = class _Datepicker extends Component {
4487
4596
  this.el.parentElement.appendChild(dateInput);
4488
4597
  return dateInput;
4489
4598
  }
4490
- // deprecated
4491
- open() {
4492
- console.warn("Datepicker.open() is deprecated. Remove this method and wrap in modal yourself.");
4493
- return this;
4494
- }
4495
- close() {
4496
- console.warn(
4497
- "Datepicker.close() is deprecated. Remove this method and wrap in modal yourself."
4498
- );
4499
- return this;
4500
- }
4501
4599
  };
4502
4600
  _Datepicker._template = `
4503
4601
  <div class="datepicker-container">
@@ -4507,19 +4605,13 @@ _Datepicker._template = `
4507
4605
  </div>
4508
4606
  <div class="datepicker-calendar-container">
4509
4607
  <div class="datepicker-calendar"></div>
4510
- <div class="datepicker-footer">
4511
- <!--<button class="btn-flat datepicker-clear waves-effect" style="visibility: hidden;" type="button"></button>
4512
- <div class="confirmation-btns">
4513
- <button class="btn-flat datepicker-cancel waves-effect" type="button"></button>
4514
- <button class="btn-flat datepicker-done waves-effect" type="button"></button>
4515
- </div>-->
4516
- </div>
4608
+ <div class="datepicker-footer"></div>
4517
4609
  </div>
4518
4610
  </div>`;
4519
4611
  var Datepicker = _Datepicker;
4520
4612
 
4521
4613
  // src/ts/components/lightbox.ts
4522
- var _defaults13 = {
4614
+ var _defaults12 = {
4523
4615
  inDuration: 275,
4524
4616
  outDuration: 200,
4525
4617
  onOpenStart: null,
@@ -4638,7 +4730,7 @@ var Lightbox = class _Lightbox extends Component {
4638
4730
  this._setupEventHandlers();
4639
4731
  }
4640
4732
  static get defaults() {
4641
- return _defaults13;
4733
+ return _defaults12;
4642
4734
  }
4643
4735
  /**
4644
4736
  * Initializes instances of Lightbox.
@@ -4802,217 +4894,41 @@ var Lightbox = class _Lightbox extends Component {
4802
4894
  }
4803
4895
  };
4804
4896
 
4805
- // src/ts/components/modal.ts
4806
- var _defaults14 = {
4807
- opacity: 0.5,
4808
- inDuration: 250,
4809
- outDuration: 250,
4810
- onOpenStart: null,
4811
- onOpenEnd: null,
4812
- onCloseStart: null,
4813
- onCloseEnd: null,
4814
- preventScrolling: true,
4815
- dismissible: true,
4816
- startingTop: "4%",
4817
- endingTop: "10%"
4818
- };
4819
- var _Modal_static, createHtml_fn, createHtmlElement_fn;
4820
- var _Modal = class _Modal extends Component {
4897
+ // src/ts/components/parallax.ts
4898
+ var _defaults13 = {};
4899
+ var Parallax = class _Parallax extends Component {
4821
4900
  constructor(el, options) {
4822
- super(el, options, _Modal);
4823
- this.el["Expressive_Modal"] = this;
4901
+ super(el, options, _Parallax);
4902
+ this.el["Expressive_Parallax"] = this;
4824
4903
  this.options = {
4825
- ..._Modal.defaults,
4904
+ ..._Parallax.defaults,
4826
4905
  ...options
4827
4906
  };
4828
- this.el.tabIndex = 0;
4829
- this._setupEventHandlers();
4907
+ if (!this.el.querySelector("img, video")) {
4908
+ console.error("Parallax: no <img> or <video> to move inside the .parallax element");
4909
+ }
4830
4910
  }
4831
4911
  static get defaults() {
4832
- return _defaults14;
4912
+ return _defaults13;
4833
4913
  }
4834
4914
  static init(els, options = {}) {
4835
- return super.init(els, options, _Modal);
4915
+ return super.init(els, options, _Parallax);
4836
4916
  }
4837
4917
  static getInstance(el) {
4838
- return el["Expressive_Modal"];
4918
+ return el["Expressive_Parallax"];
4839
4919
  }
4840
4920
  destroy() {
4841
- }
4842
- _setupEventHandlers() {
4843
- }
4844
- _removeEventHandlers() {
4845
- }
4846
- _handleTriggerClick() {
4847
- }
4848
- _handleOverlayClick() {
4849
- }
4850
- _handleModalCloseClick() {
4851
- }
4852
- _handleKeydown() {
4853
- }
4854
- _handleFocus() {
4855
- }
4856
- open() {
4857
- return this;
4858
- }
4859
- close() {
4860
- return this;
4861
- }
4862
- static create(config) {
4863
- const isServer = false;
4864
- if (isServer) return __privateMethod(this, _Modal_static, createHtml_fn).call(this, config);
4865
- return __privateMethod(this, _Modal_static, createHtmlElement_fn).call(this, config);
4866
- }
4867
- };
4868
- _Modal_static = new WeakSet();
4869
- createHtml_fn = function(config) {
4870
- const title = config.header ? `<h2>${typeof config.header === "string" ? config.header : ""}</h2>` : "";
4871
- const actions = config.footer ? `<form method="dialog">${typeof config.footer === "string" ? config.footer : ""}</form>` : "";
4872
- return `<dialog id="${config.id}">
4873
- ${title}
4874
- <div>${typeof config.content === "string" ? config.content : ""}</div>
4875
- ${actions}
4876
- </dialog>`;
4877
- };
4878
- createHtmlElement_fn = function(config) {
4879
- const dialog = document.createElement("dialog");
4880
- dialog.id = config.id;
4881
- return dialog;
4882
- };
4883
- __privateAdd(_Modal, _Modal_static);
4884
- var Modal = _Modal;
4885
-
4886
- // src/ts/components/parallax.ts
4887
- var _defaults15 = {
4888
- responsiveThreshold: 0
4889
- };
4890
- var Parallax = class _Parallax extends Component {
4891
- constructor(el, options) {
4892
- super(el, options, _Parallax);
4893
- this.el["Expressive_Parallax"] = this;
4894
- this.options = {
4895
- ..._Parallax.defaults,
4896
- ...options
4897
- };
4898
- if (!this.el.querySelector("img, video")) {
4899
- console.error("Parallax: no <img> or <video> to move inside the .parallax element");
4900
- }
4901
- }
4902
- static get defaults() {
4903
- return _defaults15;
4904
- }
4905
- static init(els, options = {}) {
4906
- return super.init(els, options, _Parallax);
4907
- }
4908
- static getInstance(el) {
4909
- return el["Expressive_Parallax"];
4910
- }
4911
- destroy() {
4912
- this.el["Expressive_Parallax"] = void 0;
4913
- }
4914
- };
4915
-
4916
- // src/ts/components/pushpin.ts
4917
- var _defaults16 = {
4918
- top: 0,
4919
- bottom: Infinity,
4920
- offset: 0,
4921
- onPositionChange: null
4922
- };
4923
- var _Pushpin = class _Pushpin extends Component {
4924
- constructor(el, options) {
4925
- super(el, options, _Pushpin);
4926
- this.el["Expressive_Pushpin"] = this;
4927
- this.options = {
4928
- ..._Pushpin.defaults,
4929
- ...options
4930
- };
4931
- this.originalOffset = this.el.offsetTop;
4932
- _Pushpin._pushpins.push(this);
4933
- this._setupEventHandlers();
4934
- this._updatePosition();
4935
- }
4936
- static get defaults() {
4937
- return _defaults16;
4938
- }
4939
- /**
4940
- * Initializes instances of Pushpin.
4941
- * @param els HTML elements.
4942
- * @param options Component options.
4943
- */
4944
- static init(els, options = {}) {
4945
- return super.init(els, options, _Pushpin);
4946
- }
4947
- static getInstance(el) {
4948
- return el["Expressive_Pushpin"];
4949
- }
4950
- destroy() {
4951
- this.el.style.top = null;
4952
- this._removePinClasses();
4953
- const index = _Pushpin._pushpins.indexOf(this);
4954
- _Pushpin._pushpins.splice(index, 1);
4955
- if (_Pushpin._pushpins.length === 0) {
4956
- this._removeEventHandlers();
4957
- }
4958
- this.el["Expressive_Pushpin"] = void 0;
4959
- }
4960
- static _updateElements() {
4961
- for (let i = 0; i < _Pushpin._pushpins.length; i++) {
4962
- _Pushpin._pushpins[i]._updatePosition();
4963
- }
4964
- }
4965
- _setupEventHandlers() {
4966
- document.addEventListener("scroll", _Pushpin._updateElements, { passive: true });
4967
- }
4968
- _removeEventHandlers() {
4969
- document.removeEventListener("scroll", _Pushpin._updateElements);
4970
- }
4971
- _updatePosition() {
4972
- const scrolled = Utils.getDocumentScrollTop() + this.options.offset;
4973
- if (this.options.top <= scrolled && this.options.bottom >= scrolled && !this.el.classList.contains("pinned")) {
4974
- this._removePinClasses();
4975
- this.el.style.top = `${this.options.offset}px`;
4976
- this.el.classList.add("pinned");
4977
- if (typeof this.options.onPositionChange === "function") {
4978
- this.options.onPositionChange.call(this, "pinned");
4979
- }
4980
- }
4981
- if (scrolled < this.options.top && !this.el.classList.contains("pin-top")) {
4982
- this._removePinClasses();
4983
- this.el.style.top = "0";
4984
- this.el.classList.add("pin-top");
4985
- if (typeof this.options.onPositionChange === "function") {
4986
- this.options.onPositionChange.call(this, "pin-top");
4987
- }
4988
- }
4989
- if (scrolled > this.options.bottom && !this.el.classList.contains("pin-bottom")) {
4990
- this._removePinClasses();
4991
- this.el.classList.add("pin-bottom");
4992
- this.el.style.top = `${this.options.bottom - this.originalOffset}px`;
4993
- if (typeof this.options.onPositionChange === "function") {
4994
- this.options.onPositionChange.call(this, "pin-bottom");
4995
- }
4996
- }
4997
- }
4998
- _removePinClasses() {
4999
- this.el.classList.remove("pin-top", "pinned", "pin-bottom");
4921
+ this.el["Expressive_Parallax"] = void 0;
5000
4922
  }
5001
4923
  };
5002
- _Pushpin._pushpins = [];
5003
- var Pushpin = _Pushpin;
5004
4924
 
5005
4925
  // src/ts/components/scrollspy.ts
5006
- var _defaults17 = {
5007
- throttle: 100,
4926
+ var _defaultGetActiveElement = (id) => `a[href="#${id}"]`;
4927
+ var _defaults14 = {
5008
4928
  scrollOffset: 200,
5009
- // offset - 200 allows elements near bottom of page to scroll
5010
4929
  activeClass: "active",
5011
- getActiveElement: (id) => {
5012
- return 'a[href="#' + id + '"]';
5013
- },
5014
- keepTopElementActive: false,
5015
- animationDuration: null
4930
+ getActiveElement: _defaultGetActiveElement,
4931
+ keepTopElementActive: false
5016
4932
  };
5017
4933
  var _ScrollSpy = class _ScrollSpy extends Component {
5018
4934
  constructor(el, options) {
@@ -5022,22 +4938,17 @@ var _ScrollSpy = class _ScrollSpy extends Component {
5022
4938
  ..._ScrollSpy.defaults,
5023
4939
  ...options
5024
4940
  };
4941
+ this.el.style.setProperty(
4942
+ "--md-comp-scrollspy-offset",
4943
+ `${this.options.scrollOffset}px`
4944
+ );
5025
4945
  _ScrollSpy._elements.push(this);
5026
- _ScrollSpy._count++;
5027
- _ScrollSpy._increment++;
5028
- this.tickId = -1;
5029
- this.id = _ScrollSpy._increment.toString();
5030
- this._setupEventHandlers();
5031
- _ScrollSpy._handleWindowScroll();
4946
+ _ScrollSpy._ensureObserver(this.options.scrollOffset);
4947
+ _ScrollSpy._observer?.observe(this.el);
5032
4948
  }
5033
4949
  static get defaults() {
5034
- return _defaults17;
4950
+ return _defaults14;
5035
4951
  }
5036
- /**
5037
- * Initializes instances of ScrollSpy.
5038
- * @param els HTML elements.
5039
- * @param options Component options.
5040
- */
5041
4952
  static init(els, options = {}) {
5042
4953
  return super.init(els, options, _ScrollSpy);
5043
4954
  }
@@ -5045,348 +4956,233 @@ var _ScrollSpy = class _ScrollSpy extends Component {
5045
4956
  return el["Expressive_ScrollSpy"];
5046
4957
  }
5047
4958
  destroy() {
5048
- const elementIndex = _ScrollSpy._elements.indexOf(this);
5049
- if (elementIndex >= 0) _ScrollSpy._elements.splice(elementIndex, 1);
5050
- const inViewIndex = _ScrollSpy._elementsInView.indexOf(this);
5051
- if (inViewIndex >= 0) _ScrollSpy._elementsInView.splice(inViewIndex, 1);
5052
- const visibleIndex = _ScrollSpy._visibleElements.indexOf(this.el);
5053
- if (visibleIndex >= 0) _ScrollSpy._visibleElements.splice(visibleIndex, 1);
5054
- _ScrollSpy._count--;
5055
- this._removeEventHandlers();
5056
- const actElem = document.querySelector(this.options.getActiveElement(this.el.id));
5057
- actElem?.classList.remove(this.options.activeClass);
5058
- this.el["Expressive_ScrollSpy"] = void 0;
5059
- }
5060
- _setupEventHandlers() {
5061
- if (_ScrollSpy._count === 1) {
5062
- _ScrollSpy._throttledScroll = Utils.throttle(_ScrollSpy._handleWindowScroll, this.options.throttle);
5063
- _ScrollSpy._throttledResize = Utils.throttle(_ScrollSpy._handleWindowScroll, 200);
5064
- window.addEventListener("scroll", _ScrollSpy._throttledScroll, { passive: true });
5065
- window.addEventListener("resize", _ScrollSpy._throttledResize, { passive: true });
5066
- document.body.addEventListener("click", _ScrollSpy._handleTriggerClick);
5067
- }
5068
- }
5069
- _removeEventHandlers() {
5070
- if (_ScrollSpy._count === 0) {
5071
- window.removeEventListener("scroll", _ScrollSpy._throttledScroll);
5072
- window.removeEventListener("resize", _ScrollSpy._throttledResize);
5073
- document.body.removeEventListener("click", _ScrollSpy._handleTriggerClick);
5074
- _ScrollSpy._throttledScroll = null;
5075
- _ScrollSpy._throttledResize = null;
4959
+ const index = _ScrollSpy._elements.indexOf(this);
4960
+ if (index >= 0) _ScrollSpy._elements.splice(index, 1);
4961
+ _ScrollSpy._ratios.delete(this.el);
4962
+ _ScrollSpy._observer?.unobserve(this.el);
4963
+ const link = _ScrollSpy._linkFor(this.el.id, this.options);
4964
+ if (link && link === _ScrollSpy._active) {
4965
+ _ScrollSpy._clearActive(this.options);
4966
+ } else {
4967
+ link?.classList.remove(this.options.activeClass);
4968
+ link?.removeAttribute("aria-current");
4969
+ }
4970
+ if (_ScrollSpy._elements.length === 0) {
4971
+ _ScrollSpy._observer?.disconnect();
4972
+ _ScrollSpy._observer = null;
4973
+ _ScrollSpy._ratios.clear();
4974
+ _ScrollSpy._active = null;
4975
+ } else {
4976
+ _ScrollSpy._syncActive();
5076
4977
  }
4978
+ this.el["Expressive_ScrollSpy"] = void 0;
5077
4979
  }
5078
- static _findElements(top, right, bottom, left) {
5079
- const hits = [];
5080
- const docElem = document.documentElement;
5081
- const clientTop = docElem.clientTop;
5082
- const clientLeft = docElem.clientLeft;
5083
- const scrollY = window.scrollY;
5084
- const scrollX = window.scrollX;
5085
- for (let i = 0; i < _ScrollSpy._elements.length; i++) {
5086
- const scrollspy = _ScrollSpy._elements[i];
5087
- const currTop = top + scrollspy.options.scrollOffset || 200;
5088
- const box = scrollspy.el.getBoundingClientRect();
5089
- if (box.height > 0) {
5090
- const elTop = box.top + scrollY - clientTop, elLeft = box.left + scrollX - clientLeft, elRight = elLeft + box.width, elBottom = elTop + box.height;
5091
- const isIntersect = !(elLeft > right || elRight < left || elTop > bottom || elBottom < currTop);
5092
- if (isIntersect) {
5093
- hits.push(scrollspy);
5094
- }
5095
- }
5096
- }
5097
- return hits;
4980
+ static _ensureObserver(offset) {
4981
+ if (_ScrollSpy._observer) return;
4982
+ if (typeof IntersectionObserver === "undefined") return;
4983
+ _ScrollSpy._observer = new IntersectionObserver(_ScrollSpy._onIntersect, {
4984
+ rootMargin: `-${offset}px 0px -45% 0px`,
4985
+ threshold: [0, 0.1, 0.25, 0.5, 0.75, 1]
4986
+ });
5098
4987
  }
5099
- _enter() {
5100
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter(
5101
- (value) => value.getBoundingClientRect().height !== 0
5102
- );
5103
- if (_ScrollSpy._visibleElements[0]) {
5104
- const actElem = document.querySelector(
5105
- this.options.getActiveElement(_ScrollSpy._visibleElements[0].id)
5106
- );
5107
- actElem?.classList.remove(this.options.activeClass);
5108
- if (_ScrollSpy._visibleElements[0]["Expressive_ScrollSpy"] && this.id < _ScrollSpy._visibleElements[0]["Expressive_ScrollSpy"].id) {
5109
- _ScrollSpy._visibleElements.unshift(this.el);
4988
+ static _syncActive() {
4989
+ if (!_ScrollSpy._elements.length) return;
4990
+ const options = _ScrollSpy._elements[0].options;
4991
+ let best = null;
4992
+ let bestRatio = 0;
4993
+ for (const spy of _ScrollSpy._elements) {
4994
+ const ratio = _ScrollSpy._ratios.get(spy.el) ?? 0;
4995
+ if (ratio > bestRatio) {
4996
+ bestRatio = ratio;
4997
+ best = spy;
4998
+ }
4999
+ }
5000
+ if (!best) {
5001
+ if (options.keepTopElementActive) {
5002
+ best = _ScrollSpy._nearestAbove() ?? _ScrollSpy._elements[0];
5110
5003
  } else {
5111
- _ScrollSpy._visibleElements.push(this.el);
5004
+ _ScrollSpy._clearActive(options);
5005
+ return;
5112
5006
  }
5113
- } else {
5114
- _ScrollSpy._visibleElements.push(this.el);
5115
5007
  }
5116
- _ScrollSpy._resetKeptTopActiveElement(this.options.activeClass);
5117
- const selector = this.options.getActiveElement(_ScrollSpy._visibleElements[0].id);
5118
- document.querySelector(selector)?.classList.add(this.options.activeClass);
5008
+ const next = _ScrollSpy._linkFor(best.el.id, best.options);
5009
+ if (next === _ScrollSpy._active) return;
5010
+ _ScrollSpy._clearActive(options);
5011
+ if (!next) return;
5012
+ next.classList.add(best.options.activeClass);
5013
+ next.setAttribute("aria-current", "true");
5014
+ _ScrollSpy._active = next;
5119
5015
  }
5120
- _exit() {
5121
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter(
5122
- (value) => value.getBoundingClientRect().height !== 0
5123
- );
5124
- if (_ScrollSpy._visibleElements[0]) {
5125
- const actElem = document.querySelector(
5126
- this.options.getActiveElement(_ScrollSpy._visibleElements[0].id)
5127
- );
5128
- actElem?.classList.remove(this.options.activeClass);
5129
- _ScrollSpy._visibleElements = _ScrollSpy._visibleElements.filter((x) => x.id != this.el.id);
5130
- if (_ScrollSpy._visibleElements[0]) {
5131
- const selector = this.options.getActiveElement(_ScrollSpy._visibleElements[0].id);
5132
- document.querySelector(selector)?.classList.add(this.options.activeClass);
5133
- _ScrollSpy._resetKeptTopActiveElement(this.options.activeClass);
5134
- }
5135
- }
5136
- }
5137
- static _resetKeptTopActiveElement(activeClass) {
5138
- if (_ScrollSpy._keptTopActiveElement) {
5139
- _ScrollSpy._keptTopActiveElement.classList.remove(activeClass);
5140
- _ScrollSpy._keptTopActiveElement = null;
5141
- }
5142
- }
5143
- static _getDistanceToViewport(element) {
5144
- const rect = element.getBoundingClientRect();
5145
- const distance = rect.top;
5146
- return distance;
5147
- }
5148
- static _smoothScrollIntoView(element, duration = 300) {
5149
- const targetPosition = element.getBoundingClientRect().top + (window.scrollY || window.pageYOffset);
5150
- const startPosition = window.scrollY || window.pageYOffset;
5151
- const distance = targetPosition - startPosition;
5152
- const startTime = performance.now();
5153
- function scrollStep(currentTime) {
5154
- const elapsed = currentTime - startTime;
5155
- const progress = Math.min(elapsed / duration, 1);
5156
- const scrollY = startPosition + distance * progress;
5157
- if (progress < 1) {
5158
- window.scrollTo(0, scrollY);
5159
- requestAnimationFrame(scrollStep);
5160
- } else {
5161
- window.scrollTo(0, targetPosition);
5016
+ static _nearestAbove() {
5017
+ let best = null;
5018
+ let bestTop = -Infinity;
5019
+ for (const spy of _ScrollSpy._elements) {
5020
+ const top = spy.el.getBoundingClientRect().top;
5021
+ if (top <= 0 && top >= bestTop) {
5022
+ bestTop = top;
5023
+ best = spy;
5162
5024
  }
5163
5025
  }
5164
- requestAnimationFrame(scrollStep);
5026
+ return best;
5165
5027
  }
5166
- };
5167
- _ScrollSpy._keptTopActiveElement = null;
5168
- // The document-level listeners are shared by every instance, so the
5169
- // references they are registered with have to be shared too - registering
5170
- // with one instance's bound handler and unregistering with another's is a
5171
- // silent no-op that leaves the listener attached forever.
5172
- _ScrollSpy._throttledScroll = null;
5173
- _ScrollSpy._throttledResize = null;
5174
- _ScrollSpy._handleTriggerClick = (e) => {
5175
- const trigger = e.target;
5176
- for (let i = _ScrollSpy._elements.length - 1; i >= 0; i--) {
5177
- const scrollspy = _ScrollSpy._elements[i];
5178
- const x = document.querySelector('a[href="#' + scrollspy.el.id + '"]');
5179
- if (trigger === x) {
5180
- e.preventDefault();
5181
- if (scrollspy.el["Expressive_ScrollSpy"].options.animationDuration) {
5182
- _ScrollSpy._smoothScrollIntoView(
5183
- scrollspy.el,
5184
- scrollspy.el["Expressive_ScrollSpy"].options.animationDuration
5185
- );
5186
- } else {
5187
- scrollspy.el.scrollIntoView({ behavior: "smooth" });
5028
+ static _clearActive(options) {
5029
+ if (!_ScrollSpy._active) return;
5030
+ _ScrollSpy._active.classList.remove(options.activeClass);
5031
+ _ScrollSpy._active.removeAttribute("aria-current");
5032
+ _ScrollSpy._active = null;
5033
+ }
5034
+ /**
5035
+ * Default lookup compares href attributes (no interpolated selector).
5036
+ * A custom getActiveElement still returns a selector.
5037
+ */
5038
+ static _linkFor(id, options) {
5039
+ if (!id) return null;
5040
+ if (options.getActiveElement !== _defaultGetActiveElement) {
5041
+ try {
5042
+ return document.querySelector(options.getActiveElement(id));
5043
+ } catch {
5044
+ return null;
5188
5045
  }
5189
- break;
5190
5046
  }
5047
+ const href = `#${id}`;
5048
+ const links = document.querySelectorAll('a[href^="#"]');
5049
+ for (let i = 0; i < links.length; i++) {
5050
+ if (links[i].getAttribute("href") === href) return links[i];
5051
+ }
5052
+ return null;
5191
5053
  }
5192
5054
  };
5193
- _ScrollSpy._handleWindowScroll = () => {
5194
- _ScrollSpy._ticks++;
5195
- const top = Utils.getDocumentScrollTop(), left = Utils.getDocumentScrollLeft(), right = left + window.innerWidth, bottom = top + window.innerHeight;
5196
- const intersections = _ScrollSpy._findElements(top, right, bottom, left);
5197
- for (let i = 0; i < intersections.length; i++) {
5198
- const scrollspy = intersections[i];
5199
- const lastTick = scrollspy.tickId;
5200
- if (lastTick < 0) {
5201
- scrollspy._enter();
5202
- }
5203
- scrollspy.tickId = _ScrollSpy._ticks;
5204
- }
5205
- for (let i = 0; i < _ScrollSpy._elementsInView.length; i++) {
5206
- const scrollspy = _ScrollSpy._elementsInView[i];
5207
- const lastTick = scrollspy.tickId;
5208
- if (lastTick >= 0 && lastTick !== _ScrollSpy._ticks) {
5209
- scrollspy._exit();
5210
- scrollspy.tickId = -1;
5211
- }
5212
- }
5213
- _ScrollSpy._elementsInView = intersections;
5214
- if (_ScrollSpy._elements.length) {
5215
- const options = _ScrollSpy._elements[0].el["Expressive_ScrollSpy"].options;
5216
- if (options.keepTopElementActive && _ScrollSpy._visibleElements.length === 0) {
5217
- _ScrollSpy._resetKeptTopActiveElement(options.activeClass);
5218
- const topElements = _ScrollSpy._elements.map((value) => ({ value, distance: _ScrollSpy._getDistanceToViewport(value.el) })).filter((entry) => entry.distance <= 0).sort((a, b) => a.distance - b.distance).map((entry) => entry.value);
5219
- const nearestTopElement = topElements.length ? topElements[topElements.length - 1] : _ScrollSpy._elements[0];
5220
- const actElem = document.querySelector(options.getActiveElement(nearestTopElement.el.id));
5221
- actElem?.classList.add(options.activeClass);
5222
- _ScrollSpy._keptTopActiveElement = actElem;
5055
+ _ScrollSpy._elements = [];
5056
+ _ScrollSpy._observer = null;
5057
+ _ScrollSpy._ratios = /* @__PURE__ */ new Map();
5058
+ _ScrollSpy._active = null;
5059
+ _ScrollSpy._onIntersect = (entries) => {
5060
+ for (const entry of entries) {
5061
+ if (entry.isIntersecting && entry.intersectionRatio > 0) {
5062
+ _ScrollSpy._ratios.set(entry.target, entry.intersectionRatio);
5063
+ } else {
5064
+ _ScrollSpy._ratios.delete(entry.target);
5223
5065
  }
5224
5066
  }
5067
+ _ScrollSpy._syncActive();
5225
5068
  };
5226
- _ScrollSpy._elements = [];
5227
- _ScrollSpy._elementsInView = [];
5228
- _ScrollSpy._visibleElements = [];
5229
- _ScrollSpy._count = 0;
5230
- _ScrollSpy._increment = 0;
5231
- _ScrollSpy._ticks = 0;
5232
5069
  var ScrollSpy = _ScrollSpy;
5233
5070
 
5234
5071
  // src/ts/components/sidenav.ts
5235
- var _defaults18 = {
5072
+ var _defaults15 = {
5236
5073
  edge: "left",
5237
5074
  draggable: true,
5238
5075
  dragTargetWidth: "10px",
5239
- inDuration: 250,
5240
- outDuration: 200,
5241
5076
  onOpenStart: null,
5242
5077
  onOpenEnd: null,
5243
5078
  onCloseStart: null,
5244
- onCloseEnd: null,
5245
- preventScrolling: true
5079
+ onCloseEnd: null
5246
5080
  };
5081
+ var LARGE_UP = "(width >= 993px)";
5247
5082
  var _Sidenav = class _Sidenav extends Component {
5248
5083
  constructor(el, options) {
5249
5084
  super(el, options, _Sidenav);
5250
- this._handleDragTargetDrag = (e) => {
5251
- if (!this._isDraggable()) return;
5252
- let totalDeltaX = this._calculateDelta(e);
5253
- const dragDirection = totalDeltaX > 0 ? "right" : "left";
5254
- totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
5255
- if (this.options.edge === dragDirection) {
5256
- totalDeltaX = 0;
5257
- }
5258
- let transformX = totalDeltaX;
5259
- let transformPrefix = "translateX(-100%)";
5260
- if (this.options.edge === "right") {
5261
- transformPrefix = "translateX(100%)";
5262
- transformX = -transformX;
5263
- }
5264
- this.percentOpen = Math.min(1, totalDeltaX / this._width);
5265
- this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`;
5266
- this._overlay.style.opacity = this.percentOpen.toString();
5267
- };
5268
- this._handleDragTargetRelease = () => {
5269
- if (this.isDragged) {
5270
- if (this.percentOpen > 0.2) {
5271
- this.open();
5272
- } else {
5273
- this._animateOut();
5085
+ /**
5086
+ * Opens the overlay drawer. No-op while the sidenav is docked
5087
+ * (sidenav-fixed at the large breakpoint).
5088
+ */
5089
+ this.open = () => {
5090
+ if (this._isCurrentlyFixed() || this.isOpen || !this._dialog) return;
5091
+ _Sidenav._sidenavs.forEach((other) => {
5092
+ if (other !== this && other.isOpen) other.close();
5093
+ });
5094
+ if (typeof this.options.onOpenStart === "function") {
5095
+ this.options.onOpenStart.call(this, this.el);
5096
+ }
5097
+ this.isOpen = true;
5098
+ this._dialog.classList.remove("dragging");
5099
+ this._clearShift();
5100
+ if (!this._dialog.open) {
5101
+ try {
5102
+ this._dialog.showModal();
5103
+ } catch {
5274
5104
  }
5275
- this.isDragged = false;
5276
- this._verticallyScrolling = false;
5277
5105
  }
5278
- };
5279
- this._handleCloseDrag = (e) => {
5280
- if (!this.isOpen || !this._isDraggable()) return;
5281
- let totalDeltaX = this._calculateDelta(e);
5282
- const dragDirection = totalDeltaX > 0 ? "right" : "left";
5283
- totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
5284
- if (this.options.edge !== dragDirection) {
5285
- totalDeltaX = 0;
5106
+ this._syncTriggers();
5107
+ if (typeof this.options.onOpenEnd === "function") {
5108
+ this.options.onOpenEnd.call(this, this.el);
5286
5109
  }
5287
- let transformX = -totalDeltaX;
5288
- if (this.options.edge === "right") {
5289
- transformX = -transformX;
5110
+ };
5111
+ /**
5112
+ * Closes the overlay drawer. No-op while the sidenav is docked.
5113
+ */
5114
+ this.close = () => {
5115
+ if (this._isCurrentlyFixed() || !this.isOpen) return;
5116
+ this._beginClose();
5117
+ if (this._dialog?.open) {
5118
+ this._closing = true;
5119
+ this._dialog.close();
5120
+ } else {
5121
+ this._finishClose();
5290
5122
  }
5291
- this.percentOpen = Math.min(1, 1 - totalDeltaX / this._width);
5292
- this.el.style.transform = `translateX(${transformX}px)`;
5293
- this._overlay.style.opacity = this.percentOpen.toString();
5294
5123
  };
5295
- this._calculateDelta = (e) => {
5296
- if (!this.isDragged) {
5297
- this._startDrag(e);
5124
+ this._onDialogClose = () => {
5125
+ if (this.isOpen) {
5126
+ this._beginClose();
5127
+ this._finishClose();
5128
+ return;
5129
+ }
5130
+ if (this._closing) {
5131
+ this._closing = false;
5132
+ this._finishClose();
5298
5133
  }
5299
- this._dragMoveUpdate(e);
5300
- return this._xPos - this._startingXpos;
5301
5134
  };
5302
- this._handleCloseRelease = () => {
5303
- if (this.isOpen && this.isDragged) {
5304
- if (this.percentOpen > 0.8) {
5305
- this._animateIn();
5306
- } else {
5307
- this.close();
5308
- }
5309
- this.isDragged = false;
5310
- this._verticallyScrolling = false;
5135
+ this._onBreakpointChange = () => {
5136
+ if (this._isCurrentlyFixed() && this.isOpen) {
5137
+ this.close();
5311
5138
  }
5312
5139
  };
5313
- // Handles closing of Sidenav when element with class .sidenav-close
5314
5140
  this._handleCloseTriggerClick = (e) => {
5315
- const closeTrigger = e.target.closest(".sidenav-close");
5141
+ const target = e.target;
5142
+ if (!(target instanceof Element)) return;
5143
+ const closeTrigger = target.closest(".sidenav-close");
5316
5144
  if (closeTrigger && !this._isCurrentlyFixed()) {
5317
5145
  this.close();
5318
5146
  }
5319
5147
  };
5320
- this._handleWindowResize = () => {
5321
- if (this.lastWindowWidth !== window.innerWidth) {
5322
- if (window.innerWidth > 992) {
5323
- this.open();
5324
- } else {
5325
- this.close();
5326
- }
5327
- }
5328
- this.lastWindowWidth = window.innerWidth;
5329
- this.lastWindowHeight = window.innerHeight;
5148
+ this._handleDragTargetDrag = (e) => {
5149
+ if (!this._isDraggable()) return;
5150
+ const delta = this._rawDelta(e);
5151
+ const towardOpen = this.options.edge === "left" ? delta : -delta;
5152
+ const visible = Math.min(this._width, Math.max(0, towardOpen));
5153
+ const percentOpen = this._width ? visible / this._width : 0;
5154
+ this._applyShift(visible - this._width, percentOpen);
5330
5155
  };
5331
- /**
5332
- * Opens Sidenav.
5333
- */
5334
- this.open = () => {
5335
- if (this.isOpen === true) return;
5336
- this.isOpen = true;
5337
- if (typeof this.options.onOpenStart === "function") {
5338
- this.options.onOpenStart.call(this, this.el);
5339
- }
5340
- if (this._isCurrentlyFixed()) {
5341
- this.el.style.transform = "translateX(0)";
5342
- this._enableBodyScrolling();
5343
- this._overlay.style.display = "none";
5344
- } else {
5345
- if (this.options.preventScrolling) this._preventBodyScrolling();
5346
- if (!this.isDragged || this.percentOpen != 1) this._animateIn();
5347
- this._setAriaHidden();
5348
- this._setTabIndex();
5156
+ this._handleDragTargetRelease = () => {
5157
+ if (!this.isDragged) return;
5158
+ this._dialog?.classList.remove("dragging");
5159
+ if (this.percentOpen > 0.2) {
5160
+ this.open();
5161
+ } else if (this._dialog?.open && !this.isOpen) {
5162
+ this._clearShift();
5163
+ this._dialog.close();
5349
5164
  }
5165
+ this.isDragged = false;
5166
+ this._verticallyScrolling = false;
5350
5167
  };
5351
- /**
5352
- * Closes Sidenav.
5353
- */
5354
- this.close = () => {
5355
- if (this.isOpen === false) return;
5356
- this.isOpen = false;
5357
- if (typeof this.options.onCloseStart === "function") {
5358
- this.options.onCloseStart.call(this, this.el);
5359
- }
5360
- if (this._isCurrentlyFixed()) {
5361
- const transformX = this.options.edge === "left" ? "-105%" : "105%";
5362
- this.el.style.transform = `translateX(${transformX})`;
5168
+ this._handleCloseDrag = (e) => {
5169
+ if (!this.isOpen || !this._isDraggable()) return;
5170
+ const delta = this._rawDelta(e);
5171
+ const towardClose = this.options.edge === "left" ? -delta : delta;
5172
+ const hidden = Math.min(this._width, Math.max(0, towardClose));
5173
+ const percentOpen = this._width ? 1 - hidden / this._width : 1;
5174
+ this._applyShift(-hidden, percentOpen);
5175
+ };
5176
+ this._handleCloseRelease = () => {
5177
+ if (!this.isOpen || !this.isDragged) return;
5178
+ this._dialog?.classList.remove("dragging");
5179
+ if (this.percentOpen > 0.8) {
5180
+ this._clearShift();
5363
5181
  } else {
5364
- this._enableBodyScrolling();
5365
- if (!this.isDragged || this.percentOpen != 0) {
5366
- this._animateOut();
5367
- } else {
5368
- this._overlay.style.display = "none";
5369
- }
5370
- this._setAriaHidden();
5371
- this._setTabIndex();
5182
+ this.close();
5372
5183
  }
5373
- };
5374
- this._setAriaHidden = () => {
5375
- this.el.ariaHidden = this.isOpen ? "false" : "true";
5376
- const navWrapper = document.querySelector(".nav-wrapper ul");
5377
- if (navWrapper) navWrapper.ariaHidden = this.isOpen.toString();
5378
- };
5379
- this._setTabIndex = () => {
5380
- const navLinks = document.querySelectorAll(".nav-wrapper ul li a");
5381
- const sideNavLinks = document.querySelectorAll(".sidenav li a");
5382
- if (navLinks)
5383
- navLinks.forEach((navLink) => {
5384
- navLink.tabIndex = this.isOpen ? -1 : 0;
5385
- });
5386
- if (sideNavLinks)
5387
- sideNavLinks.forEach((sideNavLink) => {
5388
- sideNavLink.tabIndex = this.isOpen ? 0 : -1;
5389
- });
5184
+ this.isDragged = false;
5185
+ this._verticallyScrolling = false;
5390
5186
  };
5391
5187
  this.el["Expressive_Sidenav"] = this;
5392
5188
  this.options = {
@@ -5397,17 +5193,26 @@ var _Sidenav = class _Sidenav extends Component {
5397
5193
  this.isOpen = false;
5398
5194
  this.isFixed = this.el.classList.contains("sidenav-fixed");
5399
5195
  this.isDragged = false;
5400
- this.lastWindowWidth = window.innerWidth;
5401
- this.lastWindowHeight = window.innerHeight;
5402
- this._createOverlay();
5196
+ this.dragTarget = null;
5197
+ this._dialog = null;
5198
+ this._createdDialog = false;
5199
+ this._closing = false;
5200
+ this.percentOpen = 0;
5201
+ this._startingXpos = 0;
5202
+ this._xPos = 0;
5203
+ this._width = 0;
5204
+ this._initialScrollTop = 0;
5205
+ this._verticallyScrolling = false;
5206
+ this._mql = window.matchMedia(LARGE_UP);
5207
+ this._setupDialog();
5403
5208
  this._createDragTarget();
5404
- this._setupEventHandlers();
5405
5209
  this._setupClasses();
5406
- this._setupFixed();
5210
+ this._setupEventHandlers();
5211
+ this._syncTriggers();
5407
5212
  _Sidenav._sidenavs.push(this);
5408
5213
  }
5409
5214
  static get defaults() {
5410
- return _defaults18;
5215
+ return _defaults15;
5411
5216
  }
5412
5217
  /**
5413
5218
  * Initializes instances of Sidenav.
@@ -5422,182 +5227,284 @@ var _Sidenav = class _Sidenav extends Component {
5422
5227
  }
5423
5228
  destroy() {
5424
5229
  this._removeEventHandlers();
5425
- this._enableBodyScrolling();
5426
- this._overlay.parentNode.removeChild(this._overlay);
5427
- this.dragTarget.parentNode.removeChild(this.dragTarget);
5230
+ if (this._dialog?.open) {
5231
+ try {
5232
+ this._dialog.close();
5233
+ } catch {
5234
+ }
5235
+ }
5236
+ this._clearShift();
5237
+ this._unwrapDialog();
5238
+ this._removeDragTarget();
5428
5239
  this.el["Expressive_Sidenav"] = void 0;
5429
- this.el.style.transform = "";
5430
5240
  const index = _Sidenav._sidenavs.indexOf(this);
5431
5241
  if (index >= 0) {
5432
5242
  _Sidenav._sidenavs.splice(index, 1);
5433
5243
  }
5434
5244
  }
5435
- _createOverlay() {
5436
- this._overlay = document.createElement("div");
5437
- this._overlay.classList.add("sidenav-overlay");
5438
- this._overlay.addEventListener("click", this.close);
5439
- document.body.appendChild(this._overlay);
5245
+ _beginClose() {
5246
+ this.isOpen = false;
5247
+ this._dialog?.classList.remove("dragging");
5248
+ this._clearShift();
5249
+ if (typeof this.options.onCloseStart === "function") {
5250
+ this.options.onCloseStart.call(this, this.el);
5251
+ }
5252
+ this._syncTriggers();
5253
+ }
5254
+ _finishClose() {
5255
+ if (typeof this.options.onCloseEnd === "function") {
5256
+ this.options.onCloseEnd.call(this, this.el);
5257
+ }
5258
+ }
5259
+ _setupDialog() {
5260
+ if (this.el instanceof HTMLDialogElement) {
5261
+ this._dialog = this.el;
5262
+ this._createdDialog = false;
5263
+ return;
5264
+ }
5265
+ const parent = this.el.parentElement;
5266
+ if (parent instanceof HTMLDialogElement && parent.classList.contains("sidenav-overlay")) {
5267
+ this._dialog = parent;
5268
+ this._createdDialog = false;
5269
+ return;
5270
+ }
5271
+ const dialog = document.createElement("dialog");
5272
+ dialog.classList.add("sidenav-overlay");
5273
+ this.el.replaceWith(dialog);
5274
+ dialog.appendChild(this.el);
5275
+ this._dialog = dialog;
5276
+ this._createdDialog = true;
5277
+ }
5278
+ _unwrapDialog() {
5279
+ if (!this._createdDialog || !this._dialog) return;
5280
+ this._dialog.replaceWith(this.el);
5281
+ this._dialog = null;
5282
+ this._createdDialog = false;
5283
+ }
5284
+ _createDragTarget() {
5285
+ if (!this.options.draggable) return;
5286
+ const dragTarget = document.createElement("div");
5287
+ dragTarget.classList.add("drag-target");
5288
+ dragTarget.style.width = this.options.dragTargetWidth;
5289
+ if (this.isFixed) dragTarget.dataset.fixed = "";
5290
+ document.body.appendChild(dragTarget);
5291
+ this.dragTarget = dragTarget;
5292
+ }
5293
+ _removeDragTarget() {
5294
+ this.dragTarget?.remove();
5295
+ this.dragTarget = null;
5296
+ }
5297
+ _setupClasses() {
5298
+ if (this.options.edge === "right") {
5299
+ this.el.classList.add("right-aligned");
5300
+ this._dialog?.classList.add("right-aligned");
5301
+ this.dragTarget?.classList.add("right-aligned");
5302
+ }
5440
5303
  }
5441
5304
  _setupEventHandlers() {
5442
5305
  if (_Sidenav._sidenavs.length === 0) {
5443
- document.body.addEventListener("click", this._handleTriggerClick);
5306
+ document.body.addEventListener("click", _Sidenav._handleTriggerClick);
5444
5307
  }
5445
5308
  const passive = { passive: true };
5446
- this.dragTarget.addEventListener("touchmove", this._handleDragTargetDrag, passive);
5447
- this.dragTarget.addEventListener("touchend", this._handleDragTargetRelease);
5448
- this._overlay.addEventListener("touchmove", this._handleCloseDrag, passive);
5449
- this._overlay.addEventListener("touchend", this._handleCloseRelease);
5450
- this.el.addEventListener("touchmove", this._handleCloseDrag, passive);
5451
- this.el.addEventListener("touchend", this._handleCloseRelease);
5309
+ this.dragTarget?.addEventListener("touchmove", this._handleDragTargetDrag, passive);
5310
+ this.dragTarget?.addEventListener("touchend", this._handleDragTargetRelease);
5311
+ this._dialog?.addEventListener("touchmove", this._handleCloseDrag, passive);
5312
+ this._dialog?.addEventListener("touchend", this._handleCloseRelease);
5313
+ this._dialog?.addEventListener("close", this._onDialogClose);
5452
5314
  this.el.addEventListener("click", this._handleCloseTriggerClick);
5453
- if (this.isFixed) {
5454
- window.addEventListener("resize", this._handleWindowResize, passive);
5455
- }
5456
- this._setAriaHidden();
5457
- this._setTabIndex();
5315
+ this._mql.addEventListener("change", this._onBreakpointChange);
5458
5316
  }
5459
5317
  _removeEventHandlers() {
5460
5318
  if (_Sidenav._sidenavs.length === 1) {
5461
- document.body.removeEventListener("click", this._handleTriggerClick);
5462
- }
5463
- this.dragTarget.removeEventListener("touchmove", this._handleDragTargetDrag);
5464
- this.dragTarget.removeEventListener("touchend", this._handleDragTargetRelease);
5465
- this._overlay.removeEventListener("touchmove", this._handleCloseDrag);
5466
- this._overlay.removeEventListener("touchend", this._handleCloseRelease);
5467
- this.el.removeEventListener("touchmove", this._handleCloseDrag);
5468
- this.el.removeEventListener("touchend", this._handleCloseRelease);
5469
- this.el.removeEventListener("click", this._handleCloseTriggerClick);
5470
- if (this.isFixed) {
5471
- window.removeEventListener("resize", this._handleWindowResize);
5319
+ document.body.removeEventListener("click", _Sidenav._handleTriggerClick);
5472
5320
  }
5321
+ this.dragTarget?.removeEventListener("touchmove", this._handleDragTargetDrag);
5322
+ this.dragTarget?.removeEventListener("touchend", this._handleDragTargetRelease);
5323
+ this._dialog?.removeEventListener("touchmove", this._handleCloseDrag);
5324
+ this._dialog?.removeEventListener("touchend", this._handleCloseRelease);
5325
+ this._dialog?.removeEventListener("close", this._onDialogClose);
5326
+ this.el.removeEventListener("click", this._handleCloseTriggerClick);
5327
+ this._mql.removeEventListener("change", this._onBreakpointChange);
5473
5328
  }
5474
- _handleTriggerClick(e) {
5475
- const trigger = e.target.closest(".sidenav-trigger");
5476
- if (e.target && trigger) {
5477
- const sidenavId = Utils.getIdFromTrigger(trigger);
5478
- const sidenavInstance = document.getElementById(sidenavId)?.["Expressive_Sidenav"];
5479
- if (sidenavInstance) {
5480
- sidenavInstance.open();
5481
- }
5329
+ static _handleTriggerClick(e) {
5330
+ const target = e.target;
5331
+ if (!(target instanceof Element)) return;
5332
+ const trigger = target.closest(".sidenav-trigger");
5333
+ if (!trigger || !(trigger instanceof HTMLElement)) return;
5334
+ const sidenavId = Utils.getIdFromTrigger(trigger);
5335
+ const sidenavInstance = document.getElementById(sidenavId)?.["Expressive_Sidenav"];
5336
+ if (sidenavInstance) {
5337
+ sidenavInstance.open();
5482
5338
  e.preventDefault();
5483
5339
  }
5484
5340
  }
5485
- // Set variables needed at the beginning of drag and stop any current transition.
5341
+ _isDraggable() {
5342
+ return this.options.draggable && !this._isCurrentlyFixed() && !this._verticallyScrolling;
5343
+ }
5344
+ _isCurrentlyFixed() {
5345
+ return this.isFixed && this._mql.matches;
5346
+ }
5486
5347
  _startDrag(e) {
5487
5348
  const clientX = e.targetTouches[0].clientX;
5488
5349
  this.isDragged = true;
5489
5350
  this._startingXpos = clientX;
5490
- this._xPos = this._startingXpos;
5491
- this._time = Date.now();
5492
- this._width = this.el.getBoundingClientRect().width;
5493
- this._overlay.style.display = "block";
5351
+ this._xPos = clientX;
5352
+ this._width = this._dialog?.getBoundingClientRect().width || this.el.getBoundingClientRect().width;
5494
5353
  this._initialScrollTop = this.isOpen ? this.el.scrollTop : Utils.getDocumentScrollTop();
5495
5354
  this._verticallyScrolling = false;
5355
+ this._dialog?.classList.add("dragging");
5356
+ if (this._dialog && !this._dialog.open) {
5357
+ try {
5358
+ this._dialog.showModal();
5359
+ } catch {
5360
+ }
5361
+ }
5496
5362
  }
5497
- //Set variables needed at each drag move update tick
5498
5363
  _dragMoveUpdate(e) {
5499
5364
  const clientX = e.targetTouches[0].clientX;
5500
5365
  const currentScrollTop = this.isOpen ? this.el.scrollTop : Utils.getDocumentScrollTop();
5501
- this.deltaX = Math.abs(this._xPos - clientX);
5502
5366
  this._xPos = clientX;
5503
- this.velocityX = this.deltaX / (Date.now() - this._time);
5504
- this._time = Date.now();
5505
5367
  if (this._initialScrollTop !== currentScrollTop) {
5506
5368
  this._verticallyScrolling = true;
5507
5369
  }
5508
5370
  }
5509
- _setupClasses() {
5510
- if (this.options.edge === "right") {
5511
- this.el.classList.add("right-aligned");
5512
- this.dragTarget.classList.add("right-aligned");
5513
- }
5514
- }
5515
- _removeClasses() {
5516
- this.el.classList.remove("right-aligned");
5517
- this.dragTarget.classList.remove("right-aligned");
5518
- }
5519
- _setupFixed() {
5520
- if (this._isCurrentlyFixed()) this.open();
5521
- }
5522
- _isDraggable() {
5523
- return this.options.draggable && !this._isCurrentlyFixed() && !this._verticallyScrolling;
5371
+ _rawDelta(e) {
5372
+ if (!this.isDragged) this._startDrag(e);
5373
+ this._dragMoveUpdate(e);
5374
+ return this._xPos - this._startingXpos;
5375
+ }
5376
+ _applyShift(shift, percentOpen) {
5377
+ this.percentOpen = percentOpen;
5378
+ const host = this._dialog ?? this.el;
5379
+ host.style.setProperty("--md-comp-nav-drawer-shift", `${shift}px`);
5380
+ host.style.setProperty("--md-comp-nav-drawer-open", String(percentOpen));
5381
+ }
5382
+ _clearShift() {
5383
+ const host = this._dialog ?? this.el;
5384
+ host.style.removeProperty("--md-comp-nav-drawer-shift");
5385
+ host.style.removeProperty("--md-comp-nav-drawer-open");
5386
+ }
5387
+ _syncTriggers() {
5388
+ if (!this.id) return;
5389
+ document.querySelectorAll(".sidenav-trigger").forEach((trigger) => {
5390
+ if (!(trigger instanceof HTMLElement)) return;
5391
+ if (Utils.getIdFromTrigger(trigger) !== this.id) return;
5392
+ trigger.setAttribute("aria-expanded", this.isOpen ? "true" : "false");
5393
+ trigger.setAttribute("aria-controls", this.id);
5394
+ });
5524
5395
  }
5525
- _isCurrentlyFixed() {
5526
- return this.isFixed && window.innerWidth > 992;
5396
+ };
5397
+ _Sidenav._sidenavs = [];
5398
+ var Sidenav = _Sidenav;
5399
+
5400
+ // src/ts/components/navigationRail.ts
5401
+ var _defaults16 = {
5402
+ onOpenStart: null,
5403
+ onOpenEnd: null,
5404
+ onCloseStart: null,
5405
+ onCloseEnd: null
5406
+ };
5407
+ var COMPACT = "(width < 601px)";
5408
+ var NavigationRail = class _NavigationRail extends Component {
5409
+ constructor(el, options) {
5410
+ super(el, options, _NavigationRail);
5411
+ /**
5412
+ * Expands the rail. On compact windows the overlay (scrim) is CSS.
5413
+ */
5414
+ this.expand = () => {
5415
+ if (this.isExpanded) return;
5416
+ if (typeof this.options.onOpenStart === "function") {
5417
+ this.options.onOpenStart.call(this, this.el);
5418
+ }
5419
+ this.isExpanded = true;
5420
+ this.el.classList.add("expanded");
5421
+ this._sync();
5422
+ if (typeof this.options.onOpenEnd === "function") {
5423
+ this.options.onOpenEnd.call(this, this.el);
5424
+ }
5425
+ };
5426
+ /**
5427
+ * Collapses the rail.
5428
+ */
5429
+ this.collapse = () => {
5430
+ if (!this.isExpanded) return;
5431
+ if (typeof this.options.onCloseStart === "function") {
5432
+ this.options.onCloseStart.call(this, this.el);
5433
+ }
5434
+ this.isExpanded = false;
5435
+ this.el.classList.remove("expanded");
5436
+ this._sync();
5437
+ if (typeof this.options.onCloseEnd === "function") {
5438
+ this.options.onCloseEnd.call(this, this.el);
5439
+ }
5440
+ };
5441
+ /**
5442
+ * Toggles expanded / collapsed.
5443
+ */
5444
+ this.toggle = () => {
5445
+ if (this.isExpanded) this.collapse();
5446
+ else this.expand();
5447
+ };
5448
+ this._onClick = (e) => {
5449
+ const target = e.target;
5450
+ if (!(target instanceof Node)) return;
5451
+ if (this._toggle && (target === this._toggle || this._toggle.contains(target))) {
5452
+ this.toggle();
5453
+ e.preventDefault();
5454
+ return;
5455
+ }
5456
+ if (target === this.el && this.isExpanded && this._isModal()) {
5457
+ this.collapse();
5458
+ }
5459
+ };
5460
+ this._onKeyDown = (e) => {
5461
+ if (e.key !== "Escape") return;
5462
+ if (this.isExpanded && this._isModal()) this.collapse();
5463
+ };
5464
+ this.el["Expressive_NavigationRail"] = this;
5465
+ this.options = {
5466
+ ..._NavigationRail.defaults,
5467
+ ...options
5468
+ };
5469
+ this._toggle = this._findToggle();
5470
+ this._mql = window.matchMedia(COMPACT);
5471
+ this.isExpanded = this.el.classList.contains("expanded");
5472
+ this._sync();
5473
+ this.el.addEventListener("click", this._onClick);
5474
+ document.addEventListener("keydown", this._onKeyDown);
5527
5475
  }
5528
- _createDragTarget() {
5529
- const dragTarget = document.createElement("div");
5530
- dragTarget.classList.add("drag-target");
5531
- dragTarget.style.width = this.options.dragTargetWidth;
5532
- document.body.appendChild(dragTarget);
5533
- this.dragTarget = dragTarget;
5476
+ static get defaults() {
5477
+ return _defaults16;
5534
5478
  }
5535
- _preventBodyScrolling() {
5536
- document.body.style.overflow = "hidden";
5479
+ static init(els, options = {}) {
5480
+ return super.init(els, options, _NavigationRail);
5537
5481
  }
5538
- _enableBodyScrolling() {
5539
- document.body.style.overflow = "";
5482
+ static getInstance(el) {
5483
+ return el["Expressive_NavigationRail"];
5540
5484
  }
5541
- _animateIn() {
5542
- this._animateSidenavIn();
5543
- this._animateOverlayIn();
5485
+ destroy() {
5486
+ this.el.removeEventListener("click", this._onClick);
5487
+ document.removeEventListener("keydown", this._onKeyDown);
5488
+ this.el["Expressive_NavigationRail"] = void 0;
5544
5489
  }
5545
- _animateOut() {
5546
- this._animateSidenavOut();
5547
- this._animateOverlayOut();
5490
+ _findToggle() {
5491
+ const first = this.el.querySelector(":scope > button:not(.button)");
5492
+ return first instanceof HTMLButtonElement ? first : null;
5548
5493
  }
5549
- _animateSidenavIn() {
5550
- let slideOutPercent = this.options.edge === "left" ? -1 : 1;
5551
- if (this.isDragged) {
5552
- slideOutPercent = this.options.edge === "left" ? slideOutPercent + this.percentOpen : slideOutPercent - this.percentOpen;
5553
- }
5554
- const duration = this.options.inDuration;
5555
- this.el.style.transition = "none";
5556
- this.el.style.transform = "translateX(" + slideOutPercent * 100 + "%)";
5557
- setTimeout(() => {
5558
- this.el.style.transition = `transform ${duration}ms ease`;
5559
- this.el.style.transform = "translateX(0)";
5560
- }, 1);
5561
- setTimeout(() => {
5562
- if (typeof this.options.onOpenEnd === "function") this.options.onOpenEnd.call(this, this.el);
5563
- }, duration);
5494
+ _isCompact() {
5495
+ return this._mql.matches;
5564
5496
  }
5565
- _animateSidenavOut() {
5566
- const endPercent = this.options.edge === "left" ? -1 : 1;
5567
- const duration = this.options.outDuration;
5568
- this.el.style.transition = `transform ${duration}ms ease`;
5569
- this.el.style.transform = "translateX(" + endPercent * 100 + "%)";
5570
- setTimeout(() => {
5571
- if (typeof this.options.onCloseEnd === "function")
5572
- this.options.onCloseEnd.call(this, this.el);
5573
- }, duration);
5497
+ _isModal() {
5498
+ return this.el.classList.contains("modal") || this._isCompact();
5574
5499
  }
5575
- _animateOverlayIn() {
5576
- let start = 0;
5577
- if (this.isDragged) start = this.percentOpen;
5578
- else this._overlay.style.display = "block";
5579
- const duration = this.options.inDuration;
5580
- this._overlay.style.transition = "none";
5581
- this._overlay.style.opacity = start.toString();
5582
- setTimeout(() => {
5583
- this._overlay.style.transition = `opacity ${duration}ms ease`;
5584
- this._overlay.style.opacity = "1";
5585
- }, 1);
5586
- }
5587
- _animateOverlayOut() {
5588
- const duration = this.options.outDuration;
5589
- this._overlay.style.transition = `opacity ${duration}ms ease`;
5590
- this._overlay.style.opacity = "0";
5591
- setTimeout(() => {
5592
- this._overlay.style.display = "none";
5593
- }, duration);
5500
+ _sync() {
5501
+ this.el.setAttribute("aria-expanded", this.isExpanded ? "true" : "false");
5502
+ this._toggle?.setAttribute("aria-expanded", this.isExpanded ? "true" : "false");
5594
5503
  }
5595
5504
  };
5596
- _Sidenav._sidenavs = [];
5597
- var Sidenav = _Sidenav;
5598
5505
 
5599
5506
  // src/ts/components/slider.ts
5600
- var _defaults19 = {
5507
+ var _defaults17 = {
5601
5508
  indicators: true,
5602
5509
  height: 400,
5603
5510
  duration: 500,
@@ -5745,7 +5652,7 @@ var Slider = class _Slider extends Component {
5745
5652
  this.start();
5746
5653
  }
5747
5654
  static get defaults() {
5748
- return _defaults19;
5655
+ return _defaults17;
5749
5656
  }
5750
5657
  /**
5751
5658
  * Initializes instances of Slider.
@@ -5898,7 +5805,7 @@ var Slider = class _Slider extends Component {
5898
5805
  };
5899
5806
 
5900
5807
  // src/ts/components/tabs.ts
5901
- var _defaults20 = {
5808
+ var _defaults18 = {
5902
5809
  duration: 300,
5903
5810
  onShow: null,
5904
5811
  swipeable: false,
@@ -5976,7 +5883,7 @@ var Tabs = class _Tabs extends Component {
5976
5883
  this._setupEventHandlers();
5977
5884
  }
5978
5885
  static get defaults() {
5979
- return _defaults20;
5886
+ return _defaults18;
5980
5887
  }
5981
5888
  /**
5982
5889
  * Initializes instances of Tabs.
@@ -6015,7 +5922,7 @@ var Tabs = class _Tabs extends Component {
6015
5922
  }
6016
5923
  _queryTabLinks() {
6017
5924
  return this.el.querySelectorAll(
6018
- ":scope > a, :scope > .tab > a, :scope > li.tab > a"
5925
+ ":scope > a, :scope > .tab > a"
6019
5926
  );
6020
5927
  }
6021
5928
  _createIndicator() {
@@ -6057,7 +5964,7 @@ var Tabs = class _Tabs extends Component {
6057
5964
  }
6058
5965
  });
6059
5966
  const tabsWrapper = document.createElement("div");
6060
- tabsWrapper.classList.add("tabs-content", "carousel", "carousel-slider");
5967
+ tabsWrapper.classList.add("tabs-content", "carousel", "flat");
6061
5968
  tabsContent[0].parentElement.insertBefore(tabsWrapper, tabsContent[0]);
6062
5969
  tabsContent.forEach((tabContent) => {
6063
5970
  tabsWrapper.appendChild(tabContent);
@@ -6143,229 +6050,8 @@ var Tabs = class _Tabs extends Component {
6143
6050
  }
6144
6051
  };
6145
6052
 
6146
- // src/ts/components/tapTarget.ts
6147
- var _defaults21 = {
6148
- onOpen: null,
6149
- onClose: null
6150
- };
6151
- var _TapTarget = class _TapTarget extends Component {
6152
- constructor(el, options) {
6153
- super(el, options, _TapTarget);
6154
- this.wrapper = null;
6155
- this.waveEl = null;
6156
- this.contentEl = null;
6157
- this._createdWrapper = false;
6158
- this._createdWave = false;
6159
- this._usePopover = false;
6160
- this._liftedStatic = false;
6161
- this._opening = false;
6162
- /**
6163
- * Open Tap Target.
6164
- */
6165
- this.open = () => {
6166
- if (this.isOpen || !this.originEl || !this.wrapper) return;
6167
- _TapTarget._taptargets.forEach((other) => {
6168
- if (other !== this) other.close();
6169
- });
6170
- this._calculatePositioning();
6171
- if (typeof this.options.onOpen === "function") {
6172
- this.options.onOpen.call(this, this.originEl);
6173
- }
6174
- this.isOpen = true;
6175
- this.wrapper.classList.add("open");
6176
- this.originEl.setAttribute("aria-expanded", "true");
6177
- if (!this._usePopover) {
6178
- this.originEl.classList.add("tap-target-origin");
6179
- if (getComputedStyle(this.originEl).position === "static") {
6180
- this.originEl.style.position = "relative";
6181
- this._liftedStatic = true;
6182
- }
6183
- }
6184
- if (this._usePopover) {
6185
- this._opening = true;
6186
- try {
6187
- this.wrapper.showPopover();
6188
- } catch {
6189
- }
6190
- requestAnimationFrame(() => {
6191
- this._opening = false;
6192
- });
6193
- }
6194
- };
6195
- /**
6196
- * Close Tap Target.
6197
- */
6198
- this.close = () => {
6199
- if (!this.isOpen) return;
6200
- if (typeof this.options.onClose === "function" && this.originEl) {
6201
- this.options.onClose.call(this, this.originEl);
6202
- }
6203
- this.isOpen = false;
6204
- this.wrapper?.classList.remove("open");
6205
- this.originEl?.setAttribute("aria-expanded", "false");
6206
- this.originEl?.classList.remove("tap-target-origin");
6207
- if (this._liftedStatic && this.originEl) {
6208
- this.originEl.style.position = "";
6209
- this._liftedStatic = false;
6210
- }
6211
- if (this._usePopover && this.wrapper) {
6212
- try {
6213
- this.wrapper.hidePopover();
6214
- } catch {
6215
- }
6216
- }
6217
- };
6218
- // Built once per instance; a fresh throttle per event never fires.
6219
- this._handleThrottledResize = Utils.throttle(() => this._handleResize(), 200);
6220
- this._handleOriginKeydown = (e) => {
6221
- if (Utils.keys.ENTER.includes(e.key) || e.key === " ") {
6222
- e.preventDefault();
6223
- this._handleTargetToggle();
6224
- }
6225
- };
6226
- this._handleTargetToggle = () => {
6227
- if (!this.isOpen) this.open();
6228
- else this.close();
6229
- };
6230
- this._handleResize = () => {
6231
- if (this.isOpen) this._calculatePositioning();
6232
- };
6233
- this._handlePopoverToggle = (e) => {
6234
- const state = "newState" in e ? String(e.newState) : "";
6235
- if (state === "open") return;
6236
- if (this._opening) {
6237
- try {
6238
- this.wrapper?.showPopover();
6239
- } catch {
6240
- }
6241
- return;
6242
- }
6243
- if (this.isOpen) this.close();
6244
- };
6245
- this.el["Expressive_TapTarget"] = this;
6246
- this.options = {
6247
- ..._TapTarget.defaults,
6248
- ...options
6249
- };
6250
- this.isOpen = false;
6251
- this.originEl = el.dataset.target ? document.getElementById(el.dataset.target) : null;
6252
- if (!this.originEl) {
6253
- console.error(`TapTarget: no element with id "${el.dataset.target ?? ""}" to attach to`);
6254
- return;
6255
- }
6256
- this._setup();
6257
- this._calculatePositioning();
6258
- this._setupEventHandlers();
6259
- _TapTarget._taptargets.push(this);
6260
- }
6261
- static get defaults() {
6262
- return _defaults21;
6263
- }
6264
- static init(els, options = {}) {
6265
- return super.init(els, options, _TapTarget);
6266
- }
6267
- static getInstance(el) {
6268
- return el["Expressive_TapTarget"];
6269
- }
6270
- destroy() {
6271
- this.close();
6272
- this._removeEventHandlers();
6273
- this._teardownDom();
6274
- this.el["Expressive_TapTarget"] = void 0;
6275
- const index = _TapTarget._taptargets.indexOf(this);
6276
- if (index >= 0) _TapTarget._taptargets.splice(index, 1);
6277
- }
6278
- _setup() {
6279
- const parent = this.el.parentElement;
6280
- if (parent?.classList.contains("tap-target-wrapper")) {
6281
- this.wrapper = parent;
6282
- } else {
6283
- this.wrapper = document.createElement("div");
6284
- this.wrapper.classList.add("tap-target-wrapper");
6285
- this.el.before(this.wrapper);
6286
- this.wrapper.append(this.el);
6287
- this._createdWrapper = true;
6288
- }
6289
- this.contentEl = this.el.querySelector(".tap-target-content");
6290
- if (!this.contentEl) {
6291
- this.contentEl = document.createElement("div");
6292
- this.contentEl.className = "tap-target-content";
6293
- while (this.el.firstChild) this.contentEl.append(this.el.firstChild);
6294
- this.el.append(this.contentEl);
6295
- }
6296
- this.waveEl = this.el.querySelector(".tap-target-wave") ?? this.wrapper.querySelector(".tap-target-wave");
6297
- if (!this.waveEl) {
6298
- this.waveEl = document.createElement("div");
6299
- this.waveEl.className = "tap-target-wave";
6300
- this._createdWave = true;
6301
- }
6302
- this.el.prepend(this.waveEl);
6303
- this.el.setAttribute("role", "dialog");
6304
- this._labelFromHeading();
6305
- const origin = this.originEl;
6306
- origin.setAttribute("aria-expanded", "false");
6307
- origin.setAttribute("aria-controls", this.el.id || this._ensureId());
6308
- this._usePopover = typeof this.wrapper.showPopover === "function";
6309
- if (this._usePopover) {
6310
- this.wrapper.setAttribute("popover", "auto");
6311
- }
6312
- }
6313
- _ensureId() {
6314
- if (!this.el.id) this.el.id = `tap-target-${Utils.guid()}`;
6315
- return this.el.id;
6316
- }
6317
- _labelFromHeading() {
6318
- const heading = this.contentEl?.querySelector("h1, h2, h3, h4, h5, h6");
6319
- if (!heading) return;
6320
- if (!heading.id) heading.id = `tap-target-title-${Utils.guid()}`;
6321
- this.el.setAttribute("aria-labelledby", heading.id);
6322
- }
6323
- _teardownDom() {
6324
- if (this._createdWave) this.waveEl?.remove();
6325
- if (this._createdWrapper && this.wrapper) {
6326
- this.wrapper.before(this.el);
6327
- this.wrapper.remove();
6328
- }
6329
- this.wrapper = null;
6330
- this.waveEl = null;
6331
- }
6332
- _setupEventHandlers() {
6333
- if (!this.originEl) return;
6334
- this.originEl.addEventListener("click", this._handleTargetToggle);
6335
- if (!this.originEl.matches('button, a, [tabindex], .btn, [role="button"]')) {
6336
- this.originEl.tabIndex = 0;
6337
- this.originEl.addEventListener("keydown", this._handleOriginKeydown);
6338
- }
6339
- this.wrapper?.addEventListener("toggle", this._handlePopoverToggle);
6340
- window.addEventListener("resize", this._handleThrottledResize, { passive: true });
6341
- }
6342
- _removeEventHandlers() {
6343
- if (!this.originEl) return;
6344
- this.originEl.removeEventListener("click", this._handleTargetToggle);
6345
- this.originEl.removeEventListener("keydown", this._handleOriginKeydown);
6346
- this.wrapper?.removeEventListener("toggle", this._handlePopoverToggle);
6347
- window.removeEventListener("resize", this._handleThrottledResize);
6348
- }
6349
- _calculatePositioning() {
6350
- if (!this.originEl || !this.wrapper) return;
6351
- const rect = this.originEl.getBoundingClientRect();
6352
- const x = rect.left + rect.width / 2;
6353
- const y = rect.top + rect.height / 2;
6354
- const size = Math.max(rect.width, rect.height, 1);
6355
- this.wrapper.style.setProperty("--md-comp-tap-target-x", `${x}px`);
6356
- this.wrapper.style.setProperty("--md-comp-tap-target-y", `${y}px`);
6357
- this.wrapper.style.setProperty("--md-comp-tap-target-origin-size", `${size}px`);
6358
- const vertical = y <= window.innerHeight / 2 ? "top" : "bottom";
6359
- const onCenter = x >= window.innerWidth * 0.25 && x <= window.innerWidth * 0.75;
6360
- const horizontal = onCenter ? "center" : x <= window.innerWidth / 2 ? "left" : "right";
6361
- this.wrapper.dataset.edge = `${vertical}-${horizontal}`;
6362
- }
6363
- };
6364
- _TapTarget._taptargets = [];
6365
- var TapTarget = _TapTarget;
6366
-
6367
6053
  // src/ts/components/timepicker.ts
6368
- var _defaults22 = {
6054
+ var _defaults19 = {
6369
6055
  dialRadius: 135,
6370
6056
  outerRadius: 105,
6371
6057
  innerRadius: 70,
@@ -6563,7 +6249,7 @@ var _Timepicker = class _Timepicker extends Component {
6563
6249
  }
6564
6250
  }
6565
6251
  static get defaults() {
6566
- return _defaults22;
6252
+ return _defaults19;
6567
6253
  }
6568
6254
  /**
6569
6255
  * Initializes instances of Timepicker.
@@ -6646,7 +6332,7 @@ var _Timepicker = class _Timepicker extends Component {
6646
6332
  }
6647
6333
  /*private _createButton(text: string, visibility: string): HTMLButtonElement {
6648
6334
  const button = document.createElement('button');
6649
- button.classList.add('btn', 'waves-effect', 'text');
6335
+ button.classList.add('waves-effect', 'text');
6650
6336
  button.style.visibility = visibility;
6651
6337
  button.type = 'button';
6652
6338
  button.tabIndex = -1;
@@ -6687,14 +6373,14 @@ var _Timepicker = class _Timepicker extends Component {
6687
6373
  _clockSetup() {
6688
6374
  if (this.options.twelveHour) {
6689
6375
  this._amBtn = document.createElement("div");
6690
- this._amBtn.classList.add("am-btn", "btn");
6376
+ this._amBtn.classList.add("am-btn");
6691
6377
  this._amBtn.innerText = "AM";
6692
6378
  this._amBtn.tabIndex = 0;
6693
6379
  this._amBtn.addEventListener("click", this._handleAmPmClick);
6694
6380
  this._amBtn.addEventListener("keypress", this._handleAmPmKeypress);
6695
6381
  this.spanAmPm.appendChild(this._amBtn);
6696
6382
  this._pmBtn = document.createElement("div");
6697
- this._pmBtn.classList.add("pm-btn", "btn");
6383
+ this._pmBtn.classList.add("pm-btn");
6698
6384
  this._pmBtn.innerText = "PM";
6699
6385
  this._pmBtn.tabIndex = 0;
6700
6386
  this._pmBtn.addEventListener("click", this._handleAmPmClick);
@@ -6901,19 +6587,6 @@ var _Timepicker = class _Timepicker extends Component {
6901
6587
  this.hours = (/* @__PURE__ */ new Date()).getHours();
6902
6588
  this.inputHours.value = (this.hours % (this.options.twelveHour ? 12 : 24)).toString();
6903
6589
  }
6904
- // deprecated
6905
- open() {
6906
- console.warn(
6907
- "Timepicker.close() is deprecated. Remove this method and wrap in modal yourself."
6908
- );
6909
- return this;
6910
- }
6911
- close() {
6912
- console.warn(
6913
- "Timepicker.close() is deprecated. Remove this method and wrap in modal yourself."
6914
- );
6915
- return this;
6916
- }
6917
6590
  };
6918
6591
  _Timepicker._template = `<div class="timepicker-container">
6919
6592
  <div class="timepicker-digital-display">
@@ -6945,8 +6618,8 @@ _Timepicker._template = `<div class="timepicker-container">
6945
6618
  </div>`;
6946
6619
  var Timepicker = _Timepicker;
6947
6620
 
6948
- // src/ts/components/toasts.ts
6949
- var _defaults23 = {
6621
+ // src/ts/components/snackbar.ts
6622
+ var _defaults20 = {
6950
6623
  text: "",
6951
6624
  action: "",
6952
6625
  onAction: null,
@@ -6958,97 +6631,109 @@ var _defaults23 = {
6958
6631
  completeCallback: null,
6959
6632
  activationPercent: 0.8
6960
6633
  };
6961
- var _Toast = class _Toast {
6962
- constructor(options) {
6634
+ var _Snackbar = class _Snackbar {
6635
+ constructor(options = {}) {
6636
+ this._dismissed = false;
6963
6637
  this.options = {
6964
- ..._Toast.defaults,
6638
+ ..._Snackbar.defaults,
6965
6639
  ...options
6966
6640
  };
6641
+ if (options.displayLength === void 0 && this.options.action) {
6642
+ this.options.displayLength = 1e4;
6643
+ }
6967
6644
  this.message = this.options.text;
6968
6645
  this.panning = false;
6969
6646
  this.timeRemaining = this.options.displayLength;
6970
- if (_Toast._toasts.length === 0) {
6971
- _Toast._createContainer();
6647
+ if (_Snackbar._snackbars.length > 0) {
6648
+ for (const snackbar of [..._Snackbar._snackbars]) {
6649
+ snackbar._dismissed = true;
6650
+ clearTimeout(snackbar.counterTimeout);
6651
+ snackbar.el.remove();
6652
+ }
6653
+ _Snackbar._snackbars.length = 0;
6654
+ }
6655
+ if (!_Snackbar._container || !_Snackbar._container.isConnected) {
6656
+ _Snackbar._createContainer();
6972
6657
  }
6973
- _Toast._toasts.push(this);
6974
- const toastElement = this._createToast();
6975
- toastElement["Expressive_Toast"] = this;
6976
- this.el = toastElement;
6658
+ _Snackbar._snackbars.push(this);
6659
+ const snackbarElement = this._createSnackbar();
6660
+ snackbarElement["Expressive_Snackbar"] = this;
6661
+ this.el = snackbarElement;
6977
6662
  this._animateIn();
6978
6663
  this._setTimer();
6979
6664
  }
6980
6665
  static get defaults() {
6981
- return _defaults23;
6666
+ return _defaults20;
6982
6667
  }
6983
6668
  static getInstance(el) {
6984
- return el["Expressive_Toast"];
6669
+ return el["Expressive_Snackbar"];
6985
6670
  }
6986
6671
  static _createContainer() {
6987
6672
  const container = document.createElement("div");
6988
- container.setAttribute("id", "toast-container");
6989
- container.addEventListener("touchstart", _Toast._onDragStart);
6990
- container.addEventListener("touchmove", _Toast._onDragMove);
6991
- container.addEventListener("touchend", _Toast._onDragEnd);
6992
- container.addEventListener("mousedown", _Toast._onDragStart);
6993
- document.addEventListener("mousemove", _Toast._onDragMove);
6994
- document.addEventListener("mouseup", _Toast._onDragEnd);
6673
+ container.setAttribute("id", "snackbar-container");
6674
+ container.addEventListener("touchstart", _Snackbar._onDragStart);
6675
+ container.addEventListener("touchmove", _Snackbar._onDragMove);
6676
+ container.addEventListener("touchend", _Snackbar._onDragEnd);
6677
+ container.addEventListener("mousedown", _Snackbar._onDragStart);
6678
+ document.addEventListener("mousemove", _Snackbar._onDragMove);
6679
+ document.addEventListener("mouseup", _Snackbar._onDragEnd);
6995
6680
  document.body.appendChild(container);
6996
- _Toast._container = container;
6681
+ _Snackbar._container = container;
6997
6682
  }
6998
6683
  static _removeContainer() {
6999
- document.removeEventListener("mousemove", _Toast._onDragMove);
7000
- document.removeEventListener("mouseup", _Toast._onDragEnd);
7001
- _Toast._container.remove();
7002
- _Toast._container = null;
6684
+ document.removeEventListener("mousemove", _Snackbar._onDragMove);
6685
+ document.removeEventListener("mouseup", _Snackbar._onDragEnd);
6686
+ _Snackbar._container.remove();
6687
+ _Snackbar._container = null;
7003
6688
  }
7004
6689
  static _onDragStart(e) {
7005
6690
  const target = e.target;
7006
- if (target && !target.closest("button, a") && target.closest(".toast, .snackbar")) {
7007
- const toastElem = target.closest(".toast, .snackbar");
7008
- const toast = toastElem["Expressive_Toast"];
7009
- if (!toast) return;
7010
- toast.panning = true;
7011
- toast._pauseTimer();
7012
- _Toast._draggedToast = toast;
7013
- toast.el.classList.add("panning");
7014
- toast.el.style.transition = "";
7015
- toast.startingXPos = _Toast._xPos(e);
7016
- toast.time = Date.now();
7017
- toast.xPos = _Toast._xPos(e);
6691
+ if (target && !target.closest("button, a") && target.closest(".snackbar")) {
6692
+ const snackbarElem = target.closest(".snackbar");
6693
+ const snackbar = snackbarElem["Expressive_Snackbar"];
6694
+ if (!snackbar) return;
6695
+ snackbar.panning = true;
6696
+ snackbar._pauseTimer();
6697
+ _Snackbar._draggedSnackbar = snackbar;
6698
+ snackbar.el.classList.add("panning");
6699
+ snackbar.el.style.transition = "";
6700
+ snackbar.startingXPos = _Snackbar._xPos(e);
6701
+ snackbar.time = Date.now();
6702
+ snackbar.xPos = _Snackbar._xPos(e);
7018
6703
  }
7019
6704
  }
7020
6705
  static _onDragMove(e) {
7021
- if (!!_Toast._draggedToast) {
6706
+ if (!!_Snackbar._draggedSnackbar) {
7022
6707
  e.preventDefault();
7023
- const toast = _Toast._draggedToast;
7024
- toast.deltaX = Math.abs(toast.xPos - _Toast._xPos(e));
7025
- toast.xPos = _Toast._xPos(e);
7026
- toast.velocityX = toast.deltaX / (Date.now() - toast.time);
7027
- toast.time = Date.now();
7028
- const totalDeltaX = toast.xPos - toast.startingXPos;
7029
- const activationDistance = toast.el.offsetWidth * toast.options.activationPercent;
7030
- toast.el.style.transform = `translateX(${totalDeltaX}px)`;
7031
- toast.el.style.opacity = (1 - Math.abs(totalDeltaX / activationDistance)).toString();
6708
+ const snackbar = _Snackbar._draggedSnackbar;
6709
+ snackbar.deltaX = Math.abs(snackbar.xPos - _Snackbar._xPos(e));
6710
+ snackbar.xPos = _Snackbar._xPos(e);
6711
+ snackbar.velocityX = snackbar.deltaX / (Date.now() - snackbar.time);
6712
+ snackbar.time = Date.now();
6713
+ const totalDeltaX = snackbar.xPos - snackbar.startingXPos;
6714
+ const activationDistance = snackbar.el.offsetWidth * snackbar.options.activationPercent;
6715
+ snackbar.el.style.transform = `translateX(${totalDeltaX}px)`;
6716
+ snackbar.el.style.opacity = (1 - Math.abs(totalDeltaX / activationDistance)).toString();
7032
6717
  }
7033
6718
  }
7034
6719
  static _onDragEnd() {
7035
- if (!!_Toast._draggedToast) {
7036
- const toast = _Toast._draggedToast;
7037
- toast.panning = false;
7038
- toast.el.classList.remove("panning");
7039
- const totalDeltaX = toast.xPos - toast.startingXPos;
7040
- const activationDistance = toast.el.offsetWidth * toast.options.activationPercent;
7041
- const shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance || toast.velocityX > 1;
6720
+ if (!!_Snackbar._draggedSnackbar) {
6721
+ const snackbar = _Snackbar._draggedSnackbar;
6722
+ snackbar.panning = false;
6723
+ snackbar.el.classList.remove("panning");
6724
+ const totalDeltaX = snackbar.xPos - snackbar.startingXPos;
6725
+ const activationDistance = snackbar.el.offsetWidth * snackbar.options.activationPercent;
6726
+ const shouldBeDismissed = Math.abs(totalDeltaX) > activationDistance || snackbar.velocityX > 1;
7042
6727
  if (shouldBeDismissed) {
7043
- toast.wasSwiped = true;
7044
- toast.dismiss();
6728
+ snackbar.wasSwiped = true;
6729
+ snackbar.dismiss();
7045
6730
  } else {
7046
- toast.el.style.transition = "transform .2s, opacity .2s";
7047
- toast.el.style.transform = "";
7048
- toast.el.style.opacity = "";
7049
- toast._resumeTimer();
6731
+ snackbar.el.style.transition = "transform .2s, opacity .2s";
6732
+ snackbar.el.style.transform = "";
6733
+ snackbar.el.style.opacity = "";
6734
+ snackbar._resumeTimer();
7050
6735
  }
7051
- _Toast._draggedToast = null;
6736
+ _Snackbar._draggedSnackbar = null;
7052
6737
  }
7053
6738
  }
7054
6739
  static _xPos(e) {
@@ -7058,30 +6743,30 @@ var _Toast = class _Toast {
7058
6743
  return e.clientX;
7059
6744
  }
7060
6745
  /**
7061
- * dismiss all toasts.
6746
+ * dismiss all snackbars.
7062
6747
  */
7063
6748
  static dismissAll() {
7064
- for (const toast of [..._Toast._toasts]) {
7065
- toast.dismiss();
6749
+ for (const snackbar of [..._Snackbar._snackbars]) {
6750
+ snackbar.dismiss();
7066
6751
  }
7067
6752
  }
7068
- _createToast() {
7069
- let toast = this.options.toastId ? document.getElementById(this.options.toastId) : document.createElement("div");
7070
- if (toast instanceof HTMLTemplateElement) {
7071
- const node = toast.content.cloneNode(true);
7072
- toast = node.firstElementChild;
6753
+ _createSnackbar() {
6754
+ let snackbar = this.options.snackbarId ? document.getElementById(this.options.snackbarId) : document.createElement("div");
6755
+ if (snackbar instanceof HTMLTemplateElement) {
6756
+ const node = snackbar.content.cloneNode(true);
6757
+ snackbar = node.firstElementChild;
7073
6758
  }
7074
- toast.classList.add("toast", "snackbar");
7075
- toast.setAttribute("role", "status");
7076
- toast.setAttribute("aria-live", "polite");
7077
- toast.setAttribute("aria-atomic", "true");
6759
+ snackbar.classList.add("snackbar");
6760
+ snackbar.setAttribute("role", "status");
6761
+ snackbar.setAttribute("aria-live", "polite");
6762
+ snackbar.setAttribute("aria-atomic", "true");
7078
6763
  if (this.options.classes.length > 0) {
7079
- toast.classList.add(...this.options.classes.split(" ").filter(Boolean));
6764
+ snackbar.classList.add(...this.options.classes.split(" ").filter(Boolean));
7080
6765
  }
7081
6766
  if (this.message) {
7082
6767
  const text = document.createElement("p");
7083
6768
  text.textContent = this.message;
7084
- toast.replaceChildren(text);
6769
+ snackbar.replaceChildren(text);
7085
6770
  }
7086
6771
  if (this.options.action) {
7087
6772
  const action = document.createElement("button");
@@ -7094,7 +6779,7 @@ var _Toast = class _Toast {
7094
6779
  }
7095
6780
  this.dismiss();
7096
6781
  });
7097
- toast.appendChild(action);
6782
+ snackbar.appendChild(action);
7098
6783
  }
7099
6784
  if (this.options.dismissible) {
7100
6785
  const close = document.createElement("button");
@@ -7110,20 +6795,21 @@ var _Toast = class _Toast {
7110
6795
  e.stopPropagation();
7111
6796
  this.dismiss();
7112
6797
  });
7113
- toast.appendChild(close);
6798
+ snackbar.appendChild(close);
7114
6799
  }
7115
- _Toast._container.appendChild(toast);
7116
- return toast;
6800
+ _Snackbar._container.appendChild(snackbar);
6801
+ return snackbar;
7117
6802
  }
7118
6803
  _animateIn() {
7119
6804
  this.el.style.display = "";
7120
6805
  this.el.style.opacity = "0";
6806
+ this.el.style.transform = "translateY(24px)";
7121
6807
  this.el.style.transition = `
7122
- top ${this.options.inDuration}ms ease,
6808
+ transform ${this.options.inDuration}ms ease,
7123
6809
  opacity ${this.options.inDuration}ms ease
7124
6810
  `;
7125
6811
  setTimeout(() => {
7126
- this.el.style.top = "0";
6812
+ this.el.style.transform = "";
7127
6813
  this.el.style.opacity = "1";
7128
6814
  }, 1);
7129
6815
  }
@@ -7131,7 +6817,7 @@ var _Toast = class _Toast {
7131
6817
  * Arm the dismissal timer.
7132
6818
  *
7133
6819
  * One timeout, not a 20ms interval ticking a counter down: the old form woke
7134
- * the page up 50 times a second per toast purely to subtract 20 from a
6820
+ * the page up 50 times a second per snackbar purely to subtract 20 from a
7135
6821
  * number. Dragging pauses the countdown via _pauseTimer/_resumeTimer instead.
7136
6822
  */
7137
6823
  _setTimer() {
@@ -7152,9 +6838,11 @@ var _Toast = class _Toast {
7152
6838
  this._setTimer();
7153
6839
  }
7154
6840
  /**
7155
- * Dismiss toast with animation.
6841
+ * Dismiss snackbar with animation.
7156
6842
  */
7157
6843
  dismiss() {
6844
+ if (this._dismissed) return;
6845
+ this._dismissed = true;
7158
6846
  clearTimeout(this.counterTimeout);
7159
6847
  this.counterTimeout = null;
7160
6848
  const activationDistance = this.el.offsetWidth * this.options.activationPercent;
@@ -7174,24 +6862,24 @@ var _Toast = class _Toast {
7174
6862
  if (typeof this.options.completeCallback === "function") {
7175
6863
  this.options.completeCallback();
7176
6864
  }
7177
- if (this.el.id != this.options.toastId) {
6865
+ if (this.el.id != this.options.snackbarId) {
7178
6866
  this.el.remove();
7179
- const index = _Toast._toasts.indexOf(this);
7180
- if (index >= 0) _Toast._toasts.splice(index, 1);
7181
- if (_Toast._toasts.length === 0 && _Toast._container) {
7182
- _Toast._removeContainer();
6867
+ const index = _Snackbar._snackbars.indexOf(this);
6868
+ if (index >= 0) _Snackbar._snackbars.splice(index, 1);
6869
+ if (_Snackbar._snackbars.length === 0 && _Snackbar._container && _Snackbar._container.childElementCount === 0) {
6870
+ _Snackbar._removeContainer();
7183
6871
  }
7184
6872
  }
7185
6873
  }, this.options.outDuration);
7186
6874
  }
7187
6875
  };
7188
- _Toast._toasts = [];
7189
- _Toast._container = null;
7190
- _Toast._draggedToast = null;
7191
- var Toast = _Toast;
6876
+ _Snackbar._snackbars = [];
6877
+ _Snackbar._container = null;
6878
+ _Snackbar._draggedSnackbar = null;
6879
+ var Snackbar = _Snackbar;
7192
6880
 
7193
6881
  // src/ts/components/tooltip.ts
7194
- var _defaults24 = {
6882
+ var _defaults21 = {
7195
6883
  exitDelay: 200,
7196
6884
  enterDelay: 0,
7197
6885
  text: "",
@@ -7259,7 +6947,7 @@ var Tooltip = class _Tooltip extends Component {
7259
6947
  this._setupEventHandlers();
7260
6948
  }
7261
6949
  static get defaults() {
7262
- return _defaults24;
6950
+ return _defaults21;
7263
6951
  }
7264
6952
  /**
7265
6953
  * Initializes instances of Tooltip.
@@ -7282,7 +6970,7 @@ var Tooltip = class _Tooltip extends Component {
7282
6970
  }
7283
6971
  _appendTooltipEl() {
7284
6972
  this.tooltipEl = document.createElement("div");
7285
- this.tooltipEl.classList.add("tooltip", "material-tooltip");
6973
+ this.tooltipEl.classList.add("tooltip");
7286
6974
  this.tooltipEl.id = `tooltip-${Utils.guid()}`;
7287
6975
  this.tooltipEl.setAttribute("role", "tooltip");
7288
6976
  this.el.setAttribute("aria-describedby", this.tooltipEl.id);
@@ -7439,18 +7127,15 @@ var AUTO_INIT_COMPONENTS = {
7439
7127
  Cards: { component: Cards, selector: CARDS_SELECTOR },
7440
7128
  Carousel: { component: Carousel, selector: ".carousel" },
7441
7129
  Chips: { component: Chips, selector: ".chips" },
7442
- Collapsible: { component: Collapsible, selector: ".collapsible" },
7443
7130
  Datepicker: { component: Datepicker, selector: ".datepicker" },
7444
- Dropdown: { component: Dropdown, selector: ".dropdown-trigger" },
7131
+ Menu: { component: Menu, selector: ".menu-trigger" },
7445
7132
  Lightbox: { component: Lightbox, selector: ".lightboxed" },
7446
- Modal: { component: Modal, selector: ".modal" },
7447
7133
  Parallax: { component: Parallax, selector: ".parallax" },
7448
- Pushpin: { component: Pushpin, selector: ".pushpin" },
7449
7134
  ScrollSpy: { component: ScrollSpy, selector: ".scrollspy" },
7450
7135
  FormSelect: { component: FormSelect, selector: "select" },
7451
7136
  Sidenav: { component: Sidenav, selector: ".sidenav" },
7137
+ NavigationRail: { component: NavigationRail, selector: ".navigation-rail" },
7452
7138
  Tabs: { component: Tabs, selector: ".tabs" },
7453
- TapTarget: { component: TapTarget, selector: ".tap-target" },
7454
7139
  Timepicker: { component: Timepicker, selector: ".timepicker" },
7455
7140
  Tooltip: { component: Tooltip, selector: ".tooltipped" },
7456
7141
  FloatingActionButton: {
@@ -7467,7 +7152,7 @@ function AutoInit(context = document.body, options) {
7467
7152
  }
7468
7153
 
7469
7154
  // src/ts/index.ts
7470
- var version = "0.3.0";
7155
+ var version = "0.5.0";
7471
7156
  if (typeof document !== "undefined") {
7472
7157
  document.addEventListener("keydown", Utils.docHandleKeydown, true);
7473
7158
  document.addEventListener("keyup", Utils.docHandleKeyup, true);
@@ -7480,4 +7165,6 @@ Waves.Init();
7480
7165
  Range.Init();
7481
7166
  Cards.Init();
7482
7167
  Dialogs.Init();
7168
+ BottomSheets.Init();
7169
+ SideSheets.Init();
7483
7170
  //# sourceMappingURL=expressive.cjs.map